Archived

This topic is now archived and is closed to further replies.

JIMbond21

Come on smart people, HELP ME!!!

Recommended Posts

JIMbond21    122
Ok, I know there are a lot of smart and knowlegable people that post on this forum, obviously I''m not one of them. I''ve been trying to create a function for drawing transparent bitmaps with windows gdi and nomatter what I do nothing works, I post the functions I use earlier last night, but evidently no one knows anything about windows gdi and transparent bitmaps, and yes I have done a fair amount of research trying to make this stuff work, but so far unsuccesful. So for those smart and knowlegable poeple out there, can you show me how to draw a bitmap with transparent area of any color choice using windows gdi or look at my functions and tell me whats wrong? The post with the functions was "What''s wrong with this???" on page 2.

Share this post


Link to post
Share on other sites
flangazor    516
From what I recall, straight GDI doesn''t inherently support tranparent bitmaps.

You may be best trying to use libpng in conjunction with png files; which actually have alpha channels.

gl hf

Share this post


Link to post
Share on other sites
CodeMunkie    805
The short answer is you can't do that because GDI does not support transparency, alpha blends, etc. What you have to do is masking. First you have to make what is called a mask image. The mask is a bitmap that is the same dimensions as the image you want to show except it is black and white. You make everything in the mask image that you want to be seen black and everything that you want to be transparent white. In your original image you make the transparent parts black and the parts you want to be seen, well, normal colored.
Now in code, blit the mask to the screen using SRCAND. Then blit your actual image to the screen using SRCINVERT. You now magically have transparency.

EDIT: Ok, I see in your other post you are trying to create the mask on the fly. Maybe the mask is not correct. Have you tried generating the mask image manually?

[edited by - CodeMunkie on August 14, 2003 12:55:38 PM]

Share this post


Link to post
Share on other sites
stimarco    1071
Hi,

You need to look through the MSDN documentation. Search for "Alpha Blending". Their web-based docs on the subject can be found here:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_00h3.asp

Note that this feature isn't supported on all versions of Windows and it does require your bitmaps to be stored in a specific format. The speed will depend on the graphics card's drivers. Most graphics cards now support acceleration of GDI functions, but not all.

--
Sean Timarco Baggaley

(Looking through the rest of the docs they have there, I think they may be describing the GDI API as it currently exists under Windows XP. I'm fairly certain that the Windows 9x series of operating systems never supported this.)

[edited by - stimarco on August 14, 2003 1:06:47 PM]

Share this post


Link to post
Share on other sites
stimarco    1071

Google also throws up this:

http://www.mvps.org/user32/gditutorial.html

Looks like it may answer your questions more directly.

--
Sean Timarco Baggaley

Share this post


Link to post
Share on other sites
Silverbolter    122
Hi,

If you are interested in doing transparent bitmaps with DirectDraw, which you''ll use eventually. Goto the SWEET SNIPPLETS section of gamedev.net and find a tutorial on "Direct Draw the easy way" or something. Basically this tutorial will teach you to setup DirectDraw easily and use it with ddutil.h.

After that, look through the MSDN DirectDraw 7 documention and learn about color keys. If you look into ddutil.h you''ll see CSurface and CDisplay classes which have a set color key function defined. Looking into that code will teach you how to do transparent blits. And lots of other things. All within a class you can use.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by JIMbond21
The post with the functions was "What''s wrong with this???" on page 2.


<A HREF="http://www.gamedev.net/community/forums/topic.asp?topic_id=174751">Here</A>

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
http://www.gamedev.net/community/forums/topic.asp?topic_id=174751

Share this post


Link to post
Share on other sites
OneBitWonder    122
A good windows GDI tutorial can be found at:

www.gametutorials.com

Just click on the tutorials button and then the link that goes into win32 programming tutorials. It will talk about everything you will probably want to know. Transparent blitting, double buffering, keyboard and mouse input, etc...

Share this post


Link to post
Share on other sites
Ilici    862
well u could make ur own alpha blending. use an offscreen buffer for drawing and than blt it to the DC.

look at opengl blending for reference on blending and use that for ur drawing functions - its quite easy

Share this post


Link to post
Share on other sites
jgarcia    122
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

Share this post


Link to post
Share on other sites
JIMbond21    122
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???

Share this post


Link to post
Share on other sites
Colin Jeanne    1114
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

Share this post


Link to post
Share on other sites
jgarcia    122

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

Share this post


Link to post
Share on other sites
JIMbond21    122
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.

Share this post


Link to post
Share on other sites
JIMbond21    122
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 class

class 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.

Share this post


Link to post
Share on other sites
jgarcia    122
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.

Share this post


Link to post
Share on other sites