1
2/* Jim - SDL extension
3 * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * A copy of the license is also included in the source distribution
12 * of Jim, as a TXT file name called LICENSE.
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <errno.h>
25#include <SDL/SDL.h>
26#include <SDL/SDL_gfxPrimitives.h>
27
28#include "jim.h"
29#include "jimautoconf.h"
30
31#define AIO_CMD_LEN 128
32
33typedef struct JimSdlSurface
34{
35    SDL_Surface *screen;
36} JimSdlSurface;
37
38static void JimSdlSetError(Jim_Interp *interp)
39{
40    Jim_SetResultString(interp, SDL_GetError(), -1);
41}
42
43static void JimSdlDelProc(Jim_Interp *interp, void *privData)
44{
45    JimSdlSurface *jss = privData;
46
47    JIM_NOTUSED(interp);
48
49    SDL_FreeSurface(jss->screen);
50    Jim_Free(jss);
51}
52
53/* Calls to commands created via [sdl.surface] are implemented by this
54 * C command. */
55static int JimSdlHandlerCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
56{
57    JimSdlSurface *jss = Jim_CmdPrivData(interp);
58    int option;
59    static const char * const options[] = {
60        "free", "flip", "pixel", "rectangle", "box", "line", "aaline",
61        "circle", "aacircle", "fcircle", NULL
62    };
63    enum
64    { OPT_FREE, OPT_FLIP, OPT_PIXEL, OPT_RECTANGLE, OPT_BOX, OPT_LINE,
65        OPT_AALINE, OPT_CIRCLE, OPT_AACIRCLE, OPT_FCIRCLE
66    };
67
68    if (argc < 2) {
69        Jim_WrongNumArgs(interp, 1, argv, "method ?args ...?");
70        return JIM_ERR;
71    }
72    if (Jim_GetEnum(interp, argv[1], options, &option, "SDL surface method", JIM_ERRMSG) != JIM_OK)
73        return JIM_ERR;
74    if (option == OPT_PIXEL) {
75        /* PIXEL */
76        long x, y, red, green, blue, alpha = 255;
77
78        if (argc != 7 && argc != 8) {
79            Jim_WrongNumArgs(interp, 2, argv, "x y red green blue ?alpha?");
80            return JIM_ERR;
81        }
82        if (Jim_GetLong(interp, argv[2], &x) != JIM_OK ||
83            Jim_GetLong(interp, argv[3], &y) != JIM_OK ||
84            Jim_GetLong(interp, argv[4], &red) != JIM_OK ||
85            Jim_GetLong(interp, argv[5], &green) != JIM_OK ||
86            Jim_GetLong(interp, argv[6], &blue) != JIM_OK) {
87            return JIM_ERR;
88        }
89        if (argc == 8 && Jim_GetLong(interp, argv[7], &alpha) != JIM_OK)
90            return JIM_ERR;
91        pixelRGBA(jss->screen, x, y, red, green, blue, alpha);
92        return JIM_OK;
93    }
94    else if (option == OPT_RECTANGLE || option == OPT_BOX ||
95        option == OPT_LINE || option == OPT_AALINE) {
96        /* RECTANGLE, BOX, LINE, AALINE */
97        long x1, y1, x2, y2, red, green, blue, alpha = 255;
98
99        if (argc != 9 && argc != 10) {
100            Jim_WrongNumArgs(interp, 2, argv, "x y red green blue ?alpha?");
101            return JIM_ERR;
102        }
103        if (Jim_GetLong(interp, argv[2], &x1) != JIM_OK ||
104            Jim_GetLong(interp, argv[3], &y1) != JIM_OK ||
105            Jim_GetLong(interp, argv[4], &x2) != JIM_OK ||
106            Jim_GetLong(interp, argv[5], &y2) != JIM_OK ||
107            Jim_GetLong(interp, argv[6], &red) != JIM_OK ||
108            Jim_GetLong(interp, argv[7], &green) != JIM_OK ||
109            Jim_GetLong(interp, argv[8], &blue) != JIM_OK) {
110            return JIM_ERR;
111        }
112        if (argc == 10 && Jim_GetLong(interp, argv[9], &alpha) != JIM_OK)
113            return JIM_ERR;
114        switch (option) {
115            case OPT_RECTANGLE:
116                rectangleRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
117                break;
118            case OPT_BOX:
119                boxRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
120                break;
121            case OPT_LINE:
122                lineRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
123                break;
124            case OPT_AALINE:
125                aalineRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
126                break;
127        }
128        return JIM_OK;
129    }
130    else if (option == OPT_CIRCLE || option == OPT_AACIRCLE || option == OPT_FCIRCLE) {
131        /* CIRCLE, AACIRCLE, FCIRCLE */
132        long x, y, radius, red, green, blue, alpha = 255;
133
134        if (argc != 8 && argc != 9) {
135            Jim_WrongNumArgs(interp, 2, argv, "x y radius red green blue ?alpha?");
136            return JIM_ERR;
137        }
138        if (Jim_GetLong(interp, argv[2], &x) != JIM_OK ||
139            Jim_GetLong(interp, argv[3], &y) != JIM_OK ||
140            Jim_GetLong(interp, argv[4], &radius) != JIM_OK ||
141            Jim_GetLong(interp, argv[5], &red) != JIM_OK ||
142            Jim_GetLong(interp, argv[6], &green) != JIM_OK ||
143            Jim_GetLong(interp, argv[7], &blue) != JIM_OK) {
144            return JIM_ERR;
145        }
146        if (argc == 9 && Jim_GetLong(interp, argv[8], &alpha) != JIM_OK)
147            return JIM_ERR;
148        switch (option) {
149            case OPT_CIRCLE:
150                circleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
151                break;
152            case OPT_AACIRCLE:
153                aacircleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
154                break;
155            case OPT_FCIRCLE:
156                filledCircleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
157                break;
158        }
159        return JIM_OK;
160    }
161    else if (option == OPT_FREE) {
162        /* FREE */
163        if (argc != 2) {
164            Jim_WrongNumArgs(interp, 2, argv, "");
165            return JIM_ERR;
166        }
167        Jim_DeleteCommand(interp, Jim_String(argv[0]));
168        return JIM_OK;
169    }
170    else if (option == OPT_FLIP) {
171        /* FLIP */
172        if (argc != 2) {
173            Jim_WrongNumArgs(interp, 2, argv, "");
174            return JIM_ERR;
175        }
176        SDL_Flip(jss->screen);
177        return JIM_OK;
178    }
179    return JIM_OK;
180}
181
182static int JimSdlSurfaceCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
183{
184    JimSdlSurface *jss;
185    char buf[AIO_CMD_LEN];
186    Jim_Obj *objPtr;
187    long screenId, xres, yres;
188    SDL_Surface *screen;
189
190    if (argc != 3) {
191        Jim_WrongNumArgs(interp, 1, argv, "xres yres");
192        return JIM_ERR;
193    }
194    if (Jim_GetLong(interp, argv[1], &xres) != JIM_OK ||
195        Jim_GetLong(interp, argv[2], &yres) != JIM_OK)
196        return JIM_ERR;
197
198    /* Try to create the surface */
199    screen = SDL_SetVideoMode(xres, yres, 32, SDL_SWSURFACE | SDL_ANYFORMAT);
200    if (screen == NULL) {
201        JimSdlSetError(interp);
202        return JIM_ERR;
203    }
204    /* Get the next file id */
205    if (Jim_EvalGlobal(interp, "if {[catch {incr sdl.surfaceId}]} {set sdl.surfaceId 0}") != JIM_OK)
206        return JIM_ERR;
207    objPtr = Jim_GetVariableStr(interp, "sdl.surfaceId", JIM_ERRMSG);
208    if (objPtr == NULL)
209        return JIM_ERR;
210    if (Jim_GetLong(interp, objPtr, &screenId) != JIM_OK)
211        return JIM_ERR;
212
213    /* Create the SDL screen command */
214    jss = Jim_Alloc(sizeof(*jss));
215    jss->screen = screen;
216    sprintf(buf, "sdl.surface%ld", screenId);
217    Jim_CreateCommand(interp, buf, JimSdlHandlerCommand, jss, JimSdlDelProc);
218    Jim_SetResultString(interp, buf, -1);
219    return JIM_OK;
220}
221
222int Jim_sdlInit(Jim_Interp *interp)
223{
224    if (Jim_PackageProvide(interp, "sdl", "1.0", JIM_ERRMSG))
225        return JIM_ERR;
226
227    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
228        JimSdlSetError(interp);
229        return JIM_ERR;
230    }
231    atexit(SDL_Quit);
232    Jim_CreateCommand(interp, "sdl.screen", JimSdlSurfaceCommand, NULL, NULL);
233    return JIM_OK;
234}
235