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

panda/src/dxgsg7/dxGraphicsStateGuardian7.cxx

Go to the documentation of this file.
00001 // Filename: dxGraphicsStateGuardian7.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 "dxGraphicsStateGuardian7.h"
00020 #include "config_dxgsg7.h"
00021 
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 #include <mmsystem.h>
00056 
00057 // print out simple drawprim stats every few secs
00058 //#define COUNT_DRAWPRIMS
00059 
00060 //#define PRINT_TEXSTATS
00061 
00062 //#define DISABLE_DECALING
00063 #define DISABLE_POLYGON_OFFSET_DECALING
00064 // currently doesnt work well enough in toontown models for us to use
00065 // prob is when viewer gets close to decals, they disappear into wall poly, need to investigate
00066 
00067 // test non-optimized general geom pipe for all models
00068 // apparently DPStrided faults for some color G_OVERALL cases, so comment out for now
00069 // not clear that it is actually faster in practice, it may even be slightly slower
00070 #define DONT_USE_DRAWPRIMSTRIDED
00071 
00072 //const int VERT_BUFFER_SIZE = (8*1024L);
00073 // For sparkle particles, we can have 4 vertices per sparkle, and a
00074 // particle pool size of 1024 particles
00075 
00076 // for sprites, 1000 prims, 6 verts/prim, 24 bytes/vert
00077 const int VERT_BUFFER_SIZE = (32*6*1024L);
00078 
00079 // if defined, pandadx only handles 1 panda display region
00080 // note multiple region code doesnt work now (see prepare_display_region,set_clipper)
00081 #define NO_MULTIPLE_DISPLAY_REGIONS
00082 
00083 TypeHandle DXGraphicsStateGuardian7::_type_handle;
00084 
00085 // bit masks used for drawing primitives
00086 // bitmask type: normal=0x1,color=0x2,texcoord=0x4
00087 typedef enum { NothingSet=0,NormalOnly,ColorOnly,Normal_Color,TexCoordOnly,
00088                Normal_TexCoord,Color_TexCoord,Normal_Color_TexCoord
00089 } DrawLoopFlags;
00090 
00091 #define PER_NORMAL   NormalOnly
00092 #define PER_COLOR    ColorOnly
00093 #define PER_TEXCOORD TexCoordOnly
00094 
00095 static D3DMATRIX matIdentity;
00096 
00097 #ifdef COUNT_DRAWPRIMS
00098 // you should just use Intel GPT instead of this stuff
00099 
00100 static DWORD cDPcount=0;
00101 static DWORD cVertcount=0;
00102 static DWORD cTricount=0;
00103 static DWORD cGeomcount=0;
00104 
00105 static LPDIRECTDRAWSURFACE7 pLastTexture=NULL;
00106 static DWORD cDP_noTexChangeCount=0;
00107 static LPDIRECT3DDEVICE7 global_pD3DDevice = NULL;
00108 
00109 static void CountDPs(DWORD nVerts,DWORD nTris) {
00110     cDPcount++;
00111     cVertcount+=nVerts;
00112     cTricount+=nTris;
00113 
00114     if(_pCurDeviceTexture==pLastTexture) {
00115         cDP_noTexChangeCount++;
00116     } else pLastTexture = _pCurDeviceTexture;
00117 }
00118 #else
00119 #define CountDPs(nv,nt)
00120 #endif
00121 
00122 #define MY_D3DRGBA(r,g,b,a) ((D3DCOLOR) D3DRGBA(r,g,b,a))
00123 
00124 #if defined(DO_PSTATS) || defined(PRINT_TEXSTATS)
00125 static bool bTexStatsRetrievalImpossible=false;
00126 #endif
00127 
00128 //#define Colorf_to_D3DCOLOR(out_color) (MY_D3DRGBA((out_color)[0], (out_color)[1], (out_color)[2], (out_color)[3]))
00129 
00130 INLINE DWORD
00131 Colorf_to_D3DCOLOR(const Colorf &cColorf) {
00132 // MS VC defines _M_IX86 for x86.  gcc should define _X86_
00133 #if defined(_M_IX86) || defined(_X86_)
00134     DWORD d3dcolor,tempcolorval=255;
00135 
00136     // note the default FPU rounding mode will give 255*0.5f=0x80, not 0x7F as VC would force it to by resetting rounding mode
00137     // dont think this makes much difference
00138 
00139     __asm {
00140         push ebx   ; want to save this in case this fn is inlined
00141         push ecx
00142         mov ecx, cColorf
00143         fild tempcolorval
00144         fld DWORD PTR [ecx]
00145         fmul ST(0),ST(1)
00146         fistp tempcolorval  ; no way to store directly to int register
00147         mov eax, tempcolorval
00148         shl eax, 16
00149 
00150         fld DWORD PTR [ecx+4]  ;grn
00151         fmul ST(0),ST(1)
00152         fistp tempcolorval
00153         mov ebx,tempcolorval
00154         shl ebx, 8
00155         or eax,ebx
00156 
00157         fld DWORD PTR [ecx+8]  ;blue
00158         fmul ST(0),ST(1)
00159         fistp tempcolorval
00160         or eax,tempcolorval
00161 
00162         fld DWORD PTR [ecx+12] ;alpha
00163         fmul ST(0),ST(1)
00164         fistp tempcolorval
00165         ; simulate pop 255.0 off FP stack w/o store, mark top as empty and increment stk ptr
00166         ffree ST(0)
00167         fincstp
00168         mov ebx,tempcolorval
00169         shl ebx, 24
00170         or eax,ebx
00171         mov d3dcolor,eax
00172         pop ecx
00173         pop ebx
00174     }
00175 
00176    //   dxgsg7_cat.debug() << (void*)d3dcolor << endl;
00177    return d3dcolor;
00178 #else //!_X86_
00179    return MY_D3DRGBA(cColorf[0], cColorf[1], cColorf[2], cColorf[3]);
00180 #endif //!_X86_
00181 }
00182 #ifdef _DEBUG
00183 void
00184 dbgPrintVidMem(LPDIRECTDRAW7 pDD, LPDDSCAPS2 lpddsCaps,const char *pMsg) {
00185   DWORD dwTotal,dwFree;
00186   HRESULT hr;
00187 
00188  //  These Caps bits arent allowed to be specified when calling GetAvailVidMem.
00189  //  They don't affect surface allocation in a vram heap.
00190 
00191 #define AVAILVIDMEM_BADCAPS  (DDSCAPS_BACKBUFFER   | \
00192                               DDSCAPS_FRONTBUFFER  | \
00193                               DDSCAPS_COMPLEX      | \
00194                               DDSCAPS_FLIP         | \
00195                               DDSCAPS_OWNDC        | \
00196                               DDSCAPS_PALETTE      | \
00197                               DDSCAPS_SYSTEMMEMORY | \
00198                               DDSCAPS_VISIBLE      | \
00199                               DDSCAPS_WRITEONLY)
00200 
00201   DDSCAPS2 ddsCaps = *lpddsCaps;
00202   ddsCaps.dwCaps &= ~(AVAILVIDMEM_BADCAPS);  // turn off the bad caps
00203   //  ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; done internally by DX anyway
00204   
00205   if(FAILED(  hr = pDD->GetAvailableVidMem(&ddsCaps,&dwTotal,&dwFree))) {
00206     wdxdisplay7_cat.debug() << "GetAvailableVidMem failed : result = " << ConvD3DErrorToString(hr) << endl;
00207     exit(1);
00208   }
00209 
00210   // Write a debug message to the console reporting the texture memory.
00211   char tmpstr[100],tmpstr2[100];
00212   sprintf(tmpstr,"%.4g",dwTotal/1000000.0);
00213   sprintf(tmpstr2,"%.4g",dwFree/1000000.0);
00214   if(wdxdisplay7_cat.is_debug())
00215     wdxdisplay7_cat.debug() << "AvailableVidMem before creating "<< pMsg << ",(megs) total: " << tmpstr << "  free:" << tmpstr2 <<endl;
00216 }
00217 #endif
00218 
00219 void DXGraphicsStateGuardian7::
00220 set_color_clear_value(const Colorf& value) {
00221   _color_clear_value = value;
00222   _d3dcolor_clear_value =  Colorf_to_D3DCOLOR(value);
00223 }
00224 
00225 ////////////////////////////////////////////////////////////////////
00226 //     Function: DXGraphicsStateGuardian7::Constructor
00227 //       Access: Public
00228 //  Description:
00229 ////////////////////////////////////////////////////////////////////
00230 DXGraphicsStateGuardian7::
00231 DXGraphicsStateGuardian7(const FrameBufferProperties &properties) :
00232   GraphicsStateGuardian(properties) 
00233 {
00234     // allocate local buffers used during rendering
00235 
00236     GraphicsStateGuardian::reset();
00237 
00238     _pScrn = NULL;
00239     _pCurFvfBufPtr = NULL;
00240     _pFvfBufBasePtr = new BYTE[VERT_BUFFER_SIZE];  // allocate storage for vertex info.
00241     _index_buf = new WORD[D3DMAXNUMVERTICES];  // allocate storage for vertex index info.
00242     _dx_ready = false;
00243     _overlay_windows_supported = false;
00244 
00245 //    _pScrn->pddsPrimary = _pScrn->pddsZBuf = _pScrn->pddsBack = NULL;
00246 //    _pDD = NULL;
00247 //    _pScrn->pD3DDevice = NULL;
00248 
00249     // non-dx obj values inited here should not change if resize is
00250     // called and dx objects need to be recreated (otherwise they
00251     // belong in dx_init, with other renderstate
00252 
00253     ZeroMemory(&matIdentity,sizeof(D3DMATRIX));
00254     matIdentity._11 = matIdentity._22 = matIdentity._33 = matIdentity._44 = 1.0f;
00255 
00256     // All implementations have the following buffers.
00257     _buffer_mask = (RenderBuffer::T_color |
00258                     RenderBuffer::T_depth |
00259                     RenderBuffer::T_back
00260 //                  RenderBuffer::T_stencil |
00261 //                  RenderBuffer::T_accum
00262                     );
00263 
00264     //   this is incorrect for general mono displays, need both right and left flags set.
00265     //   stereo has not been handled yet for dx
00266     //    _buffer_mask &= ~RenderBuffer::T_right;
00267 
00268     _cur_read_pixel_buffer=RenderBuffer::T_front;
00269 
00270     set_color_clear_value(_color_clear_value);
00271 }
00272 
00273 ////////////////////////////////////////////////////////////////////
00274 //     Function: DXGraphicsStateGuardian7::Destructor
00275 //       Access: Public
00276 //  Description:
00277 ////////////////////////////////////////////////////////////////////
00278 DXGraphicsStateGuardian7::
00279 ~DXGraphicsStateGuardian7() {
00280 /*   
00281     if(IS_VALID_PTR(_pScrn)) {
00282         assert((_pScrn->pD3DDevice==NULL) || IS_VALID_PTR(_pScrn->pD3DDevice));
00283         _pScrn->pD3DDevice->SetTexture(0, NULL);  // this frees reference to the old texture
00284     }
00285 */
00286     _pCurTexContext = NULL;
00287 
00288     // free_dxgsg_objects() ????????????
00289 
00290     free_pointers();
00291     SAFE_DELETE_ARRAY(_pFvfBufBasePtr)
00292     SAFE_DELETE_ARRAY(_index_buf);
00293 }
00294 
00295 ////////////////////////////////////////////////////////////////////
00296 //     Function: DXGraphicsStateGuardian7::reset
00297 //       Access: Public, Virtual
00298 //  Description: Resets all internal state as if the gsg were newly
00299 //               created.  The GraphicsWindow pointer represents a
00300 //               typical window that might be used for this context;
00301 //               it may be required to set up the frame buffer
00302 //               properly the first time.
00303 ////////////////////////////////////////////////////////////////////
00304 void DXGraphicsStateGuardian7::
00305 reset() {
00306     GraphicsStateGuardian::reset();
00307     dxgsg7_cat.error() << "DXGSG reset() not implemented properly yet!\n";
00308     // delete all the objs too, right?
00309     //dx_init();
00310 }
00311 
00312 void DXGraphicsStateGuardian7::  
00313 set_context(DXScreenData *pNewContextData) {
00314     // dont do copy from window since dx_init sets fields too.
00315     // simpler to keep all of it in one place, so use ptr to window struct
00316 
00317     assert(pNewContextData!=NULL);
00318     _pScrn = pNewContextData;
00319     _pD3DDevice = _pScrn->pD3DDevice;   //copy this one field for speed of deref
00320 }
00321 
00322 // recreate dx objects without modifying gsg state, other than clearing state cache
00323 void DXGraphicsStateGuardian7::
00324 free_dxgsg_objects(void) {
00325     ULONG refcnt;
00326 
00327     free_pointers();
00328 
00329     // dont want a full reset of gsg, just a state clear
00330     set_state(RenderState::make_empty());
00331     // want gsg to pass all state settings through
00332     // we need to reset our internal state guards right here because dx_init() should be called after this,
00333     // which resets all of them to our defaults, and syncs them with the D3DRENDERSTATE
00334 
00335     _dx_ready = false;
00336 
00337     if (_pScrn->pD3DDevice!=NULL) {
00338         _pScrn->pD3DDevice->SetTexture(0,NULL);  // should release this stuff internally anyway
00339         RELEASE(_pScrn->pD3DDevice,dxgsg7,"d3dDevice",RELEASE_DOWN_TO_ZERO);
00340     }
00341 
00342     DeleteAllVideoSurfaces();
00343 
00344     // Release the DDraw and D3D objects used by the app
00345     RELEASE(_pScrn->pddsZBuf,dxgsg7,"zbuffer",false);
00346     RELEASE(_pScrn->pddsBack,dxgsg7,"backbuffer",false);
00347     RELEASE(_pScrn->pddsPrimary,dxgsg7,"primary surface",false);
00348 }
00349 
00350 HRESULT CALLBACK EnumTexFmtsCallback( LPDDPIXELFORMAT pddpf, VOID* param ) {
00351     // wont build if its a member fn, so had to do this stuff
00352 #ifdef USE_TEXFMTVEC
00353     DDPixelFormatVec *pPixFmtVec =  (DDPixelFormatVec *) param;
00354     pPixFmtVec->push_back(*pddpf);
00355 #else
00356     DXGraphicsStateGuardian7 *mystate = (DXGraphicsStateGuardian7 *) param;
00357     assert(mystate->_cNumTexPixFmts < MAX_DX_TEXPIXFMTS);
00358     memcpy( &(mystate->_pTexPixFmts[mystate->_cNumTexPixFmts]), pddpf, sizeof(DDPIXELFORMAT) );
00359     mystate->_cNumTexPixFmts++;
00360 #endif
00361     return DDENUMRET_OK;
00362 }
00363 
00364 ////////////////////////////////////////////////////////////////////
00365 //     Function: DXGraphicsStateGuardian7::reset
00366 //       Access: Public, Virtual
00367 //  Description: Handles initialization which assumes that DX has already been
00368 //               set up.
00369 ////////////////////////////////////////////////////////////////////
00370 void DXGraphicsStateGuardian7::
00371 dx_init( void) {
00372 /*
00373          LPDIRECTDRAW7     context,
00374           LPDIRECTDRAWSURFACE7  pri,
00375           LPDIRECTDRAWSURFACE7  back,
00376           LPDIRECTDRAWSURFACE7  zbuf,
00377           LPDIRECT3D7          pD3D,
00378           LPDIRECT3DDEVICE7    pDevice,
00379           RECT viewrect) */
00380     assert(_pScrn->pDD!=NULL);
00381     assert(_pScrn->pD3D!=NULL);
00382     assert(_pScrn->pD3DDevice!=NULL);
00383     assert(_pScrn->pddsPrimary!=NULL);
00384     assert(_pScrn->pddsBack!=NULL);
00385 
00386 //    _pDD=_pScrn->pDD;  // save for speed of access
00387 //    _pCurD3DDevice = _pScrn->pD3DDevice;
00388 
00389 /*    _pDD = context;
00390     _pScrn->pddsPrimary = pri;
00391     _pScrn->pddsBack = back;
00392     _pScrn->pddsZBuf = zbuf;
00393     _pScrn->pD3D = pD3D;
00394     _pScrn->pD3DDevice = pDevice;
00395     _view_rect = viewrect;
00396 */
00397 
00398     ZeroMemory(&_lmodel_ambient,sizeof(Colorf));
00399     _pScrn->pD3DDevice->SetRenderState( D3DRENDERSTATE_AMBIENT, 0x0);
00400 
00401     _clip_plane_bits = 0;
00402     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPLANEENABLE , 0x0);
00403 
00404     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, true);
00405     _clipping_enabled = true;
00406 
00407     _CurShadeMode =  D3DSHADE_FLAT;
00408     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, _CurShadeMode);
00409 
00410     _depth_write_enabled = true;
00411     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, _depth_write_enabled);
00412 
00413     // need to free these properly
00414 #ifndef USE_TEXFMTVEC
00415     _cNumTexPixFmts = 0;
00416     _pTexPixFmts = NULL;
00417 #endif
00418     _pCurTexContext = NULL;
00419 
00420     // none of these are implemented
00421     //_multisample_enabled = false;
00422     //_point_smooth_enabled = false;
00423 
00424     _line_smooth_enabled = false;
00425     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_EDGEANTIALIAS, false);
00426 
00427     _color_material_enabled = false;
00428     _normals_enabled = false;
00429 
00430     _depth_test_enabled = D3DZB_FALSE;
00431     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
00432 
00433     _blend_enabled = false;
00434     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, (DWORD)_blend_enabled);
00435 
00436     _pScrn->pD3DDevice->GetRenderState(D3DRENDERSTATE_SRCBLEND, (DWORD*)&_blend_source_func);
00437     _pScrn->pD3DDevice->GetRenderState(D3DRENDERSTATE_DESTBLEND, (DWORD*)&_blend_dest_func);
00438 
00439     _fog_enabled = false;
00440     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, _fog_enabled);
00441 
00442     _current_projection_mat = LMatrix4f::ident_mat();
00443     _projection_mat_stack_count = 0;
00444     _has_scene_graph_color = false;
00445 
00446 //  GL stuff that hasnt been translated to DX
00447 //    _scissor_enabled = false;
00448 //    _multisample_alpha_one_enabled = false;
00449 //    _multisample_alpha_mask_enabled = false;
00450 //    _line_width = 1.0f;
00451 //    _point_size = 1.0f;
00452 
00453     assert(_pScrn->pddsBack!=NULL);  // dxgsg7 is always double-buffered right now
00454 
00455 #ifdef COUNT_DRAWPRIMS
00456      global_pD3DDevice = pDevice;
00457 #endif
00458     _pCurrentGeomContext = NULL;
00459     _bDrawPrimDoSetupVertexBuffer = false;
00460 
00461     _last_testcooplevel_result = S_OK;
00462 
00463     // only 1 channel on dx currently
00464     //_panda_gfx_channel = _win->get_channel(0);
00465 
00466     HRESULT hr;
00467 
00468 #ifdef USE_TEXFMTVEC
00469     assert(_pScrn->TexPixFmts.size()==0);
00470 
00471     if(FAILED(hr=_pScrn->pD3DDevice->EnumTextureFormats(EnumTexFmtsCallback, &_pScrn->TexPixFmts))) {
00472 #else
00473     _pTexPixFmts = new DDPIXELFORMAT[MAX_DX_TEXPIXFMTS];
00474     _cNumTexPixFmts = 0;
00475     assert(_pTexPixFmts!=NULL);
00476 
00477     if(FAILED(hr=_pScrn->pD3DDevice->EnumTextureFormats(EnumTexFmtsCallback, this))) {
00478 #endif
00479         if(hr==D3DERR_TEXTURE_NO_SUPPORT) {
00480             dxgsg7_cat.error() << "EnumTextureFormats indicates No Texturing Support on this HW!, exiting...\n";
00481             exit(1);
00482         } else {
00483             dxgsg7_cat.error() << "EnumTextureFormats failed! hr = " << ConvD3DErrorToString(hr) << endl;
00484         }
00485     }
00486 
00487     DX_DECLARE_CLEAN(DDCAPS,ddCaps);
00488     if (FAILED(hr = _pScrn->pDD->GetCaps(&ddCaps,NULL))) {
00489         dxgsg7_cat.fatal() << "GetCaps failed on DDraw! hr = " << ConvD3DErrorToString(hr) << "\n";
00490         exit(1);
00491     }
00492 
00493     // s3 virge drivers sometimes give crap values for these
00494     if(_pScrn->D3DDevDesc.dwMaxTextureWidth==0)
00495        _pScrn->D3DDevDesc.dwMaxTextureWidth=256;
00496 
00497     if(_pScrn->D3DDevDesc.dwMaxTextureHeight==0)
00498        _pScrn->D3DDevDesc.dwMaxTextureHeight=256;
00499 
00500 //  shouldve already been set
00501 //    sc_bIsTNLDevice = (IsEqualGUID(_pScrn->D3DDevDesc.deviceGUID,IID_IDirect3DTnLHalDevice)!=0);
00502 
00503     if ((dx_decal_type==GDT_offset) && !(_pScrn->D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBIAS)) {
00504 #ifdef _DEBUG
00505         // dx7 doesnt support PLANEMASK renderstate
00506 #if(DIRECT3D_VERSION < 0x700)
00507         dxgsg7_cat.debug() << "dx-decal-type 'offset' not supported by hardware, switching to decal masking\n";
00508 #else
00509         dxgsg7_cat.debug() << "dx-decal-type 'offset' not supported by hardware, switching to decal double-draw blend-based masking\n";
00510 #endif
00511 #endif
00512 #if(DIRECT3D_VERSION < 0x700)
00513         dx_decal_type = GDT_mask;
00514 #else
00515         dx_decal_type = GDT_blend;
00516 #endif
00517     }
00518 
00519 #ifdef DISABLE_POLYGON_OFFSET_DECALING
00520 #ifdef _DEBUG
00521     dxgsg7_cat.spam() << "polygon-offset decaling disabled in dxgsg7, switching to double-draw decaling\n";
00522 #endif
00523 
00524 #if(DIRECT3D_VERSION < 0x700)
00525     dx_decal_type = GDT_mask;
00526 #else
00527     dx_decal_type = GDT_blend;
00528 #endif
00529 #endif
00530 
00531     if ((dx_decal_type==GDT_mask) && !(_pScrn->D3DDevDesc.dpcTriCaps.dwMiscCaps & D3DPMISCCAPS_MASKPLANES)) {
00532 #ifdef _DEBUG
00533         dxgsg7_cat.debug() << "No hardware support for colorwrite disabling, switching to dx-decal-type 'mask' to 'blend'\n";
00534 #endif
00535         dx_decal_type = GDT_blend;
00536     }
00537 
00538     if (((dx_decal_type==GDT_blend)||(dx_decal_type==GDT_mask)) && !(_pScrn->D3DDevDesc.dpcTriCaps.dwMiscCaps & D3DPMISCCAPS_MASKZ)) {
00539         dxgsg7_cat.error() << "dx-decal-type mask impossible to implement, no hardware support for Z-masking, decals will not appear correctly!\n";
00540     }
00541 
00542 //#define REQUIRED_BLENDCAPS (D3DPBLENDCAPS_ZERO|D3DPBLENDCAPS_ONE|D3DPBLENDCAPS_SRCCOLOR|D3DPBLENDCAPS_INVSRCCOLOR| \
00543 //                            D3DPBLENDCAPS_SRCALPHA|D3DPBLENDCAPS_INVSRCALPHA | D3DPBLENDCAPS_DESTALPHA|D3DPBLENDCAPS_INVDESTALPHA|D3DPBLENDCAPS_DESTCOLOR|D3DPBLENDCAPS_INVDESTCOLOR)
00544 // voodoo3 doesnt support commented out ones, & we dont need them now
00545 
00546 #define REQUIRED_BLENDCAPS (D3DPBLENDCAPS_ZERO|D3DPBLENDCAPS_ONE|  /*D3DPBLENDCAPS_SRCCOLOR|D3DPBLENDCAPS_INVSRCCOLOR| */ \
00547                             D3DPBLENDCAPS_SRCALPHA|D3DPBLENDCAPS_INVSRCALPHA /* | D3DPBLENDCAPS_DESTALPHA|D3DPBLENDCAPS_INVDESTALPHA|D3DPBLENDCAPS_DESTCOLOR|D3DPBLENDCAPS_INVDESTCOLOR*/)
00548 
00549     if (((_pScrn->D3DDevDesc.dpcTriCaps.dwSrcBlendCaps & REQUIRED_BLENDCAPS)!=REQUIRED_BLENDCAPS) ||
00550         ((_pScrn->D3DDevDesc.dpcTriCaps.dwDestBlendCaps & REQUIRED_BLENDCAPS)!=REQUIRED_BLENDCAPS)) {
00551         dxgsg7_cat.error() << "device is missing alpha blending capabilities, blending may not work correctly: SrcBlendCaps: 0x"<< (void*) _pScrn->D3DDevDesc.dpcTriCaps.dwSrcBlendCaps << "  DestBlendCaps: "<< (void*) _pScrn->D3DDevDesc.dpcTriCaps.dwDestBlendCaps << endl;
00552     }
00553 
00554     if (!(_pScrn->D3DDevDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_TRANSPARENCY)) {
00555         dxgsg7_cat.error() << "device is missing texture transparency capability, transparency may not work correctly!  TextureCaps: 0x"<< (void*) _pScrn->D3DDevDesc.dpcTriCaps.dwTextureCaps << endl;
00556     }
00557 
00558     // just require trilinear.  if it can do that, it can probably do all the lesser point-sampling variations too
00559 #define REQUIRED_TEXFILTERCAPS (D3DPTFILTERCAPS_MAGFLINEAR |  D3DPTFILTERCAPS_MINFLINEAR | D3DPTFILTERCAPS_LINEAR)
00560     if ((_pScrn->D3DDevDesc.dpcTriCaps.dwTextureFilterCaps & REQUIRED_TEXFILTERCAPS)!=REQUIRED_TEXFILTERCAPS) {
00561         dxgsg7_cat.error() << "device is missing texture bilinear filtering capability, textures may appear blocky!  TextureFilterCaps: 0x"<< (void*) _pScrn->D3DDevDesc.dpcTriCaps.dwTextureFilterCaps << endl;
00562     }
00563 #define REQUIRED_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_LINEARMIPLINEAR)
00564 
00565     if (!(ddCaps.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) {
00566         dxgsg7_cat.debug() << "device does not have mipmap texturing filtering capability!   TextureFilterCaps: 0x"<< (void*) _pScrn->D3DDevDesc.dpcTriCaps.dwTextureFilterCaps << endl;
00567         dx_ignore_mipmaps = TRUE;
00568     } else if ((_pScrn->D3DDevDesc.dpcTriCaps.dwTextureFilterCaps & REQUIRED_MIPMAP_TEXFILTERCAPS)!=REQUIRED_MIPMAP_TEXFILTERCAPS) {
00569         dxgsg7_cat.debug() << "device is missing tri-linear mipmap filtering capability, texture mipmaps may not supported! TextureFilterCaps: 0x"<< (void*) _pScrn->D3DDevDesc.dpcTriCaps.dwTextureFilterCaps << endl;
00570     }
00571 
00572 #define REQUIRED_TEXBLENDCAPS (D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2)
00573     if ((_pScrn->D3DDevDesc.dwTextureOpCaps & REQUIRED_TEXBLENDCAPS)!=REQUIRED_TEXBLENDCAPS) {
00574         dxgsg7_cat.error() << "device is missing some required texture blending capabilities, texture blending may not work properly! TextureOpCaps: 0x"<< (void*) _pScrn->D3DDevDesc.dwTextureOpCaps << endl;
00575     }
00576 
00577     if(_pScrn->D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGTABLE) {
00578         // watch out for drivers that emulate per-pixel fog with per-vertex fog (Riva128, Matrox Millen G200)
00579         // some of these require gouraud-shading to be set to work, as if you were using vertex fog
00580         _doFogType=PerPixelFog;
00581     } else {
00582         // every card is going to have vertex fog, since it's implemented in d3d runtime
00583         assert((_pScrn->D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGVERTEX )!=0);
00584 
00585         // vtx fog may look crappy if you have large polygons in the foreground and they get clipped,
00586         // so you may want to disable it
00587 
00588         if(dx_no_vertex_fog) {
00589             _doFogType = None;
00590         } else {
00591             _doFogType = PerVertexFog;
00592 
00593             // range-based fog only works with vertex fog in dx7/8
00594             if(dx_use_rangebased_fog && (_pScrn->D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGRANGE))
00595                 _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_RANGEFOGENABLE, true);
00596         }
00597     }
00598 
00599     SetRect(&_pScrn->clip_rect, 0,0,0,0);  // no clip rect set
00600 
00601     // Lighting, let's turn it off by default
00602     _lighting_enabled = false;
00603     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, _lighting_enabled);
00604 
00605     // turn on dithering if the rendertarget is < 8bits/color channel
00606     DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd_back);
00607     _pScrn->pddsBack->GetSurfaceDesc(&ddsd_back);
00608     _dither_enabled = (!dx_no_dithering) && ((ddsd_back.ddpfPixelFormat.dwRGBBitCount < 24) &&
00609                        (_pScrn->D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_DITHER));
00610     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, _dither_enabled);
00611 
00612     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPING,true);
00613 
00614     // Stencil test is off by default
00615     _stencil_test_enabled = false;
00616     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_STENCILENABLE, _stencil_test_enabled);
00617 
00618     // Antialiasing.
00619     enable_line_smooth(false);
00620 //  enable_multisample(true);
00621 
00622     _current_fill_mode = RenderModeAttrib::M_filled;
00623     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID);
00624 
00625     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1);
00626 
00627     if(dx_auto_normalize_lighting)
00628          _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_NORMALIZENORMALS, true);
00629 
00630     // initial clip rect
00631     SetRect(&_pScrn->clip_rect, 0,0,0,0);     // no clip rect set
00632 
00633     // must do SetTSS here because redundant states are filtered out by our code based on current values above, so
00634     // initial conditions must be correct
00635 
00636     _CurTexBlendMode = TextureApplyAttrib::M_modulate;
00637     SetTextureBlendMode(_CurTexBlendMode,FALSE);
00638     _texturing_enabled = false;
00639     _pScrn->pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE);  // disables texturing
00640 
00641     // Init more Texture State
00642     _CurTexMagFilter=(D3DTEXTUREMAGFILTER) 0x0;
00643     _CurTexMinFilter=(D3DTEXTUREMINFILTER) 0x0;
00644     _CurTexMipFilter=(D3DTEXTUREMIPFILTER) 0x0;
00645     _CurTexWrapModeU=_CurTexWrapModeV=Texture::WM_clamp;
00646     _CurTexAnisoDegree=1;
00647 
00648     // this code must match apply_texture() code for states above
00649     // so DX TSS renderstate matches dxgsg7 state
00650 
00651     _pScrn->pD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_POINT);
00652     _pScrn->pD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFP_POINT);
00653     _pScrn->pD3DDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, D3DTFP_NONE);
00654     _pScrn->pD3DDevice->SetTextureStageState(0, D3DTSS_MAXANISOTROPY,_CurTexAnisoDegree);
00655     _pScrn->pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSU,get_texture_wrap_mode(_CurTexWrapModeU));
00656     _pScrn->pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESSV,get_texture_wrap_mode(_CurTexWrapModeV));
00657 
00658 #ifdef _DEBUG
00659     if ((_pScrn->D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS) &&
00660         (dx_global_miplevel_bias!=0.0f)) {
00661         _pScrn->pD3DDevice->SetTextureStageState(0, D3DTSS_MIPMAPLODBIAS, *((LPDWORD) (&dx_global_miplevel_bias)) );
00662     }
00663 #endif
00664 
00665     if (dx_full_screen_antialiasing) {
00666       if(_pScrn->D3DDevDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT) {
00667         _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_ANTIALIAS,D3DANTIALIAS_SORTINDEPENDENT);
00668         if(dxgsg7_cat.is_debug())
00669             dxgsg7_cat.debug() << "enabling full-screen anti-aliasing\n";
00670       } else {
00671         if(dxgsg7_cat.is_debug())
00672             dxgsg7_cat.debug() << "device doesnt support full-screen anti-aliasing\n";
00673       }
00674     }
00675 
00676 #ifndef NDEBUG
00677     if(dx_force_backface_culling!=0) {
00678       if((dx_force_backface_culling > 0) &&
00679          (dx_force_backface_culling < D3DCULL_FORCE_DWORD)) {
00680              _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, dx_force_backface_culling);
00681       } else {
00682           dx_force_backface_culling=0;
00683           if(dxgsg7_cat.is_debug())
00684               dxgsg7_cat.debug() << "error, invalid value for dx-force-backface-culling\n";
00685       }
00686     }
00687     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, dx_force_backface_culling);
00688 #else
00689     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
00690 #endif
00691 
00692     _alpha_func = D3DCMP_ALWAYS;
00693     _alpha_func_refval = 1.0f;
00694     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, _alpha_func);
00695     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHAREF, (_alpha_func_refval*255.0f));
00696     _alpha_test_enabled = false;
00697     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, _alpha_test_enabled);
00698 
00699     // Make sure the DX state matches all of our initial attribute states.
00700     CPT(RenderAttrib) dta = DepthTestAttrib::make(DepthTestAttrib::M_less);
00701     CPT(RenderAttrib) dwa = DepthWriteAttrib::make(DepthWriteAttrib::M_on);
00702     CPT(RenderAttrib) cfa = CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise);
00703 
00704     dta->issue(this);
00705     dwa->issue(this);
00706     cfa->issue(this);
00707 }
00708 
00709 ////////////////////////////////////////////////////////////////////
00710 //     Function: DXGraphicsStateGuardian7::do_clear
00711 //       Access: Public, Virtual
00712 //  Description: Clears all of the indicated buffers to their assigned
00713 //               colors.
00714 ////////////////////////////////////////////////////////////////////
00715 void DXGraphicsStateGuardian7::
00716 do_clear(const RenderBuffer &buffer) {
00717   //    DO_PSTATS_STUFF(PStatTimer timer(_win->_clear_pcollector));
00718 
00719     nassertv(buffer._gsg == this);
00720     int buffer_type = buffer._buffer_type;
00721 
00722     int flags = 0;
00723 
00724     if (buffer_type & RenderBuffer::T_depth) {
00725         flags |=  D3DCLEAR_ZBUFFER;
00726         assert(_pScrn->pddsZBuf!=NULL);
00727     }
00728     if (buffer_type & RenderBuffer::T_back)       //set appropriate flags
00729         flags |=  D3DCLEAR_TARGET;
00730     if (buffer_type & RenderBuffer::T_stencil)
00731         flags |=  D3DCLEAR_STENCIL;
00732 
00733     HRESULT  hr = _pScrn->pD3DDevice->Clear(0, NULL, flags, _d3dcolor_clear_value,
00734                                     (D3DVALUE) _depth_clear_value, (DWORD)_stencil_clear_value);
00735     if (hr != DD_OK)
00736         dxgsg7_cat.error() << "clear_buffer failed:  Clear returned " << ConvD3DErrorToString(hr) << endl;
00737     /*  The following line will cause the background to always clear to a medium red
00738     _color_clear_value[0] = .5;
00739     /*  The following lines will cause the background color to cycle from black to red.
00740     _color_clear_value[0] += .001;
00741      if (_color_clear_value[0] > 1.0f) _color_clear_value[0] = 0.0f;
00742      */
00743 }
00744 
00745 ////////////////////////////////////////////////////////////////////
00746 //     Function: DXGraphicsStateGuardian7::prepare_display_region
00747 //       Access: Public, Virtual
00748 //  Description: Prepare a display region for rendering (set up
00749 //       scissor region and viewport)
00750 ////////////////////////////////////////////////////////////////////
00751 void DXGraphicsStateGuardian7::
00752 prepare_display_region() {
00753   if (_current_display_region == (DisplayRegion*)0L) {
00754     dxgsg7_cat.error()
00755       << "Invalid NULL display region in prepare_display_region()\n";
00756 
00757   } else if (_current_display_region != _actual_display_region) {
00758     _actual_display_region = _current_display_region;
00759 
00760     int l, b, w, h;
00761     _actual_display_region->get_region_pixels(l, b, w, h);
00762 
00763     // Create the viewport
00764     D3DVIEWPORT7 vp = {
00765       l, b,
00766       w, h, 
00767       0.0f, 1.0f
00768     };
00769     HRESULT hr = _pScrn->pD3DDevice->SetViewport(&vp);
00770     if (FAILED(hr)) {
00771       dxgsg7_cat.error()
00772         << "SetViewport(" << l << ", " << b << ", " << w << ", " << h
00773         << ") failed : result = " << ConvD3DErrorToString(hr)
00774         << endl;
00775     }
00776     
00777     // Note: for DX9, also change scissor clipping state here
00778   }
00779 }
00780 
00781 ////////////////////////////////////////////////////////////////////
00782 //     Function: DXGraphicsStateGuardian7::prepare_lens
00783 //       Access: Public, Virtual
00784 //  Description: Makes the current lens (whichever lens was most
00785 //               recently specified with push_lens()) active, so that
00786 //               it will transform future rendered geometry.  Normally
00787 //               this is only called from the draw process, and
00788 //               usually it is called immediately after a call to
00789 //               push_lens().
00790 //
00791 //               The return value is true if the lens is acceptable,
00792 //               false if it is not.
00793 ////////////////////////////////////////////////////////////////////
00794 bool DXGraphicsStateGuardian7::
00795 prepare_lens() {
00796   if (_current_lens == (Lens *)NULL) {
00797     return false;
00798   }
00799 
00800   if (!_current_lens->is_linear()) {
00801     return false;
00802   }
00803 
00804   const LMatrix4f &projection_mat = _current_lens->get_projection_mat();
00805 
00806   // The projection matrix must always be left-handed Y-up internally,
00807   // even if our coordinate system of choice is otherwise.
00808   LMatrix4f new_projection_mat =
00809     LMatrix4f::convert_mat(CS_yup_left, _current_lens->get_coordinate_system()) *
00810     projection_mat;
00811 
00812   HRESULT hr;
00813   hr = _pScrn->pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION,
00814                                      (LPD3DMATRIX)new_projection_mat.get_data());
00815   return SUCCEEDED(hr);
00816 }
00817 
00818 #ifndef NO_MULTIPLE_DISPLAY_REGIONS
00819 ////////////////////////////////////////////////////////////////////
00820 //     Function: set_clipper
00821 //       Access:
00822 //  Description: Useless in DX at the present time
00823 ////////////////////////////////////////////////////////////////////
00824 void DXGraphicsStateGuardian7::set_clipper(RECT cliprect) {
00825 
00826     LPDIRECTDRAWCLIPPER Clipper;
00827     HRESULT result;
00828 
00829     // For windowed mode, the clip region is associated with the window,
00830     // and DirectX does not allow you to create clip regions.
00831     if (_win->is_fullscreen()) return;
00832 
00833     /* The cliprect we receive is normalized so that (0,0) means the upper left of
00834        the client portion of the window.
00835         At least, I think that's true, and the following code assumes that.
00836         So we must adjust the clip region by offsetting it to the origin of the
00837         view rectangle.
00838     */
00839     clip_rect = cliprect;       // store the normalized clip rect
00840     cliprect.left += _view_rect.left;
00841     cliprect.right += _view_rect.left;
00842     cliprect.top += _view_rect.top;
00843     cliprect.bottom += _view_rect.top;
00844     RGNDATA *rgn_data = (RGNDATA *)malloc(sizeof(RGNDATAHEADER) + sizeof(RECT));
00845     HRGN hrgn = CreateRectRgn(cliprect.left, cliprect.top, cliprect.right, cliprect.bottom);
00846     GetRegionData(hrgn, sizeof(RGNDATAHEADER) + sizeof(RECT), rgn_data);
00847 
00848     if (_pScrn->pddsPrimary->GetClipper(&Clipper) != DD_OK) {
00849         result = _pScrn->pDD->CreateClipper(0, &Clipper, NULL);
00850         result = Clipper->SetClipList(rgn_data, 0);
00851         result = _pScrn->pddsPrimary->SetClipper(Clipper);
00852     } else {
00853         result = Clipper->SetClipList(rgn_data, 0 );
00854         if (result == DDERR_CLIPPERISUSINGHWND) {
00855             result = _pScrn->pddsPrimary->SetClipper(NULL);
00856             result = _pScrn->pDD->CreateClipper(0, &Clipper, NULL);
00857             result = Clipper->SetClipList(rgn_data, 0 ) ;
00858             result = _pScrn->pddsPrimary->SetClipper(Clipper);
00859         }
00860     }
00861     free(rgn_data);
00862     DeleteObject(hrgn);
00863 }
00864 #endif
00865 
00866 #if defined(_DEBUG) || defined(COUNT_DRAWPRIMS)
00867 typedef enum {DrawPrim,DrawIndexedPrim,DrawPrimStrided} DP_Type;
00868 static const char *DP_Type_Strs[3] = {"DrawPrimitive","DrawIndexedPrimitive","DrawPrimitiveStrided"};
00869 
00870 void INLINE TestDrawPrimFailure(DP_Type dptype,HRESULT hr,LPDIRECTDRAW7 pDD,DWORD nVerts,DWORD nTris) {
00871         if(FAILED(hr)) {
00872             // loss of exclusive mode is not a real DrawPrim problem, ignore it
00873             HRESULT testcooplvl_hr = pDD->TestCooperativeLevel();
00874             if((testcooplvl_hr != DDERR_NOEXCLUSIVEMODE)||(testcooplvl_hr != DDERR_EXCLUSIVEMODEALREADYSET)) {
00875                 dxgsg7_cat.fatal() << DP_Type_Strs[dptype] << "() failed: result = " << ConvD3DErrorToString(hr) << endl;
00876                 exit(1);
00877             }
00878         }
00879 
00880         CountDPs(nVerts,nTris);
00881 }
00882 #else
00883 #define TestDrawPrimFailure(a,b,c,nVerts,nTris) CountDPs(nVerts,nTris);
00884 #endif
00885 
00886 ////////////////////////////////////////////////////////////////////
00887 //     Function: DXGraphicsStateGuardian7::report_texmgr_stats
00888 //       Access: Protected
00889 //  Description: Reports the DX texture manager's activity to PStats.
00890 ////////////////////////////////////////////////////////////////////
00891 void DXGraphicsStateGuardian7::
00892 report_texmgr_stats() {
00893 
00894 #if defined(DO_PSTATS)||defined(PRINT_TEXSTATS)
00895 
00896   HRESULT hr;
00897   DWORD dwTexTotal,dwTexFree,dwVidTotal,dwVidFree;
00898 
00899 #ifndef PRINT_TEXSTATS
00900   if (_total_texmem_pcollector.is_active())
00901 #endif
00902   {
00903       DDSCAPS2 ddsCaps;
00904 
00905       ZeroMemory(&ddsCaps,sizeof(ddsCaps));
00906 
00907       ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
00908       if(FAILED(  hr = _pScrn->pDD->GetAvailableVidMem(&ddsCaps,&dwVidTotal,&dwVidFree))) {
00909             dxgsg7_cat.debug() << "report_texmgr GetAvailableVidMem for VIDMEM failed : result = " << ConvD3DErrorToString(hr) << endl;
00910             exit(1);
00911       }
00912 
00913       ddsCaps.dwCaps = DDSCAPS_TEXTURE;
00914       if(FAILED(  hr = _pScrn->pDD->GetAvailableVidMem(&ddsCaps,&dwTexTotal,&dwTexFree))) {
00915             dxgsg7_cat.debug() << "report_texmgr GetAvailableVidMem for TEXTURE failed : result = " << ConvD3DErrorToString(hr) << endl;
00916             exit(1);
00917       }
00918   }
00919 
00920   D3DDEVINFO_TEXTUREMANAGER tminfo;
00921   ZeroMemory(&tminfo,sizeof(D3DDEVINFO_TEXTUREMANAGER));
00922 
00923   if(!bTexStatsRetrievalImpossible) {
00924       hr = _pScrn->pD3DDevice->GetInfo(D3DDEVINFOID_TEXTUREMANAGER,&tminfo,sizeof(D3DDEVINFO_TEXTUREMANAGER));
00925       if (hr!=D3D_OK) {
00926           if (hr==S_FALSE) {
00927               static int PrintedMsg=2;
00928               if(PrintedMsg>0) {
00929                   if(dxgsg7_cat.is_debug())
00930                     dxgsg7_cat.debug() << " ************ texstats GetInfo() requires debug DX DLLs to be installed!!  ***********\n";
00931                   ZeroMemory(&tminfo,sizeof(D3DDEVINFO_TEXTUREMANAGER));
00932                   bTexStatsRetrievalImpossible=true;
00933               }
00934           } else {
00935               dxgsg7_cat.error() << "d3ddev->GetInfo(TEXTUREMANAGER) failed to get tex stats: result = " << ConvD3DErrorToString(hr) << endl;
00936               return;
00937           }
00938       }
00939   }
00940 
00941 #ifdef PRINT_TEXSTATS
00942     char tmpstr1[50],tmpstr2[50],tmpstr3[50],tmpstr4[50];
00943     sprintf(tmpstr1,"%.4g",dwVidTotal/1000000.0);
00944     sprintf(tmpstr2,"%.4g",dwVidFree/1000000.0);
00945     sprintf(tmpstr3,"%.4g",dwTexTotal/1000000.0);
00946     sprintf(tmpstr4,"%.4g",dwTexFree/1000000.0);
00947     dxgsg7_cat.debug() << "\nAvailableVidMem for RenderSurfs: (megs) total: " << tmpstr1 << "  free: " << tmpstr2
00948                       << "\nAvailableVidMem for Textures:    (megs) total: " << tmpstr3 << "  free: " << tmpstr4 << endl;
00949 
00950    if(!bTexStatsRetrievalImpossible) {
00951             dxgsg7_cat.spam()
00952                 << "\n bThrashing:\t" << tminfo.bThrashing
00953                 << "\n NumEvicts:\t" << tminfo.dwNumEvicts
00954                 << "\n NumVidCreates:\t" << tminfo.dwNumVidCreates
00955                 << "\n NumTexturesUsed:\t" << tminfo.dwNumTexturesUsed
00956                 << "\n NumUsedTexInVid:\t" << tminfo.dwNumUsedTexInVid
00957                 << "\n WorkingSet:\t" << tminfo.dwWorkingSet
00958                 << "\n WorkingSetBytes:\t" << tminfo.dwWorkingSetBytes
00959                 << "\n TotalManaged:\t" << tminfo.dwTotalManaged
00960                 << "\n TotalBytes:\t" << tminfo.dwTotalBytes
00961                 << "\n LastPri:\t" << tminfo.dwLastPri << endl;
00962 
00963             D3DDEVINFO_TEXTURING texappinfo;
00964             ZeroMemory(&texappinfo,sizeof(D3DDEVINFO_TEXTURING));
00965             hr = _pScrn->pD3DDevice->GetInfo(D3DDEVINFOID_TEXTURING,&texappinfo,sizeof(D3DDEVINFO_TEXTURING));
00966             if (hr!=D3D_OK) {
00967                 dxgsg7_cat.error() << "GetInfo(TEXTURING) failed : result = " << ConvD3DErrorToString(hr) << endl;
00968                 return;
00969             } else {
00970                 dxgsg7_cat.spam()
00971                 << "\n NumTexLoads:\t" << texappinfo.dwNumLoads
00972                 << "\n ApproxBytesLoaded:\t" << texappinfo.dwApproxBytesLoaded
00973                 << "\n NumPreLoads:\t" << texappinfo.dwNumPreLoads
00974                 << "\n NumSet:\t" << texappinfo.dwNumSet
00975                 << "\n NumCreates:\t" << texappinfo.dwNumCreates
00976                 << "\n NumDestroys:\t" << texappinfo.dwNumDestroys
00977                 << "\n NumSetPriorities:\t" << texappinfo.dwNumSetPriorities
00978                 << "\n NumSetLODs:\t" << texappinfo.dwNumSetLODs
00979                 << "\n NumLocks:\t" << texappinfo.dwNumLocks
00980                 << "\n NumGetDCs:\t" << texappinfo.dwNumGetDCs << endl;
00981             }
00982     }
00983 #endif
00984 
00985 #ifdef DO_PSTATS
00986   // Tell PStats about the state of the texture memory.
00987 
00988   if (_texmgrmem_total_pcollector.is_active()) {
00989       // report zero if no debug dlls, to signal this info is invalid
00990       _texmgrmem_total_pcollector.set_level(tminfo.dwTotalBytes);
00991       _texmgrmem_resident_pcollector.set_level(tminfo.dwWorkingSetBytes);
00992   }
00993 
00994   if (_total_texmem_pcollector.is_active()) {
00995     _total_texmem_pcollector.set_level(dwTexTotal);
00996     _used_texmem_pcollector.set_level(dwTexTotal - dwTexFree);
00997   }
00998 #endif
00999 
01000 #endif
01001 }
01002 
01003 ////////////////////////////////////////////////////////////////////
01004 //     Function: DXGraphicsStateGuardian7::add_to_FVFBuf
01005 //       Access: Private
01006 //  Description: This adds data to the flexible vertex format
01007 ////////////////////////////////////////////////////////////////////
01008 INLINE void DXGraphicsStateGuardian7::
01009 add_to_FVFBuf(void *data,  size_t bytes) {
01010     memcpy(_pCurFvfBufPtr, data, bytes);
01011     _pCurFvfBufPtr += bytes;
01012 }
01013 
01014 // generates slightly fewer instrs
01015 #define add_DWORD_to_FVFBuf(data) { *((DWORD *)_pCurFvfBufPtr) = (DWORD) data;  _pCurFvfBufPtr += sizeof(DWORD);}
01016 
01017 typedef enum {
01018     FlatVerts,IndexedVerts,MixedFmtVerts
01019 } GeomVertFormat;
01020 
01021 #define COPYVERTDATA_2_VERTEXBUFFER(PrimType,NumVertices) {                                     \
01022             DWORD numVertBytes=_pCurFvfBufPtr-_pFvfBufBasePtr;                                  \
01023             memcpy(_pCurrentGeomContext->_pEndofVertData,_pFvfBufBasePtr,numVertBytes);         \
01024             DPInfo dpInfo;                                                                      \
01025             dpInfo.nVerts=NumVertices;                                                          \
01026             dpInfo.primtype=PrimType;                                                           \
01027             _pCurrentGeomContext->_PrimInfo.push_back(dpInfo);                                  \
01028             _pCurrentGeomContext->_num_verts+=dpInfo.nVerts;                                    \
01029             _pCurrentGeomContext->_pEndofVertData+=numVertBytes; }
01030 
01031 
01032 INLINE void DXGraphicsStateGuardian7::
01033 transform_color(Colorf &InColor,D3DCOLOR &OutRGBAColor) {
01034   Colorf transformed
01035     ((InColor[0] * _current_color_scale[0]) + _current_color_offset[0],
01036      (InColor[1] * _current_color_scale[1]) + _current_color_offset[1],
01037      (InColor[2] * _current_color_scale[2]) + _current_color_offset[2],
01038      (InColor[3] * _current_color_scale[3]) + _current_color_offset[3]);
01039   OutRGBAColor = Colorf_to_D3DCOLOR(transformed);
01040 }
01041 
01042 ////////////////////////////////////////////////////////////////////
01043 //     Function: DXGraphicsStateGuardian7::draw_prim_setup
01044 //       Access: Private
01045 //  Description: This adds data to the flexible vertex format
01046 ////////////////////////////////////////////////////////////////////
01047 size_t DXGraphicsStateGuardian7::
01048 draw_prim_setup(const Geom *geom) {
01049     //  Set the flags for the flexible vertex format and compute the bytes
01050     //  required to store a single vertex.
01051     // Assumes _perVertex,_perPrim,_perComp flags are setup prior to entry
01052     // (especially for shademode).  maybe should change this, since we usually
01053     // get attr info anyway)
01054 
01055     #ifdef _DEBUG
01056       assert(geom->get_binding(G_COORD) != G_OFF);
01057     #endif
01058 
01059 #define GET_NEXT_VERTEX(NEXTVERT) { NEXTVERT = geom->get_next_vertex(vi); }
01060 #define GET_NEXT_NORMAL() { p_normal = geom->get_next_normal(ni); }
01061 #define GET_NEXT_TEXCOORD() { p_texcoord = geom->get_next_texcoord(ti); }
01062 #define GET_NEXT_COLOR() {                                                           \
01063     Colorf tempcolor = geom->get_next_color(ci);                                     \
01064     if(_color_transform_enabled == 0) {                                                 \
01065         _curD3Dcolor = Colorf_to_D3DCOLOR(tempcolor);                                \
01066     } else {                                                                         \
01067         transform_color(tempcolor,_curD3Dcolor);                                     \
01068     }}
01069 
01070 ////////
01071 
01072    // this stuff should eventually replace the iterators below
01073    PTA_Vertexf coords;
01074    PTA_ushort vindexes;
01075 
01076    geom->get_coords(coords,vindexes);
01077    if(vindexes!=NULL) {
01078       _pCurCoordIndex = _coordindex_array = &vindexes[0];
01079    } else {
01080       _pCurCoordIndex = _coordindex_array = NULL;
01081    }
01082    _pCurCoord = _coord_array = &coords[0];
01083 
01084    ///////////////
01085 
01086    vi = geom->make_vertex_iterator();
01087    _curFVFflags = D3DFVF_XYZ;
01088    size_t vertex_size = sizeof(D3DVALUE) * 3;
01089 
01090    GeomBindType ColorBinding=geom->get_binding(G_COLOR);
01091    bool bDoColor=(ColorBinding != G_OFF);
01092 
01093    if (bDoColor || _has_scene_graph_color) {
01094         ci = geom->make_color_iterator();
01095         _curFVFflags |= D3DFVF_DIFFUSE;
01096         vertex_size += sizeof(D3DCOLOR);
01097 
01098         if (_has_scene_graph_color) {
01099             if (_scene_graph_color_stale) {
01100               // Compute the D3DCOLOR for the scene graph override color.
01101               if(_color_transform_enabled == 0) {
01102                 _scene_graph_color_D3DCOLOR = Colorf_to_D3DCOLOR(_scene_graph_color);
01103               } else {
01104                 transform_color(_scene_graph_color, _scene_graph_color_D3DCOLOR);
01105               }
01106               _scene_graph_color_stale = false;
01107             }
01108             _curD3Dcolor = _scene_graph_color_D3DCOLOR;  // set primitive color if there is one.
01109             _perVertex &= ~PER_COLOR;
01110             _perPrim &= ~PER_COLOR;
01111             _perComp &= ~PER_COLOR;
01112          } else if(ColorBinding == G_OVERALL){
01113             GET_NEXT_COLOR();
01114 
01115             _perVertex &= ~PER_COLOR;
01116             _perPrim &= ~PER_COLOR;
01117             _perComp &= ~PER_COLOR;
01118         }
01119    }
01120 
01121    if (geom->get_binding(G_NORMAL) != G_OFF) {
01122         ni = geom->make_normal_iterator();
01123         _curFVFflags |= D3DFVF_NORMAL;
01124         vertex_size += sizeof(D3DVALUE) * 3;
01125 
01126         if (geom->get_binding(G_NORMAL) == G_OVERALL)
01127             p_normal = geom->get_next_normal(ni);    // set overall normal if there is one
01128    }
01129 
01130 
01131    GeomBindType TexCoordBinding;
01132    PTA_TexCoordf texcoords;
01133    PTA_ushort tindexes;
01134    geom->get_texcoords(texcoords,TexCoordBinding,tindexes);
01135    if (TexCoordBinding != G_OFF) {
01136        assert(TexCoordBinding == G_PER_VERTEX);
01137 
01138        // used by faster path
01139        if(tindexes!=NULL) {
01140           _pCurTexCoordIndex = _texcoordindex_array = &tindexes[0];
01141        } else {
01142           _pCurTexCoordIndex = _texcoordindex_array = NULL;
01143        }
01144        _pCurTexCoord = _texcoord_array = &texcoords[0];
01145        //////
01146 
01147        ti = geom->make_texcoord_iterator();
01148        _curFVFflags |= (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
01149        vertex_size += sizeof(float) * 2;
01150    }
01151 
01152     // If we have per-vertex colors or normals, we need smooth shading.
01153     // Otherwise we want flat shading for performance reasons.
01154 
01155    // Note on fogging:
01156    // the fogging expression should really be || (_fog_enabled && (_doFogType==PerVertexFog))
01157    // instead of just || (_fog_enabled), since GOURAUD shading should not be required for PerPixel
01158    // fog, but the problem is some cards (Riva128,Matrox G200) emulate pixel fog with table fog
01159    // but dont force the shading mode to gouraud internally, so you end up with flat-shaded fog colors
01160    // (note, TNT does the right thing tho).  So I guess we must do gouraud shading for all fog rendering for now
01161    // note that if _doFogType==None, _fog_enabled will always be false
01162 
01163    D3DSHADEMODE needed_shademode =
01164        (((_perVertex & (PER_COLOR | (wants_normals() ? PER_NORMAL : 0))) || _fog_enabled) ?
01165         D3DSHADE_GOURAUD : D3DSHADE_FLAT);
01166 
01167    set_shademode(needed_shademode);
01168 
01169    return vertex_size;
01170 }
01171 
01172 ////////////////////////////////////////////////////////////////////
01173 //     Function: DXGraphicsStateGuardian7::draw_prim_inner_loop
01174 //       Access: Private
01175 //  Description: This adds data to the flexible vertex format with a check
01176 //               for component normals and color
01177 ////////////////////////////////////////////////////////////////////
01178 void DXGraphicsStateGuardian7::
01179 draw_prim_inner_loop(int nVerts, const Geom *geom, ushort perFlags) {
01180     Vertexf NextVert;
01181 
01182     for(;nVerts > 0;nVerts--) {
01183          // coord info will always be _perVertex
01184         GET_NEXT_VERTEX(NextVert);     // need to optimize these
01185         add_to_FVFBuf((void *)&NextVert, sizeof(D3DVECTOR));
01186 
01187         if(perFlags==(ushort)TexCoordOnly) {
01188             // break out the common case (for animated chars) 1st
01189             GET_NEXT_TEXCOORD();
01190         } else {
01191             switch (DrawLoopFlags(perFlags)) {
01192                 case Color_TexCoord:
01193                     GET_NEXT_TEXCOORD();
01194                 case ColorOnly:
01195                     GET_NEXT_COLOR();
01196                     break;
01197                 case Normal_Color:
01198                     GET_NEXT_COLOR();
01199                 case NormalOnly:
01200                     GET_NEXT_NORMAL();
01201                     break;
01202                 case Normal_Color_TexCoord:
01203                     GET_NEXT_COLOR();
01204                 case Normal_TexCoord:
01205                     GET_NEXT_NORMAL();
01206                 // case TexCoordOnly:
01207                     GET_NEXT_TEXCOORD();
01208                     break;
01209             }
01210         }
01211 
01212         if (_curFVFflags & D3DFVF_NORMAL)
01213             add_to_FVFBuf((void *)&p_normal, sizeof(D3DVECTOR));
01214         if (_curFVFflags & D3DFVF_DIFFUSE)
01215             add_DWORD_to_FVFBuf(_curD3Dcolor);
01216         if (_curFVFflags & D3DFVF_TEXCOUNT_MASK)
01217             add_to_FVFBuf((void *)&p_texcoord, sizeof(TexCoordf));
01218     }
01219 }
01220 
01221 ////////////////////////////////////////////////////////////////////
01222 //     Function: DXGraphicsStateGuardian7::draw_prim_inner_loop_coordtexonly
01223 //       Access: Private
01224 //  Description: FastPath loop used by animated character data
01225 ////////////////////////////////////////////////////////////////////
01226 void DXGraphicsStateGuardian7::
01227 draw_prim_inner_loop_coordtexonly(int nVerts, const Geom *geom) {
01228     // assumes coord and texcoord data is per-vertex,
01229     // color is not per-vert/component (which would require fetching new vals in the vertex loop),
01230     // and no normal data. this should be common situation for animated character data
01231     // inc'ing local ptrs instead of member ones, seems to optimize better
01232     // bypass all the slow vertex iterator stuff
01233 
01234     #ifdef _DEBUG
01235      {
01236       assert(geom->get_binding(G_NORMAL) == G_OFF);
01237       GeomBindType ColorBinding = geom->get_binding(G_COLOR);
01238       assert((ColorBinding != G_PER_VERTEX) || (ColorBinding != G_PER_COMPONENT));
01239       assert(geom->get_binding(G_TEXCOORD) == G_PER_VERTEX);
01240      }
01241     #endif
01242 
01243     Vertexf *pCurCoord = _pCurCoord;
01244     ushort *pCurCoordIndex = _pCurCoordIndex;
01245     TexCoordf *pCurTexCoord = _pCurTexCoord;
01246     ushort *pCurTexCoordIndex = _pCurTexCoordIndex;
01247 
01248     BYTE *pLocalFvfBufPtr = _pCurFvfBufPtr;
01249     DWORD cur_color = _curD3Dcolor;
01250     bool bDoIndexedTexCoords = (_texcoordindex_array != NULL);
01251     bool bDoIndexedCoords = (_coordindex_array != NULL);
01252 
01253     for(;nVerts>0;nVerts--) {
01254         if(bDoIndexedCoords) {
01255            memcpy(pLocalFvfBufPtr,(void*)&_coord_array[*pCurCoordIndex],sizeof(D3DVECTOR));
01256            pCurCoordIndex++;
01257         } else {
01258            memcpy(pLocalFvfBufPtr,(void*)pCurCoord,sizeof(D3DVECTOR));
01259            pCurCoord++;
01260         }
01261 
01262         pLocalFvfBufPtr+=sizeof(D3DVECTOR);
01263 
01264         *((DWORD *)pLocalFvfBufPtr) = cur_color;
01265         pLocalFvfBufPtr += sizeof(DWORD);
01266 
01267         if(bDoIndexedTexCoords) {
01268            memcpy(pLocalFvfBufPtr,(void*)&_texcoord_array[*pCurTexCoordIndex],sizeof(TexCoordf));
01269            pCurTexCoordIndex++;
01270         } else {
01271            memcpy(pLocalFvfBufPtr,(void*)pCurTexCoord,sizeof(TexCoordf));
01272            pCurTexCoord++;
01273         }
01274         pLocalFvfBufPtr+=sizeof(TexCoordf);
01275     }
01276 
01277     _pCurFvfBufPtr=pLocalFvfBufPtr;
01278     _pCurCoord = pCurCoord;
01279     _pCurCoordIndex = pCurCoordIndex;
01280     _pCurTexCoord = pCurTexCoord;
01281     _pCurTexCoordIndex = pCurTexCoordIndex;
01282 }
01283 
01284 ////////////////////////////////////////////////////////////////////
01285 //     Function: DXGraphicsStateGuardian7::draw_point
01286 //       Access: Public, Virtual
01287 //  Description:
01288 ////////////////////////////////////////////////////////////////////
01289 void DXGraphicsStateGuardian7::
01290 draw_point(GeomPoint *geom, GeomContext *gc) {
01291 
01292 #ifdef GSG_VERBOSE
01293     dxgsg7_cat.debug() << "draw_point()" << endl;
01294 #endif
01295 
01296     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
01297     DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
01298 
01299     // The DX Way
01300 
01301     int nPrims = geom->get_num_prims();
01302 
01303     if (nPrims==0) {
01304         dxgsg7_cat.warning() << "draw_point() called with ZERO vertices!!" << endl;
01305         return;
01306     }
01307 
01308 #ifdef _DEBUG
01309     static BOOL bPrintedMsg=FALSE;
01310 
01311     if (!bPrintedMsg && (geom->get_size()!=1.0f)) {
01312         bPrintedMsg=TRUE;
01313         dxgsg7_cat.warning() << "D3D does not support drawing points of non-unit size, setting point size to 1.0f!\n";
01314     }
01315 #endif
01316 
01317     nassertv(nPrims < D3DMAXNUMVERTICES );
01318 
01319     PTA_Vertexf coords;
01320     PTA_Normalf norms;
01321     PTA_Colorf colors;
01322     PTA_TexCoordf texcoords;
01323     GeomBindType bind;
01324     PTA_ushort vindexes,nindexes,tindexes,cindexes;
01325 
01326     geom->get_coords(coords,vindexes);
01327     geom->get_normals(norms,bind,nindexes);
01328     geom->get_colors(colors,bind,cindexes);
01329     geom->get_texcoords(texcoords,bind,tindexes);
01330 
01331     GeomVertFormat GeomVrtFmt=FlatVerts;
01332 
01333     // first determine if we're indexed or non-indexed
01334 
01335     if ((vindexes!=NULL)&&(cindexes!=NULL)&&(tindexes!=NULL)&&(nindexes!=NULL)) {
01336         GeomVrtFmt=IndexedVerts;
01337     } else if (!((vindexes==NULL)&&(cindexes==NULL)&&(tindexes==NULL)&&(nindexes==NULL)))
01338         GeomVrtFmt=MixedFmtVerts;
01339 
01340 #ifdef DONT_USE_DRAWPRIMSTRIDED
01341     GeomVrtFmt=MixedFmtVerts;
01342 #else
01343     if(_bDrawPrimDoSetupVertexBuffer) {
01344       GeomVrtFmt=MixedFmtVerts;
01345     }
01346 #endif
01347 
01348     _perVertex = 0x0;
01349     _perPrim = 0x0;
01350     if (geom->get_binding(G_NORMAL) == G_PER_VERTEX)
01351         _perVertex |= PER_NORMAL;
01352     if (geom->get_binding(G_COLOR) == G_PER_VERTEX)
01353         _perVertex |= PER_COLOR;
01354 
01355     // for Indexed Prims and mixed indexed/non-indexed prims, we will use old pipeline for now
01356     // need to add code to handle fully indexed mode (and handle cases with index arrays of different lengths,
01357     // values (may only be possible to handle certain cases without reverting to old pipeline)
01358     if (GeomVrtFmt!=FlatVerts) {
01359         size_t vertex_size = draw_prim_setup(geom);
01360 
01361         nassertv(_pCurFvfBufPtr == NULL);    // make sure the storage pointer is clean.
01362         nassertv(nPrims * vertex_size < VERT_BUFFER_SIZE);
01363         _pCurFvfBufPtr = _pFvfBufBasePtr;          // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
01364 
01365         // iterate through the point
01366         draw_prim_inner_loop(nPrims, geom, _perVertex | _perPrim);
01367 
01368         nassertv((nPrims*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr));
01369 
01370         if(!_bDrawPrimDoSetupVertexBuffer) {
01371            HRESULT hr = _pScrn->pD3DDevice->DrawPrimitive(D3DPT_POINTLIST, _curFVFflags, _pFvfBufBasePtr, nPrims, NULL);
01372            TestDrawPrimFailure(DrawPrim,hr,_pScrn->pDD,nPrims,0);
01373         } else {
01374             COPYVERTDATA_2_VERTEXBUFFER(D3DPT_POINTLIST,nPrims);
01375         }
01376     } else {  // setup for strided
01377 
01378         size_t vertex_size = draw_prim_setup(geom);
01379 
01380         // new code only handles non-indexed pointlists (is this enough?)
01381         nassertv((vindexes==NULL)&&(cindexes==NULL)&&(tindexes==NULL)&&(nindexes==NULL));
01382 
01383         D3DDRAWPRIMITIVESTRIDEDDATA dps_data;
01384         memset(&dps_data,0,sizeof(D3DDRAWPRIMITIVESTRIDEDDATA));
01385 
01386         dps_data.position.lpvData = (VOID*)coords;
01387         dps_data.position.dwStride = sizeof(D3DVECTOR);
01388 
01389         if (_curFVFflags & D3DFVF_NORMAL) {
01390             dps_data.normal.lpvData = (VOID*)norms;
01391             dps_data.normal.dwStride = sizeof(D3DVECTOR);
01392         }
01393 
01394         if (_curFVFflags & D3DFVF_DIFFUSE) {
01395             _pCurFvfBufPtr=_pFvfBufBasePtr;
01396 
01397             dps_data.diffuse.lpvData = (VOID*)_pFvfBufBasePtr;
01398             dps_data.diffuse.dwStride = sizeof(D3DCOLOR);
01399 
01400             // Geom nodes store floats for colors, drawprim requires ARGB dwords
01401             // BUGBUG: eventually this hack every-frame all-colors conversion needs
01402             // to be done only once as part of a vertex buffer
01403 
01404             if(_color_transform_enabled == 0) {
01405               for (int i=0;i<nPrims;i++) {
01406                 Colorf out_color=colors[i];
01407                 add_DWORD_to_FVFBuf(Colorf_to_D3DCOLOR(out_color));
01408               }
01409             } else {
01410               for (int i=0;i<nPrims;i++) {
01411                 D3DCOLOR RGBA_color;
01412                 transform_color(colors[i],RGBA_color);
01413                 add_DWORD_to_FVFBuf(RGBA_color);
01414               }
01415             }
01416         }
01417 
01418         if (_curFVFflags & D3DFVF_TEXCOUNT_MASK) {
01419             dps_data.textureCoords[0].lpvData = (VOID*)texcoords;
01420             dps_data.textureCoords[0].dwStride = sizeof(TexCoordf);
01421         }
01422 
01423         HRESULT hr = _pScrn->pD3DDevice->DrawPrimitiveStrided(D3DPT_POINTLIST, _curFVFflags, &dps_data, nPrims, NULL);
01424         TestDrawPrimFailure(DrawPrimStrided,hr,_pScrn->pDD,nPrims,0);
01425     }
01426 
01427     _pCurFvfBufPtr = NULL;
01428 }
01429 
01430 ////////////////////////////////////////////////////////////////////
01431 //     Function: DXGraphicsStateGuardian7::draw_line
01432 //       Access: Public, Virtual
01433 //  Description:
01434 ////////////////////////////////////////////////////////////////////
01435 void DXGraphicsStateGuardian7::
01436 draw_line(GeomLine* geom, GeomContext *gc) {
01437 
01438 #ifdef GSG_VERBOSE
01439     dxgsg7_cat.debug() << "draw_line()" << endl;
01440 #endif
01441     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
01442     DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
01443 
01444 #ifdef _DEBUG
01445     static BOOL bPrintedMsg=FALSE;
01446 
01447     // note: need to implement approximation of non-1.0 width lines with quads
01448 
01449     if (!bPrintedMsg && (geom->get_width()!=1.0f)) {
01450         bPrintedMsg=TRUE;
01451         if(dxgsg7_cat.is_debug())
01452             dxgsg7_cat.debug() << "DX does not support drawing lines with a non-1.0f pixel width, setting width to 1.0f!\n";
01453     }
01454 #endif
01455 
01456     int nPrims = geom->get_num_prims();
01457 
01458     if (nPrims==0) {
01459         if(dxgsg7_cat.is_debug())
01460            dxgsg7_cat.debug() << "draw_line() called with ZERO vertices!!" << endl;
01461         return;
01462     }
01463 
01464     _perVertex = 0x0;
01465     _perPrim = 0x0;
01466     _perComp = 0x0;
01467 
01468     switch(geom->get_binding(G_NORMAL)) {
01469         case G_PER_VERTEX:
01470             _perVertex |=  PER_NORMAL;
01471             break;
01472         case G_PER_COMPONENT:
01473             _perComp |=  PER_NORMAL;
01474             break;
01475         default:
01476             _perPrim |=  PER_NORMAL;
01477     }
01478 
01479     switch(geom->get_binding(G_COLOR)) {
01480         case G_PER_VERTEX:
01481             _perVertex |=  PER_COLOR;
01482             break;
01483         case G_PER_COMPONENT:
01484             _perComp |= PER_COLOR;
01485             break;
01486         default:
01487             _perPrim |= PER_COLOR;
01488     }
01489 
01490     size_t vertex_size = draw_prim_setup(geom);
01491 
01492     BYTE *_tmp_fvfOverrunBuf = NULL;
01493     nassertv(_pCurFvfBufPtr == NULL);    // make sure the storage pointer is clean.
01494 //  nassertv(nPrims * 2 * vertex_size < VERT_BUFFER_SIZE);
01495 
01496     if (nPrims * 2 * vertex_size > VERT_BUFFER_SIZE) {
01497         // bugbug: need cleaner way to handle tmp buffer size overruns (malloc/realloc?)
01498         _pCurFvfBufPtr = _tmp_fvfOverrunBuf = new BYTE[nPrims * 2 * vertex_size];
01499     } else  _pCurFvfBufPtr = _pFvfBufBasePtr;            // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
01500 
01501     for (int i = 0; i < nPrims; i++) {
01502         if (_perPrim & PER_COLOR) {
01503             GET_NEXT_COLOR();
01504         }
01505         if (_perPrim & PER_NORMAL)
01506             p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
01507         draw_prim_inner_loop(2, geom, _perVertex);
01508     }
01509 
01510     HRESULT hr;
01511 
01512     DWORD nVerts = nPrims<<1;
01513 
01514     if(!_bDrawPrimDoSetupVertexBuffer) {
01515         if (_tmp_fvfOverrunBuf == NULL) {
01516             nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr));
01517             hr = _pScrn->pD3DDevice->DrawPrimitive(D3DPT_LINELIST, _curFVFflags, _pFvfBufBasePtr, nVerts, NULL);
01518         } else {
01519             nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_tmp_fvfOverrunBuf));
01520             hr = _pScrn->pD3DDevice->DrawPrimitive(D3DPT_LINELIST, _curFVFflags, _tmp_fvfOverrunBuf, nVerts, NULL);
01521             delete [] _tmp_fvfOverrunBuf;
01522         }
01523         TestDrawPrimFailure(DrawPrim,hr,_pScrn->pDD,nVerts,0);
01524     } else {
01525         COPYVERTDATA_2_VERTEXBUFFER(D3DPT_LINELIST,nVerts);
01526     }
01527 
01528     _pCurFvfBufPtr = NULL;
01529 }
01530 
01531 void DXGraphicsStateGuardian7::
01532 draw_linestrip(GeomLinestrip* geom, GeomContext *gc) {
01533 
01534 #ifdef _DEBUG
01535     static BOOL bPrintedMsg=FALSE;
01536 
01537     if (!bPrintedMsg && (geom->get_width()!=1.0f)) {
01538         bPrintedMsg=TRUE;
01539         if(dxgsg7_cat.is_debug())
01540             dxgsg7_cat.debug() << "DX does not support drawing lines with a non-1.0f pixel width, setting width to 1.0f!\n";
01541     }
01542 #endif
01543 
01544   draw_linestrip_base(geom,gc,false);
01545 }
01546 
01547 ////////////////////////////////////////////////////////////////////
01548 //     Function: DXGraphicsStateGuardian7::draw_linestrip
01549 //       Access: Public, Virtual
01550 //  Description:
01551 ////////////////////////////////////////////////////////////////////
01552 void DXGraphicsStateGuardian7::
01553 draw_linestrip_base(Geom* geom, GeomContext *gc, bool bConnectEnds) {
01554 // Note draw_linestrip_base() may be called from non-line draw_fns to support wireframe mode
01555 
01556 #ifdef GSG_VERBOSE
01557     dxgsg7_cat.debug() << "draw_linestrip()" << endl;
01558 #endif
01559 
01560     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
01561     DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
01562 
01563     int nPrims = geom->get_num_prims();
01564     const int *pLengthArr = geom->get_lengths();
01565 
01566     if(nPrims==0) {
01567         if(dxgsg7_cat.is_debug())
01568             dxgsg7_cat.debug() << "draw_linestrip() called with ZERO vertices!!" << endl;
01569         return;
01570     }
01571 
01572     _perVertex = 0x0;
01573     _perPrim = 0x0;
01574     _perComp = 0x0;
01575 
01576     switch(geom->get_binding(G_NORMAL)) {
01577         case G_PER_VERTEX:
01578             _perVertex |=  PER_NORMAL;
01579             break;
01580         case G_PER_COMPONENT:
01581             _perComp |=  PER_NORMAL;
01582             break;
01583         default:
01584             _perPrim |= PER_NORMAL;
01585     }
01586 
01587     switch(geom->get_binding(G_COLOR)) {
01588         case G_PER_VERTEX:
01589             _perVertex |=  PER_COLOR;
01590             break;
01591         case G_PER_COMPONENT:
01592             _perComp |= PER_COLOR;
01593             break;
01594         default:
01595             _perPrim |= PER_COLOR;
01596     }
01597 
01598     size_t vertex_size = draw_prim_setup(geom);
01599     ushort perFlags = _perVertex | _perComp;
01600 
01601     bool bPerPrimColor = ((_perPrim & PER_COLOR)!=0);
01602     bool bPerPrimNormal = ((_perPrim & PER_NORMAL)!=0);
01603 
01604     DWORD nVerts;
01605 
01606     if(pLengthArr==NULL) // we've been called by draw_quad, which has no lengths array
01607       nVerts=4;
01608 
01609     for (int i = 0; i < nPrims; i++) {
01610         if (bPerPrimColor) {
01611             GET_NEXT_COLOR();
01612         }
01613 
01614         if (bPerPrimNormal) {
01615             p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
01616         }
01617 
01618         if(pLengthArr!=NULL) {
01619             nVerts= *(pLengthArr++);
01620             nassertv(nVerts >= 2);
01621         }
01622 
01623         nassertv(_pCurFvfBufPtr == NULL);   // make sure the storage pointer is clean.
01624         nassertv(nVerts * vertex_size < VERT_BUFFER_SIZE);
01625         _pCurFvfBufPtr = _pFvfBufBasePtr;   // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
01626 
01627         draw_prim_inner_loop(nVerts, geom, perFlags);
01628 
01629         if(bConnectEnds) {
01630              // append first vertex to end
01631              memcpy(_pCurFvfBufPtr,_pFvfBufBasePtr,vertex_size);
01632              _pCurFvfBufPtr+=vertex_size;
01633              nVerts++;
01634         }
01635 
01636         nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr));
01637 
01638         if(!_bDrawPrimDoSetupVertexBuffer) {
01639             HRESULT hr = _pScrn->pD3DDevice->DrawPrimitive(D3DPT_LINESTRIP, _curFVFflags, _pFvfBufBasePtr, nVerts, NULL);
01640             TestDrawPrimFailure(DrawPrim,hr,_pScrn->pDD,nVerts,0);
01641         } else {
01642             COPYVERTDATA_2_VERTEXBUFFER(D3DPT_LINESTRIP,nVerts);
01643         }
01644 
01645         _pCurFvfBufPtr = NULL;
01646     }
01647 }
01648 
01649 // this class exists because an alpha sort is necessary for correct
01650 // sprite rendering, and we can't simply sort the vertex arrays as
01651 // each vertex may or may not have corresponding information in the
01652 // x/y texel-world-ratio and rotation arrays.
01653 typedef struct {
01654     Vertexf _v;
01655     D3DCOLOR _c;
01656     float _x_ratio;
01657     float _y_ratio;
01658     float _theta;
01659 } WrappedSprite;
01660 
01661 class WrappedSpriteSortPtr {
01662 public:
01663     float z;
01664     WrappedSprite *pSpr;
01665 };
01666 
01667 // this struct exists because the STL can sort faster than i can.
01668 struct draw_sprite_vertex_less {
01669     INLINE bool operator ()(const WrappedSpriteSortPtr& v0,
01670                             const WrappedSpriteSortPtr& v1) const {
01671         return v0.z > v1.z; // reversed from gl due to left-handed coordsys of d3d
01672     }
01673 };
01674 
01675 ////////////////////////////////////////////////////////////////////
01676 //     Function: DXGraphicsStateGuardian7::draw_sprite
01677 //       Access: Public, Virtual
01678 //  Description:
01679 ////////////////////////////////////////////////////////////////////
01680 void DXGraphicsStateGuardian7::
01681 draw_sprite(GeomSprite *geom, GeomContext *gc) {
01682 
01683     // this is a little bit of a mess, but it's ok.  Here's the deal:
01684     // we want to draw, and draw quickly, an arbitrarily large number
01685     // of sprites all facing the screen.  Performing the billboard math
01686     // for ~1000 sprites is way too slow.  Ideally, we want one
01687     // matrix transformation that will handle everything, and this is
01688     // just about what ends up happening. We're getting the front-facing
01689     // effect by setting up a new frustum (of the same z-depth as the
01690     // current one) that is very small in x and y.  This way regularly
01691     // rendered triangles that might not be EXACTLY facing the camera
01692     // will certainly look close enough.  Then, we transform to camera-space
01693     // by hand and apply the inverse frustum to the transformed point.
01694     // For some cracked out reason, this actually works.
01695 
01696 
01697     // Note: for DX8, try to use the PointSprite primitive instead of doing all the stuff below
01698 
01699 #ifdef GSG_VERBOSE
01700     dxgsg7_cat.debug() << "draw_sprite()" << endl;
01701 #endif
01702     // get the array traversal set up.
01703     int nprims = geom->get_num_prims();
01704 
01705     if (nprims==0) {
01706         return;
01707     }
01708 
01709     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
01710 
01711     DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(nprims));
01712 
01713     bool bReEnableDither=false;
01714 
01715     Geom::VertexIterator vi = geom->make_vertex_iterator();
01716     Geom::ColorIterator ci = geom->make_color_iterator();
01717 
01718     // note although sprite particles technically dont require a texture,
01719     // the texture dimensions are used to initialize the size calculations
01720     // the code in spriteParticleRenderer.cxx does not handle the no-texture case now
01721 
01722     float tex_xsize = 1.0f;
01723     float tex_ysize = 1.0f;
01724 
01725     Texture *tex = geom->get_texture();
01726     if(tex !=NULL) {
01727       // set up the texture-rendering state
01728       modify_state(RenderState::make
01729                    (TextureAttrib::make(tex),
01730                     TextureApplyAttrib::make(TextureApplyAttrib::M_modulate)));
01731       tex_xsize = tex->_pbuffer->get_xsize();
01732       tex_ysize = tex->_pbuffer->get_ysize();
01733     }
01734 
01735     // save the modelview matrix
01736     const LMatrix4f &modelview_mat = _transform->get_mat();
01737 
01738     // We don't need to mess with the aspect ratio, since we are now
01739     // using the default projection matrix, which has the right aspect
01740     // ratio built in.
01741 
01742     // null the world xform, so sprites are orthog to scrn
01743     _pScrn->pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matIdentity);
01744     // only need to change _WORLD xform, _VIEW xform is Identity
01745 
01746     // precomputation stuff
01747     float tex_left = geom->get_ll_uv()[0];
01748     float tex_right = geom->get_ur_uv()[0];
01749     float tex_bottom = geom->get_ll_uv()[1];
01750     float tex_top = geom->get_ur_uv()[1];
01751 
01752     float half_width =  0.5f * tex_xsize * fabs(tex_right - tex_left);
01753     float half_height = 0.5f * tex_ysize * fabs(tex_top - tex_bottom);
01754     float scaled_width, scaled_height;
01755 
01756     // the user can override alpha sorting if they want
01757     bool alpha = false;
01758 
01759     if (!geom->get_alpha_disable()) {
01760       // figure out if alpha's enabled (if not, no reason to sort)
01761       const TransparencyAttrib *trans = _state->get_transparency();
01762       if (trans != (const TransparencyAttrib *)NULL) {
01763         alpha = (trans->get_mode() != TransparencyAttrib::M_none);
01764       }
01765     }
01766 
01767     // inner loop vars
01768     int i;
01769     Vertexf source_vert, cameraspace_vert;
01770     float *x_walk, *y_walk, *theta_walk;
01771     float theta;
01772 
01773     nassertv(geom->get_x_bind_type() != G_PER_VERTEX);
01774     nassertv(geom->get_y_bind_type() != G_PER_VERTEX);
01775 
01776     // set up the non-built-in bindings
01777     bool x_overall = (geom->get_x_bind_type() == G_OVERALL);
01778     bool y_overall = (geom->get_y_bind_type() == G_OVERALL);
01779     bool theta_overall = (geom->get_theta_bind_type() == G_OVERALL);
01780     bool color_overall = (geom->get_binding(G_COLOR) == G_OVERALL);
01781     bool theta_on = !(geom->get_theta_bind_type() == G_OFF);
01782 
01783     // x direction
01784     if (x_overall)
01785         scaled_width = geom->_x_texel_ratio[0] * half_width;
01786     else {
01787         nassertv(((int)geom->_x_texel_ratio.size() >= geom->get_num_prims()));
01788         x_walk = &geom->_x_texel_ratio[0];
01789     }
01790 
01791     // y direction
01792     if (y_overall)
01793         scaled_height = geom->_y_texel_ratio[0] * half_height;
01794     else {
01795         nassertv(((int)geom->_y_texel_ratio.size() >= geom->get_num_prims()));
01796         y_walk = &geom->_y_texel_ratio[0];
01797     }
01798 
01799     // theta
01800     if (theta_on) {
01801         if (theta_overall)
01802             theta = geom->_theta[0];
01803         else {
01804             nassertv(((int)geom->_theta.size() >= geom->get_num_prims()));
01805             theta_walk = &geom->_theta[0];
01806         }
01807     }
01808 
01809     /////////////////////////////////////////////////////////////////////
01810     // INNER LOOP PART 1 STARTS HERE
01811     // Here we transform each point to cameraspace and fill our sort
01812     // vector with the final geometric information.
01813     /////////////////////////////////////////////////////////////////////
01814 
01815     Colorf v_color;
01816 
01817     // sort container and iterator
01818     pvector< WrappedSpriteSortPtr > sorted_sprite_vector;
01819     pvector< WrappedSpriteSortPtr >::iterator sorted_vec_iter;
01820 
01821     WrappedSprite *SpriteArray = new WrappedSprite[nprims];
01822 
01823     //BUGBUG: could we use _fvfbuf for this to avoid perframe alloc?
01824     // alternately, alloc once when retained mode becomes available
01825 
01826     if (SpriteArray==NULL) {
01827         dxgsg7_cat.fatal() << "draw_sprite() out of memory!!" << endl;
01828         return;
01829     }
01830 
01831     // the state is set, start running the prims
01832 
01833     WrappedSprite *pSpr;
01834 
01835     for (pSpr=SpriteArray,i = 0; i < nprims; i++,pSpr++) {
01836 
01837         source_vert = geom->get_next_vertex(vi);
01838         cameraspace_vert = source_vert * modelview_mat;
01839 
01840         pSpr->_v.set(cameraspace_vert[0],cameraspace_vert[1],cameraspace_vert[2]);
01841 
01842         if (!color_overall) {
01843             GET_NEXT_COLOR();
01844             pSpr->_c = _curD3Dcolor;
01845         }
01846         if (!x_overall)
01847             pSpr->_x_ratio = *x_walk++;
01848         if (!y_overall)
01849             pSpr->_y_ratio = *y_walk++;    // go along array of ratio values stored in geom
01850         if (theta_on && (!theta_overall))
01851             pSpr->_theta = *theta_walk++;
01852     }
01853 
01854     if (alpha) {
01855         sorted_sprite_vector.reserve(nprims);   //pre-alloc space for nprims
01856 
01857         for (pSpr=SpriteArray,i = 0; i < nprims; i++,pSpr++) {   // build STL-sortable array
01858             WrappedSpriteSortPtr ws_ptr;
01859             ws_ptr.z=pSpr->_v[2];
01860             ws_ptr.pSpr=pSpr;
01861             sorted_sprite_vector.push_back(ws_ptr);
01862         }
01863 
01864         // sort the verts properly by alpha (if necessary).  Of course,
01865         // the sort is only local, not scene-global, so if you look closely you'll
01866         // notice that alphas may be screwy.  It's ok though, because this is fast.
01867         // if you want accuracy, use billboards and take the speed hit.
01868 
01869         sort(sorted_sprite_vector.begin(), sorted_sprite_vector.end(), draw_sprite_vertex_less());
01870         sorted_vec_iter = sorted_sprite_vector.begin();
01871 
01872         // disabling dither for alpha particle-systems.
01873         // ATI sez:  most applications ignore the fact that since alpha blended primitives
01874         // combine the data in the frame buffer with the data in the current pixel, pixels
01875         // can be dithered multiple times and accentuate the dither pattern. This is particularly
01876         // true in particle systems which rely on the cumulative visual effect of many overlapping
01877         // alpha blended primitives.
01878 
01879         if(_dither_enabled) {
01880             bReEnableDither=true;
01881             enable_dither(false);
01882         }
01883     }
01884 
01885     Vertexf ul, ur, ll, lr;
01886 
01887     ////////////////////////////////////////////////////////////////////////////
01888     // INNER LOOP PART 2 STARTS HERE
01889     // Now we run through the cameraspace vector and compute the geometry for each
01890     // tristrip.  This includes scaling as per the ratio arrays, as well as
01891     // rotating in the z.
01892     ////////////////////////////////////////////////////////////////////////////
01893 
01894     D3DCOLOR CurColor;
01895 
01896     #if 0
01897         //   not going to attempt this bDoColor optimization to use default white color in flat-shaded
01898         //   mode anymore,  it just make the logic confusing below.  from now on, always have color in FVF
01899 
01900         _curFVFflags = D3DFVF_XYZ | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)) ;
01901         DWORD vertex_size = sizeof(float) * 2 + sizeof(D3DVALUE) * 3;
01902 
01903         bool bDoColor=true;
01904 
01905         if (color_overall) {
01906             GET_NEXT_COLOR();
01907             CurColor = _curD3Dcolor;
01908             bDoColor = (_curD3Dcolor != ~0);  // dont need to add color if it's all white
01909         }
01910 
01911         if (bDoColor) {
01912             _curFVFflags |= D3DFVF_DIFFUSE;
01913             vertex_size+=sizeof(D3DCOLOR);
01914         }
01915     #else
01916       _curFVFflags = D3DFVF_XYZ | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)) | D3DFVF_DIFFUSE;
01917       DWORD vertex_size = sizeof(float) * 2 + sizeof(D3DVALUE) * 3 + sizeof(D3DCOLOR);
01918 
01919       if (color_overall) {
01920         GET_NEXT_COLOR();
01921         CurColor = _curD3Dcolor;
01922       }
01923     #endif
01924 
01925     // see note on fog in draw_prim_setup
01926     bool bUseGouraudShadedColor=_fog_enabled;
01927 
01928     set_shademode(!_fog_enabled ? D3DSHADE_FLAT: D3DSHADE_GOURAUD);
01929 
01930     #ifdef _DEBUG
01931      nassertv(_pCurFvfBufPtr == NULL);   // make sure the storage pointer is clean.
01932      nassertv(nprims * 4 * vertex_size < VERT_BUFFER_SIZE);
01933      nassertv(nprims * 6 < D3DMAXNUMVERTICES );
01934     #endif
01935 
01936     _pCurFvfBufPtr = _pFvfBufBasePtr;          // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
01937 
01938     const float TexCrdSets[4][2] = {
01939       { tex_left, tex_bottom },
01940       { tex_right, tex_bottom },
01941       { tex_left, tex_top },
01942       { tex_right, tex_top }
01943     };
01944 
01945 #define QUADVERTLISTLEN 6
01946 
01947     DWORD QuadVertIndexList[QUADVERTLISTLEN] = { 0, 1, 2, 3, 2, 1};
01948     DWORD CurDPIndexArrLength=0,CurVertCount=0;
01949 
01950     for (pSpr=SpriteArray,i = 0; i < nprims; i++,pSpr++) {   // build STL-sortable array
01951 
01952         if (alpha) {
01953             pSpr = sorted_vec_iter->pSpr;
01954             sorted_vec_iter++;
01955         }
01956 
01957         // if not G_OVERALL, calculate the scale factors    //huh??
01958         if (!x_overall)
01959             scaled_width = pSpr->_x_ratio * half_width;
01960 
01961         if (!y_overall)
01962             scaled_height = pSpr->_y_ratio * half_height;
01963 
01964         // if not G_OVERALL, do some trig for this z rotate   //what is the theta angle??
01965         if (theta_on) {
01966             if (!theta_overall)
01967                 theta = pSpr->_theta;
01968 
01969             // create the rotated points.  BUGBUG: this matmult will be slow if we dont get inlining
01970             // rotate_mat calls sin() on an unbounded val, possible to make it faster with lookup table (modulate to 0-360 range?)
01971 
01972             LMatrix3f xform_mat = LMatrix3f::rotate_mat(theta) *
01973                                   LMatrix3f::scale_mat(scaled_width, scaled_height);
01974 
01975             ur = (LVector3f( 1.0f,  1.0f, 0.0f) * xform_mat) + pSpr->_v;
01976             ul = (LVector3f(-1.0f,  1.0f, 0.0f) * xform_mat) + pSpr->_v;
01977             lr = (LVector3f( 1.0f, -1.0f, 0.0f) * xform_mat) + pSpr->_v;
01978             ll = (LVector3f(-1.0f, -1.0f, 0.0f) * xform_mat) + pSpr->_v;
01979         } else {
01980             // create points for unrotated rect sprites
01981             float x,y,negx,negy,z;
01982 
01983             x = pSpr->_v[0] + scaled_width;
01984             y = pSpr->_v[1] + scaled_height;
01985             negx = pSpr->_v[0] - scaled_width;
01986             negy = pSpr->_v[1] - scaled_height;
01987             z = pSpr->_v[2];
01988 
01989             ur.set(x, y, z);
01990             ul.set(negx, y, z);
01991             lr.set(x, negy, z);
01992             ll.set(negx, negy, z);
01993         }
01994 
01995         // can no longer assume flat-shaded (because of vtx fog), so always copy full color in there
01996 
01997         /*********  LL vertex  **********/
01998 
01999         add_to_FVFBuf((void *)ll.get_data(), sizeof(D3DVECTOR));
02000         if (!color_overall)  // otherwise its already been set globally
02001            CurColor = pSpr->_c;
02002         add_DWORD_to_FVFBuf(CurColor); // only need to cpy color on 1st vert, others are just empty ignored space
02003         add_to_FVFBuf((void *)TexCrdSets[0], sizeof(float)*2);
02004 
02005         /*********  LR vertex  **********/
02006 
02007         add_to_FVFBuf((void *)lr.get_data(), sizeof(D3DVECTOR));
02008 
02009         // if flat shading, dont need to write color for middle vtx, just incr ptr
02010         if(bUseGouraudShadedColor)
02011             *((DWORD *)_pCurFvfBufPtr) = (DWORD) CurColor;
02012         _pCurFvfBufPtr += sizeof(D3DCOLOR);
02013 
02014         add_to_FVFBuf((void *)TexCrdSets[1], sizeof(float)*2);
02015 
02016         /*********  UL vertex  **********/
02017 
02018         add_to_FVFBuf((void *)ul.get_data(), sizeof(D3DVECTOR));
02019         // if flat shading, dont need to write color for middle vtx, just incr ptr
02020         if(bUseGouraudShadedColor)
02021             *((DWORD *)_pCurFvfBufPtr) = (DWORD) CurColor;
02022         _pCurFvfBufPtr += sizeof(D3DCOLOR);
02023         add_to_FVFBuf((void *)TexCrdSets[2], sizeof(float)*2);
02024 
02025         /*********  UR vertex  **********/
02026 
02027         add_to_FVFBuf((void *)ur.get_data(), sizeof(D3DVECTOR));
02028         add_DWORD_to_FVFBuf(CurColor);
02029         add_to_FVFBuf((void *)TexCrdSets[3], sizeof(float)*2);
02030 
02031         for (int ii=0;ii<QUADVERTLISTLEN;ii++) {
02032             _index_buf[CurDPIndexArrLength+ii]=QuadVertIndexList[ii]+CurVertCount;
02033         }
02034         CurDPIndexArrLength+=QUADVERTLISTLEN;
02035         CurVertCount+=4;
02036     }
02037 
02038     nassertv(((4*nprims)*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr));
02039 
02040     // cant do tristrip/fan since it would require 1 call want to make 1 call for multiple quads which arent connected
02041     // best we can do is indexed primitive, which sends 2 redundant indices instead of sending 2 redundant full verts
02042     HRESULT hr = _pScrn->pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, _curFVFflags, _pFvfBufBasePtr, 4*nprims, _index_buf,QUADVERTLISTLEN*nprims,NULL);
02043     TestDrawPrimFailure(DrawIndexedPrim,hr,_pScrn->pDD,QUADVERTLISTLEN*nprims,nprims);
02044 
02045     _pCurFvfBufPtr = NULL;
02046     delete [] SpriteArray;
02047 
02048     // restore the matrices
02049     _pScrn->pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD,
02050                                   (LPD3DMATRIX)modelview_mat.get_data());
02051     if(bReEnableDither)
02052         enable_dither(true);
02053 }
02054 
02055 ////////////////////////////////////////////////////////////////////
02056 //     Function: DXGraphicsStateGuardian7::draw_polygon
02057 //       Access: Public, Virtual
02058 //  Description:
02059 ////////////////////////////////////////////////////////////////////
02060 void DXGraphicsStateGuardian7::
02061 draw_polygon(GeomPolygon *geom, GeomContext *gc) {
02062 
02063 #ifdef GSG_VERBOSE
02064    dxgsg7_cat.debug() << "draw_polygon()" << endl;
02065 #endif
02066    DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
02067    DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
02068 
02069    // wireframe polygon will be drawn as linestrip, otherwise draw as multi-tri trifan
02070    DWORD rstate;
02071    _pScrn->pD3DDevice->GetRenderState(D3DRENDERSTATE_FILLMODE, &rstate);
02072    if(rstate!=D3DFILL_WIREFRAME) {
02073        draw_multitri(geom, D3DPT_TRIANGLEFAN);
02074    } else {
02075        draw_linestrip_base(geom,gc,true);
02076    }
02077 }
02078 
02079 ////////////////////////////////////////////////////////////////////
02080 //     Function: DXGraphicsStateGuardian7::draw_quad
02081 //       Access: Public, Virtual
02082 //  Description:
02083 ////////////////////////////////////////////////////////////////////
02084 void DXGraphicsStateGuardian7::
02085 draw_quad(GeomQuad *geom, GeomContext *gc) {
02086 
02087 #ifdef GSG_VERBOSE
02088     dxgsg7_cat.debug() << "draw_quad()" << endl;
02089 #endif
02090    DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
02091    DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
02092 
02093    // wireframe quad will be drawn as linestrip, otherwise draw as multi-tri trifan
02094    DWORD rstate;
02095    _pScrn->pD3DDevice->GetRenderState(D3DRENDERSTATE_FILLMODE, &rstate);
02096    if(rstate!=D3DFILL_WIREFRAME) {
02097        draw_multitri(geom, D3DPT_TRIANGLEFAN);
02098    } else {
02099        draw_linestrip_base(geom,gc,true);
02100    }
02101 }
02102 
02103 ////////////////////////////////////////////////////////////////////
02104 //     Function: DXGraphicsStateGuardian7::draw_tri
02105 //       Access: Public, Virtual
02106 //  Description:
02107 ////////////////////////////////////////////////////////////////////
02108 void DXGraphicsStateGuardian7::
02109 draw_tri(GeomTri *geom, GeomContext *gc) {
02110 
02111 #ifdef GSG_VERBOSE
02112     dxgsg7_cat.debug() << "draw_tri()" << endl;
02113 #endif
02114     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
02115     DO_PSTATS_STUFF(_vertices_tri_pcollector.add_level(geom->get_num_vertices()));
02116 
02117 #if 0
02118     if (_pCurTexContext!=NULL) {
02119         dxgsg7_cat.spam() << "Cur active DX texture: " << _pCurTexContext->_tex->get_name() << "\n";
02120     }
02121 #endif
02122 
02123 #ifdef COUNT_DRAWPRIMS
02124     cGeomcount++;
02125 #endif
02126 
02127     DWORD nPrims = geom->get_num_prims();
02128     HRESULT hr;
02129 
02130     PTA_Vertexf coords;
02131     PTA_Normalf norms;
02132     PTA_Colorf colors;
02133     PTA_TexCoordf texcoords;
02134     GeomBindType TexCoordBinding,ColorBinding,NormalBinding;
02135     PTA_ushort vindexes,nindexes,tindexes,cindexes;
02136 
02137     geom->get_coords(coords,vindexes);
02138     geom->get_normals(norms,NormalBinding,nindexes);
02139     geom->get_colors(colors,ColorBinding,cindexes);
02140     geom->get_texcoords(texcoords,TexCoordBinding,tindexes);
02141 
02142 /*
02143    for now, always use complex path, since DPstrided path never gave speedup
02144     GeomVertFormat GeomVrtFmt=FlatVerts;
02145 
02146     // first determine if we're indexed or non-indexed
02147 
02148 
02149     if ((vindexes!=NULL)&&(cindexes!=NULL)&&(tindexes!=NULL)&&(nindexes!=NULL)) {
02150         GeomVrtFmt=IndexedVerts;
02151         //make sure array sizes are consistent, we can only pass 1 size to DrawIPrm
02152 //      nassertv(coords.size==norms.size);      nassertv(coords.size==colors.size);     nassertv(coords.size==texcoords.size);  need to assert only if we have this w/same binding
02153         // indexed mode requires all used norms,colors,texcoords,coords array be the same
02154         // length, or 0 or 1 (dwStride==0), also requires all elements to use the same index array
02155     }
02156 
02157     else if (!((vindexes==NULL)&&(cindexes==NULL)&&(tindexes==NULL)&&(nindexes==NULL)))
02158         GeomVrtFmt=MixedFmtVerts;
02159 
02160 #ifdef DONT_USE_DRAWPRIMSTRIDED
02161     GeomVrtFmt=MixedFmtVerts;
02162 #else
02163     if(_bDrawPrimDoSetupVertexBuffer) {
02164       GeomVrtFmt=MixedFmtVerts;
02165     }
02166 #endif
02167 
02168     // for Indexed Prims and mixed indexed/non-indexed prims, we will use old pipeline for now
02169     // need to add code to handle fully indexed mode (and handle cases with index arrays of different lengths,
02170     // values (may only be possible to handle certain cases without reverting to old pipeline)
02171     if (GeomVrtFmt!=FlatVerts)
02172 */
02173 
02174      {
02175         // this is the old geom setup, it reformats every vtx into an output array passed to d3d
02176 
02177         _perVertex = 0x0;
02178         _perPrim = 0x0;
02179 
02180         bool bUseTexCoordOnlyLoop = ((ColorBinding != G_PER_VERTEX) &&
02181                                      (NormalBinding == G_OFF) &&
02182                                      (TexCoordBinding != G_OFF));
02183         bool bPerPrimNormal=false;
02184 
02185         if(bUseTexCoordOnlyLoop) {
02186            _perVertex |= PER_TEXCOORD;  // TexCoords are either G_OFF or G_PER_VERTEX
02187         } else {
02188             if(NormalBinding == G_PER_VERTEX)
02189                 _perVertex |= PER_NORMAL;
02190             else if(NormalBinding == G_PER_PRIM) {
02191                     _perPrim |= PER_NORMAL;
02192                     bPerPrimNormal=true;
02193             }
02194 
02195             if(TexCoordBinding == G_PER_VERTEX)
02196                _perVertex |= PER_TEXCOORD;
02197         }
02198 
02199         bool bPerPrimColor=(ColorBinding == G_PER_PRIM);
02200         if(bPerPrimColor)
02201            _perPrim |= PER_COLOR;
02202           else if(ColorBinding == G_PER_VERTEX)
02203                  _perVertex |= PER_COLOR;
02204 
02205         size_t vertex_size = draw_prim_setup(geom);
02206 
02207         // Note: draw_prim_setup could unset color flags if global color is set, so must
02208         //       recheck this flag here!
02209         bPerPrimColor=(_perPrim & PER_COLOR)!=0x0;
02210 
02211         #ifdef _DEBUG
02212           // is it Ok not to recompute bUseTexCoordOnlyLoop even if draw_prim_setup unsets color flags?
02213           // add this check to make sure
02214            bool bNewUseTexCoordOnlyLoop = (((_perVertex & PER_COLOR)==0x0) &&
02215                                            ((_curFVFflags & D3DFVF_NORMAL)==0x0) &&
02216                                            ((_curFVFflags & D3DFVF_TEX1)!=0x0));
02217 
02218            if(bUseTexCoordOnlyLoop && (!bNewUseTexCoordOnlyLoop)) {
02219                // ok for bUseTexCoordOnlyLoop to be false, and bNew to be true.
02220                // draw_prim_setup can sometimes turn off the _perComp color for
02221                // G_OVERALL and scene-graph-color cases, which causes bNew to be true,
02222                // while the original bUseTexCoordOnly is still false.
02223                // the case we want to prevent is accidently using the texcoordloop
02224                // instead of the general one, using the general one should always work.
02225 
02226                DebugBreak();
02227                assert(0);
02228            }
02229         #endif
02230 
02231         nassertv(_pCurFvfBufPtr == NULL);    // make sure the storage pointer is clean.
02232         nassertv(nPrims * 3 * vertex_size < VERT_BUFFER_SIZE);
02233         _pCurFvfBufPtr = _pFvfBufBasePtr;          // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
02234 
02235         // iterate through the triangle primitive
02236 
02237         for (uint i = 0; i < nPrims; i++) {
02238             if(bPerPrimColor) {  // remember color might be G_OVERALL too!
02239                 GET_NEXT_COLOR();
02240             }
02241 
02242             if(bUseTexCoordOnlyLoop) {
02243                draw_prim_inner_loop_coordtexonly(3, geom);
02244             } else {
02245                 if(bPerPrimNormal)
02246                     p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
02247 
02248                 draw_prim_inner_loop(3, geom, _perVertex);
02249             }
02250         }
02251 
02252         DWORD nVerts=nPrims*3;
02253 
02254         nassertv((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr));
02255 
02256         if(!_bDrawPrimDoSetupVertexBuffer) {
02257             hr = _pScrn->pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, _curFVFflags, _pFvfBufBasePtr, nVerts, NULL);
02258             TestDrawPrimFailure(DrawPrim,hr,_pScrn->pDD,nVerts,nPrims);
02259         } else {
02260             COPYVERTDATA_2_VERTEXBUFFER(D3DPT_TRIANGLELIST,nVerts);
02261         }
02262 
02263         _pCurFvfBufPtr = NULL;
02264     }
02265 
02266 /*
02267     else {
02268 
02269         // new geom setup that uses strided DP calls to avoid making an extra pass over the data
02270 
02271         D3DDRAWPRIMITIVESTRIDEDDATA dps_data;
02272         memset(&dps_data,0,sizeof(D3DDRAWPRIMITIVESTRIDEDDATA));
02273 
02274 #ifdef _DEBUG
02275         nassertv(!geom->uses_components());  // code ignores lengths array
02276         nassertv(geom->get_binding(G_COORD) == G_PER_VERTEX);
02277 #endif
02278 
02279         D3DPRIMITIVETYPE primtype=D3DPT_TRIANGLELIST;
02280 
02281         DWORD fvf_flags = D3DFVF_XYZ;
02282         dps_data.position.lpvData = (VOID*)coords;
02283         dps_data.position.dwStride = sizeof(D3DVECTOR);
02284 
02285         // see fog comment in draw_prim_setup
02286         D3DSHADEMODE NeededShadeMode = (_fog_enabled) ? D3DSHADE_GOURAUD : D3DSHADE_FLAT;
02287 
02288         const DWORD dwVertsperPrim=3;
02289 
02290         if ((NormalBinding != G_OFF) && wants_normals()) {
02291 
02292             dps_data.normal.lpvData = (VOID*)norms;
02293             dps_data.normal.dwStride = sizeof(D3DVECTOR);
02294 
02295 #ifdef _DEBUG
02296             nassertv(geom->get_num_vertices_per_prim()==3);
02297             nassertv( nPrims*dwVertsperPrim*sizeof(D3DVECTOR) <= D3DMAXNUMVERTICES*sizeof(WORD));
02298             if (NormalBinding==G_PER_VERTEX)
02299                 nassertv(norms.size()>=nPrims*dwVertsperPrim);
02300 #endif
02301 
02302             fvf_flags |= D3DFVF_NORMAL;
02303             NeededShadeMode = D3DSHADE_GOURAUD;
02304 
02305             Normalf *pExpandedNormalArray = (Normalf *)_index_buf;  // BUGBUG:  need to use real permanent buffers for this conversion
02306             if (NormalBinding==G_PER_PRIM) {
02307                 // must use tmp array to duplicate-expand per-prim norms to per-vert norms
02308                 Normalf *pOutVec = pExpandedNormalArray;
02309                 Normalf *pInVec=norms;
02310 
02311                 nassertv(norms.size()>=nPrims);
02312 
02313                 for (uint i=0;i<nPrims;i++,pInVec++,pOutVec+=dwVertsperPrim) {
02314                     *pOutVec     = *pInVec;
02315                     *(pOutVec+1) = *pInVec;
02316                     *(pOutVec+2) = *pInVec;
02317                 }
02318 
02319                 dps_data.normal.lpvData = (VOID*)pExpandedNormalArray;
02320 
02321             } else if (NormalBinding==G_OVERALL) {
02322                 // copy the one global color in, set stride to 0
02323                 *pExpandedNormalArray=norms[0];
02324                 dps_data.normal.lpvData = (VOID*)pExpandedNormalArray;
02325                 dps_data.normal.dwStride = 0;
02326             }
02327         }
02328 
02329         // We should issue geometry colors only if the scene graph color is off.
02330         bool bDoGlobalSceneGraphColor = FALSE;
02331         bool bDoColor = (_vertex_colors_enabled && ColorBinding != G_OFF);
02332         if (_has_scene_graph_color) {
02333           bDoColor = TRUE;
02334           bDoGlobalSceneGraphColor = TRUE;
02335           ColorBinding = G_OVERALL;
02336         }
02337 
02338         if (bDoColor || bDoGlobalSceneGraphColor) {
02339             D3DCOLOR *pOutColor,*pConvertedColorArray;
02340             Colorf *pInColor=colors;
02341             pOutColor = pConvertedColorArray = (D3DCOLOR *)_pFvfBufBasePtr;
02342 
02343 #ifdef _DEBUG
02344             nassertv( nPrims*dwVertsperPrim*sizeof(D3DCOLOR) <= VERT_BUFFER_SIZE);
02345 #endif
02346 
02347             fvf_flags |= D3DFVF_DIFFUSE;
02348 
02349             dps_data.diffuse.lpvData = (VOID*)pConvertedColorArray;
02350             dps_data.diffuse.dwStride = sizeof(D3DCOLOR);
02351 
02352             if (ColorBinding==G_PER_PRIM) {
02353                 // must use tmp array to expand per-prim info to per-vert info
02354 
02355                 // Geom nodes store floats for colors, drawprim requires ARGB dwords
02356                 // BUGBUG: eventually this hack every-frame all-colors conversion needs
02357                 // to be done only once as part of a vertex buffer
02358 
02359                 if (NeededShadeMode!=D3DSHADE_FLAT) {
02360                     // but if lighting enabled, we need to color every vert since shading will be GOURAUD
02361 
02362                     if(_color_transform_enabled == 0) {
02363                         for (uint i=0;i<nPrims;i++,pInColor++,pOutColor+=dwVertsperPrim) {
02364                             D3DCOLOR newcolr = Colorf_to_D3DCOLOR(*pInColor);
02365                             *pOutColor     = newcolr;
02366                             *(pOutColor+1) = newcolr;
02367                             *(pOutColor+2) = newcolr;
02368                         }
02369                      } else {
02370                         for (uint i=0;i<nPrims;i++,pInColor++,pOutColor+=dwVertsperPrim) {
02371                             D3DCOLOR newcolr;
02372                             transform_color(*pInColor,newcolr);
02373 
02374                             *pOutColor     = newcolr;
02375                             *(pOutColor+1) = newcolr;
02376                             *(pOutColor+2) = newcolr;
02377                         }
02378                     }
02379                 } else {
02380                     // dont write 2nd,3rd colors in output buffer, these are not used in flat shading
02381                     // MAKE SURE ShadeMode never set to GOURAUD after this!
02382 
02383                     if(_color_transform_enabled == 0) {
02384                         for (uint i=0;i<nPrims;i++,pInColor++,pOutColor+=dwVertsperPrim) {
02385                             *pOutColor = Colorf_to_D3DCOLOR(*pInColor);
02386                         }
02387                      } else {
02388                         for (uint i=0;i<nPrims;i++,pInColor++,pOutColor+=dwVertsperPrim) {
02389                             transform_color(*pInColor,*pOutColor);
02390                         }
02391                     }
02392                 }
02393             } else if (ColorBinding==G_PER_VERTEX) {
02394                 NeededShadeMode = D3DSHADE_GOURAUD;
02395 
02396                 // want to do this conversion once in retained mode
02397                 DWORD cNumColors=nPrims*dwVertsperPrim;
02398 
02399                     if(_color_transform_enabled == 0) {
02400                         for (uint i=0;i<cNumColors;i++,pInColor++,pOutColor++) {
02401                             *pOutColor = Colorf_to_D3DCOLOR(*pInColor);
02402                         }
02403                      } else {
02404                         for (uint i=0;i<cNumColors;i++,pInColor++,pOutColor++) {
02405                             transform_color(*pInColor,*pOutColor);
02406                         }
02407                     }
02408             } else {
02409 #ifdef _DEBUG
02410                 nassertv(ColorBinding==G_OVERALL);
02411 #endif
02412                 // copy the one global color in, set stride to 0
02413 
02414                 if(_color_transform_enabled == 0) {
02415                     if (bDoGlobalSceneGraphColor) {
02416                         Colorf colr = _scene_graph_color;
02417                         *pConvertedColorArray = Colorf_to_D3DCOLOR(colr);
02418                     } else {
02419                         *pConvertedColorArray = Colorf_to_D3DCOLOR(*pInColor);
02420                     }
02421                 } else {
02422                     if (bDoGlobalSceneGraphColor) {
02423                         Colorf colr = _scene_graph_color;
02424                         transform_color(colr,*pConvertedColorArray);
02425                     } else {
02426                         transform_color(*pInColor,*pConvertedColorArray);
02427                     }
02428                 }
02429 
02430                 dps_data.diffuse.dwStride = 0;
02431             }
02432         }
02433 
02434         if ((TexCoordBinding != G_OFF) && _texturing_enabled) {
02435 
02436 #ifdef _DEBUG
02437             nassertv(TexCoordBinding == G_PER_VERTEX);  // only sensible choice for a tri
02438 #endif
02439 
02440             dps_data.textureCoords[0].lpvData = (VOID*)texcoords;
02441             dps_data.textureCoords[0].dwStride = sizeof(TexCoordf);
02442             fvf_flags |= (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
02443         }
02444 
02445         set_shademode(NeededShadeMode);
02446 
02447         DWORD nVerts = nPrims*dwVertsperPrim;
02448 
02449         hr = _pScrn->pD3DDevice->DrawPrimitiveStrided(primtype, fvf_flags, &dps_data, nVerts, NULL);
02450         TestDrawPrimFailure(DrawPrimStrided,hr,_pScrn->pDD,nVerts,nPrims);
02451 
02452         _pCurFvfBufPtr = NULL;
02453     }
02454 */
02455 ///////////////////////////
02456 
02457 /*
02458 #if 0
02459     // test triangle for me to dbg experiments only
02460     float vert_buf[15] = {
02461         0.0f, 0.0f, 0.0f,  0.0f, 0.0f,
02462         33.0, 0.0f, 0.0f,  0.0f, 2.0,
02463         0.0f, 0.0f, 33.0,  2.0, 0.0f
02464     };
02465 
02466     _pScrn->pD3DDevice->SetTextureStageState(0,D3DTSS_ADDRESSU,D3DTADDRESS_BORDER);
02467     _pScrn->pD3DDevice->SetTextureStageState(0,D3DTSS_ADDRESSV,D3DTADDRESS_BORDER);
02468     _pScrn->pD3DDevice->SetTextureStageState(0,D3DTSS_BORDERCOLOR,MY_D3DRGBA(0,0,0,0));
02469 
02470     _curFVFflags =  D3DFVF_XYZ | (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0)) ;
02471     HRESULT hr = _pScrn->pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,  _curFVFflags, vert_buf, nPrims*3, NULL);
02472     TestDrawPrimFailure(DrawPrim,hr,_pScrn->pDD,nPrims*3,nPrims);
02473 #endif
02474 */
02475 }
02476 
02477 ////////////////////////////////////////////////////////////////////
02478 //     Function: DXGraphicsStateGuardian7::draw_tristrip
02479 //       Access: Public, Virtual
02480 //  Description:
02481 ////////////////////////////////////////////////////////////////////
02482 void DXGraphicsStateGuardian7::
02483 draw_tristrip(GeomTristrip *geom, GeomContext *gc) {
02484 
02485 #ifdef GSG_VERBOSE
02486   dxgsg7_cat.debug() << "draw_tristrip()" << endl;
02487 #endif
02488   DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
02489   DO_PSTATS_STUFF(_vertices_tristrip_pcollector.add_level(geom->get_num_vertices()));
02490 
02491   draw_multitri(geom, D3DPT_TRIANGLESTRIP);
02492 }
02493 
02494 ////////////////////////////////////////////////////////////////////
02495 //     Function: DXGraphicsStateGuardian7::draw_trifan
02496 //       Access: Public, Virtual
02497 //  Description:
02498 ////////////////////////////////////////////////////////////////////
02499 void DXGraphicsStateGuardian7::
02500 draw_trifan(GeomTrifan *geom, GeomContext *gc) {
02501 
02502 #ifdef GSG_VERBOSE
02503     dxgsg7_cat.debug() << "draw_trifan()" << endl;
02504 #endif
02505   DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
02506   DO_PSTATS_STUFF(_vertices_trifan_pcollector.add_level(geom->get_num_vertices()));
02507 
02508   draw_multitri(geom, D3DPT_TRIANGLEFAN);
02509 }
02510 
02511 ////////////////////////////////////////////////////////////////////
02512 //     Function: DXGraphicsStateGuardian7::draw_multitri
02513 //       Access: Public, Virtual
02514 //  Description: handles trifans and tristrips
02515 ////////////////////////////////////////////////////////////////////
02516 void DXGraphicsStateGuardian7::
02517 draw_multitri(Geom *geom, D3DPRIMITIVETYPE trilisttype) {
02518 
02519     DWORD nPrims = geom->get_num_prims();
02520     const uint *pLengthArr = (const uint *) ((const int *)geom->get_lengths());
02521     HRESULT hr;
02522 
02523     if(nPrims==0) {
02524         #ifdef _DEBUG
02525           dxgsg7_cat.warning() << "draw_multitri() called with ZERO vertices!!" << endl;
02526         #endif
02527         return;
02528     }
02529 
02530 #ifdef COUNT_DRAWPRIMS
02531     cGeomcount++;
02532 #endif
02533 
02534     PTA_Vertexf coords;
02535     PTA_Normalf norms;
02536     PTA_Colorf colors;
02537     PTA_TexCoordf texcoords;
02538     GeomBindType TexCoordBinding,ColorBinding,NormalBinding;
02539     PTA_ushort vindexes,nindexes,tindexes,cindexes;
02540 
02541     geom->get_coords(coords,vindexes);
02542     geom->get_normals(norms,NormalBinding,nindexes);
02543     geom->get_colors(colors,ColorBinding,cindexes);
02544     geom->get_texcoords(texcoords,TexCoordBinding,tindexes);
02545 /*
02546     GeomVertFormat GeomVrtFmt;
02547 
02548 #ifdef DONT_USE_DRAWPRIMSTRIDED
02549     GeomVrtFmt=MixedFmtVerts;
02550 #else
02551     GeomVrtFmt=FlatVerts;
02552 
02553     if(!geom->uses_components()) {
02554        GeomVrtFmt=MixedFmtVerts; // dont need efficiency here, just use simpler codepath
02555     } else {
02556         // first determine if we're indexed or non-indexed
02557         if((vindexes!=NULL)&&(cindexes!=NULL)&&(tindexes!=NULL)&&(nindexes!=NULL)) {
02558             GeomVrtFmt=IndexedVerts;
02559             //make sure array sizes are consistent, we can only pass 1 size to DrawIPrm
02560             //      nassertv(coords.size==norms.size);      nassertv(coords.size==colors.size);     nassertv(coords.size==texcoords.size);  need to assert only if we have this w/same binding
02561             // indexed mode requires all used norms,colors,texcoords,coords array be the same
02562             // length, or 0 or 1 (dwStride==0), also requires all elements to use the same index array
02563         } else if (!((vindexes==NULL)&&(cindexes==NULL)&&(tindexes==NULL)&&(nindexes==NULL)))
02564             GeomVrtFmt=MixedFmtVerts;
02565     }
02566 
02567     if(_bDrawPrimDoSetupVertexBuffer) {
02568       GeomVrtFmt=MixedFmtVerts;
02569     }
02570 #endif
02571 
02572     // for Indexed Prims and mixed indexed/non-indexed prims, we will use old pipeline
02573     // cant handle indexed prims because usually have different index arrays for different components,
02574     // and DrIdxPrmStrd only accepts 1 index array for all components
02575     if (GeomVrtFmt!=FlatVerts)
02576 */
02577 
02578     {
02579         // this is the old geom setup, it reformats every vtx into an output array passed to d3d
02580         _perVertex = 0x0;
02581         _perPrim = 0x0;
02582         _perComp = 0x0;
02583 
02584         bool bIsTriList=(trilisttype==D3DPT_TRIANGLESTRIP);
02585         bool bPerPrimColor=(ColorBinding == G_PER_PRIM);
02586         bool bPerPrimNormal;
02587         bool bUseTexCoordOnlyLoop = (((ColorBinding == G_OVERALL) || bPerPrimColor) &&
02588                                      (NormalBinding == G_OFF) &&
02589                                      (TexCoordBinding != G_OFF));
02590 
02591         if(bUseTexCoordOnlyLoop) {
02592            if(bPerPrimColor) {
02593               _perPrim = PER_COLOR;
02594            }
02595         } else {
02596             switch (NormalBinding) {
02597                 case G_PER_VERTEX:
02598                     _perVertex |= PER_NORMAL;
02599                     break;
02600                 case G_PER_PRIM:
02601                     _perPrim |= PER_NORMAL;
02602                     break;
02603                 case G_PER_COMPONENT:
02604                     _perComp |= PER_NORMAL;
02605                     break;
02606             }
02607 
02608             bPerPrimNormal=((_perPrim & PER_NORMAL)!=0);
02609 
02610             if (TexCoordBinding == G_PER_VERTEX)
02611                 _perVertex |= PER_TEXCOORD;
02612 
02613             switch (ColorBinding) {
02614                 case G_PER_PRIM:
02615                     _perPrim |= PER_COLOR;
02616                     break;
02617                 case G_PER_COMPONENT:
02618                     _perComp |= PER_COLOR;
02619                     break;
02620                 case G_PER_VERTEX:
02621                     _perVertex |= PER_COLOR;
02622                     break;
02623             }
02624         }
02625 
02626         // draw_prim_setup() REQUIRES _perVertex, etc flags setup properly prior to call
02627         size_t vertex_size = draw_prim_setup(geom);
02628 
02629         // Note: draw_prim_setup could unset color flags if global color is set, so must
02630         //       recheck this flag here!
02631         bPerPrimColor=(_perPrim & PER_COLOR)!=0;
02632 
02633         #ifdef _DEBUG
02634           // is it Ok not to recompute bUseTexCoordOnlyLoop even if draw_prim_setup unsets color flags?
02635           // add this check to make sure.  texcoordonly needs input that with unchanging color, except per-prim
02636            bool bNewUseTexCoordOnlyLoop = ((((_perComp|_perVertex) & PER_COLOR)==0x0) &&
02637                                            ((_curFVFflags & D3DFVF_NORMAL)==0x0) &&
02638                                            ((_curFVFflags & D3DFVF_TEX1)!=0x0));
02639 
02640            if(bUseTexCoordOnlyLoop && (!bNewUseTexCoordOnlyLoop)) {
02641                // ok for bUseTexCoordOnlyLoop to be false, and bNew to be true.
02642                // draw_prim_setup can sometimes turn off the _perComp color for
02643                // G_OVERALL and scene-graph-color cases, which causes bNew to be true,
02644                // while the original bUseTexCoordOnly is still false.
02645                // the case we want to prevent is accidently using the texcoordloop
02646                // instead of the general one, using the general one should always work.
02647 
02648                DebugBreak();
02649                assert(0);
02650            }
02651         #endif
02652 
02653         // iterate through the triangle primitives
02654         int nVerts;
02655         if(pLengthArr==NULL) {
02656            // we've been called by draw_quad, which has no lengths array
02657            nVerts=4;
02658         }
02659 
02660         for (uint i = 0; i < nPrims; i++) {
02661 
02662             if(pLengthArr!=NULL) {
02663               nVerts = *(pLengthArr++);
02664             }
02665 
02666             if(bPerPrimColor) {
02667                 GET_NEXT_COLOR();
02668             }
02669 
02670 #ifdef _DEBUG
02671             nassertv(nVerts >= 3);
02672             nassertv(_pCurFvfBufPtr == NULL);    // make sure the storage pointer is clean.
02673             nassertv(nVerts * vertex_size < VERT_BUFFER_SIZE);
02674 #endif
02675             _pCurFvfBufPtr = _pFvfBufBasePtr;            // _pCurFvfBufPtr changes,  _pFvfBufBasePtr doesn't
02676 
02677             if(_perComp==0x0) {
02678                  if(bUseTexCoordOnlyLoop) {
02679                     draw_prim_inner_loop_coordtexonly(nVerts, geom);
02680                  } else {
02681                      if (bPerPrimNormal)
02682                          p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
02683 
02684                      draw_prim_inner_loop(nVerts, geom, _perVertex);
02685                  }
02686             } else {
02687                 if(bPerPrimNormal)
02688                     p_normal = geom->get_next_normal(ni);   // set primitive normal if there is one.
02689 
02690                 if(bIsTriList) {
02691                    // in flat shade mode, D3D strips color using the 1st vertex.
02692                    // (note: differs from OGL, which always uses last vtx for strips&fans
02693 
02694                     // Store all but last 2 verts
02695                     draw_prim_inner_loop(nVerts-2, geom, _perVertex | _perComp);
02696 
02697                     // _perComp attribs should not be fetched for last 2 verts
02698                     draw_prim_inner_loop(2, geom, _perVertex);
02699                 } else {
02700                    // in flat shade mode, D3D fans color using the 2nd vertex.
02701                    // (note: differs from OGL, which always uses last vtx for strips&fans
02702                    // _perComp attribs should not be fetched for first & last verts, they will
02703                    // be associated with middle n-2 verts
02704 
02705                     draw_prim_inner_loop(1, geom, _perVertex);
02706                     draw_prim_inner_loop(nVerts-2, geom, _perVertex | _perComp);
02707                     draw_prim_inner_loop(1, geom, _perVertex);
02708                 }
02709             }
02710 
02711             assert((nVerts*vertex_size) == (_pCurFvfBufPtr-_pFvfBufBasePtr));
02712 
02713             if(!_bDrawPrimDoSetupVertexBuffer) {
02714                 hr = _pScrn->pD3DDevice->DrawPrimitive(trilisttype,  _curFVFflags, _pFvfBufBasePtr, nVerts, NULL);
02715                 TestDrawPrimFailure(DrawPrim,hr,_pScrn->pDD,nVerts,nVerts-2);
02716             } else {
02717                 COPYVERTDATA_2_VERTEXBUFFER(trilisttype,nVerts);
02718             }
02719 
02720             _pCurFvfBufPtr = NULL;
02721         }
02722     }
02723 
02724 #if 0
02725     else {
02726 
02727         // new geom setup that uses strided DP calls to avoid making an extra pass over the data
02728 
02729         D3DDRAWPRIMITIVESTRIDEDDATA dps_data;
02730         memset(&dps_data,0,sizeof(D3DDRAWPRIMITIVESTRIDEDDATA));
02731 
02732 #ifdef _DEBUG
02733         nassertv(geom->uses_components());
02734         nassertv(geom->get_binding(G_COORD) == G_PER_VERTEX);
02735 #endif
02736 
02737         DWORD fvf_flags = D3DFVF_XYZ;
02738         dps_data.position.lpvData = (VOID*)coords;
02739         dps_data.position.dwStride = sizeof(D3DVECTOR);
02740 
02741         D3DSHADEMODE NeededShadeMode = D3DSHADE_FLAT;
02742 
02743         DWORD cTotalVerts=0;
02744 
02745         for (uint i=0;i<nPrims;i++) {
02746             cTotalVerts+= pLengthArr[i];
02747         }
02748 
02749         const DWORD cNumMoreVertsthanTris=2;
02750 
02751         if((NormalBinding != G_OFF) && wants_normals()) {
02752 
02753             dps_data.normal.lpvData = (VOID*)norms;
02754             dps_data.normal.dwStride = sizeof(D3DVECTOR);
02755 
02756 #ifdef _DEBUG
02757             nassertv(geom->get_num_more_vertices_than_components()==2);
02758             nassertv(NormalBinding!=G_PER_COMPONENT); // makes no sense, unimplementable for strips since normals always shared across tris
02759             nassertv( cTotalVerts*sizeof(D3DVECTOR) <= D3DMAXNUMVERTICES*sizeof(WORD));
02760             if(NormalBinding==G_PER_VERTEX)
02761                 nassertv(norms.size()>=cTotalVerts);
02762 #endif
02763             fvf_flags |= D3DFVF_NORMAL;
02764             NeededShadeMode = D3DSHADE_GOURAUD;
02765 
02766             Normalf *pExpandedNormalArray = (Normalf *)_index_buf;  // BUGBUG:  need to use real permanent buffers instead of _indexbuf hack
02767 
02768             if(NormalBinding==G_PER_PRIM) {
02769                 // we have 1 normal per strip
02770                 // must use tmp array to duplicate-expand per-prim norms to per-vert norms
02771                 Normalf *pOutVec = pExpandedNormalArray;
02772                 Normalf *pInVec=norms;
02773                 const uint *pLengths=pLengthArr;
02774 
02775                 nassertv(norms.size()>=nPrims);
02776 
02777                 for (uint i=0;i<nPrims;i++,pInVec++,pLengths++) {
02778                     for (uint j=0;j<(*pLengths);j++,pOutVec++) {
02779                         *pOutVec = *pInVec;
02780                     }
02781                 }
02782 
02783                 dps_data.normal.lpvData = (VOID*)pExpandedNormalArray;
02784 
02785             } else if(NormalBinding==G_OVERALL) {
02786                 // copy the one global color in, set stride to 0
02787                 *pExpandedNormalArray=norms[0];
02788                 dps_data.normal.lpvData = (VOID*)pExpandedNormalArray;
02789                 dps_data.normal.dwStride = 0;
02790             }
02791         }
02792 
02793         // We should issue geometry colors only if the scene graph color is off.
02794         bool bDoGlobalSceneGraphColor = FALSE;
02795         bool bDoColor = (_vertex_colors_enabled && ColorBinding != G_OFF);
02796         if (_has_scene_graph_color) {
02797           bDoColor = TRUE;
02798           bDoGlobalSceneGraphColor = TRUE;
02799           ColorBinding = G_OVERALL;
02800         }
02801 
02802         if (bDoColor || bDoGlobalSceneGraphColor) {
02803             D3DCOLOR *pOutColor,*pConvertedColorArray;
02804             Colorf *pInColor=colors;
02805             pOutColor = pConvertedColorArray = (D3DCOLOR *)_pFvfBufBasePtr;
02806 
02807 #ifdef _DEBUG
02808             nassertv( cTotalVerts*sizeof(D3DCOLOR) <= VERT_BUFFER_SIZE);
02809 #endif
02810 
02811             fvf_flags |= D3DFVF_DIFFUSE;
02812 
02813             dps_data.diffuse.lpvData = (VOID*)pConvertedColorArray;
02814             dps_data.diffuse.dwStride = sizeof(D3DCOLOR);
02815 
02816             if (ColorBinding==G_PER_VERTEX) {
02817                 NeededShadeMode = D3DSHADE_GOURAUD;
02818 
02819                 if(_color_transform_enabled == 0) {
02820                     for (uint i=0;i<cTotalVerts;i++,pInColor++,pOutColor++) {
02821                         *pOutColor = Colorf_to_D3DCOLOR(*pInColor);
02822                     }
02823                 } else {
02824                     for (uint i=0;i<cTotalVerts;i++,pInColor++,pOutColor++) {
02825                         transform_color(*pInColor,*pOutColor);
02826                     }
02827                 }
02828             } else if (ColorBinding==G_PER_PRIM) {
02829                 // must use tmp array to expand per-prim info to per-vert info
02830                 // eventually want to do this conversion once in retained mode
02831                 // have one color per strip, need 1 color per vert
02832 
02833                 // could save 2 clr writes per strip/fan in flat shade mode but not going to bother here
02834 
02835                 if(_color_transform_enabled == 0) {
02836                     for (uint j=0;j<nPrims;j++,pInColor++) {
02837                         D3DCOLOR lastcolr = Colorf_to_D3DCOLOR(*pInColor);
02838                         DWORD cStripLength=pLengthArr[j];
02839                         for (uint i=0;i<cStripLength;i++,pOutColor++) {
02840                             *pOutColor = lastcolr;
02841                         }
02842                     }
02843                 } else {
02844                     for (uint j=0;j<nPrims;j++,pInColor++) {
02845                         D3DCOLOR lastcolr;
02846                         transform_color(*pInColor,lastcolr);
02847                         DWORD cStripLength=pLengthArr[j];
02848                         for (uint i=0;i<cStripLength;i++,pOutColor++) {
02849                             *pOutColor = lastcolr;
02850                         }
02851                     }
02852                 }
02853             } else if (ColorBinding==G_PER_COMPONENT) {
02854                 // have a color per tri, need a color per vert (2 more than #tris)
02855                 // want to do this conversion once in retained mode
02856                 nassertv(colors.size() >= cTotalVerts-nPrims*cNumMoreVertsthanTris);
02857 
02858                 #define MULTITRI_COLORCOPY_LOOP                                       \
02859                     DWORD cCurStripColorCnt=pLengthArr[j]-cNumMoreVertsthanTris;      \
02860                     for (uint i=0;i<cCurStripColorCnt;i++,pInColor++,pOutColor++)
02861 
02862                 #define COLOR_CONVERT_COPY_STMT  {*pOutColor = Colorf_to_D3DCOLOR(*pInColor);}
02863                 #define COLOR_CONVERT_XFORM_STMT {transform_color(*pInColor,*pOutColor);}
02864 
02865                 #define COMPONENT_COLOR_COPY_LOOPS(COLOR_COPYSTMT)  {                        \
02866                     if (NeededShadeMode == D3DSHADE_FLAT) {                                  \
02867                         /* FLAT shade mode.  for tristrips, skip writing last 2 verts.  */   \
02868                         /* for trifans, skip first and last verts                       */   \
02869                         if (trilisttype==D3DPT_TRIANGLESTRIP) {                              \
02870                             for (uint j=0;j<nPrims;j++) {                                    \
02871                                 MULTITRI_COLORCOPY_LOOP {                                    \
02872                                    COLOR_COPYSTMT;                                           \
02873                                 }                                                            \
02874                                 pOutColor+=cNumMoreVertsthanTris;                            \
02875                             }                                                                \
02876                         } else {  /* trifan */                                               \
02877                             for (uint j=0;j<nPrims;j++) {                                    \
02878                                 pOutColor++;                                                 \
02879                                 MULTITRI_COLORCOPY_LOOP {                                    \
02880                                    COLOR_COPYSTMT;                                           \
02881                                 }                                                            \
02882                                 pOutColor++;                                                 \
02883                             }                                                                \
02884                         }                                                                    \
02885                     } else {  /* GOURAUD shademode (due to presence of normals) */           \
02886                         if (trilisttype==D3DPT_TRIANGLESTRIP) {                              \
02887                             for (uint j=0;j<nPrims;j++) {                                    \
02888                                 MULTITRI_COLORCOPY_LOOP {                                    \
02889                                    COLOR_COPYSTMT;                                           \
02890                                 }                                                            \
02891                                 DWORD lastcolr = *(pOutColor-1);                             \
02892                                 *pOutColor++ = lastcolr;                                     \
02893                                 *pOutColor++ = lastcolr;                                     \
02894                             }                                                                \
02895                         } else {  /* trifan */                                               \
02896                             for (uint j=0;j<nPrims;j++) {                                    \
02897                                 COLOR_COPYSTMT;                                              \
02898                                 pOutColor++;                                                 \
02899                                 MULTITRI_COLORCOPY_LOOP {                                    \
02900                                    COLOR_COPYSTMT;                                           \
02901                                 }                                                            \
02902                                 *pOutColor++ = *(pOutColor-1);                               \
02903                             }                                                                \
02904                         }                                                                    \
02905                     }                                                                        \
02906                   }
02907 
02908                 if(_color_transform_enabled == 0) {
02909                   COMPONENT_COLOR_COPY_LOOPS(COLOR_CONVERT_COPY_STMT);
02910                 } else {
02911                   COMPONENT_COLOR_COPY_LOOPS(COLOR_CONVERT_XFORM_STMT);
02912                 }
02913             } else {
02914 #ifdef _DEBUG
02915                 nassertv(ColorBinding==G_OVERALL);
02916 #endif
02917                 // copy the one global color in, set stride to 0
02918 
02919                 if(_color_transform_enabled == 0) {
02920                     if (bDoGlobalSceneGraphColor) {
02921                         Colorf colr = _scene_graph_color();
02922                         *pConvertedColorArray = Colorf_to_D3DCOLOR(colr);
02923                     } else {
02924                         *pConvertedColorArray = Colorf_to_D3DCOLOR(*pInColor);
02925                     }
02926                 } else {
02927                     if (bDoGlobalSceneGraphColor) {
02928                         Colorf colr = _scene_graph_color();
02929                         transform_color(colr,*pConvertedColorArray);
02930                     } else {
02931                         transform_color(*pInColor,*pConvertedColorArray);
02932                     }
02933                 }
02934 
02935                 dps_data.diffuse.dwStride = 0;
02936             }
02937         }
02938 
02939         if ((TexCoordBinding != G_OFF) && _texturing_enabled) {
02940 
02941 #ifdef _DEBUG
02942             nassertv(TexCoordBinding == G_PER_VERTEX);  // only sensible choice for a tri
02943 #endif
02944 
02945             dps_data.textureCoords[0].lpvData = (VOID*)texcoords;
02946             dps_data.textureCoords[0].dwStride = sizeof(TexCoordf);
02947             fvf_flags |= (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
02948         }
02949 
02950         set_shademode(NeededShadeMode);
02951 
02952         for (uint j=0;j<nPrims;j++) {
02953             const uint cCurNumStripVerts = pLengthArr[j];
02954 
02955             hr = _pScrn->pD3DDevice->DrawPrimitiveStrided(trilisttype, fvf_flags, &dps_data, cCurNumStripVerts, NULL);
02956             TestDrawPrimFailure(DrawPrimStrided,hr,_pScrn->pDD,cCurNumStripVerts,cCurNumStripVerts-2);
02957 
02958             dps_data.position.lpvData = (VOID*)(((char*) dps_data.position.lpvData) + cCurNumStripVerts*dps_data.position.dwStride);
02959             dps_data.diffuse.lpvData = (VOID*)(((char*) dps_data.diffuse.lpvData) + cCurNumStripVerts*dps_data.diffuse.dwStride);
02960             dps_data.normal.lpvData = (VOID*)(((char*) dps_data.normal.lpvData) + cCurNumStripVerts*dps_data.normal.dwStride);
02961             dps_data.textureCoords[0].lpvData = (VOID*)(((char*) dps_data.textureCoords[0].lpvData) + cCurNumStripVerts*dps_data.textureCoords[0].dwStride);
02962         }
02963 
02964         nassertv(_pCurFvfBufPtr == NULL);
02965     }
02966 #endif
02967 }
02968 
02969 //-----------------------------------------------------------------------------
02970 // Name: GenerateSphere()
02971 // Desc: Makes vertex and index data for ellipsoid w/scaling factors sx,sy,sz
02972 //       tries to match gluSphere behavior
02973 //-----------------------------------------------------------------------------
02974 
02975 void DXGraphicsStateGuardian7::
02976 GenerateSphere(void *pVertexSpace,DWORD dwVertSpaceByteSize,
02977                void *pIndexSpace,DWORD dwIndexSpaceByteSize,
02978                D3DVECTOR *pCenter, float fRadius,
02979                DWORD wNumRings, DWORD wNumSections, float sx, float sy, float sz,
02980                DWORD *pNumVertices,DWORD *pNumIndices,DWORD fvfFlags,DWORD dwVertSize) {
02981 
02982     float x, y, z, rsintheta;
02983     D3DVECTOR vPoint;
02984 
02985 //#define DBG_GENSPHERE
02986 #define M_PI 3.1415926f   // probably should get this from mathNumbers.h instead
02987 
02988     nassertv(wNumRings>=2 && wNumSections>=2);
02989     wNumRings--;  // wNumRings indicates number of vertex rings (not tri-rings).
02990                   // gluSphere 'stacks' arg for 1 vert ring is 2, so convert to our '1'.
02991     wNumSections++;  // to make us equiv to gluSphere
02992 
02993     //Figure out needed space for the triangles and vertices.
02994     DWORD dwNumVertices,dwNumIndices,dwNumTriangles;
02995 
02996 #define DOTEXTURING (fvfFlags & D3DFVF_TEXCOUNT_MASK)
02997 #define DONORMAL (fvfFlags & D3DFVF_NORMAL)
02998 #define DOCOLOR (fvfFlags & D3DFVF_DIFFUSE)
02999 
03000     if (DOTEXTURING) {
03001         // if texturing, we need full rings of identical position verts at poles to hold diff texture coords
03002         wNumRings+=2;
03003         dwNumVertices = *pNumVertices = wNumRings * wNumSections;
03004         dwNumTriangles = (wNumRings-1) * wNumSections * 2;
03005     } else {
03006         dwNumVertices = *pNumVertices = wNumRings * wNumSections + 2;
03007         dwNumTriangles = wNumRings*wNumSections*2;
03008     }
03009 
03010     dwNumIndices = *pNumIndices = dwNumTriangles*3;
03011 
03012     D3DVERTEX* pvVertices = (D3DVERTEX*) pVertexSpace;
03013     WORD *pwIndices = (WORD *) pIndexSpace;
03014 
03015     nassertv(dwNumVertices*dwVertSize < VERT_BUFFER_SIZE);
03016     nassertv(dwNumIndices < D3DMAXNUMVERTICES );
03017 
03018     // Generate vertex at the top point
03019     D3DVECTOR vTopPoint  = *pCenter + D3DVECTOR( 0.0f, +sy*fRadius, 0.0f);
03020     D3DVECTOR vBotPoint  = *pCenter + D3DVECTOR( 0.0f, -sy*fRadius, 0.0f);
03021     D3DVECTOR vNormal = D3DVECTOR( 0.0f, 1.0f, 0.0f );
03022     float texCoords[2];
03023 
03024     nassertv(pVertexSpace==_pCurFvfBufPtr);  // add_to_FVFBuf requires this
03025 
03026 #define ADD_GENSPHERE_VERTEX_TO_BUFFER(VERT)                      \
03027     add_to_FVFBuf((void *)&(VERT), sizeof(D3DVECTOR));            \
03028     if(fvfFlags & D3DFVF_NORMAL)                                  \
03029         add_to_FVFBuf((void *)&vNormal, sizeof(D3DVECTOR));       \
03030     if(fvfFlags & D3DFVF_DIFFUSE)                                 \
03031         add_DWORD_to_FVFBuf(_curD3Dcolor);                              \
03032     if(fvfFlags & D3DFVF_TEXCOUNT_MASK)                           \
03033         add_to_FVFBuf((void *)texCoords, sizeof(TexCoordf));
03034 
03035 #ifdef DBG_GENSPHERE
03036     int nvs_written=0;
03037     memset(pVertexSpace,0xFF,dwNumVertices*dwVertSize);
03038 #endif
03039 
03040     if (! DOTEXTURING) {
03041         ADD_GENSPHERE_VERTEX_TO_BUFFER(vTopPoint);
03042 #ifdef DBG_GENSPHERE
03043         nvs_written++;
03044 #endif
03045     }
03046 
03047     // Generate vertex points for rings
03048     float inv_radius = 1.0f/fRadius;
03049     const float reciprocal_PI=1.0f/M_PI;
03050     const float reciprocal_2PI=1.0f/(2.0*M_PI);
03051     DWORD i;
03052     float theta,dtheta;
03053 
03054     if (DOTEXTURING) {
03055         // numRings already includes 1st and last rings for this case
03056         dtheta = (float)(M_PI / (wNumRings-1));     //Angle between each ring (ignore 2 fake rings)
03057         theta = 0.0f;
03058     } else {
03059         dtheta = (float)(M_PI / (wNumRings + 1));   //Angle between each ring
03060         theta = dtheta;
03061     }
03062     float phi,dphi   = (float)(2*M_PI / (wNumSections-1)); //Angle between each section
03063 
03064     for (i = 0; i < wNumRings; i++) {
03065         float costheta,sintheta,cosphi,sinphi;
03066         phi =   0.0f;
03067 
03068         if (DOTEXTURING) {
03069             texCoords[1] = theta * reciprocal_PI;  // v is the same for each ring
03070         }
03071 
03072         // could optimize all this sin/cos stuff w/tables
03073         csincos(theta,&sintheta,&costheta);
03074         y = fRadius * costheta;     // y is the same for each ring
03075 
03076         rsintheta = fRadius * sintheta;
03077 
03078         for (DWORD j = 0; j < wNumSections; j++) {
03079             csincos(phi,&sinphi,&cosphi);
03080             x = rsintheta * sinphi;
03081             z = rsintheta * cosphi;
03082 
03083 #ifdef DBG_GENSPHERE
03084             nvs_written++;
03085 #endif
03086             vPoint = *pCenter + D3DVECTOR( sx*x, sy*y, sz*z );
03087 
03088             add_to_FVFBuf((void *)&vPoint, sizeof(D3DVECTOR));
03089 
03090             if (DONORMAL) {
03091                 // this is wrong normal for the non-spherical case (i think you need to multiply by 1/scale factor per component)
03092                 vNormal = Normalize(D3DVECTOR( x*inv_radius, y*inv_radius, z*inv_radius ));
03093                 add_to_FVFBuf((void *)&vNormal, sizeof(D3DVECTOR));
03094             }
03095 
03096             if (DOCOLOR)
03097                 add_DWORD_to_FVFBuf(_curD3Dcolor);
03098 
03099             if (DOTEXTURING) {
03100                 texCoords[0] = 1.0f - phi*reciprocal_2PI;
03101                 add_to_FVFBuf((void *)texCoords, sizeof(TexCoordf));
03102             }
03103 
03104             phi += dphi;
03105         }
03106         theta += dtheta;
03107     }
03108 
03109     if (! DOTEXTURING) {
03110         // Generate bottom vertex
03111         vNormal = D3DVECTOR( 0.0f, -1.0f, 0.0f );
03112         ADD_GENSPHERE_VERTEX_TO_BUFFER(vBotPoint);
03113 #ifdef DBG_GENSPHERE
03114         nvs_written++;
03115 #endif
03116     }
03117 
03118 #ifdef DBG_GENSPHERE
03119     assert(nvs_written == dwNumVertices);
03120 #endif
03121 
03122 
03123 #ifdef DBG_GENSPHERE
03124     memset(pwIndices,0xFF,dwNumIndices*sizeof(WORD));
03125 #endif
03126 
03127     // inited for textured case
03128     DWORD cur_vertring_startidx=0;    // first vertex in current ring
03129     DWORD CurFinalTriIndex = 0;       // index of next tri to be written
03130 
03131     if (! DOTEXTURING) {
03132         // Generate caps using unique the bot/top vert
03133         // for non-textured case, could render the caps as indexed trifans,
03134         // but should be no perf difference b/w indexed trilists and indexed trifans
03135         // and this has advantage of being aggregable into 1 big DPrim call for whole sphere
03136 
03137         for (i = 0; i < wNumSections; i++) {
03138             DWORD TopCapTriIndex=3*i;
03139             DWORD BotCapTriIndex=3*(dwNumTriangles - wNumSections + i);
03140             DWORD i_incd = ((i + 1) % wNumSections);
03141 
03142             pwIndices[TopCapTriIndex++] = 0;
03143             pwIndices[TopCapTriIndex++] = i + 1;
03144             pwIndices[TopCapTriIndex] =  i_incd + 1;
03145 
03146             pwIndices[BotCapTriIndex++] = (WORD)( dwNumVertices - 1 );
03147             pwIndices[BotCapTriIndex++] = (WORD)( dwNumVertices - 2 - i );
03148             pwIndices[BotCapTriIndex] = (WORD)( dwNumVertices - 2 - i_incd);
03149         }
03150 
03151         cur_vertring_startidx = 1;          // first vertex in current ring (skip top vert)
03152         CurFinalTriIndex = wNumSections;    // index of tri to be written, wNumSections to skip the top cap row
03153     }
03154 
03155     DWORD j_incd,base_index;
03156 
03157     // technically we could break into a strip for every row (or 1 big strip connected w/degenerate tris)
03158     // but indexed trilists should actually be just as fast on HW
03159 
03160     // Generate triangles for the rings
03161     for (i = 0; i < wNumRings-1; i++) {
03162         for (DWORD j = 0; j < wNumSections; j++) {
03163 
03164             base_index=3*CurFinalTriIndex;  // final vert index is 3*finaltriindex
03165             j_incd=(j+1) % wNumSections;
03166 
03167             DWORD v1_row1_idx,v2_row1_idx,v1_row2_idx,v2_row2_idx;
03168 
03169             v1_row1_idx = cur_vertring_startidx + j;
03170             v2_row1_idx = cur_vertring_startidx + j_incd;
03171             v1_row2_idx = v1_row1_idx + wNumSections;
03172             v2_row2_idx = v2_row1_idx + wNumSections;
03173 
03174 #ifdef DBG_GENSPHERE
03175             assert(v2_row2_idx<dwNumVertices);
03176             assert(v1_row2_idx<dwNumVertices);
03177             assert(v2_row1_idx<dwNumVertices);
03178             assert(v1_row1_idx<dwNumVertices);
03179 #endif
03180 
03181             pwIndices[base_index++] = v1_row1_idx;
03182             pwIndices[base_index++] = v1_row2_idx;
03183             pwIndices[base_index++] = v2_row2_idx;
03184 
03185             pwIndices[base_index++] = v1_row1_idx;
03186             pwIndices[base_index++] = v2_row2_idx;
03187             pwIndices[base_index++] = v2_row1_idx;
03188 
03189             CurFinalTriIndex += 2;  // we wrote 2 tris, add 2 to finaltriindex
03190         }
03191         cur_vertring_startidx += wNumSections;
03192     }
03193 
03194 #ifdef DBG_GENSPHERE
03195     if (DOTEXTURING) {
03196         assert(CurFinalTriIndex == dwNumTriangles);
03197         assert(base_index == dwNumIndices);
03198     } else {
03199         assert(CurFinalTriIndex == dwNumTriangles-wNumSections);
03200         assert(base_index == dwNumIndices-wNumSections*3);
03201     }
03202 
03203     for (i = 0; i < dwNumIndices; i++)
03204         assert(pwIndices[i] <dwNumVertices);
03205 #endif
03206 }
03207 
03208 
03209 ////////////////////////////////////////////////////////////////////
03210 //     Function: DXGraphicsStateGuardian7::draw_sphere
03211 //       Access: Public, Virtual
03212 //  Description:
03213 ////////////////////////////////////////////////////////////////////
03214 void DXGraphicsStateGuardian7::
03215 draw_sphere(GeomSphere *geom, GeomContext *gc) {
03216 
03217 #define SPHERE_NUMSLICES 16
03218 #define SPHERE_NUMSTACKS 10
03219 
03220 #ifdef GSG_VERBOSE
03221     dxgsg7_cat.debug() << "draw_sphere()" << endl;
03222 #endif
03223     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
03224     DO_PSTATS_STUFF(_vertices_other_pcollector.add_level(geom->get_num_vertices()));
03225 
03226     int nprims = geom->get_num_prims();
03227 
03228     if (nprims==0) {
03229         dxgsg7_cat.warning() << "draw_sphere() called with ZERO vertices!!" << endl;
03230         return;
03231     }
03232 
03233     Geom::VertexIterator vi = geom->make_vertex_iterator();
03234     Geom::ColorIterator ci;
03235     bool bperPrimColor = (geom->get_binding(G_COLOR) == G_PER_PRIM);
03236     if (bperPrimColor)
03237         ci = geom->make_color_iterator();
03238 
03239     _perVertex = 0x0;
03240     _perPrim = 0x0;
03241     _perComp = 0x0;
03242 
03243     for (int i = 0; i < nprims; i++) {
03244         DWORD nVerts,nIndices;
03245         Vertexf center = geom->get_next_vertex(vi);
03246         Vertexf edge = geom->get_next_vertex(vi);
03247         LVector3f v = edge - center;
03248         float fRadius = sqrt(dot(v, v));
03249 
03250         size_t vertex_size = draw_prim_setup(geom);
03251 
03252         _pCurFvfBufPtr = _pFvfBufBasePtr;
03253 
03254         if (bperPrimColor) {
03255             GET_NEXT_COLOR();
03256         }
03257 
03258         GenerateSphere(_pCurFvfBufPtr, VERT_BUFFER_SIZE,
03259                        _index_buf, D3DMAXNUMVERTICES,
03260                        (D3DVECTOR *)&center, fRadius,
03261                        SPHERE_NUMSTACKS, SPHERE_NUMSLICES,
03262                        1.0f, 1.0f, 1.0f,  // no scaling factors, do a sphere not ellipsoid
03263                        &nVerts,&nIndices,_curFVFflags,vertex_size);
03264 
03265         // possible optimization: make DP 1 for all spheres call here, since trilist is independent tris.
03266         // indexes couldnt start w/0 tho, need to pass offset to gensph
03267         HRESULT hr = _pScrn->pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,  _curFVFflags, _pFvfBufBasePtr, nVerts, _index_buf,nIndices,NULL);
03268         TestDrawPrimFailure(DrawIndexedPrim,hr,_pScrn->pDD,nVerts,(nIndices>>2));
03269     }
03270 
03271     _pCurFvfBufPtr = NULL;
03272 }
03273 
03274 ////////////////////////////////////////////////////////////////////
03275 //     Function: DXGraphicsStateGuardian7::prepare_texture
03276 //       Access: Public, Virtual
03277 //  Description: Creates a new retained-mode representation of the
03278 //               given texture, and returns a newly-allocated
03279 //               TextureContext pointer to reference it.  It is the
03280 //               responsibility of the calling function to later
03281 //               call release_texture() with this same pointer (which
03282 //               will also delete the pointer).
03283 ////////////////////////////////////////////////////////////////////
03284 TextureContext *DXGraphicsStateGuardian7::
03285 prepare_texture(Texture *tex) {
03286 
03287     DXTextureContext7 *dtc = new DXTextureContext7(tex);
03288 #ifdef WBD_GL_MODE
03289     glGenTextures(1, &gtc->_index);
03290 
03291     bind_texture(gtc);
03292     glPrioritizeTextures(1, &gtc->_index, &gtc->_priority);
03293     specify_texture(tex);
03294     apply_texture_immediate(tex);
03295 #else
03296 
03297 #ifdef USE_TEXFMTVEC
03298     if (dtc->CreateTexture(_pScrn->pD3DDevice,_pScrn->TexPixFmts,&_pScrn->D3DDevDesc) == NULL) {
03299 #else
03300     if (dtc->CreateTexture(_pScrn->pD3DDevice,_cNumTexPixFmts,_pTexPixFmts,&_pScrn->D3DDevDesc) == NULL) {
03301 #endif
03302         delete dtc;
03303         return NULL;
03304     }
03305 #endif              // WBD_GL_MODE
03306 
03307     bool inserted = mark_prepared_texture(dtc);
03308 
03309     // If this assertion fails, the same texture was prepared twice,
03310     // which shouldn't be possible, since the texture itself should
03311     // detect this.
03312     nassertr(inserted, NULL);
03313 
03314     return dtc;
03315 }
03316 
03317 ////////////////////////////////////////////////////////////////////
03318 //     Function: DXGraphicsStateGuardian7::apply_texture
03319 //       Access: Public, Virtual
03320 //  Description: Makes the texture the currently available texture for
03321 //               rendering.
03322 ////////////////////////////////////////////////////////////////////
03323 void DXGraphicsStateGuardian7::
03324 apply_texture(TextureContext *tc) {
03325     if (tc==NULL) {
03326         return;  // use enable_texturing to disable/enable
03327     }
03328     #ifdef DO_PSTATS
03329        add_to_texture_record(tc);
03330     #endif
03331 
03332 //  bind_texture(tc);
03333 
03334 //  specify_texture(tc->_texture);
03335     // Note: if this code changes, make sure to change initialization SetTSS code in dx_init as well
03336     // so DX TSS renderstate matches dxgsg7 state
03337 
03338     DXTextureContext7 *dtc = DCAST(DXTextureContext7, tc);
03339 
03340     int dirty = dtc->get_dirty_flags();
03341 
03342     if (dirty) {
03343       // If the texture image has changed, or if its use of mipmaps has
03344       // changed, we need to re-create the image.  Ignore other types of
03345       // changes, which arent significant for dx
03346 
03347       if((dirty & (Texture::DF_image | Texture::DF_mipmap)) != 0) {
03348           // If this is *only* because of a mipmap change, issue a
03349           // warning--it is likely that this change is the result of an
03350           // error or oversight.
03351           if ((dirty & Texture::DF_image) == 0) {
03352             dxgsg7_cat.warning()
03353               << "Texture " << *dtc->_texture << " has changed mipmap state.\n";
03354           }
03355 
03356           dtc->DeleteTexture();
03357 #ifdef USE_TEXFMTVEC
03358           if (dtc->CreateTexture(_pScrn->pD3DDevice,_pScrn->TexPixFmts,&_pScrn->D3DDevDesc) == NULL) {
03359 #else
03360           if (dtc->CreateTexture(_pScrn->pD3DDevice,_cNumTexPixFmts,_pTexPixFmts,&_pScrn->D3DDevDesc) == NULL) {
03361 #endif
03362             // Oops, we can't re-create the texture for some reason.
03363             dxgsg7_cat.error() << "Unable to re-create texture " << *dtc->_texture << endl;
03364 
03365             release_texture(dtc);
03366             enable_texturing(false);
03367             return;
03368           }
03369       }
03370       dtc->clear_dirty_flags();
03371     } else {
03372        if(_pCurTexContext == dtc) {
03373           return;  // tex already set (and possible problem in state-sorting?)
03374        }
03375     }
03376 
03377     Texture *tex = tc->_texture;
03378     Texture::WrapMode wrapU,wrapV;
03379     wrapU=tex->get_wrapu();
03380     wrapV=tex->get_wrapv();
03381 
03382     if (wrapU!=_CurTexWrapModeU) {
03383         _pScrn->pD3DDevice->SetTextureStageState(0,D3DTSS_ADDRESSU,get_texture_wrap_mode(wrapU));
03384         _CurTexWrapModeU = wrapU;
03385     }
03386     if (wrapV!=_CurTexWrapModeV) {
03387         _pScrn->pD3DDevice->SetTextureStageState(0,D3DTSS_ADDRESSV,get_texture_wrap_mode(wrapV));
03388         _CurTexWrapModeV = wrapV;
03389     }
03390 
03391     uint aniso_degree=tex->get_anisotropic_degree();
03392     if(_CurTexAnisoDegree != aniso_degree) {
03393         _pScrn->pD3DDevice->SetTextureStageState(0,D3DTSS_MAXANISOTROPY,aniso_degree);
03394         _CurTexAnisoDegree = aniso_degree;
03395     }
03396 
03397     Texture::FilterType ft=tex->get_magfilter();
03398 
03399     D3DTEXTUREMAGFILTER newMagFilter;
03400     if (aniso_degree<=1) {
03401         newMagFilter=((ft!=Texture::FT_nearest) ? D3DTFG_LINEAR : D3DTFG_POINT);
03402 
03403         #ifdef _DEBUG
03404         if((ft!=Texture::FT_linear)&&(ft!=Texture::FT_nearest)) {
03405              dxgsg7_cat.error() << "MipMap filter type setting for texture magfilter makes no sense,  texture: " << tex->get_name() << "\n";
03406         }
03407         #endif
03408     } else {
03409         newMagFilter=D3DTFG_ANISOTROPIC;
03410     }
03411 
03412     if(_CurTexMagFilter!=newMagFilter) {
03413         _CurTexMagFilter=newMagFilter;
03414         _pScrn->pD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, newMagFilter);
03415     }
03416 
03417 #ifdef _DEBUG
03418     assert(Texture::FT_linear_mipmap_linear < 8);
03419 #endif
03420 /*
03421  enum FilterType {
03422     FT_nearest,FT_linear,FT_nearest_mipmap_nearest,FT_linear_mipmap_nearest,
03423     FT_nearest_mipmap_linear, FT_linear_mipmap_linear, };
03424 */
03425  static D3DTEXTUREMINFILTER PandaToD3DMinType[8] =
03426     {D3DTFN_POINT,D3DTFN_LINEAR,D3DTFN_POINT,D3DTFN_LINEAR,D3DTFN_POINT,D3DTFN_LINEAR};
03427  static D3DTEXTUREMIPFILTER PandaToD3DMipType[8] =
03428     {D3DTFP_NONE,D3DTFP_NONE,D3DTFP_POINT,D3DTFP_POINT,D3DTFP_LINEAR,D3DTFP_LINEAR};
03429 
03430     ft=tex->get_minfilter();
03431 
03432     D3DTEXTUREMIPFILTER newMipFilter = PandaToD3DMipType[(DWORD)ft];
03433 
03434     #ifndef NDEBUG
03435        // sanity check
03436        extern char *PandaFilterNameStrs[];
03437        if((!(dtc->_bHasMipMaps))&&(newMipFilter!=D3DTFP_NONE)) {
03438                 dxgsg7_cat.error() << "Trying to set mipmap filtering for texture with no generated mipmaps!! texname[" << tex->get_name() << "], filter("<<PandaFilterNameStrs[ft]<<")\n";
03439                 newMipFilter=D3DTFP_NONE;
03440        }
03441     #endif
03442 
03443 
03444     D3DTEXTUREMINFILTER newMinFilter = PandaToD3DMinType[(DWORD)ft];
03445 
03446     if(aniso_degree>=2) {
03447         newMinFilter=D3DTFN_ANISOTROPIC;
03448     }
03449 
03450     if(newMinFilter!=_CurTexMinFilter) {
03451         _CurTexMinFilter = newMinFilter;
03452         _pScrn->pD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, newMinFilter);
03453     }
03454 
03455     if(newMipFilter!=_CurTexMipFilter) {
03456         _CurTexMipFilter = newMipFilter;
03457         _pScrn->pD3DDevice->SetTextureStageState(0, D3DTSS_MIPFILTER, newMipFilter);
03458     }
03459 
03460     // bugbug:  does this handle the case of untextured geometry?
03461     //          we dont see this bug cause we never mix textured/untextured
03462     _pScrn->pD3DDevice->SetTexture(0,dtc->_surface);
03463 
03464 #if 0
03465     if (dtc!=NULL) {
03466         dxgsg7_cat.spam() << "Setting active DX texture: " << dtc->_tex->get_name() << "\n";
03467     }
03468 #endif
03469 
03470     _pCurTexContext = dtc;   // enable_texturing needs this
03471 }
03472 
03473 ////////////////////////////////////////////////////////////////////
03474 //     Function: DXGraphicsStateGuardian7::release_texture
03475 //       Access: Public, Virtual
03476 //  Description: Frees the GL resources previously allocated for the
03477 //               texture.
03478 ////////////////////////////////////////////////////////////////////
03479 void DXGraphicsStateGuardian7::
03480 release_texture(TextureContext *tc) {
03481     DXTextureContext7 *gtc = DCAST(DXTextureContext7, tc);
03482     Texture *tex = tc->_texture;
03483 
03484     gtc->DeleteTexture();
03485     bool erased = unmark_prepared_texture(gtc);
03486 
03487     // If this assertion fails, a texture was released that hadn't been
03488     // prepared (or a texture was released twice).
03489     nassertv(erased);
03490 
03491     tex->clear_gsg(this);
03492 
03493     delete gtc;
03494 }
03495 
03496 #if 1
03497 
03498 void DXGraphicsStateGuardian7::
03499 copy_texture(TextureContext *tc, const DisplayRegion *dr) {
03500     dxgsg7_cat.fatal() << "DX copy_texture unimplemented!!!";
03501 }
03502 
03503 #else
03504 static int logs[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
03505     4096, 0};
03506 
03507 // This function returns the smallest power of two greater than or
03508 // equal to x.
03509 static int binary_log_cap(const int x) {
03510     int i = 0;
03511     for (; (x > logs[i]) && (logs[i] != 0); ++i);
03512     if (logs[i] == 0)
03513         return 4096;
03514     return logs[i];
03515 }
03516 
03517 ////////////////////////////////////////////////////////////////////
03518 //     Function: DXGraphicsStateGuardian7::copy_texture
03519 //       Access: Public, Virtual
03520 //  Description: Copy the pixel region indicated by the display
03521 //       region from the framebuffer into texture memory
03522 ////////////////////////////////////////////////////////////////////
03523 void DXGraphicsStateGuardian7::
03524 copy_texture(TextureContext *tc, const DisplayRegion *dr) {
03525 
03526     nassertv(tc != NULL && dr != NULL);
03527 
03528     Texture *tex = tc->_texture;
03529 
03530     // Determine the size of the grab from the given display region
03531     // If the requested region is not a power of two, grab a region that is
03532     // a power of two that contains the requested region
03533     int xo, yo, req_w, req_h;
03534     dr->get_region_pixels(xo, yo, req_w, req_h);
03535     int w = binary_log_cap(req_w);
03536     int h = binary_log_cap(req_h);
03537     if (w != req_w || h != req_h) {
03538         tex->_requested_w = req_w;
03539         tex->_requested_h = req_h;
03540         tex->_has_requested_size = true;
03541     }
03542 
03543     PixelBuffer *pb = tex->_pbuffer;
03544 
03545     pb->set_xorg(xo);
03546     pb->set_yorg(yo);
03547     pb->set_xsize(w);
03548     pb->set_ysize(h);
03549 
03550 
03551     bind_texture(tc);
03552     glCopyTexImage2D( GL_TEXTURE_2D, tex->get_level(),
03553                       get_internal_image_format(pb->get_format()),
03554                       pb->get_xorg(), pb->get_yorg(),
03555                       pb->get_xsize(), pb->get_ysize(), pb->get_border() );
03556 }
03557 #endif
03558 
03559 ////////////////////////////////////////////////////////////////////
03560 //     Function: DXGraphicsStateGuardian7::copy_texture
03561 //       Access: Public, Virtual
03562 //  Description:
03563 ////////////////////////////////////////////////////////////////////
03564 void DXGraphicsStateGuardian7::
03565 copy_texture(TextureContext *tc, const DisplayRegion *dr, const RenderBuffer &rb) {
03566     dxgsg7_cat.fatal() << "DX copy_texture unimplemented!!!";
03567     return;
03568 
03569     set_read_buffer(rb);
03570     copy_texture(tc, dr);
03571 }
03572 
03573 ////////////////////////////////////////////////////////////////////
03574 //     Function: DXGraphicsStateGuardian7::texture_to_pixel_buffer
03575 //       Access: Public, Virtual
03576 //  Description:
03577 ////////////////////////////////////////////////////////////////////
03578 void DXGraphicsStateGuardian7::
03579 texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb) {
03580 #if 1
03581     dxgsg7_cat.error()
03582       << "texture_to_pixel_buffer unimplemented!\n";
03583 #else
03584     nassertv(tc != NULL && pb != NULL);
03585 
03586     Texture *tex = tc->_texture;
03587 
03588     int w = tex->_pbuffer->get_xsize();
03589     int h = tex->_pbuffer->get_ysize();
03590 
03591     PT(DisplayRegion) dr = _win->make_scratch_display_region(w, h);
03592 
03593     FrameBufferStack old_fb = push_frame_buffer
03594                               (get_render_buffer(RenderBuffer::T_back | RenderBuffer::T_depth),
03595                                dr);
03596 
03597     texture_to_pixel_buffer(tc, pb, dr);
03598 
03599     pop_frame_buffer(old_fb);
03600 #endif
03601 }
03602 
03603 ////////////////////////////////////////////////////////////////////
03604 //     Function: DXGraphicsStateGuardian7::texture_to_pixel_buffer
03605 //       Access: Public, Virtual
03606 //  Description:
03607 ////////////////////////////////////////////////////////////////////
03608 void DXGraphicsStateGuardian7::
03609 texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
03610                         const DisplayRegion *dr) {
03611     dxgsg7_cat.error()
03612       << "texture_to_pixel_buffer unimplemented!\n";
03613 }
03614 
03615 ////////////////////////////////////////////////////////////////////
03616 //     Function: DXGraphicsStateGuardian7::copy_pixel_buffer
03617 //       Access: Public, Virtual
03618 //  Description:
03619 ////////////////////////////////////////////////////////////////////
03620 void DXGraphicsStateGuardian7::
03621 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
03622 
03623     extern HRESULT ConvertDDSurftoPixBuf(PixelBuffer *pixbuf,LPDIRECTDRAWSURFACE7 pDDSurf);
03624 
03625     nassertv(pb != NULL && dr != NULL);
03626 
03627     int xo, yo, w, h;
03628     dr->get_region_pixels(xo, yo, w, h);
03629 
03630     // only handled simple case
03631     nassertv(xo==0);
03632     nassertv(yo==0);
03633     nassertv(w==pb->get_xsize());
03634     nassertv(h==pb->get_ysize());
03635 
03636 /*
03637     set_pack_alignment(1);
03638     glReadPixels( pb->get_xorg() + xo, pb->get_yorg() + yo,
03639                   pb->get_xsize(), pb->get_ysize(),
03640                   get_external_image_format(pb->get_format()),
03641                   get_image_type(pb->get_image_type()),
03642                   pb->_image.p() );
03643 */
03644 
03645 
03646     (void) ConvertDDSurftoPixBuf(pb,((_cur_read_pixel_buffer & RenderBuffer::T_back) ? _pScrn->pddsBack : _pScrn->pddsPrimary));
03647 
03648     nassertv(!pb->_image.empty());
03649 }
03650 
03651 ////////////////////////////////////////////////////////////////////
03652 //     Function: DXGraphicsStateGuardian7::copy_pixel_buffer
03653 //       Access: Public, Virtual
03654 //  Description:
03655 ////////////////////////////////////////////////////////////////////
03656 void DXGraphicsStateGuardian7::
03657 copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
03658                   const RenderBuffer &rb) {
03659     set_read_buffer(rb);
03660     copy_pixel_buffer(pb, dr);
03661 }
03662 
03663 ////////////////////////////////////////////////////////////////////
03664 //     Function: DXGraphicsStateGuardian7::apply_material
03665 //       Access: Public, Virtual
03666 //  Description:
03667 ////////////////////////////////////////////////////////////////////
03668 void DXGraphicsStateGuardian7::apply_material( const Material* material ) {
03669     D3DMATERIAL7 cur_material;
03670     cur_material.dcvDiffuse = *(D3DCOLORVALUE *)(material->get_diffuse().get_data());
03671     cur_material.dcvAmbient = *(D3DCOLORVALUE *)(material->get_ambient().get_data());
03672     cur_material.dcvSpecular = *(D3DCOLORVALUE *)(material->get_specular().get_data());
03673     cur_material.dcvEmissive = *(D3DCOLORVALUE *)(material->get_emission().get_data());
03674     cur_material.dvPower   =  material->get_shininess();
03675     _pScrn->pD3DDevice->SetMaterial(&cur_material);
03676 }
03677 
03678 ////////////////////////////////////////////////////////////////////
03679 //     Function: DXGraphicsStateGuardian7::apply_fog
03680 //       Access: Public, Virtual
03681 //  Description:
03682 ////////////////////////////////////////////////////////////////////
03683 void DXGraphicsStateGuardian7::
03684 apply_fog(Fog *fog) {
03685   if(_doFogType==None)
03686     return;
03687 
03688   Fog::Mode panda_fogmode = fog->get_mode();
03689   D3DFOGMODE d3dfogmode = get_fog_mode_type(panda_fogmode);
03690 
03691 
03692   // should probably avoid doing redundant SetRenderStates, but whatever
03693   _pScrn->pD3DDevice->SetRenderState((D3DRENDERSTATETYPE)_doFogType, d3dfogmode);
03694 
03695   const Colorf &fog_colr = fog->get_color();
03696   _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR,
03697                                   MY_D3DRGBA(fog_colr[0], fog_colr[1], fog_colr[2], 0.0f));  // Alpha bits are not used
03698 
03699   // do we need to adjust fog start/end values based on D3DPRASTERCAPS_WFOG/D3DPRASTERCAPS_ZFOG ?
03700   // if not WFOG, then docs say we need to adjust values to range [0,1]
03701 
03702   switch (panda_fogmode) {
03703   case Fog::M_linear:
03704     {
03705       float onset, opaque;
03706       fog->get_linear_range(onset, opaque);
03707 
03708       _pScrn->pD3DDevice->SetRenderState( D3DRENDERSTATE_FOGSTART,
03709                                        *((LPDWORD) (&onset)) );
03710       _pScrn->pD3DDevice->SetRenderState( D3DRENDERSTATE_FOGEND,
03711                                        *((LPDWORD) (&opaque)) );
03712     }
03713     break;
03714   case Fog::M_exponential:
03715   case Fog::M_exponential_squared:
03716     {
03717       // Exponential fog is always camera-relative.
03718       float fog_density = fog->get_exp_density();
03719       _pScrn->pD3DDevice->SetRenderState( D3DRENDERSTATE_FOGDENSITY,
03720                                        *((LPDWORD) (&fog_density)) );
03721     }
03722     break;
03723   }
03724 }
03725 
03726 void DXGraphicsStateGuardian7::SetTextureBlendMode(TextureApplyAttrib::Mode TexBlendMode,bool bCanJustEnable) {
03727 
03728 /*class TextureApplyAttrib {
03729   enum Mode {
03730     M_modulate,M_decal,M_blend,M_replace,M_add};
03731 */
03732     static D3DTEXTUREOP TexBlendColorOp1[/* TextureApplyAttrib::Mode maxval*/ 10] =
03733     {D3DTOP_MODULATE,D3DTOP_BLENDTEXTUREALPHA,D3DTOP_MODULATE,D3DTOP_SELECTARG1,D3DTOP_ADD};
03734 
03735     //if bCanJustEnable, then we only need to make sure ColorOp is turned on and set properly
03736     if (bCanJustEnable && (TexBlendMode==_CurTexBlendMode)) {
03737         // just reset COLOROP 0 to enable pipeline, rest is already set properly
03738         _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, TexBlendColorOp1[TexBlendMode] );
03739         return;
03740     }
03741 
03742     _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP, TexBlendColorOp1[TexBlendMode] );
03743 
03744     switch (TexBlendMode) {
03745 
03746         case TextureApplyAttrib::M_modulate:
03747             // emulates GL_MODULATE glTexEnv mode
03748             // want to multiply tex-color*pixel color to emulate GL modulate blend (see glTexEnv)
03749             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
03750             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
03751             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
03752             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
03753             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
03754 
03755             break;
03756         case TextureApplyAttrib::M_decal:
03757             // emulates GL_DECAL glTexEnv mode
03758             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
03759             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
03760 
03761             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
03762             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
03763 
03764             break;
03765         case TextureApplyAttrib::M_replace:
03766             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
03767 
03768             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
03769             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
03770             break;
03771         case TextureApplyAttrib::M_add:
03772             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
03773             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
03774 
03775             // since I'm making up 'add' mode, use modulate.  "adding" alpha never makes sense right?
03776             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
03777             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
03778             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
03779 
03780             break;
03781         case TextureApplyAttrib::M_blend:
03782             dxgsg7_cat.error()
03783             << "Impossible to emulate GL_BLEND in DX exactly " << (int) TexBlendMode << endl;
03784 /*
03785            // emulate GL_BLEND glTexEnv
03786 
03787            GL requires 2 independent operations on 3 input vars for this mode
03788            DX texture pipeline requires re-using input of last stage on each new op, so I dont think
03789            exact emulation is possible
03790            _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
03791            _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE | D3DTA_COMPLEMENT );
03792            _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
03793 
03794            _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
03795            _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
03796            _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
03797 
03798            need to SetTexture(1,tex) also
03799            _pScrn->pD3DDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_MODULATE ); wrong
03800            _pScrn->pD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
03801            _pScrn->pD3DDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TFACTOR );
03802 
03803            _pScrn->pD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
03804            _pScrn->pD3DDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT );
03805 */
03806 
03807 
03808             break;
03809         default:
03810             dxgsg7_cat.error() << "Unknown texture blend mode " << (int) TexBlendMode << endl;
03811             break;
03812     }
03813 }
03814 
03815 
03816 ////////////////////////////////////////////////////////////////////
03817 //     Function: DXGraphicsStateGuardian7::enable_texturing
03818 //       Access:
03819 //  Description:
03820 ////////////////////////////////////////////////////////////////////
03821 INLINE void DXGraphicsStateGuardian7::
03822 enable_texturing(bool val) {
03823 //  if (_texturing_enabled == val) {  // this check is mostly for internal gsg calls, panda already screens out redundant state changes
03824 //        return;
03825 //  }
03826 
03827     _texturing_enabled = val;
03828 
03829 //  assert(_pCurTexContext!=NULL);  we're definitely called with it NULL for both true and false
03830 //  I'm going to allow enabling texturing even if no tex has been set yet, seems to cause no probs
03831 
03832     if (val == FALSE) {
03833         _pScrn->pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE);
03834     } else {
03835           SetTextureBlendMode(_CurTexBlendMode,TRUE);
03836     }
03837 }
03838 
03839 ////////////////////////////////////////////////////////////////////
03840 //     Function: DXGraphicsStateGuardian7::issue_transform
03841 //       Access: Public, Virtual
03842 //  Description: Sends the indicated transform matrix to the graphics
03843 //               API to be applied to future vertices.
03844 ////////////////////////////////////////////////////////////////////
03845 void DXGraphicsStateGuardian7::
03846 issue_transform(const TransformState *transform) {
03847   _pScrn->pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD,
03848                                 (LPD3DMATRIX)transform->get_mat().get_data());
03849 }
03850 
03851 ////////////////////////////////////////////////////////////////////
03852 //     Function: DXGraphicsStateGuardian7::issue_tex_matrix
03853 //       Access: Public, Virtual
03854 //  Description:
03855 ////////////////////////////////////////////////////////////////////
03856 void DXGraphicsStateGuardian7::
03857 issue_tex_matrix(const TexMatrixAttrib *attrib) {
03858   // Not implemented.
03859 }
03860 
03861 ////////////////////////////////////////////////////////////////////
03862 //     Function: DXGraphicsStateGuardian7::issue_texture
03863 //       Access: Public, Virtual
03864 //  Description:
03865 ////////////////////////////////////////////////////////////////////
03866 void DXGraphicsStateGuardian7::
03867 issue_texture(const TextureAttrib *attrib) {
03868   if (attrib->is_off()) {
03869     enable_texturing(false);
03870   } else {
03871     enable_texturing(true);
03872     Texture *tex = attrib->get_texture();
03873     nassertv(tex != (Texture *)NULL);
03874     tex->apply(this);
03875   }
03876 }
03877 
03878 ////////////////////////////////////////////////////////////////////
03879 //     Function: DXGraphicsStateGuardian7::issue_material
03880 //       Access: Public, Virtual
03881 //  Description:
03882 ////////////////////////////////////////////////////////////////////
03883 void DXGraphicsStateGuardian7::
03884 issue_material(const MaterialAttrib *attrib) {
03885   const Material *material = attrib->get_material();
03886   if (material != (const Material *)NULL) {
03887     apply_material(material);
03888   } else {
03889     // Apply a default material when materials are turned off.
03890     Material empty;
03891     apply_material(&empty);
03892   }
03893 }
03894 
03895 ////////////////////////////////////////////////////////////////////
03896 //     Function: DXGraphicsStateGuardian7::issue_render_mode
03897 //       Access: Public, Virtual
03898 //  Description:
03899 ////////////////////////////////////////////////////////////////////
03900 void DXGraphicsStateGuardian7::
03901 issue_render_mode(const RenderModeAttrib *attrib) {
03902   RenderModeAttrib::Mode mode = attrib->get_mode();
03903 
03904   switch (mode) {
03905   case RenderModeAttrib::M_filled:
03906     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID);
03907     break;
03908 
03909   case RenderModeAttrib::M_wireframe:
03910     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_WIREFRAME);
03911     break;
03912 
03913   default:
03914     dxgsg7_cat.error()
03915       << "Unknown render mode " << (int)mode << endl;
03916   }
03917 
03918   _current_fill_mode = mode;
03919 }
03920 
03921 ////////////////////////////////////////////////////////////////////
03922 //     Function: DXGraphicsStateGuardian7::issue_texture_apply
03923 //       Access: Public, Virtual
03924 //  Description:
03925 ////////////////////////////////////////////////////////////////////
03926 void DXGraphicsStateGuardian7::
03927 issue_texture_apply(const TextureApplyAttrib *attrib) {
03928 }
03929 
03930 ////////////////////////////////////////////////////////////////////
03931 //     Function: DXGraphicsStateGuardian7::issue_depth_test
03932 //       Access: Public, Virtual
03933 //  Description:
03934 ////////////////////////////////////////////////////////////////////
03935 void DXGraphicsStateGuardian7::
03936 issue_depth_test(const DepthTestAttrib *attrib) {
03937   DepthTestAttrib::PandaCompareFunc mode = attrib->get_mode();
03938   if (mode == DepthTestAttrib::M_none) {
03939     _depth_test_enabled = false;
03940     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
03941   } else {
03942     _depth_test_enabled = true;
03943     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_TRUE);
03944     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, (D3DCMPFUNC) mode);
03945   }
03946 }
03947 
03948 ////////////////////////////////////////////////////////////////////
03949 //     Function: DXGraphicsStateGuardian7::issue_alpha_test
03950 //       Access: Public, Virtual
03951 //  Description:
03952 ////////////////////////////////////////////////////////////////////
03953 void DXGraphicsStateGuardian7::
03954 issue_alpha_test(const AlphaTestAttrib *attrib) {
03955   AlphaTestAttrib::PandaCompareFunc mode = attrib->get_mode();
03956   if (mode == AlphaTestAttrib::M_none) {
03957     enable_alpha_test(false);
03958   } else {
03959     //  AlphaTestAttrib::PandaCompareFunc === D3DCMPFUNC
03960     call_dxAlphaFunc((D3DCMPFUNC)mode, attrib->get_reference_alpha());
03961     enable_alpha_test(true);
03962   }
03963 }
03964 
03965 ////////////////////////////////////////////////////////////////////
03966 //     Function: DXGraphicsStateGuardian7::issue_depth_write
03967 //       Access: Public, Virtual
03968 //  Description:
03969 ////////////////////////////////////////////////////////////////////
03970 void DXGraphicsStateGuardian7::
03971 issue_depth_write(const DepthWriteAttrib *attrib) {
03972   enable_zwritemask(attrib->get_mode() == DepthWriteAttrib::M_on);
03973 }
03974 
03975 ////////////////////////////////////////////////////////////////////
03976 //     Function: DXGraphicsStateGuardian7::issue_cull_face
03977 //       Access: Public, Virtual
03978 //  Description:
03979 ////////////////////////////////////////////////////////////////////
03980 void DXGraphicsStateGuardian7::
03981 issue_cull_face(const CullFaceAttrib *attrib) {
03982   CullFaceAttrib::Mode mode = attrib->get_effective_mode();
03983 
03984   switch (mode) {
03985   case CullFaceAttrib::M_cull_none:
03986     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
03987     break;
03988   case CullFaceAttrib::M_cull_clockwise:
03989     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CW);
03990     break;
03991   case CullFaceAttrib::M_cull_counter_clockwise:
03992     _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW);
03993     break;
03994   default:
03995     dxgsg7_cat.error()
03996       << "invalid cull face mode " << (int)mode << endl;
03997     break;
03998   }
03999 }
04000 
04001 ////////////////////////////////////////////////////////////////////
04002 //     Function: DXGraphicsStateGuardian7::issue_fog
04003 //       Access: Public, Virtual
04004 //  Description:
04005 ////////////////////////////////////////////////////////////////////
04006 void DXGraphicsStateGuardian7::
04007 issue_fog(const FogAttrib *attrib) {
04008   if (!attrib->is_off()) {
04009     enable_fog(true);
04010     Fog *fog = attrib->get_fog();
04011     nassertv(fog != (Fog *)NULL);
04012     apply_fog(fog);
04013   } else {
04014     enable_fog(false);
04015   }
04016 }
04017 
04018 ////////////////////////////////////////////////////////////////////
04019 //     Function: DXGraphicsStateGuardian7::issue_depth_offset
04020 //       Access: Public, Virtual
04021 //  Description:
04022 ////////////////////////////////////////////////////////////////////
04023 void DXGraphicsStateGuardian7::
04024 issue_depth_offset(const DepthOffsetAttrib *attrib) {
04025   int offset = attrib->get_offset();
04026   _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_ZBIAS, offset);
04027 }
04028 
04029 ////////////////////////////////////////////////////////////////////
04030 //     Function: DXGraphicsStateGuardian7::bind_light
04031 //       Access: Public, Virtual
04032 //  Description: Called the first time a particular light has been
04033 //               bound to a given id within a frame, this should set
04034 //               up the associated hardware light with the light's
04035 //               properties.
04036 ////////////////////////////////////////////////////////////////////
04037 void DXGraphicsStateGuardian7::
04038 bind_light(PointLight *light, int light_id) {
04039   // Get the light in "world coordinates".  This means the light in
04040   // the coordinate space of the camera, converted to DX's coordinate
04041   // system.
04042   NodePath light_np(light);
04043   const LMatrix4f &light_mat = light_np.get_mat(_scene_setup->get_camera_path());
04044   LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
04045   LPoint3f pos = light->get_point() * rel_mat;
04046 
04047   D3DCOLORVALUE black;
04048   black.r = black.g = black.b = black.a = 0.0f;
04049   D3DLIGHT7  alight;
04050   alight.dltType =  D3DLIGHT_POINT;
04051   alight.dcvDiffuse  = *(D3DCOLORVALUE *)(light->get_color().get_data());
04052   alight.dcvAmbient  =  black ;
04053   alight.dcvSpecular = *(D3DCOLORVALUE *)(light->get_specular_color().get_data());
04054 
04055   // Position needs to specify x, y, z, and w
04056   // w == 1 implies non-infinite position
04057   alight.dvPosition = *(D3DVECTOR *)pos.get_data();
04058 
04059   alight.dvRange =  D3DLIGHT_RANGE_MAX;
04060   alight.dvFalloff =  1.0f;
04061 
04062   const LVecBase3f &att = light->get_attenuation();
04063   alight.dvAttenuation0 = (D3DVALUE)att[0];
04064   alight.dvAttenuation1 = (D3DVALUE)att[1];
04065   alight.dvAttenuation2 = (D3DVALUE)att[2];
04066 
04067   HRESULT res = _pScrn->pD3DDevice->SetLight(light_id, &alight);
04068 }
04069 
04070 ////////////////////////////////////////////////////////////////////
04071 //     Function: DXGraphicsStateGuardian7::bind_light
04072 //       Access: Public, Virtual
04073 //  Description: Called the first time a particular light has been
04074 //               bound to a given id within a frame, this should set
04075 //               up the associated hardware light with the light's
04076 //               properties.
04077 ////////////////////////////////////////////////////////////////////
04078 void DXGraphicsStateGuardian7::
04079 bind_light(DirectionalLight *light, int light_id) {
04080   // Get the light in "world coordinates".  This means the light in
04081   // the coordinate space of the camera, converted to DX's coordinate
04082   // system.
04083   NodePath light_np(light);
04084   const LMatrix4f &light_mat = light_np.get_mat(_scene_setup->get_camera_path());
04085   LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
04086   LVector3f dir = light->get_direction() * rel_mat;
04087 
04088   D3DCOLORVALUE black;
04089   black.r = black.g = black.b = black.a = 0.0f;
04090 
04091   D3DLIGHT7  alight;
04092   ZeroMemory(&alight, sizeof(D3DLIGHT7));
04093 
04094   alight.dltType =  D3DLIGHT_DIRECTIONAL;
04095   alight.dcvDiffuse  = *(D3DCOLORVALUE *)(light->get_color().get_data());
04096   alight.dcvAmbient  =  black ;
04097   alight.dcvSpecular = *(D3DCOLORVALUE *)(light->get_specular_color().get_data());
04098 
04099   alight.dvDirection = *(D3DVECTOR *)dir.get_data();
04100 
04101   alight.dvRange =  D3DLIGHT_RANGE_MAX;
04102   alight.dvFalloff =  1.0f;
04103 
04104   alight.dvAttenuation0 = 1.0f;       // constant
04105   alight.dvAttenuation1 = 0.0f;       // linear
04106   alight.dvAttenuation2 = 0.0f;       // quadratic
04107 
04108   HRESULT res = _pScrn->pD3DDevice->SetLight(light_id, &alight);
04109 }
04110 
04111 ////////////////////////////////////////////////////////////////////
04112 //     Function: DXGraphicsStateGuardian7::bind_light
04113 //       Access: Public, Virtual
04114 //  Description: Called the first time a particular light has been
04115 //               bound to a given id within a frame, this should set
04116 //               up the associated hardware light with the light's
04117 //               properties.
04118 ////////////////////////////////////////////////////////////////////
04119 void DXGraphicsStateGuardian7::
04120 bind_light(Spotlight *light, int light_id) {
04121   Lens *lens = light->get_lens();
04122   nassertv(lens != (Lens *)NULL);
04123 
04124   // Get the light in "world coordinates".  This means the light in
04125   // the coordinate space of the camera, converted to DX's coordinate
04126   // system.
04127   NodePath light_np(light);
04128   const LMatrix4f &light_mat = light_np.get_mat(_scene_setup->get_camera_path());
04129   LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
04130   LPoint3f pos = lens->get_nodal_point() * rel_mat;
04131   LVector3f dir = lens->get_view_vector() * rel_mat;
04132 
04133   D3DCOLORVALUE black;
04134   black.r = black.g = black.b = black.a = 0.0f;
04135 
04136   D3DLIGHT7  alight;
04137   ZeroMemory(&alight, sizeof(D3DLIGHT7));
04138 
04139   alight.dltType =  D3DLIGHT_SPOT;
04140   alight.dcvAmbient  =  black ;
04141   alight.dcvDiffuse  = *(D3DCOLORVALUE *)(light->get_color().get_data());
04142   alight.dcvSpecular = *(D3DCOLORVALUE *)(light->get_specular_color().get_data());
04143 
04144   alight.dvPosition = *(D3DVECTOR *)pos.get_data();
04145 
04146   alight.dvDirection = *(D3DVECTOR *)dir.get_data();
04147 
04148   alight.dvRange =  D3DLIGHT_RANGE_MAX;
04149   alight.dvFalloff =  1.0f;
04150   alight.dvTheta =  0.0f;
04151   alight.dvPhi =  lens->get_hfov();
04152 
04153   const LVecBase3f &att = light->get_attenuation();
04154   alight.dvAttenuation0 = (D3DVALUE)att[0];
04155   alight.dvAttenuation1 = (D3DVALUE)att[1];
04156   alight.dvAttenuation2 = (D3DVALUE)att[2];
04157 
04158   HRESULT res = _pScrn->pD3DDevice->SetLight(light_id, &alight);
04159 }
04160 
04161 #if 0
04162 ////////////////////////////////////////////////////////////////////
04163 //     Function: DXGraphicsStateGuardian7::begin_frame
04164 //       Access: Public, Virtual
04165 //  Description: Called before each frame is rendered, to allow the
04166 //               GSG a chance to do any internal cleanup before
04167 //               beginning the frame.
04168 //
04169 //               The return value is true if successful (in which case
04170 //               the frame will be drawn and end_frame() will be
04171 //               called later), or false if unsuccessful (in which
04172 //               case nothing will be drawn and end_frame() will not
04173 //               be called).
04174 ////////////////////////////////////////////////////////////////////
04175 bool DXGraphicsStateGuardian7::
04176 begin_frame() {
04177   return GraphicsStateGuardian::begin_frame();
04178 }
04179 #endif
04180 
04181 ////////////////////////////////////////////////////////////////////
04182 //     Function: DXGraphicsStateGuardian7::begin_scene
04183 //       Access: Public, Virtual
04184 //  Description: Called between begin_frame() and end_frame() to mark
04185 //               the beginning of drawing commands for a "scene"
04186 //               (usually a particular DisplayRegion) within a frame.
04187 //               All 3-D drawing commands, except the clear operation,
04188 //               must be enclosed within begin_scene() .. end_scene().
04189 //
04190 //               The return value is true if successful (in which case
04191 //               the scene will be drawn and end_scene() will be
04192 //               called later), or false if unsuccessful (in which
04193 //               case nothing will be drawn and end_scene() will not
04194 //               be called).
04195 ////////////////////////////////////////////////////////////////////
04196 bool DXGraphicsStateGuardian7::
04197 begin_scene() {
04198   if (!GraphicsStateGuardian::begin_scene()) {
04199     return false;
04200   }
04201 
04202   HRESULT hr = _pScrn->pD3DDevice->BeginScene();
04203 
04204   if (FAILED(hr)) {
04205     if ((hr == DDERR_SURFACELOST) || (hr == DDERR_SURFACEBUSY)) {
04206       if (dxgsg7_cat.is_debug()) {
04207         dxgsg7_cat.debug()
04208           << "BeginScene returns " << ConvD3DErrorToString(hr) << endl;
04209       }
04210       
04211       CheckCooperativeLevel();
04212 
04213     } else {
04214       dxgsg7_cat.error()
04215         << "BeginScene failed, unhandled error hr == "
04216         << ConvD3DErrorToString(hr) << endl;
04217       exit(1);
04218     }
04219     return false;
04220   }
04221 
04222   return true;
04223 }
04224 
04225 ////////////////////////////////////////////////////////////////////
04226 //     Function: DXGraphicsStateGuardian7::end_scene
04227 //       Access: Public, Virtual
04228 //  Description: Called between begin_frame() and end_frame() to mark
04229 //               the end of drawing commands for a "scene" (usually a
04230 //               particular DisplayRegion) within a frame.  All 3-D
04231 //               drawing commands, except the clear operation, must be
04232 //               enclosed within begin_scene() .. end_scene().
04233 ////////////////////////////////////////////////////////////////////
04234 void DXGraphicsStateGuardian7::
04235 end_scene() {
04236   HRESULT hr = _pScrn->pD3DDevice->EndScene();
04237 
04238   if (FAILED(hr)) {
04239     if ((hr == DDERR_SURFACELOST) || (hr == DDERR_SURFACEBUSY)) {
04240       if (dxgsg7_cat.is_debug()) {
04241         dxgsg7_cat.debug()
04242           << "EndScene returns " << ConvD3DErrorToString(hr) << endl;
04243       }
04244 
04245       CheckCooperativeLevel();
04246 
04247     } else {
04248       dxgsg7_cat.error()
04249         << "EndScene failed, unhandled error hr == " 
04250         << ConvD3DErrorToString(hr) << endl;
04251       exit(1);
04252     }
04253   }
04254 
04255   GraphicsStateGuardian::end_scene();
04256 }
04257 
04258 ////////////////////////////////////////////////////////////////////
04259 //     Function: DXGraphicsStateGuardian7::end_frame
04260 //       Access: Public, Virtual
04261 //  Description: Called after each frame is rendered, to allow the
04262 //               GSG a chance to do any internal cleanup after
04263 //               rendering the frame, and before the window flips.
04264 ////////////////////////////////////////////////////////////////////
04265 void DXGraphicsStateGuardian7::
04266 end_frame() {
04267 #ifdef COUNT_DRAWPRIMS
04268   {
04269 #define FRAMES_PER_DPINFO 90
04270     static DWORD LastDPInfoFrame=0;
04271     static DWORD LastTickCount=0;
04272 
04273     if (_cur_frame_count-LastDPInfoFrame > FRAMES_PER_DPINFO) {
04274       DWORD CurTickCount=GetTickCount();
04275       float delta_secs=(CurTickCount-LastTickCount)/1000.0f;
04276 
04277       float numframes=_cur_frame_count-LastDPInfoFrame;
04278       float verts_per_frame = cVertcount/numframes;
04279       float tris_per_frame = cTricount/numframes;
04280       float DPs_per_frame = cDPcount/numframes;
04281       float DPs_notexchange_per_frame = cDP_noTexChangeCount/numframes;
04282       float verts_per_DP = cVertcount/(float)cDPcount;
04283       float verts_per_sec = cVertcount/delta_secs;
04284       float tris_per_sec = cTricount/delta_secs;
04285       float Geoms_per_frame = cGeomcount/numframes;
04286       float DrawPrims_per_Geom = cDPcount/(float)cGeomcount;
04287       float verts_per_Geom = cVertcount/(float)cGeomcount;
04288 
04289       dxgsg7_cat.debug() << "==================================="
04290                         << "\n Avg Verts/sec:\t\t" << verts_per_sec
04291                         << "\n Avg Tris/sec:\t\t" << tris_per_sec
04292                         << "\n Avg Verts/frame:\t" << verts_per_frame
04293                         << "\n Avg Tris/frame:\t" << tris_per_frame
04294                         << "\n Avg DrawPrims/frm:\t" << DPs_per_frame
04295                         << "\n Avg Verts/DrawPrim:\t" << verts_per_DP
04296                         << "\n Avg DrawPrims w/no Texture Change from prev DrawPrim/frm:\t" << DPs_notexchange_per_frame
04297                         << "\n Avg Geoms/frm:\t" << Geoms_per_frame
04298                         << "\n Avg DrawPrims/Geom:\t" << DrawPrims_per_Geom
04299                         << "\n Avg Verts/Geom:\t" << verts_per_Geom
04300                         << endl;
04301 
04302       LastDPInfoFrame=_cur_frame_count;
04303       cDPcount = cVertcount=cTricount=cDP_noTexChangeCount=cGeomcount=0;
04304       LastTickCount=CurTickCount;
04305     }
04306   }
04307 #endif
04308 
04309 #if defined(DO_PSTATS)||defined(PRINT_TEXSTATS)
04310 #ifndef PRINT_TEXSTATS
04311   if (_texmgrmem_total_pcollector.is_active())
04312 #endif
04313   {
04314 #define TICKS_PER_GETTEXINFO (2.5*1000)   // 2.5 second interval
04315     static DWORD LastTickCount=0;
04316     DWORD CurTickCount=GetTickCount();
04317 
04318     if (CurTickCount-LastTickCount > TICKS_PER_GETTEXINFO) {
04319       LastTickCount=CurTickCount;
04320       report_texmgr_stats();
04321     }
04322   }
04323 #endif
04324 
04325   // Note: regular GraphicsWindow::end_frame is being called,
04326   // but we override gsg::end_frame, so need to explicitly call it here
04327   // (currently it's an empty fn)
04328   GraphicsStateGuardian::end_frame();
04329 }
04330 
04331 ////////////////////////////////////////////////////////////////////
04332 //     Function: DXGraphicsStateGuardian7::wants_normals
04333 //       Access: Public, Virtual
04334 //  Description:
04335 ////////////////////////////////////////////////////////////////////
04336 INLINE bool DXGraphicsStateGuardian7::
04337 wants_normals() const {
04338     return (_lighting_enabled || _normals_enabled);
04339 }
04340 
04341 ////////////////////////////////////////////////////////////////////
04342 //     Function: DXGraphicsStateGuardian7::wants_texcoords
04343 //       Access: Public, Virtual
04344 //  Description:
04345 ////////////////////////////////////////////////////////////////////
04346 INLINE bool DXGraphicsStateGuardian7::
04347 wants_texcoords() const {
04348     return _texturing_enabled;
04349 }
04350 
04351 
04352 ////////////////////////////////////////////////////////////////////
04353 //     Function: DXGraphicsStateGuardian7::depth_offset_decals
04354 //       Access: Public, Virtual
04355 //  Description: Returns true if this GSG can implement decals using a
04356 //               DepthOffsetAttrib, or false if that is unreliable
04357 //               and the three-step rendering process should be used
04358 //               instead.
04359 ////////////////////////////////////////////////////////////////////
04360 bool DXGraphicsStateGuardian7::
04361 depth_offset_decals() {
04362   return dx_depth_offset_decals;
04363 }
04364 
04365 ////////////////////////////////////////////////////////////////////
04366 //     Function: DXGraphicsStateGuardian7::get_internal_coordinate_system
04367 //       Access: Public, Virtual
04368 //  Description: Should be overridden by derived classes to return the
04369 //               coordinate system used internally by the GSG, if any
04370 //               one particular coordinate system is used.  The
04371 //               default, CS_default, indicates that the GSG can use
04372 //               any coordinate system.
04373 //
04374 //               If this returns other than CS_default, the
04375 //               GraphicsEngine will automatically convert all
04376 //               transforms into the indicated coordinate system.
04377 ////////////////////////////////////////////////////////////////////
04378 CoordinateSystem DXGraphicsStateGuardian7::
04379 get_internal_coordinate_system() const {
04380   return CS_yup_left;
04381 }
04382 
04383 ////////////////////////////////////////////////////////////////////
04384 //     Function: DXGraphicsStateGuardian7::compute_distance_to
04385 //       Access: Public, Virtual
04386 //  Description: This function may only be called during a render
04387 //               traversal; it will compute the distance to the
04388 //               indicated point, assumed to be in modelview
04389 //               coordinates, from the camera plane.
04390 ////////////////////////////////////////////////////////////////////
04391 INLINE float DXGraphicsStateGuardian7::
04392 compute_distance_to(const LPoint3f &point) const {
04393     // In the case of a DXGraphicsStateGuardian7, we know that the
04394     // modelview matrix already includes the relative transform from the
04395     // camera, as well as a to-y-up conversion.  Thus, the distance to
04396     // the camera plane is simply the +z distance.  (negative of gl compute_distance_to,
04397     // since d3d uses left-hand coords)
04398 
04399     return point[2];
04400 }
04401 
04402 ////////////////////////////////////////////////////////////////////
04403 //     Function: DXGraphicsStateGuardian7::set_draw_buffer
04404 //       Access: Protected
04405 //  Description: Sets up the glDrawBuffer to render into the buffer
04406 //               indicated by the RenderBuffer object.  This only sets
04407 //               up the color bits; it does not affect the depth,
04408 //               stencil, accum layers.
04409 ////////////////////////////////////////////////////////////////////
04410 void DXGraphicsStateGuardian7::
04411 set_draw_buffer(const RenderBuffer &rb) {
04412     dxgsg7_cat.fatal() << "DX set_draw_buffer unimplemented!!!";
04413     return;
04414 
04415 #ifdef WBD_GL_MODE
04416     switch (rb._buffer_type & RenderBuffer::T_color) {
04417         case RenderBuffer::T_front:
04418             call_glDrawBuffer(GL_FRONT);
04419             break;
04420 
04421         case RenderBuffer::T_back:
04422             call_glDrawBuffer(GL_BACK);
04423             break;
04424 
04425         case RenderBuffer::T_right:
04426             call_glDrawBuffer(GL_RIGHT);
04427             break;
04428 
04429         case RenderBuffer::T_left:
04430             call_glDrawBuffer(GL_LEFT);
04431             break;
04432 
04433         case RenderBuffer::T_front_right:
04434             call_glDrawBuffer(GL_FRONT_RIGHT);
04435             break;
04436 
04437         case RenderBuffer::T_front_left:
04438             call_glDrawBuffer(GL_FRONT_LEFT);
04439             break;
04440 
04441         case RenderBuffer::T_back_right:
04442             call_glDrawBuffer(GL_BACK_RIGHT);
04443             break;
04444 
04445         case RenderBuffer::T_back_left:
04446             call_glDrawBuffer(GL_BACK_LEFT);
04447             break;
04448 
04449         default:
04450             call_glDrawBuffer(GL_FRONT_AND_BACK);
04451     }
04452 #endif              // WBD_GL_MODE
04453 }
04454 
04455 ////////////////////////////////////////////////////////////////////
04456 //     Function: DXGraphicsStateGuardian7::set_read_buffer
04457 //       Access: Protected
04458 //  Description: Vestigial analog of glReadBuffer
04459 ////////////////////////////////////////////////////////////////////
04460 void DXGraphicsStateGuardian7::
04461 set_read_buffer(const RenderBuffer &rb) {
04462 
04463     if(rb._buffer_type & RenderBuffer::T_front) {
04464             _cur_read_pixel_buffer=RenderBuffer::T_front;
04465     } else  if(rb._buffer_type & RenderBuffer::T_back) {
04466             _cur_read_pixel_buffer=RenderBuffer::T_back;
04467     } else {
04468             dxgsg7_cat.error() << "Invalid or unimplemented Argument to set_read_buffer!\n";
04469     }
04470     return;
04471 }
04472 
04473 ////////////////////////////////////////////////////////////////////
04474 //     Function: DXGraphicsStateGuardian7::get_texture_wrap_mode
04475 //       Access: Protected
04476 //  Description: Maps from the Texture's internal wrap mode symbols to
04477 //               GL's.
04478 ////////////////////////////////////////////////////////////////////
04479 INLINE D3DTEXTUREADDRESS DXGraphicsStateGuardian7::
04480 get_texture_wrap_mode(Texture::WrapMode wm) const {
04481 
04482     if (wm == Texture::WM_clamp)
04483         return D3DTADDRESS_CLAMP;
04484     else if (wm != Texture::WM_repeat) {
04485 #ifdef _DEBUG
04486         dxgsg7_cat.error() << "Invalid or Unimplemented Texture::WrapMode value!\n";
04487 #endif
04488     }
04489 
04490     return D3DTADDRESS_WRAP;
04491 }
04492 
04493 ////////////////////////////////////////////////////////////////////
04494 //     Function: DXGraphicsStateGuardian7::get_fog_mode_type
04495 //       Access: Protected
04496 //  Description: Maps from the fog types to gl version
04497 ////////////////////////////////////////////////////////////////////
04498 INLINE D3DFOGMODE DXGraphicsStateGuardian7::
04499 get_fog_mode_type(Fog::Mode m) const {
04500   switch (m) {
04501   case Fog::M_linear:
04502     return D3DFOG_LINEAR;
04503   case Fog::M_exponential:
04504     return D3DFOG_EXP;
04505   case Fog::M_exponential_squared:
04506     return D3DFOG_EXP2;
04507   }
04508   dxgsg7_cat.error() << "Invalid Fog::Mode value" << endl;
04509   return D3DFOG_EXP;
04510 }
04511 
04512 ////////////////////////////////////////////////////////////////////
04513 //     Function: DXGraphicsStateGuardian7::enable_lighting
04514 //       Access: Protected, Virtual
04515 //  Description: Intended to be overridden by a derived class to
04516 //               enable or disable the use of lighting overall.  This
04517 //               is called by issue_light() according to whether any
04518 //               lights are in use or not.
04519 ////////////////////////////////////////////////////////////////////
04520 void DXGraphicsStateGuardian7::
04521 enable_lighting(bool enable) {
04522   _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, (DWORD)enable);
04523 }
04524 
04525 ////////////////////////////////////////////////////////////////////
04526 //     Function: DXGraphicsStateGuardian7::set_ambient_light
04527 //       Access: Protected, Virtual
04528 //  Description: Intended to be overridden by a derived class to
04529 //               indicate the color of the ambient light that should
04530 //               be in effect.  This is called by issue_light() after
04531 //               all other lights have been enabled or disabled.
04532 ////////////////////////////////////////////////////////////////////
04533 void DXGraphicsStateGuardian7::
04534 set_ambient_light(const Colorf &color) {
04535   _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT,
04536                                   Colorf_to_D3DCOLOR(color));
04537 }
04538 
04539 ////////////////////////////////////////////////////////////////////
04540 //     Function: DXGraphicsStateGuardian7::enable_light
04541 //       Access: Protected, Virtual
04542 //  Description: Intended to be overridden by a derived class to
04543 //               enable the indicated light id.  A specific Light will
04544 //               already have been bound to this id via bind_light().
04545 ////////////////////////////////////////////////////////////////////
04546 void DXGraphicsStateGuardian7::
04547 enable_light(int light_id, bool enable) {
04548   HRESULT res = _pScrn->pD3DDevice->LightEnable(light_id, enable);
04549 
04550 #ifdef GSG_VERBOSE
04551   dxgsg7_cat.debug()
04552     << "LightEnable(" << light_id << "=" << enable << ")" << endl;
04553 #endif
04554 }
04555 
04556 ////////////////////////////////////////////////////////////////////
04557 //     Function: DXGraphicsStateGuardian7::slot_new_clip_plane
04558 //       Access: Protected, Virtual
04559 //  Description: This will be called by the base class before a
04560 //               particular clip plane id will be used for the first
04561 //               time.  It is intended to allow the derived class to
04562 //               reserve any additional resources, if required, for
04563 //               the new clip plane; and also to indicate whether the
04564 //               hardware supports this many simultaneous clipping
04565 //               planes.
04566 //
04567 //               The return value should be true if the additional
04568 //               plane is supported, or false if it is not.
04569 ////////////////////////////////////////////////////////////////////
04570 bool DXGraphicsStateGuardian7::
04571 slot_new_clip_plane(int plane_id) {
04572   return (plane_id < D3DMAXUSERCLIPPLANES);
04573 }
04574 
04575 ////////////////////////////////////////////////////////////////////
04576 //     Function: DXGraphicsStateGuardian7::enable_clip_plane
04577 //       Access: Protected, Virtual
04578 //  Description: Intended to be overridden by a derived class to
04579 //               enable the indicated clip_plane id.  A specific
04580 //               PlaneNode will already have been bound to this id via
04581 //               bind_clip_plane().
04582 ////////////////////////////////////////////////////////////////////
04583 INLINE void DXGraphicsStateGuardian7::
04584 enable_clip_plane(int plane_id, bool enable) {
04585   assert(plane_id < D3DMAXUSERCLIPPLANES);
04586 
04587   DWORD bitflag = ((DWORD)1 << plane_id);
04588   if (enable) {
04589     _clip_plane_bits |= bitflag;
04590   } else {
04591     _clip_plane_bits &= ~bitflag;
04592   }
04593 
04594   _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPLANEENABLE, _clip_plane_bits);
04595 }
04596 
04597 ////////////////////////////////////////////////////////////////////
04598 //     Function: DXGraphicsStateGuardian7::bind_clip_plane
04599 //       Access: Protected, Virtual
04600 //  Description: Called the first time a particular clip_plane has been
04601 //               bound to a given id within a frame, this should set
04602 //               up the associated hardware clip_plane with the clip_plane's
04603 //               properties.
04604 ////////////////////////////////////////////////////////////////////
04605 void DXGraphicsStateGuardian7::
04606 bind_clip_plane(PlaneNode *plane, int plane_id) {
04607   // Get the plane in "world coordinates".  This means the plane in
04608   // the coordinate space of the camera, converted to DX's coordinate
04609   // system.
04610   NodePath plane_np(plane);
04611   const LMatrix4f &plane_mat = plane_np.get_mat(_scene_setup->get_camera_path());
04612   LMatrix4f rel_mat = plane_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
04613   Planef world_plane = plane->get_plane() * rel_mat;
04614 
04615   _pScrn->pD3DDevice->SetClipPlane(plane_id, (float *)world_plane.get_data());
04616 }
04617 
04618 ////////////////////////////////////////////////////////////////////
04619 //     Function: DXGraphicsStateGuardian7::set_blend_mode
04620 //       Access: Protected, Virtual
04621 //  Description: Called after any of these three blending states have
04622 //               changed; this function is responsible for setting the
04623 //               appropriate color blending mode based on the given
04624 //               properties.
04625 ////////////////////////////////////////////////////////////////////
04626 void DXGraphicsStateGuardian7::
04627 set_blend_mode(ColorWriteAttrib::Mode color_write_mode,
04628                ColorBlendAttrib::Mode color_blend_mode,
04629                TransparencyAttrib::Mode transparency_mode) {
04630   // If color_write_mode is off, we disable writing to the color using
04631   // blending.  I don't know if it is possible in DX to disable color
04632   // outside of a blend mode.
04633   if (color_write_mode == ColorWriteAttrib::M_off) {
04634     enable_blend(true);
04635     call_dxBlendFunc(D3DBLEND_ZERO, D3DBLEND_ONE);
04636     return;
04637   }
04638 
04639   // Is there a color blend set?
04640   switch (color_blend_mode) {
04641   case ColorBlendAttrib::M_none:
04642     break;
04643 
04644   case ColorBlendAttrib::M_multiply:
04645     enable_blend(true);
04646     call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ZERO);
04647     return;
04648 
04649   case ColorBlendAttrib::M_add:
04650     enable_blend(true);
04651     call_dxBlendFunc(D3DBLEND_ONE, D3DBLEND_ONE);
04652     return;
04653 
04654   case ColorBlendAttrib::M_multiply_add:
04655     enable_blend(true);
04656     call_dxBlendFunc(D3DBLEND_DESTCOLOR, D3DBLEND_ONE);
04657     return;
04658 
04659   default:
04660     dxgsg7_cat.error()
04661       << "Unknown color blend mode " << (int)color_blend_mode << endl;
04662     break;
04663   }
04664 
04665   // No color blend; is there a transparency set?
04666   switch (transparency_mode) {
04667   case TransparencyAttrib::M_none:
04668   case TransparencyAttrib::M_binary:
04669     break;
04670 
04671   case TransparencyAttrib::M_alpha:
04672   case TransparencyAttrib::M_alpha_sorted:
04673   case TransparencyAttrib::M_multisample:
04674   case TransparencyAttrib::M_multisample_mask:
04675   case TransparencyAttrib::M_dual:
04676     enable_blend(true);
04677     call_dxBlendFunc(D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA);
04678     return;
04679 
04680   default:
04681     dxgsg7_cat.error()
04682       << "invalid transparency mode " << (int)transparency_mode << endl;
04683     break;
04684   }
04685 
04686   // Nothing's set, so disable blending.
04687   enable_blend(false);
04688 }
04689 
04690 ////////////////////////////////////////////////////////////////////
04691 //     Function: DXGraphicsStateGuardian7::free_pointers
04692 //       Access: Public
04693 //  Description: Frees some memory that was explicitly allocated
04694 //               within the dxgsg7.
04695 ////////////////////////////////////////////////////////////////////
04696 void DXGraphicsStateGuardian7::
04697 free_pointers() {
04698 #ifdef USE_TEXFMTVEC
04699     _pScrn->TexPixFmts.clear();
04700 #else
04701     SAFE_DELETE_ARRAY(_pTexPixFmts);
04702 #endif
04703 }
04704 
04705 ////////////////////////////////////////////////////////////////////
04706 //     Function: DXGraphicsStateGuardian7::save_frame_buffer
04707 //       Access: Public
04708 //  Description: Saves the indicated planes of the frame buffer
04709 //               (within the indicated display region) and returns it
04710 //               in some meaningful form that can be restored later
04711 //               via restore_frame_buffer().  This is a helper
04712 //               function for push_frame_buffer() and
04713 //               pop_frame_buffer().
04714 ////////////////////////////////////////////////////////////////////
04715 PT(SavedFrameBuffer) DXGraphicsStateGuardian7::
04716 save_frame_buffer(const RenderBuffer &buffer,
04717                   CPT(DisplayRegion) dr) {
04718 
04719     dxgsg7_cat.error() << "save_frame_buffer unimplemented!!\n";
04720     return NULL;
04721 
04722 #if 0
04723     DXSavedFrameBuffer7 *sfb = new DXSavedFrameBuffer7(buffer, dr);
04724 
04725     if (buffer._buffer_type & RenderBuffer::T_depth) {
04726         // Save the depth buffer.
04727         sfb->_depth =
04728         new PixelBuffer(PixelBuffer::depth_buffer(dr->get_pixel_width(),
04729                                                   dr->get_pixel_height()));
04730         copy_pixel_buffer(sfb->_depth, dr, buffer);
04731     }
04732 
04733     if (buffer._buffer_type & RenderBuffer::T_back) {
04734         // Save the color buffer.
04735         sfb->_back_rgba = new Texture;
04736         copy_texture(sfb->_back_rgba->prepare(this), dr, buffer);
04737     }
04738 
04739     return sfb;
04740 #endif
04741 }
04742 
04743 ////////////////////////////////////////////////////////////////////
04744 //     Function: DXGraphicsStateGuardian7::restore_frame_buffer
04745 //       Access: Public
04746 //  Description: Restores the frame buffer that was previously saved.
04747 ////////////////////////////////////////////////////////////////////
04748 void DXGraphicsStateGuardian7::
04749 restore_frame_buffer(SavedFrameBuffer *frame_buffer) {
04750     dxgsg7_cat.error() << "restore_frame_buffer unimplemented!!\n";
04751     return;
04752 }
04753 
04754 TypeHandle DXGraphicsStateGuardian7::get_type(void) const {
04755     return get_class_type();
04756 }
04757 
04758 TypeHandle DXGraphicsStateGuardian7::get_class_type(void) {
04759     return _type_handle;
04760 }
04761 
04762 void DXGraphicsStateGuardian7::init_type(void) {
04763     GraphicsStateGuardian::init_type();
04764     register_type(_type_handle, "DXGraphicsStateGuardian7",
04765                   GraphicsStateGuardian::get_class_type());
04766 }
04767 
04768 ////////////////////////////////////////////////////////////////////
04769 //     Function: dx_cleanup
04770 //  Description: Clean up the DirectX environment.
04771 ////////////////////////////////////////////////////////////////////
04772 void DXGraphicsStateGuardian7::
04773 dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled) {
04774   static bool bAtExitFnEverCalled=false;
04775 
04776     if(dxgsg7_cat.is_spam()) {
04777         dxgsg7_cat.spam() << "dx_cleanup called, bAtExitFnCalled=" << bAtExitFnCalled << ", bAtExitFnEverCalled=" << bAtExitFnEverCalled << endl;
04778     }
04779 
04780     bAtExitFnEverCalled = (bAtExitFnEverCalled || bAtExitFnCalled);
04781 
04782     // for now, I can't trust any of the ddraw/d3d releases during atexit(),
04783     // so just return directly.  maybe revisit this later, if have problems
04784     // restarting d3d/ddraw after one of these uncleaned-up exits
04785     if(bAtExitFnEverCalled)
04786       return;
04787 
04788     ULONG refcnt;
04789 
04790     // unsafe to do the D3D releases after exit() called, since DLL_PROCESS_DETACH
04791     // msg already delivered to d3d.dll and it's unloaded itself
04792     if(!bAtExitFnEverCalled) {
04793 
04794         PRINTREFCNT(_pScrn->pDD,"exit start IDirectDraw7");
04795 
04796         // these 2 calls release ddraw surfaces and vbuffers.  unsafe unless not on exit
04797         release_all_textures();
04798         release_all_geoms();
04799 
04800         PRINTREFCNT(_pScrn->pDD,"after release_all_textures IDirectDraw7");
04801 
04802         // Do a safe check for releasing the D3DDEVICE. RefCount should be zero.
04803         // if we're called from exit(), _pScrn->pD3DDevice may already have been released
04804         if (_pScrn->pD3DDevice!=NULL) {
04805             _pScrn->pD3DDevice->SetTexture(0,NULL);  // should release this stuff internally anyway
04806             RELEASE(_pScrn->pD3DDevice,dxgsg7,"d3dDevice",RELEASE_DOWN_TO_ZERO);
04807         }
04808 
04809         PRINTREFCNT(_pScrn->pDD,"after d3ddevice release IDirectDraw7");
04810 
04811         if((_pScrn->pddsBack!=NULL)&&(_pScrn->pddsZBuf!=NULL))
04812             _pScrn->pddsBack->DeleteAttachedSurface(0x0,_pScrn->pddsZBuf);
04813 
04814         // Release the DDraw and D3D objects used by the app
04815         RELEASE(_pScrn->pddsZBuf,dxgsg7,"zbuffer",false);
04816 
04817         PRINTREFCNT(_pScrn->pDD,"before releasing d3d obj, IDirectDraw7");
04818         RELEASE(_pScrn->pD3D,dxgsg7,"IDirect3D7 _pScrn->pD3D",false); //RELEASE_DOWN_TO_ZERO);
04819         PRINTREFCNT(_pScrn->pDD,"after releasing d3d obj, IDirectDraw7");
04820 
04821         // is it wrong to explictly release _pScrn->pddsBack if it is part of complex surface chain (as in full_pScrn->mode)?
04822         RELEASE(_pScrn->pddsBack,dxgsg7,"backbuffer",false);
04823         RELEASE(_pScrn->pddsPrimary,dxgsg7,"primary surface",false);
04824 
04825         PRINTREFCNT(_pScrn->pDD,"after releasing all surfs, IDirectDraw7");
04826     }
04827 
04828     // for some reason, DLL_PROCESS_DETACH has not yet been sent to ddraw, so we can still call its fns
04829 
04830     // Do a safe check for releasing DDRAW. RefCount should be zero.
04831     if (_pScrn->pDD!=NULL) {
04832         if(bRestoreDisplayMode) {
04833           HRESULT hr = _pScrn->pDD->RestoreDisplayMode();
04834           if(dxgsg7_cat.is_spam())
04835                 dxgsg7_cat.spam() << "dx_cleanup -  Restoring original desktop DisplayMode\n";
04836           if(FAILED(hr)) {
04837                 dxgsg7_cat.error() << "dx_cleanup -  RestoreDisplayMode failed, hr = " << ConvD3DErrorToString(hr) << endl;
04838           }
04839         }
04840 
04841         if(bAtExitFnCalled) {
04842            // if exit() called, there is definitely no more need for the IDDraw object,
04843            // so we can make sure it's fully released
04844            // note currently this is never called
04845            RELEASE(_pScrn->pDD,dxgsg7,"IDirectDraw7 _pScrn->pDD", RELEASE_DOWN_TO_ZERO);
04846         } else {
04847            // seems wrong to release to zero, since it might be being used somewhere else?
04848 
04849            RELEASE(_pScrn->pDD,dxgsg7,"IDirectDraw7 _pScrn->pDD", false);
04850            if(refcnt>0) {
04851               if(dxgsg7_cat.is_spam())
04852                 dxgsg7_cat.debug() << "dx_cleanup -  warning IDDraw7 refcnt = " << refcnt << ", should be zero!\n";
04853            }
04854         }
04855     }
04856 }
04857 
04858 ////////////////////////////////////////////////////////////////////
04859 //     Function: dx_setup_after_resize
04860 //  Description: Recreate the back buffer and zbuffers at the new size
04861 ////////////////////////////////////////////////////////////////////
04862 void DXGraphicsStateGuardian7::
04863 dx_setup_after_resize(RECT *pViewRect) {
04864     if (_pScrn->pddsBack == NULL) // nothing created yet
04865         return;
04866 
04867     // for safety, need some better error-cleanup here
04868     assert((_pScrn->pddsPrimary!=NULL) && (_pScrn->pddsBack!=NULL) && (_pScrn->pddsZBuf!=NULL));
04869 
04870     DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd_back);
04871     DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd_zbuf);
04872 
04873     _pScrn->pddsBack->GetSurfaceDesc(&ddsd_back);
04874     _pScrn->pddsZBuf->GetSurfaceDesc(&ddsd_zbuf);
04875 
04876     ULONG refcnt;
04877 
04878     if((_pScrn->pddsBack!=NULL)&&(_pScrn->pddsZBuf!=NULL))
04879         _pScrn->pddsBack->DeleteAttachedSurface(0x0,_pScrn->pddsZBuf);
04880 
04881     RELEASE(_pScrn->pddsZBuf,dxgsg7,"zbuffer",false);
04882     RELEASE(_pScrn->pddsBack,dxgsg7,"backbuffer",false);
04883     RELEASE(_pScrn->pddsPrimary,dxgsg7,"primary surface",false);
04884 
04885     assert((_pScrn->pddsPrimary == NULL) && (_pScrn->pddsBack == NULL) && (_pScrn->pddsZBuf == NULL));
04886     _pScrn->view_rect = *pViewRect;
04887 
04888     DWORD renderWid = _pScrn->view_rect.right - _pScrn->view_rect.left;
04889     DWORD renderHt = _pScrn->view_rect.bottom - _pScrn->view_rect.top;
04890 
04891     ddsd_back.dwWidth  = ddsd_zbuf.dwWidth = renderWid;
04892     ddsd_back.dwHeight = ddsd_zbuf.dwHeight = renderHt;
04893 
04894     DX_DECLARE_CLEAN(DDSURFACEDESC2, ddsd);
04895 
04896     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
04897     ddsd.dwFlags        = DDSD_CAPS;
04898 
04899     PRINTVIDMEM(_pScrn->pDD,&ddsd.ddsCaps,"resize primary surf");
04900     HRESULT hr;
04901 
04902     if (FAILED(hr = _pScrn->pDD->CreateSurface( &ddsd, &_pScrn->pddsPrimary, NULL ))) {
04903         dxgsg7_cat.fatal() << "resize() - CreateSurface failed for primary : result = " << ConvD3DErrorToString(hr) << endl;
04904         exit(1);
04905     }
04906 
04907     if (!_pScrn->bIsFullScreen) {
04908         // Create a clipper object which handles all our clipping for cases when
04909         // our window is partially obscured by other windows.
04910         LPDIRECTDRAWCLIPPER Clipper;
04911 
04912         if (FAILED(hr = _pScrn->pDD->CreateClipper( 0, &Clipper, NULL ))) {
04913             dxgsg7_cat.fatal()
04914             << "CreateClipper after resize failed : result = " << ConvD3DErrorToString(hr) << endl;
04915             exit(1);
04916         }
04917         // Associate the clipper with our window. Note that, afterwards, the
04918         // clipper is internally referenced by the primary surface, so it is safe
04919         // to release our local reference to it.
04920         Clipper->SetHWnd( 0, _pScrn->hWnd );
04921         _pScrn->pddsPrimary->SetClipper( Clipper );
04922         Clipper->Release();
04923     }
04924 
04925     // Recreate the backbuffer. (might want to handle failure due to
04926     // running out of video memory)
04927 
04928     ddsd_back.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;  // just to make sure
04929     ddsd_back.ddsCaps.dwCaps |= DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
04930 
04931     PRINTVIDMEM(_pScrn->pDD,&ddsd_back.ddsCaps,"resize backbuffer surf");
04932 
04933     if (FAILED(hr = _pScrn->pDD->CreateSurface( &ddsd_back, &_pScrn->pddsBack, NULL ))) {
04934         dxgsg7_cat.fatal() << "resize() - CreateSurface failed for backbuffer : result = " << ConvD3DErrorToString(hr) << endl;
04935         exit(1);
04936     }
04937 
04938     PRINTVIDMEM(_pScrn->pDD,&ddsd_back.ddsCaps,"resize zbuffer surf");
04939 
04940     // Recreate and attach a z-buffer.
04941     if (FAILED(hr = _pScrn->pDD->CreateSurface( &ddsd_zbuf, &_pScrn->pddsZBuf, NULL ))) {
04942         dxgsg7_cat.fatal() << "resize() - CreateSurface failed for Z buffer: result = " << ConvD3DErrorToString(hr) << endl;
04943         exit(1);
04944     }
04945 
04946     // Attach the z-buffer to the back buffer.
04947     if ((hr = _pScrn->pddsBack->AddAttachedSurface( _pScrn->pddsZBuf ) ) != DD_OK) {
04948         dxgsg7_cat.fatal() << "resize() - AddAttachedSurface failed : result = " << ConvD3DErrorToString(hr) << endl;
04949         exit(1);
04950     }
04951 
04952     if ((hr = _pScrn->pD3DDevice->SetRenderTarget(_pScrn->pddsBack,0x0) ) != DD_OK) {
04953         dxgsg7_cat.fatal() << "resize() - SetRenderTarget failed : result = " << ConvD3DErrorToString(hr) << endl;
04954         exit(1);
04955     }
04956 
04957     // It doesn't seem necessary to create a new viewport for the
04958     // window, since Panda creates a new viewport before rendering
04959     // into each DisplayRegion.  Creating this redundant viewport may
04960     // just lead to confusion.
04961     /*
04962     // Create the viewport
04963     D3DVIEWPORT7 vp = { 
04964       0, 0,
04965       renderWid, renderHt, 
04966       0.0f, 1.0f
04967     };
04968     hr = _pScrn->pD3DDevice->SetViewport( &vp );
04969     if (hr != DD_OK) {
04970         dxgsg7_cat.fatal()
04971         << "SetViewport failed : result = " << ConvD3DErrorToString(hr) << endl;
04972         exit(1);
04973     }
04974     */
04975 
04976 //    _dxgsg->set_context(&_wcontext); 
04977 }
04978 
04979 bool refill_tex_callback(TextureContext *tc,void *void_dxgsg7_ptr) {
04980      DXTextureContext7 *dtc = DCAST(DXTextureContext7, tc);
04981 //   DXGraphicsStateGuardian7 *dxgsg7 = (DXGraphicsStateGuardian7 *)void_dxgsg7_ptr; not needed?
04982 
04983      // Re-fill the contents of textures and vertex buffers
04984      // which just got restored now.
04985      HRESULT hr=dtc->FillDDSurfTexturePixels();
04986      return hr==S_OK;
04987 }
04988 
04989 bool delete_tex_callback(TextureContext *tc,void *void_dxgsg7_ptr) {
04990      DXTextureContext7 *dtc = DCAST(DXTextureContext7, tc);
04991 
04992      // release DDSurf (but not the texture context)
04993      dtc->DeleteTexture();
04994      return true;
04995 }
04996 
04997 bool recreate_tex_callback(TextureContext *tc,void *void_dxgsg7_ptr) {
04998      DXTextureContext7 *dtc = DCAST(DXTextureContext7, tc);
04999      DXGraphicsStateGuardian7 *dxgsg7 = (DXGraphicsStateGuardian7 *)void_dxgsg7_ptr;
05000 
05001      // Re-fill the contents of textures and vertex buffers
05002      // which just got restored now.
05003 
05004      LPDIRECTDRAWSURFACE7 ddtex =
05005 #ifdef USE_TEXFMTVEC
05006         dtc->CreateTexture(dxgsg7->_pScrn->pD3DDevice,_pScrn->TexPixFmts,&dxgsg7->_pScrn->D3DDevDesc);
05007 #else
05008         dtc->CreateTexture(dxgsg7->_pScrn->pD3DDevice,dxgsg7->_cNumTexPixFmts,dxgsg7->_pTexPixFmts,&dxgsg7->_pScrn->D3DDevDesc);
05009 #endif
05010      return ddtex!=NULL;
05011 }
05012 
05013 // release all textures and vertex/index buffers
05014 HRESULT DXGraphicsStateGuardian7::DeleteAllVideoSurfaces(void) {
05015   // BUGBUG: need to handle vertexbuffer handling here
05016 
05017   // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it
05018   traverse_prepared_textures(delete_tex_callback,this);
05019 
05020   if(dxgsg7_cat.is_debug())
05021       dxgsg7_cat.debug() << "release of all textures complete\n";
05022   return S_OK;
05023 }
05024 
05025 // recreate all textures and vertex/index buffers
05026 HRESULT DXGraphicsStateGuardian7::RecreateAllVideoSurfaces(void) {
05027   // BUGBUG: need to handle vertexbuffer handling here
05028 
05029   // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it
05030   traverse_prepared_textures(recreate_tex_callback,this);
05031 
05032   if(dxgsg7_cat.is_debug())
05033       dxgsg7_cat.debug() << "recreation of all textures complete\n";
05034   return S_OK;
05035 }
05036 
05037 HRESULT DXGraphicsStateGuardian7::RestoreAllVideoSurfaces(void) {
05038   // BUGBUG: this should also restore vertex buffer contents when they are implemented
05039   // You will need to destroy and recreate
05040   // optimized vertex buffers however, restoring is not enough.
05041 
05042   HRESULT hr;
05043 
05044   // note: could go through and just restore surfs that return IsLost() true
05045   // apparently that isnt as reliable w/some drivers tho
05046   if (FAILED(hr = _pScrn->pDD->RestoreAllSurfaces() )) {
05047         dxgsg7_cat.fatal() << "RestoreAllSurfs failed : result = " << ConvD3DErrorToString(hr) << endl;
05048     exit(1);
05049   }
05050 
05051   // cant access template in libpanda.dll directly due to vc++ limitations, use traverser to get around it
05052   traverse_prepared_textures(refill_tex_callback,this);
05053 
05054   if(dxgsg7_cat.is_debug())
05055       dxgsg7_cat.debug() << "restore and refill of video surfaces complete...\n";
05056   return S_OK;
05057 }
05058 
05059 
05060 ////////////////////////////////////////////////////////////////////
05061 //     Function: show_frame
05062 //       Access:
05063 //       Description:   Repaint primary buffer from back buffer
05064 ////////////////////////////////////////////////////////////////////
05065 void DXGraphicsStateGuardian7::show_frame(void) {
05066   if(_pScrn->pddsPrimary==NULL)
05067     return;
05068 
05069   //  DO_PSTATS_STUFF(PStatTimer timer(_win->_swap_pcollector));  // this times just the flip, so it must go here in dxgsg7, instead of wdxdisplay, which would time the whole frame
05070 
05071   if (_pScrn->bIsFullScreen) {
05072     show_full_screen_frame();
05073   } else {
05074     show_windowed_frame();
05075   }
05076 }
05077 
05078 ////////////////////////////////////////////////////////////////////
05079 //     Function: dxGraphicsStateGuardian7::support_overlay_window
05080 //       Access: Public
05081 //  Description: Specifies whether dialog windows placed on top of the
05082 //               dx rendering window should be supported.  This
05083 //               requires a bit of extra overhead, so it should only
05084 //               be activated when necessary; however, if it is not
05085 //               activated, a window that pops up over the fullscreen
05086 //               DX window (like a dialog box, or particularly like
05087 //               the IME composition or candidate windows) may not be
05088 //               visible.
05089 //
05090 //               This is not necessary when running in windowed mode,
05091 //               but it does no harm.
05092 ////////////////////////////////////////////////////////////////////
05093 void DXGraphicsStateGuardian7::
05094 support_overlay_window(bool flag) {
05095   if (_overlay_windows_supported && !flag) {
05096     // Disable support for overlay windows.
05097     _overlay_windows_supported = false;
05098 
05099     if (_pScrn->bIsFullScreen) {
05100       _pScrn->pddsPrimary->SetClipper(NULL);
05101     }
05102 
05103   } else if (!_overlay_windows_supported && flag) {
05104     // Enable support for overlay windows.
05105     _overlay_windows_supported = true;
05106 
05107     if (_pScrn->bIsFullScreen) {
05108       // Create a Clipper object to blt the whole screen.
05109       LPDIRECTDRAWCLIPPER Clipper;
05110 
05111       if (_pScrn->pDD->CreateClipper(0, &Clipper, NULL) == DD_OK) {
05112         Clipper->SetHWnd(0, _pScrn->hWnd);
05113         _pScrn->pddsPrimary->SetClipper(Clipper);
05114       }
05115       _pScrn->pDD->FlipToGDISurface();
05116       Clipper->Release();
05117     }
05118   }
05119 }
05120 
05121 
05122 ////////////////////////////////////////////////////////////////////
05123 //     Function: show_full_screen_frame
05124 //       Access:
05125 //       Description:   Repaint primary buffer from back buffer
05126 ////////////////////////////////////////////////////////////////////
05127 void DXGraphicsStateGuardian7::show_full_screen_frame(void) {
05128   HRESULT hr;
05129 
05130   // Flip the front and back buffers, to make what we just rendered
05131   // visible.
05132 
05133   if(!_overlay_windows_supported) {
05134     // Normally, we can just do the fast flip operation.
05135     DWORD dwFlipFlags = DDFLIP_WAIT;
05136 
05137     if (!dx_sync_video) {
05138       // If the user indicated via Config that we shouldn't wait for
05139       // video sync, then don't wait (if the hardware supports this).
05140       // This will introduce visible artifacts like tearing, and may
05141       // cause the frame rate to grow excessively (and pointlessly)
05142       // high, starving out other processes.
05143       dwFlipFlags |= DDFLIP_NOVSYNC;
05144       //  dwFlipFlags = DDFLIP_DONOTWAIT | DDFLIP_NOVSYNC;
05145     }
05146 
05147     // bugbug: dont we want triple buffering instead of wasting time
05148     // waiting for vsync?
05149     hr = _pScrn->pddsPrimary->Flip( NULL, dwFlipFlags);
05150   } else {
05151       // If we're asking for overlay windows, we have to blt instead of
05152       // flip, so we don't lose the window.
05153       hr = _pScrn->pddsPrimary->Blt( NULL, _pScrn->pddsBack,  NULL, DDBLT_WAIT, NULL );
05154   }
05155 
05156   if(FAILED(hr)) {
05157       if((hr == DDERR_SURFACELOST) || (hr == DDERR_SURFACEBUSY)) {
05158         CheckCooperativeLevel();
05159       } else {
05160         dxgsg7_cat.error() << "show_frame() - Flip failed w/unexpected error code: " << ConvD3DErrorToString(hr) << endl;
05161         exit(1);
05162       }
05163   }
05164 }
05165 
05166 ////////////////////////////////////////////////////////////////////
05167 //     Function: show_windowed_frame
05168 //       Access: Public
05169 //  Description: Repaint primary buffer from back buffer (windowed
05170 //               mode only)
05171 ////////////////////////////////////////////////////////////////////
05172 void DXGraphicsStateGuardian7::show_windowed_frame(void) {
05173   HRESULT hr;
05174 
05175   DX_DECLARE_CLEAN(DDBLTFX, bltfx);
05176 
05177   if (dx_sync_video) {
05178     // Wait for the video refresh *before* we blt the rendered image
05179     // onto the window.  This will (a) prevent the "tearing" of the
05180     // image that would occur if only part of the image happened to be
05181     // copied into the window before the video refresh occurred, and
05182     // (b) prevent our frame rate from going excessively (and
05183     // pointlessly) higher than our video refresh rate, starving out
05184     // other processes.
05185 
05186     // Unfortunately, when the system is even lightly loaded, this
05187     // wait call sometimes appears to wait through multiple frames
05188     // before returning, causing our frame rate to be unreasonably low
05189     // and erratic.  There doesn't appear to be any way to prevent
05190     // this behavior; thus, we allow the user to avoid this wait,
05191     // based on the Config settings.
05192 
05193     bltfx.dwDDFX |= DDBLTFX_NOTEARING;  // hmm, does any driver actually recognize this flag?
05194   }
05195 
05196   hr = _pScrn->pddsPrimary->Blt( &_pScrn->view_rect, _pScrn->pddsBack,  NULL, DDBLT_DDFX | DDBLT_WAIT, &bltfx );
05197 
05198   if (dx_sync_video) {
05199     HRESULT hr = _pScrn->pDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
05200     if(hr != DD_OK) {
05201       dxgsg7_cat.error() << "WaitForVerticalBlank() failed : " << ConvD3DErrorToString(hr) << endl;
05202       exit(1);
05203     }
05204   }
05205 
05206   if(FAILED(hr)) {
05207     if((hr == DDERR_SURFACELOST) || (hr == DDERR_SURFACEBUSY)) {
05208       CheckCooperativeLevel();
05209     } else {
05210       dxgsg7_cat.error() << "show_frame() - Blt failed : " << ConvD3DErrorToString(hr) << endl;
05211       exit(1);
05212     }
05213   }
05214 
05215 }
05216 
05217 bool DXGraphicsStateGuardian7::
05218 CheckCooperativeLevel(bool bDoReactivateWindow) {
05219   HRESULT hr = _pScrn->pDD->TestCooperativeLevel();
05220 
05221   if (SUCCEEDED(_last_testcooplevel_result)) {
05222     if (SUCCEEDED(hr)) {
05223       // this means this was just a safety check, dont need to restore surfs
05224       return true;
05225     }
05226 
05227     // otherwise something just went wrong
05228     if (hr == DDERR_NOEXCLUSIVEMODE || hr == DDERR_EXCLUSIVEMODEALREADYSET) {
05229       // This means that mode changes had taken place, surfaces
05230       // were lost but still we are in the original mode, so we
05231       // simply restore all surfaces and keep going.
05232 
05233       if (dxgsg7_cat.is_debug()) {
05234         dxgsg7_cat.debug()
05235           << "Another app has DDRAW exclusive mode, waiting...\n";
05236       }
05237 
05238       // This doesn't seem to be necessary.
05239       /*
05240       if (_dx_ready) {
05241         _win->deactivate_window();
05242         _dx_ready = FALSE;
05243       }
05244       */
05245 
05246     } else if (hr == DDERR_WRONGMODE) {
05247       // This means that the desktop mode has changed.  need to
05248       // destroy all of dx stuff and recreate everything back again,
05249       // which is a big hit
05250       dxgsg7_cat.error()
05251         << "detected display mode change in TestCoopLevel, must recreate all DDraw surfaces, D3D devices, this is not handled yet. hr == " << ConvD3DErrorToString(hr) << endl;
05252       exit(1);
05253     } else if (FAILED(hr)) {
05254       dxgsg7_cat.error()
05255         << "unexpected return code from TestCoopLevel: " 
05256         << ConvD3DErrorToString(hr) << endl;
05257       exit(1);
05258     }
05259 
05260   } else {
05261     // testcooplvl was failing, handle case where it now succeeds
05262 
05263     if (SUCCEEDED(hr)) {
05264       if (_last_testcooplevel_result == DDERR_EXCLUSIVEMODEALREADYSET ||
05265           _last_testcooplevel_result == DDERR_NOEXCLUSIVEMODE) {
05266         if (dxgsg7_cat.is_debug()) {
05267           dxgsg7_cat.debug()
05268             << "other app relinquished exclusive mode, refilling surfs...\n";
05269         }
05270       }
05271 
05272       // This isn't necessary either.
05273       /*
05274       if (bDoReactivateWindow) {
05275         _win->reactivate_window();
05276       }
05277       */
05278 
05279       RestoreAllVideoSurfaces();
05280 
05281       //      _dx_ready = TRUE;
05282 
05283     } else if (hr == DDERR_WRONGMODE) {
05284       // This means that the desktop mode has changed.  need to
05285       // destroy all of dx stuff and recreate everything back again,
05286       // which is a big hit
05287       dxgsg7_cat.error()
05288         << "detected desktop display mode change in TestCoopLevel, must recreate all DDraw surfaces & D3D devices, this is not handled yet.  " << ConvD3DErrorToString(hr) << endl;
05289       //_win->close_window();
05290       exit(1);
05291     } else if ((hr!=DDERR_NOEXCLUSIVEMODE) && (hr!=DDERR_EXCLUSIVEMODEALREADYSET)) {
05292       dxgsg7_cat.error() 
05293         << "unexpected return code from TestCoopLevel: " << ConvD3DErrorToString(hr) << endl;
05294       exit(1);
05295     }
05296   }
05297 
05298   _last_testcooplevel_result = hr;
05299   return SUCCEEDED(hr);
05300 }
05301 
05302 ////////////////////////////////////////////////////////////////////
05303 //     Function: handle_window_move
05304 //       Access:
05305 //  Description: we receive the new x and y position of the client
05306 ////////////////////////////////////////////////////////////////////
05307 void DXGraphicsStateGuardian7::adjust_view_rect(int x, int y) {
05308     if (_pScrn->view_rect.left != x || _pScrn->view_rect.top != y) {
05309         _pScrn->view_rect.right = x + _pScrn->view_rect.right - _pScrn->view_rect.left;
05310         _pScrn->view_rect.left = x;
05311         _pScrn->view_rect.bottom = y + _pScrn->view_rect.bottom - _pScrn->view_rect.top;
05312         _pScrn->view_rect.top = y;
05313 
05314 //  set_clipper(clip_rect);
05315     }
05316 }
05317 
05318 #if 0
05319 
05320 ////////////////////////////////////////////////////////////////////
05321 //     Function: GLGraphicsStateGuardian::save_mipmap_images
05322 //       Access: Protected
05323 //  Description: Saves out each mipmap level of the indicated texture
05324 //               (which must also be the currently active texture in
05325 //               the GL state) as a separate image file to disk.
05326 ////////////////////////////////////////////////////////////////////
05327 void DXGraphicsStateGuardian7::read_mipmap_images(Texture *tex) {
05328    Filename filename = tex->get_name();
05329    string name;
05330    if (filename.empty()) {
05331      static index = 0;
05332      name = "texture" + format_string(index);
05333      index++;
05334    } else {
05335      name = filename.get_basename_wo_extension();
05336    }
05337 
05338    PixelBuffer *pb = tex->get_ram_image();
05339    nassertv(pb != (PixelBuffer *)NULL);
05340 
05341    GLenum external_format = get_external_image_format(pb->get_format());
05342    GLenum type = get_image_type(pb->get_image_type());
05343 
05344    int xsize = pb->get_xsize();
05345    int ysize = pb->get_ysize();
05346 
05347    // Specify byte-alignment for the pixels on output.
05348    glPixelStorei(GL_PACK_ALIGNMENT, 1);
05349 
05350    int mipmap_level = 0;
05351    do {
05352      xsize = max(xsize, 1);
05353      ysize = max(ysize, 1);
05354 
05355      PT(PixelBuffer) mpb =
05356        new PixelBuffer(xsize, ysize, pb->get_num_components(),
05357                        pb->get_component_width(), pb->get_image_type(),
05358                        pb->get_format());
05359      glGetTexImage(GL_TEXTURE_2D, mipmap_level, external_format,
05360                    type, mpb->_image);
05361      Filename mipmap_filename = name + "_" + format_string(mipmap_level) + ".pnm";
05362      nout << "Writing mipmap level " << mipmap_level
05363           << " (" << xsize << " by " << ysize << ") "
05364           << mipmap_filename << "\n";
05365      mpb->write(mipmap_filename);
05366 
05367      xsize >>= 1;
05368      ysize >>= 1;
05369      mipmap_level++;
05370    } while (xsize > 0 && ysize > 0);
05371 }
05372 #endif
05373 
05374 
05375 #if 0
05376 //-----------------------------------------------------------------------------
05377 // Name: SetViewMatrix()
05378 // Desc: Given an eye point, a lookat point, and an up vector, this
05379 //       function builds a 4x4 view matrix.
05380 //-----------------------------------------------------------------------------
05381 HRESULT SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom, D3DVECTOR& vAt,
05382                        D3DVECTOR& vWorldUp ) {
05383     // Get the z basis vector, which points straight ahead. This is the
05384     // difference from the eyepoint to the lookat point.
05385     D3DVECTOR vView = vAt - vFrom;
05386 
05387     float fLength = Magnitude( vView );
05388     if (fLength < 1e-6f)
05389         return E_INVALIDARG;
05390 
05391     // Normalize the z basis vector
05392     vView /= fLength;
05393 
05394     // Get the dot product, and calculate the projection of the z basis
05395     // vector onto the up vector. The projection is the y basis vector.
05396     float fDotProduct = DotProduct( vWorldUp, vView );
05397 
05398     D3DVECTOR vUp = vWorldUp - fDotProduct * vView;
05399 
05400     // If this vector has near-zero length because the input specified a
05401     // bogus up vector, let's try a default up vector
05402     if (1e-6f > ( fLength = Magnitude( vUp ) )) {
05403         vUp = D3DVECTOR( 0.0f, 1.0f, 0.0f ) - vView.y * vView;
05404 
05405         // If we still have near-zero length, resort to a different axis.
05406         if (1e-6f > ( fLength = Magnitude( vUp ) )) {
05407             vUp = D3DVECTOR( 0.0f, 0.0f, 1.0f ) - vView.z * vView;
05408 
05409             if (1e-6f > ( fLength = Magnitude( vUp ) ))
05410                 return E_INVALIDARG;
05411         }
05412     }
05413 
05414     // Normalize the y basis vector
05415     vUp /= fLength;
05416 
05417     // The x basis vector is found simply with the cross product of the y
05418     // and z basis vectors
05419     D3DVECTOR vRight = CrossProduct( vUp, vView );
05420 
05421     // Start building the matrix. The first three rows contains the basis
05422     // vectors used to rotate the view to point at the lookat point
05423     mat._11 = vRight.x;  mat._12 = vUp.x;  mat._13 = vView.x;  mat._14 = 0.0f;
05424     mat._21 = vRight.y;  mat._22 = vUp.y;  mat._23 = vView.y;  mat._24 = 0.0f;
05425     mat._31 = vRight.z;  mat._32 = vUp.z;  mat._33 = vView.z;  mat._34 = 0.0f;
05426 
05427     // Do the translation values (rotations are still about the eyepoint)
05428     mat._41 = - DotProduct( vFrom, vRight );
05429     mat._42 = - DotProduct( vFrom, vUp );
05430     mat._43 = - DotProduct( vFrom, vView );
05431     mat._44 = 1.0f;
05432 
05433     return S_OK;
05434 }
05435 
05436 #endif
05437 
05438 
05439 ////////////////////////////////////////////////////////////////////
05440 //     Function: DXGraphicsStateGuardian7::prepare_geom_node
05441 //       Access: Public, Virtual
05442 //  Description: Prepares the indicated GeomNode for retained-mode
05443 //               rendering.  If this function returns non-NULL, the
05444 //               value returned will be passed back to a future call
05445 //               to draw_geom_node(), which is expected to draw the
05446 //               contents of the node.
05447 ////////////////////////////////////////////////////////////////////
05448 GeomNodeContext *DXGraphicsStateGuardian7::
05449 prepare_geom_node(GeomNode *node) {
05450 #if 0   // temporarily disabled until ported to new scene graph
05451  if(link_tristrips) {
05452   for(int iGeom=0;iGeom<node->get_num_geoms();iGeom++) {
05453     dDrawable *drawable1 = node->get_geom(iGeom);
05454 
05455     if(!drawable1->is_of_type(Geom::get_class_type()))
05456       continue;
05457 
05458     Geom *geomptr=DCAST(Geom, drawable1);
05459     assert(geomptr!=NULL);
05460 
05461     if(!geomptr->is_of_type(GeomTristrip::get_class_type()))
05462       continue;
05463 
05464     GeomTristrip *me = DCAST(GeomTristrip, geomptr);
05465     assert(me!=NULL);
05466 
05467     int nPrims=me->get_num_prims();
05468     if(nPrims==1)
05469       continue;
05470 
05471     if(dxgsg7_cat.is_debug()) {
05472        static bool bPrintedMsg=false;
05473        if(!bPrintedMsg) {
05474            dxgsg7_cat.debug() << "linking tristrips together with degenerate tris\n";
05475            bPrintedMsg=true;
05476        }
05477     }
05478 
05479     bool bStripReversalNeeded;
05480     unsigned int nOrigTotalVerts=0;
05481     PTA_int new_lengths;
05482     int p;
05483 
05484     // sum things up so can reserve space for new vecs
05485     for(p=0;p<nPrims;p++) {
05486       nOrigTotalVerts+=me->get_length(p);
05487     }
05488 
05489     // could compute it exactly if I wanted to reproduce all the cTotalVertsOutputSoFar logic in the loop below
05490     // might save on memory reallocations. try to overestimate using *3.
05491     int cEstimatedTotalVerts=nOrigTotalVerts+nPrims*3-2;
05492 
05493     #define INIT_ATTRVARS(ATTRNAME,PTA_TYPENAME)                                                 \
05494        PTA_##PTA_TYPENAME old_##ATTRNAME##s,new_##ATTRNAME##s;                                   \
05495        PTA_ushort old_##ATTRNAME##_indices,new_##ATTRNAME##_indices;                             \
05496        GeomBindType ATTRNAME##binding;                                                           \
05497        me->get_##ATTRNAME##s(old_##ATTRNAME##s, ATTRNAME##binding, old_##ATTRNAME##_indices);    \
05498                                                                                                  \
05499        PTA_##PTA_TYPENAME::iterator old_##ATTRNAME##_iter=old_##ATTRNAME##s.begin();             \
05500        PTA_ushort::iterator old_##ATTRNAME##index_iter;                                          \
05501                                                                                                  \
05502        if((ATTRNAME##binding!=G_OFF)&&(ATTRNAME##binding!=G_OVERALL)) {                          \
05503          if(old_##ATTRNAME##_indices!=NULL) {                                                    \
05504              old_##ATTRNAME##index_iter=old_##ATTRNAME##_indices.begin();                        \
05505              new_##ATTRNAME##_indices.reserve(cEstimatedTotalVerts);                             \
05506          } else {                                                                                \
05507              new_##ATTRNAME##s.reserve(cEstimatedTotalVerts);                                    \
05508          }                                                                                       \
05509        }
05510 
05511     INIT_ATTRVARS(coord,Vertexf);
05512     INIT_ATTRVARS(color,Colorf);
05513     INIT_ATTRVARS(normal,Normalf);
05514     INIT_ATTRVARS(texcoord,TexCoordf);
05515 
05516 #define IsOdd(X) (((X) & 0x1)!=0)
05517 
05518     uint cTotalVertsOutputSoFar=0;
05519     int nVerts;
05520     bool bAddExtraStartVert;
05521 
05522     for(p=0;p<nPrims;p++) {
05523       nVerts=me->get_length(p);
05524 
05525          // if bStripStateStartsBackfacing, then if the current strip
05526          // ends frontfacing, we can fix the problem by just reversing
05527          // the current strip order.  But if the current strip ends
05528          // backfacing, this will not work, since last tri is encoded for backfacing slot
05529          // so it will be incorrectly backfacing when you put it in a backfacing
05530          // slot AND reverse the vtx order.
05531 
05532          // insert an extra pad vertex at the beginning to force the
05533          // strip backface-state parity to change (more expensive, since
05534          // we make 1 more degen tri).  We always want the first tri
05535          // to start in a front-facing slot (unless it's a reversed end
05536 
05537          bStripReversalNeeded = false;
05538          bAddExtraStartVert=false;
05539 
05540          if(p==0) {
05541            cTotalVertsOutputSoFar+=nVerts+1;
05542          } else {
05543             if(!IsOdd(cTotalVertsOutputSoFar)) {
05544                // we're starting on a backfacing slot
05545                if(IsOdd(nVerts)) {
05546                   bStripReversalNeeded = true;
05547                } else {
05548                 bAddExtraStartVert=true;
05549                 cTotalVertsOutputSoFar++;
05550                }
05551             }
05552 
05553             cTotalVertsOutputSoFar+=nVerts+2;
05554             if(p==nPrims-1)
05555               cTotalVertsOutputSoFar--;
05556          }
05557 
05558 #define PERVERTEX_ATTRLOOP(OLDVERT_ITERATOR,NEWVERT_VECTOR,VECLENGTH,NUMSTARTPADDINGATTRS,NUMENDPADDINGATTRS)    \
05559           if(bStripReversalNeeded) {                                                        \
05560               /* to preserve normal-direction property for backface-cull purposes, */       \
05561               /* vtx order must be reversed*/                                               \
05562                                                                                             \
05563               OLDVERT_ITERATOR+=((VECLENGTH)-1);  /* start at last vert, and go back*/      \
05564               /*dxgsg7_cat.debug() << "doing reversal on strip " << p << " of length " << nVerts << endl;*/ \
05565                                                                                             \
05566               if(p!=0) {                                                                    \
05567                  /* copy first vert twice to link with last strip*/                         \
05568                  for(int i=0;i<NUMSTARTPADDINGATTRS;i++)                                    \
05569                       NEWVERT_VECTOR.push_back(*OLDVERT_ITERATOR);                          \
05570               }                                                                             \
05571                                                                                             \
05572               for(int v=0;v<(VECLENGTH);v++,OLDVERT_ITERATOR--) {                           \
05573                   NEWVERT_VECTOR.push_back(*OLDVERT_ITERATOR);                              \
05574               }                                                                             \
05575                                                                                             \
05576               OLDVERT_ITERATOR++;                                                           \
05577                                                                                             \
05578               if(p!=(nPrims-1)) {                                                           \
05579                   /* copy last vert twice to link to next strip  */                         \
05580                  for(int i=0;i<NUMENDPADDINGATTRS;i++)                                      \
05581                     NEWVERT_VECTOR.push_back(*OLDVERT_ITERATOR);                            \
05582               }                                                                             \
05583                                                                                             \
05584               OLDVERT_ITERATOR+=(VECLENGTH);                                                \
05585                                                                                             \
05586           } else {                                                                          \
05587               if(p!=0) {                                                                    \
05588                  /* copy first vert twice to link with last strip*/                         \
05589                  for(int i=0;i<NUMSTARTPADDINGATTRS;i++)                                    \
05590                       NEWVERT_VECTOR.push_back(*OLDVERT_ITERATOR);                          \
05591               }                                                                             \
05592                                                                                             \
05593               for(int v=0;v<(VECLENGTH);v++,OLDVERT_ITERATOR++)                             \
05594                   NEWVERT_VECTOR.push_back(*OLDVERT_ITERATOR);                              \
05595                                                                                             \
05596               if(p!=(nPrims-1)) {                                                           \
05597                   /* copy last vert twice to link to next strip  */                         \
05598                  for(int i=0;i<NUMENDPADDINGATTRS;i++)                                      \
05599                     NEWVERT_VECTOR.push_back(*(OLDVERT_ITERATOR-1));                        \
05600               }                                                                             \
05601           }
05602 
05603 
05604 #define CONVERT_ATTR_VECTOR(ATTRNAME)                                                          \
05605       switch(ATTRNAME##binding) {                                                              \
05606             case G_OFF:                                                                        \
05607             case G_OVERALL:                                                                    \
05608                 break;                                                                         \
05609                                                                                                \
05610             case G_PER_PRIM: {                                                                 \
05611               /* must convert to per-component*/                                               \
05612               /* nPrims*2+origTotalVerts-2 components  */                                      \
05613                 int veclength=nVerts+2;                                                        \
05614                 if((p==0)||(p==(nPrims-1)))                                                    \
05615                     veclength--;                                                               \
05616                 if(bAddExtraStartVert)                                                         \
05617                    veclength++;                                                                \
05618                                                                                                \
05619                 if(old_##ATTRNAME##_indices!=NULL) {                                           \
05620                     for(int v=0;v<veclength;v++)                                               \
05621                        new_##ATTRNAME##_indices.push_back(*old_##ATTRNAME##index_iter);        \
05622                                                                                                \
05623                     old_##ATTRNAME##index_iter++; /* move on to val for next strip*/           \
05624                  } else {                                                                      \
05625                       for(int v=0;v<veclength;v++)                                             \
05626                          new_##ATTRNAME##s.push_back(*old_##ATTRNAME##_iter);                  \
05627                                                                                                \
05628                       old_##ATTRNAME##_iter++; /* move on to val for next strip*/              \
05629                  }                                                                             \
05630                  break;                                                                        \
05631              }                                                                                 \
05632                                                                                                \
05633             case G_PER_COMPONENT:                                                              \
05634             case G_PER_VERTEX: {                                                               \
05635                 int veclength,numstartcopies,numendcopies;                                     \
05636                                                                                                \
05637                 if(ATTRNAME##binding==G_PER_VERTEX) {                                          \
05638                     veclength=nVerts;                                                          \
05639                     numstartcopies=numendcopies=1;                                             \
05640                 } else {                                                                       \
05641                     veclength=nVerts-2;                                                        \
05642                     numstartcopies=numendcopies=2;                                             \
05643                 }                                                                              \
05644                 if(bAddExtraStartVert)                                                         \
05645                    numstartcopies++;                                                           \
05646                                                                                                \
05647                 if(old_##ATTRNAME##_indices!=NULL) {                                           \
05648                     PERVERTEX_ATTRLOOP(old_##ATTRNAME##index_iter,new_##ATTRNAME##_indices,veclength,numstartcopies,numendcopies); \
05649                 } else {                                                                       \
05650                     /* non-indexed case */                                                     \
05651                     PERVERTEX_ATTRLOOP(old_##ATTRNAME##_iter,new_##ATTRNAME##s,veclength,numstartcopies,numendcopies); \
05652                 }                                                                              \
05653             }                                                                                  \
05654             break;                                                                             \
05655       }                                                                                        \
05656 
05657 
05658       CONVERT_ATTR_VECTOR(coord);
05659 
05660       #ifdef _DEBUG
05661          if(old_coord_indices==NULL)
05662            assert(cTotalVertsOutputSoFar==new_coords.size());
05663          else
05664            assert(cTotalVertsOutputSoFar==new_coord_indices.size());
05665       #endif
05666 
05667       CONVERT_ATTR_VECTOR(color);
05668       CONVERT_ATTR_VECTOR(normal);
05669       CONVERT_ATTR_VECTOR(texcoord);
05670 
05671     }  // end per-Prim (strip) loop
05672 
05673     if(old_coord_indices!=NULL)  {
05674         me->set_coords(old_coords, new_coord_indices);
05675         new_lengths.push_back(new_coord_indices.size());
05676     } else {
05677         me->set_coords(new_coords);
05678         new_lengths.push_back(new_coords.size());
05679     }
05680 
05681     me->set_lengths(new_lengths);
05682     me->set_num_prims(1);
05683 
05684     #define SET_NEW_ATTRIBS(ATTRNAME)                                                                 \
05685     if((ATTRNAME##binding!=G_OFF) && (ATTRNAME##binding!=G_OVERALL)) {                                \
05686         if(ATTRNAME##binding==G_PER_PRIM)                                                             \
05687            ATTRNAME##binding=G_PER_COMPONENT;                                                         \
05688         if(old_##ATTRNAME##_indices==NULL) {                                                          \
05689            me->set_##ATTRNAME##s(new_##ATTRNAME##s, ATTRNAME##binding);                               \
05690         } else {                                                                                      \
05691            me->set_##ATTRNAME##s(old_##ATTRNAME##s, ATTRNAME##binding, new_##ATTRNAME##_indices);     \
05692         }                                                                                             \
05693     }
05694     /*
05695     int ii;
05696     for( ii=0;ii<old_coords.size();ii++)
05697         dxgsg7_cat.debug() << "old coord[" << ii <<"] " << old_coords[ii] << endl;
05698     dxgsg7_cat.debug() << "=================\n";
05699     for(ii=0;ii<new_coords.size();ii++)
05700         dxgsg7_cat.debug() << "new coord[" << ii <<"] " << new_coords[ii] << endl;
05701     dxgsg7_cat.debug() << "=================\n";
05702 
05703     for( ii=0;ii<old_normals.size();ii++)
05704         dxgsg7_cat.debug() << "old norm[" << ii <<"] " << old_normals[ii] << endl;
05705     dxgsg7_cat.debug() << "=================\n";
05706     for(ii=0;ii<new_normals.size();ii++)
05707         dxgsg7_cat.debug() << "new norm[" << ii <<"] " << new_normals[ii] << endl;
05708 
05709     if(old_color_indices!=NULL) {
05710 
05711     for( ii=0;ii<old_color_indices.size();ii++)
05712         dxgsg7_cat.debug() << "old colorindex[" << ii <<"] " << old_color_indices[ii] << endl;
05713     dxgsg7_cat.debug() << "=================\n";
05714     for( ii=0;ii<new_color_indices.size();ii++)
05715         dxgsg7_cat.debug() << "new colorindex[" << ii <<"] " << new_color_indices[ii] << endl;
05716     }
05717     */
05718 
05719     SET_NEW_ATTRIBS(color);
05720     SET_NEW_ATTRIBS(normal);
05721     SET_NEW_ATTRIBS(texcoord);
05722 
05723     me->make_dirty();
05724   }
05725  } // if(link_tristrips)
05726 
05727   // for now, only using vertexbufs for static Geom, so
05728   // Make sure we have at least some static Geoms in the GeomNode;
05729   int cNumVerts=0,i,num_geoms = node->get_num_geoms();
05730 
05731   // need to always put in space for color because we might have some scene-graph color we need to add?
05732   // will that even work?  I think we'd have to overwrite all the VB colors dynamically, and then restore
05733   // them from somewhere if the global color goes away
05734 
05735   DWORD fvfFlags=D3DFVF_XYZ;// | D3DFVF_DIFFUSE;
05736 
05737   for (i = 0; (i < num_geoms); i++) {
05738     dDrawable *drawable1 = node->get_geom(i);
05739     if(!drawable1->is_of_type(Geom::get_class_type()))
05740       continue;
05741 
05742     Geom *geom=DCAST(Geom, drawable1);
05743     assert(geom!=NULL);
05744 
05745     DWORD new_fvfFlags=D3DFVF_XYZ;
05746 
05747     if(!geom->is_dynamic()) {
05748         cNumVerts+=geom->get_num_vertices();
05749         if(geom->get_binding(G_COLOR) != G_OFF)
05750             new_fvfFlags |= D3DFVF_DIFFUSE;
05751         if(geom->get_binding(G_NORMAL) != G_OFF)
05752             new_fvfFlags |= D3DFVF_NORMAL;
05753         if(geom->get_binding(G_TEXCOORD) != G_OFF)
05754             new_fvfFlags |= (D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
05755     }
05756     if(i!=0) {
05757        if(fvfFlags!=new_fvfFlags) {
05758            // all primitives within a geom must use the same FVF type for the DrawPrim api
05759            dxgsg7_cat.error() << "error creating vertex buffer, geoms within geomnode require differing vertex data types!!\n";
05760            exit(1);
05761        }
05762     } else fvfFlags=new_fvfFlags;
05763   }
05764 
05765   if(cNumVerts==0) {
05766     // Never mind.
05767     return (GeomNodeContext *)NULL;
05768   }
05769 
05770   if(cNumVerts>D3DMAXNUMVERTICES) {
05771       dxgsg7_cat.error() << "geom node contains more than " << D3DMAXNUMVERTICES << " vertices, cant create 1 vertex buffer\n";
05772       exit(1);
05773   }
05774 
05775   // Ok, we've got something; use it.
05776   DXGeomNodeContext7 *dx_gnc = new DXGeomNodeContext7(node);
05777 
05778   assert(dx_gnc!=NULL);
05779 
05780   // right now there is a 1-1 correspondence b/w vertbufs and geomnodecontexts.
05781   // later multiple geomnodecontexts will use the same vertbuf
05782 
05783   HRESULT hr;
05784   LPDIRECT3D7 pD3D;
05785 
05786   assert(_pScrn->pD3DDevice!=NULL);
05787   hr=_pScrn->pD3DDevice->GetDirect3D(&pD3D);
05788   assert(!FAILED(hr));
05789   LPDIRECT3DVERTEXBUFFER7 pD3DVertexBuffer;
05790   DX_DECLARE_CLEAN(D3DVERTEXBUFFERDESC, VBdesc);
05791 
05792   VBdesc.dwCaps = D3DVBCAPS_WRITEONLY;
05793   VBdesc.dwCaps |= _pScrn->bIsTNLDevice ? 0x0 : D3DVBCAPS_SYSTEMMEMORY;
05794   VBdesc.dwFVF=fvfFlags;
05795   VBdesc.dwNumVertices=cNumVerts;
05796 
05797   hr=pD3D->CreateVertexBuffer(&VBdesc,&pD3DVertexBuffer,0x0);
05798   if(FAILED(hr)) {
05799     dxgsg7_cat.error() << "error creating vertex buffer: " << ConvD3DErrorToString(hr) << endl;
05800     delete dx_gnc;
05801     exit(1);
05802   }
05803 
05804   dx_gnc->_pVB = pD3DVertexBuffer;
05805 
05806   if(!_pScrn->bIsTNLDevice) {
05807       // create VB for ProcessVerts to xform to
05808 
05809       fvfFlags&=~D3DFVF_XYZ;    // switch to xformed vert type
05810       fvfFlags&=~D3DFVF_NORMAL; // xformed verts are also lighted, so no normals allowed
05811       fvfFlags|=D3DFVF_XYZRHW;
05812       VBdesc.dwFVF=fvfFlags;
05813 
05814       hr=pD3D->CreateVertexBuffer(&VBdesc,&pD3DVertexBuffer,0x0);
05815       if(FAILED(hr)) {
05816           dxgsg7_cat.error() << "error creating xformed vertex buffer: " << ConvD3DErrorToString(hr) << endl;
05817           delete dx_gnc;
05818           exit(1);
05819       }
05820 
05821       dx_gnc->_pXformed_VB = pD3DVertexBuffer;
05822   }
05823 
05824   pD3D->Release();
05825 
05826   dx_gnc->_num_verts=0;
05827   dx_gnc->_start_index=0;
05828 
05829   LPVOID pVertData=NULL;
05830   DWORD dwVBFlags = DDLOCK_NOOVERWRITE | DDLOCK_NOSYSLOCK | DDLOCK_SURFACEMEMORYPTR |
05831                     DDLOCK_WAIT | DDLOCK_DISCARDCONTENTS;
05832 
05833   hr=dx_gnc->_pVB->Lock(dwVBFlags,&pVertData,NULL);
05834   if(FAILED(hr)) {
05835         dxgsg7_cat.error() << "error locking vertex buffer: " << ConvD3DErrorToString(hr) << endl;
05836         delete dx_gnc;
05837         exit(1);
05838   }
05839 
05840   assert(pVertData!=NULL);
05841   _pCurrentGeomContext = dx_gnc;
05842   _pCurrentGeomContext->_pEndofVertData=(BYTE*)pVertData;
05843   _bDrawPrimDoSetupVertexBuffer = true;
05844 
05845 
05846   for (i = 0; (i < num_geoms); i++) {
05847     dDrawable *drawable1 = node->get_geom(i);
05848     if(!drawable1->is_of_type(Geom::get_class_type()))
05849       continue;
05850 
05851     Geom *geom=DCAST(Geom, drawable1);
05852     assert(geom!=NULL);
05853 
05854     if(geom->is_dynamic()) {
05855       dx_gnc->_other_geoms.push_back(geom);
05856     } else {
05857        dx_gnc->_cached_geoms.push_back(geom);
05858        node->get_geom(i)->draw(this);
05859     }
05860   }
05861 
05862   _bDrawPrimDoSetupVertexBuffer = false;
05863   _pCurrentGeomContext->_pEndofVertData=NULL;
05864   _pCurrentGeomContext = NULL;
05865 
05866   hr=dx_gnc->_pVB->Unlock();
05867   if(FAILED(hr)) {
05868       dxgsg7_cat.error() << "error unlocking vertex buffer: " << ConvD3DErrorToString(hr) << endl;
05869       delete dx_gnc;
05870       exit(1);
05871   }
05872 
05873   assert(cNumVerts==dx_gnc->_num_verts);
05874 
05875   hr=dx_gnc->_pVB->Optimize(_pScrn->pD3DDevice,0x0);
05876   if(FAILED(hr)) {
05877       dxgsg7_cat.error() << "error optimizing vertex buffer: " << ConvD3DErrorToString(hr) << endl;
05878       delete dx_gnc;
05879       exit(1);
05880   }
05881 
05882   if(dxgsg7_cat.is_spam())
05883       dxgsg7_cat.spam() << "creating vertex buffer of size: " << cNumVerts << endl;
05884 
05885 #if 0  //DO_PSTATS
05886   float num_verts_after =
05887     _vertices_tristrip_pcollector.get_level() +
05888     _vertices_trifan_pcollector.get_level() +
05889     _vertices_tri_pcollector.get_level() +
05890     _vertices_other_pcollector.get_level();
05891   float num_verts = num_verts_after - num_verts_before;
05892   ggnc->_num_verts = (int)(num_verts + 0.5);
05893 #endif
05894 
05895   bool inserted = mark_prepared_geom_node(dx_gnc);
05896 
05897   // If this assertion fails, the same GeomNode was prepared twice,
05898   // which shouldn't be possible, since the GeomNode itself should
05899   // detect this.
05900   nassertr(inserted, NULL);
05901 
05902   return dx_gnc;
05903 #endif   // temporarily disabled until ported to new scene graph
05904   return NULL;
05905 }
05906 
05907 ////////////////////////////////////////////////////////////////////
05908 //     Function: DXGraphicsStateGuardian7::draw_geom_node
05909 //       Access: Public, Virtual
05910 //  Description: Draws a GeomNode previously indicated by a call to
05911 //               prepare_geom_node().
05912 ////////////////////////////////////////////////////////////////////
05913 void DXGraphicsStateGuardian7::
05914 draw_geom_node(GeomNode *node, const RenderState *state, GeomNodeContext *gnc) {
05915 #if 0   // temporarily disabled until ported to new scene graph
05916 
05917   uint i,num_geoms = node->get_num_geoms();
05918 
05919   if (gnc == (GeomNodeContext *)NULL) {
05920 
05921     // We don't have a saved context; just draw the GeomNode in
05922     // immediate mode.
05923     for (i = 0; i < num_geoms; i++) {
05924         node->get_geom(i)->draw(this);
05925     }
05926     return;
05927   }
05928 
05929   // We do have a saved context; use it.
05930   add_to_geom_node_record(gnc);
05931   DXGeomNodeContext7 *dx_gnc = DCAST(DXGeomNodeContext7, gnc);
05932 
05933   #ifdef _DEBUG
05934      assert(dx_gnc->_pVB!=NULL);
05935      assert((!_pScrn->bIsTNLDevice)==(dx_gnc->_pXformed_VB!=NULL));
05936   #endif
05937 
05938   if(!_pScrn->bIsTNLDevice) {
05939       HRESULT hr;
05940 
05941       DWORD PVOp=D3DVOP_CLIP | D3DVOP_TRANSFORM | D3DVOP_EXTENTS;
05942 
05943       D3DVERTEXBUFFERDESC VBdesc;
05944       VBdesc.dwSize=sizeof(VBdesc);
05945       hr=dx_gnc->_pVB->GetVertexBufferDesc(&VBdesc);   // would be useful to keep fvf in vertbuf struct to avoid having to do this
05946       if(FAILED(hr)) {
05947         dxgsg7_cat.error() << "error in getvbdesc: " << ConvD3DErrorToString(hr) << endl;
05948         exit(1);
05949       }
05950 
05951       if(_lighting_enabled && (VBdesc.dwFVF & D3DFVF_NORMAL)) {
05952           PVOp|=D3DVOP_LIGHT;
05953       }
05954 
05955       hr=dx_gnc->_pXformed_VB->ProcessVertices(PVOp,0,dx_gnc->_num_verts,dx_gnc->_pVB,0,_pScrn->pD3DDevice,0x0);
05956       if(FAILED(hr)) {
05957         dxgsg7_cat.error() << "error in ProcessVertices: " << ConvD3DErrorToString(hr) << endl;
05958         exit(1);
05959       }
05960 
05961       // disable clipping, since VB is already xformed and clipped
05962       if(_clipping_enabled)
05963           _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, false);
05964   }
05965 
05966   // assume we need gouraud for now.  we can make this more complex to select flat conditionally later
05967   set_shademode(D3DSHADE_GOURAUD);
05968   int cur_startvert=dx_gnc->_start_index;
05969 
05970   for (i = 0; i < dx_gnc->_cached_geoms.size(); i++) {
05971     // I think we can just draw them directly? since cant account for issued stuff (since
05972     // its already encoded in the VB), and we can set the renderstates here (e.g. gouraud mode)
05973     //      dx_gnc->_cached_geoms[i]->draw(this);
05974 
05975      DPInfo *dpi=&dx_gnc->_PrimInfo[i];
05976 
05977      LPDIRECT3DVERTEXBUFFER7 pVB;
05978      if(_pScrn->bIsTNLDevice) {
05979          pVB=dx_gnc->_pVB;
05980      } else {
05981          pVB=dx_gnc->_pXformed_VB;
05982      }
05983 
05984      HRESULT hr = _pScrn->pD3DDevice->DrawPrimitiveVB(dpi->primtype,pVB,cur_startvert,dpi->nVerts,0x0);
05985      TestDrawPrimFailure(DrawPrim,hr,_pScrn->pDD,dpi->nVerts,0);
05986 
05987      cur_startvert+=dpi->nVerts;
05988   }
05989 
05990   if((!_pScrn->bIsTNLDevice) && _clipping_enabled)
05991       _pScrn->pD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPING, true);
05992 
05993   // Also draw all the dynamic Geoms.
05994   for (i = 0; i < dx_gnc->_other_geoms.size(); i++) {
05995       dx_gnc->_other_geoms[i]->draw(this);
05996   }
05997 
05998 #if 0 //def DO_PSTATS
05999     DO_PSTATS_STUFF(PStatTimer timer(_draw_primitive_pcollector));
06000     _vertices_display_list_pcollector.add_level(dx_gnc->_num_verts);
06001 #endif
06002 #endif   // temporarily disabled until ported to new scene graph
06003 }
06004 
06005 ////////////////////////////////////////////////////////////////////
06006 //     Function: DXGraphicsStateGuardian7::release_geom_node
06007 //       Access: Public, Virtual
06008 //  Description: Frees the resources previously allocated via a call
06009 //               to prepare_geom_node(), including deleting the
06010 //               GeomNodeContext itself, if necessary.
06011 ////////////////////////////////////////////////////////////////////
06012 void DXGraphicsStateGuardian7::
06013 release_geom_node(GeomNodeContext *gnc) {
06014 #if 0   // temporarily disabled until ported to new scene graph
06015   if (gnc != (GeomNodeContext *)NULL) {
06016     DXGeomNodeContext7 *dx_gnc = DCAST(DXGeomNodeContext7, gnc);
06017 
06018     bool erased = unmark_prepared_geom_node(dx_gnc);
06019 
06020     // If this assertion fails, a GeomNode was released that hadn't
06021     // been prepared (or a GeomNode was released twice).
06022     nassertv(erased);
06023 
06024     dx_gnc->_node->clear_gsg(this);
06025     delete dx_gnc;  // should release vertex buffer
06026   }
06027 #endif   // temporarily disabled until ported to new scene graph
06028 }

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