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

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

workaround added for 32 bpp blitting with matrox display driver

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