Panda3D

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