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

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

DIB section: do not fetch more colors from a bitmap header than biClrUsed (if ..= 0); GetDIBits: save and restore negative height & log failure

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