Come on smart people, HELP ME!!!

Started by
16 comments, last by JIMbond21 20 years, 8 months ago
Transparent Bitmaps


Qui fut tout, et qui ne fut rien
Invader''s Realm
Advertisement
In Borland C++ Builder exists a class named "Graphics.TBitmap" with this class you don''t need to use mask for transparency, because this class has a property named "transparent" ... ok its not your case.

I recomend you, to use Mask, its very easy but for each frame of your animation you must need another with only black and white pixels with the exactly same size.

Here is some part of the code, I hope you understand, if not, let me know if you like all the code and I''ll send to you.

...
WM_PAINT:
BeginPaint(hWnd, &PaintStruct);

//First of all, we have an auxiliar Canvas
//then copy the "background" image to the auxiliar canvas.
BitBlt(hAuxDC,0,0,g_ScreenWidth,g_ScreenHeight,
hImgFondoDC,0,0,SRCCOPY);

//Second copy the Mask Image in one position inside the
//auxiliar canvas using the AND operator.
//Remember the mask image always have a white background
//and all other pixels in black ( like a shadow of your
//frame )
BitBlt(hAuxDC,posx,posy,WFRAME,bBits.bmHeight, hMaskDerechaImgDC,WFRAME*tickFrame,0,SRCAND);

//Third, copy the original Frame image ( not the mask )
//in the same position of the mask but using the SRCPAINT
//operator
BitBlt(hAuxDC,posx,posy,WFRAME,bBits.bmHeight,
hImgDC,WFRAME*tickFrame,0,SRCPAINT);

//Finally copy all the auxiliar canvas to your original
//canvas.
BitBlt(hDC,0,0,g_ScreenWidth,g_ScreenHeight,
hAuxDC,0,0,SRCCOPY);

EndPaint(hWnd, &PaintStruct);

...

Regards,
J.Martin
J.Martin Garcia Rangel
I''ve solved the transparent bltting problem, I found that I couldn''t make a mask everytime I wanted to draw the bitmap, I had to make one mask image and use it over and over. Now I need help with the bitmap movement, yes I use a global double buffing system, for better performance, and a high frame rate, but the movement is jumpy and choppy, do any of you know how to fix this???
THX,JAP
quote:Original post by JIMbond21
Now I need help with the bitmap movement, yes I use a global double buffing system, for better performance, and a high frame rate, but the movement is jumpy and choppy, do any of you know how to fix this???


Can you post the code relating to the movement updates?


Qui fut tout, et qui ne fut rien
Invader''s Realm

The movement code it''s the same. If you see the calls to the "BitBlt" function, it takes a several variables:

posx --> The "new" position of the Frame in the X axis
posy --> The "new" position of the Frame in the Y axis
WFRAME --> Is the Width of a single Frame
( I have a single bitmap with all frames with the same
space between them )
tickFrame --> this is the index of the frame that I will paint

In a TIMER I call to the "InvalidateRect" passing the rectangle of the window (0,0,WindowWidth,WindowHeight), this call the paint event. But first in the timer I increase the tickFrame variable.

WM_TIMER:
...
tickFrame++;
if (tickFrame>=NUMFRAMES) tickFrame=0;
InvalidateRect(...)
...

Then when I call the BitBlt function I will show the Frame in the tickFrame position.

Are you using BitBlt ?, I think that is the fast method for paint in a canvas.

J.Martin
J.Martin Garcia Rangel
Well the code is a bit complicated, I couldn''t figure out how to make a global double buffer at the time I was trying to, so I made a double buffer class that had text and bitmap drawing functions built into it. I will post the code for the class and the app that I''m using to test this, which is where the movement problem is occuring and where there transparent problem was, but that''s fixed, later because I going to be busy.
THX,JAP
OK, here''s the source code for my buffer class and the app that I''m trying to test it with.


The buffer class:

//  "Buffer.h"// Includes the standard windows header file// Making sure to avoid redefinition#ifndef _WINDOWS_H_#define _WINDOWS_H_    #include <windows.h>#endif// The Buffer classclass Buffer{public:    // Constructors / Destructor    Buffer ();    Buffer( HWND hwnd );    ~Buffer();    // Buffer controls functions    void CreateBuffer ( HWND hwnd );    void ResizeBuffer( HWND hwnd );    void DrawBufferToWindow();    void ClearBuffer();    void DrawBitmap( HBITMAP hbmBitmap, HBITMAP hbmMask, int x, int y );    void DrawText( char* szText, char* szFont, int Size, COLORREF crColor, bool bBold, bool bItalic, bool bUnderline, int x, int y);private:    // Variables needed    HWND        m_hwnd;    HDC         m_hdcBuffer;    HBITMAP     m_hbmBuffer;    HBITMAP     m_hbmOldBuffer;    RECT        m_rcDimentions;    HDC         m_hdc;    // Private Buffer control functions    int GetStringLength( char* String );};// Constructor, sets most variables to null.// This Constructor is used when making a global// double buffer, it requires the use of the// function void Buffer::CreateBuffer ( HWND hwnd )// following the creation of the window used in the// appliation. "hwnd" points to this window.Buffer::Buffer (){    m_hwnd = NULL;    m_hdcBuffer = NULL;    m_hbmBuffer = NULL;    m_hbmOldBuffer = NULL;    m_hdc = NULL;}// Constructor, creates the double buffer for "hwnd".// This Constructor is used for making a local double// buffer in the message handler of the application.Buffer::Buffer( HWND hwnd ){    m_hwnd = hwnd;    GetClientRect(m_hwnd, &m_rcDimentions);    m_hdc = GetDC(m_hwnd);    m_hdcBuffer = CreateCompatibleDC(m_hdc);    m_hbmBuffer = CreateCompatibleBitmap(m_hdc, m_rcDimentions.right, m_rcDimentions.bottom);    m_hbmOldBuffer = (HBITMAP)SelectObject(m_hdcBuffer, m_hbmBuffer);    FillRect(m_hdcBuffer, &m_rcDimentions, (HBRUSH)GetStockObject(LTGRAY_BRUSH));}// Destructor, deletes the double buffer.Buffer::~Buffer(){    SelectObject(m_hdcBuffer, m_hbmOldBuffer);    DeleteDC(m_hdcBuffer);    DeleteObject(m_hbmBuffer);    ReleaseDC(m_hwnd, m_hdc);}// This function is used when the Buffer()// Constructor is used.  This function creates// the double buffer for "hwnd".void Buffer::CreateBuffer ( HWND hwnd ){    m_hwnd = hwnd;    GetClientRect(m_hwnd, &m_rcDimentions);    m_hdc = GetDC(m_hwnd);    m_hdcBuffer = CreateCompatibleDC(m_hdc);    m_hbmBuffer = CreateCompatibleBitmap(m_hdc, m_rcDimentions.right, m_rcDimentions.bottom);    m_hbmOldBuffer = (HBITMAP)SelectObject(m_hdcBuffer, m_hbmBuffer);    FillRect(m_hdcBuffer, &m_rcDimentions, (HBRUSH)GetStockObject(LTGRAY_BRUSH));}// This function resizes the double buffer// to the new size of the window in the// application. "hwnd" points to the window.void Buffer::ResizeBuffer( HWND hwnd ){    SelectObject(m_hdcBuffer, m_hbmOldBuffer);    DeleteDC(m_hdcBuffer);    DeleteObject(m_hbmBuffer);    ReleaseDC(m_hwnd, m_hdc);    m_hwnd = hwnd;    GetClientRect(m_hwnd, &m_rcDimentions);    m_hdc = GetDC(m_hwnd);    m_hdcBuffer = CreateCompatibleDC(m_hdc);    m_hbmBuffer = CreateCompatibleBitmap(m_hdc, m_rcDimentions.right, m_rcDimentions.bottom);    m_hbmOldBuffer = (HBITMAP)SelectObject(m_hdcBuffer, m_hbmBuffer);    FillRect(m_hdcBuffer, &m_rcDimentions, (HBRUSH)GetStockObject(LTGRAY_BRUSH));}// This function draws a bitmap to the double buffer,// with "hbmBitmap" pointing to the bitmap, "hbmMask"// is the mask for bitmap transparency for "hbmBitmap,// and "x" and "y" are the position relative to the// window of where the bitmap will be drawn.void Buffer::DrawBitmap( HBITMAP hbmBitmap, HBITMAP hbmMask, int x, int y ){    BITMAP bitmap;    HDC hdcMem = CreateCompatibleDC(m_hdcBuffer);    HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMask);    GetObject(hbmBitmap, sizeof(bitmap), &bitmap);    BitBlt(m_hdcBuffer, x, y, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCAND);    SelectObject(hdcMem, hbmBitmap);    BitBlt(m_hdcBuffer, x, y, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCPAINT);    SelectObject(hdcMem, hbmOld);    DeleteDC(hdcMem);}// This function draws text to the double buffer at the// postion specified by "x" and "y". "szText" is the text// to be drawn and "szFont" is the font face that it uses,// "Size" is the point size the text is drawn, "crColor"// is the color of the text, "bBold" is true if the// text is bold, "bItalic" is true if the text is italic,// and "bUnderline" is true if the text is underlined.void Buffer::DrawText( char* szText, char* szFont, int Size, COLORREF crColor, bool bBold, bool bItalic, bool bUnderline, int x, int y){    HFONT hfFont;    long lfHeight;        HDC hdc2 = GetDC(NULL);    lfHeight = -MulDiv(Size, GetDeviceCaps(hdc2, LOGPIXELSY), 72);    ReleaseDC(NULL, hdc2);    hfFont = CreateFont(lfHeight, 0, 0, 0, 700 * bBold, bItalic, bUnderline, 0, 0, 0, 0, 0, 0, szFont);    HFONT hfFontOld = (HFONT)SelectObject(m_hdcBuffer, hfFont);    SetBkColor(m_hdcBuffer, RGB(255,255,255));    SetTextColor(m_hdcBuffer, crColor);    SetBkMode(m_hdcBuffer, TRANSPARENT);    TextOut(m_hdcBuffer, x, y, szText, GetStringLength(szText));    SetTextColor(m_hdcBuffer, RGB(0,0,0));    SelectObject(m_hdcBuffer, hfFontOld);    DeleteObject(hfFont);}// This function draws the double buffer to the// current window in "m_hwnd", the HWND variable// for the class.void Buffer::DrawBufferToWindow(){    BitBlt(m_hdc, 0, 0, m_rcDimentions.right, m_rcDimentions.bottom, m_hdcBuffer, 0, 0, SRCCOPY);}// This function clears the double buffer to// a light gray color.void Buffer::ClearBuffer(){    FillRect(m_hdcBuffer, &m_rcDimentions, (HBRUSH)GetStockObject(LTGRAY_BRUSH));}// This function returns the length of the string// that is passed to it, used in the DrawText method.int Buffer::GetStringLength( char* String ){    int Length;    for(Length = 0; *String; String++, Length++);    return Length;}


The app:

#ifndef _WINDOWS_H_#define _WINDOWS_H_    #include <windows.h>#endif#include "Buffer.h"const char game_name[] = "Bitmaps";HWND game_window = NULL;HINSTANCE game_instance;Buffer bBuffer;bool game_done = false;HBITMAP hbmBall = NULL;HBITMAP hbmMask = NULL;void Wait( float Time ){    MSG msg;    int Start = GetTickCount();    while((GetTickCount() - Start) < (33 * Time))    {        if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){			TranslateMessage(&msg);			DispatchMessage(&msg);		}    }}HBITMAP CreateBitmapMask( HBITMAP hbmBitmap, COLORREF crTransparent ){    HDC hdcMem, hdcMem2;    HBITMAP hbmMask;    BITMAP bitmap;    GetObject(hbmBitmap, sizeof(BITMAP), &bitmap);    hbmMask = CreateBitmap(bitmap.bmWidth, bitmap.bmHeight, 1, 1, NULL);    hdcMem = CreateCompatibleDC(0);    hdcMem2 = CreateCompatibleDC(0);    SelectObject(hdcMem, hbmBitmap);    SelectObject(hdcMem2, hbmMask);    COLORREF crOld = SetBkColor(hdcMem, crTransparent);    BitBlt(hdcMem2, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);    BitBlt(hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem2, 0, 0, SRCINVERT);    SetBkColor(hdcMem, crOld);    DeleteDC(hdcMem);    DeleteDC(hdcMem2);    return hbmMask;}LRESULT CALLBACK game_proc(HWND hwnd, UINT msg,WPARAM wParam,LPARAM lParam){    switch(msg)    {    case WM_CREATE:        hbmBall = (HBITMAP)LoadImage(NULL,"Redball.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);        hbmMask = CreateBitmapMask(hbmBall, RGB(255,255,255));    case WM_SIZE:        bBuffer.ResizeBuffer(hwnd);        return 0;    case WM_CLOSE:		game_done = true;		return 0;	case WM_DESTROY:		PostQuitMessage(0);		return 0;    default:        return DefWindowProc(hwnd, msg, wParam, lParam);    }}int APIENTRY WinMain( HINSTANCE p_instance, HINSTANCE p_prev_instance, LPSTR p_cmd_line, int p_show ){    MSG msg;	game_instance = p_instance;	WNDCLASS window_class;	window_class.style				= CS_OWNDC;	window_class.cbClsExtra			= 0;	window_class.cbWndExtra			= 0;	window_class.hInstance			= game_instance;	window_class.hIcon				= LoadIcon(NULL,IDI_WINLOGO);	window_class.hCursor			= LoadCursor(NULL,IDC_ARROW);	window_class.hbrBackground		= (HBRUSH)GetStockObject(LTGRAY_BRUSH);	window_class.lpszMenuName		= NULL;	window_class.lpszClassName		= "Game Class";	window_class.lpfnWndProc		= game_proc;    if(!RegisterClass(&window_class)){        MessageBox(game_window, "Couldn''t register class", "Error", MB_OK | MB_ICONEXCLAMATION);        return 0;	}    game_window = CreateWindow("Game Class",game_name,WS_OVERLAPPEDWINDOW | WS_VISIBLE,0,0,640,480,NULL,NULL,game_instance,NULL);    bBuffer.CreateBuffer(game_window);    int x = 100;    int y = 100;    char String[100];    while(!game_done){        if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){			TranslateMessage(&msg);			DispatchMessage(&msg);		}        if(GetKeyState(VK_UP)&0x80){            y -= 10;        }        if(GetKeyState(VK_DOWN)&0x80){            y += 10;        }        if(GetKeyState(VK_RIGHT)&0x80){            x += 10;        }        if(GetKeyState(VK_LEFT)&0x80){            x -= 10;        }        if(GetKeyState(''R'')&0x80){            x = 100;            y = 100;        }        bBuffer.ClearBuffer();        wsprintf(String,"%d, %d",x,y);        bBuffer.DrawText(String,"Comic Sans MS",20,RGB(255,255,255),1,0,0,0,0);        bBuffer.DrawBitmap(hbmBall,hbmMask,x,y);        bBuffer.DrawBufferToWindow();        Wait(0.1);    }    if(!DestroyWindow(game_window)){        MessageBox(game_window, "Couldn''t destroy window", "Error", MB_OK | MB_ICONEXCLAMATION);        return 0;	}	game_window = NULL;	if(!UnregisterClass("Game Class",game_instance)){        MessageBox(game_window, "Couldn''t unregister class", "Error", MB_OK | MB_ICONEXCLAMATION);        return 0;	}	return 0;}


Well let me know if anyone can figure why the movement is jumpy and choppy.
THX,JAP
Your paint code it''s ok. Your problem is the movement, this is because the Frame is moving too fast. I think you must use a TIMER with some Interval, maybe 300 - 500 milisenconds.
This timer must evaluate if the user user press one key then move the frame in the correct direction, BUT NOT IN A WHILE, each time that the timer event execute you must move ( if its requiered ) the frame.
J.Martin Garcia Rangel

This topic is closed to new replies.

Advertisement