]> git.mdlowis.com Git - proto/cerise-os.git/commitdiff
initial commit
authorMichael D. Lowis <mike.lowis@gentex.com>
Thu, 1 Sep 2022 19:18:48 +0000 (15:18 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Thu, 1 Sep 2022 19:18:48 +0000 (15:18 -0400)
ansivt.h [new file with mode: 0644]
experiments/fonts.c [new file with mode: 0644]
experiments/interactors.c [new file with mode: 0644]
experiments/os.c [new file with mode: 0644]
experiments/sdl_bezier.c [new file with mode: 0644]
experiments/ximage.c [new file with mode: 0644]
experiments/ximage_fb.c [new file with mode: 0644]
main.c [new file with mode: 0644]

diff --git a/ansivt.h b/ansivt.h
new file mode 100644 (file)
index 0000000..ffc86f0
--- /dev/null
+++ b/ansivt.h
@@ -0,0 +1,355 @@
+/*
+    Minimal set of routines for working with ANSI terminal escape codes for
+    controlling terminal operation on POSIX systems.
+
+    Copyright 2017, Michael D. Lowis
+
+    Permission to use, copy, modify, and/or distribute this software
+    for any purpose with or without fee is hereby granted, provided
+    that the above copyright notice and this permission notice appear
+    in all copies.
+
+    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+    WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+    AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+    DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+    TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+    PERFORMANCE OF THIS SOFTWARE.
+*/
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+
+static void ttyresp(char* buf, int bufsz) {
+    for (int i = 0; i < bufsz; i++) {
+        if (read(STDIN_FILENO, buf+i, 1) != 1) break;
+        if (buf[i] == 'R') break;
+    }
+}
+
+static void ttysendrecv(const char* req, const char* resp, ...) {
+    char buf[32] = {0};
+    (void)write(STDOUT_FILENO, req, strlen(req));
+    ttyresp(buf, sizeof(buf)-1);
+    va_list args;
+    va_start(args, resp);
+    vsscanf(buf, resp, args);
+    va_end(args);
+}
+
+static bool ttyrawmode(bool enable) {
+    static bool enabled = false;
+    static struct termios orig_termios;
+    if (enabled && !enable) {
+        tcsetattr(STDOUT_FILENO, TCSAFLUSH, &orig_termios);
+    } else if (!enabled && enable){
+        if (tcgetattr(STDOUT_FILENO, &orig_termios) < 0) goto done;
+        struct termios raw = orig_termios;
+        raw.c_iflag    &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+        raw.c_oflag    &= ~(OPOST);
+        raw.c_cflag    |= (CS8);
+        raw.c_lflag    &= ~(ECHO | ICANON | IEXTEN | ISIG);
+        raw.c_cc[VMIN]  = 0;
+        raw.c_cc[VTIME] = 1;
+        if (tcsetattr(STDOUT_FILENO,TCSAFLUSH, &raw) < 0) goto done;
+        enabled = true;
+    }
+done:
+    return enabled;
+}
+
+enum {
+    /* Special Keys */
+    KEY_F1               = (0xFFFF-0),
+    KEY_F2               = (0xFFFF-1),
+    KEY_F3               = (0xFFFF-2),
+    KEY_F4               = (0xFFFF-3),
+    KEY_F5               = (0xFFFF-4),
+    KEY_F6               = (0xFFFF-5),
+    KEY_F7               = (0xFFFF-6),
+    KEY_F8               = (0xFFFF-7),
+    KEY_F9               = (0xFFFF-8),
+    KEY_F10              = (0xFFFF-9),
+    KEY_F11              = (0xFFFF-10),
+    KEY_F12              = (0xFFFF-11),
+    KEY_INSERT           = (0xFFFF-12),
+    KEY_DELETE           = (0xFFFF-13),
+    KEY_HOME             = (0xFFFF-14),
+    KEY_END              = (0xFFFF-15),
+    KEY_PGUP             = (0xFFFF-16),
+    KEY_PGDN             = (0xFFFF-17),
+    KEY_ARROW_UP         = (0xFFFF-18),
+    KEY_ARROW_DOWN       = (0xFFFF-19),
+    KEY_ARROW_RIGHT      = (0xFFFF-20),
+    KEY_ARROW_LEFT       = (0xFFFF-21),
+    KEY_MOUSE_LEFT       = (0xFFFF-22),
+    KEY_MOUSE_RIGHT      = (0xFFFF-23),
+    KEY_MOUSE_MIDDLE     = (0xFFFF-24),
+    KEY_MOUSE_RELEASE    = (0xFFFF-25),
+    KEY_MOUSE_WHEEL_UP   = (0xFFFF-26),
+    KEY_MOUSE_WHEEL_DOWN = (0xFFFF-27),
+
+    /* ASCII Control Characters */
+    KEY_CTRL_TILDE       = 0x00,
+    KEY_CTRL_2           = 0x00,
+    KEY_CTRL_A           = 0x01,
+    KEY_CTRL_B           = 0x02,
+    KEY_CTRL_C           = 0x03,
+    KEY_CTRL_D           = 0x04,
+    KEY_CTRL_E           = 0x05,
+    KEY_CTRL_F           = 0x06,
+    KEY_CTRL_G           = 0x07,
+    KEY_BACKSPACE        = 0x08,
+    KEY_CTRL_H           = 0x08,
+    KEY_TAB              = 0x09,
+    KEY_CTRL_I           = 0x09,
+    KEY_CTRL_J           = 0x0A,
+    KEY_CTRL_K           = 0x0B,
+    KEY_CTRL_L           = 0x0C,
+    KEY_ENTER            = 0x0D,
+    KEY_CTRL_M           = 0x0D,
+    KEY_CTRL_N           = 0x0E,
+    KEY_CTRL_O           = 0x0F,
+    KEY_CTRL_P           = 0x10,
+    KEY_CTRL_Q           = 0x11,
+    KEY_CTRL_R           = 0x12,
+    KEY_CTRL_S           = 0x13,
+    KEY_CTRL_T           = 0x14,
+    KEY_CTRL_U           = 0x15,
+    KEY_CTRL_V           = 0x16,
+    KEY_CTRL_W           = 0x17,
+    KEY_CTRL_X           = 0x18,
+    KEY_CTRL_Y           = 0x19,
+    KEY_CTRL_Z           = 0x1A,
+    KEY_ESC              = 0x1B,
+    KEY_CTRL_LSQ_BRACKET = 0x1B,
+    KEY_CTRL_3           = 0x1B,
+    KEY_CTRL_4           = 0x1C,
+    KEY_CTRL_BACKSLASH   = 0x1C,
+    KEY_CTRL_5           = 0x1D,
+    KEY_CTRL_RSQ_BRACKET = 0x1D,
+    KEY_CTRL_6           = 0x1E,
+    KEY_CTRL_7           = 0x1F,
+    KEY_CTRL_SLASH       = 0x1F,
+    KEY_CTRL_UNDERSCORE  = 0x1F,
+    KEY_SPACE            = 0x20,
+    KEY_BACKSPACE2       = 0x7F,
+    KEY_CTRL_8           = 0x7F,
+};
+
+static int readkey(void) {
+    int nread;
+    char c, seq[3];
+    while ((nread = read(STDIN_FILENO,&c,1)) == 0);
+    if (nread < 0) return EOF;
+    if (c != KEY_ESC) return c;
+    /* Otherwise parse the escape sequence */
+    while (true) {
+        /* If this is just an ESC, we'll timeout here. */
+        if (read(STDIN_FILENO, seq,   1) == 0) return KEY_ESC;
+        if (read(STDIN_FILENO, seq+1, 1) == 0) return KEY_ESC;
+        /* Parse the escape sequence */
+        if ('[' == seq[0]) {
+            if ((seq[1] >= '0') && (seq[1] <= '9')) {
+                /* Extended escape, read additional byte. */
+                if (read(STDIN_FILENO, seq+2, 1) == 0) return KEY_ESC;
+                if (seq[2] == '~') {
+                    switch(seq[1]) {
+                        case '3': return KEY_DELETE;
+                        case '5': return KEY_PGUP;
+                        case '6': return KEY_PGDN;
+                    }
+                }
+            } else {
+                switch(seq[1]) {
+                    case 'A': return KEY_ARROW_UP;
+                    case 'B': return KEY_ARROW_DOWN;
+                    case 'C': return KEY_ARROW_RIGHT;
+                    case 'D': return KEY_ARROW_LEFT;
+                    case 'H': return KEY_HOME;
+                    case 'F': return KEY_END;
+                }
+            }
+        } else if ('O' == seq[0]) {
+            switch(seq[1]) {
+                case 'H': return KEY_HOME;
+                case 'F': return KEY_END;
+            }
+        }
+    }
+    /* should never get here */
+    return EOF;
+}
+
+/* Screen Buffer Handling
+ *****************************************************************************/
+static struct {
+    size_t capacity;
+    size_t length;
+    char* buffer;
+} ScreenBuf;
+
+static void scrsize(int* rows, int* cols) {
+    /* save cursor pos, try to move to lower right, read pos, restore pos */
+    ttysendrecv("\033[s\033[999;999H\033[6n\033[u", "\033[%d;%dR", rows, cols);
+}
+
+static void scrdraw(void) {
+    write(STDOUT_FILENO, ScreenBuf.buffer, ScreenBuf.length);
+    ScreenBuf.length = 0;
+}
+
+static void scrputc(char ch) {
+    /* Make sure there's space for the new char */
+    if (ScreenBuf.buffer == NULL) {
+        ScreenBuf.capacity = 8u;
+        ScreenBuf.buffer   = (char*)calloc(ScreenBuf.capacity, 1u);
+    } else if (ScreenBuf.length+1u >= ScreenBuf.capacity) {
+        ScreenBuf.capacity = ScreenBuf.capacity << 1u;
+        ScreenBuf.buffer = (char*)realloc(ScreenBuf.buffer, ScreenBuf.capacity);
+    }
+    /* Append the char */
+    ScreenBuf.buffer[ScreenBuf.length++] = ch;
+    ScreenBuf.buffer[ScreenBuf.length]   = '\0';
+}
+
+static int scrputs(char* str) {
+    int nwrite = 0;
+    while (*str) {
+        scrputc(*(str++));
+        nwrite++;
+    }
+    return nwrite;
+}
+
+static int scrprintf(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    size_t strsz = vsnprintf(NULL, 0, fmt, args);
+    va_end(args);
+    char* str = malloc(strsz+1);
+    va_start(args, fmt);
+    int nwrite = vsnprintf(str, strsz+1, fmt, args);
+    va_end(args);
+    scrputs(str);
+    free(str);
+    return nwrite;
+}
+
+static void scrclrup(void) {
+    scrputs("\033[0J");
+}
+
+static void scrclrdn(void) {
+    scrputs("\033[1J");
+}
+
+static void scrclr(void) {
+    scrputs("\033[2J");
+}
+
+static void scrclrlnl(void) {
+    scrputs("\033[0K");
+}
+
+static void scrclrlnr(void) {
+    scrputs("\033[1K");
+}
+
+static void scrclrln(void) {
+    scrputs("\033[2K");
+}
+
+/* Cursor Handling
+ *****************************************************************************/
+static void csrhome(void) {
+    scrputs("\033[H");
+}
+
+static void csrlinebeg(void) {
+    scrputs("\033[0G");
+}
+
+static void csrmove(int l, int c) {
+    scrprintf("\033[%d;%dH", l, c);
+}
+
+static void csrup(int n) {
+    scrprintf("\033[%dA", n);
+}
+
+static void csrdn(int n) {
+    scrprintf("\033[%dB", n);
+}
+
+static void csrleft(int n) {
+    scrprintf("\033[%dC", n);
+}
+
+static void csrright(int n) {
+    scrprintf("\033[%dD", n);
+}
+
+static void csrsave(void) {
+    scrputs("\033[s");
+}
+
+static void csrrestore(void) {
+    scrputs("\033[u");
+}
+
+static void csrhide(void) {
+    scrputs("\033[?25l");
+}
+
+static void csrshow(void) {
+    scrputs("\033[?25h");
+}
+
+/* Attribute Handling
+ *****************************************************************************/
+enum {
+    NORMAL   = 0,
+    BOLD     = 1,
+    UNDRLINE = 4,
+    BLINK    = 5,
+    REVERSE  = 7,
+    CONCEAL  = 8,
+};
+
+enum {
+    BLACK   = 0,
+    RED     = 1,
+    GREEN   = 2,
+    YELLOW  = 3,
+    BLUE    = 4,
+    MAGENTA = 5,
+    CYAN    = 6,
+    WHITE   = 7,
+};
+
+static void attrset(int a, int fg, int bg) {
+    scrprintf("\033[%d;%d;%dm",a, 30+fg, 40+bg);
+}
+
+static void attrclr(void) {
+    scrputs("\033[m");
+}
+
+static void attrsetstyle(int a) {
+    scrprintf("\033[%dm", a);
+}
+
+static void attrsetfg(int fg) {
+    scrprintf("\033[%dm", fg + 30);
+}
+
+static void attrsetbg(int bg) {
+    scrprintf("\033[%dm", bg + 40);
+}
diff --git a/experiments/fonts.c b/experiments/fonts.c
new file mode 100644 (file)
index 0000000..dcfa9c5
--- /dev/null
@@ -0,0 +1,142 @@
+int
+xloadfont(Font *f, FcPattern *pattern)
+{
+       FcPattern *configured;
+       FcPattern *match;
+       FcResult result;
+       XGlyphInfo extents;
+       int wantattr, haveattr;
+
+       /*
+        * Manually configure instead of calling XftMatchFont
+        * so that we can use the configured pattern for
+        * "missing glyph" lookups.
+        */
+       configured = FcPatternDuplicate(pattern);
+       if (!configured)
+               return 1;
+
+       FcConfigSubstitute(NULL, configured, FcMatchPattern);
+       XftDefaultSubstitute(xw.dpy, xw.scr, configured);
+
+       match = FcFontMatch(NULL, configured, &result);
+       if (!match) {
+               FcPatternDestroy(configured);
+               return 1;
+       }
+
+       if (!(f->match = XftFontOpenPattern(xw.dpy, match))) {
+               FcPatternDestroy(configured);
+               FcPatternDestroy(match);
+               return 1;
+       }
+
+       if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) ==
+           XftResultMatch)) {
+               /*
+                * Check if xft was unable to find a font with the appropriate
+                * slant but gave us one anyway. Try to mitigate.
+                */
+               if ((XftPatternGetInteger(f->match->pattern, "slant", 0,
+                   &haveattr) != XftResultMatch) || haveattr < wantattr) {
+                       f->badslant = 1;
+                       fputs("font slant does not match\n", stderr);
+               }
+       }
+
+       if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) ==
+           XftResultMatch)) {
+               if ((XftPatternGetInteger(f->match->pattern, "weight", 0,
+                   &haveattr) != XftResultMatch) || haveattr != wantattr) {
+                       f->badweight = 1;
+                       fputs("font weight does not match\n", stderr);
+               }
+       }
+
+       XftTextExtentsUtf8(xw.dpy, f->match,
+               (const FcChar8 *) ascii_printable,
+               strlen(ascii_printable), &extents);
+
+       f->set = NULL;
+       f->pattern = configured;
+
+       f->ascent = f->match->ascent;
+       f->descent = f->match->descent;
+       f->lbearing = 0;
+       f->rbearing = f->match->max_advance_width;
+
+       f->height = f->ascent + f->descent;
+       f->width = DIVCEIL(extents.xOff, strlen(ascii_printable));
+
+       return 0;
+}
+
+void
+xloadfonts(const char *fontstr, double fontsize)
+{
+       FcPattern *pattern;
+       double fontval;
+
+       if (fontstr[0] == '-')
+               pattern = XftXlfdParse(fontstr, False, False);
+       else
+               pattern = FcNameParse((const FcChar8 *)fontstr);
+
+       if (!pattern)
+               die("can't open font %s\n", fontstr);
+
+       if (fontsize > 1) {
+               FcPatternDel(pattern, FC_PIXEL_SIZE);
+               FcPatternDel(pattern, FC_SIZE);
+               FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);
+               usedfontsize = fontsize;
+       } else {
+               if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
+                               FcResultMatch) {
+                       usedfontsize = fontval;
+               } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) ==
+                               FcResultMatch) {
+                       usedfontsize = -1;
+               } else {
+                       /*
+                        * Default font size is 12, if none given. This is to
+                        * have a known usedfontsize value.
+                        */
+                       FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12);
+                       usedfontsize = 12;
+               }
+               defaultfontsize = usedfontsize;
+       }
+
+       if (xloadfont(&dc.font, pattern))
+               die("can't open font %s\n", fontstr);
+
+       if (usedfontsize < 0) {
+               FcPatternGetDouble(dc.font.match->pattern,
+                                  FC_PIXEL_SIZE, 0, &fontval);
+               usedfontsize = fontval;
+               if (fontsize == 0)
+                       defaultfontsize = fontval;
+       }
+
+       /* Setting character width and height. */
+       win.cw = ceilf(dc.font.width * cwscale);
+       win.ch = ceilf(dc.font.height * chscale);
+
+       FcPatternDel(pattern, FC_SLANT);
+       FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+       if (xloadfont(&dc.ifont, pattern))
+               die("can't open font %s\n", fontstr);
+
+       FcPatternDel(pattern, FC_WEIGHT);
+       FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
+       if (xloadfont(&dc.ibfont, pattern))
+               die("can't open font %s\n", fontstr);
+
+       FcPatternDel(pattern, FC_SLANT);
+       FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
+       if (xloadfont(&dc.bfont, pattern))
+               die("can't open font %s\n", fontstr);
+
+       FcPatternDestroy(pattern);
+}
diff --git a/experiments/interactors.c b/experiments/interactors.c
new file mode 100644 (file)
index 0000000..075171d
--- /dev/null
@@ -0,0 +1,142 @@
+#include <stdio.h>
+#include <stdbool.h>
+
+struct Interactor;
+
+typedef struct {
+    void (*set_as_bool)(struct Interactor*, bool);
+    void (*set_as_int)(struct Interactor*, long);
+    void (*set_as_real)(struct Interactor*, double);
+    void (*set_as_string)(struct Interactor*, const char*);
+    bool (*get_as_bool)(struct Interactor*);
+    long (*get_as_int)(struct Interactor*);
+    double (*get_as_real)(struct Interactor*);
+    const char* (*get_as_string)(struct Interactor*);
+} InteractorFuncs;
+
+typedef struct Interactor {
+    const InteractorFuncs* funcs;
+    void (*on_update)(void);
+    char* name;
+    void* value;
+} Interactor;
+
+void UI_AddBoolInteractor(char* name, bool* value, void (*on_update)(void));
+void UI_AddIntInteractor(char* name, long* value, void (*on_update)(void));
+void UI_AddRealInteractor(char* name, double* value, void (*on_update)(void));
+void UI_AddStringInteractor(char* name, const char** value, void (*on_update)(void));
+
+typedef struct UIConfig UIConfig;
+
+UIConfig* UI_Dialog(char* title, long width, long height);
+UIConfig* UI_Window(char* title, long width, long height);
+
+void UI_GridBoxStart(UIConfig* cfg, long cols);
+void UI_GridBoxEnd(UIConfig* cfg);
+void UI_Label(UIConfig* cfg, char* text);
+void UI_TextBox(UIConfig* cfg, char* text);
+void UI_Button(UIConfig* cfg, char* text, char* int_name);
+
+/*********
+    Interactor Implementation
+*********/
+
+static size_t InteractorCount = 0;
+static Interactor InteractorList[1024] = {0};
+
+InteractorFuncs BoolFuncs = {0};
+InteractorFuncs IntFuncs = {0};
+InteractorFuncs RealFuncs = {0};
+InteractorFuncs StringFuncs = {0};
+
+void UI_AddInteractor(char* name, void* value, InteractorFuncs* funcs, void (*on_update)(void))
+{
+    InteractorList[InteractorCount].funcs = funcs;
+    InteractorList[InteractorCount].on_update = on_update;
+    InteractorList[InteractorCount].name = name;
+    InteractorList[InteractorCount].value = value;
+    InteractorCount++;
+}
+
+void UI_AddBoolInteractor(char* name, bool* value, void (*on_update)(void))
+{
+    UI_AddInteractor(name, value, &BoolFuncs, on_update);
+}
+
+void UI_AddIntInteractor(char* name, long* value, void (*on_update)(void))
+{
+    UI_AddInteractor(name, value, &IntFuncs, on_update);
+}
+
+void UI_AddRealInteractor(char* name, double* value, void (*on_update)(void))
+{
+    UI_AddInteractor(name, value, &RealFuncs, on_update);
+}
+
+void UI_AddStringInteractor(char* name, const char** value, void (*on_update)(void))
+{
+    UI_AddInteractor(name, value, &StringFuncs, on_update);
+}
+
+/*********
+    Widget Routine Implementations
+*********/
+
+UIConfig* UI_Dialog(char* title, long width, long height)
+{
+}
+
+UIConfig* UI_Window(char* title, long width, long height)
+{
+}
+
+
+void UI_GridBoxStart(UIConfig* cfg, long cols)
+{
+}
+
+void UI_GridBoxEnd(UIConfig* cfg)
+{
+}
+
+void UI_Label(UIConfig* cfg, char* text)
+{
+}
+
+void UI_TextBox(UIConfig* cfg, char* text)
+{
+}
+
+void UI_Button(UIConfig* cfg, char* text, char* int_name)
+{
+}
+
+/*********
+    Main Routine
+*********/
+
+int main(int argc, char** argv)
+{
+    UIConfig* cfg = UI_Dialog("title goes here", 640, 480); // UI_Window
+    UI_GridBoxStart(cfg, 2);
+    {
+        UI_Label(cfg, "First Name");
+        UI_TextBox(cfg, "first-name");
+        UI_Label(cfg, "Last Name");
+        UI_TextBox(cfg, "last-name");
+        UI_Button(cfg, "OK", "ok-button");
+        UI_Button(cfg, "Cancel", "cancel-button");
+    }
+    UI_GridBoxEnd(cfg);
+}
+/*
+    (dialog [width: 640 height: 480]
+        (grid-box [columns: 2]
+            (label "First Name")
+            (text-box [data: "first-name"])
+            (label "Last Name")
+            (text-box [data: "last-name"])
+            (button [data: "ok-button"] "OK")
+            (button [data: "cancel-button"] "Cancel")))
+
+*/
\ No newline at end of file
diff --git a/experiments/os.c b/experiments/os.c
new file mode 100644 (file)
index 0000000..669470b
--- /dev/null
@@ -0,0 +1,104 @@
+typdef struct Node {
+    struct Node* prev;
+    struct Node* next;
+} Node;
+
+typdef struct {
+    Node head;
+    Node tail;
+} List;
+
+typedef struct Task {
+    Node node;
+    uintptr_t* stack;
+} Task;
+
+
+void OS_Start(void)
+{
+    /* initialize global state */
+    /* add Init and Idle tasks to the task list */
+    //TaskAdd(&InitTask);
+    //TaskAdd(&IdleTask);
+    /* yield the CPU to trigger the scheduler and start init task */
+    //YieldCPU();
+}
+
+void* OS_ServiceRequest(uintptr_t pc, void* stack)
+{
+//    /* Save the task's current stack pointer. */
+//    if(GOS_CurrentTaskID != GOS_INVALID_TASK)
+//    {
+//        GOS_Task_StackPointers[GOS_CurrentTaskID] = p_task_stack;
+//    }
+//
+//    In_Interrupt_Context_Flag = true;
+//
+//    /* Reset any pending exclusive access flags */
+//    __asm__ __volatile__("CLREX");
+//
+//    /* Handle the IRQ */
+//    IrqHandle();
+//
+//    In_Interrupt_Context_Flag = false;
+//
+//    /* Return the task's stack. */
+//    return GOS_Task_StackPointers[GOS_CurrentTaskID];
+}
+
+static void TaskAdd(void* task)
+{
+    /* allocate memory */
+    /* set task state to "ready" */
+    /* add to end of task list */
+}
+
+static void YieldCPU(void)
+{
+    if (Interrupt_Context)
+    {
+        RunScheduler();
+    }
+    else
+    {
+        /* trigger a software interrupt to make the kernel scheduler run */
+        __asm__ __volatile__("SVC 0\n");
+    }
+}
+
+static void RunScheduler(void)
+{
+/*
+    suspend interrupts
+
+    task_running = (valid && state == RUNNING)
+
+    if !task_running || next_priority > task_priority
+        next_task = TaskPop()
+
+        if (task_running)
+            current_task.state = READY_WITH_CONTEXT ???
+            TaskAdd(current_task)
+        end
+
+        if (next_task needs init?)
+            InitializeTaskContext(next_task)
+        end
+
+        current_task = next_task
+        current_task.state = RUNNING
+    end
+
+    resume interrupts
+*/
+}
+
+static void InitializeTaskContext(void* task)
+{
+/*
+    task->stack = allocate(DEFAULT_STACK_SIZE);
+    populate register cache and initial state on the stack (CreateInitialStack)
+*/
+}
+
+
diff --git a/experiments/sdl_bezier.c b/experiments/sdl_bezier.c
new file mode 100644 (file)
index 0000000..df5126d
--- /dev/null
@@ -0,0 +1,223 @@
+// C program to implement
+// Cubic Bezier Curve
+
+/* install SDL library for running thing code*/
+/* install by using this commamnd line : sudo apt-get install libsdl2-dev */
+/* run this code using command : gcc fileName.c -lSDL2 -lm*/
+
+#include<stdio.h>
+#include<stdlib.h>
+#include<math.h>
+#include<SDL2/SDL.h>
+
+SDL_Window* window = NULL;
+SDL_Renderer* renderer = NULL;
+int mousePosX , mousePosY ;
+int xnew , ynew ;
+
+/*Function to draw all other 7 pixels present at symmetric position*/
+void drawCircle(int xc, int yc, int x, int y)
+{
+    SDL_RenderDrawPoint(renderer,xc+x,yc+y) ;
+    SDL_RenderDrawPoint(renderer,xc-x,yc+y);
+    SDL_RenderDrawPoint(renderer,xc+x,yc-y);
+    SDL_RenderDrawPoint(renderer,xc-x,yc-y);
+    SDL_RenderDrawPoint(renderer,xc+y,yc+x);
+    SDL_RenderDrawPoint(renderer,xc-y,yc+x);
+    SDL_RenderDrawPoint(renderer,xc+y,yc-x);
+    SDL_RenderDrawPoint(renderer,xc-y,yc-x);
+}
+
+/*Function for circle-generation using Bresenham's algorithm */
+void circleBres(int xc, int yc, int r)
+{
+    int x = 0, y = r;
+    int d = 3 - 2 * r;
+    while (y >= x)
+    {
+        /*for each pixel we will draw all eight pixels */
+        drawCircle(xc, yc, x, y);
+        x++;
+
+        /*check for decision parameter and correspondingly update d, x, y*/
+        if (d > 0)
+        {
+            y--;
+            d = d + 4 * (x - y) + 10;
+        }
+        else
+            d = d + 4 * x + 6;
+        drawCircle(xc, yc, x, y);
+    }
+}
+
+/* Function that take input as Control Point x_coordinates and
+Control Point y_coordinates and draw bezier curve */
+void bezierCurve(int x[] , int y[])
+{
+    double xu = 0.0 , yu = 0.0 , u = 0.0 ;
+    int i = 0 ;
+    for(u = 0.0 ; u <= 1.0 ; u += 0.01)
+    {
+        xu = pow(1-u,3) * x[0] +
+             3 * u * pow(1-u,2) * x[1] +
+             3 * pow(u,2) * (1-u) * x[2] +
+             pow(u,3) * x[3];
+        yu = pow(1-u,3) * y[0] +
+             3 * u * pow(1-u,2) * y[1] +
+             3 * pow(u,2) * (1-u) * y[2] +
+             pow(u,3) * y[3];
+        SDL_RenderDrawPoint(renderer , (int)xu , (int)yu) ;
+    }
+}
+int main(int argc, char* argv[])
+{
+    /*initialize sdl*/
+    if (SDL_Init(SDL_INIT_EVERYTHING) == 0)
+    {
+        /*
+            This function is used to create a window and default renderer.
+            int SDL_CreateWindowAndRenderer(int width
+                                          ,int height
+                                          ,Uint32 window_flags
+                                          ,SDL_Window** window
+                                          ,SDL_Renderer** renderer)
+            return 0 on success and -1 on error
+        */
+        if(SDL_CreateWindowAndRenderer(300, 300, 0, &window, &renderer) == 0)
+        {
+            SDL_bool done = SDL_FALSE;
+
+            int i = 0 ;
+            int x[4] , y[4] , flagDrawn = 0 ;
+
+            while (!done)
+            {
+                SDL_Event event;
+
+                /*set background color to black*/
+                SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
+                SDL_RenderClear(renderer);
+
+                /*set draw color to white*/
+                SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
+
+                /* We are drawing cubic bezier curve
+                which has four control points */
+                if(i==4)
+                {
+                    bezierCurve(x , y) ;
+                    flagDrawn = 1 ;
+                }
+
+                /*grey color circle to encircle control Point P0*/
+                SDL_SetRenderDrawColor(renderer, 128, 128, 128, SDL_ALPHA_OPAQUE);
+                circleBres(x[0] , y[0] , 8) ;
+
+                /*Red Line between control Point P0 & P1*/
+                SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
+                SDL_RenderDrawLine(renderer , x[0] , y[0] , x[1] , y[1]) ;
+
+                /*grey color circle to encircle control Point P1*/
+                SDL_SetRenderDrawColor(renderer, 128, 128, 128, SDL_ALPHA_OPAQUE);
+                circleBres(x[1] , y[1] , 8) ;
+
+                /*Red Line between control Point P1 & P2*/
+                SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
+                SDL_RenderDrawLine(renderer , x[1] , y[1] , x[2] , y[2]) ;
+
+                /*grey color circle to encircle control Point P2*/
+                SDL_SetRenderDrawColor(renderer, 128, 128, 128, SDL_ALPHA_OPAQUE);
+                circleBres(x[2] , y[2] , 8) ;
+
+                /*Red Line between control Point P2 & P3*/
+                SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
+                SDL_RenderDrawLine(renderer , x[2] , y[2] , x[3] , y[3]) ;
+
+                /*grey color circle to encircle control Point P3*/
+                SDL_SetRenderDrawColor(renderer, 128, 128, 128, SDL_ALPHA_OPAQUE);
+                circleBres(x[3] , y[3] , 8) ;
+
+                /*We are Polling SDL events*/
+                if (SDL_PollEvent(&event))
+                {
+                    /* if window cross button clicked then quit from window */
+                    if (event.type == SDL_QUIT)
+                    {
+                        done = SDL_TRUE;
+                    }
+                    /*Mouse Button is Down */
+                    if(event.type == SDL_MOUSEBUTTONDOWN)
+                    {
+                        /*If left mouse button down then store
+                          that point as control point*/
+                        if(event.button.button == SDL_BUTTON_LEFT)
+                        {
+                            /*store only four points
+                            because of cubic bezier curve*/
+                            if(i < 4)
+                            {
+                                printf("Control Point(P%d):(%d,%d)\n"
+                                ,i,mousePosX,mousePosY) ;
+
+                                /*Storing Mouse x and y positions
+                                in our x and y coordinate array */
+                                x[i] = mousePosX ;
+                                y[i] = mousePosY ;
+                                i++ ;
+                            }
+                        }
+                    }
+                    /*Mouse is in motion*/
+                    if(event.type == SDL_MOUSEMOTION)
+                    {
+                        /*get x and y positions from motion of mouse*/
+                        xnew = event.motion.x ;
+                        ynew = event.motion.y ;
+
+                        int j ;
+
+                        /* change coordinates of control point
+                         after bezier curve has been drawn */
+                        if(flagDrawn == 1)
+                        {
+                            for(j = 0 ; j < i ; j++)
+                            {
+                                /*Check mouse position if in b/w circle then
+                          change position of that control point to mouse new
+                                position which are coming from mouse motion*/
+                                if((float)sqrt(abs(xnew-x[j]) * abs(xnew-x[j])
+                                     + abs(ynew-y[j]) * abs(ynew-y[j])) < 8.0)
+                                {
+                                    /*change coordinate of jth control point*/
+                                    x[j] = xnew ;
+                                    y[j] = ynew ;
+                                    printf("Changed Control Point(P%d):(%d,%d)\n"
+                                           ,j,xnew,ynew) ;
+                                }
+                            }
+                        }
+                        /*updating mouse positions to positions
+                        coming from motion*/
+                        mousePosX = xnew ;
+                        mousePosY = ynew ;
+                    }
+                }
+                /*show the window*/
+                SDL_RenderPresent(renderer);
+            }
+        }
+        /*Destroy the renderer and window*/
+        if (renderer)
+        {
+            SDL_DestroyRenderer(renderer);
+        }
+        if (window)
+        {
+            SDL_DestroyWindow(window);
+        }
+    }
+    /*clean up SDL*/
+    SDL_Quit();
+    return 0;
+}
\ No newline at end of file
diff --git a/experiments/ximage.c b/experiments/ximage.c
new file mode 100644 (file)
index 0000000..cb0246a
--- /dev/null
@@ -0,0 +1,407 @@
+/* https://magcius.github.io/xplain/article/rast1.html */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <math.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+
+/******************************************************************************/
+
+#include <time.h>
+#include <sys/time.h>
+
+typedef double Timer;
+
+static Timer timer_start(void)
+{
+    struct timespec now;
+    clock_gettime(CLOCK_MONOTONIC, &now);
+    return ((double)now.tv_sec + ((double)now.tv_nsec / 1000000000));
+}
+
+static Timer timer_elapsed(Timer timer)
+{
+    Timer now = timer_start();
+    return now - timer;
+}
+
+/******************************************************************************/
+
+typedef struct {
+    XImage* ximage;
+    int* pixels;
+    int width;
+    int height;
+} PixelBuf;
+
+static inline int ARGB(int a, int r, int g, int b)
+{
+    return (
+          ((a & 0xFF) << 24u)
+        | ((r & 0xFF) << 16u)
+        | (g & 0xFF) << 8u
+        | (b & 0xFF)
+    );
+}
+
+static inline int RGB(int r, int g, int b)
+{
+    return ARGB(255, r, g, b);
+}
+
+static inline int GetAlpha(int color)
+{
+    return ((color >> 24u) & 0xFF);
+}
+
+static inline int GetRed(int color)
+{
+    return ((color >> 16u) & 0xFF);
+}
+
+static inline int GetGreen(int color)
+{
+    return ((color >> 8u) & 0xFF);
+}
+
+static inline int GetBlue(int color)
+{
+    return (color & 0xFF);
+}
+
+/******************************************************************************/
+
+static float Lerp(float a, float b, float t)
+{
+    return (a * (1.0 - t)) + (b * t);
+}
+
+static int LerpARGB(int c1, int c2, float t)
+{
+    int alpha = Lerp(GetAlpha(c1), GetAlpha(c2), t);
+    int red   = Lerp(GetRed(c1),   GetRed(c2),   t);
+    int green = Lerp(GetGreen(c1), GetGreen(c2), t);
+    int blue  = Lerp(GetBlue(c1),  GetBlue(c2),  t);
+    return RGB(red, green, blue);
+}
+
+/******************************************************************************/
+
+static inline void SetPixelAt(PixelBuf* pixbuf, int x, int y, int pixel)
+{
+    pixbuf->pixels[(y * pixbuf->width) + x] = pixel;
+}
+
+static inline int GetPixelAt(PixelBuf* pixbuf, int x, int y)
+{
+    return pixbuf->pixels[(y * pixbuf->width) + x];
+}
+
+static void BlendPixelAt(PixelBuf* pixbuf, int x, int y, int src)
+{
+    int old = GetPixelAt(pixbuf, x, y);
+    int new = LerpARGB(old, src, (float)GetAlpha(src) / 255.0);
+    SetPixelAt(pixbuf, x, y, new);
+}
+
+/******************************************************************************/
+
+static void ClearBuffer(PixelBuf* pixbuf)
+{
+    int npixels = pixbuf->width * pixbuf->height;
+    for (int i = 0; i < npixels; i++)
+    {
+        pixbuf->pixels[i] = 0x000000;
+    }
+}
+
+static void FillRectangle(PixelBuf* pixbuf, int x, int y, int w, int h, int clr)
+{
+    for (int y1 = y; y1 < (y + h); y1++)
+    {
+        for (int x1 = x; x1 < (x + w); x1++)
+        {
+            BlendPixelAt(pixbuf, x1, y1, clr);
+        }
+    }
+}
+
+static bool IsInCircle(float centerX, float centerY, float radius, float x, float y)
+{
+    float distX = (x - centerX);
+    float distY = (y - centerY);
+    float distance = (distX * distX) + (distY * distY);
+    return (distance <= (radius * radius));
+}
+
+static void FillCircle(PixelBuf* pixbuf, int centerX, int centerY, int radius, int clr)
+{
+    float nSubpixelsX = 4;
+    float nSubpixelsY = 4;
+
+    int x1 = floor(centerX - radius);
+    int y1 = floor(centerY - radius);
+    int x2 = ceil(centerX + radius);
+    int y2 = ceil(centerY + radius);
+    for (int y = y1; y < y2; y++)
+    {
+        for (int x = x1; x < x2; x++)
+        {
+            float coverage = 0;
+            for (float subpixelY = 0; subpixelY < nSubpixelsY; subpixelY++)
+            {
+                for (float subpixelX = 0; subpixelX < nSubpixelsX; subpixelX++)
+                {
+                    float sampX = x + ((subpixelX + 0.5) / nSubpixelsX);
+                    float sampY = y + ((subpixelY + 0.5) / nSubpixelsY);
+                    if (IsInCircle(centerX, centerY, radius, sampX, sampY))
+                    {
+                        coverage += 1;
+                    }
+                }
+            }
+            coverage /= nSubpixelsX * nSubpixelsY;
+
+            if (coverage == 0)
+            {
+                continue;
+            }
+
+            int rgba = ARGB(
+                255 * (((float)GetAlpha(clr) / 255.0) * coverage),
+                GetRed(clr),
+                GetGreen(clr),
+                GetBlue(clr)
+            );
+            BlendPixelAt(pixbuf, x, y, rgba);
+        }
+    }
+}
+
+static void FillLinearGrad(PixelBuf* pixbuf, int x, int y, int width, int height, int clr1, int clr2)
+{
+    int startX = x;
+    int endX = width;
+    for (int x = startX; x < endX; x++)
+    {
+        double t = (double)(x - startX) / (double)(endX - startX);
+        int rgb = LerpARGB(clr1, clr2, t);
+        FillRectangle(pixbuf, x, y, 1, height, rgb);
+    }
+}
+
+/******************************************************************************/
+
+/*
+    https://pomax.github.io/bezierinfo/#introduction
+    https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
+    https://en.wikipedia.org/wiki/Nonzero-rule
+    https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule
+*/
+
+#define MAX_SEGMENTS 1024
+
+typedef struct {
+    enum { LINE, ARC, BEZIER } type;
+    float minx, miny;
+    float begx, begy;
+    float endx, endy;
+    union {
+        struct {
+            float cpx1, cpy1;
+            float radius;
+        } arc;
+        struct {
+            float cpx1, cpy1;
+            float cpx2, cpy2;
+        } curve;
+    };
+} Segment_T;
+
+float CurrX = 0.0;
+float CurrY = 0.0;
+size_t NSegments;
+
+Segment_T Segments[MAX_SEGMENTS];
+
+static void BeginPath(void)
+{
+    CurrX = 0.0;
+    CurrY = 0.0;
+    NSegments = 0;
+    Segments[0].begx = 0.0;
+    Segments[0].begy = 0.0;
+}
+
+static void MoveTo(float x, float y)
+{
+    CurrX = x, CurrY = y;
+}
+
+static void LineTo(float x, float y)
+{
+    if (NSegments < MAX_SEGMENTS)
+    {
+        Segments[NSegments].type = LINE;
+        Segments[NSegments].begx = CurrX;
+        Segments[NSegments].begy = CurrY;
+        Segments[NSegments].endx = x;
+        Segments[NSegments].endy = y;
+        NSegments++;
+    }
+}
+
+static void ArcTo(float x, float y)
+{
+}
+
+
+static void BezierCurveTo(float cx1, float cy1, float cx2, float cy2, float x, float y)
+{
+    if (NSegments < MAX_SEGMENTS)
+    {
+        Segments[NSegments].begx = CurrX;
+        Segments[NSegments].begy = CurrY;
+        Segments[NSegments].curve.cpx1 = cx1;
+        Segments[NSegments].curve.cpy1 = cy1;
+        Segments[NSegments].curve.cpx2 = cx2;
+        Segments[NSegments].curve.cpy2 = cy2;
+        Segments[NSegments].endx = x;
+        Segments[NSegments].endy = y;
+        NSegments++;
+    }
+}
+
+static void QuadraticCurveTo(float cx, float cy, float x, float y)
+{
+    BezierCurveTo(
+        cx, cy,
+        cx, cy,
+        x, y
+    );
+}
+
+static void ClosePath(void)
+{
+    LineTo(Segments[0].begx, Segments[0].begy);
+}
+
+static void Stroke(void)
+{
+    /* draw all segments with stroke style */
+}
+
+static void Fill(void)
+{
+    /* fill the closed sections with fill style */
+}
+
+/******************************************************************************/
+
+static void animate_rect(PixelBuf* pixbuf, float secs)
+{
+    int startX = 1;
+    int endX = pixbuf->width - 50;
+    int x = (int)floor( Lerp(startX, endX, secs) );
+    int y = 1;
+    FillRectangle(pixbuf, x, y, 50, 50, ARGB(127, 127, 127, 127));
+}
+
+void redraw(PixelBuf* pixbuf)
+{
+    ClearBuffer(pixbuf);
+
+    FillLinearGrad(pixbuf,
+        0, 0,
+        1000, 700,
+        RGB(255, 255, 0),
+        RGB(0, 255, 255)
+    );
+
+    FillRectangle(pixbuf, 10, 10, 100, 100, ARGB(255, 255, 0, 0));
+    FillRectangle(pixbuf, 60, 60, 100, 100, ARGB(127, 0, 0, 255));
+
+    FillCircle(pixbuf, 300, 60, 50, ARGB(255,255,0,0));
+    FillCircle(pixbuf, 350, 110, 50, ARGB(127,0,0,255));
+
+    static double time = 0;
+    animate_rect(pixbuf, time);
+    time += 0.01;
+    if (time >= 1)
+    {
+        time = 0.0;
+    }
+}
+
+int main(int argc, char **argv)
+{
+    Display * dpy = XOpenDisplay(NULL);
+
+    int nxvisuals = 0;
+    XVisualInfo vinfo;
+    XVisualInfo visual_template = {0};
+    visual_template.screen = DefaultScreen(dpy);
+    XVisualInfo * visual_list = XGetVisualInfo (dpy, VisualScreenMask, &visual_template, &nxvisuals);
+
+    if (!XMatchVisualInfo(dpy, XDefaultScreen(dpy), 24, TrueColor, &vinfo))
+    {
+        fprintf(stderr, "no such visual\n");
+        return 1;
+    }
+
+    Window parent = XDefaultRootWindow(dpy);
+
+    XSync(dpy, True);
+
+    printf("creating RGBA child\n");
+
+    Visual * visual = vinfo.visual;
+    int depth = vinfo.depth;
+
+    XSetWindowAttributes attrs;
+    attrs.colormap = XCreateColormap(dpy, XDefaultRootWindow(dpy), visual, AllocNone);
+    attrs.background_pixel = 0;
+    attrs.border_pixel = 0;
+
+    #define W 1000
+    #define H 700
+
+    Window win = XCreateWindow(dpy, parent, 100, 100, W, H, 0, depth, InputOutput,
+                        visual, CWBackPixel | CWColormap | CWBorderPixel, &attrs);
+
+    PixelBuf pixbuf = {0};
+    pixbuf.width = W;
+    pixbuf.height = H;
+    pixbuf.pixels = malloc((pixbuf.width * pixbuf.height) * 4);
+    pixbuf.ximage = XCreateImage(dpy, vinfo.visual, depth, ZPixmap, 0, (char *)pixbuf.pixels, pixbuf.width, pixbuf.height, 8, pixbuf.width*4);
+
+    XSync(dpy, True);
+    XSelectInput(dpy, win, ExposureMask | KeyPressMask);
+
+    XGCValues gcv = { .graphics_exposures = 0 };
+    unsigned long gcm = GCGraphicsExposures;
+    GC NormalGC = XCreateGC(dpy, parent, gcm, &gcv);
+
+    XMapWindow(dpy, win);
+    XEvent event;
+    while(!XNextEvent(dpy, &event))
+    {
+        Timer now = timer_start();
+        redraw(&pixbuf);
+        Timer draw = timer_elapsed(now);
+        XPutImage(dpy, win, NormalGC, pixbuf.ximage, 0, 0, 0, 0, pixbuf.width, pixbuf.height);
+        Timer put = timer_elapsed(now);
+        XFlush(dpy);
+        Timer flush = timer_elapsed(now);
+        printf("%f %f %f\n", draw, put, flush);
+    }
+
+    printf("No error\n");
+
+    return 0;
+}
diff --git a/experiments/ximage_fb.c b/experiments/ximage_fb.c
new file mode 100644 (file)
index 0000000..e80cf94
--- /dev/null
@@ -0,0 +1,78 @@
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/fb.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+
+int main()
+{
+   struct fb_var_screeninfo screen_info;
+   struct fb_fix_screeninfo fixed_info;
+   char *buffer = NULL;
+   size_t buflen;
+   int fd = -1;
+   int r = 1;
+
+   fd = open("/dev/fb0", O_RDWR);
+   if (fd >= 0)
+   {
+      if (!ioctl(fd, FBIOGET_VSCREENINFO, &screen_info) &&
+          !ioctl(fd, FBIOGET_FSCREENINFO, &fixed_info))
+      {
+         buflen = screen_info.yres_virtual * fixed_info.line_length;
+         buffer = mmap(NULL,
+                       buflen,
+                       PROT_READ|PROT_WRITE,
+                       MAP_SHARED,
+                       fd,
+                       0);
+         if (buffer != MAP_FAILED)
+         {
+            /*
+             * TODO: something interesting here.
+             * "buffer" now points to screen pixels.
+             * Each individual pixel might be at:
+             *    buffer + x * screen_info.bits_per_pixel/8
+             *           + y * fixed_info.line_length
+             * Then you can write pixels at locations such as that.
+             */
+
+             r = 0;   /* Indicate success */
+         }
+         else
+         {
+            perror("mmap");
+         }
+      }
+      else
+      {
+         perror("ioctl");
+      }
+   }
+   else
+   {
+      perror("open");
+   }
+
+    int length = (screen_info.yres_virtual * fixed_info.line_length)/4;
+    int* screen = (int*)buffer;
+    for (int i = 0; i < length; i++)
+    {
+        screen[i] = 0xFFFFFF;
+    }
+
+   /*
+    * Clean up
+    */
+   if (buffer && buffer != MAP_FAILED)
+      munmap(buffer, buflen);
+   if (fd >= 0)
+      close(fd);
+
+   return r;
+}
\ No newline at end of file
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..7142148
--- /dev/null
+++ b/main.c
@@ -0,0 +1,112 @@
+#include "ansivt.h"
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/fb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+
+struct {
+    struct {
+        int width;
+        int height;
+        uint32_t* mem;
+    } screen;
+    struct {
+        void (*handler)(int key);
+    } keyboard;
+} System;
+
+void check(int cond, char* msg)
+{
+    if (!cond)
+    {
+        perror(msg);
+        abort();
+    }
+}
+
+uint32_t* init_video(int* width, int* height)
+{
+    int status;
+    struct fb_var_screeninfo screen_info;
+    struct fb_fix_screeninfo fixed_info;
+
+    /* get the video buffer dimensions in pixels */
+    int fd = open("/dev/fb0", O_RDWR);
+    check(fd >= 0, "open:");
+    status = ioctl(fd, FBIOGET_VSCREENINFO, &screen_info);
+    check(!status, "ioctl:");
+    status = ioctl(fd, FBIOGET_FSCREENINFO, &fixed_info);
+    check(!status, "ioctl:");
+
+    /* map the video buffer into our address space */
+    size_t buflen = screen_info.yres_virtual * fixed_info.line_length;
+    char* buffer = mmap(NULL, buflen, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+    check(buffer != MAP_FAILED, "mmap:");
+
+    /* return the data */
+    *width  = fixed_info.line_length / 4;
+    *height = screen_info.yres_virtual;
+    return (uint32_t*)buffer;
+}
+
+void init_keyboard(void)
+{
+    ttyrawmode(true);
+    csrhide();
+    scrdraw();
+}
+
+void redraw(void)
+{
+//    Graphics_Clear(pixbuf);
+//
+//    Graphics_FillLinearGrad(pixbuf,
+//        0, 0,
+//        1000, 700,
+//        RGB(255, 255, 0),
+//        RGB(0, 255, 255)
+//    );
+//
+//    Graphics_FillRectangle(pixbuf, 10, 10, 100, 100, ARGB(255, 255, 0, 0));
+//    Graphics_FillRectangle(pixbuf, 60, 60, 100, 100, ARGB(127, 0, 0, 255));
+//
+//    Graphics_FillCircle(pixbuf, 300, 60, 50, ARGB(255,255,0,0));
+//    Graphics_FillCircle(pixbuf, 350, 110, 50, ARGB(127,0,0,255));
+}
+
+int main(int argc, char** argv)
+{
+    System.screen.mem = init_video(
+        &System.screen.width,
+        &System.screen.height);
+    init_keyboard();
+
+    /* monitor for keyboard events */
+    while (true)
+    {
+        /* process keyboard events */
+        /* process mouse events */
+        /* run tasks */
+
+//        int key = readkey();
+//        if (key == KEY_CTRL_Q) { break; }
+//
+//        /* clear the screen to white */
+//        int length = System.screen.width * System.screen.height;
+//        for (int i = 0; i < length; i++)
+//        {
+//            System.screen.mem[i] = 0xFFFFFF;
+//        }
+    }
+
+    /* uninitialize */
+    ttyrawmode(false);
+    csrhide();
+    scrdraw();
+
+    return 0;
+}