source: trunk/src/gdi32/dibitmap.cpp@ 10367

Last change on this file since 10367 was 10167, checked in by sandervl, 22 years ago

DT: Fix for partial blits in StretchDIBits; optimized rgb conversion calls

File size: 24.1 KB
Line 
1/* $Id: dibitmap.cpp,v 1.41 2003-07-16 10:46:17 sandervl Exp $ */
2
3/*
4 * GDI32 dib & bitmap code
5 *
6 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1998 Patrick Haller
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12#include <os2win.h>
13#include <stdlib.h>
14#include <stdarg.h>
15#include <string.h>
16#include <misc.h>
17#include <cpuhlp.h>
18#include <winuser32.h>
19#include "dibsect.h"
20#include "rgbcvt.h"
21#include <stats.h>
22#include "oslibgpi.h"
23#include <objhandle.h>
24
25#define DBG_LOCALLOG DBG_dibitmap
26#include "dbglocal.h"
27
28ULONG CalcBitmapSize(ULONG cBits, LONG cx, LONG cy);
29
30//******************************************************************************
31//******************************************************************************
32HBITMAP WIN32API CreateDIBitmap(HDC hdc, const BITMAPINFOHEADER *lpbmih,
33 DWORD fdwInit, const void *lpbInit,
34 const BITMAPINFO *lpbmi, UINT fuUsage)
35{
36 int iHeight;
37 HBITMAP rc;
38 DWORD bitfields[3];
39 WORD *newbits = NULL;
40
41 //TEMPORARY HACK TO PREVENT CRASH IN OPEN32 (WSeB GA)
42 iHeight = lpbmih->biHeight;
43 if(lpbmih->biHeight < 0)
44 {
45 dprintf(("GDI32: CreateDIBitmap negative height! (%d,%d)", lpbmih->biWidth, lpbmih->biHeight));
46 //TODO: doesn't work if memory is readonly!!
47 ((BITMAPINFOHEADER *)lpbmih)->biHeight = -lpbmih->biHeight;
48
49 if(lpbInit && fdwInit == CBM_INIT)
50 {
51 // upside down
52 HBITMAP rc = 0;
53 long lLineByte = DIB_GetDIBWidthBytes(lpbmih->biWidth, lpbmih->biBitCount);
54 long lHeight = lpbmih->biHeight;
55
56 newbits = (WORD *)malloc( lLineByte * lHeight );
57 if(newbits) {
58 unsigned char *pbSrc = (unsigned char *)lpbInit + lLineByte * (lHeight - 1);
59 unsigned char *pbDst = (unsigned char *)newbits;
60 for(int y = 0; y < lHeight; y++) {
61 memcpy( pbDst, pbSrc, lLineByte );
62 pbDst += lLineByte;
63 pbSrc -= lLineByte;
64 }
65 rc = CreateDIBitmap(hdc, lpbmih, fdwInit, newbits, lpbmi, fuUsage);
66 free( newbits );
67 }
68
69 ((BITMAPINFOHEADER *)lpbmih)->biHeight = iHeight;
70 return rc;
71 }
72 }
73
74 // 2000/09/01 PH Netscape 4.7
75 // If color depth of lpbhmi is 16 bit and lpbmi is 8 bit,
76 // Open32 will crash since it won't allocate any palette color memory,
77 // however wants to copy it later on ...
78 int biBitCount = lpbmih->biBitCount;
79
80 if (lpbmih->biBitCount != lpbmi->bmiHeader.biBitCount)
81 {
82 dprintf(("GDI32: CreateDIBitmap: color depths of bitmaps differ! (%d,%d\n", lpbmih->biBitCount,
83 lpbmi->bmiHeader.biBitCount));
84
85 ((BITMAPINFOHEADER *)lpbmih)->biBitCount = lpbmi->bmiHeader.biBitCount;
86 }
87
88 switch(lpbmih->biBitCount) {
89 case 15:
90 case 16: //Default if BI_BITFIELDS not set is RGB 555
91 bitfields[0] = (lpbmih->biCompression == BI_BITFIELDS) ? *(DWORD *)lpbmi->bmiColors : DEFAULT_16BPP_RED_MASK;
92 bitfields[1] = (lpbmih->biCompression == BI_BITFIELDS) ? *((DWORD *)lpbmi->bmiColors + 1) : DEFAULT_16BPP_GREEN_MASK;
93 bitfields[2] = (lpbmih->biCompression == BI_BITFIELDS) ? *((DWORD *)lpbmi->bmiColors + 2) : DEFAULT_16BPP_BLUE_MASK;
94 break;
95 case 24:
96 case 32:
97 bitfields[0] = (lpbmih->biCompression == BI_BITFIELDS) ? *(DWORD *)lpbmi->bmiColors : DEFAULT_24BPP_RED_MASK;
98 bitfields[1] = (lpbmih->biCompression == BI_BITFIELDS) ? *((DWORD *)lpbmi->bmiColors + 1) : DEFAULT_24BPP_GREEN_MASK;
99 bitfields[2] = (lpbmih->biCompression == BI_BITFIELDS) ? *((DWORD *)lpbmi->bmiColors + 2) : DEFAULT_24BPP_BLUE_MASK;
100 break;
101 default:
102 bitfields[0] = 0;
103 bitfields[1] = 0;
104 bitfields[2] = 0;
105 break;
106 }
107 if(bitfields[1] == RGB555_GREEN_MASK && lpbInit && fdwInit == CBM_INIT)
108 {//RGB 555?
109 dprintf(("RGB 555->565 conversion required %x %x %x", bitfields[0], bitfields[1], bitfields[2]));
110
111 int imgsize = CalcBitmapSize(lpbmih->biBitCount, lpbmih->biWidth, lpbmih->biHeight);
112
113 newbits = (WORD *)malloc(imgsize);
114 pRGB555to565(newbits, (WORD *)lpbInit, imgsize/sizeof(WORD));
115
116 lpbInit = newbits;
117 }
118
119 rc = O32_CreateDIBitmap(hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage);
120
121 dprintf(("GDI32: CreateDIBitmap %x %x %x %x %x returned %x (%d,%d, bps %d)", hdc, lpbmih, fdwInit, lpbInit, fuUsage, rc, lpbmih->biWidth, lpbmih->biHeight, lpbmih->biBitCount));
122
123 if(newbits) free(newbits);
124
125 ((BITMAPINFOHEADER *)lpbmih)->biHeight = iHeight;
126 ((BITMAPINFOHEADER *)lpbmih)->biBitCount = biBitCount;
127
128 if(rc) {
129 STATS_CreateDIBitmap(rc, hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage);
130 if(bitfields[1] == RGB565_GREEN_MASK) {
131 //mark bitmap as RGB565
132 dprintf(("RGB565 bitmap"));
133 ObjSetHandleFlag(rc, OBJHANDLE_FLAG_BMP_RGB565, TRUE);
134 }
135 }
136
137 return rc;
138}
139//******************************************************************************
140//******************************************************************************
141HBITMAP WIN32API CreateCompatibleBitmap( HDC hdc, int nWidth, int nHeight)
142{
143 HBITMAP hBitmap;
144 pDCData pHps;
145
146 pHps = (pDCData)OSLibGpiQueryDCData((HPS)hdc);
147 if(!pHps)
148 {
149 SetLastError(ERROR_INVALID_HANDLE);
150 return 0;
151 }
152
153 hBitmap = O32_CreateCompatibleBitmap(hdc, nWidth, nHeight);
154 if(hBitmap) {
155 STATS_CreateCompatibleBitmap(hBitmap,hdc, nWidth, nHeight);
156 if(pHps->hwnd == 1) { //1 == HWND_DESKTOP
157 dprintf(("Screen compatible bitmap"));
158 ObjSetHandleFlag(hBitmap, OBJHANDLE_FLAG_BMP_SCREEN_COMPATIBLE, 1);
159 }
160 }
161
162 return hBitmap;
163}
164//******************************************************************************
165//CreateDisardableBitmap is obsolete and can be replaced by CreateCompatibleBitmap
166//******************************************************************************
167HBITMAP WIN32API CreateDiscardableBitmap(HDC hDC, int nWidth, int nHeight)
168{
169 dprintf(("GDI32: CreateDisardableBitmap"));
170 return CreateCompatibleBitmap(hDC, nWidth, nHeight);
171}
172//******************************************************************************
173//******************************************************************************
174HBITMAP WIN32API CreateBitmap(int nWidth, int nHeight, UINT cPlanes,
175 UINT cBitsPerPel, const void *lpvBits)
176{
177 HBITMAP hBitmap;
178
179 hBitmap = O32_CreateBitmap(nWidth, nHeight, cPlanes, cBitsPerPel, lpvBits);
180 if(hBitmap) STATS_CreateBitmap(hBitmap,nWidth, nHeight, cPlanes, cBitsPerPel, lpvBits);
181 return(hBitmap);
182}
183//******************************************************************************
184//******************************************************************************
185HBITMAP WIN32API CreateBitmapIndirect( const BITMAP *pBitmap)
186{
187 HBITMAP hBitmap;
188
189 dprintf(("GDI32: CreateBitmapIndirect (%d,%d) bpp %d bits %x", pBitmap->bmWidth, pBitmap->bmHeight, pBitmap->bmBitsPixel, pBitmap->bmBits));
190 hBitmap = O32_CreateBitmapIndirect(pBitmap);
191 if(hBitmap) STATS_CreateBitmapIndirect(hBitmap, pBitmap);
192 return hBitmap;
193}
194//******************************************************************************
195//*********************************************************************************
196HBITMAP WIN32API CreateDIBSection( HDC hdc, BITMAPINFO *pbmi, UINT iUsage,
197 VOID **ppvBits, HANDLE hSection, DWORD dwOffset)
198{
199 HBITMAP res = 0;
200 BOOL fFlip = 0;
201 int iHeight, iWidth;
202 BOOL fCreateDC = FALSE;
203
204 dprintf(("GDI32: CreateDIBSection %x %x %x %x %x %d", hdc, pbmi, iUsage, ppvBits, hSection, dwOffset));
205
206 //SvL: 13-9-98: StarCraft uses bitmap with negative height
207 iWidth = pbmi->bmiHeader.biWidth;
208 if(pbmi->bmiHeader.biWidth < 0)
209 {
210 dprintf(("CreateDIBSection: width %d", pbmi->bmiHeader.biWidth));
211 pbmi->bmiHeader.biWidth = -pbmi->bmiHeader.biWidth;
212 fFlip = FLIP_HOR;
213 }
214 iHeight = pbmi->bmiHeader.biHeight;
215 if(pbmi->bmiHeader.biHeight < 0)
216 {
217 dprintf(("CreateDIBSection: height %d", pbmi->bmiHeader.biHeight));
218 pbmi->bmiHeader.biHeight = -pbmi->bmiHeader.biHeight;
219 fFlip |= FLIP_VERT;
220 }
221
222 //SvL: RP7 (update) calls this api with hdc == 0
223 if(hdc == 0) {
224 hdc = CreateCompatibleDC(0);
225 fCreateDC = TRUE;
226 }
227 res = O32_CreateDIBitmap(hdc, &pbmi->bmiHeader, 0, NULL, pbmi, iUsage);
228 if (res)
229 {
230 char PalSize;
231 DIBSection *dsect;
232
233 dsect = new DIBSection((BITMAPINFOHEADER_W *)&pbmi->bmiHeader, (char *)&pbmi->bmiColors, iUsage, hSection, dwOffset, (DWORD)res, fFlip);
234
235 if(dsect != NULL)
236 {
237 PalSize = dsect->GetBitCount();
238
239 if(!ppvBits && PalSize <= 8)
240 {
241 ULONG Pal[256], nrcolors;
242 LOGPALETTE tmpPal = { 0x300,1,{0,0,0,0}};
243 HPALETTE hpalCur;
244
245 // Now get the current Palette from the DC
246 hpalCur = GetCurrentObject(hdc, OBJ_PAL);
247
248 // and use it to set the DIBColorTable
249 nrcolors = GetPaletteEntries( hpalCur, 0, 1<<PalSize, (LPPALETTEENTRY)&Pal);
250 dsect->SetDIBColorTable(0, nrcolors, (LPPALETTEENTRY)&Pal);
251 }
252
253 if(ppvBits!=NULL)
254 *ppvBits = dsect->GetDIBObject();
255
256 pbmi->bmiHeader.biWidth = iWidth;
257 pbmi->bmiHeader.biHeight = iHeight;
258
259 if(fCreateDC) DeleteDC(hdc);
260
261 STATS_CreateDIBSection(res, hdc, pbmi, iUsage, ppvBits, hSection, dwOffset);
262
263 return(res);
264 }
265 }
266 if(fCreateDC) DeleteDC(hdc);
267
268 /* Error. */
269 if (res)
270 DeleteObject(res);
271 *ppvBits = NULL;
272
273#ifdef DEBUG
274 dprintf(("GDI32: CreateDIBSection, error!\n"));
275 dprintf(("pbmi->biWidth %d", pbmi->bmiHeader.biWidth));
276 dprintf(("pbmi->biHeight %d", pbmi->bmiHeader.biHeight));
277 dprintf(("pbmi->biBitCount %d", pbmi->bmiHeader.biBitCount));
278#endif
279
280 return 0;
281}
282//******************************************************************************
283//******************************************************************************
284UINT WIN32API GetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries,
285 RGBQUAD *pColors)
286{
287 DIBSection *dsect = DIBSection::findHDC(hdc);
288 UINT rc;
289 int i;
290
291 dprintf(("GetDIBColorTable %x %d->%d %x", hdc, uStartIndex, cEntries, pColors));
292
293 if(dsect)
294 {
295 return(dsect->GetDIBColorTable(uStartIndex, cEntries, pColors));
296 }
297 //TODO: Is this correct?????
298 // Wine returns 0 if bitmap selected into dc with bpp > 8
299 HPALETTE hpal = GetCurrentObject(hdc, OBJ_PAL);
300 rc = O32_GetPaletteEntries(hpal, uStartIndex, cEntries, (PALETTEENTRY *)pColors);
301 for(i=0;i<cEntries;i++)
302 {
303 BYTE tmp;
304 tmp = pColors[i].rgbBlue;
305 pColors[i].rgbBlue = pColors[i].rgbRed;
306 pColors[i].rgbRed = tmp;
307 pColors[i].rgbReserved = 0;
308 }
309 dprintf(("GDI32: GetDIBColorTable returns %d\n", rc));
310 return(rc);
311}
312//******************************************************************************
313//******************************************************************************
314UINT WIN32API SetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries,
315 RGBQUAD *pColors)
316{
317 DIBSection *dsect = DIBSection::findHDC(hdc);
318
319 dprintf(("GDI32: SetDIBColorTable %x %d,%d %x", hdc, uStartIndex, cEntries, pColors));
320 if(dsect)
321 {
322 return(dsect->SetDIBColorTable(uStartIndex, cEntries, pColors));
323 }
324 else return(0);
325}
326//******************************************************************************
327//******************************************************************************
328LONG WIN32API GetBitmapBits( HBITMAP hBitmap, LONG arg2, PVOID arg3)
329{
330 dprintf(("GDI32: GetBitmapBits %x", hBitmap));
331 return O32_GetBitmapBits(hBitmap, arg2, arg3);
332}
333//******************************************************************************
334//******************************************************************************
335LONG WIN32API SetBitmapBits( HBITMAP hBitmap, LONG arg2, const VOID * arg3)
336{
337 dprintf(("GDI32: SetBitmapBits %x", hBitmap));
338 return O32_SetBitmapBits(hBitmap, (DWORD)arg2, arg3);
339}
340//******************************************************************************
341//******************************************************************************
342BOOL WIN32API GetBitmapDimensionEx( HBITMAP hBitmap, PSIZE pSize)
343{
344 dprintf(("GDI32: GetBitmapDimensionEx %x (%d,%d)", hBitmap, pSize->cx, pSize->cy));
345 return O32_GetBitmapDimensionEx(hBitmap, pSize);
346}
347//******************************************************************************
348//******************************************************************************
349BOOL WIN32API SetBitmapDimensionEx( HBITMAP arg1, int arg2, int arg3, PSIZE arg4)
350{
351 dprintf(("GDI32: SetBitmapDimensionEx"));
352 return O32_SetBitmapDimensionEx(arg1, arg2, arg3, arg4);
353}
354//******************************************************************************
355//******************************************************************************
356int WIN32API GetDIBits(HDC hdc, HBITMAP hBitmap, UINT uStartScan, UINT cScanLines,
357 void *lpvBits, PBITMAPINFO lpbi, UINT uUsage)
358{
359 int nrlines;
360 pDCData pHps;
361 HDC hdcMem;
362 DWORD biCompression;
363
364 dprintf(("GDI32: GetDIBits %x %x %d %d %x %x (biBitCount %d) %d", hdc, hBitmap, uStartScan, cScanLines, lpvBits, lpbi, lpbi->bmiHeader.biBitCount, uUsage));
365
366#if 0
367 if(lpvBits && DIBSection::getSection() != NULL)
368 {
369 DIBSection *dsect;
370
371 dsect = DIBSection::findObj(hBitmap);
372 if(dsect) {
373 char *bmpBits = dsect->GetDIBObject();
374
375 if(lpbi->bmiHeader.biBitCount == dsect->GetBitCount() &&
376 lpbi->bmiHeader.biWidth > 0)
377 {
378 LONG lLineByte;
379
380 dprintf(("Quick copy from DIB section memory"));
381 lLineByte = DIB_GetDIBWidthBytes(lpbi->bmiHeader.biWidth, lpbi->bmiHeader.biBitCount);
382
383 memcpy(lpvBits, bmpBits+(uStartScan*lLineByte), cScanLines*lLineByte);
384 return cScanLines;
385 }
386 }
387 }
388#endif
389
390 //SvL: WGSS screws up the DC if it's a memory DC
391 // TODO: Fix in WGSS (tries to select another bitmap in the DC which fails)
392 pHps = (pDCData)OSLibGpiQueryDCData((HPS)hdc);
393 if(!pHps)
394 {
395 SetLastError(ERROR_INVALID_HANDLE);
396 return 0;
397 }
398 if(pHps->isMemoryPS) {
399 hdcMem = CreateCompatibleDC(0);
400 }
401 else hdcMem = hdc;
402
403 if(lpvBits) {
404 biCompression = lpbi->bmiHeader.biCompression;
405 }
406
407 //If the app wants bitmap data and upside down, then flip image
408 if(lpvBits && lpbi->bmiHeader.biHeight < 0 && (lpbi->bmiHeader.biCompression == BI_RGB ||
409 lpbi->bmiHeader.biCompression == BI_BITFIELDS))
410 {
411 INT rc = -1;
412 long lLineByte;
413 LONG height = lpbi->bmiHeader.biHeight;
414
415 lpbi->bmiHeader.biHeight = -lpbi->bmiHeader.biHeight;
416
417 lLineByte = DIB_GetDIBWidthBytes(lpbi->bmiHeader.biWidth, lpbi->bmiHeader.biBitCount);
418
419 dprintf(("flip bitmap (negative height)"));
420 char *pNewBits = (char *)malloc( lLineByte * cScanLines );
421 if(pNewBits) {
422 nrlines = O32_GetDIBits(hdcMem, hBitmap, uStartScan, cScanLines, pNewBits, lpbi, uUsage);
423
424 unsigned char *pbSrc = (unsigned char *)pNewBits + lLineByte * (cScanLines - 1);
425 unsigned char *pbDst = (unsigned char *)lpvBits;
426 for(int y = 0; y < cScanLines; y++) {
427 memcpy( pbDst, pbSrc, lLineByte );
428 pbDst += lLineByte;
429 pbSrc -= lLineByte;
430 }
431 free(pNewBits);
432 }
433 else DebugInt3();
434
435 //restore height
436 lpbi->bmiHeader.biHeight = height;
437 }
438 else {
439 LONG height = lpbi->bmiHeader.biHeight;
440
441 if(lpbi->bmiHeader.biHeight < 0) {
442 lpbi->bmiHeader.biHeight = -lpbi->bmiHeader.biHeight;
443 }
444 nrlines = O32_GetDIBits(hdcMem, hBitmap, uStartScan, cScanLines, lpvBits, lpbi, uUsage);
445
446 //restore height
447 lpbi->bmiHeader.biHeight = height;
448 }
449
450 if(lpvBits) {
451 //WGSS always sets it to BI_RGB
452 lpbi->bmiHeader.biCompression = biCompression;
453 }
454
455 if(pHps->isMemoryPS)
456 DeleteDC(hdcMem);
457
458 //Only return bitfields info if the app wants it
459 if(lpvBits && lpbi->bmiHeader.biCompression == BI_BITFIELDS) {
460 // set proper color masks (only if lpvBits not NULL)
461 switch(lpbi->bmiHeader.biBitCount) {
462 case 15:
463 case 16: //RGB 565
464 {
465 DWORD dwFlags;
466
467 dwFlags = ObjQueryHandleFlags(hBitmap);
468 if(dwFlags & (OBJHANDLE_FLAG_BMP_SCREEN_COMPATIBLE|OBJHANDLE_FLAG_BMP_RGB565)) {
469 ((DWORD*)(lpbi->bmiColors))[0] = RGB565_RED_MASK;
470 ((DWORD*)(lpbi->bmiColors))[1] = RGB565_GREEN_MASK;
471 ((DWORD*)(lpbi->bmiColors))[2] = RGB565_BLUE_MASK;
472 }
473 else {
474 ((DWORD*)(lpbi->bmiColors))[0] = RGB555_RED_MASK;
475 ((DWORD*)(lpbi->bmiColors))[1] = RGB555_GREEN_MASK;
476 ((DWORD*)(lpbi->bmiColors))[2] = RGB555_BLUE_MASK;
477 }
478 break;
479 }
480 case 24:
481 case 32:
482 ((DWORD*)(lpbi->bmiColors))[0] = DEFAULT_24BPP_RED_MASK;
483 ((DWORD*)(lpbi->bmiColors))[1] = DEFAULT_24BPP_GREEN_MASK;
484 ((DWORD*)(lpbi->bmiColors))[2] = DEFAULT_24BPP_BLUE_MASK;
485 break;
486 }
487 dprintf(("BI_BITFIELDS: %x %x %x", ((DWORD*)(lpbi->bmiColors))[0], ((DWORD*)(lpbi->bmiColors))[1], ((DWORD*)(lpbi->bmiColors))[2]));
488 }
489 if(nrlines && lpvBits && lpbi->bmiHeader.biBitCount == 16 && ((DWORD*)(lpbi->bmiColors))[1] == RGB555_GREEN_MASK)
490 {//RGB 555?
491 dprintf(("RGB 565->555 conversion required"));
492
493 int imgsize = CalcBitmapSize(lpbi->bmiHeader.biBitCount,
494 lpbi->bmiHeader.biWidth, nrlines);
495
496 pRGB565to555((WORD *)lpvBits, (WORD *)lpvBits, imgsize/sizeof(WORD));
497 }
498
499 //WGSS/Open32 returns 1 when querying the bitmap info; must return nr of scanlines
500 //(0 signals failure)
501 if(lpvBits == NULL) {
502 if(nrlines != 0)
503 nrlines = cScanLines;
504 else dprintf(("GetDIBits failed!!"));
505 }
506 return nrlines;
507}
508//******************************************************************************
509//******************************************************************************
510void WIN32API ConvertRGB555to565(LPVOID dest, LPVOID src, UINT imgsize)
511{
512 pRGB555to565((WORD *)dest, (WORD *)src, imgsize/sizeof(WORD));
513}
514//******************************************************************************
515//******************************************************************************
516int WIN32API SetDIBits(HDC hdc, HBITMAP hBitmap, UINT startscan, UINT numlines, const VOID *pBits,
517 const BITMAPINFO *pBitmapInfo, UINT usage)
518{
519 int ret;
520 DWORD bitfields[3];
521 WORD *newbits = NULL;
522
523 dprintf(("GDI32: SetDIBits %x %x %x %x %x %x %x", hdc, hBitmap, startscan, numlines, pBits, pBitmapInfo, usage));
524
525 //SvL: Open32's SetDIBits really messes things up for 1 bpp bitmaps, must use SetBitmapBits
526 if(pBitmapInfo->bmiHeader.biBitCount == 1 && startscan == 0 && numlines == pBitmapInfo->bmiHeader.biHeight)
527 {//WARNING: hack alert!
528 int dibwidth = DIB_GetDIBWidthBytes(pBitmapInfo->bmiHeader.biWidth, 1);
529 int bmpwidth = BITMAP_GetWidthBytes(pBitmapInfo->bmiHeader.biWidth, 1);
530 char *newpix = (char *)malloc(dibwidth*pBitmapInfo->bmiHeader.biHeight);
531 char *orgpix = (char *)pBits;
532 int ret;
533
534 dprintf(("Flipping 1bpp bitmap and calling SetBitmapBits (WORKAROUND) (%d -> %d)", dibwidth, bmpwidth));
535 newpix += ((pBitmapInfo->bmiHeader.biHeight-1)*bmpwidth);
536
537 //flip bitmap here; SetDIBits assumes origin is left bottom, SetBitmapBits left top
538 //SetDIBits assumes DWORD aligned data
539 //SetBitmapBits assumes WORD aligned data
540 for(int i=0;i<pBitmapInfo->bmiHeader.biHeight;i++) {
541 memcpy(newpix, orgpix, bmpwidth);
542
543 newpix -= bmpwidth;
544 orgpix += dibwidth;
545 }
546 newpix += bmpwidth;
547 ret = O32_SetBitmapBits(hBitmap, pBitmapInfo->bmiHeader.biSizeImage, newpix);
548
549 free(newpix);
550 return ret;
551 }
552#ifdef DEBUG
553 if(pBitmapInfo->bmiHeader.biBitCount == 1) {
554 dprintf(("ERROR: SetDIBits does NOT work well for 1 bpp bitmaps!!!!!"));
555 }
556#endif
557
558 switch(pBitmapInfo->bmiHeader.biBitCount) {
559 case 15:
560 case 16: //Default if BI_BITFIELDS not set is RGB 555
561 bitfields[0] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *(DWORD *)pBitmapInfo->bmiColors : DEFAULT_16BPP_RED_MASK;
562 bitfields[1] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 1) : DEFAULT_16BPP_GREEN_MASK;
563 bitfields[2] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 2) : DEFAULT_16BPP_BLUE_MASK;
564 break;
565
566 case 24:
567 case 32:
568 bitfields[0] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *(DWORD *)pBitmapInfo->bmiColors : DEFAULT_24BPP_RED_MASK;
569 bitfields[1] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 1) : DEFAULT_24BPP_GREEN_MASK;
570 bitfields[2] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 2) : DEFAULT_24BPP_BLUE_MASK;
571 break;
572 default:
573 bitfields[0] = 0;
574 bitfields[1] = 0;
575 bitfields[2] = 0;
576 break;
577 }
578 if(pBits && bitfields[1] == RGB555_GREEN_MASK)
579 {//RGB 555?
580 dprintf(("RGB 555->565 conversion required %x %x %x", bitfields[0], bitfields[1], bitfields[2]));
581
582 int imgsize = CalcBitmapSize(pBitmapInfo->bmiHeader.biBitCount,
583 pBitmapInfo->bmiHeader.biWidth, numlines);
584
585 newbits = (WORD *)malloc(imgsize);
586 pRGB555to565(newbits, (WORD *)pBits, imgsize/sizeof(WORD));
587 pBits = newbits;
588 }
589
590 //If upside down, reverse scanlines and call SetDIBits again
591 if(pBitmapInfo->bmiHeader.biHeight < 0 && (pBitmapInfo->bmiHeader.biCompression == BI_RGB ||
592 pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS))
593 {
594 // upside down
595 INT rc = -1;
596 long lLineByte;
597
598 //TODO: doesn't work if memory is readonly!!
599 ((BITMAPINFO *)pBitmapInfo)->bmiHeader.biHeight = -pBitmapInfo->bmiHeader.biHeight;
600
601 lLineByte = DIB_GetDIBWidthBytes(pBitmapInfo->bmiHeader.biWidth, pBitmapInfo->bmiHeader.biBitCount);
602
603 dprintf(("Reverse bitmap (negative height)"));
604 char *pNewBits = (char *)malloc( lLineByte * numlines );
605 if(pNewBits) {
606 unsigned char *pbSrc = (unsigned char *)pBits + lLineByte * (numlines - 1);
607 unsigned char *pbDst = (unsigned char *)pNewBits;
608 for(int y = 0; y < numlines; y++) {
609 memcpy( pbDst, pbSrc, lLineByte );
610 pbDst += lLineByte;
611 pbSrc -= lLineByte;
612 }
613 ret = O32_SetDIBits(hdc, hBitmap, startscan, numlines, pNewBits, pBitmapInfo, usage);
614 free(pNewBits);
615 }
616 else DebugInt3();
617
618 //TODO: doesn't work if memory is readonly!!
619 ((BITMAPINFO *)pBitmapInfo)->bmiHeader.biHeight = -pBitmapInfo->bmiHeader.biHeight;
620 }
621 else {
622 ret = O32_SetDIBits(hdc, hBitmap, startscan, numlines, pBits, pBitmapInfo, usage);
623 }
624 if(newbits) free(newbits);
625
626 if(DIBSection::getSection() != NULL)
627 {
628 DIBSection *dsect;
629
630 dsect = DIBSection::findObj(hBitmap);
631 if(dsect) {
632 HBITMAP hBmpOld = SelectObject(hdc, hBitmap);
633 dsect->sync(hdc, 0, dsect->GetHeight());
634 SelectObject(hdc, hBmpOld);
635 }
636 }
637
638 return ret;
639}
640//******************************************************************************
641//******************************************************************************
Note: See TracBrowser for help on using the repository browser.