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