#include"mx_sdl.h" static SDL_Event g_event; static SDL_Window** g_windows = NULL; static SDL_Renderer** g_renderers = NULL; static SDL_Texture** g_textures = NULL; static int64_t g_window_count = 0; static int64_t g_renderer_count = 0; static int64_t g_texture_count = 0; static TTF_Font** g_fonts = NULL; static int64_t g_font_count = 0; static SDL_Texture** g_render_targets = NULL; static int64_t* g_target_widths = NULL; static int64_t* g_target_heights = NULL; static int64_t g_render_target_count = 0; int64_t init(void) { SDL_SetMainReady(); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) == 0) { return 0; } return 1; } void quit(void) { if (g_fonts) { for (int64_t i = 0; i < g_font_count; ++i) { if (g_fonts[i]) TTF_CloseFont(g_fonts[i]); } free(g_fonts); g_fonts = NULL; g_font_count = 0; } if (g_target_widths) { free(g_target_widths); g_target_widths = NULL; } if (g_target_heights) { free(g_target_heights); g_target_heights = NULL; } g_render_target_count = 0; if (g_textures) { for (int64_t i = 0; i < g_texture_count; ++i) { g_textures[i] = NULL; } free(g_textures); g_textures = NULL; g_texture_count = 0; } if (g_renderers) { for (int64_t i = 0; i < g_renderer_count; ++i) { if (g_renderers[i]) SDL_DestroyRenderer(g_renderers[i]); } free(g_renderers); g_renderers = NULL; g_renderer_count = 0; } if (g_windows) { for (int64_t i = 0; i < g_window_count; ++i) { if (g_windows[i]) SDL_DestroyWindow(g_windows[i]); } free(g_windows); g_windows = NULL; g_window_count = 0; } SDL_Quit(); } int64_t create_window(const char* title, int64_t x, int64_t y, int64_t w, int64_t h, int64_t flags) { SDL_Window* window = SDL_CreateWindow(title, (int)x, (int)y, (int)w, (int)h, (Uint32)flags); if (!window) return -1; void *tmp = realloc(g_windows, sizeof(SDL_Window*) * (g_window_count + 1)); if (!tmp) { SDL_DestroyWindow(window); return -1; } g_windows = tmp; g_windows[g_window_count] = window; SDL_Surface *surf = SDL_LoadBMP("icon.bmp"); if(surf != NULL) { SDL_SetWindowIcon(window, surf); SDL_FreeSurface(surf); } return g_window_count++; } void destroy_window(int64_t window_id) { if (window_id >= 0 && window_id < g_window_count && g_windows[window_id]) { SDL_DestroyWindow(g_windows[window_id]); g_windows[window_id] = NULL; } } void set_window_icon(uint64_t window_id, const char *path) { SDL_Surface *surf = SDL_LoadBMP(path); if(!surf) return; SDL_SetWindowIcon(g_windows[window_id], surf); SDL_FreeSurface(surf); } int64_t create_renderer(int64_t window_id, int64_t index, int64_t flags) { if (window_id < 0 || window_id >= g_window_count || !g_windows[window_id]) return -1; SDL_Renderer* renderer = SDL_CreateRenderer(g_windows[window_id], (int)index, (Uint32)flags); if (!renderer) return -1; void *tmp = realloc(g_renderers, sizeof(SDL_Renderer*) * (g_renderer_count + 1)); if (!tmp) { SDL_DestroyRenderer(renderer); return -1; } g_renderers = tmp; g_renderers[g_renderer_count] = renderer; return g_renderer_count++; } void destroy_renderer(int64_t renderer_id) { if (renderer_id >= 0 && renderer_id < g_renderer_count && g_renderers[renderer_id]) { SDL_DestroyRenderer(g_renderers[renderer_id]); g_renderers[renderer_id] = NULL; } } int64_t create_render_target(int64_t renderer_id, int64_t width, int64_t height) { if (renderer_id < 0 || renderer_id >= g_renderer_count || !g_renderers[renderer_id]) return -1; SDL_RenderSetLogicalSize(g_renderers[renderer_id], (int)width, (int)height); void *tmp2 = realloc(g_target_widths, sizeof(int64_t) * (g_render_target_count + 1)); void *tmp3 = realloc(g_target_heights, sizeof(int64_t) * (g_render_target_count + 1)); if (!tmp2 || !tmp3) { if (tmp2) g_target_widths = tmp2; if (tmp3) g_target_heights = tmp3; return -1; } g_target_widths = tmp2; g_target_heights = tmp3; g_target_widths[g_render_target_count] = width; g_target_heights[g_render_target_count] = height; SDL_SetRenderDrawColor(g_renderers[renderer_id], 0, 0, 0, 255); SDL_RenderClear(g_renderers[renderer_id]); return g_render_target_count++; } void set_render_target(int64_t renderer_id, int64_t target_id) { (void)renderer_id; (void)target_id; } void destroy_render_target(int64_t target_id) { (void)target_id; } int64_t poll_event(void) { return SDL_PollEvent(&g_event); } int64_t get_event_type(void) { return g_event.type; } int64_t get_key_code(void) { return g_event.key.keysym.sym; } int64_t get_mouse_x(void) { return g_event.motion.x; } int64_t get_mouse_y(void) { return g_event.motion.y; } int64_t get_mouse_button(void) { return g_event.button.button; } void set_draw_color(int64_t renderer_id, int64_t r, int64_t g, int64_t b, int64_t a) { if (renderer_id >= 0 && renderer_id < g_renderer_count && g_renderers[renderer_id]) { SDL_SetRenderDrawColor(g_renderers[renderer_id], (Uint8)r, (Uint8)g, (Uint8)b, (Uint8)a); } } void clear(int64_t renderer_id) { if (renderer_id >= 0 && renderer_id < g_renderer_count && g_renderers[renderer_id]) { SDL_RenderClear(g_renderers[renderer_id]); } } void present(int64_t renderer_id) { if (renderer_id >= 0 && renderer_id < g_renderer_count && g_renderers[renderer_id]) { SDL_RenderPresent(g_renderers[renderer_id]); } } void present_scaled(int64_t renderer_id, int64_t target_id, int64_t scale_width, int64_t scale_height) { (void)target_id; (void)scale_width; (void)scale_height; if (renderer_id < 0 || renderer_id >= g_renderer_count || !g_renderers[renderer_id]) return; SDL_RenderPresent(g_renderers[renderer_id]); } void present_stretched(int64_t renderer_id, int64_t target_id, int64_t dst_width, int64_t dst_height) { (void)target_id; (void)dst_width; (void)dst_height; if (renderer_id < 0 || renderer_id >= g_renderer_count || !g_renderers[renderer_id]) return; SDL_RenderPresent(g_renderers[renderer_id]); } void draw_point(int64_t renderer_id, int64_t x, int64_t y) { if (renderer_id >= 0 && renderer_id < g_renderer_count && g_renderers[renderer_id]) { SDL_RenderDrawPoint(g_renderers[renderer_id], (int)x, (int)y); } } void draw_line(int64_t renderer_id, int64_t x1, int64_t y1, int64_t x2, int64_t y2) { if (renderer_id >= 0 && renderer_id < g_renderer_count && g_renderers[renderer_id]) { SDL_RenderDrawLine(g_renderers[renderer_id], (int)x1, (int)y1, (int)x2, (int)y2); } } void draw_rect(int64_t renderer_id, int64_t x, int64_t y, int64_t w, int64_t h) { if (renderer_id >= 0 && renderer_id < g_renderer_count && g_renderers[renderer_id]) { SDL_Rect rect = {(int)x, (int)y, (int)w, (int)h}; SDL_RenderDrawRect(g_renderers[renderer_id], &rect); } } void fill_rect(int64_t renderer_id, int64_t x, int64_t y, int64_t w, int64_t h) { if (renderer_id >= 0 && renderer_id < g_renderer_count && g_renderers[renderer_id]) { SDL_Rect rect = {(int)x, (int)y, (int)w, (int)h}; SDL_RenderFillRect(g_renderers[renderer_id], &rect); } } int64_t create_texture(int64_t renderer_id, int64_t format, int64_t access, int64_t w, int64_t h) { if (renderer_id < 0 || renderer_id >= g_renderer_count || !g_renderers[renderer_id]) return -1; SDL_Texture* texture = SDL_CreateTexture(g_renderers[renderer_id], (Uint32)format, (int)access, (int)w, (int)h); if (!texture) return -1; void *tmp = realloc(g_textures, sizeof(SDL_Texture*) * (g_texture_count + 1)); if (!tmp) { SDL_DestroyTexture(texture); return -1; } g_textures = tmp; g_textures[g_texture_count] = texture; return g_texture_count++; } void destroy_texture(int64_t texture_id) { if (texture_id >= 0 && texture_id < g_texture_count && g_textures[texture_id]) { SDL_DestroyTexture(g_textures[texture_id]); g_textures[texture_id] = NULL; } } int64_t load_texture(int64_t renderer_id, const char* file_path) { if (renderer_id < 0 || renderer_id >= g_renderer_count || !g_renderers[renderer_id]) return -1; SDL_Surface* surface = SDL_LoadBMP(file_path); if (!surface) return -2; SDL_Texture* texture = SDL_CreateTextureFromSurface(g_renderers[renderer_id], surface); SDL_FreeSurface(surface); if (!texture) return -3; void *tmp = realloc(g_textures, sizeof(SDL_Texture*) * (g_texture_count + 1)); if (!tmp) { SDL_DestroyTexture(texture); return -1; } g_textures = tmp; g_textures[g_texture_count] = texture; return g_texture_count++; } void render_texture(int64_t renderer_id, int64_t texture_id, int64_t src_x, int64_t src_y, int64_t src_w, int64_t src_h, int64_t dst_x, int64_t dst_y, int64_t dst_w, int64_t dst_h) { if (renderer_id >= 0 && renderer_id < g_renderer_count && g_renderers[renderer_id] && texture_id >= 0 && texture_id < g_texture_count && g_textures[texture_id]) { SDL_Renderer *renderer = g_renderers[renderer_id]; SDL_Texture *texture = g_textures[texture_id]; int tex_w, tex_h; SDL_QueryTexture(texture, NULL, NULL, &tex_w, &tex_h); float su0 = 0.0f, sv0 = 0.0f, su1 = 1.0f, sv1 = 1.0f; if (!((src_x == -1 || src_y == -1) && src_w == -1 && src_h == -1)) { su0 = (float)src_x / tex_w; sv0 = (float)src_y / tex_h; su1 = (float)(src_x + src_w) / tex_w; sv1 = (float)(src_y + src_h) / tex_h; } float dx, dy, dw, dh; if (dst_x == -1 && dst_y == -1 && dst_w == -1 && dst_h == -1) { int ow, oh; SDL_GetRendererOutputSize(renderer, &ow, &oh); dx = 0; dy = 0; dw = (float)ow; dh = (float)oh; } else { dx = (float)dst_x; dy = (float)dst_y; dw = (float)dst_w; dh = (float)dst_h; } SDL_Color white = {255, 255, 255, 255}; SDL_Vertex verts[4] = { { {dx, dy }, white, {su0, sv0} }, { {dx + dw, dy }, white, {su1, sv0} }, { {dx + dw, dy + dh}, white, {su1, sv1} }, { {dx, dy + dh}, white, {su0, sv1} }, }; int indices[6] = {0, 1, 2, 0, 2, 3}; SDL_RenderGeometry(renderer, texture, verts, 4, indices, 6); } } int64_t update_texture(int64_t texture_id, const void* pixels, int64_t pitch) { if (texture_id >= 0 && texture_id < g_texture_count && g_textures[texture_id]) { return SDL_UpdateTexture(g_textures[texture_id], NULL, pixels, (int)pitch) == 0 ? 1 : 0; } return 0; } int64_t lock_texture(int64_t texture_id, void** pixels, int64_t* pitch) { if (texture_id >= 0 && texture_id < g_texture_count && g_textures[texture_id]) { int p; int result = SDL_LockTexture(g_textures[texture_id], NULL, pixels, &p); *pitch = p; return result == 0 ? 1 : 0; } return 0; } void unlock_texture(int64_t texture_id) { if (texture_id >= 0 && texture_id < g_texture_count && g_textures[texture_id]) { SDL_UnlockTexture(g_textures[texture_id]); } } int64_t get_ticks(void) { return SDL_GetTicks(); } void delay(int64_t ms) { SDL_Delay((Uint32)ms); } int64_t open_audio(int64_t freq, int64_t format, int64_t channels, int64_t samples) { SDL_AudioSpec wanted_spec; wanted_spec.freq = (int)freq; wanted_spec.format = (SDL_AudioFormat)format; wanted_spec.channels = (Uint8)channels; wanted_spec.samples = (Uint16)samples; wanted_spec.callback = NULL; wanted_spec.userdata = NULL; return SDL_OpenAudio(&wanted_spec, NULL) == 0 ? 1 : 0; } void close_audio(void) { SDL_CloseAudio(); } void pause_audio(int64_t pause_on) { SDL_PauseAudio(pause_on ? 1 : 0); } int64_t load_wav(const char* file_path, int64_t* audio_buf, int64_t* audio_len, int64_t* audio_spec) { SDL_AudioSpec* spec = (SDL_AudioSpec*)malloc(sizeof(SDL_AudioSpec)); if (!spec) return 0; Uint8* buf; Uint32 len; if (SDL_LoadWAV(file_path, spec, &buf, &len) == NULL) { free(spec); return 0; } *audio_buf = (int64_t)buf; *audio_len = len; *audio_spec = (int64_t)spec; return 1; } void free_wav(int64_t audio_buf) { if (audio_buf) { SDL_FreeWAV((Uint8*)audio_buf); } } int64_t queue_audio(const void* data, int64_t len) { return SDL_QueueAudio(1, data, (Uint32)len) == 0 ? 1 : 0; } int64_t get_queued_audio_size(void) { return SDL_GetQueuedAudioSize(1); } void clear_queued_audio(void) { SDL_ClearQueuedAudio(1); } int64_t get_mouse_buttons(void) { int x, y; return SDL_GetMouseState(&x, &y); } int64_t get_relative_mouse_x(void) { int x, y; SDL_GetRelativeMouseState(&x, &y); return x; } int64_t get_relative_mouse_y(void) { int x, y; SDL_GetRelativeMouseState(&x, &y); return y; } int64_t get_relative_mouse_buttons(void) { int x, y; return SDL_GetRelativeMouseState(&x, &y); } int64_t get_keyboard_state(int64_t* numkeys) { int nk; const Uint8* state = SDL_GetKeyboardState(&nk); *numkeys = nk; return (int64_t)state; } int64_t is_key_pressed(int64_t scancode) { int numkeys; const Uint8* state = SDL_GetKeyboardState(&numkeys); if (scancode < 0 || scancode >= numkeys) return 0; return state[scancode] ? 1 : 0; } int64_t get_num_keys(void) { int numkeys; SDL_GetKeyboardState(&numkeys); return numkeys; } void set_clipboard_text(const char* text) { SDL_SetClipboardText(text); } const char* get_clipboard_text(void) { static char* last_clipboard = NULL; if (last_clipboard) SDL_free(last_clipboard); last_clipboard = SDL_GetClipboardText(); return last_clipboard; } void set_window_title(int64_t window_id, const char* title) { if (window_id >= 0 && window_id < g_window_count && g_windows[window_id]) { SDL_SetWindowTitle(g_windows[window_id], title); } } void set_window_position(int64_t window_id, int64_t x, int64_t y) { if (window_id >= 0 && window_id < g_window_count && g_windows[window_id]) { SDL_SetWindowPosition(g_windows[window_id], (int)x, (int)y); } } void get_window_size(int64_t window_id, int64_t* w, int64_t* h) { if (window_id >= 0 && window_id < g_window_count && g_windows[window_id]) { int ww, hh; SDL_GetWindowSize(g_windows[window_id], &ww, &hh); *w = ww; *h = hh; } } void set_window_fullscreen(int64_t window_id, int64_t fullscreen) { if (window_id >= 0 && window_id < g_window_count && g_windows[window_id]) { SDL_SetWindowFullscreen(g_windows[window_id], fullscreen ? SDL_WINDOW_FULLSCREEN : 0); } } void get_renderer_output_size(int64_t renderer_id, int64_t* w, int64_t* h) { if (renderer_id >= 0 && renderer_id < g_renderer_count && g_renderers[renderer_id]) { int ww, hh; SDL_GetRendererOutputSize(g_renderers[renderer_id], &ww, &hh); *w = ww; *h = hh; } } void show_cursor(int64_t show) { SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE); } int64_t init_text(void) { return TTF_Init() == 0 ? 1 : 0; } void quit_text(void) { if (g_fonts) { for (int64_t i = 0; i < g_font_count; ++i) { if (g_fonts[i]) TTF_CloseFont(g_fonts[i]); } free(g_fonts); g_fonts = NULL; g_font_count = 0; } TTF_Quit(); } int64_t load_font(const char* file, int64_t ptsize) { TTF_Font* font = TTF_OpenFont(file, (int)ptsize); if (!font) return -1; void *tmp = realloc(g_fonts, sizeof(TTF_Font*) * (g_font_count + 1)); if (!tmp) { TTF_CloseFont(font); return -1; } g_fonts = tmp; g_fonts[g_font_count] = font; return g_font_count++; } void draw_text(int64_t renderer_id, int64_t font_id, const char* text, int64_t x, int64_t y, int64_t r, int64_t g, int64_t b, int64_t a) { if (renderer_id < 0 || renderer_id >= g_renderer_count || !g_renderers[renderer_id]) return; if (font_id < 0 || font_id >= g_font_count || !g_fonts[font_id]) return; SDL_Color color = { (Uint8)r, (Uint8)g, (Uint8)b, (Uint8)a }; SDL_Surface* surface = TTF_RenderUTF8_Blended(g_fonts[font_id], text, color); if (!surface) return; SDL_Texture* texture = SDL_CreateTextureFromSurface(g_renderers[renderer_id], surface); if (!texture) { SDL_FreeSurface(surface); return; } SDL_Rect dst = { (int)x, (int)y, surface->w, surface->h }; /* Use SDL_RenderGeometry to avoid SDL3-compat crash */ float fx = (float)x, fy = (float)y; float fw = (float)surface->w, fh = (float)surface->h; SDL_Color white = {255, 255, 255, 255}; SDL_Vertex verts[4] = { { {fx, fy }, white, {0.0f, 0.0f} }, { {fx + fw, fy }, white, {1.0f, 0.0f} }, { {fx + fw, fy + fh}, white, {1.0f, 1.0f} }, { {fx, fy + fh}, white, {0.0f, 1.0f} }, }; int indices[6] = {0, 1, 2, 0, 2, 3}; SDL_RenderGeometry(g_renderers[renderer_id], texture, verts, 4, indices, 6); SDL_DestroyTexture(texture); SDL_FreeSurface(surface); } int64_t create_rgb_surface(int64_t width, int64_t height, int64_t depth) { SDL_Surface* s = NULL; int w = (int)width, h = (int)height, d = (int)depth; if (d == 32) s = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_RGBA32); else if (d == 24) s = SDL_CreateRGBSurfaceWithFormat(0, w, h, 24, SDL_PIXELFORMAT_RGB24); else if (d == 16) s = SDL_CreateRGBSurfaceWithFormat(0, w, h, 16, SDL_PIXELFORMAT_RGB565); else return 0; return (int64_t)s; } void free_surface(int64_t surf_ptr) { if (surf_ptr) SDL_FreeSurface((SDL_Surface*)surf_ptr); } int64_t blit_surface(int64_t src_ptr, int64_t dst_ptr, int64_t x, int64_t y) { if (!src_ptr || !dst_ptr) return 0; SDL_Surface* src = (SDL_Surface*)src_ptr; SDL_Surface* dst = (SDL_Surface*)dst_ptr; SDL_Rect dst_rc = { (int)x, (int)y, 0, 0 }; return SDL_BlitSurface(src, NULL, dst, &dst_rc) == 0 ? 1 : 0; } int64_t get_mouse_state(int64_t* x, int64_t* y) { int ix, iy; Uint32 m = SDL_GetMouseState(&ix, &iy); if (x) *x = ix; if (y) *y = iy; return (int64_t)m; } int64_t get_relative_mouse_state(int64_t* x, int64_t* y) { int ix, iy; Uint32 m = SDL_GetRelativeMouseState(&ix, &iy); if (x) *x = ix; if (y) *y = iy; return (int64_t)m; }