Advertisement
Guest User

Direct3D8.cpp

a guest
May 9th, 2022
1,437
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 192.14 KB | None | 0 0
  1. /*=============================================================================
  2.     Direct3D8.cpp: Duke Forever Direct3D8 support.
  3.     Copyright 1997-1999 Epic Games, Inc. All Rights Reserved.
  4.  
  5.     Revision history:
  6.         * Created by independent contractor who wishes to remanin anonymous.
  7.         * Taken over by Tim Sweeney.
  8.         * Completed vertex buffer and GeForce support, hit detection. - Erik
  9.         * Fog on gouraud polygons enabled if hardware has single-pass specular capability.
  10. =============================================================================*/
  11.  
  12. // Includes.
  13. #pragma warning(disable : 4291)
  14. #pragma warning(disable : 4201)
  15. #pragma warning(disable : 4701)
  16. #pragma warning(disable : 4800)
  17.  
  18. // Unreal includes.
  19. #include "Engine.h"
  20. #include "UnRender.h"
  21.  
  22. #pragma hdrstop
  23. EXECVAR     (float, FogStart,        50.f  );
  24. EXECVAR     (float, FogEnd,          100.f );
  25. EXECVAR     (INT,   RenderParticles, true  );
  26. EXECVAR     (INT,   RenderMeshes,    true  );
  27. EXECVAR     (INT,   RenderSurfaces,  true  );
  28. EXECVAR     (INT,   RenderLines,     true  );
  29. EXECVAR     (INT,   RenderTiles,     true  );
  30. EXECVAR     (INT,   RenderPoints,    true  );
  31. EXECVAR     (INT,   WorldDetail,     true  );
  32. EXECVAR_HELP(INT,   CacheBlending,   true, "Whether or not D3D's render states should be cached.  Useful for debugging render state problems." );
  33.  
  34. float LodBias=-0.60;
  35.  
  36. //#define LOG_PRESENT_PARMS
  37.  
  38. // NJS: When the following is defined, Validate() is called on entry to every driver function.
  39. // When VALIDATE_ALL is not defined, it compiles away to nothing.
  40. //#define VALIDATE_ALL
  41.  
  42.  
  43. #ifdef VALIDATE_ALL
  44.     #define VALIDATE DriverValidate()
  45. #else
  46.     #define VALIDATE
  47. #endif
  48.  
  49. EXECVAR_HELP(float, NearZ, 200.f, "Detail texture Z range.");
  50. EXECFUNC(GetNearZ)
  51. {
  52.     GDnExec->Printf(TEXT("%f"), NearZ);
  53. }
  54.  
  55. static const FLOAT NEAR_CLIP     =1.f;
  56. static const FLOAT FAR_CLIP      =65535.f;
  57. static const FLOAT NEAR_CLIP_HACK=NEAR_CLIP*1.01f; // vogel: workaround for precision issues
  58.  
  59. // Globals.
  60. HRESULT h;
  61.  
  62. #define DOHITTEST
  63. const int HIT_SIZE = 8;
  64. #define IGNOREPIX 0xfe0d
  65. static DWORD HitPixels[HIT_SIZE][HIT_SIZE];
  66.  
  67. #define WORLDSURFACE_VERTEXBUFFER_SIZE  4096   // UT levels reach a maximum of about 380; can get well over 512 for complex surfaces.
  68. #define ACTORPOLY_VERTEXBUFFER_SIZE     16384  // Reaches 7 at most (clipped triangles) - used for tiles, lines and points also.
  69.                                                // NJS: Increased to 4096 in the desperate hope that we might be able to fit an entire mesh in one.
  70. #define LINE_VERTEXBUFFER_SIZE          16384    // Only draws 1 line at a time, so 2 verts is all we need
  71. #define PARTICLE_VERTEXBUFFER_SIZE      16384  // NJS: Expand when ready.
  72. #define LoadLibraryX(a) TCHAR_CALL_OS(LoadLibraryW(a),LoadLibraryA(TCHAR_TO_ANSI(a)))
  73. #define SAFETRY(cmd) {try{cmd;}catch(...){debugf(TEXT("Exception in ") TEXT(#cmd));}}
  74. static bool ErrorCalled=false;
  75.  
  76. #define D3D_CHECK(VALUE) \
  77.     do\
  78.     {\
  79.         HRESULT __hr=(VALUE);\
  80.         if(FAILED(__hr))\
  81.         {       \
  82.             appErrorf(TEXT("[%s, %i] D3D ERROR: ") TEXT(#VALUE) TEXT(" == %s"),appFromAnsi(__FILE__),__LINE__,DXGetErrorString8(__hr));\
  83.         }\
  84.     } while(0)
  85.                        
  86.  
  87.  
  88. //
  89. // GetFormatBPP
  90. // Returns the number of bits/pixel used by a specified format.
  91. // If you add support for another format, you must add a case for it here.
  92. //
  93. int GetFormatBPP(D3DFORMAT Format)
  94. {
  95.     switch(Format)
  96.     {
  97.         case D3DFMT_A8R8G8B8:
  98.         case D3DFMT_X8R8G8B8:
  99.         case D3DFMT_D24S8:
  100.         case D3DFMT_D32:       
  101.             return 32;
  102.  
  103.         case D3DFMT_A1R5G5B5:
  104.         case D3DFMT_R5G6B5:
  105.         case D3DFMT_X1R5G5B5:
  106.         case D3DFMT_D16:
  107.             return 16;
  108.  
  109.         case D3DFMT_P8:
  110.             return 8;
  111.    
  112.         case D3DFMT_DXT1:
  113.             return 4;
  114.    
  115.         default:
  116.             return 0;
  117.     }
  118. }
  119.  
  120. #ifdef LOG_PRESENT_PARMS
  121. static void LogPresentParms(D3DPRESENT_PARAMETERS &PresentParms)
  122. {
  123.     debugf(TEXT("--- PresentParms:"));
  124.  
  125.     //PresentParms.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
  126.  
  127.     debugf(TEXT("PresentParms.Windowed=%i"),PresentParms.Windowed);
  128.     debugf(TEXT("PresentParms.hDeviceWindow=%08x"),PresentParms.hDeviceWindow);
  129.    
  130.     debugf(TEXT("PresentParms.BackBufferWidth=%i"),PresentParms.BackBufferWidth);
  131.     debugf(TEXT("PresentParms.BackBufferHeight=%i"),PresentParms.BackBufferHeight);
  132.     debugf(TEXT("PresentParms.BackBufferCount=%i"),PresentParms.BackBufferCount);
  133.     debugf(TEXT("PresentParms.EnableAutoDepthStencil=%i"),PresentParms.EnableAutoDepthStencil);
  134.  
  135.     TCHAR *PresentationInterval;
  136.     switch(PresentParms.FullScreen_PresentationInterval)
  137.     {
  138.         case D3DPRESENT_INTERVAL_DEFAULT:   PresentationInterval=TEXT("D3DPRESENT_INTERVAL_DEFAULT"); break;
  139.         case D3DPRESENT_INTERVAL_IMMEDIATE: PresentationInterval=TEXT("D3DPRESENT_INTERVAL_IMMEDIATE"); break;
  140.         case D3DPRESENT_INTERVAL_ONE:       PresentationInterval=TEXT("D3DPRESENT_INTERVAL_ONE"); break;
  141.         case D3DPRESENT_INTERVAL_TWO:       PresentationInterval=TEXT("D3DPRESENT_INTERVAL_TWO"); break;
  142.         case D3DPRESENT_INTERVAL_THREE:     PresentationInterval=TEXT("D3DPRESENT_INTERVAL_THREE"); break;
  143.         case D3DPRESENT_INTERVAL_FOUR:      PresentationInterval=TEXT("D3DPRESENT_INTERVAL_FOUR"); break;
  144.         default: PresentationInterval=TEXT("Unknown"); break;
  145.     }
  146.  
  147.     debugf(TEXT("PresentParms.FullScreen_PresentationInterval=%s"),PresentationInterval);
  148.     debugf(TEXT("PresentParms.FullScreen_RefreshRateInHz=%i"),PresentParms.FullScreen_RefreshRateInHz);
  149.     debugf(TEXT("PresentParms.SwapEffect=%i"),PresentParms.SwapEffect);
  150.  
  151.  
  152.     TCHAR *BackBufferFormatName;
  153.     #define CHECK_FORMAT(NAME) case NAME: BackBufferFormatName=TEXT(#NAME); break
  154.  
  155.     switch(PresentParms.BackBufferFormat)
  156.     {
  157.         CHECK_FORMAT(D3DFMT_X8R8G8B8);
  158.         CHECK_FORMAT(D3DFMT_A8R8G8B8);
  159.         CHECK_FORMAT(D3DFMT_R5G6B5);
  160.         CHECK_FORMAT(D3DFMT_X1R5G5B5);
  161.         default: BackBufferFormatName=TEXT("Unknown"); break;
  162.     }
  163.     debugf(TEXT("PresentParms.BackBufferFormat=%u(%u-bit) (%s)"),PresentParms.BackBufferFormat,GetFormatBPP(PresentParms.BackBufferFormat),BackBufferFormatName);
  164.     debugf(TEXT("PresentParms.AutoDepthStencilFormat=%u(%u-bit)"),PresentParms.AutoDepthStencilFormat,GetFormatBPP(PresentParms.AutoDepthStencilFormat));
  165.  
  166. }
  167. #endif
  168.  
  169. //#define BATCH_PROJECTOR_POLYS
  170.  
  171. #ifdef BATCH_PROJECTOR_POLYS
  172.     #define PROJECTOR_VERTEXBUFFER_SIZE     (16384)
  173. #endif
  174.  
  175. /*-----------------------------------------------------------------------------
  176.     Vertex definitions.
  177. -----------------------------------------------------------------------------*/
  178. struct FD3DDefaultVertexBuffer
  179. {
  180.     enum {USAGE=D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC};
  181. };
  182.  
  183. struct FD3DScreenVertex : public FD3DDefaultVertexBuffer
  184. {
  185.     enum {FVF=D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2};
  186.     FPlane      Position;
  187.     FColor      Color;
  188.     FLOAT       U[2];
  189.     FLOAT       U2[2];
  190. };
  191.  
  192. struct FD3DTLVertex : public FD3DDefaultVertexBuffer
  193. {
  194.     enum {FVF=D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2};
  195.     FPlane      Position;
  196.     FColor      Diffuse,
  197.                 Specular;
  198.     FLOAT       U[2];
  199.     FLOAT       U2[2];
  200. };
  201.  
  202. struct FD3DTileVertex : public FD3DDefaultVertexBuffer
  203. {
  204.     enum {FVF=D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1};
  205.     FPlane      Position;
  206.     FLOAT       U[2];
  207. };
  208.  
  209. struct FD3DVertex : public FD3DDefaultVertexBuffer
  210. {
  211.     enum {FVF=D3DFVF_XYZ  | D3DFVF_DIFFUSE};
  212.     FVector     Position;
  213.     FColor      Diffuse;
  214. };
  215.  
  216. typedef struct FD3DParticle : public FD3DDefaultVertexBuffer
  217. {
  218.     enum { FVF=D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0) };
  219.     FVector Position;
  220.     DWORD   Diffuse;
  221.     D3DXVECTOR2 TextureVector;
  222. } PARTICLE_VERTEX;
  223.  
  224.  
  225. template <class T>
  226. class FD3DVertexBuffer
  227. {
  228. public:
  229.     IDirect3DDevice8*       Device;
  230.     IDirect3DVertexBuffer8* VertexBuffer8;
  231.     INT                     Length,
  232.                             First,
  233.                             Rover;
  234.  
  235.     // Constructor.
  236.     FD3DVertexBuffer()
  237.     {
  238.         // Setup member variables.
  239.         Length = 0;
  240.         Rover = 0;
  241.         VertexBuffer8 = NULL;
  242.         Device=NULL;
  243.     }
  244.  
  245.     ~FD3DVertexBuffer()
  246.     {
  247.         Exit();
  248.     }
  249.  
  250.     // Init - Initialize the vertex buffer.
  251.     void Init(IDirect3DDevice8* InDevice, INT InLength)
  252.     {
  253.         Exit(); // Destroy any previous vertex buffer.
  254.  
  255.         check(InDevice); Device = InDevice;
  256.         check(InLength); Length = InLength;
  257.        
  258.         // Create the vertex buffer.
  259.         D3D_CHECK(Device->CreateVertexBuffer(Length*sizeof(T),
  260.                                              T::USAGE,
  261.                                              T::FVF,
  262.                                              D3DPOOL_DEFAULT,
  263.                                              &VertexBuffer8));
  264.     }
  265.  
  266.     // Exit - Releases the vertex buffer.
  267.     void Exit()
  268.     {
  269.         SafeRelease(VertexBuffer8);
  270.     }
  271.  
  272.     // Lock - Locks a range of vertices for writing.
  273.     // NJS: Start Extension added so existing VB's can be relocked.
  274.     T* Lock(INT Num, INT Start=-1)
  275.     {
  276.         check(VertexBuffer8);
  277.         check(Length);
  278.         check(Num<Length);
  279.  
  280.         T*  VertexData;
  281.  
  282.         // Lock the vertex buffer.
  283.         if(Start!=-1)
  284.         {
  285.             D3D_CHECK(VertexBuffer8->Lock(Start * sizeof(T),Num * sizeof(T),(BYTE**) &VertexData,D3DLOCK_NOOVERWRITE));
  286.         }
  287.         else if(Rover + Num < Length)
  288.         {
  289.             D3D_CHECK(VertexBuffer8->Lock(Rover * sizeof(T),Num * sizeof(T),(BYTE**) &VertexData,D3DLOCK_NOOVERWRITE));
  290.             First =Rover;
  291.  
  292.             Rover+=Num;
  293.  
  294.         } else
  295.         {
  296.             D3D_CHECK(VertexBuffer8->Lock(0,Num * sizeof(T),(BYTE**) &VertexData,D3DLOCK_DISCARD));
  297.             First=0;
  298.             Rover=Num;
  299.         }
  300.  
  301.         return VertexData;
  302.     }
  303.  
  304.     // Unlock - Unlocks the locked vertices.
  305.     INT Unlock()
  306.     {
  307.         check(VertexBuffer8);
  308.  
  309.         D3D_CHECK(VertexBuffer8->Unlock());
  310.  
  311.         return First;
  312.     }
  313.  
  314.     // Set - Makes this vertex buffer the current vertex buffer.
  315.     void Set()
  316.     {
  317.         check(Device);
  318.         check(VertexBuffer8);
  319.  
  320.         // Set stream source 0 and the vertex shader.
  321.         D3D_CHECK(Device->SetRenderState(D3DRS_SOFTWAREVERTEXPROCESSING,FALSE));
  322.         D3D_CHECK(Device->SetVertexShader(T::FVF));
  323.         D3D_CHECK(Device->SetStreamSource(0,VertexBuffer8,sizeof(T)));
  324.     }
  325. };
  326.  
  327. // NJS: Globals related to D3D initialization.  In the process of being cleaned up:
  328. static IDirect3D8 *Direct3D8;
  329. TArray<D3DADAPTER_IDENTIFIER8> Adapters;
  330. INT BestAdapterIndex = 0;
  331. D3DCAPS8                DeviceCaps8;
  332. D3DADAPTER_IDENTIFIER8  DeviceIdentifier;
  333. TArray<D3DDISPLAYMODE>  DisplayModes;
  334. #define PYR(n)         ((n)*((n+1))/2)
  335. _WORD                   RScale[PYR(128)];
  336. _WORD                   GScale[PYR(128)];
  337. _WORD                   BScale[PYR(128)];
  338.  
  339. // Texture information classes.
  340. struct FPixFormat
  341. {
  342.     // Pixel format info.
  343.     bool                Supported;      // Whether this pixel format is supported for textures with the current device.
  344.     D3DFORMAT           Direct3DFormat; // The corresponding Direct3D pixel format.
  345.     FPixFormat*         Next;           // Next in linked list of all compatible pixel formats.
  346.     const TCHAR*        Desc;           // Stat: Human readable name for stats.
  347.     INT                 BitsPerPixel;   // Total bits per pixel.
  348.  
  349.     // Multi-frame stats.
  350.     INT                 Binned;         // Stat: How many textures of this format are available in bins.
  351.     INT                 BinnedRAM;      // Stat: How much RAM is used by total textures of this format in the cache.
  352.     INT                 ActiveRAMPeak;  // Stat: The highest active ram has ever been:
  353.     // Per-frame stats.
  354.     INT                 Active;         // Stat: How many textures of this format are active.
  355.     INT                 ActiveRAM;      // Stat: How much RAM is used by active textures of this format per frame.
  356.     INT                 Sets;           // Stat: Number of SetTexture was called this frame on textures of this format.
  357.     INT                 Uploads;        // Stat: Number of texture Blts this frame.
  358.     INT                 UploadCycles;   // Stat: Cycles spent Blting.
  359.  
  360.    
  361.     FPixFormat()
  362.     {
  363.         memset(this,0,sizeof(*this));
  364.     }
  365.  
  366.     void ResetStats()
  367.     {
  368.         ActiveRAMPeak=ActiveRAM;
  369.         Sets = Uploads = UploadCycles = Active = ActiveRAM = 0;
  370.     }
  371. };
  372.  
  373. D3DDISPLAYMODE          OriginalDisplayMode;
  374.  
  375. /*-----------------------------------------------------------------------------
  376.     UD3DRenderDevice definition.
  377. -----------------------------------------------------------------------------*/
  378. class DLL_EXPORT UD3DRenderDevice : public URenderDevice
  379. {
  380.     DECLARE_CLASS(UD3DRenderDevice,URenderDevice,CLASS_Config)
  381.  
  382.     // Defines.
  383.     struct FTexInfo;
  384.  
  385.     // JEP...
  386.     struct ProjectorInfo
  387.     {
  388.         FSceneNode              *Frame;
  389.         IDirect3DTexture8       *pRenderTargetTex;
  390.         IDirect3DSurface8       *pRenderTargetSurf;
  391.  
  392.         FBspNode                *GNodes;
  393.  
  394.         FCoords                 CameraToLight;
  395.  
  396.         // Pre computes
  397.         FLOAT                   OneOverX;           // Pre-computed 1/Frame->X
  398.         FLOAT                   OneOverY;           // Pre-computed 1/Frame->Y
  399.         FLOAT                   _33;                // wFar / (wFar - wNear);
  400.         FLOAT                   _43;                // -_33 * wNear;
  401.         FLOAT                   FadeScale;
  402.     };
  403.  
  404.     TArray<ProjectorInfo>       ProjectorArray;
  405.  
  406.     struct RenderTargetInfo
  407.     {
  408.         UBOOL                   Active;                 // == false if it was freed (and put on the freed list)
  409.         IDirect3DTexture8       *pRenderTargetTex;
  410.         IDirect3DSurface8       *pRenderTargetSurf;
  411.         INT                     Width;
  412.         INT                     Height;
  413.     };
  414.  
  415.     TArray<RenderTargetInfo>    RenderTargetArray;
  416.     TArray<INT>                 FreeRenderTargets;
  417.     // ...JEP
  418.  
  419.     // 'Abstract base class' of the texture fillers:
  420.     struct FTexFiller
  421.     {
  422.         FPixFormat* PixelFormat;
  423.         virtual void BeginUpload( FTexInfo* Tex, const FTextureInfo& Info, DWORD PolyFlags, DWORD PolyFlagsEx ) {}
  424.         virtual void UploadMipmap( FTexInfo* Tex, FRainbowPtr Dest, INT Stride, const FTextureInfo& Info, INT MipIndex, DWORD PolyFlags ) {}
  425.     };
  426.  
  427.     struct FTexInfo
  428.     {
  429.         IDirect3DTexture8*  Texture8;
  430.         DWORD               SizeBytes;
  431.  
  432.         QWORD               CacheId;
  433.         UBOOL               Masking;
  434.         INT                 FirstMip;
  435.         FLOAT               UScale,
  436.                             VScale;
  437.         FColor              MaxColor;
  438.         UBOOL               UseMips;
  439.  
  440.         FTexFiller*         Filler;
  441.         INT                 FrameCounter;
  442.  
  443.         FTexInfo*           HashNext;
  444.         FTexInfo*           NextTexture;
  445.     };
  446.  
  447.     struct FTexFillerDXT1 : public FTexFiller
  448.     {
  449.         FTexFillerDXT1( UD3DRenderDevice* InOuter ) { PixelFormat=&InOuter->FormatDXT1; }
  450.         void UploadMipmap( FTexInfo* ti, FRainbowPtr Dest, INT Stride, const FTextureInfo& Info, INT MipIndex, DWORD PolyFlags )
  451.         {
  452.             INT USize = Max(Info.Mips[MipIndex]->USize, 4);
  453.             INT VSize = Max(Info.Mips[MipIndex]->VSize, 4);
  454.             appMemcpy( Dest.PtrVOID, Info.Mips[MipIndex]->DataPtr, (USize * VSize)/2 );
  455.         }
  456.     };
  457.  
  458.     struct FTexFillerP8_P8 : public FTexFiller
  459.     {
  460.         FTexFillerP8_P8( UD3DRenderDevice* InOuter ) { PixelFormat=&InOuter->FormatP8; }
  461.         void UploadMipmap( FTexInfo* Tex, FRainbowPtr Dest, INT Stride, const FTextureInfo& Info, INT MipIndex )
  462.         {
  463.             FRainbowPtr Src  = Info.Mips[MipIndex]->DataPtr;
  464.             for( INT j=Info.Mips[MipIndex]->VSize-1; j>=0; j-- )
  465.             {
  466.                 for( INT k=Info.Mips[MipIndex]->USize-1; k>=0; k-- )
  467.                     *Dest.PtrBYTE++ = *Src.PtrBYTE++;
  468.                 Dest.PtrBYTE += Stride - Info.Mips[MipIndex]->USize;
  469.             }
  470.         }
  471.     };
  472.     struct FTexFiller8888_RGBA8 : public FTexFiller
  473.     {
  474.         FTexFiller8888_RGBA8( UD3DRenderDevice* InOuter ) { PixelFormat=&InOuter->Format8888; }
  475.         void UploadMipmap( FTexInfo* ti, FRainbowPtr Dest, INT Stride, const FTextureInfo& Info, INT MipIndex, DWORD PolyFlags )
  476.         {
  477.             INT  USize      = Info.Mips[MipIndex]->USize;
  478.             INT  VSize      = Info.Mips[MipIndex]->VSize;
  479.             FRainbowPtr Src = Info.Mips[MipIndex]->DataPtr;
  480.             for( INT j=VSize-1; j>=0; j--,Dest.PtrDWORD += Stride-USize*sizeof(DWORD) )
  481.                 for( INT k=USize-1; k>=0; k--,Dest.PtrDWORD++ )
  482.                 {
  483.                     *Dest.PtrDWORD = *Src.PtrDWORD++;
  484.                     //*Dest.PtrDWORD|=0xFF000000;
  485.                 }
  486.         }
  487.     };
  488.     struct FTexFiller8888_RGBA7 : public FTexFiller
  489.     {
  490.         FTexFiller8888_RGBA7( UD3DRenderDevice* InOuter ) { PixelFormat=&InOuter->Format8888; }
  491.         void UploadMipmap( FTexInfo* ti, FRainbowPtr Dest, INT Stride, const FTextureInfo& Info, INT MipIndex, DWORD PolyFlags )
  492.         {
  493.  
  494.             DWORD*      TempBuffer = new DWORD[Info.Mips[MipIndex]->USize * Info.Mips[MipIndex]->VSize];
  495.             FRainbowPtr RealDest = Dest;
  496.  
  497.             Dest.PtrDWORD = TempBuffer;
  498.             Stride = Info.Mips[MipIndex]->USize * 4;
  499.  
  500.             FRainbowPtr Src  = Info.Mips[MipIndex]->DataPtr;
  501.             for( INT v=0; v<Info.VClamp; v++,Dest.PtrBYTE+=Stride-Info.UClamp*sizeof(DWORD),Src.PtrDWORD+=Info.USize-Info.UClamp )
  502.                 for( INT u=0; u<Info.UClamp; u++,Src.PtrDWORD++,Dest.PtrDWORD++ )
  503.                     *Dest.PtrDWORD = *Src.PtrDWORD*2;
  504.  
  505.         }
  506.     };
  507.     struct FTexFiller8888_P8 : public FTexFiller
  508.     {
  509.         DWORD AlphaPalette[256];
  510.  
  511.         FTexFiller8888_P8( UD3DRenderDevice* InOuter ) { PixelFormat=&InOuter->Format8888; }
  512.         void UploadMipmap( FTexInfo* ti, FRainbowPtr Dest, INT Stride, const FTextureInfo& Info, INT MipIndex, DWORD PolyFlags )
  513.         {
  514.             INT     USize      = Info.Mips[MipIndex]->USize;
  515.             INT     VSize      = Info.Mips[MipIndex]->VSize;
  516.  
  517.             FRainbowPtr Src = Info.Mips[MipIndex]->DataPtr;
  518.             for( INT j=VSize-1; j>=0; j--,Dest.PtrBYTE+=Stride-USize*sizeof(DWORD) )
  519.                 for( INT k=USize-1; k>=0; k--,Dest.PtrDWORD++ )
  520.                     *Dest.PtrDWORD = AlphaPalette[*Src.PtrBYTE++];
  521.  
  522.         }
  523.         void BeginUpload( FTexInfo* ti, const FTextureInfo& Info, DWORD PolyFlags, DWORD PolyFlagsEx )
  524.         {
  525.             // Compute the alpha palette:
  526.             for( INT i=0; i<NUM_PAL_COLORS; i++ )
  527.                 AlphaPalette[i] = D3DCOLOR_RGBA(Info.Palette[i].R,Info.Palette[i].G,Info.Palette[i].B,Info.Palette[i].A);
  528.            
  529.             if( PolyFlags & PF_Masked )
  530.                 AlphaPalette[0] = 0;
  531.         }
  532.     };
  533.     struct FTexFiller1555_RGBA7 : public FTexFiller
  534.     {
  535.         FTexFiller1555_RGBA7( UD3DRenderDevice* InOuter ) { PixelFormat=&InOuter->Format1555; }
  536.         void UploadMipmap( FTexInfo* ti, FRainbowPtr Dest, INT Stride, const FTextureInfo& Info, INT MipIndex, DWORD PolyFlags )
  537.         {
  538.             _WORD*      RPtr     = RScale + PYR(Info.MaxColor->R/2);
  539.             _WORD*      GPtr     = GScale + PYR(Info.MaxColor->G/2);
  540.             _WORD*      BPtr     = BScale + PYR(Info.MaxColor->B/2);
  541.             FRainbowPtr Src      = Info.Mips[MipIndex]->DataPtr;
  542.             for( INT v=0; v<Info.VClamp; v++,Dest.PtrBYTE+=Stride-Info.UClamp*2,Src .PtrDWORD+=Info.USize-Info.UClamp )
  543.                 for( INT u=0; u<Info.UClamp; u++,Src.PtrDWORD++ )
  544.                     *Dest.PtrWORD++ = BPtr[Src.PtrBYTE[0]] + GPtr[Src.PtrBYTE[1]] + RPtr[Src.PtrBYTE[2]];
  545.         }
  546.     };
  547.     struct FTexFiller1555_P8 : public FTexFiller
  548.     {
  549.         DWORD AlphaPalette[256];
  550.  
  551.         FTexFiller1555_P8( UD3DRenderDevice* InOuter ) { PixelFormat=&InOuter->Format1555; }
  552.         void UploadMipmap( FTexInfo* ti, FRainbowPtr Dest, INT Stride, const FTextureInfo& Info, INT MipIndex, DWORD PolyFlags )
  553.         {
  554.             INT  USize      = Info.Mips[MipIndex]->USize;
  555.             INT  VSize      = Info.Mips[MipIndex]->VSize;
  556.             FRainbowPtr Src = Info.Mips[MipIndex]->DataPtr;
  557.  
  558.             for( INT j=VSize-1; j>=0; j--,Dest.PtrBYTE+=Stride-Info.Mips[MipIndex]->USize*2 )
  559.                 for( INT k=USize-1; k>=0; k-- )
  560.                     *Dest.PtrWORD++ = AlphaPalette[*Src.PtrBYTE++];
  561.         }
  562.  
  563.         void BuildAlphaPalette( FColor* Pal, DWORD FracA, DWORD MaskA, DWORD FracR, DWORD MaskR, DWORD FracG, DWORD MaskG, DWORD FracB, DWORD MaskB )
  564.         {
  565.             DWORD* Dest = AlphaPalette;
  566.             for( FColor *End=Pal+NUM_PAL_COLORS; Pal<End; Pal++ )
  567.             {
  568.                
  569.                 *Dest++
  570.                 =  (((Min(MaskA,FracA*Pal->A))&MaskA)
  571.                 |   ((Min(MaskR,FracR*Pal->R))&MaskR)
  572.                 |   ((Min(MaskG,FracG*Pal->G))&MaskG)
  573.                 |   ((Min(MaskB,FracB*Pal->B))&MaskB))>>16;
  574.             }
  575.         }
  576.         void BeginUpload( FTexInfo* ti, const FTextureInfo& Info, DWORD PolyFlags, DWORD PolyFlagsEx )
  577.         {
  578.             // Convert lighten and darknen modulate as a modulated texture, but don't add one.
  579.             if(PolyFlagsEx&(PFX_LightenModulate|PFX_DarkenModulate))
  580.             {
  581.                 FColor* Pal = Info.Palette;
  582.                 DWORD* Dest = AlphaPalette;
  583.  
  584.                 for( FColor *End=Pal+NUM_PAL_COLORS; Pal<End; Pal++ )
  585.                 {
  586.                     *Dest++
  587.                     =((Min<INT>(0x80000000,(Pal->A*0x01000000)&0x80000000))
  588.                     | (Min<INT>(0x7C000000,(Pal->R*0x007fffff)&0x7C000000))
  589.                     | (Min<INT>(0x03E00000,(Pal->G*0x0003ffff)&0x03E00000))
  590.                     | (Min<INT>(0x001F0000,(Pal->B*0x00001fff)&0x001F0000)) )>>16;
  591.                 }
  592.             } else
  593.             // Have to add one to the texture, so we can darken it down by half an element later.
  594.             if((PolyFlags & (PF_Modulated|PF_Translucent)) == PF_Modulated)// Prevent brightness adjustment when modulating
  595.             {
  596.                 FColor* Pal = Info.Palette;
  597.                 DWORD* Dest = AlphaPalette;
  598.  
  599.                 for( FColor *End=Pal+NUM_PAL_COLORS; Pal<End; Pal++ )
  600.                 {
  601.                     *Dest++
  602.                     =((Min<INT>(0x80000000,(Pal->A*0x01000000)&0x80000000))
  603.                     | (Min<INT>(0x7C000000,((Pal->R+1)*0x007fffff)&0x7C000000))
  604.                     | (Min<INT>(0x03E00000,((Pal->G+1)*0x0003ffff)&0x03E00000))
  605.                     | (Min<INT>(0x001F0000,((Pal->B+1)*0x00001fff)&0x001F0000)) )>>16;
  606.                 }
  607.             } else
  608.             BuildAlphaPalette
  609.             (
  610.                 Info.Palette,
  611.                 0x1000000, 0x80000000,
  612.                 /*appRound(*/0x07fffffff/Max<INT>(ti->MaxColor.R,1)/*)*/, 0x7C000000,
  613.                 /*appRound(*/0x003ffffff/Max<INT>(ti->MaxColor.G,1)/*)*/, 0x03E00000,
  614.                 /*appRound(*/0x0001fffff/Max<INT>(ti->MaxColor.B,1)/*)*/, 0x001F0000
  615.                 /* Adjustment of 1.4* for 16-bit rendering modes to make
  616.                    brightness scaling of world textures comparable to that of 3dfx.
  617.                    NJS: removed the 1.4 scaling.
  618.                 */
  619.             );
  620.             if( PolyFlags & PF_Masked )
  621.                 AlphaPalette[0] = 0; //0x3DEF;
  622.         }
  623.     };
  624.  
  625.     struct FD3DStats
  626.     {
  627.         INT   SurfTime, PolyTime, TileTime, ParticleTime, BeamTime, QueueTime, D3DPolyTime, D3DVertexRender, D3DVertexSetup, D3DVertexLock;
  628.         DWORD Surfs, Polys, MaskedPolys, Tiles, GouraudPolys, Particles, ParticleTextureChanges, Beams, SuccessorMisses, QueueCount;
  629.         DWORD TexUploads;          
  630.         INT   VBLocks;
  631.     };
  632.  
  633.     // Cached texture hash. !! Unify with vertex buffer/index buffer caching.
  634.     FTexInfo*               CachedTextures;
  635.     FTexInfo*               TextureHash[4096];
  636.     FTexInfo                NoTexture;
  637.  
  638.     // Round robin vertex buffers used to contain world surfaces and mesh triangles.
  639.     FD3DVertexBuffer<FD3DScreenVertex> WorldVertices;
  640.     FD3DVertexBuffer<FD3DTLVertex>     ActorVertices;
  641.     FD3DVertexBuffer<FD3DVertex>       LineVertices;
  642.     FD3DVertexBuffer<FD3DParticle>     ParticleVertices;
  643.  
  644.  
  645. #ifdef BATCH_PROJECTOR_POLYS
  646.     FD3DVertexBuffer<FD3DScreenVertex>  ProjectorVertices; 
  647. #endif
  648.  
  649.     void CleanupVertexBuffers()
  650.     {
  651.         WorldVertices.Exit();
  652.         ActorVertices.Exit();
  653.         LineVertices.Exit();
  654.         ParticleVertices.Exit();
  655.    
  656.     #ifdef BATCH_PROJECTOR_POLYS
  657.         ProjectorVertices.Exit();
  658.     #endif
  659.     }
  660.  
  661.     // Saved viewport info.
  662.     INT                     ViewportX;
  663.     INT                     ViewportY;
  664.     HWND                    ViewporthWnd;
  665.     DWORD                   ViewportColorBits;
  666.     UBOOL                   ViewportFullscreen;
  667.  
  668.     // Pixel formats from D3D.
  669.     FPixFormat              FormatDXT1;
  670.     FPixFormat              FormatP8;
  671.     FPixFormat              Format8888;
  672.     FPixFormat              Format1555;
  673.     FPixFormat*             FirstPixelFormat;
  674.  
  675.     // Fillers.
  676.     FTexFillerDXT1          FillerDXT1;
  677.     FTexFiller8888_RGBA8    Filler8888_RGBA8;
  678.     FTexFiller8888_RGBA7    Filler8888_RGBA7;
  679.     FTexFiller8888_P8       Filler8888_P8;
  680.     FTexFiller1555_RGBA7    Filler1555_RGBA7;
  681.     FTexFiller1555_P8       Filler1555_P8;
  682.     FTexFillerP8_P8         FillerP8_P8;
  683.  
  684.     // From D3D.
  685.     D3DFORMAT               BackBufferFormat;
  686.  
  687.     D3DFORMAT               RenderTargetFormat;         // Current format to create rendertargets at
  688.     IDirect3DSurface8       *pOriginalRenderTarget;     // Used to restore back to original render target
  689.     IDirect3DSurface8       *pOriginalZStencil;         // Used to restore back to original zstencil
  690.     IDirect3DTexture8       *ClipperTexture;            // Texture used to clip textures to the projector frustum
  691.     void                    *TempRT;
  692.     void                    *CurrentRenderTarget;
  693.  
  694.     // Direct3D init sequence objects and variables.
  695.     IDirect3DDevice8*       Direct3DDevice8;
  696.  
  697.     // Direct3D-specific render options.
  698.     BITFIELD                UseTrilinear;
  699.     BITFIELD                UseEditorGammaCorrection;
  700.     BITFIELD                UseD3DSoftwareRenderer;
  701.     BITFIELD                UseTripleBuffering;
  702.     BITFIELD                UseVSync;
  703.     BITFIELD                UseVertexSpecular;
  704.     BITFIELD                UsePrecache;
  705.     BITFIELD                Use2ndTierTextureCache;
  706.     BITFIELD                Use32BitTextures;
  707.     INT                     MaxResWidth, MaxResHeight;
  708.    
  709.     // Info used while rendering a frame.
  710.     D3DVIEWPORT8            ViewportInfo;
  711.     D3DXMATRIX              WorldMatrix;
  712.     D3DXMATRIX              ViewMatrix;
  713.     D3DXMATRIX              ViewMatrix4x3;
  714.     D3DXMATRIX              InvViewMatrix;
  715.     D3DXMATRIX              ProjectionMatrix;
  716.     D3DXMATRIX              ProjViewMatrix;
  717.  
  718.     FPlane                  FlashScale;
  719.     FPlane                  FlashFog;
  720.     DWORD                   LockFlags;
  721.     DWORD                   CurrentPolyFlags;
  722.     DWORD                   CurrentPolyFlagsEx;
  723.     FD3DStats               Stats;
  724.     FTexInfo*               Stages[8];
  725.     FD3DTLVertex            Verts[ACTORPOLY_VERTEXBUFFER_SIZE];
  726.     INT                     FrameCounter;
  727.     INT                     PrecacheCycle;
  728.  
  729.     // JEP...
  730. #ifdef BATCH_PROJECTOR_POLYS
  731.     #define MAX_PROJECTOR_VERTS             (PROJECTOR_VERTEXBUFFER_SIZE)   // Upper bounds before a forced flush
  732.     #define MAX_PROJECTOR_SURFS             (512)
  733.     #define MAX_PROJECTOR_POLYS             (16384)
  734.    
  735.     struct ProjectorSurf
  736.     {
  737.         DWORD               ProjectorFlags;
  738.  
  739.         INT                 FirstVert;
  740.         INT                 NumVerts;
  741.         INT                 FirstPoly;
  742.         INT                 NumPolys;
  743.     };
  744.  
  745.     ProjectorSurf           ProjectorSurfs[MAX_PROJECTOR_SURFS];   
  746.     INT                     NumProjectorSurfs;
  747.     INT                     ProjectorPolys[MAX_PROJECTOR_POLYS];
  748.     INT                     NumProjectorPolys;
  749.     FD3DTLVertex            ProjectorVerts[MAX_PROJECTOR_VERTS];
  750.     FVector                 ProjectorPoints[MAX_PROJECTOR_VERTS];
  751.     INT                     NumProjectorVerts;
  752. #endif
  753.     // ...JEP
  754.  
  755.     // Hit detection
  756.     TArray<BYTE>    HitStack;
  757.     BYTE*           HitData;
  758.     INT*            HitSize;
  759.     INT             HitCount;
  760.  
  761.     // Current state.
  762.     UViewport*      LockedViewport;
  763.     UBOOL           CurrentFullscreen;
  764.     INT             CurrentColorBytes;
  765.     INT             FullScreenWidth;
  766.     INT             FullScreenHeight;
  767.     UBOOL           ForceReset;
  768.     INT             PaletteIndex;
  769.  
  770.     // Used for D3D render state emulation and caching.
  771.     float           ZBias;
  772.     D3DBLEND        SrcBlend;
  773.     D3DBLEND        DstBlend;
  774.     INT             AlphaBlendEnable;
  775.     INT             TextureClampMode;
  776.     INT             BeginSceneCount;
  777.  
  778.     INT             LockCount;
  779.  
  780.     UBOOL           DistanceFogEnabled;
  781.     UBOOL           UseDistanceFog;
  782.  
  783.     FLOAT           DistanceFogBegin;
  784.     FLOAT           DistanceFogEnd;
  785.     FColor          DistanceFogColor;
  786.  
  787.     // UObject interface.
  788.     void StaticConstructor()
  789.     {
  790.         new(GetClass(),TEXT("UseTrilinear"),            RF_Public)UBoolProperty( CPP_PROPERTY(UseTrilinear              ), TEXT("Options"), CPF_Config );
  791.         new(GetClass(),TEXT("UseEditorGammaCorrection"),RF_Public)UBoolProperty( CPP_PROPERTY(UseEditorGammaCorrection  ), TEXT("Options"), CPF_Config );
  792.         new(GetClass(),TEXT("UseTripleBuffering"),      RF_Public)UBoolProperty( CPP_PROPERTY(UseTripleBuffering        ), TEXT("Options"), CPF_Config );
  793.         new(GetClass(),TEXT("UseVSync"),                RF_Public)UBoolProperty( CPP_PROPERTY(UseVSync                  ), TEXT("Options"), CPF_Config );
  794.         new(GetClass(),TEXT("UsePrecache"),             RF_Public)UBoolProperty( CPP_PROPERTY(UsePrecache               ), TEXT("Options"), CPF_Config );
  795.         new(GetClass(),TEXT("Use2ndTierTextureCache"),  RF_Public)UBoolProperty( CPP_PROPERTY(Use2ndTierTextureCache    ), TEXT("Options"), CPF_Config );
  796.         new(GetClass(),TEXT("Use32BitTextures"),        RF_Public)UBoolProperty( CPP_PROPERTY(Use32BitTextures          ), TEXT("Options"), CPF_Config );
  797.  
  798.         DetailTextures          = TRUE;
  799.         SpanBased               = FALSE;
  800.         SupportsFogMaps         = TRUE;
  801.         MaxResWidth             = MAXINT;
  802.         MaxResHeight            = MAXINT;
  803.     }
  804.  
  805.     // URenderDevice interface.
  806.     UD3DRenderDevice()
  807.     :   Filler1555_RGBA7(this)
  808.     ,   Filler8888_RGBA7(this)
  809.     ,   Filler8888_RGBA8(this)
  810.     ,   FillerDXT1      (this)
  811.     ,   Filler1555_P8   (this)
  812.     ,   Filler8888_P8   (this)
  813.     ,   FillerP8_P8     (this)
  814.     {
  815.         VALIDATE;
  816.     }
  817.  
  818.     // Basically the destructor, called directly from the destructor at least.
  819.     void Destroy()
  820.     {
  821.         QueueParticleShutdown();
  822.  
  823.         // Punt to my superclass:  FIXME: don't think this is a good idea with virtual destructors.
  824.         Super::Destroy();
  825.     }
  826.  
  827.     static void __fastcall InitD3D()
  828.     {
  829.         // Have we already been initialized?
  830.         if(Direct3D8)
  831.             return;
  832.  
  833.         // Create the Direct3D object.
  834.         verify(Direct3D8=Direct3DCreate8(D3D_SDK_VERSION));
  835.  
  836.         // Enumerate Direct3D adapters.
  837.         INT NumAdapters = Direct3D8->GetAdapterCount();
  838.         Adapters.Empty(NumAdapters);
  839.  
  840.         debugf(NAME_Init,TEXT("Direct3D adapters detected:"));
  841.  
  842.         for(INT Index=0;Index<NumAdapters;Index++)
  843.         {
  844.             D3DADAPTER_IDENTIFIER8 AdapterIdentifier;
  845.  
  846.             D3D_CHECK(Direct3D8->GetAdapterIdentifier(Index,D3DENUM_NO_WHQL_LEVEL,&AdapterIdentifier));
  847.  
  848.             debugf(TEXT("Adaptor Detected: %s/%s"),appFromAnsi(AdapterIdentifier.Driver),appFromAnsi(AdapterIdentifier.Description));
  849.             Adapters.AddItem(AdapterIdentifier);
  850.         }
  851.  
  852.         if(!Adapters.Num())
  853.             appErrorf(TEXT("No Direct3D adapters found"));
  854.  
  855.         // Find best Direct3D adapter.
  856.         for(Index = 0;Index < Adapters.Num();Index++)
  857.             if(appStrstr(appFromAnsi(Adapters(Index).Description),TEXT("Primary")))
  858.                 BestAdapterIndex = Index;
  859.  
  860.         // Get the Direct3D caps for the best adapter.
  861.         D3D_CHECK(Direct3D8->GetDeviceCaps(BestAdapterIndex,D3DDEVTYPE_HAL,&DeviceCaps8));
  862.  
  863.         // Get device identifier.
  864.         // szDriver, szDescription aren't guaranteed consistent (might change by mfgr, distrubutor, language, etc). Don't do any compares on these.
  865.         // liDriverVersion is safe to do QWORD comparisons on.
  866.         // User has changed drivers/cards iff guidDeviceIdentifier changes.
  867.         DeviceIdentifier = Adapters(BestAdapterIndex);
  868.  
  869.         debugf(NAME_Init,TEXT("DukeForever Direct3D support initializing."));
  870.  
  871.         // Init pyramic-compressed scaling tables.
  872.         for( INT A=0; A<128; A++ )
  873.         {
  874.             for( INT B=0; B<=A; B++ )
  875.             {
  876.                 INT M=Max(A,1);
  877.                 RScale[PYR(A)+B] = (Min((B*0x08000)/M,0x7C00) & 0xf800);
  878.                 GScale[PYR(A)+B] = (Min((B*0x00400)/M,0x03e0) & 0x07e0);
  879.                 BScale[PYR(A)+B] = (Min((B*0x00020)/M,0x001f) & 0x001f);
  880.             }
  881.         }
  882.  
  883.         D3D_CHECK(Direct3D8->GetAdapterDisplayMode(BestAdapterIndex,&OriginalDisplayMode));
  884.     }
  885.  
  886.     UBOOL __fastcall Init( UViewport* InViewport, INT NewX, INT NewY, INT NewColorBytes, UBOOL Fullscreen )
  887.     {
  888.         DescFlags=RDDESCF_Certified;
  889.  
  890.         // Ensure that D3D has been properly initialized:
  891.         InitD3D();
  892.  
  893.         Description=appFromAnsi(DeviceIdentifier.Description);
  894.  
  895.         // Local settings:
  896.         Viewport=InViewport;
  897.         DistanceFogEnabled=UseDistanceFog=FALSE;
  898.  
  899.         return SetRes( NewX, NewY, NewColorBytes, Fullscreen );
  900.     }
  901.  
  902.     void __fastcall Exit()
  903.     {
  904.         UnSetRes(NULL,0);  
  905.  
  906.         if(Viewport) Flush(0); // (Unsetres calls flush anyways)
  907.         else
  908.         {
  909.             CleanupVertexBuffers();
  910.             RestoreGamma();
  911.            
  912.             SAFETRY(SafeRelease(Direct3DDevice8));
  913.         }
  914.     }
  915.     void ShutdownAfterError()
  916.     {
  917.         ErrorCalled=true;
  918.         debugf(NAME_Exit, TEXT("UD3DRenderDevice::ShutdownAfterError"));
  919.         UnSetRes(NULL,0);
  920.  
  921.         SAFETRY(SafeRelease(Direct3DDevice8));
  922.     }
  923.  
  924.     void UpdateGamma( UViewport* Viewport )
  925.     {
  926.         UBOOL UseWindowedGamma = UseEditorGammaCorrection && GIsEditor;
  927.  
  928.         if( Direct3DDevice8 && (ViewportFullscreen||UseWindowedGamma) && (DeviceCaps8.Caps2 & D3DCAPS2_FULLSCREENGAMMA) )
  929.         {
  930.             FLOAT Brightness = Viewport->GetOuterUClient()->Brightness;
  931.  
  932.             Brightness*=2;
  933.             if(Brightness<=0) Brightness=0.01f;
  934.             D3DGAMMARAMP Ramp;
  935.             for( INT x=0; x<256; x++ )
  936.             {
  937.                     Ramp.red[x] = Ramp.green[x] = Ramp.blue[x] = Clamp<INT>(appPow(x/255.0,1.0/Brightness)*65535.0,0,65535);
  938.             }
  939.             Direct3DDevice8->SetGammaRamp(D3DSGR_CALIBRATE, &Ramp);
  940.         }
  941.     }
  942.  
  943.     void RestoreGamma()
  944.     {
  945.         if( Direct3DDevice8 && (DeviceCaps8.Caps2 & D3DCAPS2_FULLSCREENGAMMA) )
  946.         {
  947.             D3DGAMMARAMP Ramp;
  948.             for( INT x=0; x<256; x++ )
  949.                 Ramp.red[x] = Ramp.green[x] = Ramp.blue[x] = x << 8;
  950.             Direct3DDevice8->SetGammaRamp(D3DSGR_CALIBRATE, &Ramp);    
  951.         }
  952.     }
  953.    
  954.     void __fastcall Flush( UBOOL AllowPrecache )
  955.     {
  956.         if( Direct3DDevice8 )
  957.         {
  958.             for( DWORD i=0; i<DeviceCaps8.MaxSimultaneousTextures; i++ )
  959.             {
  960.                 SetTextureNULL(i);
  961.             }
  962.  
  963.             while(CachedTextures)
  964.             {
  965.                 FTexInfo*   TexInfo = CachedTextures;
  966.  
  967.                 CachedTextures = TexInfo->NextTexture;
  968.  
  969.                 TexInfo->Filler->PixelFormat->ActiveRAM=0;
  970.                 TexInfo->Filler->PixelFormat->BinnedRAM=0;
  971.                 TexInfo->Filler->PixelFormat->Active=0;
  972.                 TexInfo->Filler->PixelFormat->Binned=0;
  973.                 if(TexInfo->Texture8)
  974.                     D3D_CHECK(SafeRelease(TexInfo->Texture8));
  975.  
  976.                 SafeDelete(TexInfo);
  977.             };
  978.  
  979.             PaletteIndex = 0;
  980.  
  981.             for( i=0; i<ARRAY_COUNT(TextureHash); i++ )
  982.                 TextureHash[i]=NULL;
  983.  
  984.             UBOOL UseWindowedGamma = UseEditorGammaCorrection && GIsEditor;
  985.  
  986.             if( (ViewportFullscreen||UseWindowedGamma) && DeviceCaps8.Caps2 & D3DCAPS2_FULLSCREENGAMMA)
  987.             {
  988.                 FLOAT Brightness = Viewport->GetOuterUClient()->Brightness;
  989.  
  990.                 D3DGAMMARAMP Ramp;
  991.                 Brightness*=2;
  992.                 if(Brightness<=0) Brightness=0.01;
  993.  
  994.                 for( INT x=0; x<256; x++ )
  995.                 {
  996.                         Ramp.red[x] = Ramp.green[x] = Ramp.blue[x] = Clamp<INT>(appPow(x/255.0,1.0/Brightness)*65535.0,0,65535);
  997.  
  998.                 }
  999.                 Direct3DDevice8->SetGammaRamp(D3DSGR_CALIBRATE, &Ramp);            
  1000.             }
  1001.  
  1002.             Direct3DDevice8->SetStreamSource(0,NULL,0);
  1003.             Direct3DDevice8->SetIndices(NULL,0);
  1004.         }
  1005.  
  1006.         if( AllowPrecache )
  1007.             PrecacheOnFlip = UsePrecache;
  1008.     }
  1009.  
  1010.     void __fastcall PreRender( FSceneNode* Frame )
  1011.     {
  1012.         // Setup view matrix.
  1013.         memset( &ViewMatrix, 0, sizeof(ViewMatrix));
  1014.         ViewMatrix._11 = Frame->Coords.XAxis.X;
  1015.         ViewMatrix._12 = -Frame->Coords.YAxis.X;
  1016.         ViewMatrix._13 = Frame->Coords.ZAxis.X;
  1017.         ViewMatrix._21 = Frame->Coords.XAxis.Y;
  1018.         ViewMatrix._22 = -Frame->Coords.YAxis.Y;
  1019.         ViewMatrix._23 = Frame->Coords.ZAxis.Y;
  1020.         ViewMatrix._31 = Frame->Coords.XAxis.Z;
  1021.         ViewMatrix._32 = -Frame->Coords.YAxis.Z;
  1022.         ViewMatrix._33 = Frame->Coords.ZAxis.Z;
  1023.         ViewMatrix._41 = Frame->Coords.XAxis | -Frame->Coords.Origin;
  1024.         ViewMatrix._42 = Frame->Coords.YAxis | Frame->Coords.Origin;
  1025.         ViewMatrix._43 = Frame->Coords.ZAxis | -Frame->Coords.Origin;
  1026.         ViewMatrix._44 = 1;
  1027.  
  1028.         // Setup inverse view matrix.
  1029.         D3DXMatrixInverse( &InvViewMatrix, NULL, &ViewMatrix );
  1030.         Direct3DDevice8->SetTransform( D3DTS_VIEW, &ViewMatrix );
  1031.  
  1032.         // ONLY X-movement seems correct...
  1033.         // _Not_ just transpose of the Viewmatrix above ???
  1034.         // Alternative arrangement for vertex shader.
  1035.         // just output Y and Z reversed works!!!
  1036.         FCoords View = Frame->Coords;
  1037.         ViewMatrix4x3._11 =  View.XAxis.X;
  1038.         ViewMatrix4x3._12 =  View.XAxis.Y;
  1039.         ViewMatrix4x3._13 =  View.XAxis.Z;
  1040.         ViewMatrix4x3._14 = -View.XAxis | View.Origin;
  1041.         ViewMatrix4x3._21 = -View.YAxis.X;
  1042.         ViewMatrix4x3._22 = -View.YAxis.Y;
  1043.         ViewMatrix4x3._23 = -View.YAxis.Z;
  1044.         ViewMatrix4x3._24 =  View.YAxis | View.Origin;
  1045.         ViewMatrix4x3._31 = -View.ZAxis.X;
  1046.         ViewMatrix4x3._32 = -View.ZAxis.Y;
  1047.         ViewMatrix4x3._33 = -View.ZAxis.Z;
  1048.         ViewMatrix4x3._34 =  View.ZAxis | View.Origin;
  1049.         ViewMatrix4x3._41 = 0.0f;
  1050.         ViewMatrix4x3._42 = 0.0f;
  1051.         ViewMatrix4x3._43 = 0.0f;
  1052.         ViewMatrix4x3._44 = 1.0f;
  1053.  
  1054.         if(Frame->Viewport->IsOrtho())
  1055.         {
  1056.             FLOAT   Width = Frame->Zoom * Frame->FX2,
  1057.                     Height = Frame->Zoom * Frame->FY2;
  1058.  
  1059.             appMemzero( &ProjectionMatrix, sizeof(ProjectionMatrix));
  1060.             ProjectionMatrix._11 = 1.0f / Width;
  1061.             ProjectionMatrix._22 = 1.0f / Height;
  1062.             ProjectionMatrix._44 = 1.0f;
  1063.         }
  1064.         else
  1065.         {
  1066.             // Setup projection matrix.
  1067.             appMemzero( &ProjectionMatrix, sizeof(ProjectionMatrix));
  1068.             FLOAT wNear=NEAR_CLIP, wFar=FAR_CLIP;
  1069.             FLOAT FOV = Frame->Viewport->Actor->FovAngle * PI/360.f;
  1070.             ProjectionMatrix._11 = 1/appTan( FOV );
  1071.             ProjectionMatrix._22 = Frame->FX / appTan( FOV ) / Frame->FY;
  1072.             ProjectionMatrix._33 = wFar / (wFar - wNear);
  1073.             ProjectionMatrix._34 = 1.f;
  1074.             ProjectionMatrix._43 = -ProjectionMatrix._33 * wNear;
  1075.             ProjectionMatrix._44 = 0.f;
  1076.  
  1077.             // Hacked part-negative matrix for skeletal -> FIX at skeletal shader(viewmatrix?) level instead!
  1078.             D3DXMATRIX NegativeMatrix;
  1079.             appMemzero( &NegativeMatrix, sizeof(NegativeMatrix) );
  1080.             NegativeMatrix._11 = 1/appTan( FOV );
  1081.             NegativeMatrix._22 = Frame->FX / appTan( FOV ) / Frame->FY;
  1082.             NegativeMatrix._33 =- wFar / (wFar - wNear);
  1083.             NegativeMatrix._34 =- 1.f;
  1084.             NegativeMatrix._43 =- -NegativeMatrix._33 * wNear;
  1085.             NegativeMatrix._44 =- 0.f;
  1086.             D3DXMatrixMultiply(&ProjViewMatrix, &NegativeMatrix, &ViewMatrix4x3);
  1087.         }
  1088.  
  1089.         Direct3DDevice8->SetTransform( D3DTS_PROJECTION, &ProjectionMatrix );
  1090.  
  1091.         // disable hardware lighting mode
  1092.         Direct3DDevice8->SetRenderState( D3DRS_LIGHTING, 0 );
  1093.     }
  1094.  
  1095.     void __fastcall Lock( FColor FogColor, float FogDensity, INT FogDistance, FPlane InFlashScale, FPlane InFlashFog, FPlane ScreenClear, DWORD InLockFlags, BYTE* InHitData, INT* InHitSize )
  1096.     {
  1097.         LockCount++;
  1098.         if(!GIsEditor)
  1099.         {
  1100.             //check(LockCount==1);
  1101.         }
  1102.  
  1103.         INT FailCount=0;
  1104.         FrameCounter++;
  1105.  
  1106.         // NJS: Deal with multi-viewport strangeness in the editor:
  1107.         if(GIsEditor)
  1108.         {          
  1109.             ZBias=-1.f; // Set ZBias to an invalid state to force it to be reset next time SetZBias is called
  1110.             AlphaBlendEnable=-1;
  1111.             // BeginSceneCount=0;   // Should match up reguardless
  1112.             SrcBlend=(D3DBLEND)0; // Setting Src Blending to an invalid state will force it to be reset next time SetSrcBlend is called.
  1113.             DstBlend=(D3DBLEND)0; // Setting Dst Blending to an invalid state will force it to be reset next time SetSrcBlend is called.
  1114.             SetBlending(0xFFFFFFFF,0xFFFFFFFF); // NJS: FIXME
  1115.             SetBlending(0,0);                   // NJS: FIXME
  1116.             SetDistanceFog(true);
  1117.             SetDistanceFog(false);
  1118.             SetTextureNULL(0);
  1119.             SetTextureNULL(1);
  1120.         }
  1121.  
  1122.         {
  1123.             DistanceFogColor=FogColor;
  1124.             DistanceFogBegin=FogDistance;
  1125.             FLOAT FogDensitySquared=FogDensity*FogDensity;
  1126.             if(!FogDensitySquared) FogDensitySquared=0.001f;
  1127.             if(FogDensity<DistanceFogBegin) DistanceFogEnd=DistanceFogBegin+700.f;
  1128.             else DistanceFogEnd=FogDensity;
  1129.         }
  1130.  
  1131.         UseDistanceFog=(bool)((LockFlags&LOCKR_LightDiminish));
  1132.         SetDistanceFog(false);
  1133.  
  1134.         // Remember parameters.
  1135.         LockFlags  = InLockFlags;
  1136.         FlashScale = InFlashScale;
  1137.         FlashFog   = InFlashFog;
  1138.  
  1139.         // Hit detection.
  1140.         HitCount   = 0;
  1141.         HitData    = InHitData;
  1142.         HitSize    = InHitSize;
  1143.  
  1144.         // Check cooperative level.
  1145.         HRESULT hr=NULL, hr2=NULL;
  1146.         verify(Direct3DDevice8);
  1147.         hr=Direct3DDevice8->TestCooperativeLevel();
  1148.         if( hr!=D3D_OK )
  1149.         {
  1150.             debugf(TEXT("TestCooperativeLevel failed (%s)"),DXGetErrorString8(hr));
  1151.             Failed:
  1152.             // D3DERR_DEVICELOST is returned if the device was lost, but exclusive mode isn't available again yet.
  1153.             // D3DERR_DEVICENOTRESET is returned if the device was lost, but can be reset.
  1154.  
  1155.             // Wait to regain exclusive access to the device.
  1156.  
  1157.             do hr2=Direct3DDevice8->TestCooperativeLevel();
  1158.             while(hr2==D3DERR_DEVICELOST);
  1159.  
  1160.             if(hr2==D3DERR_DEVICENOTRESET)
  1161.             {
  1162.                 debugf(TEXT("Resetting mode (%s)"),DXGetErrorString8(hr2));
  1163.                 if( !SetRes(ViewportX, ViewportY, ViewportColorBits/8, ViewportFullscreen) )
  1164.                     if(!ErrorCalled)
  1165.                     {
  1166.                         ErrorCalled=true;
  1167.                         appErrorf(TEXT("Failed resetting mode. (%s)"),DXGetErrorString8(hr2));
  1168.                     }
  1169.             }
  1170.         }
  1171.  
  1172.         // Lock the back buffer to prevent the driver from queueing frames, causing 'input lag':
  1173.         if(!GIsEditor)
  1174.         {
  1175.             IDirect3DSurface8 *BackBuffer;
  1176.             Direct3DDevice8->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&BackBuffer);
  1177.             D3DLOCKED_RECT Rect;
  1178.             BackBuffer->LockRect(&Rect,NULL,D3DLOCK_READONLY|D3DLOCK_NO_DIRTY_UPDATE );
  1179.             BackBuffer->UnlockRect();
  1180.             SafeRelease(BackBuffer);
  1181.         }
  1182.        
  1183.         // Clear the Z-buffer.
  1184.         Direct3DDevice8->Clear( 0, NULL, D3DCLEAR_ZBUFFER | ((LockFlags & LOCKR_ClearScreen) ? D3DCLEAR_TARGET : 0), (D3DCOLOR)FColor(ScreenClear).TrueColor(), 1.f, 0 );
  1185.  
  1186.         // Init stats.
  1187.         memset( &Stats, 0, sizeof(Stats) );
  1188.         for( FPixFormat* Fmt=FirstPixelFormat; Fmt; Fmt=Fmt->Next )
  1189.             Fmt->ResetStats();
  1190.  
  1191.         // Begin scene.
  1192.         //check(BeginSceneCount==0);
  1193.         if( FAILED(h=Direct3DDevice8->BeginScene()) )
  1194.         {
  1195.             if( ++FailCount==1 )
  1196.                 goto Failed;
  1197.  
  1198.             appErrorf(TEXT("BeginScene failed (%s)"),DXGetErrorString8(h));
  1199.         }
  1200.  
  1201.         BeginSceneCount++;
  1202.     }
  1203.  
  1204.     void __fastcall PrecacheTexture( FTextureInfo& Info, DWORD PolyFlags, DWORD PolyFlagsEx )
  1205.     {
  1206.         SetTexture( 0, Info, PolyFlags|Info.Texture->PolyFlags, 1, PolyFlagsEx|Info.Texture->PolyFlagsEx );
  1207.         PrecacheCycle = 1;
  1208.     }
  1209.  
  1210.     void __fastcall Unlock( BOOL Blit )
  1211.     {
  1212.         LockCount--;
  1213.         if(!GIsEditor)
  1214.         {
  1215.             //check(LockCount==0);
  1216.         }
  1217.  
  1218.         check(Direct3DDevice8);
  1219.  
  1220.     #ifdef BATCH_PROJECTOR_POLYS
  1221.         FlushProjectorPolys();
  1222.     #endif
  1223.  
  1224.         //Direct3DDevice8->EndScene();
  1225.         EndScene();
  1226.  
  1227.         if( PrecacheCycle )
  1228.         {
  1229.             PrecacheCycle = 0;
  1230.         }
  1231.         if( Blit )
  1232.             Direct3DDevice8->Present(NULL,NULL,NULL,NULL);
  1233.  
  1234.         // Hit detection.
  1235.         check(HitStack.Num()==0);
  1236.         if( HitSize )
  1237.             *HitSize = HitCount;
  1238.     }
  1239.  
  1240.     void __fastcall DrawComplexSurface( FSceneNode* Frame, FSurfaceInfo& Surface, FSurfaceFacet& Facet )
  1241.     {
  1242.         if(!RenderSurfaces)
  1243.             return;
  1244.  
  1245.         clock(Stats.SurfTime);
  1246.         Stats.Surfs++;
  1247.  
  1248.         PreRender(Frame);
  1249.         UBOOL bHeatVision  = (Frame->Viewport->Actor->CameraStyle == PCS_HeatVision);  
  1250.         UBOOL bNightVision = (Frame->Viewport->Actor->CameraStyle == PCS_NightVision);
  1251.        
  1252.         FColor myFinalColor( 255, 255, 255, 0 );
  1253.         if(bHeatVision)
  1254.         {
  1255.             myFinalColor.R = 7.5f;
  1256.             myFinalColor.G = 0.f;
  1257.             myFinalColor.B = 38.f;
  1258.             Surface.PolyFlags&=~PF_FlatShaded;
  1259.         } else if(bNightVision)
  1260.         {
  1261.             myFinalColor.R = 0.f;
  1262.             myFinalColor.G = 128.f;
  1263.             myFinalColor.B = 0.f;
  1264.             Surface.PolyFlags&=~PF_FlatShaded;
  1265.         }
  1266.  
  1267.         // Mutually exclusive effects.
  1268.         if((Surface.DetailTexture && Surface.FogMap) || (!DetailTextures))
  1269.             Surface.DetailTexture = NULL;
  1270.  
  1271.         INT VertexCount=0;
  1272.         for( FSavedPoly* Poly=Facet.Polys; Poly; Poly = Poly->Next )
  1273.             VertexCount += Poly->NumPts;
  1274.         UBOOL IsSelected = GIsEditor && (( Surface.PolyFlags & PF_Selected )!= 0);
  1275.         DWORD SurfPolyFlags   = ( Surface.PolyFlags & ~PF_Selected ) | PF_TwoSided | (Surface.Texture->Texture->PolyFlags);
  1276.         DWORD SurfPolyFlagsEx = Surface.PolyFlagsEx | (Surface.Texture->Texture->PolyFlagsEx);
  1277.  
  1278.         SetDistanceFog(!(SurfPolyFlags&PF_Unlit));
  1279.         SetZBias(0);
  1280.  
  1281.         INT StoreVertInfo = (IsSelected) + (Surface.LightMap!=NULL) + (Surface.MacroTexture!=NULL) + (Surface.DetailTexture!=NULL) + (Surface.FogMap!=NULL) + (ProjectorArray.Num() > 0);      
  1282.  
  1283.         WorldVertices.Set();
  1284.  
  1285.         // Render texture and lightmap.
  1286.         if( /*UseMultitexture &&*/ Surface.LightMap!=NULL && Surface.MacroTexture==NULL )
  1287.         {
  1288.             StoreVertInfo--;
  1289.             // Use multitexturing when rendering base + lightmap.          
  1290.             if(SurfPolyFlags&PF_FlatShaded)
  1291.             {
  1292.                 SetTextureNULL( 0 );
  1293.                 SetTextureNULL( 1 );
  1294.                 SetBlending();
  1295.             }
  1296.             else
  1297.             {
  1298.                 SetTexture( 0, *Surface.Texture, SurfPolyFlags, 0, SurfPolyFlagsEx );
  1299.                 SetTexture( 1, *Surface.LightMap, 0, 0, true );
  1300.                 // PF_Memorize to signify multitexturing.
  1301.                 SetBlending( SurfPolyFlags|PF_Memorized, SurfPolyFlagsEx );
  1302.             }
  1303.             // Set up all poly vertices.
  1304.             FD3DScreenVertex* V=(FD3DScreenVertex*) WorldVertices.Lock(VertexCount);
  1305.             D3DCOLOR clr;
  1306.  
  1307.             if(Surface.PolyFlags&PF_FlatShaded)
  1308.                 clr = FColor( Surface.FlatColor).TrueColor() | 0xff000000;
  1309.             else
  1310.                 clr = FColor(Stages[0]->MaxColor.Plane() * Stages[1]->MaxColor.Plane()).TrueColor() | 0xff000000;
  1311.  
  1312.             if(bHeatVision||bNightVision)
  1313.             {
  1314.                 clr=myFinalColor.TrueColor() | 0xFF000000;
  1315.             }
  1316.  
  1317.             if(SurfPolyFlagsEx&(PFX_LightenModulate|PFX_DarkenModulate))
  1318.             {
  1319.                 clr=0xFFFFFFFF;
  1320.             }
  1321.             else if(SurfPolyFlags&PF_Modulated)
  1322.             {
  1323.                 clr = (0xFF<<24)|(248<<16)|(248<<8)|248;    // NJS: 248 is the darkening correction needed to remove boxes from modulated decals, etc
  1324.             }
  1325.  
  1326.             INT n=0;
  1327.             for( FSavedPoly* Poly=Facet.Polys; Poly; Poly=Poly->Next )
  1328.             {
  1329.                 for( INT i=0; i<Poly->NumPts; i++, n++, V++ )
  1330.                 {
  1331.                     GET_COLOR_DWORD(V->Color)   = clr;
  1332.                     FLOAT R = V->Position.W   = Poly->Pts[i]->RZ * Frame->RProj.Z;
  1333.                     FLOAT Z = V->Position.Z    = ProjectionMatrix._33 + ProjectionMatrix._43 * R;                  
  1334.                     FLOAT Y = V->Position.Y    = Poly->Pts[i]->ScreenY + Frame->YB - 0.5f;
  1335.                     FLOAT X = V->Position.X    = Poly->Pts[i]->ScreenX + Frame->XB - 0.5f;
  1336.                    
  1337.                     //X=V->Position.X+= (appSin(Poly->Pts[i]->Point.Y+appSeconds()*2.2f)*3.1f);  // NJS: Caustics simulation
  1338.                    
  1339.                     FVector TexPlane = (*(FVector*)Poly->Pts[i] - Facet.MapCoords.Origin);
  1340.                     FLOAT u  = Facet.MapCoords.XAxis | TexPlane;
  1341.                     FLOAT v  = Facet.MapCoords.YAxis | TexPlane;
  1342.  
  1343.                     // *************************
  1344.                     // NJS: Been getting random crashes around here recently, so just be sure of a few things:
  1345.                     check(Surface.Texture);
  1346.                     check(Surface.LightMap);
  1347.                     check(Stages[0]);
  1348.                     check(Stages[1]);
  1349.                     check(V);
  1350.                     check(V->U);
  1351.                     check(V->U2);
  1352.                     // *************************
  1353.  
  1354.                     V->U [0] = (u - Surface.Texture->Pan.X                                   ) * Stages[0]->UScale;
  1355.                     V->U [1] = (v - Surface.Texture->Pan.Y                                   ) * Stages[0]->VScale;
  1356.                     V->U2[0] = (u - Surface.LightMap->Pan.X + 0.5f * Surface.LightMap->UScale) * Stages[1]->UScale;
  1357.                     V->U2[1] = (v - Surface.LightMap->Pan.Y + 0.5f * Surface.LightMap->VScale) * Stages[1]->VScale;
  1358.  
  1359.                     //V->U[2] = 1.0f;
  1360.                     //V->U[3] = 1.0f;
  1361.                    
  1362.                     if( StoreVertInfo )
  1363.                     {
  1364.                         check(n<ARRAY_COUNT(Verts));
  1365.                         Verts[n].Position.X = X;    
  1366.                         Verts[n].Position.Y = Y;
  1367.                         Verts[n].Position.Z = Z;
  1368.                         Verts[n].Position.W = R;
  1369.                         Verts[n].U[0]= u;
  1370.                         Verts[n].U[1]= v;
  1371.                     }          
  1372.                 }
  1373.             }
  1374.  
  1375.             // Draw base texture + lightmap.
  1376.             INT First = WorldVertices.Unlock();
  1377.        
  1378.             for( Poly=Facet.Polys; Poly; Poly=Poly->Next)
  1379.             {
  1380.                 Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN, First, Poly->NumPts - 2 );
  1381.                 First += Poly->NumPts;
  1382.                 Stats.Polys++;
  1383.             }
  1384.  
  1385.             SetTextureNULL(1);
  1386.             // Handle depth buffering the appropriate areas of masked textures.
  1387.             if( SurfPolyFlags & PF_Masked )
  1388.                 Direct3DDevice8->SetRenderState( D3DRS_ZFUNC, D3DCMP_EQUAL );
  1389.         }
  1390.         else
  1391.         {
  1392.             // Set up all poly vertices.
  1393.             if(SurfPolyFlags&PF_FlatShaded)
  1394.             {
  1395.                 SetTextureNULL(0);
  1396.                 SetTextureNULL(1);
  1397.                 SetBlending();
  1398.             } else
  1399.             {
  1400.                 SetTexture( 0, *Surface.Texture, SurfPolyFlags, 0 );
  1401.                 SetBlending( SurfPolyFlags&~PF_Memorized, SurfPolyFlagsEx );
  1402.             }
  1403.  
  1404.             // Count things to draw to plan when to do the final color-scaling pass.
  1405.             INT ModulateThings = (Surface.Texture!=NULL) + (Surface.LightMap!=NULL) + (Surface.MacroTexture!=NULL);
  1406.             FPlane FinalColor(1,1,1,1);        
  1407.             FD3DScreenVertex* V=(FD3DScreenVertex*) WorldVertices.Lock(VertexCount);
  1408.             D3DCOLOR Clr;
  1409.             if( SurfPolyFlags & PF_FlatShaded )
  1410.                 Clr = FColor( Surface.FlatColor).TrueColor() | 0xff000000;
  1411.             else
  1412.                 Clr = UpdateModulation( ModulateThings, FinalColor, Stages[0]->MaxColor.Plane() );
  1413.  
  1414.             if(bHeatVision||bNightVision)
  1415.             {
  1416.                 Clr=myFinalColor.TrueColor() | 0xFF000000;
  1417.             }
  1418.  
  1419.             if(SurfPolyFlagsEx&(PFX_LightenModulate|PFX_DarkenModulate))
  1420.             {
  1421.                 Clr=0xFFFFFFFF;
  1422.             }
  1423.             else if(SurfPolyFlags&PF_Modulated)
  1424.             {
  1425.                 Clr = (0xFF<<24)|(248<<16)|(248<<8)|248;
  1426.             }
  1427.  
  1428.             INT n=0;
  1429.             //Queued3DLinesFlush(Frame);
  1430.  
  1431.             for( FSavedPoly* Poly=Facet.Polys; Poly; Poly=Poly->Next )
  1432.             {
  1433.                 // Set up vertices.
  1434.                 for( INT i=0; i<Poly->NumPts; i++, n++, V++ )
  1435.                 {
  1436.                     GET_COLOR_DWORD(V->Color) = Clr;
  1437.                     //GET_COLOR_DWORD(V->Color) =appRand() ^ (appRand()<<16);
  1438.                     FLOAT X = V->Position.X  = Poly->Pts[i]->ScreenX + Frame->XB - 0.5f;
  1439.                     FLOAT Y = V->Position.Y  = Poly->Pts[i]->ScreenY + Frame->YB - 0.5f;
  1440.                     FLOAT R = V->Position.W = Poly->Pts[i]->RZ * Frame->RProj.Z;
  1441.                     FLOAT Z = V->Position.Z  = ProjectionMatrix._33 + ProjectionMatrix._43 * R;
  1442.                     FVector TexPlane = (*(FVector*)Poly->Pts[i] - Facet.MapCoords.Origin);
  1443.                     FLOAT u  = Facet.MapCoords.XAxis | TexPlane;
  1444.                     FLOAT v  = Facet.MapCoords.YAxis | TexPlane;
  1445.                     V->U[0] = (u - Surface.Texture->Pan.X) * Stages[0]->UScale;
  1446.                     V->U[1] = (v - Surface.Texture->Pan.Y) * Stages[0]->VScale;
  1447.  
  1448.                     if( StoreVertInfo )
  1449.                     {
  1450.                         Verts[n].Position.X = X;    
  1451.                         Verts[n].Position.Y = Y;
  1452.                         Verts[n].Position.Z = Z;
  1453.                         Verts[n].Position.W = R;
  1454.                         Verts[n].U[0]= u;
  1455.                         Verts[n].U[1]= v;
  1456.                     }
  1457.                 }
  1458.             }
  1459.  
  1460.             // Draw bare base texture.
  1461.             INT First = WorldVertices.Unlock();
  1462.             //WorldVertices.Set();
  1463.             for( Poly=Facet.Polys; Poly; n+=Poly->NumPts,Poly=Poly->Next)
  1464.             {
  1465.                 Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN, First, Poly->NumPts - 2 );
  1466.                 First += Poly->NumPts;
  1467.                 Stats.Polys++;
  1468.             }
  1469.  
  1470.             SetDistanceFog(false);
  1471.  
  1472.             // Handle depth buffering the appropriate areas of masked textures.
  1473.             if( SurfPolyFlags & PF_Masked )
  1474.                 Direct3DDevice8->SetRenderState( D3DRS_ZFUNC, D3DCMP_EQUAL );
  1475.            
  1476.             // Macrotexture.
  1477.             if( Surface.MacroTexture )
  1478.             {
  1479.                 // Set the macrotexture.
  1480.                 SetBlending( PF_Modulated );
  1481.                 SetTexture( 0, *Surface.MacroTexture, 0, 0 );
  1482.                 D3DCOLOR Clr = UpdateModulation( ModulateThings, FinalColor, Stages[0]->MaxColor.Plane() );
  1483.                 FD3DScreenVertex* V=(FD3DScreenVertex*) WorldVertices.Lock(VertexCount);
  1484.                 INT n=0;
  1485.                 for( Poly=Facet.Polys; Poly; Poly=Poly->Next )
  1486.                 {
  1487.                     for( INT i=0; i<Poly->NumPts; i++,n++,V++ )
  1488.                     {
  1489.                         V->Color = Clr;
  1490.                         V->Position.X = Verts[n].Position.X;    
  1491.                         V->Position.Y = Verts[n].Position.Y;
  1492.                         V->Position.W = Verts[n].Position.W;
  1493.                         V->Position.Z = Verts[n].Position.Z;
  1494.                         V->U[0] = (Verts[n].U[0] - Surface.MacroTexture->Pan.X) * Stages[0]->UScale;
  1495.                         V->U[1] = (Verts[n].U[1] - Surface.MacroTexture->Pan.Y) * Stages[0]->VScale;
  1496.                     }
  1497.                 }
  1498.  
  1499.                 // Draw.
  1500.                 INT First = WorldVertices.Unlock();
  1501.  
  1502.                 for( Poly=Facet.Polys; Poly; n+=Poly->NumPts,Poly=Poly->Next)
  1503.                 {
  1504.                     Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN,  First, Poly->NumPts - 2 );
  1505.                     First += Poly->NumPts;
  1506.                     Stats.Polys++;
  1507.                 }
  1508.             }
  1509.  
  1510.             // Non-multitextured light map.
  1511.             if( Surface.LightMap )
  1512.             {
  1513.                 // Set the light map.
  1514.                 SetBlending( PF_Modulated );
  1515.                 SetTexture( 0, *Surface.LightMap, 0, 0 );
  1516.                 D3DCOLOR Clr = UpdateModulation( ModulateThings, FinalColor, Stages[0]->MaxColor.Plane() );
  1517.                 FD3DScreenVertex* V=(FD3DScreenVertex*) WorldVertices.Lock(VertexCount);
  1518.                 INT n=0;
  1519.                 for( Poly=Facet.Polys; Poly; Poly=Poly->Next )
  1520.                 {
  1521.                     for( INT i=0; i<Poly->NumPts; i++,n++,V++ )
  1522.                     {
  1523.                         V->Color = Clr;
  1524.                         V->Position.X  = Verts[n].Position.X;    
  1525.                         V->Position.Y  = Verts[n].Position.Y;
  1526.                         V->Position.W = Verts[n].Position.W;
  1527.                         V->Position.Z  = Verts[n].Position.Z;
  1528.                         V->U[0] = (Verts[n].U[0] - Surface.LightMap->Pan.X + 0.5f * Surface.LightMap->UScale) * Stages[0]->UScale;
  1529.                         V->U[1] = (Verts[n].U[1] - Surface.LightMap->Pan.Y + 0.5f * Surface.LightMap->VScale) * Stages[0]->VScale;
  1530.                     }
  1531.                 }
  1532.  
  1533.                 // Draw.
  1534.                 INT First = WorldVertices.Unlock();
  1535.  
  1536.                 for( Poly=Facet.Polys; Poly; n+=Poly->NumPts,Poly=Poly->Next)
  1537.                 {
  1538.                     Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN, First, Poly->NumPts - 2 );
  1539.                     First += Poly->NumPts;
  1540.                     Stats.Polys++;
  1541.                 }
  1542.             }
  1543.         }
  1544.  
  1545.         SetDistanceFog(false);
  1546.  
  1547.         // Draw detail texture overlaid.
  1548.         if(Surface.DetailTexture&&!(SurfPolyFlags&PF_FlatShaded))
  1549.         {          
  1550.             INT DetailMax = 1;
  1551.  
  1552.             FLOAT DetailScale=1.f;
  1553.             FLOAT LocalNearZ=NearZ; //380.0f;
  1554.             //if( !GIsEditor )
  1555.                 *Surface.DetailTexture->MaxColor = FColor(255,255,255,255);
  1556.            
  1557.             INT AreDetailing = 0;          
  1558.             while( DetailMax-- > 0 )           
  1559.             {              
  1560.                 FLOAT InvZ = (1.f/LocalNearZ);
  1561.                 FLOAT SZ = ProjectionMatrix._33 + ProjectionMatrix._43 * InvZ;
  1562.  
  1563.                 INT n=0;
  1564.                 for( FSavedPoly* Poly=Facet.Polys; Poly; Poly=Poly->Next )
  1565.                 {
  1566.                     UBOOL IsNear[32], CountNear = 0;               
  1567.                     // Any textures close enough that they need detail texturing ?
  1568.                     for( INT i=0; i<Poly->NumPts; i++ )
  1569.                     {
  1570.                         IsNear[i] = Poly->Pts[i]->Point.Z < LocalNearZ;
  1571.                         CountNear += IsNear[i];
  1572.                     }                                      
  1573.                     if( CountNear )
  1574.                     {
  1575.                         INT NumNear = 0;
  1576.                         FD3DScreenVertex* V=(FD3DScreenVertex*) WorldVertices.Lock(32);  // Safe upper limit for (clipped) facet's triangles * 3                       
  1577.                         // Prepare state, minimize changes.
  1578.                         if( AreDetailing==0 )
  1579.                         {
  1580.                             SetBlending( PF_Modulated );
  1581.                             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_BLENDDIFFUSEALPHA );
  1582.                             SetZBias(15.f);
  1583.                             SetTexture( 0, *Surface.DetailTexture, 0, 0 );
  1584.                             AreDetailing = 1;
  1585.                         }
  1586.                         // j = one before i; m is one before n;  n is the index into serialized predigested vertex MasterU/V
  1587.                         for( INT i=0, j=Poly->NumPts-1, m=n+Poly->NumPts-1; i<Poly->NumPts; j=i++, m=n++ )
  1588.                         {  
  1589.                             // Extra vertex if needed to create a new boundary of visible detailing.
  1590.                             if( IsNear[i] ^ IsNear[j] )
  1591.                             {
  1592.                                 // near-point-to-detailboundary distance divided by full edge Z distance.
  1593.                                 // slip Z, X and Y up to that point.
  1594.                                 FLOAT G    = (Poly->Pts[i]->Point.Z - LocalNearZ) / (Poly->Pts[i]->Point.Z - Poly->Pts[j]->Point.Z);
  1595.                                 FLOAT F    = 1.f - G;
  1596.                                 V->Position.W = InvZ;
  1597.                                 V->Position.Z = SZ;
  1598.                                 V->Position.X = (F * Poly->Pts[i]->ScreenX * Poly->Pts[i]->Point.Z + G * Poly->Pts[j]->ScreenX * Poly->Pts[j]->Point.Z) * InvZ + Frame->XB - 0.5f;
  1599.                                 V->Position.Y = (F * Poly->Pts[i]->ScreenY * Poly->Pts[i]->Point.Z + G * Poly->Pts[j]->ScreenY * Poly->Pts[j]->Point.Z) * InvZ + Frame->YB - 0.5f;
  1600.                                 if(!WorldDetail)
  1601.                                 {
  1602.                                     V->U[0] = (F * Verts[n].U[0] + G * Verts[m].U[0] - Surface.DetailTexture->Pan.X) * Stages[0]->UScale * DetailScale;
  1603.                                     V->U[1] = (F * Verts[n].U[1] + G * Verts[m].U[1] - Surface.DetailTexture->Pan.Y) * Stages[0]->VScale * DetailScale;
  1604.                                 } else
  1605.                                 {
  1606.                                     V->U[0] = (F * Verts[n].U[0] + G * Verts[m].U[0] - Surface.DetailTexture->Pan.X) * DetailScale * 0.052083;
  1607.                                     V->U[1] = (F * Verts[n].U[1] + G * Verts[m].U[1] - Surface.DetailTexture->Pan.Y) * DetailScale * 0.052083 ;
  1608.  
  1609.                                 }
  1610.  
  1611.                                 V->Color = D3DCOLOR_RGBA(0x7F, 0x7F, 0x7F, 0);
  1612.                                 V++;
  1613.                                 NumNear++;
  1614.                             }
  1615.                             if( IsNear[i] )
  1616.                             {
  1617.                                 V->Position.W =Verts[n].Position.W;
  1618.                                 V->Position.Z =Verts[n].Position.Z;
  1619.                                 V->Position.X =Verts[n].Position.X;
  1620.                                 V->Position.Y =Verts[n].Position.Y;
  1621.                                 if(!WorldDetail)
  1622.                                 {
  1623.                                     V->U[0] = (Verts[n].U[0] - Surface.DetailTexture->Pan.X) * Stages[0]->UScale * DetailScale;
  1624.                                     V->U[1] = (Verts[n].U[1] - Surface.DetailTexture->Pan.Y) * Stages[0]->VScale * DetailScale;
  1625.                                 } else
  1626.                                 {
  1627.                                     V->U[0] = (Verts[n].U[0] - Surface.DetailTexture->Pan.X) * DetailScale * 0.052083;
  1628.                                     V->U[1] = (Verts[n].U[1] - Surface.DetailTexture->Pan.Y) * DetailScale * 0.052083;
  1629.  
  1630.                                 }
  1631.                                 DWORD A               = Min<DWORD>( appRound(100.f * (LocalNearZ / Poly->Pts[i]->Point.Z - 1.f)), 255 );
  1632.                                 V->Color = D3DCOLOR_RGBA( 0x7F, 0x7F, 0x7F, A );
  1633.                                 V++;
  1634.                                 NumNear++;
  1635.                             }
  1636.  
  1637.                         }
  1638.                         n -= Poly->NumPts;
  1639.                        
  1640.                         INT First = WorldVertices.Unlock();
  1641.  
  1642.                         Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN, First, NumNear - 2 );
  1643.                         Stats.Polys++;
  1644.                     }                          
  1645.                     n += Poly->NumPts;
  1646.                 }
  1647.                 DetailScale *= 4.223f;
  1648.                 LocalNearZ  /= 4.223f;
  1649.             }      
  1650.             if( AreDetailing )
  1651.             {
  1652.                 Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  1653.                 SetZBias(0);
  1654.                 AreDetailing = 0;
  1655.             }
  1656.         }
  1657.         else if( Surface.FogMap )
  1658.         {
  1659.             SetBlending( PF_Highlighted );
  1660.             SetTexture( 0, *Surface.FogMap, 0, 0 );
  1661.             D3DCOLOR Clr = Stages[0]->MaxColor.TrueColor() | 0xff000000;
  1662.             if( !Format8888.Supported ) // Texture has no alpha.
  1663.                 Clr&=~0xff000000;
  1664.  
  1665.             FD3DScreenVertex* V=(FD3DScreenVertex*) WorldVertices.Lock(VertexCount);
  1666.             INT n = 0;
  1667.             for( FSavedPoly* Poly=Facet.Polys; Poly; Poly=Poly->Next )
  1668.             {
  1669.                 for( INT i=0; i<Poly->NumPts; i++, n++, V++ )
  1670.                 {
  1671.                     GET_COLOR_DWORD(V->Color) = Clr;
  1672.                     V->Position.X  = Verts[n].Position.X;    
  1673.                     V->Position.Y  = Verts[n].Position.Y;
  1674.                     V->Position.W = Verts[n].Position.W;
  1675.                     V->Position.Z  = Verts[n].Position.Z;
  1676.                     V->U[0] = (Verts[n].U[0] - Surface.FogMap->Pan.X + 0.5f * Surface.FogMap->UScale) * Stages[0]->UScale;
  1677.                     V->U[1] = (Verts[n].U[1] - Surface.FogMap->Pan.Y + 0.5f * Surface.FogMap->VScale) * Stages[0]->VScale;
  1678.                 }
  1679.             }
  1680.             // Draw
  1681.             INT First = WorldVertices.Unlock();
  1682.  
  1683.             for( Poly=Facet.Polys; Poly; n+=Poly->NumPts,Poly=Poly->Next)
  1684.             {
  1685.                 Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN, First, Poly->NumPts - 2 );
  1686.                 First += Poly->NumPts;
  1687.                 Stats.Polys++;
  1688.             }      
  1689.         }
  1690.  
  1691.         if( Surface.PolyFlags & PF_FlatShaded )  // Wireframe Overlay
  1692.         {
  1693.             SetZBias(16.f);
  1694.                         // Set up all poly vertices.
  1695.             FD3DScreenVertex* V=(FD3DScreenVertex*) WorldVertices.Lock(VertexCount);
  1696.            
  1697.             for( FSavedPoly* Poly=Facet.Polys; Poly; Poly=Poly->Next )
  1698.             {
  1699.                 for( INT i=0; i<Poly->NumPts; i++, V++ )
  1700.                 {
  1701.                     GET_COLOR_DWORD(V->Color)   = 0; //clr;
  1702.                     V->Position.X    = Poly->Pts[i]->ScreenX + Frame->XB - 0.5f;
  1703.                     V->Position.Y    = Poly->Pts[i]->ScreenY + Frame->YB - 0.5f;
  1704.                     FLOAT R = V->Position.W   = Poly->Pts[i]->RZ * Frame->RProj.Z;
  1705.                     V->Position.Z    = ProjectionMatrix._33 + ProjectionMatrix._43 * R;                            
  1706.                 }
  1707.             }
  1708.  
  1709.             // Draw base texture + lightmap.
  1710.             INT First = WorldVertices.Unlock();
  1711.             WorldVertices.Set();
  1712.  
  1713.            
  1714.             //First=OriginalFirst;
  1715.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DISABLE  );
  1716.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
  1717.            
  1718.             for( Poly=Facet.Polys; Poly; Poly=Poly->Next)
  1719.             {
  1720.                 Direct3DDevice8->DrawPrimitive( D3DPT_LINESTRIP,First,Poly->NumPts-1);
  1721.                 First += Poly->NumPts;
  1722.             }
  1723.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  1724.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  1725.            
  1726.             SetZBias(0.f);
  1727.         }
  1728.  
  1729.         //  Draw selection markings on a surface: specular overlay.
  1730.         if( IsSelected )
  1731.         {
  1732.             SetBlending(PF_Translucent);
  1733.             SetTextureNULL( 0 );
  1734.             SetTextureNULL( 1 );
  1735.  
  1736.             INT n=0;
  1737.             for( FSavedPoly* Poly=Facet.Polys; Poly; Poly=Poly->Next )
  1738.             {
  1739.                 // draw per facet...
  1740.                 FD3DTLVertex* V=(FD3DTLVertex*) ActorVertices.Lock(Poly->NumPts);
  1741.                 for( INT i=0; i<Poly->NumPts; i++, n++, V++ )
  1742.                 {
  1743.                     V->Position.X = Verts[n].Position.X;
  1744.                     V->Position.Y = Verts[n].Position.Y;
  1745.                     V->Position.Z = Verts[n].Position.Z;
  1746.                     V->Position.W = Verts[n].Position.W;
  1747.  
  1748.                     V->Specular   = D3DCOLOR_RGBA( 255,255,255,255);
  1749.                     V->Diffuse    = D3DCOLOR_RGBA( 10,5,60,255);         // Arbitrary marker color.
  1750.                 }
  1751.  
  1752.                 INT First = ActorVertices.Unlock();
  1753.  
  1754.                 ActorVertices.Set();
  1755.  
  1756.                 Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN, First, Poly->NumPts - 2 );
  1757.                 Stats.Polys++;
  1758.             }
  1759.         }
  1760.  
  1761.         // JEP... Project all projector textures onto surface
  1762.         if (ProjectorArray.Num() > 0 && Frame->Recursion == 0 && Surface.ProjectorFlags)
  1763.         {
  1764.         #ifdef BATCH_PROJECTOR_POLYS
  1765.             ProjectorSurf       *ProjSurf;
  1766.  
  1767.             ProjSurf = &ProjectorSurfs[NumProjectorSurfs];
  1768.  
  1769.             ProjSurf->ProjectorFlags = Surface.ProjectorFlags;
  1770.             ProjSurf->FirstVert = NumProjectorVerts;
  1771.             ProjSurf->NumVerts = 0;
  1772.             ProjSurf->FirstPoly = NumProjectorPolys;
  1773.             ProjSurf->NumPolys = 0;
  1774.  
  1775.             INT     *PPoly = &ProjectorPolys[ProjSurf->FirstPoly];
  1776.             FVector *PP = &ProjectorPoints[ProjSurf->FirstVert];
  1777.  
  1778.             for( Poly=Facet.Polys; Poly; Poly=Poly->Next)
  1779.             {
  1780.                 //if (!Frame->Level->Model->Nodes(Poly->iNode).ProjectorFlags)
  1781.                 //  continue;
  1782.  
  1783.                 PPoly[ProjSurf->NumPolys++] = Poly->NumPts;
  1784.  
  1785.                 // Copy camera space verts over (need them to generate uv's during rendering pass)
  1786.                 for (INT j=0; j< Poly->NumPts; j++)
  1787.                     PP[ProjSurf->NumVerts++] = Poly->Pts[j]->Point;
  1788.             }
  1789.  
  1790.             memcpy(&ProjectorVerts[ProjSurf->FirstVert], &Verts[0], ProjSurf->NumVerts*sizeof(Verts[0]));
  1791.            
  1792.             NumProjectorVerts += ProjSurf->NumVerts;
  1793.             NumProjectorPolys += ProjSurf->NumPolys;
  1794.            
  1795.             NumProjectorSurfs++;
  1796.  
  1797.             if (NumProjectorSurfs > 64)
  1798.                 FlushProjectorPolys();
  1799.         #else
  1800.             SetTextureNULL( 0 );
  1801.             SetTextureNULL( 1 );
  1802.             SetBlending( PF_Modulated );
  1803.             SetDistanceFog(false);
  1804.  
  1805.             SetTextureClampMode(1);
  1806.  
  1807.             //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  1808.             //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_DESTCOLOR );
  1809.             //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
  1810.             SetAlphaBlendEnable(TRUE);
  1811.             SetSrcBlend(D3DBLEND_DESTCOLOR);
  1812.             SetDstBlend(D3DBLEND_ZERO);
  1813.  
  1814.             // Setup clipper texture (also used for fade out)
  1815.             Direct3DDevice8->SetTexture(1, ClipperTexture);
  1816.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  1817.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_ADD);
  1818.             //Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  1819.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
  1820.  
  1821.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP );
  1822.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP );
  1823.  
  1824.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_POINT);
  1825.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_POINT);
  1826.            
  1827.             for (int i=ProjectorArray.Num()-1; i>=0 ; i--)
  1828.             {
  1829.                 DWORD Mask = 1<<i;
  1830.  
  1831.                 if (!(Surface.ProjectorFlags & Mask))
  1832.                     continue;
  1833.  
  1834.                 ProjectorInfo *pProjector = &ProjectorArray(i);
  1835.  
  1836.                 if (!pProjector->GNodes)
  1837.                     continue;
  1838.  
  1839.                 // Set the texture to the render target that belongs to this projector
  1840.                 Direct3DDevice8->SetTexture(0, pProjector->pRenderTargetTex);
  1841.  
  1842.                 // Lock the world verts
  1843.                 FD3DScreenVertex* V=(FD3DScreenVertex*)WorldVertices.Lock(VertexCount);
  1844.  
  1845.                 INT n = 0;
  1846.  
  1847.                 // For each poly, project the verts onto the projector front plane to get the UV's
  1848.                 for( Poly=Facet.Polys; Poly; Poly=Poly->Next)
  1849.                 {
  1850.                     if (!(pProjector->GNodes[Poly->iNode].ProjectorFlags & Mask))
  1851.                     {
  1852.                         n += Poly->NumPts;
  1853.                         continue;
  1854.                     }
  1855.  
  1856.                     for( INT j=0; j<Poly->NumPts; j++, n++, V++ )
  1857.                     {
  1858.                         V->Position.X = Verts[n].Position.X;    
  1859.                         V->Position.Y = Verts[n].Position.Y;
  1860.                         V->Position.Z = Verts[n].Position.Z;
  1861.                         V->Position.W = Verts[n].Position.W;
  1862.                         V->Color = 0xffffffff;
  1863.  
  1864.                         // Grab a copy of the vert
  1865.                         FTransform      P;
  1866.  
  1867.                         // Transform point into projector space
  1868.                         P.Point = Poly->Pts[j]->Point.TransformPointBy(pProjector->CameraToLight);
  1869.                        
  1870.                     #if 1  
  1871.                         // Project point onto projector front plane
  1872.                         P.Point.Z = max(1.0f, P.Point.Z);
  1873.                         P.Project(pProjector->Frame);
  1874.  
  1875.                         // Snag UV's
  1876.                         V->U[0] = P.ScreenX*pProjector->OneOverX;
  1877.                         V->U[1] = P.ScreenY*pProjector->OneOverY;
  1878.                        
  1879.                         V->Position.W *= P.Point.Z;
  1880.                     #else
  1881.                         // Ortho projection
  1882.                         V->U[0] = (P.Point.X/125)+0.5f;
  1883.                         V->U[1] = (P.Point.Y/125)+0.5f;
  1884.                     #endif
  1885.  
  1886.                         // Clip and fade out (this is the UV's for the clipper/fade out texture layer)
  1887.                     #if 1
  1888.                         FLOAT R = P.RZ * pProjector->Frame->RProj.Z;        // (1.0f/Z)
  1889.                         V->U2[0] = (pProjector->_33 + pProjector->_43 * R)*pProjector->FadeScale;
  1890.                         V->U2[1] = 0.0f;
  1891.                     #endif
  1892.                     }
  1893.                 }
  1894.  
  1895.                 // Unlock world verts
  1896.                 INT First = WorldVertices.Unlock();
  1897.  
  1898.                 for( Poly=Facet.Polys; Poly; Poly=Poly->Next)
  1899.                 {
  1900.                     if (!(pProjector->GNodes[Poly->iNode].ProjectorFlags & Mask))
  1901.                         continue;
  1902.                     Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN, First, Poly->NumPts - 2 );
  1903.                     First += Poly->NumPts;
  1904.                 }
  1905.             }
  1906.             SetTextureNULL(0);
  1907.             SetTextureNULL(1);
  1908.  
  1909.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  1910.  
  1911.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  1912.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  1913.  
  1914.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP );
  1915.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP );
  1916.  
  1917.             //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  1918.             //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR );
  1919.             //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR );
  1920.             SetAlphaBlendEnable(TRUE);
  1921.             SetSrcBlend(D3DBLEND_DESTCOLOR);
  1922.             SetDstBlend(D3DBLEND_SRCCOLOR);
  1923.             SetTextureClampMode(0);
  1924.  
  1925.         #endif
  1926.         }
  1927.         // ...JEP
  1928.  
  1929.         // Finish mask handling.
  1930.         if( SurfPolyFlags & PF_Masked )
  1931.             Direct3DDevice8->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESSEQUAL );
  1932.  
  1933.         VALIDATE;
  1934.  
  1935.         unclock(Stats.SurfTime);
  1936.     }
  1937.  
  1938.     struct QueuedPolygon
  1939.     {
  1940.         DWORD PolyFlags,
  1941.               PolyFlagsEx;
  1942.         FTextureInfo *Texture;
  1943.         UTexture *Tex;
  1944.         FTransTexture v[3];
  1945.     };
  1946.  
  1947.     TArray<QueuedPolygon> QueuedPolygons;
  1948.  
  1949.     bool __fastcall QueuePolygonDoes()  
  1950.     {
  1951.         return true;
  1952.     }
  1953.  
  1954.     bool __fastcall QueuePolygonBegin(FSceneNode* Frame)
  1955.     {
  1956.         CurrentFrame=Frame;
  1957.         return true;
  1958.     }
  1959.  
  1960.     void __fastcall QueuePolygonEnd(DWORD ProjectorFlags = 0)
  1961.     {
  1962.         int QueuedPolygonCount=QueuedPolygons.Num();
  1963.  
  1964.         if(!QueuedPolygonCount)
  1965.             return;
  1966.  
  1967.         check(Direct3DDevice8);
  1968.  
  1969.         clock(Stats.PolyTime);
  1970.         Stats.QueueCount++;
  1971.         Stats.Polys+=QueuedPolygonCount;
  1972.  
  1973.         PreRender(CurrentFrame);
  1974.  
  1975.         FLOAT ZBiasHack=((GUglyHackFlags&1)&&ViewportColorBits==16 )? 0.25f : 1.0f;
  1976.  
  1977.         int VertexCount=QueuedPolygonCount*3;
  1978.         verify(VertexCount<=ACTORPOLY_VERTEXBUFFER_SIZE);
  1979.         clock(Stats.D3DVertexLock);
  1980.  
  1981.         FD3DTLVertex *Vertex = (FD3DTLVertex*)ActorVertices.Lock(VertexCount);
  1982.         Stats.VBLocks++;
  1983.         unclock(Stats.D3DVertexLock);
  1984.  
  1985.         clock(Stats.D3DVertexSetup);
  1986.  
  1987.         INT  n = 0;
  1988.         BOOL StoreVert = (ProjectorArray.Num() > 0 && CurrentFrame->Recursion == 0 && ProjectorFlags) ? true : false;
  1989.  
  1990.         for(int i=0;i<QueuedPolygonCount;i++)
  1991.         {
  1992.             QueuedPolygon &p=QueuedPolygons(i);            
  1993.  
  1994.             SetTexture(0,*p.Texture, p.PolyFlags, false,p.PolyFlagsEx );    // NJS: Fixme! No need for texture set to be here other than to compute scaling factors
  1995.  
  1996.             UBOOL DoFog=((p.PolyFlags&(PF_RenderFog|PF_Translucent|PF_Modulated))==PF_RenderFog);      
  1997.  
  1998.             for( INT Index = 0; Index < 3; Index++ )
  1999.             {  
  2000.                 FD3DTLVertex V;
  2001.                 FLOAT   RHW = ZBiasHack * p.v[Index].RZ * CurrentFrame->RProj.Z;
  2002.  
  2003.                 V.Position.X = p.v[Index].ScreenX + CurrentFrame->XB - 0.5f;
  2004.                 V.Position.Y = p.v[Index].ScreenY + CurrentFrame->YB - 0.5f;
  2005.                 V.Position.Z = ProjectionMatrix._33 + ProjectionMatrix._43 * RHW;
  2006.                 V.Position.W = RHW;
  2007.  
  2008.                 // JEP...
  2009.                 if (StoreVert)
  2010.                 {
  2011.                     Verts[n].Position.X = V.Position.X;
  2012.                     Verts[n].Position.Y = V.Position.Y;
  2013.                     Verts[n].Position.Z = V.Position.Z;
  2014.                     Verts[n].Position.W = V.Position.W;
  2015.                     n++;
  2016.                 }
  2017.                 // JEP...
  2018.  
  2019.                 V.U[0] = p.v[Index].U * Stages[0]->UScale;
  2020.                 V.U[1] = p.v[Index].V * Stages[0]->VScale;
  2021.  
  2022.                 V.Specular=0;
  2023.                 if(p.PolyFlagsEx&(PFX_LightenModulate|PFX_DarkenModulate))
  2024.                 {
  2025.                     V.Diffuse  = 0xffffffff;
  2026.  
  2027.                 }
  2028.                 else if ( p.PolyFlags & PF_Modulated )
  2029.                 {
  2030.                     // NJS: Diffuse is scaled down to compensate for the fact that the src=dst dst=src blending
  2031.                     // mode doesn't work so well with 16 bit textures.  Thus to fix it, we lighten the texture
  2032.                     // up by one, and then drop it down here to compensate.  Doing this allows us to hit 127 exactly.
  2033.                     V.Diffuse = (0xFF<<24)|(248<<16)|(248<<8)|248;
  2034.                     //V.Diffuse = 0xffffffff;
  2035.                 }
  2036.                 else if ( DoFog )
  2037.                 {
  2038.                     FLOAT W=1.f-p.v[Index].Fog.W;
  2039.  
  2040.                     check(Stages[0]);
  2041.                     V.Diffuse=FColor((p.v[Index].Light.Z*Stages[0]->MaxColor.B*W)
  2042.                                      (p.v[Index].Light.Y*Stages[0]->MaxColor.G*W),
  2043.                                      (p.v[Index].Light.X*Stages[0]->MaxColor.R*W),
  2044.                                      255);
  2045.                 }
  2046.                 else
  2047.                 {
  2048.                     check(Stages[0]);
  2049.                     V.Diffuse=FColor((p.v[Index].Light.Z*Stages[0]->MaxColor.B),
  2050.                                      (p.v[Index].Light.Y*Stages[0]->MaxColor.G),
  2051.                                      (p.v[Index].Light.X*Stages[0]->MaxColor.R),
  2052.                                      255);
  2053.                 }
  2054.  
  2055.                 *Vertex=V;
  2056.                 Vertex++;
  2057.  
  2058.             }
  2059.         }
  2060.         unclock(Stats.D3DVertexSetup);
  2061.  
  2062.         SetTextureNULL(0);
  2063.         SetTextureNULL(1);
  2064.         SetZBias(0);
  2065.  
  2066.         clock(Stats.D3DVertexRender);
  2067.         INT First = ActorVertices.Unlock();
  2068.         ActorVertices.Set();
  2069.        
  2070.         bool CurrentDoFog=false;
  2071.         for(i=0;i<QueuedPolygonCount;)
  2072.         {
  2073.             QueuedPolygon &p=QueuedPolygons(i);
  2074.             // Set the polygon texture.
  2075.  
  2076.             SetTexture(0,*p.Texture, p.PolyFlags, false, p.PolyFlagsEx );  
  2077.             SetBlending(p.PolyFlags,p.PolyFlagsEx);
  2078.             //SetBlending(PF_Translucent,0);
  2079.             //SetBlending(p.PolyFlags,0);
  2080.  
  2081.             SetDistanceFog(!(p.PolyFlags&PF_Unlit));
  2082.  
  2083.             // Set the correct fog mode:
  2084.             UBOOL DoFog=((p.PolyFlags&(PF_RenderFog|PF_Translucent|PF_Modulated))==PF_RenderFog);      
  2085.  
  2086.             if(DoFog&&(!CurrentDoFog))
  2087.             {
  2088.                 CurrentDoFog=true;
  2089.                 Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_SPECULAR );          
  2090.                 Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_ADD );
  2091.             } else if((!DoFog)&&CurrentDoFog)
  2092.             {
  2093.                 CurrentDoFog=false;
  2094.                 Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  2095.                 Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
  2096.             }
  2097.            
  2098.             // Set the correct clamping mode:
  2099.             SetTextureClampMode((p.PolyFlags & PF_MeshUVClamp)?1:0);
  2100.  
  2101.             // See how many of my sucessor polys share my attributes, and draw them as well:
  2102.             for(int j=i+1;j<QueuedPolygonCount;j++)
  2103.             {
  2104.                 if(p.PolyFlags!=QueuedPolygons(j).PolyFlags)     break;
  2105.                 if(p.PolyFlagsEx!=QueuedPolygons(j).PolyFlagsEx) break;
  2106.                 if(p.Texture!=QueuedPolygons(j).Texture)         break;
  2107.             }
  2108.             int count=j-i;
  2109.             Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLELIST, First+(i*3), count );
  2110.             i+=count;
  2111.         }
  2112.  
  2113.         SetDistanceFog(true);
  2114.         SetTextureClampMode(0);
  2115.  
  2116.         if(CurrentDoFog==true)
  2117.         {
  2118.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
  2119.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  2120.         }
  2121.  
  2122.         RenderQueuedPolygonsForProjectors(ProjectorFlags);      // JEP
  2123.  
  2124.         QueuedPolygons.Clear();
  2125.  
  2126.         // Terminate polygon clipping:
  2127.         unclock(Stats.D3DVertexRender);
  2128.         unclock(Stats.PolyTime);
  2129.     }
  2130.  
  2131.     void __fastcall QueuePolygon( FTextureInfo* Info, FTransTexture** Pts, INT NumPts, DWORD PolyFlags, DWORD ExFlags, FSpanBuffer *Span )
  2132.     {
  2133.         if(!RenderMeshes)
  2134.             return;
  2135.  
  2136.         clock(Stats.QueueTime);
  2137.         clock(Stats.PolyTime);
  2138.  
  2139.         if(PolyFlags&PF_Masked) Stats.MaskedPolys++;
  2140.  
  2141.         QueuedPolygon &p=QueuedPolygons(QueuedPolygons.Add());
  2142.         p.PolyFlags=PolyFlags&(~PF_Memorized);
  2143.         p.PolyFlagsEx=ExFlags|PFX_Clip;
  2144.         p.Texture=Info;
  2145.  
  2146.         memcpy(&p.v[0],Pts[0],sizeof(FTransTexture));
  2147.         memcpy(&p.v[1],Pts[1],sizeof(FTransTexture));
  2148.         memcpy(&p.v[2],Pts[2],sizeof(FTransTexture));
  2149.        
  2150.         unclock(Stats.PolyTime);
  2151.         unclock(Stats.QueueTime);
  2152.     }
  2153.    
  2154.     bool __fastcall QueuePolygonBeginFast(FSceneNode* Frame)
  2155.     {
  2156.         CurrentFrame=Frame;
  2157.         return true;
  2158.     }
  2159.  
  2160.     void __fastcall QueuePolygonFast(FTransTexture** Pts, INT NumPts)
  2161.     {
  2162.         clock(Stats.QueueTime);
  2163.         clock(Stats.PolyTime);
  2164.  
  2165.         QueuedPolygon &p=QueuedPolygons(QueuedPolygons.Add());
  2166.  
  2167.         memcpy(&p.v[0],Pts[0],sizeof(FTransTexture));
  2168.         memcpy(&p.v[1],Pts[1],sizeof(FTransTexture));
  2169.         memcpy(&p.v[2],Pts[2],sizeof(FTransTexture));
  2170.        
  2171.         unclock(Stats.PolyTime);
  2172.         unclock(Stats.QueueTime);
  2173.     }
  2174.  
  2175.     #define PROJECT_VERT(p, pProj, V)                               \
  2176.     {                                                               \
  2177.         FTransform      P;                                          \
  2178.         /* Transform point into projector space */                  \
  2179.         P.Point = p.TransformPointBy(pProj->CameraToLight);         \
  2180.         P.Point.Z = max(1.0f, P.Point.Z);                           \
  2181.         /* Project point onto projector front plane */              \
  2182.         P.Project(pProj->Frame);                                    \
  2183.         V->U[0] = P.ScreenX*pProjector->OneOverX;                   \
  2184.         V->U[1] = P.ScreenY*pProjector->OneOverY;                   \
  2185.         V->Position.W *= P.Point.Z;                                 \
  2186.         FLOAT R = P.RZ * pProj->Frame->RProj.Z;                     \
  2187.         /* Clip and fade out (this is the UV's for the clipper/fade out texture layer) */   \
  2188.         V->U2[0] = (pProj->_33 + pProj->_43 * R)*pProj->FadeScale;  \
  2189.         V->U2[1] = 0.0f;                                            \
  2190.     }                                                               \
  2191.  
  2192.     void __fastcall QueuePolygonEndFast()
  2193.     {
  2194.         VALIDATE;
  2195.         int QueuedPolygonCount=QueuedPolygons.Num();
  2196.  
  2197.         if(!QueuedPolygonCount)
  2198.             return;
  2199.  
  2200.         check(Direct3DDevice8);
  2201.  
  2202.         clock(Stats.PolyTime);
  2203.         Stats.QueueCount++;
  2204.         Stats.Polys+=QueuedPolygonCount;
  2205.  
  2206.         PreRender(CurrentFrame);
  2207.  
  2208.         int VertexCount=QueuedPolygonCount*3;
  2209.         verify(VertexCount<=ACTORPOLY_VERTEXBUFFER_SIZE);
  2210.  
  2211.         //Direct3DDevice8->SetRenderState( D3DRS_ZFUNC, D3DCMP_ALWAYS );
  2212.  
  2213.         clock(Stats.D3DVertexLock);
  2214.         FD3DTLVertex *Vertex = (FD3DTLVertex*)ActorVertices.Lock(VertexCount);
  2215.         Stats.VBLocks++;
  2216.         unclock(Stats.D3DVertexLock);
  2217.  
  2218.         clock(Stats.D3DVertexSetup);
  2219.         for(int i=0;i<QueuedPolygonCount;i++)
  2220.         {
  2221.             QueuedPolygon &p=QueuedPolygons(i);            
  2222.  
  2223.             for( INT Index = 0; Index < 3; Index++ )
  2224.             {  
  2225.                 FD3DTLVertex    V;
  2226.  
  2227.                 V.Position.X = p.v[Index].ScreenX + CurrentFrame->XB - 0.5f;
  2228.                 V.Position.Y = p.v[Index].ScreenY + CurrentFrame->YB - 0.5f;
  2229.  
  2230.  
  2231.                 if (V.Position.X < CurrentFrame->XB)
  2232.                     V.Position.X = CurrentFrame->XB;
  2233.                 else if (V.Position.X > CurrentFrame->X)
  2234.                     V.Position.X = CurrentFrame->X;
  2235.  
  2236.                 if (V.Position.Y < CurrentFrame->YB)
  2237.                     V.Position.Y = CurrentFrame->YB;
  2238.                 else if (V.Position.Y > CurrentFrame->Y)
  2239.                     V.Position.Y = CurrentFrame->Y;
  2240.  
  2241.                 V.Position.Z = 1.0f;
  2242.                 V.Position.W = 1.0f;
  2243.  
  2244.                 V.Specular=0;
  2245.                
  2246.                 #define SHADOW_VAL      (0)
  2247.  
  2248.                 V.Diffuse  = (SHADOW_VAL<<16) | (SHADOW_VAL<<8) | SHADOW_VAL;
  2249.  
  2250.                 *Vertex=V;
  2251.                 Vertex++;
  2252.  
  2253.             }
  2254.         }
  2255.         unclock(Stats.D3DVertexSetup);
  2256.  
  2257.         SetTextureNULL( 0 );
  2258.  
  2259.         clock(Stats.D3DVertexRender);
  2260.         INT First = ActorVertices.Unlock();
  2261.         ActorVertices.Set();
  2262.        
  2263.         SetZBias(0);
  2264.         SetDistanceFog(false);
  2265.         SetBlending();
  2266.        
  2267.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  2268.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
  2269.  
  2270.         // Turn off zbuffering
  2271.         Direct3DDevice8->SetRenderState( D3DRS_ZFUNC, D3DCMP_ALWAYS);
  2272.        
  2273.         // Draw the VB
  2274.         //Direct3DDevice8->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
  2275.         Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLELIST, First, QueuedPolygonCount);
  2276.         //Direct3DDevice8->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
  2277.        
  2278.         // Turn zbuffering back on
  2279.         Direct3DDevice8->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESSEQUAL );
  2280.  
  2281.         SetDistanceFog(true);
  2282.         SetTextureClampMode(0);
  2283.  
  2284.         QueuedPolygons.Clear();
  2285.  
  2286.         // Terminate polygon clipping:
  2287.         unclock(Stats.D3DVertexRender);
  2288.         unclock(Stats.PolyTime);
  2289.     }
  2290.  
  2291.     void RenderQueuedPolygonsForProjectors(DWORD ProjectorFlags)
  2292.     {
  2293.         int QueuedPolygonCount=QueuedPolygons.Num();
  2294.  
  2295.         if(!QueuedPolygonCount)
  2296.             return;
  2297.        
  2298.         int VertexCount=QueuedPolygonCount*3;
  2299.         verify(VertexCount<=ACTORPOLY_VERTEXBUFFER_SIZE);
  2300.  
  2301.         if (ProjectorArray.Num() <= 0 || CurrentFrame->Recursion != 0 || !ProjectorFlags)
  2302.             return;         // No projectors to check
  2303.  
  2304.         // Setup projector render states
  2305.         SetTextureNULL( 0 );
  2306.         SetTextureNULL( 1 );
  2307.         SetBlending( PF_Modulated );
  2308.         SetDistanceFog(false);
  2309.  
  2310.         SetTextureClampMode(1);
  2311.  
  2312.         //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  2313.         //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR );
  2314.         //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
  2315.         SetAlphaBlendEnable(TRUE);
  2316.         SetSrcBlend(D3DBLEND_DESTCOLOR);
  2317.         SetDstBlend(D3DBLEND_ZERO);
  2318.     #if 1
  2319.         // Setup clipper texture (also used for fade out)
  2320.         Direct3DDevice8->SetTexture(1, ClipperTexture);
  2321.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  2322.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_ADD);
  2323.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
  2324.  
  2325.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP );
  2326.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP );
  2327.  
  2328.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_POINT);
  2329.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_POINT);
  2330.     #endif
  2331.            
  2332.         for (int p=ProjectorArray.Num()-1; p>=0 ; p--)
  2333.         {
  2334.             DWORD       Mask = 1<<p;
  2335.  
  2336.             if (!(Mask & ProjectorFlags))
  2337.                 continue;
  2338.  
  2339.             ProjectorInfo *pProjector = &ProjectorArray(p);
  2340.  
  2341.             // Set the texture to the render target that belongs to this projector
  2342.             Direct3DDevice8->SetTexture(0, pProjector->pRenderTargetTex);
  2343.  
  2344.             // Fill up the VB with the verts for this projector
  2345.             clock(Stats.D3DVertexLock);
  2346.             FD3DTLVertex *Vertex = (FD3DTLVertex*)ActorVertices.Lock(VertexCount);
  2347.             Stats.VBLocks++;
  2348.             unclock(Stats.D3DVertexLock);
  2349.  
  2350.             clock(Stats.D3DVertexSetup);
  2351.  
  2352.             INT n = 0, NumMaskedPolys = 0;
  2353.  
  2354.             for(int i=0;i<QueuedPolygonCount;i++)
  2355.             {
  2356.                 QueuedPolygon &p=QueuedPolygons(i);            
  2357.  
  2358.                 if (p.PolyFlags&PF_Masked)
  2359.                     NumMaskedPolys++;
  2360.  
  2361.                 for( INT Index = 0; Index < 3; Index++, n++)
  2362.                 {  
  2363.                     Vertex->Position.X = Verts[n].Position.X;
  2364.                     Vertex->Position.Y = Verts[n].Position.Y;
  2365.                     Vertex->Position.Z = Verts[n].Position.Z;
  2366.                     Vertex->Position.W = Verts[n].Position.W;
  2367.            
  2368.                     Vertex->Specular = 0;
  2369.                     Vertex->Diffuse  = 0xffffffff;
  2370.  
  2371.                     //PROJECT_VERT(p.v[Index].Point, pProjector, Vertex);
  2372.  
  2373.                     // Grab a copy of the vert
  2374.                     FTransform      P;
  2375.  
  2376.                     // Transform point into projector space
  2377.                     P.Point = p.v[Index].Point.TransformPointBy(pProjector->CameraToLight);
  2378.                        
  2379.                     // Project point onto projector front plane
  2380.                     P.Point.Z = max(1.0f, P.Point.Z);
  2381.                     P.Project(pProjector->Frame);
  2382.  
  2383.                     // Snag UV's
  2384.                     Vertex->U[0] = P.ScreenX*pProjector->OneOverX;
  2385.                     Vertex->U[1] = P.ScreenY*pProjector->OneOverY;
  2386.                        
  2387.                     Vertex->Position.W *= P.Point.Z;
  2388.  
  2389.                     // Clip and fade out (this is the UV's for the clipper/fade out texture layer)
  2390.                 #if 1
  2391.                     FLOAT R = P.RZ * pProjector->Frame->RProj.Z;        // (1.0f/Z)
  2392.                     Vertex->U2[0] = (pProjector->_33 + pProjector->_43 * R)*pProjector->FadeScale;
  2393.                     Vertex->U2[1] = 0.0f;
  2394.                 #endif
  2395.            
  2396.                     Vertex++;
  2397.                 }
  2398.             }
  2399.             unclock(Stats.D3DVertexSetup);
  2400.  
  2401.             INT First = ActorVertices.Unlock();
  2402.             ActorVertices.Set();
  2403.        
  2404.             // If we have some masked polygons, we have to seperate them out, and compare only equal zbuffer values
  2405.             //  This way, we don't see shadows in mid-air (shadows being projected onto the invisible parts of textures)
  2406.             if (NumMaskedPolys)
  2407.             {
  2408.                 for(i=0;i<QueuedPolygonCount;)
  2409.                 {
  2410.                     QueuedPolygon &p=QueuedPolygons(i);
  2411.  
  2412.                     for(int j=i+1;j<QueuedPolygonCount;j++)
  2413.                     {
  2414.                         if ((p.PolyFlags&PF_Masked) != (QueuedPolygons(j).PolyFlags&PF_Masked))
  2415.                             break;
  2416.                     }
  2417.                
  2418.                     INT Count = j-i;
  2419.  
  2420.                     // Handle masked polygons
  2421.                     if (p.PolyFlags & PF_Masked)
  2422.                         Direct3DDevice8->SetRenderState( D3DRS_ZFUNC, D3DCMP_EQUAL );
  2423.  
  2424.                     Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLELIST, First+(i*3), Count);
  2425.                
  2426.                     // Finish masked polygons
  2427.                     if (p.PolyFlags & PF_Masked)
  2428.                         Direct3DDevice8->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESSEQUAL );
  2429.                    
  2430.                     i += Count;
  2431.                 }
  2432.             }
  2433.             else
  2434.             {
  2435.                 // Draw the entire VB (no masked polygons)
  2436.                 Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLELIST, First, QueuedPolygonCount);
  2437.             }
  2438.         }
  2439.  
  2440.         // Restore render states
  2441.         Direct3DDevice8->SetTexture(0, NULL);
  2442.  
  2443.         //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  2444.         //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR );
  2445.         //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR );
  2446.         SetAlphaBlendEnable(TRUE);
  2447.         SetSrcBlend(D3DBLEND_DESTCOLOR);
  2448.         SetDstBlend(D3DBLEND_SRCCOLOR);
  2449.  
  2450.         Direct3DDevice8->SetTexture(1, NULL);
  2451.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  2452.  
  2453.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  2454.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  2455.  
  2456.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP );
  2457.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP );
  2458.  
  2459.         SetDistanceFog(true);
  2460.         SetTextureClampMode(0);
  2461.     }
  2462.  
  2463.     // NJS: FIXME: Still needed for to keep world decals working correctly:
  2464.     void __fastcall DrawGouraudPolygon( FSceneNode* Frame, FTextureInfo& Info, FTransTexture** Pts, INT NumPts, DWORD PolyFlags, FSpanBuffer* Span, DWORD PolyFlagsEx )
  2465.     {
  2466.         if(!RenderMeshes)
  2467.             return;
  2468.  
  2469.         clock(Stats.PolyTime);
  2470.  
  2471.         Stats.Polys++;
  2472.         if(PolyFlags&PF_Masked) Stats.MaskedPolys++;
  2473.  
  2474.         UBOOL DoFog=((PolyFlags&(PF_RenderFog|PF_Translucent|PF_Modulated))==PF_RenderFog);    
  2475.  
  2476.         // Set up vertices.
  2477.         PolyFlags&=(~PF_Memorized)/*&(~PF_Selected)*/;
  2478.  
  2479.         // Set the polygon texture.
  2480.         PolyFlags|=PF_TwoSided;   // NJS: Hack, shouldn't have to do this.
  2481.         PolyFlagsEx|=PFX_Clip;
  2482.  
  2483.         SetBlending( PolyFlags, PolyFlagsEx );     
  2484.         SetTexture(0,Info,PolyFlags,0, PolyFlagsEx);
  2485.         SetZBias(0);
  2486.  
  2487.  
  2488.  
  2489.         if(PolyFlags&PF_Unlit) SetDistanceFog(false);
  2490.         else                   SetDistanceFog(true);
  2491.  
  2492.         // Kludge for 16-bit zbuffer limitations - compress weapon in 1/z space.
  2493.         // "Have HUD draw the player's weapon on top (and any other overlays which should happen before screen flashes)"
  2494.         FLOAT ZBiasHack = ( (GUglyHackFlags&1) && ViewportColorBits==16 )? 0.25f : 1.0f;
  2495.  
  2496.         FTransTexture** SourceVertex;
  2497.         FD3DTLVertex*   Vertex = (FD3DTLVertex*) ActorVertices.Lock(NumPts);
  2498.  
  2499.         SourceVertex = Pts;
  2500.  
  2501.         for( INT Index = 0; Index < NumPts; Index++ )
  2502.         {  
  2503.             FLOAT   RHW = ZBiasHack * (*SourceVertex)->RZ * Frame->RProj.Z;
  2504.  
  2505.             Vertex->Position.X = (*SourceVertex)->ScreenX + Frame->XB - 0.5f;
  2506.             Vertex->Position.Y = (*SourceVertex)->ScreenY + Frame->YB - 0.5f;
  2507.             Vertex->Position.Z = ProjectionMatrix._33 + ProjectionMatrix._43 * RHW;
  2508.             Vertex->Position.W = RHW;
  2509.  
  2510.             Vertex->U[0] = (*SourceVertex)->U * Stages[0]->UScale;
  2511.             Vertex->U[1] = (*SourceVertex)->V * Stages[0]->VScale;
  2512.  
  2513.             Vertex->Specular=0;
  2514.             if(PolyFlagsEx&(PFX_LightenModulate|PFX_DarkenModulate))
  2515.             {
  2516.                 Vertex->Diffuse  = 0xffffffff;
  2517.  
  2518.             } else
  2519.             if ( PolyFlags & PF_Modulated )
  2520.             {
  2521.                 Vertex->Diffuse = (0xFF<<24)|(248<<16)|(248<<8)|248;
  2522.             }
  2523.             else if ( DoFog )
  2524.             {
  2525.                 FLOAT W = 1.f - (*SourceVertex)->Fog.W;
  2526.  
  2527.                 Vertex->Diffuse  = FColor(
  2528.                     appRound((*SourceVertex)->Light.Z*Stages[0]->MaxColor.B*W),
  2529.                     appRound((*SourceVertex)->Light.Y*Stages[0]->MaxColor.G*W),
  2530.                     appRound((*SourceVertex)->Light.X*Stages[0]->MaxColor.R*W),
  2531.                     255 );             
  2532.             }
  2533.             else
  2534.             {
  2535.                 Vertex->Diffuse  = FColor(
  2536.                     appRound((*SourceVertex)->Light.Z*Stages[0]->MaxColor.B),
  2537.                     appRound((*SourceVertex)->Light.Y*Stages[0]->MaxColor.G),
  2538.                     appRound((*SourceVertex)->Light.X*Stages[0]->MaxColor.R),
  2539.                     255 );
  2540.                 Vertex->Specular = 0;
  2541.             }
  2542.  
  2543.             Vertex++;
  2544.             SourceVertex++;
  2545.         }
  2546.  
  2547.         INT First = ActorVertices.Unlock();
  2548.  
  2549.  
  2550.         ActorVertices.Set();
  2551.  
  2552.         if(PolyFlags & PF_MeshUVClamp)
  2553.         {
  2554.             SetTextureClampMode(1);
  2555.         }
  2556.        
  2557.         if ( DoFog )
  2558.         {
  2559.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_SPECULAR );          
  2560.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_ADD );
  2561.  
  2562.             Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN, First, NumPts - 2 );
  2563.  
  2564.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
  2565.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  2566.         }
  2567.         else
  2568.             Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN, First, NumPts - 2 );
  2569.  
  2570.  
  2571.         if(PolyFlags & PF_MeshUVClamp)
  2572.             SetTextureClampMode(0);
  2573.  
  2574.         //SetBlending();
  2575.         unclock(Stats.PolyTime);
  2576.     }
  2577.     __forceinline void RotateAboutOrigin2D(float originX, float originY, float &x, float &y, float theta)
  2578.     {
  2579.         float xTick, yTick;
  2580.         x-=originX; y-=originY;
  2581.         xTick = ((GMath.CosFloat(theta)*x) - (GMath.SinFloat(theta)*y));
  2582.         yTick = ((GMath.SinFloat(theta)*x) + (GMath.CosFloat(theta)*y));
  2583.         x=xTick+originX; y=yTick+originY;
  2584.     }
  2585.  
  2586.     // Modify the texture clamp mode:
  2587.     void __fastcall SetTextureClampMode( INT Mode )
  2588.     {
  2589.         if(TextureClampMode!=Mode)
  2590.         {
  2591.             TextureClampMode=Mode;
  2592.             D3DTEXTUREADDRESS TextureMode=(Mode==1)?D3DTADDRESS_CLAMP:D3DTADDRESS_WRAP;
  2593.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ADDRESSU, TextureMode );
  2594.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ADDRESSV, TextureMode );
  2595.         }
  2596.     }
  2597.  
  2598.     void __fastcall DrawTile(FSceneNode* Frame,
  2599.                              FTextureInfo& Info,
  2600.                              FLOAT X, FLOAT Y,
  2601.                              FLOAT XL, FLOAT YL,
  2602.                              FLOAT U, FLOAT V,
  2603.                              FLOAT UL, FLOAT VL,
  2604.                              class FSpanBuffer* Span,
  2605.                              FLOAT Z,
  2606.                              FPlane InColor, FPlane Fog,
  2607.                              DWORD PolyFlags,
  2608.                              DWORD PolyFlagsEx,
  2609.                              FLOAT alpha,
  2610.                              FLOAT rot,
  2611.                              FLOAT rotationOffsetX,
  2612.                              FLOAT rotationOffsetY
  2613.     )
  2614.     {
  2615.         // Exclude tiles from rendering?
  2616.         if(!RenderTiles)
  2617.             return;
  2618.  
  2619.         clock(Stats.TileTime);
  2620.         Stats.Tiles++;          // Keep track of tiles rendered.
  2621.         SetDistanceFog(false);
  2622.  
  2623.  
  2624.         //PolyFlags  =PF_TwoSided | PF_NoOcclude ;
  2625.         //PolyFlagsEx=PFX_Translucent2;
  2626.  
  2627.         //alpha=Clamp<float>(appSin(appSeconds()),0,1);
  2628.  
  2629.  
  2630.         PolyFlags&=~(PF_Memorized/*|PF_Selected*/);     // Remove multitexture and editor flags.
  2631.         if(!GIsEditor) PolyFlags&=~PF_Selected; // NJS: test this and take teh PF_Selected out the above.
  2632.  
  2633.  
  2634.         if( Info.Palette && Info.Palette[128].A!=255 && !(PolyFlags&PF_Translucent) )
  2635.             PolyFlags |= PF_Highlighted;
  2636.  
  2637.         if(alpha!=1.f)
  2638.         {
  2639.             if(!(PolyFlags&PF_Translucent)
  2640.              &&!(PolyFlagsEx&PFX_Translucent2))
  2641.                 PolyFlags|=PF_Translucent;
  2642.         }
  2643.  
  2644.         PolyFlags|=PF_TwoSided;
  2645.         PolyFlagsEx|=PFX_Clip|Info.Texture->PolyFlagsEx;
  2646.    
  2647.         if(PolyFlagsEx&PFX_AlphaMap)
  2648.         {
  2649.             PolyFlags&=~PF_Translucent;
  2650.             PolyFlags&=~PF_Modulated;
  2651.             if(!GIsEditor) PolyFlags&=~PF_Highlighted;
  2652.             PolyFlagsEx&=~(PFX_Translucent2|PFX_LightenModulate|PFX_DarkenModulate);
  2653.         }
  2654.  
  2655.         SetBlending(PolyFlags,PolyFlagsEx);
  2656.         SetTexture(0,Info,PolyFlags,0,PolyFlagsEx);
  2657.        
  2658.         // Offset points to guarantee that we will sample directly from the center of the texture pixels
  2659.         X += Frame->XB - 0.5f;
  2660.         Y += Frame->YB - 0.5f;
  2661.  
  2662.         // NJS: Hack to compensate for the fact that software was depending on wrap around integer arithmetic:
  2663.         if(GIsEditor)
  2664.         {
  2665.             if(Z==0.f)  Z+=2000;
  2666.             if(Z<0)     Z*=-1;
  2667.         }
  2668.  
  2669.         FColor          Color = (PolyFlagsEx & (PFX_LightenModulate|PFX_DarkenModulate)) ? FColor(255,255,255,255) : FColor(Stages[0]->MaxColor.Plane() * InColor);
  2670.         if(PolyFlags&PF_Modulated) Color = (0xFF<<24)|(248<<16)|(248<<8)|248;
  2671.  
  2672.         FLOAT           RZ = 1.f/Z,
  2673.                         SZ = ProjectionMatrix._33 + ProjectionMatrix._43 * RZ;
  2674.         FD3DTLVertex*   Vertices = (FD3DTLVertex*) ActorVertices.Lock(4);
  2675.  
  2676.         DWORD dwDiffuse;
  2677.         if(alpha!=1.f/*&&(!(PolyFlagsEx&PFX_AlphaMap))*/)
  2678.         {
  2679.             DWORD R=Stages[0]->MaxColor.R*alpha*InColor.X,
  2680.                   G=Stages[0]->MaxColor.G*alpha*InColor.Y,
  2681.                   B=Stages[0]->MaxColor.B*alpha*InColor.Z,
  2682.                   A=Stages[0]->MaxColor.A*alpha; // *InColor.X
  2683.            
  2684.             if(R>Stages[0]->MaxColor.R) R=Stages[0]->MaxColor.R;
  2685.             if(G>Stages[0]->MaxColor.G) G=Stages[0]->MaxColor.G;
  2686.             if(B>Stages[0]->MaxColor.B) B=Stages[0]->MaxColor.B;
  2687.             if(A>Stages[0]->MaxColor.A) A=Stages[0]->MaxColor.A;
  2688.  
  2689.             dwDiffuse=D3DCOLOR_RGBA(R,G,B,A);
  2690.         } else
  2691.         {
  2692.             dwDiffuse=Color.TrueColor()|0xFF000000;
  2693.         }
  2694.  
  2695.         //dwDiffuse=0xFFFFFFFF;
  2696.         Vertices[0].Diffuse    = dwDiffuse;
  2697.         Vertices[0].Position.Z = SZ;
  2698.         Vertices[0].Position.W = RZ;
  2699.         Vertices[1].Diffuse    = dwDiffuse;
  2700.         Vertices[1].Position.Z = SZ;
  2701.         Vertices[1].Position.W = RZ;
  2702.         Vertices[2].Diffuse    = dwDiffuse;
  2703.         Vertices[2].Position.Z = SZ;
  2704.         Vertices[2].Position.W = RZ;
  2705.         Vertices[3].Diffuse    = dwDiffuse;
  2706.         Vertices[3].Position.Z = SZ;
  2707.         Vertices[3].Position.W = RZ;
  2708.  
  2709.         bool MirrorHoriz = ( PolyFlagsEx & PFX_MirrorHorizontal ) ? true : false,
  2710.              MirrorVert  = ( PolyFlagsEx & PFX_MirrorVertical )   ? true : false;
  2711.  
  2712.         if (MirrorHoriz && !MirrorVert)
  2713.         {
  2714.             Vertices[0].Position.X=X;    Vertices[0].Position.Y=Y;    Vertices[0].U[0]=U+UL; Vertices[0].U[1]=V;
  2715.             Vertices[1].Position.X=X;    Vertices[1].Position.Y=Y+YL; Vertices[1].U[0]=U+UL; Vertices[1].U[1]=V+VL;
  2716.             Vertices[2].Position.X=X+XL; Vertices[2].Position.Y=Y+YL; Vertices[2].U[0]=U;    Vertices[2].U[1]=V+VL;
  2717.             Vertices[3].Position.X=X+XL; Vertices[3].Position.Y=Y;    Vertices[3].U[0]=U;    Vertices[3].U[1]=V;
  2718.  
  2719.         } else if (MirrorVert && !MirrorHoriz)
  2720.         {
  2721.             Vertices[0].Position.X=X;    Vertices[0].Position.Y=Y;    Vertices[0].U[0]=U;       Vertices[0].U[1]=V+VL;
  2722.             Vertices[1].Position.X=X;    Vertices[1].Position.Y=Y+YL; Vertices[1].U[0]=U;       Vertices[1].U[1]=V;
  2723.             Vertices[2].Position.X=X+XL; Vertices[2].Position.Y=Y+YL; Vertices[2].U[0]=U+UL;    Vertices[2].U[1]=V;
  2724.             Vertices[3].Position.X=X+XL; Vertices[3].Position.Y=Y;    Vertices[3].U[0]=U+UL;    Vertices[3].U[1]=V+VL;
  2725.  
  2726.         } else if (MirrorHoriz && MirrorVert)
  2727.         {
  2728.             Vertices[0].Position.X=X;    Vertices[0].Position.Y=Y;    Vertices[0].U[0]=U+UL;    Vertices[0].U[1]=V+VL;
  2729.             Vertices[1].Position.X=X;    Vertices[1].Position.Y=Y+YL; Vertices[1].U[0]=U+UL;    Vertices[1].U[1]=V;
  2730.             Vertices[2].Position.X=X+XL; Vertices[2].Position.Y=Y+YL; Vertices[2].U[0]=U   ;    Vertices[2].U[1]=V;
  2731.             Vertices[3].Position.X=X+XL; Vertices[3].Position.Y=Y;    Vertices[3].U[0]=U   ;    Vertices[3].U[1]=V+VL;
  2732.  
  2733.         } else
  2734.         {
  2735.             Vertices[0].Position.X=X;    Vertices[0].Position.Y=Y;    Vertices[0].U[0]=U;       Vertices[0].U[1]=V   ;
  2736.             Vertices[1].Position.X=X;    Vertices[1].Position.Y=Y+YL; Vertices[1].U[0]=U;       Vertices[1].U[1]=V+VL;
  2737.             Vertices[2].Position.X=X+XL; Vertices[2].Position.Y=Y+YL; Vertices[2].U[0]=U+UL;    Vertices[2].U[1]=V+VL;
  2738.             Vertices[3].Position.X=X+XL; Vertices[3].Position.Y=Y;    Vertices[3].U[0]=U+UL;    Vertices[3].U[1]=V   ;
  2739.         }
  2740.  
  2741.         Vertices[0].U[0]*=Stages[0]->UScale;
  2742.         Vertices[0].U[1]*=Stages[0]->VScale;
  2743.         Vertices[1].U[0]*=Stages[0]->UScale;
  2744.         Vertices[1].U[1]*=Stages[0]->VScale;
  2745.         Vertices[2].U[0]*=Stages[0]->UScale;
  2746.         Vertices[2].U[1]*=Stages[0]->VScale;
  2747.         Vertices[3].U[0]*=Stages[0]->UScale;
  2748.         Vertices[3].U[1]*=Stages[0]->VScale;
  2749.  
  2750.         // NJS: Do I have rotation?
  2751.         if(rot)
  2752.         {
  2753.             float originX=(Vertices[0].Position.X+XL/2.f)+rotationOffsetX, originY=(Vertices[0].Position.Y+YL/2.f)+rotationOffsetY;
  2754.  
  2755.             for(int index=0;index<4;index++)
  2756.             {  
  2757.                 float x=Vertices[index].Position.X,
  2758.                       y=Vertices[index].Position.Y;
  2759.  
  2760.                 RotateAboutOrigin2D(originX,originY,x,y,rot);
  2761.                 Vertices[index].Position.X=x;
  2762.                 Vertices[index].Position.Y=y;
  2763.             }
  2764.         }
  2765.  
  2766.         INT First=ActorVertices.Unlock();
  2767.         ActorVertices.Set();
  2768.  
  2769.         Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN, First, 2 );
  2770.         unclock(Stats.TileTime);
  2771.     }
  2772.    
  2773.     void __fastcall RecursiveSubdivideLine(UCanvas *c, UTexture *t, FColor BeamColor, FColor BeamEndColor, FLOAT BeamStartWidth, FLOAT BeamEndWidth, DWORD PolyFlags, FLOAT MaxAmplitude, FVector LineStart, FVector LineEnd, FVector RangeStart, FVector RangeEnd, INT depth)
  2774.     {
  2775.         VALIDATE;
  2776.         verify(c);
  2777.         // Have I traversed to the lowest point?
  2778.         if(!depth)
  2779.         {
  2780.             // Draw the segment:
  2781.             dnDraw3DLine(c->Frame,t,PolyFlags,RangeStart,RangeEnd,BeamStartWidth,BeamEndWidth,BeamColor,BeamColor,true);
  2782.             return;
  2783.         }
  2784.  
  2785.         FVector Direction=RangeEnd-RangeStart;
  2786.         FVector Midpoint=RangeStart+(Direction/2);
  2787.        
  2788.         // Move the midpoint around randomly on the plane that the direction is the normal of.
  2789.         Direction=LineEnd-LineStart;
  2790.         Direction.Normalize();
  2791.  
  2792.         FVector Axis1, Axis2;
  2793.         Direction.FindBestAxisVectors( Axis1, Axis2 );
  2794.         Axis1.Normalize();
  2795.         Axis2.Normalize();
  2796.  
  2797.         Midpoint+=Axis1*(((MaxAmplitude*2)*appFrand())-MaxAmplitude);
  2798.         Midpoint+=Axis2*(((MaxAmplitude*2)*appFrand())-MaxAmplitude);
  2799.  
  2800.         FColor ColorMidpoint=BeamColor;
  2801.         ColorMidpoint.R+=(BeamEndColor.R-BeamColor.R)/2;
  2802.         ColorMidpoint.G+=(BeamEndColor.G-BeamColor.G)/2;
  2803.         ColorMidpoint.B+=(BeamEndColor.B-BeamColor.B)/2;
  2804.         ColorMidpoint.A+=(BeamEndColor.A-BeamColor.A)/2;
  2805.  
  2806.         // Delegate the rendering of the 2 line segments:
  2807.         RecursiveSubdivideLine(c,t,BeamColor,ColorMidpoint,BeamStartWidth, BeamEndWidth,PolyFlags,MaxAmplitude/2,LineStart,LineEnd,RangeStart,Midpoint,depth-1);
  2808.         RecursiveSubdivideLine(c,t,ColorMidpoint,BeamEndColor,BeamStartWidth, BeamEndWidth,PolyFlags,MaxAmplitude/2,LineStart,LineEnd,Midpoint,RangeEnd,depth-1);
  2809.     }
  2810.  
  2811.     void __fastcall SineWave(UCanvas *c, UTexture *t, FColor BeamColor, FColor BeamEndColor, FLOAT BeamStartWidth, FLOAT BeamEndWidth, DWORD PolyFlags, FLOAT MaxAmplitude, FLOAT MaxFrequency, FLOAT Noise, FLOAT TimeSeconds, FVector LineStart, FVector LineEnd, FVector RangeStart, FVector RangeEnd, INT depth,FLOAT TimeScale)
  2812.     {
  2813.         VALIDATE;
  2814.         int LineSegments=((int)appPow(2,depth))+1;
  2815.         FVector CurrentPosition=LineStart;
  2816.         FVector PreviousPosition=CurrentPosition;
  2817.         FVector Distance=LineEnd-LineStart;
  2818.         FVector Direction=Distance;
  2819.         Direction.Normalize();
  2820.         FLOAT Length=Distance.Size();
  2821.         FLOAT StepLength=Length/LineSegments;
  2822.  
  2823.         FVector Axis1, Axis2;
  2824.         Direction.FindBestAxisVectors( Axis1, Axis2 );
  2825.         Axis1.Normalize();
  2826.         Axis2.Normalize();
  2827.  
  2828.         FColor PreviousColor=BeamColor,
  2829.                CurrentColor=BeamColor;
  2830.  
  2831.         FLOAT RFactor=(((FLOAT)(BeamEndColor.R-BeamColor.R))/(FLOAT)LineSegments);
  2832.         FLOAT GFactor=(((FLOAT)(BeamEndColor.G-BeamColor.G))/(FLOAT)LineSegments);
  2833.         FLOAT BFactor=(((FLOAT)(BeamEndColor.B-BeamColor.B))/(FLOAT)LineSegments);
  2834.         FLOAT AFactor=(((FLOAT)(BeamEndColor.A-BeamColor.A))/(FLOAT)LineSegments);
  2835.  
  2836.         for(int i=0;i<LineSegments;i++)
  2837.         {
  2838.             FLOAT LengthToHere=(i*StepLength);
  2839.             CurrentPosition=LineStart+(LengthToHere*Direction);
  2840.            
  2841.             CurrentPosition+=(Axis1*(appSin(TimeSeconds*13*TimeScale+LengthToHere*MaxFrequency+appFrand()*Noise-(Noise/2))*MaxAmplitude));
  2842.             CurrentPosition+=(Axis2*(appCos(TimeSeconds*13*TimeScale+LengthToHere*MaxFrequency+appFrand()*Noise-(Noise/2))*MaxAmplitude));
  2843.  
  2844.             // Compute current color:
  2845.             CurrentColor=BeamColor;
  2846.             CurrentColor.R+=(int)(RFactor*i);
  2847.             CurrentColor.G+=(int)(GFactor*i);
  2848.             CurrentColor.B+=(int)(BFactor*i);
  2849.             CurrentColor.A+=(int)(AFactor*i);
  2850.  
  2851.             // Draw the line:
  2852.             dnDraw3DLine(c->Frame,t,PolyFlags,PreviousPosition,CurrentPosition,BeamStartWidth,BeamEndWidth,PreviousColor,CurrentColor,true);
  2853.  
  2854.             PreviousPosition=CurrentPosition;
  2855.             PreviousColor=CurrentColor;
  2856.         }
  2857.     }
  2858.  
  2859.     void __fastcall DoubleSineWave(UCanvas *c, UTexture *t, FColor BeamColor, FColor BeamEndColor, FLOAT BeamStartWidth, FLOAT BeamEndWidth, DWORD PolyFlags, FLOAT MaxAmplitude, FLOAT MaxFrequency, FLOAT Noise, FLOAT TimeSeconds, FVector LineStart, FVector LineEnd, FVector RangeStart, FVector RangeEnd, INT depth,FLOAT TimeScale)
  2860.     {
  2861.         int LineSegments=((int)appPow(2,depth))+1;
  2862.         FVector CurrentPosition=LineStart;
  2863.         FVector PreviousPosition=CurrentPosition;
  2864.         FVector Distance=LineEnd-LineStart;
  2865.         FVector Direction=Distance;
  2866.         Direction.Normalize();
  2867.         FLOAT Length=Distance.Size();
  2868.         FLOAT StepLength=Length/LineSegments;
  2869.  
  2870.         FVector Axis1, Axis2;
  2871.         Direction.FindBestAxisVectors(Axis1,Axis2);
  2872.         Axis1.Normalize();
  2873.         Axis2.Normalize();
  2874.  
  2875.         FColor PreviousColor=BeamColor,
  2876.                CurrentColor=BeamColor;
  2877.  
  2878.         FLOAT RFactor=(((FLOAT)(BeamEndColor.R-BeamColor.R))/(FLOAT)LineSegments);
  2879.         FLOAT GFactor=(((FLOAT)(BeamEndColor.G-BeamColor.G))/(FLOAT)LineSegments);
  2880.         FLOAT BFactor=(((FLOAT)(BeamEndColor.B-BeamColor.B))/(FLOAT)LineSegments);
  2881.         FLOAT AFactor=(((FLOAT)(BeamEndColor.A-BeamColor.A))/(FLOAT)LineSegments);
  2882.  
  2883.         for(int i=0;i<LineSegments;i++)
  2884.         {
  2885.             FLOAT LengthToHere=(i*StepLength);
  2886.             CurrentPosition=LineStart+(LengthToHere*Direction);
  2887.            
  2888.             FLOAT OriginalMaxAmplitude=MaxAmplitude;
  2889.             MaxAmplitude*=appSin(((FLOAT)i/(FLOAT)LineSegments)*10+TimeSeconds*4.5);
  2890.             CurrentPosition+=(Axis1*(appSin(TimeSeconds*13*TimeScale+LengthToHere*MaxFrequency+appFrand()*Noise-(Noise/2))*MaxAmplitude));
  2891.             CurrentPosition+=(Axis2*(appCos(TimeSeconds*13*TimeScale+LengthToHere*MaxFrequency+appFrand()*Noise-(Noise/2))*MaxAmplitude));
  2892.             MaxAmplitude=OriginalMaxAmplitude;
  2893.  
  2894.             // Compute current color:
  2895.             CurrentColor=BeamColor;
  2896.             CurrentColor.R+=(int)(RFactor*i);
  2897.             CurrentColor.G+=(int)(GFactor*i);
  2898.             CurrentColor.B+=(int)(BFactor*i);
  2899.             CurrentColor.A+=(int)(AFactor*i);
  2900.  
  2901.             // Draw the line:
  2902.             dnDraw3DLine(c->Frame,t,PolyFlags,PreviousPosition,CurrentPosition,BeamStartWidth,BeamEndWidth,PreviousColor,CurrentColor,true);
  2903.  
  2904.             PreviousPosition=CurrentPosition;
  2905.             PreviousColor=CurrentColor;
  2906.         }
  2907.     }
  2908.  
  2909.     float inline __fastcall SamplePoint(int x, int y,FLOAT MaxAmplitude, FLOAT MaxFrequency, FLOAT Noise,FLOAT TimeSeconds)
  2910.     {
  2911.         VALIDATE;
  2912.  
  2913.         FLOAT value=0;
  2914.        
  2915.         MaxFrequency*=8;
  2916.         value+=appSin(TimeSeconds*8+x*MaxFrequency)*MaxAmplitude;
  2917.        
  2918.         return value;
  2919.     }
  2920.  
  2921.     void __fastcall MovingGrid(UCanvas *c, UTexture *t, FColor BeamColor, FColor BeamEndColor, FLOAT BeamStartWidth, FLOAT BeamEndWidth, DWORD PolyFlags, FLOAT MaxAmplitude, FLOAT MaxFrequency, FLOAT Noise, FLOAT TimeSeconds, FVector LineStart, FVector LineEnd, INT Tesselation)
  2922.     {
  2923.         VALIDATE;
  2924.  
  2925.         FVector AxisZ=LineEnd-LineStart;
  2926.         FLOAT Length=AxisZ.Size();
  2927.         FLOAT LengthIncrement=Length/Tesselation;
  2928.         AxisZ.Normalize();
  2929.  
  2930.         FVector AxisX, AxisY;
  2931.         AxisZ.FindBestAxisVectors( AxisX, AxisY );
  2932.         AxisX.Normalize();
  2933.         AxisY.Normalize();
  2934.  
  2935.         FVector AxisXIncrement=AxisX*LengthIncrement;
  2936.         FVector AxisYIncrement=AxisY*LengthIncrement;
  2937.         for(INT x=0;x<Tesselation;x++)
  2938.         {
  2939.             FVector CurrentLocation=LineStart+(AxisXIncrement*(x-Tesselation/2.0f))-(AxisYIncrement*(Tesselation/2.0f));
  2940.             for(INT y=0;y<Tesselation;y++)
  2941.             {
  2942.                 FVector A=CurrentLocation;
  2943.                 A.Z+=SamplePoint(x,y,MaxAmplitude, MaxFrequency, Noise, TimeSeconds);
  2944.  
  2945.                 // Connect this point to it's four neighbors:
  2946.                 if(x!=Tesselation-1)
  2947.                 {
  2948.                     FVector B=CurrentLocation+AxisXIncrement;
  2949.                     B.Z+=SamplePoint(x+1,y,MaxAmplitude, MaxFrequency, Noise,TimeSeconds);
  2950.                     dnDraw3DLine(c->Frame,t,PolyFlags,A,B,BeamStartWidth,BeamEndWidth,BeamColor,BeamEndColor);
  2951.                 }
  2952.                 if(y!=Tesselation-1)
  2953.                 {
  2954.                     FVector B=CurrentLocation+AxisYIncrement;
  2955.                     B.Z+=SamplePoint(x,y+1,MaxAmplitude, MaxFrequency, Noise,TimeSeconds);
  2956.                     dnDraw3DLine(c->Frame,t,PolyFlags,A,B,BeamStartWidth,BeamEndWidth,BeamColor,BeamEndColor);
  2957.                 }
  2958.                 CurrentLocation+=AxisYIncrement;
  2959.             }
  2960.         }
  2961.     }
  2962.  
  2963.     void __fastcall DrawSpline(ABeamSystem &System, UCanvas *c, UTexture *t, FColor BeamColor, FColor BeamEndColor, FLOAT BeamStartWidth, FLOAT BeamEndWidth, DWORD PolyFlags, FLOAT MaxAmplitude, FLOAT MaxFrequency, FLOAT Noise, FLOAT TimeSeconds, FVector LineStart, FVector LineEnd, INT Tesselation)
  2964.     {
  2965.         VALIDATE;
  2966.         // Ensure that the beam is tesselated:
  2967.         if(System.TesselationLevel<=0)  return;
  2968.         if(System.ControlPointCount<=0) return;
  2969.  
  2970.         int i;
  2971.  
  2972.         // Update the positions of the control points based on their actor's positions (if any):
  2973.         for(i=0;i<ARRAY_COUNT(System.ControlPoint);i++)
  2974.             if(System.ControlPoint[i].PositionActor)
  2975.                 System.ControlPoint[i].Position=System.ControlPoint[i].PositionActor->Location;
  2976.  
  2977.  
  2978.         FVector PreviousLocation=System.ControlPoint[0].Position;
  2979.         FRotator Bogus=FRotator(0,0,0);
  2980.         FVector LastPoint=PreviousLocation;
  2981.         FVector NewLastPoint=PreviousLocation;
  2982.  
  2983.         for(i=0;i<System.ControlPointCount-1;i++)
  2984.         {
  2985.  
  2986.             FVector CurrentLocation=System.ControlPoint[i].Position;
  2987.             int k=i+1;
  2988.             if(k>=System.ControlPointCount) k=System.ControlPointCount-1;
  2989.             FVector NextLocation=System.ControlPoint[k].Position;
  2990.             k++;
  2991.             if(k>=System.ControlPointCount) k=System.ControlPointCount-1;
  2992.             FVector NextLocation1=System.ControlPoint[k].Position;
  2993.  
  2994.             for(int j=0;j<System.TesselationLevel;j++)
  2995.             {
  2996.                 KRSpline_Sample(((float)j/(float)System.TesselationLevel),
  2997.                                  NewLastPoint,    Bogus,
  2998.                                  PreviousLocation,Bogus,
  2999.                                  CurrentLocation, Bogus,
  3000.                                  NextLocation,    Bogus,
  3001.                                  NextLocation1,   Bogus);
  3002.  
  3003.                 dnDraw3DLine(c->Frame,t, 0,LastPoint,NewLastPoint,System.BeamStartWidth,System.BeamEndWidth,System.BeamColor,System.BeamEndColor,true);
  3004.  
  3005.                 LastPoint=NewLastPoint;
  3006.             }
  3007.        
  3008.             PreviousLocation=System.ControlPoint[i].Position;
  3009.         }
  3010.     }
  3011.  
  3012.     void __fastcall dnDrawBeam( ABeamSystem &System, FSceneNode *Frame )
  3013.     {
  3014.         VALIDATE;
  3015.  
  3016.         // Don't worry about it if not enabled:
  3017.         if(!System.Enabled) return;
  3018.  
  3019.         if(System.BeamType==BST_Spline) System.NumberDestinations=1;
  3020.  
  3021.         // Check to see if destination actor is valid:
  3022.         if(!System.NumberDestinations)
  3023.             return;
  3024.  
  3025.         // CDH... check to make sure camera style matches, if applicable
  3026.         if (!GIsEditor && System.BeamPlayerCameraStyleMode!=BPCS_None)
  3027.         {
  3028.             if ((System.BeamPlayerCameraStyleMode==BPCS_Equal) && (System.BeamPlayerCameraStyle!=Frame->Viewport->Actor->CameraStyle))
  3029.                 return;
  3030.             else if ((System.BeamPlayerCameraStyleMode==BPCS_NotEqual) && (System.BeamPlayerCameraStyle==Frame->Viewport->Actor->CameraStyle))
  3031.                 return;
  3032.         }
  3033.         // ...CDH
  3034.         clock(Stats.BeamTime);
  3035.  
  3036.         FLOAT TimeSeconds = System.Level->GameTimeSeconds;
  3037.         appSrand((*(DWORD *)&TimeSeconds)^((DWORD)&System));    // Makes the beams pausable, as they are based off of game time.
  3038.  
  3039.         UCanvas *c=Frame->Viewport->Canvas;
  3040.  
  3041.         PreRender(Frame);
  3042.  
  3043.         if(System.BeamStartWidth<1) System.BeamStartWidth=1;
  3044.         if(System.BeamEndWidth<1)   System.BeamEndWidth=1;
  3045.  
  3046.         if(System.TesselationLevel>16)     System.TesselationLevel=16;
  3047.         else if(System.TesselationLevel<1) System.TesselationLevel=1;
  3048.  
  3049.         System.BoundingBoxMin=System.Location-FVector(5,5,5);
  3050.         System.BoundingBoxMax=System.Location+FVector(5,5,5);
  3051.  
  3052.         // Force animated textures to update:
  3053.         UTexture *BeamTexture=System.BeamTexture;
  3054.         if(BeamTexture) BeamTexture=BeamTexture->Get(appSeconds());
  3055.  
  3056.         for(INT i=0;i<System.NumberDestinations;i++)
  3057.         {
  3058.             Stats.Beams++;
  3059.  
  3060.             FVector DestinationLocation;
  3061.             if(System.BeamType!=BST_Spline)
  3062.             {
  3063.                 DestinationLocation=System.DestinationActor[i]->Location + System.DestinationOffset[i];
  3064.  
  3065.                      if(DestinationLocation.X<System.BoundingBoxMin.X) System.BoundingBoxMin.X=DestinationLocation.X;
  3066.                 else if(DestinationLocation.X>System.BoundingBoxMax.X) System.BoundingBoxMax.X=DestinationLocation.X;
  3067.  
  3068.                      if(DestinationLocation.Y<System.BoundingBoxMin.Y) System.BoundingBoxMin.Y=DestinationLocation.Y;
  3069.                 else if(DestinationLocation.Y>System.BoundingBoxMax.Y) System.BoundingBoxMax.Y=DestinationLocation.Y;
  3070.  
  3071.                      if(DestinationLocation.Z<System.BoundingBoxMin.Z) System.BoundingBoxMin.Z=DestinationLocation.Z;
  3072.                 else if(DestinationLocation.Z>System.BoundingBoxMax.Z) System.BoundingBoxMax.Z=DestinationLocation.Z;
  3073.             }
  3074.  
  3075.             // Draws from Location to DestinationActor->Location.
  3076.             switch(System.BeamType)
  3077.             {
  3078.                 case BST_RandomWalk:
  3079.                     // BST_RandomWalk not implemented Yet, fall through to recursive subdivide:
  3080.  
  3081.                 case BST_RecursiveSubdivide:
  3082.                     RecursiveSubdivideLine(c, BeamTexture, System.BeamColor, System.BeamEndColor, System.BeamStartWidth, System.BeamEndWidth, 0, System.MaxAmplitude, System.Location, DestinationLocation,System.Location, DestinationLocation, System.TesselationLevel);
  3083.                     break;
  3084.  
  3085.                 case BST_SineWave:
  3086.                     SineWave(c, BeamTexture, System.BeamColor, System.BeamEndColor, System.BeamStartWidth, System.BeamEndWidth, 0, System.MaxAmplitude, System.MaxFrequency, System.Noise, TimeSeconds, System.Location, DestinationLocation,System.Location, DestinationLocation, System.TesselationLevel,System.TimeScale);
  3087.                     break;
  3088.  
  3089.                 case BST_DoubleSineWave:
  3090.                     DoubleSineWave(c, BeamTexture, System.BeamColor, System.BeamEndColor, System.BeamStartWidth, System.BeamEndWidth, 0, System.MaxAmplitude, System.MaxFrequency, System.Noise, TimeSeconds, System.Location, DestinationLocation,System.Location, DestinationLocation, System.TesselationLevel,System.TimeScale);
  3091.                     break;
  3092.  
  3093.                 case BST_Spline:
  3094.                     DrawSpline(System,c, BeamTexture, System.BeamColor, System.BeamEndColor, System.BeamStartWidth, System.BeamEndWidth, 0, System.MaxAmplitude, System.MaxFrequency, System.Noise, TimeSeconds, System.Location, DestinationLocation,System.TesselationLevel);
  3095.                     break;
  3096.  
  3097.                 case BST_Straight:
  3098.                     dnDraw3DLine(c->Frame,BeamTexture, 0,System.Location,DestinationLocation,System.BeamStartWidth,System.BeamEndWidth,System.BeamColor,System.BeamEndColor,true);
  3099.                     break;
  3100.  
  3101.                 case BST_Grid:
  3102.                     MovingGrid(c, BeamTexture, System.BeamColor, System.BeamEndColor, System.BeamStartWidth, System.BeamEndWidth, 0, System.MaxAmplitude, System.MaxFrequency, System.Noise, TimeSeconds, System.Location, DestinationLocation,System.TesselationLevel);
  3103.                     break;
  3104.             }
  3105.             QueuedLinesFlush(System,Frame,BeamTexture,0);
  3106.  
  3107.         }
  3108.         QueueParticleFlush(System,Frame);
  3109.         unclock(Stats.BeamTime);
  3110.     }
  3111.  
  3112.     // Particle output subsystem:
  3113.     struct QueuedParticle
  3114.     {
  3115.         FD3DParticle v[6];
  3116.     };
  3117.  
  3118.     struct QueuedParticleByTexture
  3119.     {
  3120.         UTexture *Texture;
  3121.         QueuedParticle *p;
  3122.         int ParticleCount, ParticleMax;
  3123.     };
  3124.  
  3125.     TArray<QueuedParticleByTexture> QueuedParticles;
  3126.     void __fastcall QueueParticleShutdown()
  3127.     {
  3128.         VALIDATE;
  3129.  
  3130.         for(int i=0;i<QueuedParticles.Num();i++)
  3131.             if(QueuedParticles(i).p&&QueuedParticles(i).ParticleMax)
  3132.                 appFree(QueuedParticles(i).p);
  3133.     }
  3134.  
  3135.     // NJS: The texture is passed in order to insert it into the proper queue.
  3136.     inline QueuedParticle &QueuedParticleAlloc(UTexture *Texture=NULL)
  3137.     {
  3138.         VALIDATE;
  3139.  
  3140.         // Attempt to find the bin this texture fits under, or allocate one if nessecary:
  3141.         for(int bin=0;bin<QueuedParticles.Num();bin++)
  3142.             if(QueuedParticles(bin).Texture==Texture)
  3143.                 break;
  3144.  
  3145.         // Couldn't locate the bin for this particle system, allocate one of the free bins.
  3146.         if(bin>=QueuedParticles.Num())
  3147.         {
  3148.             // Find an empty bin (ie, particle count is zero)
  3149.             for(bin=0;bin<QueuedParticles.Num();bin++)
  3150.                 if(!QueuedParticles(bin).ParticleCount)
  3151.                     break;
  3152.  
  3153.             // No bins available, allocate and initialize one:
  3154.             if(bin>=QueuedParticles.Num())
  3155.                 bin=QueuedParticles.AddZeroed();
  3156.  
  3157.             // Set the bin's texture to my own.
  3158.             QueuedParticles(bin).Texture=Texture;
  3159.         }
  3160.  
  3161.         // Ok, I've got a valid bin, now allocate a particle out of it:
  3162.         int ParticleIndex=QueuedParticles(bin).ParticleCount;
  3163.         QueuedParticles(bin).ParticleCount++;
  3164.  
  3165.         // Do I need to allocate more particles to make room for the new one?
  3166.         if(QueuedParticles(bin).ParticleCount>=QueuedParticles(bin).ParticleMax)
  3167.         {
  3168.             QueuedParticles(bin).ParticleMax+=Min(Max(QueuedParticles(bin).ParticleMax+1,4),256);   // Basically double the size of the particle queue until we hit 256 particles, then alloc no more than 256 at a time.
  3169.             QueuedParticles(bin).p=(QueuedParticle *)appRealloc(QueuedParticles(bin).p,(QueuedParticles(bin).ParticleMax+1)*sizeof(QueuedParticle),_T("Queued Particles"));
  3170.         }
  3171.        
  3172.         // Return a reference to the allocated particle:
  3173.         return QueuedParticles(bin).p[ParticleIndex];
  3174.     }
  3175.  
  3176.     void __fastcall QueueParticleFlush(AParticleSystem &System, FSceneNode *Frame)
  3177.     {
  3178.         VALIDATE;
  3179.  
  3180.         // Early out if there are no particles queued for rendering.
  3181.         if(!QueuedParticles.Num())
  3182.             return;
  3183.  
  3184.         DWORD PolyFlags,
  3185.               PolyFlagsEx;
  3186.         //GetActorPolyFlags(Frame,&System,PolyFlags,PolyFlagsEx);
  3187.         System.STY2PolyFlags( Frame, PolyFlags, PolyFlagsEx);
  3188.         PolyFlags|=PF_TwoSided;
  3189.         PolyFlagsEx|=PFX_Clip;
  3190.  
  3191.         // Configure the Z-Buffer
  3192.              if(System.ZBufferMode==ZBM_Occlude) PolyFlags|=PF_Occlude; // Full Z buffer occlusion 
  3193.         else if(System.ZBufferMode==ZBM_None)                           // No Z buffer interaction whatsoever
  3194.         {
  3195.             Direct3DDevice8->SetRenderState( D3DRS_ZFUNC, D3DCMP_ALWAYS );
  3196.             PolyFlags&=~PF_Occlude;
  3197.         }
  3198.         else PolyFlags&=~PF_Occlude;    // Read only Z Buffer
  3199.  
  3200.         UBOOL VariableAlpha=true;
  3201.         if((System.AlphaStart==1.f)&&(System.AlphaEnd==1.f)) VariableAlpha=false;
  3202.         if(VariableAlpha) PolyFlags|=PF_Translucent;
  3203.        
  3204.         SetBlending(PolyFlags,PolyFlagsEx);
  3205.  
  3206.         // Set the zbias for the entire particle system:
  3207.         SetZBias(System.ZBias); //Direct3DDevice8->SetRenderState(D3DRS_ZBIAS,System.ZBias);
  3208.         SetTextureNULL(1);
  3209.  
  3210.         SetDistanceFog(false);
  3211.  
  3212.         // Count the total number of particles in this system, tallying the particles queued for each material.
  3213.         int TotalParticleCount=0;
  3214.         for(int i=0;i<QueuedParticles.Num();i++)
  3215.         {
  3216.             TotalParticleCount+=QueuedParticles(i).ParticleCount;
  3217.         }
  3218.  
  3219.         Stats.Particles+=TotalParticleCount;
  3220.  
  3221.         // First set up the vertex buffer:
  3222.         verify(TotalParticleCount*6<PARTICLE_VERTEXBUFFER_SIZE);
  3223.         FD3DParticle *Vertices=(FD3DParticle*)ParticleVertices.Lock(TotalParticleCount*6);
  3224.         FD3DParticle *v=Vertices;
  3225.         for(i=0;i<QueuedParticles.Num();i++)
  3226.             if(QueuedParticles(i).ParticleCount)
  3227.             {
  3228.                 memcpy(v,QueuedParticles(i).p,QueuedParticles(i).ParticleCount*sizeof(QueuedParticle));
  3229.                 v+=QueuedParticles(i).ParticleCount*6;
  3230.             }
  3231.  
  3232.         INT First = ParticleVertices.Unlock();
  3233.        
  3234.         // Now render the vertex buffer:
  3235.         ParticleVertices.Set();
  3236.  
  3237.         UTexture *CurrentTexture=NULL;
  3238.         FTextureInfo CurrentTextureInfo;
  3239.         int ParticleIndex=0;
  3240.         SetTextureNULL(1);
  3241.  
  3242.         for(i=0;i<QueuedParticles.Num();i++)
  3243.         {
  3244.             int RunLength=QueuedParticles(i).ParticleCount;
  3245.             QueuedParticles(i).ParticleCount=0;
  3246.             if(!RunLength)
  3247.                 continue;
  3248.  
  3249.             // Unset the current texture if any:
  3250.             if(CurrentTexture)
  3251.             {
  3252.                 CurrentTexture->Unlock( CurrentTextureInfo );
  3253.                 CurrentTexture=NULL;
  3254.             }
  3255.  
  3256.  
  3257.             CurrentTexture=QueuedParticles(i).Texture;
  3258.             if(CurrentTexture)
  3259.             {
  3260.                 Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  3261.                 Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  3262.                
  3263.                 CurrentTexture->Lock( CurrentTextureInfo, 0/*Frame->Viewport->CurrentTime*/, -1, Frame->Viewport->RenDev );
  3264.                 SetTexture( 0, CurrentTextureInfo, PolyFlags, 0, PolyFlagsEx|CurrentTexture->PolyFlagsEx );
  3265.                 SetBlending(PolyFlags,PolyFlagsEx|CurrentTexture->PolyFlagsEx);
  3266.             }
  3267.             else
  3268.             {
  3269.                 //!!should optimize to avoid changing shade mode, color op, alpha op.
  3270.                 Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DISABLE  );
  3271.                 Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
  3272.             }
  3273.  
  3274.  
  3275.             Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLELIST, First+(ParticleIndex*6), RunLength*2);
  3276.             ParticleIndex+=RunLength;
  3277.         }
  3278.  
  3279.         if(CurrentTexture)
  3280.         {
  3281.             CurrentTexture->Unlock(CurrentTextureInfo);
  3282.             CurrentTexture=NULL;
  3283.         } else
  3284.         {
  3285.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  3286.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  3287.         }
  3288.  
  3289.         if(System.ZBufferMode==ZBM_None)                            // No Z buffer interaction whatsoever
  3290.             Direct3DDevice8->SetRenderState(D3DRS_ZFUNC,D3DCMP_LESSEQUAL);
  3291.     }
  3292.  
  3293.     void __fastcall dnDrawParticles( ASoftParticleSystem &System, FSceneNode *Frame )
  3294.     {
  3295.         VALIDATE;
  3296.  
  3297.         if(!RenderParticles)
  3298.             return;
  3299.  
  3300.         clock(Stats.ParticleTime);
  3301.         INT ParticleCount=System.HighestParticleNumber;
  3302.        
  3303.         // Make sure the xform matrix is correctly set up:
  3304.         PreRender(Frame);
  3305.         FParticle *Particles=(FParticle *)System.ParticleSystemHandle;
  3306.  
  3307.         // Texture Management:
  3308.         UTexture *CurrentTexture=NULL;
  3309.         FTextureInfo CurrentTextureInfo;
  3310.  
  3311.         if(System.UseLines)
  3312.         {
  3313.             for(INT i=0; i<ParticleCount; i++)
  3314.             {
  3315.                 FVector PreviousLocation;
  3316.                 FVector NextLocation;
  3317.  
  3318.                 // Am I drawing a series of connected particle lines?
  3319.                 if(System.Connected)
  3320.                 {
  3321.                     int SuccessorIndex=-1;
  3322.  
  3323.                     // Attempt to find my successor:
  3324.                     // First try the very next particle in sequence.  In non-starved particle systems, where particles have a constant lifetime, it is VERY likely to be the next particle in sequence.
  3325.                     if((i<(ParticleCount-1))&&((Particles[i+1].SpawnNumber)==(Particles[i].SpawnNumber+1)))
  3326.                         SuccessorIndex=i+1;
  3327.                     else
  3328.                     {
  3329.                         Stats.SuccessorMisses++;    // Track how many sucessors were missed.
  3330.                         // Scan through the particles and try to find my successor:
  3331.                         for(INT j=0;j<ParticleCount;j++)                             // Scan through all potentially active particles.
  3332.                             if(Particles[j].SpawnNumber==Particles[i].SpawnNumber+1) // And it's my successor.
  3333.                             {
  3334.                                 SuccessorIndex=j;
  3335.                                 break;
  3336.                             }
  3337.                     }
  3338.  
  3339.                     if(SuccessorIndex==-1) continue; // No sucessor found, can't draw this segment.
  3340.                     PreviousLocation=Particles[i].Location;
  3341.                     NextLocation=Particles[SuccessorIndex].Location;
  3342.                 } else
  3343.                 {
  3344.                     PreviousLocation=Particles[i].PreviousLocation;
  3345.                     NextLocation=Particles[i].Location;
  3346.  
  3347.                     // If drawscale isn't one, then compute new line length:
  3348.                     if((Particles[i].DrawScale!=1)||System.ConstantLength)
  3349.                     {
  3350.                         FVector Distance=NextLocation-PreviousLocation;
  3351.                         FLOAT   Length=System.ConstantLength?1:Distance.Size();
  3352.                        
  3353.                         if(Length)
  3354.                         {
  3355.                             FVector Direction=Distance;
  3356.                             Direction.Normalize();
  3357.                             FVector Midpoint=System.ConstantLength?NextLocation:(PreviousLocation+Direction*(Length/2));
  3358.  
  3359.                             Length*=Particles[i].DrawScale;
  3360.                             Length/=2;
  3361.  
  3362.                             PreviousLocation=Midpoint-(Direction*Length);
  3363.                             NextLocation=Midpoint+(Direction*Length);
  3364.                         }
  3365.                     }
  3366.                 }
  3367.                 dnDraw3DLine(Frame,Particles[i].Texture,0,PreviousLocation,NextLocation,System.LineStartWidth,System.LineEndWidth,System.LineStartColor,System.LineEndColor);
  3368.             }
  3369.         } else 
  3370.         {
  3371.  
  3372.             float BaseParticleScaleX=1.f,
  3373.                   BaseParticleScaleY=1.f;
  3374.    
  3375.             if(Particles[0].Texture)
  3376.             {
  3377.                 //Particles[0].Texture=Particles[0].Texture->Get(appSeconds()/*Frame->Viewport->CurrentTime*/);
  3378.                 Particles[0].Texture->Lock( CurrentTextureInfo, 0/*Frame->Viewport->CurrentTime*/, -1, Frame->Viewport->RenDev );
  3379.                 SetTexture( 0, CurrentTextureInfo, 0, false );
  3380.                 Particles[0].Texture->Unlock(CurrentTextureInfo);
  3381.             }
  3382.  
  3383.             UBOOL VariableAlpha=true;
  3384.             if((System.AlphaStart==1.f)&&(System.AlphaEnd==1.f)) VariableAlpha=false;
  3385.             FLOAT SystemAlphaScale=System.AlphaStartUseSystemAlpha?1.f:System.SystemAlphaScale;
  3386.  
  3387.             for(INT i=0;i<ParticleCount;i++)
  3388.             {
  3389.                 if(!Particles[i].Texture) continue;     // Ignore untextured particles
  3390.  
  3391.                 QueuedParticle &p=QueuedParticleAlloc(Particles[i].Texture);
  3392.                
  3393.                 // Manage the texture swaps:
  3394.                 if(Particles[i].Texture!=CurrentTexture)
  3395.                 {
  3396.                     CurrentTexture=Particles[i].Texture;
  3397.                     BaseParticleScaleX=System.TextureScaleX*128*(Particles[i].Texture->USize*(1/256.f));
  3398.                     BaseParticleScaleY=System.TextureScaleY*128*(Particles[i].Texture->VSize*(1/256.f));
  3399.                 }
  3400.                
  3401.                 FD3DParticle *Vertices=p.v;
  3402.  
  3403.                 DWORD dwDiffuse;
  3404.                
  3405.                 if(VariableAlpha)
  3406.                 {
  3407.                     FLOAT alphaLevel=Clamp((float)(Particles[i].Alpha*SystemAlphaScale),0.f,1.f);
  3408.                     dwDiffuse=D3DCOLOR_RGBA((int)Clamp(((float)(alphaLevel*Stages[0]->MaxColor.R)),0.f,(float)Stages[0]->MaxColor.R),
  3409.                                             (int)Clamp(((float)(alphaLevel*Stages[0]->MaxColor.G)),0.f,(float)Stages[0]->MaxColor.G),
  3410.                                             (int)Clamp(((float)(alphaLevel*Stages[0]->MaxColor.B)),0.f,(float)Stages[0]->MaxColor.B),
  3411.                                             (int)Clamp(((float)(alphaLevel*Stages[0]->MaxColor.A)),0.f,(float)Stages[0]->MaxColor.A));
  3412.  
  3413.                 } else
  3414.                 {
  3415.                     dwDiffuse=D3DCOLOR_RGBA(Stages[0]->MaxColor.R,
  3416.                                             Stages[0]->MaxColor.G,
  3417.                                             Stages[0]->MaxColor.B,
  3418.                                             Stages[0]->MaxColor.A);
  3419.  
  3420.                 }
  3421.  
  3422.                 float DrawScaleU=(Particles[i].DrawScale*BaseParticleScaleX);
  3423.                 float DrawScaleV=(Particles[i].DrawScale*BaseParticleScaleY);
  3424.            
  3425.                 // NJS: New:
  3426.                 FVector RightVector=Frame->Coords.XAxis;
  3427.                 FVector UpVector   =Frame->Coords.YAxis;
  3428.                 FVector forward    =Frame->Coords.ZAxis;
  3429.  
  3430.                 // NJS: Do I have rotation?
  3431.                 if(Particles[i].Rotation)  
  3432.                 {
  3433.                     UpVector   =RotateAboutAxis(UpVector,Particles[i].Rotation,forward);
  3434.                     RightVector=RotateAboutAxis(RightVector,Particles[i].Rotation,forward);
  3435.                 }
  3436.  
  3437.                 UpVector*=DrawScaleV;
  3438.                 RightVector*=DrawScaleU;
  3439.                 FVector vecPos=Particles[i].WorldLocation;
  3440.  
  3441.                 Vertices[0].Position = vecPos + (-RightVector+UpVector);
  3442.                 Vertices[0].Diffuse = dwDiffuse;
  3443.                 Vertices[0].TextureVector = D3DXVECTOR2(1.0f, 1.0f);
  3444.  
  3445.                 Vertices[1].Position = vecPos + (RightVector+UpVector);
  3446.                 Vertices[1].Diffuse = dwDiffuse;
  3447.                 Vertices[1].TextureVector = D3DXVECTOR2(0.0f, 1.0f);
  3448.  
  3449.                 Vertices[2].Position = vecPos + (RightVector+-UpVector);
  3450.                 Vertices[2].Diffuse = dwDiffuse;
  3451.                 Vertices[2].TextureVector = D3DXVECTOR2(0.0f, 0.0f);
  3452.  
  3453.                 Vertices[3]=Vertices[2];
  3454.  
  3455.                 Vertices[4].Position = vecPos + (-RightVector+-UpVector) ;
  3456.                 Vertices[4].Diffuse = dwDiffuse;
  3457.                 Vertices[4].TextureVector = D3DXVECTOR2(1.0f, 0.0f);
  3458.  
  3459.                 Vertices[5]=Vertices[0];
  3460.             }
  3461.         }
  3462.  
  3463.         QueueParticleFlush(System,Frame);
  3464.         unclock(Stats.ParticleTime);
  3465.     }
  3466.  
  3467.     struct QueuedLineSegment
  3468.     {
  3469.         FVector v[2];
  3470.         FLOAT Width;
  3471.         FColor StartColor,
  3472.                EndColor;
  3473.     };
  3474.  
  3475.     TArray<QueuedLineSegment> QueuedLines;
  3476.     void __fastcall QueuedLinesFlush(ABeamSystem &System,
  3477.                                      FSceneNode *Frame,
  3478.                                      UTexture *Texture,
  3479.                                      DWORD PolyFlags)
  3480.     {
  3481.         VALIDATE;
  3482.  
  3483.         int QueuedLineCount=QueuedLines.Num();
  3484.         if(!QueuedLineCount) return;
  3485.         SetZBias(0);
  3486.  
  3487.         FVector LastStart[2];
  3488.  
  3489.         // Compute the height of a sub texture segment
  3490.         float SubTextureHeight=1.f;
  3491.         if(System.SubTextureCount>1) SubTextureHeight=(1.f/System.SubTextureCount);
  3492.  
  3493.         // Whether the reverse pan pass has been performed yet or not.
  3494.         bool ReversePanPassDone=false;
  3495.  
  3496.         for(;;)
  3497.         {
  3498.             float XSystemStart=System.BeamTexturePanOffsetX+(System.BeamTexturePanX*System.Level->GameTimeSeconds);
  3499.             float XSystemEnd=XSystemStart+System.BeamTextureScaleX;
  3500.  
  3501.             if((System.BeamReversePanPass&&ReversePanPassDone))
  3502.                 Exchange(XSystemStart,XSystemEnd);
  3503.  
  3504.             float XFraction=(XSystemEnd-XSystemStart)/QueuedLineCount;
  3505.  
  3506.             int SubTextureIndex=0;
  3507.  
  3508.             if(System.SubTextureCount>1)
  3509.                 SubTextureIndex=appRand()%System.SubTextureCount;
  3510.  
  3511.             for(int i=0;i<QueuedLineCount;i++)
  3512.             {
  3513.                 QueuedLineSegment &l=QueuedLines(i);
  3514.                 QueuedParticle &p=QueuedParticleAlloc(Texture); // Alloc the particle to hold this line segment.
  3515.                 FVector &Start=l.v[0];
  3516.                 FVector &End  =l.v[1];
  3517.  
  3518.                 FD3DParticle *Vertices=p.v;
  3519.                 DWORD dwDiffuseStart=l.StartColor.TrueColor();
  3520.                 DWORD dwDiffuseEnd  =l.EndColor.TrueColor();
  3521.            
  3522.                 //FVector forward=Frame->Coords.ZAxis;         
  3523.                 FVector UpVector=(Start-ViewLocation) cross (End-ViewLocation);
  3524.                 UpVector.Normalize();
  3525.  
  3526.                 // texture coordinates:
  3527.                 float TexLeft=0.f,
  3528.                       TexTop=1.f,
  3529.                       TexRight=1.f,
  3530.                       TexBottom=0.f;
  3531.  
  3532.                 if(System.SubTextureCount>1)
  3533.                 {
  3534.                     TexBottom=SubTextureIndex*SubTextureHeight;
  3535.                     TexTop=TexBottom+SubTextureHeight;
  3536.                 }
  3537.  
  3538.                 TexLeft=XSystemStart+(i*XFraction);
  3539.                 TexRight=TexLeft+XFraction;
  3540.  
  3541.                 Exchange(TexLeft,TexRight);
  3542.  
  3543.                 float VertPan=System.BeamTexturePanOffsetY+(System.BeamTexturePanY*System.Level->GameTimeSeconds);
  3544.                 TexTop+=VertPan;
  3545.                 TexBottom+=VertPan;
  3546.  
  3547.                 if(i)
  3548.                 {
  3549.                     Vertices[0].Position=LastStart[0];
  3550.                     Vertices[1].Position=LastStart[1];
  3551.                 } else
  3552.                 {
  3553.                     Vertices[0].Position=Start+UpVector*l.Width;
  3554.                     Vertices[1].Position=Start-UpVector*l.Width;
  3555.                 }
  3556.  
  3557.                 Vertices[0].Diffuse=dwDiffuseStart;
  3558.                 Vertices[0].TextureVector=D3DXVECTOR2(TexRight, TexBottom);
  3559.  
  3560.                 Vertices[1].Diffuse=dwDiffuseStart;
  3561.                 Vertices[1].TextureVector=D3DXVECTOR2(TexRight, TexTop);
  3562.  
  3563.                 Vertices[2].Position=End -UpVector * l.Width; //EndWidth;
  3564.                 Vertices[2].Diffuse=dwDiffuseEnd;
  3565.                 Vertices[2].TextureVector=D3DXVECTOR2(TexLeft, TexTop);
  3566.  
  3567.                 Vertices[3]=Vertices[2];
  3568.                
  3569.                 Vertices[4].Position=End+UpVector*l.Width;
  3570.                 Vertices[4].Diffuse=dwDiffuseEnd;
  3571.                 Vertices[4].TextureVector=D3DXVECTOR2(TexLeft, TexBottom);
  3572.  
  3573.                 Vertices[5]=Vertices[0];
  3574.  
  3575.                 LastStart[1]=Vertices[2].Position;
  3576.                 LastStart[0]=Vertices[4].Position;
  3577.             }
  3578.             if(System.BeamReversePanPass&&!ReversePanPassDone)
  3579.             {
  3580.                 ReversePanPassDone=true;
  3581.                 continue;
  3582.             }
  3583.  
  3584.             break;
  3585.         }
  3586.  
  3587.         QueuedLines.Clear();
  3588.         QueueParticleFlush(System,Frame);
  3589.     }
  3590.  
  3591.     // Soon to be merged with draw particles, will be modified to dump all lines out at once.
  3592.     void __fastcall dnDraw3DLine
  3593.     (
  3594.         FSceneNode *Frame,
  3595.         UTexture   *Texture,
  3596.         DWORD       PolyFlags,
  3597.         FVector     Start,
  3598.         FVector     End,
  3599.         FLOAT       StartWidth,
  3600.         FLOAT       EndWidth,
  3601.         FColor      StartColor,
  3602.         FColor      EndColor,
  3603.         bool        Connected=false
  3604.     )
  3605.     {
  3606.         VALIDATE;
  3607.  
  3608.         if(!RenderLines)
  3609.             return;
  3610.  
  3611.         // Special case single width lines:
  3612.         if((StartWidth==1.f)&&(EndWidth==1.f))
  3613.         {
  3614.             DWORD PolyFlagsEx=PFX_Clip;
  3615.             if(Texture) PolyFlagsEx|=Texture->PolyFlagsEx;
  3616.  
  3617.             SetBlending(PolyFlags,PolyFlagsEx);
  3618.             SetZBias(0);
  3619.             FTextureInfo CurrentTextureInfo;
  3620.            
  3621.             if(Texture)
  3622.             {
  3623.                 Texture->Lock( CurrentTextureInfo, Frame->Viewport->CurrentTime, -1, this );
  3624.                 SetTexture( 0, CurrentTextureInfo, PolyFlags, 0, PolyFlagsEx );
  3625.             } else
  3626.             {
  3627.                 //!!should optimize to avoid changing shade mode, color op, alpha op.
  3628.                 Direct3DDevice8->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
  3629.                 Direct3DDevice8->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
  3630.             }
  3631.  
  3632.             // Handle lines with a width of one:
  3633.             FD3DVertex* Vertices = (FD3DVertex*) LineVertices.Lock(2);
  3634.  
  3635.             Vertices[0].Position=Start;
  3636.             Vertices[0].Diffuse = FColor(StartColor).TrueColor();
  3637.  
  3638.             Vertices[1].Position=End;
  3639.             Vertices[1].Diffuse = FColor(EndColor).TrueColor();
  3640.  
  3641.             INT First = LineVertices.Unlock();
  3642.  
  3643.             LineVertices.Set();
  3644.  
  3645.             Direct3DDevice8->DrawPrimitive( D3DPT_LINELIST, First, 1 );
  3646.             Stats.Particles++;
  3647.  
  3648.             if(Texture)
  3649.             {
  3650.                 Texture->Unlock(CurrentTextureInfo);
  3651.             } else
  3652.             {
  3653.                 Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  3654.                 Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  3655.             }
  3656.  
  3657.             return;
  3658.         }
  3659.  
  3660.         if(Connected)
  3661.         {
  3662.             QueuedLineSegment &l=QueuedLines(QueuedLines.Add());
  3663.  
  3664.             l.v[0]=Start;
  3665.             l.v[1]=End;
  3666.             l.Width=StartWidth;
  3667.             l.StartColor=StartColor;
  3668.             l.EndColor=EndColor;
  3669.             return;
  3670.         }
  3671.  
  3672.         // Draw unconnected non single width lines:
  3673.         QueuedParticle &p=QueuedParticleAlloc(Texture);
  3674.  
  3675.         FD3DParticle *Vertices=p.v;
  3676.         DWORD dwDiffuseStart = StartColor.TrueColor();
  3677.         DWORD dwDiffuseEnd   = EndColor.TrueColor();
  3678.  
  3679.         // Compute forward and up vectors
  3680.         FVector UpVector=(Start-ViewLocation) cross (End-ViewLocation);
  3681.         UpVector.Normalize();
  3682.  
  3683.  
  3684.         Vertices[0].Position = Start   + UpVector * StartWidth;
  3685.         Vertices[0].Diffuse = dwDiffuseStart;
  3686.         Vertices[0].TextureVector = D3DXVECTOR2(1.f, 1.f);
  3687.  
  3688.         Vertices[1].Position = Start -  UpVector* StartWidth;
  3689.         Vertices[1].Diffuse = dwDiffuseStart;
  3690.         Vertices[1].TextureVector = D3DXVECTOR2(0.f, 1.f);
  3691.  
  3692.         Vertices[2].Position = End -UpVector * EndWidth;
  3693.         Vertices[2].Diffuse = dwDiffuseEnd;
  3694.         Vertices[2].TextureVector = D3DXVECTOR2(0.f, 0.f);
  3695.  
  3696.         Vertices[3]=Vertices[2];
  3697.        
  3698.         Vertices[4].Position = End + UpVector * EndWidth;
  3699.         Vertices[4].Diffuse = dwDiffuseEnd;
  3700.         Vertices[4].TextureVector = D3DXVECTOR2(1.f, 0.f);
  3701.  
  3702.         Vertices[5]=Vertices[0];
  3703.     }
  3704.  
  3705.     UBOOL Exec( const TCHAR* Cmd, FOutputDevice& Ar )
  3706.     {
  3707.         VALIDATE;
  3708.  
  3709.         if( URenderDevice::Exec( Cmd, Ar ) )
  3710.         {
  3711.             return 1;
  3712.         }
  3713.         else if( ParseCommand(&Cmd,TEXT("GetRes")) )
  3714.         {
  3715.             if(DisplayModes.Num())
  3716.             {
  3717.                 TArray<FVector> Res;
  3718.                 for( TArray<D3DDISPLAYMODE>::TIterator It(DisplayModes); It; ++It )
  3719.                     if( GetFormatBPP(It->Format) == 16)
  3720.                         Res.AddUniqueItem( FVector(It->Width, It->Height, 0) );
  3721.                 for( INT i=0; i<Res.Num() && i<16/*script limitation*/; i++ )
  3722.                     if( Res(i).X<=MaxResWidth && Res(i).Y<=MaxResHeight )
  3723.                         Ar.Logf( i ? TEXT(" %ix%i") : TEXT("%ix%i"), (INT)Res(i).X, (INT)Res(i).Y );
  3724.                 return 1;
  3725.             }
  3726.         }
  3727.         else if( ParseCommand(&Cmd,TEXT("LodBias")) )
  3728.         {
  3729.             LodBias=appAtof(Cmd);
  3730.             Ar.Logf(TEXT("Texture LodBias = %f"),LodBias); 
  3731.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_MIPMAPLODBIAS, *(DWORD*)&LodBias );
  3732.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MIPMAPLODBIAS, *(DWORD*)&LodBias );
  3733.             return 1;
  3734.         }
  3735.  
  3736.         return 0;
  3737.     }
  3738.  
  3739.     void __fastcall _Validate(char *File,int Line)
  3740.     {
  3741.         Super::_Validate(File,Line);
  3742.  
  3743.         int Count=Queued3DLineVertices.Num();
  3744.         if((Count>=LINE_VERTEXBUFFER_SIZE)||(Count<0))
  3745.         {
  3746.             appErrorf(TEXT("check((Count<LINE_VERTEXBUFFER_SIZE)&&(Count>=0)) failed! Count=%i this:%08x [%s:%i]"),Queued3DLineVertices.Num(),this,appFromAnsi(File),Line);
  3747.             DebugBreak();
  3748.         }
  3749.  
  3750.     }
  3751.  
  3752.     TArray<FD3DVertex> Queued3DLineVertices;
  3753.     void __fastcall Queue3DLine( FSceneNode* Frame, FPlane Color, DWORD LineFlags, FVector OrigP, FVector OrigQ)
  3754.     {
  3755.         if(!RenderLines)
  3756.             return;
  3757.        
  3758.         VALIDATE;
  3759.         // Ensure that we don't overflow the line vertex buffer:
  3760.         if((Queued3DLineVertices.Num()+12)>=LINE_VERTEXBUFFER_SIZE)
  3761.             Queued3DLinesFlush(Frame);
  3762.  
  3763.  
  3764.         FD3DVertex &v=Queued3DLineVertices(Queued3DLineVertices.Add());
  3765.  
  3766.         v.Position=OrigP;
  3767.         v.Diffuse = FColor(Color).TrueColor() | 0xff000000;
  3768.  
  3769.         FD3DVertex &v1=Queued3DLineVertices(Queued3DLineVertices.Add());
  3770.  
  3771.         v1.Position=OrigQ;
  3772.         v1.Diffuse = FColor(Color).TrueColor() | 0xff000000;       
  3773.     }
  3774.  
  3775.     void __fastcall Queued3DLinesFlush(FSceneNode* Frame)
  3776.     {
  3777.         VALIDATE;
  3778.  
  3779.         int Count=Queued3DLineVertices.Num();
  3780.  
  3781.         // Make sure we don't exceed our maximum size:
  3782.  
  3783.         if(!Count) return;
  3784.         SetBlending(PF_TwoSided,PFX_Clip|PFX_FlatShade);
  3785.         SetZBias(0);
  3786.  
  3787.         //!!should optimize to avoid changing shade mode, color op, alpha op.
  3788.         //Direct3DDevice8->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );
  3789.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DISABLE  );
  3790.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
  3791.  
  3792.         check(Count<LINE_VERTEXBUFFER_SIZE); // NJS: URGENT FIX.. iterate through line vertices. - should never happen because of the check in Queue3DLine, but still.
  3793.         FD3DVertex* Vertices = (FD3DVertex*) LineVertices.Lock(Count);
  3794.         memcpy(Vertices,Queued3DLineVertices.GetData(),Count*sizeof(FD3DVertex));
  3795.         INT First = LineVertices.Unlock();
  3796.         LineVertices.Set();
  3797.  
  3798.         Direct3DDevice8->DrawPrimitive( D3DPT_LINELIST, First, Count/2 );
  3799.         // Line code:
  3800.  
  3801.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  3802.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  3803.         //Direct3DDevice8->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
  3804.  
  3805.         Queued3DLineVertices.Clear();
  3806.     }
  3807.  
  3808.     virtual void __fastcall Draw3DLine( FSceneNode* Frame, FPlane Color, DWORD LineFlags, FVector OrigP, FVector OrigQ )
  3809.     {
  3810.         VALIDATE;
  3811.         if(!RenderLines) return;
  3812.  
  3813.         SetBlending(0,PFX_Clip);
  3814.         SetZBias(0);
  3815.  
  3816.         FD3DVertex* Vertices = (FD3DVertex*) LineVertices.Lock(2);
  3817.  
  3818.         //!!should optimize to avoid changing shade mode, color op, alpha op.
  3819.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DISABLE  );
  3820.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
  3821.  
  3822.         Vertices[0].Position.X = OrigP.X;
  3823.         Vertices[0].Position.Y = OrigP.Y;
  3824.         Vertices[0].Position.Z = OrigP.Z;
  3825.         Vertices[0].Diffuse = FColor(Color).TrueColor() | 0xff000000;
  3826.  
  3827.         Vertices[1].Position.X = OrigQ.X;
  3828.         Vertices[1].Position.Y = OrigQ.Y;
  3829.         Vertices[1].Position.Z = OrigQ.Z;
  3830.         Vertices[1].Diffuse = FColor(Color).TrueColor() | 0xff000000;
  3831.  
  3832.         INT First = LineVertices.Unlock();
  3833.  
  3834.         LineVertices.Set();
  3835.  
  3836.         Direct3DDevice8->DrawPrimitive( D3DPT_LINELIST, First, 1 );
  3837.  
  3838.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  3839.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  3840.     }
  3841.  
  3842.     void __fastcall Draw2DLine( FSceneNode* Frame, FPlane Color, DWORD LineFlags, FVector P1, FVector P2 )
  3843.     {
  3844.         VALIDATE;
  3845.         //appErrorf(_T("******** Draw2DLine called, please report to Nick"));
  3846.         ///*   
  3847.         if(!RenderLines) return;
  3848.         SetBlending();
  3849.         FD3DTLVertex*   Vertices = (FD3DTLVertex*) ActorVertices.Lock(2);
  3850.  
  3851.         //!!should optimize to avoid changing shade mode, color op, alpha op.
  3852.         Direct3DDevice8->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );
  3853.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DISABLE  );
  3854.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
  3855.  
  3856.         Vertices[0].Position.X = P1.X - 0.5f;
  3857.         Vertices[0].Position.Y = P1.Y - 0.5f;
  3858.         Vertices[0].Position.Z = ProjectionMatrix._33 + ProjectionMatrix._43;
  3859.         Vertices[0].Position.W = 1.f;
  3860.         Vertices[0].Diffuse = FColor(Color).TrueColor() | 0xff000000;
  3861.         Vertices[0].Specular = 0;
  3862.  
  3863.         Vertices[1].Position.X = P2.X - 0.5f;
  3864.         Vertices[1].Position.Y = P2.Y - 0.5f;
  3865.         Vertices[1].Position.Z = ProjectionMatrix._33 + ProjectionMatrix._43;
  3866.         Vertices[1].Position.W = 1.f;
  3867.         Vertices[1].Diffuse = FColor(Color).TrueColor() | 0xff000000;
  3868.         Vertices[1].Specular = 0;
  3869.  
  3870.         INT First = ActorVertices.Unlock();
  3871.  
  3872.         ActorVertices.Set();
  3873.  
  3874.         Direct3DDevice8->DrawPrimitive( D3DPT_LINELIST, First, 1 );
  3875.  
  3876.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  3877.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  3878.         Direct3DDevice8->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
  3879.     }
  3880.  
  3881.     void __fastcall UD3DRenderDevice::Draw2DPoint( FSceneNode* Frame, FPlane Color, DWORD LineFlags, FLOAT X1, FLOAT Y1, FLOAT X2, FLOAT Y2, FLOAT Z )
  3882.     {
  3883.         VALIDATE;
  3884.         if(!RenderPoints)
  3885.             return;
  3886.  
  3887.         PreRender(Frame);
  3888.         SetBlending(0,PFX_FlatShade);
  3889.  
  3890.         FD3DTLVertex*   Vertices = (FD3DTLVertex*) ActorVertices.Lock(5);
  3891.  
  3892.         //!!should optimize to avoid changing shade mode, color op, alpha op.
  3893.         //Direct3DDevice8->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );
  3894.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DISABLE );
  3895.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
  3896.  
  3897.         float PositionZ=ProjectionMatrix._33 + ProjectionMatrix._43;
  3898.         Vertices[0].Position.X = X1;
  3899.         Vertices[0].Position.Y = Y1;
  3900.         Vertices[0].Position.Z = PositionZ;
  3901.         Vertices[0].Position.W = 1.f;
  3902.         Vertices[0].Diffuse = FColor(Color).TrueColor() | 0xff000000;
  3903.         Vertices[0].Specular = 0;
  3904.  
  3905.         Vertices[1].Position.X = X2;
  3906.         Vertices[1].Position.Y = Y1;
  3907.         Vertices[1].Position.Z = PositionZ;
  3908.         Vertices[1].Position.W = 1.f;
  3909.         Vertices[1].Diffuse = FColor(Color).TrueColor() | 0xff000000;
  3910.         Vertices[1].Specular = 0;
  3911.        
  3912.         Vertices[2].Position.X = X2;
  3913.         Vertices[2].Position.Y = Y2;
  3914.         Vertices[2].Position.Z = PositionZ;
  3915.         Vertices[2].Position.W = 1.f;
  3916.         Vertices[2].Diffuse = FColor(Color).TrueColor() | 0xff000000;
  3917.         Vertices[2].Specular = 0;
  3918.  
  3919.         Vertices[3].Position.X = X1;
  3920.         Vertices[3].Position.Y = Y2;
  3921.         Vertices[3].Position.Z = PositionZ;
  3922.         Vertices[3].Position.W = 1.f;
  3923.         Vertices[3].Diffuse = FColor(Color).TrueColor() | 0xff000000;
  3924.         Vertices[3].Specular = 0;
  3925.  
  3926.         Vertices[4].Position.X = X1;
  3927.         Vertices[4].Position.Y = Y1;
  3928.         Vertices[4].Position.Z = PositionZ;
  3929.         Vertices[4].Position.W = 1.f;
  3930.         Vertices[4].Diffuse = FColor(Color).TrueColor() | 0xff000000;
  3931.         Vertices[4].Specular = 0;
  3932.  
  3933.         INT First = ActorVertices.Unlock();
  3934.  
  3935.         ActorVertices.Set();
  3936.  
  3937.         Direct3DDevice8->DrawPrimitive( D3DPT_LINESTRIP, First, 4 );
  3938.  
  3939.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  3940.         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  3941.     }
  3942.  
  3943.  
  3944. #ifdef DOHITTEST
  3945.     //  Hit testing.       
  3946.     //  Push hit data.
  3947.     void __fastcall UD3DRenderDevice::PushHit( const BYTE* Data, INT Count )
  3948.     {
  3949.  
  3950.         VALIDATE;
  3951.  
  3952.         check(Viewport->HitYL<=HIT_SIZE);
  3953.         check(Viewport->HitXL<=HIT_SIZE);
  3954.  
  3955.         // Get the current render target surface.
  3956.         IDirect3DSurface8*  RenderTarget;
  3957.  
  3958.         if(FAILED(h=Direct3DDevice8->GetRenderTarget(&RenderTarget)))
  3959.         {
  3960.             debugf(TEXT("D3D Driver: GetRenderTarget failed (%s)"),DXGetErrorString8(h));
  3961.             return;
  3962.         }
  3963.  
  3964.         // Lock the render target.
  3965.  
  3966.         D3DLOCKED_RECT  LockedRect;
  3967.  
  3968.         if(FAILED(h=RenderTarget->LockRect(&LockedRect,NULL,0)))
  3969.         {
  3970.             debugf(TEXT("D3D Driver: LockRect failed (%s)"),DXGetErrorString8(h));
  3971.             return;
  3972.         }
  3973.  
  3974.         // Save the passed info on the working stack.
  3975.  
  3976.         INT Index = HitStack.Add(Count);
  3977.  
  3978.         appMemcpy(&HitStack(Index),Data,Count);
  3979.  
  3980.         // Cleanup under cursor.
  3981.         switch( ViewportColorBits )
  3982.         {
  3983.             case 16:
  3984.             {
  3985.                 _WORD* src = (_WORD*) LockedRect.pBits;
  3986.                 src = (_WORD*) ((BYTE*)src + Viewport->HitX * 2 + Viewport->HitY * LockedRect.Pitch);
  3987.                 for( INT Y=0; Y<Viewport->HitYL; Y++, src=(_WORD*)((BYTE*)src + LockedRect.Pitch) )
  3988.                 {
  3989.                     for( INT X=0; X<Viewport->HitXL; X++ )
  3990.                     {
  3991.                         HitPixels[X][Y] = src[X];
  3992.                         src[X] = IGNOREPIX;
  3993.                     }
  3994.                 }
  3995.                 break;
  3996.             }
  3997.             case 24:
  3998.             {
  3999.                 BYTE* src = (BYTE*) LockedRect.pBits;
  4000.                 src = src + Viewport->HitX*3  + Viewport->HitY * LockedRect.Pitch;
  4001.                 for( INT Y=0; Y<Viewport->HitYL; Y++, src+=LockedRect.Pitch )
  4002.                 {
  4003.                     for( INT X=0; X<Viewport->HitXL; X++ )
  4004.                     {
  4005.                         HitPixels[X][Y] = *((DWORD*)&src[X*3]);
  4006.                         *((DWORD*)&src[X*3]) = IGNOREPIX;
  4007.                     }
  4008.                 }          
  4009.                 break;
  4010.             }
  4011.             case 32:
  4012.             {
  4013.                 DWORD* src = (DWORD*) LockedRect.pBits;
  4014.                 src = (DWORD*)((BYTE*)src + Viewport->HitX * 4 + Viewport->HitY * LockedRect.Pitch);
  4015.                 for( INT Y=0; Y<Viewport->HitYL; Y++, src=(DWORD*)((BYTE*)src + LockedRect.Pitch) )
  4016.                 {
  4017.                     for( INT X=0; X<Viewport->HitXL; X++ )
  4018.                     {
  4019.                         HitPixels[X][Y] = src[X];
  4020.                         src[X] = IGNOREPIX;
  4021.                     }
  4022.                 }
  4023.                 break;
  4024.             }
  4025.         }
  4026.  
  4027.         // Unlock the render target, and release our reference to it.
  4028.  
  4029.         RenderTarget->UnlockRect();
  4030.         SafeRelease(RenderTarget);
  4031.     };
  4032.  
  4033.     // Pop hit data.
  4034.     void __fastcall UD3DRenderDevice::PopHit( INT Count, UBOOL bForce )
  4035.     {
  4036.         VALIDATE;
  4037.  
  4038.         //debugf(TEXT("POPHIT stacknum   %i  Count %i "),HitStack.Num(),Count);
  4039.         check(Count <= HitStack.Num());
  4040.         UBOOL Hit=0;
  4041.  
  4042.         // Get the current render target surface.
  4043.         IDirect3DSurface8*  RenderTarget;
  4044.  
  4045.         if(FAILED(h=Direct3DDevice8->GetRenderTarget(&RenderTarget)))
  4046.         {
  4047.             debugf(TEXT("D3D Driver: GetRenderTarget failed (%s)"),DXGetErrorString8(h));
  4048.             return;
  4049.         }
  4050.  
  4051.         // Lock the render target.
  4052.         D3DLOCKED_RECT  LockedRect;
  4053.  
  4054.         if(FAILED(h=RenderTarget->LockRect(&LockedRect,NULL,0)))
  4055.         {
  4056.             debugf(TEXT("D3D Driver: LockRect failed (%s)"),DXGetErrorString8(h));
  4057.             return;
  4058.         }
  4059.  
  4060.         // Check under cursor and restore.
  4061.         switch( ViewportColorBits )
  4062.         {
  4063.             case 16:
  4064.             {
  4065.                 _WORD* src = (_WORD*) LockedRect.pBits;
  4066.                 src = (_WORD*) ((BYTE*)src + Viewport->HitX * 2 + Viewport->HitY * LockedRect.Pitch);
  4067.                 for( INT Y=0; Y<Viewport->HitYL; Y++, src=(_WORD*)((BYTE*)src + LockedRect.Pitch) )
  4068.                 {
  4069.                     for( INT X=0; X<Viewport->HitXL; X++ )
  4070.                     {
  4071.                         if( src[X] != IGNOREPIX )
  4072.                             Hit=1;
  4073.                         src[X] = (_WORD)HitPixels[X][Y];   
  4074.                    
  4075.                     }
  4076.                 }
  4077.                 break;
  4078.             }
  4079.             case 24:
  4080.             {
  4081.                 BYTE* src = (BYTE*) LockedRect.pBits;
  4082.                 src = src + Viewport->HitX*3  + Viewport->HitY * LockedRect.Pitch;
  4083.                 for( INT Y=0; Y<Viewport->HitYL; Y++, src+=LockedRect.Pitch )
  4084.                 {
  4085.                     for( INT X=0; X<Viewport->HitXL; X++ )
  4086.                     {
  4087.                         if( *((DWORD*)&src[X*3]) != IGNOREPIX )
  4088.                             Hit=1;
  4089.                         *((DWORD*)&src[X*3]) = HitPixels[X][Y];                    
  4090.                     }
  4091.                 }          
  4092.                 break;
  4093.             }
  4094.             case 32:
  4095.             {
  4096.                 DWORD* src = (DWORD*) LockedRect.pBits;
  4097.                 src = (DWORD*)((BYTE*)src + Viewport->HitX * 4 + Viewport->HitY * LockedRect.Pitch);
  4098.                 for( INT Y=0; Y<Viewport->HitYL; Y++, src=(DWORD*)((BYTE*)src + LockedRect.Pitch) )
  4099.                 {
  4100.                     for( INT X=0; X<Viewport->HitXL; X++ )
  4101.                     {                      
  4102.                         if ( src[X] != IGNOREPIX )
  4103.                             Hit=1;
  4104.                         src[X] = HitPixels[X][Y];                      
  4105.                     }
  4106.                 }
  4107.                 break;
  4108.             }      
  4109.         }
  4110.  
  4111.         // Unlock the render target, and release our reference to it.
  4112.  
  4113.         RenderTarget->UnlockRect();
  4114.         SafeRelease(RenderTarget);
  4115.  
  4116.         // Handle hit.
  4117.         if( Hit || bForce )
  4118.         {
  4119.             if( HitStack.Num() <= *HitSize )
  4120.             {
  4121.                 HitCount = HitStack.Num();
  4122.                 appMemcpy( HitData, &HitStack(0), HitCount );
  4123.             }
  4124.             else HitCount = 0;
  4125.         }
  4126.         // Remove the passed info from the working stack.
  4127.         HitStack.Remove( HitStack.Num()-Count, Count );
  4128.     }
  4129. #else
  4130.     void __fastcall UD3DRenderDevice::PushHit( const BYTE* Data, INT Count ) { VALIDATE; }
  4131.     void __fastcall UD3DRenderDevice::PopHit( INT Count, UBOOL bForce )      { VALIDATE; }
  4132. #endif
  4133.  
  4134.     void __fastcall GetStats( TCHAR* Result )
  4135.     {
  4136.         VALIDATE;
  4137.  
  4138.         *Result=0;
  4139.         appSprintf
  4140.         (
  4141.             Result,
  4142.             TEXT("total:%.1fms (surf=%04i, %03.1fms) (poly=%05i, %.1fms (Queue:%1.fms Render: %.1fms, VertexSetup:%1.fms (Lock:%i %1.fms) DrawPrim:%.1fms) (%i masked)) (tile=%i, %.1fms) (particles=%i, %.1fms (texture changes:%i, succ misses:%i)) (beams=%i, %.1fms) texuploads=%i"),
  4143.             GSecondsPerCycle * 1000 *(Stats.SurfTime+Stats.PolyTime+Stats.TileTime+Stats.ParticleTime+Stats.BeamTime),
  4144.             Stats.Surfs,
  4145.             GSecondsPerCycle * 1000 * Stats.SurfTime,
  4146.             Stats.Polys,
  4147.             GSecondsPerCycle * 1000 * Stats.PolyTime,
  4148.             GSecondsPerCycle * 1000 * Stats.QueueTime,
  4149.             GSecondsPerCycle * 1000 * Stats.D3DVertexRender,
  4150.             GSecondsPerCycle * 1000 * Stats.D3DVertexSetup,
  4151.             Stats.VBLocks,
  4152.             GSecondsPerCycle * 1000 * Stats.D3DVertexLock,
  4153.             GSecondsPerCycle * 1000 * Stats.D3DPolyTime,
  4154.             Stats.MaskedPolys,
  4155.             Stats.Tiles,
  4156.             GSecondsPerCycle * 1000 * Stats.TileTime,
  4157.             Stats.Particles,
  4158.             GSecondsPerCycle * 1000 * Stats.ParticleTime,          
  4159.             Stats.ParticleTextureChanges,
  4160.             Stats.SuccessorMisses,
  4161.             Stats.Beams,
  4162.             GSecondsPerCycle * 1000 * Stats.BeamTime,          
  4163.             Stats.TexUploads
  4164.         );
  4165.  
  4166.         for( FPixFormat* Fmt=FirstPixelFormat; Fmt; Fmt=Fmt->Next )
  4167.             appSprintf
  4168.             (
  4169.                 Result + appStrlen(Result),
  4170.                 TEXT(" Format:%s (Active/Binned Ram:%iK/%iK, textures:%i/%i) sets:%i (uploads:%i, %.1fms)"),
  4171.                 Fmt->Desc,
  4172.                 Fmt->ActiveRAM/1024,
  4173.                 Fmt->BinnedRAM/1024,
  4174.                 Fmt->Active,
  4175.                 Fmt->Binned,
  4176.                 Fmt->Sets,
  4177.                 Fmt->Uploads,
  4178.                 Fmt->UploadCycles * GSecondsPerCycle * 1000.f
  4179.             );
  4180.     }
  4181.     void __fastcall ClearZ( FSceneNode* Frame )
  4182.     {
  4183.         VALIDATE;
  4184.  
  4185.         // Clear only the Z-buffer.
  4186.         Direct3DDevice8->Clear( 0, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, 0, 1.0, 0 );
  4187.  
  4188.     }
  4189.     void __fastcall ReadPixels( FColor* Pixels, UBOOL BackBuffer = false)
  4190.     {
  4191.         VALIDATE;
  4192.  
  4193.         IDirect3DSurface8*  TempScreenBuffer;
  4194.    
  4195.         if (!BackBuffer)
  4196.         {
  4197.             // Create the temp surface to hold the front buffer
  4198.             D3D_CHECK((h=Direct3DDevice8->CreateImageSurface( ViewportX, ViewportY, D3DFMT_A8R8G8B8, &TempScreenBuffer )));
  4199.  
  4200.             // Fill the temporary surface with the contents of the front buffer.
  4201.             D3D_CHECK((h=Direct3DDevice8->GetFrontBuffer( TempScreenBuffer )));
  4202.         }
  4203.         else
  4204.         {
  4205.             EndScene();
  4206.  
  4207.             // Get a pointer to the back buffer
  4208.             D3D_CHECK((h=Direct3DDevice8->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &TempScreenBuffer)));
  4209.         }
  4210.  
  4211.         // Lock the temporary surface.
  4212.         D3DLOCKED_RECT  LockedRect;
  4213.         memset(&LockedRect,0,sizeof(LockedRect));
  4214.  
  4215.         D3D_CHECK((TempScreenBuffer->LockRect(&LockedRect,NULL,D3DLOCK_READONLY)));
  4216.  
  4217.         // Compute gamma correction.
  4218.         BYTE    GammaCorrect[256];
  4219.         INT     Index;
  4220.  
  4221.         if(DeviceCaps8.Caps2 & D3DCAPS2_FULLSCREENGAMMA)
  4222.         {
  4223.             //FLOAT Gamma = Viewport->GetOuterUClient()->Gamma;
  4224.             FLOAT Brightness = Viewport->GetOuterUClient()->Brightness;
  4225.             //FLOAT Contrast = Viewport->GetOuterUClient()->Contrast;
  4226.  
  4227.             if(!Brightness) Brightness=0.01;
  4228.             for(Index = 0;Index < 256;Index++)
  4229.                 GammaCorrect[Index] = Clamp<INT>(appPow(Index/255.0,1.0/Brightness)*65535.0,0,65535);
  4230.  
  4231.                 //GammaCorrect[Index] = Clamp<INT>( appRound( (Contrast+0.5f)*appPow(Index/255.f,1.0f/Gamma)*65535.f + (Brightness-0.5f)*32768.f - Contrast*32768.f + 16384.f ) / 256, 0, 255 );
  4232.         }
  4233.         else
  4234.         {
  4235.             for(Index = 0;Index < 256;Index++)
  4236.                 GammaCorrect[Index] = Index;
  4237.         }
  4238.        
  4239.  
  4240.         // Copy the contents of the temporary surface to the destination.
  4241.         FColor* Dest = Pixels;
  4242.         INT     X, Y;
  4243.  
  4244.         if (BackBuffer)
  4245.         {
  4246.             D3DSURFACE_DESC Desc;
  4247.             DWORD           rl, rr, gl, gr, bl, br, mask;
  4248.             DWORD           RBitMask = 0, GBitMask = 0, BBitMask = 0, BitCount = 0;
  4249.             DWORD           R, G, B;
  4250.  
  4251.             TempScreenBuffer->GetDesc(&Desc);
  4252.  
  4253.             switch (Desc.Format)
  4254.             {
  4255.                 case D3DFMT_R8G8B8:
  4256.                 {
  4257.                     RBitMask = 0xff0000;
  4258.                     GBitMask = 0x00ff00;
  4259.                     BBitMask = 0x0000ff;
  4260.                     BitCount = 24;
  4261.                     break;
  4262.                 }
  4263.                 case D3DFMT_A8R8G8B8:
  4264.                 case D3DFMT_X8R8G8B8:
  4265.                 {
  4266.                     RBitMask = 0xff0000;
  4267.                     GBitMask = 0x00ff00;
  4268.                     BBitMask = 0x0000ff;
  4269.                     BitCount = 32;
  4270.                     break;
  4271.                 }
  4272.                 case D3DFMT_R5G6B5:
  4273.                 {
  4274.                     RBitMask = (31<<11);
  4275.                     GBitMask = (63<<5 );
  4276.                     BBitMask = (31<<0 );
  4277.                     BitCount = 16;
  4278.                     break;
  4279.                 }
  4280.                 case D3DFMT_X1R5G5B5:
  4281.                 case D3DFMT_A1R5G5B5:
  4282.                 {
  4283.                     RBitMask = (31<<10);
  4284.                     GBitMask = (31<<5 );
  4285.                     BBitMask = (31<<0 );
  4286.                     BitCount = 16;
  4287.                     break;
  4288.                 }
  4289.             }
  4290.  
  4291.             // Compute needed bit shifts.
  4292.             for( rr=0, mask=RBitMask; !(mask&1); mask>>=1, ++rr );
  4293.             for( rl=8; mask&1; mask>>=1, --rl );
  4294.             for( gr=0, mask=GBitMask; !(mask&1); mask>>=1, ++gr );
  4295.             for( gl=8; mask&1; mask>>=1, --gl );
  4296.             for( br=0, mask=BBitMask; !(mask&1); mask>>=1, ++br );
  4297.             for( bl=8; mask&1; mask>>=1, --bl );
  4298.  
  4299.             switch (BitCount)
  4300.             {
  4301.                 case 16:
  4302.                 {
  4303.                     WORD    *Src = (WORD*) LockedRect.pBits;
  4304.                     INT     Extra = (LockedRect.Pitch/sizeof(WORD)) - ViewportX;
  4305.                
  4306.                     for(Y = 0;Y < ViewportY;Y++)
  4307.                     {
  4308.                         for(X = 0;X < ViewportX;X++)
  4309.                         {      
  4310.                             R = (((*Src) & RBitMask) >> rr) << rl;
  4311.                             G = (((*Src) & GBitMask) >> gr) << gl;
  4312.                             B = (((*Src) & BBitMask) >> br) << bl;
  4313.  
  4314.                             GET_COLOR_DWORD(*Dest++) = (R<<16)|(G<<8)|B;
  4315.                             Src++;
  4316.                         }
  4317.            
  4318.                         Src += Extra;
  4319.                     }
  4320.                     break;
  4321.                 }
  4322.                 case 24:
  4323.                 {
  4324.                     char    *Src = (char*) LockedRect.pBits;
  4325.                     INT     Extra = (LockedRect.Pitch - ViewportX*3);
  4326.                
  4327.                     for(Y = 0;Y < ViewportY;Y++)
  4328.                     {
  4329.                         for(X = 0;X < ViewportX;X++)
  4330.                         {      
  4331.                             R = (((*((DWORD*)Src)) & RBitMask) >> rr) << rl;
  4332.                             G = (((*((DWORD*)Src)) & GBitMask) >> gr) << gl;
  4333.                             B = (((*((DWORD*)Src)) & BBitMask) >> br) << bl;
  4334.  
  4335.                             GET_COLOR_DWORD(*Dest++) = (R<<16)|(G<<8)|B;
  4336.                             Src+=3;
  4337.                         }
  4338.            
  4339.                         Src += Extra;
  4340.                     }
  4341.                     break;
  4342.                 }
  4343.  
  4344.                 case 32:
  4345.                 {
  4346.                     DWORD   *Src = (DWORD*) LockedRect.pBits;
  4347.                     INT     Extra = (LockedRect.Pitch/sizeof(DWORD)) - ViewportX;
  4348.                
  4349.                     for(Y = 0;Y < ViewportY;Y++)
  4350.                     {
  4351.                         for(X = 0;X < ViewportX;X++)
  4352.                         {      
  4353.                             R = (((*Src) & RBitMask) >> rr) << rl;
  4354.                             G = (((*Src) & GBitMask) >> gr) << gl;
  4355.                             B = (((*Src) & BBitMask) >> br) << bl;
  4356.  
  4357.                             GET_COLOR_DWORD(*Dest++) = (R<<16)|(G<<8)|B;
  4358.                             Src++;
  4359.                         }
  4360.            
  4361.                         Src += Extra;
  4362.                     }
  4363.                     break;
  4364.                 }
  4365.             }
  4366.         }
  4367.         else
  4368.         {
  4369.             char*   Src = (char*) LockedRect.pBits;
  4370.  
  4371.             for(Y = 0;Y < ViewportY;Y++)
  4372.             {
  4373.                 for(X = 0;X < ViewportX;X++)
  4374.                 {
  4375.                     GET_COLOR_DWORD(*Dest++) = *((DWORD*) Src);
  4376.                     Src += sizeof(DWORD);
  4377.                 }
  4378.            
  4379.                 Src += (LockedRect.Pitch - (ViewportX * sizeof(DWORD)));
  4380.             }
  4381.         }
  4382.         // Unlock the temporary surface.
  4383.  
  4384.         TempScreenBuffer->UnlockRect();
  4385.  
  4386.         // Release the temporary surface.
  4387.         SafeRelease(TempScreenBuffer);
  4388.  
  4389.         if (BackBuffer)
  4390.             BeginScene();
  4391.  
  4392.     }
  4393.     void __fastcall UD3DRenderDevice::EndFlash()
  4394.     {
  4395.         VALIDATE;
  4396.  
  4397.         if( FlashScale!=FVector(.5f,.5f,.5f) || FlashFog!=FVector(0,0,0) )
  4398.         {
  4399.             // Set up color.
  4400.             FColor   D3DColor = FColor(FPlane(FlashFog.X,FlashFog.Y,FlashFog.Z,Min(FlashScale.X*2.f,1.f)));                
  4401.             D3DCOLOR Color    = D3DCOLOR_RGBA(D3DColor.R, D3DColor.G, D3DColor.B, D3DColor.A);
  4402.  
  4403.             // Initialize vertex array
  4404.             FD3DScreenVertex Vertices[4];
  4405.  
  4406.             Vertices[0].Position.X = 0;
  4407.             Vertices[0].Position.Y = 0;
  4408.             Vertices[0].Position.W = 0.5f;
  4409.             Vertices[0].Position.Z = ProjectionMatrix._33 + ProjectionMatrix._43 * 0.5f;
  4410.             GET_COLOR_DWORD(Vertices[0].Color) = Color;
  4411.  
  4412.             Vertices[1].Position.X = 0;
  4413.             Vertices[1].Position.Y = Viewport->SizeY;
  4414.             Vertices[1].Position.W = 0.5f;
  4415.             Vertices[1].Position.Z = ProjectionMatrix._33 + ProjectionMatrix._43 * 0.5f;
  4416.             GET_COLOR_DWORD(Vertices[1].Color) = Color;
  4417.  
  4418.             Vertices[2].Position.X = Viewport->SizeX;
  4419.             Vertices[2].Position.Y = Viewport->SizeY;
  4420.             Vertices[2].Position.Z = ProjectionMatrix._33 + ProjectionMatrix._43 * 0.5f;
  4421.             Vertices[2].Position.W = 0.5f;
  4422.             GET_COLOR_DWORD(Vertices[2].Color) = Color;
  4423.  
  4424.             Vertices[3].Position.X = Viewport->SizeX;
  4425.             Vertices[3].Position.Y = 0;
  4426.             Vertices[3].Position.W = 0.5f;
  4427.             Vertices[3].Position.Z = ProjectionMatrix._33 + ProjectionMatrix._43 * 0.5f;
  4428.             GET_COLOR_DWORD(Vertices[3].Color) = Color;        
  4429.  
  4430.            
  4431.             // Draw it.
  4432.             SetBlending( PF_Translucent| PF_NoOcclude | PF_TwoSided, PFX_Clip );
  4433.             //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  4434.             //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );         
  4435.             //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_SRCALPHA );
  4436.             SetAlphaBlendEnable(TRUE);
  4437.             SetSrcBlend(D3DBLEND_ONE);
  4438.             SetDstBlend(D3DBLEND_SRCALPHA);
  4439.  
  4440.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DISABLE ); // v 0.4
  4441.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
  4442.             Direct3DDevice8->SetRenderState( D3DRS_ZFUNC, D3DCMP_ALWAYS );
  4443.  
  4444.             Direct3DDevice8->SetVertexShader( FD3DScreenVertex::FVF );
  4445.             Direct3DDevice8->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, Vertices, sizeof(FD3DScreenVertex) );
  4446.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
  4447.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
  4448.             Direct3DDevice8->SetRenderState( D3DRS_ZFUNC, D3DCMP_LESSEQUAL );
  4449.             SetBlending();
  4450.         }
  4451.     }
  4452.  
  4453.     //============================================================================================
  4454.     //  API's for caching and Tracking D3D's internal state:
  4455.     //============================================================================================
  4456.     float __fastcall SetZBias( FLOAT NewZBias=0.f )
  4457.     {
  4458.         VALIDATE;
  4459.  
  4460.         float FormerZBias=ZBias;
  4461.  
  4462.         NewZBias=Clamp(NewZBias,0.f,16.f);
  4463.         if(ZBias!=NewZBias || !CacheBlending)
  4464.         {
  4465.             ZBias=NewZBias;
  4466.             Direct3DDevice8->SetRenderState(D3DRS_ZBIAS,ZBias);
  4467.         }
  4468.  
  4469.         return FormerZBias;
  4470.     }
  4471.  
  4472.     D3DBLEND __fastcall SetSrcBlend( D3DBLEND NewSrcBlend = D3DBLEND_ZERO )
  4473.     {
  4474.         D3DBLEND FormerSrcBlend=SrcBlend;
  4475.  
  4476.         if(NewSrcBlend!=FormerSrcBlend || !CacheBlending)
  4477.         {
  4478.             check((NewSrcBlend>0)&&(NewSrcBlend<=D3DBLEND_BOTHINVSRCALPHA));
  4479.             Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND,  NewSrcBlend );
  4480.             SrcBlend=NewSrcBlend;
  4481.         }
  4482.  
  4483.         return FormerSrcBlend;
  4484.     }
  4485.  
  4486.     D3DBLEND __fastcall SetDstBlend( D3DBLEND NewDstBlend = D3DBLEND_ZERO )
  4487.     {
  4488.         D3DBLEND FormerDstBlend=DstBlend;
  4489.  
  4490.         if(NewDstBlend!=FormerDstBlend || !CacheBlending)
  4491.         {
  4492.             check((NewDstBlend>0)&&(NewDstBlend<=D3DBLEND_BOTHINVSRCALPHA));
  4493.             Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND,  NewDstBlend );
  4494.             DstBlend=NewDstBlend;
  4495.         }
  4496.  
  4497.         return FormerDstBlend;
  4498.     }
  4499.  
  4500.     INT __fastcall SetAlphaBlendEnable(INT NewAlphaBlendEnable)
  4501.     {
  4502.         INT FormerAlphaBlendEnable=AlphaBlendEnable;
  4503.         check((NewAlphaBlendEnable==TRUE)||(NewAlphaBlendEnable==FALSE));
  4504.         if(NewAlphaBlendEnable!=FormerAlphaBlendEnable || !CacheBlending )
  4505.         {
  4506.             Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, NewAlphaBlendEnable );
  4507.             AlphaBlendEnable=NewAlphaBlendEnable;
  4508.         }
  4509.  
  4510.         return FormerAlphaBlendEnable;
  4511.     }
  4512.  
  4513.     HRESULT __fastcall BeginScene()
  4514.     {
  4515.         BeginSceneCount++;
  4516.         //check(BeginSceneCount==1);
  4517.  
  4518.         return Direct3DDevice8->BeginScene();
  4519.     }
  4520.  
  4521.     HRESULT __fastcall EndScene()
  4522.     {
  4523.         BeginSceneCount--;
  4524.         //check(BeginSceneCount==0);
  4525.  
  4526.         return Direct3DDevice8->EndScene();
  4527.     }
  4528.  
  4529.     //============================================================================================
  4530.     // Unreal's Original Blending System, trying to get away from this, and go with direct D3D
  4531.     // state caching:
  4532.     //============================================================================================
  4533.     void __fastcall SetBlending( DWORD PolyFlags=0, DWORD PolyFlagsEx=0 )
  4534.     {
  4535.         VALIDATE;
  4536.  
  4537.         //if(!GIsEditor) PolyFlags&=~PF_Selected;
  4538.         // Adjust PolyFlags according to Unreal's precedence rules.
  4539.         // Allows gouraud-polygonal fog only if specular is supported (1-pass fogging).
  4540.         if( (PolyFlags & (PF_RenderFog|PF_Translucent|PF_Modulated))!=PF_RenderFog || !UseVertexSpecular )
  4541.             PolyFlags &= ~PF_RenderFog;
  4542.  
  4543.         if( (!(PolyFlags & (PF_Translucent|PF_Modulated))&&(!(PolyFlagsEx & (PFX_AlphaMap|PFX_LightenModulate|PFX_DarkenModulate|PFX_Translucent2)))) )
  4544.             PolyFlags |= PF_Occlude;
  4545.         else if( PolyFlags & PF_Translucent )
  4546.             PolyFlags &= ~PF_Masked;
  4547.  
  4548.         // Detect changes in the blending modes.
  4549.         DWORD Xor   = CurrentPolyFlags   ^ PolyFlags;
  4550.         DWORD XorEx = CurrentPolyFlagsEx ^ PolyFlagsEx;
  4551.         // Adjust Cull Mode based on 'two sided flag*
  4552.         if(Xor&PF_TwoSided)
  4553.         {
  4554.             Direct3DDevice8->SetRenderState( D3DRS_CULLMODE,(PolyFlags&PF_TwoSided)?D3DCULL_NONE:D3DCULL_CCW);
  4555.         }
  4556.  
  4557.         if(XorEx&PFX_Clip)
  4558.         {
  4559.             Direct3DDevice8->SetRenderState( D3DRS_CLIPPING, (bool)(PolyFlagsEx&PFX_Clip));
  4560.         }
  4561.  
  4562.         if(XorEx&PFX_FlatShade)
  4563.         {
  4564.             Direct3DDevice8->SetRenderState( D3DRS_SHADEMODE, (PolyFlagsEx&PFX_FlatShade)?D3DSHADE_FLAT:D3DSHADE_GOURAUD );
  4565.         }
  4566.  
  4567.         if( (Xor  & (PF_Translucent|PF_Modulated|PF_Invisible|PF_Occlude|PF_Masked|PF_Highlighted|PF_NoSmooth|PF_RenderFog|PF_Memorized|PF_Selected))
  4568.           ||(XorEx& (PFX_AlphaMap|PFX_LightenModulate|PFX_DarkenModulate|PFX_Translucent2)))
  4569.         {
  4570.             if( Xor&(PF_Invisible|PF_Translucent|PF_Modulated|PF_Highlighted) || (XorEx&(PFX_AlphaMap|PFX_LightenModulate|PFX_DarkenModulate|PFX_Translucent2)))
  4571.             {
  4572.                 if ((XorEx & PFX_AlphaMap) && (!(PolyFlagsEx & PFX_AlphaMap)))
  4573.                 {
  4574.                     if (UseTrilinear)
  4575.                         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_MIPFILTER , D3DTEXF_LINEAR );
  4576.                     else
  4577.                         Direct3DDevice8->SetTextureStageState( 0, D3DTSS_MIPFILTER , D3DTEXF_POINT  );
  4578.                    
  4579.                     Direct3DDevice8->SetRenderState( D3DRS_ALPHAREF, 127);
  4580.                     Direct3DDevice8->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE );
  4581.                 }
  4582.  
  4583.                 if( !(PolyFlags & (PF_Invisible|PF_Translucent|PF_Modulated|PF_Highlighted)) && !(PolyFlagsEx & (PFX_AlphaMap|PFX_LightenModulate|PFX_DarkenModulate|PFX_Translucent2)))
  4584.                 {
  4585.                     SetAlphaBlendEnable(FALSE);
  4586.                     //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  4587.                 }
  4588.                 else if( PolyFlagsEx & PFX_Translucent2)
  4589.                 {
  4590.                     //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  4591.                     //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, Src);
  4592.                     //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, Dst );
  4593.                     SetAlphaBlendEnable(TRUE);
  4594.                     SetSrcBlend(D3DBLEND_SRCALPHA);
  4595.                     SetDstBlend(D3DBLEND_INVSRCCOLOR);
  4596.                 }
  4597.                 else if( PolyFlags & PF_Invisible )
  4598.                 {
  4599.                     //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  4600.                     //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ZERO );
  4601.                     //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  4602.                     SetAlphaBlendEnable(TRUE);
  4603.                     SetSrcBlend(D3DBLEND_ZERO);
  4604.                     SetDstBlend(D3DBLEND_ONE);
  4605.                 }
  4606.                 else if(PolyFlagsEx &PFX_DarkenModulate )
  4607.                 {
  4608.                     //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  4609.                     //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, 1  );
  4610.                     //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, 3  );
  4611.                     SetAlphaBlendEnable(TRUE);
  4612.                     SetSrcBlend(D3DBLEND_ZERO);
  4613.                     SetDstBlend(D3DBLEND_SRCCOLOR);
  4614.                 }
  4615.                 else if( PolyFlagsEx & PFX_LightenModulate )
  4616.                 {
  4617.                     //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  4618.                     //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, 2  );
  4619.                     //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, 2  );
  4620.                     SetAlphaBlendEnable(TRUE);
  4621.                     SetSrcBlend(D3DBLEND_ONE);
  4622.                     SetDstBlend(D3DBLEND_ONE);
  4623.                 }
  4624.                 else if( PolyFlags & PF_Translucent )
  4625.                 {
  4626.                     //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  4627.                     //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
  4628.                     //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR );
  4629.                     SetAlphaBlendEnable(TRUE);
  4630.                     SetSrcBlend(D3DBLEND_ONE);
  4631.                     SetDstBlend(D3DBLEND_INVSRCCOLOR);
  4632.                 }
  4633.                 else if( PolyFlags & PF_Modulated )
  4634.                 {
  4635.                     //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  4636.                     //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR );
  4637.                     //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR );
  4638.                     SetAlphaBlendEnable(TRUE);
  4639.                     SetSrcBlend(D3DBLEND_DESTCOLOR);
  4640.                     SetDstBlend(D3DBLEND_SRCCOLOR);
  4641.                 }
  4642.                 else if( PolyFlags & PF_Highlighted )
  4643.                 {
  4644.                     //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  4645.                     //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
  4646.                     //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  4647.                     SetAlphaBlendEnable(TRUE);
  4648.                     SetSrcBlend(D3DBLEND_ONE);
  4649.                     SetDstBlend(D3DBLEND_INVSRCALPHA);
  4650.                 }
  4651.                 else if( PolyFlagsEx & PFX_AlphaMap )
  4652.                 {
  4653.                     //debugf(_T("**Turning alphamap on."));
  4654.                     //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE);
  4655.                     //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA);
  4656.                     //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  4657.                     SetAlphaBlendEnable(TRUE);
  4658.                     SetSrcBlend(D3DBLEND_SRCALPHA);
  4659.                     SetDstBlend(D3DBLEND_INVSRCALPHA);
  4660.  
  4661.                     Direct3DDevice8->SetRenderState( D3DRS_ALPHAREF, 8);
  4662.                     Direct3DDevice8->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATER );
  4663.                     Direct3DDevice8->SetRenderState( D3DRS_ALPHATESTENABLE, 1 );
  4664.  
  4665.                     Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1);
  4666.                     Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  4667.                     Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
  4668.                    
  4669.                     Direct3DDevice8->SetTextureStageState( 0, D3DTSS_MIPFILTER , D3DTEXF_NONE );
  4670.                 }
  4671.             }
  4672.            
  4673.             if( Xor & PF_Invisible )
  4674.             {
  4675.                 UBOOL Invisible = ((PolyFlags&PF_Invisible)!=0);
  4676.                 SetAlphaBlendEnable(Invisible);
  4677.                 //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, Invisible );
  4678.                 //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ZERO );
  4679.                 //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  4680.                 SetSrcBlend(D3DBLEND_ZERO);
  4681.                 SetDstBlend(D3DBLEND_ONE);
  4682.  
  4683.             }
  4684.             if( Xor & PF_Occlude )
  4685.             {
  4686.                 Direct3DDevice8->SetRenderState( D3DRS_ZWRITEENABLE, (PolyFlags&PF_Occlude)!=0 );
  4687.             }
  4688.             if( Xor & PF_Masked )
  4689.             {
  4690.                 if( PolyFlags&PF_Masked )
  4691.                 {
  4692.                     Direct3DDevice8->SetRenderState( D3DRS_ALPHAREF, 127 );
  4693.                     Direct3DDevice8->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATER );
  4694.                     Direct3DDevice8->SetRenderState( D3DRS_ALPHATESTENABLE, 1 );
  4695.                 }
  4696.                 else
  4697.                 {
  4698.                     Direct3DDevice8->SetRenderState( D3DRS_ALPHATESTENABLE, 0 );
  4699.                 }
  4700.             }
  4701.             if( Xor & PF_NoSmooth )
  4702.             {
  4703.                 Direct3DDevice8->SetTextureStageState( 0, D3DTSS_MAGFILTER, (PolyFlags & PF_NoSmooth) ? D3DTEXF_POINT : D3DTEXF_LINEAR );
  4704.                 Direct3DDevice8->SetTextureStageState( 0, D3DTSS_MINFILTER, (PolyFlags & PF_NoSmooth) ? D3DTEXF_POINT : D3DTEXF_LINEAR );
  4705.             }
  4706.             if( Xor & PF_RenderFog )
  4707.             {
  4708.                 Direct3DDevice8->SetRenderState( D3DRS_SPECULARENABLE, (PolyFlags&PF_RenderFog)!=0 );
  4709.             }
  4710.             if( (Xor & PF_Memorized) || (Xor & PF_Selected) )
  4711.             {
  4712.                 if( PolyFlags&PF_Memorized )
  4713.                 {
  4714.                     // Lightmap
  4715.                     Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
  4716.                     Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
  4717.                 }
  4718.                 else
  4719.                 if( PolyFlags&PF_Selected )
  4720.                 {
  4721.                     // Alphamap
  4722.                     Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
  4723.                     Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
  4724.                 }
  4725.                 else
  4726.                 {
  4727.                     Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
  4728.                     Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
  4729.                 }
  4730.             }
  4731.         }
  4732.  
  4733.         CurrentPolyFlags  =PolyFlags;
  4734.         CurrentPolyFlagsEx=PolyFlagsEx;
  4735.     }
  4736.  
  4737.  
  4738.     void __forceinline ReleaseOldestTexture()
  4739.     {
  4740.         VALIDATE;
  4741.  
  4742.         if(!CachedTextures) return;
  4743.  
  4744.         INT Threshold=CachedTextures->Filler->PixelFormat->ActiveRAMPeak+1024*1024*3;
  4745.         if(Threshold<7*1024*1024) Threshold=7*1024*1024;
  4746.  
  4747.         while(CachedTextures && (CachedTextures->Filler->PixelFormat->BinnedRAM>Threshold))
  4748.         {
  4749.             FTexInfo *LowestFrameCount=NULL;
  4750.             FTexInfo *LowestFrameCountPrevious=NULL;
  4751.             FTexInfo *Previous=NULL;
  4752.             for(FTexInfo *Iterator=CachedTextures;Iterator;Previous=Iterator,Iterator=Iterator->NextTexture)
  4753.             {
  4754.                 if(!LowestFrameCount||(Iterator->FrameCounter<=LowestFrameCount->FrameCounter))
  4755.                 {
  4756.                     // Don't kick out anything that isn't over 60 frames old.
  4757.                     if((FrameCounter-Iterator->FrameCounter)>60)
  4758.                     {
  4759.                         LowestFrameCount=Iterator;
  4760.                         LowestFrameCountPrevious=Previous;
  4761.                     }
  4762.                 }
  4763.             }
  4764.  
  4765.             if(!LowestFrameCount) return;
  4766.  
  4767.             LowestFrameCount->Filler->PixelFormat->BinnedRAM -= LowestFrameCount->SizeBytes;
  4768.             LowestFrameCount->Filler->PixelFormat->Binned--;
  4769.  
  4770.             // Detach myself from the normal list:
  4771.             if(!LowestFrameCountPrevious)
  4772.             {
  4773.                 CachedTextures=CachedTextures->NextTexture;
  4774.             } else
  4775.             {
  4776.                 LowestFrameCountPrevious->NextTexture=LowestFrameCount->NextTexture;
  4777.             }
  4778.  
  4779.             INT HashIndex = ((7*(DWORD)LowestFrameCount->CacheId+(DWORD)(LowestFrameCount->CacheId>>32))) & (ARRAY_COUNT(TextureHash)-1);
  4780.  
  4781.             Previous=NULL;
  4782.             for(Iterator = TextureHash[HashIndex];
  4783.                 Iterator && Iterator!=LowestFrameCount;
  4784.                 Previous=Iterator,Iterator = Iterator->HashNext)
  4785.                 ;
  4786.  
  4787.             if(Iterator==LowestFrameCount)
  4788.             {
  4789.                 if(!Previous)
  4790.                 {
  4791.                     TextureHash[HashIndex]=TextureHash[HashIndex]->HashNext;
  4792.                 } else
  4793.                 {
  4794.                     Previous->HashNext=LowestFrameCount->HashNext;
  4795.                 }
  4796.             }
  4797.  
  4798.             if(LowestFrameCount->Texture8)
  4799.                 SafeRelease(LowestFrameCount->Texture8);
  4800.            
  4801.             SafeDelete(LowestFrameCount);
  4802.  
  4803.         }
  4804.     }
  4805.  
  4806.     void __forceinline __fastcall SetTextureNULL( DWORD dwStage )
  4807.     {
  4808.         check((dwStage>=0)&&(dwStage<ARRAY_COUNT(Stages)));
  4809.  
  4810.         Direct3DDevice8->SetTexture( dwStage, NULL );
  4811.         Stages[dwStage] = &NoTexture;
  4812.     }
  4813.  
  4814.     void __fastcall SetTexture( DWORD dwStage, FTextureInfo& Info, DWORD PolyFlags=0, UBOOL Precache=FALSE, DWORD PolyFlagsEx=0, UBOOL IsLightmap=FALSE )
  4815.     {
  4816.         check((dwStage>=0)&&(dwStage<ARRAY_COUNT(Stages)));
  4817.  
  4818.         UBOOL Masking=(PolyFlags&PF_Masked)?TRUE:FALSE;
  4819.         if(Stages[dwStage] && Stages[dwStage]->CacheId == Info.CacheID && Stages[dwStage]->Masking==Masking)
  4820.             return;
  4821.  
  4822.         INT HashIndex = (7 * (DWORD) Info.CacheID + (DWORD) (Info.CacheID >> 32)) & (ARRAY_COUNT(TextureHash) - 1);
  4823.  
  4824.  
  4825.         for(FTexInfo* TexInfo = TextureHash[HashIndex];
  4826.             TexInfo && !(TexInfo->CacheId == Info.CacheID && TexInfo->Masking==Masking);
  4827.             TexInfo = TexInfo->HashNext)
  4828.             ;
  4829.  
  4830.         if(!TexInfo)
  4831.         {
  4832.             if(Use2ndTierTextureCache)
  4833.                 ReleaseOldestTexture();
  4834.  
  4835.             // Create a new Direct3D texture.
  4836.             TexInfo = new FTexInfo;
  4837.             TexInfo->CacheId = Info.CacheID;
  4838.             TexInfo->Masking=Masking;
  4839.  
  4840.             TexInfo->NextTexture = CachedTextures;
  4841.             CachedTextures = TexInfo;
  4842.  
  4843.             TexInfo->HashNext = TextureHash[HashIndex];
  4844.             TextureHash[HashIndex] = TexInfo;
  4845.  
  4846.             // Get filler object.
  4847.  
  4848.             FTexFiller* Filler = NULL;
  4849.  
  4850.             switch(Info.Format)
  4851.             {
  4852.                 case TEXF_P8:    Filler = ( !Format1555.Supported || Use32BitTextures )? (FTexFiller*) &Filler8888_P8 : (FTexFiller*) &Filler1555_P8; break;
  4853.                 case TEXF_DXT1:  Filler = &FillerDXT1; break;
  4854.                 case TEXF_RGBA7: Filler = (!Format1555.Supported || Use32BitTextures ) ? (FTexFiller*) &Filler8888_RGBA7 : (FTexFiller*) &Filler1555_RGBA7; break;
  4855.                 case TEXF_RGBA8: Filler = &Filler8888_RGBA8; break;
  4856.                 default:
  4857.                     appErrorf(TEXT("Unsupported Texture Format"));
  4858.             }
  4859.            
  4860.             TexInfo->Filler=Filler;
  4861.             if(Info.bParametric)
  4862.             {
  4863.                 TexInfo->UseMips=false;
  4864.                 Info.NumMips=1;
  4865.             }
  4866.  
  4867.             // Calculate the mipmap to use.
  4868.             DWORD   FirstMip = 0;
  4869.  
  4870.             while(Info.Mips[FirstMip]->USize > (INT) DeviceCaps8.MaxTextureWidth || Info.Mips[FirstMip]->VSize > (INT) DeviceCaps8.MaxTextureHeight)
  4871.                 if(++FirstMip >= (DWORD) Info.NumMips)
  4872.                     appErrorf(TEXT("D3D Driver: Encountered oversize texture without sufficient mipmaps"));
  4873.  
  4874.             DWORD   USize = Info.Mips[FirstMip]->USize,
  4875.                     VSize = Info.Mips[FirstMip]->VSize;
  4876.  
  4877.             // Setup the texture info.
  4878.             TexInfo->FirstMip = FirstMip;
  4879.             TexInfo->UScale = 1.f / (USize * (1 << FirstMip) * Info.UScale);
  4880.             TexInfo->VScale = 1.f / (VSize * (1 << FirstMip) * Info.VScale);
  4881.             TexInfo->UseMips = (FirstMip < (DWORD) Info.NumMips - 1);
  4882.  
  4883.             // Create the Direct3D texture.
  4884.             D3D_CHECK((h=Direct3DDevice8->CreateTexture(USize,VSize,Info.NumMips - FirstMip,0,Filler->PixelFormat->Direct3DFormat,
  4885.                 D3DPOOL_MANAGED,&TexInfo->Texture8)));
  4886.  
  4887.             TexInfo->SizeBytes = Info.USize * Info.VSize * TexInfo->Filler->PixelFormat->BitsPerPixel / 8;
  4888.             if(!Info.NumMips) TexInfo->SizeBytes+=TexInfo->SizeBytes/3;    
  4889.  
  4890.             TexInfo->Filler->PixelFormat->Binned++;
  4891.             TexInfo->Filler->PixelFormat->BinnedRAM += TexInfo->SizeBytes;
  4892.  
  4893.             Info.bRealtimeChanged = 1;
  4894.         }
  4895.  
  4896.         // Transfer texture data.
  4897.         if( Info.bRealtimeChanged /*&& Info.bParametric || (Info.Format==TEXF_RGBA7 && GET_COLOR_DWORD(*Info.MaxColor)==0xFFFFFFFF)*/ )
  4898.         {
  4899.             DWORD Cycles=0;
  4900.             clock(Cycles);
  4901.  
  4902.             // Get ready for blt.      
  4903.             if(!IsLightmap&&!Use2ndTierTextureCache) Info.Load();   // Dynamically load the texture if it hasn't already been done. (auto checks for parametric)
  4904.  
  4905.             //debugf(_T("Uploading texture:%s"),Info.Texture->GetFullName());
  4906.             Info.CacheMaxColor();
  4907.             TexInfo->MaxColor = (Format8888.Supported && Use32BitTextures) ? FColor(255,255,255,1) : *Info.MaxColor;
  4908.  
  4909.             // Update texture data.
  4910.             TexInfo->Filler->PixelFormat->Uploads++;
  4911.             TexInfo->Filler->BeginUpload( TexInfo, Info, PolyFlags, PolyFlagsEx );
  4912.             INT Count = Info.NumMips - TexInfo->FirstMip;
  4913.             for( INT MipIndex=TexInfo->FirstMip, ListIndex=0; ListIndex<Count; ListIndex++,MipIndex++ )
  4914.             {
  4915.                 // Lock the mip-level.
  4916.                 D3DLOCKED_RECT  LockedRect;
  4917.                 D3DSURFACE_DESC SurfaceDesc;
  4918.                 int             BPP=GetFormatBPP(TexInfo->Filler->PixelFormat->Direct3DFormat);
  4919.  
  4920.                 TexInfo->Texture8->GetLevelDesc(ListIndex,&SurfaceDesc);
  4921.                 TexInfo->Texture8->LockRect(ListIndex,&LockedRect,NULL,0);
  4922.                
  4923.                 if(Info.Mips[MipIndex]->DataPtr)
  4924.                 {
  4925.                     if(Info.Format==TEXF_RGBA7)
  4926.                     {
  4927.                         TexInfo->Filler->UploadMipmap(TexInfo,(BYTE*) LockedRect.pBits,LockedRect.Pitch,Info,MipIndex,PolyFlags);
  4928.                     } else
  4929.                     {
  4930.                         for(DWORD u = 0;u < SurfaceDesc.Width;u += Info.Mips[MipIndex]->USize)
  4931.                             for(DWORD v = 0;v < SurfaceDesc.Height;v += Info.Mips[MipIndex]->VSize)
  4932.                                 TexInfo->Filler->UploadMipmap(TexInfo,(BYTE*) LockedRect.pBits + u * BPP / 8 + v * LockedRect.Pitch,LockedRect.Pitch,Info,MipIndex,PolyFlags);
  4933.                     }
  4934.                 }
  4935.  
  4936.                 // Unlock the mip-level.
  4937.                 TexInfo->Texture8->UnlockRect(ListIndex);
  4938.             }
  4939.             Stats.TexUploads++;
  4940.  
  4941.             // Unload texture.
  4942.             Info.bRealtimeChanged = 0;
  4943.            
  4944.             if(!Info.bRealtime&&!Info.bParametric&&!IsLightmap&&!Use2ndTierTextureCache&&(Info.Texture&&!Info.Texture->IsA(UProceduralTexture::StaticClass()))) Info.Unload(); 
  4945.             unclock(Cycles);
  4946.             TexInfo->Filler->PixelFormat->UploadCycles += Cycles;
  4947.         }
  4948.        
  4949.         if( Precache )
  4950.         {
  4951.             Stages[dwStage] = TexInfo;
  4952.             return;
  4953.         }
  4954.         // Update texture info.
  4955.  
  4956.         if(TexInfo->FrameCounter != FrameCounter)
  4957.         {
  4958.             TexInfo->Filler->PixelFormat->Active++;
  4959.             TexInfo->Filler->PixelFormat->ActiveRAM += TexInfo->SizeBytes;
  4960.         }
  4961.  
  4962.         TexInfo->FrameCounter = FrameCounter;
  4963.         TexInfo->Filler->PixelFormat->Sets++;
  4964.  
  4965.         // Set Direct3D state.
  4966.         Direct3DDevice8->SetTexture(dwStage,TexInfo->Texture8);
  4967.  
  4968.         if(!Stages[dwStage] || TexInfo->UseMips != Stages[dwStage]->UseMips)
  4969.             Direct3DDevice8->SetTextureStageState(dwStage,D3DTSS_MIPFILTER,TexInfo->UseMips == 0 ? D3DTEXF_NONE : UseTrilinear ? D3DTEXF_LINEAR : D3DTEXF_POINT);
  4970.        
  4971.         Stages[dwStage] = TexInfo;
  4972.         VALIDATE;
  4973.  
  4974.     }
  4975.  
  4976.     // JEP...
  4977.     void CleanupRenderTargetResources(void)
  4978.     {
  4979.         for (INT i = 0; i < RenderTargetArray.Num(); i++)
  4980.             ShutdownRenderTargetRes(&RenderTargetArray(i));
  4981.  
  4982.         SafeRelease(ClipperTexture);
  4983.     }
  4984.     // ...JEP
  4985.  
  4986.     void RecognizePixelFormat( FPixFormat& Dest, const D3DFORMAT Direct3DFormat, const TCHAR* InDesc )
  4987.     {
  4988.         VALIDATE;
  4989.  
  4990.         Dest.Supported       = true;
  4991.         Dest.Direct3DFormat  = Direct3DFormat;
  4992.         Dest.Desc            = InDesc;
  4993.         Dest.BitsPerPixel    = GetFormatBPP(Direct3DFormat);
  4994.         Dest.Next            = FirstPixelFormat;
  4995.         FirstPixelFormat     = &Dest;
  4996.     }
  4997.  
  4998.     UBOOL __fastcall SetRes( INT NewX, INT NewY, INT NewColorBytes, UBOOL Fullscreen )
  4999.     {
  5000.         debugf(TEXT("SetRes(NewX=%i,NewY=%i,NewColorBytes=%i,Fullscreen%i) (this:%08x);"),NewX,NewY,NewColorBytes,Fullscreen,this);
  5001.         // Verify my current state:
  5002.         verify(this);
  5003.         verify(Direct3D8);
  5004.         verify(NewColorBytes<=4);
  5005.         //if(BeginSceneCount) EndScene();
  5006.         //check(LockCount==0);
  5007.         if(LockCount>0)
  5008.             Unlock(0);
  5009.  
  5010.         // If D3D already inited, uninit it now.:
  5011.         UnSetRes(NULL,0);
  5012.  
  5013.         // Enumerate device display modes.
  5014.         DisplayModes.Empty(Direct3D8->GetAdapterModeCount(BestAdapterIndex));
  5015.  
  5016.         for(DWORD Index=0;Index<Direct3D8->GetAdapterModeCount(BestAdapterIndex);Index++)
  5017.         {
  5018.             D3DDISPLAYMODE  DisplayMode;
  5019.             Direct3D8->EnumAdapterModes(BestAdapterIndex,Index,&DisplayMode);
  5020.  
  5021.             if((DisplayMode.Width >=640)
  5022.              &&(DisplayMode.Height>=480))
  5023.                 DisplayModes.AddItem(DisplayMode);
  5024.         }
  5025.  
  5026.         // Exit if just testing.
  5027.         if(!Viewport)
  5028.         {
  5029.             SaveConfig();
  5030.             UnSetRes(TEXT("Successfully tested Direct3D presence"),0);
  5031.             return 1;
  5032.         }
  5033.  
  5034.         // Remember parameters.
  5035.         ViewporthWnd       = (HWND)Viewport->GetWindow();
  5036.         ViewportX          = Min( NewX, MaxResWidth  );
  5037.         ViewportY          = Min( NewY, MaxResHeight );
  5038.         ViewportColorBits  = NewColorBytes * 8;
  5039.         ViewportFullscreen = Fullscreen;
  5040.  
  5041.         D3DFORMAT AdapterFormat;
  5042.  
  5043.         // See if the window is full screen.
  5044.         if(Fullscreen)
  5045.         {
  5046.             if(DisplayModes.Num()==0 )
  5047.                 return UnSetRes(TEXT("No fullscreen display modes found"),0);
  5048.  
  5049.             // Find matching display mode.
  5050.  
  5051.             INT BestMode = 0,
  5052.                 BestError = MAXINT;
  5053.  
  5054.             for(INT Index = 0;Index < DisplayModes.Num();Index++)
  5055.             {
  5056.                 INT ThisError
  5057.                 =   Abs((INT)DisplayModes(Index).Width -(INT)ViewportX)
  5058.                 +   Abs((INT)DisplayModes(Index).Height-(INT)ViewportY)
  5059.                 +   Abs((INT)GetFormatBPP(DisplayModes(Index).Format)-(INT)ViewportColorBits);
  5060.  
  5061.                 if(ThisError < BestError && (GetFormatBPP(DisplayModes(Index).Format)==16 || GetFormatBPP(DisplayModes(Index).Format)==24 || GetFormatBPP(DisplayModes(Index).Format)==32) && (DisplayModes(Index).Format >= D3DFMT_R8G8B8 && DisplayModes(Index).Format <= D3DFMT_X4R4G4B4))
  5062.                 {
  5063.                     BestMode = Index;
  5064.                     BestError = ThisError;
  5065.                 //  debugf(NAME_Init,TEXT("Next mode is best match so far:"));
  5066.                 }
  5067.                
  5068.                 //debugf(NAME_Init,TEXT("Enum modes: %ix%ix%i "),(INT)DisplayModes(Index).Width,(INT)DisplayModes(Index).Height,GetFormatBPP(DisplayModes(Index).Format));
  5069.             }
  5070.  
  5071.             if(BestError == MAXINT)
  5072.                 return UnSetRes(TEXT("No acceptable display modes found"),0);
  5073.  
  5074.             ViewportColorBits = GetFormatBPP(DisplayModes(BestMode).Format);
  5075.             ViewportX         = DisplayModes(BestMode).Width;
  5076.             ViewportY         = DisplayModes(BestMode).Height;
  5077.  
  5078.             AdapterFormat = DisplayModes(BestMode).Format;
  5079.  
  5080.             debugf(NAME_Init,TEXT("Best-match display mode: %ix%ix%i (Error=%i)"),DisplayModes(BestMode).Width,DisplayModes(BestMode).Height,GetFormatBPP(DisplayModes(BestMode).Format),BestError);
  5081.  
  5082.         }
  5083.         else
  5084.         {
  5085. #if 0
  5086.             D3DDISPLAYMODE  DisplayMode;
  5087.  
  5088.             if(FAILED(h=Direct3D8->GetAdapterDisplayMode(BestAdapterIndex,&DisplayMode)))
  5089.                 return UnSetRes(TEXT("GetAdapterDisplayMode"),h);
  5090.  
  5091.             AdapterFormat = DisplayMode.Format;
  5092.             ViewportColorBits = GetFormatBPP(AdapterFormat);
  5093. #else
  5094.             AdapterFormat = OriginalDisplayMode.Format;
  5095.             //ViewportX = OriginalDisplayMode.Width;
  5096.             //ViewportY= OriginalDisplayMode.Height;
  5097.             ViewportColorBits = GetFormatBPP(AdapterFormat);
  5098. #endif
  5099.         }
  5100.  
  5101.         // Setup the presentation parameters.
  5102.         D3DPRESENT_PARAMETERS PresentParms;
  5103.         appMemzero(&PresentParms,sizeof(PresentParms));
  5104.  
  5105.         //Fullscreen=1;
  5106.         //if(GIsEditor)
  5107.         PresentParms.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
  5108.  
  5109.         PresentParms.Windowed = !Fullscreen;
  5110.         PresentParms.hDeviceWindow = (HWND)ViewporthWnd;
  5111.         PresentParms.SwapEffect = Fullscreen ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_COPY;
  5112.         PresentParms.BackBufferWidth = Max(ViewportX,1);
  5113.         PresentParms.BackBufferHeight = Max(ViewportY,1);
  5114.         PresentParms.BackBufferCount = (Fullscreen ? (UseTripleBuffering ? 3: 2) : 1);
  5115.         PresentParms.EnableAutoDepthStencil = TRUE;
  5116.         PresentParms.FullScreen_PresentationInterval = Fullscreen ? (UseVSync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE) : D3DPRESENT_INTERVAL_DEFAULT;
  5117.         PresentParms.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
  5118.  
  5119.         //PresentParms.FullScreen_PresentationInterval=D3DPRESENT_INTERVAL_DEFAULT/*D3DPRESENT_INTERVAL_ONE*/ /*D3DPRESENT_INTERVAL_IMMEDIATE*/;
  5120.         //PresentParms.SwapEffect=D3DSWAPEFFECT_COPY;
  5121.        
  5122.         // Determine which back buffer format to use.
  5123.         D3DFORMAT BackBufferFormat = (ViewportColorBits == 32 ? D3DFMT_A8R8G8B8 : ViewportColorBits == 16 ? D3DFMT_R5G6B5 : D3DFMT_X8R8G8B8);
  5124.         while(Direct3D8->CheckDeviceFormat(BestAdapterIndex,D3DDEVTYPE_HAL,AdapterFormat,D3DUSAGE_RENDERTARGET,D3DRTYPE_SURFACE,BackBufferFormat) != D3D_OK)
  5125.         {
  5126.                  if(BackBufferFormat == D3DFMT_A8R8G8B8)    BackBufferFormat = D3DFMT_X8R8G8B8;
  5127.             else if(BackBufferFormat == D3DFMT_X8R8G8B8)    BackBufferFormat = D3DFMT_R5G6B5;
  5128.             else if(BackBufferFormat == D3DFMT_R8G8B8)      BackBufferFormat = D3DFMT_X8R8G8B8;
  5129.             else if(BackBufferFormat == D3DFMT_R5G6B5)      BackBufferFormat = D3DFMT_X1R5G5B5;
  5130.             else return UnSetRes(TEXT("CheckDeviceFormat"),0);
  5131.  
  5132.             if(Fullscreen)
  5133.                 AdapterFormat = BackBufferFormat;
  5134.         }
  5135.  
  5136.         PresentParms.BackBufferFormat = BackBufferFormat;
  5137.  
  5138.         // Determine which depth buffer format to use.
  5139.         D3DFORMAT DepthFormat = (ViewportColorBits==32 ? D3DFMT_D32 : D3DFMT_D16);
  5140.  
  5141.         while(Direct3D8->CheckDeviceFormat(BestAdapterIndex,D3DDEVTYPE_HAL,AdapterFormat,D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,DepthFormat) != D3D_OK ||
  5142.               Direct3D8->CheckDepthStencilMatch(BestAdapterIndex,D3DDEVTYPE_HAL,AdapterFormat,BackBufferFormat,DepthFormat) != D3D_OK)
  5143.         {
  5144.                  if(DepthFormat == D3DFMT_D32)    DepthFormat = D3DFMT_D24S8;
  5145.             else if(DepthFormat == D3DFMT_D24S8)  DepthFormat = D3DFMT_D16;
  5146.             else if(DepthFormat == D3DFMT_D16)
  5147.                 return UnSetRes(TEXT("CheckDepthStencilMatch"),0);
  5148.         }
  5149.  
  5150.         //debugf(TEXT("Using depth-buffer format %u(%u-bit)"),DepthFormat,GetFormatBPP(DepthFormat));
  5151.         PresentParms.AutoDepthStencilFormat = DepthFormat;
  5152.  
  5153. #ifdef LOG_PRESENT_PARMS
  5154.         // Dump present parms, useful for debugging.
  5155.         LogPresentParms(PresentParms);
  5156. #endif
  5157.  
  5158.         if(Direct3DDevice8)
  5159.         {
  5160.             CleanupRenderTargetResources();
  5161.             CleanupVertexBuffers();
  5162.  
  5163.             //SafeRelease(Direct3DDevice8);
  5164.  
  5165.             D3D_CHECK(Direct3DDevice8->Reset(&PresentParms));
  5166.         }
  5167.  
  5168.         if(!Direct3DDevice8)
  5169.         {
  5170.             //PresentParms.SwapEffect=D3DSWAPEFFECT_DISCARD;
  5171.             PresentParms.MultiSampleType=D3DMULTISAMPLE_NONE;
  5172.            
  5173.             // Create the Direct3D device.
  5174.             if(FAILED(h=Direct3D8->CreateDevice(BestAdapterIndex,D3DDEVTYPE_HAL,ViewporthWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING,&PresentParms,&Direct3DDevice8)))
  5175.             {
  5176.                 debugf(TEXT("ViewporthWnd:%08x"),ViewporthWnd);
  5177.                 debugf(TEXT("Failed to set hardware vertex processing: %s, attempting to set software vertexprocessing"),DXGetErrorString8(h));
  5178.                 // If hardware vertex processing failed, switch to software:
  5179.                 if(FAILED(h=Direct3D8->CreateDevice(BestAdapterIndex,D3DDEVTYPE_HAL,ViewporthWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&PresentParms,&Direct3DDevice8)))
  5180.                     return UnSetRes(TEXT("CreateDevice (Failed to set software vertex processing)"),h);
  5181.                 else
  5182.                     debugf(_T("Device is using software vertex processing."));
  5183.             }
  5184.         }
  5185.  
  5186.         // Set viewport.
  5187.         ViewportInfo.X      = 0;
  5188.         ViewportInfo.Y      = 0;
  5189.         ViewportInfo.Width  = ViewportX;
  5190.         ViewportInfo.Height = ViewportY;
  5191.         ViewportInfo.MaxZ   = 1.f;
  5192.         ViewportInfo.MinZ   = 0.f;
  5193.         verify(!FAILED(Direct3DDevice8->SetViewport(&ViewportInfo)));
  5194.         verify(!FAILED(Direct3DDevice8->GetViewport(&ViewportInfo)));
  5195.  
  5196.         // Handle the texture formats we need.
  5197.         {
  5198.             // Determine which texture formats the device supports by calling CheckDeviceFormat for each supported format.
  5199.             FirstPixelFormat = NULL;
  5200.  
  5201.             if(!FAILED(Direct3D8->CheckDeviceFormat(BestAdapterIndex,D3DDEVTYPE_HAL,AdapterFormat,0,D3DRTYPE_TEXTURE,D3DFMT_A8R8G8B8)))
  5202.                 RecognizePixelFormat(Format8888,D3DFMT_A8R8G8B8,TEXT("A8R8G8B8"));
  5203.                        
  5204.             if(!FAILED(Direct3D8->CheckDeviceFormat(BestAdapterIndex,D3DDEVTYPE_HAL,AdapterFormat,0,D3DRTYPE_TEXTURE,D3DFMT_A1R5G5B5)))
  5205.                RecognizePixelFormat(Format1555,D3DFMT_A1R5G5B5,TEXT("A1R5G5B5"));
  5206.         }
  5207.  
  5208.         // Verify mipmapping supported.
  5209.         if(!(DeviceCaps8.TextureFilterCaps & D3DPTFILTERCAPS_MIPFPOINT)
  5210.          &&!(DeviceCaps8.TextureFilterCaps & D3DPTFILTERCAPS_MIPFLINEAR))
  5211.         {
  5212.             appErrorf(TEXT("D3D Driver: Mipmapping not available with this driver"));
  5213.         } else
  5214.         {
  5215.             if( DeviceCaps8.TextureFilterCaps & D3DPTFILTERCAPS_MIPFLINEAR )
  5216.                 debugf( NAME_Init, TEXT("D3D Driver: Supports trilinear"));
  5217.             else
  5218.                 UseTrilinear = 0;
  5219.         }
  5220.  
  5221.         // Check caps.
  5222.         if( DeviceCaps8.ShadeCaps & D3DPSHADECAPS_SPECULARGOURAUDRGB )
  5223.             debugf( NAME_Init, TEXT("D3D Driver: Supports specular gouraud") );
  5224.         else
  5225.             UseVertexSpecular = 0;
  5226.  
  5227.         if( DeviceCaps8.TextureOpCaps & D3DTEXOPCAPS_BLENDDIFFUSEALPHA )
  5228.             debugf( NAME_Init, TEXT("D3D Driver: Supports BLENDDIFFUSEALPHA") );
  5229.         else
  5230.             DetailTextures = 0;
  5231.  
  5232.  
  5233.         // Depth buffering.
  5234.         Direct3DDevice8->SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE  );
  5235. #if 0
  5236.         /* NJS: Potentially enable W-buffering if it exists. */
  5237.         if( DeviceCaps8.RasterCaps & D3DPRASTERCAPS_WBUFFER)
  5238.         {
  5239.             debugf( NAME_Init, TEXT("D3D Driver: Supports w-buffering.") );
  5240.             if((ViewportColorBits==16) ) // NVidia w-buffering in 32-bit color is borked on Pentium III's.
  5241.             {
  5242.                 Direct3DDevice8->SetRenderState( D3DRS_ZENABLE, D3DZB_USEW );
  5243.                 debugf( NAME_Init, TEXT("D3D Driver: w-buffering enabled.") );
  5244.             } else
  5245.                 debugf(NAME_Init, TEXT("D3D Driver: w-buffering NOT enabled."));
  5246.         }
  5247. #endif
  5248.  
  5249.         // Init render states.
  5250.         {
  5251.             Direct3DDevice8->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
  5252.             Direct3DDevice8->SetRenderState( D3DRS_DITHERENABLE, TRUE );
  5253.             Direct3DDevice8->SetRenderState( D3DRS_ZFUNC,D3DCMP_LESSEQUAL);
  5254.             Direct3DDevice8->SetRenderState( D3DRS_FOGCOLOR, 0 );        
  5255.             Direct3DDevice8->SetRenderState( D3DRS_FOGTABLEMODE, D3DFOG_LINEAR );
  5256.             FLOAT FogStart=0.f, FogEnd = 65535.f;
  5257.             Direct3DDevice8->SetRenderState( D3DRS_FOGSTART, *(DWORD*)&FogStart );
  5258.             Direct3DDevice8->SetRenderState( D3DRS_FOGEND, *(DWORD*)&FogEnd );
  5259.             Direct3DDevice8->SetRenderState( D3DRS_LIGHTING, FALSE );
  5260.             ZBias=-1.f; // Set ZBias to an invalid state to force it to be reset next time SetZBias is called
  5261.             SrcBlend=(D3DBLEND)0;
  5262.             DstBlend=(D3DBLEND)0;
  5263.             AlphaBlendEnable=-1;
  5264.             BeginSceneCount=0;
  5265.             LockCount=0;
  5266.             TextureClampMode=-1;
  5267.  
  5268.             D3DMATERIAL8 Material8;
  5269.             memset(&Material8,0,sizeof(Material8));
  5270.  
  5271.             Material8.Ambient.r = 1.0f; Material8.Ambient.g = 1.0f; Material8.Ambient.b = 1.0f; Material8.Ambient.a = 1.0f;
  5272.             Material8.Diffuse.r = 0.5f; Material8.Diffuse.g = 0.5f; Material8.Diffuse.b = 0.5f; Material8.Diffuse.a = 1.0f;
  5273.             Material8.Power = 0.f;
  5274.  
  5275.             Direct3DDevice8->SetMaterial(&Material8);
  5276.             Direct3DDevice8->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_GOURAUD);
  5277.             Direct3DDevice8->SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE,D3DMCS_COLOR1);
  5278.             Direct3DDevice8->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE,D3DMCS_MATERIAL);
  5279.         }
  5280.  
  5281.         // Init texture stage state.
  5282.         {
  5283.             // Set stage 0 state.
  5284.             //FLOAT LodBias=-0.5f;
  5285.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_MIPMAPLODBIAS, *(DWORD*)&LodBias );
  5286.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ADDRESSU,   D3DTADDRESS_WRAP );
  5287.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ADDRESSV,   D3DTADDRESS_WRAP );
  5288.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  5289.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  5290.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  5291.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  5292.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
  5293.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
  5294.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  5295.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  5296.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_MIPFILTER, (UseTrilinear ? D3DTEXF_LINEAR : D3DTEXF_POINT));
  5297.             Direct3DDevice8->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
  5298.  
  5299.             // Set stage 1 state.
  5300.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MIPMAPLODBIAS, *(DWORD*)&LodBias );
  5301.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSU,   D3DTADDRESS_WRAP );
  5302.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSV,   D3DTADDRESS_WRAP );
  5303.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  5304.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT );
  5305.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
  5306.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  5307.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT );
  5308.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
  5309.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  5310.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  5311.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MIPFILTER, UseTrilinear ? D3DTEXF_LINEAR : D3DTEXF_POINT  );
  5312.             Direct3DDevice8->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 );
  5313.         }
  5314.  
  5315.         // Update the viewport.
  5316.         verify(Viewport->ResizeViewport((Fullscreen ? BLIT_Fullscreen : 0) | BLIT_Direct3D, NewX, ViewportY, ViewportColorBits / 8 ));
  5317.         Lock( FColor(0,0,0), 0, 0, FPlane(0,0,0,0), FPlane(0,0,0,0), FPlane(0,0,0,0), LOCKR_ClearScreen, NULL, NULL );
  5318.         Unlock(1);
  5319.  
  5320.         // Allocate dynamic vertex buffers.
  5321.         WorldVertices.Init(Direct3DDevice8,WORLDSURFACE_VERTEXBUFFER_SIZE);
  5322.         ActorVertices.Init(Direct3DDevice8,ACTORPOLY_VERTEXBUFFER_SIZE);
  5323.         LineVertices.Init(Direct3DDevice8,LINE_VERTEXBUFFER_SIZE);
  5324.         ParticleVertices.Init(Direct3DDevice8,PARTICLE_VERTEXBUFFER_SIZE);
  5325.  
  5326.     #ifdef BATCH_PROJECTOR_POLYS
  5327.         ProjectorVertices.Init(Direct3DDevice8, PROJECTOR_VERTEXBUFFER_SIZE);
  5328.     #endif
  5329.         Flush(!GIsEditor);  // Don't force a precache.
  5330.  
  5331.         // JEP...
  5332.         // Determine which rendertarget format to use, and create clipper texture
  5333.         {
  5334.             D3DDISPLAYMODE      DisplayMode;
  5335.  
  5336.             Direct3D8->GetAdapterDisplayMode(BestAdapterIndex,&DisplayMode);
  5337.  
  5338.             AdapterFormat = DisplayMode.Format;
  5339.  
  5340.             //RenderTargetFormat = D3DFMT_R5G6B5;
  5341.             RenderTargetFormat = AdapterFormat;
  5342.  
  5343.             TCHAR *FmtStr = TEXT("Unknown");
  5344.  
  5345.             if (Direct3D8->CheckDeviceFormat(BestAdapterIndex,D3DDEVTYPE_HAL,AdapterFormat,D3DUSAGE_RENDERTARGET,D3DRTYPE_SURFACE,RenderTargetFormat) != D3D_OK)
  5346.                 RenderTargetFormat = D3DFMT_UNKNOWN;
  5347.  
  5348.             #define FMT2STR(x) case x: FmtStr = TEXT(#x); break;
  5349.  
  5350.             switch (RenderTargetFormat)
  5351.             {
  5352.                 FMT2STR(D3DFMT_A8R8G8B8);
  5353.                 FMT2STR(D3DFMT_X8R8G8B8);
  5354.                 FMT2STR(D3DFMT_R5G6B5);
  5355.                 FMT2STR(D3DFMT_X1R5G5B5);
  5356.             }
  5357.  
  5358.             debugf(NAME_Init,TEXT("Rendertarget format: %s"), FmtStr);
  5359.        
  5360.             if (RenderTargetFormat != D3DFMT_UNKNOWN)
  5361.             {
  5362.                 // Create a 128x1 clipper texture (also used to fade projected textures out)
  5363.                 if (Direct3DDevice8->CreateTexture(128,1,1,0,D3DFMT_R5G6B5,D3DPOOL_MANAGED,&ClipperTexture) == D3D_OK)
  5364.                 {
  5365.                     debugf(NAME_Init,TEXT("Clipper texture created"));
  5366.  
  5367.                     D3DLOCKED_RECT  LockedRect;
  5368.                     D3DSURFACE_DESC SurfaceDesc;
  5369.  
  5370.                     ClipperTexture->GetLevelDesc(0,&SurfaceDesc);
  5371.  
  5372.                     if (ClipperTexture->LockRect(0,&LockedRect,NULL,0) == D3D_OK)
  5373.                     {
  5374.                         WORD *Bits = (WORD*)LockedRect.pBits;
  5375.  
  5376.                         // Create a grey scale ramp
  5377.                         for(DWORD u = 0;u < SurfaceDesc.Width; u++)
  5378.                         {
  5379.                             WORD    Val = (u<<1);
  5380.                
  5381.                             if (u == 0)     // This is the pixel that will actually clip out pixels that are behind the near projector plane
  5382.                                 Val = 255;
  5383.  
  5384.                             Bits[u] = ((Val>>3)<<11) | ((Val>>2)<<5) | (Val>>3);
  5385.                         }
  5386.  
  5387.                         ClipperTexture->UnlockRect(0);
  5388.                     }
  5389.                 }
  5390.             }
  5391.  
  5392.             // If we already have some render targets, re-create them with (potentially) new format
  5393.             for (INT i = 0; i < RenderTargetArray.Num(); i++)
  5394.                 if (!InitRenderTargetRes(&RenderTargetArray(i)))
  5395.                     appErrorf(TEXT("SetRes: InitRenderTargetRes FAILED"));
  5396.         }
  5397.         // ...JEP
  5398.  
  5399.         return 1;
  5400.     }
  5401.  
  5402.     UBOOL __fastcall UnSetRes( const TCHAR* Msg, HRESULT h )
  5403.     {
  5404.         if(BeginSceneCount) EndScene();
  5405.  
  5406.         Flush(0);
  5407.         CleanupRenderTargetResources(); // JEP: Free render targets
  5408.         CleanupVertexBuffers();
  5409.  
  5410.         if( Msg ) debugf(NAME_Init,TEXT("%s (%s)"),Msg,DXGetErrorString8(h));
  5411.         return 0;
  5412.     }
  5413.  
  5414.     D3DCOLOR UpdateModulation( INT& ModulateThings, FPlane& FinalColor, const FPlane& MaxColor )
  5415.     {
  5416.         VALIDATE;
  5417.  
  5418.         FinalColor *= MaxColor;
  5419.         return --ModulateThings ? 0xffffffff : (FColor(FinalColor).TrueColor() | 0xff000000);
  5420.     }
  5421.  
  5422.     void SetDistanceFog(UBOOL Enable)
  5423.     {  
  5424.         VALIDATE;
  5425.  
  5426.         if((!UseDistanceFog)||(Enable==DistanceFogEnabled)) return;
  5427.  
  5428.         if(Enable)
  5429.         {      
  5430.             // Enable fog.
  5431.             Direct3DDevice8->SetRenderState(D3DRS_FOGENABLE, TRUE);
  5432.             Direct3DDevice8->SetRenderState(D3DRS_RANGEFOGENABLE, TRUE);
  5433.  
  5434.             // Set the fog color.
  5435.             Direct3DDevice8->SetRenderState(D3DRS_FOGCOLOR, ((DWORD)(DistanceFogColor.R)<<16) | ((DWORD)(DistanceFogColor.G)<<8) | ((DWORD)(DistanceFogColor.B)));
  5436.  
  5437.             // Set fog parameters.
  5438.             Direct3DDevice8->SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_LINEAR);
  5439.             Direct3DDevice8->SetRenderState(D3DRS_FOGSTART, *(DWORD *)(&DistanceFogBegin));
  5440.             Direct3DDevice8->SetRenderState(D3DRS_FOGEND,   *(DWORD *)(&DistanceFogEnd));
  5441.         }
  5442.         else
  5443.             Direct3DDevice8->SetRenderState(D3DRS_FOGENABLE, FALSE);       
  5444.  
  5445.         DistanceFogEnabled=Enable;
  5446.     }
  5447.  
  5448.     // JEP...
  5449.     #define RENDER_TARGET_TO_INDEX(x) ((INT)x-1)
  5450.     #define INDEX_TO_RENDER_TARGET(x) ((void*)(x+1))        // The +1 is so that we can assume 0 is NULL
  5451.  
  5452.     //============================================================================================
  5453.     //  InitRenderTargetRes
  5454.     //============================================================================================
  5455.     UBOOL InitRenderTargetRes(RenderTargetInfo *RT)
  5456.     {
  5457.         if (!RT->Active)
  5458.         {
  5459.             if (RT->pRenderTargetTex || RT->pRenderTargetSurf)
  5460.                 appErrorf(TEXT("InitRenderTargetRes: RenderTarget is invalid."));
  5461.             return true;
  5462.         }
  5463.  
  5464.         if (RT->pRenderTargetTex)
  5465.         {
  5466.             if (!RT->pRenderTargetSurf)
  5467.                 appErrorf(TEXT("InitRenderTargetRes: RenderTarget is invalid (no surface)."));
  5468.             return true;
  5469.         }
  5470.  
  5471.         if (Direct3DDevice8->CreateTexture(RT->Width,RT->Height,1,D3DUSAGE_RENDERTARGET,RenderTargetFormat,D3DPOOL_DEFAULT,&RT->pRenderTargetTex) != D3D_OK)
  5472.             return false;
  5473.  
  5474.         RT->pRenderTargetTex->GetSurfaceLevel(0, &RT->pRenderTargetSurf);
  5475.  
  5476.         return true;
  5477.     }
  5478.  
  5479.     //============================================================================================
  5480.     //  ShutdownRenderTargetRes
  5481.     //============================================================================================
  5482.     UBOOL ShutdownRenderTargetRes(RenderTargetInfo *RT)
  5483.     {
  5484.         if (!RT->Active)
  5485.         {
  5486.             if (RT->pRenderTargetSurf || RT->pRenderTargetTex)
  5487.                 appErrorf(TEXT("ShutdownRenderTargetRes: RenderTarget is invalid."));
  5488.             return true;
  5489.         }
  5490.  
  5491.         SafeRelease(RT->pRenderTargetSurf);
  5492.  
  5493.         SafeRelease(RT->pRenderTargetTex);
  5494.  
  5495.         RT->pRenderTargetSurf = NULL;
  5496.         RT->pRenderTargetTex = NULL;
  5497.  
  5498.         return true;
  5499.     }
  5500.  
  5501.     //============================================================================================
  5502.     //  CreateRenderTarget
  5503.     //============================================================================================
  5504.     void *CreateRenderTarget(INT W, INT H)
  5505.     {
  5506.         if (RenderTargetFormat == D3DFMT_UNKNOWN)
  5507.             return NULL;
  5508.  
  5509.         RenderTargetInfo    RenderTarget;
  5510.  
  5511.         memset(&RenderTarget, 0, sizeof(RenderTarget));
  5512.  
  5513.         RenderTarget.Width = W;
  5514.         RenderTarget.Height = H;
  5515.  
  5516.         RenderTarget.Active = true;
  5517.  
  5518.         if (!InitRenderTargetRes(&RenderTarget))
  5519.             return NULL;
  5520.  
  5521.         // Look on the free'd list first
  5522.         if (FreeRenderTargets.Num())
  5523.         {
  5524.             INT FreeIndex = FreeRenderTargets(0);
  5525.             RenderTargetArray(FreeIndex) = RenderTarget;
  5526.             FreeRenderTargets.Remove(0);
  5527.             return INDEX_TO_RENDER_TARGET(FreeIndex);
  5528.         }
  5529.  
  5530.         return INDEX_TO_RENDER_TARGET(RenderTargetArray.AddItem(RenderTarget));
  5531.     }
  5532.    
  5533.     //============================================================================================
  5534.     //  DestroyRenderTarget
  5535.     //============================================================================================
  5536.     void DestroyRenderTarget(void **pRenderTarget)
  5537.     {
  5538.         INT Index = RENDER_TARGET_TO_INDEX(*pRenderTarget);
  5539.  
  5540.         if (Index < 0 || Index >= RenderTargetArray.Num())
  5541.             appErrorf(TEXT("DestroyRenderTarget: Invalid RenderTarget"));
  5542.        
  5543.         ShutdownRenderTargetRes(&RenderTargetArray(Index));
  5544.        
  5545.         RenderTargetArray(Index).Active = false;
  5546.  
  5547.         *pRenderTarget = NULL;
  5548.        
  5549.         FreeRenderTargets.AddItem(Index);
  5550.     }
  5551.  
  5552.     //============================================================================================
  5553.     //  SetRenderTarget
  5554.     //============================================================================================
  5555.     void SetRenderTarget(void *pRenderTarget, void *pNewZStencil)
  5556.     {
  5557.         INT Index = RENDER_TARGET_TO_INDEX(pRenderTarget);
  5558.  
  5559.         if (Index < 0 || Index >= RenderTargetArray.Num())
  5560.             appErrorf(TEXT("SetRenderTarget: Invalid RenderTarget"));
  5561.  
  5562.         if (!pOriginalZStencil)
  5563.         {
  5564.             // Remember the original render targets
  5565.             Direct3DDevice8->GetRenderTarget(&pOriginalRenderTarget);
  5566.             Direct3DDevice8->GetDepthStencilSurface(&pOriginalZStencil);
  5567.         }
  5568.  
  5569.         if (!RenderTargetArray(Index).pRenderTargetSurf)
  5570.             appErrorf(TEXT("AddProjector: NULL RenderTargetSurf"));
  5571.  
  5572.         // Set the render target
  5573.         Direct3DDevice8->SetRenderTarget(RenderTargetArray(Index).pRenderTargetSurf, NULL);
  5574.        
  5575.         // Clear the render target
  5576.         Direct3DDevice8->Clear(0, NULL, D3DCLEAR_TARGET, 0xffffffff, 1.f, 0 );
  5577.         /*
  5578.         D3DRECT     Rect;
  5579.  
  5580.         Rect.x1 = 1;
  5581.         Rect.y1 = 1;
  5582.         Rect.x2 = 127;
  5583.         Rect.y2 = 127;
  5584.  
  5585.         Direct3DDevice8->Clear(1, &Rect, D3DCLEAR_TARGET, 0, 1.f, 0 );
  5586.         */
  5587.        
  5588.         CurrentRenderTarget = pRenderTarget;
  5589.     }
  5590.    
  5591.     //============================================================================================
  5592.     //  RestoreRenderTarget
  5593.     //============================================================================================
  5594.     void RestoreRenderTarget(void)
  5595.     {
  5596.         if (!pOriginalZStencil)
  5597.             return;         // Already using original rendertarget
  5598.        
  5599.         // Set the rendertarget/zstencil back to the original
  5600.         Direct3DDevice8->SetRenderTarget(pOriginalRenderTarget, pOriginalZStencil);
  5601.  
  5602.         // Release the copies we had
  5603.         SafeRelease(pOriginalRenderTarget);
  5604.         SafeRelease(pOriginalZStencil);
  5605.  
  5606.         // Set them to NULL to we know next time around that we have been restored
  5607.         pOriginalRenderTarget = NULL;
  5608.         pOriginalZStencil = NULL;
  5609.  
  5610.         CurrentRenderTarget = NULL;
  5611.     }
  5612.  
  5613.     //============================================================================================
  5614.     //  DrawTex
  5615.     //============================================================================================
  5616.     void __fastcall DrawTex(FSceneNode          *Frame,
  5617.                             FLOAT               X, FLOAT Y,
  5618.                             FLOAT               XL, FLOAT YL,
  5619.                             FLOAT               U, FLOAT V,
  5620.                             FLOAT               UL, FLOAT VL,
  5621.                             IDirect3DTexture8   *Tex)
  5622.     {
  5623.         VALIDATE;
  5624.        
  5625.         SetDistanceFog(false);
  5626.    
  5627.         //SetBlending(PFX_DarkenModulate);//PF_Modulated);
  5628.         SetBlending();
  5629.         SetTextureNULL(0);
  5630.        
  5631.         Direct3DDevice8->SetTexture(0, Tex);
  5632.  
  5633.         SetTextureClampMode(1);
  5634.  
  5635.         FD3DTLVertex    *Vertices = (FD3DTLVertex*) ActorVertices.Lock(4);
  5636.  
  5637.         DWORD dwDiffuse = 0xffffffff;
  5638.  
  5639.         for (INT i=0; i<4; i++)
  5640.         {
  5641.             Vertices[i].Diffuse    = dwDiffuse;
  5642.             Vertices[i].Position.Z = 1.0f;
  5643.             Vertices[i].Position.W = 1.0f;
  5644.         }
  5645.  
  5646.         Vertices[0].Position.X=X;    Vertices[0].Position.Y=Y;    Vertices[0].U[0]=U;       Vertices[0].U[1]=V   ;
  5647.         Vertices[1].Position.X=X+XL; Vertices[1].Position.Y=Y;    Vertices[1].U[0]=U+UL;    Vertices[1].U[1]=V   ;
  5648.         Vertices[2].Position.X=X+XL; Vertices[2].Position.Y=Y+YL; Vertices[2].U[0]=U+UL;    Vertices[2].U[1]=V+VL;
  5649.         Vertices[3].Position.X=X;    Vertices[3].Position.Y=Y+YL; Vertices[3].U[0]=U;       Vertices[3].U[1]=V+VL;
  5650.  
  5651.         INT First=ActorVertices.Unlock();
  5652.        
  5653.         ActorVertices.Set();
  5654.  
  5655.         Direct3DDevice8->DrawPrimitive( D3DPT_TRIANGLEFAN, First, 2 );
  5656.         Direct3DDevice8->SetTexture(0, NULL);
  5657.        
  5658.         SetTextureClampMode(0);
  5659.     }
  5660.  
  5661.     //============================================================================================
  5662.     //  AddProjector
  5663.     //============================================================================================
  5664.     void __fastcall AddProjector(FSceneNode *Frame, void *pRenderTarget, FTextureInfo *Info, FLOAT wNear, FLOAT wFar, FLOAT FadeScale)
  5665.     {
  5666.         ProjectorInfo   Projector;
  5667.        
  5668.         Projector.Frame = Frame;
  5669.        
  5670.         Projector.CameraToLight = Frame->Coords;
  5671.         Projector.CameraToLight <<= Frame->Parent->Uncoords;
  5672.        
  5673.         Projector.OneOverX = 1.0f/(float)Frame->X;
  5674.         Projector.OneOverY = 1.0f/(float)Frame->Y;
  5675.  
  5676.         Projector._33 = wFar / (wFar - wNear);
  5677.         Projector._43 = -Projector._33 * wNear;
  5678.         Projector.FadeScale = FadeScale;
  5679.  
  5680.         if (Frame->Level && Frame->Level->Model)
  5681.             Projector.GNodes = &Frame->Level->Model->Nodes(0);
  5682.         else
  5683.             Projector.GNodes = NULL;
  5684.  
  5685.         if (pRenderTarget)
  5686.         {
  5687.             INT Index = RENDER_TARGET_TO_INDEX(pRenderTarget);
  5688.  
  5689.             if (Index < 0 || Index >= RenderTargetArray.Num())
  5690.                 appErrorf(TEXT("AddProjector: Invalid RenderTarget"));
  5691.  
  5692.             RenderTargetInfo &RT = RenderTargetArray(Index);
  5693.  
  5694.             // Assign the texture to this projector
  5695.             Projector.pRenderTargetTex = RT.pRenderTargetTex;
  5696.  
  5697.     #if 1
  5698.         // Render tex into itself, have convolution smooth texture out
  5699.         #if 1
  5700.             if (CurrentRenderTarget == pRenderTarget)
  5701.             {
  5702.                 if (!TempRT)
  5703.                     TempRT = CreateRenderTarget(128, 128);
  5704.  
  5705.                 if (TempRT)
  5706.                 {
  5707.                     INT Index2 = RENDER_TARGET_TO_INDEX(TempRT);
  5708.  
  5709.                     if (Index2 < 0 || Index2 >= RenderTargetArray.Num())
  5710.                         appErrorf(TEXT("AddProjector: Invalid RenderTarget2"));
  5711.  
  5712.                     RenderTargetInfo &RT2 = RenderTargetArray(Index2);
  5713.  
  5714.                     SetRenderTarget(TempRT, NULL);
  5715.  
  5716.                     float Val = (1.0f/128.0f);
  5717.  
  5718.                     DrawTex(Frame, 0.0f, 0.0f, 127.0f, 127.0f,Val*0.5f,Val*0.5f, 1.0f, 1.0f, RT.pRenderTargetTex);
  5719.                     SetRenderTarget(pRenderTarget, NULL);
  5720.                     DrawTex(Frame, 0.0f, 0.0f, 127.0f, 127.0f,-Val*0.5f,-Val*0.5f, 1.0f, 1.0f, RT2.pRenderTargetTex);
  5721.                 }
  5722.             }
  5723.         #else
  5724.             if (CurrentRenderTarget == pRenderTarget)
  5725.             {
  5726.                 float Val = (1.0f/128.0f);
  5727.            
  5728.                 EndScene();
  5729.                 BeginScene();
  5730.  
  5731.                 DrawTex(Frame, 0.0f, 0.0f, 127.0f, 127.0f,Val*0.5f,Val*0.5f, 1.0f, 1.0f, RT.pRenderTargetTex);
  5732.                 DrawTex(Frame, 0.0f, 0.0f, 127.0f, 127.0f,-Val*0.5f,-Val*0.5f, 1.0f, 1.0f, RT.pRenderTargetTex);
  5733.             }
  5734.         #endif
  5735.     #endif
  5736.  
  5737.             if (!Projector.pRenderTargetTex)
  5738.                 appErrorf(TEXT("AddProjector: NULL RenderTarget"));
  5739.         }
  5740.         else
  5741.         {
  5742.             //Projector.pRenderTargetTex = NULL;
  5743.             //Projector.Texture = Info->Texture;
  5744.         }
  5745.  
  5746.         ProjectorArray.AddItem(Projector);
  5747.     }
  5748.  
  5749.     //============================================================================================
  5750.     //  ResetProjectors
  5751.     //============================================================================================
  5752.     void __fastcall ResetProjectors(void)
  5753.     {
  5754.     #ifdef BATCH_PROJECTOR_POLYS
  5755.         FlushProjectorPolys();
  5756.     #endif
  5757.  
  5758.         ProjectorArray.Clear();
  5759.     }
  5760.    
  5761. #ifdef BATCH_PROJECTOR_POLYS
  5762.     //============================================================================================
  5763.     //  FlushProjectorPolys
  5764.     //============================================================================================
  5765.     void __fastcall FlushProjectorPolys(void)
  5766.     {
  5767.         if (!NumProjectorSurfs)
  5768.         {
  5769.             check(NumProjectorPolys == 0);
  5770.             check(NumProjectorVerts == 0);
  5771.             return;
  5772.         }
  5773.    
  5774.         ProjectorVertices.Set();
  5775.  
  5776.         SetTextureNULL( 0 );
  5777.         SetTextureNULL( 1 );
  5778.         SetBlending( PF_Modulated );
  5779.         SetDistanceFog(false);
  5780.  
  5781.         SetTextureClampMode(1);
  5782.  
  5783.         //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  5784.         //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR );
  5785.         //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ZERO );
  5786.         SetAlphaBlendEnable(TRUE);
  5787.         SetSrcBlend(D3DBLEND_DESTCOLOR);
  5788.         SetDstBlend(D3DBLEND_ZERO);
  5789.  
  5790.         // Setup clipper texture (also used for fade out)
  5791.         Direct3DDevice8->SetTexture(1, ClipperTexture);
  5792.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  5793.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_ADD);
  5794.         //Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  5795.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
  5796.  
  5797.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP );
  5798.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP );
  5799.  
  5800.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_POINT);
  5801.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_POINT);
  5802.  
  5803.         for (INT p=0; p< ProjectorArray.Num(); p++)
  5804.         {
  5805.             ProjectorInfo *pProjector = &ProjectorArray(p);
  5806.  
  5807.             // Lock the projector verts
  5808.             FD3DScreenVertex *V= (FD3DScreenVertex*)ProjectorVertices.Lock(NumProjectorVerts);
  5809.  
  5810.             static  PolysVisible[1024];
  5811.  
  5812.             for (INT i=0; i< NumProjectorSurfs; i++)
  5813.             {
  5814.                 ProjectorSurf   *Surf = &ProjectorSurfs[i];
  5815.  
  5816.                 if (!(Surf->ProjectorFlags & (1<<p)))
  5817.                     continue;
  5818.  
  5819.                 INT             *Poly = &ProjectorPolys[Surf->FirstPoly];
  5820.                 FVector         *PP = &ProjectorPoints[Surf->FirstVert];
  5821.                 FD3DTLVertex    *PV = &ProjectorVerts[Surf->FirstVert];
  5822.  
  5823.                 for (INT j=0; j<Surf->NumPolys; j++)
  5824.                 {
  5825.                     // Compute outcodes.
  5826.                     BYTE Outcode = FVF_OutReject;
  5827.  
  5828.                     for (INT v=0; v<Poly[j]; v++)
  5829.                     {
  5830.                         V->Position.X = PV->Position.X;    
  5831.                         V->Position.Y = PV->Position.Y;
  5832.                         V->Position.Z = PV->Position.Z;
  5833.                         V->Position.W = PV->Position.W;
  5834.                         V->Color = 0xffffffff;
  5835.                        
  5836.                         // Grab a copy of the vert
  5837.                         FTransform      P;
  5838.  
  5839.                         // Transform point into projector space
  5840.                         P.Point = PP->TransformPointBy(pProjector->CameraToLight);
  5841.  
  5842.                     #if 1  
  5843.                         // Project point onto projector front plane
  5844.                         P.Point.Z = max(1.0f, P.Point.Z);
  5845.                         P.Project(pProjector->Frame);
  5846.                        
  5847.                         P.ComputeOutcode(pProjector->Frame);
  5848.                         Outcode &= P.Flags;
  5849.  
  5850.                         // Snag UV's
  5851.                         V->U[0] = P.ScreenX*pProjector->OneOverX;
  5852.                         V->U[1] = P.ScreenY*pProjector->OneOverY;
  5853.                        
  5854.                         V->Position.W *= P.Point.Z;
  5855.                     #else
  5856.                         // Ortho projection
  5857.                         V->U[0] = (P.Point.X/125)+0.5f;
  5858.                         V->U[1] = (P.Point.Y/125)+0.5f;
  5859.                     #endif
  5860.  
  5861.                         // Clip and fade out (this is the UV's for the clipper/fade out texture layer)
  5862.                     #if 1
  5863.                         FLOAT R = P.RZ * pProjector->Frame->RProj.Z;        // (1.0f/Z)
  5864.                         V->U2[0] = (pProjector->_33 + pProjector->_43 * R)*0.6;
  5865.                         V->U2[1] = 0.0f;
  5866.                     #endif
  5867.  
  5868.                         V++;
  5869.                         PP++;
  5870.                         PV++;
  5871.  
  5872.                         PolysVisible[j] = (Outcode == 0);
  5873.                     }
  5874.                 }
  5875.             }
  5876.            
  5877.             // Unlock world verts
  5878.             INT First = ProjectorVertices.Unlock();
  5879.  
  5880.             // Set the texture to the render target that belongs to this projector
  5881.             Direct3DDevice8->SetTexture(0, pProjector->pRenderTargetTex);
  5882.  
  5883.             for (i=0; i< NumProjectorSurfs; i++)
  5884.             {
  5885.                 ProjectorSurf   *Surf = &ProjectorSurfs[i];
  5886.  
  5887.                 if (!(Surf->ProjectorFlags & (1<<p)))
  5888.                     continue;
  5889.  
  5890.                 INT     *Poly = &ProjectorPolys[Surf->FirstPoly];
  5891.  
  5892.                 for (INT j=0; j<Surf->NumPolys; j++)
  5893.                 {
  5894.                     if (PolysVisible[j])
  5895.                         Direct3DDevice8->DrawPrimitive(D3DPT_TRIANGLEFAN, First, Poly[j]-2);
  5896.                     First += Poly[j];
  5897.                 }
  5898.             }
  5899.         }
  5900.            
  5901.         Direct3DDevice8->SetTexture(1, NULL);
  5902.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  5903.  
  5904.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  5905.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  5906.  
  5907.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP );
  5908.         Direct3DDevice8->SetTextureStageState( 1, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP );
  5909.  
  5910.         Direct3DDevice8->SetTexture(0, NULL);
  5911.         //Direct3DDevice8->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  5912.         //Direct3DDevice8->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR );
  5913.         //Direct3DDevice8->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR );
  5914.         SetAlphaBlendEnable(TRUE);
  5915.         SetSrcBlend(D3DBLEND_DESTCOLOR);
  5916.         SetDstBelnd(D3DBLEND_SRCCOLOR);
  5917.         SetTextureClampMode(0);
  5918.  
  5919.         NumProjectorVerts = 0;
  5920.         NumProjectorPolys = 0;
  5921.         NumProjectorSurfs = 0;
  5922.     }
  5923. #endif
  5924.     // ...JEP
  5925. };
  5926.  
  5927. // Package and class implementation:
  5928. IMPLEMENT_PACKAGE(D3DDrv);
  5929. IMPLEMENT_CLASS(UD3DRenderDevice);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement