add an overdraw buffer to allow for layered rendering
This commit is contained in:
@@ -4,13 +4,22 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BASE,
|
||||||
|
OVERDRAW
|
||||||
|
} framebuffer_e;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
bool is_running;
|
bool is_running;
|
||||||
bool framebuffer_dirty;
|
bool framebuffer_base_dirty;
|
||||||
|
bool framebuffer_overdraw_dirty;
|
||||||
SDL_Rect dirty_rect;
|
SDL_Rect dirty_rect;
|
||||||
uint16_t width, height;
|
uint16_t width, height;
|
||||||
uint32_t *framebuffer;
|
// base layer ~ layer 0
|
||||||
|
uint32_t *framebuffer_base;
|
||||||
|
// layer on top of that ~ layer 1
|
||||||
|
uint32_t *framebuffer_overdraw;
|
||||||
} game_state_t;
|
} game_state_t;
|
||||||
|
|
||||||
extern game_state_t *game_state;
|
extern game_state_t *game_state;
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* animate a rectangle's position changing over time
|
||||||
|
* => x0 -> x1, y0 -> y1, all else stays the same
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
anim_rect_pos(
|
||||||
|
uint32_t x0,
|
||||||
|
uint32_t y0,
|
||||||
|
uint32_t x1,
|
||||||
|
uint32_t y1,
|
||||||
|
uint32_t w,
|
||||||
|
uint32_t h,
|
||||||
|
uint32_t color
|
||||||
|
);
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <dangerzone/engine.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
put_pixel(
|
put_pixel(
|
||||||
|
framebuffer_e framebuffer,
|
||||||
unsigned int x,
|
unsigned int x,
|
||||||
unsigned int y,
|
unsigned int y,
|
||||||
uint32_t color
|
uint32_t color
|
||||||
@@ -11,5 +14,6 @@ put_pixel(
|
|||||||
|
|
||||||
void
|
void
|
||||||
clear_framebuffer(
|
clear_framebuffer(
|
||||||
|
framebuffer_e framebuffer,
|
||||||
uint32_t color
|
uint32_t color
|
||||||
);
|
);
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <dangerzone/engine.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
put_rect(
|
put_rect(
|
||||||
|
framebuffer_e framebuffer,
|
||||||
uint32_t x,
|
uint32_t x,
|
||||||
uint32_t y,
|
uint32_t y,
|
||||||
uint32_t w,
|
uint32_t w,
|
||||||
@@ -11,6 +14,7 @@ put_rect(
|
|||||||
uint32_t color
|
uint32_t color
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: remove, deprecated, you can use put_rect for the same thing
|
||||||
void
|
void
|
||||||
clear_rect(int x, int y, int w, int h, uint32_t color);
|
clear_rect(int x, int y, int w, int h, uint32_t color);
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <dangerzone/engine.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
put_char(
|
put_char(
|
||||||
|
framebuffer_e framebuffer,
|
||||||
char c,
|
char c,
|
||||||
uint32_t x,
|
uint32_t x,
|
||||||
uint32_t y,
|
uint32_t y,
|
||||||
@@ -14,6 +17,7 @@ put_char(
|
|||||||
|
|
||||||
void
|
void
|
||||||
put_string(
|
put_string(
|
||||||
|
framebuffer_e framebuffer,
|
||||||
const char *text,
|
const char *text,
|
||||||
uint32_t x,
|
uint32_t x,
|
||||||
uint32_t y,
|
uint32_t y,
|
||||||
|
|||||||
+41
-9
@@ -42,9 +42,15 @@ mark_dirty_rect(int x, int y, int w, int h)
|
|||||||
.h = h
|
.h = h
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!game_state->framebuffer_dirty) {
|
if (!game_state->framebuffer_base_dirty) {
|
||||||
game_state->dirty_rect = rect;
|
game_state->dirty_rect = rect;
|
||||||
game_state->framebuffer_dirty = true;
|
game_state->framebuffer_base_dirty = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!game_state->framebuffer_overdraw_dirty) {
|
||||||
|
game_state->dirty_rect = rect;
|
||||||
|
game_state->framebuffer_overdraw_dirty = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,9 +89,24 @@ mark_dirty_rect(int x, int y, int w, int h)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
upload_dirty_texture(void)
|
upload_dirty_texture(
|
||||||
{
|
framebuffer_e framebuffer
|
||||||
if (!game_state->framebuffer_dirty) {
|
) {
|
||||||
|
uint32_t *current_framebuffer;
|
||||||
|
switch (framebuffer) {
|
||||||
|
case BASE:
|
||||||
|
current_framebuffer = game_state->framebuffer_base;
|
||||||
|
break;
|
||||||
|
case OVERDRAW:
|
||||||
|
current_framebuffer = game_state->framebuffer_overdraw;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!game_state->framebuffer_base_dirty &&
|
||||||
|
!game_state->framebuffer_overdraw_dirty
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +138,7 @@ upload_dirty_texture(void)
|
|||||||
(size_t)rect.w * sizeof(uint32_t);
|
(size_t)rect.w * sizeof(uint32_t);
|
||||||
|
|
||||||
const uint8_t *source =
|
const uint8_t *source =
|
||||||
(const uint8_t *)game_state->framebuffer +
|
(const uint8_t *)current_framebuffer +
|
||||||
(size_t)rect.y * source_pitch +
|
(size_t)rect.y * source_pitch +
|
||||||
(size_t)rect.x * sizeof(uint32_t);
|
(size_t)rect.x * sizeof(uint32_t);
|
||||||
|
|
||||||
@@ -134,7 +155,16 @@ upload_dirty_texture(void)
|
|||||||
|
|
||||||
SDL_UnlockTexture(texture);
|
SDL_UnlockTexture(texture);
|
||||||
|
|
||||||
game_state->framebuffer_dirty = false;
|
switch (framebuffer) {
|
||||||
|
case BASE:
|
||||||
|
game_state->framebuffer_base_dirty = false;
|
||||||
|
break;
|
||||||
|
case OVERDRAW:
|
||||||
|
game_state->framebuffer_overdraw_dirty = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -152,7 +182,8 @@ engine_start() {
|
|||||||
internal_state->engine_update_framebuffer();
|
internal_state->engine_update_framebuffer();
|
||||||
|
|
||||||
// update the texture with the modified framebuffer
|
// update the texture with the modified framebuffer
|
||||||
upload_dirty_texture();
|
upload_dirty_texture(BASE);
|
||||||
|
upload_dirty_texture(OVERDRAW);
|
||||||
|
|
||||||
SDL_RenderClear(
|
SDL_RenderClear(
|
||||||
internal_state->sdl_state->renderer
|
internal_state->sdl_state->renderer
|
||||||
@@ -174,6 +205,7 @@ void
|
|||||||
engine_stop() {
|
engine_stop() {
|
||||||
engine_sdl_destroy(internal_state->sdl_state);
|
engine_sdl_destroy(internal_state->sdl_state);
|
||||||
free(internal_state);
|
free(internal_state);
|
||||||
free(game_state->framebuffer);
|
free(game_state->framebuffer_base);
|
||||||
|
free(game_state->framebuffer_overdraw);
|
||||||
free(game_state);
|
free(game_state);
|
||||||
}
|
}
|
||||||
@@ -160,14 +160,23 @@ engine_init(
|
|||||||
return RCODE_FAILURE;
|
return RCODE_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
game_state->framebuffer = (uint32_t *)
|
game_state->framebuffer_base = (uint32_t *)
|
||||||
malloc(sizeof(uint32_t) * window_width * window_height);
|
malloc(sizeof(uint32_t) * window_width * window_height);
|
||||||
if (game_state->framebuffer == NULL) {
|
if (game_state->framebuffer_base == NULL) {
|
||||||
free(internal_state);
|
free(internal_state);
|
||||||
free(game_state);
|
free(game_state);
|
||||||
return RCODE_FAILURE;
|
return RCODE_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
game_state->framebuffer_overdraw = (uint32_t *)
|
||||||
|
malloc(sizeof(uint32_t) * window_width * window_height);
|
||||||
|
if (game_state->framebuffer_overdraw == NULL) {
|
||||||
|
free(internal_state);
|
||||||
|
free(game_state->framebuffer_base);
|
||||||
|
free(game_state);
|
||||||
|
return RCODE_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
internal_state->engine_poll_events
|
internal_state->engine_poll_events
|
||||||
= engine_poll_events;
|
= engine_poll_events;
|
||||||
|
|
||||||
@@ -181,13 +190,15 @@ engine_init(
|
|||||||
);
|
);
|
||||||
if (internal_state->sdl_state == NULL) {
|
if (internal_state->sdl_state == NULL) {
|
||||||
free(internal_state);
|
free(internal_state);
|
||||||
free(game_state->framebuffer);
|
free(game_state->framebuffer_base);
|
||||||
|
free(game_state->framebuffer_overdraw);
|
||||||
free(game_state);
|
free(game_state);
|
||||||
return RCODE_FAILURE;
|
return RCODE_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
game_state->is_running = true;
|
game_state->is_running = true;
|
||||||
game_state->framebuffer_dirty = true;
|
game_state->framebuffer_base_dirty = true;
|
||||||
|
game_state->framebuffer_overdraw_dirty = true;
|
||||||
game_state->dirty_rect = (SDL_Rect) {
|
game_state->dirty_rect = (SDL_Rect) {
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#include <dangerzone/render/anim.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
anim_rect_pos(
|
||||||
|
uint32_t x0,
|
||||||
|
uint32_t y0,
|
||||||
|
uint32_t x1,
|
||||||
|
uint32_t y1,
|
||||||
|
uint32_t w,
|
||||||
|
uint32_t h,
|
||||||
|
uint32_t color
|
||||||
|
) {
|
||||||
|
// TODO: I THINK I NEED LAYERED BUFFERS
|
||||||
|
|
||||||
|
// one step is one pixel
|
||||||
|
uint32_t stepsx = x1 - x0;
|
||||||
|
uint32_t stepsy = y1 - y0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. get the row / column in the direction of the movement
|
||||||
|
*/
|
||||||
|
}
|
||||||
@@ -2,16 +2,36 @@
|
|||||||
#include <dangerzone/render/misc.h>
|
#include <dangerzone/render/misc.h>
|
||||||
#include <dangerzone/render/rect.h>
|
#include <dangerzone/render/rect.h>
|
||||||
|
|
||||||
|
#include "internal/engine_internal.h"
|
||||||
#include "internal/util/error.h"
|
#include "internal/util/error.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// helper function to return the correct pointer to a framebuffer for drawing selection
|
||||||
|
uint32_t*
|
||||||
|
get_framebuffer(
|
||||||
|
framebuffer_e framebuffer
|
||||||
|
) {
|
||||||
|
switch (framebuffer) {
|
||||||
|
case BASE:
|
||||||
|
return game_state->framebuffer_base;
|
||||||
|
case OVERDRAW:
|
||||||
|
return game_state->framebuffer_overdraw;
|
||||||
|
default:
|
||||||
|
return game_state->framebuffer_base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// alter a pixel at an imaginary x & y coordinates
|
// alter a pixel at an imaginary x & y coordinates
|
||||||
void
|
void
|
||||||
put_pixel(
|
put_pixel(
|
||||||
|
framebuffer_e framebuffer,
|
||||||
unsigned int x,
|
unsigned int x,
|
||||||
unsigned int y,
|
unsigned int y,
|
||||||
uint32_t color
|
uint32_t color
|
||||||
) {
|
) {
|
||||||
|
uint32_t *current_framebuffer = get_framebuffer(framebuffer);
|
||||||
|
|
||||||
uint16_t w = game_state->width;
|
uint16_t w = game_state->width;
|
||||||
uint16_t h = game_state->height;
|
uint16_t h = game_state->height;
|
||||||
|
|
||||||
@@ -21,7 +41,7 @@ put_pixel(
|
|||||||
"at x = %d, y = %d", x, y
|
"at x = %d, y = %d", x, y
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
game_state->framebuffer[game_state->width * y + x]
|
current_framebuffer[game_state->width * y + x]
|
||||||
= color;
|
= color;
|
||||||
|
|
||||||
mark_dirty_rect(x, y, 1, 1);
|
mark_dirty_rect(x, y, 1, 1);
|
||||||
@@ -31,12 +51,15 @@ put_pixel(
|
|||||||
// fill the entire framebuffer with a given color
|
// fill the entire framebuffer with a given color
|
||||||
void
|
void
|
||||||
clear_framebuffer(
|
clear_framebuffer(
|
||||||
|
framebuffer_e framebuffer,
|
||||||
uint32_t color
|
uint32_t color
|
||||||
) {
|
) {
|
||||||
|
uint32_t *current_framebuffer = get_framebuffer(framebuffer);
|
||||||
|
|
||||||
for (size_t i = 0;
|
for (size_t i = 0;
|
||||||
i < (size_t)game_state->width * game_state->height;
|
i < (size_t)game_state->width * game_state->height;
|
||||||
++i) {
|
++i) {
|
||||||
game_state->framebuffer[i] = color;
|
current_framebuffer[i] = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_dirty_rect(
|
mark_dirty_rect(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
put_rect(
|
put_rect(
|
||||||
|
framebuffer_e framebuffer,
|
||||||
uint32_t x,
|
uint32_t x,
|
||||||
uint32_t y,
|
uint32_t y,
|
||||||
uint32_t w,
|
uint32_t w,
|
||||||
@@ -18,12 +19,13 @@ put_rect(
|
|||||||
) {
|
) {
|
||||||
for (int i = x; i < x + w; i++) {
|
for (int i = x; i < x + w; i++) {
|
||||||
for (int j = y; j < y + h; j++) {
|
for (int j = y; j < y + h; j++) {
|
||||||
put_pixel(i, j, color);
|
put_pixel(framebuffer, i, j, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mark_dirty_rect(x, y, w, h);
|
mark_dirty_rect(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove, see rect.h
|
||||||
void
|
void
|
||||||
clear_rect(int x, int y, int w, int h, uint32_t color)
|
clear_rect(int x, int y, int w, int h, uint32_t color)
|
||||||
{
|
{
|
||||||
@@ -33,7 +35,7 @@ clear_rect(int x, int y, int w, int h, uint32_t color)
|
|||||||
px < game_state->width &&
|
px < game_state->width &&
|
||||||
py >= 0 &&
|
py >= 0 &&
|
||||||
py < game_state->height) {
|
py < game_state->height) {
|
||||||
game_state->framebuffer[
|
game_state->framebuffer_base[
|
||||||
py * game_state->width + px
|
py * game_state->width + px
|
||||||
] = color;
|
] = color;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ static const uint8_t font[128][FONT_ROWS] = {
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
put_char(
|
put_char(
|
||||||
|
framebuffer_e framebuffer,
|
||||||
char c,
|
char c,
|
||||||
uint32_t x,
|
uint32_t x,
|
||||||
uint32_t y,
|
uint32_t y,
|
||||||
@@ -107,6 +108,7 @@ put_char(
|
|||||||
? fg_color : bg_color;
|
? fg_color : bg_color;
|
||||||
|
|
||||||
put_rect(
|
put_rect(
|
||||||
|
framebuffer,
|
||||||
x + col * size,
|
x + col * size,
|
||||||
y + row * size,
|
y + row * size,
|
||||||
size,
|
size,
|
||||||
@@ -121,6 +123,7 @@ put_char(
|
|||||||
|
|
||||||
void
|
void
|
||||||
put_string(
|
put_string(
|
||||||
|
framebuffer_e framebuffer,
|
||||||
const char *text,
|
const char *text,
|
||||||
uint32_t x,
|
uint32_t x,
|
||||||
uint32_t y,
|
uint32_t y,
|
||||||
@@ -137,7 +140,7 @@ put_string(
|
|||||||
x = start_x;
|
x = start_x;
|
||||||
y += (FONT_ROWS + line_spacing) * size;
|
y += (FONT_ROWS + line_spacing) * size;
|
||||||
} else {
|
} else {
|
||||||
put_char(*text, x, y, size, fg_color, bg_color);
|
put_char(framebuffer, *text, x, y, size, fg_color, bg_color);
|
||||||
x += (FONT_COLS + spacing) * size;
|
x += (FONT_COLS + spacing) * size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-4
@@ -358,7 +358,8 @@ client_update_framebuffer()
|
|||||||
// 20, 20, 2, 2, 3, 0x000000, 0xFFFF00
|
// 20, 20, 2, 2, 3, 0x000000, 0xFFFF00
|
||||||
// );
|
// );
|
||||||
|
|
||||||
clear_framebuffer(0x000000);
|
// FIXME: why?
|
||||||
|
//clear_framebuffer(BASE, 0x000000);
|
||||||
|
|
||||||
uint32_t tile_size = game_state->width / SIZE;
|
uint32_t tile_size = game_state->width / SIZE;
|
||||||
uint8_t border_width = 10;
|
uint8_t border_width = 10;
|
||||||
@@ -373,7 +374,8 @@ client_update_framebuffer()
|
|||||||
uint32_t w = tile_size - border_width;
|
uint32_t w = tile_size - border_width;
|
||||||
uint32_t h = tile_size - border_width;
|
uint32_t h = tile_size - border_width;
|
||||||
uint32_t background_color = colors(game.area[j][i]);
|
uint32_t background_color = colors(game.area[j][i]);
|
||||||
put_rect(x, y, w, h, background_color);
|
put_rect(BASE, x, y, w, h, 0xFFFFFF);
|
||||||
|
put_rect(OVERDRAW, x, y, w, h, background_color);
|
||||||
|
|
||||||
// number in foreground
|
// number in foreground
|
||||||
uint32_t foreground_color = 0x000000;
|
uint32_t foreground_color = 0x000000;
|
||||||
@@ -389,7 +391,7 @@ client_update_framebuffer()
|
|||||||
uint32_t n_rev = numrev(n);
|
uint32_t n_rev = numrev(n);
|
||||||
uint32_t digit_offset = 1;
|
uint32_t digit_offset = 1;
|
||||||
if (n != 0) {
|
if (n != 0) {
|
||||||
put_string(n_str, x + border_width, y + border_width, font_size, digit_offset, 12, foreground_color, background_color);
|
put_string(OVERDRAW, n_str, x + border_width, y + border_width, font_size, digit_offset, 12, foreground_color, background_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -402,7 +404,7 @@ client_update_framebuffer()
|
|||||||
alloced = true;
|
alloced = true;
|
||||||
|
|
||||||
sprintf(score_text, "score: %6d", game.score);
|
sprintf(score_text, "score: %6d", game.score);
|
||||||
put_string(score_text, border_width / 2, tile_size * SIZE + border_width / 2, 6, 1, 12, 0xFFFFFF, 0x000000);
|
put_string(OVERDRAW, score_text, border_width / 2, tile_size * SIZE + border_width / 2, 6, 1, 12, 0xFFFFFF, 0x000000);
|
||||||
|
|
||||||
if (alloced) {
|
if (alloced) {
|
||||||
free(n_str);
|
free(n_str);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
add_executable(game_snake snake.c)
|
#add_executable(game_snake snake.c)
|
||||||
target_link_libraries(game_snake PRIVATE dangerzone_engine)
|
#target_link_libraries(game_snake PRIVATE dangerzone_engine)
|
||||||
|
|
||||||
add_executable(game_2048 2048.c)
|
add_executable(game_2048 2048.c)
|
||||||
target_link_libraries(game_2048 PRIVATE dangerzone_engine)
|
target_link_libraries(game_2048 PRIVATE dangerzone_engine)
|
||||||
|
|
||||||
add_executable(game_window window.c)
|
#add_executable(game_window window.c)
|
||||||
target_link_libraries(game_window PRIVATE dangerzone_engine)
|
#target_link_libraries(game_window PRIVATE dangerzone_engine)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <dangerzone/engine.h>
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define WINDOW_NAME_MAX_LENGTH 128
|
#define WINDOW_NAME_MAX_LENGTH 128
|
||||||
@@ -47,3 +47,7 @@ engine_sdl_destroy(
|
|||||||
engine_sdl_state_t *state
|
engine_sdl_state_t *state
|
||||||
);
|
);
|
||||||
|
|
||||||
|
uint32_t*
|
||||||
|
get_framebuffer(
|
||||||
|
framebuffer_e framebuffer
|
||||||
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user