xhartae/chapter/chapter_5.c

257 lines
12 KiB
C
Raw Normal View History

/*
Copyright (c) 2023 : Ognjen 'xolatile' Milan Robovic
Xhartae 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 CHAPTER_5_SOURCE
#define CHAPTER_5_SOURCE
#include "chapter_5.h"
2023-11-20 20:52:40 -05:00
2023-11-30 14:50:42 -05:00
#define BLESSES_FONT_WIDTH (8)
#define BLESSES_FONT_HEIGHT (8)
2023-11-30 12:26:42 -05:00
#define BLESSES_FONT_TABULATOR (4)
2023-11-30 14:50:42 -05:00
#define BLESSES_SIGNAL_COUNT (144)
static char * blesses_window_title = "xolatile";
static int blesses_window_width = 1800;
static int blesses_window_height = 900;
static int * blesses_sub_framebuffer = NULL;
static int * blesses_framebuffer = NULL;
static void (* blesses_action [BLESSES_SIGNAL_COUNT]) (void) = { NULL };
static xcb_window_t blesses_window = 0;
static xcb_gcontext_t blesses_context = 0;
static xcb_pixmap_t blesses_pixmap = 0;
static xcb_connection_t * blesses_connection = NULL;
static xcb_screen_t * blesses_screen = NULL;
static xcb_image_t * blesses_image = NULL;
static void blesses_initialize (void) {
2023-11-30 12:26:42 -05:00
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);
fatal_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);
2023-11-30 14:50:42 -05:00
xcb_change_property (blesses_connection, XCB_PROP_MODE_REPLACE, blesses_window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, (unsigned int) string_length (blesses_window_title), blesses_window_title);
2023-11-30 12:26:42 -05:00
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);
2023-11-30 14:59:26 -05:00
if (blesses_zoom == TRUE) {
blesses_sub_framebuffer = allocate (blesses_window_width * blesses_window_height * (int) sizeof (* blesses_sub_framebuffer) / 4);
} else {
blesses_sub_framebuffer = allocate (blesses_window_width * blesses_window_height * (int) sizeof (* blesses_sub_framebuffer));
}
blesses_framebuffer = allocate (blesses_window_width * blesses_window_height * (int) sizeof (* blesses_framebuffer));
2023-11-30 12:26:42 -05:00
}
2023-11-30 14:50:42 -05:00
static void blesses_deinitialize (void) {
2023-11-30 12:26:42 -05:00
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);
}
2023-11-30 14:50:42 -05:00
int blesses_active = FALSE;
int blesses_cursor_x = 0;
int blesses_cursor_y = 0;
int blesses_signal = 0;
2023-11-30 14:59:26 -05:00
int blesses_zoom = TRUE;
2023-11-30 14:50:42 -05:00
void blesses_configure (void) {
blesses_active = TRUE;
2023-11-30 14:59:26 -05:00
blesses_initialize ();
2023-11-30 14:50:42 -05:00
}
2023-11-30 12:26:42 -05:00
void blesses_synchronize (void) {
int i = 0;
2023-11-30 14:50:42 -05:00
unsigned short int window_width = (unsigned short int) blesses_window_width;
unsigned short int window_height = (unsigned short int) blesses_window_height;
2023-11-30 12:26:42 -05:00
xcb_generic_event_t * generic_event = NULL;
2023-11-30 14:59:26 -05:00
if (blesses_zoom == TRUE) {
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];
}
} else {
for (i = 0; i != blesses_window_width * blesses_window_height; i++) {
blesses_framebuffer [i] = blesses_sub_framebuffer [i];
}
2023-11-30 12:26:42 -05:00
}
blesses_sub_framebuffer = deallocate (blesses_sub_framebuffer);
2023-11-30 14:50:42 -05:00
blesses_image = xcb_image_create_native (blesses_connection, window_width, window_height, XCB_IMAGE_FORMAT_Z_PIXMAP, blesses_screen->root_depth,
blesses_framebuffer, (unsigned int) (window_width * window_height * (int) sizeof (* blesses_framebuffer)),
2023-11-30 12:26:42 -05:00
(unsigned char *) blesses_framebuffer);
xcb_image_put (blesses_connection, blesses_pixmap, blesses_context, blesses_image, 0, 0, 0);
xcb_image_destroy (blesses_image);
2023-11-30 14:50:42 -05:00
xcb_copy_area (blesses_connection, blesses_pixmap, blesses_window, blesses_context, 0, 0, 0, 0, window_width, window_height);
2023-11-30 12:26:42 -05:00
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) {
2023-11-30 14:50:42 -05:00
blesses_active = FALSE;
2023-11-30 12:26:42 -05:00
}
if (blesses_signal == 25) {
blesses_zoom = ! blesses_zoom;
}
2023-11-30 12:26:42 -05:00
} break;
default: {
} break;
}
generic_event = deallocate (generic_event);
if ((blesses_sub_framebuffer == NULL) && (blesses_framebuffer == NULL)) {
2023-11-30 14:59:26 -05:00
if (blesses_zoom == TRUE) {
blesses_sub_framebuffer = allocate (blesses_window_width * blesses_window_height * (int) sizeof (* blesses_sub_framebuffer) / 4);
} else {
blesses_sub_framebuffer = allocate (blesses_window_width * blesses_window_height * (int) sizeof (* blesses_sub_framebuffer));
}
// blesses_sub_framebuffer = allocate ((blesses_window_width * blesses_window_height * (int) sizeof (* blesses_sub_framebuffer)) / ((blesses_zoom == TRUE) ? 4 : 1));
2023-11-30 14:59:26 -05:00
blesses_framebuffer = allocate (blesses_window_width * blesses_window_height * (int) sizeof (* blesses_framebuffer));
2023-11-30 12:26:42 -05:00
}
2023-11-30 14:50:42 -05:00
if (blesses_active == FALSE) {
blesses_deinitialize ();
}
2023-11-30 12:26:42 -05:00
}
void blesses_render_background_colour (int background) {
int x, y;
for (y = 0; y != blesses_window_height / ((blesses_zoom == TRUE) ? 2 : 1); ++y) {
for (x = 0; x != blesses_window_width / ((blesses_zoom == TRUE) ? 2 : 1); ++x) {
blesses_sub_framebuffer [y * (blesses_window_width / ((blesses_zoom == TRUE) ? 2 : 1)) + x] = (int) (0XFF000000 | (unsigned int) background);
2023-11-30 12:26:42 -05:00
}
}
}
void blesses_render_character (char character, int foreground, int background, int x, int y) {
const unsigned long int font_code ['~' - ' ' + 2] = {
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;
if ((x <= -1) || (x >= blesses_window_width / ((blesses_zoom == TRUE) ? 2 : 1) - BLESSES_FONT_WIDTH)) return;
if ((y <= -1) || (y >= blesses_window_height / ((blesses_zoom == TRUE) ? 2 : 1) - BLESSES_FONT_HEIGHT)) return;
2023-11-30 12:26:42 -05:00
fatal_failure (blesses_sub_framebuffer == NULL, "blesses : render_character : Sub framebuffer was not allocated.");
fatal_failure (blesses_framebuffer == NULL, "blesses : render_character : Framebuffer was not allocated.");
fatal_failure (character_is_invisible (character), "blesses : render_character : Character is not in visible ASCII range.");
fatal_failure (x <= -1, "blesses : render_character : X position is under lower limit.");
fatal_failure (y <= -1, "blesses : render_character : Y position is under lower limit.");
fatal_failure (x >= blesses_window_width - BLESSES_FONT_WIDTH, "blesses : render_character : X position is above upper limit.");
fatal_failure (y >= blesses_window_height - BLESSES_FONT_HEIGHT, "blesses : render_character : Y position is above upper limit.");
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 / ((blesses_zoom == TRUE) ? 2 : 1)) + v] = ((font_code [(int) (character - ' ')] >> offset) % 2)
2023-11-30 14:59:26 -05:00
? foreground
: background;
2023-11-30 12:26:42 -05:00
}
}
void blesses_render_string (char * string, int foreground, int background, int x, int y) {
blesses_render_string_limit (string, string_length (string), foreground, background, x, y);
}
void blesses_render_number (int number, int foreground, int background, int x, int y) {
blesses_render_string (number_to_string (number), foreground, background, x, y);
}
void blesses_render_string_limit (char * string, int limit, int foreground, int background, int x, int y) {
int offset;
for (offset = 0; offset != limit; ++offset) {
if (string [offset] == '\n') {
x *= 0;
y += BLESSES_FONT_HEIGHT;
} else if (string [offset] == '\t') {
x += BLESSES_FONT_WIDTH * BLESSES_FONT_TABULATOR;
} else {
blesses_render_character (string [offset], foreground, background, x, y);
x += BLESSES_FONT_WIDTH;
}
}
}
void blesses_render_number_limit (int number, int limit, int foreground, int background, int x, int y) {
blesses_render_string_limit (number_to_string (number), limit, foreground, background, x, y);
}
#endif