#include #include "DDAccess.h" // This module has access to machine-dependent variables. #include "pstypes.h" #include "pserror.h" #include "Application.h" #include "renderer.h" #include "3d.h" #include "bitmap.h" #include "lightmap.h" #include "rend_d3d.h" #include "d3dtypes.h" #include "d3d.h" #include "ddraw.h" #include "grdefs.h" #include "module.h" #include "bumpmap.h" #include "mem.h" #include "rtperformance.h" #include "appdatabase.h" #include static oeApplication *ParentApplication; extern int FindArg(char *); extern oeAppDatabase *Database; rendering_state D3D_state = {0}; // set initted to zero renderer_preferred_state D3D_preferred_state = {0, 1, 1.5}; int D3D_polys_drawn = 0; int D3D_verts_processed = 0; int D3D_sets_this_frame[8] = {0, 0, 0, 0, 0, 0, 0, 0}; int D3D_uploads = 0; int D3D_num_texelfx = 0; static int D3D_last_frame_polys_drawn = 0; static int D3D_last_frame_verts_processed = 0; static int D3D_last_uploads = 0; #define NUM_TEXTURE_CLASSES 8 // Specific DirectDraw/Direct3D variables LPDIRECTDRAW lpDD1 = NULL; LPDIRECTDRAW4 lpDD = NULL; LPDIRECT3D3 lpD3D = NULL; LPDIRECT3DDEVICE3 lpD3DDevice = NULL; LPDIRECT3DDEVICE lpD3DDeviceEB = NULL; LPDIRECTDRAWSURFACE4 lpBackBuffer = NULL; LPDIRECTDRAWSURFACE4 lpFrontBuffer = NULL; LPDIRECTDRAWSURFACE4 lpZBuffer = NULL; LPDIRECTDRAWCOLORCONTROL lpColorControl = NULL; LPDIRECTDRAWGAMMACONTROL lpGammaControl = NULL; LPDIRECT3DVIEWPORT3 lpViewport = NULL; LPDIRECT3DTEXTURE2 lpTextureInterface = NULL; LPDIRECTDRAWSURFACE4 *BitmapTextureSurfaces, *LightmapTextureSurfaces, *UploadSurfaces, *Upload4444Surfaces, *UploadBumpmapSurfaces, *BumpmapTextureSurfaces = NULL; int d3d_EnvironmentMap = -1; #define MAX_D2D_DEVICES 6 #define MAX_D3D_DEVICES 6 typedef struct d3d_device { GUID guid_2d; LPGUID pguid_2d; GUID guid_3d; LPGUID pguid_3d; char name[1024]; } d3d_device; d3d_device D2D_devices[MAX_D2D_DEVICES]; d3d_device D3D_devices[MAX_D3D_DEVICES]; int Num_d2d_devices = 0; int Num_d3d_devices = 0; // Cache variables int d3d_Cache_tick = 0; static int Last_texture_bound[3] = {-1, -1, -1}; // For zbuffer enumeration #define MAX_ZDEPTHS 16 int NumZDepths = 0; DDPIXELFORMAT ZPixFormats[MAX_ZDEPTHS]; // For texture format enumeration #define MAX_TEXTURE_FORMATS 128 int Num_texture_formats = 0; DDPIXELFORMAT RGB_texture_format, Texture_4444_format, Compressed_texture_format, Bumpmap_texture_format; DDPIXELFORMAT TextureFormats[MAX_TEXTURE_FORMATS]; bool D3D_multitexture_state = false; bool D3D_bumpmap_state = false; ubyte D3D_frame_started = 0; float d3d_FogDiff = 0; // For verifying the texture/alpha types before rendering int Alpha_always_set = -1; // Alpha to multiply by static float Alpha_multiplier = 1.0; static float d3d_Alpha_factor = 1.0f; // Caps for this device bool d3d_MultiTexture = false; bool d3d_WBuffer = false; bool d3d_ZBias = false; bool d3d_CanMip = false; bool d3d_CanGamma = false; bool d3d_CanFog = false; bool d3d_CanZCompare = false; bool d3d_CanBumpmap = false; bool d3d_CanCompress = false; bool d3d_TextureMemories = false; bool d3d_IsRiva128 = false; bool d3d_SubpixelCorrect = true; float d3d_WBias = 0, UV_diff = 0; void d3d_SetD3DIdentity(D3DMATRIX *mat) { memset(mat, 0, sizeof(D3DMATRIX)); mat->_11 = 1; mat->_22 = 1; mat->_33 = 1; mat->_44 = 1; } void d3d_SetWBufferDepth(float dvWFar) { HRESULT res; D3DMATRIX matWorld; D3DMATRIX matView; D3DMATRIX matProj; d3d_SetD3DIdentity(&matWorld); d3d_SetD3DIdentity(&matView); d3d_SetD3DIdentity(&matProj); res = lpD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matWorld); res = lpD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &matView); matProj._43 = 0; matProj._34 = 1; matProj._44 = 1; matProj._33 = 1 / (dvWFar - 1) + 1; res = lpD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &matProj); } // Get the capabilities of the Direct3D device void d3d_GetCaps() { d3d_TextureMemories = false; d3d_CanFog = false; d3d_MultiTexture = false; d3d_WBuffer = false; d3d_ZBias = false; d3d_CanMip = false; d3d_CanGamma = false; d3d_CanZCompare = false; d3d_WBias = 0; d3d_CanBumpmap = false; d3d_IsRiva128 = false; d3d_SubpixelCorrect = true; // Check whether the device supports real multitexturing (if not, we're // going to emulate it using multipass rendering) D3DDEVICEDESC ddHwDesc, ddSwDesc; ddHwDesc.dwSize = sizeof(D3DDEVICEDESC); ddSwDesc.dwSize = sizeof(D3DDEVICEDESC); lpD3DDevice->GetCaps(&ddHwDesc, &ddSwDesc); // See if we have separate texture memories if (ddHwDesc.dwDevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES) { d3d_TextureMemories = true; mprintf((0, "Device has texture memories!\n")); } // Check to see if this device supports bumpmapping if (ddHwDesc.dwTextureOpCaps & D3DTEXOPCAPS_BUMPENVMAP) { d3d_CanBumpmap = true; mprintf((0, "Device support bumpmapping!\n")); } else { mprintf((0, "Device DOES NOT support bumpmapping!\n")); } if (!FindArg("-bumped")) { d3d_CanBumpmap = false; mprintf((0, "Turning off bumpmapping because switch not found.\n")); } // Check if the device supports single pass multiple texture. if (ddHwDesc.wMaxSimultaneousTextures > 1) { if (ddHwDesc.dwTextureOpCaps & D3DTEXOPCAPS_MODULATE) { d3d_MultiTexture = true; UseMultitexture = true; } else { UseMultitexture = false; d3d_TextureMemories = false; } } if (FindArg("-NoMultitexture")) { d3d_MultiTexture = false; UseMultitexture = false; d3d_TextureMemories = false; } if (d3d_MultiTexture) mprintf((0, "Device has multitexture caps!\n")); else mprintf((0, "Device DOES NOT have multitexture caps!\n")); // Get triangle caps and check for caps LPD3DPRIMCAPS pdpc = &ddHwDesc.dpcTriCaps; // Check for Z compare caps if (pdpc->dwZCmpCaps & D3DPCMPCAPS_LESSEQUAL) { d3d_CanZCompare = true; mprintf((0, "Device HAS Z compare caps!\n")); } else mprintf((0, "Device DOES NOT have Z compare caps!\n")); // Check if it supports Wbuffering if (pdpc->dwRasterCaps & D3DPRASTERCAPS_WBUFFER) { mprintf((0, "Device has Wbuffer!\n")); d3d_WBuffer = true; UseWBuffer = true; } else { mprintf((0, "Device DOES NOT have Wbuffer!\n")); d3d_WBuffer = false; UseWBuffer = false; } // Check for zbias if (pdpc->dwRasterCaps & D3DPRASTERCAPS_ZBIAS) { mprintf((0, "Device has ZBias!\n")); d3d_ZBias = true; } else { mprintf((0, "Device DOES NOT have ZBias!\n")); d3d_ZBias = false; } // Check for fog table if (pdpc->dwRasterCaps & D3DPRASTERCAPS_FOGVERTEX) { mprintf((0, "Device has Fogtable!\n")); d3d_CanFog = true; } else { mprintf((0, "Device DOES NOT have Fogtable!\n")); d3d_CanFog = false; } if (FindArg("-NoOutdoorFog")) d3d_CanFog = false; // Check for mip mapping if (pdpc->dwTextureFilterCaps & (D3DPTFILTERCAPS_MIPLINEAR)) { d3d_CanMip = true; mprintf((0, "Device has mip map capabilities!\n")); } else { d3d_CanMip = false; mprintf((0, "Device DOES NOT have mip map capabilities!\n")); } // Get the interface to the gamma control int ddrval = lpFrontBuffer->QueryInterface(IID_IDirectDrawGammaControl, (LPVOID *)&lpGammaControl); if (ddrval != DD_OK) mprintf((0, "D3D_INIT: QueryInterface for gamma failed.\n")); else { mprintf((0, "Gamma interface detection successful!\n")); d3d_CanGamma = true; } DDCAPS hcaps, helcaps; memset(&hcaps, 0, sizeof(DDCAPS)); memset(&helcaps, 0, sizeof(DDCAPS)); hcaps.dwSize = sizeof(DDCAPS); helcaps.dwSize = sizeof(DDCAPS); lpDD->GetCaps(&hcaps, &helcaps); if (hcaps.dwCaps2 & DDCAPS2_PRIMARYGAMMA) { mprintf((0, "Device DOES NOT have gamma support.\n")); } else { mprintf((0, "Secondary gamma detection successful!\n")); } // Now detect for riva128 (only if wbuffer is not detected for that card) DDDEVICEIDENTIFIER did; lpDD->GetDeviceIdentifier(&did, 0); if (d3d_WBuffer == false && did.dwVendorId == 0x12d2) { if (did.dwDeviceId == 0x18 || did.dwDeviceId == 0x19) { d3d_IsRiva128 = true; // NoLightmaps=true; mprintf((0, "Device IS Riva128!\n")); } else { mprintf((0, "Device IS NOT Riva128!\n")); } } if (FindArg("-subpixelcorrect")) d3d_SubpixelCorrect = false; } // Sets up an enviroment variable string for our gamma void d3d_SetGammaString(float val) { char *envstring = "SST_GAMMA"; char envvalue[10]; sprintf(envvalue, "%f", val); SetEnvironmentVariable(envstring, envvalue); mprintf((0, "Setting D3D gamma to %f\n", val)); } // Places a device into our global list of 3d devices to choose from HRESULT WINAPI d3d_Enumerate3DDevice(LPGUID lpGUID, LPSTR lpDeviceDescription, LPSTR lpDeviceName, LPD3DDEVICEDESC lpHWDesc, LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext) { int use_it = 0; if (lpHWDesc && lpHWDesc->dwFlags != 0) use_it = 1; if (use_it) { mprintf((0, "Found 3d device %s: %s\n", lpDeviceName, lpDeviceDescription)); d3d_device *d2d = (d3d_device *)lpContext; d3d_device *d3d = (d3d_device *)&D3D_devices[Num_d3d_devices++]; if (lpGUID) { memmove(&d3d->guid_3d, lpGUID, sizeof(GUID)); d3d->pguid_3d = &d3d->guid_3d; } else { memset(&d3d->guid_3d, 0, sizeof(GUID)); d3d->pguid_3d = NULL; } memmove(&d3d->guid_2d, &d2d->guid_2d, sizeof(GUID)); if (d2d->pguid_2d) { d3d->pguid_2d = &d3d->guid_2d; } else { d3d->pguid_2d = NULL; } strcat(d3d->name, d2d->name); } return D3DENUMRET_OK; } // Places a device into our global list of 2d devices to choose from BOOL WINAPI d3d_Enumerate2DDevice(LPGUID lpGUID, LPSTR lpDeviceDescription, LPSTR lpDeviceName, LPVOID lpContext) { d3d_device *d2d = (d3d_device *)&D2D_devices[Num_d2d_devices++]; mprintf((0, "Found 2d device %s: %s\n", lpDeviceName, lpDeviceDescription)); if (lpGUID) { memmove(&d2d->guid_2d, lpGUID, sizeof(GUID)); d2d->pguid_2d = &d2d->guid_2d; } else { memset(&d2d->guid_2d, 0, sizeof(GUID)); d2d->pguid_2d = NULL; } strcpy(d2d->name, lpDeviceDescription); return D3DENUMRET_OK; } // Enumerates the zbuffer types we have to choose from long WINAPI d3d_EnumZPixelFormats(LPDDPIXELFORMAT pixfmt, LPVOID lpContext) { if (NumZDepths >= MAX_ZDEPTHS) return D3DENUMRET_OK; if (!(pixfmt->dwFlags & DDPF_ZBUFFER)) return D3DENUMRET_OK; ZPixFormats[NumZDepths++] = *pixfmt; return D3DENUMRET_OK; } // Enumerates the texture pixel formats we have to choose from long WINAPI d3d_EnumTexturePixelFormats(LPDDPIXELFORMAT pixfmt, LPVOID lpContext) { if (Num_texture_formats >= MAX_TEXTURE_FORMATS) return D3DENUMRET_CANCEL; TextureFormats[Num_texture_formats++] = *pixfmt; return D3DENUMRET_OK; } // Sets up the best device to use d3d_device *d3d_PollDevices() { int i; HRESULT ddrval; Num_d2d_devices = 0; Num_d3d_devices = 0; ddrval = DirectDrawEnumerate(d3d_Enumerate2DDevice, NULL); if (ddrval != DD_OK) { mprintf((0, "D3D_INIT: DirectDrawEnumerate failed.\n")); goto D3DError; } // Go through all 2d devices then create their 3d devices to create the total // number of 3d devices to to choose from mprintf((0, "Found %d 2d devices...checking for 3d devices.\n", Num_d2d_devices)); for (i = 0; i < Num_d2d_devices; i++) { d3d_device *d2d = (d3d_device *)&D2D_devices[i]; // Create direct draw surface ddrval = DirectDrawCreate(d2d->pguid_2d, &lpDD1, NULL); if (ddrval != DD_OK) { mprintf((0, "D3D_INIT: DirectDrawCreate failed.\n")); goto D3DError; } ddrval = lpDD1->QueryInterface(IID_IDirect3D3, (LPVOID *)&lpD3D); if (ddrval != DD_OK) { lpD3D = NULL; mprintf((0, "D3D_INIT: QueryInterface failed.\n")); goto D3DError; } // Enumerate this 3d device ddrval = lpD3D->EnumDevices(d3d_Enumerate3DDevice, d2d); if (ddrval != DD_OK) { mprintf((0, "WIN_DD32: D3D enum devices failed. (0x%x)\n", ddrval)); } lpD3D->Release(); lpD3D = NULL; lpDD1->Release(); lpDD1 = NULL; } for (i = 0; i < Num_d3d_devices; i++) { mprintf((0, "D3D Device %d: %s\n", i, D3D_devices[i].name)); } if (Num_d3d_devices <= 0) { mprintf((0, "No D3D device found!\n")); return NULL; } if (Num_d3d_devices > 0) { int use_device = 0; if (Num_d3d_devices > 1) { char tempbuffer[255]; int templen = 255; mprintf((0, "More than one D3D device found!\n")); Database->read("RenderingDeviceName", tempbuffer, &templen); int done = 0; for (i = 0; i < Num_d3d_devices && !done; i++) { if (!stricmp(tempbuffer, D3D_devices[i].name)) { use_device = i; done = 1; } } if (done == 0) use_device = 0; } // use_device=Num_d3d_devices-1; if (FindArg("-useseconddevice") && Num_d3d_devices > 1) use_device = Num_d3d_devices - 1; mprintf((0, "Using %s\n", D3D_devices[use_device].name)); // Use the last device. return &D3D_devices[use_device]; } return NULL; D3DError: mprintf((0, "Direct3D Polling failed.\n")); return NULL; } // Returns the number of bits used in a mask WORD d3d_GetNumOfBits(DWORD dwMask) { WORD wBits = 0; while (dwMask) { dwMask = dwMask & (dwMask - 1); wBits++; } return wBits; } int d3d_GetTexClass(int handle, int map_type) { int w, tex_class; if (map_type == MAP_TYPE_LIGHTMAP) w = GameLightmaps[handle].square_res; else if (map_type == MAP_TYPE_BUMPMAP) w = GameBumpmaps[handle].width; else w = bm_w(handle, 0); if (w == 256) tex_class = 0; else if (w == 128) tex_class = 1; else if (w == 64) tex_class = 2; else if (w == 32) tex_class = 3; else { mprintf((0, "Bad class for d3d!\n")); Int3(); } return tex_class; } // Given a bitmap handle, a map type, and a destination d3d slot, takes the data // from the application and massages it for direct3d's consumption void d3d_UploadBitmapToSurface(int handle, int map_type, int slot, int new_upload) { DDSURFACEDESC2 surf_desc; LPDIRECTDRAWSURFACE4 dest_sp, upload_sp; HRESULT ddrval; int w, h; ushort *src_data; // mprintf ((0,"Uploading bitmap %d type %d\n",handle,map_type)); // mprintf ((0,"Slot=%d handle=%d\n",slot,handle)); ASSERT(slot != -1); ASSERT(slot == handle); int tex_class = d3d_GetTexClass(handle, map_type); if (map_type == MAP_TYPE_BITMAP) { w = bm_w(handle, 0); h = bm_h(handle, 0); ASSERT(GameBitmaps[handle].cache_slot == handle); if (bm_format(handle) == BITMAP_FORMAT_4444) upload_sp = Upload4444Surfaces[tex_class]; else upload_sp = UploadSurfaces[tex_class]; dest_sp = BitmapTextureSurfaces[slot]; src_data = bm_data(handle, 0); } else if (map_type == MAP_TYPE_BUMPMAP) { w = bump_w(handle); h = bump_h(handle); ASSERT(GameBumpmaps[handle].cache_slot == handle); dest_sp = BumpmapTextureSurfaces[slot]; src_data = bump_data(handle); } else { w = lm_w(handle); h = lm_h(handle); ASSERT(GameLightmaps[handle].cache_slot == handle); dest_sp = LightmapTextureSurfaces[slot]; upload_sp = UploadSurfaces[tex_class]; src_data = lm_data(handle); } ASSERT(dest_sp != NULL); memset(&surf_desc, 0, sizeof(DDSURFACEDESC2)); surf_desc.dwSize = sizeof(DDSURFACEDESC2); surf_desc.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); // Now that we have a lock, blit this bitmap to the surface if (map_type == MAP_TYPE_BUMPMAP) { ddrval = dest_sp->Lock(NULL, &surf_desc, DDLOCK_WAIT, NULL); if (ddrval != DD_OK) { mprintf((0, "D3D:Normal upload lock error %d! %s\n", ddrval, d3d_ErrorString(ddrval))); return; } ushort *dest_data = (ushort *)surf_desc.lpSurface; memcpy(dest_data, src_data, w * h * 2); // Unlock the surface dest_sp->Unlock(NULL); } else if (map_type == MAP_TYPE_LIGHTMAP) { // Light maps aren't square, but our surfaces are... int partial_replace = 0; RECT lmap_rect; if (!new_upload && (GameLightmaps[handle].flags & LF_LIMITS)) { partial_replace = 1; lmap_rect.left = 0; lmap_rect.right = w; lmap_rect.top = GameLightmaps[handle].cy1; lmap_rect.bottom = GameLightmaps[handle].cy2; ddrval = upload_sp->Lock(&lmap_rect, &surf_desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); // ddrval=dest_sp->Lock(&lmap_rect,&surf_desc,DDLOCK_WAIT|DDLOCK_WRITEONLY,NULL); } else ddrval = upload_sp->Lock(NULL, &surf_desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); // ddrval=dest_sp->Lock(NULL,&surf_desc,DDLOCK_WAIT|DDLOCK_WRITEONLY,NULL); if (ddrval != DD_OK) { mprintf((0, "D3D:Upload lock error %d! %s\n", ddrval, d3d_ErrorString(ddrval))); return; } ushort *left_data = (ushort *)surf_desc.lpSurface; int bm_left = 0; int size = GameLightmaps[handle].square_res; if (partial_replace) { int y1 = (GameLightmaps[handle].cy1); int y2 = (GameLightmaps[handle].cy2); int ph = (y2 - y1); bm_left += (w * y1); for (int i = 0; i < ph; i++, left_data += size, bm_left += w) { ushort *dest_data = left_data; for (int t = 0; t < w; t++) { *dest_data++ = src_data[bm_left + t]; } } // Unlock the lightmap surface upload_sp->Unlock(&lmap_rect); dest_sp->Blt(&lmap_rect, upload_sp, &lmap_rect, DDBLT_WAIT, NULL); } else { for (int i = 0; i < h; i++, left_data += size, bm_left += w) { ushort *dest_data = left_data; for (int t = 0; t < w; t++) { *dest_data++ = src_data[bm_left + t]; } } // Unlock the lightmap surface upload_sp->Unlock(NULL); dest_sp->Blt(NULL, upload_sp, NULL, DDBLT_WAIT, NULL); } } else // Must bit a bitmap { if (d3d_CanMip && map_type == MAP_TYPE_BITMAP && GameBitmaps[handle].flags & BF_MIPMAPPED) { LPDIRECTDRAWSURFACE4 dest_mipsurf = dest_sp; DDSCAPS2 ddsCaps; ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP; for (int i = 0; i < NUM_MIP_LEVELS; i++) { ddrval = upload_sp->Lock(NULL, &surf_desc, DDLOCK_WAIT, NULL); if (ddrval != DD_OK) { mprintf((0, "D3D:mip=%d Upload lock error %d! %s\n", i, ddrval, d3d_ErrorString(ddrval))); return; } src_data = bm_data(handle, i); w = bm_w(handle, i); h = bm_h(handle, i); ushort *dest_data = (ushort *)surf_desc.lpSurface; // Copy the raw data into the directx surface int pitch_diff = (surf_desc.lPitch / 2) - w; for (int y = 0; y < h; y++, dest_data += pitch_diff) { for (int x = 0; x < w; x++) { *dest_data++ = *src_data++; } } upload_sp->Unlock(NULL); dest_mipsurf->Blt(NULL, upload_sp, NULL, DDBLT_WAIT, NULL); if (i != NUM_MIP_LEVELS - 1) // Get next mip surface { if (bm_format(handle) == BITMAP_FORMAT_4444) upload_sp = Upload4444Surfaces[tex_class + 1 + i]; else upload_sp = UploadSurfaces[tex_class + 1 + i]; ddrval = dest_mipsurf->GetAttachedSurface(&ddsCaps, &dest_mipsurf); if (ddrval != DD_OK) { mprintf((0, "Couldn't get attached dest mip surface %d!\n", i)); return; } dest_mipsurf->Release(); } } } else { // Do a non-mipped bitmap ddrval = upload_sp->Lock(NULL, &surf_desc, DDLOCK_WAIT, NULL); if (ddrval != DD_OK) { mprintf((0, "D3D:Normal upload lock error %d! %s\n", ddrval, d3d_ErrorString(ddrval))); return; } ushort *dest_data = (ushort *)surf_desc.lpSurface; memcpy(dest_data, src_data, w * h * 2); // Unlock the surface upload_sp->Unlock(NULL); dest_sp->Blt(NULL, upload_sp, NULL, DDBLT_WAIT, NULL); } } if (map_type == MAP_TYPE_BITMAP) GameBitmaps[handle].flags &= ~BF_CHANGED; else if (map_type == MAP_TYPE_BUMPMAP) GameBumpmaps[handle].flags &= ~BUMPF_CHANGED; else GameLightmaps[handle].flags &= ~(LF_CHANGED | LF_LIMITS); D3D_uploads++; } // Returns index into the global array of texture interfaces we have int d3d_CreateTextureFromBitmap(int bm_handle, int map_type) { int w, h; int retval = -1; HRESULT ddrval; // mprintf ((0,"Creating texture from handle %d type %d\n",bm_handle,map_type)); if (map_type == MAP_TYPE_BUMPMAP) { ASSERT(GameBumpmaps[bm_handle].cache_slot == -1); w = bump_w(bm_handle); h = bump_h(bm_handle); } else if (map_type == MAP_TYPE_LIGHTMAP) { ASSERT(GameLightmaps[bm_handle].cache_slot == -1); w = GameLightmaps[bm_handle].square_res; h = GameLightmaps[bm_handle].square_res; } else { ASSERT(GameBitmaps[bm_handle].cache_slot == -1); w = bm_w(bm_handle, 0); h = bm_h(bm_handle, 0); // Pointer to a bitmap surface } // Create a texture interface and make it auto-managed DDSURFACEDESC2 ddsd; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; ddsd.dwWidth = w; ddsd.dwHeight = h; if (map_type == MAP_TYPE_BITMAP && bm_format(bm_handle) == BITMAP_FORMAT_4444) { ddsd.ddpfPixelFormat = Texture_4444_format; ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_HINTSTATIC; } else if (d3d_CanCompress && map_type == MAP_TYPE_BITMAP && bm_format(bm_handle) == BITMAP_FORMAT_1555 && (GameBitmaps[bm_handle].flags & BF_COMPRESSABLE)) { ddsd.ddpfPixelFormat = Compressed_texture_format; ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC; ddsd.ddpfPixelFormat.dwFourCC = FOURCC_DXT1; ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_HINTSTATIC; } else if (map_type == MAP_TYPE_BUMPMAP) { ddsd.ddpfPixelFormat = Bumpmap_texture_format; ddsd.ddpfPixelFormat.dwFlags = DDPF_BUMPDUDV; ddsd.ddpfPixelFormat.dwBumpBitCount = 16; ddsd.ddpfPixelFormat.dwBumpDuBitMask = 0x000000ff; ddsd.ddpfPixelFormat.dwBumpDvBitMask = 0x0000ff00; ddsd.ddpfPixelFormat.dwBumpLuminanceBitMask = 0x00000000; } else { if (map_type == MAP_TYPE_LIGHTMAP) { ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_HINTDYNAMIC; } else if (map_type == MAP_TYPE_BITMAP && GameBitmaps[bm_handle].flags & BF_MIPMAPPED) ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_HINTSTATIC; ddsd.ddpfPixelFormat = RGB_texture_format; } if (d3d_CanMip && map_type == MAP_TYPE_BITMAP && GameBitmaps[bm_handle].flags & BF_MIPMAPPED) { ddsd.dwFlags |= DDSD_MIPMAPCOUNT; ddsd.dwMipMapCount = NUM_MIP_LEVELS; ddsd.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP; } // Assign the correct texture stage if (d3d_TextureMemories) { ddsd.dwFlags |= DDSD_TEXTURESTAGE; if (map_type == MAP_TYPE_LIGHTMAP) ddsd.dwTextureStage = 1; else ddsd.dwTextureStage = 0; } int dest_index; if (map_type == MAP_TYPE_BITMAP) { dest_index = bm_handle; ASSERT(GameBitmaps[bm_handle].cache_slot == -1); ddrval = lpDD->CreateSurface(&ddsd, &BitmapTextureSurfaces[dest_index], NULL); } else if (map_type == MAP_TYPE_BUMPMAP) { dest_index = bm_handle; ASSERT(GameBumpmaps[bm_handle].cache_slot == -1); ddrval = lpDD->CreateSurface(&ddsd, &BumpmapTextureSurfaces[dest_index], NULL); } else { dest_index = bm_handle; ASSERT(GameLightmaps[bm_handle].cache_slot == -1); ddrval = lpDD->CreateSurface(&ddsd, &LightmapTextureSurfaces[dest_index], NULL); } if (ddrval != DD_OK) { mprintf((0, "Creating texture surface failed!\n")); return -1; } ASSERT(dest_index == bm_handle); if (map_type == MAP_TYPE_LIGHTMAP) { GameLightmaps[bm_handle].cache_slot = bm_handle; d3d_UploadBitmapToSurface(bm_handle, map_type, dest_index, 1); retval = dest_index; } else if (map_type == MAP_TYPE_BUMPMAP) { GameBumpmaps[bm_handle].cache_slot = bm_handle; d3d_UploadBitmapToSurface(bm_handle, map_type, dest_index, 1); retval = dest_index; } else { GameBitmaps[bm_handle].cache_slot = bm_handle; d3d_UploadBitmapToSurface(bm_handle, map_type, dest_index, 1); retval = dest_index; } return retval; } // Frees all the memory used by the texture cache void d3d_FreeTextureCache() { int i; if (UploadSurfaces) { for (i = 0; i < NUM_TEXTURE_CLASSES; i++) { UploadSurfaces[i]->Release(); } mem_free(UploadSurfaces); UploadSurfaces = NULL; } if (Upload4444Surfaces) { for (i = 0; i < NUM_TEXTURE_CLASSES; i++) { Upload4444Surfaces[i]->Release(); } mem_free(Upload4444Surfaces); Upload4444Surfaces = NULL; } if (BitmapTextureSurfaces) { for (i = 0; i < MAX_BITMAPS; i++) { if (GameBitmaps[i].cache_slot != -1) { if (GameBitmaps[i].cache_slot != i) { mprintf((0, "Error cache slot is %d when it should be %d!\n", GameBitmaps[i].cache_slot, i)); } ASSERT(GameBitmaps[i].cache_slot == i); d3d_FreePreUploadedTexture(i, MAP_TYPE_BITMAP); } } mem_free(BitmapTextureSurfaces); BitmapTextureSurfaces = NULL; } if (BumpmapTextureSurfaces) { for (i = 0; i < MAX_BUMPMAPS; i++) { if (GameBumpmaps[i].cache_slot != -1) { ASSERT(GameBumpmaps[i].cache_slot == i); d3d_FreePreUploadedTexture(i, MAP_TYPE_BUMPMAP); } } mem_free(BumpmapTextureSurfaces); BumpmapTextureSurfaces = NULL; } if (LightmapTextureSurfaces) { for (i = 0; i < MAX_LIGHTMAPS; i++) { if (GameLightmaps[i].cache_slot != -1) { ASSERT(GameLightmaps[i].cache_slot == i); d3d_FreePreUploadedTexture(i, MAP_TYPE_LIGHTMAP); } } mem_free(LightmapTextureSurfaces); LightmapTextureSurfaces = NULL; } } // Creates the surfaces we use for uploading int d3d_CreateUploadSurfaces() { int i; HRESULT ddrval; for (i = 0; i < NUM_TEXTURE_CLASSES; i++) { // Create a texture interface and make it auto-managed DDSURFACEDESC2 ddsd; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; ddsd.dwWidth = 256 >> i; ddsd.dwHeight = 256 >> i; ddsd.ddpfPixelFormat = RGB_texture_format; ddrval = lpDD->CreateSurface(&ddsd, &UploadSurfaces[i], NULL); if (ddrval != DD_OK) { mprintf((0, "Creating 1555 texture surface failed!\n")); return 0; } } // Now create 4444 surfaces for (i = 0; i < NUM_TEXTURE_CLASSES; i++) { // Create a texture interface and make it auto-managed DDSURFACEDESC2 ddsd; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; ddsd.dwWidth = 256 >> i; ddsd.dwHeight = 256 >> i; ddsd.ddpfPixelFormat = Texture_4444_format; ddrval = lpDD->CreateSurface(&ddsd, &Upload4444Surfaces[i], NULL); if (ddrval != DD_OK) { mprintf((0, "Creating 4444 texture surface failed!\n")); return 0; } } return 1; } // Loads an environment map for bumpmapping. Returns 1 on success, 0 on fail int d3d_LoadEnvironmentMap() { if (d3d_EnvironmentMap != -1) return 1; d3d_EnvironmentMap = bm_AllocLoadFileBitmap("Environment.ogf", 0); if (d3d_EnvironmentMap < 0) return 0; return 1; } // Initializes the texture cache for Direct3D int d3d_TextureCacheInit() { int i; // Clear our cache slots for (i = 0; i < MAX_LIGHTMAPS; i++) { GameLightmaps[i].cache_slot = -1; } for (i = 0; i < MAX_BITMAPS; i++) { GameBitmaps[i].cache_slot = -1; } for (i = 0; i < MAX_BUMPMAPS; i++) { GameBumpmaps[i].cache_slot = -1; } // Allocate room to hold all our surfaces UploadSurfaces = (LPDIRECTDRAWSURFACE4 *)mem_malloc(NUM_TEXTURE_CLASSES * sizeof(LPDIRECTDRAWSURFACE4)); if (UploadSurfaces == NULL) { mprintf((0, "Couldn't allocate memory for UploadSurfaces!\n")); rend_SetErrorMessage("Couldn't alloc mem for UploadSurfaces!"); return 0; } // Allocate room to hold all our 4444 surfaces Upload4444Surfaces = (LPDIRECTDRAWSURFACE4 *)mem_malloc(NUM_TEXTURE_CLASSES * sizeof(LPDIRECTDRAWSURFACE4)); if (Upload4444Surfaces == NULL) { mprintf((0, "Couldn't allocate memory for Upload4444Surfaces!\n")); rend_SetErrorMessage("Couldn't alloc mem for Upload4444Surfaces!"); return 0; } BitmapTextureSurfaces = (LPDIRECTDRAWSURFACE4 *)mem_malloc(MAX_BITMAPS * sizeof(LPDIRECTDRAWSURFACE4)); if (BitmapTextureSurfaces == NULL) { mprintf((0, "Couldn't allocate memory for BitmapTextureSurfaces!\n")); rend_SetErrorMessage("Couldn't alloc mem for BitmapTextureSurfaces!"); return 0; } // Allocate room to hold all our surfaces LightmapTextureSurfaces = (LPDIRECTDRAWSURFACE4 *)mem_malloc(MAX_LIGHTMAPS * sizeof(LPDIRECTDRAWSURFACE4)); if (LightmapTextureSurfaces == NULL) { mprintf((0, "Couldn't allocate memory for LightmapTextureSurfaces!\n")); rend_SetErrorMessage("Couldn't alloc mem for LightmapTextureSurfaces!"); return 0; } if (d3d_CanBumpmap) { BumpmapTextureSurfaces = (LPDIRECTDRAWSURFACE4 *)mem_malloc(MAX_BUMPMAPS * sizeof(LPDIRECTDRAWSURFACE4)); if (BumpmapTextureSurfaces == NULL) { mprintf((0, "Couldn't allocate memory for BumpmapTextureSurfaces!\n")); rend_SetErrorMessage("Couldn't alloc mem for BumpmapTextureSurfaces!"); return 0; } if (!d3d_LoadEnvironmentMap()) { mprintf((0, "couldn't load env map\n")); return 0; } } // Enumerate those texture formats lpD3DDevice->EnumTextureFormats(d3d_EnumTexturePixelFormats, 0); if (Num_texture_formats < 1) { mprintf((0, "No texture formats available!\n")); rend_SetErrorMessage("No valid texture formats available!"); return 0; } // Find a pixel format with 1555 int found_format = -1; for (i = 0; i < Num_texture_formats && found_format == -1; i++) { DDPIXELFORMAT *pf = &TextureFormats[i]; int rcount, gcount, bcount, acount; rcount = d3d_GetNumOfBits(pf->dwRBitMask); gcount = d3d_GetNumOfBits(pf->dwGBitMask); bcount = d3d_GetNumOfBits(pf->dwBBitMask); acount = d3d_GetNumOfBits(pf->dwRGBAlphaBitMask); if (rcount == 5 && gcount == 5 && bcount == 5 && acount == 1) { found_format = i; mprintf((1, "Alpha bit mask is %d!\n", pf->dwRGBAlphaBitMask)); } } if (found_format == -1) { mprintf((0, "Couldn't find a valid 1555 pixel format!\n")); rend_SetErrorMessage("Couldn't find a valid 1555 pixel format! Card doesn't support 1555 format!"); return 0; } RGB_texture_format = TextureFormats[found_format]; // Find a pixel format with 4444 found_format = -1; for (i = 0; i < Num_texture_formats && found_format == -1; i++) { DDPIXELFORMAT *pf = &TextureFormats[i]; int rcount, gcount, bcount, acount; rcount = d3d_GetNumOfBits(pf->dwRBitMask); gcount = d3d_GetNumOfBits(pf->dwGBitMask); bcount = d3d_GetNumOfBits(pf->dwBBitMask); acount = d3d_GetNumOfBits(pf->dwRGBAlphaBitMask); if (rcount == 4 && gcount == 4 && bcount == 4 && acount == 4) { found_format = i; mprintf((1, "Alpha bit mask is %d!\n", pf->dwRGBAlphaBitMask)); } } if (found_format == -1) { mprintf((0, "Couldn't find a valid 4444 pixel format!\n")); rend_SetErrorMessage("Couldn't find a valid 4444 pixel format! Card doesn't support 1555 format!"); return 0; } Texture_4444_format = TextureFormats[found_format]; // Find a pixel format with bumpmapping (if supported) if (d3d_CanBumpmap) { found_format = -1; for (i = 0; i < Num_texture_formats && found_format == -1; i++) { DDPIXELFORMAT *pf = &TextureFormats[i]; if (pf->dwFlags & DDPF_BUMPDUDV) { if (pf->dwBumpBitCount == 16 && pf->dwBumpDuBitMask == 0x000000ff && pf->dwBumpDvBitMask == 0x0000ff00 && pf->dwBumpLuminanceBitMask == 0) { found_format = i; mprintf((0, "Found a suitable bumpmapping format\n")); } } } if (found_format == -1) { mprintf((0, "Couldn't find a valid bumpmap pixel format!\n")); d3d_CanBumpmap = false; } else Bumpmap_texture_format = TextureFormats[found_format]; } // Check to see if it supports S3 compression // Find a pixel format with 1555 found_format = -1; for (i = 0; i < Num_texture_formats && found_format == -1; i++) { DDPIXELFORMAT *pf = &TextureFormats[i]; int rcount, gcount, bcount, acount; rcount = d3d_GetNumOfBits(pf->dwRBitMask); gcount = d3d_GetNumOfBits(pf->dwGBitMask); bcount = d3d_GetNumOfBits(pf->dwBBitMask); acount = d3d_GetNumOfBits(pf->dwRGBAlphaBitMask); if (pf->dwFourCC == FOURCC_DXT1) { found_format = i; mprintf((0, "Compress format: r=%d g=%d b=%d a=%d\n", rcount, gcount, bcount, acount)); mprintf((1, "Texture compression alpha bit mask is %d!\n", pf->dwRGBAlphaBitMask)); } } if (found_format == -1 || FindArg("-nocompress")) { mprintf((0, "Device doesn't support texture compression!\n")); d3d_CanCompress = false; } else { mprintf((0, "Device DOES support texture compression!\n")); d3d_CanCompress = true; Compressed_texture_format = TextureFormats[found_format]; } if (!d3d_CreateUploadSurfaces()) return 0; return 1; } // Sets up some default rendering states for Direct3D void d3d_SetDefaultStates() { // lpD3DDevice->SetLightState( D3DLIGHTSTATE_AMBIENT, 0xffffffff ); lpD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE); lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, TRUE); lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATER); lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHAREF, 0); lpD3DDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE); if (d3d_MultiTexture) { // Set second texel unit stages lpD3DDevice->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFN_LINEAR); lpD3DDevice->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR); lpD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); lpD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); lpD3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1); lpD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); lpD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); lpD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); lpD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); lpD3DDevice->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); D3D_multitexture_state = false; } if (d3d_CanBumpmap) { D3D_bumpmap_state = false; float _val = 0; lpD3DDevice->SetTextureStageState(1, D3DTSS_MIPFILTER, D3DTFP_LINEAR); lpD3DDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); lpD3DDevice->SetTextureStageState(2, D3DTSS_TEXCOORDINDEX, 1); lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVMAT00, *(DWORD *)(&(_val = 1.0f))); lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVMAT01, *(DWORD *)(&(_val = 0.0f))); lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVMAT10, *(DWORD *)(&(_val = 0.0f))); lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVMAT11, *(DWORD *)(&(_val = 1.0f))); lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVLSCALE, *(DWORD *)(&(_val = 1.0f))); lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVLOFFSET, *(DWORD *)(&(_val = 0.0f))); lpD3DDevice->SetTextureStageState(2, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); lpD3DDevice->SetTextureStageState(2, D3DTSS_COLORARG1, D3DTA_TEXTURE); lpD3DDevice->SetTextureStageState(2, D3DTSS_COLORARG2, D3DTA_CURRENT); } lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE); lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL); lpD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE); // Choose Wbuffer or straight zbuffer d3d_SetZBufferState(1); D3D_state.cur_color = 0x00FFFFFF; D3D_state.cur_bilinear_state = -1; D3D_state.cur_zbuffer_state = 1; D3D_state.cur_texture_quality = -1; D3D_state.cur_texture_type = TT_PERSPECTIVE_SPECIAL; // D3D doesn't support this state, so when d3d_SetTextureType // gets called we're guaranteed this will get set right D3D_state.cur_light_state = LS_GOURAUD; D3D_state.cur_color_model = CM_MONO; D3D_state.cur_bilinear_state = -1; D3D_state.cur_alpha_type = -1; Alpha_always_set = -1; d3d_SetWrapType(WT_WRAP); if (D3D_preferred_state.filtering) d3d_SetFiltering(1); else d3d_SetFiltering(0); if (D3D_preferred_state.mipping) d3d_SetMipState(1); else d3d_SetMipState(0); d3d_SetAlphaValue(255); d3d_SetAlphaType(AT_ALWAYS); d3d_SetZBufferState(1); d3d_SetZValues(0, 3000); d3d_SetGammaValue(D3D_preferred_state.gamma); d3d_SetFlatColor(GR_RGB(255, 128, 255)); D3D_state.screen_width = D3D_preferred_state.width; D3D_state.screen_height = D3D_preferred_state.height; if (d3d_WBuffer) d3d_SetWBufferDepth(5000); mprintf((0, "Direct3D initted to %d x %d\n", D3D_state.screen_width, D3D_state.screen_height)); Last_texture_bound[0] = -1; Last_texture_bound[1] = -1; Last_texture_bound[2] = -1; } // Returns true if we're using DirectX 6.0 bool d3d_UsingDX6() { LONG lResult; HKEY hKey = NULL; int dx_version = 0; lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectX", NULL, KEY_QUERY_VALUE, &hKey); if (lResult == ERROR_SUCCESS) { char version[32]; DWORD dwType, dwLen; dwLen = 32; lResult = RegQueryValueEx(hKey, "Version", NULL, &dwType, (ubyte *)version, &dwLen); if (lResult == ERROR_SUCCESS) { dx_version = atoi(strstr(version, ".") + 1); } else { int val; DWORD dwType, dwLen; dwLen = 4; lResult = RegQueryValueEx(hKey, "InstalledVersion", NULL, &dwType, (ubyte *)&val, &dwLen); if (lResult == ERROR_SUCCESS) { dx_version = val; } RegCloseKey(hKey); } } if (dx_version >= 6) return true; return false; } // Sets up our Direct3D rendering context // Returns 1 if ok, 0 if something bad int d3d_Init(oeApplication *app, renderer_preferred_state *pref_state) { HRESULT ddrval; HWND hwnd; d3d_device *dd; DDSURFACEDESC2 ddsd2; DDSCAPS2 ddscaps; int retval = 1; bool retried = false; int found_format = -1, i; if (!d3d_UsingDX6()) { rend_SetErrorMessage("DirectX 6 is not properly installed."); return 0; } ParentApplication = app; if (pref_state != &D3D_preferred_state) D3D_preferred_state = *pref_state; TryAgain: // Poll for valid 3d devices dd = d3d_PollDevices(); if (!dd) { mprintf((1, "ERROR: No Direct3D devices found!!!")); rend_SetErrorMessage("No Direct3D devices found!!!"); return 0; } hwnd = (HWND)((oeWin32Application *)app)->m_hWnd; // Create our direct draw stuff ddrval = DirectDrawCreate(dd->pguid_2d, &lpDD1, NULL); if (ddrval != DD_OK) { mprintf((0, "D3D_INIT: DirectDrawCreate failed.\n")); rend_SetErrorMessage("DirectDrawCreate failed."); goto D3DError; } ddrval = lpDD1->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpDD); if (ddrval != DD_OK) { lpDD = NULL; rend_SetErrorMessage("DirectDrawCreate2 failed."); mprintf((0, "D3D_INIT: DirectDrawCreate2 failed.\n")); goto D3DError; } ddrval = lpDD->SetCooperativeLevel(hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT); if (ddrval != DD_OK) { mprintf((0, "D3D_INIT: SetCooperativeLevel EXCLUSIVE failed.\n D3D_Error=%s\n", d3d_ErrorString(ddrval))); rend_SetErrorMessage("SetCoopLevel EXCULUSIVE failed."); goto D3DError; } // Go to full screen! if (D3D_preferred_state.bit_depth != 16 && D3D_preferred_state.bit_depth != 32) D3D_preferred_state.bit_depth = 16; mprintf((0, "Opening screen with bit-depth of %d.\n", D3D_preferred_state.bit_depth)); ddrval = lpDD->SetDisplayMode(D3D_preferred_state.width, D3D_preferred_state.height, D3D_preferred_state.bit_depth, 0, 0); if (ddrval != DD_OK) { mprintf((0, "D3D_INIT: SetDisplayMode failed, trying default!\n")); retval = -1; D3D_preferred_state.width = 640; D3D_preferred_state.height = 480; D3D_preferred_state.bit_depth = 16; ddrval = lpDD->SetDisplayMode(D3D_preferred_state.width, D3D_preferred_state.height, 16, 0, 0); if (ddrval != DD_OK) { mprintf((0, "D3D_INIT: SetDisplayMode failed.\n")); rend_SetErrorMessage("SetDisplayMode failed."); goto D3DError; } } memset(&ddsd2, 0, sizeof(ddsd2)); ddsd2.dwSize = sizeof(ddsd2); ddsd2.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX; ddsd2.dwBackBufferCount = 1; ddrval = lpDD->CreateSurface(&ddsd2, &lpFrontBuffer, NULL); if (ddrval != DD_OK) { mprintf((0, "D3D_INIT: CreateSurface (Front) failed.\n")); rend_SetErrorMessage("CreateSurface (front) failed."); goto D3DError; } memset(&ddscaps, 0, sizeof(DDSCAPS2)); ddscaps.dwCaps = DDSCAPS_BACKBUFFER; ddrval = lpFrontBuffer->GetAttachedSurface(&ddscaps, &lpBackBuffer); if (ddrval != DD_OK) { mprintf((0, "D3D_INIT: GetAttachedSurface (Back) failed. Erorr=%s\n", d3d_ErrorString(ddrval))); rend_SetErrorMessage("CreateSurface (back) failed."); goto D3DError; } // Create the Direct3d device ddrval = lpDD->QueryInterface(IID_IDirect3D3, (LPVOID *)&lpD3D); if (ddrval != DD_OK) { lpD3D = NULL; mprintf((0, "D3D_INIT: QueryInterface failed.\n")); rend_SetErrorMessage("QueryInterface D3D failed."); goto D3DError; } // Enumerate Z Buffer NumZDepths = 0; lpD3D->EnumZBufferFormats(dd->guid_3d, d3d_EnumZPixelFormats, 0); if (NumZDepths == 0) { mprintf((0, "D3D_INIT: Couldn't find zbuffer format!\n")); rend_SetErrorMessage("Couldn't find a zbuffer format!"); goto D3DError; } // Create a z-buffer and attach it to the backbuffer memset(&ddsd2, 0, sizeof(ddsd2)); ddsd2.dwSize = sizeof(ddsd2); ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; ddsd2.dwWidth = D3D_preferred_state.width; ddsd2.dwHeight = D3D_preferred_state.height; memset(&ddsd2.ddpfPixelFormat, 0, sizeof(ddsd2.ddpfPixelFormat)); found_format = 0; // Try to find a 32bit z buffer if (FindArg("-z32bit")) { for (i = 0; i < NumZDepths && found_format == -1; i++) { if (ZPixFormats[i].dwZBufferBitDepth == 32) found_format = i; } // Couldn't find a 32bit z, just use first one if (found_format == -1) found_format = 0; else mprintf((0, "Found a 32bit zbuffer.\n")); } ddsd2.ddpfPixelFormat = ZPixFormats[found_format]; // This should be used for hardware ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY; ddrval = lpDD->CreateSurface(&ddsd2, &lpZBuffer, NULL); if (ddrval != DD_OK) { mprintf((0, "D3D_INIT: Create Zbuffer failed.\nError=%s\n", d3d_ErrorString(ddrval))); rend_SetErrorMessage("Creating zbuffer failed."); goto D3DError; } if (lpBackBuffer->AddAttachedSurface(lpZBuffer) != DD_OK) { mprintf((0, "D3D_INIT: Attach Zbuffer failed.\n")); rend_SetErrorMessage("Attach ZBuffer failed."); goto D3DError; } // Create the D3D device ddrval = lpD3D->CreateDevice(dd->guid_3d, lpBackBuffer, &lpD3DDevice, 0); if (ddrval != DD_OK) { rend_SetErrorMessage("Create D3D Device3 failed."); mprintf((0, "D3D_INIT: Create D3D Device3 failed. %s\n", d3d_ErrorString(ddrval))); if (retried == false) { retried = true; d3d_Close(); D3D_preferred_state.width = 640; D3D_preferred_state.height = 480; D3D_preferred_state.bit_depth = 16; retval = -1; goto TryAgain; } else { goto D3DError; } } // Create and add viewport ddrval = lpD3D->CreateViewport(&lpViewport, NULL); if (ddrval != DD_OK) { rend_SetErrorMessage("CreateViewport failed."); mprintf((0, "D3D_INIT: CreateViewport failed.\n")); goto D3DError; } ddrval = lpD3DDevice->AddViewport(lpViewport); if (ddrval != DD_OK) { rend_SetErrorMessage("AddViewport failed."); mprintf((0, "D3D_INIT: AddViewport failed.\n")); goto D3DError; } // Setup the viewport for a reasonable viewing area D3DVIEWPORT2 viewdata; memset(&viewdata, 0, sizeof(viewdata)); // Compensate for aspect ratio viewdata.dwSize = sizeof(viewdata); viewdata.dwX = viewdata.dwY = 0; viewdata.dwWidth = D3D_preferred_state.width; viewdata.dwHeight = D3D_preferred_state.height; viewdata.dvMinZ = 0.0F; viewdata.dvMaxZ = 5000.0; viewdata.dvClipX = -1.0; viewdata.dvClipY = -((float)D3D_preferred_state.height / (float)D3D_preferred_state.width); viewdata.dvClipWidth = 2.0; viewdata.dvClipHeight = ((float)D3D_preferred_state.height / (float)D3D_preferred_state.width) * 2; ddrval = lpViewport->SetViewport2(&viewdata); if (ddrval != DD_OK) { rend_SetErrorMessage("SetViewport failed."); mprintf((0, "D3D_INIT: SetViewport failed.\n")); goto D3DError; } ddrval = lpD3DDevice->SetCurrentViewport(lpViewport); if (ddrval != DD_OK) { rend_SetErrorMessage("SetCurrentViewport failed."); mprintf((0, "D3D_INIT: SetCurrentViewport failed.\n")); goto D3DError; } d3d_GetCaps(); if (!d3d_TextureCacheInit()) { goto D3DError; } mprintf((0, "Direct3D Initialized OK!\n")); d3d_SetDefaultStates(); D3D_state.initted = 1; return retval; D3DError: mprintf((0, "Direct3D Initialization failed.\n")); d3d_Close(); Int3(); return 0; } // Releases the rendering context void d3d_Close() { if (lpColorControl) { lpColorControl->Release(); lpColorControl = NULL; } if (lpViewport) { lpViewport->Release(); lpViewport = NULL; } if (lpD3DDevice) { lpD3DDevice->Release(); lpD3DDevice = NULL; } if (lpZBuffer) { lpZBuffer->Release(); lpZBuffer = NULL; } if (lpBackBuffer) { lpBackBuffer->Release(); lpBackBuffer = NULL; } if (lpFrontBuffer) { lpFrontBuffer->Release(); lpFrontBuffer = NULL; } if (lpD3D) { lpD3D->EvictManagedTextures(); d3d_FreeTextureCache(); lpD3D->Release(); lpD3D = NULL; } if (lpDD1) { HRESULT ddrval; HWND hwnd = (HWND)((oeWin32Application *)ParentApplication)->m_hWnd; ddrval = lpDD->RestoreDisplayMode(); if (ddrval != DD_OK) { mprintf((0, "RestoreDisplayMode failed (0x%x)\n", ddrval)); } ddrval = lpDD->SetCooperativeLevel(hwnd, DDSCL_NORMAL); if (ddrval != DD_OK) { mprintf((0, "WIN_DD32: SetCooperativeLevel W Failed (0x%x)\n", ddrval)); } lpDD1->Release(); lpDD1 = NULL; } D3D_state.initted = 0; } // Sets the flat color...used for screen clears and the like void d3d_SetFlatColor(ddgr_color color) { if (D3D_state.cur_color == color) return; D3D_state.cur_color = color; } // returns the alpha that we should use int d3d_GetAlphaMultiplier() { switch (D3D_state.cur_alpha_type) { case AT_ALWAYS: return 255; case AT_CONSTANT: return D3D_state.cur_alpha; case AT_TEXTURE: return 255; case AT_CONSTANT_TEXTURE: return D3D_state.cur_alpha; case AT_VERTEX: return 255; case AT_CONSTANT_TEXTURE_VERTEX: case AT_CONSTANT_VERTEX: return D3D_state.cur_alpha; case AT_TEXTURE_VERTEX: return 255; case AT_LIGHTMAP_BLEND: case AT_LIGHTMAP_BLEND_SATURATE: return D3D_state.cur_alpha; case AT_SATURATE_TEXTURE: return D3D_state.cur_alpha; case AT_SATURATE_VERTEX: return 255; case AT_SATURATE_CONSTANT_VERTEX: return D3D_state.cur_alpha; case AT_SATURATE_TEXTURE_VERTEX: return 255; case AT_SPECULAR: return 255; default: mprintf((0, "Unrecognized alpha type=%d\n", D3D_state.cur_alpha_type)); // Int3(); // no type defined,get jason return 255; } } // Sets the alpha multiply factor void d3d_SetAlphaMultiplier() { Alpha_multiplier = d3d_GetAlphaMultiplier(); } extern bool Force_one_texture; // Sets up our bitmap/lightmap/bumpmap to be the next thing drawn int d3d_MakeBitmapCurrent(int handle, int map_type, int tn) { LPDIRECT3DTEXTURE2 tex_interface; HRESULT ddrval; LPDIRECTDRAWSURFACE4 sp; if (map_type == MAP_TYPE_BITMAP) { if (Force_one_texture) handle = 0; if (GameBitmaps[handle].cache_slot == -1) { int retval = d3d_CreateTextureFromBitmap(handle, map_type); if (retval < 0) return 0; } else { if (GameBitmaps[handle].flags & BF_CHANGED) { d3d_UploadBitmapToSurface(handle, map_type, GameBitmaps[handle].cache_slot, 0); } } ASSERT(GameBitmaps[handle].cache_slot != -1); sp = BitmapTextureSurfaces[GameBitmaps[handle].cache_slot]; } else if (map_type == MAP_TYPE_BUMPMAP) { if (GameBumpmaps[handle].cache_slot == -1) { int retval = d3d_CreateTextureFromBitmap(handle, map_type); if (retval < 0) return 0; } else { if (GameBumpmaps[handle].flags & BUMPF_CHANGED) { d3d_UploadBitmapToSurface(handle, map_type, GameBumpmaps[handle].cache_slot, 0); } } ASSERT(GameBumpmaps[handle].cache_slot != -1); sp = BumpmapTextureSurfaces[GameBumpmaps[handle].cache_slot]; } else { if (Force_one_texture) handle = 0; if (GameLightmaps[handle].cache_slot == -1) { int retval = d3d_CreateTextureFromBitmap(handle, map_type); if (retval < 0) return 0; } else { if (GameLightmaps[handle].flags & LF_CHANGED) { d3d_UploadBitmapToSurface(handle, map_type, GameLightmaps[handle].cache_slot, 0); } } ASSERT(GameLightmaps[handle].cache_slot != -1); sp = LightmapTextureSurfaces[GameLightmaps[handle].cache_slot]; } int texnum = handle; if (map_type == MAP_TYPE_LIGHTMAP) texnum += 100000; else if (map_type == MAP_TYPE_BUMPMAP) texnum += 200000; if (Last_texture_bound[tn] != texnum) { ddrval = sp->QueryInterface(IID_IDirect3DTexture2, (void **)&tex_interface); if (ddrval != S_OK) { mprintf((0, "D3D:MakeBitmapCurrent error %d! %s\n", ddrval, d3d_ErrorString(ddrval))); return 0; } if (lpD3DDevice->SetTexture(tn, tex_interface) != D3D_OK) { tex_interface->Release(); return 0; } D3D_sets_this_frame[0]++; Last_texture_bound[tn] = texnum; tex_interface->Release(); } return 1; } // Sets up our rendering pipeline for bumpmapping void d3d_SetBumpmappingBlendModes(bool state) { ASSERT(d3d_CanBumpmap); if (D3D_bumpmap_state == state) return; D3D_bumpmap_state = state; if (state) { // Bump Texture // lpD3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0); lpD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_BUMPENVMAP); lpD3DDevice->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); lpD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); lpD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); float _val = 0; lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVMAT00, *(DWORD *)(&(_val = 1.0f))); lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVMAT01, *(DWORD *)(&(_val = 0.0f))); lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVMAT10, *(DWORD *)(&(_val = 0.0f))); lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVMAT11, *(DWORD *)(&(_val = 1.0f))); lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVLSCALE, *(DWORD *)(&(_val = 1.0f))); lpD3DDevice->SetTextureStageState(1, D3DTSS_BUMPENVLOFFSET, *(DWORD *)(&(_val = 0.0f))); // Environment Texture // lpD3DDevice->SetTextureStageState(2, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); lpD3DDevice->SetTextureStageState(2, D3DTSS_TEXCOORDINDEX, 1); lpD3DDevice->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_MODULATE2X); lpD3DDevice->SetTextureStageState(2, D3DTSS_COLORARG1, D3DTA_TEXTURE); lpD3DDevice->SetTextureStageState(2, D3DTSS_COLORARG2, D3DTA_CURRENT); // Environment Texture // // lpD3DDevice->SetTexture(2, d3d_EnvironmentMap); } else { lpD3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1); lpD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); lpD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); lpD3DDevice->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); lpD3DDevice->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE); lpD3DDevice->SetTextureStageState(2, D3DTSS_ALPHAOP, D3DTOP_DISABLE); } } // Turns on/off multitexture blending void d3d_SetMultiTextureBlendMode(bool state) { if (D3D_multitexture_state == state && D3D_bumpmap_state == 0) return; D3D_multitexture_state = state; D3D_bumpmap_state = 0; if (state) { if (Overlay_type == OT_BLEND_SATURATE) { lpD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADD); lpD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_ADD); } else { lpD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); lpD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE); } } else { lpD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); lpD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); } } typedef struct { float x, y, z; float w; DWORD color; DWORD specular; } FlatVertex; typedef struct { float x, y, z; float w; DWORD color; DWORD specular; float u1, v1; } TextureVertex; typedef struct { float x, y, z; float w; DWORD color; DWORD specular; float u1, v1; float u2, v2; } MultiTextureVertex; static TextureVertex TVerts[100]; static MultiTextureVertex MTVerts[100]; static FlatVertex FlatVerts[100]; // Takes nv vertices and draws the polygon defined by those vertices. void d3d_DrawFlatPolygon(g3Point **p, int nv) { HRESULT ddrval; int alpha = Alpha_multiplier * d3d_Alpha_factor; for (int i = 0; i < nv; i++) { int r, g, b; g3Point *pnt = p[i]; TVerts[i].x = pnt->p3_sx + D3D_state.clip_x1; TVerts[i].y = pnt->p3_sy + D3D_state.clip_y1; TVerts[i].z = std::max(0, 1.0 - (1.0 / (pnt->p3_z + (Z_bias + d3d_WBias)))); TVerts[i].w = 1.0 / (pnt->p3_z + Z_bias + d3d_WBias); TVerts[i].u1 = pnt->p3_u; TVerts[i].v1 = pnt->p3_v; if (D3D_state.cur_alpha_type & ATF_VERTEX) alpha = (pnt->p3_a * (float)Alpha_multiplier * d3d_Alpha_factor); if (D3D_state.cur_fog_state) { float fog; DWORD fogval; if (pnt->p3_z < D3D_state.cur_fog_start) fogval = 255; else if (pnt->p3_z > D3D_state.cur_fog_end) fogval = 0; else { float val = pnt->p3_z - D3D_state.cur_fog_start; fog = val / d3d_FogDiff; fogval = ((1 - fog) * 255.0); } TVerts[i].specular = (fogval << 24); } if (D3D_state.cur_light_state != LS_NONE) { // Do lighting based on intesity (MONO) or colored (RGB) if (D3D_state.cur_color_model == CM_MONO) { r = pnt->p3_l * 255.0; g = pnt->p3_l * 255.0; b = pnt->p3_l * 255.0; } else { if (D3D_state.cur_light_state == LS_FLAT_GOURAUD) { r = GR_COLOR_RED(D3D_state.cur_color); g = GR_COLOR_GREEN(D3D_state.cur_color); b = GR_COLOR_BLUE(D3D_state.cur_color); } else { r = pnt->p3_r * 255.0; g = pnt->p3_g * 255.0; b = pnt->p3_b * 255.0; } } } else { r = GR_COLOR_RED(D3D_state.cur_color); g = GR_COLOR_GREEN(D3D_state.cur_color); b = GR_COLOR_BLUE(D3D_state.cur_color); } TVerts[i].color = (alpha << 24) | (r << 16) | (g << 8) | b; } D3D_polys_drawn++; D3D_verts_processed += nv; ddrval = lpD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_TEX1 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_XYZRHW, (LPVOID)TVerts, nv, D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); if (ddrval != DD_OK) { mprintf((0, "D3D:DrawFlatPolygon error %d! %s\n", ddrval, d3d_ErrorString(ddrval))); } } // Draws an bumpmapped polygon over the existing polygon int d3d_DrawBumpmappedPolygon(g3Point **p, int nv, int handle) { ASSERT(Overlay_type == OT_NONE); // ASSERT (BumpmapTextureSurfaces[handle] != NULL); HRESULT ddrval; int alpha = Alpha_multiplier * d3d_Alpha_factor; float one_over_cur_far_z = 1.0 / D3D_state.cur_far_z; for (int i = 0; i < nv; i++) { int r, g, b; g3Point *pnt = p[i]; MultiTextureVertex *tvert = &MTVerts[i]; tvert->x = pnt->p3_sx + D3D_state.clip_x1; tvert->y = pnt->p3_sy + D3D_state.clip_y1; tvert->z = std::max(0, 1.0 - (1.0 / (pnt->p3_z + (Z_bias + d3d_WBias)))); tvert->w = 1.0 / (pnt->p3_z + Z_bias + d3d_WBias); tvert->u1 = pnt->p3_u; tvert->v1 = pnt->p3_v; tvert->u2 = pnt->p3_u2; tvert->v2 = pnt->p3_v2; if (D3D_state.cur_alpha_type & ATF_VERTEX) alpha = (pnt->p3_a * (float)Alpha_multiplier * d3d_Alpha_factor); if (D3D_state.cur_fog_state) { float fog; DWORD fogval; if (pnt->p3_z < D3D_state.cur_fog_start) fogval = 255; else if (pnt->p3_z > D3D_state.cur_fog_end) fogval = 0; else { float val = pnt->p3_z - D3D_state.cur_fog_start; fog = val / d3d_FogDiff; fogval = ((1 - fog) * 255.0); } tvert->specular = (fogval << 24); } if (D3D_state.cur_light_state != LS_NONE) { // Do lighting based on intesity (MONO) or colored (RGB) if (D3D_state.cur_color_model == CM_MONO) { r = pnt->p3_l * 255.0; g = pnt->p3_l * 255.0; b = pnt->p3_l * 255.0; } else { if (D3D_state.cur_light_state == LS_FLAT_GOURAUD) { r = GR_COLOR_RED(D3D_state.cur_color); g = GR_COLOR_GREEN(D3D_state.cur_color); b = GR_COLOR_BLUE(D3D_state.cur_color); } else { r = pnt->p3_r * 255.0; g = pnt->p3_g * 255.0; b = pnt->p3_b * 255.0; } } } else { r = 255; g = 255; b = 255; } tvert->color = (alpha << 24) | (r << 16) | (g << 8) | b; } if (!d3d_MakeBitmapCurrent(handle, MAP_TYPE_BITMAP, 0)) { mprintf((0, "Couldn't make the map current!\n")); return 0; } if (!d3d_MakeBitmapCurrent(Bump_map, MAP_TYPE_BUMPMAP, 1)) { mprintf((0, "could not set bump mapping blend modes\n")); return 0; } if (d3d_EnvironmentMap == -1) { mprintf((0, "Couldn't make environment map!\n")); return 0; } if (!d3d_MakeBitmapCurrent(d3d_EnvironmentMap, MAP_TYPE_BITMAP, 2)) { mprintf((0, "Couldn't set environment map!\n")); return 0; } d3d_SetBumpmappingBlendModes(1); D3D_polys_drawn++; D3D_verts_processed += nv; ddrval = lpD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_TEX2 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_XYZRHW, (LPVOID)MTVerts, nv, D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); if (ddrval != DD_OK) { mprintf((0, "D3D:DrawBumpmappedPolygon error %d! %s\n", ddrval, d3d_ErrorString(ddrval))); } return 1; } // Draws an overlay polygon over the existing polygon void d3d_DrawMultiTexturePolygon(g3Point **p, int nv, int handle, int map_type) { HRESULT ddrval; int alpha = Alpha_multiplier * d3d_Alpha_factor; float one_over_square_res = 1.0 / GameLightmaps[Overlay_map].square_res; float one_over_cur_far_z = 1.0 / D3D_state.cur_far_z; float xscalar = (float)GameLightmaps[Overlay_map].width * one_over_square_res; float yscalar = (float)GameLightmaps[Overlay_map].height * one_over_square_res; float lmdiff = (1.0 / GameLightmaps[Overlay_map].square_res) / 2.0; for (int i = 0; i < nv; i++) { int r, g, b; g3Point *pnt = p[i]; MultiTextureVertex *tvert = &MTVerts[i]; tvert->x = pnt->p3_sx + D3D_state.clip_x1; tvert->y = pnt->p3_sy + D3D_state.clip_y1; tvert->z = std::max(0, 1.0 - (1.0 / (pnt->p3_z + (Z_bias + d3d_WBias)))); tvert->w = 1.0 / (pnt->p3_z + Z_bias + d3d_WBias); tvert->u1 = pnt->p3_u + UV_diff; tvert->v1 = pnt->p3_v + UV_diff; tvert->u2 = (pnt->p3_u2 * xscalar) + lmdiff; tvert->v2 = (pnt->p3_v2 * yscalar) + lmdiff; if (D3D_state.cur_alpha_type & ATF_VERTEX) alpha = (pnt->p3_a * (float)Alpha_multiplier * d3d_Alpha_factor); if (D3D_state.cur_fog_state) { float fog; DWORD fogval; if (pnt->p3_z < D3D_state.cur_fog_start) fogval = 255; else if (pnt->p3_z > D3D_state.cur_fog_end) fogval = 0; else { float val = pnt->p3_z - D3D_state.cur_fog_start; fog = val / d3d_FogDiff; fogval = ((1 - fog) * 255.0); } tvert->specular = (fogval << 24); } if (D3D_state.cur_light_state != LS_NONE) { // Do lighting based on intesity (MONO) or colored (RGB) if (D3D_state.cur_color_model == CM_MONO) { r = pnt->p3_l * 255.0; g = pnt->p3_l * 255.0; b = pnt->p3_l * 255.0; } else { if (D3D_state.cur_light_state == LS_FLAT_GOURAUD) { r = GR_COLOR_RED(D3D_state.cur_color); g = GR_COLOR_GREEN(D3D_state.cur_color); b = GR_COLOR_BLUE(D3D_state.cur_color); } else { r = pnt->p3_r * 255.0; g = pnt->p3_g * 255.0; b = pnt->p3_b * 255.0; } } } else { r = 255; g = 255; b = 255; } tvert->color = (alpha << 24) | (r << 16) | (g << 8) | b; } if (!d3d_MakeBitmapCurrent(handle, map_type, 0)) { mprintf((0, "Couldn't make the map current!\n")); return; } if (!d3d_MakeBitmapCurrent(Overlay_map, MAP_TYPE_LIGHTMAP, 1)) { mprintf((0, "Couldn't make the map current!\n")); return; } d3d_SetMultiTextureBlendMode(true); D3D_polys_drawn++; D3D_verts_processed += nv; ddrval = lpD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_TEX2 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_XYZRHW, (LPVOID)MTVerts, nv, D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); if (ddrval != DD_OK) { mprintf((0, "D3D:DrawPolygon error %d! %s\n", ddrval, d3d_ErrorString(ddrval))); } } // Takes nv vertices anddraws the polygon defined by those vertices. Uses bitmap "handle" // as a texture void d3d_DrawPolygon(int handle, g3Point **p, int nv, int map_type) { HRESULT ddrval; TextureVertex *tvert_ptr; int i; if (d3d_CanBumpmap && Bumpmap_ready) { ASSERT(Overlay_type == OT_NONE); if (!d3d_DrawBumpmappedPolygon(p, nv, handle)) { mprintf((0, "error in d3d_DrawBumpmappedPolygon\n")); } rend_SetBumpmapReadyState(0, 0); return; } if (d3d_CanBumpmap && D3D_bumpmap_state) d3d_SetBumpmappingBlendModes(0); if ((!D3D_state.cur_texture_quality)) { if (D3D_state.cur_alpha_type == AT_SPECULAR) { if (!d3d_MakeBitmapCurrent(handle, map_type, 0)) return; } if (d3d_MultiTexture) // If this device can do multitexture, clear it so it won't d3d_SetMultiTextureBlendMode(false); d3d_DrawFlatPolygon(p, nv); return; } // Figure out subpixel correction for UVs if (d3d_SubpixelCorrect) { if (map_type == MAP_TYPE_BITMAP) { UV_diff = (1.0 / (float)bm_w(handle, 0)) / 2.0; } else if (map_type == MAP_TYPE_LIGHTMAP) { UV_diff = (1.0 / (float)lm_w(handle)) / 2.0; } else UV_diff = 0; } else UV_diff = 0; if (Overlay_type != OT_NONE && d3d_MultiTexture) { d3d_DrawMultiTexturePolygon(p, nv, handle, map_type); return; } int alpha = Alpha_multiplier * d3d_Alpha_factor; for (i = 0; i < nv; i++) { int r, g, b; g3Point *pnt = p[i]; tvert_ptr = &TVerts[i]; tvert_ptr->x = pnt->p3_sx + D3D_state.clip_x1; tvert_ptr->y = pnt->p3_sy + D3D_state.clip_y1; tvert_ptr->z = std::max(0, 1.0 - (1.0 / (pnt->p3_z + (Z_bias + d3d_WBias)))); tvert_ptr->w = 1.0 / (pnt->p3_z + Z_bias + d3d_WBias); tvert_ptr->u1 = pnt->p3_u + UV_diff; tvert_ptr->v1 = pnt->p3_v + UV_diff; if (D3D_state.cur_alpha_type & ATF_VERTEX) alpha = (pnt->p3_a * (float)Alpha_multiplier * d3d_Alpha_factor); if (D3D_state.cur_fog_state) { float fog; DWORD fogval; if (pnt->p3_z < D3D_state.cur_fog_start) fogval = 255; else if (pnt->p3_z > D3D_state.cur_fog_end) fogval = 0; else { float val = pnt->p3_z - D3D_state.cur_fog_start; fog = val / d3d_FogDiff; fogval = ((1 - fog) * 255.0); } tvert_ptr->specular = (fogval << 24); } if (D3D_state.cur_light_state != LS_NONE) { if (D3D_state.cur_light_state == LS_FLAT_GOURAUD) { r = GR_COLOR_RED(D3D_state.cur_color); g = GR_COLOR_GREEN(D3D_state.cur_color); b = GR_COLOR_BLUE(D3D_state.cur_color); } else { // Do lighting based on intesity (MONO) or colored (RGB) if (D3D_state.cur_color_model == CM_MONO) { r = pnt->p3_l * 255.0; g = r; b = r; } else { r = pnt->p3_r * 255.0; g = pnt->p3_g * 255.0; b = pnt->p3_b * 255.0; } } } else { r = 255; g = 255; b = 255; } tvert_ptr->color = (alpha << 24) | (r << 16) | (g << 8) | b; } if (!d3d_MakeBitmapCurrent(handle, map_type, 0)) { mprintf((0, "Couldn't make the map current!\n")); return; } if (d3d_MultiTexture) // If this device can do multitexture, clear it so it won't d3d_SetMultiTextureBlendMode(false); D3D_polys_drawn++; D3D_verts_processed += nv; ddrval = lpD3DDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, D3DFVF_TEX1 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_XYZRHW, (LPVOID)TVerts, nv, D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); // Now draw an overlay if (Overlay_type != OT_NONE) { if (Overlay_type == OT_BLEND || Overlay_type == OT_BLEND_SATURATE) { sbyte atype = D3D_state.cur_alpha_type; if (Overlay_type == OT_BLEND) d3d_SetAlphaType(AT_LIGHTMAP_BLEND); else d3d_SetAlphaType(AT_LIGHTMAP_BLEND_SATURATE); if (!d3d_MakeBitmapCurrent(Overlay_map, MAP_TYPE_LIGHTMAP, 0)) { mprintf((0, "Couldn't make the map current!\n")); return; } float xscalar = (float)GameLightmaps[Overlay_map].width / (float)GameLightmaps[Overlay_map].square_res; float yscalar = (float)GameLightmaps[Overlay_map].height / (float)GameLightmaps[Overlay_map].square_res; for (int i = 0; i < nv; i++) { g3Point *pnt = p[i]; TVerts[i].u1 = pnt->p3_u2 * xscalar; TVerts[i].v1 = pnt->p3_v2 * yscalar; } D3D_polys_drawn++; D3D_verts_processed += nv; ddrval = lpD3DDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, (1 << D3DFVF_TEXCOUNT_SHIFT) | D3DFVF_TEX0 | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_XYZRHW, (LPVOID)TVerts, nv, D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); d3d_SetAlphaType(atype); } } if (ddrval != DD_OK) { mprintf((0, "D3D:DrawPolygon error %d! %s\n", ddrval, d3d_ErrorString(ddrval))); } } // Does whatever needs to be done to get D3D ready for the current frame void d3d_BeginFrame(int x1, int y1, int x2, int y2, int clear_flags) { HRESULT ddrval; // ASSERT (D3D_frame_started==0); ASSERT(x1 >= 0 && x1 <= D3D_state.screen_width); ASSERT(x2 >= 0 && x2 <= D3D_state.screen_width); ASSERT(y1 >= 0 && y1 <= D3D_state.screen_height); ASSERT(y2 >= 0 && y2 <= D3D_state.screen_height); D3D_state.clip_x1 = x1; D3D_state.clip_y1 = y1; D3D_state.clip_x2 = x2; D3D_state.clip_y2 = y2; ddrval = lpD3DDevice->BeginScene(); if (ddrval != D3D_OK) { mprintf((0, "D3D:Failed to begin scene!\n%s\n", d3d_ErrorString(ddrval))); return; } D3D_frame_started = 1; D3DRECT myrect; myrect.x1 = x1; myrect.x2 = x2; myrect.y1 = y1; myrect.y2 = y2; if (clear_flags & RF_CLEAR_ZBUFFER) { if (clear_flags & RF_CLEAR_COLOR) { lpViewport->Clear2(1UL, &myrect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3D_state.cur_color, 1.0f, 0L); } else { lpViewport->Clear2(1UL, &myrect, D3DCLEAR_ZBUFFER, D3D_state.cur_color, 1.0f, 0L); } } else if (clear_flags & RF_CLEAR_COLOR) { lpViewport->Clear2(1UL, &myrect, D3DCLEAR_TARGET, D3D_state.cur_color, 1.0f, 0L); } } // Ends the frame void d3d_EndFrame() { ASSERT(D3D_frame_started); HRESULT ddrval; ddrval = lpD3DDevice->EndScene(); if (ddrval != D3D_OK) { mprintf((0, "D3D:Failed to end scene!\n%s\n", d3d_ErrorString(ddrval))); return; } D3D_frame_started = 0; } // Flips the screen void d3d_Flip() { HRESULT ddrval; ASSERT(D3D_frame_started == 0); TryFlipAgain: if (lpFrontBuffer->IsLost() == DDERR_SURFACELOST) { lpFrontBuffer->Restore(); } if (lpBackBuffer->IsLost() == DDERR_SURFACELOST) { lpBackBuffer->Restore(); } if (lpZBuffer->IsLost() == DDERR_SURFACELOST) { lpZBuffer->Restore(); } if (D3D_preferred_state.vsync_on) ddrval = lpFrontBuffer->Flip(NULL, DDFLIP_WAIT); else ddrval = lpFrontBuffer->Flip(NULL, NULL); if (ddrval == DDERR_SURFACELOST) { mprintf((0, "Front surface lost... attempting to restore...\n")); Sleep(500); // Wait 1/2 second goto TryFlipAgain; } /*else if (ddrval != DD_OK ) { mprintf((0,"D3D:Fullscreen flip failed! %s\n",d3d_ErrorString(ddrval) )); }*/ // Print stats from the current frame #ifndef RELEASE int i; RTP_INCRVALUE(texture_uploads, D3D_uploads); RTP_INCRVALUE(polys_drawn, D3D_polys_drawn); mprintf_at((1, 1, 0, "Uploads=%d Polys=%d Verts=%d ", D3D_uploads, D3D_polys_drawn, D3D_verts_processed)); mprintf_at((1, 2, 0, "Sets= 0:%d 1:%d 2:%d 3:%d ", D3D_sets_this_frame[0], D3D_sets_this_frame[1], D3D_sets_this_frame[2], D3D_sets_this_frame[3])); mprintf_at((1, 3, 0, "Sets= 4:%d 5:%d ", D3D_sets_this_frame[4], D3D_sets_this_frame[5])); for (i = 0; i < 8; i++) D3D_sets_this_frame[i] = 0; #endif D3D_last_frame_polys_drawn = D3D_polys_drawn; D3D_last_frame_verts_processed = D3D_verts_processed; D3D_last_uploads = D3D_uploads; D3D_polys_drawn = 0; D3D_verts_processed = 0; D3D_uploads = 0; } // Sets our texturing type (ie linear,persective,flat,etc) void d3d_SetTextureType(texture_type state) { if (state != TT_FLAT) state = TT_PERSPECTIVE; if (state == D3D_state.cur_texture_type) return; D3D_sets_this_frame[1]++; switch (state) { case TT_FLAT: D3D_state.cur_texture_quality = 0; lpD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); break; case TT_LINEAR: case TT_LINEAR_SPECIAL: case TT_PERSPECTIVE: case TT_PERSPECTIVE_SPECIAL: lpD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); lpD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); lpD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); D3D_state.cur_texture_quality = 2; break; default: Int3(); // huh? Get Jason break; } D3D_state.cur_texture_type = state; } // Sets the lighting state of D3D void d3d_SetLightingState(light_state state) { // Don't do redundant state sets if (state == D3D_state.cur_light_state) return; D3D_sets_this_frame[2]++; switch (state) { case LS_NONE: lpD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD); D3D_state.cur_light_state = LS_NONE; break; case LS_FLAT_GOURAUD: lpD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD); D3D_state.cur_light_state = LS_FLAT_GOURAUD; break; case LS_GOURAUD: case LS_PHONG: lpD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD); D3D_state.cur_light_state = LS_GOURAUD; break; default: Int3(); break; } } // Sets the D3D color model (either rgb or mono) void d3d_SetColorModel(color_model state) { // Don't do redundant state sets if (state == D3D_state.cur_color_model) return; switch (state) { case CM_MONO: D3D_state.cur_color_model = CM_MONO; break; case CM_RGB: D3D_state.cur_color_model = CM_RGB; break; default: Int3(); break; } } // Sets the state of bilinear filtering for our textures void d3d_SetFiltering(sbyte state) { sbyte curstate = (sbyte)state; if (curstate == D3D_state.cur_bilinear_state) return; D3D_sets_this_frame[3]++; D3D_state.cur_bilinear_state = curstate; if (state && D3D_preferred_state.filtering) { lpD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); lpD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_LINEAR); } else { lpD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_POINT); lpD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFG_POINT); } } // Sets the state of zbuffering to on or off void d3d_SetZBufferState(sbyte state) { if (state == D3D_state.cur_zbuffer_state) return; D3D_sets_this_frame[4]++; D3D_state.cur_zbuffer_state = state; if (state) { if (d3d_WBuffer) lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_USEW); else lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE); } else { lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE); } } int Last_z_buffer_write_mask_state = -1; void d3d_SetZBufferWriteMask(int state) { if (state == Last_z_buffer_write_mask_state) return; D3D_sets_this_frame[4]++; Last_z_buffer_write_mask_state = state; if (state) { lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE); } else { lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE); } } // Sets our near and far clipping planes void d3d_SetZValues(float nearz, float farz) { D3D_state.cur_near_z = nearz; D3D_state.cur_far_z = farz; } // Clears the display to a specified color void d3d_ClearScreen(ddgr_color color) { D3DRECT myrect; myrect.x1 = 0; myrect.x2 = D3D_state.screen_width; myrect.y1 = 0; myrect.y2 = D3D_state.screen_height; lpViewport->Clear2(1UL, &myrect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, color, 1.0f, 0L); } // Clears the zbuffer void d3d_ClearZBuffer() { D3DRECT myrect; myrect.x1 = 0; myrect.x2 = D3D_state.screen_width; myrect.y1 = 0; myrect.y2 = D3D_state.screen_height; lpViewport->Clear2(1UL, &myrect, D3DCLEAR_ZBUFFER, 0, 1.0f, 0L); } // Fills a rectangle on the display void d3d_FillRect(ddgr_color color, int x1, int y1, int x2, int y2) { D3DRECT myrect; myrect.x1 = x1 + D3D_state.clip_x1; myrect.x2 = x2 + D3D_state.clip_x1; myrect.y1 = y1 + D3D_state.clip_y1; myrect.y2 = y2 + D3D_state.clip_y1; lpViewport->Clear2(1UL, &myrect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, color, 1.0f, 0L); } // Sets a pixel on the display void d3d_SetPixel(ddgr_color color, int x, int y) {} // Sets the alpha value void d3d_SetAlphaValue(ubyte val) { D3D_state.cur_alpha = val; d3d_SetAlphaMultiplier(); } // Sets the overall alpha scale factor (all alpha values are scaled by this value) // usefull for motion blur effect void d3d_SetAlphaFactor(float val) { d3d_Alpha_factor = val; } // Returns the current Alpha factor float d3d_GetAlphaFactor(void) { return d3d_Alpha_factor; } void d3d_SetAlwaysAlpha(bool state) { if (state) { if (Alpha_always_set != 1) { D3D_sets_this_frame[5]++; lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_ALWAYS); lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE); Alpha_always_set = 1; } } else { if (Alpha_always_set != 0) { D3D_sets_this_frame[5]++; lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATER); lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHAREF, 0); lpD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); Alpha_always_set = 0; } } } // Sets the type of alpha blending you want void d3d_SetAlphaType(sbyte atype) { if (atype == D3D_state.cur_alpha_type) return; // No redundant state setting D3D_sets_this_frame[5]++; switch (atype) { case AT_ALWAYS: d3d_SetAlwaysAlpha(true); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); break; case AT_TEXTURE: d3d_SetAlwaysAlpha(true); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_BLENDTEXTUREALPHA); break; case AT_CONSTANT: d3d_SetAlwaysAlpha(false); lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); break; case AT_LIGHTMAP_BLEND: d3d_SetAlwaysAlpha(false); lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ZERO); lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_SRCCOLOR); // lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_BLENDTEXTUREALPHA ); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); break; case AT_VERTEX: case AT_CONSTANT_VERTEX: d3d_SetAlwaysAlpha(false); lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); break; case AT_CONSTANT_TEXTURE: case AT_CONSTANT_TEXTURE_VERTEX: case AT_TEXTURE_VERTEX: d3d_SetAlwaysAlpha(false); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); break; case AT_SATURATE_VERTEX: case AT_SATURATE_CONSTANT_VERTEX: d3d_SetAlwaysAlpha(false); lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE); break; case AT_SATURATE_TEXTURE: case AT_SATURATE_TEXTURE_VERTEX: case AT_LIGHTMAP_BLEND_SATURATE: d3d_SetAlwaysAlpha(false); lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); break; case AT_SPECULAR: d3d_SetAlwaysAlpha(false); lpD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); lpD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); lpD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); lpD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); lpD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE); break; default: // Int3(); // no type defined,get jason break; } D3D_state.cur_alpha_type = atype; d3d_SetAlphaMultiplier(); } // Sets the near and far plane of fog // Note, the d3d_Far_z variable must be valid for this function to work correctly void d3d_SetFogBorders(float nearz, float farz) { D3D_state.cur_fog_start = nearz; D3D_state.cur_fog_end = farz; d3d_FogDiff = farz - nearz; return; } // Sets the fog state to on or off void d3d_SetFogState(sbyte state) { if (!d3d_CanFog) state = 0; // if (state==D3D_state.cur_fog_state) // return; if (state && d3d_CanFog) { lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE); lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR, D3D_state.cur_fog_color); } else { lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE); } D3D_state.cur_fog_state = state; } // sets fog color void d3d_SetFogColor(ddgr_color fogcolor) { if (fogcolor == D3D_state.cur_fog_color) return; lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR, D3D_state.cur_fog_color); D3D_state.cur_fog_color = fogcolor; } // Draws a 2d line void d3d_DrawLine(int x1, int y1, int x2, int y2) { rend_SetAlphaType(AT_CONSTANT); rend_SetAlphaValue(255); rend_SetLighting(LS_NONE); rend_SetTextureType(TT_FLAT); g3Point p1, p2; if (x1 < 0) x1 = 0; if (y1 < 0) y1 = 0; if (x1 >= D3D_state.clip_x2) x1 = D3D_state.clip_x2 - 1; if (y1 >= D3D_state.clip_y2) y1 = D3D_state.clip_y2 - 1; if (x2 < 0) x2 = 0; if (y2 < 0) y2 = 0; if (x2 >= D3D_state.clip_x2) x2 = D3D_state.clip_x2 - 1; if (y2 >= D3D_state.clip_y2) y2 = D3D_state.clip_y2 - 1; p1.p3_sx = x1; p1.p3_sy = y1; p2.p3_sx = x2; p2.p3_sy = y2; p1.p3_z = .001f; p2.p3_z = .001f; d3d_DrawSpecialLine(&p1, &p2); } // Sets the D wrapping type void d3d_SetWrapType(wrap_type val) { if (val == D3D_state.cur_wrap_type) return; D3D_sets_this_frame[6]++; D3D_state.cur_wrap_type = val; if (val == WT_WRAP) { lpD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); lpD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); lpD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); } else if (val == WT_CLAMP) { lpD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); lpD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); lpD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); } else if (val == WT_WRAP_V) { lpD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); lpD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); } else Int3(); // Get Jason } // Fills in projection variables void d3d_GetProjectionParameters(int *width, int *height) { *width = D3D_state.clip_x2 - D3D_state.clip_x1; *height = D3D_state.clip_y2 - D3D_state.clip_y1; } // Returns the aspect ratio of the physical screen float d3d_GetAspectRatio() { float aspect_ratio = (float)((3.0 * D3D_state.screen_width) / (4.0 * D3D_state.screen_height)); return aspect_ratio; } // Draws a line using the states set by the renderer lib void d3d_DrawSpecialLine(g3Point *p0, g3Point *p1) { int alpha = Alpha_multiplier * d3d_Alpha_factor; for (int i = 0; i < 2; i++) { int r, g, b; g3Point *pnt = p0; if (i) pnt = p1; FlatVerts[i].x = pnt->p3_sx + D3D_state.clip_x1; FlatVerts[i].y = pnt->p3_sy + D3D_state.clip_y1; // FlatVerts[i].z=std::min(1.0,(pnt->p3_z+(Z_bias+d3d_WBias))/D3D_state.cur_far_z); FlatVerts[i].z = std::max(0, 1.0 - (1.0 / (pnt->p3_z + (Z_bias + d3d_WBias)))); FlatVerts[i].w = 1.0 / (pnt->p3_z + Z_bias + d3d_WBias); if (D3D_state.cur_alpha_type & ATF_VERTEX) alpha = (pnt->p3_a * (float)Alpha_multiplier * d3d_Alpha_factor); if (D3D_state.cur_fog_state) { float fog; DWORD fogval; if (pnt->p3_z < D3D_state.cur_fog_start) fogval = 255; else if (pnt->p3_z > D3D_state.cur_fog_end) fogval = 0; else { float val = pnt->p3_z - D3D_state.cur_fog_start; fog = val / d3d_FogDiff; fogval = ((1 - fog) * 255.0); } FlatVerts[i].specular = (fogval << 24); } if (D3D_state.cur_light_state != LS_NONE) { // Do lighting based on intesity (MONO) or colored (RGB) if (D3D_state.cur_color_model == CM_MONO) { r = pnt->p3_l * 255.0; g = pnt->p3_l * 255.0; b = pnt->p3_l * 255.0; } else { if (D3D_state.cur_light_state == LS_FLAT_GOURAUD) { r = GR_COLOR_RED(D3D_state.cur_color); g = GR_COLOR_GREEN(D3D_state.cur_color); b = GR_COLOR_BLUE(D3D_state.cur_color); } else { r = pnt->p3_r * 255.0; g = pnt->p3_g * 255.0; b = pnt->p3_b * 255.0; } } } else { r = GR_COLOR_RED(D3D_state.cur_color); g = GR_COLOR_GREEN(D3D_state.cur_color); b = GR_COLOR_BLUE(D3D_state.cur_color); } FlatVerts[i].color = (alpha << 24) | (r << 16) | (g << 8) | b; } lpD3DDevice->DrawPrimitive(D3DPT_LINELIST, D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_XYZRHW, (LPVOID)FlatVerts, 2, D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT | D3DDP_DONOTUPDATEEXTENTS); } void d3d_SetMipState(sbyte state) { D3D_state.cur_mip_state = state; if (d3d_CanMip && state) { lpD3DDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTFP_POINT); } else { lpD3DDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTFP_NONE); } } // Sets up a some global preferences for D3D int d3d_SetPreferredState(renderer_preferred_state *pref_state) { int retval = 1; renderer_preferred_state old_state = D3D_preferred_state; mprintf((0, "In D3d_SetPreferredState\n")); D3D_preferred_state = *pref_state; if (D3D_state.initted) { int reinit = 0; // Change gamma if needed if (pref_state->width != D3D_state.screen_width || pref_state->height != D3D_state.screen_height || pref_state->bit_depth != old_state.bit_depth) reinit = 1; if (reinit) { d3d_Close(); retval = d3d_Init(ParentApplication, &D3D_preferred_state); } else { if (old_state.gamma != pref_state->gamma) { d3d_SetGammaValue(pref_state->gamma); } if (old_state.mipping != pref_state->mipping) { d3d_SetMipState(pref_state->mipping); } } } else D3D_preferred_state = *pref_state; return retval; } // Sets the resolution that D3D uses void d3d_SetResolution(int width, int height) { D3D_preferred_state.width = width; D3D_preferred_state.height = height; if (D3D_state.initted) { if (width != D3D_state.screen_width || height != D3D_state.screen_height) { d3d_Close(); d3d_Init(ParentApplication, &D3D_preferred_state); } } } // Sets the gamma correction value void d3d_SetGammaValue(float val) { D3D_preferred_state.gamma = val; if (!d3d_CanGamma) return; mprintf((0, "Setting gamma to %f\n", val)); DDGAMMARAMP rampvals; for (int i = 0; i < 256; i++) { float norm = (float)i / 255.0; float newval = powf(norm, 1.0f / val); newval *= 65535; newval = std::min(65535, newval); newval = std::max(0, newval); rampvals.red[i] = newval; rampvals.green[i] = newval; rampvals.blue[i] = newval; } HRESULT rval = lpGammaControl->SetGammaRamp(0, &rampvals); mprintf((0, "Gamma return val is %d (%x) (%s)\n", rval, rval, d3d_ErrorString(rval))); } // Gets the current state of the renderer void d3d_GetRenderState(rendering_state *rstate) { memcpy(rstate, &D3D_state, sizeof(rendering_state)); } // Sets the coplanar z bias for rendered polygons void d3d_SetCoplanarPolygonOffset(float factor) { short depth_level; if (d3d_ZBias && !d3d_WBuffer) { depth_level = (factor * 2); lpD3DDevice->SetRenderState(D3DRENDERSTATE_ZBIAS, depth_level); } else { if (d3d_WBuffer) d3d_WBias = -factor / 4.0; else d3d_WBias = -factor; } } // Creates a on the video card if needed void d3d_PreUploadTextureToCard(int handle, int map_type) { if (map_type == MAP_TYPE_BITMAP) { if (GameBitmaps[handle].cache_slot == -1) { d3d_CreateTextureFromBitmap(handle, map_type); } } else if (map_type == MAP_TYPE_BUMPMAP) { if (GameBumpmaps[handle].cache_slot == -1) { d3d_CreateTextureFromBitmap(handle, map_type); } } else { if (GameLightmaps[handle].cache_slot == -1) { d3d_CreateTextureFromBitmap(handle, map_type); } } } // Evicts local texture memory void d3d_FreePreUploadedTexture(int handle, int map_type) { if (map_type == MAP_TYPE_BITMAP) { if (GameBitmaps[handle].cache_slot != -1) { BitmapTextureSurfaces[GameBitmaps[handle].cache_slot]->Release(); GameBitmaps[handle].cache_slot = -1; } } else if (map_type == MAP_TYPE_BUMPMAP) { if (GameBumpmaps[handle].cache_slot != -1) { BumpmapTextureSurfaces[GameBumpmaps[handle].cache_slot]->Release(); GameBumpmaps[handle].cache_slot = -1; } } else { if (GameLightmaps[handle].cache_slot != -1) { LightmapTextureSurfaces[GameLightmaps[handle].cache_slot]->Release(); GameLightmaps[handle].cache_slot = -1; } } } int d3d_lfb_locked = 0; // Locks the linear frame buffer for application access void d3d_GetLFBLock(renderer_lfb *lfb) { if (d3d_lfb_locked != 0) { mprintf((0, "ERROR!!! You are trying to get an lfb lock and there already is one!\n")); lfb->data = NULL; return; } DDSURFACEDESC2 surf_desc; HRESULT ddrval; memset(&surf_desc, 0, sizeof(DDSURFACEDESC2)); surf_desc.dwSize = sizeof(DDSURFACEDESC2); surf_desc.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); ddrval = lpBackBuffer->Lock(NULL, &surf_desc, DDLOCK_WAIT, NULL); if (ddrval == DD_OK) { lfb->data = (ushort *)surf_desc.lpSurface; lfb->bytes_per_row = surf_desc.lPitch; d3d_lfb_locked = 1; } else { lfb->data = NULL; lfb->bytes_per_row = 0; } } // Releases the previous LFB lock void d3d_ReleaseLFBLock(renderer_lfb *lfb) { if (d3d_lfb_locked != 1) { mprintf((0, "ERROR!!! You are trying to release an LFB lock and there is none!\n")); return; } // Release the lock lpBackBuffer->Unlock(NULL); d3d_lfb_locked = 0; } ubyte d3d_Framebuffer_ready = 0; ushort *d3d_Framebuffer_translate = NULL; // Gets a renderer ready for a framebuffer copy, or stops a framebuffer copy void d3d_SetFrameBufferCopyState(bool state) { if (state) { bool bit15 = false; ASSERT(d3d_Framebuffer_ready == 0); ASSERT(D3D_preferred_state.bit_depth == 16); d3d_Framebuffer_ready = 1; d3d_Framebuffer_translate = (ushort *)mem_malloc(32768 * 2); ASSERT(d3d_Framebuffer_translate); // Figure out to do 15 or 16bit DDPIXELFORMAT ddpf; ddpf.dwSize = sizeof(ddpf); HRESULT ddrval = lpFrontBuffer->GetPixelFormat(&ddpf); if (ddrval != DD_OK) { Int3(); return; } bit15 = (ddpf.dwGBitMask == 0x03e0) ? true : false; for (int i = 0; i < 32768; i++) { int r = (i >> 10) & 0x1f; int g = (i >> 5) & 0x1f; int b = (i) & 0x1f; if (bit15 == false) { g <<= 1; d3d_Framebuffer_translate[i] = (r << 11) | (g << 5) | (b); } else { d3d_Framebuffer_translate[i] = (r << 10) | (g << 5) | (b); } } } else { ASSERT(d3d_Framebuffer_ready == 1); d3d_Framebuffer_ready = 0; mem_free(d3d_Framebuffer_translate); } } // Takes a bitmap and blits it to the screen using linear frame buffer stuff // X and Y are the destination X,Y void d3d_CopyBitmapToFramebuffer(int bm_handle, int x, int y) { renderer_lfb lfb; ASSERT(d3d_Framebuffer_ready); lfb.data = NULL; lfb.type = LFB_LOCK_WRITE; d3d_GetLFBLock(&lfb); if (lfb.data == NULL) return; // No copy! int w = bm_w(bm_handle, 0); int h = bm_h(bm_handle, 0); ushort *dptr = lfb.data; ushort *sptr = (ushort *)bm_data(bm_handle, 0); dptr += (y * (lfb.bytes_per_row / 2)); dptr += x; int i, t; for (i = 0; i < h; i++, dptr += (lfb.bytes_per_row / 2)) { for (t = 0; t < w; t++, sptr++) { dptr[t] = d3d_Framebuffer_translate[(*sptr & ~OPAQUE_FLAG)]; } } d3d_ReleaseLFBLock(&lfb); } // Takes a screenshot of the frontbuffer and puts it into the passed bitmap handle void d3d_Screenshot(int bm_handle) { ushort *dest_data; int i, t; DDSURFACEDESC2 surf_desc; HRESULT ddrval; int bitdepth; ASSERT((bm_w(bm_handle, 0)) == D3D_state.screen_width); ASSERT((bm_h(bm_handle, 0)) == D3D_state.screen_height); DDPIXELFORMAT ddpf; // do 8bit or 16bit copy depending on surface type ddpf.dwSize = sizeof(ddpf); ddrval = lpFrontBuffer->GetPixelFormat(&ddpf); if (ddrval != DD_OK) return; bitdepth = ddpf.dwRGBBitCount; dest_data = bm_data(bm_handle, 0); memset(&surf_desc, 0, sizeof(DDSURFACEDESC2)); surf_desc.dwSize = sizeof(DDSURFACEDESC2); surf_desc.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); ddrval = lpFrontBuffer->Lock(NULL, &surf_desc, DDLOCK_WAIT, NULL); if (ddrval == DD_OK) { int w = D3D_state.screen_width, h = D3D_state.screen_height; if (bitdepth == 16 || bitdepth == 15) { int shorts_per_row = surf_desc.lPitch / 2; bool bit15 = (ddpf.dwGBitMask == 0x03e0) ? true : false; ushort pix; ushort *rptr; rptr = (ushort *)surf_desc.lpSurface; // Go through and read our pixels if (bit15 == false) { // Do 16bit for (i = 0; i < h; i++) { for (t = 0; t < w; t++) { pix = rptr[i * shorts_per_row + t]; int r = (pix >> 11 & 0x1f) << 3; int g = (pix >> 5 & 0x3f) << 2; int b = (pix & 0x1f) << 3; r = std::min(255, (float)r * 1.4f); g = std::min(255, (float)g * 1.4f); b = std::min(255, (float)b * 1.4f); pix = GR_RGB16(r, g, b); dest_data[i * w + t] = OPAQUE_FLAG | pix; } } } else { // Do 15 bit for (i = 0; i < h; i++) { for (t = 0; t < w; t++) { pix = rptr[i * shorts_per_row + t]; int r = (pix >> 10 & 0x1f) << 3; int g = (pix >> 5 & 0x1f) << 3; int b = (pix & 0x1f) << 3; r = std::min(255, (float)r * 1.4f); g = std::min(255, (float)g * 1.4f); b = std::min(255, (float)b * 1.4f); pix = GR_RGB16(r, g, b); dest_data[i * w + t] = OPAQUE_FLAG | pix; } } } } else { int shorts_per_row = surf_desc.lPitch / 2; int ints_per_row = surf_desc.lPitch / 4; uint pix; uint *rptr; rptr = (uint *)surf_desc.lpSurface; // Go through and read our pixels for (i = 0; i < h; i++) { for (t = 0; t < w; t++) { pix = rptr[i * ints_per_row + t]; int r = (pix >> 16 & 0xff); int g = (pix >> 8 & 0xff); int b = (pix & 0xff); r = std::min(255, (float)r * 1.4f); g = std::min(255, (float)g * 1.4f); b = std::min(255, (float)b * 1.4f); short short_pix = GR_RGB16(r, g, b); dest_data[i * w + t] = OPAQUE_FLAG | short_pix; } } } // Release the lock lpFrontBuffer->Unlock(NULL); } else { mprintf((0, "Couldn't get a lock to d3d front buffer!\n")); Int3(); } } // Returns a string describing the passed in error char *d3d_ErrorString(int error) { switch (error) { case DD_OK: return "No error.\0"; case DDERR_ALREADYINITIALIZED: return "This object is already initialized.\0"; case DDERR_BLTFASTCANTCLIP: return "Return if a clipper object is attached to the source surface passed into a BltFast call.\0"; case DDERR_CANNOTATTACHSURFACE: return "This surface can not be attached to the requested surface.\0"; case DDERR_CANNOTDETACHSURFACE: return "This surface can not be detached from the requested surface.\0"; case DDERR_CANTCREATEDC: return "Windows can not create any more DCs.\0"; case DDERR_CANTDUPLICATE: return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created.\0"; case DDERR_CLIPPERISUSINGHWND: return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd.\0"; case DDERR_COLORKEYNOTSET: return "No src color key specified for this operation.\0"; case DDERR_CURRENTLYNOTAVAIL: return "Support is currently not available.\0"; case DDERR_DIRECTDRAWALREADYCREATED: return "A DirectDraw object representing this driver has already been created for this process.\0"; case DDERR_EXCEPTION: return "An exception was encountered while performing the requested operation.\0"; case DDERR_EXCLUSIVEMODEALREADYSET: return "An attempt was made to set the cooperative level when it was already set to exclusive.\0"; case DDERR_GENERIC: return "Generic failure.\0"; case DDERR_HEIGHTALIGN: return "Height of rectangle provided is not a multiple of reqd alignment.\0"; case DDERR_HWNDALREADYSET: return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or " "palettes created.\0"; case DDERR_HWNDSUBCLASSED: return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring " "state.\0"; case DDERR_IMPLICITLYCREATED: return "This surface can not be restored because it is an implicitly created surface.\0"; case DDERR_INCOMPATIBLEPRIMARY: return "Unable to match primary surface creation request with existing primary surface.\0"; case DDERR_INVALIDCAPS: return "One or more of the caps bits passed to the callback are incorrect.\0"; case DDERR_INVALIDCLIPLIST: return "DirectDraw does not support the provided cliplist.\0"; case DDERR_INVALIDDIRECTDRAWGUID: return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier.\0"; case DDERR_INVALIDMODE: return "DirectDraw does not support the requested mode.\0"; case DDERR_INVALIDOBJECT: return "DirectDraw received a pointer that was an invalid DIRECTDRAW object.\0"; case DDERR_INVALIDPARAMS: return "One or more of the parameters passed to the function are incorrect.\0"; case DDERR_INVALIDPIXELFORMAT: return "The pixel format was invalid as specified.\0"; case DDERR_INVALIDPOSITION: return "Returned when the position of the overlay on the destination is no longer legal for that destination.\0"; case DDERR_INVALIDRECT: return "Rectangle provided was invalid.\0"; case DDERR_LOCKEDSURFACES: return "Operation could not be carried out because one or more surfaces are locked.\0"; case DDERR_NO3D: return "There is no 3D present.\0"; case DDERR_NOALPHAHW: return "Operation could not be carried out because there is no alpha accleration hardware present or available.\0"; case DDERR_NOBLTHW: return "No blitter hardware present.\0"; case DDERR_NOCLIPLIST: return "No cliplist available.\0"; case DDERR_NOCLIPPERATTACHED: return "No clipper object attached to surface object.\0"; case DDERR_NOCOLORCONVHW: return "Operation could not be carried out because there is no color conversion hardware present or available.\0"; case DDERR_NOCOLORKEY: return "Surface doesn't currently have a color key\0"; case DDERR_NOCOLORKEYHW: return "Operation could not be carried out because there is no hardware support of the destination color key.\0"; case DDERR_NOCOOPERATIVELEVELSET: return "Create function called without DirectDraw object method SetCooperativeLevel being called.\0"; case DDERR_NODC: return "No DC was ever created for this surface.\0"; case DDERR_NODDROPSHW: return "No DirectDraw ROP hardware.\0"; case DDERR_NODIRECTDRAWHW: return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware.\0"; case DDERR_NOEMULATION: return "Software emulation not available.\0"; case DDERR_NOEXCLUSIVEMODE: return "Operation requires the application to have exclusive mode but the application does not have exclusive " "mode.\0"; case DDERR_NOFLIPHW: return "Flipping visible surfaces is not supported.\0"; case DDERR_NOGDI: return "There is no GDI present.\0"; case DDERR_NOHWND: return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND.\0"; case DDERR_NOMIRRORHW: return "Operation could not be carried out because there is no hardware present or available.\0"; case DDERR_NOOVERLAYDEST: return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on to " "establish a destination.\0"; case DDERR_NOOVERLAYHW: return "Operation could not be carried out because there is no overlay hardware present or available.\0"; case DDERR_NOPALETTEATTACHED: return "No palette object attached to this surface.\0"; case DDERR_NOPALETTEHW: return "No hardware support for 16 or 256 color palettes.\0"; case DDERR_NORASTEROPHW: return "Operation could not be carried out because there is no appropriate raster op hardware present or " "available.\0"; case DDERR_NOROTATIONHW: return "Operation could not be carried out because there is no rotation hardware present or available.\0"; case DDERR_NOSTRETCHHW: return "Operation could not be carried out because there is no hardware support for stretching.\0"; case DDERR_NOT4BITCOLOR: return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color " "palette.\0"; case DDERR_NOT4BITCOLORINDEX: return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color " "index palette.\0"; case DDERR_NOT8BITCOLOR: return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color.\0"; case DDERR_NOTAOVERLAYSURFACE: return "Returned when an overlay member is called for a non-overlay surface.\0"; case DDERR_NOTEXTUREHW: return "Operation could not be carried out because there is no texture mapping hardware present or available.\0"; case DDERR_NOTFLIPPABLE: return "An attempt has been made to flip a surface that is not flippable.\0"; case DDERR_NOTFOUND: return "Requested item was not found.\0"; case DDERR_NOTLOCKED: return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this process, " "has been attempted.\0"; case DDERR_NOTPALETTIZED: return "The surface being used is not a palette-based surface.\0"; case DDERR_NOVSYNCHW: return "Operation could not be carried out because there is no hardware support for vertical blank synchronized " "operations.\0"; case DDERR_NOZBUFFERHW: return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0"; case DDERR_NOZOVERLAYHW: return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z " "layering of overlays.\0"; case DDERR_OUTOFCAPS: return "The hardware needed for the requested operation has already been allocated.\0"; case DDERR_OUTOFMEMORY: return "DirectDraw does not have enough memory to perform the operation.\0"; case DDERR_OUTOFVIDEOMEMORY: return "DirectDraw does not have enough memory to perform the operation.\0"; case DDERR_OVERLAYCANTCLIP: return "The hardware does not support clipped overlays.\0"; case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: return "Can only have ony color key active at one time for overlays.\0"; case DDERR_OVERLAYNOTVISIBLE: return "Returned when GetOverlayPosition is called on a hidden overlay.\0"; case DDERR_PALETTEBUSY: return "Access to this palette is being refused because the palette is already locked by another thread.\0"; case DDERR_PRIMARYSURFACEALREADYEXISTS: return "This process already has created a primary surface.\0"; case DDERR_REGIONTOOSMALL: return "Region passed to Clipper::GetClipList is too small.\0"; case DDERR_SURFACEALREADYATTACHED: return "This surface is already attached to the surface it is being attached to.\0"; case DDERR_SURFACEALREADYDEPENDENT: return "This surface is already a dependency of the surface it is being made a dependency of.\0"; case DDERR_SURFACEBUSY: return "Access to this surface is being refused because the surface is already locked by another thread.\0"; case DDERR_SURFACEISOBSCURED: return "Access to surface refused because the surface is obscured.\0"; case DDERR_SURFACELOST: return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object " "representing this surface should have Restore called on it.\0"; case DDERR_SURFACENOTATTACHED: return "The requested surface is not attached.\0"; case DDERR_TOOBIGHEIGHT: return "Height requested by DirectDraw is too large.\0"; case DDERR_TOOBIGSIZE: return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0"; case DDERR_TOOBIGWIDTH: return "Width requested by DirectDraw is too large.\0"; case DDERR_UNSUPPORTED: return "Action not supported.\0"; case DDERR_UNSUPPORTEDFORMAT: return "FOURCC format requested is unsupported by DirectDraw.\0"; case DDERR_UNSUPPORTEDMASK: return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0"; case DDERR_VERTICALBLANKINPROGRESS: return "Vertical blank is in progress.\0"; case DDERR_WASSTILLDRAWING: return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is " "incomplete.\0"; case DDERR_WRONGMODE: return "This surface can not be restored because it was created in a different mode.\0"; case DDERR_XALIGN: return "Rectangle provided was not horizontally aligned on required boundary.\0"; case D3DERR_BADMAJORVERSION: return "D3DERR_BADMAJORVERSION\0"; case D3DERR_BADMINORVERSION: return "D3DERR_BADMINORVERSION\0"; case D3DERR_EXECUTE_LOCKED: return "D3DERR_EXECUTE_LOCKED\0"; case D3DERR_EXECUTE_NOT_LOCKED: return "D3DERR_EXECUTE_NOT_LOCKED\0"; case D3DERR_EXECUTE_CREATE_FAILED: return "D3DERR_EXECUTE_CREATE_FAILED\0"; case D3DERR_EXECUTE_DESTROY_FAILED: return "D3DERR_EXECUTE_DESTROY_FAILED\0"; case D3DERR_EXECUTE_LOCK_FAILED: return "D3DERR_EXECUTE_LOCK_FAILED\0"; case D3DERR_EXECUTE_UNLOCK_FAILED: return "D3DERR_EXECUTE_UNLOCK_FAILED\0"; case D3DERR_EXECUTE_FAILED: return "D3DERR_EXECUTE_FAILED\0"; case D3DERR_EXECUTE_CLIPPED_FAILED: return "D3DERR_EXECUTE_CLIPPED_FAILED\0"; case D3DERR_TEXTURE_NO_SUPPORT: return "D3DERR_TEXTURE_NO_SUPPORT\0"; case D3DERR_TEXTURE_NOT_LOCKED: return "D3DERR_TEXTURE_NOT_LOCKED\0"; case D3DERR_TEXTURE_LOCKED: return "D3DERR_TEXTURELOCKED\0"; case D3DERR_TEXTURE_CREATE_FAILED: return "D3DERR_TEXTURE_CREATE_FAILED\0"; case D3DERR_TEXTURE_DESTROY_FAILED: return "D3DERR_TEXTURE_DESTROY_FAILED\0"; case D3DERR_TEXTURE_LOCK_FAILED: return "D3DERR_TEXTURE_LOCK_FAILED\0"; case D3DERR_TEXTURE_UNLOCK_FAILED: return "D3DERR_TEXTURE_UNLOCK_FAILED\0"; case D3DERR_TEXTURE_LOAD_FAILED: return "D3DERR_TEXTURE_LOAD_FAILED\0"; case D3DERR_MATRIX_CREATE_FAILED: return "D3DERR_MATRIX_CREATE_FAILED\0"; case D3DERR_MATRIX_DESTROY_FAILED: return "D3DERR_MATRIX_DESTROY_FAILED\0"; case D3DERR_MATRIX_SETDATA_FAILED: return "D3DERR_MATRIX_SETDATA_FAILED\0"; case D3DERR_SETVIEWPORTDATA_FAILED: return "D3DERR_SETVIEWPORTDATA_FAILED\0"; case D3DERR_MATERIAL_CREATE_FAILED: return "D3DERR_MATERIAL_CREATE_FAILED\0"; case D3DERR_MATERIAL_DESTROY_FAILED: return "D3DERR_MATERIAL_DESTROY_FAILED\0"; case D3DERR_MATERIAL_SETDATA_FAILED: return "D3DERR_MATERIAL_SETDATA_FAILED\0"; case D3DERR_LIGHT_SET_FAILED: return "D3DERR_LIGHT_SET_FAILED\0"; default: return "Unrecognized error value.\0"; } } // Returns 1 if the renderer supports bumpmapping int d3d_SupportsBumpmapping() { if (d3d_CanBumpmap) return 1; return 0; } // returns directdraw object void *d3d_DirectDrawObj(void **frontsurf, void **backsurf) { *backsurf = (void *)lpBackBuffer; *frontsurf = (void *)lpFrontBuffer; return lpDD1; } // Resets the texture cache void d3d_ResetCache() { d3d_FreeTextureCache(); d3d_TextureCacheInit(); } // returns rendering statistics for the frame void d3d_GetStatistics(tRendererStats *stats) { stats->poly_count = D3D_last_frame_polys_drawn; stats->vert_count = D3D_last_frame_verts_processed; stats->texture_uploads = D3D_last_uploads; }