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