From 84af630ce0fea4b13d2d18ea22f0d48cbb65990d Mon Sep 17 00:00:00 2001 From: xolatile Date: Sun, 1 Oct 2023 15:09:40 -0400 Subject: [PATCH] Initial stuff, experimented with it locally so far... --- example/base.c | 18 +++++ example/compile.sh | 11 +++ install.sh | 8 +++ xlesses.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++ xlesses.h | 50 ++++++++++++++ 5 files changed, 279 insertions(+) create mode 100644 example/base.c create mode 100644 example/compile.sh create mode 100644 install.sh create mode 100644 xlesses.c create mode 100644 xlesses.h diff --git a/example/base.c b/example/base.c new file mode 100644 index 0000000..900fad2 --- /dev/null +++ b/example/base.c @@ -0,0 +1,18 @@ +#include +#include + +int main (void) { + blesses_initialize (); + + while (blesses_active != 0) { + blesses_render_string ("Heyo world!", 8, 0, 0XCC6633, 0X3366CC); + blesses_render_character ('@', 8, 8, 0X3366CC, 0XCC6633); + blesses_render_character ('@', 0, 0, 0X3366CC, 0XCC6633); + + blesses_synchronize (); + } + + blesses_deinitialize (); + + return (EXIT_SUCCESS); +} diff --git a/example/compile.sh b/example/compile.sh new file mode 100644 index 0000000..21f2514 --- /dev/null +++ b/example/compile.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -xe + +gcc -g -ansi -Wall -Wextra -Wpedantic -o ./example/base ./example/base.c -lxcb -lxcb-image + +valgrind --show-leak-kinds=all --leak-check=full --log-file=./example/base.log ./example/base + +xighlight -V < ./example/base.log + +exit diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..a05cff1 --- /dev/null +++ b/install.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +set -xe + +cp xlesses.h /usr/include/xolatile/xlesses.h +cp xlesses.c /usr/include/xolatile/xlesses.c + +exit diff --git a/xlesses.c b/xlesses.c new file mode 100644 index 0000000..967ebfe --- /dev/null +++ b/xlesses.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic + * + * Xlesses is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation. + * And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version. + * It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3. + */ + +#ifndef XLESSES_SOURCE +#define XLESSES_SOURCE + +#include +#include +char * blesses_window_title = "xolatile"; +int blesses_window_width = 640; +int blesses_window_height = 480; +int blesses_active = 1; +int blesses_cursor_x = 0; +int blesses_cursor_y = 0; +int blesses_signal = 0; +int * blesses_sub_framebuffer = NULL; +int * blesses_framebuffer = NULL; + +void (* blesses_action [BLESSES_SIGNAL_COUNT]) (void) = { NULL }; + +xcb_window_t blesses_window = 0; +xcb_gcontext_t blesses_context = 0; +xcb_pixmap_t blesses_pixmap = 0; +xcb_connection_t * blesses_connection = NULL; +xcb_screen_t * blesses_screen = NULL; +xcb_image_t * blesses_image = NULL; + +void blesses_initialize (void) { + unsigned int window_flags [2] = { + 0, + XCB_EVENT_MASK_NO_EVENT | + XCB_EVENT_MASK_EXPOSURE | + XCB_EVENT_MASK_RESIZE_REDIRECT | + XCB_EVENT_MASK_KEY_RELEASE | + XCB_EVENT_MASK_KEY_PRESS | + XCB_EVENT_MASK_BUTTON_RELEASE | + XCB_EVENT_MASK_BUTTON_PRESS + }; + + unsigned short int window_width = (unsigned short int) blesses_window_width; + unsigned short int window_height = (unsigned short int) blesses_window_height; + + blesses_connection = xcb_connect (NULL, NULL); + + log_in (LOG_FAILURE, blesses_connection == NULL, "blesses : blesses_initialize : XCB connection is null pointer."); + + blesses_screen = xcb_setup_roots_iterator (xcb_get_setup (blesses_connection)).data; + + blesses_window = xcb_generate_id (blesses_connection); + blesses_context = xcb_generate_id (blesses_connection); + blesses_pixmap = xcb_generate_id (blesses_connection); + + window_flags [0] = blesses_screen->black_pixel; + + xcb_create_window (blesses_connection, blesses_screen->root_depth, blesses_window, blesses_screen->root, 0, 0, window_width, window_height, 10, XCB_WINDOW_CLASS_INPUT_OUTPUT, + blesses_screen->root_visual, XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, window_flags); + + xcb_map_window (blesses_connection, blesses_window); + + xcb_change_property (blesses_connection, XCB_PROP_MODE_REPLACE, blesses_window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, string_length (blesses_window_title), blesses_window_title); + + xcb_create_pixmap (blesses_connection, blesses_screen->root_depth, blesses_pixmap, blesses_window, window_width, window_height); + + xcb_create_gc (blesses_connection, blesses_context, blesses_pixmap, 0, NULL); + + xcb_flush (blesses_connection); + + blesses_sub_framebuffer = allocate (blesses_window_width * blesses_window_height * (int) sizeof (* blesses_sub_framebuffer) / 4); + blesses_framebuffer = allocate (blesses_window_width * blesses_window_height * (int) sizeof (* blesses_framebuffer)); + + log_out (); +} + +void blesses_deinitialize (void) { + blesses_sub_framebuffer = deallocate (blesses_sub_framebuffer); + blesses_framebuffer = deallocate (blesses_framebuffer); + + xcb_free_gc (blesses_connection, blesses_context); + + xcb_free_pixmap (blesses_connection, blesses_pixmap); + + xcb_destroy_window (blesses_connection, blesses_window); + + xcb_disconnect (blesses_connection); +} + +void blesses_synchronize (void) { + int i = 0; + int j = 0; + + xcb_generic_event_t * generic_event = NULL; + + for (i = 0; i != blesses_window_width * blesses_window_height; i++) { + blesses_framebuffer [i] = blesses_sub_framebuffer [((i / blesses_window_width) / 2) * (blesses_window_width / 2) + (i % blesses_window_width) / 2]; + } + + blesses_sub_framebuffer = deallocate (blesses_sub_framebuffer); + + blesses_image = xcb_image_create_native (blesses_connection, blesses_window_width, blesses_window_height, XCB_IMAGE_FORMAT_Z_PIXMAP, blesses_screen->root_depth, + blesses_framebuffer, (unsigned int) (blesses_window_width * blesses_window_height * (int) sizeof (* blesses_framebuffer)), + (unsigned char *) blesses_framebuffer); + + xcb_image_put (blesses_connection, blesses_pixmap, blesses_context, blesses_image, 0, 0, 0); + + xcb_image_destroy (blesses_image); + + xcb_copy_area (blesses_connection, blesses_pixmap, blesses_window, blesses_context, 0, 0, 0, 0, blesses_window_width, blesses_window_height); + + blesses_framebuffer = NULL; + + generic_event = xcb_wait_for_event (blesses_connection); + + switch (generic_event->response_type & 127) { + case XCB_EXPOSE: { + xcb_flush (blesses_connection); + } break; + case XCB_KEY_PRESS: { + blesses_signal = (int) ((xcb_key_press_event_t *) generic_event)->detail; + if (blesses_signal == 24) { + blesses_active = 0; + } + } break; + default: { + echo ("--\n"); + } break; + } + + generic_event = deallocate (generic_event); + + if ((blesses_sub_framebuffer == NULL) && (blesses_framebuffer == NULL)) { + blesses_sub_framebuffer = allocate (blesses_window_width * blesses_window_height * (int) sizeof (* blesses_sub_framebuffer) / 4); + blesses_framebuffer = allocate (blesses_window_width * blesses_window_height * (int) sizeof (* blesses_framebuffer)); + } + + log_out (); +} + +void blesses_render_character (char character, int x, int y, int foreground, int background) { + const unsigned long int font_code ['~' - ' ' + 1] = { + 0X0000000000000000, 0X00180018183C3C18, 0X0000000000363636, 0X006C6CFE6CFE6C6C, 0X00187ED07C16FC30, 0X0060660C18306606, 0X00DC66B61C36361C, 0X0000000000181818, + 0X0030180C0C0C1830, 0X000C18303030180C, 0X0000187E3C7E1800, 0X000018187E181800, 0X0C18180000000000, 0X000000007E000000, 0X0018180000000000, 0X0000060C18306000, + 0X003C666E7E76663C, 0X007E181818181C18, 0X007E0C183060663C, 0X003C66603860663C, 0X0030307E363C3830, 0X003C6660603E067E, 0X003C66663E060C38, 0X000C0C0C1830607E, + 0X003C66663C66663C, 0X001C30607C66663C, 0X0018180018180000, 0X0C18180018180000, 0X0030180C060C1830, 0X0000007E007E0000, 0X000C18306030180C, 0X001800181830663C, + 0X003C06765676663C, 0X006666667E66663C, 0X003E66663E66663E, 0X003C66060606663C, 0X001E36666666361E, 0X007E06063E06067E, 0X000606063E06067E, 0X003C66667606663C, + 0X006666667E666666, 0X007E18181818187E, 0X001C36303030307C, 0X0066361E0E1E3666, 0X007E060606060606, 0X00C6C6D6D6FEEEC6, 0X006666767E6E6666, 0X003C66666666663C, + 0X000606063E66663E, 0X006C36566666663C, 0X006666363E66663E, 0X003C66603C06663C, 0X001818181818187E, 0X003C666666666666, 0X00183C6666666666, 0X00C6EEFED6D6C6C6, + 0X0066663C183C6666, 0X001818183C666666, 0X007E060C1830607E, 0X003E06060606063E, 0X00006030180C0600, 0X007C60606060607C, 0X000000000000663C, 0XFFFF000000000000, + 0X000000000030180C, 0X007C667C603C0000, 0X003E6666663E0606, 0X003C6606663C0000, 0X007C6666667C6060, 0X003C067E663C0000, 0X000C0C0C3E0C0C38, 0X3C607C66667C0000, + 0X00666666663E0606, 0X003C1818181C0018, 0X0E181818181C0018, 0X0066361E36660606, 0X003C18181818181C, 0X00C6D6D6FE6C0000, 0X00666666663E0000, 0X003C6666663C0000, + 0X06063E66663E0000, 0XE0607C66667C0000, 0X000606066E360000, 0X003E603C067C0000, 0X00380C0C0C3E0C0C, 0X007C666666660000, 0X00183C6666660000, 0X006CFED6D6C60000, + 0X00663C183C660000, 0X3C607C6666660000, 0X007E0C18307E0000, 0X003018180E181830, 0X0018181818181818, 0X000C18187018180C, 0X000000000062D68C, 0X0000000000000000 + }; + + int offset = 0; + + log_in (LOG_WARNING, blesses_sub_framebuffer == NULL, "blesses : render_character : Sub framebuffer was not allocated."); + log_in (LOG_WARNING, blesses_framebuffer == NULL, "blesses : render_character : Framebuffer was not allocated."); + log_in (LOG_WARNING, character_is_invisible (character), "blesses : render_character : Character is not in visible ASCII range."); + + for (offset = 0; offset != BLESSES_FONT_WIDTH * BLESSES_FONT_HEIGHT; ++offset) { + int u = offset / BLESSES_FONT_WIDTH + y; + int v = offset % BLESSES_FONT_WIDTH + x; + + blesses_sub_framebuffer [u * (blesses_window_width / 2) + v] = ((font_code [(int) (character - ' ')] >> offset) % 2) ? foreground : background; + } + + log_out (); +} + +void blesses_render_string (char * string, int x, int y, int foreground, int background) { + int offset = 0; + + do { + if (string [offset] == '\t') { + x += BLESSES_FONT_WIDTH * 3; + } else if (string [offset] == '\n') { + y += BLESSES_FONT_HEIGHT; + x *= 0; + } else { + blesses_render_character (string [offset], x, y, foreground, background); + } + + x += BLESSES_FONT_WIDTH; + } while (++offset != string_length (string)); +} + +#endif diff --git a/xlesses.h b/xlesses.h new file mode 100644 index 0000000..68089db --- /dev/null +++ b/xlesses.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic + * + * Xlesses is free software! You will redistribute it or modify it under the terms of the GNU General Public License by Free Software Foundation. + * And when you do redistribute it or modify it, it will use either version 3 of the License, or (at yours truly opinion) any later version. + * It is distributed in the hope that it will be useful or harmful, it really depends... But no warranty what so ever, seriously. See GNU/GPLv3. + */ + +#ifndef XLESSES_HEADER +#define XLESSES_HEADER + +#include +#include + +#include +#include +#include + +#define BLESSES_FONT_WIDTH (8) +#define BLESSES_FONT_HEIGHT (8) + +#define BLESSES_SIGNAL_COUNT (144) + +extern char * blesses_window_title; +extern int blesses_window_width; +extern int blesses_window_height; +extern int blesses_active; +extern int blesses_cursor_x; +extern int blesses_cursor_y; +extern int blesses_signal; +extern int * blesses_sub_framebuffer; +extern int * blesses_framebuffer; + +extern void (* blesses_action [BLESSES_SIGNAL_COUNT]) (void); + +extern xcb_window_t blesses_window; +extern xcb_gcontext_t blesses_context; +extern xcb_pixmap_t blesses_pixmap; +extern xcb_connection_t * blesses_connection; +extern xcb_screen_t * blesses_screen; +extern xcb_image_t * blesses_image; + +extern void blesses_initialize (void); +extern void blesses_deinitialize (void); +extern void blesses_synchronize (void); + +extern void blesses_render_character (char, int, int, int, int); +extern void blesses_render_string (char *, int, int, int, int); + +#endif