1 /*
2   Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
3 
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7 
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely.
11 */
12 
13 /* Simple program:  draw a RGB triangle, with texture  */
14 
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <time.h>
18 
19 #ifdef __EMSCRIPTEN__
20 #include <emscripten/emscripten.h>
21 #endif
22 
23 #include "SDL_test_common.h"
24 
25 static SDLTest_CommonState *state;
26 static SDL_bool use_texture = SDL_FALSE;
27 static SDL_Texture **sprites;
28 static SDL_BlendMode blendMode = SDL_BLENDMODE_NONE;
29 static double angle = 0.0;
30 static int sprite_w, sprite_h;
31 
32 int done;
33 
34 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
35 static void
quit(int rc)36 quit(int rc)
37 {
38     SDL_free(sprites);
39     SDLTest_CommonQuit(state);
40     exit(rc);
41 }
42 
43 int
LoadSprite(const char * file)44 LoadSprite(const char *file)
45 {
46     int i;
47     SDL_Surface *temp;
48 
49     /* Load the sprite image */
50     temp = SDL_LoadBMP(file);
51     if (temp == NULL) {
52         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
53         return (-1);
54     }
55     sprite_w = temp->w;
56     sprite_h = temp->h;
57 
58     /* Set transparent pixel as the pixel at (0,0) */
59     if (temp->format->palette) {
60         SDL_SetColorKey(temp, 1, *(Uint8 *) temp->pixels);
61     } else {
62         switch (temp->format->BitsPerPixel) {
63         case 15:
64             SDL_SetColorKey(temp, 1, (*(Uint16 *) temp->pixels) & 0x00007FFF);
65             break;
66         case 16:
67             SDL_SetColorKey(temp, 1, *(Uint16 *) temp->pixels);
68             break;
69         case 24:
70             SDL_SetColorKey(temp, 1, (*(Uint32 *) temp->pixels) & 0x00FFFFFF);
71             break;
72         case 32:
73             SDL_SetColorKey(temp, 1, *(Uint32 *) temp->pixels);
74             break;
75         }
76     }
77 
78     /* Create textures from the image */
79     for (i = 0; i < state->num_windows; ++i) {
80         SDL_Renderer *renderer = state->renderers[i];
81         sprites[i] = SDL_CreateTextureFromSurface(renderer, temp);
82         if (!sprites[i]) {
83             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
84             SDL_FreeSurface(temp);
85             return (-1);
86         }
87         if (SDL_SetTextureBlendMode(sprites[i], blendMode) < 0) {
88             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set blend mode: %s\n", SDL_GetError());
89             SDL_FreeSurface(temp);
90             SDL_DestroyTexture(sprites[i]);
91             return (-1);
92         }
93     }
94     SDL_FreeSurface(temp);
95 
96     /* We're ready to roll. :) */
97     return (0);
98 }
99 
100 
101 void
loop()102 loop()
103 {
104     int i;
105     SDL_Event event;
106 
107     /* Check for events */
108     while (SDL_PollEvent(&event)) {
109 
110         if (event.type == SDL_MOUSEMOTION) {
111             if (event.motion.state) {
112                 int xrel, yrel;
113                 int window_w, window_h;
114                 SDL_Window *window = SDL_GetWindowFromID(event.motion.windowID);
115                 SDL_GetWindowSize(window, &window_w, &window_h);
116                 xrel = event.motion.xrel;
117                 yrel = event.motion.yrel;
118                 if (event.motion.y < window_h / 2) {
119                     angle += xrel;
120                 } else {
121                     angle -= xrel;
122                 }
123                 if (event.motion.x < window_w / 2) {
124                     angle -= yrel;
125                 } else {
126                     angle += yrel;
127                 }
128             }
129         } else {
130             SDLTest_CommonEvent(state, &event, &done);
131         }
132     }
133 
134     for (i = 0; i < state->num_windows; ++i) {
135         SDL_Renderer *renderer = state->renderers[i];
136         if (state->windows[i] == NULL)
137             continue;
138         SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
139         SDL_RenderClear(renderer);
140 
141         {
142             SDL_Rect viewport;
143             SDL_Vertex verts[3];
144             double a;
145             double d;
146             int cx, cy;
147 
148             /* Query the sizes */
149             SDL_RenderGetViewport(renderer, &viewport);
150             SDL_zeroa(verts);
151             cx = viewport.x + viewport.w / 2;
152             cy = viewport.y + viewport.h / 2;
153             d = (viewport.w + viewport.h) / 5;
154 
155             a = (angle * 3.1415) / 180.0;
156             verts[0].position.x = cx + d * SDL_cos(a);
157             verts[0].position.y = cy + d * SDL_sin(a);
158             verts[0].color.r = 0xFF;
159             verts[0].color.g = 0;
160             verts[0].color.b = 0;
161             verts[0].color.a = 0xFF;
162 
163             a = ((angle + 120) * 3.1415) / 180.0;
164             verts[1].position.x = cx + d * SDL_cos(a);
165             verts[1].position.y = cy + d * SDL_sin(a);
166             verts[1].color.r = 0;
167             verts[1].color.g = 0xFF;
168             verts[1].color.b = 0;
169             verts[1].color.a = 0xFF;
170 
171             a = ((angle + 240) * 3.1415) / 180.0;
172             verts[2].position.x = cx + d * SDL_cos(a);
173             verts[2].position.y = cy + d * SDL_sin(a);
174             verts[2].color.r = 0;
175             verts[2].color.g = 0;
176             verts[2].color.b = 0xFF;
177             verts[2].color.a = 0xFF;
178 
179             if (use_texture) {
180                 verts[0].tex_coord.x = 0.5;
181                 verts[0].tex_coord.y = 0.0;
182                 verts[1].tex_coord.x = 1.0;
183                 verts[1].tex_coord.y = 1.0;
184                 verts[2].tex_coord.x = 0.0;
185                 verts[2].tex_coord.y = 1.0;
186             }
187 
188             SDL_RenderGeometry(renderer, sprites[i], verts, 3, NULL, 0);
189         }
190 
191         SDL_RenderPresent(renderer);
192     }
193 #ifdef __EMSCRIPTEN__
194     if (done) {
195         emscripten_cancel_main_loop();
196     }
197 #endif
198 }
199 
200 int
main(int argc,char * argv[])201 main(int argc, char *argv[])
202 {
203     int i;
204     const char *icon = "icon.bmp";
205     Uint32 then, now, frames;
206 
207     /* Enable standard application logging */
208     SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
209 
210     /* Initialize test framework */
211     state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
212     if (!state) {
213         return 1;
214     }
215     for (i = 1; i < argc;) {
216         int consumed;
217 
218         consumed = SDLTest_CommonArg(state, i);
219         if (consumed == 0) {
220             consumed = -1;
221             if (SDL_strcasecmp(argv[i], "--blend") == 0) {
222                 if (argv[i + 1]) {
223                     if (SDL_strcasecmp(argv[i + 1], "none") == 0) {
224                         blendMode = SDL_BLENDMODE_NONE;
225                         consumed = 2;
226                     } else if (SDL_strcasecmp(argv[i + 1], "blend") == 0) {
227                         blendMode = SDL_BLENDMODE_BLEND;
228                         consumed = 2;
229                     } else if (SDL_strcasecmp(argv[i + 1], "add") == 0) {
230                         blendMode = SDL_BLENDMODE_ADD;
231                         consumed = 2;
232                     } else if (SDL_strcasecmp(argv[i + 1], "mod") == 0) {
233                         blendMode = SDL_BLENDMODE_MOD;
234                         consumed = 2;
235                     }
236                 }
237             } else if (SDL_strcasecmp(argv[i], "--use-texture") == 0) {
238                 use_texture = SDL_TRUE;
239                 consumed = 1;
240             }
241         }
242         if (consumed < 0) {
243             static const char *options[] = { "[--blend none|blend|add|mod]", "[--use-texture]", NULL };
244             SDLTest_CommonLogUsage(state, argv[0], options);
245             return 1;
246         }
247         i += consumed;
248     }
249     if (!SDLTest_CommonInit(state)) {
250         return 2;
251     }
252 
253     /* Create the windows, initialize the renderers, and load the textures */
254     sprites =
255         (SDL_Texture **) SDL_malloc(state->num_windows * sizeof(*sprites));
256     if (!sprites) {
257         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n");
258         quit(2);
259     }
260     /* Create the windows and initialize the renderers */
261     for (i = 0; i < state->num_windows; ++i) {
262         SDL_Renderer *renderer = state->renderers[i];
263         SDL_SetRenderDrawBlendMode(renderer, blendMode);
264         SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
265         SDL_RenderClear(renderer);
266         sprites[i] = NULL;
267     }
268     if (use_texture) {
269         if (LoadSprite(icon) < 0) {
270             quit(2);
271         }
272     }
273 
274 
275     srand((unsigned int)time(NULL));
276 
277     /* Main render loop */
278     frames = 0;
279     then = SDL_GetTicks();
280     done = 0;
281 
282 #ifdef __EMSCRIPTEN__
283     emscripten_set_main_loop(loop, 0, 1);
284 #else
285     while (!done) {
286         ++frames;
287         loop();
288         }
289 #endif
290 
291     /* Print out some timing information */
292     now = SDL_GetTicks();
293     if (now > then) {
294         double fps = ((double) frames * 1000) / (now - then);
295         SDL_Log("%2.2f frames per second\n", fps);
296     }
297 
298     quit(0);
299 
300     return 0;
301 }
302 
303 /* vi: set ts=4 sw=4 expandtab: */
304