Thread: Rendering 32-bit images - alpha is ignored

  1. #16
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    You need to explain to me what the difference is. Plain Win32 API doesn't mean anything to me as I'm using Windows functions as AlphaBlend and DrawDibDraw are both things in the Windows SDK. Please explain this.

    Also, I editted my previous message with more clues I found.

  2. #17
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by ulillillia View Post
    I loaded a TGA image with alpha channel used (32-bit color)
    Can you show the code that does this? Exactly how is the BMPInfo and BMP data getting filled out? All the basic calls look right, so I'm suspecting bogus or corrupted data somewhere.

  3. #18
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    Ok, I didn't know that DrawDib was also standard Win32, but what I mean is only using the standard GDI functions declared in wingdi.h and (some of them) defined in msimg32.lib.
    I don't know if that's correct, but try to stick to functions like AlphaBlend, CreateDIBitmap(), nothing that has to do with "DrawDib", to see if it does work with just GDI.

  4. #19
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    Well, I apparently need to post everything related to it....

    Code:
    struct SceneryData
    {
    	int XMain; // base integer X position
    	int YMain; // base integer Y position
    	double x; // actual X position
    	double y; // actual Y position
    	double Scaling; // background scaling (distance)
    };
    
    BLENDFUNCTION AlphaUsage; // the blend function
    
    unsigned char MountainsData[524288]; // The mountains background (1024x128 image at 32-bit color)
    LPVOID MountainsDataPointer;
    BITMAPINFOHEADER MountainsInfo;
    LPBITMAPINFOHEADER MountainsInfoPointer;
    struct SceneryData Mountains;
    
    FILE *FileHandle; // handle for reading/writing files
    
    char LoadFile(const char FileName[64], char FileType, BITMAPINFOHEADER *BMPInfo, unsigned char *BMPData)
    {
    	char BasePath[128]; // the base path, that of which started from
    	char FullFileName[192]; // the full path combining the base path and the parameter
    	unsigned int ArrayIndex = 0;
    	float NewColor = 0;
    	
    	strcpy(BasePath, "C:\\My Documents\\My programs\\Interactive Animation\\"); // get the obvious base path first
    	sprintf(FullFileName, "%s%s", BasePath, FileName); // combine the base path and file name
    	FileHandle = fopen(FullFileName, "rb"); // read the source file to display, binary mode
    	
    	// FileHandle = fopen(FileName, "rb"); // read the source file to display, binary mode
    	
    	// skip first 18 bytes for TGA then read in BGRA format
    	
    	if (FileHandle == 0) // if the file can't be found
    	{
    		return 1; // indicates an error occurred
    	}
    	
    	if (FileType == 1) // reading a BMP file
    	{
    		fseek(FileHandle, 14, SEEK_SET); // skip the basic file header data but read from the info header
    		fread(&BMPInfo->biSize, 4, 1, FileHandle); // bytes 0E through 11
    		fread(&BMPInfo->biWidth, 4, 1, FileHandle); // 12 through 15
    		fread(&BMPInfo->biHeight, 4, 1, FileHandle); // 16 through 19
    		fread(&BMPInfo->biPlanes, 2, 1, FileHandle); // 1A and 1B
    		fread(&BMPInfo->biBitCount, 2, 1, FileHandle); // 1C and 1D
    		fread(&BMPInfo->biCompression, 4, 1, FileHandle); // 1E through 21
    		fread(&BMPInfo->biSizeImage, 4, 1, FileHandle); // 22 through 25
    		fread(&BMPInfo->biXPelsPerMeter, 4, 1, FileHandle); // 26 through 29
    		fread(&BMPInfo->biYPelsPerMeter, 4, 1, FileHandle); // 2A through 2D
    		fread(&BMPInfo->biClrUsed, 4, 1, FileHandle); // 2E through 31
    		fread(&BMPInfo->biClrImportant, 4, 1, FileHandle); // 32 through 35
    		fread(BMPData, 1, BMPInfo->biSizeImage, FileHandle); // read the main image data // reads in BGR format
    	}
    	
    	if (FileType == 2) // reading a TGA file
    	{
    		fseek(FileHandle, 12, SEEK_SET); // skip the basic file header data but read from the info header
    		BMPInfo->biSize = 40; // the size of the struct, always 40 in my case (due to true color being used)
    		fread(&BMPInfo->biWidth, 2, 1, FileHandle); // image width, 2 bytes in the case of TGAs
    		fread(&BMPInfo->biHeight, 2, 1, FileHandle); // image height, 2 bytes in the case of TGAs
    		BMPInfo->biPlanes = 1; // always 1
    		BMPInfo->biBitCount = 32; // number of bits per pixel, always to be 32 for TGA images (due to alpha channel)
    		BMPInfo->biCompression = BI_RGB; // no compression used
    		BMPInfo->biSizeImage = BMPInfo->biWidth*BMPInfo->biHeight*4; // width times height times bitcount divided by 8 gives the image data size
    		BMPInfo->biXPelsPerMeter = 2835; // resolution in pixels per meter
    		BMPInfo->biYPelsPerMeter = 2835;
    		BMPInfo->biClrUsed = 0; // always 0 in my case
    		BMPInfo->biClrImportant = 0; // same here
    		fseek(FileHandle, 18, SEEK_SET); // skip to the main image data
    		fread(BMPData, 1, BMPInfo->biSizeImage, FileHandle); // read the main image data // reads in BGRA format
    		
    		if (DebugTest[0] == 0) // Wow!  It's a test!
    		{
    			DebugTest[1] = (int)BMPData[331776]; // the pixel at 0, 46 in The GIMP in the TGA image to be opened
    			DebugTest[2] = (int)BMPData[331777];
    			DebugTest[3] = (int)BMPData[331778];
    			DebugTest[4] = (int)BMPData[331779];
    		}
    		
    		while (ArrayIndex < BMPInfo->biSizeImage) // premultiplies the colors for alphablend to work
    		{
    			/*
    			BMPData[ArrayIndex] = BMPData[ArrayIndex] * BMPData[ArrayIndex+3] / 255;
    			BMPData[ArrayIndex+1] = BMPData[ArrayIndex+1] * BMPData[ArrayIndex+3] / 255;
    			BMPData[ArrayIndex+2] = BMPData[ArrayIndex+2] * BMPData[ArrayIndex+3] / 255;
    			*/
    			
    			NewColor = (float)BMPData[ArrayIndex]*(float)BMPData[ArrayIndex+3]/255.0+0.5;
    			BMPData[ArrayIndex] = (unsigned char)NewColor;
    			NewColor = (float)BMPData[ArrayIndex+1]*(float)BMPData[ArrayIndex+3]/255.0+0.5;
    			BMPData[ArrayIndex+1] = (unsigned char)NewColor;
    			NewColor = (float)BMPData[ArrayIndex+2]*(float)BMPData[ArrayIndex+3]/255.0+0.5;
    			BMPData[ArrayIndex+2] = (unsigned char)NewColor;
    			ArrayIndex += 4;
    		}
    		
    		if (DebugTest[0] == 0) // Nice, anyone for a test?
    		{
    			DebugTest[0] = 1; // so this test is processed only once
    			DebugTest[5] = (int)BMPData[331776]; // the same pixel, but after premultiplication is applied
    			DebugTest[6] = (int)BMPData[331777];
    			DebugTest[7] = (int)BMPData[331778];
    			DebugTest[8] = (int)BMPData[331779];
    			
    			sprintf(DebugDetails, "The previous color values were %d %d %d %d.\nThe new color values are %d %d %d %d.", DebugTest[1], DebugTest[2], DebugTest[3], DebugTest[4], DebugTest[5], DebugTest[6], DebugTest[7], DebugTest[8]); // for debugging
    			MessageBox(hwnd, DebugDetails, "Debug Results", MB_OK);
    		}
    	}
    	
    	fclose(FileHandle); // close the file releasing the handle
    	
    	return 0;
    }
    
    void InitiateObjectPositions()
    {
    	Logo.x = 0.0;
    	Logo.y = 64.0;
    	Logo.Scaling = 1.0;
    	Mountains.x = 4.0;
    	Mountains.XMain = 4;
    	Mountains.y = 116.0;
    	Mountains.YMain = 116;
    	Mountains.Scaling = 1125;
    }
    
    void InitializeDrawing()
    {
    	HDCScreen = GetDC(hwnd); // set the screen buffer DC
    	HDCBack = CreateCompatibleDC(HDCScreen); // create a compatible DC, of which is to be used for drawing into the back buffer
    	HBMPBack = CreateCompatibleBitmap(HDCScreen, 800, 600); // create compatible bitmap, used for drawing into, but not on screen
    	SelectObject(HDCBack, HBMPBack); // select the created bitmap
    	ImageHandle = DrawDibOpen(); // set the DrawDib DC handle
    	AlphaUsage.BlendOp = 0;
    	AlphaUsage.BlendFlags = 0;
    	AlphaUsage.SourceConstantAlpha = 255;
    	AlphaUsage.AlphaFormat = AC_SRC_ALPHA;
    	
    	... // unrelated code for setting up front and back buffers' BITMAPINFOHEADER structures
    }
    
    void DrawScenery()
    {
    	/* This function renders and displays the scene.
    	Rules:
    	
    	*  The entire area must be filled, no gaps nor exceptions (the side and sky objects do this)
    	*  The scene must be ordered so that it is drawn back to front.
    	*  The scene should tile when neccessary cropping it so that it doesn't exceed the interior window area.
    	*  Use for loops for repeated drawing of the same image.
    	*  Draw into the back buffer then blit it into the front buffer before actually drawing the scene.
    	*/
    	
    	DrawDibDraw(ImageHandle, HDCBack, 0, 0, SkyBGInfo.biWidth, SkyBGInfo.biHeight, SkyBGInfoPointer, SkyBGDataPointer, 0, 0, SkyBGInfo.biWidth, SkyBGInfo.biHeight, 0);
    	DrawDibDraw(ImageHandle, HDCBack, 0, 240, FogInfo.biWidth, FogInfo.biHeight, FogInfoPointer, FogDataPointer, 0, 0, FogInfo.biWidth, FogInfo.biHeight, 0);
    	// DrawDibDraw(ImageHandle, HDCBack, Mountains.XMain, Mountains.YMain, MountainsInfo.biWidth, MountainsInfo.biHeight, MountainsInfoPointer, MountainsDataPointer, 0, 0, MountainsInfo.biWidth, MountainsInfo.biHeight, 0);
    	// BitBlt(HDCBack, Mountains.XMain, Mountains.YMain, MountainsInfo.biWidth, MountainsInfo.biHeight, HDCScreen, MountainsInfo.biWidth, MountainsInfo.biHeight, SRCCOPY); // just another old-fashioned test
    	AlphaBlend(HDCBack, Mountains.XMain, Mountains.YMain, MountainsInfo.biWidth, MountainsInfo.biHeight, HDCScreen, 0, 0, MountainsInfo.biWidth, MountainsInfo.biHeight, AlphaUsage);
    	DrawDibDraw(ImageHandle, HDCBack, Logo.XMain, Logo.YMain, LogoInfo.biWidth, LogoInfo.biHeight, LogoInfoPointer, LogoDataPointer, 0, 0, LogoInfo.biWidth, LogoInfo.biHeight, 0);
    	DrawDibDraw(ImageHandle, HDCBack, 640, 0, RightSidePanelInfo.biWidth, RightSidePanelInfo.biHeight, RightSidePanelInfoPointer, RightSidePanelDataPointer, 0, 0, RightSidePanelInfo.biWidth, RightSidePanelInfo.biHeight, 0);
    	DrawDibDraw(ImageHandle, HDCBack, 0, 480, BottomSidePanelInfo.biWidth, BottomSidePanelInfo.biHeight, BottomSidePanelInfoPointer, BottomSidePanelDataPointer, 0, 0, BottomSidePanelInfo.biWidth, BottomSidePanelInfo.biHeight, 0);
    	
    	BitBlt(HDCScreen, 0, 0, WindowSizeBase.x, WindowSizeBase.y, HDCBack, 0, 0, SRCCOPY); // swaps the back and front buffers for displaying
    }
    
    // in the main windows function:
    
    	DebugTest[0] = 0; // set up for debugging stuff to prevent message boxes from appearing nonstop without end
    	InitializeDrawing(); // set up HDC's, front and back buffers, and alpha blend details
    	
    	LoadFile("Logo.bmp", 1, &LogoInfo, &LogoData);
    	LogoInfoPointer = &LogoInfo;
    	LogoDataPointer = &LogoData;
    	LoadFile("SkyBG.bmp", 1, &SkyBGInfo, &SkyBGData);
    	SkyBGInfoPointer = &SkyBGInfo;
    	SkyBGDataPointer = &SkyBGData;
    	LoadFile("Fog.bmp", 1, &FogInfo, &FogData);
    	FogInfoPointer = &FogInfo;
    	FogDataPointer = &FogData;
    	LoadFile("MountainsBG.tga", 2, &MountainsInfo, &MountainsData);
    	MountainsInfoPointer = &MountainsInfo;
    	MountainsDataPointer = &MountainsData;
    	LoadFile("RightSidePanel.bmp", 1, &RightSidePanelInfo, &RightSidePanelData);
    	RightSidePanelInfoPointer = &RightSidePanelInfo;
    	RightSidePanelDataPointer = &RightSidePanelData;
    	LoadFile("BottomSidePanel.bmp", 1, &BottomSidePanelInfo, &BottomSidePanelData);
    	BottomSidePanelInfoPointer = &BottomSidePanelInfo;
    	BottomSidePanelDataPointer = &BottomSidePanelData;
    	
    	InitiateObjectPositions(); // sets positions for the objects
    	
    	while(GameRunning == 1) // this is the main loop
    	{
    		PeekMessage(&msg,hwnd,NULL,NULL,PM_REMOVE);
    		if (msg.message == WM_QUIT) // check for a quit message
    		{
    			GameRunning = 0; // if found, quit app
    			break;
    		}
    		
    		else
    		{
    			// At the start of each frame, the clock is advanced as close as possible to 1/60 of a second.
    			AdvanceClock();
    
    			// Next, keyboard input should be processed
    			ProcessInput();
    			
    			// After that, the positions of the objects are processed
    			MoveObjects();
    
    			// Then, the scene must be drawn
    			DrawScenery();
    			
    			// Finally, translate and dispatch any Windows messages into event queue
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    	}
    	
    	// free up handles and other resources
    	DrawDibClose(ImageHandle); // free the resources
    	ReleaseDC(hwnd, HDCScreen); // free the DC handles
    	DeleteDC(HDCBack);
    	DeleteObject(HBMPBack);
    }
    Yeah, it's a lot of code, but it appears as if I need to post this much. Unrelated code and functions are left out. Heh, if it helps, I'll even post the image in question. Download the ZIP file containing the TGA here. All other files are BMPs and they display perfectly fine with DrawDibDraw. Since the thread has gone on to page 2, I figured I'd post the results I'm seeing and this is the best screenshot I've uploaded showing the effects very clearly. If it helps, this is what I should be seeing (as a simulated screenshot, created through a simple modification in The GIMP).

  5. #20
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by ulillillia View Post
    Code:
    		fread(&BMPInfo->biWidth, 2, 1, FileHandle); // image width, 2 bytes in the case of TGAs
    		fread(&BMPInfo->biHeight, 2, 1, FileHandle); // image height, 2 bytes in the case of TGAs
    This is a problem. The biWidth and biHeight fields are LONG variables, but you're only reading 2 bytes into them. The high bytes remain uninitialized. You make the same mistake in the BMP loader as well.

    The funny repetitive effect you are seeing is a pretty typical symptom of having corrupted values.

    Also, you should never read multi-byte quantities directly into memory. In the case of TGA you got lucky because the values are little-endian and so is your machine. But this is not guaranteed to be the case. Instead, you should read each byte of the multi-byte quantity and pack the bytes into an integer as appropriate to their endianness.

  6. #21
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    Okay, so I made the changes and now the TGA isn't being displayed at all. The BMPs, however, are displaying perfectly fine. What else is wrong?

    Code:
    // updated LoadFile function
    
    char LoadFile(const char FileName[64], char FileType, BITMAPINFOHEADER *BMPInfo, unsigned char *BMPData)
    {
    	char BasePath[128]; // the base path, that of which started from
    	char FullFileName[192]; // the full path combining the base path and the parameter
    	unsigned int ArrayIndex = 0;
    	float NewColor = 0;
    	unsigned char ValuesBase[4]; // for fixing endianness
    	
    	strcpy(BasePath, "C:\\My Documents\\My programs\\Interactive Animation\\"); // get the obvious base path first
    	sprintf(FullFileName, "&#37;s%s", BasePath, FileName); // combine the base path and file name
    	FileHandle = fopen(FullFileName, "rb"); // read the source file to display, binary mode
    	
    	// FileHandle = fopen(FileName, "rb"); // read the source file to display, binary mode
    	
    	// skip first 18 bytes for TGA then read in BGRA format
    	
    	if (FileHandle == 0) // if the file can't be found
    	{
    		return 1; // indicates an error occurred
    	}
    	
    	if (FileType == 1) // reading a BMP file
    	{
    		fseek(FileHandle, 14, SEEK_SET); // skip the basic file header data but read from the info header
    		fread(&ValuesBase, 1, 4, FileHandle); // bytes 0E through 11
    		BMPInfo->biSize = (DWORD)ValuesBase[0]+(DWORD)ValuesBase[1]*256+(DWORD)ValuesBase[2]*65536+(DWORD)ValuesBase[3]*16777216;
    		fread(&ValuesBase, 1, 4, FileHandle); // bytes 0E through 11
    		BMPInfo->biWidth = (long)ValuesBase[0]+(long)ValuesBase[1]*256+(long)ValuesBase[2]*65536+(long)ValuesBase[3]*16777216;
    		fread(&ValuesBase, 1, 4, FileHandle); // bytes 0E through 11
    		BMPInfo->biHeight = (long)ValuesBase[0]+(long)ValuesBase[1]*256+(long)ValuesBase[2]*65536+(long)ValuesBase[3]*16777216;
    		fread(&ValuesBase, 1, 2, FileHandle); // bytes 0E through 11
    		BMPInfo->biPlanes = (WORD)ValuesBase[0]+(WORD)ValuesBase[1]*256;
    		fread(&ValuesBase, 1, 2, FileHandle); // bytes 0E through 11
    		BMPInfo->biBitCount = (WORD)ValuesBase[0]+(WORD)ValuesBase[1]*256;
    		fread(&ValuesBase, 1, 4, FileHandle); // bytes 0E through 11
    		BMPInfo->biCompression = (DWORD)ValuesBase[0]+(DWORD)ValuesBase[1]*256+(DWORD)ValuesBase[2]*65536+(DWORD)ValuesBase[3]*16777216;
    		fread(&ValuesBase, 1, 4, FileHandle); // bytes 0E through 11
    		BMPInfo->biSizeImage = (DWORD)ValuesBase[0]+(DWORD)ValuesBase[1]*256+(DWORD)ValuesBase[2]*65536+(DWORD)ValuesBase[3]*16777216;
    		fread(&ValuesBase, 1, 4, FileHandle); // bytes 0E through 11
    		BMPInfo->biXPelsPerMeter = (long)ValuesBase[0]+(long)ValuesBase[1]*256+(long)ValuesBase[2]*65536+(long)ValuesBase[3]*16777216;
    		fread(&ValuesBase, 1, 4, FileHandle); // bytes 0E through 11
    		BMPInfo->biYPelsPerMeter = (long)ValuesBase[0]+(long)ValuesBase[1]*256+(long)ValuesBase[2]*65536+(long)ValuesBase[3]*16777216;
    		fread(&ValuesBase, 1, 4, FileHandle); // bytes 0E through 11
    		BMPInfo->biClrUsed = (DWORD)ValuesBase[0]+(DWORD)ValuesBase[1]*256+(DWORD)ValuesBase[2]*65536+(DWORD)ValuesBase[3]*16777216;
    		fread(&ValuesBase, 1, 4, FileHandle); // bytes 0E through 11
    		BMPInfo->biClrImportant = (DWORD)ValuesBase[0]+(DWORD)ValuesBase[1]*256+(DWORD)ValuesBase[2]*65536+(DWORD)ValuesBase[3]*16777216;
    		fread(BMPData, 1, BMPInfo->biSizeImage, FileHandle); // read the main image data // reads in BGR format
    		
    		/*
    		fread(&BMPInfo->biSize, 4, 1, FileHandle); // bytes 0E through 11
    		fread(&BMPInfo->biWidth, 4, 1, FileHandle); // 12 through 15
    		fread(&BMPInfo->biHeight, 4, 1, FileHandle); // 16 through 19
    		fread(&BMPInfo->biPlanes, 2, 1, FileHandle); // 1A and 1B
    		fread(&BMPInfo->biBitCount, 2, 1, FileHandle); // 1C and 1D
    		fread(&BMPInfo->biCompression, 4, 1, FileHandle); // 1E through 21
    		fread(&BMPInfo->biSizeImage, 4, 1, FileHandle); // 22 through 25
    		fread(&BMPInfo->biXPelsPerMeter, 4, 1, FileHandle); // 26 through 29
    		fread(&BMPInfo->biYPelsPerMeter, 4, 1, FileHandle); // 2A through 2D
    		fread(&BMPInfo->biClrUsed, 4, 1, FileHandle); // 2E through 31
    		fread(&BMPInfo->biClrImportant, 4, 1, FileHandle); // 32 through 35
    		fread(BMPData, 1, BMPInfo->biSizeImage, FileHandle); // read the main image data // reads in BGR format
    		*/
    	}
    	
    	if (FileType == 2) // reading a TGA file
    	{
    		fseek(FileHandle, 12, SEEK_SET); // skip the basic file header data but read from the info header
    		BMPInfo->biSize = 40; // the size of the struct, always 40 in my case (due to true color being used)
    		fread(&ValuesBase, 1, 2, FileHandle);
    		BMPInfo->biWidth = (long)ValuesBase[0]+(long)ValuesBase[1]*256; // only two bytes are read for TGAs
    		fread(&ValuesBase, 1, 2, FileHandle);
    		BMPInfo->biWidth = (long)ValuesBase[0]+(long)ValuesBase[1]*256; // only two bytes are read for TGAs
    		
    		// fread(&BMPInfo->biWidth, 2, 1, FileHandle); // image width, 2 bytes in the case of TGAs
    		// fread(&BMPInfo->biHeight, 2, 1, FileHandle); // image height, 2 bytes in the case of TGAs
    		BMPInfo->biPlanes = 1; // always 1
    		BMPInfo->biBitCount = 32; // number of bits per pixel, always to be 32 for TGA images (due to alpha channel)
    		BMPInfo->biCompression = BI_RGB; // no compression used
    		BMPInfo->biSizeImage = BMPInfo->biWidth*BMPInfo->biHeight*4; // width times height times bitcount divided by 8 gives the image data size
    		BMPInfo->biXPelsPerMeter = 2835; // resolution in pixels per meter
    		BMPInfo->biYPelsPerMeter = 2835;
    		BMPInfo->biClrUsed = 0; // always 0 in my case
    		BMPInfo->biClrImportant = 0; // same here
    		fseek(FileHandle, 18, SEEK_SET); // skip to the main image data
    		fread(BMPData, 1, BMPInfo->biSizeImage, FileHandle); // read the main image data // reads in BGRA format
    		
    		if (DebugTest[0] == 0) // Wow!  It's a test!
    		{
    			DebugTest[1] = (int)BMPData[331776];
    			DebugTest[2] = (int)BMPData[331777];
    			DebugTest[3] = (int)BMPData[331778];
    			DebugTest[4] = (int)BMPData[331779];
    		}
    		
    		while (ArrayIndex < BMPInfo->biSizeImage) // premultiplies the colors for alphablend to work
    		{
    			/*
    			BMPData[ArrayIndex] = BMPData[ArrayIndex] * BMPData[ArrayIndex+3] / 255;
    			BMPData[ArrayIndex+1] = BMPData[ArrayIndex+1] * BMPData[ArrayIndex+3] / 255;
    			BMPData[ArrayIndex+2] = BMPData[ArrayIndex+2] * BMPData[ArrayIndex+3] / 255;
    			*/
    			
    			NewColor = (float)BMPData[ArrayIndex]*(float)BMPData[ArrayIndex+3]/255.0+0.5;
    			BMPData[ArrayIndex] = (unsigned char)NewColor;
    			NewColor = (float)BMPData[ArrayIndex+1]*(float)BMPData[ArrayIndex+3]/255.0+0.5;
    			BMPData[ArrayIndex+1] = (unsigned char)NewColor;
    			NewColor = (float)BMPData[ArrayIndex+2]*(float)BMPData[ArrayIndex+3]/255.0+0.5;
    			BMPData[ArrayIndex+2] = (unsigned char)NewColor;
    			ArrayIndex += 4;
    		}
    		
    		if (DebugTest[0] == 0) // Nice, anyone for a test?
    		{
    			DebugTest[0] = 1; // so this test is processed only once
    			DebugTest[5] = (int)BMPData[331776];
    			DebugTest[6] = (int)BMPData[331777];
    			DebugTest[7] = (int)BMPData[331778];
    			DebugTest[8] = (int)BMPData[331779];
    			
    			sprintf(DebugDetails, "The previous color values were %d %d %d %d.\nThe new color values are %d %d %d %d.", DebugTest[1], DebugTest[2], DebugTest[3], DebugTest[4], DebugTest[5], DebugTest[6], DebugTest[7], DebugTest[8]); // for debugging
    			MessageBox(hwnd, DebugDetails, "Debug Results", MB_OK);
    		}
    	}
    	
    	fclose(FileHandle); // close the file releasing the handle
    	
    	return 0;
    }
    I've only seen little endian. I've never seen big endian. I know it's processor-related, but what CPUs use big endian? 4080 in little endian, as an unsigned short, is 32832, but as big endian, it's 16512 instead, a huge difference.

    Edit: I noticed that I had the biWidth value specified twice for some odd reason. Then again, fixing that, I'm still getting the exact same effects - the copy effect. So now what's wrong?

    Edit #2: Even specifying the width and height directly into the function, it still happens. This leaves either the structure or the two HDC's. It's unlikely the HDC's since DrawDibDraw uses them and BitBlt also does and no problems occur with either of these.

    Code:
    	AlphaUsage.BlendOp = AC_SRC_OVER;
    	AlphaUsage.BlendFlags = 0;
    	AlphaUsage.SourceConstantAlpha = 255;
    	AlphaUsage.AlphaFormat = AC_SRC_ALPHA;
    	
    	AlphaBlend(HDCBack, 8, 8, 1024, 128, HDCScreen, 0, 0, 1024, 128, AlphaUsage);
    With this, pretty much everything is ruled out as problematic except these two areas. The copy effect recurs every 8 pixels right and down given this. There must be something wrong in this area. Both HDCBack (the back buffer being drawn into) and HDCScreen (the front buffer to be drawn to the screen) show nonzero values when using the debug things indicating that they are valid. This leaves only the structure as faulty, but I don't see anything wrong.
    Last edited by ulillillia; 04-16-2007 at 06:50 PM. Reason: Fixed mistakes, but copy effect still present

  7. #22
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    I don't think this really helps, but first try to simplify your loading function:

    - First support for example only type 2, 32bpp.

    - You're reading from offset to offset, I also did this at first, but it makes your code pretty large and harder to read. You can put the header data you need in a struct, like this:
    Code:
    struct TGAHEADER
    {
            unsigned char  cIdentificationField;
            bool           bMapIncluded;
            unsigned char  cTgaType;
            char           cIgnore[9];
            short          iWidth;
            short          iHeight;
            unsigned char  cBpp;
            unsigned char  cImageDescriptor;
    };
    Try to make the function as small as possible, you can expand it later on. This makes it easier to see if there's any error in it.

  8. #23
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    Just in case: the image is not runlength encoded I hope? (sorry, a bit stupid:P)

    But, more important, you have this code twice:
    Code:
    		fread(&ValuesBase, 1, 2, FileHandle);
    		BMPInfo->biWidth = (long)ValuesBase[0]+(long)ValuesBase[1]*256; // only two bytes are read for TGAs
    		fread(&ValuesBase, 1, 2, FileHandle);
    		BMPInfo->biWidth = (long)ValuesBase[0]+(long)ValuesBase[1]*256; // only two bytes are read for TGAs
    Instead of reading in the width and height, you read the height into the width. I think you just forgot to edit after copy.pasting it.

  9. #24
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    Fixing that will probably display the image again, and again wrong. What I am seeing in your screenshot, is once an image without transparent pixels normally displayed, and below that the image alpha blended, with some weird effects. In case you drew the image only once, I would like to know what the original picture looks like, and its height.

  10. #25
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    Code:
    		fseek(FileHandle, 12, SEEK_SET); // skip the basic file header data but read from the info header
    		BMPInfo->biSize = 40; // the size of the struct, always 40 in my case (due to true color being used)
    		fread(&ValuesBase, 1, 2, FileHandle);
    		BMPInfo->biWidth = (long)ValuesBase[0]+(long)ValuesBase[1]*256; // only two bytes are read for TGAs
    		fread(&ValuesBase, 1, 2, FileHandle);
    		BMPInfo->biWidth = (long)ValuesBase[0]+(long)ValuesBase[1]*256; // only two bytes are read for TGAs
    What do you think of this:
    Code:
    fseek(FileHandle, 12, SEEK_SET); 
    short width, height
    fread(&width, 1, 2, FileHandle);
    fread(&height, 1, 2, FileHandle);
    BMPInfo->biWidth = (long)width;
    BMPInfo->biHeight = (long)height;



    Also, I don't understand where the hell your image is coming from! I don't see the code that turns MountainsData into a HBITMAP, and this:
    Code:
    AlphaBlend(HDCBack, Mountains.XMain, Mountains.YMain, MountainsInfo.biWidth, MountainsInfo.biHeight, HDCScreen, 0, 0, MountainsInfo.biWidth, MountainsInfo.biHeight, AlphaUsage);
    doesn't do anything useful. It draws from your window to your back buffer, and that has nothing to do with the image you want to AlphaBlend.

  11. #26
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    I mentioned of having fixed the double width mistake and it was indeed from using some copy paste (a special kind of paste that copies things). If you've seen the code in my massive reply above (#19), you'd see that I've got everything being drawn again and again, once per frame. The image simply doesn't appear or display. And no, I don't have run-length encoding (RLE) used with the image, it's uncompressed. At the bottom of my long message (#19), there are 3 links. One contains the TGA I'm trying to load (as a ZIP file - unzip it first then view it). The second URL is what I'm seeing. The third URL is what I should be seeing if successful.

    http://www.ulillillia.us/temporary/MountainsBG.zip
    http://www.ulillillia.us/temporary/CProgNoAlpha02.png
    http://www.ulillillia.us/temporary/CProgNoAlpha03.png

    From the best I can tell, it seems to be something with the structure, but having done a Google search, I'm supposedly using it correctly which leaves nothing else as problematic. Could it be Visual C++ 2005 Express being faulty or posing a limit? Am I using the wrong function? I don't see any other reason why it wouldn't work.

  12. #27
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    Also, I don't understand where the hell your image is coming from! I don't see the code that turns MountainsData into a HBITMAP, and this:

    Code:
    AlphaBlend(HDCBack, Mountains.XMain, Mountains.YMain, MountainsInfo.biWidth, MountainsInfo.biHeight, HDCScreen, 0, 0, MountainsInfo.biWidth, MountainsInfo.biHeight, AlphaUsage);
    doesn't do anything useful. It draws from your window to your back buffer, and that has nothing to do with the image you want to AlphaBlend.
    The documentation didn't mention anything about an HBITMAP for either the blend function or the AlphaBlend function. It asks for two HDC's, four positions and four dimensions along with the blend function. Can you clarify what I need to do? Why two HDC's? Where would the HBITMAP go? In replacement of HDCScreen I take it?

  13. #28
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    In my last post I said that I don't see any code that displays your image, only a useless line that uses AlphaBlend to blend some pixels from the window to your screen buffer, so it's obvious that you aren't seeing the image. Maybe you could take a closer look at the TGA2_32::draw function I posted earlier.
    Also let me say that you provide good information. But where did you buy that "copy paste". I'd like to copy my cat.

  14. #29
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    OK, that's the part you are missing. Let's say, GDI functions don't work with pointers to pixel data but with HBITMAPs. Actually, BitBlt work with two DCs. The first one is the DC you draw on (your back buffer), and the second one is a HDC associated with the HBITMAP, to get the data from. You blit from a DC, to a DC. That's very important.

    Let's say you have the pixel data and the bitmap infoheader ready. This is a fragment from my code that creates a HBITMAP object:

    (see next post)

  15. #30
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    You need a BITMAPINFO object, which contains a BITMAPINFOHEADER, and you already have a BITMAPINFOHEADER (MountainsInfo).

    Code:
    BITMAPINFO bmi = { MountainsInfo, };
    
    // CreateDIBitmap() needs a device context handle, just like CreateCompatibleBitmap(), to
    // ensure the created bitmap is compatible with the screen
    HBITMAP hMountainsBitmap = CreateDIBitmap(HDCScreen, &bmi.bmiHeader, CBM_INIT, MountainsData, &bmi, DIB_RGB_COLORS);
    
    //You need to keep this bitmap. When drawing it, you create a memory device context to blit 
    //from and associate it with hMountainsBitmap:
    
        HDC hMemDC = CreateCompatibleDC(HDCScreen);
        SelectObject(hMemDC, hMountainsBitmap);
        BLENDFUNCTION bf;
        bf.AlphaFormat = AC_SRC_ALPHA;
        bf.BlendOp = AC_SRC_OVER;
        bf.SourceConstantAlpha = 255;  // whatever you want
        bf.BlendFlags = 0;
        AlphaBlend(HDCBack, Mountains.XMain, Mountains.YMain, MountainsInfo.biWidth, MountainsInfo.biHeight, hMemDC, 0, 0, MountainsInfo.biWidth, MountainsInfo.biHeight, bf);
        DeleteDC(hMemDC);
    That's it. Afterwards ypu should delete the HBITMAP object:

    Code:
    DeleteObject(hMountainsBitmap);

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. 32 bit color depth bitmap problem with XP
    By kalabala in forum C++ Programming
    Replies: 0
    Last Post: 12-22-2008, 06:56 AM
  2. binary numbers
    By watshamacalit in forum C Programming
    Replies: 4
    Last Post: 01-14-2003, 11:06 PM
  3. 16 bit or 32 bit
    By Juganoo in forum C Programming
    Replies: 9
    Last Post: 12-19-2002, 07:24 AM
  4. 32 bit or 16 ???
    By GiraffeMan in forum C Programming
    Replies: 11
    Last Post: 04-24-2002, 12:56 PM
  5. Array of boolean
    By DMaxJ in forum C++ Programming
    Replies: 11
    Last Post: 10-25-2001, 11:45 PM