Panda3D

dxGraphicsStateGuardian9.cxx

00001 // Filename: dxGraphicsStateGuardian9.cxx
00002 // Created by:  mike (02Feb99)
00003 // Updated by: fperazzi, PandaSE (05May10) (added get_supports_cg_profile)
00004 //
00005 ////////////////////////////////////////////////////////////////////
00006 //
00007 // PANDA 3D SOFTWARE
00008 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00009 //
00010 // All use of this software is subject to the terms of the revised BSD
00011 // license.  You should have received a copy of this license along
00012 // with this source code in a file named "LICENSE."
00013 //
00014 ////////////////////////////////////////////////////////////////////
00015 
00016 #include "dxGraphicsStateGuardian9.h"
00017 #include "config_dxgsg9.h"
00018 #include "displayRegion.h"
00019 #include "renderBuffer.h"
00020 #include "geom.h"
00021 #include "graphicsWindow.h"
00022 #include "graphicsEngine.h"
00023 #include "lens.h"
00024 #include "ambientLight.h"
00025 #include "directionalLight.h"
00026 #include "pointLight.h"
00027 #include "spotlight.h"
00028 #include "textureAttrib.h"
00029 #include "texGenAttrib.h"
00030 #include "shadeModelAttrib.h"
00031 #include "cullFaceAttrib.h"
00032 #include "transparencyAttrib.h"
00033 #include "alphaTestAttrib.h"
00034 #include "depthTestAttrib.h"
00035 #include "depthWriteAttrib.h"
00036 #include "colorWriteAttrib.h"
00037 #include "texMatrixAttrib.h"
00038 #include "materialAttrib.h"
00039 #include "renderModeAttrib.h"
00040 #include "rescaleNormalAttrib.h"
00041 #include "fogAttrib.h"
00042 #include "depthOffsetAttrib.h"
00043 #include "lightAttrib.h"
00044 #include "stencilAttrib.h"
00045 #include "scissorAttrib.h"
00046 #include "fog.h"
00047 #include "throw_event.h"
00048 #include "geomVertexFormat.h"
00049 #include "geomVertexData.h"
00050 #include "geomTriangles.h"
00051 #include "geomTristrips.h"
00052 #include "geomTrifans.h"
00053 #include "geomLines.h"
00054 #include "geomLinestrips.h"
00055 #include "geomPoints.h"
00056 #include "geomVertexReader.h"
00057 #include "dxGeomMunger9.h"
00058 #include "config_gobj.h"
00059 #include "dxVertexBufferContext9.h"
00060 #include "dxIndexBufferContext9.h"
00061 #include "dxOcclusionQueryContext9.h"
00062 #include "pStatTimer.h"
00063 #include "pStatCollector.h"
00064 #include "wdxGraphicsBuffer9.h"
00065 #include "config_pgraph.h"
00066 #include "shaderGenerator.h"
00067 #ifdef HAVE_CG
00068 #include "Cg/cgD3D9.h"
00069 #endif
00070 
00071 #include <mmsystem.h>
00072 
00073 #include <dxsdkver.h>
00074 
00075 #define tostring(x) #x
00076 #define SDK_VERSION(major,minor) tostring(major) << "." << tostring(minor)
00077 #define DIRECTX_SDK_VERSION  SDK_VERSION (_DXSDK_PRODUCT_MAJOR, _DXSDK_PRODUCT_MINOR) << "." << SDK_VERSION (_DXSDK_BUILD_MAJOR, _DXSDK_BUILD_MINOR)
00078 
00079 TypeHandle DXGraphicsStateGuardian9::_type_handle;
00080 
00081 D3DMATRIX DXGraphicsStateGuardian9::_d3d_ident_mat;
00082 
00083 unsigned char *DXGraphicsStateGuardian9::_temp_buffer = NULL;
00084 unsigned char *DXGraphicsStateGuardian9::_safe_buffer_start = NULL;
00085 
00086 LPDIRECT3DDEVICE9 DXGraphicsStateGuardian9::_cg_device = NULL;
00087 
00088 #define __D3DLIGHT_RANGE_MAX ((float)sqrt(FLT_MAX))  //for some reason this is missing in dx9 hdrs
00089 
00090 #define MY_D3DRGBA(r, g, b, a) ((D3DCOLOR) D3DCOLOR_COLORVALUE(r, g, b, a))
00091 
00092 ////////////////////////////////////////////////////////////////////
00093 //     Function: DXGraphicsStateGuardian9::Constructor
00094 //       Access: Public
00095 //  Description:
00096 ////////////////////////////////////////////////////////////////////
00097 DXGraphicsStateGuardian9::
00098 DXGraphicsStateGuardian9(GraphicsEngine *engine, GraphicsPipe *pipe) :
00099   GraphicsStateGuardian(CS_yup_left, engine, pipe)
00100 {
00101   if (dxgsg9_cat.is_debug()) {
00102     dxgsg9_cat.debug()
00103       << "DXGraphicsStateGuardian9 " << this << " constructing\n";
00104   }
00105 
00106   // Assume that we will get a hardware-accelerated context, unless
00107   // the window tells us otherwise.
00108   _is_hardware = true;
00109 
00110   _screen = NULL;
00111   _d3d_device = NULL;
00112 
00113   _dx_is_ready = false;
00114   _vertex_blending_enabled = false;
00115   _overlay_windows_supported = false;
00116   _tex_stats_retrieval_impossible = false;
00117 
00118   _active_vbuffer = NULL;
00119   _active_ibuffer = NULL;
00120 
00121   // This is a static member, but we initialize it here in the
00122   // constructor anyway.  It won't hurt if it gets repeatedly
00123   // initalized.
00124   ZeroMemory(&_d3d_ident_mat, sizeof(D3DMATRIX));
00125   _d3d_ident_mat._11 = _d3d_ident_mat._22 = _d3d_ident_mat._33 = _d3d_ident_mat._44 = 1.0f;
00126 
00127   _cur_read_pixel_buffer = RenderBuffer::T_front;
00128 
00129   // DirectX drivers seem to consistently invert the texture when
00130   // they copy framebuffer-to-texture.  Ok.
00131   _copy_texture_inverted = true;
00132 
00133   // D3DRS_POINTSPRITEENABLE doesn't seem to support remapping the
00134   // texture coordinates via a texture matrix, so we don't advertise
00135   // GR_point_sprite_tex_matrix.
00136   _supported_geom_rendering =
00137     Geom::GR_point | Geom::GR_point_uniform_size |
00138     Geom::GR_point_perspective | Geom::GR_point_sprite |
00139     Geom::GR_indexed_other |
00140     Geom::GR_triangle_strip | Geom::GR_triangle_fan |
00141     Geom::GR_flat_first_vertex;
00142 
00143   _gsg_managed_textures = dx_management | dx_texture_management;
00144   _gsg_managed_vertex_buffers = dx_management;
00145   _gsg_managed_index_buffers = dx_management;
00146 
00147   _last_fvf = 0;
00148 
00149   _vertex_shader_version_major = 0;
00150   _vertex_shader_version_minor = 0;
00151   _pixel_shader_version_major = 0;
00152   _pixel_shader_version_minor = 0;
00153 
00154   _vertex_shader_profile = 0;
00155   _pixel_shader_profile = 0;
00156 
00157   _vertex_shader_maximum_constants = 0;
00158 
00159   _supports_stream_offset = false;
00160 
00161   get_gamma_table();
00162   atexit (atexit_function);
00163 }
00164 
00165 ////////////////////////////////////////////////////////////////////
00166 //     Function: DXGraphicsStateGuardian9::Destructor
00167 //       Access: Public
00168 //  Description:
00169 ////////////////////////////////////////////////////////////////////
00170 DXGraphicsStateGuardian9::
00171 ~DXGraphicsStateGuardian9() {
00172   if (dxgsg9_cat.is_debug()) {
00173     dxgsg9_cat.debug()
00174       << "DXGraphicsStateGuardian9 " << this << " destructing\n";
00175   }
00176 
00177   if (IS_VALID_PTR(_d3d_device)) {
00178     _d3d_device->SetTexture(0, NULL);  // this frees reference to the old texture
00179   }
00180 
00181   free_nondx_resources();
00182 }
00183 
00184 ////////////////////////////////////////////////////////////////////
00185 //     Function: DXGraphicsStateGuardian9::prepare_texture
00186 //       Access: Public, Virtual
00187 //  Description: Creates a new retained-mode representation of the
00188 //               given texture, and returns a newly-allocated
00189 //               TextureContext pointer to reference it.  It is the
00190 //               responsibility of the calling function to later
00191 //               call release_texture() with this same pointer (which
00192 //               will also delete the pointer).
00193 //
00194 //               This function should not be called directly to
00195 //               prepare a texture.  Instead, call Texture::prepare().
00196 ////////////////////////////////////////////////////////////////////
00197 TextureContext *DXGraphicsStateGuardian9::
00198 prepare_texture(Texture *tex) {
00199   DXTextureContext9 *dtc = new DXTextureContext9(_prepared_objects, tex);
00200 
00201   if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) {
00202     dxgsg9_cat.error()
00203       << *dtc->get_texture() << " is stored in an unsupported compressed format.\n";
00204     return NULL;
00205   }
00206 
00207   return dtc;
00208 }
00209 
00210 ////////////////////////////////////////////////////////////////////
00211 //     Function: DXGraphicsStateGuardian9::apply_texture
00212 //       Access: Public
00213 //  Description: Makes the texture the currently available texture for
00214 //               rendering on the ith stage.
00215 ////////////////////////////////////////////////////////////////////
00216 void DXGraphicsStateGuardian9::
00217 apply_texture(int i, TextureContext *tc) {
00218   if (tc == (TextureContext *)NULL) {
00219     // The texture wasn't bound properly or something, so ensure
00220     // texturing is disabled and just return.
00221     set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
00222     return;
00223   }
00224   if (!update_texture(tc, false)) {
00225     // Couldn't get the texture image or something.
00226     set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
00227     return;
00228   }
00229 
00230   tc->set_active(true);
00231 
00232   DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
00233   Texture *tex = tc->get_texture();
00234 
00235   Texture::WrapMode wrap_u, wrap_v, wrap_w;
00236 
00237   DWORD address_u;
00238   DWORD address_v;
00239   DWORD address_w;
00240 
00241   wrap_u = tex->get_wrap_u();
00242   wrap_v = tex->get_wrap_v();
00243   wrap_w = tex->get_wrap_w();
00244 
00245   address_u = get_texture_wrap_mode(wrap_u);
00246   address_v = get_texture_wrap_mode(wrap_v);
00247   address_w = get_texture_wrap_mode(wrap_w);
00248 
00249   set_sampler_state(i, D3DSAMP_ADDRESSU, address_u);
00250   set_sampler_state(i, D3DSAMP_ADDRESSV, address_v);
00251   set_sampler_state(i, D3DSAMP_ADDRESSW, address_w);
00252 
00253   DWORD border_color;
00254   border_color = Colorf_to_D3DCOLOR(tex->get_border_color());
00255 
00256   set_sampler_state(i, D3DSAMP_BORDERCOLOR, border_color);
00257 
00258   uint aniso_degree = tex->get_effective_anisotropic_degree();
00259   Texture::FilterType ft = tex->get_effective_magfilter();
00260 
00261   if (aniso_degree >= 1) {
00262     set_sampler_state(i, D3DSAMP_MAXANISOTROPY, aniso_degree);
00263   }
00264 
00265   int supports_anisotropic_mag_filter;
00266   D3DTEXTUREFILTERTYPE new_mag_filter;
00267   
00268   supports_anisotropic_mag_filter = (_screen -> _d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
00269   if (aniso_degree <= 1 || supports_anisotropic_mag_filter == 0) {
00270     new_mag_filter = ((ft != Texture::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT);
00271   } else {
00272     new_mag_filter = D3DTEXF_ANISOTROPIC;
00273   }
00274 
00275   HRESULT hr;
00276   hr = set_sampler_state(i, D3DSAMP_MAGFILTER, new_mag_filter);
00277   if (hr != D3D_OK) {
00278     dxgsg9_cat.error()
00279       << "ERROR: set_sampler_state (D3DSAMP_MAGFILTER, " 
00280       << new_mag_filter << ") failed for texture:" << tex -> get_name() << endl;    
00281   }
00282 
00283   // map Panda composite min+mip filter types to d3d's separate min & mip filter types
00284   D3DTEXTUREFILTERTYPE new_min_filter = get_d3d_min_type(tex->get_effective_minfilter());
00285   D3DTEXTUREFILTERTYPE new_mip_filter = get_d3d_mip_type(tex->get_effective_minfilter());
00286 
00287   if (!tex->might_have_ram_image()) {
00288     // If the texture is completely dynamic, don't try to issue
00289     // mipmaps--pandadx doesn't support auto-generated mipmaps at this
00290     // point.
00291     new_mip_filter = D3DTEXF_NONE;
00292   }
00293 
00294   // sanity check
00295   if (!dtc->has_mipmaps()) {
00296     new_mip_filter = D3DTEXF_NONE;
00297   }
00298 
00299   if (aniso_degree >= 2) {
00300     new_min_filter = D3DTEXF_ANISOTROPIC;
00301   }
00302 
00303   set_sampler_state(i, D3DSAMP_MINFILTER, new_min_filter);
00304   set_sampler_state(i, D3DSAMP_MIPFILTER, new_mip_filter);
00305 
00306   _d3d_device->SetTexture(i, dtc->get_d3d_texture());
00307 }
00308 
00309 ////////////////////////////////////////////////////////////////////
00310 //     Function: DXGraphicsStateGuardian9::update_texture
00311 //       Access: Public, Virtual
00312 //  Description: Ensures that the current Texture data is refreshed
00313 //               onto the GSG.  This means updating the texture
00314 //               properties and/or re-uploading the texture image, if
00315 //               necessary.  This should only be called within the
00316 //               draw thread.
00317 //
00318 //               If force is true, this function will not return until
00319 //               the texture has been fully uploaded.  If force is
00320 //               false, the function may choose to upload a simple
00321 //               version of the texture instead, if the texture is not
00322 //               fully resident (and if get_incomplete_render() is
00323 //               true).
00324 ////////////////////////////////////////////////////////////////////
00325 bool DXGraphicsStateGuardian9::
00326 update_texture(TextureContext *tc, bool force) {
00327   DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
00328 
00329   // If the texture image has changed, or if its use of mipmaps has
00330   // changed, we need to re-create the image.
00331 
00332   if (dtc->was_modified()) {
00333     if (!upload_texture(dtc, force)) {
00334       // Oops, we can't re-create the texture for some reason.
00335       Texture *tex = tc->get_texture();
00336       dxgsg9_cat.error()
00337         << "Unable to re-create texture " << *tex << endl;
00338       return false;
00339     }
00340   }
00341   dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
00342 
00343   return true;
00344 }
00345 
00346 ////////////////////////////////////////////////////////////////////
00347 //     Function: DXGraphicsStateGuardian9::upload_texture
00348 //       Access: Public
00349 //  Description: Creates a texture surface on the graphics card and
00350 //               fills it with its pixel data.
00351 ////////////////////////////////////////////////////////////////////
00352 bool DXGraphicsStateGuardian9::
00353 upload_texture(DXTextureContext9 *dtc, bool force) {
00354   Texture *tex = dtc->get_texture();
00355   if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) {
00356     dxgsg9_cat.error()
00357       << *tex << " is stored in an unsupported compressed format.\n";
00358     return false;
00359   }
00360 
00361   dtc->delete_texture();
00362   dtc->update_data_size_bytes(0);
00363   dtc->mark_unloaded();
00364   
00365   if (_effective_incomplete_render && !force) {
00366     bool has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image();
00367     if (!has_image && tex->might_have_ram_image() &&
00368         tex->has_simple_ram_image() &&
00369         !_loader.is_null()) {
00370       // If we don't have the texture data right now, go get it, but in
00371       // the meantime load a temporary simple image in its place.
00372       async_reload_texture(dtc);
00373       has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image();
00374       if (!has_image) {
00375         if (dtc->was_simple_image_modified()) {
00376           return dtc->create_simple_texture(*_screen);
00377         }
00378         return true;
00379       }
00380     }
00381   }
00382   
00383   return dtc->create_texture(*_screen);
00384 }
00385 
00386 ////////////////////////////////////////////////////////////////////
00387 //     Function: DXGraphicsStateGuardian9::release_texture
00388 //       Access: Public, Virtual
00389 //  Description: Frees the GL resources previously allocated for the
00390 //               texture.
00391 ////////////////////////////////////////////////////////////////////
00392 void DXGraphicsStateGuardian9::
00393 release_texture(TextureContext *tc) {
00394   DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
00395   delete dtc;
00396 }
00397 
00398 ////////////////////////////////////////////////////////////////////
00399 //     Function: DXGraphicsStateGuardian9::extract_texture_data
00400 //       Access: Public, Virtual
00401 //  Description: This method should only be called by the
00402 //               GraphicsEngine.  Do not call it directly; call
00403 //               GraphicsEngine::extract_texture_data() instead.
00404 //
00405 //               This method will be called in the draw thread to
00406 //               download the texture memory's image into its
00407 //               ram_image value.  It returns true on success, false
00408 //               otherwise.
00409 ////////////////////////////////////////////////////////////////////
00410 bool DXGraphicsStateGuardian9::
00411 extract_texture_data(Texture *tex) {
00412   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
00413   nassertr(tc != (TextureContext *)NULL, false);
00414   DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
00415 
00416   return dtc->extract_texture_data(*_screen);
00417 }
00418 
00419 ////////////////////////////////////////////////////////////////////
00420 //     Function: DXGraphicsStateGuardian9::prepare_shader
00421 //       Access: Public, Virtual
00422 //  Description:
00423 ////////////////////////////////////////////////////////////////////
00424 ShaderContext *DXGraphicsStateGuardian9::
00425 prepare_shader(Shader *se) {
00426 #ifdef HAVE_CG
00427   CLP(ShaderContext) *result = new CLP(ShaderContext)(se, this);
00428   return result;
00429 #endif
00430   return NULL;
00431 }
00432 
00433 ////////////////////////////////////////////////////////////////////
00434 //     Function: DXGraphicsStateGuardian9::release_shader
00435 //       Access: Public, Virtual
00436 //  Description:
00437 ////////////////////////////////////////////////////////////////////
00438 void DXGraphicsStateGuardian9::
00439 release_shader(ShaderContext *sc) {
00440   CLP(ShaderContext) *gsc = DCAST(CLP(ShaderContext), sc);
00441   delete gsc;
00442 }
00443 
00444 ////////////////////////////////////////////////////////////////////
00445 //     Function: DXGraphicsStateGuardian9::prepare_vertex_buffer
00446 //       Access: Public, Virtual
00447 //  Description: Creates a new retained-mode representation of the
00448 //               given data, and returns a newly-allocated
00449 //               VertexBufferContext pointer to reference it.  It is the
00450 //               responsibility of the calling function to later
00451 //               call release_vertex_buffer() with this same pointer (which
00452 //               will also delete the pointer).
00453 //
00454 //               This function should not be called directly to
00455 //               prepare a buffer.  Instead, call Geom::prepare().
00456 ////////////////////////////////////////////////////////////////////
00457 VertexBufferContext *DXGraphicsStateGuardian9::
00458 prepare_vertex_buffer(GeomVertexArrayData *data) {
00459   DXVertexBufferContext9 *dvbc = new DXVertexBufferContext9(_prepared_objects, data, *(this -> _screen));
00460   return dvbc;
00461 }
00462 
00463 ////////////////////////////////////////////////////////////////////
00464 //     Function: DXGraphicsStateGuardian9::apply_vertex_buffer
00465 //       Access: Public
00466 //  Description: Updates the vertex buffer with the current data, and
00467 //               makes it the current vertex buffer for rendering.
00468 ////////////////////////////////////////////////////////////////////
00469 bool DXGraphicsStateGuardian9::
00470 apply_vertex_buffer(VertexBufferContext *vbc,
00471                     CLP(ShaderContext) *shader_context,
00472                     const GeomVertexArrayDataHandle *reader, 
00473                     bool force,
00474                     string name) {
00475   DXVertexBufferContext9 *dvbc = DCAST(DXVertexBufferContext9, vbc);
00476 
00477   bool set_stream_source;
00478   HRESULT hr;
00479   UINT stream;
00480   UINT offset;
00481 
00482   set_stream_source = false;
00483   stream = 0;
00484   offset = 0;
00485 
00486   if (dvbc->_vbuffer == NULL) {
00487     // Attempt to create a new vertex buffer.
00488     if (vertex_buffers &&
00489         reader->get_usage_hint() != Geom::UH_client) {
00490       dvbc->create_vbuffer(*_screen, reader, name);
00491     }
00492 
00493     if (dvbc->_vbuffer != NULL) {
00494       if (!dvbc->upload_data(reader, force)) {
00495         return false;
00496       }
00497 
00498       dvbc->mark_loaded(reader);
00499 
00500       set_stream_source = true;
00501 
00502     } else {
00503       _active_vbuffer = NULL;
00504     }
00505 
00506   } else {
00507     if (dvbc->was_modified(reader)) {
00508       if (dvbc->changed_size(reader)) {
00509         // We have to destroy the old vertex buffer and create a new
00510         // one.
00511         dvbc->create_vbuffer(*_screen, reader, name);
00512       }
00513 
00514       if (!dvbc->upload_data(reader, force)) {
00515         return false;
00516       }
00517 
00518       dvbc->mark_loaded(reader);
00519       _active_vbuffer = NULL;
00520     }
00521 
00522     if (_active_vbuffer != dvbc) {
00523       set_stream_source = true;
00524     }
00525   }
00526   dvbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
00527 
00528   if (shader_context == 0) {
00529     // FVF MODE
00530     if (set_stream_source) {
00531       hr = _d3d_device->SetStreamSource
00532         (stream, dvbc->_vbuffer, offset, reader->get_array_format()->get_stride());
00533       if (FAILED(hr)) {
00534         dxgsg9_cat.error()
00535           << "SetStreamSource failed" << D3DERRORSTRING(hr);
00536       }
00537       _active_vbuffer = dvbc;
00538       _active_ibuffer = NULL;
00539       dvbc->set_active(true);
00540     }
00541 
00542     if ((dvbc->_fvf != _last_fvf)) {
00543       hr = _d3d_device->SetFVF(dvbc->_fvf);
00544       if (FAILED(hr)) {
00545         dxgsg9_cat.error() << "SetFVF failed" << D3DERRORSTRING(hr);
00546       }
00547 
00548       _last_fvf = dvbc->_fvf;
00549     }
00550   }
00551   else {
00552     // SHADER MODE
00553     if (set_stream_source) {
00554       if (dvbc -> _direct_3d_vertex_declaration) {
00555         if (dvbc -> _shader_context == shader_context) {
00556           // same shader as before, no need to remap a new vertex declaration
00557         }
00558         else {
00559           // need to make a new vertex declaration since the new shader may
00560           // have a different mapping
00561           dvbc -> _direct_3d_vertex_declaration -> Release ( );
00562           dvbc -> _direct_3d_vertex_declaration = 0;
00563           dvbc -> _shader_context = 0;
00564         }
00565       }
00566 
00567       if (dvbc -> _direct_3d_vertex_declaration == 0 &&
00568           dvbc -> _vertex_element_type_array) {
00569         VertexElementArray *vertex_element_array;
00570 
00571         vertex_element_array = shader_context -> _vertex_element_array;
00572         if (vertex_element_array) {
00573           int index;
00574 
00575           for (index = 0; index < vertex_element_array->total_elements; index++) {
00576             VERTEX_ELEMENT_TYPE *vertex_element_type;
00577             VERTEX_ELEMENT_TYPE *source_vertex_element_type;
00578 
00579             vertex_element_type =
00580               &vertex_element_array -> vertex_element_type_array [index];
00581 
00582             // MAP VERTEX ELEMENTS to VERTEX SHADER INPUTS
00583             // get offsets from vertex data for certain types of vertex elements
00584 
00585             offset = 0;
00586             source_vertex_element_type = dvbc -> _vertex_element_type_array;
00587             while (source_vertex_element_type -> vs_input_type != VS_END) {
00588               if (source_vertex_element_type -> vs_input_type == vertex_element_type -> vs_input_type &&
00589                   source_vertex_element_type -> index == vertex_element_type -> index) {
00590                   offset = source_vertex_element_type -> offset;
00591                   break;
00592               }
00593               source_vertex_element_type++;
00594             }
00595             if (source_vertex_element_type -> vs_input_type == VS_END) {
00596               dxgsg9_cat.error()
00597                 << "unable to find a mapping for vertex shader input type="
00598                 << vertex_element_type -> vs_input_type
00599                 << " from vertex elements\n";
00600             }
00601 
00602             vertex_element_array -> set_vertex_element_offset (index, offset);
00603           }
00604 
00605           hr = _d3d_device -> CreateVertexDeclaration (
00606             vertex_element_array -> vertex_element_array,
00607             &dvbc -> _direct_3d_vertex_declaration);
00608           if (FAILED (hr)) {
00609             dxgsg9_cat.error()
00610               << "CreateVertexDeclaration failed"
00611               << D3DERRORSTRING(hr);
00612 
00613             if (0) {
00614               // DEBUG
00615               printf ("TOTAL ELEMENTS: %d \n",  vertex_element_array -> total_elements);
00616               for (index = 0; index < vertex_element_array -> total_elements; index++) 
00617               {
00618                 DIRECT_3D_VERTEX_ELEMENT *vertex_element;
00619                 VERTEX_ELEMENT_TYPE *vertex_element_type;
00620 
00621                 vertex_element = &vertex_element_array -> vertex_element_array [index];
00622                 vertex_element_type = &vertex_element_array -> vertex_element_type_array [index];
00623 
00624                 printf ("  index %d Stream %d  Offset %d Type %d Method %d Usage %d UsageIndex %d \n", index, vertex_element -> Stream, vertex_element -> Offset, vertex_element -> Type, vertex_element -> Method, vertex_element -> Usage, vertex_element -> UsageIndex);
00625               }
00626             }
00627           }
00628 
00629           dvbc -> _shader_context = shader_context;
00630         }
00631         else {
00632           dxgsg9_cat.error() << "apply_vertex_buffer ( ): shader_context vertex_element_array == 0\n";
00633         }
00634       }
00635 
00636       offset = 0;
00637       hr = _d3d_device->SetStreamSource
00638         (stream, dvbc->_vbuffer, offset, reader->get_array_format()->get_stride());
00639       if (FAILED(hr)) {
00640         dxgsg9_cat.error()
00641           << "SetStreamSource failed" << D3DERRORSTRING(hr);
00642       }
00643       _active_vbuffer = dvbc;
00644       _active_ibuffer = NULL;
00645       dvbc->set_active(true);
00646     }
00647 
00648     if (dvbc -> _direct_3d_vertex_declaration) {
00649       hr = _d3d_device -> SetVertexDeclaration (dvbc -> _direct_3d_vertex_declaration);
00650       if (FAILED(hr)) {
00651         dxgsg9_cat.error()
00652           << "SetVertexDeclaration failed" << D3DERRORSTRING(hr);
00653       }
00654     }
00655   }
00656 
00657   return true;
00658 }
00659 
00660 ////////////////////////////////////////////////////////////////////
00661 //     Function: DXGraphicsStateGuardian9::release_vertex_buffer
00662 //       Access: Public, Virtual
00663 //  Description: Frees the GL resources previously allocated for the
00664 //               data.  This function should never be called
00665 //               directly; instead, call Data::release() (or simply
00666 //               let the Data destruct).
00667 ////////////////////////////////////////////////////////////////////
00668 void DXGraphicsStateGuardian9::
00669 release_vertex_buffer(VertexBufferContext *vbc) {
00670   DXVertexBufferContext9 *dvbc = DCAST(DXVertexBufferContext9, vbc);
00671   delete dvbc;
00672 }
00673 
00674 ////////////////////////////////////////////////////////////////////
00675 //     Function: DXGraphicsStateGuardian9::prepare_index_buffer
00676 //       Access: Public, Virtual
00677 //  Description: Creates a new retained-mode representation of the
00678 //               given data, and returns a newly-allocated
00679 //               IndexBufferContext pointer to reference it.  It is the
00680 //               responsibility of the calling function to later call
00681 //               release_index_buffer() with this same pointer (which
00682 //               will also delete the pointer).
00683 //
00684 //               This function should not be called directly to
00685 //               prepare a buffer.  Instead, call Geom::prepare().
00686 ////////////////////////////////////////////////////////////////////
00687 IndexBufferContext *DXGraphicsStateGuardian9::
00688 prepare_index_buffer(GeomPrimitive *data) {
00689   DXIndexBufferContext9 *dibc = new DXIndexBufferContext9(_prepared_objects, data);
00690   return dibc;
00691 }
00692 
00693 ////////////////////////////////////////////////////////////////////
00694 //     Function: DXGraphicsStateGuardian9::apply_index_buffer
00695 //       Access: Public
00696 //  Description: Updates the index buffer with the current data, and
00697 //               makes it the current index buffer for rendering.
00698 ////////////////////////////////////////////////////////////////////
00699 bool DXGraphicsStateGuardian9::
00700 apply_index_buffer(IndexBufferContext *ibc,
00701                    const GeomPrimitivePipelineReader *reader, bool force) {
00702   DXIndexBufferContext9 *dibc = DCAST(DXIndexBufferContext9, ibc);
00703 
00704   if (dibc->_ibuffer == NULL) {
00705     // Attempt to create a new index buffer.
00706     dibc->create_ibuffer(*_screen, reader);
00707 
00708     if (dibc->_ibuffer != NULL) {
00709       if (!dibc->upload_data(reader, force)) {
00710         return false;
00711       }
00712       dibc->mark_loaded(reader);
00713 
00714       _d3d_device->SetIndices(dibc->_ibuffer);
00715       _active_ibuffer = dibc;
00716       dibc->set_active(true);
00717 
00718     } else {
00719       _d3d_device->SetIndices(NULL);
00720       _active_ibuffer = NULL;
00721     }
00722 
00723   } else {
00724     if (dibc->was_modified(reader)) {
00725       if (dibc->changed_size(reader)) {
00726         // We have to destroy the old index buffer and create a new
00727         // one.
00728         dibc->create_ibuffer(*_screen, reader);
00729       }
00730 
00731       if (!dibc->upload_data(reader, force)) {
00732         return false;
00733       }
00734 
00735       dibc->mark_loaded(reader);
00736       _active_ibuffer = NULL;
00737     }
00738 
00739     if (_active_ibuffer != dibc) {
00740       _d3d_device->SetIndices(dibc->_ibuffer);
00741       _active_ibuffer = dibc;
00742       dibc->set_active(true);
00743     }
00744   }
00745   dibc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
00746 
00747   return true;
00748 }
00749 
00750 ////////////////////////////////////////////////////////////////////
00751 //     Function: DXGraphicsStateGuardian9::release_index_buffer
00752 //       Access: Public, Virtual
00753 //  Description: Frees the GL resources previously allocated for the
00754 //               data.  This function should never be called
00755 //               directly; instead, call Data::release() (or simply
00756 //               let the Data destruct).
00757 ////////////////////////////////////////////////////////////////////
00758 void DXGraphicsStateGuardian9::
00759 release_index_buffer(IndexBufferContext *ibc) {
00760   DXIndexBufferContext9 *dibc = DCAST(DXIndexBufferContext9, ibc);
00761   delete dibc;
00762 }
00763 
00764 ////////////////////////////////////////////////////////////////////
00765 //     Function: DXGraphicsStateGuardian9::begin_occlusion_query
00766 //       Access: Public, Virtual
00767 //  Description: Begins a new occlusion query.  After this call, you
00768 //               may call begin_draw_primitives() and
00769 //               draw_triangles()/draw_whatever() repeatedly.
00770 //               Eventually, you should call end_occlusion_query()
00771 //               before the end of the frame; that will return a new
00772 //               OcclusionQueryContext object that will tell you how
00773 //               many pixels represented by the bracketed geometry
00774 //               passed the depth test.
00775 //
00776 //               It is not valid to call begin_occlusion_query()
00777 //               between another begin_occlusion_query()
00778 //               .. end_occlusion_query() sequence.
00779 ////////////////////////////////////////////////////////////////////
00780 void DXGraphicsStateGuardian9::
00781 begin_occlusion_query() {
00782   nassertv(_supports_occlusion_query);
00783   nassertv(_current_occlusion_query == (OcclusionQueryContext *)NULL);
00784 
00785   IDirect3DQuery9 *query;
00786   HRESULT hr = _d3d_device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query);
00787   if (FAILED(hr)) {
00788     dxgsg9_cat.warning()
00789       << "Occlusion query failed.\n";
00790     return;
00791   }
00792   
00793   PT(DXOcclusionQueryContext9) queryobj = new DXOcclusionQueryContext9(query);
00794 
00795   if (dxgsg9_cat.is_debug()) {
00796     dxgsg9_cat.debug()
00797       << "beginning occlusion query " << query << "\n";
00798   }
00799 
00800   query->Issue(D3DISSUE_BEGIN);
00801   _current_occlusion_query = queryobj;
00802 }
00803 
00804 ////////////////////////////////////////////////////////////////////
00805 //     Function: DXGraphicsStateGuardian9::end_occlusion_query
00806 //       Access: Public, Virtual
00807 //  Description: Ends a previous call to begin_occlusion_query().
00808 //               This call returns the OcclusionQueryContext object
00809 //               that will (eventually) report the number of pixels
00810 //               that passed the depth test between the call to
00811 //               begin_occlusion_query() and end_occlusion_query().
00812 ////////////////////////////////////////////////////////////////////
00813 PT(OcclusionQueryContext) DXGraphicsStateGuardian9::
00814 end_occlusion_query() {
00815   if (_current_occlusion_query == (OcclusionQueryContext *)NULL) {
00816     return NULL;
00817   }
00818 
00819   PT(OcclusionQueryContext) result = _current_occlusion_query;
00820 
00821   IDirect3DQuery9 *query = DCAST(DXOcclusionQueryContext9, result)->_query;
00822     
00823   if (dxgsg9_cat.is_debug()) {
00824     dxgsg9_cat.debug()
00825       << "ending occlusion query " << query << "\n";
00826   }
00827 
00828   _current_occlusion_query = NULL;
00829   query->Issue(D3DISSUE_END);
00830 
00831   return result;
00832 }
00833 
00834 ////////////////////////////////////////////////////////////////////
00835 //     Function: DXGraphicsStateGuardian9::make_geom_munger
00836 //       Access: Public, Virtual
00837 //  Description: Creates a new GeomMunger object to munge vertices
00838 //               appropriate to this GSG for the indicated state.
00839 ////////////////////////////////////////////////////////////////////
00840 PT(GeomMunger) DXGraphicsStateGuardian9::
00841 make_geom_munger(const RenderState *state, Thread *current_thread) {
00842   PT(DXGeomMunger9) munger = new DXGeomMunger9(this, state);
00843   return GeomMunger::register_munger(munger, current_thread);
00844 }
00845 
00846 ////////////////////////////////////////////////////////////////////
00847 //     Function: DXGraphicsStateGuardian9::clear
00848 //       Access: Public, Virtual
00849 //  Description: Clears all of the indicated buffers to their assigned
00850 //               colors.
00851 ////////////////////////////////////////////////////////////////////
00852 void DXGraphicsStateGuardian9::
00853 clear(DrawableRegion *clearable) {
00854 
00855   DWORD main_flags = 0;
00856   DWORD aux_flags = 0;
00857 
00858   D3DCOLOR color_clear_value = Colorf_to_D3DCOLOR(clearable->get_clear_color());
00859   float depth_clear_value = clearable->get_clear_depth();
00860   DWORD stencil_clear_value = (DWORD)(clearable->get_clear_stencil());
00861 
00862   //set appropriate flags
00863   if (clearable->get_clear_color_active()) {
00864     main_flags |=  D3DCLEAR_TARGET;
00865   }
00866 
00867   if (clearable->get_clear_depth_active()) {
00868     aux_flags |=  D3DCLEAR_ZBUFFER;
00869     nassertv(_screen->_presentation_params.EnableAutoDepthStencil);
00870   }
00871 
00872   if (clearable->get_clear_stencil_active()) {
00873     // clear only if there is a stencil buffer
00874     if (_screen->_presentation_params.EnableAutoDepthStencil &&
00875       IS_STENCIL_FORMAT(_screen->_presentation_params.AutoDepthStencilFormat)) {
00876       aux_flags |=  D3DCLEAR_STENCIL;
00877     }
00878   }
00879 
00880   if ((main_flags | aux_flags) != 0) {
00881     HRESULT hr = _d3d_device->Clear(0, NULL, main_flags | aux_flags, color_clear_value,
00882                                     depth_clear_value, stencil_clear_value);
00883     if (FAILED(hr) && main_flags == D3DCLEAR_TARGET && aux_flags != 0) {
00884       // Maybe there's a problem with the one or more of the auxiliary
00885       // buffers.
00886       hr = _d3d_device->Clear(0, NULL, D3DCLEAR_TARGET, color_clear_value,
00887                               depth_clear_value, stencil_clear_value);
00888       if (!FAILED(hr)) {
00889         // Yep, it worked without them.  That's a problem.  Which buffer
00890         // poses the problem?
00891         if (clearable->get_clear_depth_active()) {
00892           aux_flags |=  D3DCLEAR_ZBUFFER;
00893           HRESULT hr2 = _d3d_device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color_clear_value,
00894                                            depth_clear_value, stencil_clear_value);
00895           if (FAILED(hr2)) {          
00896             dxgsg9_cat.error()
00897               << "Unable to clear depth buffer; removing.\n";
00898             // This is really hacky code.
00899             ((FrameBufferProperties *)_current_properties)->set_depth_bits(0);
00900           }
00901         }
00902         if (clearable->get_clear_stencil_active()) {
00903           aux_flags |=  D3DCLEAR_STENCIL;
00904           HRESULT hr2 = _d3d_device->Clear(0, NULL, D3DCLEAR_STENCIL, color_clear_value,
00905                                            stencil_clear_value, stencil_clear_value);
00906           if (FAILED(hr2)) {
00907             dxgsg9_cat.error()
00908               << "Unable to clear stencil buffer; removing.\n";
00909             // This is really hacky code.
00910             ((FrameBufferProperties *)_current_properties)->set_stencil_bits(0);
00911             _supports_stencil = false;
00912           }
00913         }
00914       }
00915     }
00916 
00917     if (FAILED(hr)) {
00918       dxgsg9_cat.error()
00919         << "clear_buffer failed:  Clear returned " << D3DERRORSTRING(hr);
00920     }
00921   }
00922 }
00923 
00924 ////////////////////////////////////////////////////////////////////
00925 //     Function: DXGraphicsStateGuardian9::prepare_display_region
00926 //       Access: Public, Virtual
00927 //  Description: Prepare a display region for rendering (set up
00928 //       scissor region and viewport)
00929 ////////////////////////////////////////////////////////////////////
00930 void DXGraphicsStateGuardian9::
00931 prepare_display_region(DisplayRegionPipelineReader *dr,
00932                        Lens::StereoChannel stereo_channel) {
00933   nassertv(dr != (DisplayRegionPipelineReader *)NULL);
00934   GraphicsStateGuardian::prepare_display_region(dr, stereo_channel);
00935 
00936   int l, u, w, h;
00937   dr->get_region_pixels_i(l, u, w, h);
00938 
00939   // Create the viewport
00940   D3DVIEWPORT9 vp = { l, u, w, h, 0.0f, 1.0f };
00941   _current_viewport = vp;
00942   HRESULT hr = _d3d_device->SetViewport(&_current_viewport);
00943   if (FAILED(hr)) {
00944     dxgsg9_cat.error()
00945       << "_screen->_swap_chain = " << _screen->_swap_chain << " _swap_chain = " << _swap_chain << "\n";
00946     dxgsg9_cat.error()
00947       << "SetViewport(" << l << ", " << u << ", " << w << ", " << h
00948       << ") failed" << D3DERRORSTRING(hr);
00949 
00950     D3DVIEWPORT9 vp_old;
00951     _d3d_device->GetViewport(&vp_old);
00952     dxgsg9_cat.error()
00953       << "GetViewport(" << vp_old.X << ", " << vp_old.Y << ", " << vp_old.Width << ", "
00954       << vp_old.Height << ") returned: Trying to set that vp---->\n";
00955     hr = _d3d_device->SetViewport(&vp_old);
00956     set_render_state(D3DRS_SCISSORTESTENABLE, FALSE);
00957 
00958     if (FAILED(hr)) {
00959       dxgsg9_cat.error() << "Failed again\n";
00960       throw_event("panda3d-render-error");
00961       nassertv(false);
00962     }
00963   }
00964 
00965   if (_screen->_can_direct_disable_color_writes) {
00966     set_render_state(D3DRS_COLORWRITEENABLE, _color_write_mask);
00967   }
00968 }
00969 
00970 ////////////////////////////////////////////////////////////////////
00971 //     Function: DXGraphicsStateGuardian9::calc_projection_mat
00972 //       Access: Public, Virtual
00973 //  Description: Given a lens, calculates the appropriate projection
00974 //               matrix for use with this gsg.  Note that the
00975 //               projection matrix depends a lot upon the coordinate
00976 //               system of the rendering API.
00977 //
00978 //               The return value is a TransformState if the lens is
00979 //               acceptable, NULL if it is not.
00980 ////////////////////////////////////////////////////////////////////
00981 CPT(TransformState) DXGraphicsStateGuardian9::
00982 calc_projection_mat(const Lens *lens) {
00983   if (lens == (Lens *)NULL) {
00984     return NULL;
00985   }
00986 
00987   if (!lens->is_linear()) {
00988     return NULL;
00989   }
00990 
00991   // DirectX also uses a Z range of 0 to 1, whereas the Panda
00992   // convention is for the projection matrix to produce a Z range of
00993   // -1 to 1.  We have to rescale to compensate.
00994   static const LMatrix4f rescale_mat
00995     (1, 0, 0, 0,
00996      0, 1, 0, 0,
00997      0, 0, 0.5, 0,
00998      0, 0, 0.5, 1);
00999 
01000   LMatrix4f result =
01001     LMatrix4f::convert_mat(CS_yup_left, _current_lens->get_coordinate_system()) *
01002     lens->get_projection_mat(_current_stereo_channel) *
01003     rescale_mat;
01004 
01005   if (_scene_setup->get_inverted()) {
01006     // If the scene is supposed to be inverted, then invert the
01007     // projection matrix.
01008     result *= LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f);
01009   }
01010 
01011   return TransformState::make_mat(result);
01012 }
01013 
01014 ////////////////////////////////////////////////////////////////////
01015 //     Function: DXGraphicsStateGuardian9::prepare_lens
01016 //       Access: Public, Virtual
01017 //  Description: Makes the current lens (whichever lens was most
01018 //               recently specified with set_scene()) active, so
01019 //               that it will transform future rendered geometry.
01020 //               Normally this is only called from the draw process,
01021 //               and usually it is called by set_scene().
01022 //
01023 //               The return value is true if the lens is acceptable,
01024 //               false if it is not.
01025 ////////////////////////////////////////////////////////////////////
01026 bool DXGraphicsStateGuardian9::
01027 prepare_lens() {
01028   HRESULT hr =
01029     _d3d_device->SetTransform(D3DTS_PROJECTION,
01030                               (D3DMATRIX*)_projection_mat->get_mat().get_data());
01031   return SUCCEEDED(hr);
01032 }
01033 
01034 ////////////////////////////////////////////////////////////////////
01035 //     Function: DXGraphicsStateGuardian9::begin_frame
01036 //       Access: Public, Virtual
01037 //  Description: Called before each frame is rendered, to allow the
01038 //               GSG a chance to do any internal cleanup before
01039 //               beginning the frame.
01040 //
01041 //               The return value is true if successful (in which case
01042 //               the frame will be drawn and end_frame() will be
01043 //               called later), or false if unsuccessful (in which
01044 //               case nothing will be drawn and end_frame() will not
01045 //               be called).
01046 ////////////////////////////////////////////////////////////////////
01047 bool DXGraphicsStateGuardian9::
01048 begin_frame(Thread *current_thread) {
01049 
01050   GraphicsStateGuardian::begin_frame(current_thread);
01051 
01052   if (_d3d_device == NULL) {
01053     dxgsg9_cat.debug()
01054       << this << "::begin_frame(): no device.\n";
01055     return false;
01056   }
01057 
01058   HRESULT hr = _d3d_device->BeginScene();
01059 
01060   if (FAILED(hr)) {
01061     if (hr == D3DERR_DEVICELOST) {
01062       if (dxgsg9_cat.is_debug()) {
01063         dxgsg9_cat.debug()
01064           << "BeginScene returns D3DERR_DEVICELOST" << endl;
01065       }
01066 
01067       check_cooperative_level();
01068 
01069     } else {
01070       dxgsg9_cat.error()
01071         << "BeginScene failed, unhandled error hr == "
01072         << D3DERRORSTRING(hr) << endl;
01073       throw_event("panda3d-render-error");
01074     }
01075     return false;
01076   }
01077 
01078   return true;
01079 }
01080 
01081 ////////////////////////////////////////////////////////////////////
01082 //     Function: DXGraphicsStateGuardian9::begin_scene
01083 //       Access: Public, Virtual
01084 //  Description: Called between begin_frame() and end_frame() to mark
01085 //               the beginning of drawing commands for a "scene"
01086 //               (usually a particular DisplayRegion) within a frame.
01087 //               All 3-D drawing commands, except the clear operation,
01088 //               must be enclosed within begin_scene() .. end_scene().
01089 //
01090 //               The return value is true if successful (in which case
01091 //               the scene will be drawn and end_scene() will be
01092 //               called later), or false if unsuccessful (in which
01093 //               case nothing will be drawn and end_scene() will not
01094 //               be called).
01095 ////////////////////////////////////////////////////////////////////
01096 bool DXGraphicsStateGuardian9::
01097 begin_scene() {
01098   if (!GraphicsStateGuardian::begin_scene()) {
01099     return false;
01100   }
01101 
01102 /*
01103   HRESULT hr = _d3d_device->BeginScene();
01104 
01105   if (FAILED(hr)) {
01106     if (hr == D3DERR_DEVICELOST) {
01107       if (dxgsg9_cat.is_debug()) {
01108         dxgsg9_cat.debug()
01109           << "BeginScene returns D3DERR_DEVICELOST" << endl;
01110       }
01111 
01112       check_cooperative_level();
01113 
01114     } else {
01115       dxgsg9_cat.error()
01116         << "BeginScene failed, unhandled error hr == "
01117         << D3DERRORSTRING(hr) << endl;
01118       throw_event("panda3d-render-error");
01119     }
01120     return false;
01121   }
01122 */
01123 
01124   return true;
01125 }
01126 
01127 ////////////////////////////////////////////////////////////////////
01128 //     Function: DXGraphicsStateGuardian9::end_scene
01129 //       Access: Public, Virtual
01130 //  Description: Called between begin_frame() and end_frame() to mark
01131 //               the end of drawing commands for a "scene" (usually a
01132 //               particular DisplayRegion) within a frame.  All 3-D
01133 //               drawing commands, except the clear operation, must be
01134 //               enclosed within begin_scene() .. end_scene().
01135 ////////////////////////////////////////////////////////////////////
01136 void DXGraphicsStateGuardian9::
01137 end_scene() {
01138   GraphicsStateGuardian::end_scene();
01139 
01140   if (_vertex_array_shader_context != 0) {
01141     _vertex_array_shader_context->disable_shader_vertex_arrays(this);
01142     _vertex_array_shader = (Shader *)NULL;
01143     _vertex_array_shader_context = (CLP(ShaderContext) *)NULL;
01144   }
01145   if (_texture_binding_shader_context != 0) {
01146     _texture_binding_shader_context->disable_shader_texture_bindings(this);
01147     _texture_binding_shader = (Shader *)NULL;
01148     _texture_binding_shader_context = (CLP(ShaderContext) *)NULL;
01149   }
01150   if (_current_shader_context != 0) {
01151     _current_shader_context->unbind(this);
01152     _current_shader = (Shader *)NULL;
01153     _current_shader_context = (CLP(ShaderContext) *)NULL;
01154   }
01155 
01156   _dlights.clear();
01157 
01158 /*
01159   HRESULT hr = _d3d_device->EndScene();
01160 
01161   if (FAILED(hr)) {
01162     if (hr == D3DERR_DEVICELOST) {
01163       if (dxgsg9_cat.is_debug()) {
01164         dxgsg9_cat.debug()
01165           << "EndScene returns DeviceLost\n";
01166       }
01167       check_cooperative_level();
01168 
01169     } else {
01170       dxgsg9_cat.error()
01171         << "EndScene failed, unhandled error hr == " << D3DERRORSTRING(hr);
01172       throw_event("panda3d-render-error");
01173     }
01174     return;
01175   }
01176 */
01177 
01178 }
01179 
01180 ////////////////////////////////////////////////////////////////////
01181 //     Function: GraphicsStateGuardian::end_frame
01182 //       Access: Public, Virtual
01183 //  Description: Called after each frame is rendered, to allow the
01184 //               GSG a chance to do any internal cleanup after
01185 //               rendering the frame, and before the window flips.
01186 ////////////////////////////////////////////////////////////////////
01187 void DXGraphicsStateGuardian9::
01188 end_frame(Thread *current_thread) {
01189 
01190   HRESULT hr = _d3d_device->EndScene();
01191 
01192   if (FAILED(hr)) {
01193     if (hr == D3DERR_DEVICELOST) {
01194       if (dxgsg9_cat.is_debug()) {
01195         dxgsg9_cat.debug()
01196           << "EndScene returns DeviceLost\n";
01197       }
01198       check_cooperative_level();
01199 
01200     } else {
01201       dxgsg9_cat.error()
01202         << "EndScene failed, unhandled error hr == " << D3DERRORSTRING(hr);
01203       throw_event("panda3d-render-error");
01204     }
01205     return;
01206   }
01207 
01208 #if defined(DO_PSTATS)
01209   if (_texmgrmem_total_pcollector.is_active()) {
01210 #define TICKS_PER_GETTEXINFO (2.5*1000)   // 2.5 second interval
01211     static DWORD last_tick_count = 0;
01212     DWORD cur_tick_count = GetTickCount();
01213 
01214     if (cur_tick_count - last_tick_count > TICKS_PER_GETTEXINFO) {
01215       last_tick_count = cur_tick_count;
01216       report_texmgr_stats();
01217     }
01218   }
01219 #endif
01220 
01221   // Note: regular GraphicsWindow::end_frame is being called,
01222   // but we override gsg::end_frame, so need to explicitly call it here
01223   // (currently it's an empty fn)
01224   GraphicsStateGuardian::end_frame(current_thread);
01225 }
01226 
01227 ////////////////////////////////////////////////////////////////////
01228 //     Function: DXGraphicsStateGuardian9::begin_draw_primitives
01229 //       Access: Public, Virtual
01230 //  Description: Called before a sequence of draw_primitive()
01231 //               functions are called, this should prepare the vertex
01232 //               data for rendering.  It returns true if the vertices
01233 //               are ok, false to abort this group of primitives.
01234 ////////////////////////////////////////////////////////////////////
01235 bool DXGraphicsStateGuardian9::
01236 begin_draw_primitives(const GeomPipelineReader *geom_reader,
01237                       const GeomMunger *munger,
01238                       const GeomVertexDataPipelineReader *data_reader,
01239                       bool force) {
01240   if (!GraphicsStateGuardian::begin_draw_primitives(geom_reader, munger,
01241                                                     data_reader, force)) {
01242     return false;
01243   }
01244   nassertr(_data_reader != (GeomVertexDataPipelineReader *)NULL, false);
01245 
01246   string name;
01247   const Geom *geom;
01248   
01249   name = "";
01250   geom = geom_reader -> get_object ( );
01251   if (geom)
01252   {
01253     CPT(GeomVertexData) geom_vertex_data;
01254     geom_vertex_data = geom -> get_vertex_data();
01255     
01256     name = geom_vertex_data -> get_name();
01257     
01258 //    cout << name << "\n";
01259   }
01260 
01261 
01262 // SHADER
01263   if (_vertex_array_shader_context==0) {
01264     if (_current_shader_context==0) {
01265 //      ?????       update_standard_vertex_arrays();
01266     } else {
01267 //      ?????       disable_standard_vertex_arrays();
01268       _current_shader_context->update_shader_vertex_arrays(NULL,this);
01269     }
01270   } else {
01271     if (_current_shader_context==0) {
01272       _vertex_array_shader_context->disable_shader_vertex_arrays(this);
01273 //      ?????       update_standard_vertex_arrays();
01274     } else {
01275       _current_shader_context->
01276         update_shader_vertex_arrays(_vertex_array_shader_context,this);
01277     }
01278   }
01279   _vertex_array_shader = _current_shader;
01280   _vertex_array_shader_context = _current_shader_context;
01281 
01282   const GeomVertexFormat *format = _data_reader->get_format ( );
01283   const GeomVertexArrayDataHandle *data = NULL;
01284   int number_of_arrays = _data_reader -> get_num_arrays ( );
01285 
01286   if (_current_shader_context && number_of_arrays > 1) {
01287 
01288     // find a matching vertex format for the vertex shader's input if possible
01289     VertexElementArray *vertex_element_array;
01290 
01291     vertex_element_array = _current_shader_context -> _vertex_element_array;
01292     if (vertex_element_array)
01293     {
01294       bool match;
01295       bool multiple_matches;
01296       int index;
01297       int first_index;
01298 
01299       match = false;
01300       multiple_matches = false;
01301       first_index = -1;
01302 
01303       // quick check for a match
01304       // find the one array with the minimum number of elements if possible
01305       {
01306         for (index = 0; index < number_of_arrays; index++) {
01307           data = _data_reader -> get_array_reader (index);
01308 
01309           const GeomVertexArrayFormat *array_format = data->get_array_format();
01310           int number_of_columns = array_format->get_num_columns();
01311 
01312           if (number_of_columns >= vertex_element_array -> total_elements) {
01313             if (first_index >= 0) {
01314               multiple_matches = true;
01315             }
01316             else {
01317               first_index = index;
01318             }
01319           }
01320         }
01321       }
01322 
01323       if (multiple_matches)
01324       {
01325         // ugh slow, need to find which one
01326         for (index = first_index; index < number_of_arrays; index++)
01327         {
01328           data = _data_reader -> get_array_reader (index);
01329 
01330           const GeomVertexArrayFormat *array_format = data->get_array_format();
01331           int number_of_columns = array_format->get_num_columns();
01332 
01333           if (number_of_columns >= vertex_element_array -> total_elements)
01334           {
01335 
01336             // check not implemented yet
01337             dxgsg9_cat.error ( ) << "vertex_element_type_array check not implemented yet\n";
01338             
01339             // build a vertex_element_type_array from data
01340             
01341             // compare both vertex_element_type_array for a match
01342             vertex_element_array -> vertex_element_type_array;
01343           }
01344         }
01345 
01346         // since the check is not implemented yet use first_index for now
01347         data = _data_reader -> get_array_reader (first_index);
01348 
01349         match = true;
01350       }
01351       else
01352       {
01353         if (first_index >= 0) {
01354           data = _data_reader -> get_array_reader (first_index);
01355           match = true;
01356         }
01357       }
01358 
01359       if (match) {
01360 
01361       }
01362       else {
01363         // ERROR
01364         dxgsg9_cat.error ( ) << "could not find matching vertex element data for vertex shader\n";
01365 
01366         // just use the 0 array
01367         data = _data_reader->get_array_reader(0);
01368       }
01369     }
01370     else {
01371       // ERROR
01372       dxgsg9_cat.error ( ) << "_current_shader_context -> _vertex_element_array == 0\n";
01373     }
01374   }
01375   else {
01376     // The munger should have put the FVF data in the first array.
01377     data = _data_reader->get_array_reader(0);
01378   }
01379 
01380   nassertr(data != (GeomVertexArrayDataHandle *)NULL, false);
01381   GeomVertexArrayData *data_obj = (GeomVertexArrayData *)data->get_object();
01382   nassertr(data_obj != (GeomVertexArrayData *)NULL, false);
01383   VertexBufferContext *vbc = data_obj->prepare_now(get_prepared_objects(), this);
01384   nassertr(vbc != (VertexBufferContext *)NULL, false);
01385   if (!apply_vertex_buffer(vbc, _current_shader_context, data, force, name)) {
01386     return false;
01387   }
01388 
01389   const GeomVertexAnimationSpec &animation =
01390     data_reader->get_format()->get_animation();
01391   if (animation.get_animation_type() == Geom::AT_hardware) {
01392     // Set up vertex blending.
01393     switch (animation.get_num_transforms()) {
01394     case 1:
01395       // The MSDN docs suggest we should use D3DVBF_0WEIGHTS here, but
01396       // that doesn't seem to work at all.  On the other hand,
01397       // D3DVBF_DISABLE *does* work, because it disables special
01398       // handling, meaning only the world matrix affects these
01399       // vertices--and by accident or design, the first matrix,
01400       // D3DTS_WORLDMATRIX(0), *is* the world matrix.
01401       set_render_state(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
01402       break;
01403     case 2:
01404       set_render_state(D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS);
01405       break;
01406     case 3:
01407       set_render_state(D3DRS_VERTEXBLEND, D3DVBF_2WEIGHTS);
01408       break;
01409     case 4:
01410       set_render_state(D3DRS_VERTEXBLEND, D3DVBF_3WEIGHTS);
01411       break;
01412     }
01413 
01414     if (animation.get_indexed_transforms()) {
01415       // Set up indexed vertex blending.
01416       set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE);
01417     } else {
01418       set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
01419     }
01420 
01421     const TransformTable *table = data_reader->get_transform_table();
01422     if (table != (TransformTable *)NULL) {
01423       for (int i = 0; i < table->get_num_transforms(); i++) {
01424         LMatrix4f mat;
01425         table->get_transform(i)->mult_matrix(mat, _internal_transform->get_mat());
01426         const D3DMATRIX *d3d_mat = (const D3DMATRIX *)mat.get_data();
01427         _d3d_device->SetTransform(D3DTS_WORLDMATRIX(i), d3d_mat);
01428       }
01429 
01430       // Setting the first animation matrix steps on the world matrix,
01431       // so we have to set a flag to reload the world matrix later.
01432       _transform_stale = true;
01433     }
01434     _vertex_blending_enabled = true;
01435 
01436   } else {
01437     // We're not using vertex blending.
01438     if (_vertex_blending_enabled) {
01439       set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
01440       set_render_state(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
01441       _vertex_blending_enabled = false;
01442     }
01443 
01444     if (_transform_stale && !_data_reader->is_vertex_transformed()) {
01445       const D3DMATRIX *d3d_mat = (const D3DMATRIX *)_internal_transform->get_mat().get_data();
01446       _d3d_device->SetTransform(D3DTS_WORLD, d3d_mat);
01447       _transform_stale = false;
01448     }
01449   }
01450 
01451   if (_data_reader->is_vertex_transformed()) {
01452     // If the vertex data claims to be already transformed into clip
01453     // coordinates, wipe out the current projection and modelview
01454     // matrix (so we don't attempt to transform it again).
01455 
01456     // It's tempting just to use the D3DFVF_XYZRHW specification on
01457     // these vertices, but that turns out to be a bigger hammer than
01458     // we want: that also prevents lighting calculations and user clip
01459     // planes.
01460     _d3d_device->SetTransform(D3DTS_WORLD, &_d3d_ident_mat);
01461     static const LMatrix4f rescale_mat
01462       (1, 0, 0, 0,
01463        0, 1, 0, 0,
01464        0, 0, 0.5, 0,
01465        0, 0, 0.5, 1);
01466     _transform_stale = true;
01467 
01468     _d3d_device->SetTransform(D3DTS_PROJECTION, (const D3DMATRIX *)rescale_mat.get_data());
01469   }
01470 
01471   return true;
01472 }
01473 
01474 ////////////////////////////////////////////////////////////////////
01475 //     Function: DXGraphicsStateGuardian9::draw_triangles
01476 //       Access: Public, Virtual
01477 //  Description: Draws a series of disconnected triangles.
01478 ////////////////////////////////////////////////////////////////////
01479 bool DXGraphicsStateGuardian9::
01480 draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
01481   //PStatTimer timer(_draw_primitive_pcollector);
01482 
01483   _vertices_tri_pcollector.add_level(reader->get_num_vertices());
01484   _primitive_batches_tri_pcollector.add_level(1);
01485   if (reader->is_indexed()) {
01486     int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
01487     int max_vertex = reader->get_max_vertex();
01488 
01489     if (_active_vbuffer != NULL) {
01490       // Indexed, vbuffers.
01491       IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
01492       nassertr(ibc != (IndexBufferContext *)NULL, false);
01493       if (!apply_index_buffer(ibc, reader, force)) {
01494         return false;
01495       }
01496 
01497       _d3d_device->DrawIndexedPrimitive
01498         (D3DPT_TRIANGLELIST, 0,
01499          min_vertex, max_vertex - min_vertex + 1,
01500          0, reader->get_num_primitives());
01501 
01502     } else {
01503       // Indexed, client arrays.
01504 
01505       const unsigned char *index_pointer = reader->get_read_pointer(force);
01506       if (index_pointer == NULL) {
01507         return false;
01508       }
01509       D3DFORMAT index_type = get_index_type(reader->get_index_type());
01510       const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
01511       if (vertex_pointer == NULL) {
01512         return false;
01513       }
01514 
01515       draw_indexed_primitive_up
01516         (D3DPT_TRIANGLELIST,
01517          min_vertex, max_vertex,
01518          reader->get_num_primitives(),
01519          index_pointer, index_type, vertex_pointer,
01520          _data_reader->get_format()->get_array(0)->get_stride());
01521     }
01522   } else {
01523     if (_active_vbuffer != NULL) {
01524       // Nonindexed, vbuffers.
01525 
01526       _d3d_device->DrawPrimitive
01527         (D3DPT_TRIANGLELIST,
01528          reader->get_first_vertex(),
01529          reader->get_num_primitives());
01530 
01531     } else {
01532       // Nonindexed, client arrays.
01533 
01534       const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
01535       if (vertex_pointer == NULL) {
01536         return false;
01537       }
01538 
01539       draw_primitive_up(D3DPT_TRIANGLELIST, reader->get_num_primitives(),
01540       reader->get_first_vertex(),
01541       reader->get_num_vertices(), vertex_pointer,
01542       _data_reader->get_format()->get_array(0)->get_stride());
01543     }
01544   }
01545 
01546   return true;
01547 }
01548 
01549 ////////////////////////////////////////////////////////////////////
01550 //     Function: DXGraphicsStateGuardian9::draw_tristrips
01551 //       Access: Public, Virtual
01552 //  Description: Draws a series of triangle strips.
01553 ////////////////////////////////////////////////////////////////////
01554 bool DXGraphicsStateGuardian9::
01555 draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
01556   //PStatTimer timer(_draw_primitive_pcollector);
01557 
01558   if (connect_triangle_strips && _current_fill_mode != RenderModeAttrib::M_wireframe) {
01559     // One long triangle strip, connected by the degenerate vertices
01560     // that have already been set up within the primitive.
01561     _vertices_tristrip_pcollector.add_level(reader->get_num_vertices());
01562     _primitive_batches_tristrip_pcollector.add_level(1);
01563     if (reader->is_indexed()) {
01564       int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
01565       int max_vertex = reader->get_max_vertex();
01566 
01567       if (_active_vbuffer != NULL) {
01568         // Indexed, vbuffers, one line triangle strip.
01569         IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
01570         nassertr(ibc != (IndexBufferContext *)NULL, false);
01571         if (!apply_index_buffer(ibc, reader, force)) {
01572           return false;
01573         }
01574 
01575 //dxgsg9_cat.error ( ) << "DrawIndexedPrimitive D3DPT_TRIANGLESTRIP VERTICES: " << reader->get_num_vertices ( ) << "\n";
01576 
01577         _d3d_device->DrawIndexedPrimitive
01578           (D3DPT_TRIANGLESTRIP, 0,
01579            min_vertex, max_vertex - min_vertex + 1,
01580            0, reader->get_num_vertices() - 2);
01581 
01582       } else {
01583 
01584 //dxgsg9_cat.error ( ) << "draw_indexed_primitive_up D3DPT_TRIANGLESTRIP VERTICES: " << reader->get_num_vertices ( ) << "\n";
01585 
01586         // Indexed, client arrays, one long triangle strip.
01587         const unsigned char *index_pointer = reader->get_read_pointer(force);
01588         if (index_pointer == NULL) {
01589           return false;
01590         }
01591         D3DFORMAT index_type = get_index_type(reader->get_index_type());
01592         const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
01593         if (vertex_pointer == NULL) {
01594           return false;
01595         }
01596 
01597         draw_indexed_primitive_up
01598           (D3DPT_TRIANGLESTRIP,
01599            min_vertex, max_vertex,
01600            reader->get_num_vertices() - 2,
01601            index_pointer, index_type, vertex_pointer,
01602            _data_reader->get_format()->get_array(0)->get_stride());
01603       }
01604     } else {
01605       if (_active_vbuffer != NULL) {
01606         // Nonindexed, vbuffers, one long triangle strip.
01607 
01608 //dxgsg9_cat.error ( ) << "DrawPrimitive D3DPT_TRIANGLESTRIP " << reader->get_first_vertex ( ) << " VERTICES: " << reader->get_num_vertices ( ) << "\n";
01609 
01610         _d3d_device->DrawPrimitive
01611           (D3DPT_TRIANGLESTRIP,
01612            reader->get_first_vertex(),
01613            reader->get_num_vertices() - 2);
01614 
01615       } else {
01616         // Indexed, client arrays, one long triangle strip.
01617         const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
01618         if (vertex_pointer == NULL) {
01619           return false;
01620         }
01621         draw_primitive_up(D3DPT_TRIANGLESTRIP,
01622         reader->get_num_vertices() - 2,
01623         reader->get_first_vertex(),
01624         reader->get_num_vertices(), vertex_pointer,
01625         _data_reader->get_format()->get_array(0)->get_stride());
01626       }
01627     }
01628 
01629   } else {
01630     // Send the individual triangle strips, stepping over the
01631     // degenerate vertices.
01632     CPTA_int ends = reader->get_ends();
01633     _primitive_batches_tristrip_pcollector.add_level(ends.size());
01634 
01635     if (reader->is_indexed()) {
01636       CPTA_int ends = reader->get_ends();
01637       int index_stride = reader->get_index_stride();
01638       _primitive_batches_tristrip_pcollector.add_level(ends.size());
01639 
01640       GeomVertexReader mins(reader->get_mins(), 0);
01641       GeomVertexReader maxs(reader->get_maxs(), 0);
01642       nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
01643                reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
01644 
01645       if (_active_vbuffer != NULL) {
01646         // Indexed, vbuffers, individual triangle strips.
01647         IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
01648         nassertr(ibc != (IndexBufferContext *)NULL, false);
01649         if (!apply_index_buffer(ibc, reader, force)) {
01650           return false;
01651         }
01652 
01653         unsigned int start = 0;
01654         for (size_t i = 0; i < ends.size(); i++) {
01655           _vertices_tristrip_pcollector.add_level(ends[i] - start);
01656           unsigned int min = mins.get_data1i();
01657           unsigned int max = maxs.get_data1i();
01658           _d3d_device->DrawIndexedPrimitive
01659             (D3DPT_TRIANGLESTRIP,
01660              0,
01661              min, max - min + 1,
01662              start, ends[i] - start - 2);
01663 
01664           start = ends[i] + 2;
01665         }
01666 
01667       } else {
01668         // Indexed, client arrays, individual triangle strips.
01669         int stride = _data_reader->get_format()->get_array(0)->get_stride();
01670         const unsigned char *index_pointer = reader->get_read_pointer(force);
01671         if (index_pointer == NULL) {
01672           return false;
01673         }
01674         D3DFORMAT index_type = get_index_type(reader->get_index_type());
01675         const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
01676         if (vertex_pointer == NULL) {
01677           return false;
01678         }
01679 
01680         unsigned int start = 0;
01681         for (size_t i = 0; i < ends.size(); i++) {
01682           _vertices_tristrip_pcollector.add_level(ends[i] - start);
01683           unsigned int min = mins.get_data1i();
01684           unsigned int max = maxs.get_data1i();
01685           draw_indexed_primitive_up
01686             (D3DPT_TRIANGLESTRIP,
01687              min, max,
01688              ends[i] - start - 2,
01689              index_pointer + start * index_stride, index_type,
01690              vertex_pointer, stride);
01691 
01692           start = ends[i] + 2;
01693         }
01694       }
01695     } else {
01696       unsigned int first_vertex = reader->get_first_vertex();
01697 
01698       if (_active_vbuffer != NULL) {
01699         // Nonindexed, vbuffers, individual triangle strips.
01700         unsigned int start = 0;
01701         for (size_t i = 0; i < ends.size(); i++) {
01702           _vertices_tristrip_pcollector.add_level(ends[i] - start);
01703           _d3d_device->DrawPrimitive
01704             (D3DPT_TRIANGLESTRIP,
01705              first_vertex + start, ends[i] - start - 2);
01706 
01707           start = ends[i] + 2;
01708         }
01709 
01710       } else {
01711         // Nonindexed, client arrays, individual triangle strips.
01712         const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
01713         if (vertex_pointer == NULL) {
01714           return false;
01715         }
01716         int stride = _data_reader->get_format()->get_array(0)->get_stride();
01717 
01718         unsigned int start = 0;
01719         for (size_t i = 0; i < ends.size(); i++) {
01720           _vertices_tristrip_pcollector.add_level(ends[i] - start);
01721           draw_primitive_up(D3DPT_TRIANGLESTRIP, ends[i] - start - 2,
01722           first_vertex + start,
01723           ends[i] - start,
01724           vertex_pointer, stride);
01725 
01726           start = ends[i] + 2;
01727         }
01728       }
01729     }
01730   }
01731   return true;
01732 }
01733 
01734 ////////////////////////////////////////////////////////////////////
01735 //     Function: DXGraphicsStateGuardian9::draw_trifans
01736 //       Access: Public, Virtual
01737 //  Description: Draws a series of triangle fans.
01738 ////////////////////////////////////////////////////////////////////
01739 bool DXGraphicsStateGuardian9::
01740 draw_trifans(const GeomPrimitivePipelineReader *reader, bool force) {
01741   //PStatTimer timer(_draw_primitive_pcollector);
01742 
01743   CPTA_int ends = reader->get_ends();
01744   _primitive_batches_trifan_pcollector.add_level(ends.size());
01745 
01746   if (reader->is_indexed()) {
01747     int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
01748     int max_vertex = reader->get_max_vertex();
01749 
01750     // Send the individual triangle fans.  There's no connecting fans
01751     // with degenerate vertices, so no worries about that.
01752     int index_stride = reader->get_index_stride();
01753 
01754     GeomVertexReader mins(reader->get_mins(), 0);
01755     GeomVertexReader maxs(reader->get_maxs(), 0);
01756     nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
01757              reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
01758 
01759     if (_active_vbuffer != NULL) {
01760       // Indexed, vbuffers.
01761       IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
01762       nassertr(ibc != (IndexBufferContext *)NULL, false);
01763       if (!apply_index_buffer(ibc, reader, force)) {
01764         return false;
01765       }
01766 
01767       unsigned int start = 0;
01768       for (size_t i = 0; i < ends.size(); i++) {
01769         _vertices_trifan_pcollector.add_level(ends[i] - start);
01770         unsigned int min = mins.get_data1i();
01771         unsigned int max = maxs.get_data1i();
01772         _d3d_device->DrawIndexedPrimitive
01773           (D3DPT_TRIANGLEFAN, 0,
01774            min, max - min + 1,
01775            start, ends[i] - start - 2);
01776 
01777         start = ends[i];
01778       }
01779 
01780     } else {
01781       // Indexed, client arrays.
01782       int stride = _data_reader->get_format()->get_array(0)->get_stride();
01783       const unsigned char *index_pointer = reader->get_read_pointer(force);
01784       if (index_pointer == NULL) {
01785         return false;
01786       }
01787       D3DFORMAT index_type = get_index_type(reader->get_index_type());
01788       const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
01789       if (vertex_pointer == NULL) {
01790         return false;
01791       }
01792 
01793       unsigned int start = 0;
01794       for (size_t i = 0; i < ends.size(); i++) {
01795         _vertices_trifan_pcollector.add_level(ends[i] - start);
01796         unsigned int min = mins.get_data1i();
01797         unsigned int max = maxs.get_data1i();
01798         draw_indexed_primitive_up
01799           (D3DPT_TRIANGLEFAN,
01800            min, max,
01801            ends[i] - start - 2,
01802            index_pointer + start * index_stride, index_type,
01803            vertex_pointer, stride);
01804 
01805         start = ends[i];
01806       }
01807     }
01808   } else {
01809     unsigned int first_vertex = reader->get_first_vertex();
01810 
01811     if (_active_vbuffer != NULL) {
01812       // Nonindexed, vbuffers.
01813       unsigned int start = 0;
01814       for (size_t i = 0; i < ends.size(); i++) {
01815         _vertices_trifan_pcollector.add_level(ends[i] - start);
01816         _d3d_device->DrawPrimitive
01817           (D3DPT_TRIANGLEFAN,
01818            first_vertex + start, ends[i] - start - 2);
01819 
01820         start = ends[i];
01821       }
01822 
01823     } else {
01824       // Nonindexed, client arrays.
01825       const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
01826       if (vertex_pointer == NULL) {
01827         return false;
01828       }
01829       int stride = _data_reader->get_format()->get_array(0)->get_stride();
01830 
01831       unsigned int start = 0;
01832       for (size_t i = 0; i < ends.size(); i++) {
01833         _vertices_trifan_pcollector.add_level(ends[i] - start);
01834         draw_primitive_up(D3DPT_TRIANGLEFAN,
01835         ends[i] - start - 2,
01836         first_vertex,
01837         ends[i] - start,
01838         vertex_pointer, stride);
01839         start = ends[i];
01840       }
01841     }
01842   }
01843   return true;
01844 }
01845 
01846 ////////////////////////////////////////////////////////////////////
01847 //     Function: DXGraphicsStateGuardian9::draw_lines
01848 //       Access: Public, Virtual
01849 //  Description: Draws a series of disconnected line segments.
01850 ////////////////////////////////////////////////////////////////////
01851 bool DXGraphicsStateGuardian9::
01852 draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
01853   //PStatTimer timer(_draw_primitive_pcollector);
01854   _vertices_other_pcollector.add_level(reader->get_num_vertices());
01855   _primitive_batches_other_pcollector.add_level(1);
01856 
01857   if (reader->is_indexed()) {
01858     int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
01859     int max_vertex = reader->get_max_vertex();
01860 
01861     if (_active_vbuffer != NULL) {
01862       // Indexed, vbuffers.
01863       IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
01864       nassertr(ibc != (IndexBufferContext *)NULL, false);
01865       if (!apply_index_buffer(ibc, reader, force)) {
01866         return false;
01867       }
01868 
01869       _d3d_device->DrawIndexedPrimitive
01870         (D3DPT_LINELIST,
01871      0,
01872          min_vertex, max_vertex - min_vertex + 1,
01873          0, reader->get_num_primitives());
01874 
01875     } else {
01876       // Indexed, client arrays.
01877       const unsigned char *index_pointer = reader->get_read_pointer(force);
01878       if (index_pointer == NULL) {
01879         return false;
01880       }
01881       D3DFORMAT index_type = get_index_type(reader->get_index_type());
01882       const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
01883       if (vertex_pointer == NULL) {
01884         return false;
01885       }
01886 
01887       draw_indexed_primitive_up
01888         (D3DPT_LINELIST,
01889          min_vertex, max_vertex,
01890          reader->get_num_primitives(),
01891          index_pointer, index_type, vertex_pointer,
01892          _data_reader->get_format()->get_array(0)->get_stride());
01893     }
01894   } else {
01895     if (_active_vbuffer != NULL) {
01896       // Nonindexed, vbuffers.
01897       _d3d_device->DrawPrimitive
01898         (D3DPT_LINELIST,
01899          reader->get_first_vertex(),
01900          reader->get_num_primitives());
01901 
01902     } else {
01903       // Nonindexed, client arrays.
01904       const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
01905       if (vertex_pointer == NULL) {
01906         return false;
01907       }
01908       draw_primitive_up(D3DPT_LINELIST, reader->get_num_primitives(),
01909       reader->get_first_vertex(),
01910       reader->get_num_vertices(), vertex_pointer,
01911       _data_reader->get_format()->get_array(0)->get_stride());
01912     }
01913   }
01914   return true;
01915 }
01916 
01917 ////////////////////////////////////////////////////////////////////
01918 //     Function: DXGraphicsStateGuardian9::draw_linestrips
01919 //       Access: Public, Virtual
01920 //  Description: Draws a series of line strips.
01921 ////////////////////////////////////////////////////////////////////
01922 bool DXGraphicsStateGuardian9::
01923 draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force) {
01924   return false;
01925 }
01926 
01927 ////////////////////////////////////////////////////////////////////
01928 //     Function: DXGraphicsStateGuardian9::draw_points
01929 //       Access: Public, Virtual
01930 //  Description: Draws a series of disconnected points.
01931 ////////////////////////////////////////////////////////////////////
01932 bool DXGraphicsStateGuardian9::
01933 draw_points(const GeomPrimitivePipelineReader *reader, bool force) {
01934   //PStatTimer timer(_draw_primitive_pcollector);
01935   _vertices_other_pcollector.add_level(reader->get_num_vertices());
01936   _primitive_batches_other_pcollector.add_level(1);
01937 
01938   // The munger should have protected us from indexed points--DirectX
01939   // doesn't support them.
01940   nassertr(!reader->is_indexed(), false);
01941 
01942   if (_active_vbuffer != NULL) {
01943     // Nonindexed, vbuffers.
01944     _d3d_device->DrawPrimitive
01945       (D3DPT_POINTLIST,
01946        reader->get_first_vertex(),
01947        reader->get_num_primitives());
01948 
01949   } else {
01950     // Nonindexed, client arrays.
01951     const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
01952     if (vertex_pointer == NULL) {
01953       return false;
01954     }
01955     draw_primitive_up(D3DPT_POINTLIST, reader->get_num_primitives(),
01956                       reader->get_first_vertex(),
01957                       reader->get_num_vertices(), vertex_pointer,
01958                       _data_reader->get_format()->get_array(0)->get_stride());
01959   }
01960   return true;
01961 }
01962 
01963 ////////////////////////////////////////////////////////////////////
01964 //     Function: DXGraphicsStateGuardian9::end_draw_primitives()
01965 //       Access: Public, Virtual
01966 //  Description: Called after a sequence of draw_primitive()
01967 //               functions are called, this should do whatever cleanup
01968 //               is appropriate.
01969 ////////////////////////////////////////////////////////////////////
01970 void DXGraphicsStateGuardian9::
01971 end_draw_primitives() {
01972   // Turn off vertex blending--it seems to cause problems if we leave
01973   // it on.
01974   if (_vertex_blending_enabled) {
01975     set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
01976     set_render_state(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
01977     _vertex_blending_enabled = false;
01978   }
01979 
01980   if (_data_reader->is_vertex_transformed()) {
01981     // Restore the projection matrix that we wiped out above.
01982     _d3d_device->SetTransform(D3DTS_PROJECTION,
01983                               (D3DMATRIX*)_projection_mat->get_mat().get_data());
01984   }
01985 
01986   GraphicsStateGuardian::end_draw_primitives();
01987 }
01988 
01989 ////////////////////////////////////////////////////////////////////
01990 //     Function: DXGraphicsStateGuardian9::framebuffer_copy_to_texture
01991 //       Access: Public, Virtual
01992 //  Description: Copy the pixels within the indicated display
01993 //               region from the framebuffer into texture memory.
01994 //
01995 //               If z > -1, it is the cube map index into which to
01996 //               copy.
01997 ////////////////////////////////////////////////////////////////////
01998 bool DXGraphicsStateGuardian9::
01999 framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
02000                             const RenderBuffer &rb) {
02001   set_read_buffer(rb);
02002 
02003   int orig_x = tex->get_x_size();
02004   int orig_y = tex->get_y_size();
02005 
02006   HRESULT hr;
02007   int xo, yo, w, h;
02008   dr->get_region_pixels_i(xo, yo, w, h);
02009   tex->set_size_padded(w, h);
02010 
02011   // must use a render target type texture for StretchRect
02012   tex->set_render_to_texture(true);
02013 
02014   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
02015   if (tc == (TextureContext *)NULL) {
02016     return false;
02017   }
02018   DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
02019   if (!dtc->create_texture(*_screen)) {
02020     // Oops, we can't re-create the texture for some reason.
02021     dxgsg9_cat.error()
02022       << "Unable to re-create texture " << *dtc->get_texture() << endl;
02023     return false;
02024   }
02025 
02026   if (tex->get_texture_type() != Texture::TT_2d_texture) {
02027     // For a specialty texture like a cube map, go the slow route
02028     // through RAM for now.
02029     return do_framebuffer_copy_to_ram(tex, z, dr, rb, true);
02030   }
02031   nassertr(dtc->get_d3d_2d_texture() != NULL, false);
02032 
02033   IDirect3DSurface9 *tex_level_0;
02034   hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
02035   if (FAILED(hr)) {
02036     dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
02037     return false;
02038   }
02039 
02040   // If the texture is the wrong size, we need to do something about it.
02041   D3DSURFACE_DESC texdesc;
02042   hr = tex_level_0->GetDesc(&texdesc);
02043   if (FAILED(hr)) {
02044     dxgsg9_cat.error() << "GetDesc failed in copy_texture" << D3DERRORSTRING(hr);
02045     SAFE_RELEASE(tex_level_0);
02046     return false;
02047   }
02048   if ((texdesc.Width != tex->get_x_size())||(texdesc.Height != tex->get_y_size())) {
02049     if ((orig_x != tex->get_x_size()) || (orig_y != tex->get_y_size())) {
02050       // Texture might be wrong size because we resized it and need to recreate.
02051       SAFE_RELEASE(tex_level_0);
02052       if (!dtc->create_texture(*_screen)) {
02053         // Oops, we can't re-create the texture for some reason.
02054         dxgsg9_cat.error()
02055           << "Unable to re-create texture " << *dtc->get_texture() << endl;
02056         return false;
02057       }
02058       hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
02059       if (FAILED(hr)) {
02060         dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
02061         return false;
02062       }
02063       hr = tex_level_0->GetDesc(&texdesc);
02064       if (FAILED(hr)) {
02065         dxgsg9_cat.error() << "GetDesc 2 failed in copy_texture" << D3DERRORSTRING(hr);
02066         SAFE_RELEASE(tex_level_0);
02067         return false;
02068       }
02069     }
02070     if ((texdesc.Width != tex->get_x_size())||(texdesc.Height != tex->get_y_size())) {
02071       // If it's still the wrong size, it's because driver can't create size
02072       // that we want.  In that case, there's no helping it, we have to give up.
02073       dxgsg9_cat.error()
02074         << "Unable to copy to texture, texture is wrong size: " << *dtc->get_texture() << endl;
02075       SAFE_RELEASE(tex_level_0);
02076       return false;
02077     }
02078   }
02079 
02080   DWORD render_target_index;
02081   IDirect3DSurface9 *render_target;
02082 
02083   /* ***** DX9 GetRenderTarget, assume only one render target so index = 0 */
02084   render_target_index = 0;
02085 
02086   hr = _d3d_device->GetRenderTarget(render_target_index, &render_target);
02087   if (FAILED(hr)) {
02088     dxgsg9_cat.error()
02089       << "GetRenderTarget failed in framebuffer_copy_to_texture"
02090       << D3DERRORSTRING(hr);
02091     SAFE_RELEASE(tex_level_0);
02092     return false;
02093   }
02094 
02095   RECT src_rect;
02096 
02097   src_rect.left = xo;
02098   src_rect.right = xo+w;
02099   src_rect.top = yo;
02100   src_rect.bottom = yo+h;
02101 
02102 //  THE DX8 WAY
02103 //  hr = _d3d_device->CopyRects(render_target, &src_rect, 1, tex_level_0, 0);
02104 
02105 //  DX9
02106   D3DTEXTUREFILTERTYPE filter;
02107 
02108   filter = D3DTEXF_POINT;
02109 
02110   bool okflag = true;
02111   hr = _d3d_device->StretchRect(render_target, &src_rect,
02112                                 tex_level_0, &src_rect,
02113                                 filter);
02114   if (FAILED(hr)) {
02115     dxgsg9_cat.debug()
02116       << "StretchRect failed in framebuffer_copy_to_texture"
02117       << D3DERRORSTRING(hr);
02118     okflag = false;
02119   }
02120 
02121   SAFE_RELEASE(render_target);
02122   SAFE_RELEASE(tex_level_0);
02123 
02124   if (okflag) {
02125     dtc->mark_loaded();
02126     dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
02127 
02128   } else {
02129     // The copy failed.  Fall back to copying it to RAM and back.
02130     // Terribly slow, but what are you going to do?
02131     return do_framebuffer_copy_to_ram(tex, z, dr, rb, true);
02132   }
02133 
02134   return true;
02135 }
02136 
02137 
02138 ////////////////////////////////////////////////////////////////////
02139 //     Function: DXGraphicsStateGuardian9::framebuffer_copy_to_ram
02140 //       Access: Public, Virtual
02141 //  Description: Copy the pixels within the indicated display region
02142 //               from the framebuffer into system memory, not texture
02143 //               memory.  Returns true on success, false on failure.
02144 //
02145 //               This completely redefines the ram image of the
02146 //               indicated texture.
02147 ////////////////////////////////////////////////////////////////////
02148 bool DXGraphicsStateGuardian9::
02149 framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, 
02150                         const RenderBuffer &rb) {
02151   return do_framebuffer_copy_to_ram(tex, z, dr, rb, false);
02152 }
02153 
02154 ////////////////////////////////////////////////////////////////////
02155 //     Function: DXGraphicsStateGuardian9::do_framebuffer_copy_to_ram
02156 //       Access: Public
02157 //  Description: This is the implementation of
02158 //               framebuffer_copy_to_ram(); it adds one additional
02159 //               parameter, which should be true if the framebuffer is
02160 //               to be inverted during the copy (as in the same way it
02161 //               copies to texture memory).
02162 ////////////////////////////////////////////////////////////////////
02163 bool DXGraphicsStateGuardian9::
02164 do_framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, 
02165                            const RenderBuffer &rb, bool inverted) {
02166   set_read_buffer(rb);
02167 
02168   RECT rect;
02169   nassertr(tex != NULL && dr != NULL, false);
02170 
02171   int xo, yo, w, h;
02172   dr->get_region_pixels_i(xo, yo, w, h);
02173 
02174   Texture::Format format = tex->get_format();
02175   Texture::ComponentType component_type = tex->get_component_type();
02176 
02177   switch (format) {
02178   case Texture::F_depth_stencil:
02179     // Sorry, not (yet?) supported in pandadx.
02180     return false;
02181 
02182   default:
02183     format = Texture::F_rgb;
02184     component_type = Texture::T_unsigned_byte;
02185   }
02186 
02187   Texture::TextureType texture_type;
02188   if (z >= 0) {
02189     texture_type = Texture::TT_cube_map;
02190   } else {
02191     texture_type = Texture::TT_2d_texture;
02192   }
02193 
02194   if (tex->get_x_size() != w || tex->get_y_size() != h ||
02195       tex->get_component_type() != component_type ||
02196       tex->get_format() != format ||
02197       tex->get_texture_type() != texture_type) {
02198     // Re-setup the texture; its properties have changed.
02199     tex->setup_texture(texture_type, w, h, tex->get_z_size(),
02200                        component_type, format);
02201   }
02202 
02203   rect.top = yo;
02204   rect.left = xo;
02205   rect.right = xo + w;
02206   rect.bottom = yo + h;
02207   bool copy_inverted = false;
02208 
02209   IDirect3DSurface9 *temp_surface = NULL;
02210   HRESULT hr;
02211 
02212   // Note if you try to grab the backbuffer and full-screen
02213   // anti-aliasing is on, the backbuffer might be larger than the
02214   // window size.  For screenshots it's safer to get the front buffer.
02215   if (_cur_read_pixel_buffer & RenderBuffer::T_back) {
02216     DWORD render_target_index;
02217     IDirect3DSurface9 *backbuffer = NULL;
02218     // GetRenderTarget() seems to be a little more reliable than
02219     // GetBackBuffer().  Might just be related to the swap_chain
02220     // thing.
02221 
02222     render_target_index = 0;
02223     hr = _d3d_device->GetRenderTarget(render_target_index, &backbuffer);
02224 
02225     if (FAILED(hr)) {
02226       dxgsg9_cat.error() << "GetRenderTarget failed" << D3DERRORSTRING(hr);
02227       return false;
02228     }
02229 
02230     // Since we might not be able to Lock the back buffer, we will
02231     // need to copy it to a temporary surface of the appropriate type
02232     // first.
02233     D3DPOOL pool;
02234     D3DSURFACE_DESC surface_description;
02235 
02236     backbuffer -> GetDesc (&surface_description);
02237 
02238     pool = D3DPOOL_SYSTEMMEM;
02239     hr = _d3d_device->CreateOffscreenPlainSurface(
02240                                                   surface_description.Width,
02241                                                   surface_description.Height,
02242                                                   surface_description.Format,
02243                                                   pool,
02244                                                   &temp_surface,
02245                                                   NULL);
02246     if (FAILED(hr)) {
02247       dxgsg9_cat.error()
02248         << "CreateImageSurface failed in copy_pixel_buffer()"
02249         << D3DERRORSTRING(hr);
02250       backbuffer->Release();
02251       return false;
02252     }
02253 
02254     // Now we must copy from the backbuffer to our temporary surface.
02255     hr = _d3d_device -> GetRenderTargetData (backbuffer, temp_surface);
02256     if (FAILED(hr)) {
02257       dxgsg9_cat.error() << "GetRenderTargetData failed" << D3DERRORSTRING(hr);
02258       temp_surface->Release();
02259       backbuffer->Release();
02260       return false;
02261     }
02262 
02263     copy_inverted = true;
02264 
02265     RELEASE(backbuffer, dxgsg9, "backbuffer", RELEASE_ONCE);
02266 
02267   } else if (_cur_read_pixel_buffer & RenderBuffer::T_front) {
02268 
02269     if (_screen->_presentation_params.Windowed) {
02270       // GetFrontBuffer() retrieves the entire desktop for a monitor,
02271       // so we need to reserve space for that.
02272 
02273       // We have to use GetMonitorInfo(), since this GSG may not be
02274       // for the primary monitor.
02275       MONITORINFO minfo;
02276       minfo.cbSize = sizeof(MONITORINFO);
02277       GetMonitorInfo(_screen->_monitor, &minfo);
02278 
02279       w = RECT_XSIZE(minfo.rcMonitor);
02280       h = RECT_YSIZE(minfo.rcMonitor);
02281 
02282       // set rect to client area of window in scrn coords
02283       ClientToScreen(_screen->_window, (POINT*)&rect.left);
02284       ClientToScreen(_screen->_window, (POINT*)&rect.right);
02285     }
02286 
02287     // For GetFrontBuffer(), we need a temporary surface of type
02288     // A8R8G8B8.  Unlike GetBackBuffer(), GetFrontBuffer() implicitly
02289     // performs a copy.
02290     hr = _d3d_device->CreateOffscreenPlainSurface(w, h, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &temp_surface, NULL);
02291     if (FAILED(hr)) {
02292       dxgsg9_cat.error()
02293         << "CreateImageSurface failed in copy_pixel_buffer()"
02294         << D3DERRORSTRING(hr);
02295       return false;
02296     }
02297 
02298     UINT swap_chain;
02299 
02300     swap_chain = 0;
02301     hr = _d3d_device->GetFrontBufferData(swap_chain,temp_surface);
02302 
02303     if (hr == D3DERR_DEVICELOST) {
02304       dxgsg9_cat.error()
02305         << "copy_pixel_buffer failed: device lost\n";
02306       temp_surface->Release();
02307       return false;
02308     }
02309 
02310     copy_inverted = true;
02311 
02312   } else {
02313     dxgsg9_cat.error()
02314       << "copy_pixel_buffer: unhandled current_read_pixel_buffer type\n";
02315     temp_surface->Release();
02316     return false;
02317   }
02318 
02319   if (inverted) {
02320     copy_inverted = !copy_inverted;
02321   }
02322   DXTextureContext9::d3d_surface_to_texture(rect, temp_surface,
02323                                             copy_inverted, tex, z);
02324 
02325   RELEASE(temp_surface, dxgsg9, "temp_surface", RELEASE_ONCE);
02326 
02327   nassertr(tex->has_ram_image(), false);
02328   return true;
02329 }
02330 
02331 void DXGraphicsStateGuardian9::reset_render_states (void)
02332 {
02333   int index;
02334   int maximum_texture_stages;
02335 
02336   maximum_texture_stages = D3D_MAXTEXTURESTAGES;
02337 
02338   // set to invalid values so that the state will always be set the first time
02339   memset (_render_state_array, -1, sizeof (_render_state_array));
02340   memset (_texture_stage_states_array, -1, sizeof (_texture_stage_states_array));
02341 
02342   // states that may be set intially to -1 by the user, so set it to D3D's default value
02343   _render_state_array [D3DRS_FOGCOLOR] = 0;
02344   _render_state_array [D3DRS_AMBIENT] = 0;
02345 
02346   // set to D3D default values or invalid values so that the state will always be set the first time
02347   memset (_texture_render_states_array, 0, sizeof (_texture_render_states_array));
02348 
02349   // states that may be set intially to 0 by the user, so set it to D3D's default value
02350   for (index = 0; index < MAXIMUM_TEXTURES; index++) {
02351     TextureRenderStates *texture_render_states;
02352 
02353     texture_render_states = &_texture_render_states_array [index];
02354     texture_render_states -> state_array [D3DSAMP_MAGFILTER] = D3DTEXF_POINT;
02355     texture_render_states -> state_array [D3DSAMP_MINFILTER] = D3DTEXF_POINT;
02356     texture_render_states -> state_array [D3DSAMP_MAXANISOTROPY] = 1;
02357   }
02358   _num_active_texture_stages = 0;
02359 
02360   set_render_state(D3DRS_NORMALIZENORMALS, false);
02361 
02362   _last_fvf = 0;
02363 }
02364 
02365 ////////////////////////////////////////////////////////////////////
02366 //     Function: DXGraphicsStateGuardian9::reset
02367 //       Access: Public, Virtual
02368 //  Description: Resets all internal state as if the gsg were newly
02369 //               created.  The GraphicsWindow pointer represents a
02370 //               typical window that might be used for this context;
02371 //               it may be required to set up the frame buffer
02372 //               properly the first time.
02373 ////////////////////////////////////////////////////////////////////
02374 void DXGraphicsStateGuardian9::
02375 reset() {
02376   GraphicsStateGuardian::reset();
02377 
02378   _auto_rescale_normal = false;
02379 
02380   // overwrite gsg defaults with these values
02381 
02382   HRESULT hr;
02383 
02384   // make sure gsg passes all current state down to us
02385   // set_state_and_transform(RenderState::make_empty(),
02386   // TransformState::make_identity());
02387   // want gsg to pass all state settings down so any non-matching defaults we set here get overwritten
02388 
02389   nassertv(_screen->_d3d9 != NULL);
02390   
02391   if (_d3d_device == NULL) {
02392     return;
02393   }
02394 
02395   D3DCAPS9 d3d_caps;
02396   _d3d_device->GetDeviceCaps(&d3d_caps);
02397 
02398   _vertex_shader_version_major = D3DSHADER_VERSION_MAJOR (d3d_caps.VertexShaderVersion);
02399   _vertex_shader_version_minor = D3DSHADER_VERSION_MINOR (d3d_caps.VertexShaderVersion);
02400   _pixel_shader_version_major = D3DSHADER_VERSION_MAJOR (d3d_caps.PixelShaderVersion);
02401   _pixel_shader_version_minor = D3DSHADER_VERSION_MINOR (d3d_caps.PixelShaderVersion);
02402 
02403   _vertex_shader_profile = (char *) D3DXGetVertexShaderProfile (_d3d_device);
02404   _pixel_shader_profile = (char *) D3DXGetPixelShaderProfile (_d3d_device);
02405 
02406   _vertex_shader_maximum_constants = d3d_caps.MaxVertexShaderConst;
02407 
02408   switch (_pixel_shader_version_major)
02409   {
02410     case 0:
02411       _shader_model = SM_00;
02412       break;
02413     case 1:
02414       _shader_model = SM_11;
02415       break;
02416     case 2:
02417       // minimim specification for pixel shader 2.0 is 96 instruction slots
02418       _shader_model = SM_20;
02419       if (d3d_caps.PS20Caps.NumInstructionSlots >= 512) {
02420         _shader_model = SM_2X;
02421       }
02422       break;
02423     case 3:
02424       _shader_model = SM_30;
02425       break;
02426     case 4:
02427     default:
02428       _shader_model = SM_40;
02429       break;
02430   }
02431 
02432   _auto_detect_shader_model = _shader_model;
02433 
02434 #ifdef HAVE_CG
02435   set_cg_device(_d3d_device);
02436 
02437   if (cgD3D9IsProfileSupported(CG_PROFILE_PS_2_0) &&
02438       cgD3D9IsProfileSupported(CG_PROFILE_VS_2_0)) {
02439     _supports_basic_shaders = true;
02440     _shader_caps._active_vprofile = (int)cgD3D9GetLatestVertexProfile();
02441     _shader_caps._active_fprofile = (int)cgD3D9GetLatestPixelProfile();
02442     _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VS_3_0;
02443     _shader_caps._ultimate_fprofile = (int)CG_PROFILE_PS_3_0;
02444 /*
02445     _shader_caps._active_vprofile = (int)CG_PROFILE_VS_2_0;
02446     _shader_caps._active_fprofile = (int)CG_PROFILE_PS_2_0;
02447     _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VS_2_0;
02448     _shader_caps._ultimate_fprofile = (int)CG_PROFILE_PS_2_0;
02449 */
02450   }
02451   
02452   if (dxgsg9_cat.is_debug()) {
02453     
02454     CGprofile vertex_profile;
02455     CGprofile pixel_profile;
02456     
02457     vertex_profile = cgD3D9GetLatestVertexProfile( );
02458     pixel_profile = cgD3D9GetLatestPixelProfile( );
02459     
02460     const char *vertex_profile_str =
02461       cgGetProfileString(vertex_profile);
02462     const char *pixel_profile_str =
02463       cgGetProfileString(pixel_profile);
02464     
02465     if (vertex_profile_str == NULL) {
02466       vertex_profile_str = "(null)";
02467     }
02468     if (pixel_profile_str == NULL) {
02469       pixel_profile_str = "(null)";
02470     }
02471     
02472     dxgsg9_cat.debug()
02473       << "\nCg vertex profile = " << vertex_profile_str << "  id = " << vertex_profile
02474       << "\nCg pixel profile = " << pixel_profile_str << "  id = " << pixel_profile
02475       << "\nshader model = " << _shader_model
02476       << "\n";
02477   }
02478 #endif
02479 
02480   _supports_stream_offset = (d3d_caps.DevCaps2 & D3DDEVCAPS2_STREAMOFFSET) != 0;
02481   _screen->_supports_dynamic_textures = ((d3d_caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) != 0);
02482   _screen->_supports_automatic_mipmap_generation = ((d3d_caps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP) != 0);
02483 
02484   if (support_stencil) {
02485     int min_stencil = D3DSTENCILCAPS_ZERO | D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_INCR | D3DSTENCILCAPS_DECR;
02486     if ((d3d_caps.StencilCaps & min_stencil) == min_stencil) {
02487       if (dxgsg9_cat.is_debug()) {
02488         dxgsg9_cat.debug()
02489           << "Checking for stencil; mode = "
02490           << D3DFormatStr(_screen->_presentation_params.AutoDepthStencilFormat)
02491           << "\n";
02492       }
02493       switch (_screen->_presentation_params.AutoDepthStencilFormat) {
02494         // These are the only formats that support stencil.
02495       case D3DFMT_D15S1:
02496       case D3DFMT_D24S8:
02497       case D3DFMT_D24X4S4:
02498         _supports_stencil = true;
02499         if (dxgsg9_cat.is_debug()) {
02500           dxgsg9_cat.debug()
02501             << "Stencils supported.\n";
02502         }
02503         break;
02504 
02505       default:
02506         if (dxgsg9_cat.is_debug()) {
02507           dxgsg9_cat.debug()
02508             << "Stencils NOT supported.\n";
02509         }
02510       }
02511     }
02512   }
02513 
02514   _supports_stencil_wrap = (d3d_caps.StencilCaps & D3DSTENCILCAPS_INCR) && (d3d_caps.StencilCaps & D3DSTENCILCAPS_DECR);
02515   _supports_two_sided_stencil = ((d3d_caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) != 0);
02516 
02517   _maximum_simultaneous_render_targets = d3d_caps.NumSimultaneousRTs;
02518 
02519   _supports_depth_bias = ((d3d_caps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS)) == (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS));
02520 
02521   _supports_gamma_calibration = ((d3d_caps.Caps2 & D3DCAPS2_CANCALIBRATEGAMMA) != 0);
02522 
02523   // Test for occlusion query support
02524   hr = _d3d_device->CreateQuery(D3DQUERYTYPE_OCCLUSION, NULL);
02525   _supports_occlusion_query = !FAILED(hr);
02526 
02527   if (dxgsg9_cat.is_error()) {
02528     dxgsg9_cat.debug()
02529       << "\nHwTransformAndLight = " << ((d3d_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0)
02530       << "\nMaxTextureWidth = " << d3d_caps.MaxTextureWidth
02531       << "\nMaxTextureHeight = " << d3d_caps.MaxTextureHeight
02532       << "\nMaxVolumeExtent = " << d3d_caps.MaxVolumeExtent
02533       << "\nMaxTextureAspectRatio = " << d3d_caps.MaxTextureAspectRatio
02534       << "\nTexCoordCount = " << (d3d_caps.FVFCaps & D3DFVFCAPS_TEXCOORDCOUNTMASK)
02535       << "\nMaxTextureBlendStages = " << d3d_caps.MaxTextureBlendStages
02536       << "\nMaxSimultaneousTextures = " << d3d_caps.MaxSimultaneousTextures
02537       << "\nMaxActiveLights = " << d3d_caps.MaxActiveLights
02538       << "\nMaxUserClipPlanes = " << d3d_caps.MaxUserClipPlanes
02539       << "\nMaxVertexBlendMatrices = " << d3d_caps.MaxVertexBlendMatrices
02540       << "\nMaxVertexBlendMatrixIndex = " << d3d_caps.MaxVertexBlendMatrixIndex
02541       << "\nMaxPointSize = " << d3d_caps.MaxPointSize
02542       << "\nMaxPrimitiveCount = " << d3d_caps.MaxPrimitiveCount
02543       << "\nMaxVertexIndex = " << d3d_caps.MaxVertexIndex
02544       << "\nMaxStreams = " << d3d_caps.MaxStreams
02545       << "\nMaxStreamStride = " << d3d_caps.MaxStreamStride
02546       << "\nD3DTEXOPCAPS_MULTIPLYADD = " << ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_MULTIPLYADD) != 0)
02547       << "\nD3DTEXOPCAPS_LERP = " << ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_LERP) != 0)
02548       << "\nD3DPMISCCAPS_TSSARGTEMP = " << ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) != 0)
02549       << "\nD3DPRASTERCAPS_DEPTHBIAS = " << ((d3d_caps.RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0)
02550       << "\nD3DPRASTERCAPS_SLOPESCALEDEPTHBIAS = " << ((d3d_caps.RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS) != 0)
02551       << "\nVertexShaderVersion = " << _vertex_shader_version_major << "." << _vertex_shader_version_minor
02552       << "\nPixelShaderVersion = " << _pixel_shader_version_major << "." << _pixel_shader_version_minor
02553       << "\nMaxVertexShaderConst = " << _vertex_shader_maximum_constants
02554       << "\nsupports_stream_offset = " << _supports_stream_offset
02555       << "\nsupports_dynamic_textures = " << _screen->_supports_dynamic_textures
02556       << "\nsupports_automatic_mipmap_generation = " << _screen->_supports_automatic_mipmap_generation
02557       << "\nsupports_stencil_wrap = " << _supports_stencil_wrap
02558       << "\nsupports_two_sided_stencil = " << _supports_two_sided_stencil
02559       << "\nsupports_occlusion_query = " << _supports_occlusion_query
02560       << "\nsupports_gamma_calibration = " << _supports_gamma_calibration
02561       << "\nMaxAnisotropy = " << d3d_caps.MaxAnisotropy
02562       << "\nNumSimultaneousRTs = " << d3d_caps.NumSimultaneousRTs
02563       << "\nD3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING = " << ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING) != 0)
02564       << "\nDirectX SDK version " DIRECTX_SDK_VERSION
02565       << "\n";
02566   }
02567   
02568   // OVERRIDE SUPPORT SINCE IT DOES NOT WORK WELL
02569   _screen->_supports_automatic_mipmap_generation = false;
02570 
02571   this -> reset_render_states ( );
02572 
02573   _max_vertices_per_array = d3d_caps.MaxVertexIndex;
02574   _max_vertices_per_primitive = d3d_caps.MaxPrimitiveCount;
02575 
02576   _max_texture_stages = d3d_caps.MaxSimultaneousTextures;
02577 
02578   _max_texture_dimension = min(d3d_caps.MaxTextureWidth, d3d_caps.MaxTextureHeight);
02579 
02580   _supports_texture_combine = ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_LERP) != 0);
02581   _supports_texture_saved_result = ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) != 0);
02582   _supports_texture_constant_color = ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_PERSTAGECONSTANT) != 0);
02583   _supports_texture_dot3 = true;
02584 
02585   if (_supports_texture_constant_color) {
02586     _constant_color_operand = D3DTA_CONSTANT;
02587   } else {
02588     _constant_color_operand = D3DTA_TFACTOR;
02589   }
02590 
02591   _screen->_managed_textures = _gsg_managed_textures;
02592   _screen->_managed_vertex_buffers = _gsg_managed_vertex_buffers;
02593   _screen->_managed_index_buffers = _gsg_managed_index_buffers;
02594 
02595   UINT available_texture_memory;
02596 
02597   available_texture_memory = _d3d_device->GetAvailableTextureMem ( );
02598   if (dxgsg9_cat.is_debug()) {
02599     dxgsg9_cat.debug() << "*** GetAvailableTextureMem = " <<  available_texture_memory << "\n";
02600   }
02601   _available_texture_memory = available_texture_memory;
02602 
02603   // check for render to texture support
02604   D3DDEVICE_CREATION_PARAMETERS creation_parameters;
02605 
02606   _supports_render_texture = false;
02607   _screen->_render_to_texture_d3d_format = D3DFMT_UNKNOWN;
02608   _screen->_framebuffer_d3d_format = D3DFMT_UNKNOWN;
02609 
02610   #define TOTAL_RENDER_TO_TEXTURE_FORMATS 3
02611 
02612   D3DFORMAT render_to_texture_formats [TOTAL_RENDER_TO_TEXTURE_FORMATS] =
02613   {
02614     D3DFMT_A8R8G8B8,  // check for this format first
02615     D3DFMT_X8R8G8B8,
02616     D3DFMT_UNKNOWN,   // place holder for _screen->_display_mode.Format
02617   };
02618 
02619   render_to_texture_formats [TOTAL_RENDER_TO_TEXTURE_FORMATS - 1] = _screen->_display_mode.Format;
02620 
02621   hr = _d3d_device->GetCreationParameters (&creation_parameters);
02622   if (SUCCEEDED (hr)) {
02623     _screen->_framebuffer_d3d_format = _screen->_display_mode.Format;
02624 
02625     int index;
02626     for (index = 0; index < TOTAL_RENDER_TO_TEXTURE_FORMATS; index++) {
02627       hr = _screen->_d3d9->CheckDeviceFormat (
02628           creation_parameters.AdapterOrdinal,
02629           creation_parameters.DeviceType,
02630           _screen->_display_mode.Format,
02631           D3DUSAGE_RENDERTARGET,
02632           D3DRTYPE_TEXTURE,
02633           render_to_texture_formats [index]);
02634       if (SUCCEEDED (hr)) {
02635         _screen->_render_to_texture_d3d_format = render_to_texture_formats [index];
02636         _supports_render_texture = true;
02637       }
02638       if (_supports_render_texture) {
02639         break;
02640       }
02641     }
02642   }
02643   if (dxgsg9_cat.is_debug()) {
02644     dxgsg9_cat.debug() << "Render to Texture Support = " << _supports_render_texture << "\n";
02645   }
02646 
02647   // override default config setting since it is really supported or not ???
02648 //  support_render_texture = _supports_render_texture;
02649 
02650   _supports_3d_texture = ((d3d_caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) != 0);
02651   if (_supports_3d_texture) {
02652     _max_3d_texture_dimension = d3d_caps.MaxVolumeExtent;
02653   }
02654   _supports_cube_map = ((d3d_caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) != 0);
02655   if (_supports_cube_map) {
02656     _max_cube_map_dimension = _max_texture_dimension;
02657   }
02658 
02659   _max_lights = (int)d3d_caps.MaxActiveLights;
02660   _max_clip_planes = (int)d3d_caps.MaxUserClipPlanes;
02661   _max_vertex_transforms = d3d_caps.MaxVertexBlendMatrices;
02662   _max_vertex_transform_indices = d3d_caps.MaxVertexBlendMatrixIndex;
02663 
02664   set_render_state(D3DRS_AMBIENT, 0x0);
02665 
02666   _clip_plane_bits = 0;
02667   set_render_state(D3DRS_CLIPPLANEENABLE , 0x0);
02668 
02669   set_render_state(D3DRS_CLIPPING, true);
02670 
02671   set_render_state(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
02672 
02673   set_render_state(D3DRS_ZWRITEENABLE, TRUE);
02674 
02675 /* ***** DX9 ??? D3DRS_EDGEANTIALIAS NOT IN DX9 */
02676 //  set_render_state(D3DRS_EDGEANTIALIAS, false);
02677 
02678   set_render_state(D3DRS_ZENABLE, D3DZB_FALSE);
02679 
02680   set_render_state(D3DRS_ALPHABLENDENABLE, FALSE);
02681 
02682   set_render_state(D3DRS_FOGENABLE, FALSE);
02683 
02684   _has_scene_graph_color = false;
02685 
02686   _last_testcooplevel_result = D3D_OK;
02687 
02688   for(int i = 0; i < MAX_POSSIBLE_TEXFMTS; i++) {
02689     // look for all possible DX9 texture fmts
02690     D3DFORMAT_FLAG fmtflag = D3DFORMAT_FLAG(1 << i);
02691     hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format,
02692                                           0x0, D3DRTYPE_TEXTURE, g_D3DFORMATmap[fmtflag]);
02693     if (SUCCEEDED(hr)){
02694       _screen->_supported_tex_formats_mask |= fmtflag;
02695     }
02696   }
02697 
02698   // check if compressed textures are supported
02699   #define CHECK_FOR_DXTVERSION(num) \
02700   if (_screen->_supported_tex_formats_mask & DXT##num##_FLAG) {\
02701     if (dxgsg9_cat.is_debug()) {\
02702       dxgsg9_cat.debug() << "Compressed texture format DXT" << #num << " supported \n";\
02703     }\
02704     _supports_compressed_texture = true;\
02705     _compressed_texture_formats.set_bit(Texture::CM_dxt##num);\
02706   }
02707 
02708   if (_screen->_intel_compressed_texture_bug) {
02709     dxgsg9_cat.info()
02710       << "Buggy Intel driver detected; disabling compressed textures.\n";
02711     _screen->_supported_tex_formats_mask &= 
02712       ~(DXT1_FLAG | DXT2_FLAG | DXT3_FLAG | DXT4_FLAG | DXT5_FLAG);
02713                                               
02714   } else {
02715     // Check for available compressed formats normally.
02716     CHECK_FOR_DXTVERSION(1);
02717     CHECK_FOR_DXTVERSION(2);
02718     CHECK_FOR_DXTVERSION(3);
02719     CHECK_FOR_DXTVERSION(4);
02720     CHECK_FOR_DXTVERSION(5);
02721   }
02722       
02723   #undef CHECK_FOR_DXTVERSION
02724 
02725   _screen->_supports_rgba16f_texture_format = false;
02726   hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format, 0x0, D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F);
02727   if (SUCCEEDED(hr)){
02728     _screen->_supports_rgba16f_texture_format = true;
02729   }
02730   _screen->_supports_rgba32f_texture_format = false;
02731   hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format, 0x0, D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F);
02732   if (SUCCEEDED(hr)){
02733     _screen->_supports_rgba32f_texture_format = true;
02734   }
02735 
02736   // s3 virge drivers sometimes give crap values for these
02737   if (_screen->_d3dcaps.MaxTextureWidth == 0)
02738     _screen->_d3dcaps.MaxTextureWidth = 256;
02739 
02740   if (_screen->_d3dcaps.MaxTextureHeight == 0)
02741     _screen->_d3dcaps.MaxTextureHeight = 256;
02742 
02743   if (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGTABLE) {
02744     // Watch out for drivers that emulate per-pixel fog with
02745     // per-vertex fog (Riva128, Matrox Millen G200).  Some of these
02746     // require gouraud-shading to be set to work, as if you were using
02747     // vertex fog
02748     _do_fog_type = PerPixelFog;
02749   } else {
02750     // every card is going to have vertex fog, since it's implemented
02751     // in d3d runtime.
02752     nassertv((_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGVERTEX) != 0);
02753 
02754     // vertex fog may look crappy if you have large polygons in the
02755     // foreground and they get clipped, so you may want to disable it
02756 
02757     if (dx_no_vertex_fog) {
02758       _do_fog_type = None;
02759     } else {
02760       _do_fog_type = PerVertexFog;
02761 
02762       // range-based fog only works with vertex fog in dx7/8
02763       if (dx_use_rangebased_fog && (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGRANGE)) {
02764         set_render_state(D3DRS_RANGEFOGENABLE, true);
02765       }
02766     }
02767   }
02768 
02769   _screen->_can_direct_disable_color_writes = ((_screen->_d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) != 0);
02770 
02771   // Lighting, let's turn it off initially.
02772   set_render_state(D3DRS_LIGHTING, false);
02773 
02774   // turn on dithering if the rendertarget is < 8bits/color channel
02775   bool dither_enabled = ((!dx_no_dithering) && IS_16BPP_DISPLAY_FORMAT(_screen->_presentation_params.BackBufferFormat)
02776        && (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_DITHER));
02777   set_render_state(D3DRS_DITHERENABLE, dither_enabled);
02778 
02779   set_render_state(D3DRS_CLIPPING, true);
02780 
02781   // Stencil test is off by default
02782   set_render_state(D3DRS_STENCILENABLE, FALSE);
02783   if (_supports_two_sided_stencil) {
02784     set_render_state(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
02785   }
02786 
02787   // Antialiasing.
02788 /* ***** DX9 ??? D3DRS_EDGEANTIALIAS NOT IN DX9 */
02789 //  set_render_state(D3DRS_EDGEANTIALIAS, FALSE);
02790 
02791   _current_fill_mode = RenderModeAttrib::M_filled;
02792   set_render_state(D3DRS_FILLMODE, D3DFILL_SOLID);
02793 
02794   // must do SetTSS here because redundant states are filtered out by
02795   // our code based on current values above, so initial conditions
02796   // must be correct
02797   set_texture_stage_state(0, D3DTSS_COLOROP, D3DTOP_DISABLE);  // disables texturing
02798 
02799   _cull_face_mode = CullFaceAttrib::M_cull_none;
02800   set_render_state(D3DRS_CULLMODE, D3DCULL_NONE);
02801 
02802   set_render_state(D3DRS_ALPHAFUNC, D3DCMP_ALWAYS);
02803   set_render_state(D3DRS_ALPHAREF, 255);
02804   set_render_state(D3DRS_ALPHATESTENABLE, FALSE);
02805 
02806   // this is a new DX8 state that lets you do additional operations other than ADD (e.g. subtract/max/min)
02807   // must check (_screen->_d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) (yes on GF2/Radeon8500, no on TNT)
02808   set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
02809 
02810   _current_shader = (Shader *)NULL;
02811   _current_shader_context = (CLP(ShaderContext) *)NULL;
02812   _vertex_array_shader = (Shader *)NULL;
02813   _vertex_array_shader_context = (CLP(ShaderContext) *)NULL;
02814   _texture_binding_shader = (Shader *)NULL;
02815   _texture_binding_shader_context = (CLP(ShaderContext) *)NULL;
02816 
02817   PRINT_REFCNT(dxgsg9, _d3d_device);
02818 
02819   void dx_set_stencil_functions (StencilRenderStates *stencil_render_states);
02820   dx_set_stencil_functions (_stencil_render_states);
02821 
02822   // Now that the GSG has been initialized, make it available for
02823   // optimizations.
02824   add_gsg(this);
02825 }
02826 
02827 ////////////////////////////////////////////////////////////////////
02828 //     Function: DXGraphicsStateGuardian9::apply_fog
02829 //       Access: Public, Virtual
02830 //  Description:
02831 ////////////////////////////////////////////////////////////////////
02832 void DXGraphicsStateGuardian9::
02833 apply_fog(Fog *fog) {
02834   if (_do_fog_type == None)
02835     return;
02836 
02837   Fog::Mode panda_fogmode = fog->get_mode();
02838   D3DFOGMODE d3dfogmode = get_fog_mode_type(panda_fogmode);
02839 
02840   set_render_state((D3DRENDERSTATETYPE)_do_fog_type, d3dfogmode);
02841 
02842   const Colorf &fog_colr = fog->get_color();
02843   set_render_state(D3DRS_FOGCOLOR,
02844                               MY_D3DRGBA(fog_colr[0], fog_colr[1], fog_colr[2], 0.0f));  // Alpha bits are not used
02845 
02846   // do we need to adjust fog start/end values based on D3DPRASTERCAPS_WFOG/D3DPRASTERCAPS_ZFOG ?
02847   // if not WFOG, then docs say we need to adjust values to range [0, 1]
02848 
02849   switch (panda_fogmode) {
02850   case Fog::M_linear:
02851     {
02852       float onset, opaque;
02853       fog->get_linear_range(onset, opaque);
02854 
02855       set_render_state(D3DRS_FOGSTART,
02856                                    *((LPDWORD) (&onset)));
02857       set_render_state(D3DRS_FOGEND,
02858                                    *((LPDWORD) (&opaque)));
02859     }
02860     break;
02861   case Fog::M_exponential:
02862   case Fog::M_exponential_squared:
02863     {
02864       // Exponential fog is always camera-relative.
02865       float fog_density = fog->get_exp_density();
02866       set_render_state(D3DRS_FOGDENSITY,
02867                                    *((LPDWORD) (&fog_density)));
02868     }
02869     break;
02870   }
02871 }
02872 
02873 ////////////////////////////////////////////////////////////////////
02874 //     Function: DXGraphicsStateGuardian9::do_issue_transform
02875 //       Access: Protected
02876 //  Description: Sends the indicated transform matrix to the graphics
02877 //               API to be applied to future vertices.
02878 //
02879 //               This transform is the internal_transform, already
02880 //               converted into the GSG's internal coordinate system.
02881 ////////////////////////////////////////////////////////////////////
02882 void DXGraphicsStateGuardian9::
02883 do_issue_transform() {
02884   const TransformState *transform = _internal_transform;
02885   DO_PSTATS_STUFF(_transform_state_pcollector.add_level(1));
02886 
02887   if (_current_shader_context) {
02888 //    _current_shader_context->issue_transform(this);
02889     _current_shader_context->issue_parameters(this, Shader::SSD_transform);
02890 
02891 // ??? NO NEED TO SET THE D3D TRANSFORM VIA SetTransform SINCE THE TRANSFORM IS ONLY USED IN THE SHADER
02892     const D3DMATRIX *d3d_mat = (const D3DMATRIX *)transform->get_mat().get_data();
02893     _d3d_device->SetTransform(D3DTS_WORLD, d3d_mat);
02894 
02895   }
02896   else {
02897     const D3DMATRIX *d3d_mat = (const D3DMATRIX *)transform->get_mat().get_data();
02898     _d3d_device->SetTransform(D3DTS_WORLD, d3d_mat);
02899 
02900 // DEBUG PRINT
02901 /*
02902     const float *data;
02903     data = &d3d_mat -> _11;
02904         dxgsg9_cat.debug ( ) << "do_issue_transform\n" <<
02905           data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" <<
02906           data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" <<
02907           data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" <<
02908           data[12] << " " << data[13] << " " << data[14] << " " << data[15] << "\n";
02909 */
02910 
02911   }
02912 
02913   _transform_stale = false;
02914 
02915   if (_auto_rescale_normal) {
02916     do_auto_rescale_normal();
02917   }
02918 }
02919 
02920 ////////////////////////////////////////////////////////////////////
02921 //     Function: DXGraphicsStateGuardian9::do_issue_alpha_test
02922 //       Access: Protected
02923 //  Description:
02924 ////////////////////////////////////////////////////////////////////
02925 void DXGraphicsStateGuardian9::
02926 do_issue_alpha_test() {
02927   if (_target_shader->get_flag(ShaderAttrib::F_subsume_alpha_test)) {
02928     set_render_state(D3DRS_ALPHATESTENABLE, FALSE);
02929   } else {
02930     const AlphaTestAttrib *target_alpha_test = DCAST(AlphaTestAttrib, _target_rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
02931     AlphaTestAttrib::PandaCompareFunc mode = target_alpha_test->get_mode();
02932     if (mode == AlphaTestAttrib::M_none) {
02933       set_render_state(D3DRS_ALPHATESTENABLE, FALSE);
02934     } else {
02935       //  AlphaTestAttrib::PandaCompareFunc === D3DCMPFUNC
02936       set_render_state(D3DRS_ALPHAFUNC, (D3DCMPFUNC)mode);
02937       set_render_state(D3DRS_ALPHAREF, (UINT) (target_alpha_test->get_reference_alpha()*255.0f));  //d3d uses 0x0-0xFF, not a float
02938       set_render_state(D3DRS_ALPHATESTENABLE, TRUE);
02939     }
02940   }
02941 }
02942 
02943 ////////////////////////////////////////////////////////////////////
02944 //     Function: DXGraphicsStateGuardian9::do_issue_shader
02945 //       Access: Protected
02946 //  Description:
02947 ////////////////////////////////////////////////////////////////////
02948 void DXGraphicsStateGuardian9::
02949 do_issue_shader() {
02950 
02951   CLP(ShaderContext) *context = 0;
02952   Shader *shader = 0;
02953   if (_target_shader) {
02954     shader = (Shader *)(_target_shader->get_shader());
02955   }
02956   if (shader) {
02957     context = (CLP(ShaderContext) *)(shader->prepare_now(get_prepared_objects(), this));
02958   }
02959 
02960   if (context == 0 || (context && context -> valid (this) == false)) {
02961     if (_current_shader_context != 0) {
02962       _current_shader_context->unbind(this);
02963       _current_shader = 0;
02964       _current_shader_context = 0;
02965       disable_standard_texture_bindings();
02966     }
02967     return;
02968   }
02969 
02970   if (context != _current_shader_context) {
02971     // Use a completely different shader than before.
02972     // Unbind old shader, bind the new one.
02973     if (_current_shader_context != 0) {
02974       _current_shader_context->unbind(this);
02975       _current_shader_context = 0;
02976       _current_shader = 0;
02977       disable_standard_texture_bindings();
02978     }
02979     if (context != 0) {
02980       context->bind(this);
02981       _current_shader = shader;
02982       _current_shader_context = context;
02983     }
02984   } else {
02985     // Use the same shader as before, but with new input arguments.
02986     context->issue_parameters(this, Shader::SSD_shaderinputs);
02987   }
02988 }
02989 
02990 ////////////////////////////////////////////////////////////////////
02991 //     Function: DXGraphicsStateGuardian9::do_issue_render_mode
02992 //       Access: Protected
02993 //  Description:
02994 ////////////////////////////////////////////////////////////////////
02995 void DXGraphicsStateGuardian9::
02996 do_issue_render_mode() {
02997   const RenderModeAttrib *target_render_mode = DCAST(RenderModeAttrib, _target_rs->get_attrib_def(RenderModeAttrib::get_class_slot()));
02998   RenderModeAttrib::Mode mode = target_render_mode->get_mode();
02999 
03000   switch (mode) {
03001   case RenderModeAttrib::M_unchanged:
03002   case RenderModeAttrib::M_filled:
03003   case RenderModeAttrib::M_filled_flat:
03004     set_render_state(D3DRS_FILLMODE, D3DFILL_SOLID);
03005     break;
03006 
03007   case RenderModeAttrib::M_wireframe:
03008     set_render_state(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
03009     break;
03010 
03011   case RenderModeAttrib::M_point:
03012     set_render_state(D3DRS_FILLMODE, D3DFILL_POINT);
03013     break;
03014 
03015   default:
03016     dxgsg9_cat.error()
03017       << "Unknown render mode " << (int)mode << endl;
03018   }
03019 
03020   // This might also specify the point size.
03021   float point_size = target_render_mode->get_thickness();
03022   set_render_state(D3DRS_POINTSIZE, *((DWORD*)&point_size));
03023 
03024   if (target_render_mode->get_perspective()) {
03025     set_render_state(D3DRS_POINTSCALEENABLE, TRUE);
03026 
03027     LVector3f height(0.0f, point_size, 1.0f);
03028     height = height * _projection_mat->get_mat();
03029     float s = height[1] / point_size;
03030 
03031     float zero = 0.0f;
03032     float one_over_s2 = 1.0f / (s * s);
03033     set_render_state(D3DRS_POINTSCALE_A, *((DWORD*)&zero));
03034     set_render_state(D3DRS_POINTSCALE_B, *((DWORD*)&zero));
03035     set_render_state(D3DRS_POINTSCALE_C, *((DWORD*)&one_over_s2));
03036 
03037   } else {
03038     set_render_state(D3DRS_POINTSCALEENABLE, FALSE);
03039   }
03040 
03041   _current_fill_mode = mode;
03042 }
03043 
03044 ////////////////////////////////////////////////////////////////////
03045 //     Function: DXGraphicsStateGuardian9::do_issue_rescale_normal
03046 //       Access: Protected
03047 //  Description:
03048 ////////////////////////////////////////////////////////////////////
03049 void DXGraphicsStateGuardian9::
03050 do_issue_rescale_normal() {
03051   const RescaleNormalAttrib *target_rescale_normal = DCAST(RescaleNormalAttrib, _target_rs->get_attrib_def(RescaleNormalAttrib::get_class_slot()));
03052   RescaleNormalAttrib::Mode mode = target_rescale_normal->get_mode();
03053 
03054   _auto_rescale_normal = false;
03055 
03056   switch (mode) {
03057   case RescaleNormalAttrib::M_none:
03058     set_render_state(D3DRS_NORMALIZENORMALS, false);
03059     break;
03060 
03061   case RescaleNormalAttrib::M_rescale:
03062   case RescaleNormalAttrib::M_normalize:
03063     set_render_state(D3DRS_NORMALIZENORMALS, true);
03064     break;
03065 
03066   case RescaleNormalAttrib::M_auto:
03067     _auto_rescale_normal = true;
03068     do_auto_rescale_normal();
03069     break;
03070 
03071   default:
03072     dxgsg9_cat.error()
03073       << "Unknown rescale_normal mode " << (int)mode << endl;
03074   }
03075 }
03076 
03077 ////////////////////////////////////////////////////////////////////
03078 //     Function: DXGraphicsStateGuardian9::do_issue_depth_test
03079 //       Access: Protected
03080 //  Description:
03081 ////////////////////////////////////////////////////////////////////
03082 void DXGraphicsStateGuardian9::
03083 do_issue_depth_test() {
03084   const DepthTestAttrib *target_depth_test = DCAST(DepthTestAttrib, _target_rs->get_attrib_def(DepthTestAttrib::get_class_slot()));
03085   DepthTestAttrib::PandaCompareFunc mode = target_depth_test->get_mode();
03086   if (mode == DepthTestAttrib::M_none) {
03087     set_render_state(D3DRS_ZENABLE, D3DZB_FALSE);
03088   } else {
03089     set_render_state(D3DRS_ZENABLE, D3DZB_TRUE);
03090     set_render_state(D3DRS_ZFUNC, (D3DCMPFUNC) mode);
03091   }
03092 }
03093 
03094 ////////////////////////////////////////////////////////////////////
03095 //     Function: DXGraphicsStateGuardian9::do_issue_depth_write
03096 //       Access: Protected
03097 //  Description:
03098 ////////////////////////////////////////////////////////////////////
03099 void DXGraphicsStateGuardian9::
03100 do_issue_depth_write() {
03101   const DepthWriteAttrib *target_depth_write = DCAST(DepthWriteAttrib, _target_rs->get_attrib_def(DepthWriteAttrib::get_class_slot()));
03102   DepthWriteAttrib::Mode mode = target_depth_write->get_mode();
03103   if (mode == DepthWriteAttrib::M_on) {
03104     set_render_state(D3DRS_ZWRITEENABLE, TRUE);
03105   } else {
03106     set_render_state(D3DRS_ZWRITEENABLE, FALSE);
03107   }
03108 }
03109 
03110 ////////////////////////////////////////////////////////////////////
03111 //     Function: DXGraphicsStateGuardian9::do_issue_cull_face
03112 //       Access: Protected
03113 //  Description:
03114 ////////////////////////////////////////////////////////////////////
03115 void DXGraphicsStateGuardian9::
03116 do_issue_cull_face() {
03117   const CullFaceAttrib *target_cull_face = DCAST(CullFaceAttrib, _target_rs->get_attrib_def(CullFaceAttrib::get_class_slot()));
03118   _cull_face_mode = target_cull_face->get_effective_mode();
03119 
03120   switch (_cull_face_mode) {
03121   case CullFaceAttrib::M_cull_none:
03122     set_render_state(D3DRS_CULLMODE, D3DCULL_NONE);
03123 
03124 // printf ("------------------- D3DCULL_NONE\n");
03125 
03126     break;
03127   case CullFaceAttrib::M_cull_clockwise:
03128     set_render_state(D3DRS_CULLMODE, D3DCULL_CW);
03129 
03130 // printf ("------------------- D3DCULL_CW -- CLOCKWISE \n");
03131 
03132     break;
03133   case CullFaceAttrib::M_cull_counter_clockwise:
03134     set_render_state(D3DRS_CULLMODE, D3DCULL_CCW);
03135 
03136 // printf ("------------------- D3DCULL_CCW\n");
03137 
03138     break;
03139   default:
03140     dxgsg9_cat.error()
03141       << "invalid cull face mode " << (int)_cull_face_mode << endl;
03142     break;
03143   }
03144 }
03145 
03146 ////////////////////////////////////////////////////////////////////
03147 //     Function: DXGraphicsStateGuardian9::do_issue_fog
03148 //       Access: Protected
03149 //  Description:
03150 ////////////////////////////////////////////////////////////////////
03151 void DXGraphicsStateGuardian9::
03152 do_issue_fog() {
03153   const FogAttrib *target_fog = DCAST(FogAttrib, _target_rs->get_attrib_def(FogAttrib::get_class_slot()));
03154   if (!target_fog->is_off()) {
03155     set_render_state(D3DRS_FOGENABLE, TRUE);
03156     Fog *fog = target_fog->get_fog();
03157     nassertv(fog != (Fog *)NULL);
03158     apply_fog(fog);
03159   } else {
03160     set_render_state(D3DRS_FOGENABLE, FALSE);
03161   }
03162 }
03163 
03164 ////////////////////////////////////////////////////////////////////
03165 //     Function: DXGraphicsStateGuardian9::do_issue_depth_offset
03166 //       Access: Protected
03167 //  Description:
03168 ////////////////////////////////////////////////////////////////////
03169 void DXGraphicsStateGuardian9::
03170 do_issue_depth_offset() {
03171   const DepthOffsetAttrib *target_depth_offset = DCAST(DepthOffsetAttrib, _target_rs->get_attrib_def(DepthOffsetAttrib::get_class_slot()));
03172   int offset = target_depth_offset->get_offset();
03173 
03174   if (_supports_depth_bias && !dx_broken_depth_bias) {
03175     set_render_state(D3DRS_DEPTHBIAS, offset);
03176     set_render_state(D3DRS_SLOPESCALEDEPTHBIAS, offset);
03177 
03178   } else {
03179     // DirectX depth bias isn't directly supported by the driver.
03180     // Cheese a depth bias effect by sliding the viewport backward a
03181     // bit.
03182     static const float bias_scale = dx_depth_bias_scale;
03183     D3DVIEWPORT9 vp = _current_viewport;
03184     vp.MinZ -= bias_scale * offset;
03185     vp.MaxZ -= bias_scale * offset;
03186     _d3d_device->SetViewport(&vp);
03187   }
03188 }
03189 
03190 ////////////////////////////////////////////////////////////////////
03191 //     Function: DXGraphicsStateGuardian9::do_issue_shade_model
03192 //       Access: Protected
03193 //  Description:
03194 ////////////////////////////////////////////////////////////////////
03195 void DXGraphicsStateGuardian9::
03196 do_issue_shade_model() {
03197   const ShadeModelAttrib *target_shade_model = DCAST(ShadeModelAttrib, _target_rs->get_attrib_def(ShadeModelAttrib::get_class_slot()));
03198   switch (target_shade_model->get_mode()) {
03199   case ShadeModelAttrib::M_smooth:
03200     set_render_state(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
03201     break;
03202 
03203   case ShadeModelAttrib::M_flat:
03204     set_render_state(D3DRS_SHADEMODE, D3DSHADE_FLAT);
03205     break;
03206   }
03207 }
03208 
03209 ////////////////////////////////////////////////////////////////////
03210 //     Function: DXGraphicsStateGuardian9::set_state_and_transform
03211 //       Access: Public, Virtual
03212 //  Description: Simultaneously resets the render state and the
03213 //               transform state.
03214 //
03215 //               This transform specified is the "internal" net
03216 //               transform, already converted into the GSG's internal
03217 //               coordinate space by composing it to
03218 //               get_cs_transform().  (Previously, this used to be the
03219 //               "external" net transform, with the assumption that
03220 //               that GSG would convert it internally, but that is no
03221 //               longer the case.)
03222 //
03223 //               Special case: if (state==NULL), then the target
03224 //               state is already stored in _target.
03225 ////////////////////////////////////////////////////////////////////
03226 void DXGraphicsStateGuardian9::
03227 set_state_and_transform(const RenderState *target,
03228                         const TransformState *transform) {
03229 #ifndef NDEBUG
03230   if (gsg_cat.is_spam()) {
03231     gsg_cat.spam() << "Setting GSG state to " << (void *)target << ":\n";
03232     target->write(gsg_cat.spam(false), 2);
03233   }
03234 #endif
03235   _state_pcollector.add_level(1);
03236   PStatTimer timer1(_draw_set_state_pcollector);
03237 
03238   if (transform != _internal_transform) {
03239     //PStatTimer timer(_draw_set_state_transform_pcollector);
03240     _state_pcollector.add_level(1);
03241     _internal_transform = transform;
03242     do_issue_transform();
03243   }
03244 
03245   if (target == _state_rs) {
03246     return;
03247   }
03248   _target_rs = target;
03249 
03250   _target_shader = DCAST(ShaderAttrib, _target_rs->get_attrib_def(ShaderAttrib::get_class_slot()));
03251   if (_target_shader->auto_shader()) {
03252     // If we don't have a generated shader, make sure we have a ShaderGenerator, then generate the shader.
03253     if (_target_rs->_generated_shader == NULL) {
03254       if (_shader_generator == NULL) {
03255         _shader_generator = new ShaderGenerator(this, _scene_setup->get_display_region()->get_window());
03256       }
03257       const_cast<RenderState*>(_target_rs.p())->_generated_shader = DCAST(ShaderAttrib, _shader_generator->synthesize_shader(_target_rs));
03258     }
03259     _target_shader = DCAST(ShaderAttrib, _target_rs->_generated_shader);
03260   }
03261 
03262   int alpha_test_slot = AlphaTestAttrib::get_class_slot();
03263   if (_target_rs->get_attrib(alpha_test_slot) != _state_rs->get_attrib(alpha_test_slot) ||
03264       !_state_mask.get_bit(alpha_test_slot)) {
03265     //PStatTimer timer(_draw_set_state_alpha_test_pcollector);
03266     do_issue_alpha_test();
03267     _state_mask.set_bit(alpha_test_slot);
03268   }
03269 
03270   int clip_plane_slot = ClipPlaneAttrib::get_class_slot();
03271   if (_target_rs->get_attrib(clip_plane_slot) != _state_rs->get_attrib(clip_plane_slot) ||
03272       !_state_mask.get_bit(clip_plane_slot)) {
03273     //PStatTimer timer(_draw_set_state_clip_plane_pcollector);
03274     do_issue_clip_plane();
03275     _state_mask.set_bit(clip_plane_slot);
03276   }
03277 
03278   int color_slot = ColorAttrib::get_class_slot();
03279   int color_scale_slot = ColorScaleAttrib::get_class_slot();
03280   if (_target_rs->get_attrib(color_slot) != _state_rs->get_attrib(color_slot) ||
03281       _target_rs->get_attrib(color_scale_slot) != _state_rs->get_attrib(color_scale_slot) ||
03282       !_state_mask.get_bit(color_slot) ||
03283       !_state_mask.get_bit(color_scale_slot)) {
03284     //PStatTimer timer(_draw_set_state_color_pcollector);
03285     do_issue_color();
03286     do_issue_color_scale();
03287     _state_mask.set_bit(color_slot);
03288     _state_mask.set_bit(color_scale_slot);
03289     if (_current_shader_context) {
03290       _current_shader_context->issue_parameters(this, Shader::SSD_color);
03291       _current_shader_context->issue_parameters(this, Shader::SSD_colorscale);
03292     }
03293   }
03294 
03295   int cull_face_slot = CullFaceAttrib::get_class_slot();
03296   if (_target_rs->get_attrib(cull_face_slot) != _state_rs->get_attrib(cull_face_slot) ||
03297       !_state_mask.get_bit(cull_face_slot)) {
03298     //PStatTimer timer(_draw_set_state_cull_face_pcollector);
03299     do_issue_cull_face();
03300     _state_mask.set_bit(cull_face_slot);
03301   }
03302 
03303   int depth_offset_slot = DepthOffsetAttrib::get_class_slot();
03304   if (_target_rs->get_attrib(depth_offset_slot) != _state_rs->get_attrib(depth_offset_slot) ||
03305       !_state_mask.get_bit(depth_offset_slot)) {
03306     //PStatTimer timer(_draw_set_state_depth_offset_pcollector);
03307     do_issue_depth_offset();
03308     _state_mask.set_bit(depth_offset_slot);
03309   }
03310 
03311   int depth_test_slot = DepthTestAttrib::get_class_slot();
03312   if (_target_rs->get_attrib(depth_test_slot) != _state_rs->get_attrib(depth_test_slot) ||
03313       !_state_mask.get_bit(depth_test_slot)) {
03314     //PStatTimer timer(_draw_set_state_depth_test_pcollector);
03315     do_issue_depth_test();
03316     _state_mask.set_bit(depth_test_slot);
03317   }
03318 
03319   int depth_write_slot = DepthWriteAttrib::get_class_slot();
03320   if (_target_rs->get_attrib(depth_write_slot) != _state_rs->get_attrib(depth_write_slot) ||
03321       !_state_mask.get_bit(depth_write_slot)) {
03322     //PStatTimer timer(_draw_set_state_depth_write_pcollector);
03323     do_issue_depth_write();
03324     _state_mask.set_bit(depth_write_slot);
03325   }
03326 
03327   int render_mode_slot = RenderModeAttrib::get_class_slot();
03328   if (_target_rs->get_attrib(render_mode_slot) != _state_rs->get_attrib(render_mode_slot) ||
03329       !_state_mask.get_bit(render_mode_slot)) {
03330     //PStatTimer timer(_draw_set_state_render_mode_pcollector);
03331     do_issue_render_mode();
03332     _state_mask.set_bit(render_mode_slot);
03333   }
03334 
03335   int rescale_normal_slot = RescaleNormalAttrib::get_class_slot();
03336   if (_target_rs->get_attrib(rescale_normal_slot) != _state_rs->get_attrib(rescale_normal_slot) ||
03337       !_state_mask.get_bit(rescale_normal_slot)) {
03338     //PStatTimer timer(_draw_set_state_rescale_normal_pcollector);
03339     do_issue_rescale_normal();
03340     _state_mask.set_bit(rescale_normal_slot);
03341   }
03342 
03343   int shade_model_slot = ShadeModelAttrib::get_class_slot();
03344   if (_target_rs->get_attrib(shade_model_slot) != _state_rs->get_attrib(shade_model_slot) ||
03345       !_state_mask.get_bit(shade_model_slot)) {
03346     //PStatTimer timer(_draw_set_state_shade_model_pcollector);
03347     do_issue_shade_model();
03348     _state_mask.set_bit(shade_model_slot);
03349   }
03350 
03351   int transparency_slot = TransparencyAttrib::get_class_slot();
03352   int color_write_slot = ColorWriteAttrib::get_class_slot();
03353   int color_blend_slot = ColorBlendAttrib::get_class_slot();
03354   if (_target_rs->get_attrib(transparency_slot) != _state_rs->get_attrib(transparency_slot) ||
03355       _target_rs->get_attrib(color_write_slot) != _state_rs->get_attrib(color_write_slot) ||
03356       _target_rs->get_attrib(color_blend_slot) != _state_rs->get_attrib(color_blend_slot) ||
03357       !_state_mask.get_bit(transparency_slot) ||
03358       !_state_mask.get_bit(color_write_slot) ||
03359       !_state_mask.get_bit(color_blend_slot) ||
03360       (_target_shader->get_flag(ShaderAttrib::F_disable_alpha_write) != 
03361        _state_shader->get_flag(ShaderAttrib::F_disable_alpha_write))) {
03362     //PStatTimer timer(_draw_set_state_blending_pcollector);
03363     do_issue_blending();
03364     _state_mask.set_bit(transparency_slot);
03365     _state_mask.set_bit(color_write_slot);
03366     _state_mask.set_bit(color_blend_slot);
03367   }
03368 
03369   if (_target_shader != _state_shader) {
03370     //PStatTimer timer(_draw_set_state_shader_pcollector);
03371     do_issue_shader();
03372     _state_shader = _target_shader;
03373     _state_mask.clear_bit(TextureAttrib::get_class_slot());
03374   }
03375 
03376   int texture_slot = TextureAttrib::get_class_slot();
03377   int tex_matrix_slot = TexMatrixAttrib::get_class_slot();
03378   int tex_gen_slot = TexGenAttrib::get_class_slot();
03379   if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) ||
03380       _target_rs->get_attrib(tex_matrix_slot) != _state_rs->get_attrib(tex_matrix_slot) ||
03381       _target_rs->get_attrib(tex_gen_slot) != _state_rs->get_attrib(tex_gen_slot) ||
03382       !_state_mask.get_bit(texture_slot) ||
03383       !_state_mask.get_bit(tex_matrix_slot) ||
03384       !_state_mask.get_bit(tex_gen_slot)) {
03385     //PStatTimer timer(_draw_set_state_texture_pcollector);
03386     determine_target_texture();
03387     do_issue_texture();
03388 
03389     _state_texture = _target_texture;
03390     _state_mask.set_bit(texture_slot);
03391     _state_mask.set_bit(tex_matrix_slot);
03392     _state_mask.set_bit(tex_gen_slot);
03393   }
03394 
03395   int material_slot = MaterialAttrib::get_class_slot();
03396   if (_target_rs->get_attrib(material_slot) != _state_rs->get_attrib(material_slot) ||
03397       !_state_mask.get_bit(material_slot)) {
03398     //PStatTimer timer(_draw_set_state_material_pcollector);
03399     do_issue_material();
03400     _state_mask.set_bit(material_slot);
03401     if (_current_shader_context) {
03402       _current_shader_context->issue_parameters(this, Shader::SSD_material);
03403     }
03404   }
03405 
03406   int light_slot = LightAttrib::get_class_slot();
03407   if (_target_rs->get_attrib(light_slot) != _state_rs->get_attrib(light_slot) ||
03408       !_state_mask.get_bit(light_slot)) {
03409     //PStatTimer timer(_draw_set_state_light_pcollector);
03410     do_issue_light();
03411     _state_mask.set_bit(light_slot);
03412   }
03413 
03414   int stencil_slot = StencilAttrib::get_class_slot();
03415   if (_target_rs->get_attrib(stencil_slot) != _state_rs->get_attrib(stencil_slot) ||
03416       !_state_mask.get_bit(stencil_slot)) {
03417     //PStatTimer timer(_draw_set_state_stencil_pcollector);
03418     do_issue_stencil();
03419     _state_mask.set_bit(stencil_slot);
03420   }
03421      
03422   int fog_slot = FogAttrib::get_class_slot();
03423   if (_target_rs->get_attrib(fog_slot) != _state_rs->get_attrib(fog_slot) ||
03424       !_state_mask.get_bit(fog_slot)) {
03425     //PStatTimer timer(_draw_set_state_fog_pcollector);
03426     do_issue_fog();
03427     _state_mask.set_bit(fog_slot);
03428   }
03429 
03430   int scissor_slot = ScissorAttrib::get_class_slot();
03431   if (_target_rs->get_attrib(scissor_slot) != _state_rs->get_attrib(scissor_slot) ||
03432       !_state_mask.get_bit(scissor_slot)) {
03433     //PStatTimer timer(_draw_set_state_scissor_pcollector);
03434     do_issue_scissor();
03435     _state_mask.set_bit(scissor_slot);
03436   }
03437 
03438   _state_rs = _target_rs;
03439 }
03440 
03441 ////////////////////////////////////////////////////////////////////
03442 //     Function: DXGraphicsStateGuardian9::bind_light
03443 //       Access: Public, Virtual
03444 //  Description: Called the first time a particular light has been
03445 //               bound to a given id within a frame, this should set
03446 //               up the associated hardware light with the light's
03447 //               properties.
03448 ////////////////////////////////////////////////////////////////////
03449 void DXGraphicsStateGuardian9::
03450 bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
03451   // Get the light in "world coordinates" (actually, view
03452   // coordinates).  This means the light in the coordinate space of
03453   // the camera, converted to DX's coordinate system.
03454   CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
03455   const LMatrix4f &light_mat = transform->get_mat();
03456   LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
03457   LPoint3f pos = light_obj->get_point() * rel_mat;
03458 
03459   D3DCOLORVALUE black;
03460   black.r = black.g = black.b = black.a = 0.0f;
03461   D3DLIGHT9 alight;
03462   alight.Type =  D3DLIGHT_POINT;
03463   alight.Diffuse  = get_light_color(light_obj);
03464   alight.Ambient  =  black ;
03465   alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
03466 
03467   // Position needs to specify x, y, z, and w
03468   // w == 1 implies non-infinite position
03469   alight.Position = *(D3DVECTOR *)pos.get_data();
03470 
03471   alight.Range =  __D3DLIGHT_RANGE_MAX;
03472   alight.Falloff =  1.0f;
03473 
03474   const LVecBase3f &att = light_obj->get_attenuation();
03475   alight.Attenuation0 = att[0];
03476   alight.Attenuation1 = att[1];
03477   alight.Attenuation2 = att[2];
03478 
03479   HRESULT hr = _d3d_device->SetLight(light_id, &alight);
03480   if (FAILED(hr)) {
03481     wdxdisplay9_cat.warning()
03482       << "Could not set light properties for " << light
03483       << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n";
03484   }
03485 }
03486 
03487 ////////////////////////////////////////////////////////////////////
03488 //     Function: DXGraphicsStateGuardian9::bind_light
03489 //       Access: Public, Virtual
03490 //  Description: Called the first time a particular light has been
03491 //               bound to a given id within a frame, this should set
03492 //               up the associated hardware light with the light's
03493 //               properties.
03494 ////////////////////////////////////////////////////////////////////
03495 void DXGraphicsStateGuardian9::
03496 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
03497   static PStatCollector _draw_set_state_light_bind_directional_pcollector("Draw:Set State:Light:Bind:Directional");
03498   //PStatTimer timer(_draw_set_state_light_bind_directional_pcollector);
03499 
03500   pair<DirectionalLights::iterator, bool> lookup = _dlights.insert(DirectionalLights::value_type(light, D3DLIGHT9()));
03501   D3DLIGHT9 &fdata = (*lookup.first).second;
03502   if (lookup.second) {
03503     // Get the light in "world coordinates" (actually, view
03504     // coordinates).  This means the light in the coordinate space of
03505     // the camera, converted to DX's coordinate system.
03506     CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
03507     const LMatrix4f &light_mat = transform->get_mat();
03508     LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
03509     LVector3f dir = light_obj->get_direction() * rel_mat;
03510     
03511     D3DCOLORVALUE black;
03512     black.r = black.g = black.b = black.a = 0.0f;
03513     
03514     ZeroMemory(&fdata, sizeof(D3DLIGHT9));
03515     
03516     fdata.Type =  D3DLIGHT_DIRECTIONAL;
03517     fdata.Ambient  =  black ;
03518     fdata.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
03519     
03520     fdata.Direction = *(D3DVECTOR *)dir.get_data();
03521     
03522     fdata.Range =  __D3DLIGHT_RANGE_MAX;
03523     fdata.Falloff =  1.0f;
03524     
03525     fdata.Attenuation0 = 1.0f;       // constant
03526     fdata.Attenuation1 = 0.0f;       // linear
03527     fdata.Attenuation2 = 0.0f;       // quadratic
03528   }
03529 
03530   // We have to reset the Diffuse color at each call, because it might
03531   // have changed independently of the light object itself (due to
03532   // color_scale_via_lighting being in effect).
03533   fdata.Diffuse  = get_light_color(light_obj);
03534 
03535   HRESULT hr = _d3d_device->SetLight(light_id, &fdata);
03536   if (FAILED(hr)) {
03537     wdxdisplay9_cat.warning()
03538       << "Could not set light properties for " << light
03539       << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n";
03540   }
03541 }
03542 
03543 ////////////////////////////////////////////////////////////////////
03544 //     Function: DXGraphicsStateGuardian9::bind_light
03545 //       Access: Public, Virtual
03546 //  Description: Called the first time a particular light has been
03547 //               bound to a given id within a frame, this should set
03548 //               up the associated hardware light with the light's
03549 //               properties.
03550 ////////////////////////////////////////////////////////////////////
03551 void DXGraphicsStateGuardian9::
03552 bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
03553   Lens *lens = light_obj->get_lens();
03554   nassertv(lens != (Lens *)NULL);
03555 
03556   // Get the light in "world coordinates" (actually, view
03557   // coordinates).  This means the light in the coordinate space of
03558   // the camera, converted to DX's coordinate system.
03559   CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
03560   const LMatrix4f &light_mat = transform->get_mat();
03561   LMatrix4f rel_mat = light_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
03562   LPoint3f pos = lens->get_nodal_point() * rel_mat;
03563   LVector3f dir = lens->get_view_vector() * rel_mat;
03564 
03565   D3DCOLORVALUE black;
03566   black.r = black.g = black.b = black.a = 0.0f;
03567 
03568   D3DLIGHT9  alight;
03569   ZeroMemory(&alight, sizeof(D3DLIGHT9));
03570 
03571   alight.Type =  D3DLIGHT_SPOT;
03572   alight.Ambient  =  black ;
03573   alight.Diffuse  = get_light_color(light_obj);
03574   alight.Specular = *(D3DCOLORVALUE *)(light_obj->get_specular_color().get_data());
03575 
03576   alight.Position = *(D3DVECTOR *)pos.get_data();
03577 
03578   alight.Direction = *(D3DVECTOR *)dir.get_data();
03579 
03580   alight.Range =  __D3DLIGHT_RANGE_MAX;
03581 
03582   // I determined this formular empirically.  It seems to mostly
03583   // approximate the OpenGL spotlight equation, for a reasonable range
03584   // of values for FOV.
03585   float fov = lens->get_hfov();
03586   alight.Falloff =  light_obj->get_exponent() * (fov * fov * fov) / 1620000.0f;
03587 
03588   alight.Theta =  0.0f;
03589   alight.Phi = deg_2_rad(fov);
03590 
03591   const LVecBase3f &att = light_obj->get_attenuation();
03592   alight.Attenuation0 = att[0];
03593   alight.Attenuation1 = att[1];
03594   alight.Attenuation2 = att[2];
03595 
03596   HRESULT hr = _d3d_device->SetLight(light_id, &alight);
03597   if (FAILED(hr)) {
03598     wdxdisplay9_cat.warning()
03599       << "Could not set light properties for " << light
03600       << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n";
03601   }
03602 }
03603 
03604 ////////////////////////////////////////////////////////////////////
03605 //     Function: DXGraphicsStateGuardian9::get_index_type
03606 //       Access: Protected, Static
03607 //  Description: Maps from the Geom's internal numeric type symbols
03608 //               to DirectX's.
03609 ////////////////////////////////////////////////////////////////////
03610 D3DFORMAT DXGraphicsStateGuardian9::
03611 get_index_type(Geom::NumericType numeric_type) {
03612   switch (numeric_type) {
03613   case Geom::NT_uint16:
03614     return D3DFMT_INDEX16;
03615 
03616   case Geom::NT_uint32:
03617     return D3DFMT_INDEX32;
03618   }
03619 
03620   dxgsg9_cat.error()
03621     << "Invalid index NumericType value (" << (int)numeric_type << ")\n";
03622   return D3DFMT_INDEX16;
03623 }
03624 
03625 ////////////////////////////////////////////////////////////////////
03626 //     Function: DXGraphicsStateGuardian9::do_issue_material
03627 //       Access: Public, Virtual
03628 //  Description:
03629 ////////////////////////////////////////////////////////////////////
03630 void DXGraphicsStateGuardian9::
03631 do_issue_material() {
03632   static Material empty;
03633   const Material *material;
03634   const MaterialAttrib *target_material = DCAST(MaterialAttrib, _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()));
03635   if (target_material->is_off()) {
03636     material = &empty;
03637   } else {
03638     material = target_material->get_material();
03639   }
03640 
03641   D3DMATERIAL9 cur_material;
03642   cur_material.Diffuse = *(D3DCOLORVALUE *)(material->get_diffuse().get_data());
03643   cur_material.Ambient = *(D3DCOLORVALUE *)(material->get_ambient().get_data());
03644   cur_material.Specular = *(D3DCOLORVALUE *)(material->get_specular().get_data());
03645   cur_material.Emissive = *(D3DCOLORVALUE *)(material->get_emission().get_data());
03646   cur_material.Power = material->get_shininess();
03647 
03648   if (material->has_diffuse()) {
03649     // If the material specifies an diffuse color, use it.
03650     set_render_state(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
03651   } else {
03652     // Otherwise, the diffuse color comes from the object color.
03653     if (_has_material_force_color) {
03654       cur_material.Diffuse = *(D3DCOLORVALUE *)_material_force_color.get_data();
03655       set_render_state(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
03656     } else {
03657       set_render_state(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
03658     }
03659   }
03660   if (material->has_ambient()) {
03661     // If the material specifies an ambient color, use it.
03662     set_render_state(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
03663   } else {
03664     // Otherwise, the ambient color comes from the object color.
03665     if (_has_material_force_color) {
03666       cur_material.Ambient = *(D3DCOLORVALUE *)_material_force_color.get_data();
03667       set_render_state(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
03668     } else {
03669       set_render_state(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1);
03670     }
03671   }
03672 
03673   if (material->has_specular()) {
03674     set_render_state(D3DRS_SPECULARENABLE, TRUE);
03675   } else {
03676     set_render_state(D3DRS_SPECULARENABLE, FALSE);
03677   }
03678 
03679   if (material->get_local()) {
03680     set_render_state(D3DRS_LOCALVIEWER, TRUE);
03681   } else {
03682     set_render_state(D3DRS_LOCALVIEWER, FALSE);
03683   }
03684 
03685   _d3d_device->SetMaterial(&cur_material);
03686 }
03687 
03688 ////////////////////////////////////////////////////////////////////
03689 //     Function: DXGraphicsStateGuardian9::do_issue_texture
03690 //       Access: Protected
03691 //  Description:
03692 ////////////////////////////////////////////////////////////////////
03693 void DXGraphicsStateGuardian9::
03694 do_issue_texture() {
03695   DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
03696 
03697   if (_texture_binding_shader_context==0) {
03698     if (_current_shader_context==0) {
03699       update_standard_texture_bindings();
03700     } else {
03701       disable_standard_texture_bindings();
03702       _current_shader_context->update_shader_texture_bindings(NULL,this);
03703     }
03704   } else {
03705     if (_current_shader_context==0) {
03706       _texture_binding_shader_context->disable_shader_texture_bindings(this);
03707       update_standard_texture_bindings();
03708     } else {
03709       _current_shader_context->
03710         update_shader_texture_bindings(_texture_binding_shader_context,this);
03711     }
03712   }
03713   _texture_binding_shader = _current_shader;
03714   _texture_binding_shader_context = _current_shader_context;
03715 }
03716 
03717 ////////////////////////////////////////////////////////////////////
03718 //     Function: DXGraphicsStateGuardian9::disable_standard_texture_bindings
03719 //       Access: Private
03720 //  Description:
03721 ////////////////////////////////////////////////////////////////////
03722 void DXGraphicsStateGuardian9::
03723 disable_standard_texture_bindings() {
03724   // Disable the texture stages that are no longer used.
03725   for (int i = 0; i < _num_active_texture_stages; i++) {
03726     HRESULT hr;
03727 
03728     hr = _d3d_device -> SetTexture (i, NULL);
03729     if (FAILED (hr)) {
03730       dxgsg9_cat.error()
03731         << "SetTexture ("
03732         << i
03733         << ", NULL) failed "
03734         << D3DERRORSTRING(hr);
03735     }
03736     set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
03737   }
03738 
03739   _num_active_texture_stages = 0;
03740 }
03741 
03742 ////////////////////////////////////////////////////////////////////
03743 //     Function: DXGraphicsStateGuardian9::update_standard_texture_bindings
03744 //       Access: Protected
03745 //  Description:
03746 ////////////////////////////////////////////////////////////////////
03747 void DXGraphicsStateGuardian9::
03748 update_standard_texture_bindings() {
03749   DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
03750 
03751   int num_stages = _target_texture->get_num_on_ff_stages();
03752   int num_old_stages = _max_texture_stages;
03753   if (_state_texture != (TextureAttrib *)NULL) {
03754     num_old_stages = _state_texture->get_num_on_ff_stages();
03755   }
03756 
03757   nassertv(num_stages <= _max_texture_stages &&
03758            _num_active_texture_stages <= _max_texture_stages);
03759 
03760   _texture_involves_color_scale = false;
03761 
03762   // We have to match up the texcoord stage index to the order written
03763   // out by the DXGeomMunger.  This means the texcoord names are
03764   // written in the order indicated by the TextureAttrib.
03765 
03766   int si;
03767   for (si = 0; si < num_stages; si++) {
03768     TextureStage *stage = _target_texture->get_on_ff_stage(si);
03769     int texcoord_index = _target_texture->get_ff_tc_index(si);
03770 
03771     Texture *texture = _target_texture->get_on_texture(stage);
03772     nassertv(texture != (Texture *)NULL);
03773 
03774     // We always reissue every stage in DX, just in case the texcoord
03775     // index or texgen mode or some other property has changed.
03776     TextureContext *tc = texture->prepare_now(_prepared_objects, this);
03777     apply_texture(si, tc);
03778     set_texture_blend_mode(si, stage);
03779 
03780     int texcoord_dimensions = 2;
03781 
03782     CPT(TransformState) tex_mat = TransformState::make_identity();
03783     const TexMatrixAttrib *target_tex_matrix = DCAST(TexMatrixAttrib, _target_rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
03784     if (target_tex_matrix->has_stage(stage)) {
03785       tex_mat = target_tex_matrix->get_transform(stage);
03786     }
03787 
03788     // Issue the texgen mode.
03789     TexGenAttrib::Mode mode = _target_tex_gen->get_mode(stage);
03790     bool any_point_sprite = false;
03791 
03792     switch (mode) {
03793     case TexGenAttrib::M_off:
03794     case TexGenAttrib::M_light_vector:
03795       set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX, texcoord_index);
03796       break;
03797 
03798     case TexGenAttrib::M_eye_sphere_map:
03799       {
03800         set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
03801                                 texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
03802         // This texture matrix, applied on top of the texcoord
03803         // computed by D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR,
03804         // approximates the effect produced by OpenGL's GL_SPHERE_MAP.
03805         static CPT(TransformState) sphere_map =
03806           TransformState::make_mat(LMatrix4f(0.33f, 0.0f, 0.0f, 0.0f,
03807                                              0.0f, 0.33f, 0.0f, 0.0f,
03808                                              0.0f, 0.0f, 1.0f, 0.0f,
03809                                              0.5f, 0.5f, 0.0f, 1.0f));
03810         tex_mat = tex_mat->compose(sphere_map);
03811         texcoord_dimensions = 3;
03812       }
03813       break;
03814 
03815     case TexGenAttrib::M_world_cube_map:
03816       // To achieve world reflection vector, we must transform camera
03817       // coordinates to world coordinates; i.e. apply the camera
03818       // transform.  In the case of a vector, we should not apply the
03819       // pos component of the transform.
03820       {
03821         set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
03822                                 texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
03823         texcoord_dimensions = 3;
03824         CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
03825         tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3f::zero()));
03826       }
03827       break;
03828 
03829     case TexGenAttrib::M_eye_cube_map:
03830       set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
03831                               texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
03832       tex_mat = tex_mat->compose(_inv_cs_transform);
03833       texcoord_dimensions = 3;
03834       break;
03835 
03836     case TexGenAttrib::M_world_normal:
03837       // To achieve world normal, we must transform camera coordinates
03838       // to world coordinates; i.e. apply the camera transform.  In
03839       // the case of a normal, we should not apply the pos component
03840       // of the transform.
03841       {
03842         set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
03843                                 texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
03844         texcoord_dimensions = 3;
03845         CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
03846         tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3f::zero()));
03847       }
03848       break;
03849 
03850     case TexGenAttrib::M_eye_normal:
03851       set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
03852                               texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
03853       texcoord_dimensions = 3;
03854       tex_mat = tex_mat->compose(_inv_cs_transform);
03855       break;
03856 
03857     case TexGenAttrib::M_world_position:
03858       // To achieve world position, we must transform camera
03859       // coordinates to world coordinates; i.e. apply the
03860       // camera transform.
03861       {
03862         set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
03863                                 texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
03864         texcoord_dimensions = 3;
03865         CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
03866         tex_mat = tex_mat->compose(camera_transform);
03867       }
03868       break;
03869 
03870     case TexGenAttrib::M_eye_position:
03871       set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
03872                               texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
03873       texcoord_dimensions = 3;
03874       tex_mat = tex_mat->compose(_inv_cs_transform);
03875       break;
03876 
03877     case TexGenAttrib::M_point_sprite:
03878       set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX, texcoord_index);
03879       any_point_sprite = true;
03880       break;
03881 
03882     case TexGenAttrib::M_constant:
03883       // To generate a constant UV(w) coordinate everywhere, we use
03884       // CAMERASPACEPOSITION coordinates, but we construct a special
03885       // matrix that flattens the existing values to zero and then
03886       // adds our desired value.
03887 
03888       // The only reason we need to specify CAMERASPACEPOSITION at
03889       // all, instead of using whatever texture coordinates (if any)
03890       // happen to be on the vertices, is because we need to guarantee
03891       // that there are 3-d texture coordinates, because of the
03892       // 3-component texture coordinate in get_constant_value().
03893       {
03894         set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
03895                                 texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
03896         texcoord_dimensions = 3;
03897 
03898         const TexCoord3f &v = _target_tex_gen->get_constant_value(stage);
03899         CPT(TransformState) squash =
03900           TransformState::make_pos_hpr_scale(v, LVecBase3f::zero(),
03901                                              LVecBase3f::zero());
03902         tex_mat = tex_mat->compose(squash);
03903       }
03904       break;
03905     }
03906 
03907     set_render_state(D3DRS_POINTSPRITEENABLE, any_point_sprite);
03908 
03909     if (!tex_mat->is_identity()) {
03910       if (/*tex_mat->is_2d() &&*/ texcoord_dimensions <= 2) {
03911         // For 2-d texture coordinates, we have to reorder the matrix.
03912         LMatrix4f m = tex_mat->get_mat();
03913         m.set(m(0, 0), m(0, 1), m(0, 3), 0.0f,
03914               m(1, 0), m(1, 1), m(1, 3), 0.0f,
03915               m(3, 0), m(3, 1), m(3, 3), 0.0f,
03916               0.0f, 0.0f, 0.0f, 1.0f);
03917         _d3d_device->SetTransform(get_tex_mat_sym(si), (D3DMATRIX *)m.get_data());
03918         set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
03919                                 D3DTTFF_COUNT2);
03920       } else {
03921         LMatrix4f m = tex_mat->get_mat();
03922         _d3d_device->SetTransform(get_tex_mat_sym(si), (D3DMATRIX *)m.get_data());
03923         DWORD transform_flags = texcoord_dimensions;
03924         if (m.get_col(3) != LVecBase4f(0.0f, 0.0f, 0.0f, 1.0f)) {
03925           // If we have a projected texture matrix, we also need to
03926           // set D3DTTFF_COUNT4.
03927           transform_flags = D3DTTFF_COUNT4 | D3DTTFF_PROJECTED;
03928         }
03929         set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
03930                                 transform_flags);
03931       }
03932 
03933     } else {
03934       set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
03935                               D3DTTFF_DISABLE);
03936       // For some reason, "disabling" texture coordinate transforms
03937       // doesn't seem to be sufficient.  We'll load an identity matrix
03938       // to underscore the point.
03939       _d3d_device->SetTransform(get_tex_mat_sym(si), &_d3d_ident_mat);
03940     }
03941   }
03942 
03943   // Disable the texture stages that are no longer used.
03944   for (si = num_stages; si < _num_active_texture_stages; si++) {
03945     set_texture_stage_state(si, D3DTSS_COLOROP, D3DTOP_DISABLE);
03946     _d3d_device->SetTexture(si, NULL);
03947   }
03948 
03949   // Save the count of texture stages for next time.
03950   _num_active_texture_stages = num_stages;
03951 }
03952 
03953 ////////////////////////////////////////////////////////////////////
03954 //     Function: DXGraphicsStateGuardian9::do_issue_blending
03955 //       Access: Protected, Virtual
03956 //  Description: Called after any of the things that might change
03957 //               blending state have changed, this function is
03958 //               responsible for setting the appropriate color
03959 //               blending mode based on the current properties.
03960 ////////////////////////////////////////////////////////////////////
03961 void DXGraphicsStateGuardian9::
03962 do_issue_blending() {
03963   // Handle the color_write attrib.  If color_write is off, then
03964   // all the other blending-related stuff doesn't matter.  If the
03965   // device doesn't support color-write, we use blending tricks
03966   // to effectively disable color write.
03967   const ColorWriteAttrib *target_color_write = DCAST(ColorWriteAttrib, _target_rs->get_attrib_def(ColorWriteAttrib::get_class_slot()));
03968   unsigned int color_channels =
03969     target_color_write->get_channels() & _color_write_mask;
03970   if (_target_shader->get_flag(ShaderAttrib::F_disable_alpha_write)) {
03971     color_channels &= ~(ColorWriteAttrib::C_alpha);
03972   }
03973   if (color_channels == ColorWriteAttrib::C_off) {
03974     if (_screen->_can_direct_disable_color_writes) {
03975       set_render_state(D3DRS_ALPHABLENDENABLE, FALSE);
03976       set_render_state(D3DRS_COLORWRITEENABLE, (DWORD)0x0);
03977     } else {
03978       set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
03979       set_render_state(D3DRS_SRCBLEND, D3DBLEND_ZERO);
03980       set_render_state(D3DRS_DESTBLEND, D3DBLEND_ONE);
03981     }
03982     return;
03983   } else {
03984     if (_screen->_can_direct_disable_color_writes) {
03985       set_render_state(D3DRS_COLORWRITEENABLE, color_channels);
03986     }
03987   }
03988 
03989   const ColorBlendAttrib *target_color_blend = DCAST(ColorBlendAttrib, _target_rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
03990   CPT(ColorBlendAttrib) color_blend = target_color_blend;
03991   ColorBlendAttrib::Mode color_blend_mode = target_color_blend->get_mode();
03992 
03993   const TransparencyAttrib *target_transparency = DCAST(TransparencyAttrib, _target_rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
03994   TransparencyAttrib::Mode transparency_mode = target_transparency->get_mode();
03995 
03996   // Is there a color blend set?
03997   if (color_blend_mode != ColorBlendAttrib::M_none) {
03998     set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
03999 
04000     switch (color_blend_mode) {
04001     case ColorBlendAttrib::M_add:
04002       set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
04003       break;
04004 
04005     case ColorBlendAttrib::M_subtract:
04006       set_render_state(D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
04007       break;
04008 
04009     case ColorBlendAttrib::M_inv_subtract:
04010       set_render_state(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT);
04011       break;
04012 
04013     case ColorBlendAttrib::M_min:
04014       set_render_state(D3DRS_BLENDOP, D3DBLENDOP_MIN);
04015       break;
04016 
04017     case ColorBlendAttrib::M_max:
04018       set_render_state(D3DRS_BLENDOP, D3DBLENDOP_MAX);
04019       break;
04020     }
04021 
04022     set_render_state(D3DRS_SRCBLEND,
04023         get_blend_func(color_blend->get_operand_a()));
04024     set_render_state(D3DRS_DESTBLEND,
04025         get_blend_func(color_blend->get_operand_b()));
04026     return;
04027   }
04028 
04029   // No color blend; is there a transparency set?
04030   switch (transparency_mode) {
04031   case TransparencyAttrib::M_none:
04032   case TransparencyAttrib::M_binary:
04033     break;
04034 
04035   case TransparencyAttrib::M_alpha:
04036   case TransparencyAttrib::M_multisample:
04037   case TransparencyAttrib::M_multisample_mask:
04038   case TransparencyAttrib::M_dual:
04039     set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
04040     set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
04041     set_render_state(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
04042     set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
04043     return;
04044 
04045   default:
04046     dxgsg9_cat.error()
04047       << "invalid transparency mode " << (int)transparency_mode << endl;
04048     break;
04049   }
04050 
04051   // Nothing's set, so disable blending.
04052   set_render_state(D3DRS_ALPHABLENDENABLE, FALSE);
04053 }
04054 
04055 ////////////////////////////////////////////////////////////////////
04056 //     Function: DXGraphicsStateGuardian9::reissue_transforms
04057 //       Access: Protected, Virtual
04058 //  Description: Called by clear_state_and_transform() to ensure that
04059 //               the current modelview and projection matrices are
04060 //               properly loaded in the graphics state, after a
04061 //               callback might have mucked them up.
04062 ////////////////////////////////////////////////////////////////////
04063 void DXGraphicsStateGuardian9::
04064 reissue_transforms() {
04065   prepare_lens();
04066   do_issue_transform();
04067 }
04068 
04069 ////////////////////////////////////////////////////////////////////
04070 //     Function: DXGraphicsStateGuardian9::enable_lighting
04071 //       Access: Protected, Virtual
04072 //  Description: Intended to be overridden by a derived class to
04073 //               enable or disable the use of lighting overall.  This
04074 //               is called by issue_light() according to whether any
04075 //               lights are in use or not.
04076 ////////////////////////////////////////////////////////////////////
04077 void DXGraphicsStateGuardian9::
04078 enable_lighting(bool enable) {
04079   set_render_state(D3DRS_LIGHTING, (DWORD)enable);
04080 }
04081 
04082 ////////////////////////////////////////////////////////////////////
04083 //     Function: DXGraphicsStateGuardian9::set_ambient_light
04084 //       Access: Protected, Virtual
04085 //  Description: Intended to be overridden by a derived class to
04086 //               indicate the color of the ambient light that should
04087 //               be in effect.  This is called by issue_light() after
04088 //               all other lights have been enabled or disabled.
04089 ////////////////////////////////////////////////////////////////////
04090 void DXGraphicsStateGuardian9::
04091 set_ambient_light(const Colorf &color) {
04092   Colorf c = color;
04093   c.set(c[0] * _light_color_scale[0],
04094         c[1] * _light_color_scale[1],
04095         c[2] * _light_color_scale[2],
04096         c[3] * _light_color_scale[3]);
04097 
04098   set_render_state(D3DRS_AMBIENT, Colorf_to_D3DCOLOR(c));
04099 }
04100 
04101 ////////////////////////////////////////////////////////////////////
04102 //     Function: DXGraphicsStateGuardian9::enable_light
04103 //       Access: Protected, Virtual
04104 //  Description: Intended to be overridden by a derived class to
04105 //               enable the indicated light id.  A specific Light will
04106 //               already have been bound to this id via bind_light().
04107 ////////////////////////////////////////////////////////////////////
04108 void DXGraphicsStateGuardian9::
04109 enable_light(int light_id, bool enable) {
04110   HRESULT hr = _d3d_device->LightEnable(light_id, enable);
04111 
04112   if (FAILED(hr)) {
04113     wdxdisplay9_cat.warning()
04114       << "Could not enable light " << light_id << ": "
04115       << D3DERRORSTRING(hr) << "\n";
04116   }
04117 }
04118 
04119 ////////////////////////////////////////////////////////////////////
04120 //     Function: DXGraphicsStateGuardian9::enable_clip_plane
04121 //       Access: Protected, Virtual
04122 //  Description: Intended to be overridden by a derived class to
04123 //               enable the indicated clip_plane id.  A specific
04124 //               PlaneNode will already have been bound to this id via
04125 //               bind_clip_plane().
04126 ////////////////////////////////////////////////////////////////////
04127 void DXGraphicsStateGuardian9::
04128 enable_clip_plane(int plane_id, bool enable) {
04129   if (enable) {
04130     _clip_plane_bits |= ((DWORD)1 << plane_id);
04131   } else {
04132     _clip_plane_bits &= ~((DWORD)1 << plane_id);
04133   }
04134   set_render_state(D3DRS_CLIPPLANEENABLE, _clip_plane_bits);
04135 }
04136 
04137 ////////////////////////////////////////////////////////////////////
04138 //     Function: DXGraphicsStateGuardian9::bind_clip_plane
04139 //       Access: Protected, Virtual
04140 //  Description: Called the first time a particular clip_plane has been
04141 //               bound to a given id within a frame, this should set
04142 //               up the associated hardware clip_plane with the clip_plane's
04143 //               properties.
04144 ////////////////////////////////////////////////////////////////////
04145 void DXGraphicsStateGuardian9::
04146 bind_clip_plane(const NodePath &plane, int plane_id) {
04147   // Get the plane in "world coordinates" (actually, view
04148   // coordinates).  This means the plane in the coordinate space of
04149   // the camera, converted to DX's coordinate system.
04150   CPT(TransformState) transform = plane.get_transform(_scene_setup->get_camera_path());
04151   const LMatrix4f &plane_mat = transform->get_mat();
04152   LMatrix4f rel_mat = plane_mat * LMatrix4f::convert_mat(CS_yup_left, CS_default);
04153   const PlaneNode *plane_node;
04154   DCAST_INTO_V(plane_node, plane.node());
04155   Planef world_plane = plane_node->get_plane() * rel_mat;
04156 
04157   HRESULT hr = _d3d_device->SetClipPlane(plane_id, world_plane.get_data());
04158   if (FAILED(hr)) {
04159     wdxdisplay9_cat.warning()
04160       << "Could not set clip plane for " << plane
04161       << " to id " << plane_id << ": " << D3DERRORSTRING(hr) << "\n";
04162   }
04163 }
04164 
04165 ////////////////////////////////////////////////////////////////////
04166 //     Function: DXGraphicsStateGuardian9::close_gsg
04167 //       Access: Protected, Virtual
04168 //  Description: This is called by the associated GraphicsWindow when
04169 //               close_window() is called.  It should null out the
04170 //               _win pointer and possibly free any open resources
04171 //               associated with the GSG.
04172 ////////////////////////////////////////////////////////////////////
04173 void DXGraphicsStateGuardian9::
04174 close_gsg() {
04175   GraphicsStateGuardian::close_gsg();
04176 
04177   if (dxgsg9_cat.is_debug()) {
04178     dxgsg9_cat.debug()
04179       << "Closing GSG, prepared_objects count = " 
04180       << _prepared_objects->get_ref_count() << "\n";
04181   }
04182 
04183   // Unlike in OpenGL, in DX9 it is safe to try to explicitly release
04184   // any textures here.  And it may even be a good idea.
04185   if (_prepared_objects->get_ref_count() == 1) {
04186     release_all();
04187 
04188     // Now we need to actually delete all of the objects we just
04189     // released.
04190     Thread *current_thread = Thread::get_current_thread();
04191     _prepared_objects->begin_frame(this, current_thread);
04192     _prepared_objects->end_frame(current_thread);
04193   }
04194 }
04195 
04196 ////////////////////////////////////////////////////////////////////
04197 //     Function: DXGraphicsStateGuardian9::free_nondx_resources
04198 //       Access: Public
04199 //  Description: Frees some memory that was explicitly allocated
04200 //               within the dxgsg.
04201 ////////////////////////////////////////////////////////////////////
04202 void DXGraphicsStateGuardian9::
04203 free_nondx_resources() {
04204 }
04205 
04206 ////////////////////////////////////////////////////////////////////
04207 //     Function: DXGraphicsStateGuardian9::free_d3d_device
04208 //       Access: Public
04209 //  Description: setup for re-calling dx_init(), this is not the final
04210 //               exit cleanup routine (see dx_cleanup)
04211 ////////////////////////////////////////////////////////////////////
04212 void DXGraphicsStateGuardian9::
04213 free_d3d_device() {
04214   // don't want a full reset of gsg, just a state clear
04215   _state_rs = RenderState::make_empty();
04216   _state_mask.clear();
04217 
04218   // want gsg to pass all state settings through
04219 
04220   _dx_is_ready = false;
04221 
04222   if (_d3d_device != NULL) {
04223     for(int i = 0; i < D3D_MAXTEXTURESTAGES; i++) {
04224       // d3d should release this stuff internally anyway, but whatever
04225       _d3d_device->SetTexture(i, NULL);
04226     }
04227   }
04228 
04229   release_all();
04230 
04231   if (_d3d_device != NULL) {
04232     RELEASE(_d3d_device, dxgsg9, "d3dDevice", RELEASE_DOWN_TO_ZERO);
04233   }
04234 
04235   free_nondx_resources();
04236 
04237   // obviously we don't release ID3D9, just ID3DDevice9
04238 }
04239 
04240 ////////////////////////////////////////////////////////////////////
04241 //     Function: DXGraphicsStateGuardian9::set_draw_buffer
04242 //       Access: Protected
04243 //  Description: Sets up the glDrawBuffer to render into the buffer
04244 //               indicated by the RenderBuffer object.  This only sets
04245 //               up the color bits; it does not affect the depth,
04246 //               stencil, accum layers.
04247 ////////////////////////////////////////////////////////////////////
04248 void DXGraphicsStateGuardian9::
04249 set_draw_buffer(const RenderBuffer &rb) {
04250   dxgsg9_cat.fatal() << "DX set_draw_buffer unimplemented!!!";
04251   return;
04252 }
04253 
04254 ////////////////////////////////////////////////////////////////////
04255 //     Function: DXGraphicsStateGuardian9::set_read_buffer
04256 //       Access: Protected
04257 //  Description: Vestigial analog of glReadBuffer
04258 ////////////////////////////////////////////////////////////////////
04259 void DXGraphicsStateGuardian9::
04260 set_read_buffer(const RenderBuffer &rb) {
04261   if (rb._buffer_type & RenderBuffer::T_front) {
04262     _cur_read_pixel_buffer = RenderBuffer::T_front;
04263   } else  if (rb._buffer_type & RenderBuffer::T_back) {
04264     _cur_read_pixel_buffer = RenderBuffer::T_back;      
04265   } else  if (rb._buffer_type & RenderBuffer::T_aux_rgba_ALL) {
04266     _cur_read_pixel_buffer = RenderBuffer::T_back;      
04267   } else {
04268     dxgsg9_cat.error() << "Invalid or unimplemented Argument to set_read_buffer!\n";
04269   }
04270   return;
04271 }
04272 
04273 ////////////////////////////////////////////////////////////////////
04274 //     Function: DXGraphicsStateGuardian9::do_auto_rescale_normal
04275 //       Access: Protected
04276 //  Description: Issues the appropriate DX commands to either rescale
04277 //               or normalize the normals according to the current
04278 //               transform.
04279 ////////////////////////////////////////////////////////////////////
04280 void DXGraphicsStateGuardian9::
04281 do_auto_rescale_normal() {
04282   if (_internal_transform->has_identity_scale()) {
04283     // If there's no scale, don't normalize anything.
04284     set_render_state(D3DRS_NORMALIZENORMALS, false);
04285   } else {
04286     // If there is a scale, turn on normalization.
04287     set_render_state(D3DRS_NORMALIZENORMALS, true);
04288   }
04289 }
04290 
04291 ////////////////////////////////////////////////////////////////////
04292 //     Function: DXGraphicsStateGuardian9::get_light_color
04293 //       Access: Public
04294 //  Description: Returns the array of four floats that should be
04295 //               issued as the light's color, as scaled by the current
04296 //               value of _light_color_scale, in the case of
04297 //               color_scale_via_lighting.
04298 ////////////////////////////////////////////////////////////////////
04299 const D3DCOLORVALUE &DXGraphicsStateGuardian9::
04300 get_light_color(Light *light) const {
04301   static Colorf c;
04302   c = light->get_color();
04303   c.set(c[0] * _light_color_scale[0],
04304         c[1] * _light_color_scale[1],
04305         c[2] * _light_color_scale[2],
04306         c[3] * _light_color_scale[3]);
04307   return *(D3DCOLORVALUE *)c.get_data();
04308 }
04309 
04310 ////////////////////////////////////////////////////////////////////
04311 //     Function: DXGraphicsStateGuardian9::get_blend_func
04312 //       Access: Protected, Static
04313 //  Description: Maps from ColorBlendAttrib::Operand to D3DBLEND
04314 //               value.
04315 ////////////////////////////////////////////////////////////////////
04316 D3DBLEND DXGraphicsStateGuardian9::
04317 get_blend_func(ColorBlendAttrib::Operand operand) {
04318   switch (operand) {
04319   case ColorBlendAttrib::O_zero:
04320     return D3DBLEND_ZERO;
04321 
04322   case ColorBlendAttrib::O_one:
04323     return D3DBLEND_ONE;
04324 
04325   case ColorBlendAttrib::O_incoming_color:
04326     return D3DBLEND_SRCCOLOR;
04327 
04328   case ColorBlendAttrib::O_one_minus_incoming_color:
04329     return D3DBLEND_INVSRCCOLOR;
04330 
04331   case ColorBlendAttrib::O_fbuffer_color:
04332     return D3DBLEND_DESTCOLOR;
04333 
04334   case ColorBlendAttrib::O_one_minus_fbuffer_color:
04335     return D3DBLEND_INVDESTCOLOR;
04336 
04337   case ColorBlendAttrib::O_incoming_alpha:
04338     return D3DBLEND_SRCALPHA;
04339 
04340   case ColorBlendAttrib::O_one_minus_incoming_alpha:
04341     return D3DBLEND_INVSRCALPHA;
04342 
04343   case ColorBlendAttrib::O_fbuffer_alpha:
04344     return D3DBLEND_DESTALPHA;
04345 
04346   case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
04347     return D3DBLEND_INVDESTALPHA;
04348 
04349   case ColorBlendAttrib::O_constant_color:
04350     // Not supported by DX.
04351     return D3DBLEND_SRCCOLOR;
04352 
04353   case ColorBlendAttrib::O_one_minus_constant_color:
04354     // Not supported by DX.
04355     return D3DBLEND_INVSRCCOLOR;
04356 
04357   case ColorBlendAttrib::O_constant_alpha:
04358     // Not supported by DX.
04359     return D3DBLEND_SRCALPHA;
04360 
04361   case ColorBlendAttrib::O_one_minus_constant_alpha:
04362     // Not supported by DX.
04363     return D3DBLEND_INVSRCALPHA;
04364 
04365   case ColorBlendAttrib::O_incoming_color_saturate:
04366     return D3DBLEND_SRCALPHASAT;
04367   }
04368 
04369   dxgsg9_cat.error()
04370     << "Unknown color blend operand " << (int)operand << endl;
04371   return D3DBLEND_ZERO;
04372 }
04373 
04374 ////////////////////////////////////////////////////////////////////
04375 //     Function: DXGraphicsStateGuardian9::report_texmgr_stats
04376 //       Access: Protected
04377 //  Description: Reports the DX texture manager's activity to PStats.
04378 ////////////////////////////////////////////////////////////////////
04379 void DXGraphicsStateGuardian9::
04380 report_texmgr_stats() {
04381 
04382 #ifdef DO_PSTATS
04383   HRESULT hr;
04384   hr = 0;
04385 
04386 #ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM
04387   DWORD dwTexTotal, dwTexFree, dwVidTotal, dwVidFree;
04388 
04389   if (_total_texmem_pcollector.is_active()) {
04390     DDSCAPS2 ddsCaps;
04391 
04392     ZeroMemory(&ddsCaps, sizeof(ddsCaps));
04393 
04394     ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
04395     if (FAILED( hr = _d3d_device->GetAvailableVidMem(&ddsCaps, &dwVidTotal, &dwVidFree))) {
04396       dxgsg9_cat.fatal() << "report_texmgr GetAvailableVidMem for VIDMEM failed : result = " << D3DERRORSTRING(hr);
04397       throw_event("panda3d-render-error");
04398       return;
04399     }
04400 
04401     ddsCaps.dwCaps = DDSCAPS_TEXTURE;
04402     if (FAILED( hr = _d3d_device->GetAvailableVidMem(&ddsCaps, &dwTexTotal, &dwTexFree))) {
04403       dxgsg9_cat.fatal() << "report_texmgr GetAvailableVidMem for TEXTURE failed : result = " << D3DERRORSTRING(hr);
04404       throw_event("panda3d-render-error");
04405       return;
04406     }
04407   }
04408 #endif  // TEXMGRSTATS_USES_GETAVAILVIDMEM
04409 
04410   D3DDEVINFO_RESOURCEMANAGER all_resource_stats;
04411   ZeroMemory(&all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER));
04412 
04413 /* ***** DX9, GetInfo ( ) NOT IN DX9 */
04414 /*
04415   if (!_tex_stats_retrieval_impossible) {
04416     hr = _d3d_device->GetInfo(D3DDEVINFOID_RESOURCEMANAGER, &all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER));
04417     if (hr != D3D_OK) {
04418       if (hr == S_FALSE) {
04419         static int PrintedMsg = 2;
04420         if (PrintedMsg>0) {
04421           if (dxgsg9_cat.is_debug()) {
04422             dxgsg9_cat.debug()
04423               << "texstats GetInfo() requires debug DX DLLs to be installed!!\n";
04424           }
04425           ZeroMemory(&all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER));
04426           _tex_stats_retrieval_impossible = true;
04427         }
04428       } else {
04429         dxgsg9_cat.error() << "GetInfo(RESOURCEMANAGER) failed to get tex stats: result = " << D3DERRORSTRING(hr);
04430         return;
04431       }
04432     }
04433   }
04434 */
04435 
04436   // Tell PStats about the state of the texture memory.
04437 
04438   if (_texmgrmem_total_pcollector.is_active()) {
04439     // report zero if no debug dlls, to signal this info is invalid
04440     _texmgrmem_total_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].TotalBytes);
04441     _texmgrmem_resident_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].WorkingSetBytes);
04442   }
04443 #ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM
04444   if (_total_texmem_pcollector.is_active()) {
04445     _total_texmem_pcollector.set_level(dwTexTotal);
04446     _used_texmem_pcollector.set_level(dwTexTotal - dwTexFree);
04447   }
04448 #endif  // TEXMGRSTATS_USES_GETAVAILVIDMEM
04449 #endif  // DO_PSTATS
04450 }
04451 
04452 ////////////////////////////////////////////////////////////////////
04453 //     Function: DXGraphicsStateGuardian9::set_context
04454 //       Access: Protected
04455 //  Description:
04456 ////////////////////////////////////////////////////////////////////
04457 void DXGraphicsStateGuardian9::
04458 set_context(DXScreenData *new_context) {
04459   nassertv(new_context != NULL);
04460   _screen = new_context;
04461   _d3d_device = _screen->_d3d_device;   //copy this one field for speed of deref
04462   _swap_chain = _screen->_swap_chain;   //copy this one field for speed of deref
04463 
04464   _screen->_dxgsg9 = this;
04465   set_cg_device(_d3d_device);
04466 }
04467 
04468 ////////////////////////////////////////////////////////////////////
04469 //     Function: DXGraphicsStateGuardian9::set_render_target
04470 //       Access: Protected
04471 //  Description: Set render target to the backbuffer of current swap
04472 //               chain.
04473 ////////////////////////////////////////////////////////////////////
04474 void DXGraphicsStateGuardian9::
04475 set_render_target() {
04476   if (_d3d_device == NULL) {
04477     return;
04478   }
04479 
04480   LPDIRECT3DSURFACE9 back = NULL, stencil = NULL;
04481 
04482   UINT swap_chain;
04483 
04484   /* ***** DX9 swap_chain ??? */
04485   swap_chain = 0;
04486 
04487   if (!_swap_chain)  //maybe fullscreen mode or main/single window
04488     _d3d_device->GetBackBuffer(swap_chain, 0, D3DBACKBUFFER_TYPE_MONO, &back);
04489   else
04490     _swap_chain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &back);
04491 
04492   //wdxdisplay9_cat.debug() << "swapchain is " << _swap_chain << "\n";
04493   //wdxdisplay9_cat.debug() << "back buffer is " << back << "\n";
04494 
04495   _d3d_device->GetDepthStencilSurface(&stencil);
04496 
04497 //  _d3d_device->SetRenderTarget(back, stencil);
04498   DWORD render_target_index;
04499   render_target_index = 0;
04500   _d3d_device->SetRenderTarget(render_target_index, back);
04501 
04502   if (back) {
04503     back->Release();
04504   }
04505   if (stencil) {
04506     stencil->Release();
04507   }
04508 }
04509 
04510 ////////////////////////////////////////////////////////////////////
04511 //     Function: DXGraphicsStateGuardian9::set_texture_blend_mode
04512 //       Access: Protected
04513 //  Description:
04514 ////////////////////////////////////////////////////////////////////
04515 void DXGraphicsStateGuardian9::
04516 set_texture_blend_mode(int i, const TextureStage *stage) {
04517   switch (stage->get_mode()) {
04518   case TextureStage::M_modulate:
04519   case TextureStage::M_modulate_glow:
04520   case TextureStage::M_modulate_gloss:
04521     // emulates GL_MODULATE glTexEnv mode
04522     set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_MODULATE);
04523     set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
04524     set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
04525     set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
04526     set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
04527     set_texture_stage_state(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
04528     break;
04529 
04530   case TextureStage::M_decal:
04531     // emulates GL_DECAL glTexEnv mode
04532     set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA);
04533     set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
04534     set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
04535 
04536     set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
04537     set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
04538     break;
04539 
04540   case TextureStage::M_replace:
04541     set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
04542     set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
04543 
04544     set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
04545     set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
04546     break;
04547 
04548   case TextureStage::M_add:
04549     set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_ADD);
04550     set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
04551     set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
04552 
04553     set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
04554     set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
04555     set_texture_stage_state(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
04556     break;
04557 
04558   case TextureStage::M_blend:
04559   case TextureStage::M_blend_color_scale:
04560     {
04561       set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_LERP);
04562       set_texture_stage_state(i, D3DTSS_COLORARG0, D3DTA_TEXTURE);
04563       set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
04564       set_texture_stage_state(i, D3DTSS_COLORARG1, _constant_color_operand);
04565 
04566       set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
04567       set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
04568       set_texture_stage_state(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
04569     }
04570     break;
04571 
04572   case TextureStage::M_combine:
04573     // M_combine mode begins a collection of more sophisticated modes,
04574     // which match up more closely with DirectX's built-in modes.
04575     set_texture_stage_state
04576       (i, D3DTSS_COLOROP,
04577        get_texture_operation(stage->get_combine_rgb_mode(),
04578                              stage->get_rgb_scale()));
04579 
04580     switch (stage->get_num_combine_rgb_operands()) {
04581     case 3:
04582       set_texture_stage_state
04583         (i, D3DTSS_COLORARG0,
04584          get_texture_argument(stage->get_combine_rgb_source2(),
04585                               stage->get_combine_rgb_operand2()));
04586       // fall through
04587 
04588     case 2:
04589       set_texture_stage_state
04590         (i, D3DTSS_COLORARG2,
04591          get_texture_argument(stage->get_combine_rgb_source1(),
04592                               stage->get_combine_rgb_operand1()));
04593       // fall through
04594 
04595     case 1:
04596       set_texture_stage_state
04597         (i, D3DTSS_COLORARG1,
04598          get_texture_argument(stage->get_combine_rgb_source0(),
04599                               stage->get_combine_rgb_operand0()));
04600       // fall through
04601 
04602     default:
04603       break;
04604     }
04605 
04606     set_texture_stage_state
04607       (i, D3DTSS_ALPHAOP,
04608        get_texture_operation(stage->get_combine_alpha_mode(),
04609                              stage->get_alpha_scale()));
04610 
04611     switch (stage->get_num_combine_alpha_operands()) {
04612     case 3:
04613       set_texture_stage_state
04614         (i, D3DTSS_ALPHAARG0,
04615          get_texture_argument(stage->get_combine_alpha_source2(),
04616                               stage->get_combine_alpha_operand2()));
04617       // fall through
04618 
04619     case 2:
04620       set_texture_stage_state
04621         (i, D3DTSS_ALPHAARG2,
04622          get_texture_argument(stage->get_combine_alpha_source1(),
04623                               stage->get_combine_alpha_operand1()));
04624       // fall through
04625 
04626     case 1:
04627       set_texture_stage_state
04628         (i, D3DTSS_ALPHAARG1,
04629          get_texture_argument(stage->get_combine_alpha_source0(),
04630                               stage->get_combine_alpha_operand0()));
04631       // fall through
04632 
04633     default:
04634       break;
04635     }
04636     break;
04637 
04638   default:
04639     dxgsg9_cat.error()
04640       << "Unknown texture mode " << (int)stage->get_mode() << endl;
04641     break;
04642   }
04643 
04644   if (stage->get_saved_result()) {
04645     set_texture_stage_state(i, D3DTSS_RESULTARG, D3DTA_TEMP);
04646   } else {
04647     set_texture_stage_state(i, D3DTSS_RESULTARG, D3DTA_CURRENT);
04648   }
04649 
04650   if (stage->uses_color()) {
04651     // Set up the constant color for this stage.
04652 
04653     D3DCOLOR constant_color;
04654     if (stage->involves_color_scale() && _color_scale_enabled) {
04655       Colorf color = stage->get_color();
04656       color.set(color[0] * _current_color_scale[0],
04657                 color[1] * _current_color_scale[1],
04658                 color[2] * _current_color_scale[2],
04659                 color[3] * _current_color_scale[3]);
04660       _texture_involves_color_scale = true;
04661       constant_color = Colorf_to_D3DCOLOR(color);
04662     } else {
04663       constant_color = Colorf_to_D3DCOLOR(stage->get_color());
04664     }
04665     if (_supports_texture_constant_color) {
04666       set_texture_stage_state(i, D3DTSS_CONSTANT, constant_color);
04667     } else {
04668       // This device doesn't supoprt a per-stage constant color, so we
04669       // have to fall back to a single constant color for the overall
04670       // texture pipeline.
04671       set_render_state(D3DRS_TEXTUREFACTOR, constant_color);
04672     }
04673   }
04674 }
04675 
04676 ////////////////////////////////////////////////////////////////////
04677 //     Function: DXGraphicsStateGuardian9::dx_cleanup
04678 //       Access: Protected
04679 //  Description: Clean up the DirectX environment, accounting for exit()
04680 ////////////////////////////////////////////////////////////////////
04681 void DXGraphicsStateGuardian9::
04682 dx_cleanup() {
04683   if (!_d3d_device) {
04684     return;
04685   }
04686 
04687   free_nondx_resources();
04688   PRINT_REFCNT(dxgsg9, _d3d_device);
04689 
04690   // Do a safe check for releasing the D3DDEVICE. RefCount should be zero.
04691   // if we're called from exit(), _d3d_device may already have been released
04692   RELEASE(_d3d_device, dxgsg9, "d3dDevice", RELEASE_DOWN_TO_ZERO);
04693   _screen->_d3d_device = NULL;
04694 
04695   // Releasing pD3D is now the responsibility of the GraphicsPipe destructor
04696 }
04697 
04698 ////////////////////////////////////////////////////////////////////
04699 //     Function: DXGraphicsStateGuardian9::reset_d3d_device
04700 //       Access: Protected
04701 //  Description: This function checks current device's framebuffer
04702 //               dimension against passed p_presentation_params backbuffer
04703 //               dimension to determine a device reset if there is
04704 //               only one window or it is the main window or
04705 //               fullscreen mode then, it resets the device. Finally
04706 //               it returns the new DXScreenData through parameter
04707 //               screen
04708 ////////////////////////////////////////////////////////////////////
04709 HRESULT DXGraphicsStateGuardian9::
04710 reset_d3d_device(D3DPRESENT_PARAMETERS *presentation_params,
04711                  DXScreenData **screen) {
04712   HRESULT hr;
04713 
04714   nassertr(IS_VALID_PTR(presentation_params), E_FAIL);
04715   nassertr(IS_VALID_PTR(_screen->_d3d9), E_FAIL);
04716   nassertr(IS_VALID_PTR(_d3d_device), E_FAIL);
04717 
04718   // for windowed mode make sure our format matches the desktop fmt,
04719   // in case the desktop mode has been changed
04720   _screen->_d3d9->GetAdapterDisplayMode(_screen->_card_id, &_screen->_display_mode);
04721   presentation_params->BackBufferFormat = _screen->_display_mode.Format;
04722 
04723   // here we have to look at the _presentation_reset frame buffer dimension
04724   // if current window's dimension is bigger than _presentation_reset
04725   // we have to reset the device before creating new swapchain.
04726   // inorder to reset properly, we need to release all swapchains
04727 
04728   if (true || !(_screen->_swap_chain)
04729       || (_presentation_reset.BackBufferWidth < presentation_params->BackBufferWidth)
04730       || (_presentation_reset.BackBufferHeight < presentation_params->BackBufferHeight)) {
04731     if (wdxdisplay9_cat.is_debug()) {
04732       wdxdisplay9_cat.debug()
04733         << "swap_chain = " << _screen->_swap_chain << " _presentation_reset = "
04734         << _presentation_reset.BackBufferWidth << "x" << _presentation_reset.BackBufferHeight
04735         << " presentation_params = "
04736         << presentation_params->BackBufferWidth << "x" << presentation_params->BackBufferHeight << "\n";
04737     }
04738 
04739     get_engine()->reset_all_windows(false);// reset old swapchain by releasing
04740 
04741     if (_screen->_swap_chain) {  //other windows might be using bigger buffers
04742       _presentation_reset.BackBufferWidth = max(_presentation_reset.BackBufferWidth, presentation_params->BackBufferWidth);
04743       _presentation_reset.BackBufferHeight = max(_presentation_reset.BackBufferHeight, presentation_params->BackBufferHeight);
04744 
04745     } else {  // single window, must reset to the new presentation_params dimension
04746       _presentation_reset.BackBufferWidth = presentation_params->BackBufferWidth;
04747       _presentation_reset.BackBufferHeight = presentation_params->BackBufferHeight;
04748     }
04749 
04750     // Calling this forces all of the textures and vbuffers to be
04751     // regenerated, a prerequisite to calling Reset().
04752     release_all();
04753 
04754     // Just to be extra-conservative for now, we'll go ahead and
04755     // release the vbuffers and ibuffers at least; they're relatively
04756     // cheap to replace.
04757     release_all_vertex_buffers();
04758     release_all_index_buffers();
04759 
04760     // must be called before reset
04761     Thread *current_thread = Thread::get_current_thread();
04762     _prepared_objects->begin_frame(this, current_thread);
04763 
04764     // release graphics buffer surfaces
04765     {
04766       wdxGraphicsBuffer9 *graphics_buffer;
04767       list <wdxGraphicsBuffer9 **>::iterator graphics_buffer_iterator;
04768 
04769       for (graphics_buffer_iterator = _graphics_buffer_list.begin( ); graphics_buffer_iterator != _graphics_buffer_list.end( ); graphics_buffer_iterator++)
04770       {
04771         graphics_buffer = **graphics_buffer_iterator;
04772         if (graphics_buffer -> _color_backing_store)
04773         {
04774           graphics_buffer -> _color_backing_store -> Release ( );
04775           graphics_buffer -> _color_backing_store = 0;
04776         }
04777         if (graphics_buffer -> _depth_backing_store)
04778         {
04779           graphics_buffer -> _depth_backing_store -> Release ( );
04780           graphics_buffer -> _depth_backing_store = 0;
04781         }
04782       }
04783     }
04784 
04785     this -> mark_new();
04786     hr = _d3d_device->Reset(&_presentation_reset);
04787     if (FAILED(hr) && hr != D3DERR_DEVICELOST) {
04788       return hr;
04789     }
04790 
04791     get_engine()->reset_all_windows(true);// reset with new swapchains by creating
04792     if (screen) {
04793       *screen = NULL;
04794     }
04795 
04796     if (presentation_params != &_screen->_presentation_params) {
04797       memcpy(&_screen->_presentation_params, presentation_params, sizeof(D3DPRESENT_PARAMETERS));
04798     }
04799 
04800     return hr;
04801   }
04802 
04803   // release the old swapchain and create a new one
04804   if (_screen && _screen->_swap_chain) {
04805     _screen->_swap_chain->Release();
04806     wdxdisplay9_cat.debug()
04807       << "swap chain " << _screen->_swap_chain << " is released\n";
04808     _screen->_swap_chain = NULL;
04809     hr = _d3d_device->CreateAdditionalSwapChain(presentation_params, &_screen->_swap_chain);
04810   }
04811   if (SUCCEEDED(hr)) {
04812     if (presentation_params != &_screen->_presentation_params) {
04813       memcpy(&_screen->_presentation_params, presentation_params, sizeof(D3DPRESENT_PARAMETERS));
04814     }
04815     if (screen) {
04816       *screen = _screen;
04817     }
04818   }
04819   return hr;
04820 }
04821 
04822 ////////////////////////////////////////////////////////////////////
04823 //     Function: DXGraphicsStateGuardian9::check_cooperative_level
04824 //       Access: Protected
04825 //  Description:
04826 ////////////////////////////////////////////////////////////////////
04827 bool DXGraphicsStateGuardian9::
04828 check_cooperative_level() {
04829   bool bDoReactivateWindow = false;
04830   if (_d3d_device == NULL) {
04831     return false;
04832   }
04833 
04834   HRESULT hr = _d3d_device->TestCooperativeLevel();
04835 
04836   if (SUCCEEDED(hr)) {
04837     nassertr(SUCCEEDED(_last_testcooplevel_result), false);
04838     return true;
04839   }
04840 
04841   switch (hr) {
04842   case D3DERR_DEVICENOTRESET:
04843     _dx_is_ready = false;
04844 
04845     // call this just in case
04846     _prepared_objects->begin_frame(this, Thread::get_current_thread());
04847 
04848     hr = reset_d3d_device(&_screen->_presentation_params);
04849     if (FAILED(hr)) {
04850       // I think this shouldnt fail unless I've screwed up the
04851       // _presentation_params from the original working ones somehow
04852       dxgsg9_cat.error()
04853         << "check_cooperative_level Reset() failed, hr = " << D3DERRORSTRING(hr);
04854     }
04855 
04856     hr = _d3d_device->TestCooperativeLevel();
04857     if (FAILED(hr)) {
04858       // internal chk, shouldnt fail
04859       dxgsg9_cat.error()
04860         << "TestCooperativeLevel following Reset() failed, hr = " << D3DERRORSTRING(hr);
04861 
04862     }
04863 
04864     _dx_is_ready = TRUE;
04865     break;
04866 
04867   case D3DERR_DEVICELOST:
04868     // sleep while the device is lost to free up the CPU
04869     Sleep (10);
04870     
04871     if (SUCCEEDED(_last_testcooplevel_result)) {
04872       if (_dx_is_ready) {
04873         _dx_is_ready = false;
04874         if (dxgsg9_cat.is_debug()) {
04875           dxgsg9_cat.debug() << "D3D Device was Lost, waiting...\n";
04876         }
04877       }
04878     }
04879   }
04880 
04881   _last_testcooplevel_result = hr;
04882   return SUCCEEDED(hr);
04883 }
04884 
04885 ////////////////////////////////////////////////////////////////////
04886 //     Function: DXGraphicsStateGuardian9::show_frame
04887 //       Access: Protected
04888 //  Description: redraw primary buffer
04889 ////////////////////////////////////////////////////////////////////
04890 void DXGraphicsStateGuardian9::
04891 show_frame() {
04892   if (_d3d_device == NULL) {
04893     return;
04894   }
04895 
04896   HRESULT hr;
04897 
04898   if (_swap_chain) {
04899     DWORD flags;
04900     flags = 0;
04901     
04902     hr = _swap_chain->Present((CONST RECT*)NULL, (CONST RECT*)NULL, (HWND)NULL, NULL, flags);
04903   } else {
04904     hr = _d3d_device->Present((CONST RECT*)NULL, (CONST RECT*)NULL, (HWND)NULL, NULL);
04905   }
04906 
04907   if (FAILED(hr)) {
04908     if (hr == D3DERR_DEVICELOST) {
04909       check_cooperative_level();
04910     } else {
04911       dxgsg9_cat.error()
04912         << "show_frame() - Present() failed" << D3DERRORSTRING(hr);
04913       throw_event("panda3d-render-error");
04914     }
04915   }
04916 }
04917 
04918 ////////////////////////////////////////////////////////////////////
04919 //     Function: DXGraphicsStateGuardian9::create_swap_chain
04920 //       Access: Protected
04921 //  Description:
04922 ////////////////////////////////////////////////////////////////////
04923 bool DXGraphicsStateGuardian9::
04924 create_swap_chain(DXScreenData *new_context) {
04925   // Instead of creating a device and rendering as d3ddevice->present()
04926   // we should render using SwapChain->present(). This is done to support
04927   // multiple windows rendering. For that purpose, we need to set additional
04928   // swap chains here.
04929 
04930   HRESULT hr;
04931   hr = new_context->_d3d_device->CreateAdditionalSwapChain(&new_context->_presentation_params, &new_context->_swap_chain);
04932   if (FAILED(hr)) {
04933     wdxdisplay9_cat.debug() << "Swapchain creation failed :"<<D3DERRORSTRING(hr)<<"\n";
04934     return false;
04935   }
04936   return true;
04937 }
04938 
04939 ////////////////////////////////////////////////////////////////////
04940 //     Function: DXGraphicsStateGuardian9::release_swap_chain
04941 //       Access: Protected
04942 //  Description: Release the swap chain on this DXScreenData
04943 ////////////////////////////////////////////////////////////////////
04944 bool DXGraphicsStateGuardian9::
04945 release_swap_chain(DXScreenData *new_context) {
04946   HRESULT hr;
04947   if (new_context->_swap_chain) {
04948     hr = new_context->_swap_chain->Release();
04949     if (FAILED(hr)) {
04950       wdxdisplay9_cat.debug() << "Swapchain release failed:" << D3DERRORSTRING(hr) << "\n";
04951       return false;
04952     }
04953   }
04954   return true;
04955 }
04956 
04957 ////////////////////////////////////////////////////////////////////
04958 //     Function: DXGraphicsStateGuardian9::copy_pres_reset
04959 //       Access: Protected
04960 //  Description: copies the PresReset from passed DXScreenData
04961 ////////////////////////////////////////////////////////////////////
04962 void DXGraphicsStateGuardian9::
04963 copy_pres_reset(DXScreenData *screen) {
04964   memcpy(&_presentation_reset, &_screen->_presentation_params, sizeof(D3DPRESENT_PARAMETERS));
04965 }
04966 
04967 ////////////////////////////////////////////////////////////////////
04968 //     Function: DXGraphicsStateGuardian9::get_d3d_min_type
04969 //       Access: Protected, Static
04970 //  Description:
04971 ////////////////////////////////////////////////////////////////////
04972 D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian9::
04973 get_d3d_min_type(Texture::FilterType filter_type) {
04974   switch (filter_type) {
04975   case Texture::FT_nearest:
04976     return D3DTEXF_POINT;
04977 
04978   case Texture::FT_linear:
04979     return D3DTEXF_LINEAR;
04980 
04981   case Texture::FT_nearest_mipmap_nearest:
04982     return D3DTEXF_POINT;
04983 
04984   case Texture::FT_linear_mipmap_nearest:
04985     return D3DTEXF_LINEAR;
04986 
04987   case Texture::FT_nearest_mipmap_linear:
04988     return D3DTEXF_POINT;
04989 
04990   case Texture::FT_linear_mipmap_linear:
04991     return D3DTEXF_LINEAR;
04992 
04993   case Texture::FT_shadow:
04994   case Texture::FT_default:
04995     return D3DTEXF_LINEAR;
04996   }
04997 
04998   dxgsg9_cat.error()
04999     << "Invalid FilterType value (" << (int)filter_type << ")\n";
05000   return D3DTEXF_POINT;
05001 }
05002 
05003 ////////////////////////////////////////////////////////////////////
05004 //     Function: DXGraphicsStateGuardian9::get_d3d_mip_type
05005 //       Access: Protected, Static
05006 //  Description:
05007 ////////////////////////////////////////////////////////////////////
05008 D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian9::
05009 get_d3d_mip_type(Texture::FilterType filter_type) {
05010   switch (filter_type) {
05011   case Texture::FT_nearest:
05012     return D3DTEXF_NONE;
05013 
05014   case Texture::FT_linear:
05015     return D3DTEXF_NONE;
05016 
05017   case Texture::FT_nearest_mipmap_nearest:
05018     return D3DTEXF_POINT;
05019 
05020   case Texture::FT_linear_mipmap_nearest:
05021     return D3DTEXF_POINT;
05022 
05023   case Texture::FT_nearest_mipmap_linear:
05024     return D3DTEXF_LINEAR;
05025 
05026   case Texture::FT_linear_mipmap_linear:
05027     return D3DTEXF_LINEAR;
05028 
05029   case Texture::FT_shadow:
05030   case Texture::FT_default:
05031     return D3DTEXF_NONE;
05032   }
05033 
05034   dxgsg9_cat.error()
05035     << "Invalid FilterType value (" << (int)filter_type << ")\n";
05036   return D3DTEXF_NONE;
05037 }
05038 
05039 ////////////////////////////////////////////////////////////////////
05040 //     Function: DXGraphicsStateGuardian9::get_texture_operation
05041 //       Access: Protected, Static
05042 //  Description: Returns the D3DTEXTUREOP value corresponding to the
05043 //               indicated TextureStage::CombineMode enumerated type.
05044 ////////////////////////////////////////////////////////////////////
05045 D3DTEXTUREOP DXGraphicsStateGuardian9::
05046 get_texture_operation(TextureStage::CombineMode mode, int scale) {
05047   switch (mode) {
05048   case TextureStage::CM_undefined:
05049   case TextureStage::CM_replace:
05050     return D3DTOP_SELECTARG1;
05051 
05052   case TextureStage::CM_modulate:
05053     if (scale < 2) {
05054       return D3DTOP_MODULATE;
05055     } else if (scale < 4) {
05056       return D3DTOP_MODULATE2X;
05057     } else {
05058       return D3DTOP_MODULATE4X;
05059     }
05060 
05061   case TextureStage::CM_add:
05062     return D3DTOP_ADD;
05063 
05064   case TextureStage::CM_add_signed:
05065     if (scale < 2) {
05066       return D3DTOP_ADDSIGNED;
05067     } else {
05068       return D3DTOP_ADDSIGNED2X;
05069     }
05070 
05071   case TextureStage::CM_interpolate:
05072     return D3DTOP_LERP;
05073 
05074   case TextureStage::CM_subtract:
05075     return D3DTOP_SUBTRACT;
05076 
05077   case TextureStage::CM_dot3_rgb:
05078   case TextureStage::CM_dot3_rgba:
05079     return D3DTOP_DOTPRODUCT3;
05080   }
05081 
05082   dxgsg9_cat.error()
05083     << "Invalid TextureStage::CombineMode value (" << (int)mode << ")\n";
05084   return D3DTOP_DISABLE;
05085 }
05086 
05087 ////////////////////////////////////////////////////////////////////
05088 //     Function: DXGraphicsStateGuardian9::get_texture_argument
05089 //       Access: Protected
05090 //  Description: Returns the D3DTA value corresponding to the
05091 //               indicated TextureStage::CombineSource and
05092 //               TextureStage::CombineOperand enumerated types.
05093 ////////////////////////////////////////////////////////////////////
05094 DWORD DXGraphicsStateGuardian9::
05095 get_texture_argument(TextureStage::CombineSource source,
05096                      TextureStage::CombineOperand operand) const {
05097   switch (source) {
05098   case TextureStage::CS_undefined:
05099   case TextureStage::CS_texture:
05100     return D3DTA_TEXTURE | get_texture_argument_modifier(operand);
05101 
05102   case TextureStage::CS_constant:
05103   case TextureStage::CS_constant_color_scale:
05104     return _constant_color_operand | get_texture_argument_modifier(operand);
05105 
05106   case TextureStage::CS_primary_color:
05107     return D3DTA_DIFFUSE | get_texture_argument_modifier(operand);
05108 
05109   case TextureStage::CS_previous:
05110     return D3DTA_CURRENT | get_texture_argument_modifier(operand);
05111 
05112   case TextureStage::CS_last_saved_result:
05113     return D3DTA_TEMP | get_texture_argument_modifier(operand);
05114   }
05115   dxgsg9_cat.error()
05116     << "Invalid TextureStage::CombineSource value (" << (int)source << ")\n";
05117   return D3DTA_CURRENT;
05118 }
05119 
05120 ////////////////////////////////////////////////////////////////////
05121 //     Function: DXGraphicsStateGuardian9::get_texture_argument_modifier
05122 //       Access: Protected, Static
05123 //  Description: Returns the extra bits that modify the D3DTA
05124 //               argument, according to the indicated
05125 //               TextureStage::CombineOperand enumerated type.
05126 ////////////////////////////////////////////////////////////////////
05127 DWORD DXGraphicsStateGuardian9::
05128 get_texture_argument_modifier(TextureStage::CombineOperand operand) {
05129   switch (operand) {
05130   case TextureStage::CO_src_color:
05131     return 0;
05132 
05133   case TextureStage::CO_one_minus_src_color:
05134     return D3DTA_COMPLEMENT;
05135 
05136   case TextureStage::CO_src_alpha:
05137     return D3DTA_ALPHAREPLICATE;
05138 
05139   case TextureStage::CO_one_minus_src_alpha:
05140     return D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT;
05141 
05142   case TextureStage::CO_undefined:
05143     break;
05144   }
05145   dxgsg9_cat.error()
05146     << "Invalid TextureStage::CombineOperand value (" << (int)operand << ")\n";
05147   return 0;
05148 }
05149 
05150 ////////////////////////////////////////////////////////////////////
05151 //     Function: DXGraphicsStateGuardian9::draw_primitive_up
05152 //       Access: Protected
05153 //  Description: Issues the DrawPrimitiveUP call to draw the indicated
05154 //               primitive_type from the given buffer.  We add the
05155 //               num_vertices parameter, so we can determine the size
05156 //               of the buffer.
05157 ////////////////////////////////////////////////////////////////////
05158 void DXGraphicsStateGuardian9::
05159 draw_primitive_up(D3DPRIMITIVETYPE primitive_type,
05160       unsigned int primitive_count,
05161       unsigned int first_vertex,
05162       unsigned int num_vertices,
05163       const unsigned char *buffer, size_t stride) {
05164 
05165   // It appears that the common ATI driver seems to fail to draw
05166   // anything in the DrawPrimitiveUP() call if the address range of
05167   // the buffer supplied crosses over a multiple of 0x10000.  That's
05168   // incredibly broken, yet it undeniably appears to be true.  We'll
05169   // have to hack around it.
05170 
05171   const unsigned char *buffer_start = buffer + stride * first_vertex;
05172   const unsigned char *buffer_end = buffer_start + stride * num_vertices;
05173 
05174   if (buffer_end - buffer_start > 0x10000) {
05175     // Actually, the buffer doesn't fit within the required limit
05176     // anyway.  Go ahead and draw it and hope for the best.
05177     _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count,
05178          buffer_start, stride);
05179 
05180   } else if ((((long)buffer_end ^ (long)buffer_start) & ~0xffff) == 0) {
05181     // No problem; we can draw the buffer directly.
05182     _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count,
05183          buffer_start, stride);
05184 
05185   } else {
05186     // We have a problem--the buffer crosses over a 0x10000 boundary.
05187     // We have to copy the buffer to a temporary buffer that we can
05188     // draw from.
05189     unsigned char *safe_buffer_start = get_safe_buffer_start();
05190     memcpy(safe_buffer_start, buffer_start, buffer_end - buffer_start);
05191     _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count,
05192          safe_buffer_start, stride);
05193 
05194   }
05195 }
05196 
05197 ////////////////////////////////////////////////////////////////////
05198 //     Function: DXGraphicsStateGuardian9::draw_indexed_primitive_up
05199 //       Access: Protected
05200 //  Description: Issues the DrawIndexedPrimitiveUP call to draw the
05201 //               indicated primitive_type from the given buffer.  As
05202 //               in draw_primitive_up(), above, the parameter list is
05203 //               not exactly one-for-one with the
05204 //               DrawIndexedPrimitiveUP() call, but it's similar (in
05205 //               particular, we pass max_index instead of NumVertices,
05206 //               which always seemed ambiguous to me).
05207 ////////////////////////////////////////////////////////////////////
05208 void DXGraphicsStateGuardian9::
05209 draw_indexed_primitive_up(D3DPRIMITIVETYPE primitive_type,
05210         unsigned int min_index, unsigned int max_index,
05211         unsigned int num_primitives,
05212         const unsigned char *index_data,
05213         D3DFORMAT index_type,
05214         const unsigned char *buffer, size_t stride) {
05215   // As above, we'll hack the case of the buffer crossing the 0x10000
05216   // boundary.
05217   const unsigned char *buffer_start = buffer + stride * min_index;
05218   const unsigned char *buffer_end = buffer + stride * (max_index + 1);
05219 
05220   if (buffer_end - buffer_start > 0x10000) {
05221     // Actually, the buffer doesn't fit within the required limit
05222     // anyway.  Go ahead and draw it and hope for the best.
05223     _d3d_device->DrawIndexedPrimitiveUP
05224       (primitive_type, min_index, max_index - min_index + 1, num_primitives,
05225        index_data, index_type, buffer, stride);
05226 
05227   } else if ((((long)buffer_end ^ (long)buffer_start) & ~0xffff) == 0) {
05228     // No problem; we can draw the buffer directly.
05229     _d3d_device->DrawIndexedPrimitiveUP
05230       (primitive_type, min_index, max_index - min_index + 1, num_primitives,
05231        index_data, index_type, buffer, stride);
05232 
05233   } else {
05234     // We have a problem--the buffer crosses over a 0x10000 boundary.
05235     // We have to copy the buffer to a temporary buffer that we can
05236     // draw from.
05237     unsigned char *safe_buffer_start = get_safe_buffer_start();
05238     memcpy(safe_buffer_start, buffer_start, buffer_end - buffer_start);
05239     _d3d_device->DrawIndexedPrimitiveUP
05240       (primitive_type, min_index, max_index - min_index + 1, num_primitives,
05241        index_data, index_type, safe_buffer_start - stride * min_index, stride);
05242   }
05243 }
05244 
05245 ////////////////////////////////////////////////////////////////////
05246 //     Function: DXGraphicsStateGuardian9::check_dx_allocation
05247 //       Access:
05248 //  Description: This function is called after the creation of
05249 //               textures, vertex buffers, and index buffers to
05250 //               check if DirectX is out of memory. If DirectX is
05251 //               out of memory and the LRU is being used, then
05252 //               page out some memory. This function is a fail-safe
05253 //               just in case another process allocates video
05254 //               memory, DirectX is fragmented, or there are some
05255 //               borderline memory allocation cases, ...
05256 ////////////////////////////////////////////////////////////////////
05257 bool DXGraphicsStateGuardian9::
05258 check_dx_allocation (HRESULT result, int allocation_size, int attempts)
05259 {
05260   bool retry;
05261 
05262   retry = false;
05263   if (attempts <= 4)
05264   {
05265     switch (result) {
05266       case D3D_OK:
05267         break;
05268 
05269       case D3DERR_OUTOFVIDEOMEMORY:
05270       case E_OUTOFMEMORY:
05271         // increase the page out size as the number of attempts increases
05272         {
05273           size_t current_size = _prepared_objects->_graphics_memory_lru.get_total_size();
05274           size_t target_size = max(current_size - allocation_size * attempts, 0);
05275           _prepared_objects->_graphics_memory_lru.evict_to(target_size);
05276           dxgsg9_cat.info()
05277             << "Evicted " << current_size - _prepared_objects->_graphics_memory_lru.get_total_size() << " bytes of texture memory to make room for more.\n";
05278           if (_prepared_objects->_graphics_memory_lru.get_total_size() < current_size) {
05279             retry = true;
05280           }
05281         }
05282         break;
05283 
05284       default:
05285         break;
05286     }
05287   }
05288 
05289   return retry;
05290 }
05291 
05292 ////////////////////////////////////////////////////////////////////
05293 //  DX stencil code section
05294 ////////////////////////////////////////////////////////////////////
05295 
05296 static int dx_stencil_comparison_function_array [ ] =
05297 {
05298   D3DCMP_NEVER,
05299   D3DCMP_LESS,
05300   D3DCMP_EQUAL,
05301   D3DCMP_LESSEQUAL,
05302   D3DCMP_GREATER,
05303   D3DCMP_NOTEQUAL,
05304   D3DCMP_GREATEREQUAL,
05305   D3DCMP_ALWAYS,
05306 };
05307 
05308 static int dx_stencil_operation_array [ ] =
05309 {
05310   D3DSTENCILOP_KEEP,
05311   D3DSTENCILOP_ZERO,
05312   D3DSTENCILOP_REPLACE,
05313   D3DSTENCILOP_INCR,
05314   D3DSTENCILOP_DECR,
05315   D3DSTENCILOP_INVERT,
05316 
05317   D3DSTENCILOP_INCRSAT,
05318   D3DSTENCILOP_DECRSAT,
05319 };
05320 
05321 void dx_stencil_function (StencilRenderStates::StencilRenderState stencil_render_state, StencilRenderStates *stencil_render_states) {
05322   StencilType render_state_value;
05323 
05324   DXGraphicsStateGuardian9 *gsg;
05325 
05326   gsg = (DXGraphicsStateGuardian9 *) stencil_render_states -> _gsg;
05327 
05328   render_state_value = stencil_render_states -> get_stencil_render_state (stencil_render_state);
05329 
05330   // DEBUG
05331   if (false) {
05332     dxgsg9_cat.debug()
05333       << "SRS: " <<  StencilAttrib::stencil_render_state_name_array [stencil_render_state] << ", " << render_state_value << "\n";
05334   }
05335 
05336   switch (stencil_render_state)
05337   {
05338     case StencilRenderStates::SRS_front_enable:
05339       gsg -> set_render_state (D3DRS_STENCILENABLE, render_state_value);
05340       break;
05341 
05342     case StencilRenderStates::SRS_back_enable:
05343       if (gsg -> get_supports_two_sided_stencil()) {
05344         gsg -> set_render_state (D3DRS_TWOSIDEDSTENCILMODE, render_state_value);
05345       }
05346       break;
05347 
05348     case StencilRenderStates::SRS_front_comparison_function:
05349       gsg -> set_render_state (D3DRS_STENCILFUNC, dx_stencil_comparison_function_array [render_state_value]);
05350       break;
05351     case StencilRenderStates::SRS_front_stencil_fail_operation:
05352       gsg -> set_render_state (D3DRS_STENCILFAIL, dx_stencil_operation_array [render_state_value]);
05353       break;
05354     case StencilRenderStates::SRS_front_stencil_pass_z_fail_operation:
05355       gsg -> set_render_state (D3DRS_STENCILZFAIL, dx_stencil_operation_array [render_state_value]);
05356       break;
05357     case StencilRenderStates::SRS_front_stencil_pass_z_pass_operation:
05358       gsg -> set_render_state (D3DRS_STENCILPASS, dx_stencil_operation_array [render_state_value]);
05359       break;
05360 
05361     case StencilRenderStates::SRS_reference:
05362       gsg -> set_render_state (D3DRS_STENCILREF, render_state_value);
05363       break;
05364 
05365     case StencilRenderStates::SRS_read_mask:
05366       gsg -> set_render_state (D3DRS_STENCILMASK, render_state_value);
05367       break;
05368     case StencilRenderStates::SRS_write_mask:
05369       gsg -> set_render_state (D3DRS_STENCILWRITEMASK, render_state_value);
05370       break;
05371 
05372     case StencilRenderStates::SRS_back_comparison_function:
05373       if (gsg -> get_supports_two_sided_stencil()) {
05374         gsg -> set_render_state (D3DRS_CCW_STENCILFUNC, dx_stencil_comparison_function_array [render_state_value]);
05375       }
05376       break;
05377     case StencilRenderStates::SRS_back_stencil_fail_operation:
05378       if (gsg -> get_supports_two_sided_stencil()) {
05379         gsg -> set_render_state (D3DRS_CCW_STENCILFAIL, dx_stencil_operation_array [render_state_value]);
05380       }
05381       break;
05382     case StencilRenderStates::SRS_back_stencil_pass_z_fail_operation:
05383       if (gsg -> get_supports_two_sided_stencil()) {
05384         gsg -> set_render_state (D3DRS_CCW_STENCILZFAIL, dx_stencil_operation_array [render_state_value]);
05385       }
05386       break;
05387     case StencilRenderStates::SRS_back_stencil_pass_z_pass_operation:
05388       if (gsg -> get_supports_two_sided_stencil()) {
05389         gsg -> set_render_state (D3DRS_CCW_STENCILPASS, dx_stencil_operation_array [render_state_value]);
05390       }
05391       break;
05392 
05393     default:
05394       break;
05395   }
05396 }
05397 
05398 void dx_set_stencil_functions (StencilRenderStates *stencil_render_states) {
05399   if (stencil_render_states) {
05400     StencilRenderStates::StencilRenderState stencil_render_state;
05401 
05402     for (stencil_render_state = StencilRenderStates::SRS_first; stencil_render_state < StencilRenderStates::SRS_total; stencil_render_state = (StencilRenderStates::StencilRenderState) ((int) stencil_render_state + 1)) {
05403       stencil_render_states -> set_stencil_function (stencil_render_state, dx_stencil_function);
05404     }
05405   }
05406 }
05407 
05408 ////////////////////////////////////////////////////////////////////
05409 //     Function: DXGraphicsStateGuardian9::do_issue_stencil
05410 //       Access: Protected
05411 //  Description: Set stencil render states.
05412 ////////////////////////////////////////////////////////////////////
05413 void DXGraphicsStateGuardian9::
05414 do_issue_stencil() {
05415   if (!_supports_stencil) {
05416     return;
05417   }
05418 
05419   StencilRenderStates *stencil_render_states;
05420   const StencilAttrib *stencil = DCAST(StencilAttrib, _target_rs->get_attrib_def(StencilAttrib::get_class_slot()));
05421   stencil_render_states = this -> _stencil_render_states;
05422   if (stencil && stencil_render_states) {
05423 
05424     // DEBUG
05425     if (false) {
05426       dxgsg9_cat.debug() << "STENCIL STATE CHANGE\n";
05427       dxgsg9_cat.debug() << "\n"
05428         << "SRS_front_enable " << stencil -> get_render_state (StencilAttrib::SRS_front_enable) << "\n"
05429         << "SRS_back_enable " << stencil -> get_render_state (StencilAttrib::SRS_back_enable) << "\n"
05430         << "SRS_front_comparison_function " << stencil -> get_render_state (StencilAttrib::SRS_front_comparison_function) << "\n"
05431         << "SRS_front_stencil_fail_operation " << stencil -> get_render_state (StencilAttrib::SRS_front_stencil_fail_operation) << "\n"
05432         << "SRS_front_stencil_pass_z_fail_operation " << stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_fail_operation) << "\n"
05433         << "SRS_front_stencil_pass_z_pass_operation " << stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_pass_operation) << "\n"
05434         << "SRS_reference " << stencil -> get_render_state (StencilAttrib::SRS_reference) << "\n"
05435         << "SRS_read_mask " << stencil -> get_render_state (StencilAttrib::SRS_read_mask) << "\n"
05436         << "SRS_write_mask " << stencil -> get_render_state (StencilAttrib::SRS_write_mask) << "\n"
05437         << "SRS_back_comparison_function " << stencil -> get_render_state (StencilAttrib::SRS_back_comparison_function) << "\n"
05438         << "SRS_back_stencil_fail_operation " << stencil -> get_render_state (StencilAttrib::SRS_back_stencil_fail_operation) << "\n"
05439         << "SRS_back_stencil_pass_z_fail_operation " << stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_fail_operation) << "\n"
05440         << "SRS_back_stencil_pass_z_pass_operation " << stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_pass_operation) << "\n";
05441     }
05442 
05443     bool on;
05444 
05445     on = false;
05446     stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_enable, stencil -> get_render_state (StencilAttrib::SRS_front_enable));
05447     if (stencil -> get_render_state (StencilAttrib::SRS_front_enable)) {
05448       stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_comparison_function, stencil -> get_render_state (StencilAttrib::SRS_front_comparison_function));
05449       stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_fail_operation));
05450       stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_pass_z_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_fail_operation));
05451       stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_stencil_pass_z_pass_operation, stencil -> get_render_state (StencilAttrib::SRS_front_stencil_pass_z_pass_operation));
05452       on = true;
05453     }
05454 
05455     stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_enable, stencil -> get_render_state (StencilAttrib::SRS_back_enable));
05456     if (stencil -> get_render_state (StencilAttrib::SRS_back_enable)) {
05457       stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_comparison_function, stencil -> get_render_state (StencilAttrib::SRS_back_comparison_function));
05458       stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_stencil_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_back_stencil_fail_operation));
05459       stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_stencil_pass_z_fail_operation, stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_fail_operation));
05460       stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_stencil_pass_z_pass_operation, stencil -> get_render_state (StencilAttrib::SRS_back_stencil_pass_z_pass_operation));
05461       on = true;
05462     }
05463 
05464     if (on) {
05465       stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_reference, stencil -> get_render_state (StencilAttrib::SRS_reference));
05466       stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_read_mask, stencil -> get_render_state (StencilAttrib::SRS_read_mask));
05467       stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_write_mask, stencil -> get_render_state (StencilAttrib::SRS_write_mask));
05468     }
05469 
05470     if (stencil -> get_render_state (StencilAttrib::SRS_clear)) {
05471       _d3d_device->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0.0f, stencil -> get_render_state (StencilAttrib::SRS_clear_value));
05472     }
05473   }
05474   else {
05475 
05476     // DEBUG
05477     if (false) {
05478       dxgsg9_cat.debug() << "STENCIL STATE CHANGE TO OFF \n";
05479     }
05480 
05481     stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_front_enable, 0);
05482     stencil_render_states -> set_stencil_render_state (true, StencilRenderStates::SRS_back_enable, 0);
05483   }
05484 }
05485 
05486 ////////////////////////////////////////////////////////////////////
05487 //     Function: dxGraphicsStateGuardian9::do_issue_scissor
05488 //       Access: Protected
05489 //  Description: 
05490 ////////////////////////////////////////////////////////////////////
05491 void DXGraphicsStateGuardian9::
05492 do_issue_scissor() {
05493   const ScissorAttrib *target_scissor = DCAST(ScissorAttrib, _target_rs->get_attrib_def(ScissorAttrib::get_class_slot()));
05494   const LVecBase4f &frame = target_scissor->get_frame();
05495 
05496   RECT r;
05497   r.left = _current_viewport.X + _current_viewport.Width * frame[0];
05498   r.top = _current_viewport.Y + _current_viewport.Height * (1.0f - frame[3]);
05499   r.right = _current_viewport.X + _current_viewport.Width * frame[1];
05500   r.bottom = _current_viewport.Y + _current_viewport.Height * (1.0f - frame[2]);
05501   _d3d_device->SetScissorRect(&r);
05502   set_render_state(D3DRS_SCISSORTESTENABLE, TRUE);
05503 }
05504 
05505 ////////////////////////////////////////////////////////////////////
05506 //     Function: dxGraphicsStateGuardian9::calc_fb_properties
05507 //       Access: Public
05508 //  Description: Convert DirectX framebuffer format ids into a
05509 //               FrameBufferProperties structure.
05510 ////////////////////////////////////////////////////////////////////
05511 FrameBufferProperties DXGraphicsStateGuardian9::
05512 calc_fb_properties(DWORD cformat, DWORD dformat,
05513                    DWORD multisampletype, DWORD multisamplequality) {
05514   FrameBufferProperties props;
05515   int index=0;
05516   int alpha=0;
05517   int color=0;
05518   switch (cformat) {
05519   case D3DFMT_R8G8B8:      index=0; color=24; alpha=0; break;
05520   case D3DFMT_A8R8G8B8:    index=0; color=24; alpha=8; break;
05521   case D3DFMT_X8R8G8B8:    index=0; color=24; alpha=0; break;
05522   case D3DFMT_R5G6B5:      index=0; color=16; alpha=0; break;
05523   case D3DFMT_X1R5G5B5:    index=0; color=15; alpha=0; break;
05524   case D3DFMT_A1R5G5B5:    index=0; color=15; alpha=1; break;
05525   case D3DFMT_A4R4G4B4:    index=0; color=12; alpha=4; break;
05526   case D3DFMT_R3G3B2:      index=0; color= 8; alpha=0; break;
05527   case D3DFMT_A8R3G3B2:    index=0; color= 8; alpha=8; break;
05528   case D3DFMT_X4R4G4B4:    index=0; color=12; alpha=0; break;
05529   case D3DFMT_A2B10G10R10: index=0; color=30; alpha=2; break;
05530   case D3DFMT_A8P8:        index=1; color= 8; alpha=8; break;
05531   case D3DFMT_P8:          index=1; color= 8; alpha=0; break;
05532   }
05533   props.set_color_bits(color);
05534   props.set_alpha_bits(alpha);
05535   if (index) {
05536     props.set_rgb_color(0);
05537     props.set_indexed_color(1);
05538   } else if (color) {
05539     props.set_rgb_color(1);
05540     props.set_indexed_color(0);
05541   }
05542   int depth=0;
05543   int stencil=0;
05544   switch (dformat) {
05545   case D3DFMT_D32:     depth=32; stencil=0; break;
05546   case D3DFMT_D15S1:   depth=15; stencil=1; break;
05547   case D3DFMT_D24S8:   depth=24; stencil=8; break;
05548   case D3DFMT_D16:     depth=16; stencil=0; break;
05549   case D3DFMT_D24X8:   depth=24; stencil=0; break;
05550   case D3DFMT_D24X4S4: depth=24; stencil=4; break;
05551   }
05552   props.set_depth_bits(depth);
05553   props.set_stencil_bits(stencil);
05554   if (multisampletype == D3DMULTISAMPLE_NONMASKABLE) {
05555     props.set_multisamples(2);
05556   } else {
05557     props.set_multisamples(multisampletype);
05558   }
05559   return props;
05560 }
05561 
05562 
05563 #define GAMMA_1 (255.0 * 256.0)
05564 
05565 static bool _gamma_table_initialized = false;
05566 static unsigned short _orignial_gamma_table [256 * 3];
05567 
05568 void _create_gamma_table (float gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
05569   int i;
05570   double gamma_correction;
05571 
05572   if (gamma <= 0.0) {
05573     // avoid divide by zero and negative exponents
05574     gamma = 1.0;
05575   }
05576   gamma_correction = 1.0 / (double) gamma;    
05577   
05578   for (i = 0; i < 256; i++) {
05579     double r;
05580     double g;
05581     double b;
05582 
05583     if (original_red_table) {
05584       r = (double) original_red_table [i] / GAMMA_1;
05585       g = (double) original_green_table [i] / GAMMA_1;
05586       b = (double) original_blue_table [i] / GAMMA_1;
05587     }
05588     else {    
05589       r = ((double) i / 255.0);
05590       g = r;
05591       b = r;
05592     }    
05593 
05594     r = pow (r, gamma_correction);
05595     g = pow (g, gamma_correction);
05596     b = pow (b, gamma_correction);
05597 
05598     if (r > 1.00) {
05599       r = 1.0;
05600     }
05601     if (g > 1.00) {
05602       g = 1.0;
05603     }
05604     if (b > 1.00) {
05605       b = 1.0;
05606     }
05607 
05608     r = r * GAMMA_1;    
05609     g = g * GAMMA_1;    
05610     b = b * GAMMA_1;    
05611 
05612     red_table [i] = r;
05613     green_table [i] = g;
05614     blue_table [i] = b;
05615   }    
05616 }
05617 
05618 ////////////////////////////////////////////////////////////////////
05619 //     Function: DXGraphicsStateGuardian9::get_gamma_table
05620 //       Access: Public, Static
05621 //  Description: Static function for getting the original gamma.
05622 ////////////////////////////////////////////////////////////////////
05623 bool DXGraphicsStateGuardian9::
05624 get_gamma_table(void) {
05625   bool get;  
05626 
05627   get = false;
05628   if (_gamma_table_initialized == false) {
05629     HDC hdc = GetDC(NULL);
05630 
05631     if (hdc) {   
05632       if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) {
05633         _gamma_table_initialized = true;
05634         get = true;
05635       }
05636 
05637       ReleaseDC (NULL, hdc);
05638     }
05639   }
05640   
05641   return get;
05642 }
05643 
05644 ////////////////////////////////////////////////////////////////////
05645 //     Function: DXGraphicsStateGuardian9::static_set_gamma
05646 //       Access: Public, Static
05647 //  Description: Static function for setting gamma which is needed 
05648 //               for atexit.
05649 ////////////////////////////////////////////////////////////////////
05650 bool DXGraphicsStateGuardian9::
05651 static_set_gamma(bool restore, float gamma) {
05652   bool set;  
05653   HDC hdc = GetDC(NULL);
05654 
05655   set = false;
05656   if (hdc) {   
05657     unsigned short ramp [256 * 3];
05658 
05659     if (restore && _gamma_table_initialized) {    
05660       _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
05661     }
05662     else {
05663       _create_gamma_table (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]);
05664     }
05665 
05666     if (SetDeviceGammaRamp (hdc, ramp)) {
05667       set = true;
05668     }
05669     
05670     ReleaseDC (NULL, hdc);
05671   }
05672 
05673   return set;
05674 }
05675 
05676 ////////////////////////////////////////////////////////////////////
05677 //     Function: DXGraphicsStateGuardian9::set_gamma
05678 //       Access: Published
05679 //  Description: Non static version of setting gamma.  Returns true
05680 //               on success.
05681 ////////////////////////////////////////////////////////////////////
05682 bool DXGraphicsStateGuardian9::
05683 set_gamma(float gamma) {
05684   bool set;
05685 
05686   set = static_set_gamma(false, gamma);
05687   if (set) {
05688     _gamma = gamma;  
05689   }
05690 
05691   return set;
05692 }
05693 
05694 ////////////////////////////////////////////////////////////////////
05695 //     Function: DXGraphicsStateGuardian9::restore_gamma
05696 //       Access: Published
05697 //  Description: Restore original gamma.
05698 ////////////////////////////////////////////////////////////////////
05699 void DXGraphicsStateGuardian9::
05700 restore_gamma() {
05701   static_set_gamma(true, 1.0f);
05702 }
05703 
05704 ////////////////////////////////////////////////////////////////////
05705 //     Function: DXGraphicsStateGuardian9::atexit_function
05706 //       Access: Public, Static
05707 //  Description: This function is passed to the atexit function.
05708 ////////////////////////////////////////////////////////////////////
05709 void DXGraphicsStateGuardian9::
05710 atexit_function(void) {
05711   set_cg_device(NULL);
05712   static_set_gamma(true, 1.0f);
05713 }
05714 
05715 ////////////////////////////////////////////////////////////////////
05716 //     Function: DXGraphicsStateGuardian9::get_supports_cg_profile
05717 //       Access: Public, Virtual
05718 //  Description: Returns true if this particular GSG supports the 
05719 //               specified Cg Shader Profile.
05720 ////////////////////////////////////////////////////////////////////
05721 bool DXGraphicsStateGuardian9::
05722 get_supports_cg_profile(const string &name) const {
05723 #ifndef HAVE_CG
05724   return false;
05725 #else
05726   CGprofile profile = cgGetProfile(name.c_str());
05727   
05728   if (profile ==CG_PROFILE_UNKNOWN) {
05729     dxgsg9_cat.error() << name <<", unknown Cg-profile\n";
05730     return false;
05731   }
05732   return cgD3D9IsProfileSupported(cgGetProfile(name.c_str()));
05733 #endif  // HAVE_CG
05734 }
05735 
05736 ////////////////////////////////////////////////////////////////////
05737 //     Function: DXGraphicsStateGuardian9::set_cg_device
05738 //       Access: Protected, Static
05739 //  Description: Sets the global Cg device pointer.  TODO: make this
05740 //               thread-safe somehow.  Maybe Cg is inherently not
05741 //               thread-safe.
05742 ////////////////////////////////////////////////////////////////////
05743 void DXGraphicsStateGuardian9::
05744 set_cg_device(LPDIRECT3DDEVICE9 cg_device) {
05745 #ifdef HAVE_CG
05746   if (_cg_device != cg_device) {
05747     cgD3D9SetDevice(cg_device);
05748     _cg_device = cg_device;
05749   }
05750 #endif // HAVE_CG
05751 }
05752 
05753 
05754 
05755 
05756 typedef string KEY;
05757 
05758 typedef struct _KEY_ELEMENT
05759 {
05760   KEY key;
05761   int count;
05762   int secondary_count;
05763 
05764   struct _KEY_ELEMENT *next;
05765 }
05766 KEY_ELEMENT;
05767 
05768 typedef struct _KEY_LIST
05769 {
05770   int total_key_elements;
05771   KEY_ELEMENT *key_element;
05772 }
05773 KEY_LIST;
05774 
05775 KEY_ELEMENT *new_key_element (KEY key, KEY_LIST *key_list)
05776 {
05777   KEY_ELEMENT *key_element;
05778 
05779   key_element = new KEY_ELEMENT;
05780   key_element -> key = key;
05781   key_element -> count = 1;
05782   key_element -> secondary_count = 0;
05783   key_element -> next = 0;
05784 
05785   key_list -> total_key_elements++;
05786 
05787   return key_element;
05788 }
05789 
05790 KEY_ELEMENT *first_key_element (KEY_LIST *key_list)
05791 {
05792   return key_list -> key_element;
05793 }
05794 
05795 KEY_ELEMENT *next_key_element (KEY_ELEMENT *key_element)
05796 {
05797   return key_element -> next;
05798 }
05799 
05800 void delete_key_list (KEY_LIST *key_list)
05801 {
05802   if (key_list)
05803   {
05804     KEY_ELEMENT *key_element;
05805     KEY_ELEMENT *key_element_next;
05806 
05807     key_element = first_key_element (key_list);
05808     while (key_element)
05809     {
05810       key_element_next = next_key_element (key_element);
05811       delete key_element;
05812       key_element = key_element_next;
05813     }
05814 
05815     delete key_list;
05816   }
05817 }
05818 
05819 KEY_LIST *new_key_list (void)
05820 {
05821   KEY_LIST *key_list;
05822 
05823   key_list = new KEY_LIST;
05824   memset (key_list, 0, sizeof (KEY_LIST));
05825 
05826   return key_list;
05827 }
05828 
05829 KEY_ELEMENT *add_to_key_list (KEY key, KEY_LIST *key_list)
05830 {
05831   KEY_ELEMENT *key_element;
05832   KEY_ELEMENT *last_key_element;
05833   KEY_ELEMENT *current_key_element;
05834 
05835   key_element = 0;
05836   last_key_element = 0;
05837   current_key_element = key_list -> key_element;
05838   if (current_key_element == 0)
05839   {
05840     key_element = new_key_element (key, key_list);
05841     key_list -> key_element = key_element;
05842   }
05843   else
05844   {
05845     while (current_key_element)
05846     {
05847       if (key < current_key_element -> key)
05848       {
05849         key_element = new_key_element (key, key_list);
05850         key_element -> next = current_key_element;
05851 
05852         if (last_key_element == 0)
05853         {
05854           key_list -> key_element = key_element;
05855         }
05856         else
05857         {
05858           last_key_element -> next = key_element;
05859         }
05860         break;
05861       }
05862       else
05863       {
05864         if (key > current_key_element -> key)
05865         {
05866           if (current_key_element -> next == 0)
05867           {
05868             key_element = new_key_element (key, key_list);
05869             current_key_element -> next = key_element;
05870             break;
05871           }
05872           else
05873           {
05874 
05875           }
05876         }
05877         else
05878         {
05879           current_key_element -> count++;
05880           break;
05881         }
05882       }
05883 
05884       last_key_element = current_key_element;
05885       current_key_element = current_key_element -> next;
05886     }
05887   }
05888 
05889   return key_element;
05890 }
 All Classes Functions Variables Enumerations