sdl3/php-sdl3/sdl3.c
2025-10-25 22:04:24 +02:00

369 lines
10 KiB
C

#include <SDL3/SDL_stdinc.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "php_sdl3.h"
#include "helper.h"
#include <SDL3/SDL.h>
#include <SDL3_gfx/SDL3_gfxPrimitives.h>
#include <math.h>
// Resource handles
static int le_sdl_window;
static int le_sdl_renderer;
// Destructor for window resource
static void sdl_window_dtor(zend_resource *rsrc) {
SDL_Window *win = (SDL_Window *)rsrc->ptr;
if (win) {
SDL_DestroyWindow(win);
}
}
// Destructor for renderer resource
static void sdl_renderer_dtor(zend_resource *rsrc) {
SDL_Renderer *ren = (SDL_Renderer *)rsrc->ptr;
if (ren) {
SDL_DestroyRenderer(ren);
}
}
PHP_MINIT_FUNCTION(sdl3) {
le_sdl_window = zend_register_list_destructors_ex(sdl_window_dtor, NULL, "SDL_Window", module_number);
le_sdl_renderer = zend_register_list_destructors_ex(sdl_renderer_dtor, NULL, "SDL_Renderer", module_number);
return SUCCESS;
}
PHP_FUNCTION(sdl_init) {
zend_long flags;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &flags) == FAILURE) {
RETURN_THROWS();
}
if (SDL_Init((Uint32)flags) < 0) {
RETURN_FALSE;
}
RETURN_TRUE;
}
PHP_FUNCTION(sdl_quit) {
SDL_Quit();
}
PHP_FUNCTION(sdl_create_window) {
char *title;
size_t title_len;
zend_long w, h;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll", &title, &title_len, &w, &h) == FAILURE) {
RETURN_THROWS();
}
SDL_Window *win = SDL_CreateWindow(title, (int)w, (int)h, 0);
if (!win) {
RETURN_FALSE;
}
RETURN_RES(zend_register_resource(win, le_sdl_window));
}
PHP_FUNCTION(sdl_create_renderer) {
zval *win_res;
SDL_Window *win;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &win_res) == FAILURE) {
RETURN_THROWS();
}
win = (SDL_Window *)zend_fetch_resource(Z_RES_P(win_res), "SDL_Window", le_sdl_window);
if (!win) {
RETURN_FALSE;
}
SDL_Renderer *ren = SDL_CreateRenderer(win, NULL);
if (!ren) {
RETURN_FALSE;
}
RETURN_RES(zend_register_resource(ren, le_sdl_renderer));
}
PHP_FUNCTION(sdl_set_render_draw_color) {
zval *ren_res;
SDL_Renderer *ren;
zend_long r, g, b, a;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "rllll", &ren_res, &r, &g, &b, &a) == FAILURE) {
RETURN_THROWS();
}
ren = (SDL_Renderer *)zend_fetch_resource(Z_RES_P(ren_res), "SDL_Renderer", le_sdl_renderer);
if (!ren) {
RETURN_FALSE;
}
SDL_SetRenderDrawColor(ren, (Uint8)r, (Uint8)g, (Uint8)b, (Uint8)a);
RETURN_TRUE;
}
PHP_FUNCTION(sdl_render_clear) {
zval *ren_res;
SDL_Renderer *ren;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &ren_res) == FAILURE) {
RETURN_THROWS();
}
ren = (SDL_Renderer *)zend_fetch_resource(Z_RES_P(ren_res), "SDL_Renderer", le_sdl_renderer);
if (!ren) {
RETURN_FALSE;
}
SDL_RenderClear(ren);
RETURN_TRUE;
}
PHP_FUNCTION(sdl_render_fill_rect) {
zval *ren_res;
SDL_Renderer *ren;
zval *rect_arr;
HashTable *rect_ht;
zval *data;
zend_long x, y, w, h;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ra", &ren_res, &rect_arr) == FAILURE) {
RETURN_THROWS();
}
ren = (SDL_Renderer *)zend_fetch_resource(Z_RES_P(ren_res), "SDL_Renderer", le_sdl_renderer);
if (!ren) {
RETURN_FALSE;
}
rect_ht = Z_ARRVAL_P(rect_arr);
if (((data = zend_hash_str_find(rect_ht, "x", 1)) != NULL && (x = zval_get_long(data), true)) &&
((data = zend_hash_str_find(rect_ht, "y", 1)) != NULL && (y = zval_get_long(data), true)) &&
((data = zend_hash_str_find(rect_ht, "w", 1)) != NULL && (w = zval_get_long(data), true)) &&
((data = zend_hash_str_find(rect_ht, "h", 1)) != NULL && (h = zval_get_long(data), true))) {
SDL_FRect rect = {(float)x, (float)y, (float)w, (float)h};
SDL_RenderFillRect(ren, &rect);
RETURN_TRUE;
}
zend_throw_error(NULL, "Invalid rectangle array passed to sdl_render_fill_rect. Expected ['x'=>int, 'y'=>int, 'w'=>int, 'h'=>int]");
RETURN_THROWS();
}
PHP_FUNCTION(sdl_render_present) {
zval *ren_res;
SDL_Renderer *ren;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &ren_res) == FAILURE) {
RETURN_THROWS();
}
ren = (SDL_Renderer *)zend_fetch_resource(Z_RES_P(ren_res), "SDL_Renderer", le_sdl_renderer);
if (!ren) {
RETURN_FALSE;
}
SDL_RenderPresent(ren);
RETURN_TRUE;
}
PHP_FUNCTION(sdl_delay) {
zend_long ms;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &ms) == FAILURE) {
RETURN_THROWS();
}
SDL_Delay((Uint32)ms);
}
PHP_FUNCTION(sdl_get_error) {
const char *error = SDL_GetError();
RETURN_STRING(error);
}
PHP_FUNCTION(sdl_rounded_box)
{
zval *ren_res;
SDL_Renderer *ren;
zend_long x1, y1, x2, y2, rad;
zend_long r, g, b, a;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlllllllll", &ren_res, &x1, &y1, &x2, &y2, &rad, &r, &g, &b, &a) == FAILURE) {
RETURN_THROWS();
}
ren = (SDL_Renderer *)zend_fetch_resource(Z_RES_P(ren_res), "SDL_Renderer", le_sdl_renderer);
if (!ren) {
RETURN_FALSE;
}
if (roundedBoxRGBA(ren, (Sint16)x1, (Sint16)y1, (Sint16)x2, (Sint16)y2, (Sint16)rad, (Uint8)r, (Uint8)g, (Uint8)b, (Uint8)a) == 0) {
RETURN_TRUE;
}
RETURN_FALSE;
}
#include <math.h>
PHP_FUNCTION(sdl_rounded_box_ex)
{
zval *ren_res;
SDL_Renderer *ren;
zend_long x1, y1, x2, y2;
zend_long rad_tl, rad_tr, rad_br, rad_bl;
zend_long r, g, b, a;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "rllllllllllll", &ren_res, &x1, &y1, &x2, &y2, &rad_tl, &rad_tr, &rad_br, &rad_bl, &r, &g, &b, &a) == FAILURE) {
RETURN_THROWS();
}
ren = (SDL_Renderer *)zend_fetch_resource(Z_RES_P(ren_res), "SDL_Renderer", le_sdl_renderer);
if (!ren) RETURN_FALSE;
SDL_SetRenderDrawColor(ren, r, g, b, a);
int halfw = ((Sint16)x2-(Sint16)x1) / 2;
int halfh = ((Sint16)y2-(Sint16)y1) / 2;
if (rad_tl > halfw) rad_tl = halfw; if (rad_tl > halfh) rad_tl = halfh;
if (rad_tr > halfw) rad_tr = halfw; if (rad_tr > halfh) rad_tr = halfh;
if (rad_br > halfw) rad_br = halfw; if (rad_br > halfh) rad_br = halfh;
if (rad_bl > halfw) rad_bl = halfw; if (rad_bl > halfh) rad_bl = halfh;
int r_left = (rad_tl > rad_bl) ? rad_tl : rad_bl;
int r_right = (rad_tr > rad_br) ? rad_tr : rad_br;
// 1) center vertical band (zwischen links und rechts Radien), ganze Höhe
SDL_FRect center = { x1 + rad_tl, y1, x2 - x1-rad_tl-rad_br, y2-y1 };
if (center.w > 0 && center.h > 0) SDL_RenderFillRect(ren, &center);
// 2) left vertical rectangle (zwischen oberen und unteren Ecken links)
SDL_FRect leftRect = { x1, y1 + rad_tl, rad_bl, y2-rad_tl-rad_bl-y1 };
if (leftRect.w > 0 && leftRect.h > 0) SDL_RenderFillRect(ren, &leftRect);
// 3) right vertical rectangle (zwischen oberen und unteren Ecken rechts)
SDL_FRect rightRect = { x2 - r_right, y1 + rad_tr, r_right, y2-y1-rad_tr - rad_br };
if (rightRect.w > 0 && rightRect.h > 0) SDL_RenderFillRect(ren, &rightRect);
// 4) vier gefüllte Viertel-Kreise in den Ecken
if (rad_tl > 0) filled_quarter_circle(ren, x1 + rad_tl, y1 + rad_tl, rad_tl, 0);
if (rad_tr > 0) filled_quarter_circle(ren, x2 - rad_tr, y1 + rad_tr, rad_tr, 1);
if (rad_br > 0) filled_quarter_circle(ren, x2 - rad_br, y2- rad_br, rad_br, 2);
if (rad_bl > 0) filled_quarter_circle(ren, x1 + rad_bl, y2 - rad_bl, rad_bl, 3);
RETURN_TRUE;
}
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_init, 0, 0, 1)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_quit, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_create_window, 0, 0, 3)
ZEND_ARG_INFO(0, title)
ZEND_ARG_INFO(0, w)
ZEND_ARG_INFO(0, h)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_create_renderer, 0, 0, 1)
ZEND_ARG_INFO(0, window)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_set_render_draw_color, 0, 0, 5)
ZEND_ARG_INFO(0, renderer)
ZEND_ARG_INFO(0, r)
ZEND_ARG_INFO(0, g)
ZEND_ARG_INFO(0, b)
ZEND_ARG_INFO(0, a)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_render_clear, 0, 0, 1)
ZEND_ARG_INFO(0, renderer)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_render_fill_rect, 0, 0, 2)
ZEND_ARG_INFO(0, renderer)
ZEND_ARG_INFO(0, rect)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_render_present, 0, 0, 1)
ZEND_ARG_INFO(0, renderer)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_delay, 0, 0, 1)
ZEND_ARG_INFO(0, ms)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_get_error, 0, 0, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_rounded_box, 0, 0, 10)
ZEND_ARG_INFO(0, renderer)
ZEND_ARG_INFO(0, x1)
ZEND_ARG_INFO(0, y1)
ZEND_ARG_INFO(0, x2)
ZEND_ARG_INFO(0, y2)
ZEND_ARG_INFO(0, radius)
ZEND_ARG_INFO(0, r)
ZEND_ARG_INFO(0, g)
ZEND_ARG_INFO(0, b)
ZEND_ARG_INFO(0, a)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sdl_rounded_box_ex, 0, 0, 13)
ZEND_ARG_INFO(0, renderer)
ZEND_ARG_INFO(0, x1)
ZEND_ARG_INFO(0, y1)
ZEND_ARG_INFO(0, x2)
ZEND_ARG_INFO(0, y2)
ZEND_ARG_INFO(0, rad_tl)
ZEND_ARG_INFO(0, rad_tr)
ZEND_ARG_INFO(0, rad_br)
ZEND_ARG_INFO(0, rad_bl)
ZEND_ARG_INFO(0, r)
ZEND_ARG_INFO(0, g)
ZEND_ARG_INFO(0, b)
ZEND_ARG_INFO(0, a)
ZEND_END_ARG_INFO()
const zend_function_entry sdl3_functions[] = {
PHP_FE(sdl_init, arginfo_sdl_init)
PHP_FE(sdl_quit, arginfo_sdl_quit)
PHP_FE(sdl_create_window, arginfo_sdl_create_window)
PHP_FE(sdl_create_renderer, arginfo_sdl_create_renderer)
PHP_FE(sdl_set_render_draw_color, arginfo_sdl_set_render_draw_color)
PHP_FE(sdl_render_clear, arginfo_sdl_render_clear)
PHP_FE(sdl_render_fill_rect, arginfo_sdl_render_fill_rect)
PHP_FE(sdl_render_present, arginfo_sdl_render_present)
PHP_FE(sdl_delay, arginfo_sdl_delay)
PHP_FE(sdl_get_error, arginfo_sdl_get_error)
PHP_FE(sdl_rounded_box, arginfo_sdl_rounded_box)
PHP_FE(sdl_rounded_box_ex, arginfo_sdl_rounded_box_ex)
PHP_FE_END
};
zend_module_entry sdl3_module_entry = {
STANDARD_MODULE_HEADER,
"sdl3",
sdl3_functions,
PHP_MINIT(sdl3),
NULL, // MSHUTDOWN
NULL, // RINIT
NULL, // RSHUTDOWN
NULL, // MINFO
PHP_SDL3_VERSION,
STANDARD_MODULE_PROPERTIES
};
#ifdef COMPILE_DL_SDL3
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
ZEND_GET_MODULE(sdl3)
#endif