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 | /* Simple program: Create a native window and attach an SDL renderer */ |
13 | |
14 | #include <stdio.h> |
15 | #include <stdlib.h> /* for srand() */ |
16 | #include <time.h> /* for time() */ |
17 | |
18 | #include "testnative.h" |
19 | |
20 | #define WINDOW_W 640 |
21 | #define WINDOW_H 480 |
22 | #define NUM_SPRITES 100 |
23 | #define MAX_SPEED 1 |
24 | |
25 | static NativeWindowFactory *factories[] = { |
26 | #ifdef TEST_NATIVE_WINDOWS |
27 | &WindowsWindowFactory, |
28 | #endif |
29 | #ifdef TEST_NATIVE_X11 |
30 | &X11WindowFactory, |
31 | #endif |
32 | #ifdef TEST_NATIVE_COCOA |
33 | &CocoaWindowFactory, |
34 | #endif |
35 | #ifdef TEST_NATIVE_OS2 |
36 | &OS2WindowFactory, |
37 | #endif |
38 | NULL |
39 | }; |
40 | static NativeWindowFactory *factory = NULL; |
41 | static void *native_window; |
42 | static SDL_Rect *positions, *velocities; |
43 | |
44 | /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ |
45 | static void |
46 | quit(int rc) |
47 | { |
48 | SDL_VideoQuit(); |
49 | if (native_window) { |
50 | factory->DestroyNativeWindow(native_window); |
51 | } |
52 | exit(rc); |
53 | } |
54 | |
55 | SDL_Texture * |
56 | LoadSprite(SDL_Renderer *renderer, char *file) |
57 | { |
58 | SDL_Surface *temp; |
59 | SDL_Texture *sprite; |
60 | |
61 | /* Load the sprite image */ |
62 | temp = SDL_LoadBMP(file); |
63 | if (temp == NULL) { |
64 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s" , file, SDL_GetError()); |
65 | return 0; |
66 | } |
67 | |
68 | /* Set transparent pixel as the pixel at (0,0) */ |
69 | if (temp->format->palette) { |
70 | SDL_SetColorKey(temp, 1, *(Uint8 *) temp->pixels); |
71 | } |
72 | |
73 | /* Create textures from the image */ |
74 | sprite = SDL_CreateTextureFromSurface(renderer, temp); |
75 | if (!sprite) { |
76 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n" , SDL_GetError()); |
77 | SDL_FreeSurface(temp); |
78 | return 0; |
79 | } |
80 | SDL_FreeSurface(temp); |
81 | |
82 | /* We're ready to roll. :) */ |
83 | return sprite; |
84 | } |
85 | |
86 | void |
87 | MoveSprites(SDL_Renderer * renderer, SDL_Texture * sprite) |
88 | { |
89 | int sprite_w, sprite_h; |
90 | int i; |
91 | SDL_Rect viewport; |
92 | SDL_Rect *position, *velocity; |
93 | |
94 | /* Query the sizes */ |
95 | SDL_RenderGetViewport(renderer, &viewport); |
96 | SDL_QueryTexture(sprite, NULL, NULL, &sprite_w, &sprite_h); |
97 | |
98 | /* Draw a gray background */ |
99 | SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); |
100 | SDL_RenderClear(renderer); |
101 | |
102 | /* Move the sprite, bounce at the wall, and draw */ |
103 | for (i = 0; i < NUM_SPRITES; ++i) { |
104 | position = &positions[i]; |
105 | velocity = &velocities[i]; |
106 | position->x += velocity->x; |
107 | if ((position->x < 0) || (position->x >= (viewport.w - sprite_w))) { |
108 | velocity->x = -velocity->x; |
109 | position->x += velocity->x; |
110 | } |
111 | position->y += velocity->y; |
112 | if ((position->y < 0) || (position->y >= (viewport.h - sprite_h))) { |
113 | velocity->y = -velocity->y; |
114 | position->y += velocity->y; |
115 | } |
116 | |
117 | /* Blit the sprite onto the screen */ |
118 | SDL_RenderCopy(renderer, sprite, NULL, position); |
119 | } |
120 | |
121 | /* Update the screen! */ |
122 | SDL_RenderPresent(renderer); |
123 | } |
124 | |
125 | int |
126 | main(int argc, char *argv[]) |
127 | { |
128 | int i, done; |
129 | const char *driver; |
130 | SDL_Window *window; |
131 | SDL_Renderer *renderer; |
132 | SDL_Texture *sprite; |
133 | int window_w, window_h; |
134 | int sprite_w, sprite_h; |
135 | SDL_Event event; |
136 | |
137 | /* Enable standard application logging */ |
138 | SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); |
139 | |
140 | if (SDL_VideoInit(NULL) < 0) { |
141 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL video: %s\n" , |
142 | SDL_GetError()); |
143 | exit(1); |
144 | } |
145 | driver = SDL_GetCurrentVideoDriver(); |
146 | |
147 | /* Find a native window driver and create a native window */ |
148 | for (i = 0; factories[i]; ++i) { |
149 | if (SDL_strcmp(driver, factories[i]->tag) == 0) { |
150 | factory = factories[i]; |
151 | break; |
152 | } |
153 | } |
154 | if (!factory) { |
155 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find native window code for %s driver\n" , |
156 | driver); |
157 | quit(2); |
158 | } |
159 | SDL_Log("Creating native window for %s driver\n" , driver); |
160 | native_window = factory->CreateNativeWindow(WINDOW_W, WINDOW_H); |
161 | if (!native_window) { |
162 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create native window\n" ); |
163 | quit(3); |
164 | } |
165 | window = SDL_CreateWindowFrom(native_window); |
166 | if (!window) { |
167 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create SDL window: %s\n" , SDL_GetError()); |
168 | quit(4); |
169 | } |
170 | SDL_SetWindowTitle(window, "SDL Native Window Test" ); |
171 | |
172 | /* Create the renderer */ |
173 | renderer = SDL_CreateRenderer(window, -1, 0); |
174 | if (!renderer) { |
175 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n" , SDL_GetError()); |
176 | quit(5); |
177 | } |
178 | |
179 | /* Clear the window, load the sprite and go! */ |
180 | SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); |
181 | SDL_RenderClear(renderer); |
182 | |
183 | sprite = LoadSprite(renderer, "icon.bmp" ); |
184 | if (!sprite) { |
185 | quit(6); |
186 | } |
187 | |
188 | /* Allocate memory for the sprite info */ |
189 | SDL_GetWindowSize(window, &window_w, &window_h); |
190 | SDL_QueryTexture(sprite, NULL, NULL, &sprite_w, &sprite_h); |
191 | positions = (SDL_Rect *) SDL_malloc(NUM_SPRITES * sizeof(SDL_Rect)); |
192 | velocities = (SDL_Rect *) SDL_malloc(NUM_SPRITES * sizeof(SDL_Rect)); |
193 | if (!positions || !velocities) { |
194 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n" ); |
195 | quit(2); |
196 | } |
197 | srand(time(NULL)); |
198 | for (i = 0; i < NUM_SPRITES; ++i) { |
199 | positions[i].x = rand() % (window_w - sprite_w); |
200 | positions[i].y = rand() % (window_h - sprite_h); |
201 | positions[i].w = sprite_w; |
202 | positions[i].h = sprite_h; |
203 | velocities[i].x = 0; |
204 | velocities[i].y = 0; |
205 | while (!velocities[i].x && !velocities[i].y) { |
206 | velocities[i].x = (rand() % (MAX_SPEED * 2 + 1)) - MAX_SPEED; |
207 | velocities[i].y = (rand() % (MAX_SPEED * 2 + 1)) - MAX_SPEED; |
208 | } |
209 | } |
210 | |
211 | /* Main render loop */ |
212 | done = 0; |
213 | while (!done) { |
214 | /* Check for events */ |
215 | while (SDL_PollEvent(&event)) { |
216 | switch (event.type) { |
217 | case SDL_WINDOWEVENT: |
218 | switch (event.window.event) { |
219 | case SDL_WINDOWEVENT_EXPOSED: |
220 | SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); |
221 | SDL_RenderClear(renderer); |
222 | break; |
223 | } |
224 | break; |
225 | case SDL_QUIT: |
226 | done = 1; |
227 | break; |
228 | default: |
229 | break; |
230 | } |
231 | } |
232 | MoveSprites(renderer, sprite); |
233 | } |
234 | |
235 | quit(0); |
236 | |
237 | return 0; /* to prevent compiler warning */ |
238 | } |
239 | |
240 | /* vi: set ts=4 sw=4 expandtab: */ |
241 | |