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.