Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

Go to the documentation of this file.
00001 // Filename: dxGraphicsStateGuardian.cxx
00002 // Created by:  mike (02Feb99)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "dxGraphicsStateGuardian8.h"
00020 #include "config_dxgsg8.h"
00021 #include <d3dx8.h>
00022 #include "displayRegion.h"
00023 #include "renderBuffer.h"
00024 #include "geom.h"
00025 #include "geomSphere.h"
00026 #include "geomIssuer.h"
00027 #include "graphicsWindow.h"
00028 #include "graphicsChannel.h"
00029 #include "lens.h"
00030 #include "perspectiveLens.h"
00031 #include "ambientLight.h"
00032 #include "directionalLight.h"
00033 #include "pointLight.h"
00034 #include "spotlight.h"
00035 #include "textureAttrib.h"
00036 #include "lightAttrib.h"
00037 #include "cullFaceAttrib.h"
00038 #include "transparencyAttrib.h"
00039 #include "alphaTestAttrib.h"
00040 #include "depthTestAttrib.h"
00041 #include "depthWriteAttrib.h"
00042 #include "colorWriteAttrib.h"
00043 #include "texMatrixAttrib.h"
00044 #include "materialAttrib.h"
00045 #include "renderModeAttrib.h"
00046 #include "fogAttrib.h"
00047 #include "depthOffsetAttrib.h"
00048 #include "fog.h"
00049 
00050 #ifdef DO_PSTATS
00051 #include "pStatTimer.h"
00052 #include "pStatCollector.h"
00053 #endif
00054 
00055 // disable nameless struct 'warning'
00056 #pragma warning (disable : 4201)
00057 
00058 #include <mmsystem.h>
00059 
00060 // print out simple drawprim stats every few secs
00061 //#define COUNT_DRAWPRIMS
00062 //#define PRINT_RESOURCESTATS  // uses d3d GetInfo
00063 
00064 //#define DISABLE_DECALING
00065 #define DISABLE_POLYGON_OFFSET_DECALING
00066 // currently doesnt work well enough in toontown models for us to use
00067 // prob is when viewer gets close to decals, they disappear into wall poly, need to investigate
00068 
00069 //const int VERT_BUFFER_SIZE = (8*1024L);
00070 // For sparkle particles, we can have 4 vertices per sparkle, and a
00071 // particle pool size of 1024 particles
00072 
00073 // for sprites, 1000 prims, 6 verts/prim, 24 bytes/vert
00074 const int VERT_BUFFER_SIZE = (32*6*1024L);
00075 
00076 // if defined, pandadx only handles 1 panda display region
00077 // note multiple region code doesnt work now (see prepare_display_region,set_clipper)
00078 #define NO_MULTIPLE_DISPLAY_REGIONS
00079 
00080 TypeHandle DXGraphicsStateGuardian8::_type_handle;
00081 
00082 // bit masks used for drawing primitives
00083 // bitmask type: normal=0x1,color=0x2,texcoord=0x4
00084 typedef enum { NothingSet=0,NormalOnly,ColorOnly,Normal_Color,TexCoordOnly,
00085                Normal_TexCoord,Color_TexCoord,Normal_Color_TexCoord
00086 } DrawLoopFlags;
00087 
00088 #define PER_NORMAL   NormalOnly
00089 #define PER_COLOR    ColorOnly
00090 #define PER_TEXCOORD TexCoordOnly
00091 
00092 // xform mat for vshader will usually be loaded at constant regs c4-c7
00093 #define VSHADER_XFORMMATRIX_CONSTANTREGNUMSTART 4
00094 
00095 static D3DMATRIX matIdentity;
00096 
00097 #define __D3DLIGHT_RANGE_MAX ((float)sqrt(FLT_MAX))  //for some reason this is missing in dx8 hdrs
00098 
00099 #ifdef COUNT_DRAWPRIMS
00100 // instead of this use nvidia stat drvr or GetInfo VtxStats?
00101 static DWORD cDPcount=0;
00102 static DWORD cVertcount=0;
00103 static DWORD cTricount=0;
00104 static DWORD cGeomcount=0;
00105 
00106 static IDirect3DTexture8 *pLastTexture=NULL;
00107 static DWORD cDP_noTexChangeCount=0;
00108 static LPDIRECT3DDEVICE8 global_pD3DDevice = NULL;
00109 
00110 static void CountDPs(DWORD nVerts,DWORD nTris) {
00111     cDPcount++;
00112     cVertcount+=nVerts;
00113     cTricount+=nTris;
00114 
00115     if(_pCurDeviceTexture==pLastTexture) {
00116         cDP_noTexChangeCount++;
00117     } else pLastTexture = _pCurDeviceTexture;
00118 }
00119 #else
00120 #define CountDPs(nv,nt)
00121 #endif
00122 
00123 #define MY_D3DRGBA(r,g,b,a) ((D3DCOLOR) D3DCOLOR_COLORVALUE(r,g,b,a))
00124 
00125 #if defined(DO_PSTATS) || defined(PRINT_RESOURCESTATS)
00126 static bool bTexStatsRetrievalImpossible=false;
00127 #endif
00128 
00129 //#define Colorf_to_D3DCOLOR(out_color) (MY_D3DRGBA((out_color)[0], (out_color)[1], (out_color)[2], (out_color)[3]))
00130 
00131 INLINE DWORD
00132 Colorf_to_D3DCOLOR(const Colorf &cColorf) {
00133 // MS VC defines _M_IX86 for x86.  gcc should define _X86_
00134 #if defined(_M_IX86) || defined(_X86_)
00135     DWORD d3dcolor,tempcolorval=255;
00136 
00137     // note the default FPU rounding mode will give 255*0.5f=0x80, not 0x7F as VC would force it to by resetting rounding mode
00138     // dont think this makes much difference
00139 
00140     __asm {
00141         push ebx   ; want to save this in case this fn is inlined
00142         push ecx
00143         mov ecx, cColorf
00144         fild tempcolorval
00145         fld DWORD PTR [ecx]
00146         fmul ST(0),ST(1)
00147         fistp tempcolorval  ; no way to store directly to int register
00148         mov eax, tempcolorval
00149         shl eax, 16
00150 
00151         fld DWORD PTR [ecx+4]  ;grn
00152         fmul ST(0),ST(1)
00153         fistp tempcolorval
00154         mov ebx,tempcolorval
00155         shl ebx, 8
00156         or eax,ebx
00157 
00158         fld DWORD PTR [ecx+8]  ;blue
00159         fmul ST(0),ST(1)
00160         fistp tempcolorval
00161         or eax,tempcolorval
00162 
00163         fld DWORD PTR [ecx+12] ;alpha
00164         fmul ST(0),ST(1)
00165         fistp tempcolorval
00166         ; simulate pop 255.0 off FP stack w/o store, mark top as empty and increment stk ptr
00167         ffree ST(0)
00168         fincstp
00169         mov ebx,tempcolorval
00170         shl ebx, 24
00171         or eax,ebx
00172         mov d3dcolor,eax
00173         pop ecx
00174         pop ebx
00175     }
00176 
00177    //   dxgsg8_cat.debug() << (void*)d3dcolor << endl;
00178    return d3dcolor;
00179 #else //!_X86_
00180    return MY_D3DRGBA(cColorf[0], cColorf[1], cColorf[2], cColorf[3]);
00181 #endif //!_X86_
00182 }
00183 
00184 void DXGraphicsStateGuardian8::
00185 set_color_clear_value(const Colorf& value) {
00186   _color_clear_value = value;
00187   _d3dcolor_clear_value =  Colorf_to_D3DCOLOR(value);
00188 }
00189 
00190 DXShaderHandle DXGraphicsStateGuardian8::
00191 read_pixel_shader(string &filename) {
00192     HRESULT hr;
00193     DXShaderHandle hShader=NULL;
00194     HANDLE hFile=NULL;
00195     BYTE *pShaderBytes=NULL;
00196     LPD3DXBUFFER pD3DXBuf_Constants=NULL,pD3DXBuf_CompiledShader=NULL,pD3DXBuf_CompilationErrors=NULL;
00197 
00198     assert(_pD3DDevice!=NULL);
00199     assert(_pScrn->bCanUsePixelShaders);
00200     bool bIsCompiledShader=(filename.find(".pso")!=string::npos);
00201 
00202     if(bIsCompiledShader) {
00203         hFile = CreateFile(filename.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
00204         if(hFile == INVALID_HANDLE_VALUE) {
00205             dxgsg8_cat.error() << "Could not find shader file '"<< filename << "'\n";
00206             return NULL;
00207         }
00208 
00209         UINT BytesRead,FileSize = GetFileSize(hFile, NULL);
00210 
00211         pShaderBytes = new BYTE[FileSize];
00212         if (pShaderBytes==NULL) {
00213             dxgsg8_cat.error() << "MemAlloc failed for shader file '"<< filename << "'\n";
00214             goto exit_create_pshader;
00215         }
00216 
00217         ReadFile(hFile, (void*)pShaderBytes, FileSize, (LPDWORD)&BytesRead, NULL);
00218         assert(BytesRead==FileSize);
00219     } else {
00220         #if defined(NDEBUG) && !defined(COMPILE_TEXT_SHADERFILES)
00221             // want to keep bulky d3dx shader assembler stuff out of publish build
00222             dxgsg8_cat.error() << "publish build only reads .vso compiled shaders!\n";
00223             exit(1);
00224         #else
00225            // check for file existence
00226            WIN32_FIND_DATA Junk;
00227            HANDLE FindFileHandle = FindFirstFile(filename.c_str(),&Junk);
00228            if ( FindFileHandle == INVALID_HANDLE_VALUE ) {
00229                 dxgsg8_cat.error() << "Could not find shader file '"<< filename << "'\n";
00230                 return NULL;
00231            }
00232            FindClose(FindFileHandle);
00233 
00234            hr = D3DXAssembleShaderFromFile(filename.c_str(),D3DXASM_DEBUG,NULL,&pD3DXBuf_CompiledShader,&pD3DXBuf_CompilationErrors);
00235            if(FAILED(hr)) {
00236                dxgsg8_cat.error() << "D3DXAssembleShader failed for '"<< filename << "' " << D3DERRORSTRING(hr);
00237                if(pD3DXBuf_CompilationErrors!=NULL) {
00238                    dxgsg8_cat.error() << "Compilation Errors: " << (char*) pD3DXBuf_CompilationErrors->GetBufferPointer() << endl;
00239                }
00240                exit(1);
00241            }
00242            assert(pD3DXBuf_CompilationErrors==NULL);
00243         #endif
00244    }
00245 
00246    hr = _pD3DDevice->CreatePixelShader((DWORD*) ((pD3DXBuf_CompiledShader!=NULL) ? pD3DXBuf_CompiledShader->GetBufferPointer() : pShaderBytes),
00247                                      &hShader);
00248    if (FAILED(hr)) {
00249         dxgsg8_cat.error() << "CreatePixelShader failed for '"<< filename << "' " << D3DERRORSTRING(hr);
00250         hShader=NULL;
00251    }
00252 
00253    assert(hShader!=NULL);   // NULL is invalid I hope
00254 
00255    #ifdef _DEBUG
00256       dxgsg8_cat.debug() <<  "CreatePixelShader succeeded for "<< filename << endl;
00257    #endif
00258 
00259  exit_create_pshader:
00260    SAFE_RELEASE(pD3DXBuf_CompiledShader);
00261    if(hFile!=NULL)
00262      CloseHandle(hFile);
00263    SAFE_DELETE(pShaderBytes);
00264    return hShader;
00265 }
00266 
00267 
00268 DXShaderHandle DXGraphicsStateGuardian8::
00269 read_vertex_shader(string &filename) {
00270 #ifndef USE_VERTEX_SHADERS
00271     return NULL;
00272 #else
00273     HRESULT hr;
00274     DXShaderHandle hShader=NULL;
00275     HANDLE hFile=NULL;
00276     BYTE *pShaderBytes=NULL;
00277     LPD3DXBUFFER pD3DXBuf_Constants=NULL,pD3DXBuf_CompiledShader=NULL,pD3DXBuf_CompilationErrors=NULL;
00278     #define VSDDECL_BUFSIZE 1024
00279     UINT ShaderDeclHeader[VSDDECL_BUFSIZE];
00280 
00281     // simple decl for posn + color
00282     // need way to encode header decl with vsh files (stick in comment?)  (use ID3DXEffect files?)
00283     UINT Predefined_DeclArray[] = {
00284         D3DVSD_STREAM(0),
00285         D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3 ),      // input register v0
00286         D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR ),     // input Register v5
00287       //  D3DVSD_CONST(0,1),*(DWORD*)&c[0],*(DWORD*)&c[1],*(DWORD*)&c[2],*(DWORD*)&c[3],
00288     };
00289 
00290     memcpy(ShaderDeclHeader,Predefined_DeclArray,sizeof(Predefined_DeclArray));
00291 
00292     // need to append any compiled constants to instr array
00293     UINT ShaderDeclHeader_UINTSize=sizeof(Predefined_DeclArray)/sizeof(UINT);
00294 
00295     assert(_pD3DDevice!=NULL);
00296     bool bIsCompiledShader=(filename.find(".vso")!=string::npos);
00297 
00298     if(bIsCompiledShader) {
00299         hFile = CreateFile(filename.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
00300         if(hFile == INVALID_HANDLE_VALUE) {
00301             dxgsg8_cat.error() << "Could not find shader file '"<< filename << "'\n";
00302             return NULL;
00303         }
00304 
00305         UINT BytesRead,FileSize = GetFileSize(hFile, NULL);
00306 
00307         pShaderBytes = new BYTE[FileSize];
00308         if (pShaderBytes==NULL) {
00309             dxgsg8_cat.error() << "MemAlloc failed for shader file '"<< filename << "'\n";
00310             goto exit_create_vshader;
00311         }
00312 
00313         ReadFile(hFile, (void*)pShaderBytes, FileSize, (LPDWORD)&BytesRead, NULL);
00314         assert(BytesRead==FileSize);
00315     } else {
00316         #if defined(NDEBUG) && !defined(COMPILE_TEXT_SHADERFILES)
00317             // want to keep bulky d3dx shader assembler stuff out of publish build
00318             dxgsg8_cat.error() << "publish build only reads .vso compiled shaders!\n";
00319             exit(1);
00320         #else
00321            // check for file existence
00322            WIN32_FIND_DATA Junk;
00323            HANDLE FindFileHandle = FindFirstFile(filename.c_str(),&Junk);
00324            if ( FindFileHandle == INVALID_HANDLE_VALUE ) {
00325                 dxgsg8_cat.error() << "Could not find shader file '"<< filename << "'\n";
00326                 return NULL;
00327            }
00328            FindClose(FindFileHandle);
00329 
00330            hr = D3DXAssembleShaderFromFile(filename.c_str(),D3DXASM_DEBUG,&pD3DXBuf_Constants,&pD3DXBuf_CompiledShader,&pD3DXBuf_CompilationErrors);
00331            if(FAILED(hr)) {
00332                dxgsg8_cat.error() << "D3DXAssembleShader failed for '"<< filename << "' " << D3DERRORSTRING(hr);
00333                if(pD3DXBuf_CompilationErrors!=NULL) {
00334                    dxgsg8_cat.error() << "Compilation Errors: " << (char*) pD3DXBuf_CompilationErrors->GetBufferPointer() << endl;
00335                }
00336                exit(1);
00337            }
00338            assert(pD3DXBuf_CompilationErrors==NULL);
00339 
00340            if(pD3DXBuf_Constants!=NULL) {
00341                // need to insert defined constants after shader decl
00342                memcpy(&ShaderDeclHeader[ShaderDeclHeader_UINTSize],pD3DXBuf_Constants->GetBufferPointer(),pD3DXBuf_Constants->GetBufferSize());
00343                ShaderDeclHeader_UINTSize+=pD3DXBuf_Constants->GetBufferSize()/sizeof(UINT);
00344                pD3DXBuf_Constants->Release();
00345            }
00346         #endif
00347    }
00348 
00349    assert(VSDDECL_BUFSIZE >= (ShaderDeclHeader_UINTSize+1));
00350    ShaderDeclHeader[ShaderDeclHeader_UINTSize]=D3DVSD_END();
00351 
00352    UINT UsageFlags = (_pScrn->bCanUseHWVertexShaders ? 0x0 : D3DUSAGE_SOFTWAREPROCESSING);
00353    hr = _pD3DDevice->CreateVertexShader((DWORD*)ShaderDeclHeader,
00354                                      (DWORD*) ((pD3DXBuf_CompiledShader!=NULL) ? pD3DXBuf_CompiledShader->GetBufferPointer() : pShaderBytes),
00355                                      &hShader, UsageFlags);
00356    if(FAILED(hr)) {
00357         dxgsg8_cat.error() << "CreateVertexShader failed for '"<< filename << "' " << D3DERRORSTRING(hr);
00358         hShader=NULL;
00359    }
00360 
00361    assert(hShader!=NULL);   // NULL is invalid I hope
00362 
00363    #ifdef _DEBUG
00364       dxgsg8_cat.debug() <<  "CreateVertexShader succeeded for "<< filename << endl;
00365    #endif
00366 
00367  exit_create_vshader:
00368    SAFE_RELEASE(pD3DXBuf_CompiledShader);
00369    if(hFile!=NULL)
00370      CloseHandle(hFile);
00371    SAFE_DELETE(pShaderBytes);
00372    return hShader;
00373 #endif
00374 }
00375 
00376 void DXGraphicsStateGuardian8::
00377 reset_panda_gsg(void) {
00378     GraphicsStateGuardian::reset();
00379 
00380     // overwrite gsg defaults with these values
00381 
00382     // All implementations have the following buffers.
00383     _buffer_mask = (RenderBuffer::T_color |
00384                     RenderBuffer::T_back
00385 //                    RenderBuffer::T_depth |
00386 //                  RenderBuffer::T_stencil |
00387 //                  RenderBuffer::T_accum
00388                     );
00389 
00390     //   stmt below is incorrect for general mono displays, need both right and left flags set.
00391     //   stereo not supported in dx8
00392     //    _buffer_mask &= ~RenderBuffer::T_right;
00393 }
00394 
00395 ////////////////////////////////////////////////////////////////////
00396 //     Function: DXGraphicsStateGuardian8::Constructor
00397 //       Access: Public
00398 //  Description:
00399 ////////////////////////////////////////////////////////////////////
00400 DXGraphicsStateGuardian8::
00401 DXGraphicsStateGuardian8(const FrameBufferProperties &properties) :
00402   GraphicsStateGuardian(properties) {
00403 
00404     reset_panda_gsg();
00405 
00406     _pScrn = NULL;
00407     
00408     _bDXisReady = false;
00409     _overlay_windows_supported = false;
00410 
00411     _pFvfBufBasePtr = NULL;
00412     _index_buf=NULL;
00413 
00414     // may persist across dx_init's?  (for dx8.1 but not dx8.0?)
00415     _CurVertexShader = _CurPixelShader = NULL;
00416     _pGlobalTexture = NULL;
00417 
00418     //    _max_light_range = __D3DLIGHT_RANGE_MAX;
00419 
00420     // non-dx obj values inited here should not change if resize is
00421     // called and dx objects need to be recreated (otherwise they
00422     // belong in dx_init, with other renderstate
00423 
00424     ZeroMemory(&matIdentity,sizeof(D3DMATRIX));
00425     matIdentity._11 = matIdentity._22 = matIdentity._33 = matIdentity._44 = 1.0f;
00426 
00427     _cur_read_pixel_buffer=RenderBuffer::T_front;
00428     set_color_clear_value(_color_clear_value);
00429 }
00430 
00431 ////////////////////////////////////////////////////////////////////
00432 //     Function: DXGraphicsStateGuardian8::Destructor
00433 //       Access: Public
00434 //  Description:
00435 ////////////////////////////////////////////////////////////////////
00436 DXGraphicsStateGuardian8::
00437 ~DXGraphicsStateGuardian8() {
00438     if (IS_VALID_PTR(_pD3DDevice)) 
00439         _pD3DDevice->SetTexture(0, NULL);  // this frees reference to the old texture
00440     _pCurTexContext = NULL;
00441 
00442     //free_d3d_device();   ???
00443 
00444     free_nondx_resources();
00445 }
00446 
00447 ////////////////////////////////////////////////////////////////////
00448 //     Function: DXGraphicsStateGuardian8::reset
00449 //       Access: Public, Virtual
00450 //  Description: Resets all internal state as if the gsg were newly
00451 //               created.  The GraphicsWindow pointer represents a
00452 //               typical window that might be used for this context;
00453 //               it may be required to set up the frame buffer
00454 //               properly the first time.
00455 ////////////////////////////////////////////////////////////////////
00456 void DXGraphicsStateGuardian8::
00457 reset() {
00458     reset_panda_gsg();
00459     dxgsg8_cat.error() << "DXGSG reset() not implemented properly yet!\n";
00460     // what else do we need to do?
00461     // delete all the objs too, right?
00462     // need to do a
00463     //dx_init();
00464 }
00465 
00466 // setup up for re-calling dx_init(), this is not the final exit cleanup routine (see dx_cleanup)
00467 void DXGraphicsStateGuardian8::
00468 free_d3d_device(void) {
00469     // dont want a full reset of gsg, just a state clear
00470     set_state(RenderState::make_empty());
00471     // want gsg to pass all state settings through
00472 
00473     _bDXisReady = false;
00474 
00475     if(_pD3DDevice!=NULL)
00476      for(int i=0;i<D3D_MAXTEXTURESTAGES;i++)
00477          _pD3DDevice->SetTexture(i,NULL);  // d3d should release this stuff internally anyway, but whatever
00478 
00479     DeleteAllDeviceObjects();
00480 
00481     if (_pD3DDevice!=NULL)
00482         RELEASE(_pD3DDevice,dxgsg8,"d3dDevice",RELEASE_DOWN_TO_ZERO);
00483 
00484     free_nondx_resources();
00485 
00486     // obviously we dont release ID3D8, just ID3DDevice8
00487 }
00488 
00489 ////////////////////////////////////////////////////////////////////
00490 //     Function: DXGraphicsStateGuardian8::free_nondx_resources
00491 //       Access: Public
00492 //  Description: Frees some memory that was explicitly allocated
00493 //               within the dxgsg.
00494 ////////////////////////////////////////////////////////////////////
00495 void DXGraphicsStateGuardian8::
00496 free_nondx_resources() {
00497     // this must not release any objects associated with D3D/DX!
00498     // those should be released in free_dxgsg_objects instead
00499     SAFE_DELETE_ARRAY(_index_buf);
00500     SAFE_DELETE_ARRAY(_pFvfBufBasePtr);
00501 }
00502 
00503 ////////////////////////////////////////////////////////////////////
00504 //     Function: DXGraphicsStateGuardian8::reset
00505 //       Access: Public, Virtual
00506 //  Description: Handles initialization which assumes that DX has already been
00507 //               set up.
00508 ////////////////////////////////////////////////////////////////////
00509 void DXGraphicsStateGuardian8::
00510 dx_init(void) {
00511     HRESULT hr;
00512 
00513     // make sure gsg passes all current state down to us
00514     set_state(RenderState::make_empty());
00515     // want gsg to pass all state settings down so any non-matching defaults we set here get overwritten
00516 
00517     assert(_pScrn->pD3D8!=NULL);
00518     assert(_pD3DDevice!=NULL);
00519 
00520     ZeroMemory(&_lmodel_ambient,sizeof(Colorf));
00521     _pD3DDevice->SetRenderState(D3DRS_AMBIENT, 0x0);
00522 
00523     if(_pFvfBufBasePtr==NULL)
00524         _pFvfBufBasePtr = new BYTE[VERT_BUFFER_SIZE];  // allocate storage for vertex info.
00525     if(_index_buf==NULL)
00526         _index_buf = new WORD[PANDA_MAXNUMVERTS];  // allocate storage for vertex index info.
00527 
00528     _pCurFvfBufPtr = NULL;
00529 
00530     _clip_plane_bits = 0;
00531     _pD3DDevice->SetRenderState(D3DRS_CLIPPLANEENABLE , 0x0);
00532 
00533     _pD3DDevice->SetRenderState(D3DRS_CLIPPING, true);
00534     _clipping_enabled = true;
00535 
00536     // these both reflect d3d defaults
00537     _color_writemask = 0xFFFFFFFF;
00538     _CurFVFType = 0x0;  // guards SetVertexShader fmt
00539 
00540     _bGouraudShadingOn = false;
00541     _pD3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
00542 
00543 //   this specifies if lighting model uses material color or vertex color
00544 //   (not related to gouraud/flat shading)
00545 //   _pD3DDevice->SetRenderState(D3DRS_COLORVERTEX, true);
00546 
00547     _depth_test_enabled = true;
00548     _pD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, _depth_test_enabled);
00549 
00550     _pCurTexContext = NULL;
00551 
00552     _line_smooth_enabled = false;
00553     _pD3DDevice->SetRenderState(D3DRS_EDGEANTIALIAS, false);
00554 
00555     _color_material_enabled = false;
00556     _normals_enabled = false;
00557 
00558     _depth_test_enabled = D3DZB_FALSE;
00559     _pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
00560 
00561     _blend_enabled = false;
00562     _pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, (DWORD)_blend_enabled);
00563 
00564     // just use whatever d3d defaults to here
00565     _pD3DDevice->GetRenderState(D3DRS_SRCBLEND, (DWORD*)&_blend_source_func);
00566     _pD3DDevice->GetRenderState(D3DRS_DESTBLEND, (DWORD*)&_blend_dest_func);
00567 
00568     _fog_enabled = false;
00569     _pD3DDevice->SetRenderState(D3DRS_FOGENABLE, _fog_enabled);
00570 
00571     _current_projection_mat = LMatrix4f::ident_mat();
00572     _projection_mat_stack_count = 0;
00573     _has_scene_graph_color = false;
00574 
00575 //  GL stuff that hasnt been translated to DX
00576     // none of these are implemented
00577     //_multisample_enabled = false;         // bugbug:  translate this to dx_multisample_antialiasing_level?
00578     //_point_smooth_enabled = false;
00579 
00580 //    _scissor_enabled = false;
00581 //    _multisample_alpha_one_enabled = false;
00582 //    _multisample_alpha_mask_enabled = false;
00583 //    _line_width = 1.0f;
00584 //    _point_size = 1.0f;
00585 
00586 #ifdef COUNT_DRAWPRIMS
00587      global_pD3DDevice = pDevice;
00588 #endif
00589     _pCurrentGeomContext = NULL;
00590     _bDrawPrimDoSetupVertexBuffer = false;
00591 
00592     _last_testcooplevel_result = D3D_OK;
00593 
00594 #if 0
00595     // unused now
00596     // only 1 channel on dx currently
00597     _panda_gfx_channel = _win->get_channel(0);
00598 #endif
00599 
00600     for(int i=0;i<MAX_POSSIBLE_TEXFMTS;i++) {
00601       // look for all possible DX8 texture fmts
00602       D3DFORMAT_FLAG fmtflag=D3DFORMAT_FLAG(1<<i);
00603       hr = _pScrn->pD3D8->CheckDeviceFormat(_pScrn->CardIDNum,D3DDEVTYPE_HAL,_pScrn->DisplayMode.Format,
00604                                             0x0,D3DRTYPE_TEXTURE,g_D3DFORMATmap[fmtflag]);
00605       if(SUCCEEDED(hr)){
00606         _pScrn->SupportedTexFmtsMask|=fmtflag;
00607       }
00608     }
00609 
00610     // s3 virge drivers sometimes give crap values for these
00611     if(_pScrn->d3dcaps.MaxTextureWidth==0)
00612        _pScrn->d3dcaps.MaxTextureWidth=256;
00613 
00614     if(_pScrn->d3dcaps.MaxTextureHeight==0)
00615        _pScrn->d3dcaps.MaxTextureHeight=256;
00616 
00617     if ((dx_decal_type==GDT_offset) && !(_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_ZBIAS)) {
00618        if(_pScrn->d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) {
00619          if(dxgsg8_cat.is_debug())
00620             dxgsg8_cat.debug() << "dx-decal-type 'offset' not supported by hardware, switching to mask-type decals\n";
00621          dx_decal_type = GDT_mask;
00622        } else {
00623          if(dxgsg8_cat.is_debug())
00624             dxgsg8_cat.debug() << "dx-decal-type 'offset' and color-writemasking not supported by hardware, switching to decal double-draw blend-based masking\n";
00625          dx_decal_type = GDT_blend;
00626        }
00627     }
00628 
00629 #ifdef DISABLE_POLYGON_OFFSET_DECALING
00630     if(dx_decal_type==GDT_offset) {
00631         if(dxgsg8_cat.is_spam())
00632            dxgsg8_cat.spam() << "polygon-offset decaling disabled in dxgsg, switching to double-draw decaling\n";
00633 
00634         if(_pScrn->d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) {
00635          if(dxgsg8_cat.is_debug())
00636             dxgsg8_cat.debug() << "using dx-decal-type 'GDT_mask'\n";
00637          dx_decal_type = GDT_mask;
00638         } else {
00639          if(dxgsg8_cat.is_debug())
00640             dxgsg8_cat.debug() << "dx-decal-type 'mask' not supported by hardware, switching to GDT_blend\n";
00641          dx_decal_type = GDT_blend;
00642         }
00643     }
00644 #endif
00645 
00646     if (((dx_decal_type==GDT_blend)||(dx_decal_type==GDT_mask)) && !(_pScrn->d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_MASKZ)) {
00647         dxgsg8_cat.error() << "dx-decal-types mask&blend impossible to implement, no hardware support for Z-masking, decals will not appear correctly!\n";
00648     }
00649 
00650 #define REQUIRED_DESTBLENDCAPS (D3DPBLENDCAPS_ZERO|D3DPBLENDCAPS_ONE| D3DPBLENDCAPS_SRCALPHA)
00651 #define REQUIRED_SRCBLENDCAPS  (D3DPBLENDCAPS_ZERO|D3DPBLENDCAPS_ONE| D3DPBLENDCAPS_INVSRCALPHA)
00652 
00653     if (((_pScrn->d3dcaps.SrcBlendCaps & REQUIRED_SRCBLENDCAPS)!=REQUIRED_SRCBLENDCAPS) ||
00654         ((_pScrn->d3dcaps.DestBlendCaps & REQUIRED_DESTBLENDCAPS)!=REQUIRED_DESTBLENDCAPS)) {
00655         dxgsg8_cat.error() << "device is missing alpha blending capabilities, blending may not work correctly: SrcBlendCaps: 0x"<< (void*) _pScrn->d3dcaps.SrcBlendCaps << "  DestBlendCaps: "<< (void*) _pScrn->d3dcaps.DestBlendCaps << endl;
00656     }
00657 
00658 // just 'require' bilinear with mip nearest.
00659 #define REQUIRED_TEXFILTERCAPS (D3DPTFILTERCAPS_MAGFLINEAR | D3DPTFILTERCAPS_MIPFPOINT | D3DPTFILTERCAPS_MINFLINEAR)
00660 
00661     if ((_pScrn->d3dcaps.TextureFilterCaps & REQUIRED_TEXFILTERCAPS)!=REQUIRED_TEXFILTERCAPS) {
00662         dxgsg8_cat.error() << "device is missing texture bilinear filtering capability, textures may appear blocky!  TextureFilterCaps: 0x"<< (void*) _pScrn->d3dcaps.TextureFilterCaps << endl;
00663     }
00664 
00665 #define TRILINEAR_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MINFLINEAR)
00666 
00667     // give a warning if we dont at least have bilinear + nearest mip filtering
00668     if (!(_pScrn->d3dcaps.TextureCaps & D3DPTEXTURECAPS_MIPMAP)) {
00669         if(dxgsg8_cat.is_debug())
00670            dxgsg8_cat.debug() << "device does not have mipmap texturing filtering capability! TextureFilterCaps: 0x"<< (void*) _pScrn->d3dcaps.TextureFilterCaps << endl;
00671         dx_ignore_mipmaps = TRUE;
00672     } else if ((_pScrn->d3dcaps.TextureFilterCaps & TRILINEAR_MIPMAP_TEXFILTERCAPS)!=TRILINEAR_MIPMAP_TEXFILTERCAPS) {
00673         if(dxgsg8_cat.is_debug())
00674            dxgsg8_cat.debug() << "device is missing tri-linear mipmap filtering capability, textures may look crappy\n";
00675     } else if(_pScrn->d3dcaps.DevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES) {
00676         // this cap is pretty much voodoo2-specific
00677         // turn off trilinear filtering on voodoo2 since it doubles the reqd texture memory, degrade to mip point filtering
00678         _pScrn->d3dcaps.TextureFilterCaps &= (~D3DPTFILTERCAPS_MIPFLINEAR);
00679     }
00680 
00681 #define REQUIRED_TEXBLENDCAPS (D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2)
00682     if ((_pScrn->d3dcaps.TextureOpCaps & REQUIRED_TEXBLENDCAPS)!=REQUIRED_TEXBLENDCAPS) {
00683         dxgsg8_cat.error() << "device is missing some required texture blending capabilities, texture blending may not work properly! TextureOpCaps: 0x"<< (void*) _pScrn->d3dcaps.TextureOpCaps << endl;
00684     }
00685 
00686     if(_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGTABLE) {
00687         // watch out for drivers that emulate per-pixel fog with per-vertex fog (Riva128, Matrox Millen G200)
00688         // some of these require gouraud-shading to be set to work, as if you were using vertex fog
00689         _doFogType=PerPixelFog;
00690     } else {
00691         // every card is going to have vertex fog, since it's implemented in d3d runtime
00692         assert((_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGVERTEX )!=0);
00693 
00694         // vtx fog may look crappy if you have large polygons in the foreground and they get clipped,
00695         // so you may want to disable it
00696 
00697         if(dx_no_vertex_fog) {
00698             _doFogType = None;
00699         } else {
00700             _doFogType = PerVertexFog;
00701 
00702             // range-based fog only works with vertex fog in dx7/8
00703             if(dx_use_rangebased_fog && (_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGRANGE))
00704                 _pD3DDevice->SetRenderState(D3DRS_RANGEFOGENABLE, true);
00705         }
00706     }
00707 
00708     _pScrn->bCanDirectDisableColorWrites=((_pScrn->d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE)!=0);
00709 
00710     // Lighting, let's turn it off by default
00711     _pD3DDevice->SetRenderState(D3DRS_LIGHTING, false);
00712 
00713     // turn on dithering if the rendertarget is < 8bits/color channel
00714     _dither_enabled = ((!dx_no_dithering) && IS_16BPP_DISPLAY_FORMAT(_pScrn->PresParams.BackBufferFormat)
00715                         && (_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_DITHER));
00716     _pD3DDevice->SetRenderState(D3DRS_DITHERENABLE, _dither_enabled);
00717 
00718     _pD3DDevice->SetRenderState(D3DRS_CLIPPING,true);
00719 
00720     // Stencil test is off by default
00721     _stencil_test_enabled = false;
00722     _pD3DDevice->SetRenderState(D3DRS_STENCILENABLE, _stencil_test_enabled);
00723 
00724     // Antialiasing.
00725     enable_line_smooth(false);
00726 //  enable_multisample(true);
00727 
00728     _current_fill_mode = RenderModeAttrib::M_filled;
00729     _pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
00730 
00731     _pD3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1);  // Use the diffuse vertex color.
00732 
00733     /*
00734       Panda no longer requires us to specify the maximum number of
00735       lights up front, but instead we can define slot_new_light() to
00736       decide one-at-a-time whether a particular light fits within our
00737       limit or not.  Until we override this function, there is no
00738       limit.
00739 
00740     if(_pScrn->d3dcaps.MaxActiveLights==0) {
00741         // 0 indicates no limit on # of lights, but we use DXGSG_MAX_LIGHTS anyway for now
00742       init_lights(DXGSG_MAX_LIGHTS);
00743     } else {
00744       init_lights(min(DXGSG_MAX_LIGHTS,_pScrn->d3dcaps.MaxActiveLights));
00745     }
00746     */
00747 
00748     if(dx_auto_normalize_lighting)
00749          _pD3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);
00750 
00751     // must do SetTSS here because redundant states are filtered out by our code based on current values above, so
00752     // initial conditions must be correct
00753 
00754     _CurTexBlendMode = TextureApplyAttrib::M_modulate;
00755     SetTextureBlendMode(_CurTexBlendMode,false);
00756     _texturing_enabled = false;
00757     _pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE);  // disables texturing
00758 
00759     // Init more Texture State
00760     _CurTexMagFilter=_CurTexMinFilter=_CurTexMipFilter=D3DTEXF_NONE;
00761     _CurTexWrapModeU=_CurTexWrapModeV=Texture::WM_clamp;
00762     _CurTexAnisoDegree=1;
00763 
00764     // this code must match apply_texture() code for states above
00765     // so DX TSS renderstate matches dxgsg state
00766 
00767     _pD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_POINT);
00768     _pD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_POINT);
00769     _pD3DDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTEXF_NONE);
00770     _pD3DDevice->SetTextureStageState(0, D3DTSS_MAXANISOTROPY,_CurTexAnisoDegree);
00771     _pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSU,get_texture_wrap_mode(_CurTexWrapModeU));
00772     _pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSV,get_texture_wrap_mode(_CurTexWrapModeV));
00773 
00774 #ifdef _DEBUG
00775     if ((_pScrn->d3dcaps.RasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS) &&
00776         (dx_global_miplevel_bias!=0.0f)) {
00777         _pD3DDevice->SetTextureStageState(0, D3DTSS_MIPMAPLODBIAS, *((LPDWORD) (&dx_global_miplevel_bias)) );
00778     }
00779 #endif
00780 
00781 #ifndef NDEBUG
00782     if(dx_force_backface_culling!=0) {
00783       if((dx_force_backface_culling > 0) &&
00784          (dx_force_backface_culling < D3DCULL_FORCE_DWORD)) {
00785              _pD3DDevice->SetRenderState(D3DRS_CULLMODE, dx_force_backface_culling);
00786       } else {
00787           dx_force_backface_culling=0;
00788           if(dxgsg8_cat.is_debug())
00789               dxgsg8_cat.debug() << "error, invalid value for dx-force-backface-culling\n";
00790       }
00791     }
00792     _pD3DDevice->SetRenderState(D3DRS_CULLMODE, dx_force_backface_culling);
00793 #else
00794     _pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
00795 #endif
00796 
00797     _alpha_func = D3DCMP_ALWAYS;
00798     _alpha_func_refval = 1.0f;
00799     _pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC, _alpha_func);
00800     _pD3DDevice->SetRenderState(D3DRS_ALPHAREF, (UINT)(_alpha_func_refval*255.0f));
00801     _alpha_test_enabled = false;
00802     _pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, _alpha_test_enabled);
00803 
00804     // this is a new DX8 state that lets you do additional operations other than ADD (e.g. subtract/max/min)
00805     // must check (_pScrn->d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) (yes on GF2/Radeon8500, no on TNT)
00806     _pD3DDevice->SetRenderState(D3DRS_BLENDOP,D3DBLENDOP_ADD);
00807 
00808     PRINT_REFCNT(dxgsg8,_pD3DDevice);
00809 
00810     // Make sure the DX state matches all of our initial attribute states.
00811     CPT(RenderAttrib) dta = DepthTestAttrib::make(DepthTestAttrib::M_less);
00812     CPT(RenderAttrib) dwa = DepthWriteAttrib::make(DepthWriteAttrib::M_on);
00813     CPT(RenderAttrib) cfa = CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise);
00814 
00815     dta->issue(this);
00816     dwa->issue(this);
00817     cfa->issue(this);
00818 
00819     // this is all prelim hacked in testing stuff
00820     init_shader(VertexShader,_CurVertexShader,pdx_vertexshader_filename);
00821     init_shader(PixelShader,_CurPixelShader,pdx_pixelshader_filename);
00822 
00823     if(pdx_globaltexture_filename!=NULL) {
00824         // bypasses panda tex mechanism
00825         hr = D3DXCreateTextureFromFile(_pD3DDevice,pdx_globaltexture_filename->c_str(),&_pGlobalTexture);
00826         if(FAILED(hr)) {
00827             dxgsg8_cat.fatal() << "CreateTexFromFile failed" << D3DERRORSTRING(hr);
00828             exit(1);
00829         }
00830 
00831         hr=_pD3DDevice->SetTexture(dx_globaltexture_stagenum,_pGlobalTexture);
00832         if(FAILED(hr)) {
00833                dxgsg8_cat.fatal() << "SetTexture failed" << D3DERRORSTRING(hr);
00834                exit(1);
00835         }
00836     }
00837 
00838     PRINT_REFCNT(dxgsg8,_pD3DDevice);
00839 }
00840 
00841 void DXGraphicsStateGuardian8::
00842 init_shader(ShaderType stype,DXShaderHandle &hShader,string *pFname) {
00843 
00844     if((pFname==NULL) || pFname->empty()) {
00845       hShader=NULL;
00846       return;
00847     }
00848 
00849     HRESULT hr;
00850 
00851     char *sh_typename;
00852     if(stype==VertexShader)
00853       sh_typename="Vertex";
00854     else sh_typename="Pixel";
00855 
00856     if((stype==PixelShader) && (!_pScrn->bCanUsePixelShaders)) {
00857             dxgsg8_cat.error() << "HW doesnt support pixel shaders!\n";
00858             exit(1);
00859     }
00860 
00861     if((hShader!=NULL)&&(!_pScrn->bIsDX81)) {
00862         // for dx8.0, need to release and recreate shaders after Reset() has been called
00863         if(stype==VertexShader)
00864             hr = _pD3DDevice->DeleteVertexShader(hShader);
00865           else hr = _pD3DDevice->DeletePixelShader(hShader);
00866         if(FAILED(hr))
00867             dxgsg8_cat.error() << "Delete"<< sh_typename<<"Shader failed!" << D3DERRORSTRING(hr);
00868         hShader=NULL;
00869     }
00870 
00871     if(hShader==NULL) {
00872       // doing SetShader globally for testing purps.  this really should be an object attribute
00873       // like current-texture is so it gets set and unset during traversal
00874 
00875       if(stype==VertexShader) {
00876           hShader=read_vertex_shader(*pFname);
00877           hr = _pD3DDevice->SetVertexShader(hShader);
00878       } else {
00879           hShader=read_pixel_shader(*pFname);
00880           hr = _pD3DDevice->SetPixelShader(hShader);
00881       }
00882 
00883       if(FAILED(hr))
00884          dxgsg8_cat.error() << "Set"<<sh_typename<<"Shader failed!" << D3DERRORSTRING(hr);
00885     }
00886 }
00887 
00888 ////////////////////////////////////////////////////////////////////
00889 //     Function: DXGraphicsStateGuardian8::support_overlay_window
00890 //       Access: Public
00891 //  Description: Specifies whether dialog windows placed on top of the
00892 //               dx rendering window should be supported.  This
00893 //               requires a bit of extra overhead, so it should only
00894 //               be activated when necessary; however, if it is not
00895 //               activated, a window that pops up over the fullscreen
00896 //               DX window (like a dialog box, or particularly like
00897 //               the IME composition or candidate windows) may not be
00898 //               visible.
00899 //
00900 //               This is not necessary when running in windowed mode,
00901 //               but it does no harm.
00902 ////////////////////////////////////////////////////////////////////
00903 void DXGraphicsStateGuardian8::
00904 support_overlay_window(bool flag) {
00905   // How is this supposed to be done in DX8?
00906 
00907   /*
00908   if (_overlay_windows_supported && !flag) {
00909     // Disable support for overlay windows.
00910     _overlay_windows_supported = false;
00911 
00912     if (dx_full_screen) {
00913       _pScrn->pddsPrimary->SetClipper(NULL);
00914     }
00915 
00916   } else if (!_overlay_windows_supported && flag) {
00917     // Enable support for overlay windows.
00918     _overlay_windows_supported = true;
00919 
00920     if (dx_full_screen) {
00921       // Create a Clipper object to blt the whole screen.
00922       LPDIRECTDRAWCLIPPER Clipper;
00923 
00924       if (_pScrn->pDD->CreateClipper(0, &Clipper, NULL) == DD_OK) {
00925         Clipper->SetHWnd(0, _pScrn->hWnd);
00926         _pScrn->pddsPrimary->SetClipper(Clipper);
00927       }
00928       _pScrn->pDD->FlipToGDISurface();
00929       Clipper->Release();
00930     }
00931   }
00932   */
00933 }
00934 
00935 ////////////////////////////////////////////////////////////////////
00936 //     Function: DXGraphicsStateGuardian8::do_clear
00937 //       Access: Public, Virtual
00938 //  Description: Clears all of the indicated buffers to their assigned
00939 //               colors.
00940 ////////////////////////////////////////////////////////////////////
00941 void DXGraphicsStateGuardian8::
00942 do_clear(const RenderBuffer &buffer) {
00943   //    DO_PSTATS_STUFF(PStatTimer timer(_win->_clear_pcollector));
00944 
00945     nassertv(buffer._gsg == this);
00946     int buffer_type = buffer._buffer_type;
00947 
00948     DWORD flags = 0;
00949 
00950     if(buffer_type & RenderBuffer::T_depth) {
00951         flags |=  D3DCLEAR_ZBUFFER;
00952         assert(_pScrn->PresParams.EnableAutoDepthStencil);
00953     }
00954 
00955     if(buffer_type & RenderBuffer::T_back)       //set appropriate flags
00956         flags |=  D3DCLEAR_TARGET;
00957 
00958     if(buffer_type & RenderBuffer::T_stencil) {
00959         flags |=  D3DCLEAR_STENCIL;
00960         assert(_pScrn->PresParams.EnableAutoDepthStencil && IS_STENCIL_FORMAT(_pScrn->PresParams.AutoDepthStencilFormat));
00961     }
00962 
00963     HRESULT hr = _pD3DDevice->Clear(0, NULL, flags, _d3dcolor_clear_value,
00964                                          _depth_clear_value, (DWORD)_stencil_clear_value);
00965     if(FAILED(hr))
00966         dxgsg8_cat.error() << "clear_buffer failed:  Clear returned " << D3DERRORSTRING(hr);
00967     /* The following line will cause the background to always clear to a medium red
00968     _color_clear_value[0] = .5;
00969     /* The following lines will cause the background color to cycle from black to red.
00970     _color_clear_value[0] += .001;
00971      if (_color_clear_value[0] > 1.0f) _color_clear_value[0] = 0.0f;
00972      */
00973 }
00974 
00975 ////////////////////////////////////////////////////////////////////
00976 //     Function: DXGraphicsStateGuardian8::prepare_display_region
00977 //       Access: Public, Virtual
00978 //  Description: Prepare a display region for rendering (set up
00979 //       scissor region and viewport)
00980 ////////////////////////////////////////////////////////////////////
00981 void DXGraphicsStateGuardian8::
00982 prepare_display_region() {
00983   if (_current_display_region == (DisplayRegion*)0L) {
00984     dxgsg8_cat.error()
00985       << "Invalid NULL display region in prepare_display_region()\n";
00986   } else if (_current_display_region != _actual_display_region) {
00987     _actual_display_region = _current_display_region;
00988     
00989     int l, b, w, h;
00990     _actual_display_region->get_region_pixels(l, b, w, h);
00991     
00992     // Create the viewport
00993     D3DVIEWPORT8 vp = {l,b,w,h,0.0f,1.0f};
00994     HRESULT hr = _pD3DDevice->SetViewport( &vp );
00995     if (FAILED(hr)) {
00996       dxgsg8_cat.error()
00997         << "SetViewport(" << l << ", " << b << ", " << w << ", " << h
00998         << ") failed" << D3DERRORSTRING(hr);
00999     }
01000     // Note: for DX9, also change scissor clipping state here
01001   }
01002 }
01003 
01004 ////////////////////////////////////////////////////////////////////
01005 //     Function: DXGraphicsStateGuardian8::prepare_lens
01006 //       Access: Public, Virtual
01007 //  Description: Makes the current lens (whichever lens was most
01008 //               recently specified with push_lens()) active, so that
01009 //               it will transform future rendered geometry.  Normally
01010 //               this is only called from the draw process, and
01011 //               usually it is called immediately after a call to
01012 //               push_lens().
01013 //
01014 //               The return value is true if the lens is acceptable,
01015 //               false if it is not.
01016 ////////////////////////////////////////////////////////////////////
01017 bool DXGraphicsStateGuardian8::
01018 prepare_lens() {
01019   if (_current_lens == (Lens *)NULL) {
01020     return false;
01021   }
01022 
01023   if (!_current_lens->is_linear()) {
01024     return false;
01025   }
01026 
01027   const LMatrix4f &projection_mat = _current_lens->get_projection_mat();
01028 
01029   // The projection matrix must always be left-handed Y-up internally,
01030   // even if our coordinate system of choice is otherwise.
01031   LMatrix4f new_projection_mat =
01032     LMatrix4f::convert_mat(CS_yup_left, _current_lens->get_coordinate_system()) *
01033     projection_mat;
01034 
01035   HRESULT hr;
01036   hr = _pD3DDevice->SetTransform(D3DTS_PROJECTION,
01037                                      (D3DMATRIX*)new_projection_mat.get_data());
01038   return SUCCEEDED(hr);
01039 }
01040 
01041 #ifndef NO_MULTIPLE_DISPLAY_REGIONS
01042 ////////////////////////////////////////////////////////////////////
01043 //     Function: set_clipper
01044 //       Access:
01045 //  Description: Useless in DX at the present time
01046 ////////////////////////////////////////////////////////////////////
01047 void DXGraphicsStateGuardian8::set_clipper(RECT cliprect) {
01048 
01049     LPDIRECTDRAWCLIPPER Clipper;
01050     HRESULT result;
01051 
01052     // For windowed mode, the clip region is associated with the window,
01053     // and DirectX does not allow you to create clip regions.
01054     if (dx_full_screen) return;
01055 
01056     /* The cliprect we receive is normalized so that (0,0) means the upper left of
01057        the client portion of the window.
01058         At least, I think that's true, and the following code assumes that.
01059         So we must adjust the clip region by offsetting it to the origin of the
01060         view rectangle.
01061     */
01062     clip_rect = cliprect;       // store the normalized clip rect
01063     cliprect.left += _view_rect.left;
01064     cliprect.right += _view_rect.left;
01065     cliprect.top += _view_rect.top;
01066     cliprect.bottom += _view_rect.top;
01067     RGNDATA *rgn_data = (RGNDATA *)malloc(sizeof(RGNDATAHEADER) + sizeof(RECT));
01068     HRGN hrgn = CreateRectRgn(cliprect.left, cliprect.top, cliprect.right, cliprect.bottom);
01069     GetRegionData(hrgn, sizeof(RGNDATAHEADER) + sizeof(RECT), rgn_data);
01070 
01071     if (_pD3DDevicesPrimary->GetClipper(&Clipper) != DD_OK) {
01072         result = _pD3DDevice->CreateClipper(0, &Clipper, NULL);
01073         result = Clipper->SetClipList(rgn_data, 0);
01074         result = _pD3DDevicesPrimary->SetClipper(Clipper);
01075     } else {
01076         result = Clipper->SetClipList(rgn_data, 0 );
01077         if (result == DDERR_CLIPPERISUSINGHWND) {
01078             result = _pD3DDevicesPrimary->SetClipper(NULL);
01079             result = _pD3DDevice->CreateClipper(0, &Clipper, NULL);
01080             result = Clipper->SetClipList(rgn_data, 0 ) ;
01081             result = _pD3DDevicesPrimary->SetClipper(Clipper);
01082         }
01083     }
01084     free(rgn_data);
01085     DeleteObject(hrgn);
01086 }
01087 #endif
01088 
01089 #if defined(_DEBUG) || defined(COUNT_DRAWPRIMS)
01090 typedef enum {DrawPrim,DrawIndexedPrim} DP_Type;
01091 static const char *DP_Type_Strs[3] = {"DrawPrimitive","DrawIndexedPrimitive"};
01092 
01093 void INLINE TestDrawPrimFailure(DP_Type dptype,HRESULT hr,IDirect3DDevice8 *pD3DDevice,DWORD nVerts,DWORD nTris) {
01094         if(FAILED(hr)) {
01095             // loss of exclusive mode is not a real DrawPrim problem, ignore it
01096             HRESULT testcooplvl_hr = pD3DDevice->TestCooperativeLevel();
01097             if((testcooplvl_hr != D3DERR_DEVICELOST)||(testcooplvl_hr != D3DERR_DEVICENOTRESET)) {
01098                 dxgsg8_cat.fatal() << DP_Type_Strs[dptype] << "() failed: result = " << D3DERRORSTRING(hr);
01099                 exit(1);
01100             }
01101         }
01102 
01103         CountDPs(nVerts,nTris);
01104 }
01105 #else
01106 #define TestDrawPrimFailure(a,b,c,nVerts,nTris) CountDPs(nVerts,nTris);
01107 #endif
01108 
01109 ////////////////////////////////////////////////////////////////////
01110 //     Function: DXGraphicsStateGuardian8::report_texmgr_stats
01111 //       Access: Protected
01112 //  Description: Reports the DX texture manager's activity to PStats.
01113 ////////////////////////////////////////////////////////////////////
01114 void DXGraphicsStateGuardian8::
01115 report_texmgr_stats() {
01116 
01117 #if defined(DO_PSTATS)||defined(PRINT_RESOURCESTATS)
01118   HRESULT hr;
01119 
01120 #ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM
01121   DWORD dwTexTotal,dwTexFree,dwVidTotal,dwVidFree;
01122 
01123 #ifndef PRINT_RESOURCESTATS
01124   if (_total_texmem_pcollector.is_active())
01125 #endif
01126   {
01127       DDSCAPS2 ddsCaps;
01128 
01129       ZeroMemory(&ddsCaps,sizeof(ddsCaps));
01130 
01131       ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
01132       if(FAILED(  hr = _pD3DDevice->GetAvailableVidMem(&ddsCaps,&dwVidTotal,&dwVidFree))) {
01133             dxgsg8_cat.fatal() << "report_texmgr GetAvailableVidMem for VIDMEM failed : result = " << D3DERRORSTRING(hr);
01134             exit(1);
01135       }
01136 
01137       ddsCaps.dwCaps = DDSCAPS_TEXTURE;
01138       if(FAILED(  hr = _pD3DDevice->GetAvailableVidMem(&ddsCaps,&dwTexTotal,&dwTexFree))) {
01139             dxgsg8_cat.fatal() << "report_texmgr GetAvailableVidMem for TEXTURE failed : result = " << D3DERRORSTRING(hr);
01140             exit(1);
01141       }
01142   }
01143 #endif
01144 
01145   D3DDEVINFO_RESOURCEMANAGER all_resource_stats;
01146   ZeroMemory(&all_resource_stats,sizeof(D3DDEVINFO_RESOURCEMANAGER));
01147 
01148   if(!bTexStatsRetrievalImpossible) {
01149       hr = _pD3DDevice->GetInfo(D3DDEVINFOID_RESOURCEMANAGER,&all_resource_stats,sizeof(D3DDEVINFO_RESOURCEMANAGER));
01150       if (hr!=D3D_OK) {
01151           if (hr==S_FALSE) {
01152               static int PrintedMsg=2;
01153               if(PrintedMsg>0) {
01154                   if(dxgsg8_cat.is_debug())
01155                     dxgsg8_cat.debug() << "Error: texstats GetInfo() requires debug DX DLLs to be installed!!  ***********\n";
01156                   ZeroMemory(&all_resource_stats,sizeof(D3DDEVINFO_RESOURCEMANAGER));
01157                   bTexStatsRetrievalImpossible=true;
01158               }
01159           } else {
01160               dxgsg8_cat.error() << "GetInfo(RESOURCEMANAGER) failed to get tex stats: result = " << D3DERRORSTRING(hr);
01161               return;
01162           }
01163       }
01164   }
01165 
01166 #ifdef PRINT_RESOURCESTATS
01167 #ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM
01168     char tmpstr1[50],tmpstr2[50],tmpstr3[50],tmpstr4[50];
01169     sprintf(tmpstr1,"%.4g",dwVidTotal/1000000.0);
01170     sprintf(tmpstr2,"%.4g",dwVidFree/1000000.0);
01171     sprintf(tmpstr3,"%.4g",dwTexTotal/1000000.0);
01172     sprintf(tmpstr4,"%.4g",dwTexFree/1000000.0);
01173     dxgsg8_cat.debug() << "\nAvailableVidMem for RenderSurfs: (megs) total: " << tmpstr1 << "  free: " << tmpstr2
01174                       << "\nAvailableVidMem for Textures:    (megs) total: " << tmpstr3 << "  free: " << tmpstr4 << endl;
01175 #endif
01176 
01177    #define REAL_D3DRTYPECOUNT ((UINT) D3DRTYPE_INDEXBUFFER)     // d3d boneheads defined D3DRTYPECOUNT wrong
01178    static char *ResourceNameStrs[REAL_D3DRTYPECOUNT]={"SURFACE","VOLUME","TEXTURE","VOLUME TEXTURE","CUBE TEXTURE","VERTEX BUFFER","INDEX BUFFER"};
01179    static bool bDoGetInfo[REAL_D3DRTYPECOUNT]={true,false,true,false,false,true,false};  // not using volume or cube textures yet
01180 
01181    if(!bTexStatsRetrievalImpossible) {
01182         for(UINT r=0; r<(UINT)REAL_D3DRTYPECOUNT;r++) {
01183             if(!bDoGetInfo[r])
01184                continue;
01185 
01186             D3DRESOURCESTATS *pRStats=&all_resource_stats.stats[r];
01187             if(pRStats->NumUsed>0) {
01188                 char hitrate_str[20];
01189                 float fHitRate = (pRStats->NumUsedInVidMem * 100.0f) / pRStats->NumUsed;
01190                 sprintf(hitrate_str,"%.1f",fHitRate);
01191 
01192                 dxgsg8_cat.spam()
01193                     << "\n***** Stats for " << ResourceNameStrs[r] << " ********"
01194                     << "\n HitRate:\t" << hitrate_str << "%"
01195                     << "\n bThrashing:\t" << pRStats->bThrashing
01196                     << "\n NumEvicts:\t" << pRStats->NumEvicts
01197                     << "\n NumVidCreates:\t" << pRStats->NumVidCreates
01198                     << "\n NumUsed:\t" << pRStats->NumUsed
01199                     << "\n NumUsedInVidMem:\t" << pRStats->NumUsedInVidMem
01200                     << "\n WorkingSet:\t" << pRStats->WorkingSet
01201                     << "\n WorkingSetBytes:\t" << pRStats->WorkingSetBytes
01202                     << "\n ApproxBytesDownloaded:\t" << pRStats->ApproxBytesDownloaded
01203                     << "\n TotalManaged:\t" << pRStats->TotalManaged
01204                     << "\n TotalBytes:\t" << pRStats->TotalBytes
01205                     << "\n LastPri:\t" << pRStats->LastPri << endl;
01206             } else {
01207                 dxgsg8_cat.spam()
01208                     << "\n***** Stats for " << ResourceNameStrs[r] << " ********"
01209                     << "\n NumUsed: 0\n";
01210             }
01211         }
01212 
01213         D3DDEVINFO_D3DVERTEXSTATS vtxstats;
01214         ZeroMemory(&vtxstats,sizeof(D3DDEVINFO_D3DVERTEXSTATS));
01215         hr = _pD3DDevice->GetInfo(D3DDEVINFOID_VERTEXSTATS,&vtxstats,sizeof(D3DDEVINFO_D3DVERTEXSTATS));
01216         if (hr!=D3D_OK) {
01217             dxgsg8_cat.error() << "GetInfo(D3DVERTEXSTATS) failed : result = " << D3DERRORSTRING(hr);
01218             return;
01219         } else {
01220             dxgsg8_cat.spam()
01221             << "\n***** Triangle Stats ********"
01222             << "\n NumRenderedTriangles:\t" << vtxstats.NumRenderedTriangles
01223             << "\n NumExtraClippingTriangles:\t" << vtxstats.NumExtraClippingTriangles << endl;
01224         }
01225     }
01226 #endif
01227 
01228 #ifdef DO_PSTATS
01229   // Tell PStats about the state of the texture memory.
01230 
01231   if (_texmgrmem_total_pcollector.is_active()) {
01232       // report zero if no debug dlls, to signal this info is invalid
01233       _texmgrmem_total_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].TotalBytes);
01234       _texmgrmem_resident_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].WorkingSetBytes);
01235   }
01236 #ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM
01237   if (_total_texmem_pcollector.is_active()) {
01238     _total_texmem_pcollector.set_level(dwTexTotal);
01239     _used_texmem_pcollector.set_level(dwTexTotal - dwTexFree);
01240   }
01241 #endif
01242 #endif
01243 #endif
01244 }
01245 
01246 ////////////////////////////////////////////////////////////////////
01247 //     Function: DXGraphicsStateGuardian8::add_to_FVFBuf
01248 //       Access: Private
01249 //  Description: This adds data to the flexible vertex format
01250 ////////////////////////////////////////////////////////////////////
01251 INLINE void DXGraphicsStateGuardian8::
01252 add_to_FVFBuf(void *data,  size_t bytes) {
01253     memcpy(_pCurFvfBufPtr, data, bytes);
01254     _pCurFvfBufPtr += bytes;
01255 }
01256 
01257 // generates slightly fewer instrs
01258 #define add_DWORD_to_FVFBuf(data) { *((DWORD *)_pCurFvfBufPtr) = (DWORD) data;  _pCurFvfBufPtr += sizeof(DWORD);}
01259 
01260 typedef enum {
01261     FlatVerts,IndexedVerts,MixedFmtVerts
01262 } GeomVertFormat;
01263 
01264 #define COPYVERTDATA_2_VERTEXBUFFER(PrimType,NumVertices) {                                     \
01265             DWORD numVertBytes=_pCurFvfBufPtr-_pFvfBufBasePtr;                                  \
01266             memcpy(_pCurrentGeomContext->_pEndofVertData,_pFvfBufBasePtr,numVertBytes);         \
01267             DPInfo dpInfo;                                                                      \
01268             dpInfo.nVerts=NumVertices;                                                          \
01269             dpInfo.primtype=PrimType;                                                           \
01270             _pCurrentGeomContext->_PrimInfo.push_back(dpInfo);                                  \
01271             _pCurrentGeomContext->_num_verts+=dpInfo.nVerts;                                    \
01272             _pCurrentGeomContext->_pEndofVertData+=numVertBytes; }
01273 
01274 
01275 INLINE void DXGraphicsStateGuardian8::
01276 transform_color(Colorf &InColor,D3DCOLOR &OutRGBAColor) {
01277   Colorf transformed
01278     ((InColor[0] * _current_color_scale[0]) + _current_color_offset[0],
01279      (InColor[1] * _current_color_scale[1]) + _current_color_offset[1],
01280      (InColor[2] * _current_color_scale[2]) + _current_color_offset[2],
01281      (InColor[3] * _current_color_scale[3]) + _current_color_offset[3]);
01282   OutRGBAColor = Colorf_to_D3DCOLOR(transformed);
01283 }
01284 
01285 ////////////////////////////////////////////////////////////////////
01286 //     Function: DXGraphicsStateGuardian8::draw_prim_setup
01287 //       Access: Private
01288 //  Description: This adds data to the flexible vertex format
01289 ////////////////////////////////////////////////////////////////////
01290 size_t DXGraphicsStateGuardian8::
01291 draw_prim_setup(const Geom *geom) {
01292     //  Set the flags for the flexible vertex format and compute the bytes
01293     //  required to store a single vertex.
01294     // Assumes _perVertex,_perPrim,_perComp flags are setup prior to entry
01295     // (especially for shademode).  maybe should change this, since we usually
01296     // get attr info anyway)
01297 
01298     #ifdef _DEBUG
01299       assert(geom->get_binding(G_COORD) != G_OFF);
01300     #endif
01301 
01302 #define GET_NEXT_VERTEX(NEXTVERT) { NEXTVERT = geom->get_next_vertex(vi); }
01303 #define GET_NEXT_NORMAL() { p_normal = geom->get_next_normal(ni); }
01304 #define GET_NEXT_TEXCOORD() { p_texcoord = geom->get_next_texcoord(ti); }
01305 
01306 #define GET_NEXT_COLOR() {                                                           \
01307     Colorf tempcolor = geom->get_next_color(ci);                                     \
01308     if(_color_transform_enabled == 0) {                                              \
01309         _curD3Dcolor = Colorf_to_D3DCOLOR(tempcolor);                                \
01310     } else {                                                                         \
01311         transform_color(tempcolor,_curD3Dcolor);                                     \
01312     }}
01313 
01314 ////////
01315 
01316    // this stuff should eventually replace the iterators below
01317    PTA_Vertexf coords;
01318    PTA_ushort vindexes;
01319 
01320    geom->get_coords(coords,vindexes);
01321    if(vindexes!=NULL) {
01322       _pCurCoordIndex = _coordindex_array = &vindexes[0];
01323    } else {
01324       _pCurCoordIndex = _coordindex_array = NULL;
01325    }
01326    _pCurCoord = _coord_array = &coords[0];
01327 
01328    ///////////////
01329 
01330    vi = geom->make_vertex_iterator();
01331    DWORD newFVFflags = D3DFVF_XYZ;
01332    size_t vertex_size = sizeof(float) * 3;
01333 
01334    GeomBindType ColorBinding=geom->get_binding(G_COLOR);
01335    bool bDoColor=(ColorBinding != G_OFF);
01336 
01337    if (bDoColor || _has_scene_graph_color) {
01338         ci = geom->make_color_iterator();
01339         newFVFflags |= D3DFVF_DIFFUSE;
01340         vertex_size += sizeof(D3DCOLOR);
01341 
01342         if (_has_scene_graph_color) {
01343             if (_scene_graph_color_stale) {
01344               // Compute the D3DCOLOR for the scene graph override color.
01345               if(_color_transform_enabled == 0) {
01346                 _scene_graph_color_D3DCOLOR = Colorf_to_D3DCOLOR(_scene_graph_color);
01347               } else {
01348                 transform_color(_scene_graph_color, _scene_graph_color_D3DCOLOR);
01349               }
01350               _scene_graph_color_stale = false;
01351             }
01352             _curD3Dcolor = _scene_graph_color_D3DCOLOR;  // set primitive color if there is one.
01353 
01354             _perVertex &= ~PER_COLOR;
01355             _perPrim &= ~PER_COLOR;
01356             _perComp &= ~PER_COLOR;
01357          } else if(ColorBinding == G_OVERALL){
01358             GET_NEXT_COLOR();
01359             _perVertex &= ~PER_COLOR;
01360             _perPrim &= ~PER_COLOR;
01361             _perComp &= ~PER_COLOR;
01362         }
01363    }
01364 
01365    if (geom->get_binding(G_NORMAL) != G_OFF) {
01366         ni = geom->make_normal_iterator();
01367         newFVFflags |= D3DFVF_NORMAL;
01368         vertex_size += sizeof(float) * 3;
01369 
01370         if (geom->get_binding(G_NORMAL) == G_OVERALL)
01371             p_normal = geom->get_next_normal(ni);    // set overall normal if there is one
01372    }
01373 
01374 
01375    GeomBindType TexCoordBinding;
01376    PTA_TexCoordf texcoords;
01377    PTA_ushort tindexes;
01378    geom->get_texcoords(texcoords,TexCoordBinding,tindexes);
01379    if (TexCoordBinding != G_OFF) {
01380        assert(TexCoordBinding == G_PER_VERTEX);
01381 
01382        // used by faster path
01383        if(tindexes!=NULL) {
01384           _pCurTexCoordIndex = _texcoordindex_array = &tindexes[0];
01385        } else {
01386           _pCurTexCoordIndex = _texcoordindex_array = NULL;
01387        }
01388        _pCurTexCoord = _texcoord_array = &texcoords[0];
01389        //////
01390 
01391        ti = geom->make_texcoord_iterator();
01392         newFVFflags |= (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
01393        vertex_size += sizeof(float) * 2;
01394    }
01395 
01396     // If we have per-vertex colors or normals, we need smooth shading.
01397     // Otherwise we want flat shading for performance reasons.
01398 
01399    // Note on fogging:
01400    // the fogging expression should really be || (_fog_enabled && (_doFogType==PerVertexFog))
01401    // instead of just || (_fog_enabled), since GOURAUD shading should not be required for PerPixel
01402    // fog, but the problem is some cards (Riva128,Matrox G200) emulate pixel fog with table fog
01403    // but dont force the shading mode to gouraud internally, so you end up with flat-shaded fog colors
01404    // (note, TNT does the right thing tho).  So I guess we must do gouraud shading for all fog rendering for now
01405    // note that if _doFogType==None, _fog_enabled will always be false
01406 
01407    bool need_gouraud_shading = ((_perVertex & (PER_COLOR | (wants_normals() ? PER_NORMAL : 0))) || _fog_enabled);
01408 
01409    enable_gouraud_shading(need_gouraud_shading);
01410    set_vertex_format(newFVFflags);
01411 
01412    return vertex_size;
01413 }
01414 
01415 ////////////////////////////////////////////////////////////////////
01416 //     Function: DXGraphicsStateGuardian8::draw_prim_inner_loop
01417 //       Access: Private
01418 //  Description: This adds data to the flexible vertex format with a check
01419 //               for component normals and color
01420 ////////////////////////////////////////////////////////////////////
01421 void DXGraphicsStateGuardian8::
01422 draw_prim_inner_loop(int nVerts, const Geom *geom, ushort perFlags) {
01423     Vertexf NextVert;
01424 
01425     for(;nVerts > 0;nVerts--) {
01426          // coord info will always be _perVertex
01427         GET_NEXT_VERTEX(NextVert);     // need to optimize these
01428         add_to_FVFBuf((void *)&NextVert, 3*sizeof(float));
01429 
01430         if(perFlags==(ushort)TexCoordOnly) {
01431             // break out the common case (for animated chars) 1st
01432             GET_NEXT_TEXCOORD();
01433         } else {
01434             switch (DrawLoopFlags(perFlags)) {
01435                 case Color_TexCoord:
01436                     GET_NEXT_TEXCOORD();
01437                 case ColorOnly:
01438                     GET_NEXT_COLOR();
01439                     break;
01440                 case Normal_Color:
01441                     GET_NEXT_COLOR();
01442                 case NormalOnly:
01443                     GET_NEXT_NORMAL();
01444                     break;
01445                 case Normal_Color_TexCoord:
01446                     GET_NEXT_COLOR();
01447                 case Normal_TexCoord:
01448                     GET_NEXT_NORMAL();
01449                 // case TexCoordOnly:
01450                     GET_NEXT_TEXCOORD();
01451                     break;
01452             }
01453         }
01454 
01455         if (_CurFVFType & D3DFVF_NORMAL)
01456             add_to_FVFBuf((void *)&p_normal, 3*sizeof(float));
01457         if (_CurFVFType & D3DFVF_DIFFUSE)
01458             add_DWORD_to_FVFBuf(_curD3Dcolor);
01459         if (_CurFVFType & D3DFVF_TEXCOUNT_MASK)
01460             add_to_FVFBuf((void *)&p_texcoord, sizeof(TexCoordf));
01461     }
01462 }
01463 
01464 
01465 ////////////////////////////////////////////////////////////////////
01466 //     Function: DXGraphicsStateGuardian8::draw_prim_inner_loop_coordtexonly
01467 //       Access: Private
01468 //  Description: FastPath loop used by animated character data
01469 ////////////////////////////////////////////////////////////////////
01470 void DXGraphicsStateGuardian8::
01471 draw_prim_inner_loop_coordtexonly(int nVerts, const Geom *geom) {
01472     // assumes coord and texcoord data is per-vertex,
01473     // color is not per-vert/component (which would require fetching new vals in the vertex loop),
01474     // and no normal data. this should be common situation for animated character data
01475     // inc'ing local ptrs instead of member ones, seems to optimize better
01476     // bypass all the slow vertex iterator stuff
01477 
01478     #ifdef _DEBUG
01479      {
01480       assert(geom->get_binding(G_NORMAL) == G_OFF);
01481       GeomBindType ColorBinding = geom->get_binding(G_COLOR);
01482       assert((ColorBinding != G_PER_VERTEX) || (ColorBinding != G_PER_COMPONENT));
01483       assert(geom->get_binding(G_TEXCOORD) == G_PER_VERTEX);
01484      }
01485     #endif
01486 
01487     Vertexf *pCurCoord = _pCurCoord;
01488     ushort *pCurCoordIndex = _pCurCoordIndex;
01489     TexCoordf *pCurTexCoord = _pCurTexCoord;
01490     ushort *pCurTexCoordIndex = _pCurTexCoordIndex;
01491 
01492     BYTE *pLocalFvfBufPtr = _pCurFvfBufPtr;
01493     DWORD cur_color = _curD3Dcolor;
01494     bool bDoIndexedTexCoords = (_texcoordindex_array != NULL);
01495     bool bDoIndexedCoords = (_coordindex_array != NULL);
01496 
01497     for(;nVerts>0;nVerts--) {
01498         if(bDoIndexedCoords) {
01499            memcpy(pLocalFvfBufPtr,(void*)&_coord_array[*pCurCoordIndex],3*sizeof(float));
01500            pCurCoordIndex++;
01501         } else {
01502            memcpy(pLocalFvfBufPtr,(void*)pCurCoord,3*sizeof(float));
01503            pCurCoord++;
01504         }
01505 
01506         pLocalFvfBufPtr+=3*sizeof(float);
01507 
01508         *((DWORD *)pLocalFvfBufPtr) = cur_color;
01509         pLocalFvfBufPtr += sizeof(DWORD);
01510 
01511         if(bDoIndexedTexCoords) {
01512            memcpy(pLocalFvfBufPtr,(void*)&_texcoord_array[*pCurTexCoordIndex],sizeof(TexCoordf));
01513            pCurTexCoordIndex++;
01514         } else {
01515            memcpy(pLocalFvfBufPtr,(void*)pCurTexCoord,sizeof(TexCoordf));
01516            pCurTexCoord++;
01517         }
01518         pLocalFvfBufPtr+=sizeof(TexCoordf);
01519     }
01520 
01521     _pCurFvfBufPtr=pLocalFvfBufPtr;
01522     _pCurCoord = pCurCoord;
01523     _pCurCoordIndex = pCurCoordIndex;
01524     _pCurTexCoord = pCurTexCoord;
01525     _pCurTexCoordIndex = pCurTexCoordIndex;
01526 }
01527 
01528 ////////////////////////////////////////////////////////////////////
01529 //     Function: DXGraphicsStateGuardian8::draw_point
01530 //       Access: Public, Virtual
01531 //  Description:
01532 ////////////////////////////////////////////////////////////////////
01533 void DXGraphicsStateGuardian8::
01534 draw_point(GeomPoint *geom, GeomContext *gc) {
01535 
01536 #ifdef GSG_VERBOSE
01537     dxgsg8_cat.debug() << "draw_point()" << endl;
01538 #endif
01539 
01540     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
01541     DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
01542 
01543     // The DX Way
01544 
01545     int nPrims = geom->get_num_prims();
01546 
01547     if (nPrims==0) {
01548         dxgsg8_cat.warning() << "draw_point() called with ZERO vertices!!" << endl;
01549         return;
01550     }
01551 
01552 #ifdef _DEBUG
01553     static bool bPrintedMsg=false;
01554 
01555     if (!bPrintedMsg && (geom->get_size()!=1.0f)) {
01556         bPrintedMsg=true;
01557         dxgsg8_cat.warning() << "D3D does not support drawing points of non-unit size, setting point size to 1.0f!\n";
01558     }
01559 #endif
01560 
01561     nassertv(nPrims < PANDA_MAXNUMVERTS );
01562 
01563     PTA_Vertexf coords;
01564     PTA_Normalf norms;
01565     PTA_Colorf colors;
01566     PTA_TexCoordf texcoords;
01567     GeomBindType bind;
01568     PTA_ushort vindexes,nindexes,tindexes,cindexes;
01569 
01570     geom->get_coords(coords,vindexes);
01571     geom->get_normals(norms,bind,nindexes);
01572     geom->get_colors(colors,bind,cindexes);
01573     geom->get_texcoords(texcoords,bind,tindexes);
01574 
01575     // for Indexed Prims and mixed indexed/non-indexed prims, we will use old pipeline for now
01576     // need to add code to handle fully indexed mode (and handle cases with index arrays of different lengths,
01577     // values (may only be possible to handle certain cases without reverting to old pipeline)
01578 
01579         _perVertex = 0x0;
01580         _perPrim = 0;
01581         if (geom->get_binding(G_NORMAL) == G_PER_VERTEX) _perVertex |= PER_NORMAL;
01582         if (geom->get_binding(G_COLOR) == G_PER_VERTEX) _perVertex |= PER_COLOR;
01583 
01584         size_t vertex_size = draw_prim_setup(geom);
01585 
01586         nassertv(_pCurFvfBufPtr == NULL);    // make sure the storage pointer is clean.
01587         nassertv(nPrims * vertex_size < VERT_BUFFER_SIZE);
01588         _pCurFvfBufPtr = _pFvfBufBasePtr;          // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
01589 
01590         // iterate through the point
01591         draw_prim_inner_loop(nPrims, geom, _perVertex | _perPrim);
01592 
01593         if(!_bDrawPrimDoSetupVertexBuffer) {
01594            HRESULT hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_POINTLIST, nPrims, _pFvfBufBasePtr, vertex_size);
01595            TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,nPrims,0);
01596         } else {
01597             COPYVERTDATA_2_VERTEXBUFFER(D3DPT_POINTLIST,nPrims);
01598         }
01599 
01600 
01601     _pCurFvfBufPtr = NULL;
01602 }
01603 
01604 
01605 ////////////////////////////////////////////////////////////////////
01606 //     Function: DXGraphicsStateGuardian8::draw_line
01607 //       Access: Public, Virtual
01608 //  Description:
01609 ////////////////////////////////////////////////////////////////////
01610 void DXGraphicsStateGuardian8::
01611 draw_line(GeomLine* geom, GeomContext *gc) {
01612 
01613 #ifdef GSG_VERBOSE
01614     dxgsg8_cat.debug() << "draw_line()" << endl;
01615 #endif
01616     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
01617     DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
01618 
01619 #ifdef _DEBUG
01620     static bool bPrintedMsg=false;
01621 
01622     // note: need to implement approximation of non-1.0 width lines with quads
01623 
01624     if (!bPrintedMsg && (geom->get_width()!=1.0f)) {
01625         bPrintedMsg=true;
01626         if(dxgsg8_cat.is_debug())
01627             dxgsg8_cat.debug() << "DX does not support drawing lines with a non-1.0f pixel width, setting width to 1.0f!\n";
01628     }
01629 #endif
01630 
01631     int nPrims = geom->get_num_prims();
01632 
01633     if (nPrims==0) {
01634         if(dxgsg8_cat.is_debug())
01635            dxgsg8_cat.debug() << "draw_line() called with ZERO vertices!!" << endl;
01636         return;
01637     }
01638 
01639     _perVertex = 0x0;
01640     _perPrim = 0x0;
01641     _perComp = 0x0;
01642 
01643     switch(geom->get_binding(G_COLOR)) {
01644         case G_PER_VERTEX:
01645             _perVertex |=  PER_COLOR;
01646             break;
01647         case G_PER_COMPONENT:
01648             _perComp |= PER_COLOR;
01649             break;
01650         default:
01651             _perPrim |= PER_COLOR;
01652     }
01653 
01654     switch(geom->get_binding(G_NORMAL)) {
01655         case G_PER_VERTEX:
01656             _perVertex |=  PER_NORMAL;
01657             break;
01658         case G_PER_COMPONENT:
01659             _perComp |=  PER_NORMAL;
01660             break;
01661         default:
01662             _perPrim |=  PER_NORMAL;
01663     }
01664 
01665     size_t vertex_size = draw_prim_setup(geom);
01666 
01667     BYTE *_tmp_fvfOverrunBuf = NULL;
01668     nassertv(_pCurFvfBufPtr == NULL);    // make sure the storage pointer is clean.
01669 //  nassertv(nPrims * 2 * vertex_size < VERT_BUFFER_SIZE);
01670 
01671     if (nPrims * 2 * vertex_size > VERT_BUFFER_SIZE) {
01672         // bugbug: need cleaner way to handle tmp buffer size overruns (malloc/realloc?)
01673         _pCurFvfBufPtr = _tmp_fvfOverrunBuf = new BYTE[nPrims * 2 * vertex_size];
01674     } else  _pCurFvfBufPtr = _pFvfBufBasePtr;            // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
01675 
01676     for (int i = 0; i < nPrims; i++) {
01677         if (_perPrim & PER_COLOR) {
01678             GET_NEXT_COLOR();
01679         }
01680         if (_perPrim & PER_NORMAL)
01681             p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
01682         draw_prim_inner_loop(2, geom, _perVertex);
01683     }
01684 
01685     HRESULT hr;
01686 
01687     DWORD nVerts = nPrims<<1;
01688 
01689     if(!_bDrawPrimDoSetupVertexBuffer) {
01690         if (_tmp_fvfOverrunBuf == NULL) {
01691             nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr));
01692             hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, nPrims, _pFvfBufBasePtr, vertex_size);
01693         } else {
01694             nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_tmp_fvfOverrunBuf));
01695             hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, nPrims, _tmp_fvfOverrunBuf, vertex_size);
01696             delete [] _tmp_fvfOverrunBuf;
01697         }
01698         TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,nVerts,0);
01699     } else {
01700         COPYVERTDATA_2_VERTEXBUFFER(D3DPT_LINELIST,nVerts);
01701     }
01702 
01703     _pCurFvfBufPtr = NULL;
01704 }
01705 
01706 void DXGraphicsStateGuardian8::
01707 draw_linestrip(GeomLinestrip* geom, GeomContext *gc) {
01708 
01709 #ifdef _DEBUG
01710     static BOOL bPrintedMsg=false;
01711 
01712     if (!bPrintedMsg && (geom->get_width()!=1.0f)) {
01713         bPrintedMsg=true;
01714         dxgsg8_cat.warning() << "DX does not support drawing lines with a non-1.0f pixel width, setting width to 1.0f!\n";
01715     }
01716 #endif
01717 
01718   draw_linestrip_base(geom,gc,false);
01719 }
01720 
01721 ////////////////////////////////////////////////////////////////////
01722 //     Function: DXGraphicsStateGuardian8::draw_linestrip
01723 //       Access: Public, Virtual
01724 //  Description:
01725 ////////////////////////////////////////////////////////////////////
01726 void DXGraphicsStateGuardian8::
01727 draw_linestrip_base(Geom* geom, GeomContext *gc, bool bConnectEnds) {
01728 // Note draw_linestrip_base() may be called from non-line draw_fns to support wireframe mode
01729 
01730 #ifdef GSG_VERBOSE
01731     dxgsg8_cat.debug() << "draw_linestrip()" << endl;
01732 #endif
01733 
01734     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
01735     DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
01736 
01737     int nPrims = geom->get_num_prims();
01738     const int *pLengthArr = geom->get_lengths();
01739 
01740     if(nPrims==0) {
01741         if(dxgsg8_cat.is_debug())
01742             dxgsg8_cat.debug() << "draw_linestrip() called with ZERO vertices!!" << endl;
01743         return;
01744     }
01745 
01746     _perVertex = 0x0;
01747     _perPrim = 0x0;
01748     _perComp = 0x0;
01749 
01750     switch(geom->get_binding(G_COLOR)) {
01751         case G_PER_VERTEX:
01752             _perVertex |= PER_COLOR;
01753             break;
01754         case G_PER_COMPONENT:
01755             _perComp |= PER_COLOR;
01756             break;
01757         default:
01758             _perPrim |= PER_COLOR;
01759     }
01760 
01761     switch(geom->get_binding(G_NORMAL)) {
01762         case G_PER_VERTEX:
01763             _perVertex |=  PER_NORMAL;
01764             break;
01765         case G_PER_COMPONENT:
01766             _perComp |=  PER_NORMAL;
01767             break;
01768         default:
01769             _perPrim |= PER_NORMAL;
01770     }
01771 
01772     size_t vertex_size = draw_prim_setup(geom);
01773     ushort perFlags = _perVertex | _perComp;
01774 
01775     bool bPerPrimColor = ((_perPrim & PER_COLOR)!=0);
01776     bool bPerPrimNormal = ((_perPrim & PER_NORMAL)!=0);
01777 
01778     DWORD nVerts;
01779 
01780     if(pLengthArr==NULL) // we've been called by draw_quad, which has no lengths array
01781       nVerts=4;
01782 
01783     for (int i = 0; i < nPrims; i++) {
01784         if (bPerPrimColor) {
01785             GET_NEXT_COLOR();
01786         }
01787 
01788         if (bPerPrimNormal) {
01789             p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
01790         }
01791 
01792         if(pLengthArr!=NULL) {
01793             nVerts= *(pLengthArr++);
01794             nassertv(nVerts >= 2);
01795         }
01796 
01797         nassertv(_pCurFvfBufPtr == NULL);   // make sure the storage pointer is clean.
01798         nassertv(nVerts * vertex_size < VERT_BUFFER_SIZE);
01799         _pCurFvfBufPtr = _pFvfBufBasePtr;   // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
01800 
01801         draw_prim_inner_loop(nVerts, geom, perFlags);
01802 
01803         if(bConnectEnds) {
01804              // append first vertex to end
01805              memcpy(_pCurFvfBufPtr,_pFvfBufBasePtr,vertex_size);
01806              _pCurFvfBufPtr+=vertex_size;
01807              nVerts++;
01808         }
01809 
01810         nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr));
01811 
01812         if(!_bDrawPrimDoSetupVertexBuffer) {
01813             HRESULT hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_LINESTRIP, nVerts-1, _pFvfBufBasePtr, vertex_size);
01814             TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,nVerts,0);
01815         } else {
01816             COPYVERTDATA_2_VERTEXBUFFER(D3DPT_LINESTRIP,nVerts);
01817         }
01818 
01819         _pCurFvfBufPtr = NULL;
01820     }
01821 }
01822 
01823 // this class exists because an alpha sort is necessary for correct
01824 // sprite rendering, and we can't simply sort the vertex arrays as
01825 // each vertex may or may not have corresponding information in the
01826 // x/y texel-world-ratio and rotation arrays.
01827 typedef struct {
01828     Vertexf _v;
01829     D3DCOLOR _c;
01830     float _x_ratio;
01831     float _y_ratio;
01832     float _theta;
01833 } WrappedSprite;
01834 
01835 class WrappedSpriteSortPtr {
01836 public:
01837     float z;
01838     WrappedSprite *pSpr;
01839 };
01840 
01841 // this struct exists because the STL can sort faster than i can.
01842 struct draw_sprite_vertex_less {
01843     INLINE bool operator ()(const WrappedSpriteSortPtr& v0,
01844                             const WrappedSpriteSortPtr& v1) const {
01845         return v0.z > v1.z; // reversed from gl due to left-handed coordsys of d3d
01846     }
01847 };
01848 
01849 ////////////////////////////////////////////////////////////////////
01850 //     Function: DXGraphicsStateGuardian8::draw_sprite
01851 //       Access: Public, Virtual
01852 //  Description:
01853 ////////////////////////////////////////////////////////////////////
01854 void DXGraphicsStateGuardian8::
01855 draw_sprite(GeomSprite *geom, GeomContext *gc) {
01856 
01857     // this is a little bit of a mess, but it's ok.  Here's the deal:
01858     // we want to draw, and draw quickly, an arbitrarily large number
01859     // of sprites all facing the screen.  Performing the billboard math
01860     // for ~1000 sprites is way too slow.  Ideally, we want one
01861     // matrix transformation that will handle everything, and this is
01862     // just about what ends up happening. We're getting the front-facing
01863     // effect by setting up a new frustum (of the same z-depth as the
01864     // current one) that is very small in x and y.  This way regularly
01865     // rendered triangles that might not be EXACTLY facing the camera
01866     // will certainly look close enough.  Then, we transform to camera-space
01867     // by hand and apply the inverse frustum to the transformed point.
01868     // For some cracked out reason, this actually works.
01869 
01870 
01871     // Note: for DX8, try to use the PointSprite primitive instead of doing all the stuff below
01872 
01873 #ifdef GSG_VERBOSE
01874     dxgsg8_cat.debug() << "draw_sprite()" << endl;
01875 #endif
01876     // get the array traversal set up.
01877     int nPrims = geom->get_num_prims();
01878 
01879     if (nPrims==0) {
01880         return;
01881     }
01882 
01883     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
01884 
01885     DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(nPrims));
01886 
01887     D3DMATRIX OldD3DWorldMatrix;
01888     _pD3DDevice->GetTransform(D3DTS_WORLD, &OldD3DWorldMatrix);
01889 
01890     bool bReEnableDither=false;
01891 
01892     _pD3DDevice->GetTransform(D3DTS_WORLD, &OldD3DWorldMatrix);
01893 
01894     Geom::VertexIterator vi = geom->make_vertex_iterator();
01895     Geom::ColorIterator ci = geom->make_color_iterator();
01896 
01897     // note although sprite particles technically dont require a texture,
01898     // the texture dimensions are used to initialize the size calculations
01899     // the code in spriteParticleRenderer.cxx does not handle the no-texture case now
01900 
01901     float tex_xsize = 1.0f;
01902     float tex_ysize = 1.0f;
01903 
01904     Texture *tex = geom->get_texture();
01905     if(tex !=NULL) {
01906       // set up the texture-rendering state
01907       modify_state(RenderState::make
01908                    (TextureAttrib::make(tex),
01909                     TextureApplyAttrib::make(TextureApplyAttrib::M_modulate)));
01910       tex_xsize = tex->_pbuffer->get_xsize();
01911       tex_ysize = tex->_pbuffer->get_ysize();
01912     }
01913 
01914     // save the modelview matrix
01915     const LMatrix4f &modelview_mat = _transform->get_mat();
01916 
01917     // We don't need to mess with the aspect ratio, since we are now
01918     // using the default projection matrix, which has the right aspect
01919     // ratio built in.
01920 
01921     // null the world xform, so sprites are orthog to scrn
01922     _pD3DDevice->SetTransform(D3DTS_WORLD, &matIdentity);
01923     // only need to change _WORLD xform, _VIEW xform is Identity
01924 
01925     // precomputation stuff
01926     float tex_left = geom->get_ll_uv()[0];
01927     float tex_right = geom->get_ur_uv()[0];
01928     float tex_bottom = geom->get_ll_uv()[1];
01929     float tex_top = geom->get_ur_uv()[1];
01930 
01931     float half_width =  0.5f * tex_xsize * fabs(tex_right - tex_left);
01932     float half_height = 0.5f * tex_ysize * fabs(tex_top - tex_bottom);
01933     float scaled_width, scaled_height;
01934 
01935     // the user can override alpha sorting if they want
01936     bool alpha = false;
01937 
01938     if (!geom->get_alpha_disable()) {
01939       // figure out if alpha's enabled (if not, no reason to sort)
01940       const TransparencyAttrib *trans = _state->get_transparency();
01941       if (trans != (const TransparencyAttrib *)NULL) {
01942         alpha = (trans->get_mode() != TransparencyAttrib::M_none);
01943       }
01944     }
01945 
01946     // inner loop vars
01947     int i;
01948     Vertexf source_vert, cameraspace_vert;
01949     float *x_walk, *y_walk, *theta_walk;
01950     float theta;
01951 
01952     nassertv(geom->get_x_bind_type() != G_PER_VERTEX);
01953     nassertv(geom->get_y_bind_type() != G_PER_VERTEX);
01954 
01955     // set up the non-built-in bindings
01956     bool x_overall = (geom->get_x_bind_type() == G_OVERALL);
01957     bool y_overall = (geom->get_y_bind_type() == G_OVERALL);
01958     bool theta_overall = (geom->get_theta_bind_type() == G_OVERALL);
01959     bool color_overall = (geom->get_binding(G_COLOR) == G_OVERALL);
01960     bool theta_on = !(geom->get_theta_bind_type() == G_OFF);
01961 
01962     // x direction
01963     if (x_overall)
01964         scaled_width = geom->_x_texel_ratio[0] * half_width;
01965     else {
01966         nassertv(((int)geom->_x_texel_ratio.size() >= geom->get_num_prims()));
01967         x_walk = &geom->_x_texel_ratio[0];
01968     }
01969 
01970     // y direction
01971     if (y_overall)
01972         scaled_height = geom->_y_texel_ratio[0] * half_height;
01973     else {
01974         nassertv(((int)geom->_y_texel_ratio.size() >= geom->get_num_prims()));
01975         y_walk = &geom->_y_texel_ratio[0];
01976     }
01977 
01978     // theta
01979     if (theta_on) {
01980         if (theta_overall)
01981             theta = geom->_theta[0];
01982         else {
01983             nassertv(((int)geom->_theta.size() >= geom->get_num_prims()));
01984             theta_walk = &geom->_theta[0];
01985         }
01986     }
01987 
01988     /////////////////////////////////////////////////////////////////////
01989     // INNER LOOP PART 1 STARTS HERE
01990     // Here we transform each point to cameraspace and fill our sort
01991     // vector with the final geometric information.
01992     /////////////////////////////////////////////////////////////////////
01993 
01994     Colorf v_color;
01995 
01996     // sort container and iterator
01997     pvector< WrappedSpriteSortPtr > sorted_sprite_vector;
01998     pvector< WrappedSpriteSortPtr >::iterator sorted_vec_iter;
01999 
02000     WrappedSprite *SpriteArray = new WrappedSprite[nPrims];
02001 
02002     //BUGBUG: could we use _fvfbuf for this to avoid perframe alloc?
02003     // alternately, alloc once when retained mode becomes available
02004 
02005     if (SpriteArray==NULL) {
02006         dxgsg8_cat.fatal() << "draw_sprite() out of memory!!" << endl;
02007         return;
02008     }
02009 
02010     // the state is set, start running the prims
02011 
02012     WrappedSprite *pSpr;
02013 
02014     for (pSpr=SpriteArray,i = 0; i < nPrims; i++,pSpr++) {
02015 
02016         source_vert = geom->get_next_vertex(vi);
02017         cameraspace_vert = source_vert * modelview_mat;
02018 
02019         pSpr->_v.set(cameraspace_vert[0],cameraspace_vert[1],cameraspace_vert[2]);
02020 
02021         if (!color_overall) {
02022             GET_NEXT_COLOR();
02023             pSpr->_c = _curD3Dcolor;
02024         }
02025         if (!x_overall)
02026             pSpr->_x_ratio = *x_walk++;
02027         if (!y_overall)
02028             pSpr->_y_ratio = *y_walk++;    // go along array of ratio values stored in geom
02029         if (theta_on && (!theta_overall))
02030             pSpr->_theta = *theta_walk++;
02031     }
02032 
02033     if (alpha) {
02034         sorted_sprite_vector.reserve(nPrims);   //pre-alloc space for nPrims
02035 
02036         for (pSpr=SpriteArray,i = 0; i < nPrims; i++,pSpr++) {   // build STL-sortable array
02037             WrappedSpriteSortPtr ws_ptr;
02038             ws_ptr.z=pSpr->_v[2];
02039             ws_ptr.pSpr=pSpr;
02040             sorted_sprite_vector.push_back(ws_ptr);
02041         }
02042 
02043         // sort the verts properly by alpha (if necessary).  Of course,
02044         // the sort is only local, not scene-global, so if you look closely you'll
02045         // notice that alphas may be screwy.  It's ok though, because this is fast.
02046         // if you want accuracy, use billboards and take the speed hit.
02047 
02048         sort(sorted_sprite_vector.begin(), sorted_sprite_vector.end(), draw_sprite_vertex_less());
02049         sorted_vec_iter = sorted_sprite_vector.begin();
02050 
02051         // disabling dither for alpha particle-systems.
02052         // ATI sez:  most applications ignore the fact that since alpha blended primitives
02053         // combine the data in the frame buffer with the data in the current pixel, pixels
02054         // can be dithered multiple times and accentuate the dither pattern. This is particularly
02055         // true in particle systems which rely on the cumulative visual effect of many overlapping
02056         // alpha blended primitives.
02057 
02058         if(_dither_enabled) {
02059             bReEnableDither=true;
02060             enable_dither(false);
02061         }
02062     }
02063 
02064     Vertexf ul, ur, ll, lr;
02065 
02066     ////////////////////////////////////////////////////////////////////////////
02067     // INNER LOOP PART 2 STARTS HERE
02068     // Now we run through the cameraspace vector and compute the geometry for each
02069     // tristrip.  This includes scaling as per the ratio arrays, as well as
02070     // rotating in the z.
02071     ////////////////////////////////////////////////////////////////////////////
02072 
02073     D3DCOLOR CurColor;
02074     DWORD FVFType = D3DFVF_XYZ | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)) | D3DFVF_DIFFUSE;
02075     DWORD vertex_size = sizeof(float) * 2 + sizeof(float) * 3 + sizeof(D3DCOLOR);
02076 
02077     if (color_overall) {
02078         GET_NEXT_COLOR();
02079         CurColor = _curD3Dcolor;
02080     }
02081 
02082     // see note on fog and gouraud-shading in draw_prim_setup
02083     bool bUseGouraudShadedColor=_fog_enabled;
02084     enable_gouraud_shading(_fog_enabled);
02085     set_vertex_format(FVFType);
02086 
02087     #ifdef _DEBUG
02088      nassertv(_pCurFvfBufPtr == NULL);   // make sure the storage pointer is clean.
02089      nassertv(nPrims * 4 * vertex_size < VERT_BUFFER_SIZE);
02090      nassertv(nPrims * 6 < PANDA_MAXNUMVERTS );
02091     #endif
02092 
02093     _pCurFvfBufPtr = _pFvfBufBasePtr;          // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
02094 
02095     const float TexCrdSets[4][2] = {
02096       { tex_left, tex_bottom },
02097       { tex_right, tex_bottom },
02098       { tex_left, tex_top },
02099       { tex_right, tex_top }
02100     };
02101 
02102 #define QUADVERTLISTLEN 6
02103 
02104     DWORD QuadVertIndexList[QUADVERTLISTLEN] = { 0, 1, 2, 3, 2, 1};
02105     DWORD CurDPIndexArrLength=0,CurVertCount=0;
02106 
02107     for (pSpr=SpriteArray,i = 0; i < nPrims; i++,pSpr++) {   // build STL-sortable array
02108 
02109         if (alpha) {
02110             pSpr = sorted_vec_iter->pSpr;
02111             sorted_vec_iter++;
02112         }
02113 
02114         // if not G_OVERALL, calculate the scale factors    //huh??
02115         if (!x_overall)
02116             scaled_width = pSpr->_x_ratio * half_width;
02117 
02118         if (!y_overall)
02119             scaled_height = pSpr->_y_ratio * half_height;
02120 
02121         // if not G_OVERALL, do some trig for this z rotate   //what is the theta angle??
02122         if (theta_on) {
02123             if (!theta_overall)
02124                 theta = pSpr->_theta;
02125 
02126             // create the rotated points.  BUGBUG: this matmult will be slow if we dont get inlining
02127             // rotate_mat calls sin() on an unbounded val, possible to make it faster with lookup table (modulate to 0-360 range?)
02128 
02129             LMatrix3f xform_mat = LMatrix3f::rotate_mat(theta) *
02130                                   LMatrix3f::scale_mat(scaled_width, scaled_height);
02131 
02132             ur = (LVector3f( 1.0f,  1.0f, 0.0f) * xform_mat) + pSpr->_v;
02133             ul = (LVector3f(-1.0f,  1.0f, 0.0f) * xform_mat) + pSpr->_v;
02134             lr = (LVector3f( 1.0f, -1.0f, 0.0f) * xform_mat) + pSpr->_v;
02135             ll = (LVector3f(-1.0f, -1.0f, 0.0f) * xform_mat) + pSpr->_v;
02136         } else {
02137             // create points for unrotated rect sprites
02138             float x,y,negx,negy,z;
02139 
02140             x = pSpr->_v[0] + scaled_width;
02141             y = pSpr->_v[1] + scaled_height;
02142             negx = pSpr->_v[0] - scaled_width;
02143             negy = pSpr->_v[1] - scaled_height;
02144             z = pSpr->_v[2];
02145 
02146             ur.set(x, y, z);
02147             ul.set(negx, y, z);
02148             lr.set(x, negy, z);
02149             ll.set(negx, negy, z);
02150         }
02151 
02152         // can no longer assume flat-shaded (because of vtx fog), so always copy full color in there
02153 
02154         /*********  LL vertex  **********/
02155 
02156         add_to_FVFBuf((void *)ll.get_data(), 3*sizeof(float));
02157         if (!color_overall)  // otherwise its already been set globally
02158            CurColor = pSpr->_c;
02159         add_DWORD_to_FVFBuf(CurColor); // only need to cpy color on 1st vert, others are just empty ignored space
02160         add_to_FVFBuf((void *)TexCrdSets[0], sizeof(float)*2);
02161 
02162         /*********  LR vertex  **********/
02163 
02164         add_to_FVFBuf((void *)lr.get_data(), 3*sizeof(float));
02165 
02166         // if flat shading, dont need to write color for middle vtx, just incr ptr
02167         if(bUseGouraudShadedColor)
02168             *((DWORD *)_pCurFvfBufPtr) = (DWORD) CurColor;
02169         _pCurFvfBufPtr += sizeof(D3DCOLOR);
02170 
02171         add_to_FVFBuf((void *)TexCrdSets[1], sizeof(float)*2);
02172 
02173         /*********  UL vertex  **********/
02174 
02175         add_to_FVFBuf((void *)ul.get_data(), 3*sizeof(float));
02176         // if flat shading, dont need to write color for middle vtx, just incr ptr
02177         if(bUseGouraudShadedColor)
02178             *((DWORD *)_pCurFvfBufPtr) = (DWORD) CurColor;
02179         _pCurFvfBufPtr += sizeof(D3DCOLOR);
02180         add_to_FVFBuf((void *)TexCrdSets[2], sizeof(float)*2);
02181 
02182         /*********  UR vertex  **********/
02183 
02184         add_to_FVFBuf((void *)ur.get_data(), 3*sizeof(float));
02185         add_DWORD_to_FVFBuf(CurColor);
02186         add_to_FVFBuf((void *)TexCrdSets[3], sizeof(float)*2);
02187 
02188         for (int ii=0;ii<QUADVERTLISTLEN;ii++) {
02189             _index_buf[CurDPIndexArrLength+ii]=QuadVertIndexList[ii]+CurVertCount;
02190         }
02191         CurDPIndexArrLength+=QUADVERTLISTLEN;
02192         CurVertCount+=4;
02193     }
02194 
02195     DWORD nVerts= nPrims << 2;  // 4*nPrims verts in vert array
02196     DWORD numTris = nPrims << 1;  // 2*nPrims
02197 
02198     // cant do tristrip/fan since multiple quads arent connected
02199     // best we can do is indexed primitive, which sends 2 redundant indices instead of sending 2 redundant full verts
02200     HRESULT hr = _pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0,  // start index in array
02201                                                          nVerts, numTris,
02202                                                          _index_buf, D3DFMT_INDEX16,
02203                                                          _pFvfBufBasePtr, vertex_size);
02204     TestDrawPrimFailure(DrawIndexedPrim,hr,_pD3DDevice,QUADVERTLISTLEN*nPrims,numTris);
02205 
02206     _pCurFvfBufPtr = NULL;
02207     delete [] SpriteArray;
02208 
02209     // restore the matrices
02210     _pD3DDevice->SetTransform(D3DTS_WORLD,
02211                                   (D3DMATRIX*)modelview_mat.get_data());
02212 
02213     if(bReEnableDither)
02214         enable_dither(true);
02215 }
02216 
02217 ////////////////////////////////////////////////////////////////////
02218 //     Function: DXGraphicsStateGuardian8::draw_polygon
02219 //       Access: Public, Virtual
02220 //  Description:
02221 ////////////////////////////////////////////////////////////////////
02222 void DXGraphicsStateGuardian8::
02223 draw_polygon(GeomPolygon *geom, GeomContext *gc) {
02224 
02225 #ifdef GSG_VERBOSE
02226    dxgsg8_cat.debug() << "draw_polygon()" << endl;
02227 #endif
02228    DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
02229    DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
02230 
02231    // wireframe polygon will be drawn as linestrip, otherwise draw as multi-tri trifan
02232    DWORD rstate;
02233    _pD3DDevice->GetRenderState(D3DRS_FILLMODE, &rstate);
02234    if(rstate==D3DFILL_WIREFRAME) {
02235        draw_linestrip_base(geom,gc,true);
02236    } else {
02237        draw_multitri(geom, D3DPT_TRIANGLEFAN);
02238    }
02239 }
02240 
02241 ////////////////////////////////////////////////////////////////////
02242 //     Function: DXGraphicsStateGuardian8::draw_quad
02243 //       Access: Public, Virtual
02244 //  Description:
02245 ////////////////////////////////////////////////////////////////////
02246 void DXGraphicsStateGuardian8::
02247 draw_quad(GeomQuad *geom, GeomContext *gc) {
02248 
02249 #ifdef GSG_VERBOSE
02250     dxgsg8_cat.debug() << "draw_quad()" << endl;
02251 #endif
02252    DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
02253    DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
02254 
02255    // wireframe quad will be drawn as linestrip, otherwise draw as multi-tri trifan
02256    DWORD rstate;
02257    _pD3DDevice->GetRenderState(D3DRS_FILLMODE, &rstate);
02258    if(rstate==D3DFILL_WIREFRAME) {
02259        draw_linestrip_base(geom,gc,true);
02260    } else {
02261        draw_multitri(geom, D3DPT_TRIANGLEFAN);
02262    }
02263 }
02264 
02265 
02266 ////////////////////////////////////////////////////////////////////
02267 //     Function: DXGraphicsStateGuardian8::draw_tri
02268 //       Access: Public, Virtual
02269 //  Description:
02270 ////////////////////////////////////////////////////////////////////
02271 void DXGraphicsStateGuardian8::
02272 draw_tri(GeomTri *geom, GeomContext *gc) {
02273 #ifdef GSG_VERBOSE
02274     dxgsg8_cat.debug() << "draw_tri()" << endl;
02275 #endif
02276     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
02277     DO_PSTATS_STUFF(_vertices_tri_pcollector.add_level(geom->get_num_vertices()));
02278 
02279 #if 0
02280     if (_pCurTexContext!=NULL) {
02281         dxgsg8_cat.spam() << "Cur active DX texture: " << _pCurTexContext->_tex->get_name() << "\n";
02282     }
02283 #endif
02284 
02285 #ifdef COUNT_DRAWPRIMS
02286     cGeomcount++;
02287 #endif
02288 
02289     DWORD nPrims = geom->get_num_prims();
02290     HRESULT hr;
02291 
02292     PTA_Vertexf coords;
02293     PTA_Normalf norms;
02294     PTA_Colorf colors;
02295     PTA_TexCoordf texcoords;
02296     GeomBindType TexCoordBinding,ColorBinding,NormalBinding;
02297     PTA_ushort vindexes,nindexes,tindexes,cindexes;
02298 
02299     geom->get_coords(coords,vindexes);
02300     geom->get_normals(norms,NormalBinding,nindexes);
02301     geom->get_colors(colors,ColorBinding,cindexes);
02302     geom->get_texcoords(texcoords,TexCoordBinding,tindexes);
02303 
02304         // this is the old geom setup, it reformats every vtx into an output array passed to d3d
02305 
02306         _perVertex = 0x0;
02307         _perPrim = 0x0;
02308 
02309         bool bUseTexCoordOnlyLoop = ((ColorBinding != G_PER_VERTEX) &&
02310                                      (NormalBinding == G_OFF) &&
02311                                      (TexCoordBinding != G_OFF));
02312 
02313         bool bPerPrimNormal;
02314 
02315         bool bPerPrimColor=(ColorBinding == G_PER_PRIM);
02316         if(bPerPrimColor)
02317            _perPrim = PER_COLOR;
02318           else if(ColorBinding == G_PER_VERTEX)
02319                  _perVertex = PER_COLOR;
02320 
02321         if(bUseTexCoordOnlyLoop) {
02322            _perVertex |= PER_TEXCOORD;  // TexCoords are either G_OFF or G_PER_VERTEX
02323         } else {
02324             if(NormalBinding == G_PER_VERTEX)
02325                 _perVertex |= PER_NORMAL;
02326             else if(NormalBinding == G_PER_PRIM)
02327                     _perPrim |= PER_NORMAL;
02328 
02329             bPerPrimNormal=((_perPrim & PER_NORMAL)!=0);
02330 
02331             if(TexCoordBinding == G_PER_VERTEX)
02332                _perVertex |= PER_TEXCOORD;
02333         }
02334 
02335         size_t vertex_size = draw_prim_setup(geom);
02336 
02337         // Note: draw_prim_setup could unset color flags if global color is set, so must
02338         //       recheck this flag here!
02339         bPerPrimColor=(_perPrim & PER_COLOR)!=0x0;
02340 
02341         #ifdef _DEBUG
02342           // is it Ok not to recompute bUseTexCoordOnlyLoop even if draw_prim_setup unsets color flags?
02343           // add this check to make sure
02344            bool bNewUseTexCoordOnlyLoop = (((_perVertex & PER_COLOR)==0x0) &&
02345                                            ((_CurFVFType & D3DFVF_NORMAL)==0x0) &&
02346                                            ((_CurFVFType & D3DFVF_TEX1)!=0x0));
02347            if(bUseTexCoordOnlyLoop && (!bNewUseTexCoordOnlyLoop)) {
02348                // ok for bUseTexCoordOnlyLoop to be false, and bNew to be true.
02349                // draw_prim_setup can sometimes turn off the _perComp color for
02350                // G_OVERALL and scene-graph-color cases, which causes bNew to be true,
02351                // while the original bUseTexCoordOnly is still false.
02352                // the case we want to prevent is accidently using the texcoordloop
02353                // instead of the general one, using the general one should always work.
02354 
02355                DebugBreak();
02356                assert(0);
02357            }
02358         #endif
02359 
02360         nassertv(_pCurFvfBufPtr == NULL);    // make sure the storage pointer is clean.
02361         nassertv(nPrims * 3 * vertex_size < VERT_BUFFER_SIZE);
02362         _pCurFvfBufPtr = _pFvfBufBasePtr;          // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
02363 
02364         // iterate through the triangle primitive
02365 
02366         for (uint i = 0; i < nPrims; i++) {
02367             if(bPerPrimColor) {  // remember color might be G_OVERALL too!
02368                 GET_NEXT_COLOR();
02369             }
02370 
02371             if(bUseTexCoordOnlyLoop) {
02372                draw_prim_inner_loop_coordtexonly(3, geom);
02373             } else {
02374                 if(bPerPrimNormal)
02375                     p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
02376 
02377                 draw_prim_inner_loop(3, geom, _perVertex);
02378             }
02379         }
02380 
02381         DWORD nVerts=nPrims*3;
02382 
02383         nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr));
02384 
02385         if(!_bDrawPrimDoSetupVertexBuffer) {
02386             hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, nPrims, _pFvfBufBasePtr, vertex_size);
02387             TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,nVerts,nPrims);
02388         } else {
02389             COPYVERTDATA_2_VERTEXBUFFER(D3DPT_TRIANGLELIST,nVerts);
02390         }
02391 
02392         _pCurFvfBufPtr = NULL;
02393 
02394 
02395 ///////////////////////////
02396 #if 0
02397     // test triangle for me to dbg experiments only
02398     float vert_buf[15] = {
02399         0.0f, 0.0f, 0.0f,  0.0f, 0.0f,
02400         33.0, 0.0f, 0.0f,  0.0f, 2.0,
02401         0.0f, 0.0f, 33.0,  2.0, 0.0f
02402     };
02403 
02404     _pD3DDevice->SetTextureStageState(0,D3DTSS_ADDRESSU,D3DTADDRESS_BORDER);
02405     _pD3DDevice->SetTextureStageState(0,D3DTSS_ADDRESSV,D3DTADDRESS_BORDER);
02406     _pD3DDevice->SetTextureStageState(0,D3DTSS_BORDERCOLOR,MY_D3DRGBA(0,0,0,0));
02407 
02408     DWORD FVFType =  D3DFVF_XYZ | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)) ;
02409     set_vertex_format(FVFType);
02410     HRESULT hr = _pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST,  vert_buf, 1, 5*sizeof(float));
02411     TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,3,1);
02412 #endif
02413 }
02414 
02415 ////////////////////////////////////////////////////////////////////
02416 //     Function: DXGraphicsStateGuardian8::draw_tristrip
02417 //       Access: Public, Virtual
02418 //  Description:
02419 ////////////////////////////////////////////////////////////////////
02420 void DXGraphicsStateGuardian8::
02421 draw_tristrip(GeomTristrip *geom, GeomContext *gc) {
02422 
02423 #ifdef GSG_VERBOSE
02424   dxgsg8_cat.debug() << "draw_tristrip()" << endl;
02425 #endif
02426   DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
02427   DO_PSTATS_STUFF(_vertices_tristrip_pcollector.add_level(geom->get_num_vertices()));
02428 
02429   draw_multitri(geom, D3DPT_TRIANGLESTRIP);
02430 }
02431 
02432 ////////////////////////////////////////////////////////////////////
02433 //     Function: DXGraphicsStateGuardian8::draw_trifan
02434 //       Access: Public, Virtual
02435 //  Description:
02436 ////////////////////////////////////////////////////////////////////
02437 void DXGraphicsStateGuardian8::
02438 draw_trifan(GeomTrifan *geom, GeomContext *gc) {
02439 
02440 #ifdef GSG_VERBOSE
02441     dxgsg8_cat.debug() << "draw_trifan()" << endl;
02442 #endif
02443   DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
02444   DO_PSTATS_STUFF(_vertices_trifan_pcollector.add_level(geom->get_num_vertices()));
02445 
02446   draw_multitri(geom, D3DPT_TRIANGLEFAN);
02447 }
02448 
02449 ////////////////////////////////////////////////////////////////////
02450 //     Function: DXGraphicsStateGuardian8::draw_multitri
02451 //       Access: Public, Virtual
02452 //  Description: handles trifans and tristrips
02453 ////////////////////////////////////////////////////////////////////
02454 void DXGraphicsStateGuardian8::
02455 draw_multitri(Geom *geom, D3DPRIMITIVETYPE trilisttype) {
02456 
02457     DWORD nPrims = geom->get_num_prims();
02458     const uint *pLengthArr = (const uint *) ((const int *)geom->get_lengths());
02459     HRESULT hr;
02460 
02461     if(nPrims==0) {
02462         #ifdef _DEBUG
02463           dxgsg8_cat.warning() << "draw_multitri() called with ZERO vertices!!" << endl;
02464         #endif
02465         return;
02466     }
02467 
02468 #ifdef COUNT_DRAWPRIMS
02469     cGeomcount++;
02470 #endif
02471 
02472     PTA_Vertexf coords;
02473     PTA_Normalf norms;
02474     PTA_Colorf colors;
02475     PTA_TexCoordf texcoords;
02476     GeomBindType TexCoordBinding,ColorBinding,NormalBinding;
02477     PTA_ushort vindexes,nindexes,tindexes,cindexes;
02478 
02479     geom->get_coords(coords,vindexes);
02480     geom->get_normals(norms,NormalBinding,nindexes);
02481     geom->get_colors(colors,ColorBinding,cindexes);
02482     geom->get_texcoords(texcoords,TexCoordBinding,tindexes);
02483 
02484     {
02485         // this is the old geom setup, it reformats every vtx into an output array passed to d3d
02486         _perVertex = 0x0;
02487         _perPrim = 0x0;
02488         _perComp = 0x0;
02489 
02490         bool bIsTriList=(trilisttype==D3DPT_TRIANGLESTRIP);
02491         bool bPerPrimColor=(ColorBinding == G_PER_PRIM);
02492         bool bPerPrimNormal;
02493         bool bUseTexCoordOnlyLoop = (((ColorBinding == G_OVERALL) || bPerPrimColor) &&
02494                                      (NormalBinding == G_OFF) &&
02495                                      (TexCoordBinding != G_OFF));
02496 
02497         if(bUseTexCoordOnlyLoop) {
02498            if(bPerPrimColor) {
02499                 _perPrim = PER_COLOR;
02500            }
02501         } else {
02502             switch (ColorBinding) {
02503                 case G_PER_PRIM:
02504                     _perPrim = PER_COLOR;
02505                     break;
02506                 case G_PER_COMPONENT:
02507                     _perComp = PER_COLOR;
02508                     break;
02509                 case G_PER_VERTEX:
02510                     _perVertex = PER_COLOR;
02511                     break;
02512             }
02513 
02514             switch (NormalBinding) {
02515                 case G_PER_VERTEX:
02516                     _perVertex |= PER_NORMAL;
02517                     break;
02518                 case G_PER_PRIM:
02519                     _perPrim |= PER_NORMAL;
02520                     break;
02521                 case G_PER_COMPONENT:
02522                     _perComp |= PER_NORMAL;
02523                     break;
02524             }
02525 
02526             bPerPrimNormal=((_perPrim & PER_NORMAL)!=0);
02527 
02528             if (TexCoordBinding == G_PER_VERTEX)
02529                 _perVertex |= PER_TEXCOORD;
02530         }
02531 
02532         size_t vertex_size = draw_prim_setup(geom);
02533 
02534         // Note: draw_prim_setup could unset color flags if global color is set, so must
02535         //       recheck this flag here!
02536         bPerPrimColor=(_perPrim & PER_COLOR)!=0;
02537 
02538         #ifdef _DEBUG
02539           // is it Ok not to recompute bUseTexCoordOnlyLoop even if draw_prim_setup unsets color flags?
02540           // add this check to make sure.  texcoordonly needs input that with unchanging color, except per-prim
02541            bool bNewUseTexCoordOnlyLoop = ((((_perComp|_perVertex) & PER_COLOR)==0x0) &&
02542                                            ((_CurFVFType & D3DFVF_NORMAL)==0x0) &&
02543                                            ((_CurFVFType & D3DFVF_TEX1)!=0x0));
02544 
02545            if(bUseTexCoordOnlyLoop && (!bNewUseTexCoordOnlyLoop)) {
02546                // ok for bUseTexCoordOnlyLoop to be false, and bNew to be true.
02547                // draw_prim_setup can sometimes turn off the _perComp color for
02548                // G_OVERALL and scene-graph-color cases, which causes bNew to be true,
02549                // while the original bUseTexCoordOnly is still false.
02550                // the case we want to prevent is accidently using the texcoordloop
02551                // instead of the general one, using the general one should always work.
02552 
02553                DebugBreak();
02554                assert(0);
02555            }
02556 
02557         #endif
02558 
02559         // iterate through the triangle primitives
02560 
02561         int nVerts;
02562         if(pLengthArr==NULL) {
02563            // we've been called by draw_quad, which has no lengths array
02564            nVerts=4;
02565         }
02566 
02567         for (uint i = 0; i < nPrims; i++) {
02568 
02569             if(pLengthArr!=NULL) {
02570               nVerts = *(pLengthArr++);
02571             }
02572 
02573             if(bPerPrimColor) {  // remember color might be G_OVERALL too!
02574                 GET_NEXT_COLOR();
02575             }
02576 
02577 #ifdef _DEBUG
02578             nassertv(nVerts >= 3);
02579             nassertv(_pCurFvfBufPtr == NULL);    // make sure the storage pointer is clean.
02580             nassertv(nVerts * vertex_size < VERT_BUFFER_SIZE);
02581 #endif
02582             _pCurFvfBufPtr = _pFvfBufBasePtr;            // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
02583 
02584             if(_perComp==0x0) {
02585                  if(bUseTexCoordOnlyLoop) {
02586                     draw_prim_inner_loop_coordtexonly(nVerts, geom);
02587                  } else {
02588                      if (bPerPrimNormal)
02589                          p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
02590 
02591                      draw_prim_inner_loop(nVerts, geom, _perVertex);
02592                  }
02593             } else {
02594                 if(bPerPrimNormal)
02595                     p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
02596 
02597                 if(bIsTriList) {
02598                    // in flat shade mode, D3D strips color using the 1st vertex.
02599                    // (note: differs from OGL, which always uses last vtx for strips&fans
02600 
02601                     // Store all but last 2 verts
02602                     draw_prim_inner_loop(nVerts-2, geom, _perVertex | _perComp);
02603 
02604                     // _perComp attribs should not be fetched for last 2 verts
02605                     draw_prim_inner_loop(2, geom, _perVertex);
02606                 } else {
02607                    // in flat shade mode, D3D fans color using the 2nd vertex.
02608                    // (note: differs from OGL, which always uses last vtx for strips&fans
02609                    // _perComp attribs should not be fetched for first & last verts, they will
02610                    // be associated with middle n-2 verts
02611 
02612                     draw_prim_inner_loop(1, geom, _perVertex);
02613                     draw_prim_inner_loop(nVerts-2, geom, _perVertex | _perComp);
02614                     draw_prim_inner_loop(1, geom, _perVertex);
02615                 }
02616             }
02617 
02618             assert((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr));
02619             DWORD numTris=nVerts-2;
02620 
02621             if(!_bDrawPrimDoSetupVertexBuffer) {
02622                 hr = _pD3DDevice->DrawPrimitiveUP(trilisttype, numTris, _pFvfBufBasePtr, vertex_size);
02623                 TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,nVerts,numTris);
02624             } else {
02625                 COPYVERTDATA_2_VERTEXBUFFER(trilisttype,nVerts);
02626             }
02627 
02628             _pCurFvfBufPtr = NULL;
02629         }
02630     }
02631 
02632 }
02633 
02634 //-----------------------------------------------------------------------------
02635 // Name: GenerateSphere()
02636 // Desc: Makes vertex and index data for ellipsoid w/scaling factors sx,sy,sz
02637 //       tries to match gluSphere behavior
02638 //-----------------------------------------------------------------------------
02639 
02640 // probably want to replace this with D3DX8 call
02641 
02642 void DXGraphicsStateGuardian8::
02643 GenerateSphere(void *pVertexSpace,DWORD dwVertSpaceByteSize,
02644                void *pIndexSpace,DWORD dwIndexSpaceByteSize,
02645                D3DXVECTOR3 *pCenter, float fRadius,
02646                DWORD wNumRings, DWORD wNumSections, float sx, float sy, float sz,
02647                DWORD *pNumVertices,DWORD *pNumTris,DWORD fvfFlags,DWORD dwVertSize) {
02648     float x, y, z, rsintheta;
02649     D3DXVECTOR3 vPoint;
02650 
02651 //#define DBG_GENSPHERE
02652 #define M_PI 3.1415926f   // probably should get this from mathNumbers.h instead
02653 
02654     nassertv(wNumRings>=2 && wNumSections>=2);
02655     wNumRings--;  // wNumRings indicates number of vertex rings (not tri-rings).
02656                   // gluSphere 'stacks' arg for 1 vert ring is 2, so convert to our '1'.
02657     wNumSections++;  // to make us equiv to gluSphere
02658 
02659     //Figure out needed space for the triangles and vertices.
02660     DWORD dwNumVertices,dwNumIndices,dwNumTriangles;
02661 
02662 #define DO_SPHERE_TEXTURING (fvfFlags & D3DFVF_TEXCOUNT_MASK)
02663 #define DO_SPHERE_NORMAL    (fvfFlags & D3DFVF_NORMAL)
02664 #define DO_SPHERE_COLOR     (fvfFlags & D3DFVF_DIFFUSE)
02665 
02666     if (DO_SPHERE_TEXTURING) {
02667         // if texturing, we need full rings of identical position verts at poles to hold diff texture coords
02668         wNumRings+=2;
02669         dwNumVertices = *pNumVertices = wNumRings * wNumSections;
02670         dwNumTriangles = (wNumRings-1) * wNumSections * 2;
02671     } else {
02672         dwNumVertices = *pNumVertices = wNumRings * wNumSections + 2;
02673         dwNumTriangles = wNumRings*wNumSections*2;
02674     }
02675 
02676     dwNumIndices = dwNumTriangles*3;
02677     *pNumTris = dwNumTriangles;
02678 
02679 //    D3DVERTEX* pvVertices = (D3DVERTEX*) pVertexSpace;
02680     WORD *pwIndices = (WORD *) pIndexSpace;
02681 
02682     nassertv(dwNumVertices*dwVertSize < VERT_BUFFER_SIZE);
02683     nassertv(dwNumIndices < PANDA_MAXNUMVERTS );
02684 
02685     // Generate vertex at the top point
02686     D3DXVECTOR3 vTopPoint  = *pCenter;
02687     D3DXVECTOR3 vBotPoint  = *pCenter;
02688     float yRadius=sy*fRadius;
02689     vTopPoint.y+=yRadius;
02690     vBotPoint.y-=yRadius;
02691     D3DXVECTOR3 vNormal = D3DXVECTOR3( 0.0f, 1.0f, 0.0f);
02692     float texCoords[2];
02693 
02694     nassertv(pVertexSpace==_pCurFvfBufPtr);  // add_to_FVFBuf requires this
02695 
02696 #define ADD_GENSPHERE_VERTEX_TO_BUFFER(VERT)                      \
02697     add_to_FVFBuf((void *)&(VERT), 3*sizeof(float));            \
02698     if(fvfFlags & D3DFVF_NORMAL)                                  \
02699         add_to_FVFBuf((void *)&vNormal, 3*sizeof(float));       \
02700     if(fvfFlags & D3DFVF_DIFFUSE)                                 \
02701         add_DWORD_to_FVFBuf(_curD3Dcolor);                        \
02702     if(fvfFlags & D3DFVF_TEXCOUNT_MASK)                           \
02703         add_to_FVFBuf((void *)texCoords, sizeof(TexCoordf));
02704 
02705 #ifdef DBG_GENSPHERE
02706     int nvs_written=0;
02707     memset(pVertexSpace,0xFF,dwNumVertices*dwVertSize);
02708 #endif
02709 
02710     if (! DO_SPHERE_TEXTURING) {
02711         ADD_GENSPHERE_VERTEX_TO_BUFFER(vTopPoint);
02712 #ifdef DBG_GENSPHERE
02713         nvs_written++;
02714 #endif
02715     }
02716 
02717     // Generate vertex points for rings
02718     float inv_radius = 1.0f/fRadius;
02719     const float reciprocal_PI=1.0f/M_PI;
02720     const float reciprocal_2PI=1.0f/(2.0*M_PI);
02721     DWORD i;
02722     float theta,dtheta;
02723 
02724     if (DO_SPHERE_TEXTURING) {
02725         // numRings already includes 1st and last rings for this case
02726         dtheta = (float)(M_PI / (wNumRings-1));     //Angle between each ring (ignore 2 fake rings)
02727         theta = 0.0f;
02728     } else {
02729         dtheta = (float)(M_PI / (wNumRings + 1));   //Angle between each ring
02730         theta = dtheta;
02731     }
02732     float phi,dphi   = (float)(2*M_PI / (wNumSections-1)); //Angle between each section
02733 
02734     for (i = 0; i < wNumRings; i++) {
02735         float costheta,sintheta,cosphi,sinphi;
02736         phi =   0.0f;
02737 
02738         if (DO_SPHERE_TEXTURING) {
02739             texCoords[1] = theta * reciprocal_PI;  // v is the same for each ring
02740         }
02741 
02742         // could optimize all this sin/cos stuff w/tables
02743         csincos(theta,&sintheta,&costheta);
02744         y = fRadius * costheta;     // y is the same for each ring
02745 
02746         rsintheta = fRadius * sintheta;
02747 
02748         for (DWORD j = 0; j < wNumSections; j++) {
02749             csincos(phi,&sinphi,&cosphi);
02750             x = rsintheta * sinphi;
02751             z = rsintheta * cosphi;
02752 
02753 #ifdef DBG_GENSPHERE
02754             nvs_written++;
02755 #endif
02756             vPoint.x = pCenter->x + sx*x;
02757             vPoint.y = pCenter->y + sy*y;
02758             vPoint.z = pCenter->z + sz*z;
02759 
02760             add_to_FVFBuf((void *)&vPoint, 3*sizeof(float));
02761 
02762             if (DO_SPHERE_NORMAL) {
02763                 // bugbug: this is wrong normal for the non-spherical case (i think you need to multiply by 1/scale factor per component)
02764                 D3DXVECTOR3 vVec = D3DXVECTOR3( x*inv_radius, y*inv_radius, z*inv_radius );
02765                 D3DXVec3Normalize(&vNormal,&vVec);
02766                 add_to_FVFBuf((float *)&vNormal, 3*sizeof(float));
02767             }
02768 
02769             if (DO_SPHERE_COLOR)
02770                 add_DWORD_to_FVFBuf(_curD3Dcolor);
02771 
02772             if (DO_SPHERE_TEXTURING) {
02773                 texCoords[0] = 1.0f - phi*reciprocal_2PI;
02774                 add_to_FVFBuf((void *)texCoords, sizeof(TexCoordf));
02775             }
02776 
02777             phi += dphi;
02778         }
02779         theta += dtheta;
02780     }
02781 
02782     if (! DO_SPHERE_TEXTURING) {
02783         // Generate bottom vertex
02784         vNormal = D3DXVECTOR3( 0.0f, -1.0f, 0.0f );
02785         ADD_GENSPHERE_VERTEX_TO_BUFFER(vBotPoint);
02786 #ifdef DBG_GENSPHERE
02787         nvs_written++;
02788 #endif
02789     }
02790 
02791 #ifdef DBG_GENSPHERE
02792     assert(nvs_written == dwNumVertices);
02793 #endif
02794 
02795 
02796 #ifdef DBG_GENSPHERE
02797     memset(pwIndices,0xFF,dwNumIndices*sizeof(WORD));
02798 #endif
02799 
02800     // inited for textured case
02801     DWORD cur_vertring_startidx=0;    // first vertex in current ring
02802     DWORD CurFinalTriIndex = 0;       // index of next tri to be written
02803 
02804     if (! DO_SPHERE_TEXTURING) {
02805         // Generate caps using unique the bot/top vert
02806         // for non-textured case, could render the caps as indexed trifans,
02807         // but should be no perf difference b/w indexed trilists and indexed trifans
02808         // and this has advantage of being aggregable into 1 big DPrim call for whole sphere
02809 
02810         for (i = 0; i < wNumSections; i++) {
02811             DWORD TopCapTriIndex=3*i;
02812             DWORD BotCapTriIndex=3*(dwNumTriangles - wNumSections + i);
02813             DWORD i_incd = ((i + 1) % wNumSections);
02814 
02815             pwIndices[TopCapTriIndex++] = 0;
02816             pwIndices[TopCapTriIndex++] = i + 1;
02817             pwIndices[TopCapTriIndex] =  i_incd + 1;
02818 
02819             pwIndices[BotCapTriIndex++] = (WORD)( dwNumVertices - 1 );
02820             pwIndices[BotCapTriIndex++] = (WORD)( dwNumVertices - 2 - i );
02821             pwIndices[BotCapTriIndex] = (WORD)( dwNumVertices - 2 - i_incd);
02822         }
02823 
02824         cur_vertring_startidx = 1;          // first vertex in current ring (skip top vert)
02825         CurFinalTriIndex = wNumSections;    // index of tri to be written, wNumSections to skip the top cap row
02826     }
02827 
02828     DWORD j_incd,base_index;
02829 
02830     // technically we could break into a strip for every row (or 1 big strip connected w/degenerate tris)
02831     // but indexed trilists should actually be just as fast on HW
02832 
02833     // Generate triangles for the rings
02834     for (i = 0; i < wNumRings-1; i++) {
02835         for (DWORD j = 0; j < wNumSections; j++) {
02836 
02837             base_index=3*CurFinalTriIndex;  // final vert index is 3*finaltriindex
02838             j_incd=(j+1) % wNumSections;
02839 
02840             DWORD v1_row1_idx,v2_row1_idx,v1_row2_idx,v2_row2_idx;
02841 
02842             v1_row1_idx = cur_vertring_startidx + j;
02843             v2_row1_idx = cur_vertring_startidx + j_incd;
02844             v1_row2_idx = v1_row1_idx + wNumSections;
02845             v2_row2_idx = v2_row1_idx + wNumSections;
02846 
02847 #ifdef DBG_GENSPHERE
02848             assert(v2_row2_idx<dwNumVertices);
02849             assert(v1_row2_idx<dwNumVertices);
02850             assert(v2_row1_idx<dwNumVertices);
02851             assert(v1_row1_idx<dwNumVertices);
02852 #endif
02853 
02854             pwIndices[base_index++] = v1_row1_idx;
02855             pwIndices[base_index++] = v1_row2_idx;
02856             pwIndices[base_index++] = v2_row2_idx;
02857 
02858             pwIndices[base_index++] = v1_row1_idx;
02859             pwIndices[base_index++] = v2_row2_idx;
02860             pwIndices[base_index++] = v2_row1_idx;
02861 
02862             CurFinalTriIndex += 2;  // we wrote 2 tris, add 2 to finaltriindex
02863         }
02864         cur_vertring_startidx += wNumSections;
02865     }
02866 
02867 #ifdef DBG_GENSPHERE
02868     if (DO_SPHERE_TEXTURING) {
02869         assert(CurFinalTriIndex == dwNumTriangles);
02870         assert(base_index == dwNumIndices);
02871     } else {
02872         assert(CurFinalTriIndex == dwNumTriangles-wNumSections);
02873         assert(base_index == dwNumIndices-wNumSections*3);
02874     }
02875 
02876     for (i = 0; i < dwNumIndices; i++)
02877         assert(pwIndices[i] <dwNumVertices);
02878 #endif
02879 }
02880 
02881 
02882 ////////////////////////////////////////////////////////////////////
02883 //     Function: DXGraphicsStateGuardian8::draw_sphere
02884 //       Access: Public, Virtual
02885 //  Description:
02886 ////////////////////////////////////////////////////////////////////
02887 void DXGraphicsStateGuardian8::
02888 draw_sphere(GeomSphere *geom, GeomContext *gc) {
02889 
02890 #define SPHERE_NUMSLICES 16
02891 #define SPHERE_NUMSTACKS 10
02892 
02893 #ifdef GSG_VERBOSE
02894     dxgsg8_cat.debug() << "draw_sphere()" << endl;
02895 #endif
02896     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
02897     DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
02898 
02899     int nprims = geom->get_num_prims();
02900 
02901     if (nprims==0) {
02902         dxgsg8_cat.warning() << "draw_sphere() called with ZERO vertices!!" << endl;
02903         return;
02904     }
02905 
02906     Geom::VertexIterator vi = geom->make_vertex_iterator();
02907     Geom::ColorIterator ci;
02908     bool bPerPrimColor = (geom->get_binding(G_COLOR) == G_PER_PRIM);
02909     if (bPerPrimColor)
02910         ci = geom->make_color_iterator();
02911 
02912     for (int i = 0; i < nprims; i++) {
02913 
02914         DWORD nVerts,nTris;
02915         Vertexf center = geom->get_next_vertex(vi);
02916         Vertexf edge = geom->get_next_vertex(vi);
02917         LVector3f v = edge - center;
02918         float fRadius = sqrt(dot(v, v));
02919 
02920         size_t vertex_size = draw_prim_setup(geom);
02921 
02922         _pCurFvfBufPtr = _pFvfBufBasePtr;
02923 
02924         if (bPerPrimColor) {
02925             GET_NEXT_COLOR();
02926         }
02927 
02928         GenerateSphere(_pCurFvfBufPtr, VERT_BUFFER_SIZE,
02929                        _index_buf, PANDA_MAXNUMVERTS*2,
02930                        (D3DXVECTOR3 *)&center, fRadius,
02931                        SPHERE_NUMSTACKS, SPHERE_NUMSLICES,
02932                        1.0f, 1.0f, 1.0f,  // no scaling factors, do a sphere not ellipsoid
02933                        &nVerts,&nTris,_CurFVFType,vertex_size);
02934 
02935         // possible optimization: make DP 1 for all spheres call here, since trilist is independent tris.
02936         // indexes couldnt start w/0 tho, need to pass offset to gensph
02937         HRESULT hr = _pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0,  // start index in array
02938                                                          nVerts, nTris, _index_buf, D3DFMT_INDEX16,
02939                                                          _pFvfBufBasePtr, vertex_size);
02940         TestDrawPrimFailure(DrawIndexedPrim,hr,_pD3DDevice,nVerts,nTris);
02941     }
02942 
02943     _pCurFvfBufPtr = NULL;
02944 }
02945 
02946 ////////////////////////////////////////////////////////////////////
02947 //     Function: DXGraphicsStateGuardian8::prepare_texture
02948 //       Access: Public, Virtual
02949 //  Description: Creates a new retained-mode representation of the
02950 //               given texture, and returns a newly-allocated
02951 //               TextureContext pointer to reference it.  It is the
02952 //               responsibility of the calling function to later
02953 //               call release_texture() with this same pointer (which
02954 //               will also delete the pointer).
02955 ////////////////////////////////////////////////////////////////////
02956 TextureContext *DXGraphicsStateGuardian8::
02957 prepare_texture(Texture *tex) {
02958 
02959     DXTextureContext8 *dtc = new DXTextureContext8(tex);
02960 #ifdef WBD_GL_MODE
02961     glGenTextures(1, &gtc->_index);
02962 
02963     bind_texture(gtc);
02964     glPrioritizeTextures(1, &gtc->_index, &gtc->_priority);
02965     specify_texture(tex);
02966     apply_texture_immediate(tex);
02967 #else
02968 
02969     if (dtc->CreateTexture(*_pScrn) == NULL) {
02970         delete dtc;
02971         return NULL;
02972     }
02973 #endif              // WBD_GL_MODE
02974 
02975     bool inserted = mark_prepared_texture(dtc);
02976 
02977     // If this assertion fails, the same texture was prepared twice,
02978     // which shouldn't be possible, since the texture itself should
02979     // detect this.
02980     nassertr(inserted, NULL);
02981 
02982     return dtc;
02983 }
02984 
02985 ////////////////////////////////////////////////////////////////////
02986 //     Function: DXGraphicsStateGuardian8::apply_texture
02987 //       Access: Public, Virtual
02988 //  Description: Makes the texture the currently available texture for
02989 //               rendering.
02990 ////////////////////////////////////////////////////////////////////
02991 void DXGraphicsStateGuardian8::
02992 apply_texture(TextureContext *tc) {
02993     if (tc==NULL) {
02994         return;  // use enable_texturing to disable/enable
02995     }
02996     #ifdef DO_PSTATS
02997        add_to_texture_record(tc);
02998     #endif
02999 
03000 //  bind_texture(tc);
03001 
03002 //  specify_texture(tc->_texture);
03003     // Note: if this code changes, make sure to change initialization SetTSS code in dx_init as well
03004     // so DX TSS renderstate matches dxgsg state
03005 
03006     DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc);
03007 
03008     int dirty = dtc->get_dirty_flags();
03009 
03010     if (dirty) {
03011       // If the texture image has changed, or if its use of mipmaps has
03012       // changed, we need to re-create the image.  Ignore other types of
03013       // changes, which arent significant for dx
03014 
03015       if((dirty & (Texture::DF_image | Texture::DF_mipmap)) != 0) {
03016           // If this is *only* because of a mipmap change, issue a
03017           // warning--it is likely that this change is the result of an
03018           // error or oversight.
03019           if ((dirty & Texture::DF_image) == 0) {
03020             dxgsg8_cat.warning()
03021               << "Texture " << *dtc->_texture << " has changed mipmap state.\n";
03022           }
03023 
03024           dtc->DeleteTexture();
03025           if (dtc->CreateTexture(*_pScrn) == NULL) {
03026 
03027             // Oops, we can't re-create the texture for some reason.
03028             dxgsg8_cat.error() << "Unable to re-create texture " << *dtc->_texture << endl;
03029 
03030             release_texture(dtc);
03031             enable_texturing(false);
03032             return;
03033           }
03034       }
03035       dtc->clear_dirty_flags();
03036     } else {
03037        if(_pCurTexContext == dtc) {
03038           return;  // tex already set (and possible problem in state-sorting?)
03039        }
03040     }
03041 
03042     Texture *tex = tc->_texture;
03043     Texture::WrapMode wrapU,wrapV;
03044     wrapU=tex->get_wrapu();
03045     wrapV=tex->get_wrapv();
03046 
03047     if (wrapU!=_CurTexWrapModeU) {
03048         _pD3DDevice->SetTextureStageState(0,D3DTSS_ADDRESSU,get_texture_wrap_mode(wrapU));
03049         _CurTexWrapModeU = wrapU;
03050     }
03051     if (wrapV!=_CurTexWrapModeV) {
03052         _pD3DDevice->SetTextureStageState(0,D3DTSS_ADDRESSV,get_texture_wrap_mode(wrapV));
03053         _CurTexWrapModeV = wrapV;
03054     }
03055 
03056     uint aniso_degree=tex->get_anisotropic_degree();
03057     Texture::FilterType ft=tex->get_magfilter();
03058 
03059     if(_CurTexAnisoDegree != aniso_degree) {
03060         _pD3DDevice->SetTextureStageState(0,D3DTSS_MAXANISOTROPY,aniso_degree);
03061         _CurTexAnisoDegree = aniso_degree;
03062     }
03063 
03064     D3DTEXTUREFILTERTYPE newMagFilter;
03065     if (aniso_degree<=1) {
03066         newMagFilter=((ft!=Texture::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT);
03067 
03068         #ifdef _DEBUG
03069         if((ft!=Texture::FT_linear)&&(ft!=Texture::FT_nearest)) {
03070              dxgsg8_cat.error() << "MipMap filter type setting for texture magfilter makes no sense,  texture: " << tex->get_name() << "\n";
03071         }
03072         #endif
03073     } else {
03074         newMagFilter=D3DTEXF_ANISOTROPIC;
03075     }
03076 
03077     if(_CurTexMagFilter!=newMagFilter) {
03078         _CurTexMagFilter=newMagFilter;
03079         _pD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, newMagFilter);
03080     }
03081 
03082 #ifdef _DEBUG
03083     assert(Texture::FT_linear_mipmap_linear < 8);
03084 #endif
03085 /*
03086  enum FilterType {
03087     FT_nearest,FT_linear,FT_nearest_mipmap_nearest,FT_linear_mipmap_nearest,
03088     FT_nearest_mipmap_linear, FT_linear_mipmap_linear, };
03089 */
03090  // map Panda composite min+mip filter types to d3d's separate min & mip filter types
03091  static D3DTEXTUREFILTERTYPE PandaToD3DMinType[8] =
03092     {D3DTEXF_POINT,D3DTEXF_LINEAR,D3DTEXF_POINT,D3DTEXF_LINEAR,D3DTEXF_POINT,D3DTEXF_LINEAR};
03093  static D3DTEXTUREFILTERTYPE PandaToD3DMipType[8] =
03094     {D3DTEXF_NONE,D3DTEXF_NONE,D3DTEXF_POINT,D3DTEXF_POINT,D3DTEXF_LINEAR,D3DTEXF_LINEAR};
03095 
03096     ft=tex->get_minfilter();
03097 
03098 #ifdef _DEBUG
03099     if(ft > Texture::FT_linear_mipmap_linear) {
03100                 dxgsg8_cat.error() << "Unknown tex filter type for tex: " << tex->get_name() << "  filter: "<<(DWORD)ft<<"\n";
03101                 return;
03102     }
03103 #endif
03104 
03105     D3DTEXTUREFILTERTYPE newMipFilter = PandaToD3DMipType[(DWORD)ft];
03106 
03107     #ifndef NDEBUG
03108       // sanity check
03109     extern char *PandaFilterNameStrs[];
03110     if((!(dtc->_bHasMipMaps))&&(newMipFilter!=D3DTEXF_NONE)) {
03111         dxgsg8_cat.error() << "Trying to set mipmap filtering for texture with no generated mipmaps!! texname[" << tex->get_name() << "], filter("<<PandaFilterNameStrs[ft]<<")\n";
03112         newMipFilter=D3DTEXF_NONE;
03113     }
03114     #endif
03115 
03116 
03117     D3DTEXTUREFILTERTYPE newMinFilter = PandaToD3DMinType[(DWORD)ft];
03118 
03119     if(aniso_degree>=2) {
03120         newMinFilter=D3DTEXF_ANISOTROPIC;
03121     }
03122 
03123     if(newMinFilter!=_CurTexMinFilter) {
03124         _CurTexMinFilter = newMinFilter;
03125         _pD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, newMinFilter);
03126     }
03127 
03128     if(newMipFilter!=_CurTexMipFilter) {
03129         _CurTexMipFilter = newMipFilter;
03130         _pD3DDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, newMipFilter);
03131     }
03132 
03133     // bugbug:  does this handle the case of untextured geometry?
03134     //          we dont see this bug cause we never mix textured/untextured
03135     _pD3DDevice->SetTexture(0,dtc->_pD3DTexture8);
03136 
03137 #if 0
03138     if (dtc!=NULL) {
03139         dxgsg8_cat.spam() << "Setting active DX texture: " << dtc->_tex->get_name() << "\n";
03140     }
03141 #endif
03142 
03143     _pCurTexContext = dtc;   // enable_texturing needs this
03144 }
03145 
03146 ////////////////////////////////////////////////////////////////////
03147 //     Function: DXGraphicsStateGuardian8::release_texture
03148 //       Access: Public, Virtual
03149 //  Description: Frees the GL resources previously allocated for the
03150 //               texture.
03151 ////////////////////////////////////////////////////////////////////
03152 void DXGraphicsStateGuardian8::
03153 release_texture(TextureContext *tc) {
03154     DXTextureContext8 *gtc = DCAST(DXTextureContext8, tc);
03155     Texture *tex = tc->_texture;
03156 
03157     gtc->DeleteTexture();
03158     bool erased = unmark_prepared_texture(gtc);
03159 
03160     // If this assertion fails, a texture was released that hadn't been
03161     // prepared (or a texture was released twice).
03162     nassertv(erased);
03163 
03164     tex->clear_gsg(this);
03165 
03166     delete gtc;
03167 }
03168 
03169 // copies current display region in framebuffer to the texture
03170 // usually its more efficient to do SetRenderTgt
03171 void DXGraphicsStateGuardian8::
03172 copy_texture(TextureContext *tc, const DisplayRegion *dr) {
03173 
03174   HRESULT hr;
03175   int xo, yo, w, h;
03176   dr->get_region_pixels(xo, yo, w, h);
03177 
03178   DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc);
03179   PixelBuffer *pb = dtc->_tex->_pbuffer;
03180   pb->set_size(0,0,w-xo,h-yo);
03181 
03182   IDirect3DSurface8 *pTexSurfaceLev0,*pCurRenderTarget;
03183   hr = dtc->_pD3DTexture8->GetSurfaceLevel(0,&pTexSurfaceLev0);
03184   if(FAILED(hr)) {
03185     dxgsg8_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
03186     exit(1);
03187   }
03188 
03189   hr = _pD3DDevice->GetRenderTarget(&pCurRenderTarget);
03190   if(FAILED(hr)) {
03191     dxgsg8_cat.error() << "GetRenderTgt failed in copy_texture" << D3DERRORSTRING(hr);
03192     exit(1);
03193   }
03194 
03195 
03196   RECT SrcRect;
03197 
03198   SrcRect.left = xo;
03199   SrcRect.right = xo+w;
03200   SrcRect.top = yo;
03201   SrcRect.bottom = yo+h;
03202 
03203   // now copy from fb to tex
03204   hr = _pD3DDevice->CopyRects(pCurRenderTarget,&SrcRect,1,pTexSurfaceLev0,NULL);
03205   if(FAILED(hr)) {
03206     dxgsg8_cat.error() << "CopyRects failed in copy_texture" << D3DERRORSTRING(hr);
03207     exit(1);
03208   }
03209 
03210   SAFE_RELEASE(pCurRenderTarget);
03211   SAFE_RELEASE(pTexSurfaceLev0);
03212 }
03213 
03214 
03215 ////////////////////////////////////////////////////////////////////
03216 //     Function: DXGraphicsStateGuardian8::copy_texture
03217 //       Access: Public, Virtual
03218 //  Description:
03219 ////////////////////////////////////////////////////////////////////
03220 void DXGraphicsStateGuardian8::
03221 copy_texture(TextureContext *tc, const DisplayRegion *dr, const RenderBuffer &rb) {
03222     set_read_buffer(rb);
03223     copy_texture(tc, dr);
03224 }
03225 
03226 ////////////////////////////////////////////////////////////////////
03227 //     Function: DXGraphicsStateGuardian8::texture_to_pixel_buffer
03228 //       Access: Public, Virtual
03229 //  Description:
03230 ////////////////////////////////////////////////////////////////////
03231 void DXGraphicsStateGuardian8::
03232 texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb) {
03233  // This code is now invalidated by the new design; perhaps the
03234   // interface is not needed anyway.
03235 #if 0
03236 
03237     nassertv(tc != NULL && pb != NULL);
03238 
03239     Texture *tex = tc->_texture;
03240 
03241     int w = tex->_pbuffer->get_xsize();
03242     int h = tex->_pbuffer->get_ysize();
03243 
03244     PT(DisplayRegion) dr = _win->make_scratch_display_region(w, h);
03245 
03246     FrameBufferStack old_fb = push_frame_buffer
03247                               (get_render_buffer(RenderBuffer::T_back | RenderBuffer::T_depth),
03248                                dr);
03249 
03250     texture_to_pixel_buffer(tc, pb, dr);
03251 
03252     pop_frame_buffer(old_fb);
03253 #else
03254     dxgsg8_cat.error() << "texture_to_pixel_buffer unimplemented for DX!\n";
03255 #endif
03256 }
03257 
03258 ////////////////////////////////////////////////////////////////////
03259 //     Function: DXGraphicsStateGuardian8::texture_to_pixel_buffer
03260 //       Access: Public, Virtual
03261 //  Description:
03262 ////////////////////////////////////////////////////////////////////
03263 void DXGraphicsStateGuardian8::
03264 texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
03265                         const DisplayRegion *dr) {
03266     dxgsg8_cat.error()
03267       << "texture_to_pixel_buffer unimplemented!\n";
03268 }
03269 
03270 ////////////////////////////////////////////////////////////////////
03271 //     Function: DXGraphicsStateGuardian8::copy_pixel_buffer
03272 //       Access: Public, Virtual
03273 //  Description:
03274 ////////////////////////////////////////////////////////////////////
03275 void DXGraphicsStateGuardian8::
03276 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
03277 
03278     RECT SrcCopyRect;
03279     nassertv(pb != NULL && dr != NULL);
03280 
03281     int xo, yo, w, h;
03282     dr->get_region_pixels(xo, yo, w, h);
03283 
03284     // only handled simple case
03285     nassertv(xo==0);
03286     nassertv(yo==0);
03287     nassertv(w==pb->get_xsize());
03288     nassertv(h==pb->get_ysize());
03289 
03290     IDirect3DSurface8 *pD3DSurf;
03291     HRESULT hr;
03292 
03293     RECT WindRect;
03294     GetWindowRect(_pScrn->hWnd,&WindRect);
03295 
03296     // just handling front and backbuf for now, not textures yet
03297     if(_cur_read_pixel_buffer & RenderBuffer::T_back) {
03298        hr=_pD3DDevice->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pD3DSurf);
03299 
03300        if(FAILED(hr)) {
03301            dxgsg8_cat.error() << "GetBackBuffer failed" << D3DERRORSTRING(hr);
03302            exit(1);
03303        }
03304 
03305        D3DSURFACE_DESC SurfDesc;
03306        hr = pD3DSurf->GetDesc(&SurfDesc);
03307 
03308        SrcCopyRect.top=SrcCopyRect.left=0;
03309        SrcCopyRect.right=SurfDesc.Width;
03310        SrcCopyRect.bottom=SurfDesc.Height;
03311 
03312        // note if you try to grab the backbuffer and full-screen anti-aliasing is on,
03313        // the backbuffer might be larger than the window size.  for screenshots its safer to get the front buffer.
03314 
03315     } else if(_cur_read_pixel_buffer & RenderBuffer::T_front) {
03316        // must create a A8R8G8B8 sysmem surface for GetFrontBuffer to copy to
03317 
03318         DWORD TmpSurfXsize,TmpSurfYsize;
03319 
03320         if(_pScrn->PresParams.Windowed) {
03321             // GetFrontBuffer retrieves the entire desktop for a monitor, so need space for that
03322 
03323             MONITORINFO minfo;
03324             minfo.cbSize = sizeof(MONITORINFO);
03325             GetMonitorInfo(_pScrn->hMon, &minfo);   // have to use GetMonitorInfo, since this gsg may not be for primary monitor
03326 
03327             TmpSurfXsize=RECT_XSIZE(minfo.rcMonitor);
03328             TmpSurfYsize=RECT_YSIZE(minfo.rcMonitor);
03329 
03330             // set SrcCopyRect to client area of window in scrn coords
03331             GetClientRect( _pScrn->hWnd, &SrcCopyRect);
03332             ClientToScreen( _pScrn->hWnd, (POINT*)&SrcCopyRect.left );
03333             ClientToScreen( _pScrn->hWnd, (POINT*)&SrcCopyRect.right );
03334         } else {
03335            TmpSurfXsize=RECT_XSIZE(WindRect);
03336            TmpSurfYsize=RECT_YSIZE(WindRect);
03337 
03338            SrcCopyRect.top=SrcCopyRect.left=0;
03339            SrcCopyRect.right=TmpSurfXsize;
03340            SrcCopyRect.bottom=TmpSurfYsize;
03341         }
03342 
03343         hr=_pD3DDevice->CreateImageSurface(TmpSurfXsize,TmpSurfYsize,D3DFMT_A8R8G8B8,&pD3DSurf);
03344         if(FAILED(hr)) {
03345            dxgsg8_cat.error() << "CreateImageSurface failed in copy_pixel_buffer()" << D3DERRORSTRING(hr);
03346            exit(1);
03347         }
03348 
03349         hr=_pD3DDevice->GetFrontBuffer(pD3DSurf);
03350 
03351         if(hr==D3DERR_DEVICELOST) {
03352            // dont necessary want to exit in this case
03353            pD3DSurf->Release();
03354            dxgsg8_cat.error() << "copy_pixel_buffer failed: device lost\n";
03355            return;
03356         }
03357     } else {
03358         dxgsg8_cat.error() << "copy_pixel_buffer: unhandled current_read_pixel_buffer type\n";
03359     }
03360 
03361     if((RECT_XSIZE(SrcCopyRect)>w) || (RECT_YSIZE(SrcCopyRect)>h)) {
03362      dxgsg8_cat.error() << "copy_pixel_buffer: pixel buffer size does not match selected screen RenderBuffer size!\n";
03363      exit(1);
03364     }
03365 
03366     (void) ConvertD3DSurftoPixBuf(SrcCopyRect,pD3DSurf,pb);
03367 
03368     RELEASE(pD3DSurf,dxgsg8,"pD3DSurf",RELEASE_ONCE);
03369 
03370     nassertv(!pb->_image.empty());
03371 }
03372 
03373 ////////////////////////////////////////////////////////////////////
03374 //     Function: DXGraphicsStateGuardian8::copy_pixel_buffer
03375 //       Access: Public, Virtual
03376 //  Description:
03377 ////////////////////////////////////////////////////////////////////
03378 void DXGraphicsStateGuardian8::
03379 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
03380                   const RenderBuffer &rb) {
03381     set_read_buffer(rb);
03382     copy_pixel_buffer(pb, dr);
03383 }
03384 
03385 ////////////////////////////////////////////////////////////////////
03386 //     Function: DXGraphicsStateGuardian8::apply_material
03387 //       Access: Public, Virtual
03388 //  Description:
03389 ////////////////////////////////////////////////////////////////////
03390 void DXGraphicsStateGuardian8::apply_material( const Material* material ) {
03391     D3DMATERIAL8 cur_material;
03392     cur_material.Diffuse = *(D3DCOLORVALUE *)(material->get_diffuse().get_data());
03393     cur_material.Ambient = *(D3DCOLORVALUE *)(material->get_ambient().get_data());
03394     cur_material.Specular = *(D3DCOLORVALUE *)(material->get_specular().get_data());
03395     cur_material.Emissive = *(D3DCOLORVALUE *)(material->get_emission().get_data());
03396     cur_material.Power   =  material->get_shininess();
03397     _pD3DDevice->SetMaterial(&cur_material);
03398 }
03399 
03400 ////////////////////////////////////////////////////////////////////
03401 //     Function: DXGraphicsStateGuardian8::apply_fog
03402 //       Access: Public, Virtual
03403 //  Description:
03404 ////////////////////////////////////////////////////////////////////
03405 void DXGraphicsStateGuardian8::
03406 apply_fog(Fog *fog) {
03407 
03408     if(_doFogType==None)
03409       return;
03410 
03411     Fog::Mode panda_fogmode = fog->get_mode();
03412     D3DFOGMODE d3dfogmode = get_fog_mode_type(panda_fogmode);
03413 
03414 
03415     // should probably avoid doing redundant SetRenderStates, but whatever
03416     _pD3DDevice->SetRenderState((D3DRENDERSTATETYPE)_doFogType, d3dfogmode);
03417 
03418     const Colorf &fog_colr = fog->get_color();
03419     _pD3DDevice->SetRenderState(D3DRS_FOGCOLOR,
03420                    MY_D3DRGBA(fog_colr[0], fog_colr[1], fog_colr[2], 0.0f));  // Alpha bits are not used
03421 
03422     // do we need to adjust fog start/end values based on D3DPRASTERCAPS_WFOG/D3DPRASTERCAPS_ZFOG ?
03423     // if not WFOG, then docs say we need to adjust values to range [0,1]
03424 
03425     switch (panda_fogmode) {
03426         case Fog::M_linear:
03427             {
03428                 float onset, opaque;
03429                 fog->get_linear_range(onset, opaque);
03430 
03431                 _pD3DDevice->SetRenderState( D3DRS_FOGSTART,
03432                                             *((LPDWORD) (&onset)) );
03433                 _pD3DDevice->SetRenderState( D3DRS_FOGEND,
03434                                             *((LPDWORD) (&opaque)) );
03435             }
03436             break;
03437         case Fog::M_exponential:
03438         case Fog::M_exponential_squared:
03439             {
03440                 // Exponential fog is always camera-relative.
03441                 float fog_density = fog->get_exp_density();
03442                 _pD3DDevice->SetRenderState( D3DRS_FOGDENSITY,
03443                             *((LPDWORD) (&fog_density)) );
03444             }
03445             break;
03446     }
03447 }
03448 
03449 void DXGraphicsStateGuardian8::SetTextureBlendMode(TextureApplyAttrib::Mode TexBlendMode,bool bCanJustEnable) {
03450 
03451 /*class TextureApplyAttrib {
03452   enum Mode {
03453     M_modulate,M_decal,M_blend,M_replace,M_add};
03454 */
03455     static D3DTEXTUREOP TexBlendColorOp1[/* TextureApplyAttrib::Mode maxval*/ 10] =
03456     {D3DTOP_MODULATE,D3DTOP_BLENDTEXTUREALPHA,D3DTOP_MODULATE,D3DTOP_SELECTARG1,D3DTOP_ADD};
03457 
03458     //if bCanJustEnable, then we only need to make sure ColorOp is turned on and set properly
03459     if (bCanJustEnable && (TexBlendMode==_CurTexBlendMode)) {
03460         // just reset COLOROP 0 to enable pipeline, rest is already set properly
03461         _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, TexBlendColorOp1[TexBlendMode] );
03462         return;
03463     }
03464 
03465     _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, TexBlendColorOp1[TexBlendMode] );
03466 
03467     switch (TexBlendMode) {
03468 
03469         case TextureApplyAttrib::M_modulate:
03470             // emulates GL_MODULATE glTexEnv mode
03471             // want to multiply tex-color*pixel color to emulate GL modulate blend (see glTexEnv)
03472             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
03473             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
03474             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
03475             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
03476             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
03477 
03478             break;
03479         case TextureApplyAttrib::M_decal:
03480             // emulates GL_DECAL glTexEnv mode
03481             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
03482             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
03483 
03484             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
03485             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
03486 
03487             break;
03488         case TextureApplyAttrib::M_replace:
03489             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
03490 
03491             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
03492             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
03493             break;
03494         case TextureApplyAttrib::M_add:
03495             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
03496             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
03497 
03498             // since I'm making up 'add' mode, use modulate.  "adding" alpha never makes sense right?
03499             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
03500             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
03501             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
03502 
03503             break;
03504         case TextureApplyAttrib::M_blend:
03505             dxgsg8_cat.error()
03506             << "Impossible to emulate GL_BLEND in DX exactly " << (int) TexBlendMode << endl;
03507 /*
03508            // emulate GL_BLEND glTexEnv
03509 
03510            GL requires 2 independent operations on 3 input vars for this mode
03511            DX texture pipeline requires re-using input of last stage on each new op, so I dont think
03512            exact emulation is possible
03513            _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
03514            _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE | D3DTA_COMPLEMENT );
03515            _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
03516 
03517            _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
03518            _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
03519            _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
03520 
03521            need to SetTexture(1,tex) also
03522            _pD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_MODULATE ); wrong
03523            _pD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
03524            _pD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TFACTOR );
03525 
03526            _pD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
03527            _pD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT );
03528 */
03529 
03530 
03531             break;
03532         default:
03533             dxgsg8_cat.error() << "Unknown texture blend mode " << (int) TexBlendMode << endl;
03534             break;
03535     }
03536 }
03537 
03538 
03539 ////////////////////////////////////////////////////////////////////
03540 //     Function: DXGraphicsStateGuardian8::enable_texturing
03541 //       Access:
03542 //  Description:
03543 ////////////////////////////////////////////////////////////////////
03544 INLINE void DXGraphicsStateGuardian8::
03545 enable_texturing(bool val) {
03546 //  if (_texturing_enabled == val) {  // this check is mostly for internal gsg calls, panda already screens out redundant state changes
03547 //        return;
03548 //  }
03549 
03550     _texturing_enabled = val;
03551 
03552 //  assert(_pCurTexContext!=NULL);  we're definitely called with it NULL for both true and false
03553 //  I'm going to allow enabling texturing even if no tex has been set yet, seems to cause no probs
03554 
03555     if (val == false) {
03556         _pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE);
03557     } else {
03558           SetTextureBlendMode(_CurTexBlendMode,true);
03559     }
03560 }
03561 
03562 ////////////////////////////////////////////////////////////////////
03563 //     Function: DXGraphicsStateGuardian8::issue_transform
03564 //       Access: Public, Virtual
03565 //  Description: Sends the indicated transform matrix to the graphics
03566 //               API to be applied to future vertices.
03567 ////////////////////////////////////////////////////////////////////
03568 void DXGraphicsStateGuardian8::
03569 issue_transform(const TransformState *transform) {
03570   // if we're using ONLY vertex shaders, could get avoid calling SetTrans
03571   D3DMATRIX *pMat = (D3DMATRIX*)transform->get_mat().get_data();
03572   _pD3DDevice->SetTransform(D3DTS_WORLD,pMat);
03573 
03574 #ifdef USE_VERTEX_SHADERS
03575   if(_CurVertexShader!=NULL) {
03576     // vertex shaders need access to the current xform matrix,
03577     // so need to reset this vshader 'constant' every time view matrix changes
03578       HRESULT hr =  _pD3DDevice->SetVertexShaderConstant(VSHADER_XFORMMATRIX_CONSTANTREGNUMSTART, pMat, 4);
03579       #ifdef _DEBUG
03580       if(FAILED(hr)) {
03581         dxgsg8_cat.error() << "SetVertexShader failed" << D3DERRORSTRING(hr);
03582         exit(1);
03583       }
03584       #endif
03585   }
03586 #endif
03587 }
03588 
03589 ////////////////////////////////////////////////////////////////////
03590 //     Function: DXGraphicsStateGuardian8::issue_tex_matrix
03591 //       Access: Public, Virtual
03592 //  Description:
03593 ////////////////////////////////////////////////////////////////////
03594 void DXGraphicsStateGuardian8::
03595 issue_tex_matrix(const TexMatrixAttrib *attrib) {
03596   // Not implemented yet.
03597 }
03598 
03599 ////////////////////////////////////////////////////////////////////
03600 //     Function: DXGraphicsStateGuardian8::issue_texture
03601 //       Access: Public, Virtual
03602 //  Description:
03603 ////////////////////////////////////////////////////////////////////
03604 void DXGraphicsStateGuardian8::
03605 issue_texture(const TextureAttrib *attrib) {
03606   if (attrib->is_off()) {
03607     enable_texturing(false);
03608   } else {
03609     enable_texturing(true);
03610     Texture *tex = attrib->get_texture();
03611     nassertv(tex != (Texture *)NULL);
03612     tex->apply(this);
03613   }
03614 }
03615 
03616 ////////////////////////////////////////////////////////////////////
03617 //     Function: DXGraphicsStateGuardian8::issue_material
03618 //       Access: Public, Virtual
03619 //  Description:
03620 ////////////////////////////////////////////////////////////////////
03621 void DXGraphicsStateGuardian8::
03622 issue_material(const MaterialAttrib *attrib) {
03623   const Material *material = attrib->get_material();
03624   if (material != (const Material *)NULL) {
03625     apply_material(material);
03626   } else {
03627     // Apply a default material when materials are turned off.
03628     Material empty;
03629     apply_material(&empty);
03630   }
03631 }
03632 
03633 ////////////////////////////////////////////////////////////////////
03634 //     Function: DXGraphicsStateGuardian8::issue_render_mode
03635 //       Access: Public, Virtual
03636 //  Description:
03637 ////////////////////////////////////////////////////////////////////
03638 void DXGraphicsStateGuardian8::
03639 issue_render_mode(const RenderModeAttrib *attrib) {
03640   RenderModeAttrib::Mode mode = attrib->get_mode();
03641 
03642   switch (mode) {
03643   case RenderModeAttrib::M_filled:
03644     _pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
03645     break;
03646 
03647   case RenderModeAttrib::M_wireframe:
03648     _pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
03649     break;
03650 
03651   default:
03652     dxgsg8_cat.error()
03653       << "Unknown render mode " << (int)mode << endl;
03654   }
03655 
03656   _current_fill_mode = mode;
03657 }
03658 
03659 ////////////////////////////////////////////////////////////////////
03660 //     Function: DXGraphicsStateGuardian8::issue_texture_apply
03661 //       Access: Public, Virtual
03662 //  Description:
03663 ////////////////////////////////////////////////////////////////////
03664 void DXGraphicsStateGuardian8::
03665 issue_texture_apply(const TextureApplyAttrib *attrib) {
03666 }
03667 
03668 ////////////////////////////////////////////////////////////////////
03669 //     Function: DXGraphicsStateGuardian8::issue_depth_test
03670 //       Access: Public, Virtual
03671 //  Description:
03672 ////////////////////////////////////////////////////////////////////
03673 void DXGraphicsStateGuardian8::
03674 issue_depth_test(const DepthTestAttrib *attrib) {
03675   DepthTestAttrib::PandaCompareFunc mode = attrib->get_mode();
03676   if (mode == DepthTestAttrib::M_none) {
03677     _depth_test_enabled = false;
03678     _pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
03679   } else {
03680     _depth_test_enabled = true;
03681     _pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
03682     _pD3DDevice->SetRenderState(D3DRS_ZFUNC, (D3DCMPFUNC) mode);
03683   }
03684 }
03685 
03686 ////////////////////////////////////////////////////////////////////
03687 //     Function: DXGraphicsStateGuardian8::issue_alpha_test
03688 //       Access: Public, Virtual
03689 //  Description:
03690 ////////////////////////////////////////////////////////////////////
03691 void DXGraphicsStateGuardian8::
03692 issue_alpha_test(const AlphaTestAttrib *attrib) {
03693   AlphaTestAttrib::PandaCompareFunc mode = attrib->get_mode();
03694   if (mode == AlphaTestAttrib::M_none) {
03695     enable_alpha_test(false);
03696   } else {
03697     //  AlphaTestAttrib::PandaCompareFunc === D3DCMPFUNC
03698     call_dxAlphaFunc((D3DCMPFUNC)mode, attrib->get_reference_alpha());
03699     enable_alpha_test(true);
03700   }
03701 }
03702 
03703 ////////////////////////////////////////////////////////////////////
03704 //     Function: DXGraphicsStateGuardian8::issue_depth_write
03705 //       Access: Public, Virtual
03706 //  Description:
03707 ////////////////////////////////////////////////////////////////////
03708 void DXGraphicsStateGuardian8::
03709 issue_depth_write(const DepthWriteAttrib *attrib) {
03710   enable_zwritemask(attrib->get_mode() == DepthWriteAttrib::M_on);
03711 }
03712 
03713 ////////////////////////////////////////////////////////////////////
03714 //     Function: DXGraphicsStateGuardian8::issue_cull_face
03715 //       Access: Public, Virtual
03716 //  Description:
03717 ////////////////////////////////////////////////////////////////////
03718 void DXGraphicsStateGuardian8::
03719 issue_cull_face(const CullFaceAttrib *attrib) {
03720   CullFaceAttrib::Mode mode = attrib->get_effective_mode();
03721 
03722   switch (mode) {
03723   case CullFaceAttrib::M_cull_none:
03724     _pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
03725     break;
03726   case CullFaceAttrib::M_cull_clockwise:
03727     _pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
03728     break;
03729   case CullFaceAttrib::M_cull_counter_clockwise:
03730     _pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
03731     break;
03732   default:
03733     dxgsg8_cat.error()
03734       << "invalid cull face mode " << (int)mode << endl;
03735     break;
03736   }
03737 }
03738 
03739 ////////////////////////////////////////////////////////////////////
03740 //     Function: DXGraphicsStateGuardian8::issue_fog
03741 //       Access: Public, Virtual
03742 //  Description:
03743 ////////////////////////////////////////////////////////////////////
03744 void DXGraphicsStateGuardian8::
03745 issue_fog(const FogAttrib *attrib) {
03746   if (!attrib->is_off()) {
03747     enable_fog(true);
03748     Fog *fog = attrib->get_fog();
03749     nassertv(fog != (Fog *)NULL);
03750     apply_fog(fog);
03751   } else {
03752     enable_fog(false);
03753   }
03754 }
03755 
03756 ////////////////////////////////////////////////////////////////////
03757 //     Function: DXGraphicsStateGuardian8::issue_depth_offset
03758 //       Access: Public, Virtual
03759 //  Description:
03760 ////////////////////////////////////////////////////////////////////
03761 void DXGraphicsStateGuardian8::
03762 issue_depth_offset(const DepthOffsetAttrib *attrib) {
03763   int offset = attrib->get_offset();
03764   _pD3DDevice->SetRenderState(D3DRS_ZBIAS, offset);
03765 }
03766 
03767 ////////////////////////////////////////////////////////////////////
03768 //     Function: DXGraphicsStateGuardian8::bind_light
03769 //       Access: Public, Virtual
03770 //  Description: Called the first time a particular light has been
03771 //               bound to a given id within a frame, this should set
03772 //               up the associated hardware light with the light's
03773 //               properties.
03774 ////////////////////////////////////////////////////////////////////
03775 void DXGraphicsStateGuardian8::
03776 bind_light(PointLight *light, int light_id) {
03777   // Get the light in "world coordinates".  This means the light in
03778   // the coordinate space of the camera, converted to DX's coordinate
03779   // system.
03780   NodePath light_np(light);
03781   const LMatrix4f &light_mat = light_np.get_mat(_scene_setup->get_camera_path());
03782   LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
03783   LPoint3f pos = light->get_point() * rel_mat;
03784 
03785   D3DCOLORVALUE black;
03786   black.r = black.g = black.b = black.a = 0.0f;
03787   D3DLIGHT8 alight;
03788   alight.Type =  D3DLIGHT_POINT;
03789   alight.Diffuse  = *(D3DCOLORVALUE *)(light->get_color().get_data());
03790   alight.Ambient  =  black ;
03791   alight.Specular = *(D3DCOLORVALUE *)(light->get_specular_color().get_data());
03792 
03793   // Position needs to specify x, y, z, and w
03794   // w == 1 implies non-infinite position
03795   alight.Position = *(D3DVECTOR *)pos.get_data();
03796 
03797   alight.Range =  __D3DLIGHT_RANGE_MAX;
03798   alight.Falloff =  1.0f;
03799 
03800   const LVecBase3f &att = light->get_attenuation();
03801   alight.Attenuation0 = att[0];
03802   alight.Attenuation1 = att[1];
03803   alight.Attenuation2 = att[2];
03804 
03805   HRESULT res = _pD3DDevice->SetLight(light_id, &alight);
03806 }
03807 
03808 ////////////////////////////////////////////////////////////////////
03809 //     Function: DXGraphicsStateGuardian8::bind_light
03810 //       Access: Public, Virtual
03811 //  Description: Called the first time a particular light has been
03812 //               bound to a given id within a frame, this should set
03813 //               up the associated hardware light with the light's
03814 //               properties.
03815 ////////////////////////////////////////////////////////////////////
03816 void DXGraphicsStateGuardian8::
03817 bind_light(DirectionalLight *light, int light_id) {
03818   // Get the light in "world coordinates".  This means the light in
03819   // the coordinate space of the camera, converted to DX's coordinate
03820   // system.
03821   NodePath light_np(light);
03822   const LMatrix4f &light_mat = light_np.get_mat(_scene_setup->get_camera_path());
03823   LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
03824   LVector3f dir = light->get_direction() * rel_mat;
03825 
03826   D3DCOLORVALUE black;
03827   black.r = black.g = black.b = black.a = 0.0f;
03828 
03829   D3DLIGHT8 alight;
03830   ZeroMemory(&alight, sizeof(D3DLIGHT8));
03831 
03832   alight.Type =  D3DLIGHT_DIRECTIONAL;
03833   alight.Diffuse  = *(D3DCOLORVALUE *)(light->get_color().get_data());
03834   alight.Ambient  =  black ;
03835   alight.Specular = *(D3DCOLORVALUE *)(light->get_specular_color().get_data());
03836 
03837   alight.Direction = *(D3DVECTOR *)dir.get_data();
03838 
03839   alight.Range =  __D3DLIGHT_RANGE_MAX;
03840   alight.Falloff =  1.0f;
03841 
03842   alight.Attenuation0 = 1.0f;       // constant
03843   alight.Attenuation1 = 0.0f;       // linear
03844   alight.Attenuation2 = 0.0f;       // quadratic
03845 
03846   HRESULT res = _pD3DDevice->SetLight(light_id, &alight);
03847 }
03848 
03849 ////////////////////////////////////////////////////////////////////
03850 //     Function: DXGraphicsStateGuardian8::bind_light
03851 //       Access: Public, Virtual
03852 //  Description: Called the first time a particular light has been
03853 //               bound to a given id within a frame, this should set
03854 //               up the associated hardware light with the light's
03855 //               properties.
03856 ////////////////////////////////////////////////////////////////////
03857 void DXGraphicsStateGuardian8::
03858 bind_light(Spotlight *light, int light_id) {
03859   Lens *lens = light->get_lens();
03860   nassertv(lens != (Lens *)NULL);
03861 
03862   // Get the light in "world coordinates".  This means the light in
03863   // the coordinate space of the camera, converted to DX's coordinate
03864   // system.
03865   NodePath light_np(light);
03866   const LMatrix4f &light_mat = light_np.get_mat(_scene_setup->get_camera_path());
03867   LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
03868   LPoint3f pos = lens->get_nodal_point() * rel_mat;
03869   LVector3f dir = lens->get_view_vector() * rel_mat;
03870 
03871   D3DCOLORVALUE black;
03872   black.r = black.g = black.b = black.a = 0.0f;
03873 
03874   D3DLIGHT8  alight;
03875   ZeroMemory(&alight, sizeof(D3DLIGHT8));
03876 
03877   alight.Type =  D3DLIGHT_SPOT;
03878   alight.Ambient  =  black ;
03879   alight.Diffuse  = *(D3DCOLORVALUE *)(light->get_color().get_data());
03880   alight.Specular = *(D3DCOLORVALUE *)(light->get_specular_color().get_data());
03881 
03882   alight.Position = *(D3DVECTOR *)pos.get_data();
03883 
03884   alight.Direction = *(D3DVECTOR *)dir.get_data();
03885 
03886   alight.Range =  __D3DLIGHT_RANGE_MAX;
03887   alight.Falloff =  1.0f;
03888   alight.Theta =  0.0f;
03889   alight.Phi =  lens->get_hfov();
03890 
03891   const LVecBase3f &att = light->get_attenuation();
03892   alight.Attenuation0 = att[0];
03893   alight.Attenuation1 = att[1];
03894   alight.Attenuation2 = att[2];
03895 
03896   HRESULT res = _pD3DDevice->SetLight(light_id, &alight);
03897 }
03898 
03899 ////////////////////////////////////////////////////////////////////
03900 //     Function: DXGraphicsStateGuardian8::begin_frame
03901 //       Access: Public, Virtual
03902 //  Description: Called before each frame is rendered, to allow the
03903 //               GSG a chance to do any internal cleanup before
03904 //               beginning the frame.
03905 //
03906 //               The return value is true if successful (in which case
03907 //               the frame will be drawn and end_frame() will be
03908 //               called later), or false if unsuccessful (in which
03909 //               case nothing will be drawn and end_frame() will not
03910 //               be called).
03911 ////////////////////////////////////////////////////////////////////
03912 bool DXGraphicsStateGuardian8::
03913 begin_frame() {
03914   return GraphicsStateGuardian::begin_frame();
03915 }
03916 
03917 ////////////////////////////////////////////////////////////////////
03918 //     Function: DXGraphicsStateGuardian8::begin_scene
03919 //       Access: Public, Virtual
03920 //  Description: Called between begin_frame() and end_frame() to mark
03921 //               the beginning of drawing commands for a "scene"
03922 //               (usually a particular DisplayRegion) within a frame.
03923 //               All 3-D drawing commands, except the clear operation,
03924 //               must be enclosed within begin_scene() .. end_scene().
03925 //
03926 //               The return value is true if successful (in which case
03927 //               the scene will be drawn and end_scene() will be
03928 //               called later), or false if unsuccessful (in which
03929 //               case nothing will be drawn and end_scene() will not
03930 //               be called).
03931 ////////////////////////////////////////////////////////////////////
03932 bool DXGraphicsStateGuardian8::
03933 begin_scene() {
03934   if (!GraphicsStateGuardian::begin_scene()) {
03935     return false;
03936   }
03937 
03938   HRESULT hr = _pD3DDevice->BeginScene();
03939 
03940   if (FAILED(hr)) {
03941     if (hr == D3DERR_DEVICELOST) {
03942       if (dxgsg8_cat.is_debug()) {
03943         dxgsg8_cat.debug()
03944           << "BeginScene returns D3DERR_DEVICELOST" << endl;
03945       }
03946       
03947       CheckCooperativeLevel();
03948 
03949     } else {
03950       dxgsg8_cat.error()
03951         << "BeginScene failed, unhandled error hr == "
03952         << D3DERRORSTRING(hr) << endl;
03953       exit(1);
03954     }
03955     return false;
03956   }
03957 
03958   return true;
03959 }
03960 
03961 ////////////////////////////////////////////////////////////////////
03962 //     Function: DXGraphicsStateGuardian8::end_scene
03963 //       Access: Public, Virtual
03964 //  Description: Called between begin_frame() and end_frame() to mark
03965 //               the end of drawing commands for a "scene" (usually a
03966 //               particular DisplayRegion) within a frame.  All 3-D
03967 //               drawing commands, except the clear operation, must be
03968 //               enclosed within begin_scene() .. end_scene().
03969 ////////////////////////////////////////////////////////////////////
03970 void DXGraphicsStateGuardian8::
03971 end_scene() {
03972   HRESULT hr = _pD3DDevice->EndScene();
03973   
03974   if (FAILED(hr)) {
03975 
03976     if (hr == D3DERR_DEVICELOST) {
03977       if(dxgsg8_cat.is_debug()) {
03978         dxgsg8_cat.debug()
03979           << "EndScene returns DeviceLost\n";
03980       }
03981       CheckCooperativeLevel();
03982 
03983     } else {
03984       dxgsg8_cat.error()
03985         << "EndScene failed, unhandled error hr == " << D3DERRORSTRING(hr);
03986       exit(1);
03987     }
03988     return;
03989   }
03990 }
03991 
03992 ////////////////////////////////////////////////////////////////////
03993 //     Function: GraphicsStateGuardian::end_frame
03994 //       Access: Public, Virtual
03995 //  Description: Called after each frame is rendered, to allow the
03996 //               GSG a chance to do any internal cleanup after
03997 //               rendering the frame, and before the window flips.
03998 ////////////////////////////////////////////////////////////////////
03999 void DXGraphicsStateGuardian8::
04000 end_frame() {
04001 #ifdef COUNT_DRAWPRIMS
04002     {
04003         #define FRAMES_PER_DPINFO 90
04004         static DWORD LastDPInfoFrame=0;
04005         static DWORD LastTickCount=0;
04006         const float one_thousandth = 1.0f/1000.0f;
04007 
04008         if (_cur_frame_count-LastDPInfoFrame > FRAMES_PER_DPINFO) {
04009             DWORD CurTickCount=GetTickCount();
04010             float delta_secs=(CurTickCount-LastTickCount)*one_thousandth;
04011 
04012             float numframes=_cur_frame_count-LastDPInfoFrame;
04013             float verts_per_frame = cVertcount/numframes;
04014             float tris_per_frame = cTricount/numframes;
04015             float DPs_per_frame = cDPcount/numframes;
04016             float DPs_notexchange_per_frame = cDP_noTexChangeCount/numframes;
04017             float verts_per_DP = cVertcount/(float)cDPcount;
04018             float verts_per_sec = cVertcount/delta_secs;
04019             float tris_per_sec = cTricount/delta_secs;
04020             float Geoms_per_frame = cGeomcount/numframes;
04021             float DrawPrims_per_Geom = cDPcount/(float)cGeomcount;
04022             float verts_per_Geom = cVertcount/(float)cGeomcount;
04023 
04024             dxgsg8_cat.debug() << "==================================="
04025                 << "\n Avg Verts/sec:\t\t" << verts_per_sec
04026                 << "\n Avg Tris/sec:\t\t" << tris_per_sec
04027                 << "\n Avg Verts/frame:\t" << verts_per_frame
04028                 << "\n Avg Tris/frame:\t" << tris_per_frame
04029                 << "\n Avg DrawPrims/frm:\t" << DPs_per_frame
04030                 << "\n Avg Verts/DrawPrim:\t" << verts_per_DP
04031                 << "\n Avg DrawPrims w/no Texture Change from prev DrawPrim/frm:\t" << DPs_notexchange_per_frame
04032                 << "\n Avg Geoms/frm:\t" << Geoms_per_frame
04033                 << "\n Avg DrawPrims/Geom:\t" << DrawPrims_per_Geom
04034                 << "\n Avg Verts/Geom:\t" << verts_per_Geom
04035                 << endl;
04036 
04037             LastDPInfoFrame=_cur_frame_count;
04038             cDPcount = cVertcount=cTricount=cDP_noTexChangeCount=cGeomcount=0;
04039             LastTickCount=CurTickCount;
04040         }
04041     }
04042 #endif
04043 
04044 #if defined(DO_PSTATS)||defined(PRINT_RESOURCESTATS)
04045 #ifndef PRINT_RESOURCESTATS
04046   if (_texmgrmem_total_pcollector.is_active())
04047 #endif
04048   {
04049       #define TICKS_PER_GETTEXINFO (2.5*1000)   // 2.5 second interval
04050       static DWORD LastTickCount=0;
04051       DWORD CurTickCount=GetTickCount();
04052 
04053       if (CurTickCount-LastTickCount > TICKS_PER_GETTEXINFO) {
04054           LastTickCount=CurTickCount;
04055           report_texmgr_stats();
04056       }
04057   }
04058 #endif
04059 
04060   // Note: regular GraphicsWindow::end_frame is being called,
04061   // but we override gsg::end_frame, so need to explicitly call it here
04062   // (currently it's an empty fn)
04063   GraphicsStateGuardian::end_frame();
04064 }
04065 
04066 ////////////////////////////////////////////////////////////////////
04067 //     Function: DXGraphicsStateGuardian8::wants_normals
04068 //       Access: Public, Virtual
04069 //  Description:
04070 ////////////////////////////////////////////////////////////////////
04071 INLINE bool DXGraphicsStateGuardian8::
04072 wants_normals() const {
04073     return (_lighting_enabled || _normals_enabled);
04074 }
04075 
04076 ////////////////////////////////////////////////////////////////////
04077 //     Function: DXGraphicsStateGuardian8::wants_texcoords
04078 //       Access: Public, Virtual
04079 //  Description:
04080 ////////////////////////////////////////////////////////////////////
04081 INLINE bool DXGraphicsStateGuardian8::
04082 wants_texcoords() const {
04083     return _texturing_enabled;
04084 }
04085 
04086 
04087 ////////////////////////////////////////////////////////////////////
04088 //     Function: DXGraphicsStateGuardian8::depth_offset_decals
04089 //       Access: Public, Virtual
04090 //  Description: Returns true if this GSG can implement decals using a
04091 //               DepthOffsetAttrib, or false if that is unreliable
04092 //               and the three-step rendering process should be used
04093 //               instead.
04094 ////////////////////////////////////////////////////////////////////
04095 bool DXGraphicsStateGuardian8::
04096 depth_offset_decals() {
04097   // False for now.
04098   return false;
04099 }
04100 
04101 ////////////////////////////////////////////////////////////////////
04102 //     Function: DXGraphicsStateGuardian8::get_internal_coordinate_system
04103 //       Access: Public, Virtual
04104 //  Description: Should be overridden by derived classes to return the
04105 //               coordinate system used internally by the GSG, if any
04106 //               one particular coordinate system is used.  The
04107 //               default, CS_default, indicates that the GSG can use
04108 //               any coordinate system.
04109 //
04110 //               If this returns other than CS_default, the
04111 //               GraphicsEngine will automatically convert all
04112 //               transforms into the indicated coordinate system.
04113 ////////////////////////////////////////////////////////////////////
04114 CoordinateSystem DXGraphicsStateGuardian8::
04115 get_internal_coordinate_system() const {
04116   return CS_yup_left;
04117 }
04118 
04119 ////////////////////////////////////////////////////////////////////
04120 //     Function: DXGraphicsStateGuardian8::compute_distance_to
04121 //       Access: Public, Virtual
04122 //  Description: This function may only be called during a render
04123 //               traversal; it will compute the distance to the
04124 //               indicated point, assumed to be in modelview
04125 //               coordinates, from the camera plane.
04126 ////////////////////////////////////////////////////////////////////
04127 INLINE float DXGraphicsStateGuardian8::
04128 compute_distance_to(const LPoint3f &point) const {
04129     // In the case of a DXGraphicsStateGuardian8, we know that the
04130     // modelview matrix already includes the relative transform from the
04131     // camera, as well as a to-y-up conversion.  Thus, the distance to
04132     // the camera plane is simply the +z distance.  (negative of gl compute_distance_to,
04133     // since d3d uses left-hand coords)
04134 
04135     return point[2];
04136 }
04137 
04138 ////////////////////////////////////////////////////////////////////
04139 //     Function: DXGraphicsStateGuardian8::set_draw_buffer
04140 //       Access: Protected
04141 //  Description: Sets up the glDrawBuffer to render into the buffer
04142 //               indicated by the RenderBuffer object.  This only sets
04143 //               up the color bits; it does not affect the depth,
04144 //               stencil, accum layers.
04145 ////////////////////////////////////////////////////////////////////
04146 void DXGraphicsStateGuardian8::
04147 set_draw_buffer(const RenderBuffer &rb) {
04148     dxgsg8_cat.fatal() << "DX set_draw_buffer unimplemented!!!";
04149     return;
04150 
04151 #ifdef WBD_GL_MODE
04152     switch (rb._buffer_type & RenderBuffer::T_color) {
04153         case RenderBuffer::T_front:
04154             call_glDrawBuffer(GL_FRONT);
04155             break;
04156 
04157         case RenderBuffer::T_back:
04158             call_glDrawBuffer(GL_BACK);
04159             break;
04160 
04161         case RenderBuffer::T_right:
04162             call_glDrawBuffer(GL_RIGHT);
04163             break;
04164 
04165         case RenderBuffer::T_left:
04166             call_glDrawBuffer(GL_LEFT);
04167             break;
04168 
04169         case RenderBuffer::T_front_right:
04170             call_glDrawBuffer(GL_FRONT_RIGHT);
04171             break;
04172 
04173         case RenderBuffer::T_front_left:
04174             call_glDrawBuffer(GL_FRONT_LEFT);
04175             break;
04176 
04177         case RenderBuffer::T_back_right:
04178             call_glDrawBuffer(GL_BACK_RIGHT);
04179             break;
04180 
04181         case RenderBuffer::T_back_left:
04182             call_glDrawBuffer(GL_BACK_LEFT);
04183             break;
04184 
04185         default:
04186             call_glDrawBuffer(GL_FRONT_AND_BACK);
04187     }
04188 #endif              // WBD_GL_MODE
04189 }
04190 
04191 ////////////////////////////////////////////////////////////////////
04192 //     Function: DXGraphicsStateGuardian8::set_read_buffer
04193 //       Access: Protected
04194 //  Description: Vestigial analog of glReadBuffer
04195 ////////////////////////////////////////////////////////////////////
04196 void DXGraphicsStateGuardian8::
04197 set_read_buffer(const RenderBuffer &rb) {
04198 
04199     if(rb._buffer_type & RenderBuffer::T_front) {
04200             _cur_read_pixel_buffer=RenderBuffer::T_front;
04201     } else  if(rb._buffer_type & RenderBuffer::T_back) {
04202             _cur_read_pixel_buffer=RenderBuffer::T_back;
04203     } else {
04204             dxgsg8_cat.error() << "Invalid or unimplemented Argument to set_read_buffer!\n";
04205     }
04206     return;
04207 }
04208 
04209 ////////////////////////////////////////////////////////////////////
04210 //     Function: DXGraphicsStateGuardian8::get_texture_wrap_mode
04211 //       Access: Protected
04212 //  Description: Maps from the Texture's internal wrap mode symbols to
04213 //               GL's.
04214 ////////////////////////////////////////////////////////////////////
04215 INLINE D3DTEXTUREADDRESS DXGraphicsStateGuardian8::
04216 get_texture_wrap_mode(Texture::WrapMode wm) const {
04217   static D3DTEXTUREADDRESS PandaTexWrapMode_to_D3DTexWrapMode[Texture::WM_invalid] = {
04218     D3DTADDRESS_CLAMP,D3DTADDRESS_WRAP,D3DTADDRESS_MIRROR,D3DTADDRESS_MIRRORONCE,D3DTADDRESS_BORDER};
04219 
04220     return PandaTexWrapMode_to_D3DTexWrapMode[wm];
04221 }
04222 
04223 ////////////////////////////////////////////////////////////////////
04224 //     Function: DXGraphicsStateGuardian8::get_fog_mode_type
04225 //       Access: Protected
04226 //  Description: Maps from the fog types to gl version
04227 ////////////////////////////////////////////////////////////////////
04228 INLINE D3DFOGMODE DXGraphicsStateGuardian8::
04229 get_fog_mode_type(Fog::Mode m) const {
04230   switch (m) {
04231   case Fog::M_linear:
04232     return D3DFOG_LINEAR;
04233   case Fog::M_exponential:
04234     return D3DFOG_EXP;
04235   case Fog::M_exponential_squared:
04236     return D3DFOG_EXP2;
04237   }
04238   dxgsg8_cat.error() << "Invalid Fog::Mode value" << endl;
04239   return D3DFOG_EXP;
04240 }
04241 
04242 ////////////////////////////////////////////////////////////////////
04243 //     Function: DXGraphicsStateGuardian8::enable_lighting
04244 //       Access: Protected, Virtual
04245 //  Description: Intended to be overridden by a derived class to
04246 //               enable or disable the use of lighting overall.  This
04247 //               is called by issue_light() according to whether any
04248 //               lights are in use or not.
04249 ////////////////////////////////////////////////////////////////////
04250 void DXGraphicsStateGuardian8::
04251 enable_lighting(bool enable) {
04252   _pD3DDevice->SetRenderState(D3DRS_LIGHTING, (DWORD)enable);
04253 }
04254 
04255 ////////////////////////////////////////////////////////////////////
04256 //     Function: DXGraphicsStateGuardian8::set_ambient_light
04257 //       Access: Protected, Virtual
04258 //  Description: Intended to be overridden by a derived class to
04259 //               indicate the color of the ambient light that should
04260 //               be in effect.  This is called by issue_light() after
04261 //               all other lights have been enabled or disabled.
04262 ////////////////////////////////////////////////////////////////////
04263 void DXGraphicsStateGuardian8::
04264 set_ambient_light(const Colorf &color) {
04265   _pD3DDevice->SetRenderState(D3DRS_AMBIENT,
04266                                   Colorf_to_D3DCOLOR(color));
04267 }
04268 
04269 ////////////////////////////////////////////////////////////////////
04270 //     Function: DXGraphicsStateGuardian8::enable_light
04271 //       Access: Protected, Virtual
04272 //  Description: Intended to be overridden by a derived class to
04273 //               enable the indicated light id.  A specific Light will
04274 //               already have been bound to this id via bind_light().
04275 ////////////////////////////////////////////////////////////////////
04276 void DXGraphicsStateGuardian8::
04277 enable_light(int light_id, bool enable) {
04278   HRESULT res = _pD3DDevice->LightEnable(light_id, enable);
04279 
04280 #ifdef GSG_VERBOSE
04281   dxgsg8_cat.debug()
04282     << "LightEnable(" << light_id << "=" << enable << ")" << endl;
04283 #endif
04284 }
04285 
04286 ////////////////////////////////////////////////////////////////////
04287 //     Function: DXGraphicsStateGuardian8::slot_new_clip_plane
04288 //       Access: Protected, Virtual
04289 //  Description: This will be called by the base class before a
04290 //               particular clip plane id will be used for the first
04291 //               time.  It is intended to allow the derived class to
04292 //               reserve any additional resources, if required, for
04293 //               the new clip plane; and also to indicate whether the
04294 //               hardware supports this many simultaneous clipping
04295 //               planes.
04296 //
04297 //               The return value should be true if the additional
04298 //               plane is supported, or false if it is not.
04299 ////////////////////////////////////////////////////////////////////
04300 bool DXGraphicsStateGuardian8::
04301 slot_new_clip_plane(int plane_id) {
04302   return (plane_id < D3DMAXUSERCLIPPLANES);
04303 }
04304 
04305 ////////////////////////////////////////////////////////////////////
04306 //     Function: DXGraphicsStateGuardian8::enable_clip_plane
04307 //       Access: Protected, Virtual
04308 //  Description: Intended to be overridden by a derived class to
04309 //               enable the indicated clip_plane id.  A specific
04310 //               PlaneNode will already have been bound to this id via
04311 //               bind_clip_plane().
04312 ////////////////////////////////////////////////////////////////////
04313 INLINE void DXGraphicsStateGuardian8::
04314 enable_clip_plane(int plane_id, bool enable) {
04315   assert(plane_id < D3DMAXUSERCLIPPLANES);
04316 
04317   DWORD bitflag = ((DWORD)1 << plane_id);
04318   if (enable) {
04319     _clip_plane_bits |= bitflag;
04320   } else {
04321     _clip_plane_bits &= ~bitflag;
04322   }
04323 
04324   _pD3DDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, _clip_plane_bits);
04325 }
04326 
04327 ////////////////////////////////////////////////////////////////////
04328 //     Function: DXGraphicsStateGuardian8::bind_clip_plane
04329 //       Access: Protected, Virtual
04330 //  Description: Called the first time a particular clip_plane has been
04331 //               bound to a given id within a frame, this should set
04332 //               up the associated hardware clip_plane with the clip_plane's
04333 //               properties.
04334 ////////////////////////////////////////////////////////////////////
04335 void DXGraphicsStateGuardian8::
04336 bind_clip_plane(PlaneNode *plane, int plane_id) {
04337   // Get the plane in "world coordinates".  This means the plane in
04338   // the coordinate space of the camera, converted to DX's coordinate
04339   // system.
04340   NodePath plane_np(plane);
04341   const LMatrix4f &plane_mat = plane_np.get_mat(_scene_setup->get_camera_path());
04342   LMatrix4f rel_mat = plane_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
04343   Planef world_plane = plane->get_plane() * rel_mat;
04344 
04345   _pD3DDevice->SetClipPlane(plane_id, world_plane.get_data());
04346 }
04347 
04348 void DXGraphicsStateGuardian8::
04349 issue_color_write(const ColorWriteAttrib *attrib) {
04350   _color_write_mode = attrib->get_mode();
04351   set_color_writemask((_color_write_mode ==ColorWriteAttrib::M_on) ? 0xFFFFFFFF : 0x0);
04352 }
04353 
04354 ////////////////////////////////////////////////////////////////////
04355 //     Function: DXGraphicsStateGuardian8::set_blend_mode
04356 //       Access: Protected, Virtual
04357 //  Description: Called after any of these three blending states have
04358 //               changed; this function is responsible for setting the
04359 //               appropriate color blending mode based on the given
04360 //               properties.
04361 ////////////////////////////////////////////////////////////////////
04362 void DXGraphicsStateGuardian8::
04363 set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
04364                ColorBlendAttrib::Mode color_blend_mode,
04365                TransparencyAttrib::Mode transparency_mode) {
04366 
04367   if((color_write_mode == ColorWriteAttrib::M_off) && !_pScrn->bCanDirectDisableColorWrites) {
04368     // need !_pScrn->bCanDirectDisableColorWrites guard because other issue_colorblend,issue_transp
04369     // will come this way, and they should ignore the colorwriteattrib value since it's been
04370     // handled separately in set_color_writemask
04371     enable_blend(true);
04372     call_dxBlendFunc(D3DBLEND_ZERO, D3DBLEND_ONE);
04373     return;
04374   }
04375 
04376   // Is there a color blend set?
04377   switch (color_blend_mode) {
04378   case ColorBlendAttrib::M_none:
04379     break;
04380 
04381   case ColorBlendAttrib::M_multiply:
04382     enable_blend(true);
04383     call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ZERO);
04384     return;
04385 
04386   case ColorBlendAttrib::M_add:
04387     enable_blend(true);
04388     call_dxBlendFunc(D3DBLEND_ONE, D3DBLEND_ONE);
04389     return;
04390 
04391   case ColorBlendAttrib::M_multiply_add:
04392     enable_blend(true);
04393     call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ONE);
04394     return;
04395 
04396   default:
04397     dxgsg8_cat.error()
04398       << "Unknown color blend mode " << (int)color_blend_mode << endl;
04399     break;
04400   }
04401 
04402   // No color blend; is there a transparency set?
04403   switch (transparency_mode) {
04404   case TransparencyAttrib::M_none:
04405   case TransparencyAttrib::M_binary:
04406     break;
04407 
04408   case TransparencyAttrib::M_alpha:
04409   case TransparencyAttrib::M_alpha_sorted:
04410   case TransparencyAttrib::M_multisample:
04411   case TransparencyAttrib::M_multisample_mask:
04412   case TransparencyAttrib::M_dual:
04413     enable_blend(true);
04414     call_dxBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
04415     return;
04416 
04417   default:
04418     dxgsg8_cat.error()
04419       << "invalid transparency mode " << (int)transparency_mode << endl;
04420     break;
04421   }
04422 
04423   // Nothing's set, so disable blending.
04424   enable_blend(false);
04425 }
04426 
04427 ////////////////////////////////////////////////////////////////////
04428 //     Function: DXGraphicsStateGuardian8::save_frame_buffer
04429 //       Access: Public
04430 //  Description: Saves the indicated planes of the frame buffer
04431 //               (within the indicated display region) and returns it
04432 //               in some meaningful form that can be restored later
04433 //               via restore_frame_buffer().  This is a helper
04434 //               function for push_frame_buffer() and
04435 //               pop_frame_buffer().
04436 ////////////////////////////////////////////////////////////////////
04437 PT(SavedFrameBuffer) DXGraphicsStateGuardian8::
04438 save_frame_buffer(const RenderBuffer &buffer,
04439                   CPT(DisplayRegion) dr) {
04440 
04441     dxgsg8_cat.error() << "save_frame_buffer unimplemented!!\n";
04442     return NULL;
04443 
04444 #if 0
04445     DXSavedFrameBuffer *sfb = new DXSavedFrameBuffer(buffer, dr);
04446 
04447     if (buffer._buffer_type & RenderBuffer::T_depth) {
04448         // Save the depth buffer.
04449         sfb->_depth =
04450         new PixelBuffer(PixelBuffer::depth_buffer(dr->get_pixel_width(),
04451                                                   dr->get_pixel_height()));
04452         copy_pixel_buffer(sfb->_depth, dr, buffer);
04453     }
04454 
04455     if (buffer._buffer_type & RenderBuffer::T_back) {
04456         // Save the color buffer.
04457         sfb->_back_rgba = new Texture;
04458         copy_texture(sfb->_back_rgba->prepare(this), dr, buffer);
04459     }
04460 
04461     return sfb;
04462 #endif
04463 }
04464 
04465 ////////////////////////////////////////////////////////////////////
04466 //     Function: DXGraphicsStateGuardian8::restore_frame_buffer
04467 //       Access: Public
04468 //  Description: Restores the frame buffer that was previously saved.
04469 ////////////////////////////////////////////////////////////////////
04470 void DXGraphicsStateGuardian8::
04471 restore_frame_buffer(SavedFrameBuffer *frame_buffer) {
04472     dxgsg8_cat.error() << "restore_frame_buffer unimplemented!!\n";
04473     return;
04474 }
04475 
04476 TypeHandle DXGraphicsStateGuardian8::get_type(void) const {
04477     return get_class_type();
04478 }
04479 
04480 TypeHandle DXGraphicsStateGuardian8::get_class_type(void) {
04481     return _type_handle;
04482 }
04483 
04484 void DXGraphicsStateGuardian8::init_type(void) {
04485     GraphicsStateGuardian::init_type();
04486     register_type(_type_handle, "DXGraphicsStateGuardian8",
04487                   GraphicsStateGuardian::get_class_type());
04488 }
04489 
04490 ////////////////////////////////////////////////////////////////////
04491 //     Function: dx_cleanup
04492 //  Description: Clean up the DirectX environment, accounting for exit()
04493 ////////////////////////////////////////////////////////////////////
04494 void DXGraphicsStateGuardian8::
04495 dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled) {
04496   static bool bAtExitFnEverCalled=false;
04497 
04498     if(dxgsg8_cat.is_spam()) {
04499         dxgsg8_cat.spam() << "dx_cleanup called, bAtExitFnCalled=" << bAtExitFnCalled << ", bAtExitFnEverCalled=" << bAtExitFnEverCalled << endl;
04500     }
04501 
04502     bAtExitFnEverCalled = (bAtExitFnEverCalled || bAtExitFnCalled);
04503 
04504     // for now, I can't trust any of the ddraw/d3d releases during atexit(),
04505     // so just return directly.  maybe revisit this later, if have problems
04506     // restarting d3d/ddraw after one of these uncleaned-up exits
04507     if(bAtExitFnEverCalled)
04508       return;
04509 
04510     // unsafe to do the D3D releases after exit() called, since DLL_PROCESS_DETACH
04511     // msg already delivered to d3d.dll and it's unloaded itself
04512 
04513     free_nondx_resources();
04514 
04515     PRINT_REFCNT(dxgsg8,_pD3DDevice);
04516 
04517     // these 2 calls release ddraw surfaces and vbuffers.  unsafe unless not on exit
04518     release_all_textures();
04519     release_all_geoms();
04520 
04521     PRINT_REFCNT(dxgsg8,_pD3DDevice);
04522 
04523     // delete non-panda-texture/geom DX objects (VBs/textures/shaders)
04524     SAFE_DELSHADER(Vertex,_CurVertexShader,_pD3DDevice);
04525     SAFE_DELSHADER(Pixel,_CurPixelShader,_pD3DDevice);
04526     SAFE_RELEASE(_pGlobalTexture);
04527 
04528     PRINT_REFCNT(dxgsg8,_pD3DDevice);
04529 
04530     // Do a safe check for releasing the D3DDEVICE. RefCount should be zero.
04531     // if we're called from exit(), _pD3DDevice may already have been released
04532     if (_pD3DDevice!=NULL) {
04533         for(int i=0;i<D3D_MAXTEXTURESTAGES;i++)
04534            _pD3DDevice->SetTexture(i,NULL);  // d3d should release this stuff internally anyway, but whatever
04535         RELEASE(_pD3DDevice,dxgsg8,"d3dDevice",RELEASE_DOWN_TO_ZERO);
04536         _pScrn->pD3DDevice = NULL;
04537     }
04538 
04539     // Releasing pD3D is now the responsibility of the GraphicsPipe destructor
04540 }
04541 
04542 void DXGraphicsStateGuardian8::  
04543 set_context(DXScreenData *pNewContextData) {
04544     // dont do copy from window since dx_init sets fields too.
04545     // simpler to keep all of it in one place, so use ptr to window struct
04546 
04547     assert(pNewContextData!=NULL);
04548     _pScrn = pNewContextData;
04549     _pD3DDevice = _pScrn->pD3DDevice;   //copy this one field for speed of deref
04550 }
04551 
04552 bool refill_tex_callback(TextureContext *tc,void *void_dxgsg_ptr) {
04553      DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc);
04554 //   DXGraphicsStateGuardian8 *dxgsg = (DXGraphicsStateGuardian8 *)void_dxgsg_ptr; not needed?
04555 
04556      // Re-fill the contents of textures and vertex buffers
04557      // which just got restored now.
04558      HRESULT hr=dtc->FillDDSurfTexturePixels();
04559      return hr==S_OK;
04560 }
04561 
04562 bool delete_tex_callback(TextureContext *tc,void *void_dxgsg_ptr) {
04563      DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc);
04564 
04565      // release DDSurf (but not the texture context)
04566      dtc->DeleteTexture();
04567      return true;
04568 }
04569 
04570 bool recreate_tex_callback(TextureContext *tc,void *void_dxgsg_ptr) {
04571      DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc);
04572      DXGraphicsStateGuardian8 *dxgsg = (DXGraphicsStateGuardian8 *)void_dxgsg_ptr;
04573 
04574      // Re-fill the contents of textures and vertex buffers
04575      // which just got restored now.
04576 
04577      IDirect3DTexture8 *ddtex = dtc->CreateTexture(*dxgsg->_pScrn);
04578      return ddtex!=NULL;
04579 }
04580 
04581 // release all textures and vertex/index buffers
04582 HRESULT DXGraphicsStateGuardian8::DeleteAllDeviceObjects(void) {
04583   // BUGBUG: need to release any vertexbuffers here
04584 
04585   // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it
04586 
04587   // dont call release_all_textures() because we want the panda tex obj around so it can reload its texture
04588 
04589   // bugbug:  do I still need to delete all the textures since they are all D3DPOOL_MANAGED now?
04590   traverse_prepared_textures(delete_tex_callback,this);
04591 
04592   if(dxgsg8_cat.is_debug())
04593       dxgsg8_cat.debug() << "release of all textures complete\n";
04594 
04595   // delete non-panda-texture/geom DX objects (VBs/textures/shaders)
04596   SAFE_DELSHADER(Vertex,_CurVertexShader,_pD3DDevice);
04597   SAFE_DELSHADER(Pixel,_CurPixelShader,_pD3DDevice);
04598   SAFE_RELEASE(_pGlobalTexture);
04599 
04600   assert(_pD3DDevice);
04601 
04602   SAFE_DELSHADER(Vertex,_CurVertexShader,_pD3DDevice);
04603   SAFE_DELSHADER(Pixel,_CurPixelShader,_pD3DDevice);
04604   SAFE_RELEASE(_pGlobalTexture);
04605 
04606   return S_OK;
04607 }
04608 
04609 // recreate all textures and vertex/index buffers
04610 HRESULT DXGraphicsStateGuardian8::RecreateAllDeviceObjects(void) {
04611   // BUGBUG: need to handle vertexbuffer handling here
04612 
04613   // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it
04614   traverse_prepared_textures(recreate_tex_callback,this);
04615 
04616   if(dxgsg8_cat.is_debug())
04617       dxgsg8_cat.debug() << "recreation of all textures complete\n";
04618   return S_OK;
04619 }
04620 
04621 HRESULT DXGraphicsStateGuardian8::ReleaseAllDeviceObjects(void) {
04622     // release any D3DPOOL_DEFAULT objects here (currently none)
04623     return S_OK;
04624 }
04625 
04626 ////////////////////////////////////////////////////////////////////
04627 //     Function: show_frame
04628 //       Access:
04629 //       Description:   redraw primary buffer
04630 ////////////////////////////////////////////////////////////////////
04631 void DXGraphicsStateGuardian8::show_frame(bool bNoNewFrameDrawn) {
04632   if(_pD3DDevice==NULL)
04633     return;
04634 
04635   //  DO_PSTATS_STUFF(PStatTimer timer(_win->_swap_pcollector));  // this times just the flip, so it must go here in dxgsg, instead of wdxdisplay, which would time the whole frame
04636   HRESULT hr;
04637 
04638   if(bNoNewFrameDrawn) {
04639       // a new frame has not been rendered, we just want to display the last thing
04640       // that was drawn into backbuf, if backbuf is valid
04641       if(_pScrn->PresParams.SwapEffect==D3DSWAPEFFECT_DISCARD) {
04642           // in DISCARD mode, old backbufs are not guaranteed to have valid pixels,
04643           // so we cant copy back->front here.  just give up.
04644           return;
04645       } else if(_pScrn->PresParams.SwapEffect==D3DSWAPEFFECT_FLIP) {
04646          /* bugbug:  here we should use CopyRects here to copy backbuf to front (except in
04647                      the case of frames 1 and 2 where we have no valid data in the backbuffer yet,
04648                      for those cases give up and return).
04649                      not implemented yet since right now we always do discard mode for fullscrn Present()
04650                      for speed.
04651           */
04652           return;
04653       }
04654 
04655       // otherwise we have D3DSWAPEFFECT_COPY, so fall-thru to normal Present()
04656       // may work ok as long as backbuf hasnt been touched
04657   }
04658 
04659   hr = _pD3DDevice->Present((CONST RECT*)NULL,(CONST RECT*)NULL,(HWND)NULL,NULL);
04660   if(FAILED(hr)) {
04661     if(hr == D3DERR_DEVICELOST) {
04662         CheckCooperativeLevel();
04663     } else {
04664       dxgsg8_cat.error() << "show_frame() - Present() failed" << D3DERRORSTRING(hr);
04665       exit(1);
04666     }
04667   }
04668 }
04669 
04670 HRESULT DXGraphicsStateGuardian8::reset_d3d_device(D3DPRESENT_PARAMETERS *pPresParams) {
04671   HRESULT hr;
04672 
04673   assert(IS_VALID_PTR(pPresParams));
04674   assert(IS_VALID_PTR(_pScrn->pD3D8));
04675   assert(IS_VALID_PTR(_pD3DDevice));
04676 
04677   ReleaseAllDeviceObjects();
04678 
04679   if(!dx_full_screen) {
04680       // for windowed make sure out format matches the desktop fmt, in case the
04681       // desktop mode has been changed
04682 
04683        _pScrn->pD3D8->GetAdapterDisplayMode(_pScrn->CardIDNum, &_pScrn->DisplayMode);
04684        pPresParams->BackBufferFormat = _pScrn->DisplayMode.Format;
04685   }
04686 
04687   hr=_pD3DDevice->Reset(pPresParams);
04688   if(SUCCEEDED(hr)) {
04689      if(pPresParams!=&_pScrn->PresParams)
04690          memcpy(&_pScrn->PresParams,pPresParams,sizeof(D3DPRESENT_PARAMETERS));
04691   }
04692   return hr;
04693 }
04694 
04695 bool DXGraphicsStateGuardian8::
04696 CheckCooperativeLevel(bool bDoReactivateWindow) {
04697   HRESULT hr = _pD3DDevice->TestCooperativeLevel();
04698 
04699   if(SUCCEEDED(hr)) {
04700     assert(SUCCEEDED(_last_testcooplevel_result));
04701     return true;
04702   }
04703 
04704   switch(hr) {
04705       case D3DERR_DEVICENOTRESET:
04706         _bDXisReady = false;
04707         hr=reset_d3d_device(&_pScrn->PresParams);
04708         if (FAILED(hr)) {
04709           // I think this shouldnt fail unless I've screwed up the PresParams from the original working ones somehow
04710           dxgsg8_cat.error()
04711             << "CheckCooperativeLevel Reset() failed, hr = " << D3DERRORSTRING(hr);
04712           exit(1);
04713         }
04714     
04715         // BUGBUG: is taking this out wrong??
04716         /*
04717         if(bDoReactivateWindow) {
04718            _win->reactivate_window();  //must reactivate window before you can restore surfaces (otherwise you are in WRONGVIDEOMODE, and DDraw RestoreAllSurfaces fails)
04719         }
04720         */
04721 
04722         hr = _pD3DDevice->TestCooperativeLevel();
04723         if(FAILED(hr)) {
04724           // internal chk, shouldnt fail
04725           dxgsg8_cat.error()
04726             << "TestCooperativeLevel following Reset() failed, hr = " << D3DERRORSTRING(hr);
04727           exit(1);
04728         }
04729     
04730         _bDXisReady = TRUE;
04731         break;
04732     
04733       case D3DERR_DEVICELOST:
04734         if(SUCCEEDED(_last_testcooplevel_result)) {
04735           if(_bDXisReady) {
04736             //                   _win->deactivate_window();
04737             _bDXisReady = false;
04738             if(dxgsg8_cat.is_debug())
04739               dxgsg8_cat.debug() << "D3D Device was Lost, waiting...\n";
04740           }
04741         }
04742   }
04743 
04744   _last_testcooplevel_result = hr;
04745   return SUCCEEDED(hr);
04746 }
04747 
04748 /*
04749 ////////////////////////////////////////////////////////////////////
04750 //     Function: adjust_view_rect
04751 //       Access:
04752 //  Description: we receive the new x and y position of the client
04753 ////////////////////////////////////////////////////////////////////
04754 void DXGraphicsStateGuardian8::adjust_view_rect(int x, int y) {
04755     if (_pScrn->view_rect.left != x || _pScrn->view_rect.top != y) {
04756 
04757         _pScrn->view_rect.right = x + RECT_XSIZE(_pScrn->view_rect);
04758         _pScrn->view_rect.left = x;
04759         _pScrn->view_rect.bottom = y + RECT_YSIZE(_pScrn->view_rect);
04760         _pScrn->view_rect.top = y;
04761 
04762 //  set_clipper(clip_rect);
04763     }
04764 }
04765 */
04766 
04767 #if 0
04768 
04769 ////////////////////////////////////////////////////////////////////
04770 //     Function: GLGraphicsStateGuardian::save_mipmap_images
04771 //       Access: Protected
04772 //  Description: Saves out each mipmap level of the indicated texture
04773 //               (which must also be the currently active texture in
04774 //               the GL state) as a separate image file to disk.
04775 ////////////////////////////////////////////////////////////////////
04776 void DXGraphicsStateGuardian8::read_mipmap_images(Texture *tex) {
04777    Filename filename = tex->get_name();
04778    string name;
04779    if (filename.empty()) {
04780      static index = 0;
04781      name = "texture" + format_string(index);
04782      index++;
04783    } else {
04784      name = filename.get_basename_wo_extension();
04785    }
04786 
04787    PixelBuffer *pb = tex->get_ram_image();
04788    nassertv(pb != (PixelBuffer *)NULL);
04789 
04790    GLenum external_format = get_external_image_format(pb->get_format());
04791    GLenum type = get_image_type(pb->get_image_type());
04792 
04793    int xsize = pb->get_xsize();
04794    int ysize = pb->get_ysize();
04795 
04796    // Specify byte-alignment for the pixels on output.
04797    glPixelStorei(GL_PACK_ALIGNMENT, 1);
04798 
04799    int mipmap_level = 0;
04800    do {
04801      xsize = max(xsize, 1);
04802      ysize = max(ysize, 1);
04803 
04804      PT(PixelBuffer) mpb =
04805        new PixelBuffer(xsize, ysize, pb->get_num_components(),
04806                        pb->get_component_width(), pb->get_image_type(),
04807                        pb->get_format());
04808      glGetTexImage(GL_TEXTURE_2D, mipmap_level, external_format,
04809                    type, mpb->_image);
04810      Filename mipmap_filename = name + "_" + format_string(mipmap_level) + ".pnm";
04811      nout << "Writing mipmap level " << mipmap_level
04812           << " (" << xsize << " by " << ysize << ") "
04813           << mipmap_filename << "\n";
04814      mpb->write(mipmap_filename);
04815 
04816      xsize >>= 1;
04817      ysize >>= 1;
04818      mipmap_level++;
04819    } while (xsize > 0 && ysize > 0);
04820 }
04821 #endif
04822 
04823 
04824 #if 0
04825 //-----------------------------------------------------------------------------
04826 // Name: SetViewMatrix()
04827 // Desc: Given an eye point, a lookat point, and an up vector, this
04828 //       function builds a 4x4 view matrix.
04829 //-----------------------------------------------------------------------------
04830 HRESULT SetViewMatrix( D3DMATRIX& mat, D3DXVECTOR3& vFrom, D3DXVECTOR3& vAt,
04831                        D3DXVECTOR3& vWorldUp ) {
04832     // Get the z basis vector, which points straight ahead. This is the
04833     // difference from the eyepoint to the lookat point.
04834     D3DXVECTOR3 vView = vAt - vFrom;
04835 
04836     float fLength = Magnitude( vView );
04837     if (fLength < 1e-6f)
04838         return E_INVALIDARG;
04839 
04840     // Normalize the z basis vector
04841     vView /= fLength;
04842 
04843     // Get the dot product, and calculate the projection of the z basis
04844     // vector onto the up vector. The projection is the y basis vector.
04845     float fDotProduct = DotProduct( vWorldUp, vView );
04846 
04847     D3DXVECTOR3 vUp = vWorldUp - fDotProduct * vView;
04848 
04849     // If this vector has near-zero length because the input specified a
04850     // bogus up vector, let's try a default up vector
04851     if (1e-6f > ( fLength = Magnitude( vUp ) )) {
04852         vUp = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) - vView.y * vView;
04853 
04854         // If we still have near-zero length, resort to a different axis.
04855         if (1e-6f > ( fLength = Magnitude( vUp ) )) {
04856             vUp = D3DXVECTOR3( 0.0f, 0.0f, 1.0f ) - vView.z * vView;
04857 
04858             if (1e-6f > ( fLength = Magnitude( vUp ) ))
04859                 return E_INVALIDARG;
04860         }
04861     }
04862 
04863     // Normalize the y basis vector
04864     vUp /= fLength;
04865 
04866     // The x basis vector is found simply with the cross product of the y
04867     // and z basis vectors
04868     D3DXVECTOR3 vRight = CrossProduct( vUp, vView );
04869 
04870     // Start building the matrix. The first three rows contains the basis
04871     // vectors used to rotate the view to point at the lookat point
04872     mat._11 = vRight.x;  mat._12 = vUp.x;  mat._13 = vView.x;  mat._14 = 0.0f;
04873     mat._21 = vRight.y;  mat._22 = vUp.y;  mat._23 = vView.y;  mat._24 = 0.0f;
04874     mat._31 = vRight.z;  mat._32 = vUp.z;  mat._33 = vView.z;  mat._34 = 0.0f;
04875 
04876     // Do the translation values (rotations are still about the eyepoint)
04877     mat._41 = - DotProduct( vFrom, vRight );
04878     mat._42 = - DotProduct( vFrom, vUp );
04879     mat._43 = - DotProduct( vFrom, vView );
04880     mat._44 = 1.0f;
04881 
04882     return S_OK;
04883 }
04884 
04885 #endif
04886 
04887 
04888 ////////////////////////////////////////////////////////////////////
04889 //     Function: DXGraphicsStateGuardian8::prepare_geom_node
04890 //       Access: Public, Virtual
04891 //  Description: Prepares the indicated GeomNode for retained-mode
04892 //               rendering.  If this function returns non-NULL, the
04893 //               value returned will be passed back to a future call
04894 //               to draw_geom_node(), which is expected to draw the
04895 //               contents of the node.
04896 ////////////////////////////////////////////////////////////////////
04897 GeomNodeContext *DXGraphicsStateGuardian8::
04898 prepare_geom_node(GeomNode *node) {
04899   dxgsg8_cat.error() << "prepare_geom_node unimplemented for DX8!\n";
04900   return NULL;
04901 }
04902 
04903 ////////////////////////////////////////////////////////////////////
04904 //     Function: DXGraphicsStateGuardian8::draw_geom_node
04905 //       Access: Public, Virtual
04906 //  Description: Draws a GeomNode previously indicated by a call to
04907 //               prepare_geom_node().
04908 ////////////////////////////////////////////////////////////////////
04909 void DXGraphicsStateGuardian8::
04910 draw_geom_node(GeomNode *node, const RenderState *state,
04911                GeomNodeContext *gnc) {
04912   return;  // unimplemented
04913 }
04914 
04915 ////////////////////////////////////////////////////////////////////
04916 //     Function: DXGraphicsStateGuardian8::release_geom_node
04917 //       Access: Public, Virtual
04918 //  Description: Frees the resources previously allocated via a call
04919 //               to prepare_geom_node(), including deleting the
04920 //               GeomNodeContext itself, if necessary.
04921 ////////////////////////////////////////////////////////////////////
04922 void DXGraphicsStateGuardian8::
04923 release_geom_node(GeomNodeContext *gnc) {
04924 }
04925 
04926 HRESULT CreateDX8Cursor(LPDIRECT3DDEVICE8 pd3dDevice, HCURSOR hCursor,BOOL bAddWatermark) {
04927 // copied directly from dxsdk SetDeviceCursor
04928     HRESULT hr = E_FAIL;
04929     ICONINFO iconinfo;
04930     LPDIRECT3DSURFACE8 pCursorBitmap = NULL;
04931     HDC hdcColor = NULL;
04932     HDC hdcMask = NULL;
04933     HDC hdcScreen = NULL;
04934     BITMAP bm;
04935     DWORD dwWidth,dwHeightSrc,dwHeightDest;
04936     COLORREF crColor,crMask;
04937     UINT x,y;
04938     BITMAPINFO bmi;
04939     COLORREF* pcrArrayColor = NULL;
04940     COLORREF* pcrArrayMask = NULL;
04941     DWORD* pBitmap;
04942     HGDIOBJ hgdiobjOld;
04943     bool bBWCursor;
04944 
04945     ZeroMemory( &iconinfo, sizeof(iconinfo) );
04946     if( !GetIconInfo( hCursor, &iconinfo ) )
04947         goto End;
04948 
04949     if (0 == GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm))
04950         goto End;
04951     dwWidth = bm.bmWidth;
04952     dwHeightSrc = bm.bmHeight;
04953 
04954     if( iconinfo.hbmColor == NULL ) {
04955         bBWCursor = true;
04956         dwHeightDest = dwHeightSrc / 2;
04957     } else {
04958         bBWCursor = false;
04959         dwHeightDest = dwHeightSrc;
04960     }
04961 
04962     // Create a surface for the cursor
04963     if( FAILED( hr = pd3dDevice->CreateImageSurface( dwWidth, dwHeightDest,
04964         D3DFMT_A8R8G8B8, &pCursorBitmap ) ) ) {
04965         goto End;
04966     }
04967 
04968     pcrArrayMask = new DWORD[dwWidth * dwHeightSrc];
04969 
04970     ZeroMemory(&bmi, sizeof(bmi));
04971     bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
04972     bmi.bmiHeader.biWidth = dwWidth;
04973     bmi.bmiHeader.biHeight = dwHeightSrc;
04974     bmi.bmiHeader.biPlanes = 1;
04975     bmi.bmiHeader.biBitCount = 32;
04976     bmi.bmiHeader.biCompression = BI_RGB;
04977 
04978     hdcScreen = GetDC( NULL );
04979     hdcMask = CreateCompatibleDC( hdcScreen );
04980     if( hdcMask == NULL )
04981     {
04982         hr = E_FAIL;
04983         goto End;
04984     }
04985     hgdiobjOld = SelectObject(hdcMask, iconinfo.hbmMask);
04986     GetDIBits(hdcMask, iconinfo.hbmMask, 0, dwHeightSrc,
04987         pcrArrayMask, &bmi, DIB_RGB_COLORS);
04988     SelectObject(hdcMask, hgdiobjOld);
04989 
04990     if (!bBWCursor)
04991     {
04992         pcrArrayColor = new DWORD[dwWidth * dwHeightDest];
04993         hdcColor = CreateCompatibleDC( GetDC( NULL ) );
04994         if( hdcColor == NULL )
04995         {
04996             hr = E_FAIL;
04997             goto End;
04998         }
04999         SelectObject(hdcColor, iconinfo.hbmColor);
05000         GetDIBits(hdcColor, iconinfo.hbmColor, 0, dwHeightDest,
05001             pcrArrayColor, &bmi, DIB_RGB_COLORS);
05002     }
05003 
05004     // Transfer cursor image into the surface
05005     D3DLOCKED_RECT lr;
05006     pCursorBitmap->LockRect( &lr, NULL, 0 );
05007     pBitmap = (DWORD*)lr.pBits;
05008     for( y = 0; y < dwHeightDest; y++ )
05009     {
05010         for( x = 0; x < dwWidth; x++ )
05011         {
05012             if (bBWCursor)
05013             {
05014                 crColor = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
05015                 crMask = pcrArrayMask[dwWidth*(dwHeightSrc-1-y) + x];
05016             }
05017             else
05018             {
05019                 crColor = pcrArrayColor[dwWidth*(dwHeightDest-1-y) + x];
05020                 crMask = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
05021             }
05022             if (crMask == 0)
05023                 pBitmap[dwWidth*y + x] = 0xff000000 | crColor;
05024             else
05025                 pBitmap[dwWidth*y + x] = 0x00000000;
05026 
05027             // It may be helpful to make the D3D cursor look slightly
05028             // different from the Windows cursor so you can distinguish
05029             // between the two when developing/testing code.  When
05030             // bAddWatermark is TRUE, the following code adds some
05031             // small grey "D3D" characters to the upper-left corner of
05032             // the D3D cursor image.
05033             if( bAddWatermark && x < 12 && y < 5 )
05034             {
05035                 // 11.. 11.. 11.. .... CCC0
05036                 // 1.1. ..1. 1.1. .... A2A0
05037                 // 1.1. .1.. 1.1. .... A4A0
05038                 // 1.1. ..1. 1.1. .... A2A0
05039                 // 11.. 11.. 11.. .... CCC0
05040 
05041                 const WORD wMask[5] = { 0xccc0, 0xa2a0, 0xa4a0, 0xa2a0, 0xccc0 };
05042                 if( wMask[y] & (1 << (15 - x)) )
05043                 {
05044                     pBitmap[dwWidth*y + x] |= 0xff808080;
05045                 }
05046             }
05047         }
05048     }
05049     pCursorBitmap->UnlockRect();
05050 
05051     // Set the device cursor
05052     if( FAILED( hr = pd3dDevice->SetCursorProperties( iconinfo.xHotspot,
05053         iconinfo.yHotspot, pCursorBitmap ) ) )
05054     {
05055         goto End;
05056     }
05057 
05058     hr = S_OK;
05059 
05060 End:
05061     if( iconinfo.hbmMask != NULL )
05062         DeleteObject( iconinfo.hbmMask );
05063     if( iconinfo.hbmColor != NULL )
05064         DeleteObject( iconinfo.hbmColor );
05065     if( hdcScreen != NULL )
05066         ReleaseDC( NULL, hdcScreen );
05067     if( hdcColor != NULL )
05068         DeleteDC( hdcColor );
05069     if( hdcMask != NULL )
05070         DeleteDC( hdcMask );
05071 
05072     SAFE_DELETE_ARRAY( pcrArrayColor );
05073     SAFE_DELETE_ARRAY( pcrArrayMask );
05074     RELEASE(pCursorBitmap,dxgsg8,"pCursorBitmap",RELEASE_ONCE);
05075     return hr;
05076 }
05077 
05078 #ifdef _DEBUG
05079 // defns for print formatting in debugger
05080 typedef struct {
05081   float x,y,z;
05082   float nx,ny,nz;
05083   D3DCOLOR diffuse;
05084   float u,v;
05085 } POS_NORM_COLOR_TEX_VERTEX;
05086 
05087 typedef struct {
05088   float x,y,z;
05089   D3DCOLOR diffuse;
05090   float u,v;
05091 } POS_COLOR_TEX_VERTEX;
05092 
05093 typedef struct {
05094   float x,y,z;
05095   float u,v;
05096 } POS_TEX_VERTEX;
05097 
05098 // define junk vars so symbols are included in dbginfo
05099 POS_TEX_VERTEX junk11;
05100 POS_COLOR_TEX_VERTEX junk22;
05101 POS_NORM_COLOR_TEX_VERTEX junk33;
05102 #endif
05103 

Generated on Fri May 2 00:37:15 2003 for Panda by doxygen1.3