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

Last change on this file since 6182 was 6182, checked in by sandervl, 24 years ago

GetDIBits fix

File size: 17.8 KB
Line 
1/* $Id: dibitmap.cpp,v 1.25 2001-07-06 13:46:07 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
22#define DBG_LOCALLOG DBG_dibitmap
23#include "dbglocal.h"
24
25ULONG CalcBitmapSize(ULONG cBits, LONG cx, LONG cy);
26
27//******************************************************************************
28//******************************************************************************
29HBITMAP WIN32API CreateDIBitmap(HDC hdc, const BITMAPINFOHEADER *lpbmih,
30 DWORD fdwInit, const void *lpbInit,
31 const BITMAPINFO *lpbmi, UINT fuUsage)
32{
33 int iHeight;
34 HBITMAP rc;
35 DWORD bitfields[3];
36 WORD *newbits = NULL;
37
38 //SvL: Completely wrong result when creating a 1bpp bitmap here (converted
39 // to 8bpp by Open32)
40 if(lpbmih->biBitCount == 1) {
41 dprintf(("WARNING: CreateDIBitmap doesn't handle 1bpp bitmaps very well!!!!!"));
42 }
43
44 //TEMPORARY HACK TO PREVENT CRASH IN OPEN32 (WSeB GA)
45
46 iHeight = lpbmih->biHeight;
47 if(lpbmih->biHeight < 0)
48 {
49 dprintf(("GDI32: CreateDIBitmap negative height! (%d,%d)", lpbmih->biWidth, lpbmih->biHeight));
50 ((BITMAPINFOHEADER *)lpbmih)->biHeight = -lpbmih->biHeight;
51 }
52
53 // 2000/09/01 PH Netscape 4.7
54 // If color depth of lpbhmi is 16 bit and lpbmi is 8 bit,
55 // Open32 will crash since it won't allocate any palette color memory,
56 // however wants to copy it later on ...
57 int biBitCount = lpbmih->biBitCount;
58
59 if (lpbmih->biBitCount != lpbmi->bmiHeader.biBitCount)
60 {
61 dprintf(("GDI32: CreateDIBitmap: color depths of bitmaps differ! (%d,%d\n", lpbmih->biBitCount,
62 lpbmi->bmiHeader.biBitCount));
63
64 ((BITMAPINFOHEADER *)lpbmih)->biBitCount = lpbmi->bmiHeader.biBitCount;
65 }
66
67 switch(lpbmih->biBitCount) {
68 case 15:
69 case 16: //Default if BI_BITFIELDS not set is RGB 555
70 bitfields[0] = (lpbmih->biCompression == BI_BITFIELDS) ? *(DWORD *)lpbmi->bmiColors : 0x7c00;
71 bitfields[1] = (lpbmih->biCompression == BI_BITFIELDS) ? *((DWORD *)lpbmi->bmiColors + 1) : 0x03e0;
72 bitfields[2] = (lpbmih->biCompression == BI_BITFIELDS) ? *((DWORD *)lpbmi->bmiColors + 2) : 0x001f;
73 break;
74 case 32:
75 bitfields[0] = (lpbmih->biCompression == BI_BITFIELDS) ? *(DWORD *)lpbmi->bmiColors : 0xff0000;
76 bitfields[1] = (lpbmih->biCompression == BI_BITFIELDS) ? *((DWORD *)lpbmi->bmiColors + 1) : 0xff00;
77 bitfields[2] = (lpbmih->biCompression == BI_BITFIELDS) ? *((DWORD *)lpbmi->bmiColors + 2) : 0xff;
78 break;
79 default:
80 bitfields[0] = 0;
81 bitfields[1] = 0;
82 bitfields[2] = 0;
83 break;
84 }
85 if(bitfields[1] == 0x3E0 && lpbInit && fdwInit == CBM_INIT)
86 {//RGB 555?
87 dprintf(("RGB 555->565 conversion required %x %x %x", bitfields[0], bitfields[1], bitfields[2]));
88
89 int imgsize = CalcBitmapSize(lpbmih->biBitCount, lpbmih->biWidth, lpbmih->biHeight);
90
91 newbits = (WORD *)malloc(imgsize);
92 if(CPUFeatures & CPUID_MMX) {
93 RGB555to565MMX(newbits, (WORD *)lpbInit, imgsize/sizeof(WORD));
94 }
95 else RGB555to565(newbits, (WORD *)lpbInit, imgsize/sizeof(WORD));
96 lpbInit = newbits;
97 }
98
99 rc = O32_CreateDIBitmap(hdc, lpbmih, fdwInit, lpbInit, lpbmi, fuUsage);
100
101 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));
102
103 if(newbits) free(newbits);
104
105 ((BITMAPINFOHEADER *)lpbmih)->biHeight = iHeight;
106 ((BITMAPINFOHEADER *)lpbmih)->biBitCount = biBitCount;
107
108 return rc;
109}
110//******************************************************************************
111//******************************************************************************
112HBITMAP WIN32API CreateCompatibleBitmap( HDC hdc, int nWidth, int nHeight)
113{
114 HBITMAP hBitmap;
115
116 hBitmap = O32_CreateCompatibleBitmap(hdc, nWidth, nHeight);
117 dprintf(("GDI32: CreateCompatibleBitmap %x (%d,%d) returned %x", hdc, nWidth, nHeight, hBitmap));
118 return hBitmap;
119}
120//******************************************************************************
121//CreateDisardableBitmap is obsolete and can be replaced by CreateCompatibleBitmap
122//******************************************************************************
123HBITMAP WIN32API CreateDiscardableBitmap(HDC hDC, int nWidth, int nHeight)
124{
125 dprintf(("GDI32: CreateDisardableBitmap\n"));
126 return CreateCompatibleBitmap(hDC, nWidth, nHeight);
127}
128//******************************************************************************
129//******************************************************************************
130HBITMAP WIN32API CreateBitmap(int nWidth, int nHeight, UINT cPlanes,
131 UINT cBitsPerPel, const void *lpvBits)
132{
133 HBITMAP hBitmap;
134
135 hBitmap = O32_CreateBitmap(nWidth, nHeight, cPlanes, cBitsPerPel, lpvBits);
136 dprintf(("GDI32: CreateBitmap (%d,%d) bps %d returned %x", nWidth, nHeight, cBitsPerPel, hBitmap));
137 return(hBitmap);
138}
139//******************************************************************************
140//******************************************************************************
141HBITMAP WIN32API CreateBitmapIndirect( const BITMAP *pBitmap)
142{
143 HBITMAP hBitmap;
144
145 dprintf(("GDI32: CreateBitmapIndirect (%d,%d) bpp %d bits %x", pBitmap->bmWidth, pBitmap->bmHeight, pBitmap->bmBitsPixel, pBitmap->bmBits));
146 hBitmap = O32_CreateBitmapIndirect(pBitmap);
147 dprintf(("GDI32: CreateBitmapIndirect returned %x", hBitmap));
148 return hBitmap;
149}
150//******************************************************************************
151//*********************************************************************************
152HBITMAP WIN32API CreateDIBSection( HDC hdc, BITMAPINFO *pbmi, UINT iUsage,
153 VOID **ppvBits, HANDLE hSection, DWORD dwOffset)
154{
155 HBITMAP res = 0;
156 BOOL fFlip = 0;
157 int iHeight, iWidth;
158 BOOL fCreateDC = FALSE;
159
160 dprintf(("GDI32: CreateDIBSection %x %x %x %x %x %d", hdc, pbmi, iUsage, ppvBits, hSection, dwOffset));
161
162 //SvL: 13-9-98: StarCraft uses bitmap with negative height
163 iWidth = pbmi->bmiHeader.biWidth;
164 if(pbmi->bmiHeader.biWidth < 0)
165 {
166 dprintf(("CreateDIBSection: width %d", pbmi->bmiHeader.biWidth));
167 pbmi->bmiHeader.biWidth = -pbmi->bmiHeader.biWidth;
168 fFlip = FLIP_HOR;
169 }
170 iHeight = pbmi->bmiHeader.biHeight;
171 if(pbmi->bmiHeader.biHeight < 0)
172 {
173 dprintf(("CreateDIBSection: height %d", pbmi->bmiHeader.biHeight));
174 pbmi->bmiHeader.biHeight = -pbmi->bmiHeader.biHeight;
175 fFlip |= FLIP_VERT;
176 }
177
178 //SvL: RP7 (update) calls this api with hdc == 0
179 if(hdc == 0) {
180 hdc = CreateCompatibleDC(0);
181 fCreateDC = TRUE;
182 }
183 res = O32_CreateDIBitmap(hdc, &pbmi->bmiHeader, 0, NULL, pbmi, iUsage);
184 if (res)
185 {
186 char PalSize;
187 DIBSection *dsect;
188
189 dsect = new DIBSection((BITMAPINFOHEADER_W *)&pbmi->bmiHeader, (char *)&pbmi->bmiColors, iUsage, hSection, dwOffset, (DWORD)res, fFlip);
190
191 if(dsect != NULL)
192 {
193 PalSize = dsect->GetBitCount();
194 if(PalSize <= 8)
195 {
196 ULONG Pal[256], nrcolors;
197 LOGPALETTE tmpPal = { 0x300,1,{0,0,0,0}};
198 HPALETTE hpalCur, hpalTmp;
199
200 // Now get the current Palette from the DC
201 hpalTmp = CreatePalette(&tmpPal);
202 hpalCur = SelectPalette(hdc, hpalTmp, FALSE);
203
204 // and use it to set the DIBColorTable
205 nrcolors = GetPaletteEntries( hpalCur, 0, 1<<PalSize, (LPPALETTEENTRY)&Pal);
206 dsect->SetDIBColorTable(0, nrcolors, (LPPALETTEENTRY)&Pal);
207
208 // Restore the DC Palette
209 SelectPalette(hdc,hpalCur,FALSE);
210 DeleteObject(hpalTmp);
211 }
212
213 if(ppvBits!=NULL)
214 *ppvBits = dsect->GetDIBObject();
215
216 pbmi->bmiHeader.biWidth = iWidth;
217 pbmi->bmiHeader.biHeight = iHeight;
218
219 if(fCreateDC) DeleteDC(hdc);
220 return(res);
221 }
222 }
223 if(fCreateDC) DeleteDC(hdc);
224
225 /* Error. */
226 if (res)
227 DeleteObject(res);
228 *ppvBits = NULL;
229
230#ifdef DEBUG
231 dprintf(("GDI32: CreateDIBSection, error!\n"));
232 dprintf(("pbmi->biWidth %d", pbmi->bmiHeader.biWidth));
233 dprintf(("pbmi->biHeight %d", pbmi->bmiHeader.biHeight));
234 dprintf(("pbmi->biBitCount %d", pbmi->bmiHeader.biBitCount));
235#endif
236
237 return 0;
238}
239//******************************************************************************
240//******************************************************************************
241UINT WIN32API GetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries,
242 RGBQUAD *pColors)
243{
244 DIBSection *dsect = DIBSection::findHDC(hdc);
245 UINT rc;
246 int i;
247
248 dprintf(("GetDIBColorTable %x %d->%d %x", hdc, uStartIndex, cEntries, pColors));
249
250 if(dsect)
251 {
252 return(dsect->GetDIBColorTable(uStartIndex, cEntries, pColors));
253 }
254 //TODO: Is this correct?????
255 // Wine returns 0 if bitmap selected into dc with bpp > 8
256 HPALETTE hpal = GetCurrentObject(hdc, OBJ_PAL);
257 rc = O32_GetPaletteEntries(hpal, uStartIndex, cEntries, (PALETTEENTRY *)pColors);
258 for(i=0;i<cEntries;i++)
259 {
260 BYTE tmp;
261 tmp = pColors[i].rgbBlue;
262 pColors[i].rgbBlue = pColors[i].rgbRed;
263 pColors[i].rgbRed = tmp;
264 pColors[i].rgbReserved = 0;
265 }
266 dprintf(("GDI32: GetDIBColorTable returns %d\n", rc));
267 return(rc);
268}
269//******************************************************************************
270//******************************************************************************
271UINT WIN32API SetDIBColorTable(HDC hdc, UINT uStartIndex, UINT cEntries,
272 RGBQUAD *pColors)
273{
274 DIBSection *dsect = DIBSection::findHDC(hdc);
275
276 dprintf(("GDI32: SetDIBColorTable %x %d,%d %x", hdc, uStartIndex, cEntries, pColors));
277 if(dsect)
278 {
279 return(dsect->SetDIBColorTable(uStartIndex, cEntries, pColors));
280 }
281 else return(0);
282}
283//******************************************************************************
284//******************************************************************************
285LONG WIN32API GetBitmapBits( HBITMAP hBitmap, LONG arg2, PVOID arg3)
286{
287 dprintf(("GDI32: GetBitmapBits %x", hBitmap));
288 return O32_GetBitmapBits(hBitmap, arg2, arg3);
289}
290//******************************************************************************
291//******************************************************************************
292LONG WIN32API SetBitmapBits( HBITMAP hBitmap, LONG arg2, const VOID * arg3)
293{
294 dprintf(("GDI32: SetBitmapBits %x", hBitmap));
295 return O32_SetBitmapBits(hBitmap, (DWORD)arg2, arg3);
296}
297//******************************************************************************
298//******************************************************************************
299BOOL WIN32API GetBitmapDimensionEx( HBITMAP hBitmap, PSIZE pSize)
300{
301 dprintf(("GDI32: GetBitmapDimensionEx %x (%d,%d)", hBitmap, pSize->cx, pSize->cy));
302 return O32_GetBitmapDimensionEx(hBitmap, pSize);
303}
304//******************************************************************************
305//******************************************************************************
306BOOL WIN32API SetBitmapDimensionEx( HBITMAP arg1, int arg2, int arg3, PSIZE arg4)
307{
308 dprintf(("GDI32: SetBitmapDimensionEx"));
309 return O32_SetBitmapDimensionEx(arg1, arg2, arg3, arg4);
310}
311//******************************************************************************
312//******************************************************************************
313int WIN32API GetDIBits(HDC hdc, HBITMAP hBitmap, UINT uStartScan, UINT cScanLines,
314 void *lpvBits, PBITMAPINFO lpbi, UINT uUsage)
315{
316 int nrlines;
317
318 dprintf(("GDI32: GetDIBits %x %x %d %d %x %x (biBitCount %d) %d", hdc, hBitmap, uStartScan, cScanLines, lpvBits, lpbi, lpbi->bmiHeader.biBitCount, uUsage));
319
320 //SvL: WGSS screws up the DC if it's a memory DC
321 // TODO: Fix in WGSS
322 HDC hdcMem = CreateCompatibleDC(0);
323
324 nrlines = O32_GetDIBits(hdcMem, hBitmap, uStartScan, cScanLines, lpvBits, lpbi, uUsage);
325
326 DeleteDC(hdcMem);
327
328 if(lpvBits) {
329 // set proper color masks (only if lpvBits not NULL)
330 switch(lpbi->bmiHeader.biBitCount) {
331 case 15:
332 case 16: //RGB 565
333 ((DWORD*)(lpbi->bmiColors))[0] = 0x7c00;
334 ((DWORD*)(lpbi->bmiColors))[1] = 0x03E0;
335 ((DWORD*)(lpbi->bmiColors))[2] = 0x001F;
336 break;
337 case 24:
338 case 32:
339 ((DWORD*)(lpbi->bmiColors))[0] = 0x0000FF;
340 ((DWORD*)(lpbi->bmiColors))[1] = 0x00FF00;
341 ((DWORD*)(lpbi->bmiColors))[2] = 0xFF0000;
342 break;
343 }
344 }
345 if(nrlines && lpvBits && lpbi->bmiHeader.biBitCount == 16 && ((DWORD*)(lpbi->bmiColors))[1] == 0x3E0)
346 {//RGB 555?
347 dprintf(("RGB 565->555 conversion required"));
348
349 int imgsize = CalcBitmapSize(lpbi->bmiHeader.biBitCount,
350 lpbi->bmiHeader.biWidth, nrlines);
351
352 if(CPUFeatures & CPUID_MMX) {
353 RGB565to555MMX((WORD *)lpvBits, (WORD *)lpvBits, imgsize/sizeof(WORD));
354 }
355 else RGB565to555((WORD *)lpvBits, (WORD *)lpvBits, imgsize/sizeof(WORD));
356 }
357
358 //WGSS/Open32 returns 0 when querying the bitmap info; must return nr of scanlines
359 //as 0 signals failure
360 if(lpvBits == NULL) {
361 nrlines = cScanLines;
362 }
363 dprintf(("GDI32: GetDIBits returned %d", nrlines));
364 return nrlines;
365}
366//******************************************************************************
367//******************************************************************************
368int WIN32API SetDIBits(HDC hdc, HBITMAP hBitmap, UINT startscan, UINT numlines, const VOID *pBits,
369 const BITMAPINFO *pBitmapInfo, UINT usage)
370{
371 int ret;
372 DWORD bitfields[3];
373 WORD *newbits = NULL;
374
375 dprintf(("GDI32: SetDIBits %x %x %x %x %x %x %x", hdc, hBitmap, startscan, numlines, pBits, pBitmapInfo, usage));
376
377 //SvL: Open32's SetDIBits really messes things up for 1 bpp bitmaps, must use SetBitmapBits
378 if(pBitmapInfo->bmiHeader.biBitCount == 1 && startscan == 0 && numlines == pBitmapInfo->bmiHeader.biHeight)
379 {//WARNING: hack alert!
380 int dibwidth = DIB_GetDIBWidthBytes(pBitmapInfo->bmiHeader.biWidth, 1);
381 int bmpwidth = BITMAP_GetWidthBytes(pBitmapInfo->bmiHeader.biWidth, 1);
382 char *newpix = (char *)malloc(dibwidth*pBitmapInfo->bmiHeader.biHeight);
383 char *orgpix = (char *)pBits;
384 int ret;
385
386 dprintf(("Flipping 1bpp bitmap and calling SetBitmapBits (WORKAROUND) (%d -> %d)", dibwidth, bmpwidth));
387 newpix += ((pBitmapInfo->bmiHeader.biHeight-1)*bmpwidth);
388
389 //flip bitmap here; SetDIBits assumes origin is left bottom, SetBitmapBits left top
390 //SetDIBits assumes DWORD aligned data
391 //SetBitmapBits assumes WORD aligned data
392 for(int i=0;i<pBitmapInfo->bmiHeader.biHeight;i++) {
393 memcpy(newpix, orgpix, bmpwidth);
394
395 newpix -= bmpwidth;
396 orgpix += dibwidth;
397 }
398 newpix += bmpwidth;
399 ret = O32_SetBitmapBits(hBitmap, pBitmapInfo->bmiHeader.biSizeImage, newpix);
400
401 free(newpix);
402 return ret;
403 }
404#ifdef DEBUG
405 if(pBitmapInfo->bmiHeader.biBitCount == 1) {
406 dprintf(("ERROR: SetDIBits does NOT work well for 1 bpp bitmaps!!!!!"));
407 }
408#endif
409
410 switch(pBitmapInfo->bmiHeader.biBitCount) {
411 case 15:
412 case 16: //Default if BI_BITFIELDS not set is RGB 555
413 bitfields[0] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *(DWORD *)pBitmapInfo->bmiColors : 0x7c00;
414 bitfields[1] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 1) : 0x03e0;
415 bitfields[2] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 2) : 0x001f;
416 break;
417 case 32:
418 bitfields[0] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *(DWORD *)pBitmapInfo->bmiColors : 0xff0000;
419 bitfields[1] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 1) : 0xff00;
420 bitfields[2] = (pBitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) ? *((DWORD *)pBitmapInfo->bmiColors + 2) : 0xff;
421 break;
422 default:
423 bitfields[0] = 0;
424 bitfields[1] = 0;
425 bitfields[2] = 0;
426 break;
427 }
428 if(pBits && bitfields[1] == 0x3E0)
429 {//RGB 555?
430 dprintf(("RGB 555->565 conversion required %x %x %x", bitfields[0], bitfields[1], bitfields[2]));
431
432 int imgsize = CalcBitmapSize(pBitmapInfo->bmiHeader.biBitCount,
433 pBitmapInfo->bmiHeader.biWidth, numlines);
434
435 newbits = (WORD *)malloc(imgsize);
436 if(CPUFeatures & CPUID_MMX) {
437 RGB555to565MMX(newbits, (WORD *)pBits, imgsize/sizeof(WORD));
438 }
439 else RGB555to565(newbits, (WORD *)pBits, imgsize/sizeof(WORD));
440 pBits = newbits;
441 }
442
443 ret = O32_SetDIBits(hdc, hBitmap, startscan, numlines, pBits, pBitmapInfo, usage);
444 if(newbits) free(newbits);
445
446 if(DIBSection::getSection() != NULL)
447 {
448 DIBSection *dsect;
449
450 dsect = DIBSection::findObj(hBitmap);
451 if(dsect) {
452 HBITMAP hBmpOld = SelectObject(hdc, hBitmap);
453 dsect->sync(hdc, 0, dsect->GetHeight());
454 SelectObject(hdc, hBmpOld);
455 }
456 }
457
458 return ret;
459}
460//******************************************************************************
461//******************************************************************************
Note: See TracBrowser for help on using the repository browser.