2026-05-24 21:59:29 -04:00
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
|
|
|
|
|
|
#include <akgl/renderer.h>
|
|
|
|
|
#include <akgl/staticstring.h>
|
|
|
|
|
#include <akgl/registry.h>
|
|
|
|
|
#include <akgl/heap.h>
|
|
|
|
|
#include <akgl/game.h>
|
|
|
|
|
|
|
|
|
|
#include <akerror.h>
|
|
|
|
|
#include <akstdlib.h>
|
|
|
|
|
|
|
|
|
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_init2d(akgl_RenderBackend *self)
|
|
|
|
|
{
|
|
|
|
|
akgl_String *width = NULL;
|
|
|
|
|
akgl_String *height = NULL;
|
|
|
|
|
int screenwidth;
|
|
|
|
|
int screenheight;
|
|
|
|
|
PREPARE_ERROR(e);
|
|
|
|
|
FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self");
|
|
|
|
|
|
|
|
|
|
PASS(e, akgl_get_property("game.screenwidth", &width, "0"));
|
|
|
|
|
PASS(e, akgl_get_property("game.screenheight", &height, "0"));
|
|
|
|
|
PASS(e, aksl_atoi(width->data, &screenwidth));
|
|
|
|
|
PASS(e, aksl_atoi(height->data, &screenheight));
|
|
|
|
|
SDL_Log("Initializing screen (%sx%s = %dx%d)", width->data, height->data, screenwidth, screenheight);
|
|
|
|
|
PASS(e, akgl_heap_release_string(width));
|
|
|
|
|
PASS(e, akgl_heap_release_string(height));
|
|
|
|
|
|
|
|
|
|
FAIL_ZERO_RETURN(
|
|
|
|
|
e,
|
|
|
|
|
SDL_CreateWindowAndRenderer(game.uri, screenwidth, screenheight, 0, &window, &self->sdl_renderer),
|
|
|
|
|
AKGL_ERR_SDL,
|
|
|
|
|
"Couldn't create window/renderer: %s",
|
|
|
|
|
SDL_GetError());
|
|
|
|
|
|
|
|
|
|
camera.x = 0;
|
|
|
|
|
camera.y = 0;
|
|
|
|
|
camera.w = screenwidth;
|
|
|
|
|
camera.h = screenheight;
|
|
|
|
|
|
|
|
|
|
self->shutdown = &akgl_render_2d_shutdown;
|
|
|
|
|
self->frame_start = &akgl_render_2d_frame_start;
|
|
|
|
|
self->frame_end = &akgl_render_2d_frame_end;
|
|
|
|
|
self->draw_texture = &akgl_render_2d_draw_texture;
|
|
|
|
|
self->draw_mesh = &akgl_render_2d_draw_mesh;
|
2026-05-25 21:29:18 -04:00
|
|
|
self->draw_world = &akgl_render_2d_draw_world;
|
2026-05-24 21:59:29 -04:00
|
|
|
SUCCEED_RETURN(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_shutdown(akgl_RenderBackend *self)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(e);
|
|
|
|
|
SUCCEED_RETURN(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_frame_start(akgl_RenderBackend *self)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(e);
|
2026-05-25 21:29:18 -04:00
|
|
|
FAIL_ZERO_RETURN(e, self->sdl_renderer, AKERR_NULLPOINTER, "No valid SDL rendering backend");
|
|
|
|
|
SDL_SetRenderDrawColor(self->sdl_renderer, 0, 0, 0, 255);
|
|
|
|
|
SDL_RenderClear(self->sdl_renderer);
|
2026-05-24 21:59:29 -04:00
|
|
|
SUCCEED_RETURN(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_frame_end(akgl_RenderBackend *self)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(e);
|
2026-05-25 21:29:18 -04:00
|
|
|
FAIL_ZERO_RETURN(e, self->sdl_renderer, AKERR_NULLPOINTER, "No valid SDL rendering backend");
|
|
|
|
|
SDL_RenderPresent(self->sdl_renderer);
|
2026-05-24 21:59:29 -04:00
|
|
|
SUCCEED_RETURN(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_texture(akgl_RenderBackend *self, SDL_Texture *texture, SDL_FRect *src, SDL_FRect *dest, double angle, SDL_FPoint *center, SDL_FlipMode flip)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(e);
|
|
|
|
|
FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self");
|
|
|
|
|
FAIL_ZERO_RETURN(e, texture, AKERR_NULLPOINTER, "texture");
|
|
|
|
|
//FAIL_ZERO_RETURN(e, src, AKERR_NULLPOINTER, "src");
|
|
|
|
|
//FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "dest");
|
|
|
|
|
|
|
|
|
|
if ( angle != 0 ) {
|
|
|
|
|
FAIL_ZERO_RETURN(e, center, AKERR_NULLPOINTER, "center");
|
|
|
|
|
FAIL_ZERO_RETURN(
|
|
|
|
|
e,
|
|
|
|
|
SDL_RenderTextureRotated(self->sdl_renderer, texture, src, dest, angle, center, flip),
|
|
|
|
|
AKERR_NULLPOINTER, "%s", SDL_GetError()
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
FAIL_ZERO_RETURN(
|
|
|
|
|
e,
|
|
|
|
|
SDL_RenderTexture(self->sdl_renderer, texture, src, dest),
|
|
|
|
|
AKERR_NULLPOINTER, "%s", SDL_GetError()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
SUCCEED_RETURN(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_mesh(akgl_RenderBackend *self)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(e);
|
|
|
|
|
FAIL_RETURN(e, AKERR_API, "Not implemented");
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 21:29:18 -04:00
|
|
|
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_world(akgl_RenderBackend *self, akgl_Iterator *opflags)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(e);
|
|
|
|
|
akgl_Iterator defflags;
|
|
|
|
|
SDL_Time curTime = SDL_GetTicksNS();
|
|
|
|
|
akgl_Actor *actor = NULL;
|
|
|
|
|
int j = 0;
|
|
|
|
|
|
|
|
|
|
FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self");
|
|
|
|
|
|
|
|
|
|
if ( opflags == NULL ) {
|
|
|
|
|
opflags = &defflags;
|
|
|
|
|
PASS(e, aksl_memset((void *)opflags, 0x00, sizeof(akgl_Iterator)));
|
|
|
|
|
}
|
|
|
|
|
for ( int i = 0; i < AKGL_TILEMAP_MAX_LAYERS ; i++ ) {
|
|
|
|
|
if ( i < gamemap.numlayers ) {
|
|
|
|
|
PASS(e, akgl_tilemap_draw((akgl_Tilemap *)&gamemap, &camera, i));
|
|
|
|
|
}
|
|
|
|
|
for ( int j = 0; j < AKGL_MAX_HEAP_ACTOR ; j++ ) {
|
|
|
|
|
actor = &HEAP_ACTOR[j];
|
|
|
|
|
if ( actor->refcount == 0 ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if ( actor->layer != i ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
PASS(e, actor->renderfunc(actor));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SUCCEED_RETURN(e);
|
|
|
|
|
}
|