diff options
Diffstat (limited to 'src/gfx/sdl-1.2')
| -rw-r--r-- | src/gfx/sdl-1.2/CMakeLists.txt | 19 | ||||
| -rw-r--r-- | src/gfx/sdl-1.2/include/gfx/port.h | 58 | ||||
| -rw-r--r-- | src/gfx/sdl-1.2/private_include/gfx/private.h | 26 | ||||
| -rw-r--r-- | src/gfx/sdl-1.2/src/CMakeLists.txt | 23 | ||||
| -rw-r--r-- | src/gfx/sdl-1.2/src/env.c | 204 | ||||
| -rw-r--r-- | src/gfx/sdl-1.2/src/line.c | 16 | ||||
| -rw-r--r-- | src/gfx/sdl-1.2/src/quad.c | 44 | ||||
| -rw-r--r-- | src/gfx/sdl-1.2/src/rect.c | 35 | ||||
| -rw-r--r-- | src/gfx/sdl-1.2/src/sprite.c | 143 |
9 files changed, 568 insertions, 0 deletions
diff --git a/src/gfx/sdl-1.2/CMakeLists.txt b/src/gfx/sdl-1.2/CMakeLists.txt new file mode 100644 index 0000000..11d2245 --- /dev/null +++ b/src/gfx/sdl-1.2/CMakeLists.txt @@ -0,0 +1,19 @@ +# wanix, a Unix-like operating system for WebAssembly applications. +# Copyright (C) 2025 Xavier Del Campo Romero +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +add_subdirectory(src) +target_include_directories(gfx PUBLIC include PRIVATE private_include) +target_link_libraries(gfx PUBLIC SDL::SDL PRIVATE SDL::SDL_gfx) diff --git a/src/gfx/sdl-1.2/include/gfx/port.h b/src/gfx/sdl-1.2/include/gfx/port.h new file mode 100644 index 0000000..bf94a38 --- /dev/null +++ b/src/gfx/sdl-1.2/include/gfx/port.h @@ -0,0 +1,58 @@ +#ifndef GFX_SDL_H +#define GFX_SDL_H + +#include <SDL.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +struct gfx_sprite +{ + SDL_Surface *s, *s_x; + short x, y, w, h; + unsigned char u, v; + bool transparent; +}; + +struct quad +{ + unsigned char r, g, b; + short x0, x1, x2, x3; + short y0, y1, y2, y3; + unsigned char u0, u1, u2, u3; + unsigned char v0, v1, v2, v3; + short w, h; + bool transparent; + SDL_Surface *s, *s_x; +}; + +struct gfx_rect +{ + unsigned char r, g, b; + short x, y, w, h; + bool stp; +}; + +struct stp_4line +{ + short x, y; + unsigned char r, g, b; + + struct stp_4line_vtx + { + unsigned char r, g, b; + short x, y; + } vertices[4]; +}; + +#define common_get_or_ret(t, x, ret) \ + struct t x##__, *const x = &x##__ + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_SDL_H */ diff --git a/src/gfx/sdl-1.2/private_include/gfx/private.h b/src/gfx/sdl-1.2/private_include/gfx/private.h new file mode 100644 index 0000000..e1af764 --- /dev/null +++ b/src/gfx/sdl-1.2/private_include/gfx/private.h @@ -0,0 +1,26 @@ +#ifndef GFX_SDL_12_PRIVATE_H +#define GFX_SDL_12_PRIVATE_H + +#include <gfx/gfx.h> +#include <SDL.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +enum +{ + SCREEN_W = 320, + SCREEN_H = 240 +}; + +int sprite_screen_resize_ev(struct gfx_sprite *s); +void gfx_register_sprite(struct gfx_sprite *s); +SDL_Surface *gfx_screen(void); + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_SDL_12_PRIVATE_H */ diff --git a/src/gfx/sdl-1.2/src/CMakeLists.txt b/src/gfx/sdl-1.2/src/CMakeLists.txt new file mode 100644 index 0000000..4cef50b --- /dev/null +++ b/src/gfx/sdl-1.2/src/CMakeLists.txt @@ -0,0 +1,23 @@ +# wanix, a Unix-like operating system for WebAssembly applications. +# Copyright (C) 2025 Xavier Del Campo Romero +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +target_sources(gfx PRIVATE + env.c + line.c + quad.c + rect.c + sprite.c +) diff --git a/src/gfx/sdl-1.2/src/env.c b/src/gfx/sdl-1.2/src/env.c new file mode 100644 index 0000000..2a51b97 --- /dev/null +++ b/src/gfx/sdl-1.2/src/env.c @@ -0,0 +1,204 @@ +#include <gfx/gfx.h> +#include <gfx/private.h> +#include <sdl-1.2/gfx/private.h> +#include <SDL.h> +#include <inttypes.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +int screen_w = SCREEN_W, screen_h = SCREEN_H; +static bool fullscreen; +static SDL_Surface *screen; +static struct gfx_sprite **list; +static size_t list_len; + +void gfx_deinit(void) +{ + /* screen should be already freed by SDL_Quit. */ + free(list); + SDL_QuitSubSystem(SDL_INIT_VIDEO); +} + +static struct +{ + int w, h; +} display, windowed; + +void gfx_register_sprite(struct gfx_sprite *const s) +{ + list = realloc(list, (list_len + 1) * sizeof *list); + + if (list) + list[list_len++] = s; +} + +static int resize_screen(int w, int h, const bool full_screen) +{ + Uint32 flags = SDL_HWSURFACE | SDL_RESIZABLE | SDL_ANYFORMAT | SDL_DOUBLEBUF; + + const SDL_VideoInfo *const info = SDL_GetVideoInfo(); + + if (!info) + { + fprintf(stderr, "SDL_GetVideoInfo: %s\n", SDL_GetError()); + return -1; + } + + static bool init; + + if (!init) + { + display.w = info->current_w; + display.h = info->current_h; + init = true; + } + + if (fullscreen) + { + flags |= SDL_FULLSCREEN; + w = display.w; + h = display.h; + } + else + { + windowed.w = w; + windowed.h = h; + } + + int bpp = info->vfmt->BitsPerPixel; + + if (screen) + SDL_FreeSurface(screen); + + const int max_bpp = SDL_VideoModeOK(w, h, 0, flags); + + if (max_bpp < 0) + { + fprintf(stderr, "SDL_VideoModeOK: %s\n", SDL_GetError()); + return -1; + } + else if (bpp > max_bpp) + bpp = max_bpp; + + if (!(screen = SDL_SetVideoMode(w, h, 0, flags))) + { + fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError()); + return -1; + } + + for (size_t i = 0; i < list_len; i++) + if (sprite_screen_resize_ev(list[i])) + return -1; + + screen_w = w; + screen_h = h; + fullscreen = full_screen; + return 0; +} + +SDL_Surface *gfx_screen(void) +{ + return screen; +} + +int gfx_display_size(short *const w, short *const h) +{ + *w = display.w; + *h = display.h; + return 0; +} + +int gfx_init(void) +{ + if (SDL_InitSubSystem(SDL_INIT_VIDEO)) + { + fprintf(stderr, "%s: SDL_InitSubSystem: %s\n", + __func__, SDL_GetError()); + return -1; + } + + return resize_screen(screen_w, screen_h, fullscreen); +} + +bool gfx_inside_drawenv(const short x, const short y, const short w, + const short h) +{ + return (x + w >= 0) + && x < screen_w + && (y + h >= 0) + && y < screen_h; +} + +static int get_resize_events(void) +{ + int n; + SDL_Event ev; + + while ((n = SDL_PeepEvents(&ev, 1, SDL_GETEVENT, + SDL_VIDEORESIZEMASK)) > 0) + { + if (ev.type == SDL_VIDEORESIZE) + { + const SDL_ResizeEvent *const res = &ev.resize; + + if (resize_screen(res->w, res->h, false)) + return -1; + } + } + + if (n < 0) + { + fprintf(stderr, "%s: SDL_PeepEvents: %s\n", + __func__, SDL_GetError()); + return -1; + } + + return 0; +} + +int gfx_toggle_fullscreen(void) +{ + fullscreen ^= true; + + const int w = fullscreen ? display.w : windowed.w; + const int h = fullscreen ? display.h : windowed.h; + + return resize_screen(w, h, fullscreen); +} + +int gfx_set_fullscreen(const short w, const short h) +{ + return resize_screen(display.w = w, display.h = h, fullscreen = true); +} + +bool gfx_fullscreen_available(void) +{ + return true; +} + +bool gfx_fullscreen(void) +{ + return fullscreen; +} + +int gfx_draw(void) +{ + enum {FPS = 50, REFRESH_MS = 1000 / FPS}; + static Uint32 prev; + const Uint32 cur = SDL_GetTicks(); + + if (cur - prev < REFRESH_MS) + SDL_Delay(REFRESH_MS - (cur - prev)); + + prev = SDL_GetTicks(); + + if (SDL_Flip(screen)) + { + fprintf(stderr, "SDL_Flip: %s\n", SDL_GetError()); + return -1; + } + + get_resize_events(); + return 0; +} diff --git a/src/gfx/sdl-1.2/src/line.c b/src/gfx/sdl-1.2/src/line.c new file mode 100644 index 0000000..b06a414 --- /dev/null +++ b/src/gfx/sdl-1.2/src/line.c @@ -0,0 +1,16 @@ +#include <gfx/gfx.h> +#include <gfx/port.h> +#include <sdl-1.2/gfx/private.h> +#include <stddef.h> + +void stp_4line_init(struct stp_4line *const l) +{ +} + +void semitrans_stp_4line_init(struct stp_4line *r) +{ +} + +void stp_4line_sort(struct stp_4line *const r) +{ +} diff --git a/src/gfx/sdl-1.2/src/quad.c b/src/gfx/sdl-1.2/src/quad.c new file mode 100644 index 0000000..1617a8b --- /dev/null +++ b/src/gfx/sdl-1.2/src/quad.c @@ -0,0 +1,44 @@ +#include <gfx/gfx.h> +#include <gfx/port.h> +#include <sdl-1.2/gfx/private.h> +#include <stddef.h> +#include <stdlib.h> + +int quad_from_sprite(const struct gfx_sprite *const s, struct quad *const q) +{ + q->s = s->s; + q->s_x = s->s_x; + q->u0 = q->u2 = s->u; + q->v0 = q->v1 = s->v; + q->u1 = q->u3 = s->u + s->w - 1; + q->v2 = q->v3 = s->v + s->h - 1; + q->w = s->w; + q->h = s->h; + return 0; +} + +void quad_sort(struct quad *const q) +{ + const bool xflip = q->x0 > q->x1; + + SDL_Rect r = + { + .x = xflip ? q->x1 : q->x0, + .y = q->y0 + }; + + const short w = q->u1 - q->u0 + 1, h = q->v2 - q->v0 + 1; + + SDL_Rect clip = + { + .x = xflip ? q->w - q->u0 - w: q->u0, + .y = q->v0, + .w = w, + .h = h + }; + + SDL_Surface *const s = xflip ? q->s_x : q->s; + + if (SDL_BlitSurface(s, &clip, gfx_screen(), &r)) + fprintf(stderr, "SDL_BlitSurface: %s\n", SDL_GetError()); +} diff --git a/src/gfx/sdl-1.2/src/rect.c b/src/gfx/sdl-1.2/src/rect.c new file mode 100644 index 0000000..57a2ab3 --- /dev/null +++ b/src/gfx/sdl-1.2/src/rect.c @@ -0,0 +1,35 @@ +#include <gfx/gfx.h> +#include <gfx/port.h> +#include <sdl-1.2/gfx/private.h> +#include <SDL.h> + +void gfx_rect_sort(struct gfx_rect *const r) +{ + SDL_Rect rct = + { + .x = r->x, + .y = r->y, + .w = r->w, + .h = r->h + }; + + SDL_Surface *const screen = gfx_screen(); + const Uint32 map = SDL_MapRGB(screen->format, r->r, r->g, r->b); + + if (SDL_FillRect(screen, &rct, map)) + { + fprintf(stderr, "SDL_FillRect: %s\n", SDL_GetError()); + return; + } +} + +void gfx_rect_init(struct gfx_rect *const r) +{ + *r = (const struct gfx_rect){0}; +} + +void semitrans_rect_init(struct gfx_rect *const r) +{ + gfx_rect_init(r); + r->stp = true; +} diff --git a/src/gfx/sdl-1.2/src/sprite.c b/src/gfx/sdl-1.2/src/sprite.c new file mode 100644 index 0000000..086e2b5 --- /dev/null +++ b/src/gfx/sdl-1.2/src/sprite.c @@ -0,0 +1,143 @@ +#include <gfx/gfx.h> +#include <gfx/port.h> +#include <header.h> +#include <sdl-1.2/gfx/private.h> +#include <SDL.h> +#include <SDL_rotozoom.h> +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> + +void sprite_free(struct gfx_sprite *const s) +{ + if (s && s->s) + SDL_FreeSurface(s->s); +} + +int sprite_clone(const struct gfx_sprite *const src, struct gfx_sprite *const dst) +{ + *dst = *src; + return 0; +} + +static int set_transparent(SDL_Surface *const s) +{ + /* Magenta as transparent. */ + const Uint32 map = SDL_MapRGB(s->format, 255, 0, 255); + const int ret = SDL_SetColorKey(s, SDL_SRCCOLORKEY | SDL_RLEACCEL, map); + + if (ret) + fprintf(stderr, "SDL_SetColorKey: %s\n", SDL_GetError()); + + return ret; +} + +int sprite_screen_resize_ev(struct gfx_sprite *const s) +{ + int ret = -1; + SDL_Surface *const old = s->s, *const old_x = s->s_x; + + if (s->transparent && (set_transparent(old) || set_transparent(old_x))) + goto end; + else if (!(s->s = SDL_DisplayFormat(old))) + { + fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError()); + goto end; + } + else if (!(s->s_x = SDL_DisplayFormat(old_x))) + { + fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError()); + goto end; + } + + ret = 0; + +end: + SDL_FreeSurface(old); + SDL_FreeSurface(old_x); + return ret; +} + +static int load_header(struct gfx_sprite *const s, FILE *const f) +{ + if (header_load_bool(f, "transparent", &s->transparent)) + return -1; + + return 0; +} + +static int load_bitmap(struct gfx_sprite *const s, FILE *const f) +{ + int ret = -1; + SDL_RWops *ops = NULL; + SDL_Surface *ts = NULL, *zs = NULL; + + if (!(ops = SDL_RWFromFP(f, 0))) + { + fprintf(stderr, "SDL_RWFromFP: %s\n", SDL_GetError()); + goto end; + } + else if (!(ts = SDL_LoadBMP_RW(ops, 0))) + { + fprintf(stderr, "SDL_LoadBMP_RW: %s\n", SDL_GetError()); + goto end; + } + else if (!(zs = zoomSurface(ts, -1, 1, 0))) + { + fprintf(stderr, "zoomSurface: %s\n", SDL_GetError()); + goto end; + } + else if (s->transparent && (set_transparent(ts) || set_transparent(zs))) + goto end; + else if (!(s->s = SDL_DisplayFormat(ts))) + { + fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError()); + goto end; + } + else if (!(s->s_x = SDL_DisplayFormat(zs))) + { + fprintf(stderr, "SDL_DisplayFormat: %s\n", SDL_GetError()); + goto end; + } + + gfx_register_sprite(s); + s->w = ts->w; + s->h = ts->h; + ret = 0; + +end: + SDL_FreeRW(ops); + SDL_FreeSurface(ts); + SDL_FreeSurface(zs); + return ret; +} + +int sprite_from_fp(struct gfx_sprite *const s, FILE *const f) +{ + *s = (const struct gfx_sprite){0}; + + if (load_header(s, f) || load_bitmap(s, f)) + return -1; + + return 0; +} + +void sprite_sort(struct gfx_sprite *const s) +{ + SDL_Rect r = + { + .x = s->x, + .y = s->y + }; + + SDL_Rect clip = + { + .x = s->u, + .y = s->v, + .w = s->w, + .h = s->h + }; + + if (SDL_BlitSurface(s->s, &clip, gfx_screen(), &r)) + fprintf(stderr, "SDL_BlitSurface: %s\n", SDL_GetError()); +} |
