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

Last change on this file since 10558 was 10558, checked in by sandervl, 21 years ago

CreateDIBitmap: added workaround for DIB_PAL_COLORS mode

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