me.fier.engine/modules/engine/frontend/sdl/main.c

297 lines
8.1 KiB
C
Raw Normal View History

2023-05-14 10:21:03 +00:00
// With much thanks to https://benedicthenshaw.com/soft_render_sdl2.html
// --- SETTINGS ---
// BUFFER
// How to buffer pixels.
// 0: Use SDL_Surface (fastest in software)
// 1: Use SDL_Renderer (slow?)
// TODO: Add support for GPU texture
#define ENGINE_SDL_BUFFERTYPE 0
// TRANSPARENCY
// How to draw transparent pixels (SDL_Surface buffer only).
// 0: Do not handle transparency (Fastest but non-square textures will have a halo around them)
// 1: 1-bit transparency (Alpha values under 128 are not drawn)
// 2: 8-bit transparency (Nice but slow)
// TODO: Add support for SDL_Renderer
#define ENGINE_SDL_TRANSPARENCY 1
// --- HACKS ---
// BUFFER
// Use static color conversion. This will speed up rendering, however, the wrong colors may be displayed depending on platform. This only has an effect if ENGINE_SDL_BUFFERTYPE is set to 0.
// 0 = Disable
// 1 = RGBA (raw)
// 2 = BGRA (common)
// TODO: Add custom mode with quicker conversion of known types, and slow conversion for unknown types.
#define ENGINE_SDL_COLOR 2
// INTEGER UPSCALING
// 2 makes the surface scaled 2x, 3 = 3x, etc.
// TODO: Fix ENGINE_SDL_TRANSPARENCY 2
#define ENGINE_SDL_SCALE 5
// SKIP: COLOR
// Skip setting colors every X requests. Set to 2 to skip every second request, 3 for every third, etc.
#define ENGINE_SDL_SKIP_COLOR_INTERVAL 0 // 2
// How many requests to skip, when a skip is encountered.
#define ENGINE_SDL_SKIP_COLOR_AMOUNT 2
// Whether to alternate fields. TODO
#define ENGINE_SDL_SKIP_COLOR_ALTERNATE 0
// SKIP: PIXEL
// Skip setting pixel every X requests.
#define ENGINE_SDL_SKIP_PIXEL_INTERVAL 0 // 2
#define ENGINE_SDL_SKIP_PIXEL_AMOUNT 2
#define ENGINE_SDL_SKIP_PIXEL_ALTERNATE 0
// SKIP: FRAME
#define ENGINE_SDL_SKIP_FRAME_INTERVAL 1
#define ENGINE_SDL_SKIP_FRAME_AMOUNT 1
// Entirely skip changing any colors and pixels on skipped frames, without this, this is pretty useless
#define ENGINE_SDL_SKIP_FRAME_DROP 0
// DO NOT TOUCH THESE
#if (ENGINE_SDL_SKIP_COLOR_INTERVAL > 0 && ENGINE_SDL_SKIP_COLOR_AMOUNT > 0)
#define ENGINE_SDL_SKIP_COLOR 1
#endif
#if (ENGINE_SDL_SKIP_PIXEL_INTERVAL > 0 && ENGINE_SDL_SKIP_PIXEL_AMOUNT > 0)
#define ENGINE_SDL_SKIP_PIXEL 1
#endif
#if (ENGINE_SDL_SKIP_FRAME_INTERVAL > 0 && ENGINE_SDL_SKIP_FRAME_AMOUNT > 0)
#define ENGINE_SDL_SKIP_FRAME 1
#endif
#include <SDL2/SDL.h>
SDL_Window * engine_sdl_window;
#if (ENGINE_SDL_BUFFERTYPE == 0)
SDL_Surface * engine_sdl_surface;
Uint32 * engine_sdl_pixels;
#endif
#if (ENGINE_SDL_BUFFERTYPE == 1)
SDL_Renderer * engine_sdl_renderer;
#endif
int engine_width = 0;
int engine_height = 0;
struct ENGINE_EVENT engine_getEvent() {
struct ENGINE_EVENT event;
SDL_Event sdlevent;
if (!SDL_PollEvent(&sdlevent)) {
struct ENGINE_EVENT_NONE data;
event.type = ENGINE_EVENT_TYPE_NONE;
event.data = &data;
return event;
}
if (sdlevent.type == SDL_QUIT) {
struct ENGINE_EVENT_EXIT data;
event.type = ENGINE_EVENT_TYPE_EXIT;
event.data = &data;
return event;
}
if (sdlevent.type == SDL_KEYDOWN || sdlevent.type == SDL_KEYUP) {
if (sdlevent.key.repeat != 0) { goto unknown; }
struct ENGINE_EVENT_INPUTKB data;
data.pressed = (sdlevent.type == SDL_KEYDOWN);
data.key = sdlevent.key.keysym.scancode;
event.type = ENGINE_EVENT_TYPE_INPUTKB;
event.data = &data;
return event;
}
unknown:
struct ENGINE_EVENT_UNKNOWN data;
event.type = ENGINE_EVENT_TYPE_UNKNOWN;
event.data = &data;
return event;
}
void engine_sleep(long long ms) {
SDL_Delay(ms);
}
long long engine_time_get() {
return SDL_GetTicks();
}
#ifdef ENGINE_SDL_SKIP_FRAME
char engine_sdl_skipf_interval = 0;
char engine_sdl_skipf_amount = 0;
#endif
#ifdef ENGINE_SDL_SKIP_COLOR
char engine_sdl_skipc_interval = 0;
char engine_sdl_skipc_amount = 0;
#endif
Uint32 engine_sdl_color;
void engine_setColor(char r,char g,char b,char a) {
#ifdef ENGINE_SDL_SKIP_COLOR
if (engine_sdl_skipc_interval == 0) {
if (engine_sdl_skipc_amount == 0) {
engine_sdl_skipc_interval = ENGINE_SDL_SKIP_COLOR_INTERVAL - 1;
engine_sdl_skipc_amount = ENGINE_SDL_SKIP_COLOR_AMOUNT;
} else {
--engine_sdl_skipc_amount;
return;
}
} else {
--engine_sdl_skipc_interval;
}
#endif
#if (ENGINE_SDL_SKIP_FRAME == 1 && ENGINE_SDL_SKIP_FRAME_DROP == 1)
if (engine_sdl_skipf_interval == 0 && engine_sdl_skipf_amount > 0) {
return;
}
#endif
#if (ENGINE_SDL_BUFFERTYPE == 0)
#if (ENGINE_SDL_COLOR != 0 || ENGINE_SDL_TRANSPARENCY > 0)
Uint8 * rawcolor = (Uint8 *)&engine_sdl_color; // is doing this ok?
#endif
#if (ENGINE_SDL_COLOR == 1)
rawcolor[0] = (Uint8)r;
rawcolor[1] = (Uint8)g;
rawcolor[2] = (Uint8)b;
rawcolor[3] = (Uint8)a;
#elif (ENGINE_SDL_COLOR == 2)
rawcolor[0] = (Uint8)b;
rawcolor[1] = (Uint8)g;
rawcolor[2] = (Uint8)r;
rawcolor[3] = (Uint8)a;
#else
engine_sdl_color = SDL_MapRGBA(engine_sdl_surface->format,(Uint8)r,(Uint8)g,(Uint8)b,(Uint8)a);
#if (ENGINE_SDL_TRANSPARENCY > 0)
rawcolor[3] = (Uint8)a;
#endif
#endif
#endif
#if (ENGINE_SDL_BUFFERTYPE == 1)
SDL_SetRenderDrawColor(engine_sdl_renderer,r,g,b,a);
#endif
}
#ifdef ENGINE_SDL_SKIP_PIXEL
char engine_sdl_skipp_interval = 0;
char engine_sdl_skipp_amount = 0;
#endif
void engine_drawPixel(int x,int y) {
#ifdef ENGINE_SDL_SKIP_PIXEL
if (engine_sdl_skipp_interval == 0) {
if (engine_sdl_skipp_amount == 0) {
engine_sdl_skipp_interval = ENGINE_SDL_SKIP_PIXEL_INTERVAL - 1;
engine_sdl_skipp_amount = ENGINE_SDL_SKIP_PIXEL_AMOUNT;
} else {
--engine_sdl_skipp_amount;
return;
}
} else {
--engine_sdl_skipp_interval;
}
#endif
#if (ENGINE_SDL_SKIP_FRAME == 1 && ENGINE_SDL_SKIP_FRAME_DROP == 1)
if (engine_sdl_skipf_interval == 0 && engine_sdl_skipf_amount > 0) {
return;
}
#endif
#if (ENGINE_SDL_BUFFERTYPE == 0)
#if (ENGINE_SDL_TRANSPARENCY == 1)
if (((Uint8 *)&engine_sdl_color)[3] < 128) { // is doing this ok?
return;
}
#endif
#if (ENGINE_SDL_TRANSPARENCY == 2)
Uint8 * rawcolor = (Uint8 *)&engine_sdl_color;
if (rawcolor[3] < 255) {
Uint8 * sourcecolor = (Uint8 *)&engine_sdl_pixels[x + y * engine_width];
float alpha = (float)rawcolor[3] / 255;
sourcecolor[0] = sourcecolor[0] + ((rawcolor[0] - sourcecolor[0])*alpha);
sourcecolor[1] = sourcecolor[1] + ((rawcolor[1] - sourcecolor[1])*alpha);
sourcecolor[2] = sourcecolor[2] + ((rawcolor[2] - sourcecolor[2])*alpha);
return;
}
#endif
#if (ENGINE_SDL_SCALE == 1)
engine_sdl_pixels[x + y * engine_width] = engine_sdl_color;
#else
char xi = 0;
while (xi < ENGINE_SDL_SCALE) {
char yi = 0;
while (yi < ENGINE_SDL_SCALE) {
engine_sdl_pixels[((x * ENGINE_SDL_SCALE) + xi) + ((y * ENGINE_SDL_SCALE) + yi) * (engine_width * ENGINE_SDL_SCALE)] = engine_sdl_color;
++yi;
}
++xi;
}
#endif
#endif
#if (ENGINE_SDL_BUFFERTYPE == 1)
SDL_RenderDrawPoint(engine_sdl_renderer,x,y);
#endif
}
void engine_render() {
#ifdef ENGINE_SDL_SKIP_FRAME
if (engine_sdl_skipf_interval == 0) {
if (engine_sdl_skipf_amount == 0) {
engine_sdl_skipf_interval = ENGINE_SDL_SKIP_FRAME_INTERVAL - 1;
engine_sdl_skipf_amount = ENGINE_SDL_SKIP_FRAME_AMOUNT;
} else {
--engine_sdl_skipf_amount;
return;
}
} else {
--engine_sdl_skipf_interval;
}
#endif
#if (ENGINE_SDL_BUFFERTYPE == 0)
SDL_UpdateWindowSurface(engine_sdl_window);
#endif
#if (ENGINE_SDL_BUFFERTYPE == 1)
SDL_RenderPresent(engine_sdl_renderer);
#endif
}
void engine_init(int width,int height,char *title) {
SDL_Init(SDL_INIT_VIDEO);
engine_sdl_window = SDL_CreateWindow(title,SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,width * ENGINE_SDL_SCALE,height * ENGINE_SDL_SCALE,0);
#if (ENGINE_SDL_BUFFERTYPE == 0)
engine_sdl_surface = SDL_GetWindowSurface(engine_sdl_window);
engine_sdl_pixels = engine_sdl_surface->pixels;
#endif
#if (ENGINE_SDL_BUFFERTYPE == 1)
engine_sdl_renderer = SDL_CreateRenderer(engine_sdl_window,-1,0);
#endif
engine_width = width;
engine_height = height;
#if (ENGINE_SDL_BUFFERTYPE == 1)
engine_setColor(0,0,0,255);
#ifdef ENGINE_SDL_SKIP_COLOR
engine_sdl_skipc_interval = 0;
engine_sdl_skipc_amount = 0;
#endif
SDL_RenderClear(engine_sdl_renderer);
#endif
}