From: Michael D. Lowis Date: Thu, 1 Sep 2022 19:18:48 +0000 (-0400) Subject: initial commit X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=937cb199fce2fe17f3647f017defc42fde943529;p=proto%2Fcerise-os.git initial commit --- 937cb199fce2fe17f3647f017defc42fde943529 diff --git a/ansivt.h b/ansivt.h new file mode 100644 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 +#include +#include +#include +#include +#include +#include + +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 index 0000000..dcfa9c5 --- /dev/null +++ b/experiments/fonts.c @@ -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 index 0000000..075171d --- /dev/null +++ b/experiments/interactors.c @@ -0,0 +1,142 @@ +#include +#include + +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 index 0000000..669470b --- /dev/null +++ b/experiments/os.c @@ -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 index 0000000..df5126d --- /dev/null +++ b/experiments/sdl_bezier.c @@ -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 +#include +#include +#include + +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 index 0000000..cb0246a --- /dev/null +++ b/experiments/ximage.c @@ -0,0 +1,407 @@ +/* https://magcius.github.io/xplain/article/rast1.html */ + +#include +#include +#include +#include +#include + +#include +#include + + +/******************************************************************************/ + +#include +#include + +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 index 0000000..e80cf94 --- /dev/null +++ b/experiments/ximage_fb.c @@ -0,0 +1,78 @@ +#include +#include +#include + +#include + +#include +#include + +#include + +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 index 0000000..7142148 --- /dev/null +++ b/main.c @@ -0,0 +1,112 @@ +#include "ansivt.h" +#include +#include +#include +#include +#include +#include +#include +#include + +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; +}