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