/****************************************************************************\ * * * ENGINE3.CPP - Source Code Module * * * * (c)Copyright 2001 Indotek, LLC. All Rights Reserved. * * * \****************************************************************************/ #include "internal.h" int _r3d_LensFlare[5]; BOOL R3D_STDCALL r3d_LensFlareCreate(int hImage1, int hImage2, int hImage3, int hImage4, int hImage5) { // Determine if we have an appropriate 3D alphapixel format _r3d_LensFlare[0] = hImage1; _r3d_LensFlare[1] = hImage2; _r3d_LensFlare[2] = hImage3; _r3d_LensFlare[3] = hImage4; _r3d_LensFlare[4] = hImage5; return TRUE; } BOOL R3D_STDCALL r3d_LensFlareBlit(float LightX, float LightY, float LightZ) { float MatrixView[12]; MatrixView[0] = _r3d_View.m._11; MatrixView[1] = _r3d_View.m._12; MatrixView[2] = _r3d_View.m._13; MatrixView[3] = _r3d_View.m._21; MatrixView[4] = _r3d_View.m._22; MatrixView[5] = _r3d_View.m._23; MatrixView[6] = _r3d_View.m._31; MatrixView[7] = _r3d_View.m._32; MatrixView[8] = _r3d_View.m._33; MatrixView[9] = _r3d_View.x; MatrixView[10] = _r3d_View.y; MatrixView[11] = _r3d_View.z; D3DVECTOR vLightCenter = D3DVECTOR(MatrixView[2], MatrixView[5], MatrixView[8]); D3DVECTOR vLightPt = D3DVECTOR(LightX, LightY, LightZ); FLOAT fDotProduct = DotProduct(vLightCenter, vLightPt); D3DVECTOR vArbitrary; float fSize = 4.0; vLightCenter = vLightCenter * fSize; vLightPt = vLightPt * fSize; BOOL bOffScreen; int sx, sy, handle; int Width, Height, HalfWidth, HalfHeight; // Only render flares if we are within the "flare cone of view" if (fDotProduct > 0.707106781186547524400844362104849F) { float fMatrix[12]; memcpy(fMatrix, MatrixView, 9 * 4); fMatrix[9] = fMatrix[10] = fMatrix[11] = 0.0F; r3d_SetViewMatrix(fMatrix); r3d_2DBegin(NULL, NULL, NULL); // Calculate the opposite sun point D3DVECTOR vLightAxisOppPt = vLightCenter - ((vLightPt / 2) / fDotProduct); vLightAxisOppPt = Normalize(vLightAxisOppPt); vLightAxisOppPt = vLightAxisOppPt * fSize; vLightAxisOppPt = vLightAxisOppPt * 0.85F; fMatrix[9] = vLightAxisOppPt.x; fMatrix[10] = vLightAxisOppPt.y; fMatrix[11] = vLightAxisOppPt.z; r3d_3DVertexToScreenVertex(0, 0, 0, fMatrix, &sx, &sy, &bOffScreen); if (bOffScreen == FALSE) { handle = _r3d_LensFlare[0]; Width = (int)_r3d_Surface[handle]->dwWidth; Height = (int)_r3d_Surface[handle]->dwHeight; HalfWidth = Width / 2; HalfHeight = Height / 2; r3d_2DBlit(handle, 0, Width, 0, Height, sx - HalfWidth, sx + HalfWidth, sy - HalfHeight, sy + HalfHeight, TRUE); } //r3d_ZBlit3DModel1(hModelFlare1,fMatrix); vArbitrary = vLightCenter - (((vLightPt) / 3) / fDotProduct); vArbitrary = Normalize(vArbitrary); vArbitrary = vArbitrary * fSize * 0.90F; fMatrix[9] = vArbitrary.x; fMatrix[10] = vArbitrary.y; fMatrix[11] = vArbitrary.z; //r3d_ZBlit3DModel1(hModelFlare1,fMatrix); r3d_3DVertexToScreenVertex(0, 0, 0, fMatrix, &sx, &sy, &bOffScreen); if (bOffScreen == FALSE) { handle = _r3d_LensFlare[1]; Width = (int)_r3d_Surface[handle]->dwWidth; Height = (int)_r3d_Surface[handle]->dwHeight; HalfWidth = Width / 2; HalfHeight = Height / 2; r3d_2DBlit(handle, 0, Width, 0, Height, sx - HalfWidth, sx + HalfWidth, sy - HalfHeight, sy + HalfHeight, TRUE); } vArbitrary = vLightCenter - (((vLightPt) / 4) / fDotProduct); vArbitrary = Normalize(vArbitrary); vArbitrary = vArbitrary * fSize * 0.95F; fMatrix[9] = vArbitrary.x; fMatrix[10] = vArbitrary.y; fMatrix[11] = vArbitrary.z; //r3d_ZBlit3DModel1(hModelFlare2,fMatrix); r3d_3DVertexToScreenVertex(0, 0, 0, fMatrix, &sx, &sy, &bOffScreen); if (bOffScreen == FALSE) { handle = _r3d_LensFlare[2]; Width = (int)_r3d_Surface[handle]->dwWidth; Height = (int)_r3d_Surface[handle]->dwHeight; HalfWidth = Width / 2; HalfHeight = Height / 2; r3d_2DBlit(handle, 0, Width, 0, Height, sx - HalfWidth, sx + HalfWidth, sy - HalfHeight, sy + HalfHeight, TRUE); } vArbitrary = vLightCenter - (((vLightPt) / 5) / fDotProduct); vArbitrary = Normalize(vArbitrary); vArbitrary = vArbitrary * fSize * 1.0F; fMatrix[9] = vArbitrary.x; fMatrix[10] = vArbitrary.y; fMatrix[11] = vArbitrary.z; //r3d_ZBlit3DModel1(hModelFlare1,fMatrix); r3d_3DVertexToScreenVertex(0, 0, 0, fMatrix, &sx, &sy, &bOffScreen); if (bOffScreen == FALSE) { handle = _r3d_LensFlare[3]; Width = (int)_r3d_Surface[handle]->dwWidth; Height = (int)_r3d_Surface[handle]->dwHeight; HalfWidth = Width / 2; HalfHeight = Height / 2; r3d_2DBlit(handle, 0, Width, 0, Height, sx - HalfWidth, sx + HalfWidth, sy - HalfHeight, sy + HalfHeight, TRUE); } vLightCenter = (vLightAxisOppPt + vLightPt) * 0.5F; vLightCenter = Normalize(vLightCenter); vLightCenter = vLightCenter * fSize * 1.05F; fMatrix[9] = vLightCenter.x; fMatrix[10] = vLightCenter.y; fMatrix[11] = vLightCenter.z; //r3d_ZBlit3DModel1(hModelFlare1,fMatrix); r3d_3DVertexToScreenVertex(0, 0, 0, fMatrix, &sx, &sy, &bOffScreen); if (bOffScreen == FALSE) { handle = _r3d_LensFlare[4]; Width = (int)_r3d_Surface[handle]->dwWidth; Height = (int)_r3d_Surface[handle]->dwHeight; HalfWidth = Width / 2; HalfHeight = Height / 2; r3d_2DBlit(handle, 0, Width, 0, Height, sx - HalfWidth, sx + HalfWidth, sy - HalfHeight, sy + HalfHeight, TRUE); } vArbitrary = vLightCenter + (((vLightPt) / 5) / fDotProduct); vArbitrary = Normalize(vArbitrary); vArbitrary = vArbitrary * fSize * 1.10F; fMatrix[9] = vArbitrary.x; fMatrix[10] = vArbitrary.y; fMatrix[11] = vArbitrary.z; //r3d_ZBlit3DModel1(hModelFlare4,fMatrix); r3d_3DVertexToScreenVertex(0, 0, 0, fMatrix, &sx, &sy, &bOffScreen); if (bOffScreen == FALSE) { handle = _r3d_LensFlare[3]; Width = (int)_r3d_Surface[handle]->dwWidth; Height = (int)_r3d_Surface[handle]->dwHeight; HalfWidth = Width / 2; HalfHeight = Height / 2; r3d_2DBlit(handle, 0, Width, 0, Height, sx - HalfWidth, sx + HalfWidth, sy - HalfHeight, sy + HalfHeight, TRUE); } vArbitrary = vLightCenter + (((vLightPt)) / fDotProduct); vArbitrary = Normalize(vArbitrary); vArbitrary = vArbitrary * fSize * 1.15F; fMatrix[9] = vArbitrary.x; fMatrix[10] = vArbitrary.y; fMatrix[11] = vArbitrary.z; //r3d_ZBlit3DModel1(hModelFlare0,fMatrix); r3d_3DVertexToScreenVertex(0, 0, 0, fMatrix, &sx, &sy, &bOffScreen); if (bOffScreen == FALSE) { handle = _r3d_LensFlare[2]; Width = (int)_r3d_Surface[handle]->dwWidth; Height = (int)_r3d_Surface[handle]->dwHeight; HalfWidth = Width / 2; HalfHeight = Height / 2; r3d_2DBlit(handle, 0, Width, 0, Height, sx - HalfWidth, sx + HalfWidth, sy - HalfHeight, sy + HalfHeight, TRUE); } // Reset Original View Matrix r3d_SetViewMatrix(MatrixView); r3d_2DEnd(); } return TRUE; } BOOL R3D_STDCALL _r3d_MakeMaterial(_R3D_MATERIAL *pMaterial, float r, float g, float b, float a, float pow, float sr, float sg, float sb, float er, float eg, float eb, BOOL bLoadTexture, char *TextureFilenameBMP, BOOL bLoadAlpha, char *AlphaFilenameBMP, BOOL bMipMap) { // First we load the texture BOOL bFoundDuplicate = FALSE; int LoopVar; DDSURFACEDESC2 ddsd; int x, y; int Index = 0, AlphaIndex = 0; unsigned char Alpha, Red, Green, Blue; long ucr[5], ucg[5], ucb[5], uca[5]; int hTempBitmap; unsigned long *pTextureRGBA; unsigned long dwWidthHeight; unsigned char UCcolorA, UCcolorR, UCcolorG, UCcolorB; BOOL bColorKeyedTexture; DDCOLORKEY ddColorKey; unsigned char *SurfacePointer; int SurfacePitch, TextureFormat; // We set this here... pMaterial->TextureBMP[0] = '\0'; pMaterial->bTexture = FALSE; pMaterial->AlphaBMP[0] = '\0'; pMaterial->bAlpha = FALSE; pMaterial->bMipMap = FALSE; pMaterial->lpSystemTextureSurface = NULL; pMaterial->lpSystemTexture = NULL; pMaterial->bDuplicate = FALSE; pMaterial->DuplicateIndex = 0; pMaterial->lpMaterial = NULL; pMaterial->bColorKeyedTexture = FALSE; // DirectX 6 Method BOOL bFalseAlpha = FALSE; float aFalse; pMaterial->bStoreAlpha = FALSE; if (bLoadTexture == TRUE) { if (bLoadAlpha == TRUE) { bFalseAlpha = FALSE; pMaterial->bStoreAlpha = TRUE; a = 1.0F; } else if (a < 1.0F) { bFalseAlpha = TRUE; pMaterial->bStoreAlpha = TRUE; aFalse = a; a = 1.0F; } } else if (a < 1.0F) { bFalseAlpha = FALSE; pMaterial->bStoreAlpha = TRUE; } ZeroMemory(&pMaterial->Material, sizeof(pMaterial->Material)); pMaterial->Material.dwSize = sizeof(pMaterial->Material); pMaterial->Material.diffuse.r = D3DVAL(r); pMaterial->Material.diffuse.g = D3DVAL(g); pMaterial->Material.diffuse.b = D3DVAL(b); pMaterial->Material.diffuse.a = D3DVAL(a); pMaterial->Material.ambient.r = D3DVAL((r)); pMaterial->Material.ambient.g = D3DVAL((g)); pMaterial->Material.ambient.b = D3DVAL((b)); pMaterial->Material.ambient.a = D3DVAL((a)); pMaterial->Material.specular.r = D3DVAL(sr); pMaterial->Material.specular.g = D3DVAL(sg); pMaterial->Material.specular.b = D3DVAL(sb); pMaterial->Material.specular.a = D3DVAL(1.0); pMaterial->Material.emissive.r = D3DVAL(er); pMaterial->Material.emissive.g = D3DVAL(eg); pMaterial->Material.emissive.b = D3DVAL(eb); pMaterial->Material.emissive.a = D3DVAL(1.0); pMaterial->Material.power = D3DVAL(pow); pMaterial->Material.dwRampSize = 0; // Microsoft sets this to 0... if (bLoadTexture == TRUE) { // Always save texture filename... Even if there's a duplicate... // We do this in case this material needs to be re-made because of a lost surface pMaterial->bTexture = TRUE; _r3d_strcpy(pMaterial->TextureBMP, TextureFilenameBMP); if (bLoadAlpha == TRUE) { pMaterial->bAlpha = TRUE; _r3d_strcpy(pMaterial->AlphaBMP, AlphaFilenameBMP); } // Run through all materials and see if any texture filenames match bFoundDuplicate = FALSE; for (LoopVar = 0;LoopVar < _r3d_MaterialIndex;LoopVar++) { if (bLoadAlpha == TRUE) { if (!strncmp(_r3d_Material[LoopVar].TextureBMP, TextureFilenameBMP, strlen(TextureFilenameBMP)) && !strncmp(_r3d_Material[LoopVar].AlphaBMP, AlphaFilenameBMP, strlen(AlphaFilenameBMP))) { // Found a match! pMaterial->bDuplicate = TRUE; pMaterial->DuplicateIndex = LoopVar; bFoundDuplicate = TRUE; break; } } else { if (!strncmp(_r3d_Material[LoopVar].TextureBMP, TextureFilenameBMP, strlen(TextureFilenameBMP))) { if (_r3d_Material[LoopVar].Material.diffuse.a == a) // Avoid False Alpha texture versus non False Alpha Texture { // Found a match! pMaterial->bDuplicate = TRUE; pMaterial->DuplicateIndex = LoopVar; bFoundDuplicate = TRUE; break; } } } } if (bFoundDuplicate == FALSE) { // NO MATTER WHAT, In RenderIt, // // 1) The texture must be square // 2) The texture size must be a power of 2 // 3) The texture must be an 8 or 24-bit uncompressed *.bmp file // // 4) No more PPM file support. // if (bLoadAlpha == TRUE) { if (!_r3d_SurfaceCreateScaledTexture(&hTempBitmap, pMaterial->TextureBMP, TRUE, pMaterial->AlphaBMP, "_r3d_MakeMaterial", &dwWidthHeight)) { // Error string already defined return FALSE; } } else { if (!_r3d_SurfaceCreateScaledTexture(&hTempBitmap, pMaterial->TextureBMP, FALSE, NULL, "_r3d_MakeMaterial", &dwWidthHeight)) { // Error string already defined return FALSE; } } pTextureRGBA = r3d_SurfaceGet(hTempBitmap); // Now we could run through the entire surface, look at // the Alpha components, and if any of these components // is 0 or 255 and nothing else, we can use a color // keyed texture instead for speed and higher texture // quality. Since they would not be alpha textures, // we would also not have to sort them! // // Since we want the color key to be black, we also check // to make sure that when // // Setting a color key can be tricky... For reliable results // we will use a color key value of BLACK and if any pixels // are black, we bump them up to be 9,9,9 RGB. bColorKeyedTexture = FALSE; // Assume FALSE pMaterial->bColorKeyedTexture = FALSE; // Assume FALSE if (bLoadAlpha == TRUE && bMipMap == FALSE) // We don't color key with mip-maps { bColorKeyedTexture = _r3d_bColorKeyedTexturingSupport; // Assume TRUE if device supports color keyed textures pMaterial->bColorKeyedTexture = bColorKeyedTexture; for (y = 0;y < (int)dwWidthHeight;y++) { for (x = 0;x < (int)dwWidthHeight;x++) { UCcolorA = r3d_SurfaceColorGetA(pTextureRGBA[(y * dwWidthHeight) + x]); if (UCcolorA != 0 && UCcolorA != 255) // Texture can't use a color key bColorKeyedTexture = FALSE; if (UCcolorA == 0) pTextureRGBA[(y * dwWidthHeight) + x] = (DWORD)0; } } // Modify texture to use color key of an unused color // and set the color key to the unused color if (bColorKeyedTexture == TRUE) { //if (_r3d_SolidTextureFormat== for (y = 0;y < (int)dwWidthHeight;y++) { for (x = 0;x < (int)dwWidthHeight;x++) { UCcolorA = r3d_SurfaceColorGetA(pTextureRGBA[(y * dwWidthHeight) + x]); if (UCcolorA == 255) { // Boost the color to allow our black // color key to work properly. We make // sure we boost by 9 so that our 16 BPP // modes handle the color key properly. // The smallest color value is 9 when // a range of 0-31 is used for 555. // // 255/8=31.875 // UCcolorR = r3d_SurfaceColorGetR(pTextureRGBA[(y * dwWidthHeight) + x]); UCcolorG = r3d_SurfaceColorGetG(pTextureRGBA[(y * dwWidthHeight) + x]); UCcolorB = r3d_SurfaceColorGetB(pTextureRGBA[(y * dwWidthHeight) + x]); if (UCcolorR < 9 && UCcolorG < 9 && UCcolorB < 9) { pTextureRGBA[(y * dwWidthHeight) + x] = r3d_SurfaceColorMakeRGBA(9, 9, 9, 255); } } } } // No alpha left in this texture... bLoadAlpha = FALSE; bFalseAlpha = FALSE; pMaterial->bStoreAlpha = FALSE; } } // OK, let's throw the texture data onto an // appropriate DirectDraw texture surface pMaterial->bMipMap = bMipMap; if (bMipMap == FALSE) { // Only one texture map for 0 or 1 mip-map levels // Create a texture surface in any memory... DX6 IM TEXTURE MEMORY MANAGMENT _r3d_ProperlyInitDDSD(&ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; if (bColorKeyedTexture == TRUE) { ddsd.dwFlags |= DDSD_CKSRCBLT; ddColorKey.dwColorSpaceLowValue = ddColorKey.dwColorSpaceHighValue = (DWORD)0; ddsd.ddckCKSrcBlt = ddColorKey; } ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; //|DDSCAPS2_OPAQUE; ddsd.dwWidth = ddsd.dwHeight = dwWidthHeight; if (bLoadAlpha == TRUE || bFalseAlpha == TRUE) TextureFormat = _r3d_TranslucentTextureFormat; else TextureFormat = _r3d_SolidTextureFormat; memcpy(&ddsd.ddpfPixelFormat, &_r3d_TextureFormatList[TextureFormat].ddpfPixelFormat, sizeof(ddsd.ddpfPixelFormat)); if ((_r3d_hResult = _r3d_DirectDraw4->CreateSurface(&ddsd, &pMaterial->lpSystemTextureSurface, NULL)) != DD_OK) { r3d_SurfaceDestroy(hTempBitmap); _r3d_FormulateErrorString("_r3d_MakeMaterial", "_r3d_DirectDraw4->CreateSurface(&ddsd, &pMaterial->lptmpSystemTextureSurface, NULL)", _r3d_hResult); return FALSE; } // Set color key if required if (bColorKeyedTexture == TRUE) { ddColorKey.dwColorSpaceLowValue = ddColorKey.dwColorSpaceHighValue = (DWORD)0; pMaterial->lpSystemTextureSurface->SetColorKey(DDCKEY_SRCBLT, &ddColorKey); } // Required for other functions _r3d_ProperlyInitDDSD(&pMaterial->ddsd); //ZeroMemory(&pMaterial->ddsd, sizeof(pMaterial->ddsd)); //pMaterial->ddsd.dwSize = sizeof(pMaterial->ddsd); pMaterial->ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; if ((_r3d_hResult = pMaterial->lpSystemTextureSurface->GetSurfaceDesc(&pMaterial->ddsd)) != DD_OK) { r3d_SurfaceDestroy(hTempBitmap); _r3d_FormulateErrorString("_r3d_MakeMaterial", "pMaterial->lpTextureSurface->GetSurfaceDesc(&pMaterial->ddsd)", _r3d_hResult); return FALSE; } // We need to lock the surface // We need to work with lpitch as well as pixel format memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_PITCH | DDSD_PIXELFORMAT; pMaterial->lpSystemTextureSurface->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); //mem_ptr = (unsigned char *)ddsd.lpSurface; SurfacePointer = (unsigned char *)ddsd.lpSurface; SurfacePitch = (int)ddsd.lPitch; for (y = 0;y < (int)dwWidthHeight;y++) { for (x = 0;x < (int)dwWidthHeight;x++) { Alpha = (unsigned char)((pTextureRGBA[(y * dwWidthHeight) + x] >> 24) & 0x000000FF); Blue = (unsigned char)((pTextureRGBA[(y * dwWidthHeight) + x] >> 16) & 0x000000FF); Green = (unsigned char)((pTextureRGBA[(y * dwWidthHeight) + x] >> 8) & 0x000000FF); Red = (unsigned char)((pTextureRGBA[(y * dwWidthHeight) + x]) & 0x000000FF); //fRed=(float)Red/255.0F; //fGreen=(float)Green/255.0F; //fBlue=(float)Blue/255.0F; //fAlpha=(float)Alpha/255.0F; switch (TextureFormat) { case 0: r3d_TextureAnimateSurfaceTexel0(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; case 1: r3d_TextureAnimateSurfaceTexel1(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; case 2: r3d_TextureAnimateSurfaceTexel2(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; case 3: r3d_TextureAnimateSurfaceTexel3(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; case 4: r3d_TextureAnimateSurfaceTexel4(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; case 5: r3d_TextureAnimateSurfaceTexel5(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; } } } pMaterial->lpSystemTextureSurface->Unlock(NULL); } else { // It's a mip-map _r3d_ProperlyInitDDSD(&ddsd); //ZeroMemory(&ddsd, sizeof(ddsd)); //ddsd.dwSize = sizeof(ddsd); //ddsd.dwFlags = DDSD_CAPS | DDSD_MIPMAPCOUNT; //ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT; ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX; ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; //|DDSCAPS2_OPAQUE; //ddsd.dwMipMapCount = NumMipMapLevels; //ddsd.dwMipMapCount = 0; ddsd.dwWidth = ddsd.dwHeight = dwWidthHeight; //ddsd.dwTextureStage = 0; if (bLoadAlpha == TRUE || bFalseAlpha == TRUE) TextureFormat = _r3d_TranslucentTextureFormat; else TextureFormat = _r3d_SolidTextureFormat; memcpy(&ddsd.ddpfPixelFormat, &_r3d_TextureFormatList[TextureFormat].ddpfPixelFormat, sizeof(ddsd.ddpfPixelFormat)); if ((_r3d_hResult = _r3d_DirectDraw4->CreateSurface(&ddsd, &pMaterial->lpSystemTextureSurface, NULL)) != DD_OK) { r3d_SurfaceDestroy(hTempBitmap); _r3d_FormulateErrorString("_r3d_MakeMaterial", "_r3d_DirectDraw4->CreateSurface(&ddsd, &pMaterial->lptmpSystemTextureSurface, NULL)", _r3d_hResult); return FALSE; } // Traverse the mip-map chain and smooth scale textures and apply them to each mip-map LPDIRECTDRAWSURFACE4 lpDDLevel, lpDDNextLevel; DDSCAPS2 ddsCaps2; lpDDLevel = pMaterial->lpSystemTextureSurface; lpDDLevel->AddRef(); ddsCaps2.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP; _r3d_hResult = DD_OK; while (_r3d_hResult == DD_OK) { // Process this mip map level... // (Copy to the mip-map level after smooth scaling)... // We need to lock the surface // We need to work with lpitch as well as pixel format // We need to determine whether or not we need to scale the image memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_PITCH | DDSD_PIXELFORMAT; lpDDLevel->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); //mem_ptr = (unsigned char *)ddsd.lpSurface; SurfacePointer = (unsigned char *)ddsd.lpSurface; SurfacePitch = (int)ddsd.lPitch; for (y = 0;y < (int)dwWidthHeight;y++) { for (x = 0;x < (int)dwWidthHeight;x++) { Alpha = (unsigned char)((pTextureRGBA[(y * dwWidthHeight) + x] >> 24) & 0x000000FF); Blue = (unsigned char)((pTextureRGBA[(y * dwWidthHeight) + x] >> 16) & 0x000000FF); Green = (unsigned char)((pTextureRGBA[(y * dwWidthHeight) + x] >> 8) & 0x000000FF); Red = (unsigned char)((pTextureRGBA[(y * dwWidthHeight) + x]) & 0x000000FF); switch (TextureFormat) { case 0: r3d_TextureAnimateSurfaceTexel0(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; case 1: r3d_TextureAnimateSurfaceTexel1(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; case 2: r3d_TextureAnimateSurfaceTexel2(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; case 3: r3d_TextureAnimateSurfaceTexel3(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; case 4: r3d_TextureAnimateSurfaceTexel4(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; case 5: r3d_TextureAnimateSurfaceTexel5(SurfacePointer, SurfacePitch, x, y, Alpha, Red, Green, Blue); break; } } } lpDDLevel->Unlock(NULL); // Get ready for next level _r3d_hResult = lpDDLevel->GetAttachedSurface(&ddsCaps2, &lpDDNextLevel); lpDDLevel->Release(); lpDDLevel = lpDDNextLevel; // Now scale the mip-map for the next level // We will smooth it first by averaging. for (y = 0;y < (int)dwWidthHeight;y += 2) { for (x = 0;x < (int)dwWidthHeight;x += 2) { uca[0] = (long)(pTextureRGBA[((y) * dwWidthHeight) + (x)] >> 24) & 0x000000FF; ucb[0] = (long)(pTextureRGBA[((y) * dwWidthHeight) + (x)] >> 16) & 0x000000FF; ucg[0] = (long)(pTextureRGBA[((y) * dwWidthHeight) + (x)] >> 8) & 0x000000FF; ucr[0] = (long)(pTextureRGBA[((y) * dwWidthHeight) + (x)]) & 0x000000FF; uca[1] = (long)(pTextureRGBA[((y) * dwWidthHeight) + (x+1)] >> 24) & 0x000000FF; ucb[1] = (long)(pTextureRGBA[((y) * dwWidthHeight) + (x+1)] >> 16) & 0x000000FF; ucg[1] = (long)(pTextureRGBA[((y) * dwWidthHeight) + (x+1)] >> 8) & 0x000000FF; ucr[1] = (long)(pTextureRGBA[((y) * dwWidthHeight) + (x+1)]) & 0x000000FF; uca[2] = (long)(pTextureRGBA[((y+1) * dwWidthHeight) + (x)] >> 24) & 0x000000FF; ucb[2] = (long)(pTextureRGBA[((y+1) * dwWidthHeight) + (x)] >> 16) & 0x000000FF; ucg[2] = (long)(pTextureRGBA[((y+1) * dwWidthHeight) + (x)] >> 8) & 0x000000FF; ucr[2] = (long)(pTextureRGBA[((y+1) * dwWidthHeight) + (x)]) & 0x000000FF; uca[3] = (long)(pTextureRGBA[((y+1) * dwWidthHeight) + (x+1)] >> 24) & 0x000000FF; ucb[3] = (long)(pTextureRGBA[((y+1) * dwWidthHeight) + (x+1)] >> 16) & 0x000000FF; ucg[3] = (long)(pTextureRGBA[((y+1) * dwWidthHeight) + (x+1)] >> 8) & 0x000000FF; ucr[3] = (long)(pTextureRGBA[((y+1) * dwWidthHeight) + (x+1)]) & 0x000000FF; uca[4] = (((long)uca[0] + (long)uca[1] + (long)uca[2] + (long)uca[3]) / 4L); ucb[4] = (((long)ucb[0] + (long)ucb[1] + (long)ucb[2] + (long)ucb[3]) / 4L); ucg[4] = (((long)ucg[0] + (long)ucg[1] + (long)ucg[2] + (long)ucg[3]) / 4L); ucr[4] = (((long)ucr[0] + (long)ucr[1] + (long)ucr[2] + (long)ucr[3]) / 4L); pTextureRGBA[((y/2) * (dwWidthHeight/2)) + (x/2)] = ((((long)(uca[4])) << 24) | (((long)(ucb[4])) << 16) | (((long)(ucg[4])) << 8) | (long)(ucr[4])); } } dwWidthHeight /= 2; } if ((_r3d_hResult != DD_OK) && (_r3d_hResult != DDERR_NOTFOUND)) { // Code to handle the error goes here r3d_SurfaceDestroy(hTempBitmap); _r3d_FormulateErrorString("_r3d_MakeMaterial", "lpDDLevel->GetAttachedSurface( &ddsCaps, &lpDDNextLevel)", _r3d_hResult); return FALSE; } } r3d_SurfaceDestroy(hTempBitmap); // Get the texture interface if ((_r3d_hResult = pMaterial->lpSystemTextureSurface->QueryInterface(IID_IDirect3DTexture2, (LPVOID *)&pMaterial->lpSystemTexture)) != S_OK) { _r3d_FormulateErrorString("_r3d_MakeMaterial", "pMaterial->lpSystemTextureSurface->QueryInterface(IID_IDirect3DTexture2, (LPVOID*)&pMaterial->lpSystemTexture)", _r3d_hResult); //r3d_MessageBox(r3d_GetLastErrorString(),"_r3d_MakeMaterial",_r3d_hResult); return FALSE; } } } // Create Material if ((_r3d_hResult = _r3d_Direct3D->CreateMaterial(&pMaterial->lpMaterial, NULL)) != DD_OK) { _r3d_FormulateErrorString("_r3d_MakeMaterial", "_r3d_Direct3D->CreateMaterial(&pMaterial->lpMaterial,NULL)", _r3d_hResult); return FALSE; } // Set Material if ((_r3d_hResult = pMaterial->lpMaterial->SetMaterial((D3DMATERIAL *)&pMaterial->Material)) != DD_OK) { _r3d_FormulateErrorString("_r3d_MakeMaterial", "pMaterial->lpMaterial->SetMaterial((D3DMATERIAL *)&pMaterial->Material)", _r3d_hResult); return FALSE; } // Get Material Handle if ((_r3d_hResult = pMaterial->lpMaterial->GetHandle(_r3d_Device, &pMaterial->hMaterial)) != DD_OK) { _r3d_FormulateErrorString("_r3d_MakeMaterial", "pMaterial->lpMaterial->GetHandle(_r3d_Device,&pMaterial->hMaterial)", _r3d_hResult); return FALSE; } return TRUE; } BOOL R3D_STDCALL _r3d_SetMaterial(_R3D_MATERIAL *pMat) { int hMat; _R3D_MATERIAL *pMat0; pMat0 = &_r3d_Material[0]; hMat = (int)(pMat - pMat0); return (r3d_SetMaterial(hMat)); } BOOL R3D_STDCALL r3d_SetMaterial(int handle) { // This function needs to be optimized! static LPDIRECT3DTEXTURE2 lpPreviousTexture = NULL; static BOOL bPreviousColorKeyEnable = FALSE; // Default static BOOL bPreviousAlphaBlend = FALSE; // Default int TexFormat = 0; // First, we do a little optimization if (handle == _r3d_SetMaterialLast) return TRUE; // It's already been set previously else { // Check for errors if (handle < 0 || handle >= _r3d_MaterialIndex) { _r3d_FormulateErrorString("r3d_SetMaterial", "Invalid Material Handle", DD_OK); return FALSE; } // Safe to set this _r3d_SetMaterialLast = handle; } // Handle Alpha Textures: if (_r3d_Material[handle].bStoreAlpha == TRUE) { // Multipass using alpha blending // HEY! Order of operations matters here.... It don't say // this in Microsofts crappy docs... I stole this // from one of the stinkin demos and found that this order // of operations actually works... if (bPreviousAlphaBlend == FALSE) { _r3d_Device->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); _r3d_Device->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); _r3d_Device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); bPreviousAlphaBlend = TRUE; } } else { if (bPreviousAlphaBlend == TRUE) { _r3d_Device->SetRenderState(D3DRENDERSTATE_SRCBLEND, (DWORD)D3DBLEND_ONE); _r3d_Device->SetRenderState(D3DRENDERSTATE_DESTBLEND, (DWORD)D3DBLEND_ZERO); _r3d_Device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, (DWORD)FALSE); bPreviousAlphaBlend = FALSE; } } // Set textures to duplicates only after the above code sets the // material properties. if (_r3d_Material[handle].bDuplicate == TRUE) { // To color key or not to color, that is the question if (_r3d_Material[_r3d_Material[handle].DuplicateIndex].bColorKeyedTexture == TRUE) { if (bPreviousColorKeyEnable == FALSE) { _r3d_Device->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, (DWORD)TRUE); bPreviousColorKeyEnable = TRUE; } } else { if (bPreviousColorKeyEnable == TRUE) { _r3d_Device->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, (DWORD)FALSE); bPreviousColorKeyEnable = FALSE; } } if (lpPreviousTexture != _r3d_Material[_r3d_Material[handle].DuplicateIndex].lpSystemTexture) { _r3d_Device->SetTexture(0, _r3d_Material[_r3d_Material[handle].DuplicateIndex].lpSystemTexture); lpPreviousTexture = _r3d_Material[_r3d_Material[handle].DuplicateIndex].lpSystemTexture; } } else { // To color key or not to color, that is the question if (_r3d_Material[handle].bColorKeyedTexture == TRUE) { if (bPreviousColorKeyEnable == FALSE) { _r3d_Device->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, (DWORD)TRUE); bPreviousColorKeyEnable = TRUE; } } else { if (bPreviousColorKeyEnable == TRUE) { _r3d_Device->SetRenderState(D3DRENDERSTATE_COLORKEYENABLE, (DWORD)FALSE); bPreviousColorKeyEnable = FALSE; } } if (lpPreviousTexture != _r3d_Material[handle].lpSystemTexture) { _r3d_Device->SetTexture(0, _r3d_Material[handle].lpSystemTexture); lpPreviousTexture = _r3d_Material[handle].lpSystemTexture; } } _r3d_Device->SetLightState(D3DLIGHTSTATE_MATERIAL, _r3d_Material[handle].hMaterial); return TRUE; } BOOL R3D_STDCALL _r3d_SurfaceCreateScaledTexture(int *hBitmapRet, char *pTextureFilename, BOOL bLoadAlpha, char *pAlphaFilename, char *FunctionNameString, unsigned long *dwWidthHeightRet) { unsigned long dwWidth, dwHeight; unsigned long dwWidthHeight, dwWidthAlf, dwHeightAlf; BOOL bPalette256, bPalette256Alf; int hBitmap, hBitmapScaled; char buffer[256]; // First, we get the BMP width and height if (_r3d_BMPGetInfo(pTextureFilename, FunctionNameString, &dwWidth, &dwHeight, &bPalette256) == FALSE) { // Error string already defined return FALSE; } // Now, we'll error check the alpha BMP if (bLoadAlpha) { if (_r3d_BMPGetInfo(pAlphaFilename, FunctionNameString, &dwWidthAlf, &dwHeightAlf, &bPalette256Alf) == FALSE) { // Error string already defined return FALSE; } // Now, we'll make sure that the alpha BMP and texture BMP are the // same size if (dwWidthAlf != dwWidth || dwHeightAlf != dwHeight) { sprintf(buffer, "%s is not the same size as %s", pTextureFilename, pAlphaFilename); _r3d_FormulateErrorString(FunctionNameString, "", DD_OK); return FALSE; } } // Let's force texture to be square, the largest of width or height if (dwWidth > dwHeight) dwWidthHeight = dwWidth; else if (dwWidth < dwHeight) dwWidthHeight = dwHeight; else dwWidthHeight = dwWidth; // Let's determine if this texture size is a power of 2 (within our 1024 limit) if (dwWidthHeight != _R3D_MAXTEXTURESIZE && dwWidthHeight != 768 && dwWidthHeight != 512 && dwWidthHeight != 256 && dwWidthHeight != 128 && dwWidthHeight != 64 && dwWidthHeight != 32 && dwWidthHeight != 16 && dwWidthHeight != 8 && dwWidthHeight != 4 && dwWidthHeight != 2) { // Force texture to be a power of 2 in size and scale upwards if // possible if (dwWidthHeight > 768) dwWidthHeight = 1024; if (dwWidthHeight > 512) dwWidthHeight = 768; if (dwWidthHeight > 256) dwWidthHeight = 512; if (dwWidthHeight > 128) dwWidthHeight = 256; if (dwWidthHeight > 64) dwWidthHeight = 128; if (dwWidthHeight > 32) dwWidthHeight = 64; if (dwWidthHeight > 16) dwWidthHeight = 32; if (dwWidthHeight > 8) dwWidthHeight = 16; if (dwWidthHeight > 4) dwWidthHeight = 8; if (dwWidthHeight > 2) dwWidthHeight = 4; if (dwWidthHeight > 1) dwWidthHeight = 2; } // Force texture to be within the min,max width and height constraints if (dwWidthHeight < _r3d_dwMinTextureWidthHeight) dwWidthHeight = _r3d_dwMinTextureWidthHeight; else if (dwWidthHeight > _r3d_dwMaxTextureWidthHeight) dwWidthHeight = _r3d_dwMaxTextureWidthHeight; // Load the bitmap if (!r3d_SurfaceCreateFromBMP(&hBitmap, pTextureFilename)) { // Error already defined but it won't say "_r3d_TextureLoadScale" return FALSE; } if (bLoadAlpha == TRUE) { if (!r3d_SurfaceSetAlphaFromBMP(hBitmap, pAlphaFilename)) { // Error already defined but it won't say "_r3d_TextureLoadScale" return FALSE; } } // Determine if scaling is even required and abort if not if (dwWidth == dwHeight && dwWidth == dwWidthHeight) { *hBitmapRet = hBitmap; *dwWidthHeightRet = dwWidthHeight; return TRUE; } // Now we are ready to scale the texture if (!r3d_SurfaceCreate(&hBitmapScaled, dwWidthHeight, dwWidthHeight)) { // Error already defined but it won't say "_r3d_TextureLoadScale" return FALSE; } if (!r3d_SurfaceStretchSmooth(hBitmap, hBitmapScaled)) { // Error already defined but it won't say "_r3d_TextureLoadScale" return FALSE; } r3d_SurfaceDestroy(hBitmap); *hBitmapRet = hBitmapScaled; *dwWidthHeightRet = dwWidthHeight; return TRUE; }