// 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 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_event_get() { struct ENGINE_EVENT * event = engine_malloc(NULL,sizeof(struct ENGINE_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_time_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_surface_color_set(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_surface_draw_pixel(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_window_present() { #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_window_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_surface_color_set(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 }