00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00081
00082
00083
00084 DXGraphicsStateGuardian8::
00085 DXGraphicsStateGuardian8(GraphicsEngine *engine, GraphicsPipe *pipe) :
00086 GraphicsStateGuardian(CS_yup_left, engine, pipe)
00087 {
00088
00089
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
00105
00106
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
00113
00114 _copy_texture_inverted = true;
00115
00116
00117
00118
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
00134
00135
00136
00137 DXGraphicsStateGuardian8::
00138 ~DXGraphicsStateGuardian8() {
00139 if (IS_VALID_PTR(_d3d_device)) {
00140 _d3d_device->SetTexture(0, NULL);
00141 }
00142 free_nondx_resources();
00143 }
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
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
00173
00174
00175
00176
00177 void DXGraphicsStateGuardian8::
00178 apply_texture(int i, TextureContext *tc) {
00179 if (tc == (TextureContext *)NULL) {
00180
00181
00182 _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
00183 return;
00184 }
00185 if (!update_texture(tc, false)) {
00186
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
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
00230
00231
00232 new_mip_filter = D3DTEXF_NONE;
00233 }
00234
00235
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
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266 bool DXGraphicsStateGuardian8::
00267 update_texture(TextureContext *tc, bool force) {
00268 DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc);
00269
00270
00271
00272
00273 if (dtc->was_modified()) {
00274 if (!upload_texture(dtc, force)) {
00275
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
00290
00291
00292
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
00313
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
00330
00331
00332
00333
00334 void DXGraphicsStateGuardian8::
00335 release_texture(TextureContext *tc) {
00336 DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc);
00337 delete dtc;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
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
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
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
00382
00383
00384
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
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
00419
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
00453
00454
00455
00456
00457
00458
00459 void DXGraphicsStateGuardian8::
00460 release_vertex_buffer(VertexBufferContext *vbc) {
00461 DXVertexBufferContext8 *dvbc = DCAST(DXVertexBufferContext8, vbc);
00462 delete dvbc;
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
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
00486
00487
00488
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
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
00518
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
00543
00544
00545
00546
00547
00548
00549 void DXGraphicsStateGuardian8::
00550 release_index_buffer(IndexBufferContext *ibc) {
00551 DXIndexBufferContext8 *dibc = DCAST(DXIndexBufferContext8, ibc);
00552 delete dibc;
00553 }
00554
00555
00556
00557
00558
00559
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
00569
00570
00571
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
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
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
00606
00607 hr = _d3d_device->Clear(0, NULL, D3DCLEAR_TARGET, color_clear_value,
00608 depth_clear_value, stencil_clear_value);
00609 if (!FAILED(hr)) {
00610
00611
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
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
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
00647
00648
00649
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
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
00671
00672
00673
00674
00675
00676
00677
00678
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
00691
00692
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
00706
00707 result *= LMatrix4::scale_mat(1.0f, -1.0f, 1.0f);
00708 }
00709
00710 return TransformState::make_mat(result);
00711 }
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
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
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
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
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
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
00809
00810
00811
00812
00813
00814
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
00842
00843
00844
00845
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
00864
00865
00866 GraphicsStateGuardian::end_frame(current_thread);
00867 }
00868
00869
00870
00871
00872
00873
00874
00875
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
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
00903 switch (animation.get_num_transforms()) {
00904 case 1:
00905
00906
00907
00908
00909
00910
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
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
00942
00943 _transform_stale = true;
00944 }
00945 _vertex_blending_enabled = true;
00946
00947 } else {
00948
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
00965
00966
00967
00968
00969
00970
00971
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
00988
00989
00990
00991 bool DXGraphicsStateGuardian8::
00992 draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
00993
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
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
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
01034 _d3d_device->DrawPrimitive
01035 (D3DPT_TRIANGLELIST,
01036 reader->get_first_vertex(),
01037 reader->get_num_primitives());
01038
01039 } else {
01040
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
01057
01058
01059
01060 bool DXGraphicsStateGuardian8::
01061 draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
01062
01063 if (connect_triangle_strips && _current_fill_mode != RenderModeAttrib::M_wireframe) {
01064
01065
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
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
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
01106 _d3d_device->DrawPrimitive
01107 (D3DPT_TRIANGLESTRIP,
01108 reader->get_first_vertex(),
01109 reader->get_num_vertices() - 2);
01110
01111 } else {
01112
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
01128
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
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
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
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
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
01232
01233
01234
01235 bool DXGraphicsStateGuardian8::
01236 draw_trifans(const GeomPrimitivePipelineReader *reader, bool force) {
01237
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
01246
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
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
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
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
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
01343
01344
01345
01346 bool DXGraphicsStateGuardian8::
01347 draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
01348
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
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
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
01391 _d3d_device->DrawPrimitive
01392 (D3DPT_LINELIST,
01393 reader->get_first_vertex(),
01394 reader->get_num_primitives());
01395
01396 } else {
01397
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
01414
01415
01416
01417 bool DXGraphicsStateGuardian8::
01418 draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force) {
01419 return false;
01420 }
01421
01422
01423
01424
01425
01426
01427 bool DXGraphicsStateGuardian8::
01428 draw_points(const GeomPrimitivePipelineReader *reader, bool force) {
01429
01430 _vertices_other_pcollector.add_level(reader->get_num_vertices());
01431 _primitive_batches_other_pcollector.add_level(1);
01432
01433
01434
01435 nassertr(!reader->is_indexed(), false);
01436
01437 if (_active_vbuffer != NULL) {
01438
01439 _d3d_device->DrawPrimitive
01440 (D3DPT_POINTLIST,
01441 reader->get_first_vertex(),
01442 reader->get_num_primitives());
01443
01444 } else {
01445
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
01461
01462
01463
01464
01465
01466 void DXGraphicsStateGuardian8::
01467 end_draw_primitives() {
01468
01469
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
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
01488
01489
01490
01491
01492
01493
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
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
01522
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
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
01545 SAFE_RELEASE(tex_level_0);
01546 if (!dtc->create_texture(*_screen)) {
01547
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
01566
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
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
01607
01608 return do_framebuffer_copy_to_ram(tex, z, dr, rb, true);
01609 }
01610
01611 return true;
01612 }
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
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
01632
01633
01634
01635
01636
01637
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
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
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
01689
01690
01691 if (_cur_read_pixel_buffer & RenderBuffer::T_back) {
01692 IDirect3DSurface8 *backbuffer = NULL;
01693
01694
01695
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
01704
01705
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
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
01733
01734
01735
01736
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
01745 ClientToScreen(_screen->_window, (POINT*)&rect.left);
01746 ClientToScreen(_screen->_window, (POINT*)&rect.right);
01747 }
01748
01749
01750
01751
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
01792
01793
01794
01795
01796
01797
01798
01799 void DXGraphicsStateGuardian8::
01800 reset() {
01801 GraphicsStateGuardian::reset();
01802
01803 _auto_rescale_normal = false;
01804
01805
01806
01807 HRESULT hr;
01808
01809
01810
01811
01812
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
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
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,
01904 D3DFMT_X8R8G8B8,
01905 D3DFMT_UNKNOWN,
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
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
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
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
02012
02013
02014
02015 _do_fog_type = PerPixelFog;
02016 } else {
02017
02018
02019 nassertv((_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGVERTEX) != 0);
02020
02021
02022
02023
02024 if (dx_no_vertex_fog) {
02025 _do_fog_type = None;
02026 } else {
02027 _do_fog_type = PerVertexFog;
02028
02029
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
02039 _d3d_device->SetRenderState(D3DRS_LIGHTING, false);
02040
02041
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
02049 _d3d_device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
02050
02051
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
02058
02059
02060 _d3d_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
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
02070
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
02079
02080 add_gsg(this);
02081 }
02082
02083
02084
02085
02086
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));
02101
02102
02103
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
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
02131
02132
02133
02134
02135
02136
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
02155
02156
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
02167 _d3d_device->SetRenderState(D3DRS_ALPHAFUNC, (D3DCMPFUNC)mode);
02168 _d3d_device->SetRenderState(D3DRS_ALPHAREF, (UINT) (target_alpha_test->get_reference_alpha()*255.0f));
02169 _d3d_device->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
02170 }
02171 }
02172
02173
02174
02175
02176
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
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
02229
02230
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
02262
02263
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
02279
02280
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
02294
02295
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
02321
02322
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
02339
02340
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
02351
02352
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
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
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
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
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
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
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
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
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
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
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
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
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
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
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
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
02528 determine_target_texture();
02529
02530
02531
02532
02533
02534
02535
02536
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
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
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
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
02574 do_issue_scissor();
02575 _state_mask.set_bit(scissor_slot);
02576 }
02577
02578 _state_rs = _target_rs;
02579 }
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589 void DXGraphicsStateGuardian8::
02590 bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
02591
02592
02593
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
02609
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
02630
02631
02632
02633
02634
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
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
02645
02646
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;
02668 fdata.Attenuation1 = 0.0f;
02669 fdata.Attenuation2 = 0.0f;
02670 }
02671
02672
02673
02674
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
02687
02688
02689
02690
02691
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
02699
02700
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
02726
02727
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
02749
02750
02751
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
02770
02771
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
02797 _d3d_device->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
02798 } else {
02799
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
02810 _d3d_device->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
02811 } else {
02812
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
02839
02840
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
02853
02854
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
02865
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
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
02893
02894
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
02907
02908
02909
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
02928
02929
02930
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
02949
02950
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
02974
02975
02976
02977
02978
02979
02980
02981
02982
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 ( texcoord_dimensions <= 2) {
03001
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
03017
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
03028
03029
03030 _d3d_device->SetTransform(get_tex_mat_sym(si), &_d3d_ident_mat);
03031 }
03032 }
03033
03034
03035 for (si = num_stages; si < _num_active_texture_stages; si++) {
03036 _d3d_device->SetTextureStageState(si, D3DTSS_COLOROP, D3DTOP_DISABLE);
03037 }
03038
03039
03040 _num_active_texture_stages = num_stages;
03041 }
03042
03043
03044
03045
03046
03047
03048
03049
03050
03051 void DXGraphicsStateGuardian8::
03052 reissue_transforms() {
03053 prepare_lens();
03054 do_issue_transform();
03055 }
03056
03057
03058
03059
03060
03061
03062
03063
03064
03065 void DXGraphicsStateGuardian8::
03066 enable_lighting(bool enable) {
03067 _d3d_device->SetRenderState(D3DRS_LIGHTING, (DWORD)enable);
03068 }
03069
03070
03071
03072
03073
03074
03075
03076
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
03091
03092
03093
03094
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
03109
03110
03111
03112
03113
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
03127
03128
03129
03130
03131
03132
03133 void DXGraphicsStateGuardian8::
03134 bind_clip_plane(const NodePath &plane, int plane_id) {
03135
03136
03137
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
03155
03156
03157
03158
03159
03160
03161 void DXGraphicsStateGuardian8::
03162 do_issue_blending() {
03163
03164
03165
03166
03167
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
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
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
03249 _d3d_device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
03250 }
03251
03252
03253
03254
03255
03256
03257
03258
03259
03260 void DXGraphicsStateGuardian8::
03261 close_gsg() {
03262 GraphicsStateGuardian::close_gsg();
03263
03264
03265
03266 if (_prepared_objects->get_ref_count() == 1) {
03267 release_all();
03268
03269
03270
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
03279
03280
03281
03282
03283 void DXGraphicsStateGuardian8::
03284 free_nondx_resources() {
03285 }
03286
03287
03288
03289
03290
03291
03292
03293 void DXGraphicsStateGuardian8::
03294 free_d3d_device() {
03295
03296 _state_rs = RenderState::make_empty();
03297 _state_mask.clear();
03298
03299
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);
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
03315 }
03316
03317
03318
03319
03320
03321
03322
03323
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
03333
03334
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
03350
03351
03352
03353
03354
03355 void DXGraphicsStateGuardian8::
03356 do_auto_rescale_normal() {
03357 if (_internal_transform->has_identity_scale()) {
03358
03359 _d3d_device->SetRenderState(D3DRS_NORMALIZENORMALS, false);
03360
03361 } else {
03362
03363 _d3d_device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
03364 }
03365 }
03366
03367
03368
03369
03370
03371
03372
03373
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
03388
03389
03390
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
03427 return D3DBLEND_SRCCOLOR;
03428
03429 case ColorBlendAttrib::O_one_minus_constant_color:
03430
03431 return D3DBLEND_INVSRCCOLOR;
03432
03433 case ColorBlendAttrib::O_constant_alpha:
03434
03435 return D3DBLEND_SRCALPHA;
03436
03437 case ColorBlendAttrib::O_one_minus_constant_alpha:
03438
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
03452
03453
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
03508
03509 if (_texmgrmem_total_pcollector.is_active()) {
03510
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
03525
03526
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;
03533 _swap_chain = _screen->_swap_chain;
03534
03535 _screen->_dxgsg8 = this;
03536 }
03537
03538
03539
03540
03541
03542
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)
03553 _d3d_device->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &back);
03554 else
03555 _swap_chain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &back);
03556
03557
03558
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
03572
03573
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
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
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
03634
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
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
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
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
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
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
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
03712
03713
03714
03715
03716
03717
03718
03719
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
03739
03740
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
03752
03753 RELEASE(_d3d_device, dxgsg8, "d3dDevice", RELEASE_DOWN_TO_ZERO);
03754 _screen->_d3d_device = NULL;
03755
03756
03757 }
03758
03759
03760
03761
03762
03763
03764
03765
03766
03767
03768
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
03780
03781 _screen->_d3d8->GetAdapterDisplayMode(_screen->_card_id, &_screen->_display_mode);
03782 presentation_params->BackBufferFormat = _screen->_display_mode.Format;
03783
03784
03785
03786
03787
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);
03801
03802 if (_screen->_swap_chain) {
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 {
03807 _presentation_reset.BackBufferWidth = presentation_params->BackBufferWidth;
03808 _presentation_reset.BackBufferHeight = presentation_params->BackBufferHeight;
03809 }
03810
03811
03812
03813
03814
03815 release_all();
03816
03817
03818
03819
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
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);
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
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
03886
03887
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
03907 _prepared_objects->begin_frame(this, Thread::get_current_thread());
03908
03909 hr = reset_d3d_device(&_screen->_presentation_params);
03910 if (FAILED(hr)) {
03911
03912
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
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
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
03948
03949
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
03978
03979
03980
03981 bool DXGraphicsStateGuardian8::
03982 create_swap_chain(DXScreenData *new_context) {
03983
03984
03985
03986
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
04001
04002
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
04021
04022
04023
04024 void DXGraphicsStateGuardian8::
04025 copy_pres_reset(DXScreenData *screen) {
04026 memcpy(&_presentation_reset, &_screen->_presentation_params, sizeof(D3DPRESENT_PARAMETERS));
04027 }
04028
04029
04030
04031
04032
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
04067
04068
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
04103
04104
04105
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
04151
04152
04153
04154
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
04184
04185
04186
04187
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
04214
04215
04216
04217
04218
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
04228
04229
04230
04231
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
04238
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
04244 _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count,
04245 buffer_start, stride);
04246
04247 } else {
04248
04249
04250
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
04261
04262
04263
04264
04265
04266
04267
04268
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
04278
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
04284
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
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
04297
04298
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
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
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
04389 break;
04390 case StencilRenderStates::SRS_back_stencil_fail_operation:
04391
04392 break;
04393 case StencilRenderStates::SRS_back_stencil_pass_z_fail_operation:
04394
04395 break;
04396 case StencilRenderStates::SRS_back_stencil_pass_z_pass_operation:
04397
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
04417
04418
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
04474
04475
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
04486
04487
04488
04489
04490 void DXGraphicsStateGuardian8::
04491 set_scissor(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
04492
04493
04494
04495
04496
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
04528
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
04535
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
04545
04546
04547
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
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
04652
04653
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
04678
04679
04680
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
04710
04711
04712
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
04728
04729
04730
04731 void DXGraphicsStateGuardian8::
04732 restore_gamma() {
04733 static_set_gamma(true, 1.0f);
04734 }
04735
04736
04737
04738
04739
04740
04741 void DXGraphicsStateGuardian8::
04742 atexit_function(void) {
04743 static_set_gamma(true, 1.0);
04744 }