00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <Windows.h>
00023 #include <stdio.h>
00024
00025 #include "D3DCache.h"
00026 #include "D3D_Fx.h"
00027
00028 #include "PCache.h"
00029 #include "D3DDrv.h"
00030 #include "THandle.h"
00031 #include "D3D_Err.h"
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 DRV_CacheInfo CacheInfo;
00042
00043
00044
00045
00046
00047 #if 1
00048
00049 #define MAX_WORLD_POLYS 512
00050 #define MAX_WORLD_POLY_VERTS 2048
00051
00052 #define MAX_MISC_POLYS 512
00053 #define MAX_MISC_POLY_VERTS 2048
00054
00055 #else
00056
00057 #define MAX_WORLD_POLYS 256
00058 #define MAX_WORLD_POLY_VERTS 4096
00059
00060 #define MAX_MISC_POLYS 256
00061 #define MAX_MISC_POLY_VERTS 4096
00062
00063 #endif
00064
00065 typedef struct
00066 {
00067 geFloat u;
00068 geFloat v;
00069
00070 uint32 Color;
00071 } PCache_TVert;
00072
00073 typedef struct
00074 {
00075 geRDriver_THandle *THandle;
00076
00077 DRV_LInfo *LInfo;
00078 uint32 Flags;
00079 geFloat ShiftU;
00080 geFloat ShiftV;
00081 geFloat ScaleU;
00082 geFloat ScaleV;
00083 int32 MipLevel;
00084 uint32 SortKey;
00085 int32 FirstVert;
00086 int32 NumVerts;
00087 } World_Poly;
00088
00089 #define MAX_TEXTURE_STAGES 2 // Up to 2 tmu's (stages)
00090
00091
00092
00093 typedef struct
00094 {
00095 geFloat u,v;
00096 } PCache_UVSet;
00097
00098 typedef struct
00099 {
00100 geFloat x,y,z;
00101 geFloat rhw;
00102 DWORD color;
00103 DWORD specular;
00104 PCache_UVSet uv[MAX_TEXTURE_STAGES];
00105 } PCache_Vert;
00106
00107 typedef struct
00108 {
00109 World_Poly Polys[MAX_WORLD_POLYS];
00110 World_Poly *SortedPolys[MAX_WORLD_POLYS];
00111 World_Poly *SortedPolys2[MAX_WORLD_POLYS];
00112 PCache_Vert Verts[MAX_WORLD_POLY_VERTS];
00113
00114 PCache_TVert TVerts[MAX_WORLD_POLY_VERTS];
00115
00116 int32 NumPolys;
00117 int32 NumPolys2;
00118 int32 NumVerts;
00119 } World_Cache;
00120
00121 static World_Cache WorldCache;
00122
00123 #define PREP_WORLD_VERTS_NORMAL 1 // Prep verts as normal
00124 #define PREP_WORLD_VERTS_LMAP 2 // Prep verts as lightmaps
00125 #define PREP_WORLD_VERTS_SINGLE_PASS 3 // Prep verts for a single pass
00126
00127 #define RENDER_WORLD_POLYS_NORMAL 1 // Render polys as normal
00128 #define RENDER_WORLD_POLYS_LMAP 2 // Render polys as lightmaps
00129 #define RENDER_WORLD_POLYS_SINGLE_PASS 3
00130
00131
00132
00133
00134
00135 typedef struct
00136 {
00137 geRDriver_THandle *THandle;
00138 uint32 Flags;
00139 int32 MipLevel;
00140 int32 FirstVert;
00141 int32 NumVerts;
00142
00143 uint32 SortKey;
00144 } Misc_Poly;
00145
00146 typedef struct
00147 {
00148 Misc_Poly Polys[MAX_MISC_POLYS];
00149 Misc_Poly *SortedPolys[MAX_MISC_POLYS];
00150 PCache_Vert Verts[MAX_MISC_POLY_VERTS];
00151
00152
00153 int32 NumPolys;
00154 int32 NumVerts;
00155 } Misc_Cache;
00156
00157 static Misc_Cache MiscCache;
00158
00159
00160
00161
00162 geBoolean World_PolyPrepVerts(World_Poly *pPoly, int32 PrepMode, int32 Stage1, int32 Stage2);
00163
00164 static BOOL RenderWorldPolys(int32 RenderMode);
00165 static BOOL ClearWorldCache(void);
00166 static int32 GetMipLevel(DRV_TLVertex *Verts, int32 NumVerts, geFloat ScaleU, geFloat ScaleV, int32 MaxMipLevel);
00167
00168 #include <Math.h>
00169
00170
00171
00172
00173 BOOL PCache_InsertWorldPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, DRV_TexInfo *TexInfo, DRV_LInfo *LInfo, uint32 Flags)
00174 {
00175 int32 Mip;
00176 geFloat ZRecip, DrawScaleU, DrawScaleV;
00177 World_Poly *pCachePoly;
00178 DRV_TLVertex *pVerts;
00179 PCache_TVert *pTVerts;
00180 PCache_Vert *pD3DVerts;
00181 int32 i;
00182 uint32 Alpha;
00183
00184 #ifdef _DEBUG
00185 if (LInfo)
00186 {
00187 assert(LInfo->THandle);
00188 }
00189 #endif
00190
00191 if ((WorldCache.NumVerts + NumVerts) >= MAX_WORLD_POLY_VERTS)
00192 {
00193
00194 if (!PCache_FlushWorldPolys())
00195 return GE_FALSE;
00196 }
00197 else if (WorldCache.NumPolys+1 >= MAX_WORLD_POLYS)
00198 {
00199
00200 if (!PCache_FlushWorldPolys())
00201 return GE_FALSE;
00202 }
00203
00204 DrawScaleU = 1.0f / TexInfo->DrawScaleU;
00205 DrawScaleV = 1.0f / TexInfo->DrawScaleV;
00206
00207 Mip = GetMipLevel(Verts, NumVerts, DrawScaleU, DrawScaleV, THandle->NumMipLevels-1);
00208
00209
00210 pVerts = Verts;
00211
00212
00213 pCachePoly = &WorldCache.Polys[WorldCache.NumPolys];
00214
00215 pCachePoly->THandle = THandle;
00216 pCachePoly->LInfo = LInfo;
00217 pCachePoly->Flags = Flags;
00218 pCachePoly->FirstVert = WorldCache.NumVerts;
00219 pCachePoly->NumVerts = NumVerts;
00220 pCachePoly->ShiftU = TexInfo->ShiftU;
00221 pCachePoly->ShiftV = TexInfo->ShiftV;
00222 pCachePoly->ScaleU = DrawScaleU;
00223 pCachePoly->ScaleV = DrawScaleV;
00224 pCachePoly->MipLevel = Mip;
00225
00226
00227 pCachePoly->SortKey = ((THandle - TextureHandles)<<4)+Mip;
00228
00229
00230 pD3DVerts = &WorldCache.Verts[WorldCache.NumVerts];
00231 pTVerts = &WorldCache.TVerts[WorldCache.NumVerts];
00232
00233 if (Flags & DRV_RENDER_ALPHA)
00234 Alpha = (uint32)pVerts->a<<24;
00235 else
00236 Alpha = (uint32)(255<<24);
00237
00238 for (i=0; i< NumVerts; i++)
00239 {
00240 ZRecip = 1.0f/(pVerts->z);
00241
00242 pD3DVerts->x = pVerts->x;
00243 pD3DVerts->y = pVerts->y;
00244
00245 pD3DVerts->z = (1.0f - ZRecip);
00246 pD3DVerts->rhw = ZRecip;
00247
00248 if (AppInfo.FogEnable)
00249 {
00250 DWORD FogVal;
00251 geFloat Val;
00252
00253 Val = pVerts->z;
00254
00255 if (Val > AppInfo.FogEnd)
00256 Val = AppInfo.FogEnd;
00257
00258 FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f);
00259
00260 if (FogVal < 0)
00261 FogVal = 0;
00262 else if (FogVal > 255)
00263 FogVal = 255;
00264
00265 pD3DVerts->specular = (FogVal<<24);
00266 }
00267 else
00268 pD3DVerts->specular = 0;
00269
00270
00271 pTVerts->u = pVerts->u;
00272 pTVerts->v = pVerts->v;
00273
00274 pTVerts->Color = Alpha | ((uint32)pVerts->r<<16) | ((uint32)pVerts->g<<8) | (uint32)pVerts->b;
00275
00276 pTVerts++;
00277 pVerts++;
00278 pD3DVerts++;
00279
00280 }
00281
00282
00283 WorldCache.NumVerts += NumVerts;
00284 WorldCache.NumPolys++;
00285
00286 return TRUE;
00287 }
00288
00289
00290
00291
00292 BOOL PCache_FlushWorldPolys(void)
00293 {
00294 if (!WorldCache.NumPolys)
00295 return TRUE;
00296
00297 if (!THandle_CheckCache())
00298 return GE_FALSE;
00299
00300 if (AppInfo.CanDoMultiTexture)
00301 {
00302 RenderWorldPolys(RENDER_WORLD_POLYS_SINGLE_PASS);
00303 }
00304 else
00305 {
00306
00307 if (!RenderWorldPolys(RENDER_WORLD_POLYS_NORMAL))
00308 return GE_FALSE;
00309
00310
00311 RenderWorldPolys(RENDER_WORLD_POLYS_LMAP);
00312 }
00313
00314 ClearWorldCache();
00315
00316 return TRUE;
00317 }
00318
00319
00320
00321 static int MiscBitmapHandleComp(const void *a, const void *b)
00322 {
00323 uint32 Id1, Id2;
00324
00325 Id1 = (uint32)(*(Misc_Poly**)a)->SortKey;
00326 Id2 = (uint32)(*(Misc_Poly**)b)->SortKey;
00327
00328 if ( Id1 == Id2)
00329 return 0;
00330
00331 if (Id1 < Id2)
00332 return -1;
00333
00334 return 1;
00335 }
00336
00337
00338
00339 static void SortMiscPolysByHandle(void)
00340 {
00341 Misc_Poly *pPoly;
00342 int32 i;
00343
00344 pPoly = MiscCache.Polys;
00345
00346 for (i=0; i<MiscCache.NumPolys; i++)
00347 {
00348 MiscCache.SortedPolys[i] = pPoly;
00349 pPoly++;
00350 }
00351
00352
00353 qsort(&MiscCache.SortedPolys, MiscCache.NumPolys, sizeof(MiscCache.SortedPolys[0]), MiscBitmapHandleComp);
00354 }
00355
00356
00357
00358
00359 static void FillLMapSurface(DRV_LInfo *LInfo, int32 LNum)
00360 {
00361 U16 *pTempBits;
00362 int32 w, h, Width, Height, Size;
00363 U8 *pBitPtr;
00364 RGB_LUT *Lut;
00365 geRDriver_THandle *THandle;
00366 int32 Extra;
00367
00368 THandle = LInfo->THandle;
00369
00370 pBitPtr = (U8*)LInfo->RGBLight[LNum];
00371
00372 Width = LInfo->Width;
00373 Height = LInfo->Height;
00374 Size = 1<<THandle->Log;
00375
00376 Lut = &AppInfo.Lut1;
00377
00378 THandle_Lock(THandle, 0, (void**)&pTempBits);
00379
00380 Extra = Size - Width;
00381 U8 R, G, B;
00382 U16 Color;
00383
00384 for (h=0; h< Height; h++)
00385 {
00386 for (w=0; w< Width; w++)
00387 {
00388 R = *pBitPtr++;
00389 G = *pBitPtr++;
00390 B = *pBitPtr++;
00391
00392 Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]);
00393
00394 *pTempBits++ = Color;
00395 }
00396 pTempBits += Extra;
00397 }
00398
00399 THandle_UnLock(THandle, 0);
00400 }
00401
00402 #ifdef USE_TPAGES
00403
00404
00405
00406 static void FillLMapSurface2(DRV_LInfo *LInfo, int32 LNum)
00407 {
00408 U16 *pTempBits;
00409 int32 w, h, Width, Height, Stride;
00410 U8 *pBitPtr;
00411 RGB_LUT *Lut;
00412 geRDriver_THandle *THandle;
00413 HRESULT Result;
00414 const RECT *pRect;
00415 DDSURFACEDESC2 SurfDesc;
00416 LPDIRECTDRAWSURFACE4 Surface;
00417 int32 Extra;
00418
00419 THandle = LInfo->THandle;
00420
00421 pBitPtr = (U8*)LInfo->RGBLight[LNum];
00422
00423 Width = LInfo->Width;
00424 Height = LInfo->Height;
00425
00426 Lut = &AppInfo.Lut1;
00427
00428 pRect = TPage_BlockGetRect(THandle->Block);
00429 Surface = TPage_BlockGetSurface(THandle->Block);
00430
00431 memset(&SurfDesc, 0, sizeof(DDSURFACEDESC2));
00432 SurfDesc.dwSize = sizeof(DDSURFACEDESC2);
00433
00434 Result = Surface->Lock((RECT*)pRect, &SurfDesc, DDLOCK_WAIT, NULL);
00435
00436 assert(Result == DD_OK);
00437
00438 Stride = SurfDesc.dwWidth;
00439
00440 pTempBits = (U16*)SurfDesc.lpSurface;
00441
00442 Extra = Stride - Width;
00443
00444 for (h=0; h< Height; h++)
00445 {
00446 for (w=0; w< Width; w++)
00447 {
00448 U8 R, G, B;
00449 U16 Color;
00450 R = *pBitPtr++;
00451 G = *pBitPtr++;
00452 B = *pBitPtr++;
00453
00454 Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]);
00455
00456 *pTempBits++ = Color;
00457 }
00458 pTempBits += Extra;
00459 }
00460
00461 Result = Surface->Unlock((RECT*)pRect);
00462
00463 assert(Result == DD_OK);
00464 }
00465 #endif
00466
00467
00468
00469
00470 static void LoadLMapFromSystem(DRV_LInfo *LInfo, int32 Log, int32 LNum)
00471 {
00472 U16 *pTempBits;
00473 int32 w, h, Width, Height, Size, Extra;
00474 U8 *pBitPtr;
00475 LPDIRECTDRAWSURFACE4 Surface;
00476 RGB_LUT *Lut;
00477 DDSURFACEDESC2 ddsd;
00478 HRESULT ddrval;
00479
00480 pBitPtr = (U8*)LInfo->RGBLight[LNum];
00481
00482 Width = LInfo->Width;
00483 Height = LInfo->Height;
00484 Size = 1<<Log;
00485
00486 Extra = Size - Width;
00487
00488 Lut = &AppInfo.Lut1;
00489
00490 Surface = SystemToVideo[Log].Surface;
00491
00492 memset(&ddsd, 0, sizeof(DDSURFACEDESC2));
00493 ddsd.dwSize = sizeof(DDSURFACEDESC2);
00494 ddrval = Surface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
00495
00496 assert(ddrval == DD_OK);
00497 U8 R, G, B;
00498 U16 Color;
00499
00500 pTempBits = (USHORT*)ddsd.lpSurface;
00501
00502 for (h=0; h< Height; h++)
00503 {
00504 for (w=0; w< Width; w++)
00505 {
00506 R = *pBitPtr++;
00507 G = *pBitPtr++;
00508 B = *pBitPtr++;
00509
00510 Color = (U16)(Lut->R[R] | Lut->G[G] | Lut->B[B]);
00511
00512 *pTempBits++ = Color;
00513 }
00514 pTempBits += Extra;
00515 }
00516
00517 ddrval = Surface->Unlock(NULL);
00518 assert(ddrval == DD_OK);
00519 }
00520
00521 static BOOL IsKeyDown(int KeyCode)
00522 {
00523 if (GetAsyncKeyState(KeyCode) & 0x8000)
00524 return TRUE;
00525
00526 return FALSE;
00527 }
00528
00529 extern uint32 CurrentLRU;
00530
00531
00532
00533
00534 geBoolean SetupMipData(THandle_MipData *MipData)
00535 {
00536 if (!MipData->Slot || D3DCache_SlotGetUserData(MipData->Slot) != MipData)
00537 {
00538 MipData->Slot = D3DCache_TypeFindSlot(MipData->CacheType);
00539 assert(MipData->Slot);
00540
00541 D3DCache_SlotSetUserData(MipData->Slot, MipData);
00542
00543 #ifdef SUPER_FLUSH
00544 AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0);
00545 #endif
00546
00547 return GE_FALSE;
00548 }
00549
00550 return GE_TRUE;
00551 }
00552
00553
00554
00555
00556 geBoolean SetupLMap(int32 Stage, DRV_LInfo *LInfo, int32 LNum, geBoolean Dynamic)
00557 {
00558 #ifdef D3D_MANAGE_TEXTURES
00559 #ifdef USE_TPAGES
00560 {
00561 geRDriver_THandle *THandle;
00562
00563 THandle = LInfo->THandle;
00564
00565 if (Dynamic)
00566 THandle->Flags |= THANDLE_UPDATE;
00567
00568 if (!THandle->Block)
00569 {
00570 THandle->Block = TPage_MgrFindOptimalBlock(TPageMgr, CurrentLRU);
00571 THandle->Flags |= THANDLE_UPDATE;
00572 TPage_BlockSetUserData(THandle->Block, THandle);
00573 assert(THandle->Block);
00574 }
00575 else if (TPage_BlockGetUserData(THandle->Block) != THandle)
00576 {
00577
00578 THandle->Block = TPage_MgrFindOptimalBlock(TPageMgr, CurrentLRU);
00579 assert(THandle->Block);
00580
00581 THandle->Flags |= THANDLE_UPDATE;
00582 TPage_BlockSetUserData(THandle->Block, THandle);
00583 }
00584
00585 if (THandle->Flags & THANDLE_UPDATE)
00586 FillLMapSurface2(LInfo, LNum);
00587
00588 TPage_BlockSetLRU(THandle->Block, CurrentLRU);
00589 D3DSetTexture(Stage, TPage_BlockGetTexture(THandle->Block));
00590
00591 if (Dynamic)
00592 THandle->Flags |= THANDLE_UPDATE;
00593 else
00594 THandle->Flags &= ~THANDLE_UPDATE;
00595
00596 return GE_TRUE;
00597 }
00598 #else
00599 {
00600 geRDriver_THandle *THandle;
00601
00602 THandle = LInfo->THandle;
00603
00604 if (Dynamic)
00605 THandle->MipData[0].Flags |= THANDLE_UPDATE;
00606
00607 if (THandle->MipData[0].Flags & THANDLE_UPDATE)
00608 FillLMapSurface(LInfo, LNum);
00609
00610 D3DSetTexture(Stage, THandle->MipData[0].Texture);
00611
00612 if (Dynamic)
00613 THandle->MipData[0].Flags |= THANDLE_UPDATE;
00614 else
00615 THandle->MipData[0].Flags &= ~THANDLE_UPDATE;
00616
00617 return GE_TRUE;
00618 }
00619 #endif
00620
00621 #else
00622 geRDriver_THandle *THandle;
00623 THandle_MipData *MipData;
00624
00625 THandle = LInfo->THandle;
00626 MipData = &THandle->MipData[0];
00627
00628 if (Dynamic)
00629 MipData->Flags |= THANDLE_UPDATE;
00630
00631 if (!SetupMipData(MipData))
00632 {
00633 MipData->Flags |= THANDLE_UPDATE;
00634 CacheInfo.LMapMisses++;
00635 }
00636
00637 if (MipData->Flags & THANDLE_UPDATE)
00638 {
00639 HRESULT Error;
00640 LPDIRECTDRAWSURFACE4 Surface;
00641
00642 assert(MipData->Slot);
00643
00644 Surface = D3DCache_SlotGetSurface(MipData->Slot);
00645
00646 assert(Surface);
00647 assert(THandle->Log < MAX_LMAP_LOG_SIZE);
00648 assert(SystemToVideo[THandle->Log].Surface);
00649
00650 LoadLMapFromSystem(LInfo, THandle->Log, LNum);
00651
00652 Error = Surface->BltFast(0, 0, SystemToVideo[THandle->Log].Surface, NULL, DDBLTFAST_WAIT);
00653
00654
00655
00656
00657 if (Error != DD_OK)
00658 {
00659 if(Error==DDERR_SURFACELOST)
00660 {
00661 if (!D3DMain_RestoreAllSurfaces())
00662 return GE_FALSE;
00663 }
00664 else
00665 {
00666 D3DMain_Log("SetupTexture: System to Video cache Blt failed.\n %s", D3DErrorToString(Error));
00667 return GE_FALSE;
00668 }
00669 }
00670 }
00671
00672 if (Dynamic)
00673 MipData->Flags |= THANDLE_UPDATE;
00674 else
00675 MipData->Flags &= ~THANDLE_UPDATE;
00676
00677 D3DCache_SlotSetLRU(MipData->Slot, CurrentLRU);
00678 D3DSetTexture(Stage, D3DCache_SlotGetTexture(MipData->Slot));
00679
00680 return GE_TRUE;
00681 #endif
00682 }
00683
00684
00685
00686
00687 geBoolean SetupTexture(int32 Stage, geRDriver_THandle *THandle, int32 MipLevel)
00688 {
00689 #ifdef D3D_MANAGE_TEXTURES
00690 D3DSetTexture(Stage, THandle->MipData[MipLevel].Texture);
00691 return GE_TRUE;
00692 #else
00693 THandle_MipData *MipData;
00694
00695 MipData = &THandle->MipData[MipLevel];
00696
00697 if (!SetupMipData(MipData))
00698 {
00699 MipData->Flags |= THANDLE_UPDATE;
00700 CacheInfo.TexMisses++;
00701 }
00702
00703 if (MipData->Flags & THANDLE_UPDATE)
00704 {
00705 HRESULT Error;
00706 LPDIRECTDRAWSURFACE4 Surface;
00707
00708 Surface = D3DCache_SlotGetSurface(MipData->Slot);
00709
00710 Error = Surface->BltFast(0, 0, MipData->Surface, NULL, DDBLTFAST_WAIT);
00711
00712 if (Error != DD_OK)
00713 {
00714 if(Error==DDERR_SURFACELOST)
00715 {
00716 if (!D3DMain_RestoreAllSurfaces())
00717 return FALSE;
00718 }
00719 else
00720 {
00721 D3DMain_Log("SetupTexture: System to Video cache Blt failed.\n %s", D3DErrorToString(Error));
00722 return GE_FALSE;
00723 }
00724 }
00725 }
00726
00727 MipData->Flags &= ~THANDLE_UPDATE;
00728
00729 D3DCache_SlotSetLRU(MipData->Slot, CurrentLRU);
00730 D3DSetTexture(Stage, D3DCache_SlotGetTexture(MipData->Slot));
00731
00732 return GE_TRUE;
00733 #endif
00734 }
00735
00736
00737
00738
00739 BOOL PCache_FlushMiscPolys(void)
00740 {
00741 int32 i;
00742 Misc_Poly *pPoly;
00743
00744 if (!MiscCache.NumPolys)
00745 return TRUE;
00746
00747 if (!THandle_CheckCache())
00748 return GE_FALSE;
00749
00750
00751 if (AppInfo.CanDoMultiTexture)
00752 {
00753 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
00754 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
00755 D3DSetTexture(1, NULL);
00756 }
00757
00758 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0);
00759 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
00760 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
00761 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
00762 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
00763 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
00764 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
00765 D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
00766 D3DBlendEnable(TRUE);
00767
00768
00769 SortMiscPolysByHandle();
00770
00771 for (i=0; i< MiscCache.NumPolys; i++)
00772 {
00773 pPoly = MiscCache.SortedPolys[i];
00774
00775 if (pPoly->Flags & DRV_RENDER_NO_ZMASK)
00776 D3DZEnable(FALSE);
00777 else
00778 D3DZEnable(TRUE);
00779
00780 if (pPoly->Flags & DRV_RENDER_NO_ZWRITE)
00781 D3DZWriteEnable(FALSE);
00782 else
00783 D3DZWriteEnable(TRUE);
00784
00785 if (pPoly->Flags & DRV_RENDER_CLAMP_UV)
00786 D3DTexWrap(0, FALSE);
00787 else
00788 D3DTexWrap(0, TRUE);
00789
00790 if (!SetupTexture(0, pPoly->THandle, pPoly->MipLevel))
00791 return GE_FALSE;
00792
00793 D3DTexturedPoly(&MiscCache.Verts[pPoly->FirstVert], pPoly->NumVerts);
00794 }
00795
00796
00797 D3DZWriteEnable (TRUE);
00798 D3DZEnable(TRUE);
00799
00800 MiscCache.NumPolys = 0;
00801 MiscCache.NumVerts = 0;
00802
00803 #ifdef SUPER_FLUSH
00804 AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FLUSHBATCH, 0);
00805 AppInfo.lpD3DDevice->EndScene();
00806 AppInfo.lpD3DDevice->BeginScene();
00807 #endif
00808
00809 return TRUE;
00810 }
00811
00812
00813
00814
00815 BOOL PCache_InsertMiscPoly(DRV_TLVertex *Verts, int32 NumVerts, geRDriver_THandle *THandle, uint32 Flags)
00816 {
00817 int32 Mip;
00818 geFloat ZRecip, u, v, ScaleU, ScaleV, InvScale;
00819 Misc_Poly *pCachePoly;
00820 DRV_TLVertex *pVerts;
00821 PCache_Vert *pD3DVerts;
00822 int32 i, SAlpha;
00823
00824 if ((MiscCache.NumVerts + NumVerts) >= MAX_MISC_POLY_VERTS)
00825 {
00826
00827 PCache_FlushMiscPolys();
00828 }
00829 else if (MiscCache.NumPolys+1 >= MAX_MISC_POLYS)
00830 {
00831
00832 PCache_FlushMiscPolys();
00833 }
00834
00835 Mip = GetMipLevel(Verts, NumVerts, (geFloat)THandle->Width, (geFloat)THandle->Height, THandle->NumMipLevels-1);
00836
00837
00838 pCachePoly = &MiscCache.Polys[MiscCache.NumPolys];
00839
00840 pCachePoly->THandle = THandle;
00841 pCachePoly->Flags = Flags;
00842 pCachePoly->FirstVert = MiscCache.NumVerts;
00843 pCachePoly->NumVerts = NumVerts;
00844 pCachePoly->MipLevel = Mip;
00845 pCachePoly->SortKey = ((THandle - TextureHandles)<<4)+Mip;
00846
00847
00848
00849 InvScale = 1.0f / (geFloat)((1<<THandle->Log));
00850
00851
00852 ScaleU = (geFloat)THandle->Width * InvScale;
00853 ScaleV = (geFloat)THandle->Height * InvScale;
00854
00855
00856 SAlpha = ((int32)Verts->a)<<24;
00857
00858
00859 pVerts = Verts;
00860
00861 pD3DVerts = &MiscCache.Verts[MiscCache.NumVerts];
00862
00863 for (i=0; i< NumVerts; i++)
00864 {
00865 ZRecip = 1/(pVerts->z);
00866
00867 pD3DVerts->x = pVerts->x;
00868 pD3DVerts->y = pVerts->y;
00869
00870 pD3DVerts->z = (1.0f - ZRecip);
00871 pD3DVerts->rhw = ZRecip;
00872
00873 u = pVerts->u * ScaleU;
00874 v = pVerts->v * ScaleV;
00875
00876 pD3DVerts->uv[0].u = u;
00877 pD3DVerts->uv[0].v = v;
00878
00879 pD3DVerts->color = SAlpha | ((int32)pVerts->r<<16) | ((int32)pVerts->g<<8) | (int32)pVerts->b;
00880
00881 if (AppInfo.FogEnable)
00882 {
00883 DWORD FogVal;
00884 geFloat Val;
00885
00886 Val = pVerts->z;
00887
00888 if (Val > AppInfo.FogEnd)
00889 Val = AppInfo.FogEnd;
00890
00891 FogVal = (DWORD)((AppInfo.FogEnd-Val)/(AppInfo.FogEnd-AppInfo.FogStart)*255.0f);
00892
00893 if (FogVal < 0)
00894 FogVal = 0;
00895 else if (FogVal > 255)
00896 FogVal = 255;
00897
00898 pD3DVerts->specular = (FogVal<<24);
00899 }
00900 else
00901 pD3DVerts->specular = 0;
00902
00903 pVerts++;
00904 pD3DVerts++;
00905 }
00906
00907
00908 MiscCache.NumVerts += NumVerts;
00909 MiscCache.NumPolys++;
00910
00911 return TRUE;
00912 }
00913
00914
00915
00916
00917
00918
00919
00920
00921 geBoolean World_PolyPrepVerts(World_Poly *pPoly, int32 PrepMode, int32 Stage1, int32 Stage2)
00922 {
00923 geFloat InvScale, u, v;
00924 PCache_TVert *pTVerts;
00925 PCache_Vert *pVerts;
00926 geFloat ShiftU, ShiftV, ScaleU, ScaleV;
00927 geFloat InvScale2, ShiftU2, ShiftV2;
00928 int32 j;
00929
00930 switch (PrepMode)
00931 {
00932 case PREP_WORLD_VERTS_NORMAL:
00933 {
00934 pTVerts = &WorldCache.TVerts[pPoly->FirstVert];
00935
00936 ShiftU = pPoly->ShiftU;
00937 ShiftV = pPoly->ShiftV;
00938 ScaleU = pPoly->ScaleU;
00939 ScaleV = pPoly->ScaleV;
00940
00941
00942 InvScale = 1.0f / (geFloat)((1<<pPoly->THandle->Log));
00943
00944 pVerts = &WorldCache.Verts[pPoly->FirstVert];
00945
00946 for (j=0; j< pPoly->NumVerts; j++)
00947 {
00948 u = pTVerts->u*ScaleU+ShiftU;
00949 v = pTVerts->v*ScaleV+ShiftV;
00950
00951 pVerts->uv[Stage1].u = u * InvScale;
00952 pVerts->uv[Stage1].v = v * InvScale;
00953
00954 pVerts->color = pTVerts->Color;
00955
00956 pTVerts++;
00957 pVerts++;
00958 }
00959
00960 break;
00961 }
00962
00963 case PREP_WORLD_VERTS_LMAP:
00964 {
00965 if (!pPoly->LInfo)
00966 return GE_TRUE;
00967
00968 ShiftU = (geFloat)-pPoly->LInfo->MinU + 8.0f;
00969 ShiftV = (geFloat)-pPoly->LInfo->MinV + 8.0f;
00970
00971
00972 InvScale = 1.0f/(geFloat)((1<<pPoly->LInfo->THandle->Log)<<4);
00973
00974 pTVerts = &WorldCache.TVerts[pPoly->FirstVert];
00975 pVerts = &WorldCache.Verts[pPoly->FirstVert];
00976
00977 for (j=0; j< pPoly->NumVerts; j++)
00978 {
00979 u = pTVerts->u + ShiftU;
00980 v = pTVerts->v + ShiftV;
00981
00982 pVerts->uv[Stage1].u = u * InvScale;
00983 pVerts->uv[Stage1].v = v * InvScale;
00984
00985 pVerts->color = 0xffffffff;
00986
00987 pTVerts++;
00988 pVerts++;
00989 }
00990 break;
00991 }
00992
00993 case PREP_WORLD_VERTS_SINGLE_PASS:
00994 {
00995
00996 assert(pPoly->LInfo);
00997
00998 pTVerts = &WorldCache.TVerts[pPoly->FirstVert];
00999
01000
01001 ShiftU = pPoly->ShiftU;
01002 ShiftV = pPoly->ShiftV;
01003 ScaleU = pPoly->ScaleU;
01004 ScaleV = pPoly->ScaleV;
01005
01006
01007 InvScale = 1.0f / (geFloat)((1<<pPoly->THandle->Log));
01008
01009
01010 ShiftU2 = (geFloat)-pPoly->LInfo->MinU + 8.0f;
01011 ShiftV2 = (geFloat)-pPoly->LInfo->MinV + 8.0f;
01012 InvScale2 = 1.0f/(geFloat)((1<<pPoly->LInfo->THandle->Log)<<4);
01013
01014 pVerts = &WorldCache.Verts[pPoly->FirstVert];
01015
01016 for (j=0; j< pPoly->NumVerts; j++)
01017 {
01018 u = pTVerts->u*ScaleU+ShiftU;
01019 v = pTVerts->v*ScaleV+ShiftV;
01020
01021 pVerts->uv[Stage1].u = u * InvScale;
01022 pVerts->uv[Stage1].v = v * InvScale;
01023
01024 u = pTVerts->u + ShiftU2;
01025 v = pTVerts->v + ShiftV2;
01026
01027 pVerts->uv[Stage2].u = u * InvScale2;
01028 pVerts->uv[Stage2].v = v * InvScale2;
01029
01030 pVerts->color = pTVerts->Color;
01031
01032 pTVerts++;
01033 pVerts++;
01034 }
01035
01036 break;
01037 }
01038
01039 default:
01040 return FALSE;
01041 }
01042
01043 return TRUE;
01044 }
01045
01046
01047
01048 static int BitmapHandleComp(const void *a, const void *b)
01049 {
01050 int32 Id1, Id2;
01051
01052 Id1 = (*(World_Poly**)a)->SortKey;
01053 Id2 = (*(World_Poly**)b)->SortKey;
01054
01055 if ( Id1 == Id2)
01056 return 0;
01057
01058 if (Id1 < Id2)
01059 return -1;
01060
01061 return 1;
01062 }
01063
01064
01065
01066 static void SortWorldPolysByHandle(void)
01067 {
01068 World_Poly *pPoly;
01069 int32 i;
01070
01071 pPoly = WorldCache.Polys;
01072
01073 for (i=0; i<WorldCache.NumPolys; i++)
01074 {
01075 WorldCache.SortedPolys[i] = pPoly;
01076 pPoly++;
01077 }
01078
01079
01080 qsort(&WorldCache.SortedPolys, WorldCache.NumPolys, sizeof(WorldCache.SortedPolys[0]), BitmapHandleComp);
01081 }
01082
01083 #define TSTAGE_0 0
01084 #define TSTAGE_1 1
01085
01086 D3DTEXTUREHANDLE OldId;
01087 LPDIRECT3DTEXTURE2 OldTexture[8];
01088
01089
01090
01091 static BOOL RenderWorldPolys(int32 RenderMode)
01092 {
01093 World_Poly *pPoly;
01094 int32 i;
01095
01096 if(!AppInfo.RenderingIsOK)
01097 {
01098 return TRUE;
01099 }
01100 switch (RenderMode)
01101 {
01102 case RENDER_WORLD_POLYS_NORMAL:
01103 {
01104 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
01105
01106
01107 D3DBlendEnable(TRUE);
01108 D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
01109
01110
01111 SortWorldPolysByHandle();
01112
01113 for (i=0; i< WorldCache.NumPolys; i++)
01114 {
01115 pPoly = WorldCache.SortedPolys[i];
01116
01117 if (pPoly->Flags & DRV_RENDER_CLAMP_UV)
01118 D3DTexWrap(0, FALSE);
01119 else
01120 D3DTexWrap(0, TRUE);
01121
01122 if (!SetupTexture(0, pPoly->THandle, pPoly->MipLevel))
01123 return GE_FALSE;
01124
01125 World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_NORMAL, 0, 0);
01126
01127 D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts);
01128 }
01129
01130 break;
01131 }
01132
01133 case RENDER_WORLD_POLYS_LMAP:
01134 {
01135 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0);
01136
01137 D3DTexWrap(0, FALSE);
01138
01139 D3DBlendEnable(TRUE);
01140 D3DBlendFunc (D3DBLEND_DESTCOLOR, D3DBLEND_ZERO);
01141
01142 pPoly = WorldCache.Polys;
01143 BOOL Dynamic = 0;
01144
01145 for (i=0; i< WorldCache.NumPolys; i++, pPoly++)
01146 {
01147
01148 if (!pPoly->LInfo)
01149 continue;
01150
01151
01152 D3DDRV.SetupLightmap(pPoly->LInfo, &Dynamic);
01153
01154 if (!SetupLMap(0, pPoly->LInfo, 0, Dynamic))
01155 return GE_FALSE;
01156
01157 World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_LMAP, 0, 0);
01158
01159 D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts);
01160
01161 if (pPoly->LInfo->RGBLight[1])
01162 {
01163 AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
01164
01165 D3DBlendFunc (D3DBLEND_ONE, D3DBLEND_ONE);
01166
01167
01168
01169 pPoly->LInfo->THandle->MipData[0].Slot = NULL;
01170
01171 if (!SetupLMap(0, pPoly->LInfo, 1, 1))
01172 return GE_FALSE;
01173
01174 D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts);
01175
01176 D3DBlendFunc (D3DBLEND_DESTCOLOR, D3DBLEND_ZERO);
01177
01178 if (AppInfo.FogEnable)
01179 AppInfo.lpD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE , TRUE);
01180 }
01181 }
01182 break;
01183 }
01184
01185 case RENDER_WORLD_POLYS_SINGLE_PASS:
01186 {
01187
01188 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
01189 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
01190 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
01191 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
01192 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
01193 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
01194 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
01195
01196 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 );
01197 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
01198 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
01199 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
01200 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
01201 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT );
01202
01203 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
01204
01205
01206 D3DBlendEnable(TRUE);
01207 D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
01208
01209
01210 D3DTexWrap(TSTAGE_0, TRUE);
01211 D3DTexWrap(TSTAGE_1, FALSE);
01212
01213
01214 SortWorldPolysByHandle();
01215
01216
01217 WorldCache.NumPolys2 = 0;
01218
01219 for (i=0; i< WorldCache.NumPolys; i++)
01220 {
01221 BOOL Dynamic = 0;
01222
01223 pPoly = WorldCache.SortedPolys[i];
01224
01225 if (!pPoly->LInfo)
01226 {
01227
01228 WorldCache.SortedPolys2[WorldCache.NumPolys2++] = pPoly;
01229 continue;
01230 }
01231
01232 if (pPoly->Flags & DRV_RENDER_CLAMP_UV)
01233 D3DTexWrap(TSTAGE_0, FALSE);
01234 else
01235 D3DTexWrap(TSTAGE_0, TRUE);
01236
01237 if (!SetupTexture(TSTAGE_0, pPoly->THandle, pPoly->MipLevel))
01238 return GE_FALSE;
01239
01240
01241 D3DDRV.SetupLightmap(pPoly->LInfo, &Dynamic);
01242
01243 if (!SetupLMap(TSTAGE_1, pPoly->LInfo, 0, Dynamic))
01244 return GE_FALSE;
01245
01246
01247 World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_SINGLE_PASS, TSTAGE_0, TSTAGE_1);
01248
01249
01250 D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts);
01251
01252
01253 if (pPoly->LInfo->RGBLight[1])
01254 {
01255 D3DBlendFunc (D3DBLEND_ONE, D3DBLEND_ONE);
01256
01257 #if (TSTAGE_0 == 0)
01258 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
01259 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
01260
01261 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
01262 #else
01263 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
01264 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
01265 #endif
01266
01267
01268
01269 pPoly->LInfo->THandle->MipData[0].Slot = NULL;
01270
01271 if (!SetupLMap(TSTAGE_1, pPoly->LInfo, 1, 1))
01272 return GE_FALSE;
01273
01274 D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts);
01275
01276
01277 #if (TSTAGE_0 == 0)
01278 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
01279 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
01280
01281 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
01282 #else
01283 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
01284 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
01285 #endif
01286
01287 D3DBlendFunc (D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
01288 }
01289
01290
01291 }
01292
01293
01294 #if (TSTAGE_0 == 0)
01295 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
01296 AppInfo.lpD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
01297 #else
01298 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
01299 AppInfo.lpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
01300 #endif
01301
01302
01303 for (i=0; i< WorldCache.NumPolys2; i++)
01304 {
01305 BOOL Dynamic = 0;
01306
01307 pPoly = WorldCache.SortedPolys2[i];
01308
01309 if (pPoly->Flags & DRV_RENDER_CLAMP_UV)
01310 D3DTexWrap(TSTAGE_0, FALSE);
01311 else
01312 D3DTexWrap(TSTAGE_0, TRUE);
01313
01314 if (!SetupTexture(TSTAGE_0, pPoly->THandle, pPoly->MipLevel))
01315 return GE_FALSE;
01316
01317
01318 World_PolyPrepVerts(pPoly, PREP_WORLD_VERTS_NORMAL, TSTAGE_0, TSTAGE_1);
01319
01320
01321 D3DTexturedPoly(&WorldCache.Verts[pPoly->FirstVert], pPoly->NumVerts);
01322 }
01323
01324 break;
01325 }
01326
01327 default:
01328 return FALSE;
01329 }
01330
01331
01332 return TRUE;
01333 }
01334
01335
01336
01337
01338 static BOOL ClearWorldCache(void)
01339 {
01340 WorldCache.NumPolys = 0;
01341 WorldCache.NumVerts = 0;
01342
01343 return TRUE;
01344 }
01345
01346
01347
01348 BOOL PCache_Reset(void)
01349 {
01350 WorldCache.NumPolys = 0;
01351 WorldCache.NumVerts = 0;
01352
01353 MiscCache.NumPolys = 0;
01354 MiscCache.NumVerts = 0;
01355
01356 return TRUE;
01357 }
01358
01359
01360
01361
01362 static int32 GetMipLevel(DRV_TLVertex *Verts, int32 NumVerts, geFloat ScaleU, geFloat ScaleV, int32 MaxMipLevel)
01363 {
01364 int32 Mip;
01365
01366 if (MaxMipLevel == 0)
01367 return 0;
01368
01369
01370
01371
01372 {
01373 geFloat du, dv, dx, dy, MipScale;
01374
01375 #if 1 // WAY slower, but more accurate
01376 int32 i;
01377
01378 MipScale = 999999.0f;
01379
01380 geFloat MipScaleT;
01381 DRV_TLVertex *pVert0, *pVert1;
01382 int32 i2;
01383
01384 for (i=0; i< NumVerts; i++)
01385 {
01386
01387 i2 = i+1;
01388
01389 if (i2 >= NumVerts)
01390 i2=0;
01391
01392 pVert0 = &Verts[i];
01393 pVert1 = &Verts[i2];
01394
01395 du = pVert1->u - pVert0->u;
01396 dv = pVert1->v - pVert0->v;
01397 dx = pVert1->x - pVert0->x;
01398 dy = pVert1->y - pVert0->y;
01399
01400 du *= ScaleU;
01401 dv *= ScaleV;
01402
01403 MipScaleT = ((du*du)+(dv*dv)) / ((dx*dx)+(dy*dy));
01404
01405 if (MipScaleT < MipScale)
01406 MipScale = MipScaleT;
01407 }
01408 #else // Faster, less accurate
01409 du = Verts[1].u - Verts[0].u;
01410 dv = Verts[1].v - Verts[0].v;
01411 dx = Verts[1].x - Verts[0].x;
01412 dy = Verts[1].y - Verts[0].y;
01413
01414 du *= ScaleU;
01415 dv *= ScaleV;
01416
01417 MipScale = ((du*du)+(dv*dv)) / ((dx*dx)+(dy*dy));
01418 #endif
01419
01420 #if 0
01421 if (MipScale <= 5)
01422 Mip = 0;
01423 else if (MipScale <= 20)
01424 Mip = 1;
01425 else if (MipScale <= 45)
01426 Mip = 2;
01427 else
01428 Mip = 3;
01429 #else
01430 if (MipScale <= 4)
01431 Mip = 0;
01432 else if (MipScale <= 15)
01433 Mip = 1;
01434 else if (MipScale <= 40)
01435 Mip = 2;
01436 else
01437 Mip = 3;
01438 #endif
01439 }
01440
01441 if (Mip > MaxMipLevel)
01442 Mip = MaxMipLevel;
01443
01444 return Mip;
01445 }