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