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

Last change on this file since 9614 was 9614, checked in by sandervl, 23 years ago

GetDIBits fixes (flip bitmap and only return bitfields data when requested by the app)

File size: 23.8 KB
Line 
1/* $Id: dibitmap.cpp,v 1.38 2003-01-04 18:18:05 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 if(PalSize <= 8)
241 {
242 ULONG Pal[256], nrcolors;
243 LOGPALETTE tmpPal = { 0x300,1,{0,0,0,0}};
244 HPALETTE hpalCur, hpalTmp;
245
246 // Now get the current Palette from the DC
247 hpalTmp = CreatePalette(&tmpPal);
248 hpalCur = SelectPalette(hdc, hpalTmp, FALSE);
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 // Restore the DC Palette
255 SelectPalette(hdc,hpalCur,FALSE);
256 DeleteObject(hpalTmp);
257 }
258
259 if(ppvBits!=NULL)
260 *ppvBits = dsect->GetDIBObject();
261
262 pbmi->bmiHeader.biWidth = iWidth;
263 pbmi->bmiHeader.biHeight = iHeight;
264
265 if(fCreateDC) DeleteDC(hdc);
266
267 STATS_CreateDIBSection(res, hdc, pbmi, iUsage, ppvBits, hSection, dwOffset);
268
269 return(res);
270 }
271 }
272 if(fCreateDC) DeleteDC(hdc);
273
274 /* Error. */
275 if (res)
276 DeleteObject(res);
277 *ppvBits = NULL;
278
279#ifdef DEBUG
280 dprintf(("GDI32: CreateDIBSection, error!\n"));
281 dprintf(("pbmi->biWidth %d", pbmi->bmiHeader.biWidth));
282 dprintf(("pbmi->biHeight %d", pbmi->bmiHeader.biHeight));
283 dprintf(("pbmi->biBitCount %d", pbmi->bmiHeader.biBitCount));
284#endif
285
286 return 0;
287}
288//******************************************************************************
289//******************************************************************************
290UINT WIN32API GetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries,
291 RGBQUAD *pColors)
292{
293 DIBSection *dsect = DIBSection::findHDC(hdc);
294 UINT rc;
295 int i;
296
297 dprintf(("GetDIBColorTable %x %d->%d %x", hdc, uStartIndex, cEntries, pColors));
298
299 if(dsect)
300 {
301 return(dsect->GetDIBColorTable(uStartIndex, cEntries, pColors));
302 }
303 //TODO: Is this correct?????
304 // Wine returns 0 if bitmap selected into dc with bpp > 8
305 HPALETTE hpal = GetCurrentObject(hdc, OBJ_PAL);
306 rc = O32_GetPaletteEntries(hpal, uStartIndex, cEntries, (PALETTEENTRY *)pColors);
307 for(i=0;i<cEntries;i++)
308 {
309 BYTE tmp;
310 tmp = pColors[i].rgbBlue;
311 pColors[i].rgbBlue = pColors[i].rgbRed;
312 pColors[i].rgbRed = tmp;
313 pColors[i].rgbReserved = 0;
314 }
315 dprintf(("GDI32: GetDIBColorTable returns %d\n", rc));
316 return(rc);
317}
318//******************************************************************************
319//******************************************************************************
320UINT WIN32API SetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries,
321 RGBQUAD *pColors)
322{
323 DIBSection *dsect = DIBSection::findHDC(hdc);
324
325 dprintf(("GDI32: SetDIBColorTable %x %d,%d %x", hdc, uStartIndex, cEntries, pColors));
326 if(dsect)
327 {
328 return(dsect->SetDIBColorTable(uStartIndex, cEntries, pColors));
329 }
330 else return(0);
331}
332//******************************************************************************
333//******************************************************************************
334LONG WIN32API GetBitmapBits( HBITMAP hBitmap, LONG arg2, PVOID arg3)
335{
336 dprintf(("GDI32: GetBitmapBits %x", hBitmap));
337 return O32_GetBitmapBits(hBitmap, arg2, arg3);
338}
339//******************************************************************************
340//******************************************************************************
341LONG WIN32API SetBitmapBits( HBITMAP hBitmap, LONG arg2, const VOID * arg3)
342{
343 dprintf(("GDI32: SetBitmapBits %x", hBitmap));
344 return O32_SetBitmapBits(hBitmap, (DWORD)arg2, arg3);
345}
346//******************************************************************************
347//******************************************************************************
348BOOL WIN32API GetBitmapDimensionEx( HBITMAP hBitmap, PSIZE pSize)
349{
350 dprintf(("GDI32: GetBitmapDimensionEx %x (%d,%d)", hBitmap, pSize->cx, pSize->cy));
351 return O32_GetBitmapDimensionEx(hBitmap, pSize);
352}
353//******************************************************************************
354//******************************************************************************
355BOOL WIN32API SetBitmapDimensionEx( HBITMAP arg1, int arg2, int arg3, PSIZE arg4)
356{
357 dprintf(("GDI32: SetBitmapDimensionEx"));
358 return O32_SetBitmapDimensionEx(arg1, arg2, arg3, arg4);
359}
360//******************************************************************************
361//******************************************************************************
362int WIN32API GetDIBits(HDC hdc, HBITMAP hBitmap, UINT uStartScan, UINT cScanLines,
363 void *lpvBits, PBITMAPINFO lpbi, UINT uUsage)
364{
365 int nrlines;
366 pDCData pHps;
367 HDC hdcMem;
368 DWORD biCompression;
369
370 dprintf(("GDI32: GetDIBits %x %x %d %d %x %x (biBitCount %d) %d", hdc, hBitmap, uStartScan, cScanLines, lpvBits, lpbi, lpbi->bmiHeader.biBitCount, uUsage));
371
372 //SvL: WGSS screws up the DC if it's a memory DC
373 // TODO: Fix in WGSS (tries to select another bitmap in the DC which fails)
374 pHps = (pDCData)OSLibGpiQueryDCData((HPS)hdc);
375 if(!pHps)
376 {
377 SetLastError(ERROR_INVALID_HANDLE);
378 return 0;
379 }
380 if(pHps->isMemoryPS) {
381 hdcMem = CreateCompatibleDC(0);
382 }
383 else hdcMem = hdc;
384
385 if(lpvBits) {
386 biCompression = lpbi->bmiHeader.biCompression;
387 }
388
389 //If the app wants bitmap data and upside down, then flip image
390 if(lpvBits && lpbi->bmiHeader.biHeight < 0 && (lpbi->bmiHeader.biCompression == BI_RGB ||
391 lpbi->bmiHeader.biCompression == BI_BITFIELDS))
392 {
393 INT rc = -1;
394 long lLineByte;
395 LONG height = lpbi->bmiHeader.biHeight;
396
397 lpbi->bmiHeader.biHeight = -lpbi->bmiHeader.biHeight;
398
399 lLineByte = DIB_GetDIBWidthBytes(lpbi->bmiHeader.biWidth, lpbi->bmiHeader.biBitCount);
400
401 dprintf(("flip bitmap (negative height)"));
402 char *pNewBits = (char *)malloc( lLineByte * cScanLines );
403 if(pNewBits) {
404 nrlines = O32_GetDIBits(hdcMem, hBitmap, uStartScan, cScanLines, pNewBits, lpbi, uUsage);
405
406 unsigned char *pbSrc = (unsigned char *)pNewBits + lLineByte * (cScanLines - 1);
407 unsigned char *pbDst = (unsigned char *)lpvBits;
408 for(int y = 0; y < cScanLines; y++) {
409 memcpy( pbDst, pbSrc, lLineByte );
410 pbDst += lLineByte;
411 pbSrc -= lLineByte;
412 }
413 free(pNewBits);
414 }
415 else DebugInt3();
416
417 //restore height
418 lpbi->bmiHeader.biHeight = height;
419 }
420 else {
421 nrlines = O32_GetDIBits(hdcMem, hBitmap, uStartScan, cScanLines, lpvBits, lpbi, uUsage);
422 }
423
424 if(lpvBits) {
425 //WGSS always sets it to BI_RGB
426 lpbi->bmiHeader.biCompression = biCompression;
427 }
428
429 if(pHps->isMemoryPS)
430 DeleteDC(hdcMem);
431
432 //Only return bitfields info if the app wants it
433 if(lpvBits && lpbi->bmiHeader.biCompression == BI_BITFIELDS) {
434 // set proper color masks (only if lpvBits not NULL)
435 switch(lpbi->bmiHeader.biBitCount) {
436 case 15:
437 case 16: //RGB 565
438 {
439 DWORD dwFlags;
440
441 dwFlags = ObjQueryHandleFlags(hBitmap);
442 if(dwFlags & (OBJHANDLE_FLAG_BMP_SCREEN_COMPATIBLE|OBJHANDLE_FLAG_BMP_RGB565)) {
443 ((DWORD*)(lpbi->bmiColors))[0] = RGB565_RED_MASK;
444 ((DWORD*)(lpbi->bmiColors))[1] = RGB565_GREEN_MASK;
445 ((DWORD*)(lpbi->bmiColors))[2] = RGB565_BLUE_MASK;
446 }
447 else {
448 ((DWORD*)(lpbi->bmiColors))[0] = RGB555_RED_MASK;
449 ((DWORD*)(lpbi->bmiColors))[1] = RGB555_GREEN_MASK;
450 ((DWORD*)(lpbi->bmiColors))[2] = RGB555_BLUE_MASK;
451 }
452 break;
453 }
454 case 24:
455 case 32:
456 ((DWORD*)(lpbi->bmiColors))[0] = DEFAULT_24BPP_RED_MASK;
457 ((DWORD*)(lpbi->bmiColors))[1] = DEFAULT_24BPP_GREEN_MASK;
458 ((DWORD*)(lpbi->bmiColors))[2] = DEFAULT_24BPP_BLUE_MASK;
459 break;
460 }
461 dprintf(("BI_BITFIELDS: %x %x %x", ((DWORD*)(lpbi->bmiColors))[0], ((DWORD*)(lpbi->bmiColors))[1], ((DWORD*)(lpbi->bmiColors))[2]));
462 }
463 if(nrlines && lpvBits && lpbi->bmiHeader.biBitCount == 16 && ((DWORD*)(lpbi->bmiColors))[1] == RGB555_GREEN_MASK)
464 {//RGB 555?
465 dprintf(("RGB 565->555 conversion required"));
466
467 int imgsize = CalcBitmapSize(lpbi->bmiHeader.biBitCount,
468 lpbi->bmiHeader.biWidth, nrlines);
469
470 if(CPUFeatures & CPUID_MMX) {
471 RGB565to555MMX((WORD *)lpvBits, (WORD *)lpvBits, imgsize/sizeof(WORD));
472 }
473 else RGB565to555((WORD *)lpvBits, (WORD *)lpvBits, imgsize/sizeof(WORD));
474 }
475
476 //WGSS/Open32 returns 0 when querying the bitmap info; must return nr of scanlines
477 //as 0 signals failure
478 if(lpvBits == NULL) {
479 nrlines = cScanLines;
480 }
481 return nrlines;
482}
483//******************************************************************************
484//******************************************************************************
485void WIN32API ConvertRGB555to565(LPVOID dest, LPVOID src, UINT imgsize)
486{
487 if(CPUFeatures & CPUID_MMX) {
488 RGB555to565MMX((WORD *)dest, (WORD *)src, imgsize/sizeof(WORD));
489 }
490 else RGB555to565((WORD *)dest, (WORD *)src, imgsize/sizeof(WORD));
491}
492//******************************************************************************
493//******************************************************************************
494int WIN32API SetDIBits(HDC hdc, HBITMAP hBitmap, UINT startscan, UINT numlines, const VOID *pBits,
495 const BITMAPINFO *pBitmapInfo, UINT usage)
496{
497 int ret;
498 DWORD bitfields[3];
499 WORD *newbits = NULL;
500
501 dprintf(("GDI32: SetDIBits %x %x %x %x %x %x %x", hdc, hBitmap, startscan, numlines, pBits, pBitmapInfo, usage));
502
503 //SvL: Open32's SetDIBits really messes things up for 1 bpp bitmaps, must use SetBitmapBits
504 if(pBitmapInfo->bmiHeader.biBitCount == 1 && startscan == 0 && numlines == pBitmapInfo->bmiHeader.biHeight)
505 {//WARNING: hack alert!
506 int dibwidth = DIB_GetDIBWidthBytes(pBitmapInfo->bmiHeader.biWidth, 1);
507 int bmpwidth = BITMAP_GetWidthBytes(pBitmapInfo->bmiHeader.biWidth, 1);
508 char *newpix = (char *)malloc(dibwidth*pBitmapInfo->bmiHeader.biHeight);
509 char *orgpix = (char *)pBits;
510 int ret;
511
512 dprintf(("Flipping 1bpp bitmap and calling SetBitmapBits (WORKAROUND) (%d -> %d)", dibwidth, bmpwidth));
513 newpix += ((pBitmapInfo->bmiHeader.biHeight-1)*bmpwidth);
514
515 //flip bitmap here; SetDIBits assumes origin is left bottom, SetBitmapBits left top
516 //SetDIBits assumes DWORD aligned data
517 //SetBitmapBits assumes WORD aligned data
518 for(int i=0;i<pBitmapInfo->bmiHeader.biHeight;i++) {
519 memcpy(newpix, orgpix, bmpwidth);
520
521 newpix -= bmpwidth;
522 orgpix += dibwidth;
523 }
524 newpix += bmpwidth;
525 ret = O32_SetBitmapBits(hBitmap, pBitmapInfo->bmiHeader.biSizeImage, newpix);
526
527 free(newpix);
528 return ret;
529 }
530#ifdef DEBUG
531 if(pBitmapInfo->bmiHeader.biBitCount == 1) {
532 dprintf(("ERROR: SetDIBits does NOT work well for 1 bpp bitmaps!!!!!"));
533 }
534#endif
535
536 switch(pBitmapInfo->bmiHeader.biBitCount) {
537 case 15:
538 case 16: //Default if BI_BITFIELDS not set is RGB 555
539 bitfields[0] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *(DWORD *)pBitmapInfo->bmiColors : DEFAULT_16BPP_RED_MASK;
540 bitfields[1] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 1) : DEFAULT_16BPP_GREEN_MASK;
541 bitfields[2] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 2) : DEFAULT_16BPP_BLUE_MASK;
542 break;
543
544 case 24:
545 case 32:
546 bitfields[0] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *(DWORD *)pBitmapInfo->bmiColors : DEFAULT_24BPP_RED_MASK;
547 bitfields[1] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 1) : DEFAULT_24BPP_GREEN_MASK;
548 bitfields[2] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 2) : DEFAULT_24BPP_BLUE_MASK;
549 break;
550 default:
551 bitfields[0] = 0;
552 bitfields[1] = 0;
553 bitfields[2] = 0;
554 break;
555 }
556 if(pBits && bitfields[1] == RGB555_GREEN_MASK)
557 {//RGB 555?
558 dprintf(("RGB 555->565 conversion required %x %x %x", bitfields[0], bitfields[1], bitfields[2]));
559
560 int imgsize = CalcBitmapSize(pBitmapInfo->bmiHeader.biBitCount,
561 pBitmapInfo->bmiHeader.biWidth, numlines);
562
563 newbits = (WORD *)malloc(imgsize);
564 if(CPUFeatures & CPUID_MMX) {
565 RGB555to565MMX(newbits, (WORD *)pBits, imgsize/sizeof(WORD));
566 }
567 else RGB555to565(newbits, (WORD *)pBits, imgsize/sizeof(WORD));
568 pBits = newbits;
569 }
570
571 //If upside down, reverse scanlines and call SetDIBits again
572 if(pBitmapInfo->bmiHeader.biHeight < 0 && (pBitmapInfo->bmiHeader.biCompression == BI_RGB ||
573 pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS))
574 {
575 // upside down
576 INT rc = -1;
577 long lLineByte;
578
579 //TODO: doesn't work if memory is readonly!!
580 ((BITMAPINFO *)pBitmapInfo)->bmiHeader.biHeight = -pBitmapInfo->bmiHeader.biHeight;
581
582 lLineByte = DIB_GetDIBWidthBytes(pBitmapInfo->bmiHeader.biWidth, pBitmapInfo->bmiHeader.biBitCount);
583
584 dprintf(("Reverse bitmap (negative height)"));
585 char *pNewBits = (char *)malloc( lLineByte * numlines );
586 if(pNewBits) {
587 unsigned char *pbSrc = (unsigned char *)pBits + lLineByte * (numlines - 1);
588 unsigned char *pbDst = (unsigned char *)pNewBits;
589 for(int y = 0; y < numlines; y++) {
590 memcpy( pbDst, pbSrc, lLineByte );
591 pbDst += lLineByte;
592 pbSrc -= lLineByte;
593 }
594 ret = O32_SetDIBits(hdc, hBitmap, startscan, numlines, pNewBits, pBitmapInfo, usage);
595 free(pNewBits);
596 }
597 else DebugInt3();
598
599 //TODO: doesn't work if memory is readonly!!
600 ((BITMAPINFO *)pBitmapInfo)->bmiHeader.biHeight = -pBitmapInfo->bmiHeader.biHeight;
601 }
602 else {
603 ret = O32_SetDIBits(hdc, hBitmap, startscan, numlines, pBits, pBitmapInfo, usage);
604 }
605 if(newbits) free(newbits);
606
607 if(DIBSection::getSection() != NULL)
608 {
609 DIBSection *dsect;
610
611 dsect = DIBSection::findObj(hBitmap);
612 if(dsect) {
613 HBITMAP hBmpOld = SelectObject(hdc, hBitmap);
614 dsect->sync(hdc, 0, dsect->GetHeight());
615 SelectObject(hdc, hBmpOld);
616 }
617 }
618
619 return ret;
620}
621//******************************************************************************
622//******************************************************************************
Note: See TracBrowser for help on using the repository browser.