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