From 8e818b3a5ee8647b746bf7ce7d601ca42b6a0ec4 Mon Sep 17 00:00:00 2001 From: Steve Bennett Date: Wed, 30 Dec 2020 13:54:59 +1000 Subject: sdl: convert to using jim-subcmd And add: - poll ?script? - optional window title Signed-off-by: Steve Bennett --- examples/sdlcircles.tcl | 28 ++++ examples/sdltest.tcl | 58 ++++--- jim-sdl.c | 434 +++++++++++++++++++++++++++++++----------------- 3 files changed, 348 insertions(+), 172 deletions(-) create mode 100644 examples/sdlcircles.tcl diff --git a/examples/sdlcircles.tcl b/examples/sdlcircles.tcl new file mode 100644 index 0000000..8d1274d --- /dev/null +++ b/examples/sdlcircles.tcl @@ -0,0 +1,28 @@ +package require sdl + +set xres 1024 +set yres 768 +set s [sdl.screen $xres $yres "Jim SDL Circles"] + +proc drawlist {s list} { + foreach item $list { + $s {*}$item + } +} + +proc rand_circle {xres yres maxradius alpha} { + list fcircle [rand $xres] [rand $yres] [rand $maxradius] [rand 256] [rand 256] [rand 256] $alpha +} + +loop i 0 200 { + set commands {} + loop j 0 1000 { + lappend commands [rand_circle $xres $yres 40 100] + if {$j % 50 == 0} { + #$s clear 200 200 200 + drawlist $s $commands + $s flip + sleep 0.1 + } + } +} diff --git a/examples/sdltest.tcl b/examples/sdltest.tcl index 6607574..cf42d88 100644 --- a/examples/sdltest.tcl +++ b/examples/sdltest.tcl @@ -1,28 +1,46 @@ package require sdl -set xres 1024 -set yres 768 +# Basic test of all sdl commands + +set xres 640 +set yres 384 set s [sdl.screen $xres $yres] -proc drawlist {s list} { - foreach item $list { - $s {*}$item - } -} +set cyan {0 255 255 200} +set yellow {255 255 0 200} +set red {255 0 0 200} +set green {0 255 0 200} +set grey {50 50 50 200} +set white {255 255 255} +set blue {0 0 255 200} + +$s clear {*}$grey -proc rand_circle {xres yres maxradius alpha} { - list fcircle [rand $xres] [rand $yres] [rand $maxradius] [rand 256] [rand 256] [rand 256] $alpha +$s fcircle 320 280 40 {*}$cyan +$s circle 320 280 60 {*}$yellow +$s aacircle 320 280 80 {*}$green + +$s rectangle 200 100 300 180 {*}$cyan +$s box 210 110 290 170 {*}$yellow + +set x 20 +set y 20 +set dy 10 +set dx 10 +foreach i [range 50] { + set nx $($x + $dx) + set ny $($y + $dy) + $s line $x $y $nx $ny {*}$green + $s aaline $x $($y+30) $nx $($ny+30) {*}$red + set x $nx + set y $ny + set dy $(-$dy) } -loop i 0 200 { - set commands {} - loop j 0 1000 { - lappend commands [rand_circle $xres $yres 40 100] - if {$j % 50 == 0} { - #$s clear 200 200 200 - drawlist $s $commands - $s flip - sleep 0.1 - } - } +$s rectangle 50 200 150 300 {*}$yellow +foreach i [range 500] { + $s pixel $([rand 100] + 50) $([rand 100] + 200) {*}$white } + +$s poll { sleep 0.25 } +$s free diff --git a/jim-sdl.c b/jim-sdl.c index be4fe41..32b2a20 100644 --- a/jim-sdl.c +++ b/jim-sdl.c @@ -44,6 +44,9 @@ #endif #include +#include + +static int jim_sdl_initialised; typedef struct JimSdlSurface { @@ -54,7 +57,6 @@ typedef struct JimSdlSurface #else SDL_Surface *screen; #endif - long background[4]; } JimSdlSurface; static void JimSdlSetError(Jim_Interp *interp) @@ -100,182 +102,312 @@ static void JimSdlClear(JimSdlSurface *jss, int r, int g, int b, int alpha) #endif } -/* Calls to commands created via [sdl.surface] are implemented by this - * C command. */ -static int JimSdlHandlerCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +/* Process the event loop, throwing away all events except quit. + * On quit, return JIM_EXIT. + * If necessary, this can be caught with catch -exit { ... } + */ +static int JimSdlPoll(Jim_Interp *interp) +{ + SDL_Event e; + while (SDL_PollEvent(&e)) { + if (e.type == SDL_QUIT) { + Jim_SetResultInt(interp, 0); + return JIM_EXIT; + } + } + return JIM_OK; +} + +static int jim_sdl_subcmd_free(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + Jim_DeleteCommand(interp, argv[0]); + return JIM_OK; +} + +/* [sdl flip] - present the current image, clear the new image, poll for events. + * Returns JIM_EXIT on quit event + */ +static int jim_sdl_subcmd_flip(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { JimSdlSurface *jss = Jim_CmdPrivData(interp); - int option; - static const char * const options[] = { - "free", "flip", "pixel", "rectangle", "box", "line", "aaline", - "circle", "aacircle", "fcircle", "clear", NULL - }; - enum - { OPT_FREE, OPT_FLIP, OPT_PIXEL, OPT_RECTANGLE, OPT_BOX, OPT_LINE, - OPT_AALINE, OPT_CIRCLE, OPT_AACIRCLE, OPT_FCIRCLE, OPT_CLEAR - }; - - if (argc < 2) { - Jim_WrongNumArgs(interp, 1, argv, "method ?args ...?"); +#if SDL_MAJOR_VERSION == 2 + SDL_RenderPresent(jss->screen); +#else + SDL_Flip(jss->screen); +#endif + JimSdlClear(jss, 0, 0, 0, SDL_ALPHA_OPAQUE); + + return JimSdlPoll(interp); +} + +/* [sdl poll ?script?] - present the current image, poll for events. + * Returns JIM_EXIT on quit event or JIM_OK if all events processed. + * + * If the script is given, evaluates the script on each poll loop until + * either quit event is received or the script returns something other than JIM_OK. + */ +static int jim_sdl_subcmd_poll(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + int ret = JIM_OK; +#if SDL_MAJOR_VERSION == 2 + JimSdlSurface *jss = Jim_CmdPrivData(interp); + SDL_RenderPresent(jss->screen); +#endif + while (ret == JIM_OK) { + ret = JimSdlPoll(interp); + if (ret != JIM_OK || argc != 1) { + break; + } + ret = Jim_EvalObj(interp, argv[0]); + } + return ret; +} + +static int jim_sdl_subcmd_clear(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + JimSdlSurface *jss = Jim_CmdPrivData(interp); + long vals[4]; + if (JimSdlGetLongs(interp, argc, argv, vals) != JIM_OK) { return JIM_ERR; } - if (Jim_GetEnum(interp, argv[1], options, &option, "SDL surface method", JIM_ERRMSG) != JIM_OK) + if (argc == 3) { + vals[3] = SDL_ALPHA_OPAQUE; + } + JimSdlClear(jss, vals[0], vals[1], vals[2], vals[3]); + return JIM_OK; +} + +static int jim_sdl_subcmd_pixel(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + JimSdlSurface *jss = Jim_CmdPrivData(interp); + long vals[6]; + if (JimSdlGetLongs(interp, argc, argv, vals) != JIM_OK) { return JIM_ERR; - if (option == OPT_PIXEL) { - /* PIXEL */ - /* x, y, red, green, blue, alpha = 255 */ - long vals[7]; + } + if (argc == 5) { + vals[5] = SDL_ALPHA_OPAQUE; + } + pixelRGBA(jss->screen, vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]); + return JIM_OK; +} - if (argc != 7 && argc != 8) { - Jim_WrongNumArgs(interp, 2, argv, "x y red green blue ?alpha?"); - return JIM_ERR; - } - if (JimSdlGetLongs(interp, argc - 3, argv + 3, vals) != JIM_OK) { - return JIM_ERR; - } - pixelRGBA(jss->screen, vals[0], vals[1], vals[2], vals[3], vals[4], argc == 8 ? vals[5] : SDL_ALPHA_OPAQUE); - return JIM_OK; +static int jim_sdl_subcmd_circle(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + JimSdlSurface *jss = Jim_CmdPrivData(interp); + long vals[7]; + if (JimSdlGetLongs(interp, argc, argv, vals) != JIM_OK) { + return JIM_ERR; + } + if (argc == 6) { + vals[6] = SDL_ALPHA_OPAQUE; } - else if (option == OPT_RECTANGLE || option == OPT_BOX || - option == OPT_LINE || option == OPT_AALINE) { - /* RECTANGLE, BOX, LINE, AALINE */ - long x1, y1, x2, y2, red, green, blue, alpha = 255; + circleRGBA(jss->screen, vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6]); + return JIM_OK; +} - if (argc != 9 && argc != 10) { - Jim_WrongNumArgs(interp, 2, argv, "x y red green blue ?alpha?"); - return JIM_ERR; - } - if (Jim_GetLong(interp, argv[2], &x1) != JIM_OK || - Jim_GetLong(interp, argv[3], &y1) != JIM_OK || - Jim_GetLong(interp, argv[4], &x2) != JIM_OK || - Jim_GetLong(interp, argv[5], &y2) != JIM_OK || - Jim_GetLong(interp, argv[6], &red) != JIM_OK || - Jim_GetLong(interp, argv[7], &green) != JIM_OK || - Jim_GetLong(interp, argv[8], &blue) != JIM_OK) { - return JIM_ERR; - } - if (argc == 10 && Jim_GetLong(interp, argv[9], &alpha) != JIM_OK) - return JIM_ERR; - switch (option) { - case OPT_RECTANGLE: - rectangleRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha); - break; - case OPT_BOX: - boxRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha); - break; - case OPT_LINE: - lineRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha); - break; - case OPT_AALINE: - aalineRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha); - break; - } - return JIM_OK; +static int jim_sdl_subcmd_aacircle(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + JimSdlSurface *jss = Jim_CmdPrivData(interp); + long vals[7]; + if (JimSdlGetLongs(interp, argc, argv, vals) != JIM_OK) { + return JIM_ERR; } - else if (option == OPT_CIRCLE || option == OPT_AACIRCLE || option == OPT_FCIRCLE) { - /* CIRCLE, AACIRCLE, FCIRCLE */ - long x, y, radius, red, green, blue, alpha = 255; + if (argc == 6) { + vals[6] = SDL_ALPHA_OPAQUE; + } + aacircleRGBA(jss->screen, vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6]); + return JIM_OK; +} - if (argc != 8 && argc != 9) { - Jim_WrongNumArgs(interp, 2, argv, "x y radius red green blue ?alpha?"); - return JIM_ERR; - } - if (Jim_GetLong(interp, argv[2], &x) != JIM_OK || - Jim_GetLong(interp, argv[3], &y) != JIM_OK || - Jim_GetLong(interp, argv[4], &radius) != JIM_OK || - Jim_GetLong(interp, argv[5], &red) != JIM_OK || - Jim_GetLong(interp, argv[6], &green) != JIM_OK || - Jim_GetLong(interp, argv[7], &blue) != JIM_OK) { - return JIM_ERR; - } - if (argc == 9 && Jim_GetLong(interp, argv[8], &alpha) != JIM_OK) - return JIM_ERR; - switch (option) { - case OPT_CIRCLE: - circleRGBA(jss->screen, x, y, radius, red, green, blue, alpha); - break; - case OPT_AACIRCLE: - aacircleRGBA(jss->screen, x, y, radius, red, green, blue, alpha); - break; - case OPT_FCIRCLE: - filledCircleRGBA(jss->screen, x, y, radius, red, green, blue, alpha); - break; - } - return JIM_OK; +static int jim_sdl_subcmd_fcircle(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + JimSdlSurface *jss = Jim_CmdPrivData(interp); + long vals[7]; + if (JimSdlGetLongs(interp, argc, argv, vals) != JIM_OK) { + return JIM_ERR; } - else if (option == OPT_FREE) { - /* FREE */ - if (argc != 2) { - Jim_WrongNumArgs(interp, 2, argv, ""); - return JIM_ERR; - } - Jim_DeleteCommand(interp, argv[0]); - return JIM_OK; + if (argc == 6) { + vals[6] = SDL_ALPHA_OPAQUE; } - else if (option == OPT_CLEAR) { - long vals[4]; - if (argc != 5 && argc != 6) { - Jim_WrongNumArgs(interp, 2, argv, "red green blue ?alpha?"); - return JIM_ERR; - } - if (JimSdlGetLongs(interp, argc - 2, argv + 2, vals) != JIM_OK) { - return JIM_ERR; - } - if (argc == 5) { - vals[3] = SDL_ALPHA_OPAQUE; - } - JimSdlClear(jss, vals[0], vals[1], vals[2], vals[3]); + filledCircleRGBA(jss->screen, vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6]); + return JIM_OK; +} + +static int jim_sdl_subcmd_rectangle(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + JimSdlSurface *jss = Jim_CmdPrivData(interp); + long vals[8]; + if (JimSdlGetLongs(interp, argc, argv, vals) != JIM_OK) { + return JIM_ERR; } - else if (option == OPT_FLIP) { - /* FLIP */ - if (argc != 2) { - Jim_WrongNumArgs(interp, 2, argv, ""); - return JIM_ERR; - } - { - SDL_Event e; -#if SDL_MAJOR_VERSION == 2 - SDL_RenderPresent(jss->screen); -#else - SDL_Flip(jss->screen); -#endif - JimSdlClear(jss, 0, 0, 0, SDL_ALPHA_OPAQUE); - /* Throw away all events except quit, and pass this back as JIM_EXIT. - * If necessary, this can be caught with catch -exit { ... } - */ - while (SDL_PollEvent(&e)) { - if (e.type == SDL_QUIT) { - Jim_SetResultInt(interp, 0); - return JIM_EXIT; - } - } - } - return JIM_OK; + if (argc == 7) { + vals[7] = SDL_ALPHA_OPAQUE; } + rectangleRGBA(jss->screen, vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6], vals[7]); return JIM_OK; } +static int jim_sdl_subcmd_box(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + JimSdlSurface *jss = Jim_CmdPrivData(interp); + long vals[8]; + if (JimSdlGetLongs(interp, argc, argv, vals) != JIM_OK) { + return JIM_ERR; + } + if (argc == 7) { + vals[7] = SDL_ALPHA_OPAQUE; + } + boxRGBA(jss->screen, vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6], vals[7]); + return JIM_OK; +} + +static int jim_sdl_subcmd_line(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + JimSdlSurface *jss = Jim_CmdPrivData(interp); + long vals[8]; + if (JimSdlGetLongs(interp, argc, argv, vals) != JIM_OK) { + return JIM_ERR; + } + if (argc == 7) { + vals[7] = SDL_ALPHA_OPAQUE; + } + lineRGBA(jss->screen, vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6], vals[7]); + return JIM_OK; +} + +static int jim_sdl_subcmd_aaline(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + JimSdlSurface *jss = Jim_CmdPrivData(interp); + long vals[8]; + if (JimSdlGetLongs(interp, argc, argv, vals) != JIM_OK) { + return JIM_ERR; + } + if (argc == 7) { + vals[7] = SDL_ALPHA_OPAQUE; + } + aalineRGBA(jss->screen, vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6], vals[7]); + return JIM_OK; +} + +static const jim_subcmd_type sdl_command_table[] = { + { "free", + NULL, + jim_sdl_subcmd_free, + 0, + 0, + JIM_MODFLAG_FULLARGV, + }, + { "flip", + NULL, + jim_sdl_subcmd_flip, + 0, + 0, + }, + { "poll", + "?script?", + jim_sdl_subcmd_poll, + 0, + 1, + }, + { "clear", + "red green blue ?alpha?", + jim_sdl_subcmd_clear, + 3, + 4, + }, + { "pixel", + "x y red green blue ?alpha?", + jim_sdl_subcmd_pixel, + 5, + 6, + }, + { "circle", + "x y radius red green blue ?alpha?", + jim_sdl_subcmd_circle, + 6, + 7, + }, + { "aacircle", + "x y radius red green blue ?alpha?", + jim_sdl_subcmd_aacircle, + 6, + 7, + }, + { "fcircle", + "x y radius red green blue ?alpha?", + jim_sdl_subcmd_fcircle, + 6, + 7, + }, + { "rectangle", + "x1 y1 x2 y2 red green blue ?alpha?", + jim_sdl_subcmd_rectangle, + 7, + 8, + }, + { "box", + "x1 y1 x2 y2 red green blue ?alpha?", + jim_sdl_subcmd_box, + 7, + 8, + }, + { "line", + "x1 y1 x2 y2 red green blue ?alpha?", + jim_sdl_subcmd_line, + 7, + 8, + }, + { "aaline", + "x1 y1 x2 y2 red green blue ?alpha?", + jim_sdl_subcmd_aaline, + 7, + 8, + }, + { NULL } +}; + +/* Calls to commands created via [sdl.surface] are implemented by this + * C command. */ +static int JimSdlHandlerCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, sdl_command_table, argc, argv); + + return Jim_CallSubCmd(interp, ct, argc, argv); +} + static int JimSdlSurfaceCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { JimSdlSurface *jss; char buf[128]; - long xres, yres; + long vals[2]; + const char *title; - if (argc != 3) { - Jim_WrongNumArgs(interp, 1, argv, "xres yres"); + if (argc != 3 && argc != 4) { + Jim_WrongNumArgs(interp, 1, argv, "xres yres ?title?"); return JIM_ERR; } - if (Jim_GetLong(interp, argv[1], &xres) != JIM_OK || - Jim_GetLong(interp, argv[2], &yres) != JIM_OK) + + if (JimSdlGetLongs(interp, 2, argv + 1, vals) != JIM_OK) { return JIM_ERR; + } + + if (!jim_sdl_initialised) { + jim_sdl_initialised++; + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + JimSdlSetError(interp); + return JIM_ERR; + } + atexit(SDL_Quit); + } + + title = (argc == 4) ? Jim_String(argv[3]) : "sdl"; jss = Jim_Alloc(sizeof(*jss)); memset(jss, 0, sizeof(*jss)); - jss->background[3] = SDL_ALPHA_OPAQUE; #if SDL_MAJOR_VERSION == 2 /* Try to create the surface */ - jss->win = SDL_CreateWindow("sdl", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, xres, yres, 0); + jss->win = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, vals[0], vals[1], 0); if (jss->win) { jss->screen = SDL_CreateRenderer(jss->win, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED); if (jss->screen) { @@ -287,7 +419,10 @@ static int JimSdlSurfaceCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar } } #else - jss->screen = SDL_SetVideoMode(xres, yres, 32, SDL_SWSURFACE | SDL_ANYFORMAT); + jss->screen = SDL_SetVideoMode(vals[0], vals[1], 32, SDL_SWSURFACE | SDL_ANYFORMAT); + if (jss->screen) { + SDL_WM_SetCaption(title, title); + } #endif if (jss->screen) { JimSdlClear(jss, 0, 0, 0, SDL_ALPHA_OPAQUE); @@ -310,11 +445,6 @@ int Jim_sdlInit(Jim_Interp *interp) if (Jim_PackageProvide(interp, "sdl", "1.0", JIM_ERRMSG)) return JIM_ERR; - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - JimSdlSetError(interp); - return JIM_ERR; - } - atexit(SDL_Quit); Jim_CreateCommand(interp, "sdl.screen", JimSdlSurfaceCommand, NULL, NULL); return JIM_OK; } -- cgit v1.1