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