[win32] bitmapje in een int array naar het scherm

Pagina: 1
Acties:

  • MisterData
  • Registratie: September 2001
  • Laatst online: 21:49
Ben al een tijdje bezig met uit te vogelen hoe ik het snelste een bitmap, die is opgeslagen in een int array (dus per pixel 1 int, 24bits per pixel dus), naar een window kan blitten. Ik heb al een HDC gemaakt (BeginPaint enzo) en ik weet nu ook al hoe ik Bitmaps kan maken (CreateCompatibleBitmap) maar ik kriig er niets in.... ik heb al gekeken naar BitBlt, maar daar kan ik alleen van de ene HDC naar de andere blitten.

Mis ik iets of?? Het is vast heel simpel, maar ik kom er niet uit helaas.....

mijn dank is groot _/-\o_

Verwijderd

WindowHdc = GetDC( WindowHandle );


je moet dus de hdc van je window opvragen en dan met BitBlt um ernaartoe jassen

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

AdmiralAzz: de HDC van z'n window heeft ie juist al, hij moet juist de HDC van z'n bitmap te pakken krijgen

MisterData: Je moet een DC creeeren, en die bitmap daarin selecteren. Doe dat met CreateCompatibleDC (), en dan SelectObject () om de bitmap in de DC te selecteren

vervolgens kun je gewoon blitten met BitBlt

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

crap, verkeerd gelezen dan 8)7

  • MisterData
  • Registratie: September 2001
  • Laatst online: 21:49
.oisyn schreef op 15 April 2003 @ 10:14:
AdmiralAzz: de HDC van z'n window heeft ie juist al, hij moet juist de HDC van z'n bitmap te pakken krijgen

MisterData: Je moet een DC creeeren, en die bitmap daarin selecteren. Doe dat met CreateCompatibleDC (), en dan SelectObject () om de bitmap in de DC te selecteren

vervolgens kun je gewoon blitten met BitBlt
Ja snap ik :| Maar het gaat erom dat ik die int-array in een bitmap krijg 8)7

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

SetBitmapBits, SetDIBits, SetDIBitsToDevice :?

[ Voor 59% gewijzigd door .oisyn op 15-04-2003 12:07 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Oisyn: je vergeet CreateDIBSection :)

En SetBitmapBits is een obsolete 16-bit functie, niet gebruiken dus.

Professionele website nodig?


  • MisterData
  • Registratie: September 2001
  • Laatst online: 21:49
Ik doe het nu met SetDIBitsToDevice... maar het werkt niet:

Afbeeldingslocatie: http://dev.trag.nl/meuk/fout-3dengine.gif

Het zou eigenlijk maar 1 torus knot moeten zijn :| Ik gebruik de volgende code:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
        case WM_PAINT: {
            CCanvas canvas(400,300);
            scene.Render(&canvas, &cam);

            // paint da f*cking canvas
            PAINTSTRUCT ps;
            hdc = BeginPaint(hwnd,&ps);
            
            // convert canvas to a HBITMAP
            BITMAPINFO bmi;
            bmi.bmiHeader.biBitCount = 24;
            bmi.bmiHeader.biClrImportant = 0;
            bmi.bmiHeader.biClrUsed = 0;
            bmi.bmiHeader.biCompression = BI_RGB;
            bmi.bmiHeader.biHeight = canvas.GetHeight();
            bmi.bmiHeader.biPlanes = 1;
            bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
            bmi.bmiHeader.biSizeImage = 0;
            bmi.bmiHeader.biWidth = canvas.GetWidth();
            bmi.bmiHeader.biXPelsPerMeter = 100;
            bmi.bmiHeader.biYPelsPerMeter = 100;

            SetDIBitsToDevice(hdc,0,0,canvas.GetWidth(),canvas.GetHeight(),0,0,0,
canvas.GetHeight(),canvas._buffer, &bmi, DIB_RGB_COLORS);
            
            // EndPaint balances off the BeginPaint call.
            EndPaint(hwnd,&ps);
            }


Ja, er worden teveel variabelen aangemaakt, en nee, het is niet netjesen ja, ik haat windows api-coding maar ik snap niet waarom het zo niet wil werken :(

Verwijderd

kijk anders es naar sdl?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ziet eruit als een verkeerde pixel alignment.
Gokje: je pixels zijn zeker 32 bits integers, terwijl je tegen SetDIBitsToDevice zegt dat het 24 bits per pixel zijn. En is je pixeldata bottom-up of top-down? Voor top-down data moet je de biHeight in de bmiHeader negatief maken.
Bovendien moet elke scanline op een dword-boundary aligned zijn

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MisterData
  • Registratie: September 2001
  • Laatst online: 21:49
.oisyn schreef op 15 april 2003 @ 17:36:
Ziet eruit als een verkeerde pixel alignment.
Gokje: je pixels zijn zeker 32 bits integers, terwijl je tegen SetDIBitsToDevice zegt dat het 24 bits per pixel zijn.
Ik had me vergist in de topicstart: het blijkt een unsigned char array te zijn die breedte*hoogte*3 lang is.
En is je pixeldata bottom-up of top-down? Voor top-down data moet je de biHeight in de bmiHeader negatief maken.
Denk dat ik dat eens ga proberen :)
Bovendien moet elke scanline op een dword-boundary aligned zijn
Leg uit :?

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Zo te zien maak jij een plaatje van 400 pixels breed, en inderdaad 24 bits zoals je stelt. 400 pixels / 8 * 3 = 150 bytes per regel. 150 is helaas niet DWORD (longword) aligned want niet deelbaar door 4. Da's al 1 foutje.

En dit is een enorme bug:
C++:
1
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);

Kvind het redelijk verbazend dat het uberhaupt werkt, maar daar moet je dus wel de sizeof van BITMAPINFOHEADER nemen en zo.

Verder vergeet je wat dingen op 0 te zetten, ik zou als ik jou was de struct als volgt declareren:
C++:
1
BITMAPINFO bmi = { 0 };   // Initializes contents to zero


En btw. Win32 API is allesbehalve lelijk, je moet het alleen even leren. Koop eens de bijbel van Petzold zou ik zeggen.

Professionele website nodig?


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
curry684 schreef op 16 April 2003 @ 00:08:
Kvind het redelijk verbazend dat het uberhaupt werkt, maar daar moet je dus wel de sizeof van BITMAPINFOHEADER nemen en zo.
Ik denk dat het zeker werkt als sizeof(BITMAPINFO) groter is dan sizeof(BITMAPINFOHEADER). Het nut van het opslaan in die structures is juist dat ze later uit te breiden zijn (en dat het besturingssysteem aan de grootte kan zien welke versie van de structure gebruikt wordt). Windows hoort bij een te grote size dus gewoon aan te nemen dat de structure voor een nieuwe versie geschikt is en de structure te accepteren voor zover 'ie 'm kent.
Verder vergeet je wat dingen op 0 te zetten, ik zou als ik jou was de struct als volgt declareren:
C++:
1
BITMAPINFO bmi = { 0 };   // Initializes contents to zero
Volgens mij zet je zo alleen het eerste veld van de structure op 0. Het makkelijkste is, denk ik, het gebruik van memset:
C++:
1
memset(&bmi, 0, sizeof(bmi));

Of desnoods een non-portable variant als ZeroMemory onder Windows of bzero onder UNIX-achtige besturingssystemen.

En btw. Win32 API is allesbehalve lelijk, je moet het alleen even leren. Koop eens de bijbel van Petzold zou ik zeggen.[/quote]

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op 16 April 2003 @ 01:45:
[...]

Ik denk dat het zeker werkt als sizeof(BITMAPINFO) groter is dan sizeof(BITMAPINFOHEADER). Het nut van het opslaan in die structures is juist dat ze later uit te breiden zijn (en dat het besturingssysteem aan de grootte kan zien welke versie van de structure gebruikt wordt). Windows hoort bij een te grote size dus gewoon aan te nemen dat de structure voor een nieuwe versie geschikt is en de structure te accepteren voor zover 'ie 'm kent.
Het nare is alleen dat als er een nieuwere versie is Windows verwacht dat die andere velden, die nu niet bestaan en dus niet kloppen, ook ingevuld zijn, wat er dus voor kan zorgen dat de data niet geaccepteerd wordt

Sterker nog, dat is zelfs al het geval, want er bestaat namelijk ook een BITMAPV4HEADER en een BITMAPV5HEADER. (wat dus uitbreidingen zijn op de BITMAPINFOHEADER)
Volgens mij zet je zo alleen het eerste veld van de structure op 0.
Nee dat is niet zo. Als er een initializer list is dan wordt voor alle members waar geen entry voor is in de initializer list de default (semi)constructor aangeroepen, wat dus resulteert in een initializatie van 0 voor al die members :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
.oisyn schreef op 16 april 2003 @ 10:40:
Nee dat is niet zo. Als er een initializer list is dan wordt voor alle members waar geen entry voor is in de initializer list de default (semi)constructor aangeroepen, wat dus resulteert in een initializatie van 0 voor al die members :)
Oh, dan ben ik in de war met C. Suf trouwens, dat dat zo werkt. Ik zou dan liever die eerste 0 ook weglaten (beetje lomp dat je het eerste veld wel expliciet moet initialiseren en de rest niet). Wat als het eerste veld geen constructor die een integer (of een pointer) accepteert? Dan moet je toch je initialiser aanpassen, terwijl je eigenlijk nog precies hetzelfde wil doen: de default constructor aanroepen.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Een lege initializer list kan ook gewoon ;)

C++:
1
2
3
4
5
6
7
8
struct S
{
    int a, b, c;
};

S a; // niet geinitializeerd
S b = { }; // alles op 0 geinitializeerd
S c = S (); // ook alles op 0


Bovendien werkt het in C ook zo (behalve die laatste optie natuurlijk, waar je een expliciete constructor aanroep doet)

[ Voor 89% gewijzigd door .oisyn op 16-04-2003 11:25 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
.oisyn schreef op 16 April 2003 @ 11:17:
Een lege initializer list kan ook gewoon ;)
Ah, ok. Dan snap ik niet waarom curry het dan nodig vond die 0 toe te voegen, maar de werking die jij omschrijft is in ieder geval een stuk logischer/bruikbaarder.
Bovendien werkt het in C ook zo (behalve die laatste optie natuurlijk, waar je een expliciete constructor aanroep doet)
Hmz, ik dacht dat in C alleen struct members werden geïnitialiseerd voor zover ze gespecifieerd zijn. (Dus "struct X var = { 1, 2, 3 }" initialiseert alleen de eerste 3 members). Dat blijkt (na even testen, natuurlijk) inderdaad niet zo te zijn; als je er 1 initialiseert, initialiseer je ze allemaal. Weer wat geleerd. :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op 16 April 2003 @ 12:51:
Ah, ok. Dan snap ik niet waarom curry het dan nodig vond die 0 toe te voegen
ik denk dat dat een overblijfsel is van een workaround is voor MSVC++ perikelen. Ik werk hier met MSVC++ 5 (sorry, maar het moet even: :r), en die accepteert dus ook geen lege initializer lists :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Dan snap ik niet waarom curry het dan nodig vond die 0 toe te voegen, maar de werking die jij omschrijft is in ieder geval een stuk logischer/bruikbaarder.
Sorry voor oisyn, geen oude aanwensels of zo maar puur om de leesbaarheid. :P

Kwestie van aanleren, ik lees die notatie die ik gebruikte als 'flikker het hele ding op 0'. Bij de andere notaties staat de 0 niet expliciet genoemd wat bij mensen die de notatie niet kennen voor verwarring kan zorgen.

Dit is de eerste keer dat de notatie met 0 juist voor verwarring zorgt :P

Professionele website nodig?


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

.oisyn schreef op 16 april 2003 @ 10:40:
Sterker nog, dat is zelfs al het geval, want er bestaat namelijk ook een BITMAPV4HEADER en een BITMAPV5HEADER. (wat dus uitbreidingen zijn op de BITMAPINFOHEADER)
Inderdaad, en daar BITMAP 4 bytes groter is dan BITMAPINFOHEADER, maar daarmee nog steeds kleiner is dan V4 en V5, had ik verwacht dat de API-call het ding linea recta uit zou kotsen.

Ik meen me namelijk praktijkgevallen te herinneren waarbij Windows structures niet accepteerde als de size niet tot op de byte correct was (en logisch ook om de reden die oisyn geeft).

Wellicht dat het hier geslikt wordt omdat ze intern besluiten dat een size tussen 2 versies in automatisch de oudste impliceert.

Professionele website nodig?


  • MisterData
  • Registratie: September 2001
  • Laatst online: 21:49
*schop* het werkt nog steeds niet...ik heb nu de unsigned char* weggedaan en er nu een int array van gemaakt. Die int is natuurlijk 4 bytes, maar alleen de eerste drie worden gebruikt, kijk maar naar de masks die ik gebruik:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define ALPHA 0xFF000000
#define RED 0xFF0000
#define GREEN 0xFF00
#define BLUE 0xFF
#define MASK7Bit 0xFEFEFF 
#define MASK6Bit 0xFCFCFC
#define RGB 0xFFFFFF

#define INT_GETALPHA(color) ((color&ALPHA)>>32)
#define INT_GETRED(color) ((color&RED)>>16)
#define INT_GETBLUE(color) (color&BLUE)
#define INT_GETGREEN(color) ((color&GREEN)>>8)
#define COLOR_FROM_INT(pix) CColor(INT_GETRED(pix), INT_GETGREEN(pix), INT_GETBLUE(pix))
#define MAKE_COLOR(r,g,b) (ALPHA|(r<<16)|(g<<8)|b)


Maar volgens mij kan Windows niet met deze masks overweg:
The bitmap has a maximum of 2^32 colors. If the biCompression member of the BITMAPINFOHEADER is BI_RGB, the bmiColors member of BITMAPINFO is NULL. Each DWORD in the bitmap array represents the relative intensities of blue, green, and red, respectively, for a pixel. The high byte in each DWORD is not used. The bmiColors color table is used for optimizing colors used on palette-based devices, and must contain the number of entries specified by the biClrUsed member of the BITMAPINFOHEADER.
If the biCompression member of the BITMAPINFOHEADER is BI_BITFIELDS, the bmiColors member contains three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. Each DWORD in the bitmap array represents a single pixel.

Windows NT/ 2000: When the biCompression member is BI_BITFIELDS, bits set in each DWORD mask must be contiguous and should not overlap the bits of another mask. All the bits in the pixel do not need to be used.

Windows 95/98/Me: When the biCompression member is BI_BITFIELDS, the system supports only the following 32-bpp color mask: The blue mask is 0x000000FF, the green mask is 0x0000FF00, and the red mask is 0x00FF0000.
Erg onduidelijk, want er staat Windows 9x voor, hoe zit het dan op Windows NT? Moet ik m'n colormasks anders instellen in m'n 3d engine of kan ik Windows vertellen deze masks van mij te gebruiken?

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

MisterData schreef op 19 april 2003 @ 09:17:
Maar volgens mij kan Windows niet met deze masks overweg:
Die masks zijn toch precies hetzelfde als die van jou of zie ik het verkeerd :?
Erg onduidelijk, want er staat Windows 9x voor, hoe zit het dan op Windows NT? Moet ik m'n colormasks anders instellen in m'n 3d engine of kan ik Windows vertellen deze masks van mij te gebruiken?
Voor NT staat er toch boven? Die pakt als het goed is gewoon alle masks.

Maar aangezien je masks al kloppen voor een 32-bit BI_RGB bitmap, waarom gebruik je dat dan niet gewoon?

www.madwizard.org


Verwijderd

INT_GETALPHA(color) ((color&ALPHA)>>32)
Deze is niet helemaal goed. Je verplaatst je bits 8 posities te ver. Je zult (>>24) willen doen. Niet dat je deze macro gebruikt volgens mij.

[ Voor 26% gewijzigd door Verwijderd op 19-04-2003 12:06 ]


  • MisterData
  • Registratie: September 2001
  • Laatst online: 21:49
madwizard schreef op 19 April 2003 @ 11:20:
[...]

Die masks zijn toch precies hetzelfde als die van jou of zie ik het verkeerd :?


[...]

Voor NT staat er toch boven? Die pakt als het goed is gewoon alle masks.

Maar aangezien je masks al kloppen voor een 32-bit BI_RGB bitmap, waarom gebruik je dat dan niet gewoon?
Stom, stom stom.... het was nog vroeg, had niet gezien dat 0xFF000000 hetzelfde is als 0xFF |:(
Verwijderd schreef op 19 April 2003 @ 12:03:
[...]

Deze is niet helemaal goed. Je verplaatst je bits 8 posities te ver. Je zult (>>24) willen doen. Niet dat je deze macro gebruikt volgens mij.
Bedankt voor deze bugreport ;) Ga het even fixen, gebruik hem idd niet.

  • MisterData
  • Registratie: September 2001
  • Laatst online: 21:49
En het werkt nog steeds niet... alles staat goed volgens mij:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    // paint da f*cking canvas
            PAINTSTRUCT ps;
            hdc = BeginPaint(hwnd,&ps);
            
            // convert canvas to a HBITMAP
            BITMAPINFO bmi;
            memset(&bmi, 0, sizeof(bmi));
            bmi.bmiHeader.biBitCount = 32;
            bmi.bmiHeader.biClrImportant = 0;
            bmi.bmiHeader.biClrUsed = 0;
            bmi.bmiHeader.biCompression = BI_RGB;
            bmi.bmiHeader.biHeight = -canvas.GetHeight();
            bmi.bmiHeader.biPlanes = 1;
            bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
            bmi.bmiHeader.biSizeImage = 0;
            bmi.bmiHeader.biWidth = canvas.GetWidth();
            bmi.bmiHeader.biXPelsPerMeter = 0;
            bmi.bmiHeader.biYPelsPerMeter = 0;


            //SetDIBitsToDevice(hdc,0,0,canvas.GetWidth(),canvas.GetHeight(),0,0,0,canvas.GetHeight(),canvas._buffer, &bmi, DIB_RGB_COLORS);
            //SetDIBitsToDevice(hdc, 0, canvas.GetHeight(), canvas.GetWidth(), canvas.GetHeight(), canvas.GetWidth(), 0, 0, canvas.GetHeight(), canvas._buffer, &bmi, DIB_RGB_COLORS);
            SetDIBitsToDevice(hdc,0,0,canvas.GetWidth(),canvas.GetHeight(), canvas.GetWidth(),    canvas.GetHeight(),    0,  canvas.GetWidth(),   canvas._buffer,     &bmi, DIB_RGB_COLORS   );


Zoals je ziet heb ik een aantal SetDIBitsToDevice-varianten staan, en geen van allen doen ze wat ze moeten doen (of teminste, ze doen niet wat ik ervan verwacht dat ze doen) :'(

  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
effe zoeken - heb zulke code (LONG time ago 32Bits->Screen)

edit:

gevonden, maar ik zie dat ik het net iets anders deed (een beetje sneller maar je snapt vast wel hoe je het omzet).

Ik laat windows eerst een bitmap 'aanmaken' voor me en me een pointer meegeven zodat ik direct in die bitmap can werken: ie dus ik maak slechts een keer die bitmap aan en hergebruik die zodat ik niet voor elke frame vanalles moet doen.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HBITMAP BitmapBuffer; //our BitMap Buffer
int* screen; //where our Bitmap dat WILL Be (ie NOT is)
BITMAPINFO* bmInfo = (BITMAPINFO*)new BYTE[sizeof(BITMAPINFO)+256*4];
bmInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmInfo->bmiHeader.biWidth = xres; //desired width
bmInfo->bmiHeader.biHeight = -yres; //height
bmInfo->bmiHeader.biPlanes = 1; //has to be 1
bmInfo->bmiHeader.biBitCount = 32;
bmInfo->bmiHeader.biCompression = BI_RGB; //uncompressed
bmInfo->bmiHeader.biSizeImage = 0;
bmInfo->bmiHeader.biClrImportant = 0;
bmInfo->bmiHeader.biClrUsed = 0;
bmInfo->bmiHeader.biXPelsPerMeter = 0;
bmInfo->bmiHeader.biYPelsPerMeter = 0;
BitmapBuffer = CreateDIBSection(NULL, bmInfo, DIB_RGB_COLORS, (LPVOID *)&screen, NULL, 0);


nu heb je dus een bitmap waarmee je direct aan de gang kunt. (ik heb toen een windows en dos versie gemaakt want deze methode hoeft er niets meer gecopierd te worden)

en ik teken als volgt
C++:
1
2
3
4
bitmapDC = CreateCompatibleDC(hDC); //HDC heb je vast all
SelectObject(bitmapDC, BitmapBuffer); 
StretchBlt(hDC,0,0,rc.right,rc.bottom, bitmapDC,0,0,xres,yres,SRCCOPY); //of what BLITTER dan ook)
...//clean up


deze code gebruik ik nog dagelijks... dus 2000+ compatible.

Als je nou niet windows je mem wil laten maken kun je eventueel wel met een andere BItmap fucntion zeggen welke ie moet doen...

kijk naar CreateBitmapIndirect + BITMAP struct voor hetzelfde.... (meer wat jij wil denk ik)

[ Voor 99% gewijzigd door hobbit_be op 19-04-2003 15:53 ]


  • MisterData
  • Registratie: September 2001
  • Laatst online: 21:49
woei het werkt! :P hobbit_be bedankt :* Ik had waarschijnlijk een paar keer de breedte en de hoogte omgewisseld, daardoor ging eea niet goed.

  • hobbit_be
  • Registratie: November 2002
  • Laatst online: 04-07-2025
das dan de eerste keer dat ik MisterData heb geholpen ipv vice-versa :)
Pagina: 1