Mercurial > sdl-ios-xcode
comparison src/video/SDL_renderer_gl.c @ 1918:092bd3a019c5
Starting on the OpenGL renderer...
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Wed, 19 Jul 2006 07:18:45 +0000 |
parents | |
children | 00816063b9c9 |
comparison
equal
deleted
inserted
replaced
1917:3f54b3ec5a07 | 1918:092bd3a019c5 |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 1997-2006 Sam Lantinga | |
4 | |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Lesser General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2.1 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Lesser General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Lesser General Public | |
16 License along with this library; if not, write to the Free Software | |
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | |
19 Sam Lantinga | |
20 slouken@libsdl.org | |
21 */ | |
22 #include "SDL_config.h" | |
23 | |
24 #if SDL_VIDEO_OPENGL | |
25 | |
26 #include "SDL_win32video.h" | |
27 | |
28 /* OpenGL renderer implementation */ | |
29 | |
30 static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags); | |
31 static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
32 static int GL_SetTexturePalette(SDL_Renderer * renderer, | |
33 SDL_Texture * texture, | |
34 const SDL_Color * colors, int firstcolor, | |
35 int ncolors); | |
36 static int GL_GetTexturePalette(SDL_Renderer * renderer, | |
37 SDL_Texture * texture, SDL_Color * colors, | |
38 int firstcolor, int ncolors); | |
39 static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
40 const SDL_Rect * rect, const void *pixels, | |
41 int pitch); | |
42 static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
43 const SDL_Rect * rect, int markDirty, | |
44 void **pixels, int *pitch); | |
45 static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
46 static void GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
47 int numrects, const SDL_Rect * rects); | |
48 static int GL_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect, | |
49 Uint32 color); | |
50 static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, | |
51 const SDL_Rect * srcrect, const SDL_Rect * dstrect, | |
52 int blendMode, int scaleMode); | |
53 static void GL_RenderPresent(SDL_Renderer * renderer); | |
54 static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); | |
55 static void GL_DestroyRenderer(SDL_Renderer * renderer); | |
56 | |
57 | |
58 SDL_RenderDriver GL_RenderDriver = { | |
59 GL_CreateRenderer, | |
60 { | |
61 "opengl", | |
62 (SDL_Renderer_PresentDiscard | SDL_Renderer_PresentVSync | | |
63 SDL_Renderer_Accelerated), | |
64 (SDL_TextureBlendMode_None | SDL_TextureBlendMode_Mask | | |
65 SDL_TextureBlendMode_Blend | SDL_TextureBlendMode_Add | | |
66 SDL_TextureBlendMode_Mod), | |
67 (SDL_TextureScaleMode_None | SDL_TextureScaleMode_Fast | | |
68 SDL_TextureScaleMode_Best), | |
69 12, | |
70 { | |
71 SDL_PixelFormat_Index8, | |
72 SDL_PixelFormat_RGB332, | |
73 SDL_PixelFormat_RGB444, | |
74 SDL_PixelFormat_RGB555, | |
75 SDL_PixelFormat_ARGB4444, | |
76 SDL_PixelFormat_ARGB1555, | |
77 SDL_PixelFormat_RGB565, | |
78 SDL_PixelFormat_RGB888, | |
79 SDL_PixelFormat_ARGB8888, | |
80 SDL_PixelFormat_ARGB2101010, | |
81 SDL_PixelFormat_UYVY, | |
82 SDL_PixelFormat_YUY2}, | |
83 0, | |
84 0} | |
85 }; | |
86 | |
87 typedef struct | |
88 { | |
89 SDL_GLContext context; | |
90 SDL_bool beginScene; | |
91 } GL_RenderData; | |
92 | |
93 typedef struct | |
94 { | |
95 GLuint texture; | |
96 GLfloat texw; | |
97 GLfloat texh; | |
98 void *pixels; | |
99 int pitch; | |
100 } GL_TextureData; | |
101 | |
102 static GLFORMAT | |
103 PixelFormatToOpenGL(Uint32 format,) | |
104 { | |
105 switch (format) { | |
106 case SDL_PixelFormat_Index8: | |
107 return GLFMT_P8; | |
108 case SDL_PixelFormat_RGB332: | |
109 return GLFMT_R3G3B2; | |
110 case SDL_PixelFormat_RGB444: | |
111 return GLFMT_X4R4G4B4; | |
112 case SDL_PixelFormat_RGB555: | |
113 return GLFMT_X1R5G5B5; | |
114 case SDL_PixelFormat_ARGB4444: | |
115 return GLFMT_A4R4G4B4; | |
116 case SDL_PixelFormat_ARGB1555: | |
117 return GLFMT_A1R5G5B5; | |
118 case SDL_PixelFormat_RGB565: | |
119 return GLFMT_R5G6B5; | |
120 case SDL_PixelFormat_RGB888: | |
121 return GLFMT_X8R8G8B8; | |
122 case SDL_PixelFormat_ARGB8888: | |
123 return GLFMT_A8R8G8B8; | |
124 case SDL_PixelFormat_ARGB2101010: | |
125 return GLFMT_A2R10G10B10; | |
126 case SDL_PixelFormat_UYVY: | |
127 return GLFMT_UYVY; | |
128 case SDL_PixelFormat_YUY2: | |
129 return GLFMT_YUY2; | |
130 default: | |
131 return GLFMT_UNKNOWN; | |
132 } | |
133 } | |
134 | |
135 void | |
136 GL_AddRenderDriver(_THIS) | |
137 { | |
138 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; | |
139 | |
140 if (data->d3d) { | |
141 SDL_AddRenderDriver(0, &GL_RenderDriver); | |
142 } | |
143 } | |
144 | |
145 SDL_Renderer * | |
146 GL_CreateRenderer(SDL_Window * window, Uint32 flags) | |
147 { | |
148 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); | |
149 SDL_VideoData *videodata = (SDL_VideoData *) display->device->driverdata; | |
150 SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata; | |
151 SDL_Renderer *renderer; | |
152 GL_RenderData *data; | |
153 HRESULT result; | |
154 GLPRESENT_PARAMETERS pparams; | |
155 IDirect3DSwapChain9 *chain; | |
156 | |
157 if (!(window->flags & SDL_WINDOW_OPENGL)) { | |
158 SDL_SetError | |
159 ("The OpenGL renderer can only be used on OpenGL windows"); | |
160 return NULL; | |
161 } | |
162 | |
163 renderer = (SDL_Renderer *) SDL_malloc(sizeof(*renderer)); | |
164 if (!renderer) { | |
165 SDL_OutOfMemory(); | |
166 return NULL; | |
167 } | |
168 SDL_zerop(renderer); | |
169 | |
170 data = (GL_RenderData *) SDL_malloc(sizeof(*data)); | |
171 if (!data) { | |
172 GL_DestroyRenderer(renderer); | |
173 SDL_OutOfMemory(); | |
174 return NULL; | |
175 } | |
176 SDL_zerop(data); | |
177 | |
178 renderer->CreateTexture = GL_CreateTexture; | |
179 renderer->SetTexturePalette = GL_SetTexturePalette; | |
180 renderer->GetTexturePalette = GL_GetTexturePalette; | |
181 renderer->UpdateTexture = GL_UpdateTexture; | |
182 renderer->LockTexture = GL_LockTexture; | |
183 renderer->UnlockTexture = GL_UnlockTexture; | |
184 renderer->DirtyTexture = GL_DirtyTexture; | |
185 renderer->RenderFill = GL_RenderFill; | |
186 renderer->RenderCopy = GL_RenderCopy; | |
187 renderer->RenderPresent = GL_RenderPresent; | |
188 renderer->DestroyTexture = GL_DestroyTexture; | |
189 renderer->DestroyRenderer = GL_DestroyRenderer; | |
190 renderer->info = GL_RenderDriver.info; | |
191 renderer->window = window->id; | |
192 renderer->driverdata = data; | |
193 | |
194 renderer->info.flags = | |
195 (SDL_Renderer_PresentDiscard | SDL_Renderer_Accelerated); | |
196 | |
197 data->context = SDL_GL_CreateContext(window->id); | |
198 if (!data->context) { | |
199 GL_DestroyRenderer(renderer); | |
200 return NULL; | |
201 } | |
202 if (SDL_GL_MakeCurrent(window->id, data->context) < 0) { | |
203 GL_DestroyRenderer(renderer); | |
204 return NULL; | |
205 } | |
206 data->beginScene = SDL_TRUE; | |
207 | |
208 if (flags & SDL_Renderer_PresentVSync) { | |
209 SDL_GL_SetSwapInterval(1); | |
210 } else { | |
211 SDL_GL_SetSwapInterval(0); | |
212 } | |
213 if (SDL_GL_GetSwapInterval() > 0) { | |
214 renderer->info.flags |= SDL_Renderer_PresentVSync; | |
215 } | |
216 | |
217 /* Set up parameters for rendering */ | |
218 glDisable(GL_DEPTH_TEST); | |
219 glDisable(GL_CULL_FACE); | |
220 glEnable(GL_TEXTURE_2D); | |
221 glMatrixMode(GL_PROJECTION); | |
222 glLoadIdentity(); | |
223 glMatrixMode(GL_MODELVIEW); | |
224 glLoadIdentity(); | |
225 glViewport(0, 0, window->w, window->h); | |
226 glOrtho(0.0, (GLdouble) window->w, (GLdouble) window->h, 0.0, 0.0, 1.0); | |
227 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); | |
228 | |
229 return renderer; | |
230 } | |
231 | |
232 /* Quick utility function for texture creation */ | |
233 static int | |
234 power_of_two(int input) | |
235 { | |
236 int value = 1; | |
237 | |
238 while (value < input) { | |
239 value <<= 1; | |
240 } | |
241 return value; | |
242 } | |
243 | |
244 static int | |
245 GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) | |
246 { | |
247 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; | |
248 SDL_Window *window = SDL_GetWindowFromID(renderer->window); | |
249 SDL_VideoDisplay *display = SDL_GetDisplayFromWindow(window); | |
250 GL_TextureData *data; | |
251 GLPOOL pool; | |
252 HRESULT result; | |
253 | |
254 data = (GL_TextureData *) SDL_malloc(sizeof(*data)); | |
255 if (!data) { | |
256 SDL_OutOfMemory(); | |
257 return -1; | |
258 } | |
259 SDL_zerop(data); | |
260 | |
261 texture->driverdata = data; | |
262 | |
263 if (texture->access == SDL_TextureAccess_Local) { | |
264 pool = GLPOOL_MANAGED; | |
265 } else { | |
266 pool = GLPOOL_DEFAULT; | |
267 } | |
268 result = | |
269 IDirect3DDevice9_CreateTexture(renderdata->device, texture->w, | |
270 texture->h, 1, 0, | |
271 PixelFormatToGLFMT(texture->format), | |
272 pool, &data->texture, NULL); | |
273 if (FAILED(result)) { | |
274 SDL_free(data); | |
275 GL_SetError("CreateTexture()", result); | |
276 return -1; | |
277 } | |
278 | |
279 return 0; | |
280 } | |
281 | |
282 static int | |
283 GL_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, | |
284 const SDL_Color * colors, int firstcolor, int ncolors) | |
285 { | |
286 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; | |
287 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
288 | |
289 return 0; | |
290 } | |
291 | |
292 static int | |
293 GL_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, | |
294 SDL_Color * colors, int firstcolor, int ncolors) | |
295 { | |
296 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
297 | |
298 return 0; | |
299 } | |
300 | |
301 static int | |
302 GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
303 const SDL_Rect * rect, const void *pixels, int pitch) | |
304 { | |
305 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
306 GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; | |
307 IDirect3DTexture9 *temp; | |
308 RECT d3drect; | |
309 GLLOCKED_RECT locked; | |
310 const Uint8 *src; | |
311 Uint8 *dst; | |
312 int row, length; | |
313 HRESULT result; | |
314 | |
315 result = | |
316 IDirect3DDevice9_CreateTexture(renderdata->device, texture->w, | |
317 texture->h, 1, 0, | |
318 PixelFormatToGLFMT(texture->format), | |
319 GLPOOL_SYSTEMMEM, &temp, NULL); | |
320 if (FAILED(result)) { | |
321 GL_SetError("CreateTexture()", result); | |
322 return -1; | |
323 } | |
324 | |
325 d3drect.left = rect->x; | |
326 d3drect.right = rect->x + rect->w; | |
327 d3drect.top = rect->y; | |
328 d3drect.bottom = rect->y + rect->h; | |
329 | |
330 result = IDirect3DTexture9_LockRect(temp, 0, &locked, &d3drect, 0); | |
331 if (FAILED(result)) { | |
332 IDirect3DTexture9_Release(temp); | |
333 GL_SetError("LockRect()", result); | |
334 return -1; | |
335 } | |
336 | |
337 src = pixels; | |
338 dst = locked.pBits; | |
339 length = rect->w * SDL_BYTESPERPIXEL(texture->format); | |
340 for (row = 0; row < rect->h; ++row) { | |
341 SDL_memcpy(dst, src, length); | |
342 src += pitch; | |
343 dst += locked.Pitch; | |
344 } | |
345 IDirect3DTexture9_UnlockRect(temp, 0); | |
346 | |
347 result = | |
348 IDirect3DDevice9_UpdateTexture(renderdata->device, | |
349 (IDirect3DBaseTexture9 *) temp, | |
350 (IDirect3DBaseTexture9 *) data-> | |
351 texture); | |
352 IDirect3DTexture9_Release(temp); | |
353 if (FAILED(result)) { | |
354 GL_SetError("UpdateTexture()", result); | |
355 return -1; | |
356 } | |
357 return 0; | |
358 } | |
359 | |
360 static int | |
361 GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, | |
362 const SDL_Rect * rect, int markDirty, void **pixels, | |
363 int *pitch) | |
364 { | |
365 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
366 RECT d3drect; | |
367 GLLOCKED_RECT locked; | |
368 HRESULT result; | |
369 | |
370 if (texture->access != SDL_TextureAccess_Local) { | |
371 SDL_SetError("Can't lock remote video memory"); | |
372 return -1; | |
373 } | |
374 | |
375 d3drect.left = rect->x; | |
376 d3drect.right = rect->x + rect->w; | |
377 d3drect.top = rect->y; | |
378 d3drect.bottom = rect->y + rect->h; | |
379 | |
380 result = | |
381 IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, | |
382 markDirty ? 0 : GLLOCK_NO_DIRTY_UPDATE); | |
383 if (FAILED(result)) { | |
384 GL_SetError("LockRect()", result); | |
385 return -1; | |
386 } | |
387 *pixels = locked.pBits; | |
388 *pitch = locked.Pitch; | |
389 return 0; | |
390 } | |
391 | |
392 static void | |
393 GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) | |
394 { | |
395 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
396 | |
397 IDirect3DTexture9_UnlockRect(data->texture, 0); | |
398 } | |
399 | |
400 static void | |
401 GL_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects, | |
402 const SDL_Rect * rects) | |
403 { | |
404 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
405 RECT d3drect; | |
406 int i; | |
407 | |
408 for (i = 0; i < numrects; ++i) { | |
409 const SDL_Rect *rect = &rects[i]; | |
410 | |
411 d3drect.left = rect->x; | |
412 d3drect.right = rect->x + rect->w; | |
413 d3drect.top = rect->y; | |
414 d3drect.bottom = rect->y + rect->h; | |
415 | |
416 IDirect3DTexture9_AddDirtyRect(data->texture, &d3drect); | |
417 } | |
418 } | |
419 | |
420 static int | |
421 GL_RenderFill(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 color) | |
422 { | |
423 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
424 SDL_Window *window = SDL_GetWindowFromID(renderer->window); | |
425 GLclampf r, g, b, a; | |
426 | |
427 a = ((GLclampf) ((color >> 24) & 0xFF)) / 255.0f; | |
428 r = ((GLclampf) ((color >> 16) & 0xFF)) / 255.0f; | |
429 g = ((GLclampf) ((color >> 8) & 0xFF)) / 255.0f; | |
430 b = ((GLclampf) (color & 0xFF)) / 255.0f; | |
431 | |
432 glClearColor(r, g, b, a); | |
433 glViewport(rect->x, window->h - rect->y, rect->w, rect->h); | |
434 glClear(GL_COLOR_BUFFER_BIT); | |
435 glViewport(0, 0, window->w, window->h); | |
436 return 0; | |
437 } | |
438 | |
439 static int | |
440 GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, | |
441 const SDL_Rect * srcrect, const SDL_Rect * dstrect, | |
442 int blendMode, int scaleMode) | |
443 { | |
444 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
445 GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata; | |
446 int minx, miny, maxx, maxy; | |
447 GLfloat minu, maxu, minv, maxv; | |
448 | |
449 minx = dstrect->x; | |
450 miny = dstrect->y; | |
451 maxx = dstrect->x + dstrect->w; | |
452 maxy = dstrect->y + dstrect->h; | |
453 | |
454 minu = (GLfloat) srcrect->x / texture->w; | |
455 maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; | |
456 minv = (GLfloat) srcrect->y / texture->h; | |
457 maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h; | |
458 | |
459 glBindTexture(GL_TEXTURE_2D, texturedata->texture); | |
460 | |
461 switch (blendMode) { | |
462 case SDL_TextureBlendMode_None: | |
463 glDisable(GL_BLEND); | |
464 break; | |
465 case SDL_TextureBlendMode_Mask: | |
466 case SDL_TextureBlendMode_Blend: | |
467 glEnable(GL_BLEND); | |
468 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
469 break; | |
470 case SDL_TextureBlendMode_Add: | |
471 glEnable(GL_BLEND); | |
472 glBlendFunc(GL_SRC_ALPHA, GL_ONE); | |
473 break; | |
474 case SDL_TextureBlendMode_Mod: | |
475 glEnable(GL_BLEND); | |
476 glBlendFunc(GL_ZERO, GL_SRC_COLOR); | |
477 break; | |
478 } | |
479 | |
480 switch (scaleMode) { | |
481 case SDL_TextureScaleMode_None: | |
482 case SDL_TextureScaleMode_Fast: | |
483 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
484 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
485 break; | |
486 case SDL_TextureScaleMode_Slow: | |
487 case SDL_TextureScaleMode_Best: | |
488 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
489 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
490 break; | |
491 } | |
492 | |
493 glBegin(GL_TRIANGLE_STRIP); | |
494 glTexCoord2f(minu, minv); | |
495 glVertex2i(minx, miny); | |
496 glTexCoord2f(maxu, minv); | |
497 glVertex2i(maxx, miny); | |
498 glTexCoord2f(minu, maxv); | |
499 glVertex2i(miny, maxy); | |
500 glTexCoord2f(maxu, maxv); | |
501 glVertex2i(maxx, maxy); | |
502 glEnd(); | |
503 | |
504 return 0; | |
505 } | |
506 | |
507 static void | |
508 GL_RenderPresent(SDL_Renderer * renderer) | |
509 { | |
510 SDL_GL_SwapWindow(renderer->window); | |
511 } | |
512 | |
513 static void | |
514 GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) | |
515 { | |
516 GL_TextureData *data = (GL_TextureData *) texture->driverdata; | |
517 | |
518 if (!data) { | |
519 return; | |
520 } | |
521 if (data->texture) { | |
522 IDirect3DTexture9_Release(data->texture); | |
523 } | |
524 SDL_free(data); | |
525 texture->driverdata = NULL; | |
526 } | |
527 | |
528 void | |
529 GL_DestroyRenderer(SDL_Renderer * renderer) | |
530 { | |
531 GL_RenderData *data = (GL_RenderData *) renderer->driverdata; | |
532 | |
533 if (data) { | |
534 if (data->device) { | |
535 IDirect3DDevice9_Release(data->device); | |
536 } | |
537 SDL_free(data); | |
538 } | |
539 SDL_free(renderer); | |
540 } | |
541 | |
542 #endif /* SDL_VIDEO_OPENGL */ | |
543 | |
544 /* vi: set ts=4 sw=4 expandtab: */ |