comparison src/video/windows/SDL_gdirender.c @ 5062:e8916fe9cfc8

Fixed bug #925 Changed "win32" to "windows"
author Sam Lantinga <slouken@libsdl.org>
date Thu, 20 Jan 2011 18:04:05 -0800
parents src/video/win32/SDL_gdirender.c@aa8888658021
children c2539ff054c8
comparison
equal deleted inserted replaced
5061:9e9940eae455 5062:e8916fe9cfc8
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2010 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_RENDER_GDI
25
26 #include "SDL_windowsvideo.h"
27 #include "../SDL_rect_c.h"
28 #include "../SDL_yuv_sw_c.h"
29 #include "../SDL_alphamult.h"
30
31 #ifdef _WIN32_WCE
32 #define NO_GETDIBBITS 1
33 #endif
34
35 /* GDI renderer implementation */
36
37 static SDL_Renderer *GDI_CreateRenderer(SDL_Window * window, Uint32 flags);
38 static int GDI_DisplayModeChanged(SDL_Renderer * renderer);
39 static int GDI_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
40 static int GDI_QueryTexturePixels(SDL_Renderer * renderer,
41 SDL_Texture * texture, void **pixels,
42 int *pitch);
43 static int GDI_SetTexturePalette(SDL_Renderer * renderer,
44 SDL_Texture * texture,
45 const SDL_Color * colors, int firstcolor,
46 int ncolors);
47 static int GDI_GetTexturePalette(SDL_Renderer * renderer,
48 SDL_Texture * texture, SDL_Color * colors,
49 int firstcolor, int ncolors);
50 static int GDI_SetTextureAlphaMod(SDL_Renderer * renderer,
51 SDL_Texture * texture);
52 static int GDI_SetTextureBlendMode(SDL_Renderer * renderer,
53 SDL_Texture * texture);
54 static int GDI_SetTextureScaleMode(SDL_Renderer * renderer,
55 SDL_Texture * texture);
56 static int GDI_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
57 const SDL_Rect * rect, const void *pixels,
58 int pitch);
59 static int GDI_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
60 const SDL_Rect * rect, int markDirty,
61 void **pixels, int *pitch);
62 static void GDI_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
63 static int GDI_SetDrawBlendMode(SDL_Renderer * renderer);
64 static int GDI_RenderDrawPoints(SDL_Renderer * renderer,
65 const SDL_Point * points, int count);
66 static int GDI_RenderDrawLines(SDL_Renderer * renderer,
67 const SDL_Point * points, int count);
68 static int GDI_RenderDrawRects(SDL_Renderer * renderer,
69 const SDL_Rect ** rects, int count);
70 static int GDI_RenderFillRects(SDL_Renderer * renderer,
71 const SDL_Rect ** rects, int count);
72 static int GDI_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
73 const SDL_Rect * srcrect, const SDL_Rect * dstrect);
74 static int GDI_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
75 Uint32 format, void * pixels, int pitch);
76 static int GDI_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
77 Uint32 format, const void * pixels, int pitch);
78 static void GDI_RenderPresent(SDL_Renderer * renderer);
79 static void GDI_DestroyTexture(SDL_Renderer * renderer,
80 SDL_Texture * texture);
81 static void GDI_DestroyRenderer(SDL_Renderer * renderer);
82
83
84 SDL_RenderDriver GDI_RenderDriver = {
85 GDI_CreateRenderer,
86 {
87 "gdi",
88 (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY |
89 SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 |
90 SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_ACCELERATED),
91 (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_ALPHA),
92 (SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK),
93 (SDL_SCALEMODE_NONE | SDL_SCALEMODE_FAST),
94 14,
95 {
96 SDL_PIXELFORMAT_INDEX8,
97 SDL_PIXELFORMAT_RGB555,
98 SDL_PIXELFORMAT_RGB565,
99 SDL_PIXELFORMAT_RGB888,
100 SDL_PIXELFORMAT_BGR888,
101 SDL_PIXELFORMAT_ARGB8888,
102 SDL_PIXELFORMAT_RGBA8888,
103 SDL_PIXELFORMAT_ABGR8888,
104 SDL_PIXELFORMAT_BGRA8888,
105 SDL_PIXELFORMAT_YV12,
106 SDL_PIXELFORMAT_IYUV,
107 SDL_PIXELFORMAT_YUY2,
108 SDL_PIXELFORMAT_UYVY,
109 SDL_PIXELFORMAT_YVYU},
110 0,
111 0}
112 };
113
114 typedef struct
115 {
116 HWND hwnd;
117 HDC window_hdc;
118 HDC render_hdc;
119 HDC memory_hdc;
120 HDC current_hdc;
121 #ifndef NO_GETDIBBITS
122 LPBITMAPINFO bmi;
123 #endif
124 HBITMAP hbm[3];
125 int current_hbm;
126 SDL_DirtyRectList dirty;
127 SDL_bool makedirty;
128 } GDI_RenderData;
129
130 typedef struct
131 {
132 SDL_SW_YUVTexture *yuv;
133 Uint32 format;
134 HPALETTE hpal;
135 HBITMAP hbm;
136 void *pixels;
137 int pitch;
138 SDL_bool premultiplied;
139 } GDI_TextureData;
140
141 static void
142 UpdateYUVTextureData(SDL_Texture * texture)
143 {
144 GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
145 SDL_Rect rect;
146
147 rect.x = 0;
148 rect.y = 0;
149 rect.w = texture->w;
150 rect.h = texture->h;
151 SDL_SW_CopyYUVToRGB(data->yuv, &rect, data->format, texture->w,
152 texture->h, data->pixels, data->pitch);
153 }
154
155 void
156 GDI_AddRenderDriver(_THIS)
157 {
158 int i;
159 for (i = 0; i < _this->num_displays; ++i) {
160 SDL_AddRenderDriver(&_this->displays[i], &GDI_RenderDriver);
161 }
162 }
163
164 SDL_Renderer *
165 GDI_CreateRenderer(SDL_Window * window, Uint32 flags)
166 {
167 SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata;
168 SDL_Renderer *renderer;
169 GDI_RenderData *data;
170 int bmi_size;
171 HBITMAP hbm;
172 int i, n;
173
174 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
175 if (!renderer) {
176 SDL_OutOfMemory();
177 return NULL;
178 }
179
180 data = (GDI_RenderData *) SDL_calloc(1, sizeof(*data));
181 if (!data) {
182 GDI_DestroyRenderer(renderer);
183 SDL_OutOfMemory();
184 return NULL;
185 }
186
187 windowdata->videodata->render = RENDER_GDI;
188
189 renderer->DisplayModeChanged = GDI_DisplayModeChanged;
190 renderer->CreateTexture = GDI_CreateTexture;
191 renderer->QueryTexturePixels = GDI_QueryTexturePixels;
192 renderer->SetTexturePalette = GDI_SetTexturePalette;
193 renderer->GetTexturePalette = GDI_GetTexturePalette;
194 renderer->SetTextureAlphaMod = GDI_SetTextureAlphaMod;
195 renderer->SetTextureBlendMode = GDI_SetTextureBlendMode;
196 renderer->SetTextureScaleMode = GDI_SetTextureScaleMode;
197 renderer->UpdateTexture = GDI_UpdateTexture;
198 renderer->LockTexture = GDI_LockTexture;
199 renderer->UnlockTexture = GDI_UnlockTexture;
200 renderer->SetDrawBlendMode = GDI_SetDrawBlendMode;
201 renderer->RenderDrawPoints = GDI_RenderDrawPoints;
202 renderer->RenderDrawLines = GDI_RenderDrawLines;
203 renderer->RenderDrawRects = GDI_RenderDrawRects;
204 renderer->RenderFillRects = GDI_RenderFillRects;
205 renderer->RenderCopy = GDI_RenderCopy;
206 renderer->RenderReadPixels = GDI_RenderReadPixels;
207 renderer->RenderWritePixels = GDI_RenderWritePixels;
208 renderer->RenderPresent = GDI_RenderPresent;
209 renderer->DestroyTexture = GDI_DestroyTexture;
210 renderer->DestroyRenderer = GDI_DestroyRenderer;
211 renderer->info = GDI_RenderDriver.info;
212 renderer->window = window;
213 renderer->driverdata = data;
214
215 renderer->info.flags = SDL_RENDERER_ACCELERATED;
216
217 data->hwnd = windowdata->hwnd;
218 data->window_hdc = windowdata->hdc;
219 data->render_hdc = CreateCompatibleDC(data->window_hdc);
220 data->memory_hdc = CreateCompatibleDC(data->window_hdc);
221
222 #ifndef NO_GETDIBBITS
223 /* Fill in the compatible bitmap info */
224 bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
225 data->bmi = (LPBITMAPINFO) SDL_calloc(1, bmi_size);
226 if (!data->bmi) {
227 GDI_DestroyRenderer(renderer);
228 SDL_OutOfMemory();
229 return NULL;
230 }
231 data->bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
232
233 hbm = CreateCompatibleBitmap(data->window_hdc, 1, 1);
234 GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
235 GetDIBits(data->window_hdc, hbm, 0, 1, NULL, data->bmi, DIB_RGB_COLORS);
236 DeleteObject(hbm);
237 #endif
238
239 if (flags & SDL_RENDERER_SINGLEBUFFER) {
240 renderer->info.flags |=
241 (SDL_RENDERER_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY);
242 n = 0;
243 } else if (flags & SDL_RENDERER_PRESENTFLIP2) {
244 renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2;
245 n = 2;
246 } else if (flags & SDL_RENDERER_PRESENTFLIP3) {
247 renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3;
248 n = 3;
249 } else {
250 renderer->info.flags |= SDL_RENDERER_PRESENTCOPY;
251 n = 1;
252 }
253 for (i = 0; i < n; ++i) {
254 data->hbm[i] =
255 CreateCompatibleBitmap(data->window_hdc, window->w, window->h);
256 if (!data->hbm[i]) {
257 GDI_DestroyRenderer(renderer);
258 WIN_SetError("CreateCompatibleBitmap()");
259 return NULL;
260 }
261 }
262 if (n > 0) {
263 SelectObject(data->render_hdc, data->hbm[0]);
264 data->current_hdc = data->render_hdc;
265 data->makedirty = SDL_TRUE;
266 } else {
267 data->current_hdc = data->window_hdc;
268 data->makedirty = SDL_FALSE;
269 }
270 data->current_hbm = 0;
271
272 #ifdef _WIN32_WCE
273 // check size for GDI fullscreen and rotate
274 if((window->flags & SDL_WINDOW_FULLSCREEN) &&
275 GetSystemMetrics(SM_CXSCREEN) != GetSystemMetrics(SM_CYSCREEN) &&
276 ((GetSystemMetrics(SM_CXSCREEN) < GetSystemMetrics(SM_CYSCREEN) && window->w > window->h) ||
277 (GetSystemMetrics(SM_CXSCREEN) > GetSystemMetrics(SM_CYSCREEN) && window->w < window->h)))
278 {
279 int orientation = WINCE_GetDMOrientation();
280 switch(orientation)
281 {
282 case DMDO_0: orientation = DMDO_90; break;
283 case DMDO_270: orientation = DMDO_180; break;
284 case DMDO_90: orientation = DMDO_0; break;
285 case DMDO_180: orientation = DMDO_270; break;
286
287 default:
288 GDI_DestroyRenderer(renderer);
289 return NULL;
290 }
291
292 if(0 > WINCE_SetDMOrientation(orientation))
293 {
294 GDI_DestroyRenderer(renderer);
295 return NULL;
296 }
297 }
298 #endif
299
300 return renderer;
301 }
302
303 static int
304 GDI_DisplayModeChanged(SDL_Renderer * renderer)
305 {
306 GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
307 SDL_Window *window = renderer->window;
308 int i, n;
309
310 if (renderer->info.flags & SDL_RENDERER_SINGLEBUFFER) {
311 n = 0;
312 } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
313 n = 2;
314 } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
315 n = 3;
316 } else {
317 n = 1;
318 }
319 for (i = 0; i < n; ++i) {
320 if (data->hbm[i]) {
321 DeleteObject(data->hbm[i]);
322 data->hbm[i] = NULL;
323 }
324 }
325 for (i = 0; i < n; ++i) {
326 data->hbm[i] =
327 CreateCompatibleBitmap(data->window_hdc, window->w, window->h);
328 if (!data->hbm[i]) {
329 WIN_SetError("CreateCompatibleBitmap()");
330 return -1;
331 }
332 }
333 if (n > 0) {
334 SelectObject(data->render_hdc, data->hbm[0]);
335 }
336 data->current_hbm = 0;
337
338 return 0;
339 }
340
341 static HBITMAP
342 GDI_CreateDIBSection(HDC hdc, int w, int h, int pitch, Uint32 format,
343 HPALETTE * hpal, void ** pixels)
344 {
345 int bmi_size;
346 LPBITMAPINFO bmi;
347
348 bmi_size = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
349 bmi = (LPBITMAPINFO) SDL_calloc(1, bmi_size);
350 if (!bmi) {
351 SDL_OutOfMemory();
352 return NULL;
353 }
354 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
355 bmi->bmiHeader.biWidth = w;
356 bmi->bmiHeader.biHeight = -h; /* topdown bitmap */
357 bmi->bmiHeader.biPlanes = 1;
358 bmi->bmiHeader.biSizeImage = h * pitch;
359 bmi->bmiHeader.biXPelsPerMeter = 0;
360 bmi->bmiHeader.biYPelsPerMeter = 0;
361 bmi->bmiHeader.biClrUsed = 0;
362 bmi->bmiHeader.biClrImportant = 0;
363 bmi->bmiHeader.biBitCount = SDL_BYTESPERPIXEL(format) * 8;
364 if (SDL_ISPIXELFORMAT_INDEXED(format)) {
365 bmi->bmiHeader.biCompression = BI_RGB;
366 if (hpal) {
367 int i, ncolors;
368 LOGPALETTE *palette;
369
370 ncolors = (1 << SDL_BITSPERPIXEL(format));
371 palette =
372 (LOGPALETTE *) SDL_malloc(sizeof(*palette) +
373 ncolors * sizeof(PALETTEENTRY));
374 if (!palette) {
375 SDL_free(bmi);
376 SDL_OutOfMemory();
377 return NULL;
378 }
379 palette->palVersion = 0x300;
380 palette->palNumEntries = ncolors;
381 for (i = 0; i < ncolors; ++i) {
382 palette->palPalEntry[i].peRed = 0xFF;
383 palette->palPalEntry[i].peGreen = 0xFF;
384 palette->palPalEntry[i].peBlue = 0xFF;
385 palette->palPalEntry[i].peFlags = 0;
386 }
387 *hpal = CreatePalette(palette);
388 SDL_free(palette);
389 }
390 } else {
391 int bpp;
392 Uint32 Rmask, Gmask, Bmask, Amask;
393
394 bmi->bmiHeader.biCompression = BI_BITFIELDS;
395 SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask,
396 &Amask);
397 ((Uint32 *) bmi->bmiColors)[0] = Rmask;
398 ((Uint32 *) bmi->bmiColors)[1] = Gmask;
399 ((Uint32 *) bmi->bmiColors)[2] = Bmask;
400 if (hpal) {
401 *hpal = NULL;
402 }
403 }
404 return CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, pixels, NULL, 0);
405 }
406
407 static int
408 GDI_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
409 {
410 GDI_RenderData *renderdata = (GDI_RenderData *) renderer->driverdata;
411 SDL_Window *window = renderer->window;
412 SDL_VideoDisplay *display = window->display;
413 GDI_TextureData *data;
414
415 data = (GDI_TextureData *) SDL_calloc(1, sizeof(*data));
416 if (!data) {
417 SDL_OutOfMemory();
418 return -1;
419 }
420
421 texture->driverdata = data;
422
423 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) {
424 data->yuv =
425 SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h);
426 if (!data->yuv) {
427 return -1;
428 }
429 data->format = display->current_mode.format;
430 } else {
431 data->format = texture->format;
432 }
433 data->pitch = (texture->w * SDL_BYTESPERPIXEL(data->format));
434
435 if (data->yuv || texture->access == SDL_TEXTUREACCESS_STREAMING
436 || texture->format != display->current_mode.format) {
437 data->hbm = GDI_CreateDIBSection(renderdata->memory_hdc,
438 texture->w, texture->h,
439 data->pitch, data->format,
440 &data->hpal, &data->pixels);
441 } else {
442 data->hbm = CreateCompatibleBitmap(renderdata->window_hdc,
443 texture->w, texture->h);
444 }
445 if (!data->hbm) {
446 WIN_SetError("Couldn't create bitmap");
447 return -1;
448 }
449
450 return 0;
451 }
452
453 static int
454 GDI_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture,
455 void **pixels, int *pitch)
456 {
457 GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
458
459 if (data->yuv) {
460 return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch);
461 } else {
462 *pixels = data->pixels;
463 *pitch = data->pitch;
464 return 0;
465 }
466 }
467
468 static int
469 GDI_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
470 const SDL_Color * colors, int firstcolor, int ncolors)
471 {
472 GDI_RenderData *renderdata = (GDI_RenderData *) renderer->driverdata;
473 GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
474
475 if (data->yuv) {
476 SDL_SetError("YUV textures don't have a palette");
477 return -1;
478 } else {
479 PALETTEENTRY entries[256];
480 int i;
481
482 for (i = 0; i < ncolors; ++i) {
483 entries[i].peRed = colors[i].r;
484 entries[i].peGreen = colors[i].g;
485 entries[i].peBlue = colors[i].b;
486 entries[i].peFlags = 0;
487 }
488 if (!SetPaletteEntries(data->hpal, firstcolor, ncolors, entries)) {
489 WIN_SetError("SetPaletteEntries()");
490 return -1;
491 }
492 return 0;
493 }
494 }
495
496 static int
497 GDI_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture,
498 SDL_Color * colors, int firstcolor, int ncolors)
499 {
500 GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
501
502 if (data->yuv) {
503 SDL_SetError("YUV textures don't have a palette");
504 return -1;
505 } else {
506 PALETTEENTRY entries[256];
507 int i;
508
509 if (!GetPaletteEntries(data->hpal, firstcolor, ncolors, entries)) {
510 WIN_SetError("GetPaletteEntries()");
511 return -1;
512 }
513 for (i = 0; i < ncolors; ++i) {
514 colors[i].r = entries[i].peRed;
515 colors[i].g = entries[i].peGreen;
516 colors[i].b = entries[i].peBlue;
517 }
518 return 0;
519 }
520 }
521
522 static int
523 GDI_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture)
524 {
525 return 0;
526 }
527
528 static int
529 GDI_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture)
530 {
531 GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
532
533 switch (texture->blendMode) {
534 case SDL_BLENDMODE_NONE:
535 if (data->premultiplied) {
536 /* Crap, we've lost the original pixel data... *sigh* */
537 }
538 return 0;
539 #ifndef _WIN32_WCE /* WinCE has no alphablend */
540 case SDL_BLENDMODE_MASK:
541 case SDL_BLENDMODE_BLEND:
542 if (!data->premultiplied && data->pixels) {
543 switch (texture->format) {
544 case SDL_PIXELFORMAT_ARGB8888:
545 SDL_PreMultiplyAlphaARGB8888(texture->w, texture->h,
546 (Uint32 *) data->pixels,
547 data->pitch);
548 data->premultiplied = SDL_TRUE;
549 break;
550 case SDL_PIXELFORMAT_RGBA8888:
551 SDL_PreMultiplyAlphaRGBA8888(texture->w, texture->h,
552 (Uint32 *) data->pixels,
553 data->pitch);
554 data->premultiplied = SDL_TRUE;
555 break;
556 case SDL_PIXELFORMAT_ABGR8888:
557 SDL_PreMultiplyAlphaABGR8888(texture->w, texture->h,
558 (Uint32 *) data->pixels,
559 data->pitch);
560 data->premultiplied = SDL_TRUE;
561 break;
562 case SDL_PIXELFORMAT_BGRA8888:
563 SDL_PreMultiplyAlphaBGRA8888(texture->w, texture->h,
564 (Uint32 *) data->pixels,
565 data->pitch);
566 data->premultiplied = SDL_TRUE;
567 break;
568 }
569 }
570 return 0;
571 #endif
572 default:
573 SDL_Unsupported();
574 texture->blendMode = SDL_BLENDMODE_NONE;
575 return -1;
576 }
577 }
578
579 static int
580 GDI_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture)
581 {
582 switch (texture->scaleMode) {
583 case SDL_SCALEMODE_NONE:
584 case SDL_SCALEMODE_FAST:
585 return 0;
586 case SDL_SCALEMODE_SLOW:
587 case SDL_SCALEMODE_BEST:
588 SDL_Unsupported();
589 texture->scaleMode = SDL_SCALEMODE_FAST;
590 return -1;
591 default:
592 SDL_Unsupported();
593 texture->scaleMode = SDL_SCALEMODE_NONE;
594 return -1;
595 }
596 return 0;
597 }
598
599 static int
600 GDI_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
601 const SDL_Rect * rect, const void *pixels, int pitch)
602 {
603 GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
604
605 if (data->yuv) {
606 if (SDL_SW_UpdateYUVTexture(data->yuv, rect, pixels, pitch) < 0) {
607 return -1;
608 }
609 UpdateYUVTextureData(texture);
610 return 0;
611 } else {
612 GDI_RenderData *renderdata = (GDI_RenderData *) renderer->driverdata;
613
614 if (data->pixels) {
615 Uint8 *src, *dst;
616 int row;
617 size_t length;
618
619 src = (Uint8 *) pixels;
620 dst =
621 (Uint8 *) data->pixels + rect->y * data->pitch +
622 rect->x * SDL_BYTESPERPIXEL(texture->format);
623 length = rect->w * SDL_BYTESPERPIXEL(texture->format);
624 for (row = 0; row < rect->h; ++row) {
625 SDL_memcpy(dst, src, length);
626 src += pitch;
627 dst += data->pitch;
628 }
629 if (data->premultiplied) {
630 Uint32 *pixels =
631 (Uint32 *) data->pixels + rect->y * (data->pitch / 4) +
632 rect->x;
633 switch (texture->format) {
634 case SDL_PIXELFORMAT_ARGB8888:
635 SDL_PreMultiplyAlphaARGB8888(rect->w, rect->h, pixels,
636 data->pitch);
637 break;
638 case SDL_PIXELFORMAT_RGBA8888:
639 SDL_PreMultiplyAlphaRGBA8888(rect->w, rect->h, pixels,
640 data->pitch);
641 break;
642 case SDL_PIXELFORMAT_ABGR8888:
643 SDL_PreMultiplyAlphaABGR8888(rect->w, rect->h, pixels,
644 data->pitch);
645 break;
646 case SDL_PIXELFORMAT_BGRA8888:
647 SDL_PreMultiplyAlphaBGRA8888(rect->w, rect->h, pixels,
648 data->pitch);
649 break;
650 }
651 }
652 } else if (rect->w == texture->w && pitch == data->pitch) {
653 #ifndef NO_GETDIBBITS
654 if (!SetDIBits
655 (renderdata->window_hdc, data->hbm, rect->y, rect->h, pixels,
656 renderdata->bmi, DIB_RGB_COLORS)) {
657 WIN_SetError("SetDIBits()");
658 return -1;
659 }
660 #else
661 SDL_SetError("FIXME: Update Texture");
662 return -1;
663 #endif
664 } else {
665 SDL_SetError
666 ("FIXME: Need to allocate temporary memory and do GetDIBits() followed by SetDIBits(), since we can only set blocks of scanlines at a time");
667 return -1;
668 }
669 return 0;
670 }
671 }
672
673 static int
674 GDI_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
675 const SDL_Rect * rect, int markDirty, void **pixels,
676 int *pitch)
677 {
678 GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
679
680 if (data->yuv) {
681 return SDL_SW_LockYUVTexture(data->yuv, rect, markDirty, pixels,
682 pitch);
683 } else if (data->pixels) {
684 #ifndef _WIN32_WCE
685 /* WinCE has no GdiFlush */
686 GdiFlush();
687 #endif
688 *pixels =
689 (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
690 rect->x * SDL_BYTESPERPIXEL(texture->format));
691 *pitch = data->pitch;
692 return 0;
693 } else {
694 SDL_SetError("No pixels available");
695 return -1;
696 }
697 }
698
699 static void
700 GDI_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
701 {
702 GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
703
704 if (data->yuv) {
705 SDL_SW_UnlockYUVTexture(data->yuv);
706 UpdateYUVTextureData(texture);
707 }
708 }
709
710 static int
711 GDI_SetDrawBlendMode(SDL_Renderer * renderer)
712 {
713 switch (renderer->blendMode) {
714 case SDL_BLENDMODE_NONE:
715 return 0;
716 default:
717 SDL_Unsupported();
718 renderer->blendMode = SDL_BLENDMODE_NONE;
719 return -1;
720 }
721 }
722
723 static int
724 GDI_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
725 int count)
726 {
727 GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
728 int i;
729 COLORREF color;
730
731 if (data->makedirty) {
732 /* Get the smallest rectangle that contains everything */
733 SDL_Window *window = renderer->window;
734 SDL_Rect rect;
735
736 rect.x = 0;
737 rect.y = 0;
738 rect.w = window->w;
739 rect.h = window->h;
740 if (!SDL_EnclosePoints(points, count, &rect, &rect)) {
741 /* Nothing to draw */
742 return 0;
743 }
744
745 SDL_AddDirtyRect(&data->dirty, &rect);
746 }
747
748 color = RGB(renderer->r, renderer->g, renderer->b);
749 for (i = 0; i < count; ++i) {
750 SetPixel(data->current_hdc, points[i].x, points[i].y, color);
751 }
752
753 return 0;
754 }
755
756 static int
757 GDI_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
758 int count)
759 {
760 GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
761 HPEN pen;
762 BOOL status;
763
764 if (data->makedirty) {
765 /* Get the smallest rectangle that contains everything */
766 SDL_Window *window = renderer->window;
767 SDL_Rect clip, rect;
768
769 clip.x = 0;
770 clip.y = 0;
771 clip.w = window->w;
772 clip.h = window->h;
773 SDL_EnclosePoints(points, count, NULL, &rect);
774 if (!SDL_IntersectRect(&rect, &clip, &rect)) {
775 /* Nothing to draw */
776 return 0;
777 }
778
779 SDL_AddDirtyRect(&data->dirty, &rect);
780 }
781
782 /* Should we cache the pen? .. it looks like GDI does for us. :) */
783 pen = CreatePen(PS_SOLID, 1, RGB(renderer->r, renderer->g, renderer->b));
784 SelectObject(data->current_hdc, pen);
785 {
786 LPPOINT p = SDL_stack_alloc(POINT, count);
787 int i;
788
789 for (i = 0; i < count; ++i) {
790 p[i].x = points[i].x;
791 p[i].y = points[i].y;
792 }
793 status = Polyline(data->current_hdc, p, count);
794 SDL_stack_free(p);
795 }
796 DeleteObject(pen);
797
798 /* Need to close the endpoint of the line */
799 if (points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
800 SetPixel(data->current_hdc, points[count-1].x, points[count-1].y,
801 RGB(renderer->r, renderer->g, renderer->b));
802 }
803
804 if (!status) {
805 WIN_SetError("Polyline()");
806 return -1;
807 }
808 return 0;
809 }
810
811 static int
812 GDI_RenderDrawRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
813 int count)
814 {
815 GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
816 HPEN pen;
817 POINT vertices[5];
818 int i, status = 1;
819
820 if (data->makedirty) {
821 SDL_Window *window = renderer->window;
822 SDL_Rect clip, rect;
823
824 clip.x = 0;
825 clip.y = 0;
826 clip.w = window->w;
827 clip.h = window->h;
828
829 for (i = 0; i < count; ++i) {
830 if (SDL_IntersectRect(rects[i], &clip, &rect)) {
831 SDL_AddDirtyRect(&data->dirty, &rect);
832 }
833 }
834 }
835
836 /* Should we cache the pen? .. it looks like GDI does for us. :) */
837 pen = CreatePen(PS_SOLID, 1, RGB(renderer->r, renderer->g, renderer->b));
838 SelectObject(data->current_hdc, pen);
839 for (i = 0; i < count; ++i) {
840 const SDL_Rect *rect = rects[i];
841
842 vertices[0].x = rect->x;
843 vertices[0].y = rect->y;
844
845 vertices[1].x = rect->x+rect->w-1;
846 vertices[1].y = rect->y;
847
848 vertices[2].x = rect->x+rect->w-1;
849 vertices[2].y = rect->y+rect->h-1;
850
851 vertices[3].x = rect->x;
852 vertices[3].y = rect->y+rect->h-1;
853
854 vertices[4].x = rect->x;
855 vertices[4].y = rect->y;
856
857 status &= Polyline(data->current_hdc, vertices, 5);
858 }
859 DeleteObject(pen);
860
861 if (!status) {
862 WIN_SetError("Polyline()");
863 return -1;
864 }
865 return 0;
866 }
867
868 static int
869 GDI_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects,
870 int count)
871 {
872 GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
873 RECT rc;
874 HBRUSH brush;
875 int i, status = 1;
876
877 if (data->makedirty) {
878 SDL_Window *window = renderer->window;
879 SDL_Rect clip, rect;
880
881 clip.x = 0;
882 clip.y = 0;
883 clip.w = window->w;
884 clip.h = window->h;
885
886 for (i = 0; i < count; ++i) {
887 if (SDL_IntersectRect(rects[i], &clip, &rect)) {
888 SDL_AddDirtyRect(&data->dirty, &rect);
889 }
890 }
891 }
892
893 /* Should we cache the brushes? .. it looks like GDI does for us. :) */
894 brush = CreateSolidBrush(RGB(renderer->r, renderer->g, renderer->b));
895 SelectObject(data->current_hdc, brush);
896 for (i = 0; i < count; ++i) {
897 const SDL_Rect *rect = rects[i];
898
899 rc.left = rect->x;
900 rc.top = rect->y;
901 rc.right = rect->x + rect->w;
902 rc.bottom = rect->y + rect->h;
903
904 status &= FillRect(data->current_hdc, &rc, brush);
905 }
906 DeleteObject(brush);
907
908 if (!status) {
909 WIN_SetError("FillRect()");
910 return -1;
911 }
912 return 0;
913 }
914
915 static int
916 GDI_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
917 const SDL_Rect * srcrect, const SDL_Rect * dstrect)
918 {
919 GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
920 GDI_TextureData *texturedata = (GDI_TextureData *) texture->driverdata;
921
922 if (data->makedirty) {
923 SDL_AddDirtyRect(&data->dirty, dstrect);
924 }
925
926 SelectObject(data->memory_hdc, texturedata->hbm);
927 if (texturedata->hpal) {
928 SelectPalette(data->memory_hdc, texturedata->hpal, TRUE);
929 RealizePalette(data->memory_hdc);
930 }
931 if (texture->blendMode & (SDL_BLENDMODE_MASK | SDL_BLENDMODE_BLEND)) {
932 #ifdef _WIN32_WCE
933 SDL_SetError("Texture has blendmode not supported under WinCE");
934 return -1;
935 #else
936 BLENDFUNCTION blendFunc = {
937 AC_SRC_OVER,
938 0,
939 texture->a,
940 AC_SRC_ALPHA
941 };
942 if (!AlphaBlend
943 (data->current_hdc, dstrect->x, dstrect->y, dstrect->w,
944 dstrect->h, data->memory_hdc, srcrect->x, srcrect->y, srcrect->w,
945 srcrect->h, blendFunc)) {
946 WIN_SetError("AlphaBlend()");
947 return -1;
948 }
949 #endif
950 } else {
951 if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) {
952 if (!BitBlt
953 (data->current_hdc, dstrect->x, dstrect->y, dstrect->w,
954 srcrect->h, data->memory_hdc, srcrect->x, srcrect->y,
955 SRCCOPY)) {
956 WIN_SetError("BitBlt()");
957 return -1;
958 }
959 } else {
960 if (!StretchBlt
961 (data->current_hdc, dstrect->x, dstrect->y, dstrect->w,
962 dstrect->h, data->memory_hdc, srcrect->x, srcrect->y,
963 srcrect->w, srcrect->h, SRCCOPY)) {
964 WIN_SetError("StretchBlt()");
965 return -1;
966 }
967 }
968 }
969 return 0;
970 }
971
972 static int
973 GDI_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
974 Uint32 format, void * pixels, int pitch)
975 {
976 GDI_RenderData *renderdata = (GDI_RenderData *) renderer->driverdata;
977 SDL_Window *window = renderer->window;
978 SDL_VideoDisplay *display = window->display;
979 struct {
980 HBITMAP hbm;
981 void *pixels;
982 int pitch;
983 Uint32 format;
984 } data;
985
986 data.format = display->current_mode.format;
987 data.pitch = (rect->w * SDL_BYTESPERPIXEL(data.format));
988
989 data.hbm = GDI_CreateDIBSection(renderdata->memory_hdc, rect->w, rect->h,
990 data.pitch, data.format, NULL,
991 &data.pixels);
992 if (!data.hbm) {
993 WIN_SetError("Couldn't create bitmap");
994 return -1;
995 }
996
997 SelectObject(renderdata->memory_hdc, data.hbm);
998 if (!BitBlt(renderdata->memory_hdc, 0, 0, rect->w, rect->h,
999 renderdata->current_hdc, rect->x, rect->y, SRCCOPY)) {
1000 WIN_SetError("BitBlt()");
1001 DeleteObject(data.hbm);
1002 return -1;
1003 }
1004
1005 SDL_ConvertPixels(rect->w, rect->h,
1006 data.format, data.pixels, data.pitch,
1007 format, pixels, pitch);
1008
1009 DeleteObject(data.hbm);
1010 return 0;
1011 }
1012
1013 static int
1014 GDI_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1015 Uint32 format, const void * pixels, int pitch)
1016 {
1017 GDI_RenderData *renderdata = (GDI_RenderData *) renderer->driverdata;
1018 SDL_Window *window = renderer->window;
1019 SDL_VideoDisplay *display = window->display;
1020 struct {
1021 HBITMAP hbm;
1022 void *pixels;
1023 int pitch;
1024 Uint32 format;
1025 } data;
1026
1027 data.format = display->current_mode.format;
1028 data.pitch = (rect->w * SDL_BYTESPERPIXEL(data.format));
1029
1030 data.hbm = GDI_CreateDIBSection(renderdata->memory_hdc, rect->w, rect->h,
1031 data.pitch, data.format,
1032 NULL, &data.pixels);
1033 if (!data.hbm) {
1034 WIN_SetError("Couldn't create bitmap");
1035 return -1;
1036 }
1037
1038 SDL_ConvertPixels(rect->w, rect->h, format, pixels, pitch,
1039 data.format, data.pixels, data.pitch);
1040
1041 SelectObject(renderdata->memory_hdc, data.hbm);
1042 if (!BitBlt(renderdata->current_hdc, rect->x, rect->y, rect->w, rect->h,
1043 renderdata->memory_hdc, 0, 0, SRCCOPY)) {
1044 WIN_SetError("BitBlt()");
1045 DeleteObject(data.hbm);
1046 return -1;
1047 }
1048
1049 DeleteObject(data.hbm);
1050 return 0;
1051 }
1052
1053 static void
1054 GDI_RenderPresent(SDL_Renderer * renderer)
1055 {
1056 GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
1057 SDL_DirtyRect *dirty;
1058
1059 /* Send the data to the display */
1060 if (!(renderer->info.flags & SDL_RENDERER_SINGLEBUFFER)) {
1061 for (dirty = data->dirty.list; dirty; dirty = dirty->next) {
1062 const SDL_Rect *rect = &dirty->rect;
1063 BitBlt(data->window_hdc, rect->x, rect->y, rect->w, rect->h,
1064 data->render_hdc, rect->x, rect->y, SRCCOPY);
1065 }
1066 SDL_ClearDirtyRects(&data->dirty);
1067 }
1068
1069 /* Update the flipping chain, if any */
1070 if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP2) {
1071 data->current_hbm = (data->current_hbm + 1) % 2;
1072 SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
1073 } else if (renderer->info.flags & SDL_RENDERER_PRESENTFLIP3) {
1074 data->current_hbm = (data->current_hbm + 1) % 3;
1075 SelectObject(data->render_hdc, data->hbm[data->current_hbm]);
1076 }
1077 }
1078
1079 static void
1080 GDI_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1081 {
1082 GDI_TextureData *data = (GDI_TextureData *) texture->driverdata;
1083
1084 if (!data) {
1085 return;
1086 }
1087 if (data->yuv) {
1088 SDL_SW_DestroyYUVTexture(data->yuv);
1089 }
1090 if (data->hpal) {
1091 DeleteObject(data->hpal);
1092 }
1093 if (data->hbm) {
1094 DeleteObject(data->hbm);
1095 }
1096 SDL_free(data);
1097 texture->driverdata = NULL;
1098 }
1099
1100 static void
1101 GDI_DestroyRenderer(SDL_Renderer * renderer)
1102 {
1103 GDI_RenderData *data = (GDI_RenderData *) renderer->driverdata;
1104 int i;
1105
1106 if (data) {
1107 DeleteDC(data->render_hdc);
1108 DeleteDC(data->memory_hdc);
1109 #ifndef NO_GETDIBBITS
1110 if (data->bmi) {
1111 SDL_free(data->bmi);
1112 }
1113 #endif
1114 for (i = 0; i < SDL_arraysize(data->hbm); ++i) {
1115 if (data->hbm[i]) {
1116 DeleteObject(data->hbm[i]);
1117 }
1118 }
1119 SDL_FreeDirtyRects(&data->dirty);
1120 SDL_free(data);
1121 }
1122 SDL_free(renderer);
1123 }
1124
1125 #endif /* SDL_VIDEO_RENDER_GDI */
1126
1127 /* vi: set ts=4 sw=4 expandtab: */