Mercurial > sdl-ios-xcode
annotate test/testpalette.c @ 1192:54aa9aa32327
To: sdl@libsdl.org
From: Christian Walther <cwalther@gmx.ch>
Date: Fri, 18 Nov 2005 23:39:02 +0100
Subject: [SDL] Mouse position bugs on Mac OS X
The attached patch fixes a few bugs in SDL related to the mouse position
in windowed mode on Mac OS X, reproduced using the attached minimal test
program - at least here on 10.3.9, with SDL CVS from today. Could anyone
test whether the bugs exist and are fixed by the patch on 10.2 and 10.4?
1. When using OpenGL, the vertical mouse positions obtained through
events or SDL_GetMouseState() are off by one.
2. When using OpenGL, SDL_WarpMouse() inverts the y coordinate.
3. Clicks on the topmost pixel row of the window are not recognized.
1 and 2 do not occur in non-OpenGL mode, while 3 does. All three only
occur in windowed mode, not in fullscreen.
The cause for 1 and 3 is that in Cocoa, "the location of the mouse"
seems to be defined as "the location of the top left corner of the mouse
pointer's hot pixel" (this is not documented, it's just what I found out
here), which together with the fact that Cocoa's usual y coordinates
start at the bottom and increase upwards means that the y coordinate of
the mouse runs from 1 to h, not from 0 to h-1, in a window of height h.
If it does work on 10.2 and 10.4 (I'll try to test it as soon as I can,
but at the moment all I have at hand is 10.3.9), can this be applied to
the CVS?
-Christian
To: sdl@libsdl.org
From: Christian Walther <cwalther@gmx.ch>
Date: Mon, 28 Nov 2005 10:41:51 +0100
Subject: [SDL] Re: Mouse position bugs on Mac OS X
I wrote:
> I'll try to test it as soon as I can, but at the moment all I have at hand is 10.3.9
So, here are the results of my tests (with patched and unpatched
frameworks compiled with Xcode 1.5 (gcc 3.3) on 10.3.9):
On 10.1.5, my test program doesn't run because of "Undefined symbols:
SDL undefined reference to _CGMainDisplayID expected to be defined in
Carbon". I guess not supporting 10.1 was a deliberate decision then and
that's OK with me.
On 10.2.8, 10.3.9, and 10.4.0, the bugs exist as described in my
original post and are fixed by my patch. That is, there is no difference
between pre/post 10.3 and the patched version works correctly in all
combinations of GL/non-GL and windowed/fullscreen.
I therefore recommend the patch for inclusion.
-Christian
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Mon, 28 Nov 2005 13:58:26 +0000 |
parents | be9c9c8f6d53 |
children | aff0170f9f1b |
rev | line source |
---|---|
0 | 1 /* |
2 * testpalette.c | |
3 * | |
4 * A simple test of runtime palette modification for animation | |
5 * (using the SDL_SetPalette() API). | |
6 */ | |
7 | |
8 #include <stdio.h> | |
9 #include <stdlib.h> | |
10 #include <string.h> | |
11 #include <math.h> | |
12 | |
13 /* This isn't in the Windows headers */ | |
14 #ifndef M_PI | |
15 #define M_PI 3.14159265358979323846 | |
16 #endif | |
17 | |
18 #include <SDL.h> | |
19 | |
20 /* screen size */ | |
21 #define SCRW 640 | |
22 #define SCRH 480 | |
23 | |
24 #define NBOATS 5 | |
25 #define SPEED 2 | |
26 | |
27 #ifndef MIN | |
28 #define MIN(a, b) ((a) < (b) ? (a) : (b)) | |
29 #endif | |
30 #ifndef MAX | |
31 #define MAX(a, b) ((a) > (b) ? (a) : (b)) | |
32 #endif | |
33 | |
34 /* | |
35 * wave colours: Made by taking a narrow cross-section of a wave picture | |
36 * in Gimp, saving in PPM ascii format and formatting with Emacs macros. | |
37 */ | |
38 static SDL_Color wavemap[] = { | |
39 {0,2,103}, {0,7,110}, {0,13,117}, {0,19,125}, | |
40 {0,25,133}, {0,31,141}, {0,37,150}, {0,43,158}, | |
41 {0,49,166}, {0,55,174}, {0,61,182}, {0,67,190}, | |
42 {0,73,198}, {0,79,206}, {0,86,214}, {0,96,220}, | |
43 {5,105,224}, {12,112,226}, {19,120,227}, {26,128,229}, | |
44 {33,135,230}, {40,143,232}, {47,150,234}, {54,158,236}, | |
45 {61,165,238}, {68,173,239}, {75,180,241}, {82,188,242}, | |
46 {89,195,244}, {96,203,246}, {103,210,248}, {112,218,250}, | |
47 {124,224,250}, {135,226,251}, {146,229,251}, {156,231,252}, | |
48 {167,233,252}, {178,236,252}, {189,238,252}, {200,240,252}, | |
49 {211,242,252}, {222,244,252}, {233,247,252}, {242,249,252}, | |
50 {237,250,252}, {209,251,252}, {174,251,252}, {138,252,252}, | |
51 {102,251,252}, {63,250,252}, {24,243,252}, {7,225,252}, | |
52 {4,203,252}, {3,181,252}, {2,158,252}, {1,136,251}, | |
53 {0,111,248}, {0,82,234}, {0,63,213}, {0,50,192}, | |
54 {0,39,172}, {0,28,152}, {0,17,132}, {0,7,114} | |
55 }; | |
56 | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
57 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
58 static void quit(int rc) |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
59 { |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
60 SDL_Quit(); |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
61 exit(rc); |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
62 } |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
63 |
0 | 64 static void sdlerr(char *when) |
65 { | |
66 fprintf(stderr, "SDL error: %s: %s\n", when, SDL_GetError()); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
67 quit(1); |
0 | 68 } |
69 | |
70 /* create a background surface */ | |
71 static SDL_Surface *make_bg(SDL_Surface *screen, int startcol) | |
72 { | |
73 int i; | |
74 SDL_Surface *bg = SDL_CreateRGBSurface(SDL_SWSURFACE, screen->w, screen->h, | |
75 8, 0, 0, 0, 0); | |
76 if(!bg) | |
77 sdlerr("creating background surface"); | |
78 | |
79 /* set the palette to the logical screen palette so that blits | |
80 won't be translated */ | |
81 SDL_SetColors(bg, screen->format->palette->colors, 0, 256); | |
82 | |
83 /* Make a wavy background pattern using colours 0-63 */ | |
84 if(SDL_LockSurface(bg) < 0) | |
85 sdlerr("locking background"); | |
86 for(i = 0; i < SCRH; i++) { | |
87 Uint8 *p = (Uint8 *)bg->pixels + i * bg->pitch; | |
88 int j, d; | |
89 d = 0; | |
90 for(j = 0; j < SCRW; j++) { | |
91 int v = MAX(d, -2); | |
92 v = MIN(v, 2); | |
93 if(i > 0) | |
94 v += p[-bg->pitch] + 65 - startcol; | |
95 p[j] = startcol + (v & 63); | |
96 d += ((rand() >> 3) % 3) - 1; | |
97 } | |
98 } | |
99 SDL_UnlockSurface(bg); | |
100 return(bg); | |
101 } | |
102 | |
103 /* | |
104 * Return a surface flipped horisontally. Only works for 8bpp; | |
105 * extension to arbitrary bitness is left as an exercise for the reader. | |
106 */ | |
107 static SDL_Surface *hflip(SDL_Surface *s) | |
108 { | |
109 int i; | |
110 SDL_Surface *z = SDL_CreateRGBSurface(SDL_SWSURFACE, s->w, s->h, 8, | |
111 0, 0, 0, 0); | |
112 /* copy palette */ | |
113 SDL_SetColors(z, s->format->palette->colors, | |
114 0, s->format->palette->ncolors); | |
115 if(SDL_LockSurface(s) < 0 || SDL_LockSurface(z) < 0) | |
116 sdlerr("locking flip images"); | |
117 | |
118 for(i = 0; i < s->h; i++) { | |
119 int j; | |
120 Uint8 *from = (Uint8 *)s->pixels + i * s->pitch; | |
121 Uint8 *to = (Uint8 *)z->pixels + i * z->pitch + s->w - 1; | |
122 for(j = 0; j < s->w; j++) | |
123 to[-j] = from[j]; | |
124 } | |
125 | |
126 SDL_UnlockSurface(z); | |
127 SDL_UnlockSurface(s); | |
128 return z; | |
129 } | |
130 | |
131 int main(int argc, char **argv) | |
132 { | |
133 SDL_Color cmap[256]; | |
134 SDL_Surface *screen; | |
135 SDL_Surface *bg; | |
136 SDL_Surface *boat[2]; | |
137 unsigned vidflags = 0; | |
138 unsigned start; | |
139 int fade_max = 400; | |
140 int fade_level, fade_dir; | |
141 int boatcols, frames, i, red; | |
142 int boatx[NBOATS], boaty[NBOATS], boatdir[NBOATS]; | |
143 int gamma_fade = 0; | |
144 int gamma_ramp = 0; | |
145 | |
146 if(SDL_Init(SDL_INIT_VIDEO) < 0) | |
147 sdlerr("initialising SDL"); | |
148 | |
149 while(--argc) { | |
150 ++argv; | |
151 if(strcmp(*argv, "-hw") == 0) | |
152 vidflags |= SDL_HWSURFACE; | |
153 else if(strcmp(*argv, "-fullscreen") == 0) | |
154 vidflags |= SDL_FULLSCREEN; | |
155 else if(strcmp(*argv, "-nofade") == 0) | |
156 fade_max = 1; | |
157 else if(strcmp(*argv, "-gamma") == 0) | |
158 gamma_fade = 1; | |
159 else if(strcmp(*argv, "-gammaramp") == 0) | |
160 gamma_ramp = 1; | |
161 else { | |
162 fprintf(stderr, | |
163 "usage: testpalette " | |
164 " [-hw] [-fullscreen] [-nofade] [-gamma] [-gammaramp]\n"); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
165 quit(1); |
0 | 166 } |
167 } | |
168 | |
169 /* Ask explicitly for 8bpp and a hardware palette */ | |
170 if(!(screen = SDL_SetVideoMode(SCRW, SCRH, 8, vidflags | SDL_HWPALETTE))) { | |
171 fprintf(stderr, "error setting %dx%d 8bpp indexed mode: %s\n", | |
172 SCRW, SCRH, SDL_GetError()); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
173 quit(1); |
0 | 174 } |
175 | |
176 if(!(boat[0] = SDL_LoadBMP("sail.bmp"))) | |
177 sdlerr("loading sail.bmp"); | |
178 /* We've chosen magenta (#ff00ff) as colour key for the boat */ | |
179 SDL_SetColorKey(boat[0], SDL_SRCCOLORKEY | SDL_RLEACCEL, | |
180 SDL_MapRGB(boat[0]->format, 0xff, 0x00, 0xff)); | |
181 boatcols = boat[0]->format->palette->ncolors; | |
182 boat[1] = hflip(boat[0]); | |
183 SDL_SetColorKey(boat[1], SDL_SRCCOLORKEY | SDL_RLEACCEL, | |
184 SDL_MapRGB(boat[1]->format, 0xff, 0x00, 0xff)); | |
185 | |
186 /* | |
187 * First set the physical screen palette to black, so the user won't | |
188 * see our initial drawing on the screen. | |
189 */ | |
190 memset(cmap, 0, sizeof(cmap)); | |
191 SDL_SetPalette(screen, SDL_PHYSPAL, cmap, 0, 256); | |
192 | |
193 /* | |
194 * Proper palette management is important when playing games with the | |
195 * colormap. We have divided the palette as follows: | |
196 * | |
197 * index 0..(boatcols-1): used for the boat | |
198 * index boatcols..(boatcols+63): used for the waves | |
199 */ | |
200 SDL_SetPalette(screen, SDL_LOGPAL, | |
201 boat[0]->format->palette->colors, 0, boatcols); | |
202 SDL_SetPalette(screen, SDL_LOGPAL, wavemap, boatcols, 64); | |
203 | |
204 /* | |
205 * Now the logical screen palette is set, and will remain unchanged. | |
206 * The boats already have the same palette so fast blits can be used. | |
207 */ | |
208 memcpy(cmap, screen->format->palette->colors, 256 * sizeof(SDL_Color)); | |
209 | |
210 /* save the index of the red colour for later */ | |
211 red = SDL_MapRGB(screen->format, 0xff, 0x00, 0x00); | |
212 | |
213 bg = make_bg(screen, boatcols); /* make a nice wavy background surface */ | |
214 | |
215 /* initial screen contents */ | |
216 if(SDL_BlitSurface(bg, NULL, screen, NULL) < 0) | |
217 sdlerr("blitting background to screen"); | |
218 SDL_Flip(screen); /* actually put the background on screen */ | |
219 | |
220 /* determine initial boat placements */ | |
221 for(i = 0; i < NBOATS; i++) { | |
222 boatx[i] = (rand() % (SCRW + boat[0]->w)) - boat[0]->w; | |
223 boaty[i] = i * (SCRH - boat[0]->h) / (NBOATS - 1); | |
224 boatdir[i] = ((rand() >> 5) & 1) * 2 - 1; | |
225 } | |
226 | |
227 start = SDL_GetTicks(); | |
228 frames = 0; | |
229 fade_dir = 1; | |
230 fade_level = 0; | |
231 do { | |
232 SDL_Event e; | |
233 SDL_Rect updates[NBOATS]; | |
234 SDL_Rect r; | |
235 int redphase; | |
236 | |
237 /* A small event loop: just exit on any key or mouse button event */ | |
238 while(SDL_PollEvent(&e)) { | |
239 if(e.type == SDL_KEYDOWN || e.type == SDL_QUIT | |
240 || e.type == SDL_MOUSEBUTTONDOWN) { | |
241 if(fade_dir < 0) | |
242 fade_level = 0; | |
243 fade_dir = -1; | |
244 } | |
245 } | |
246 | |
247 /* move boats */ | |
248 for(i = 0; i < NBOATS; i++) { | |
249 int old_x = boatx[i]; | |
250 /* update boat position */ | |
251 boatx[i] += boatdir[i] * SPEED; | |
252 if(boatx[i] <= -boat[0]->w || boatx[i] >= SCRW) | |
253 boatdir[i] = -boatdir[i]; | |
254 | |
255 /* paint over the old boat position */ | |
256 r.x = old_x; | |
257 r.y = boaty[i]; | |
258 r.w = boat[0]->w; | |
259 r.h = boat[0]->h; | |
260 if(SDL_BlitSurface(bg, &r, screen, &r) < 0) | |
261 sdlerr("blitting background"); | |
262 | |
263 /* construct update rectangle (bounding box of old and new pos) */ | |
264 updates[i].x = MIN(old_x, boatx[i]); | |
265 updates[i].y = boaty[i]; | |
266 updates[i].w = boat[0]->w + SPEED; | |
267 updates[i].h = boat[0]->h; | |
268 /* clip update rectangle to screen */ | |
269 if(updates[i].x < 0) { | |
270 updates[i].w += updates[i].x; | |
271 updates[i].x = 0; | |
272 } | |
273 if(updates[i].x + updates[i].w > SCRW) | |
274 updates[i].w = SCRW - updates[i].x; | |
275 } | |
276 | |
277 for(i = 0; i < NBOATS; i++) { | |
278 /* paint boat on new position */ | |
279 r.x = boatx[i]; | |
280 r.y = boaty[i]; | |
281 if(SDL_BlitSurface(boat[(boatdir[i] + 1) / 2], NULL, | |
282 screen, &r) < 0) | |
283 sdlerr("blitting boat"); | |
284 } | |
285 | |
286 /* cycle wave palette */ | |
287 for(i = 0; i < 64; i++) | |
288 cmap[boatcols + ((i + frames) & 63)] = wavemap[i]; | |
289 | |
290 if(fade_dir) { | |
291 /* Fade the entire palette in/out */ | |
292 fade_level += fade_dir; | |
293 | |
294 if(gamma_fade) { | |
295 /* Fade linearly in gamma level (lousy) */ | |
296 float level = (float)fade_level / fade_max; | |
297 if(SDL_SetGamma(level, level, level) < 0) | |
298 sdlerr("setting gamma"); | |
299 | |
300 } else if(gamma_ramp) { | |
301 /* Fade using gamma ramp (better) */ | |
302 Uint16 ramp[256]; | |
303 for(i = 0; i < 256; i++) | |
304 ramp[i] = (i * fade_level / fade_max) << 8; | |
305 if(SDL_SetGammaRamp(ramp, ramp, ramp) < 0) | |
306 sdlerr("setting gamma ramp"); | |
307 | |
308 } else { | |
309 /* Fade using direct palette manipulation (best) */ | |
310 memcpy(cmap, screen->format->palette->colors, | |
311 boatcols * sizeof(SDL_Color)); | |
312 for(i = 0; i < boatcols + 64; i++) { | |
313 cmap[i].r = cmap[i].r * fade_level / fade_max; | |
314 cmap[i].g = cmap[i].g * fade_level / fade_max; | |
315 cmap[i].b = cmap[i].b * fade_level / fade_max; | |
316 } | |
317 } | |
318 if(fade_level == fade_max) | |
319 fade_dir = 0; | |
320 } | |
321 | |
322 /* pulse the red colour (done after the fade, for a night effect) */ | |
323 redphase = frames % 64; | |
324 cmap[red].r = (int)(255 * sin(redphase * M_PI / 63)); | |
325 | |
326 SDL_SetPalette(screen, SDL_PHYSPAL, cmap, 0, boatcols + 64); | |
327 | |
328 /* update changed areas of the screen */ | |
329 SDL_UpdateRects(screen, NBOATS, updates); | |
330 frames++; | |
331 } while(fade_level > 0); | |
332 | |
333 printf("%d frames, %.2f fps\n", | |
334 frames, 1000.0 * frames / (SDL_GetTicks() - start)); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
335 |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
336 SDL_Quit(); |
0 | 337 return 0; |
338 } | |
339 |