Simple Directmedia Layer
at main 283 lines 8.6 kB view raw
1/* 2 Copyright (C) 1997-2024 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 17#include "testutils.h" 18#include <SDL3/SDL.h> 19#include <SDL3/SDL_main.h> 20#include <SDL3/SDL_test_common.h> 21 22#ifdef SDL_PLATFORM_EMSCRIPTEN 23#include <emscripten/emscripten.h> 24#endif 25 26static SDLTest_CommonState *state; 27static bool use_texture = false; 28static SDL_Texture **sprites; 29static SDL_BlendMode blendMode = SDL_BLENDMODE_NONE; 30static float angle = 0.0f; 31static int sprite_w, sprite_h; 32static int translate_cx = 0; 33static int translate_cy = 0; 34 35static int done; 36 37/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ 38static void 39quit(int rc) 40{ 41 SDL_free(sprites); 42 SDLTest_CommonQuit(state); 43 /* Let 'main()' return normally */ 44 if (rc != 0) { 45 exit(rc); 46 } 47} 48 49static int LoadSprite(const char *file) 50{ 51 int i; 52 53 for (i = 0; i < state->num_windows; ++i) { 54 /* This does the SDL_LoadBMP step repeatedly, but that's OK for test code. */ 55 sprites[i] = LoadTexture(state->renderers[i], file, true, &sprite_w, &sprite_h); 56 if (!sprites[i]) { 57 return -1; 58 } 59 if (!SDL_SetTextureBlendMode(sprites[i], blendMode)) { 60 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set blend mode: %s\n", SDL_GetError()); 61 SDL_DestroyTexture(sprites[i]); 62 return -1; 63 } 64 } 65 66 /* We're ready to roll. :) */ 67 return 0; 68} 69 70static void loop(void) 71{ 72 int i; 73 SDL_Event event; 74 75 /* Check for events */ 76 while (SDL_PollEvent(&event)) { 77 78 if (event.type == SDL_EVENT_MOUSE_MOTION) { 79 if (event.motion.state) { 80 float xrel, yrel; 81 int window_w, window_h; 82 SDL_Window *window = SDL_GetWindowFromID(event.motion.windowID); 83 SDL_GetWindowSize(window, &window_w, &window_h); 84 xrel = event.motion.xrel; 85 yrel = event.motion.yrel; 86 if (event.motion.y < (float)window_h / 2.0f) { 87 angle += xrel; 88 } else { 89 angle -= xrel; 90 } 91 if (event.motion.x < (float)window_w / 2.0f) { 92 angle -= yrel; 93 } else { 94 angle += yrel; 95 } 96 } 97 } else if (event.type == SDL_EVENT_KEY_DOWN) { 98 if (event.key.key == SDLK_LEFT) { 99 translate_cx -= 1; 100 } else if (event.key.key == SDLK_RIGHT) { 101 translate_cx += 1; 102 } else if (event.key.key == SDLK_UP) { 103 translate_cy -= 1; 104 } else if (event.key.key == SDLK_DOWN) { 105 translate_cy += 1; 106 } else { 107 SDLTest_CommonEvent(state, &event, &done); 108 } 109 } else { 110 SDLTest_CommonEvent(state, &event, &done); 111 } 112 } 113 114 for (i = 0; i < state->num_windows; ++i) { 115 SDL_Renderer *renderer = state->renderers[i]; 116 if (state->windows[i] == NULL) { 117 continue; 118 } 119 SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); 120 SDL_RenderClear(renderer); 121 122 { 123 SDL_Rect viewport; 124 SDL_Vertex verts[3]; 125 float a; 126 float d; 127 int cx, cy; 128 129 /* Query the sizes */ 130 SDL_GetRenderViewport(renderer, &viewport); 131 SDL_zeroa(verts); 132 cx = viewport.x + viewport.w / 2; 133 cy = viewport.y + viewport.h / 2; 134 d = (viewport.w + viewport.h) / 5.f; 135 136 cx += translate_cx; 137 cy += translate_cy; 138 139 a = (angle * SDL_PI_F) / 180.0f; 140 verts[0].position.x = cx + d * SDL_cosf(a); 141 verts[0].position.y = cy + d * SDL_sinf(a); 142 verts[0].color.r = 1.0f; 143 verts[0].color.g = 0; 144 verts[0].color.b = 0; 145 verts[0].color.a = 1.0f; 146 147 a = ((angle + 120) * SDL_PI_F) / 180.0f; 148 verts[1].position.x = cx + d * SDL_cosf(a); 149 verts[1].position.y = cy + d * SDL_sinf(a); 150 verts[1].color.r = 0; 151 verts[1].color.g = 1.0f; 152 verts[1].color.b = 0; 153 verts[1].color.a = 1.0f; 154 155 a = ((angle + 240) * SDL_PI_F) / 180.0f; 156 verts[2].position.x = cx + d * SDL_cosf(a); 157 verts[2].position.y = cy + d * SDL_sinf(a); 158 verts[2].color.r = 0; 159 verts[2].color.g = 0; 160 verts[2].color.b = 1.0f; 161 verts[2].color.a = 1.0f; 162 163 if (use_texture) { 164 verts[0].tex_coord.x = 0.5f; 165 verts[0].tex_coord.y = 0.0f; 166 verts[1].tex_coord.x = 1.0f; 167 verts[1].tex_coord.y = 1.0f; 168 verts[2].tex_coord.x = 0.0f; 169 verts[2].tex_coord.y = 1.0f; 170 } 171 172 SDL_RenderGeometry(renderer, sprites[i], verts, 3, NULL, 0); 173 } 174 175 SDL_RenderPresent(renderer); 176 } 177#ifdef SDL_PLATFORM_EMSCRIPTEN 178 if (done) { 179 emscripten_cancel_main_loop(); 180 } 181#endif 182} 183 184int main(int argc, char *argv[]) 185{ 186 int i; 187 const char *icon = "icon.bmp"; 188 Uint64 then, now; 189 Uint32 frames; 190 191 /* Initialize test framework */ 192 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); 193 if (!state) { 194 return 1; 195 } 196 197 for (i = 1; i < argc;) { 198 int consumed; 199 200 consumed = SDLTest_CommonArg(state, i); 201 if (consumed == 0) { 202 consumed = -1; 203 if (SDL_strcasecmp(argv[i], "--blend") == 0) { 204 if (argv[i + 1]) { 205 if (SDL_strcasecmp(argv[i + 1], "none") == 0) { 206 blendMode = SDL_BLENDMODE_NONE; 207 consumed = 2; 208 } else if (SDL_strcasecmp(argv[i + 1], "blend") == 0) { 209 blendMode = SDL_BLENDMODE_BLEND; 210 consumed = 2; 211 } else if (SDL_strcasecmp(argv[i + 1], "add") == 0) { 212 blendMode = SDL_BLENDMODE_ADD; 213 consumed = 2; 214 } else if (SDL_strcasecmp(argv[i + 1], "mod") == 0) { 215 blendMode = SDL_BLENDMODE_MOD; 216 consumed = 2; 217 } else if (SDL_strcasecmp(argv[i + 1], "mul") == 0) { 218 blendMode = SDL_BLENDMODE_MUL; 219 consumed = 2; 220 } 221 } 222 } else if (SDL_strcasecmp(argv[i], "--use-texture") == 0) { 223 use_texture = true; 224 consumed = 1; 225 } 226 } 227 if (consumed < 0) { 228 static const char *options[] = { "[--blend none|blend|add|mod|mul]", "[--use-texture]", NULL }; 229 SDLTest_CommonLogUsage(state, argv[0], options); 230 return 1; 231 } 232 i += consumed; 233 } 234 if (!SDLTest_CommonInit(state)) { 235 return 2; 236 } 237 238 /* Create the windows, initialize the renderers, and load the textures */ 239 sprites = 240 (SDL_Texture **)SDL_malloc(state->num_windows * sizeof(*sprites)); 241 if (!sprites) { 242 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n"); 243 quit(2); 244 } 245 /* Create the windows and initialize the renderers */ 246 for (i = 0; i < state->num_windows; ++i) { 247 SDL_Renderer *renderer = state->renderers[i]; 248 SDL_SetRenderDrawBlendMode(renderer, blendMode); 249 SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); 250 SDL_RenderClear(renderer); 251 sprites[i] = NULL; 252 } 253 if (use_texture) { 254 if (LoadSprite(icon) < 0) { 255 quit(2); 256 } 257 } 258 259 /* Main render loop */ 260 frames = 0; 261 then = SDL_GetTicks(); 262 done = 0; 263 264#ifdef SDL_PLATFORM_EMSCRIPTEN 265 emscripten_set_main_loop(loop, 0, 1); 266#else 267 while (!done) { 268 ++frames; 269 loop(); 270 } 271#endif 272 273 /* Print out some timing information */ 274 now = SDL_GetTicks(); 275 if (now > then) { 276 double fps = ((double)frames * 1000) / (now - then); 277 SDL_Log("%2.2f frames per second\n", fps); 278 } 279 280 quit(0); 281 282 return 0; 283}