Panda3D
dxGraphicsStateGuardian9.cxx
1 // Filename: dxGraphicsStateGuardian9.cxx
2 // Created by: mike (02Feb99)
3 // Updated by: fperazzi, PandaSE (05May10) (added get_supports_cg_profile)
4 //
5 ////////////////////////////////////////////////////////////////////
6 //
7 // PANDA 3D SOFTWARE
8 // Copyright (c) Carnegie Mellon University. All rights reserved.
9 //
10 // All use of this software is subject to the terms of the revised BSD
11 // license. You should have received a copy of this license along
12 // with this source code in a file named "LICENSE."
13 //
14 ////////////////////////////////////////////////////////////////////
15 
16 #include "dxGraphicsStateGuardian9.h"
17 #include "config_dxgsg9.h"
18 #include "displayRegion.h"
19 #include "renderBuffer.h"
20 #include "geom.h"
21 #include "graphicsWindow.h"
22 #include "graphicsEngine.h"
23 #include "lens.h"
24 #include "ambientLight.h"
25 #include "directionalLight.h"
26 #include "pointLight.h"
27 #include "spotlight.h"
28 #include "textureAttrib.h"
29 #include "texGenAttrib.h"
30 #include "shadeModelAttrib.h"
31 #include "cullFaceAttrib.h"
32 #include "transparencyAttrib.h"
33 #include "alphaTestAttrib.h"
34 #include "depthTestAttrib.h"
35 #include "depthWriteAttrib.h"
36 #include "colorWriteAttrib.h"
37 #include "texMatrixAttrib.h"
38 #include "materialAttrib.h"
39 #include "renderModeAttrib.h"
40 #include "rescaleNormalAttrib.h"
41 #include "fogAttrib.h"
42 #include "depthOffsetAttrib.h"
43 #include "lightAttrib.h"
44 #include "stencilAttrib.h"
45 #include "scissorAttrib.h"
46 #include "clipPlaneAttrib.h"
47 #include "fog.h"
48 #include "throw_event.h"
49 #include "geomVertexFormat.h"
50 #include "geomVertexData.h"
51 #include "geomTriangles.h"
52 #include "geomTristrips.h"
53 #include "geomTrifans.h"
54 #include "geomLines.h"
55 #include "geomLinestrips.h"
56 #include "geomPoints.h"
57 #include "geomVertexReader.h"
58 #include "dxGeomMunger9.h"
59 #include "config_gobj.h"
60 #include "dxVertexBufferContext9.h"
61 #include "dxIndexBufferContext9.h"
62 #include "dxOcclusionQueryContext9.h"
63 #include "pStatTimer.h"
64 #include "pStatCollector.h"
65 #include "wdxGraphicsBuffer9.h"
66 #include "config_pgraph.h"
67 #include "shaderGenerator.h"
68 #ifdef HAVE_CG
69 #include "Cg/cgD3D9.h"
70 #endif
71 
72 #include <mmsystem.h>
73 
74 #include <dxsdkver.h>
75 
76 #define tostring(x) #x
77 #define SDK_VERSION(major,minor) tostring(major) << "." << tostring(minor)
78 #define DIRECTX_SDK_VERSION SDK_VERSION (_DXSDK_PRODUCT_MAJOR, _DXSDK_PRODUCT_MINOR) << "." << SDK_VERSION (_DXSDK_BUILD_MAJOR, _DXSDK_BUILD_MINOR)
79 
80 TypeHandle DXGraphicsStateGuardian9::_type_handle;
81 
82 D3DMATRIX DXGraphicsStateGuardian9::_d3d_ident_mat;
83 
84 unsigned char *DXGraphicsStateGuardian9::_temp_buffer = NULL;
85 unsigned char *DXGraphicsStateGuardian9::_safe_buffer_start = NULL;
86 
87 #ifdef HAVE_CG
88 LPDIRECT3DDEVICE9 DXGraphicsStateGuardian9::_cg_device = NULL;
89 #endif
90 
91 #define __D3DLIGHT_RANGE_MAX ((PN_stdfloat)sqrt(FLT_MAX)) //for some reason this is missing in dx9 hdrs
92 
93 #define MY_D3DRGBA(r, g, b, a) ((D3DCOLOR) D3DCOLOR_COLORVALUE(r, g, b, a))
94 
95 ////////////////////////////////////////////////////////////////////
96 // Function: DXGraphicsStateGuardian9::Constructor
97 // Access: Public
98 // Description:
99 ////////////////////////////////////////////////////////////////////
100 DXGraphicsStateGuardian9::
101 DXGraphicsStateGuardian9(GraphicsEngine *engine, GraphicsPipe *pipe) :
102  GraphicsStateGuardian(CS_yup_left, engine, pipe)
103 {
104  if (dxgsg9_cat.is_debug()) {
105  dxgsg9_cat.debug()
106  << "DXGraphicsStateGuardian9 " << this << " constructing\n";
107  }
108 
109  // Assume that we will get a hardware-accelerated context, unless
110  // the window tells us otherwise.
111  _is_hardware = true;
112 
113  _screen = NULL;
114  _d3d_device = NULL;
115 
116  _dx_is_ready = false;
117  _vertex_blending_enabled = false;
118  _overlay_windows_supported = false;
119  _tex_stats_retrieval_impossible = false;
120  _supports_render_texture = false;
121 
122  _active_ibuffer = NULL;
123 
124  // This is a static member, but we initialize it here in the
125  // constructor anyway. It won't hurt if it gets repeatedly
126  // initalized.
127  ZeroMemory(&_d3d_ident_mat, sizeof(D3DMATRIX));
128  _d3d_ident_mat._11 = _d3d_ident_mat._22 = _d3d_ident_mat._33 = _d3d_ident_mat._44 = 1.0f;
129 
130  _cur_read_pixel_buffer = RenderBuffer::T_front;
131 
132  // DirectX drivers seem to consistently invert the texture when
133  // they copy framebuffer-to-texture. Ok.
134  _copy_texture_inverted = true;
135 
136  _gsg_managed_textures = dx_management | dx_texture_management;
137  _gsg_managed_vertex_buffers = dx_management;
138  _gsg_managed_index_buffers = dx_management;
139 
140  _last_fvf = 0;
141  _num_bound_streams = 0;
142 
143  _vertex_shader_version_major = 0;
144  _vertex_shader_version_minor = 0;
145  _pixel_shader_version_major = 0;
146  _pixel_shader_version_minor = 0;
147 
148  _vertex_shader_profile = 0;
149  _pixel_shader_profile = 0;
150 
151  _vertex_shader_maximum_constants = 0;
152 
153  _supports_stream_offset = false;
154 
155 #ifdef HAVE_CG
156  _cg_context = 0;
157 #endif
158 
159  get_gamma_table();
160  atexit (atexit_function);
161 }
162 
163 ////////////////////////////////////////////////////////////////////
164 // Function: DXGraphicsStateGuardian9::Destructor
165 // Access: Public
166 // Description:
167 ////////////////////////////////////////////////////////////////////
168 DXGraphicsStateGuardian9::
169 ~DXGraphicsStateGuardian9() {
170  if (dxgsg9_cat.is_debug()) {
171  dxgsg9_cat.debug()
172  << "DXGraphicsStateGuardian9 " << this << " destructing\n";
173  }
174 
175  if (IS_VALID_PTR(_d3d_device)) {
176  _d3d_device->SetTexture(0, NULL); // this frees reference to the old texture
177  }
178 
179  free_nondx_resources();
180 }
181 
182 ////////////////////////////////////////////////////////////////////
183 // Function: DXGraphicsStateGuardian9::prepare_texture
184 // Access: Public, Virtual
185 // Description: Creates a new retained-mode representation of the
186 // given texture, and returns a newly-allocated
187 // TextureContext pointer to reference it. It is the
188 // responsibility of the calling function to later
189 // call release_texture() with this same pointer (which
190 // will also delete the pointer).
191 //
192 // This function should not be called directly to
193 // prepare a texture. Instead, call Texture::prepare().
194 ////////////////////////////////////////////////////////////////////
196 prepare_texture(Texture *tex, int view) {
197  DXTextureContext9 *dtc = new DXTextureContext9(_prepared_objects, tex, view);
198 
199  if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) {
200  dxgsg9_cat.error()
201  << *dtc->get_texture() << " is stored in an unsupported compressed format.\n";
202  return NULL;
203  }
204 
205  return dtc;
206 }
207 
208 ////////////////////////////////////////////////////////////////////
209 // Function: DXGraphicsStateGuardian9::apply_texture
210 // Access: Public
211 // Description: Makes the texture the currently available texture for
212 // rendering on the ith stage.
213 ////////////////////////////////////////////////////////////////////
215 apply_texture(int i, TextureContext *tc, const SamplerState &sampler) {
216  if (tc == (TextureContext *)NULL) {
217  // The texture wasn't bound properly or something, so ensure
218  // texturing is disabled and just return.
219  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
220  return;
221  }
222  if (!update_texture(tc, false)) {
223  // Couldn't get the texture image or something.
224  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
225  return;
226  }
227 
228  tc->set_active(true);
229 
230  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
231  Texture *tex = tc->get_texture();
232 
233  //if (tex->get_color_space() == CS_srgb) {
234  if (Texture::is_srgb(tex->get_format())) {
235  set_sampler_state(i, D3DSAMP_SRGBTEXTURE, TRUE);
236  } else {
237  set_sampler_state(i, D3DSAMP_SRGBTEXTURE, FALSE);
238  }
239 
240  set_sampler_state(i, D3DSAMP_ADDRESSU,
241  get_texture_wrap_mode(sampler.get_wrap_u()));
242 
243  set_sampler_state(i, D3DSAMP_ADDRESSV,
244  get_texture_wrap_mode(sampler.get_wrap_v()));
245 
246  set_sampler_state(i, D3DSAMP_ADDRESSW,
247  get_texture_wrap_mode(sampler.get_wrap_w()));
248 
249  DWORD border_color;
250  border_color = LColor_to_D3DCOLOR(sampler.get_border_color());
251 
252  set_sampler_state(i, D3DSAMP_BORDERCOLOR, border_color);
253 
254  uint aniso_degree = sampler.get_effective_anisotropic_degree();
255  SamplerState::FilterType ft = sampler.get_effective_magfilter();
256 
257  if (aniso_degree >= 1) {
258  set_sampler_state(i, D3DSAMP_MAXANISOTROPY, aniso_degree);
259  }
260 
261  int supports_anisotropic_mag_filter;
262  D3DTEXTUREFILTERTYPE new_mag_filter;
263 
264  supports_anisotropic_mag_filter = (_screen -> _d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) != 0;
265  if (aniso_degree <= 1 || supports_anisotropic_mag_filter == 0) {
266  new_mag_filter = ((ft != SamplerState::FT_nearest) ? D3DTEXF_LINEAR : D3DTEXF_POINT);
267  } else {
268  new_mag_filter = D3DTEXF_ANISOTROPIC;
269  }
270 
271  HRESULT hr;
272  hr = set_sampler_state(i, D3DSAMP_MAGFILTER, new_mag_filter);
273  if (hr != D3D_OK) {
274  dxgsg9_cat.error()
275  << "ERROR: set_sampler_state (D3DSAMP_MAGFILTER, "
276  << new_mag_filter << ") failed for sampler: " << sampler << endl;
277  }
278 
279  // map Panda composite min+mip filter types to d3d's separate min & mip filter types
280  D3DTEXTUREFILTERTYPE new_min_filter = get_d3d_min_type(sampler.get_effective_minfilter());
281  D3DTEXTUREFILTERTYPE new_mip_filter = get_d3d_mip_type(sampler.get_effective_minfilter());
282 
283  if (!tex->might_have_ram_image()) {
284  // If the texture is completely dynamic, don't try to issue
285  // mipmaps--pandadx doesn't support auto-generated mipmaps at this
286  // point.
287  new_mip_filter = D3DTEXF_NONE;
288  }
289 
290  // sanity check
291  if (!dtc->has_mipmaps()) {
292  new_mip_filter = D3DTEXF_NONE;
293  }
294 
295  if (aniso_degree >= 2) {
296  new_min_filter = D3DTEXF_ANISOTROPIC;
297  }
298 
299  set_sampler_state(i, D3DSAMP_MINFILTER, new_min_filter);
300  set_sampler_state(i, D3DSAMP_MIPFILTER, new_mip_filter);
301 
302  float lod_bias = sampler.get_lod_bias();
303  set_sampler_state(i, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&lod_bias);
304 
305  _d3d_device->SetTexture(i, dtc->get_d3d_texture());
306 }
307 
308 ////////////////////////////////////////////////////////////////////
309 // Function: DXGraphicsStateGuardian9::update_texture
310 // Access: Public, Virtual
311 // Description: Ensures that the current Texture data is refreshed
312 // onto the GSG. This means updating the texture
313 // properties and/or re-uploading the texture image, if
314 // necessary. This should only be called within the
315 // draw thread.
316 //
317 // If force is true, this function will not return until
318 // the texture has been fully uploaded. If force is
319 // false, the function may choose to upload a simple
320 // version of the texture instead, if the texture is not
321 // fully resident (and if get_incomplete_render() is
322 // true).
323 ////////////////////////////////////////////////////////////////////
325 update_texture(TextureContext *tc, bool force) {
326  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
327 
328  // If the texture image has changed, or if its use of mipmaps has
329  // changed, we need to re-create the image.
330 
331  if (dtc->was_modified()) {
332  if (!upload_texture(dtc, force)) {
333  // Oops, we can't re-create the texture for some reason.
334  Texture *tex = tc->get_texture();
335  dxgsg9_cat.error()
336  << "Unable to re-create texture " << *tex << endl;
337  return false;
338  }
339  }
340  dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
341 
342  return true;
343 }
344 
345 ////////////////////////////////////////////////////////////////////
346 // Function: DXGraphicsStateGuardian9::upload_texture
347 // Access: Public
348 // Description: Creates a texture surface on the graphics card and
349 // fills it with its pixel data.
350 ////////////////////////////////////////////////////////////////////
353  Texture *tex = dtc->get_texture();
354  if (!get_supports_compressed_texture_format(tex->get_ram_image_compression())) {
355  dxgsg9_cat.error()
356  << *tex << " is stored in an unsupported compressed format.\n";
357  return false;
358  }
359 
360  dtc->delete_texture();
361  dtc->update_data_size_bytes(0);
362  dtc->mark_unloaded();
363 
364  if (_effective_incomplete_render && !force) {
365  bool has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image();
366  if (!has_image && tex->might_have_ram_image() &&
367  tex->has_simple_ram_image() &&
368  !_loader.is_null()) {
369  // If we don't have the texture data right now, go get it, but in
370  // the meantime load a temporary simple image in its place.
371  async_reload_texture(dtc);
372  has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image();
373  if (!has_image) {
374  if (dtc->was_simple_image_modified()) {
375  return dtc->create_simple_texture(*_screen);
376  }
377  return true;
378  }
379  }
380  }
381 
382  return dtc->create_texture(*_screen);
383 }
384 
385 ////////////////////////////////////////////////////////////////////
386 // Function: DXGraphicsStateGuardian9::release_texture
387 // Access: Public, Virtual
388 // Description: Frees the GL resources previously allocated for the
389 // texture.
390 ////////////////////////////////////////////////////////////////////
393  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
394  delete dtc;
395 }
396 
397 ////////////////////////////////////////////////////////////////////
398 // Function: DXGraphicsStateGuardian9::extract_texture_data
399 // Access: Public, Virtual
400 // Description: This method should only be called by the
401 // GraphicsEngine. Do not call it directly; call
402 // GraphicsEngine::extract_texture_data() instead.
403 //
404 // This method will be called in the draw thread to
405 // download the texture memory's image into its
406 // ram_image value. It returns true on success, false
407 // otherwise.
408 ////////////////////////////////////////////////////////////////////
411  bool success = true;
412 
413  int num_views = tex->get_num_views();
414  for (int view = 0; view < num_views; ++view) {
415  TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
416  nassertr(tc != (TextureContext *)NULL, false);
417  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
418 
419  if (!dtc->extract_texture_data(*_screen)) {
420  success = false;
421  }
422  }
423 
424  return success;
425 }
426 
427 ////////////////////////////////////////////////////////////////////
428 // Function: DXGraphicsStateGuardian9::prepare_shader
429 // Access: Public, Virtual
430 // Description:
431 ////////////////////////////////////////////////////////////////////
434  PStatTimer timer(_prepare_shader_pcollector);
435 
436  switch (se->get_language()) {
437  case Shader::SL_GLSL:
438  dxgsg9_cat.error()
439  << "Tried to load GLSL shader, but GLSL shaders not supported by Direct3D 9.\n";
440  return NULL;
441 
442  case Shader::SL_Cg:
443 #ifdef HAVE_CG
444  if (_supports_basic_shaders) {
445  return new CLP(ShaderContext)(se, this);
446  } else {
447  dxgsg9_cat.error()
448  << "Tried to load Cg shader, but basic shaders not supported.\n";
449  return NULL;
450  }
451 #else
452  dxgsg9_cat.error()
453  << "Tried to load Cg shader, but Cg support not compiled in.\n";
454  return NULL;
455 #endif
456 
457  default:
458  dxgsg9_cat.error()
459  << "Tried to load shader with unsupported shader language!\n";
460  return NULL;
461  }
462 
463  return NULL;
464 }
465 
466 ////////////////////////////////////////////////////////////////////
467 // Function: DXGraphicsStateGuardian9::release_shader
468 // Access: Public, Virtual
469 // Description:
470 ////////////////////////////////////////////////////////////////////
473  CLP(ShaderContext) *gsc = DCAST(CLP(ShaderContext), sc);
474  delete gsc;
475 }
476 
477 ////////////////////////////////////////////////////////////////////
478 // Function: DXGraphicsStateGuardian9::prepare_vertex_buffer
479 // Access: Public, Virtual
480 // Description: Creates a new retained-mode representation of the
481 // given data, and returns a newly-allocated
482 // VertexBufferContext pointer to reference it. It is the
483 // responsibility of the calling function to later
484 // call release_vertex_buffer() with this same pointer (which
485 // will also delete the pointer).
486 //
487 // This function should not be called directly to
488 // prepare a buffer. Instead, call Geom::prepare().
489 ////////////////////////////////////////////////////////////////////
491 prepare_vertex_buffer(GeomVertexArrayData *data) {
492  CLP(VertexBufferContext) *dvbc = new CLP(VertexBufferContext)(this, _prepared_objects, data);
493 
494  DWORD usage;
495  D3DPOOL pool;
496  if (_screen->_managed_vertex_buffers) {
497  pool = D3DPOOL_MANAGED;
498  usage = D3DUSAGE_WRITEONLY;
499  } else {
500  pool = D3DPOOL_DEFAULT;
501  usage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC;
502  }
503 
504  int num_bytes = data->get_data_size_bytes();
505 
506  PStatTimer timer(_create_vertex_buffer_pcollector, Thread::get_current_thread());
507 
508  HRESULT hr;
509  int attempts = 0;
510  do
511  {
512  hr = _screen->_d3d_device->CreateVertexBuffer(num_bytes, usage, dvbc->_fvf, pool, &dvbc->_vbuffer, NULL);
513  attempts++;
514  }
515  while (check_dx_allocation(hr, num_bytes, attempts));
516 
517  if (!FAILED(hr)) {
518  #if 0
519  if (dxgsg9_cat.is_debug() && CLP(debug_buffers)) {
520  dxgsg9_cat.debug()
521  << "creating vertex buffer " << dvbc->_vbuffer << ": "
522  << data->get_num_rows() << " vertices "
523  << *data->get_array_format() << "\n";
524  }
525  #endif
526 
527  return dvbc;
528  } else {
529  dxgsg9_cat.error()
530  << "CreateVertexBuffer failed" << D3DERRORSTRING(hr);
531 
532  dvbc->_vbuffer = NULL;
533  }
534 
535  return NULL;
536 }
537 
538 ////////////////////////////////////////////////////////////////////
539 // Function: DXGraphicsStateGuardian9::apply_vertex_buffer
540 // Access: Public
541 // Description: Updates the vertex buffer with the current data, and
542 // makes it the current vertex buffer for rendering.
543 ////////////////////////////////////////////////////////////////////
544 bool CLP(GraphicsStateGuardian)::
545 apply_vertex_buffer(VertexBufferContext *vbc,
546  const GeomVertexArrayDataHandle *reader, bool force ) {
547 
548  CLP(VertexBufferContext) *dvbc = DCAST(CLP(VertexBufferContext), vbc);
549 
550  if (dvbc->was_modified(reader)) {
551  int num_bytes = reader->get_data_size_bytes();
552  #if 0
553  if (dxgsg9_cat.is_debug() && CLP(debug_buffers)) {
554  dxgsg9_cat.debug()
555  << "copying " << num_bytes
556  << " bytes into vertex buffer " << dvbc->_vbuffer << "\n";
557  }
558  #endif
559 
560  if ( num_bytes != 0 ) {
561  const unsigned char *client_pointer = reader->get_read_pointer(force);
562  if (client_pointer == NULL) {
563  return false;
564  }
565 
566  PStatTimer timer(_load_vertex_buffer_pcollector, reader->get_current_thread());
567 
568  #if 0
569  if (dvbc->changed_size(reader)) {
570  // We have to destroy the old vertex buffer and create a new
571  // one.
572  dvbc->create_vbuffer(*_screen, reader);
573  }
574  #endif
575 
576  HRESULT hr;
577  BYTE *local_pointer;
578  if (_screen->_managed_vertex_buffers) {
579  hr = dvbc->_vbuffer->Lock(0, num_bytes, (void **) &local_pointer, 0);
580  } else {
581  hr = dvbc->_vbuffer->Lock(0, num_bytes, (void **) &local_pointer, D3DLOCK_DISCARD);
582  }
583  if (FAILED(hr)) {
584  dxgsg9_cat.error()
585  << "VertexBuffer::Lock failed" << D3DERRORSTRING(hr);
586  return false;
587  }
588 
589  memcpy(local_pointer, client_pointer, num_bytes);
590 
591  dvbc->_vbuffer->Unlock();
592 
593  _data_transferred_pcollector.add_level(num_bytes);
594  }
595 
596  dvbc->mark_loaded(reader);
597  }
598  dvbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
599 
600  return true;
601 }
602 
603 ////////////////////////////////////////////////////////////////////
604 // Function: DXGraphicsStateGuardian9::release_vertex_buffer
605 // Access: Public, Virtual
606 // Description: Frees the GL resources previously allocated for the
607 // data. This function should never be called
608 // directly; instead, call Data::release() (or simply
609 // let the Data destruct).
610 ////////////////////////////////////////////////////////////////////
611 void CLP(GraphicsStateGuardian)::
612 release_vertex_buffer(VertexBufferContext *vbc) {
613 
614  CLP(VertexBufferContext) *dvbc = DCAST(CLP(VertexBufferContext), vbc);
615 
616  #if 0
617  if (dxgsg9_cat.is_debug() && CLP(debug_buffers)) {
618  dxgsg9_cat.debug()
619  << "deleting vertex buffer " << dvbc->_vbuffer << "\n";
620  }
621  #endif
622 
623  dvbc->_vbuffer->Release();
624  dvbc->_vbuffer = NULL;
625 
626  delete dvbc;
627 }
628 
629 ////////////////////////////////////////////////////////////////////
630 // Function: DXGraphicsStateGuardian9::setup_array_data
631 // Access: Public
632 // Description: Internal function to bind a buffer object for the
633 // indicated data array, if appropriate, or to unbind a
634 // buffer object if it should be rendered from client
635 // memory.
636 //
637 // If the buffer object is bound, this function sets
638 // client_pointer to NULL (representing the start of the
639 // buffer object in server memory); if the buffer object
640 // is not bound, this function sets client_pointer the
641 // pointer to the data array in client memory, that is,
642 // the data array passed in.
643 //
644 // If force is not true, the function may return false
645 // indicating the data is not currently available.
646 ////////////////////////////////////////////////////////////////////
647 bool CLP(GraphicsStateGuardian)::
648 setup_array_data(CLP(VertexBufferContext)*& dvbc,
649  const GeomVertexArrayDataHandle* array_reader,
650  bool force) {
651 
652  // Prepare the buffer object and bind it.
653  VertexBufferContext* vbc = ((GeomVertexArrayData *)array_reader->get_object())->prepare_now(get_prepared_objects(), this);
654  nassertr(vbc != (VertexBufferContext *)NULL, false);
655  if (!apply_vertex_buffer(vbc, array_reader, force)) {
656  return false;
657  }
658 
659  dvbc = (CLP(VertexBufferContext)*)vbc;
660  return true;
661 }
662 
663 ////////////////////////////////////////////////////////////////////
664 // Function: DXGraphicsStateGuardian9::prepare_index_buffer
665 // Access: Public, Virtual
666 // Description: Creates a new retained-mode representation of the
667 // given data, and returns a newly-allocated
668 // IndexBufferContext pointer to reference it. It is the
669 // responsibility of the calling function to later call
670 // release_index_buffer() with this same pointer (which
671 // will also delete the pointer).
672 //
673 // This function should not be called directly to
674 // prepare a buffer. Instead, call Geom::prepare().
675 ////////////////////////////////////////////////////////////////////
678  DXIndexBufferContext9 *dibc = new DXIndexBufferContext9(_prepared_objects, data);
679  return dibc;
680 }
681 
682 ////////////////////////////////////////////////////////////////////
683 // Function: DXGraphicsStateGuardian9::apply_index_buffer
684 // Access: Public
685 // Description: Updates the index buffer with the current data, and
686 // makes it the current index buffer for rendering.
687 ////////////////////////////////////////////////////////////////////
690  const GeomPrimitivePipelineReader *reader, bool force) {
691  DXIndexBufferContext9 *dibc = DCAST(DXIndexBufferContext9, ibc);
692 
693  if (dibc->_ibuffer == NULL) {
694  // Attempt to create a new index buffer.
695  dibc->create_ibuffer(*_screen, reader);
696 
697  if (dibc->_ibuffer != NULL) {
698  if (!dibc->upload_data(reader, force)) {
699  return false;
700  }
701  dibc->mark_loaded(reader);
702 
703  _d3d_device->SetIndices(dibc->_ibuffer);
704  _active_ibuffer = dibc;
705  dibc->set_active(true);
706 
707  } else {
708  _d3d_device->SetIndices(NULL);
709  _active_ibuffer = NULL;
710  }
711 
712  } else {
713  if (dibc->was_modified(reader)) {
714  if (dibc->changed_size(reader)) {
715  // We have to destroy the old index buffer and create a new
716  // one.
717  dibc->create_ibuffer(*_screen, reader);
718  }
719 
720  if (!dibc->upload_data(reader, force)) {
721  return false;
722  }
723 
724  dibc->mark_loaded(reader);
725  _active_ibuffer = NULL;
726  }
727 
728  if (_active_ibuffer != dibc) {
729  _d3d_device->SetIndices(dibc->_ibuffer);
730  _active_ibuffer = dibc;
731  dibc->set_active(true);
732  }
733  }
734  dibc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
735 
736  return true;
737 }
738 
739 ////////////////////////////////////////////////////////////////////
740 // Function: DXGraphicsStateGuardian9::release_index_buffer
741 // Access: Public, Virtual
742 // Description: Frees the GL resources previously allocated for the
743 // data. This function should never be called
744 // directly; instead, call Data::release() (or simply
745 // let the Data destruct).
746 ////////////////////////////////////////////////////////////////////
749  DXIndexBufferContext9 *dibc = DCAST(DXIndexBufferContext9, ibc);
750  delete dibc;
751 }
752 
753 ////////////////////////////////////////////////////////////////////
754 // Function: DXGraphicsStateGuardian9::begin_occlusion_query
755 // Access: Public, Virtual
756 // Description: Begins a new occlusion query. After this call, you
757 // may call begin_draw_primitives() and
758 // draw_triangles()/draw_whatever() repeatedly.
759 // Eventually, you should call end_occlusion_query()
760 // before the end of the frame; that will return a new
761 // OcclusionQueryContext object that will tell you how
762 // many pixels represented by the bracketed geometry
763 // passed the depth test.
764 //
765 // It is not valid to call begin_occlusion_query()
766 // between another begin_occlusion_query()
767 // .. end_occlusion_query() sequence.
768 ////////////////////////////////////////////////////////////////////
771  nassertv(_supports_occlusion_query);
772  nassertv(_current_occlusion_query == (OcclusionQueryContext *)NULL);
773 
774  IDirect3DQuery9 *query;
775  HRESULT hr = _d3d_device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &query);
776  if (FAILED(hr)) {
777  dxgsg9_cat.warning()
778  << "Occlusion query failed.\n";
779  return;
780  }
781 
782  PT(DXOcclusionQueryContext9) queryobj = new DXOcclusionQueryContext9(query);
783 
784  if (dxgsg9_cat.is_debug()) {
785  dxgsg9_cat.debug()
786  << "beginning occlusion query " << query << "\n";
787  }
788 
789  query->Issue(D3DISSUE_BEGIN);
790  _current_occlusion_query = queryobj;
791 }
792 
793 ////////////////////////////////////////////////////////////////////
794 // Function: DXGraphicsStateGuardian9::end_occlusion_query
795 // Access: Public, Virtual
796 // Description: Ends a previous call to begin_occlusion_query().
797 // This call returns the OcclusionQueryContext object
798 // that will (eventually) report the number of pixels
799 // that passed the depth test between the call to
800 // begin_occlusion_query() and end_occlusion_query().
801 ////////////////////////////////////////////////////////////////////
802 PT(OcclusionQueryContext) DXGraphicsStateGuardian9::
803 end_occlusion_query() {
804  if (_current_occlusion_query == (OcclusionQueryContext *)NULL) {
805  return NULL;
806  }
807 
808  PT(OcclusionQueryContext) result = _current_occlusion_query;
809 
810  IDirect3DQuery9 *query = DCAST(DXOcclusionQueryContext9, result)->_query;
811 
812  if (dxgsg9_cat.is_debug()) {
813  dxgsg9_cat.debug()
814  << "ending occlusion query " << query << "\n";
815  }
816 
817  _current_occlusion_query = NULL;
818  query->Issue(D3DISSUE_END);
819 
820  return result;
821 }
822 
823 ////////////////////////////////////////////////////////////////////
824 // Function: DXGraphicsStateGuardian9::make_geom_munger
825 // Access: Public, Virtual
826 // Description: Creates a new GeomMunger object to munge vertices
827 // appropriate to this GSG for the indicated state.
828 ////////////////////////////////////////////////////////////////////
829 PT(GeomMunger) DXGraphicsStateGuardian9::
830 make_geom_munger(const RenderState *state, Thread *current_thread) {
831  PT(DXGeomMunger9) munger = new DXGeomMunger9(this, state);
832  return GeomMunger::register_munger(munger, current_thread);
833 }
834 
835 ////////////////////////////////////////////////////////////////////
836 // Function: DXGraphicsStateGuardian9::clear
837 // Access: Public, Virtual
838 // Description: Clears all of the indicated buffers to their assigned
839 // colors.
840 ////////////////////////////////////////////////////////////////////
842 clear(DrawableRegion *clearable) {
843 
844  DWORD main_flags = 0;
845  DWORD aux_flags = 0;
846 
847  if ((!clearable->get_clear_color_active())&&
848  (!clearable->get_clear_depth_active())&&
849  (!clearable->get_clear_stencil_active())) {
850  return;
851  }
852 
853  set_state_and_transform(RenderState::make_empty(), _internal_transform);
854 
855  D3DCOLOR color_clear_value = LColor_to_D3DCOLOR(clearable->get_clear_color());
856  PN_stdfloat depth_clear_value = clearable->get_clear_depth();
857  DWORD stencil_clear_value = (DWORD)(clearable->get_clear_stencil());
858 
859  //set appropriate flags
860  if (clearable->get_clear_color_active()) {
861  main_flags |= D3DCLEAR_TARGET;
862  }
863 
864  if (clearable->get_clear_depth_active()) {
865  aux_flags |= D3DCLEAR_ZBUFFER;
866  nassertv(_screen->_presentation_params.EnableAutoDepthStencil);
867  }
868 
869  if (clearable->get_clear_stencil_active()) {
870  // clear only if there is a stencil buffer
871  if (_screen->_presentation_params.EnableAutoDepthStencil &&
872  IS_STENCIL_FORMAT(_screen->_presentation_params.AutoDepthStencilFormat)) {
873  aux_flags |= D3DCLEAR_STENCIL;
874  }
875  }
876 
877  if ((main_flags | aux_flags) != 0) {
878  HRESULT hr = _d3d_device->Clear(0, NULL, main_flags | aux_flags, color_clear_value,
879  depth_clear_value, stencil_clear_value);
880  if (FAILED(hr) && main_flags == D3DCLEAR_TARGET && aux_flags != 0) {
881  // Maybe there's a problem with the one or more of the auxiliary
882  // buffers.
883  hr = _d3d_device->Clear(0, NULL, D3DCLEAR_TARGET, color_clear_value,
884  depth_clear_value, stencil_clear_value);
885  if (!FAILED(hr)) {
886  // Yep, it worked without them. That's a problem. Which buffer
887  // poses the problem?
888  if (clearable->get_clear_depth_active()) {
889  aux_flags |= D3DCLEAR_ZBUFFER;
890  HRESULT hr2 = _d3d_device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color_clear_value,
891  depth_clear_value, stencil_clear_value);
892  if (FAILED(hr2)) {
893  dxgsg9_cat.error()
894  << "Unable to clear depth buffer; removing.\n";
895  // This is really hacky code.
896  ((FrameBufferProperties *)_current_properties)->set_depth_bits(0);
897  }
898  }
899  if (clearable->get_clear_stencil_active()) {
900  aux_flags |= D3DCLEAR_STENCIL;
901  HRESULT hr2 = _d3d_device->Clear(0, NULL, D3DCLEAR_STENCIL, color_clear_value,
902  stencil_clear_value, stencil_clear_value);
903  if (FAILED(hr2)) {
904  dxgsg9_cat.error()
905  << "Unable to clear stencil buffer; removing.\n";
906  // This is really hacky code.
907  ((FrameBufferProperties *)_current_properties)->set_stencil_bits(0);
908  _supports_stencil = false;
909  }
910  }
911  }
912  }
913 
914  if (FAILED(hr)) {
915  dxgsg9_cat.error()
916  << "clear_buffer failed: Clear returned " << D3DERRORSTRING(hr);
917  }
918  }
919 }
920 
921 ////////////////////////////////////////////////////////////////////
922 // Function: DXGraphicsStateGuardian9::prepare_display_region
923 // Access: Public, Virtual
924 // Description: Prepare a display region for rendering (set up
925 // scissor region and viewport)
926 ////////////////////////////////////////////////////////////////////
929  nassertv(dr != (DisplayRegionPipelineReader *)NULL);
931 
932  int l, u, w, h;
933  dr->get_region_pixels_i(l, u, w, h);
934 
935  // Create the viewport
936  D3DVIEWPORT9 vp = { l, u, w, h, 0.0f, 1.0f };
937  _current_viewport = vp;
938  HRESULT hr = _d3d_device->SetViewport(&_current_viewport);
939  if (FAILED(hr)) {
940  dxgsg9_cat.error()
941  << "_screen->_swap_chain = " << _screen->_swap_chain << " _swap_chain = " << _swap_chain << "\n";
942  dxgsg9_cat.error()
943  << "SetViewport(" << l << ", " << u << ", " << w << ", " << h
944  << ") failed" << D3DERRORSTRING(hr);
945 
946  D3DVIEWPORT9 vp_old;
947  _d3d_device->GetViewport(&vp_old);
948  dxgsg9_cat.error()
949  << "GetViewport(" << vp_old.X << ", " << vp_old.Y << ", " << vp_old.Width << ", "
950  << vp_old.Height << ") returned: Trying to set that vp---->\n";
951  hr = _d3d_device->SetViewport(&vp_old);
952  set_render_state(D3DRS_SCISSORTESTENABLE, FALSE);
953 
954  if (FAILED(hr)) {
955  dxgsg9_cat.error() << "Failed again\n";
956  throw_event("panda3d-render-error");
957  nassertv(false);
958  }
959  }
960 
961  if (_screen->_can_direct_disable_color_writes) {
962  set_render_state(D3DRS_COLORWRITEENABLE, _color_write_mask);
963  }
964 }
965 
966 ////////////////////////////////////////////////////////////////////
967 // Function: DXGraphicsStateGuardian9::calc_projection_mat
968 // Access: Public, Virtual
969 // Description: Given a lens, calculates the appropriate projection
970 // matrix for use with this gsg. Note that the
971 // projection matrix depends a lot upon the coordinate
972 // system of the rendering API.
973 //
974 // The return value is a TransformState if the lens is
975 // acceptable, NULL if it is not.
976 ////////////////////////////////////////////////////////////////////
977 CPT(TransformState) DXGraphicsStateGuardian9::
978 calc_projection_mat(const Lens *lens) {
979  if (lens == (Lens *)NULL) {
980  return NULL;
981  }
982 
983  if (!lens->is_linear()) {
984  return NULL;
985  }
986 
987  // DirectX also uses a Z range of 0 to 1, whereas the Panda
988  // convention is for the projection matrix to produce a Z range of
989  // -1 to 1. We have to rescale to compensate.
990  static const LMatrix4 rescale_mat
991  (1, 0, 0, 0,
992  0, 1, 0, 0,
993  0, 0, 0.5, 0,
994  0, 0, 0.5, 1);
995 
996  LMatrix4 result =
997  LMatrix4::convert_mat(CS_yup_left, _current_lens->get_coordinate_system()) *
998  lens->get_projection_mat(_current_stereo_channel) *
999  rescale_mat;
1000 
1001  if (_scene_setup->get_inverted()) {
1002  // If the scene is supposed to be inverted, then invert the
1003  // projection matrix.
1004  result *= LMatrix4::scale_mat(1.0f, -1.0f, 1.0f);
1005  }
1006 
1007  return TransformState::make_mat(result);
1008 }
1009 
1010 ////////////////////////////////////////////////////////////////////
1011 // Function: DXGraphicsStateGuardian9::prepare_lens
1012 // Access: Public, Virtual
1013 // Description: Makes the current lens (whichever lens was most
1014 // recently specified with set_scene()) active, so
1015 // that it will transform future rendered geometry.
1016 // Normally this is only called from the draw process,
1017 // and usually it is called by set_scene().
1018 //
1019 // The return value is true if the lens is acceptable,
1020 // false if it is not.
1021 ////////////////////////////////////////////////////////////////////
1024  LMatrix4f mat = LCAST(float, _projection_mat->get_mat());
1025  HRESULT hr =
1026  _d3d_device->SetTransform(D3DTS_PROJECTION,
1027  (D3DMATRIX*)mat.get_data());
1028  return SUCCEEDED(hr);
1029 }
1030 
1031 ////////////////////////////////////////////////////////////////////
1032 // Function: DXGraphicsStateGuardian9::begin_frame
1033 // Access: Public, Virtual
1034 // Description: Called before each frame is rendered, to allow the
1035 // GSG a chance to do any internal cleanup before
1036 // beginning the frame.
1037 //
1038 // The return value is true if successful (in which case
1039 // the frame will be drawn and end_frame() will be
1040 // called later), or false if unsuccessful (in which
1041 // case nothing will be drawn and end_frame() will not
1042 // be called).
1043 ////////////////////////////////////////////////////////////////////
1045 begin_frame(Thread *current_thread) {
1046 
1047  GraphicsStateGuardian::begin_frame(current_thread);
1048 
1049  if (_d3d_device == NULL) {
1050  dxgsg9_cat.debug()
1051  << this << "::begin_frame(): no device.\n";
1052  return false;
1053  }
1054 
1055  HRESULT hr = _d3d_device->BeginScene();
1056 
1057  if (FAILED(hr)) {
1058  if (hr == D3DERR_DEVICELOST) {
1059  if (dxgsg9_cat.is_debug()) {
1060  dxgsg9_cat.debug()
1061  << "BeginScene returns D3DERR_DEVICELOST" << endl;
1062  }
1063 
1064  check_cooperative_level();
1065 
1066  } else {
1067  dxgsg9_cat.error()
1068  << "BeginScene failed, unhandled error hr == "
1069  << D3DERRORSTRING(hr) << endl;
1070  throw_event("panda3d-render-error");
1071  }
1072  return false;
1073  }
1074 
1075  if (_current_properties->get_srgb_color()) {
1076  set_render_state(D3DRS_SRGBWRITEENABLE, TRUE);
1077  } else {
1078  set_render_state(D3DRS_SRGBWRITEENABLE, FALSE);
1079  }
1080 
1081  return true;
1082 }
1083 
1084 ////////////////////////////////////////////////////////////////////
1085 // Function: DXGraphicsStateGuardian9::begin_scene
1086 // Access: Public, Virtual
1087 // Description: Called between begin_frame() and end_frame() to mark
1088 // the beginning of drawing commands for a "scene"
1089 // (usually a particular DisplayRegion) within a frame.
1090 // All 3-D drawing commands, except the clear operation,
1091 // must be enclosed within begin_scene() .. end_scene().
1092 //
1093 // The return value is true if successful (in which case
1094 // the scene will be drawn and end_scene() will be
1095 // called later), or false if unsuccessful (in which
1096 // case nothing will be drawn and end_scene() will not
1097 // be called).
1098 ////////////////////////////////////////////////////////////////////
1102  return false;
1103  }
1104 
1105 /*
1106  HRESULT hr = _d3d_device->BeginScene();
1107 
1108  if (FAILED(hr)) {
1109  if (hr == D3DERR_DEVICELOST) {
1110  if (dxgsg9_cat.is_debug()) {
1111  dxgsg9_cat.debug()
1112  << "BeginScene returns D3DERR_DEVICELOST" << endl;
1113  }
1114 
1115  check_cooperative_level();
1116 
1117  } else {
1118  dxgsg9_cat.error()
1119  << "BeginScene failed, unhandled error hr == "
1120  << D3DERRORSTRING(hr) << endl;
1121  throw_event("panda3d-render-error");
1122  }
1123  return false;
1124  }
1125 */
1126 
1127  return true;
1128 }
1129 
1130 ////////////////////////////////////////////////////////////////////
1131 // Function: DXGraphicsStateGuardian9::end_scene
1132 // Access: Public, Virtual
1133 // Description: Called between begin_frame() and end_frame() to mark
1134 // the end of drawing commands for a "scene" (usually a
1135 // particular DisplayRegion) within a frame. All 3-D
1136 // drawing commands, except the clear operation, must be
1137 // enclosed within begin_scene() .. end_scene().
1138 ////////////////////////////////////////////////////////////////////
1142 
1143  if (_vertex_array_shader_context != 0) {
1144  _vertex_array_shader_context->disable_shader_vertex_arrays(this);
1145  _vertex_array_shader = (Shader *)NULL;
1146  _vertex_array_shader_context = (CLP(ShaderContext) *)NULL;
1147  }
1148  if (_texture_binding_shader_context != 0) {
1149  _texture_binding_shader_context->disable_shader_texture_bindings(this);
1150  _texture_binding_shader = (Shader *)NULL;
1151  _texture_binding_shader_context = (CLP(ShaderContext) *)NULL;
1152  }
1153  if (_current_shader_context != 0) {
1154  _current_shader_context->unbind(this);
1155  _current_shader = (Shader *)NULL;
1156  _current_shader_context = (CLP(ShaderContext) *)NULL;
1157  }
1158 
1159  _dlights.clear();
1160 
1161 /*
1162  HRESULT hr = _d3d_device->EndScene();
1163 
1164  if (FAILED(hr)) {
1165  if (hr == D3DERR_DEVICELOST) {
1166  if (dxgsg9_cat.is_debug()) {
1167  dxgsg9_cat.debug()
1168  << "EndScene returns DeviceLost\n";
1169  }
1170  check_cooperative_level();
1171 
1172  } else {
1173  dxgsg9_cat.error()
1174  << "EndScene failed, unhandled error hr == " << D3DERRORSTRING(hr);
1175  throw_event("panda3d-render-error");
1176  }
1177  return;
1178  }
1179 */
1180 
1181 }
1182 
1183 ////////////////////////////////////////////////////////////////////
1184 // Function: GraphicsStateGuardian::end_frame
1185 // Access: Public, Virtual
1186 // Description: Called after each frame is rendered, to allow the
1187 // GSG a chance to do any internal cleanup after
1188 // rendering the frame, and before the window flips.
1189 ////////////////////////////////////////////////////////////////////
1191 end_frame(Thread *current_thread) {
1192 
1193  HRESULT hr = _d3d_device->EndScene();
1194 
1195  if (FAILED(hr)) {
1196  if (hr == D3DERR_DEVICELOST) {
1197  if (dxgsg9_cat.is_debug()) {
1198  dxgsg9_cat.debug()
1199  << "EndScene returns DeviceLost\n";
1200  }
1201  check_cooperative_level();
1202 
1203  } else {
1204  dxgsg9_cat.error()
1205  << "EndScene failed, unhandled error hr == " << D3DERRORSTRING(hr);
1206  throw_event("panda3d-render-error");
1207  }
1208  return;
1209  }
1210 
1211 #if defined(DO_PSTATS)
1212  if (_texmgrmem_total_pcollector.is_active()) {
1213 #define TICKS_PER_GETTEXINFO (2.5*1000) // 2.5 second interval
1214  static DWORD last_tick_count = 0;
1215  DWORD cur_tick_count = GetTickCount();
1216 
1217  if (cur_tick_count - last_tick_count > TICKS_PER_GETTEXINFO) {
1218  last_tick_count = cur_tick_count;
1219  report_texmgr_stats();
1220  }
1221  }
1222 #endif
1223 
1224  // Note: regular GraphicsWindow::end_frame is being called,
1225  // but we override gsg::end_frame, so need to explicitly call it here
1226  // (currently it's an empty fn)
1227  GraphicsStateGuardian::end_frame(current_thread);
1228 }
1229 
1230 ////////////////////////////////////////////////////////////////////
1231 // Function: DXGraphicsStateGuardian9::begin_draw_primitives
1232 // Access: Public, Virtual
1233 // Description: Called before a sequence of draw_primitive()
1234 // functions are called, this should prepare the vertex
1235 // data for rendering. It returns true if the vertices
1236 // are ok, false to abort this group of primitives.
1237 ////////////////////////////////////////////////////////////////////
1240  const GeomMunger *munger,
1241  const GeomVertexDataPipelineReader *data_reader,
1242  bool force) {
1243  if (!GraphicsStateGuardian::begin_draw_primitives(geom_reader, munger,
1244  data_reader, force)) {
1245  return false;
1246  }
1247  nassertr(_data_reader != (GeomVertexDataPipelineReader *)NULL, false);
1248 
1249  const GeomVertexFormat *format = _data_reader->get_format();
1250 
1251  const GeomVertexAnimationSpec &animation =
1252  data_reader->get_format()->get_animation();
1253  if (animation.get_animation_type() == Geom::AT_hardware) {
1254  // Set up vertex blending.
1255  switch (animation.get_num_transforms()) {
1256  case 1:
1257  // The MSDN docs suggest we should use D3DVBF_0WEIGHTS here, but
1258  // that doesn't seem to work at all. On the other hand,
1259  // D3DVBF_DISABLE *does* work, because it disables special
1260  // handling, meaning only the world matrix affects these
1261  // vertices--and by accident or design, the first matrix,
1262  // D3DTS_WORLDMATRIX(0), *is* the world matrix.
1263  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
1264  break;
1265  case 2:
1266  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS);
1267  break;
1268  case 3:
1269  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_2WEIGHTS);
1270  break;
1271  case 4:
1272  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_3WEIGHTS);
1273  break;
1274  }
1275 
1276  if (animation.get_indexed_transforms()) {
1277  // Set up indexed vertex blending.
1278  set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE);
1279  } else {
1280  set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
1281  }
1282 
1283  const TransformTable *table = data_reader->get_transform_table();
1284  if (table != (TransformTable *)NULL) {
1285  for (int i = 0; i < table->get_num_transforms(); i++) {
1286  LMatrix4 mat;
1287  table->get_transform(i)->mult_matrix(mat, _internal_transform->get_mat());
1288  const D3DMATRIX *d3d_mat = (const D3DMATRIX *)mat.get_data();
1289  _d3d_device->SetTransform(D3DTS_WORLDMATRIX(i), d3d_mat);
1290  }
1291 
1292  // Setting the first animation matrix steps on the world matrix,
1293  // so we have to set a flag to reload the world matrix later.
1294  _transform_stale = true;
1295  }
1296  _vertex_blending_enabled = true;
1297 
1298  } else {
1299  // We're not using vertex blending.
1300  if (_vertex_blending_enabled) {
1301  set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
1302  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
1303  _vertex_blending_enabled = false;
1304  }
1305 
1306  if (_transform_stale && !_data_reader->is_vertex_transformed()) {
1307  const D3DMATRIX *d3d_mat = (const D3DMATRIX *)_internal_transform->get_mat().get_data();
1308  _d3d_device->SetTransform(D3DTS_WORLD, d3d_mat);
1309  _transform_stale = false;
1310  }
1311  }
1312 
1313  if (_data_reader->is_vertex_transformed()) {
1314  // If the vertex data claims to be already transformed into clip
1315  // coordinates, wipe out the current projection and modelview
1316  // matrix (so we don't attempt to transform it again).
1317 
1318  // It's tempting just to use the D3DFVF_XYZRHW specification on
1319  // these vertices, but that turns out to be a bigger hammer than
1320  // we want: that also prevents lighting calculations and user clip
1321  // planes.
1322  _d3d_device->SetTransform(D3DTS_WORLD, &_d3d_ident_mat);
1323  static const LMatrix4f rescale_mat
1324  (1, 0, 0, 0,
1325  0, 1, 0, 0,
1326  0, 0, 0.5, 0,
1327  0, 0, 0.5, 1);
1328  _transform_stale = true;
1329 
1330  _d3d_device->SetTransform(D3DTS_PROJECTION, (const D3DMATRIX *)rescale_mat.get_data());
1331  }
1332 
1333  if (_current_shader_context == 0 /*|| !_current_shader_context->uses_custom_vertex_arrays()*/) {
1334  // No shader, or a non-Cg shader.
1335  if (_vertex_array_shader_context != 0) {
1336  _vertex_array_shader_context->disable_shader_vertex_arrays(this);
1337  }
1338  if (!update_standard_vertex_arrays(force)) {
1339  return false;
1340  }
1341  } else {
1342  // Cg shader.
1343  if (_vertex_array_shader_context == 0) {
1344  disable_standard_vertex_arrays();
1345  if (!_current_shader_context->update_shader_vertex_arrays(NULL, this, force)) {
1346  return false;
1347  }
1348  } else {
1349  if (!_current_shader_context->
1350  update_shader_vertex_arrays(_vertex_array_shader_context, this, force)) {
1351  return false;
1352  }
1353  }
1354  }
1355 
1356  _vertex_array_shader = _current_shader;
1357  _vertex_array_shader_context = _current_shader_context;
1358 
1359  return true;
1360 }
1361 
1362 ////////////////////////////////////////////////////////////////////
1363 // Function: DXGraphicsStateGuardian9::update_standard_vertex_arrays
1364 // Access: Protected
1365 // Description: Binds vertex buffers as stream sources and sets the
1366 // correct FVF format for fixed-function rendering.
1367 // Used only when the standard (non-shader) pipeline
1368 // is about to be used - dxShaderContexts are responsible
1369 // for setting up their own vertex arrays.
1370 ////////////////////////////////////////////////////////////////////
1371 bool CLP(GraphicsStateGuardian)::
1372 update_standard_vertex_arrays(bool force) {
1373 
1374  int fvf = 0;
1375  HRESULT hr;
1376 
1377  int number_of_arrays = _data_reader->get_num_arrays();
1378  for ( int array_index = 0; array_index < number_of_arrays; ++array_index ) {
1379  const GeomVertexArrayDataHandle* array_reader = _data_reader->get_array_reader( array_index );
1380  if ( array_reader == NULL ) {
1381  dxgsg9_cat.error() << "Unable to get reader for array " << array_index << "\n";
1382  return false;
1383  }
1384 
1385  // Get the vertex buffer for this array.
1386  CLP(VertexBufferContext)* dvbc;
1387  if (!setup_array_data(dvbc, array_reader, force)) {
1388  dxgsg9_cat.error() << "Unable to setup vertex buffer for array " << array_index << "\n";
1389  return false;
1390  }
1391 
1392  // Bind this array as the data source for the corresponding stream.
1393  const GeomVertexArrayFormat* array_format = array_reader->get_array_format();
1394  hr = _d3d_device->SetStreamSource( array_index, dvbc->_vbuffer, 0, array_format->get_stride() );
1395  if (FAILED(hr)) {
1396  dxgsg9_cat.error() << "SetStreamSource failed" << D3DERRORSTRING(hr);
1397  return false;
1398  }
1399 
1400  // Update our combined set of FVF flags
1401  fvf |= dvbc->_fvf;
1402  }
1403 
1404  hr = _d3d_device->SetFVF( fvf );
1405  if (FAILED(hr)) {
1406  dxgsg9_cat.error() << "SetFVF failed" << D3DERRORSTRING(hr);
1407  return false;
1408  }
1409 
1410  return true;
1411 }
1412 
1413 ////////////////////////////////////////////////////////////////////
1414 // Function: DXGraphicsStateGuardian9::disable_standard_vertex_arrays
1415 // Access: Protected
1416 // Description: Unbinds all of the streams that are currently enabled.
1417 // dxShaderContexts are responsible for setting up their
1418 // own streams, but before they can do so, the standard
1419 // streams need to be disabled to get them "out of the
1420 // way." Called only from begin_draw_primitives.
1421 ////////////////////////////////////////////////////////////////////
1422 void CLP(GraphicsStateGuardian)::
1423 disable_standard_vertex_arrays() {
1424  for ( int array_index = 0; array_index < _num_bound_streams; ++array_index )
1425  {
1426  _d3d_device->SetStreamSource( array_index, NULL, 0, 0 );
1427  }
1428  _num_bound_streams = 0;
1429 }
1430 
1431 ////////////////////////////////////////////////////////////////////
1432 // Function: DXGraphicsStateGuardian9::draw_triangles
1433 // Access: Public, Virtual
1434 // Description: Draws a series of disconnected triangles.
1435 ////////////////////////////////////////////////////////////////////
1437 draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
1438  //PStatTimer timer(_draw_primitive_pcollector);
1439 
1440  _vertices_tri_pcollector.add_level(reader->get_num_vertices());
1441  _primitive_batches_tri_pcollector.add_level(1);
1442 
1443  if (reader->is_indexed()) {
1444  int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
1445  int max_vertex = reader->get_max_vertex();
1446 
1447  // Indexed, vbuffers.
1448  IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
1449  nassertr(ibc != (IndexBufferContext *)NULL, false);
1450  if (!apply_index_buffer(ibc, reader, force)) {
1451  return false;
1452  }
1453 
1454  _d3d_device->DrawIndexedPrimitive( D3DPT_TRIANGLELIST,
1455  0,
1456  min_vertex, max_vertex - min_vertex + 1,
1457  0, reader->get_num_primitives() );
1458 
1459  #if 0
1460  // Indexed, client arrays.
1461  const unsigned char *index_pointer = reader->get_read_pointer(force);
1462  if (index_pointer == NULL) {
1463  return false;
1464  }
1465  D3DFORMAT index_type = get_index_type(reader->get_index_type());
1466  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1467  if (vertex_pointer == NULL) {
1468  return false;
1469  }
1470 
1471  draw_indexed_primitive_up( D3DPT_TRIANGLELIST,
1472  min_vertex, max_vertex,
1473  reader->get_num_primitives(),
1474  index_pointer, index_type, vertex_pointer,
1475  _data_reader->get_format()->get_array(0)->get_stride() );
1476  #endif
1477  } else {
1478  // Nonindexed, vbuffers.
1479  _d3d_device->DrawPrimitive( D3DPT_TRIANGLELIST,
1480  reader->get_first_vertex(),
1481  reader->get_num_primitives() );
1482 
1483  #if 0
1484  // Nonindexed, client arrays.
1485  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1486  if (vertex_pointer == NULL) {
1487  return false;
1488  }
1489 
1490  draw_primitive_up(D3DPT_TRIANGLELIST, reader->get_num_primitives(),
1491  reader->get_first_vertex(),
1492  reader->get_num_vertices(), vertex_pointer,
1493  _data_reader->get_format()->get_array(0)->get_stride());
1494  #endif
1495  }
1496 
1497  return true;
1498 }
1499 
1500 ////////////////////////////////////////////////////////////////////
1501 // Function: DXGraphicsStateGuardian9::draw_tristrips
1502 // Access: Public, Virtual
1503 // Description: Draws a series of triangle strips.
1504 ////////////////////////////////////////////////////////////////////
1506 draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
1507  //PStatTimer timer(_draw_primitive_pcollector);
1508 
1509  if (connect_triangle_strips && _current_fill_mode != RenderModeAttrib::M_wireframe) {
1510  // One long triangle strip, connected by the degenerate vertices
1511  // that have already been set up within the primitive.
1512  _vertices_tristrip_pcollector.add_level(reader->get_num_vertices());
1513  _primitive_batches_tristrip_pcollector.add_level(1);
1514 
1515  if (reader->is_indexed()) {
1516  int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
1517  int max_vertex = reader->get_max_vertex();
1518 
1519  // Indexed, vbuffers, one long triangle strip.
1520  IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
1521  nassertr(ibc != (IndexBufferContext *)NULL, false);
1522  if (!apply_index_buffer(ibc, reader, force)) {
1523  return false;
1524  }
1525 
1526  _d3d_device->DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP,
1527  0,
1528  min_vertex, max_vertex - min_vertex + 1,
1529  0, reader->get_num_vertices() - 2 );
1530 
1531  #if 0
1532  // Indexed, client arrays, one long triangle strip.
1533  const unsigned char *index_pointer = reader->get_read_pointer(force);
1534  if (index_pointer == NULL) {
1535  return false;
1536  }
1537  D3DFORMAT index_type = get_index_type(reader->get_index_type());
1538  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1539  if (vertex_pointer == NULL) {
1540  return false;
1541  }
1542 
1543  draw_indexed_primitive_up
1544  (D3DPT_TRIANGLESTRIP,
1545  min_vertex, max_vertex,
1546  reader->get_num_vertices() - 2,
1547  index_pointer, index_type, vertex_pointer,
1548  _data_reader->get_format()->get_array(0)->get_stride());
1549  #endif
1550  } else {
1551  // Nonindexed, vbuffers, one long triangle strip.
1552  _d3d_device->DrawPrimitive( D3DPT_TRIANGLESTRIP,
1553  reader->get_first_vertex(),
1554  reader->get_num_vertices() - 2 );
1555 
1556  #if 0
1557  // Indexed, client arrays, one long triangle strip.
1558  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1559  if (vertex_pointer == NULL) {
1560  return false;
1561  }
1562  draw_primitive_up(D3DPT_TRIANGLESTRIP,
1563  reader->get_num_vertices() - 2,
1564  reader->get_first_vertex(),
1565  reader->get_num_vertices(), vertex_pointer,
1566  _data_reader->get_format()->get_array(0)->get_stride());
1567  #endif
1568  }
1569 
1570  } else {
1571  // Send the individual triangle strips, stepping over the degenerate vertices.
1572  CPTA_int ends = reader->get_ends();
1573  _primitive_batches_tristrip_pcollector.add_level(ends.size());
1574 
1575  if (reader->is_indexed()) {
1576  CPTA_int ends = reader->get_ends();
1577  int index_stride = reader->get_index_stride();
1578  _primitive_batches_tristrip_pcollector.add_level(ends.size());
1579 
1580  GeomVertexReader mins(reader->get_mins(), 0);
1581  GeomVertexReader maxs(reader->get_maxs(), 0);
1582  nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
1583  reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
1584 
1585  // Indexed, vbuffers, individual triangle strips.
1586  IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
1587  nassertr(ibc != (IndexBufferContext *)NULL, false);
1588  if (!apply_index_buffer(ibc, reader, force)) {
1589  return false;
1590  }
1591 
1592  unsigned int start = 0;
1593  for (size_t i = 0; i < ends.size(); i++) {
1594  _vertices_tristrip_pcollector.add_level(ends[i] - start);
1595  unsigned int min = mins.get_data1i();
1596  unsigned int max = maxs.get_data1i();
1597  _d3d_device->DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP,
1598  0,
1599  min, max - min + 1,
1600  start, ends[i] - start - 2 );
1601  start = ends[i] + 2;
1602  }
1603 
1604  #if 0
1605  // Indexed, client arrays, individual triangle strips.
1606  int stride = _data_reader->get_format()->get_array(0)->get_stride();
1607  const unsigned char *index_pointer = reader->get_read_pointer(force);
1608  if (index_pointer == NULL) {
1609  return false;
1610  }
1611  D3DFORMAT index_type = get_index_type(reader->get_index_type());
1612  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1613  if (vertex_pointer == NULL) {
1614  return false;
1615  }
1616 
1617  unsigned int start = 0;
1618  for (size_t i = 0; i < ends.size(); i++) {
1619  _vertices_tristrip_pcollector.add_level(ends[i] - start);
1620  unsigned int min = mins.get_data1i();
1621  unsigned int max = maxs.get_data1i();
1622  draw_indexed_primitive_up
1623  (D3DPT_TRIANGLESTRIP,
1624  min, max,
1625  ends[i] - start - 2,
1626  index_pointer + start * index_stride, index_type,
1627  vertex_pointer, stride);
1628 
1629  start = ends[i] + 2;
1630  }
1631  #endif
1632  } else {
1633  unsigned int first_vertex = reader->get_first_vertex();
1634 
1635  // Nonindexed, vbuffers, individual triangle strips.
1636  unsigned int start = 0;
1637  for (size_t i = 0; i < ends.size(); i++) {
1638  _vertices_tristrip_pcollector.add_level(ends[i] - start);
1639  _d3d_device->DrawPrimitive( D3DPT_TRIANGLESTRIP,
1640  first_vertex + start,
1641  ends[i] - start - 2 );
1642  start = ends[i] + 2;
1643  }
1644 
1645  #if 0
1646  // Nonindexed, client arrays, individual triangle strips.
1647  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1648  if (vertex_pointer == NULL) {
1649  return false;
1650  }
1651  int stride = _data_reader->get_format()->get_array(0)->get_stride();
1652 
1653  unsigned int start = 0;
1654  for (size_t i = 0; i < ends.size(); i++) {
1655  _vertices_tristrip_pcollector.add_level(ends[i] - start);
1656  draw_primitive_up(D3DPT_TRIANGLESTRIP, ends[i] - start - 2,
1657  first_vertex + start,
1658  ends[i] - start,
1659  vertex_pointer, stride);
1660 
1661  start = ends[i] + 2;
1662  }
1663  #endif
1664  }
1665  }
1666  return true;
1667 }
1668 
1669 ////////////////////////////////////////////////////////////////////
1670 // Function: DXGraphicsStateGuardian9::draw_trifans
1671 // Access: Public, Virtual
1672 // Description: Draws a series of triangle fans.
1673 ////////////////////////////////////////////////////////////////////
1675 draw_trifans(const GeomPrimitivePipelineReader *reader, bool force) {
1676  //PStatTimer timer(_draw_primitive_pcollector);
1677 
1678  CPTA_int ends = reader->get_ends();
1679  _primitive_batches_trifan_pcollector.add_level(ends.size());
1680 
1681  if (reader->is_indexed()) {
1682  int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
1683  int max_vertex = reader->get_max_vertex();
1684 
1685  // Send the individual triangle fans. There's no connecting fans
1686  // with degenerate vertices, so no worries about that.
1687  int index_stride = reader->get_index_stride();
1688 
1689  GeomVertexReader mins(reader->get_mins(), 0);
1690  GeomVertexReader maxs(reader->get_maxs(), 0);
1691  nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
1692  reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
1693 
1694  // Indexed, vbuffers.
1695  IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
1696  nassertr(ibc != (IndexBufferContext *)NULL, false);
1697  if (!apply_index_buffer(ibc, reader, force)) {
1698  return false;
1699  }
1700 
1701  unsigned int start = 0;
1702  for (size_t i = 0; i < ends.size(); i++) {
1703  _vertices_trifan_pcollector.add_level(ends[i] - start);
1704  unsigned int min = mins.get_data1i();
1705  unsigned int max = maxs.get_data1i();
1706  _d3d_device->DrawIndexedPrimitive( D3DPT_TRIANGLEFAN,
1707  0,
1708  min, max - min + 1,
1709  start, ends[i] - start - 2 );
1710  start = ends[i];
1711  }
1712 
1713  #if 0
1714  // Indexed, client arrays.
1715  int stride = _data_reader->get_format()->get_array(0)->get_stride();
1716  const unsigned char *index_pointer = reader->get_read_pointer(force);
1717  if (index_pointer == NULL) {
1718  return false;
1719  }
1720  D3DFORMAT index_type = get_index_type(reader->get_index_type());
1721  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1722  if (vertex_pointer == NULL) {
1723  return false;
1724  }
1725 
1726  unsigned int start = 0;
1727  for (size_t i = 0; i < ends.size(); i++) {
1728  _vertices_trifan_pcollector.add_level(ends[i] - start);
1729  unsigned int min = mins.get_data1i();
1730  unsigned int max = maxs.get_data1i();
1731  draw_indexed_primitive_up
1732  (D3DPT_TRIANGLEFAN,
1733  min, max,
1734  ends[i] - start - 2,
1735  index_pointer + start * index_stride, index_type,
1736  vertex_pointer, stride);
1737 
1738  start = ends[i];
1739  }
1740  #endif
1741  } else {
1742  unsigned int first_vertex = reader->get_first_vertex();
1743 
1744  // Nonindexed, vbuffers.
1745  unsigned int start = 0;
1746  for (size_t i = 0; i < ends.size(); i++) {
1747  _vertices_trifan_pcollector.add_level(ends[i] - start);
1748  _d3d_device->DrawPrimitive( D3DPT_TRIANGLEFAN,
1749  first_vertex + start,
1750  ends[i] - start - 2 );
1751  start = ends[i];
1752  }
1753 
1754  #if 0
1755  // Nonindexed, client arrays.
1756  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1757  if (vertex_pointer == NULL) {
1758  return false;
1759  }
1760  int stride = _data_reader->get_format()->get_array(0)->get_stride();
1761 
1762  unsigned int start = 0;
1763  for (size_t i = 0; i < ends.size(); i++) {
1764  _vertices_trifan_pcollector.add_level(ends[i] - start);
1765  draw_primitive_up(D3DPT_TRIANGLEFAN,
1766  ends[i] - start - 2,
1767  first_vertex,
1768  ends[i] - start,
1769  vertex_pointer, stride);
1770  start = ends[i];
1771  }
1772  #endif
1773  }
1774  return true;
1775 }
1776 
1777 ////////////////////////////////////////////////////////////////////
1778 // Function: DXGraphicsStateGuardian9::draw_lines
1779 // Access: Public, Virtual
1780 // Description: Draws a series of disconnected line segments.
1781 ////////////////////////////////////////////////////////////////////
1783 draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
1784  //PStatTimer timer(_draw_primitive_pcollector);
1785 
1786  _vertices_other_pcollector.add_level(reader->get_num_vertices());
1787  _primitive_batches_other_pcollector.add_level(1);
1788 
1789  if (reader->is_indexed()) {
1790  int min_vertex = dx_broken_max_index ? 0 : reader->get_min_vertex();
1791  int max_vertex = reader->get_max_vertex();
1792 
1793  // Indexed, vbuffers.
1794  IndexBufferContext *ibc = ((GeomPrimitive *)(reader->get_object()))->prepare_now(get_prepared_objects(), this);
1795  nassertr(ibc != (IndexBufferContext *)NULL, false);
1796  if (!apply_index_buffer(ibc, reader, force)) {
1797  return false;
1798  }
1799 
1800  _d3d_device->DrawIndexedPrimitive( D3DPT_LINELIST,
1801  0,
1802  min_vertex, max_vertex - min_vertex + 1,
1803  0, reader->get_num_primitives() );
1804 
1805  #if 0
1806  // Indexed, client arrays.
1807  const unsigned char *index_pointer = reader->get_read_pointer(force);
1808  if (index_pointer == NULL) {
1809  return false;
1810  }
1811  D3DFORMAT index_type = get_index_type(reader->get_index_type());
1812  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1813  if (vertex_pointer == NULL) {
1814  return false;
1815  }
1816 
1817  draw_indexed_primitive_up
1818  (D3DPT_LINELIST,
1819  min_vertex, max_vertex,
1820  reader->get_num_primitives(),
1821  index_pointer, index_type, vertex_pointer,
1822  _data_reader->get_format()->get_array(0)->get_stride());
1823  #endif
1824  } else {
1825  // Nonindexed, vbuffers.
1826  _d3d_device->DrawPrimitive( D3DPT_LINELIST,
1827  reader->get_first_vertex(),
1828  reader->get_num_primitives() );
1829 
1830  #if 0
1831  // Nonindexed, client arrays.
1832  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1833  if (vertex_pointer == NULL) {
1834  return false;
1835  }
1836  draw_primitive_up(D3DPT_LINELIST, reader->get_num_primitives(),
1837  reader->get_first_vertex(),
1838  reader->get_num_vertices(), vertex_pointer,
1839  _data_reader->get_format()->get_array(0)->get_stride());
1840  #endif
1841  }
1842  return true;
1843 }
1844 
1845 ////////////////////////////////////////////////////////////////////
1846 // Function: DXGraphicsStateGuardian9::draw_linestrips
1847 // Access: Public, Virtual
1848 // Description: Draws a series of line strips.
1849 ////////////////////////////////////////////////////////////////////
1851 draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force) {
1852  return false;
1853 }
1854 
1855 ////////////////////////////////////////////////////////////////////
1856 // Function: DXGraphicsStateGuardian9::draw_points
1857 // Access: Public, Virtual
1858 // Description: Draws a series of disconnected points.
1859 ////////////////////////////////////////////////////////////////////
1861 draw_points(const GeomPrimitivePipelineReader *reader, bool force) {
1862  //PStatTimer timer(_draw_primitive_pcollector);
1863 
1864  _vertices_other_pcollector.add_level(reader->get_num_vertices());
1865  _primitive_batches_other_pcollector.add_level(1);
1866 
1867  // The munger should have protected us from indexed points--DirectX
1868  // doesn't support them.
1869  nassertr(!reader->is_indexed(), false);
1870 
1871  // Nonindexed, vbuffers.
1872  _d3d_device->DrawPrimitive( D3DPT_POINTLIST,
1873  reader->get_first_vertex(),
1874  reader->get_num_primitives() );
1875 
1876  #if 0
1877  // Nonindexed, client arrays.
1878  const unsigned char *vertex_pointer = _data_reader->get_array_reader(0)->get_read_pointer(force);
1879  if (vertex_pointer == NULL) {
1880  return false;
1881  }
1882  draw_primitive_up(D3DPT_POINTLIST, reader->get_num_primitives(),
1883  reader->get_first_vertex(),
1884  reader->get_num_vertices(), vertex_pointer,
1885  _data_reader->get_format()->get_array(0)->get_stride());
1886  #endif
1887 
1888  return true;
1889 }
1890 
1891 ////////////////////////////////////////////////////////////////////
1892 // Function: DXGraphicsStateGuardian9::end_draw_primitives()
1893 // Access: Public, Virtual
1894 // Description: Called after a sequence of draw_primitive()
1895 // functions are called, this should do whatever cleanup
1896 // is appropriate.
1897 ////////////////////////////////////////////////////////////////////
1900  // Turn off vertex blending--it seems to cause problems if we leave
1901  // it on.
1902  if (_vertex_blending_enabled) {
1903  set_render_state(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
1904  set_render_state(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
1905  _vertex_blending_enabled = false;
1906  }
1907 
1908  if (_data_reader->is_vertex_transformed()) {
1909  // Restore the projection matrix that we wiped out above.
1910  LMatrix4f mat = LCAST(float, _projection_mat->get_mat());
1911  _d3d_device->SetTransform(D3DTS_PROJECTION,
1912  (D3DMATRIX*)mat.get_data());
1913  }
1914 
1916 }
1917 
1918 ////////////////////////////////////////////////////////////////////
1919 // Function: DXGraphicsStateGuardian9::framebuffer_copy_to_texture
1920 // Access: Public, Virtual
1921 // Description: Copy the pixels within the indicated display
1922 // region from the framebuffer into texture memory.
1923 //
1924 // If z > -1, it is the cube map index into which to
1925 // copy.
1926 ////////////////////////////////////////////////////////////////////
1928 framebuffer_copy_to_texture(Texture *tex, int view, int z,
1929  const DisplayRegion *dr, const RenderBuffer &rb) {
1930  set_read_buffer(rb);
1931 
1932  int orig_x = tex->get_x_size();
1933  int orig_y = tex->get_y_size();
1934 
1935  HRESULT hr;
1936  int xo, yo, w, h;
1937  dr->get_region_pixels_i(xo, yo, w, h);
1938  tex->set_size_padded(w, h);
1939 
1940  // must use a render target type texture for StretchRect
1941  tex->set_render_to_texture(true);
1942 
1943  TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
1944  if (tc == (TextureContext *)NULL) {
1945  return false;
1946  }
1947  DXTextureContext9 *dtc = DCAST(DXTextureContext9, tc);
1948  if (!dtc->create_texture(*_screen)) {
1949  // Oops, we can't re-create the texture for some reason.
1950  dxgsg9_cat.error()
1951  << "Unable to re-create texture " << *dtc->get_texture() << endl;
1952  return false;
1953  }
1954 
1955  if (tex->get_texture_type() != Texture::TT_2d_texture) {
1956  // For a specialty texture like a cube map, go the slow route
1957  // through RAM for now.
1958  return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, true);
1959  }
1960  nassertr(dtc->get_d3d_2d_texture() != NULL, false);
1961 
1962  IDirect3DSurface9 *tex_level_0;
1963  hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
1964  if (FAILED(hr)) {
1965  dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
1966  return false;
1967  }
1968 
1969  // If the texture is the wrong size, we need to do something about it.
1970  D3DSURFACE_DESC texdesc;
1971  hr = tex_level_0->GetDesc(&texdesc);
1972  if (FAILED(hr)) {
1973  dxgsg9_cat.error() << "GetDesc failed in copy_texture" << D3DERRORSTRING(hr);
1974  SAFE_RELEASE(tex_level_0);
1975  return false;
1976  }
1977  if ((texdesc.Width != tex->get_x_size())||(texdesc.Height != tex->get_y_size())) {
1978  if ((orig_x != tex->get_x_size()) || (orig_y != tex->get_y_size())) {
1979  // Texture might be wrong size because we resized it and need to recreate.
1980  SAFE_RELEASE(tex_level_0);
1981  if (!dtc->create_texture(*_screen)) {
1982  // Oops, we can't re-create the texture for some reason.
1983  dxgsg9_cat.error()
1984  << "Unable to re-create texture " << *dtc->get_texture() << endl;
1985  return false;
1986  }
1987  hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
1988  if (FAILED(hr)) {
1989  dxgsg9_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
1990  return false;
1991  }
1992  hr = tex_level_0->GetDesc(&texdesc);
1993  if (FAILED(hr)) {
1994  dxgsg9_cat.error() << "GetDesc 2 failed in copy_texture" << D3DERRORSTRING(hr);
1995  SAFE_RELEASE(tex_level_0);
1996  return false;
1997  }
1998  }
1999  if ((texdesc.Width != tex->get_x_size())||(texdesc.Height != tex->get_y_size())) {
2000  // If it's still the wrong size, it's because driver can't create size
2001  // that we want. In that case, there's no helping it, we have to give up.
2002  dxgsg9_cat.error()
2003  << "Unable to copy to texture, texture is wrong size: " << *dtc->get_texture() << endl;
2004  SAFE_RELEASE(tex_level_0);
2005  return false;
2006  }
2007  }
2008 
2009  DWORD render_target_index;
2010  IDirect3DSurface9 *render_target;
2011 
2012  /* ***** DX9 GetRenderTarget, assume only one render target so index = 0 */
2013  render_target_index = 0;
2014 
2015  hr = _d3d_device->GetRenderTarget(render_target_index, &render_target);
2016  if (FAILED(hr)) {
2017  dxgsg9_cat.error()
2018  << "GetRenderTarget failed in framebuffer_copy_to_texture"
2019  << D3DERRORSTRING(hr);
2020  SAFE_RELEASE(tex_level_0);
2021  return false;
2022  }
2023 
2024  RECT src_rect;
2025 
2026  src_rect.left = xo;
2027  src_rect.right = xo+w;
2028  src_rect.top = yo;
2029  src_rect.bottom = yo+h;
2030 
2031 // THE DX8 WAY
2032 // hr = _d3d_device->CopyRects(render_target, &src_rect, 1, tex_level_0, 0);
2033 
2034 // DX9
2035  D3DTEXTUREFILTERTYPE filter;
2036 
2037  filter = D3DTEXF_POINT;
2038 
2039  bool okflag = true;
2040  hr = _d3d_device->StretchRect(render_target, &src_rect,
2041  tex_level_0, &src_rect,
2042  filter);
2043  if (FAILED(hr)) {
2044  dxgsg9_cat.debug()
2045  << "StretchRect failed in framebuffer_copy_to_texture"
2046  << D3DERRORSTRING(hr);
2047  okflag = false;
2048  }
2049 
2050  SAFE_RELEASE(render_target);
2051  SAFE_RELEASE(tex_level_0);
2052 
2053  if (okflag) {
2054  dtc->mark_loaded();
2055  dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
2056 
2057  } else {
2058  // The copy failed. Fall back to copying it to RAM and back.
2059  // Terribly slow, but what are you going to do?
2060  return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, true);
2061  }
2062 
2063  return true;
2064 }
2065 
2066 
2067 ////////////////////////////////////////////////////////////////////
2068 // Function: DXGraphicsStateGuardian9::framebuffer_copy_to_ram
2069 // Access: Public, Virtual
2070 // Description: Copy the pixels within the indicated display region
2071 // from the framebuffer into system memory, not texture
2072 // memory. Returns true on success, false on failure.
2073 //
2074 // This completely redefines the ram image of the
2075 // indicated texture.
2076 ////////////////////////////////////////////////////////////////////
2078 framebuffer_copy_to_ram(Texture *tex, int view, int z,
2079  const DisplayRegion *dr, const RenderBuffer &rb) {
2080  return do_framebuffer_copy_to_ram(tex, view, z, dr, rb, false);
2081 }
2082 
2083 ////////////////////////////////////////////////////////////////////
2084 // Function: DXGraphicsStateGuardian9::do_framebuffer_copy_to_ram
2085 // Access: Public
2086 // Description: This is the implementation of
2087 // framebuffer_copy_to_ram(); it adds one additional
2088 // parameter, which should be true if the framebuffer is
2089 // to be inverted during the copy (as in the same way it
2090 // copies to texture memory).
2091 ////////////////////////////////////////////////////////////////////
2093 do_framebuffer_copy_to_ram(Texture *tex, int view, int z,
2094  const DisplayRegion *dr, const RenderBuffer &rb,
2095  bool inverted) {
2096  set_read_buffer(rb);
2097 
2098  RECT rect;
2099  nassertr(tex != NULL && dr != NULL, false);
2100 
2101  int xo, yo, w, h;
2102  dr->get_region_pixels_i(xo, yo, w, h);
2103 
2104  Texture::Format format = tex->get_format();
2105  Texture::ComponentType component_type = tex->get_component_type();
2106 
2107  switch (format) {
2108  case Texture::F_depth_stencil:
2109  // Sorry, not (yet?) supported in pandadx.
2110  return false;
2111 
2112  default:
2113  format = Texture::F_rgb;
2114  component_type = Texture::T_unsigned_byte;
2115  }
2116 
2117  Texture::TextureType texture_type;
2118  if (z >= 0) {
2119  texture_type = Texture::TT_cube_map;
2120  } else {
2121  texture_type = Texture::TT_2d_texture;
2122  }
2123 
2124  if (tex->get_x_size() != w || tex->get_y_size() != h ||
2125  tex->get_component_type() != component_type ||
2126  tex->get_format() != format ||
2127  tex->get_texture_type() != texture_type) {
2128  // Re-setup the texture; its properties have changed.
2129  tex->setup_texture(texture_type, w, h, tex->get_z_size(),
2130  component_type, format);
2131  }
2132 
2133  rect.top = yo;
2134  rect.left = xo;
2135  rect.right = xo + w;
2136  rect.bottom = yo + h;
2137  bool copy_inverted = false;
2138 
2139  IDirect3DSurface9 *temp_surface = NULL;
2140  HRESULT hr;
2141 
2142  // Note if you try to grab the backbuffer and full-screen
2143  // anti-aliasing is on, the backbuffer might be larger than the
2144  // window size. For screenshots it's safer to get the front buffer.
2145  if (_cur_read_pixel_buffer & RenderBuffer::T_back) {
2146  DWORD render_target_index;
2147  IDirect3DSurface9 *backbuffer = NULL;
2148  // GetRenderTarget() seems to be a little more reliable than
2149  // GetBackBuffer(). Might just be related to the swap_chain
2150  // thing.
2151 
2152  render_target_index = 0;
2153  hr = _d3d_device->GetRenderTarget(render_target_index, &backbuffer);
2154 
2155  if (FAILED(hr)) {
2156  dxgsg9_cat.error() << "GetRenderTarget failed" << D3DERRORSTRING(hr);
2157  return false;
2158  }
2159 
2160  // Since we might not be able to Lock the back buffer, we will
2161  // need to copy it to a temporary surface of the appropriate type
2162  // first.
2163  D3DPOOL pool;
2164  D3DSURFACE_DESC surface_description;
2165 
2166  backbuffer -> GetDesc (&surface_description);
2167 
2168  pool = D3DPOOL_SYSTEMMEM;
2169  hr = _d3d_device->CreateOffscreenPlainSurface(
2170  surface_description.Width,
2171  surface_description.Height,
2172  surface_description.Format,
2173  pool,
2174  &temp_surface,
2175  NULL);
2176  if (FAILED(hr)) {
2177  dxgsg9_cat.error()
2178  << "CreateImageSurface failed in copy_pixel_buffer()"
2179  << D3DERRORSTRING(hr);
2180  backbuffer->Release();
2181  return false;
2182  }
2183 
2184  // Now we must copy from the backbuffer to our temporary surface.
2185  hr = _d3d_device -> GetRenderTargetData (backbuffer, temp_surface);
2186  if (FAILED(hr)) {
2187  dxgsg9_cat.error() << "GetRenderTargetData failed" << D3DERRORSTRING(hr);
2188  temp_surface->Release();
2189  backbuffer->Release();
2190  return false;
2191  }
2192 
2193  copy_inverted = true;
2194 
2195  RELEASE(backbuffer, dxgsg9, "backbuffer", RELEASE_ONCE);
2196 
2197  } else if (_cur_read_pixel_buffer & RenderBuffer::T_front) {
2198 
2199  if (_screen->_presentation_params.Windowed) {
2200  // GetFrontBuffer() retrieves the entire desktop for a monitor,
2201  // so we need to reserve space for that.
2202 
2203  // We have to use GetMonitorInfo(), since this GSG may not be
2204  // for the primary monitor.
2205  MONITORINFO minfo;
2206  minfo.cbSize = sizeof(MONITORINFO);
2207  GetMonitorInfo(_screen->_monitor, &minfo);
2208 
2209  w = RECT_XSIZE(minfo.rcMonitor);
2210  h = RECT_YSIZE(minfo.rcMonitor);
2211 
2212  // set rect to client area of window in scrn coords
2213  ClientToScreen(_screen->_window, (POINT*)&rect.left);
2214  ClientToScreen(_screen->_window, (POINT*)&rect.right);
2215  }
2216 
2217  // For GetFrontBuffer(), we need a temporary surface of type
2218  // A8R8G8B8. Unlike GetBackBuffer(), GetFrontBuffer() implicitly
2219  // performs a copy.
2220  hr = _d3d_device->CreateOffscreenPlainSurface(w, h, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &temp_surface, NULL);
2221  if (FAILED(hr)) {
2222  dxgsg9_cat.error()
2223  << "CreateImageSurface failed in copy_pixel_buffer()"
2224  << D3DERRORSTRING(hr);
2225  return false;
2226  }
2227 
2228  UINT swap_chain;
2229 
2230  swap_chain = 0;
2231  hr = _d3d_device->GetFrontBufferData(swap_chain,temp_surface);
2232 
2233  if (hr == D3DERR_DEVICELOST) {
2234  dxgsg9_cat.error()
2235  << "copy_pixel_buffer failed: device lost\n";
2236  temp_surface->Release();
2237  return false;
2238  }
2239 
2240  copy_inverted = true;
2241 
2242  } else {
2243  dxgsg9_cat.error()
2244  << "copy_pixel_buffer: unhandled current_read_pixel_buffer type\n";
2245  temp_surface->Release();
2246  return false;
2247  }
2248 
2249  if (inverted) {
2250  copy_inverted = !copy_inverted;
2251  }
2252  DXTextureContext9::d3d_surface_to_texture(rect, temp_surface,
2253  copy_inverted, tex, view, z);
2254 
2255  RELEASE(temp_surface, dxgsg9, "temp_surface", RELEASE_ONCE);
2256 
2257  nassertr(tex->has_ram_image(), false);
2258  return true;
2259 }
2260 
2261 void DXGraphicsStateGuardian9::reset_render_states (void)
2262 {
2263  int index;
2264  int maximum_texture_stages;
2265 
2266  maximum_texture_stages = D3D_MAXTEXTURESTAGES;
2267 
2268  // set to invalid values so that the state will always be set the first time
2269  memset (_render_state_array, -1, sizeof (_render_state_array));
2270  memset (_texture_stage_states_array, -1, sizeof (_texture_stage_states_array));
2271 
2272  // states that may be set intially to -1 by the user, so set it to D3D's default value
2273  _render_state_array [D3DRS_FOGCOLOR] = 0;
2274  _render_state_array [D3DRS_AMBIENT] = 0;
2275 
2276  // set to D3D default values or invalid values so that the state will always be set the first time
2277  memset (_texture_render_states_array, 0, sizeof (_texture_render_states_array));
2278 
2279  // states that may be set intially to 0 by the user, so set it to D3D's default value
2280  for (index = 0; index < MAXIMUM_TEXTURES; index++) {
2281  TextureRenderStates *texture_render_states;
2282 
2283  texture_render_states = &_texture_render_states_array [index];
2284  texture_render_states -> state_array [D3DSAMP_MAGFILTER] = D3DTEXF_POINT;
2285  texture_render_states -> state_array [D3DSAMP_MINFILTER] = D3DTEXF_POINT;
2286  texture_render_states -> state_array [D3DSAMP_MAXANISOTROPY] = 1;
2287  }
2288  _num_active_texture_stages = 0;
2289 
2290  set_render_state(D3DRS_NORMALIZENORMALS, false);
2291 
2292  _last_fvf = 0;
2293 }
2294 
2295 ////////////////////////////////////////////////////////////////////
2296 // Function: DXGraphicsStateGuardian9::reset
2297 // Access: Public, Virtual
2298 // Description: Resets all internal state as if the gsg were newly
2299 // created. The GraphicsWindow pointer represents a
2300 // typical window that might be used for this context;
2301 // it may be required to set up the frame buffer
2302 // properly the first time.
2303 ////////////////////////////////////////////////////////////////////
2307 
2308  // Build _inv_state_mask as a mask of 1's where we don't care, and
2309  // 0's where we do care, about the state.
2310  _inv_state_mask.clear_bit(ShaderAttrib::get_class_slot());
2311  _inv_state_mask.clear_bit(AlphaTestAttrib::get_class_slot());
2312  _inv_state_mask.clear_bit(ClipPlaneAttrib::get_class_slot());
2313  _inv_state_mask.clear_bit(ColorAttrib::get_class_slot());
2314  _inv_state_mask.clear_bit(ColorScaleAttrib::get_class_slot());
2315  _inv_state_mask.clear_bit(CullFaceAttrib::get_class_slot());
2316  _inv_state_mask.clear_bit(DepthOffsetAttrib::get_class_slot());
2317  _inv_state_mask.clear_bit(DepthTestAttrib::get_class_slot());
2318  _inv_state_mask.clear_bit(DepthWriteAttrib::get_class_slot());
2319  _inv_state_mask.clear_bit(RenderModeAttrib::get_class_slot());
2320  _inv_state_mask.clear_bit(RescaleNormalAttrib::get_class_slot());
2321  _inv_state_mask.clear_bit(ShadeModelAttrib::get_class_slot());
2322  _inv_state_mask.clear_bit(TransparencyAttrib::get_class_slot());
2323  _inv_state_mask.clear_bit(ColorWriteAttrib::get_class_slot());
2324  _inv_state_mask.clear_bit(ColorBlendAttrib::get_class_slot());
2325  _inv_state_mask.clear_bit(TextureAttrib::get_class_slot());
2326  _inv_state_mask.clear_bit(TexGenAttrib::get_class_slot());
2327  _inv_state_mask.clear_bit(TexMatrixAttrib::get_class_slot());
2328  _inv_state_mask.clear_bit(MaterialAttrib::get_class_slot());
2329  _inv_state_mask.clear_bit(LightAttrib::get_class_slot());
2330  _inv_state_mask.clear_bit(StencilAttrib::get_class_slot());
2331  _inv_state_mask.clear_bit(FogAttrib::get_class_slot());
2332  _inv_state_mask.clear_bit(ScissorAttrib::get_class_slot());
2333 
2334  // D3DRS_POINTSPRITEENABLE doesn't seem to support remapping the
2335  // texture coordinates via a texture matrix, so we don't advertise
2336  // GR_point_sprite_tex_matrix.
2337  _supported_geom_rendering =
2338  Geom::GR_point | Geom::GR_point_uniform_size |
2339  Geom::GR_point_perspective | Geom::GR_point_sprite |
2340  Geom::GR_indexed_other |
2341  Geom::GR_triangle_strip | Geom::GR_triangle_fan |
2342  Geom::GR_flat_first_vertex;
2343 
2344  _auto_rescale_normal = false;
2345 
2346  // overwrite gsg defaults with these values
2347 
2348  HRESULT hr;
2349 
2350  // make sure gsg passes all current state down to us
2351  // set_state_and_transform(RenderState::make_empty(),
2352  // TransformState::make_identity());
2353  // want gsg to pass all state settings down so any non-matching defaults we set here get overwritten
2354 
2355  nassertv(_screen->_d3d9 != NULL);
2356 
2357  if (_d3d_device == NULL) {
2358  return;
2359  }
2360 
2361  D3DCAPS9 d3d_caps;
2362  _d3d_device->GetDeviceCaps(&d3d_caps);
2363 
2364  _vertex_shader_version_major = D3DSHADER_VERSION_MAJOR (d3d_caps.VertexShaderVersion);
2365  _vertex_shader_version_minor = D3DSHADER_VERSION_MINOR (d3d_caps.VertexShaderVersion);
2366  _pixel_shader_version_major = D3DSHADER_VERSION_MAJOR (d3d_caps.PixelShaderVersion);
2367  _pixel_shader_version_minor = D3DSHADER_VERSION_MINOR (d3d_caps.PixelShaderVersion);
2368 
2369  _vertex_shader_profile = (char *) D3DXGetVertexShaderProfile (_d3d_device);
2370  _pixel_shader_profile = (char *) D3DXGetPixelShaderProfile (_d3d_device);
2371 
2372  _vertex_shader_maximum_constants = d3d_caps.MaxVertexShaderConst;
2373 
2374  switch (_pixel_shader_version_major)
2375  {
2376  case 0:
2377  _shader_model = SM_00;
2378  break;
2379  case 1:
2380  _shader_model = SM_11;
2381  break;
2382  case 2:
2383  // minimim specification for pixel shader 2.0 is 96 instruction slots
2384  _shader_model = SM_20;
2385  if (d3d_caps.PS20Caps.NumInstructionSlots >= 512) {
2386  _shader_model = SM_2X;
2387  }
2388  break;
2389  case 3:
2390  _shader_model = SM_30;
2391  break;
2392  case 4:
2393  _shader_model = SM_40;
2394  break;
2395  case 5:
2396  default:
2397  _shader_model = SM_50;
2398  break;
2399  }
2400 
2401  _auto_detect_shader_model = _shader_model;
2402 
2403 #ifdef HAVE_CG
2404  set_cg_device(_d3d_device);
2405 
2406  _cg_context = cgCreateContext();
2407 
2408  if (cgD3D9IsProfileSupported(CG_PROFILE_PS_2_0) &&
2409  cgD3D9IsProfileSupported(CG_PROFILE_VS_2_0)) {
2410  _supports_basic_shaders = true;
2411  _shader_caps._active_vprofile = (int)cgD3D9GetLatestVertexProfile();
2412  _shader_caps._active_fprofile = (int)cgD3D9GetLatestPixelProfile();
2413  _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VS_3_0;
2414  _shader_caps._ultimate_fprofile = (int)CG_PROFILE_PS_3_0;
2415 /*
2416  _shader_caps._active_vprofile = (int)CG_PROFILE_VS_2_0;
2417  _shader_caps._active_fprofile = (int)CG_PROFILE_PS_2_0;
2418  _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VS_2_0;
2419  _shader_caps._ultimate_fprofile = (int)CG_PROFILE_PS_2_0;
2420 */
2421  }
2422 
2423  if (dxgsg9_cat.is_debug()) {
2424  CGprofile vertex_profile;
2425  CGprofile pixel_profile;
2426 
2427  vertex_profile = cgD3D9GetLatestVertexProfile();
2428  pixel_profile = cgD3D9GetLatestPixelProfile();
2429 
2430  const char *vertex_profile_str =
2431  cgGetProfileString(vertex_profile);
2432  const char *pixel_profile_str =
2433  cgGetProfileString(pixel_profile);
2434 
2435  if (vertex_profile_str == NULL) {
2436  vertex_profile_str = "(null)";
2437  }
2438  if (pixel_profile_str == NULL) {
2439  pixel_profile_str = "(null)";
2440  }
2441 
2442  dxgsg9_cat.debug()
2443  << "\nCg latest vertex profile = " << vertex_profile_str << " id = " << vertex_profile
2444  << "\nCg latest pixel profile = " << pixel_profile_str << " id = " << pixel_profile
2445  << "\nshader model = " << _shader_model
2446  << "\n";
2447  }
2448 #endif
2449 
2450  _supports_stream_offset = (d3d_caps.DevCaps2 & D3DDEVCAPS2_STREAMOFFSET) != 0;
2451  _screen->_supports_dynamic_textures = ((d3d_caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES) != 0);
2452  _screen->_supports_automatic_mipmap_generation = ((d3d_caps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP) != 0);
2453 
2454  if (support_stencil) {
2455  int min_stencil = D3DSTENCILCAPS_ZERO | D3DSTENCILCAPS_REPLACE | D3DSTENCILCAPS_INCR | D3DSTENCILCAPS_DECR;
2456  if ((d3d_caps.StencilCaps & min_stencil) == min_stencil) {
2457  if (dxgsg9_cat.is_debug()) {
2458  dxgsg9_cat.debug()
2459  << "Checking for stencil; mode = "
2460  << D3DFormatStr(_screen->_presentation_params.AutoDepthStencilFormat)
2461  << "\n";
2462  }
2463  switch (_screen->_presentation_params.AutoDepthStencilFormat) {
2464  // These are the only formats that support stencil.
2465  case D3DFMT_D15S1:
2466  case D3DFMT_D24S8:
2467  case D3DFMT_D24X4S4:
2468  _supports_stencil = true;
2469  if (dxgsg9_cat.is_debug()) {
2470  dxgsg9_cat.debug()
2471  << "Stencils supported.\n";
2472  }
2473  break;
2474 
2475  default:
2476  if (dxgsg9_cat.is_debug()) {
2477  dxgsg9_cat.debug()
2478  << "Stencils NOT supported.\n";
2479  }
2480  }
2481  }
2482  }
2483 
2484  _supports_stencil_wrap = (d3d_caps.StencilCaps & D3DSTENCILCAPS_INCR) && (d3d_caps.StencilCaps & D3DSTENCILCAPS_DECR);
2485  _supports_two_sided_stencil = ((d3d_caps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) != 0);
2486 
2487  _max_color_targets = d3d_caps.NumSimultaneousRTs;
2488 
2489  _supports_depth_bias = ((d3d_caps.RasterCaps & (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS)) == (D3DPRASTERCAPS_DEPTHBIAS | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS));
2490 
2491  _supports_gamma_calibration = ((d3d_caps.Caps2 & D3DCAPS2_CANCALIBRATEGAMMA) != 0);
2492 
2493  // Test for occlusion query support
2494  hr = _d3d_device->CreateQuery(D3DQUERYTYPE_OCCLUSION, NULL);
2495  _supports_occlusion_query = !FAILED(hr);
2496 
2497  if (dxgsg9_cat.is_error()) {
2498  dxgsg9_cat.debug()
2499  << "\nHwTransformAndLight = " << ((d3d_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0)
2500  << "\nMaxTextureWidth = " << d3d_caps.MaxTextureWidth
2501  << "\nMaxTextureHeight = " << d3d_caps.MaxTextureHeight
2502  << "\nMaxVolumeExtent = " << d3d_caps.MaxVolumeExtent
2503  << "\nMaxTextureAspectRatio = " << d3d_caps.MaxTextureAspectRatio
2504  << "\nTexCoordCount = " << (d3d_caps.FVFCaps & D3DFVFCAPS_TEXCOORDCOUNTMASK)
2505  << "\nMaxTextureBlendStages = " << d3d_caps.MaxTextureBlendStages
2506  << "\nMaxSimultaneousTextures = " << d3d_caps.MaxSimultaneousTextures
2507  << "\nMaxActiveLights = " << d3d_caps.MaxActiveLights
2508  << "\nMaxUserClipPlanes = " << d3d_caps.MaxUserClipPlanes
2509  << "\nMaxVertexBlendMatrices = " << d3d_caps.MaxVertexBlendMatrices
2510  << "\nMaxVertexBlendMatrixIndex = " << d3d_caps.MaxVertexBlendMatrixIndex
2511  << "\nMaxPointSize = " << d3d_caps.MaxPointSize
2512  << "\nMaxPrimitiveCount = " << d3d_caps.MaxPrimitiveCount
2513  << "\nMaxVertexIndex = " << d3d_caps.MaxVertexIndex
2514  << "\nMaxStreams = " << d3d_caps.MaxStreams
2515  << "\nMaxStreamStride = " << d3d_caps.MaxStreamStride
2516  << "\nD3DTEXOPCAPS_MULTIPLYADD = " << ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_MULTIPLYADD) != 0)
2517  << "\nD3DTEXOPCAPS_LERP = " << ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_LERP) != 0)
2518  << "\nD3DPMISCCAPS_TSSARGTEMP = " << ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) != 0)
2519  << "\nD3DPRASTERCAPS_DEPTHBIAS = " << ((d3d_caps.RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0)
2520  << "\nD3DPRASTERCAPS_SLOPESCALEDEPTHBIAS = " << ((d3d_caps.RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS) != 0)
2521  << "\nVertexShaderVersion = " << _vertex_shader_version_major << "." << _vertex_shader_version_minor
2522  << "\nPixelShaderVersion = " << _pixel_shader_version_major << "." << _pixel_shader_version_minor
2523  << "\nMaxVertexShaderConst = " << _vertex_shader_maximum_constants
2524  << "\nsupports_stream_offset = " << _supports_stream_offset
2525  << "\nsupports_dynamic_textures = " << _screen->_supports_dynamic_textures
2526  << "\nsupports_automatic_mipmap_generation = " << _screen->_supports_automatic_mipmap_generation
2527  << "\nsupports_stencil_wrap = " << _supports_stencil_wrap
2528  << "\nsupports_two_sided_stencil = " << _supports_two_sided_stencil
2529  << "\nsupports_occlusion_query = " << _supports_occlusion_query
2530  << "\nsupports_gamma_calibration = " << _supports_gamma_calibration
2531  << "\nMaxAnisotropy = " << d3d_caps.MaxAnisotropy
2532  << "\nNumSimultaneousRTs = " << d3d_caps.NumSimultaneousRTs
2533  << "\nD3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING = " << ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING) != 0)
2534  << "\nDirectX SDK version " DIRECTX_SDK_VERSION
2535  << "\n";
2536  }
2537 
2538  // OVERRIDE SUPPORT SINCE IT DOES NOT WORK WELL
2539  _screen->_supports_automatic_mipmap_generation = false;
2540 
2541  this -> reset_render_states ( );
2542 
2543  _max_vertices_per_array = d3d_caps.MaxVertexIndex;
2544  _max_vertices_per_primitive = d3d_caps.MaxPrimitiveCount;
2545 
2546  _max_texture_stages = d3d_caps.MaxSimultaneousTextures;
2547 
2548  _max_texture_dimension = min(d3d_caps.MaxTextureWidth, d3d_caps.MaxTextureHeight);
2549 
2550  _supports_tex_non_pow2 = !(d3d_caps.TextureCaps & D3DPTEXTURECAPS_POW2);
2551 
2552  _supports_texture_combine = ((d3d_caps.TextureOpCaps & D3DTEXOPCAPS_LERP) != 0);
2553  _supports_texture_saved_result = ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) != 0);
2554  _supports_texture_constant_color = ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_PERSTAGECONSTANT) != 0);
2555  _supports_texture_dot3 = true;
2556 
2557  if (_supports_texture_constant_color) {
2558  _constant_color_operand = D3DTA_CONSTANT;
2559  } else {
2560  _constant_color_operand = D3DTA_TFACTOR;
2561  }
2562 
2563  _screen->_managed_textures = _gsg_managed_textures;
2564  _screen->_managed_vertex_buffers = _gsg_managed_vertex_buffers;
2565  _screen->_managed_index_buffers = _gsg_managed_index_buffers;
2566 
2567  UINT available_texture_memory;
2568 
2569  available_texture_memory = _d3d_device->GetAvailableTextureMem ( );
2570  if (dxgsg9_cat.is_debug()) {
2571  dxgsg9_cat.debug() << "*** GetAvailableTextureMem = " << available_texture_memory << "\n";
2572  }
2573  _available_texture_memory = available_texture_memory;
2574 
2575  // check for render to texture support
2576  D3DDEVICE_CREATION_PARAMETERS creation_parameters;
2577 
2578  _supports_render_texture = false;
2579  _screen->_render_to_texture_d3d_format = D3DFMT_UNKNOWN;
2580  _screen->_framebuffer_d3d_format = D3DFMT_UNKNOWN;
2581 
2582  #define TOTAL_RENDER_TO_TEXTURE_FORMATS 3
2583 
2584  D3DFORMAT render_to_texture_formats [TOTAL_RENDER_TO_TEXTURE_FORMATS] =
2585  {
2586  D3DFMT_A8R8G8B8, // check for this format first
2587  D3DFMT_X8R8G8B8,
2588  D3DFMT_UNKNOWN, // place holder for _screen->_display_mode.Format
2589  };
2590 
2591  render_to_texture_formats [TOTAL_RENDER_TO_TEXTURE_FORMATS - 1] = _screen->_display_mode.Format;
2592 
2593  hr = _d3d_device->GetCreationParameters (&creation_parameters);
2594  if (SUCCEEDED (hr)) {
2595  _screen->_framebuffer_d3d_format = _screen->_display_mode.Format;
2596 
2597  int index;
2598  for (index = 0; index < TOTAL_RENDER_TO_TEXTURE_FORMATS; index++) {
2599  hr = _screen->_d3d9->CheckDeviceFormat (
2600  creation_parameters.AdapterOrdinal,
2601  creation_parameters.DeviceType,
2602  _screen->_display_mode.Format,
2603  D3DUSAGE_RENDERTARGET,
2604  D3DRTYPE_TEXTURE,
2605  render_to_texture_formats [index]);
2606  if (SUCCEEDED (hr)) {
2607  _screen->_render_to_texture_d3d_format = render_to_texture_formats [index];
2608  _supports_render_texture = true;
2609  }
2610  if (_supports_render_texture) {
2611  break;
2612  }
2613  }
2614  }
2615  if (dxgsg9_cat.is_debug()) {
2616  dxgsg9_cat.debug() << "Render to Texture Support = " << _supports_render_texture << "\n";
2617  }
2618 
2619  // override default config setting since it is really supported or not ???
2620 // support_render_texture = _supports_render_texture;
2621 
2622  _supports_3d_texture = ((d3d_caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) != 0);
2623  if (_supports_3d_texture) {
2624  _max_3d_texture_dimension = d3d_caps.MaxVolumeExtent;
2625  }
2626  _supports_cube_map = ((d3d_caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) != 0);
2627  if (_supports_cube_map) {
2628  _max_cube_map_dimension = _max_texture_dimension;
2629  }
2630 
2631  _max_lights = (int)d3d_caps.MaxActiveLights;
2632  _max_clip_planes = (int)d3d_caps.MaxUserClipPlanes;
2633  _max_vertex_transforms = d3d_caps.MaxVertexBlendMatrices;
2634  _max_vertex_transform_indices = d3d_caps.MaxVertexBlendMatrixIndex;
2635 
2636  set_render_state(D3DRS_AMBIENT, 0x0);
2637 
2638  _clip_plane_bits = 0;
2639  set_render_state(D3DRS_CLIPPLANEENABLE , 0x0);
2640 
2641  set_render_state(D3DRS_CLIPPING, true);
2642 
2643  set_render_state(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
2644 
2645  set_render_state(D3DRS_ZWRITEENABLE, TRUE);
2646 
2647 /* ***** DX9 ??? D3DRS_EDGEANTIALIAS NOT IN DX9 */
2648 // set_render_state(D3DRS_EDGEANTIALIAS, false);
2649 
2650  set_render_state(D3DRS_ZENABLE, D3DZB_FALSE);
2651 
2652  set_render_state(D3DRS_ALPHABLENDENABLE, FALSE);
2653 
2654  set_render_state(D3DRS_FOGENABLE, FALSE);
2655 
2656  _has_scene_graph_color = false;
2657 
2658  _last_testcooplevel_result = D3D_OK;
2659 
2660  if (dxgsg9_cat.is_debug()) {
2661  dxgsg9_cat.debug() << "Supported texture formats:\n";
2662  }
2663 
2664  for(int i = 0; i < MAX_POSSIBLE_TEXFMTS; i++) {
2665  // look for all possible DX9 texture fmts
2666  D3DFORMAT_FLAG fmtflag = D3DFORMAT_FLAG(1 << i);
2667  hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format,
2668  0x0, D3DRTYPE_TEXTURE, g_D3DFORMATmap[fmtflag]);
2669  if (SUCCEEDED(hr)) {
2670  if (dxgsg9_cat.is_debug()) {
2671  dxgsg9_cat.debug() << " " << D3DFormatStr(g_D3DFORMATmap[fmtflag]) << "\n";
2672  }
2673  _screen->_supported_tex_formats_mask |= fmtflag;
2674  }
2675  }
2676 
2677  // check if compressed textures are supported
2678  #define CHECK_FOR_DXTVERSION(num) \
2679  if (_screen->_supported_tex_formats_mask & DXT##num##_FLAG) {\
2680  if (dxgsg9_cat.is_debug()) {\
2681  dxgsg9_cat.debug() << "Compressed texture format DXT" << #num << " supported\n";\
2682  }\
2683  _supports_compressed_texture = true;\
2684  _compressed_texture_formats.set_bit(Texture::CM_dxt##num);\
2685  }
2686 
2687  if (_screen->_intel_compressed_texture_bug) {
2688  dxgsg9_cat.info()
2689  << "Buggy Intel driver detected; disabling compressed textures.\n";
2690  _screen->_supported_tex_formats_mask &=
2691  ~(DXT1_FLAG | DXT2_FLAG | DXT3_FLAG | DXT4_FLAG | DXT5_FLAG);
2692 
2693  } else {
2694  // Check for available compressed formats normally.
2695  CHECK_FOR_DXTVERSION(1);
2696  CHECK_FOR_DXTVERSION(2);
2697  CHECK_FOR_DXTVERSION(3);
2698  CHECK_FOR_DXTVERSION(4);
2699  CHECK_FOR_DXTVERSION(5);
2700  }
2701 
2702  #undef CHECK_FOR_DXTVERSION
2703 
2704  _screen->_supports_rgba16f_texture_format = false;
2705  hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format, 0x0, D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F);
2706  if (SUCCEEDED(hr)){
2707  _screen->_supports_rgba16f_texture_format = true;
2708  }
2709  _screen->_supports_rgba32_texture_format = false;
2710  hr = _screen->_d3d9->CheckDeviceFormat(_screen->_card_id, D3DDEVTYPE_HAL, _screen->_display_mode.Format, 0x0, D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F);
2711  if (SUCCEEDED(hr)){
2712  _screen->_supports_rgba32_texture_format = true;
2713  }
2714 
2715  // s3 virge drivers sometimes give crap values for these
2716  if (_screen->_d3dcaps.MaxTextureWidth == 0)
2717  _screen->_d3dcaps.MaxTextureWidth = 256;
2718 
2719  if (_screen->_d3dcaps.MaxTextureHeight == 0)
2720  _screen->_d3dcaps.MaxTextureHeight = 256;
2721 
2722  if (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGTABLE) {
2723  // Watch out for drivers that emulate per-pixel fog with
2724  // per-vertex fog (Riva128, Matrox Millen G200). Some of these
2725  // require gouraud-shading to be set to work, as if you were using
2726  // vertex fog
2727  _do_fog_type = PerPixelFog;
2728  } else {
2729  // every card is going to have vertex fog, since it's implemented
2730  // in d3d runtime.
2731  nassertv((_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGVERTEX) != 0);
2732 
2733  // vertex fog may look crappy if you have large polygons in the
2734  // foreground and they get clipped, so you may want to disable it
2735 
2736  if (dx_no_vertex_fog) {
2737  _do_fog_type = None;
2738  } else {
2739  _do_fog_type = PerVertexFog;
2740 
2741  // range-based fog only works with vertex fog in dx7/8
2742  if (dx_use_rangebased_fog && (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_FOGRANGE)) {
2743  set_render_state(D3DRS_RANGEFOGENABLE, true);
2744  }
2745  }
2746  }
2747 
2748  _screen->_can_direct_disable_color_writes = ((_screen->_d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) != 0);
2749 
2750  // Lighting, let's turn it off initially.
2751  set_render_state(D3DRS_LIGHTING, false);
2752 
2753  // turn on dithering if the rendertarget is < 8bits/color channel
2754  bool dither_enabled = ((!dx_no_dithering) && IS_16BPP_DISPLAY_FORMAT(_screen->_presentation_params.BackBufferFormat)
2755  && (_screen->_d3dcaps.RasterCaps & D3DPRASTERCAPS_DITHER));
2756  set_render_state(D3DRS_DITHERENABLE, dither_enabled);
2757 
2758  set_render_state(D3DRS_CLIPPING, true);
2759 
2760  // Stencil test is off by default
2761  set_render_state(D3DRS_STENCILENABLE, FALSE);
2762  if (_supports_two_sided_stencil) {
2763  set_render_state(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
2764  }
2765 
2766  // Antialiasing.
2767 /* ***** DX9 ??? D3DRS_EDGEANTIALIAS NOT IN DX9 */
2768 // set_render_state(D3DRS_EDGEANTIALIAS, FALSE);
2769 
2770  _current_fill_mode = RenderModeAttrib::M_filled;
2771  set_render_state(D3DRS_FILLMODE, D3DFILL_SOLID);
2772 
2773  // must do SetTSS here because redundant states are filtered out by
2774  // our code based on current values above, so initial conditions
2775  // must be correct
2776  set_texture_stage_state(0, D3DTSS_COLOROP, D3DTOP_DISABLE); // disables texturing
2777 
2778  _cull_face_mode = CullFaceAttrib::M_cull_none;
2779  set_render_state(D3DRS_CULLMODE, D3DCULL_NONE);
2780 
2781  set_render_state(D3DRS_ALPHAFUNC, D3DCMP_ALWAYS);
2782  set_render_state(D3DRS_ALPHAREF, 255);
2783  set_render_state(D3DRS_ALPHATESTENABLE, FALSE);
2784 
2785  // this is a new DX8 state that lets you do additional operations other than ADD (e.g. subtract/max/min)
2786  // must check (_screen->_d3dcaps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) (yes on GF2/Radeon8500, no on TNT)
2787  set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
2788 
2789  _current_shader = (Shader *)NULL;
2790  _current_shader_context = (CLP(ShaderContext) *)NULL;
2791  _vertex_array_shader = (Shader *)NULL;
2792  _vertex_array_shader_context = (CLP(ShaderContext) *)NULL;
2793  _texture_binding_shader = (Shader *)NULL;
2794  _texture_binding_shader_context = (CLP(ShaderContext) *)NULL;
2795 
2796  PRINT_REFCNT(dxgsg9, _d3d_device);
2797 
2798  // Now that the GSG has been initialized, make it available for
2799  // optimizations.
2800  add_gsg(this);
2801 }
2802 
2803 ////////////////////////////////////////////////////////////////////
2804 // Function: DXGraphicsStateGuardian9::apply_fog
2805 // Access: Public, Virtual
2806 // Description:
2807 ////////////////////////////////////////////////////////////////////
2808 void DXGraphicsStateGuardian9::
2809 apply_fog(Fog *fog) {
2810  if (_do_fog_type == None)
2811  return;
2812 
2813  Fog::Mode panda_fogmode = fog->get_mode();
2814  D3DFOGMODE d3dfogmode = get_fog_mode_type(panda_fogmode);
2815 
2816  set_render_state((D3DRENDERSTATETYPE)_do_fog_type, d3dfogmode);
2817 
2818  const LColor &fog_colr = fog->get_color();
2819  set_render_state(D3DRS_FOGCOLOR,
2820  MY_D3DRGBA(fog_colr[0], fog_colr[1], fog_colr[2], 0.0f)); // Alpha bits are not used
2821 
2822  // do we need to adjust fog start/end values based on D3DPRASTERCAPS_WFOG/D3DPRASTERCAPS_ZFOG ?
2823  // if not WFOG, then docs say we need to adjust values to range [0, 1]
2824 
2825  switch (panda_fogmode) {
2826  case Fog::M_linear:
2827  {
2828  PN_stdfloat onset, opaque;
2829  fog->get_linear_range(onset, opaque);
2830 
2831  set_render_state(D3DRS_FOGSTART,
2832  *((LPDWORD) (&onset)));
2833  set_render_state(D3DRS_FOGEND,
2834  *((LPDWORD) (&opaque)));
2835  }
2836  break;
2837  case Fog::M_exponential:
2838  case Fog::M_exponential_squared:
2839  {
2840  // Exponential fog is always camera-relative.
2841  PN_stdfloat fog_density = fog->get_exp_density();
2842  set_render_state(D3DRS_FOGDENSITY,
2843  *((LPDWORD) (&fog_density)));
2844  }
2845  break;
2846  }
2847 }
2848 
2849 ////////////////////////////////////////////////////////////////////
2850 // Function: DXGraphicsStateGuardian9::do_issue_transform
2851 // Access: Protected
2852 // Description: Sends the indicated transform matrix to the graphics
2853 // API to be applied to future vertices.
2854 //
2855 // This transform is the internal_transform, already
2856 // converted into the GSG's internal coordinate system.
2857 ////////////////////////////////////////////////////////////////////
2858 void DXGraphicsStateGuardian9::
2859 do_issue_transform() {
2860  const TransformState *transform = _internal_transform;
2861  DO_PSTATS_STUFF(_transform_state_pcollector.add_level(1));
2862 
2863  if (_current_shader_context) {
2864 // _current_shader_context->issue_transform(this);
2865  _current_shader_context->issue_parameters(this, Shader::SSD_transform);
2866 
2867 // ??? NO NEED TO SET THE D3D TRANSFORM VIA SetTransform SINCE THE TRANSFORM IS ONLY USED IN THE SHADER
2868  LMatrix4f mat = LCAST(float, transform->get_mat());
2869  const D3DMATRIX *d3d_mat = (const D3DMATRIX *)mat.get_data();
2870  _d3d_device->SetTransform(D3DTS_WORLD, d3d_mat);
2871 
2872  }
2873  else {
2874  LMatrix4f mat = LCAST(float, transform->get_mat());
2875  const D3DMATRIX *d3d_mat = (const D3DMATRIX *)mat.get_data();
2876  _d3d_device->SetTransform(D3DTS_WORLD, d3d_mat);
2877 
2878 // DEBUG PRINT
2879 /*
2880  const PN_stdfloat *data;
2881  data = &d3d_mat -> _11;
2882  dxgsg9_cat.debug ( ) << "do_issue_transform\n" <<
2883  data[ 0] << " " << data[ 1] << " " << data[ 2] << " " << data[ 3] << "\n" <<
2884  data[ 4] << " " << data[ 5] << " " << data[ 6] << " " << data[ 7] << "\n" <<
2885  data[ 8] << " " << data[ 9] << " " << data[10] << " " << data[11] << "\n" <<
2886  data[12] << " " << data[13] << " " << data[14] << " " << data[15] << "\n";
2887 */
2888 
2889  }
2890 
2891  _transform_stale = false;
2892 
2893  if (_auto_rescale_normal) {
2894  do_auto_rescale_normal();
2895  }
2896 }
2897 
2898 ////////////////////////////////////////////////////////////////////
2899 // Function: DXGraphicsStateGuardian9::do_issue_alpha_test
2900 // Access: Protected
2901 // Description:
2902 ////////////////////////////////////////////////////////////////////
2903 void DXGraphicsStateGuardian9::
2904 do_issue_alpha_test() {
2905  if (_target_shader->get_flag(ShaderAttrib::F_subsume_alpha_test)) {
2906  set_render_state(D3DRS_ALPHATESTENABLE, FALSE);
2907  } else {
2908  const AlphaTestAttrib *target_alpha_test = DCAST(AlphaTestAttrib, _target_rs->get_attrib_def(AlphaTestAttrib::get_class_slot()));
2909  AlphaTestAttrib::PandaCompareFunc mode = target_alpha_test->get_mode();
2910  if (mode == AlphaTestAttrib::M_none) {
2911  set_render_state(D3DRS_ALPHATESTENABLE, FALSE);
2912  } else {
2913  // AlphaTestAttrib::PandaCompareFunc === D3DCMPFUNC
2914  set_render_state(D3DRS_ALPHAFUNC, (D3DCMPFUNC)mode);
2915  set_render_state(D3DRS_ALPHAREF, (UINT) (target_alpha_test->get_reference_alpha()*255.0f)); //d3d uses 0x0-0xFF, not a float
2916  set_render_state(D3DRS_ALPHATESTENABLE, TRUE);
2917  }
2918  }
2919 }
2920 
2921 ////////////////////////////////////////////////////////////////////
2922 // Function: DXGraphicsStateGuardian9::do_issue_shader
2923 // Access: Protected
2924 // Description:
2925 ////////////////////////////////////////////////////////////////////
2926 void DXGraphicsStateGuardian9::
2927 do_issue_shader() {
2928 
2929  CLP(ShaderContext) *context = 0;
2930  Shader *shader = 0;
2931  if (_target_shader) {
2932  shader = (Shader *)(_target_shader->get_shader());
2933  }
2934  if (shader) {
2935  context = (CLP(ShaderContext) *)(shader->prepare_now(get_prepared_objects(), this));
2936  }
2937 
2938  if (context == 0 || (context && context -> valid (this) == false)) {
2939  if (_current_shader_context != 0) {
2940  _current_shader_context->unbind(this);
2941  _current_shader = 0;
2942  _current_shader_context = 0;
2943  disable_standard_texture_bindings();
2944  }
2945  return;
2946  }
2947 
2948  if (context != _current_shader_context) {
2949  // Use a completely different shader than before.
2950  // Unbind old shader, bind the new one.
2951  if (_current_shader_context != 0) {
2952  _current_shader_context->unbind(this);
2953  _current_shader_context = 0;
2954  _current_shader = 0;
2955  disable_standard_texture_bindings();
2956  }
2957  if (context != 0) {
2958  context->bind(this);
2959  _current_shader = shader;
2960  _current_shader_context = context;
2961  }
2962  } else {
2963  // Use the same shader as before, but with new input arguments.
2964  context->issue_parameters(this, Shader::SSD_shaderinputs);
2965  }
2966 }
2967 
2968 ////////////////////////////////////////////////////////////////////
2969 // Function: DXGraphicsStateGuardian9::do_issue_render_mode
2970 // Access: Protected
2971 // Description:
2972 ////////////////////////////////////////////////////////////////////
2973 void DXGraphicsStateGuardian9::
2974 do_issue_render_mode() {
2975  const RenderModeAttrib *target_render_mode = DCAST(RenderModeAttrib, _target_rs->get_attrib_def(RenderModeAttrib::get_class_slot()));
2976  RenderModeAttrib::Mode mode = target_render_mode->get_mode();
2977 
2978  switch (mode) {
2979  case RenderModeAttrib::M_unchanged:
2980  case RenderModeAttrib::M_filled:
2981  case RenderModeAttrib::M_filled_flat:
2982  set_render_state(D3DRS_FILLMODE, D3DFILL_SOLID);
2983  break;
2984 
2985  case RenderModeAttrib::M_wireframe:
2986  set_render_state(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
2987  break;
2988 
2989  case RenderModeAttrib::M_point:
2990  set_render_state(D3DRS_FILLMODE, D3DFILL_POINT);
2991  break;
2992 
2993  default:
2994  dxgsg9_cat.error()
2995  << "Unknown render mode " << (int)mode << endl;
2996  }
2997 
2998  // This might also specify the point size.
2999  PN_stdfloat point_size = target_render_mode->get_thickness();
3000  set_render_state(D3DRS_POINTSIZE, *((DWORD*)&point_size));
3001 
3002  if (target_render_mode->get_perspective()) {
3003  set_render_state(D3DRS_POINTSCALEENABLE, TRUE);
3004 
3005  LVector3 height(0.0f, point_size, 1.0f);
3006  height = height * _projection_mat->get_mat();
3007  PN_stdfloat s = height[1] / point_size;
3008 
3009  PN_stdfloat zero = 0.0f;
3010  PN_stdfloat one_over_s2 = 1.0f / (s * s);
3011  set_render_state(D3DRS_POINTSCALE_A, *((DWORD*)&zero));
3012  set_render_state(D3DRS_POINTSCALE_B, *((DWORD*)&zero));
3013  set_render_state(D3DRS_POINTSCALE_C, *((DWORD*)&one_over_s2));
3014 
3015  } else {
3016  set_render_state(D3DRS_POINTSCALEENABLE, FALSE);
3017  }
3018 
3019  _current_fill_mode = mode;
3020 }
3021 
3022 ////////////////////////////////////////////////////////////////////
3023 // Function: DXGraphicsStateGuardian9::do_issue_rescale_normal
3024 // Access: Protected
3025 // Description:
3026 ////////////////////////////////////////////////////////////////////
3027 void DXGraphicsStateGuardian9::
3028 do_issue_rescale_normal() {
3029  const RescaleNormalAttrib *target_rescale_normal = DCAST(RescaleNormalAttrib, _target_rs->get_attrib_def(RescaleNormalAttrib::get_class_slot()));
3030  RescaleNormalAttrib::Mode mode = target_rescale_normal->get_mode();
3031 
3032  _auto_rescale_normal = false;
3033 
3034  switch (mode) {
3035  case RescaleNormalAttrib::M_none:
3036  set_render_state(D3DRS_NORMALIZENORMALS, false);
3037  break;
3038 
3039  case RescaleNormalAttrib::M_rescale:
3040  case RescaleNormalAttrib::M_normalize:
3041  set_render_state(D3DRS_NORMALIZENORMALS, true);
3042  break;
3043 
3044  case RescaleNormalAttrib::M_auto:
3045  _auto_rescale_normal = true;
3046  do_auto_rescale_normal();
3047  break;
3048 
3049  default:
3050  dxgsg9_cat.error()
3051  << "Unknown rescale_normal mode " << (int)mode << endl;
3052  }
3053 }
3054 
3055 ////////////////////////////////////////////////////////////////////
3056 // Function: DXGraphicsStateGuardian9::do_issue_depth_test
3057 // Access: Protected
3058 // Description:
3059 ////////////////////////////////////////////////////////////////////
3060 void DXGraphicsStateGuardian9::
3061 do_issue_depth_test() {
3062  const DepthTestAttrib *target_depth_test = DCAST(DepthTestAttrib, _target_rs->get_attrib_def(DepthTestAttrib::get_class_slot()));
3063  DepthTestAttrib::PandaCompareFunc mode = target_depth_test->get_mode();
3064  if (mode == DepthTestAttrib::M_none) {
3065  set_render_state(D3DRS_ZENABLE, D3DZB_FALSE);
3066  } else {
3067  set_render_state(D3DRS_ZENABLE, D3DZB_TRUE);
3068  set_render_state(D3DRS_ZFUNC, (D3DCMPFUNC) mode);
3069  }
3070 }
3071 
3072 ////////////////////////////////////////////////////////////////////
3073 // Function: DXGraphicsStateGuardian9::do_issue_depth_write
3074 // Access: Protected
3075 // Description:
3076 ////////////////////////////////////////////////////////////////////
3077 void DXGraphicsStateGuardian9::
3078 do_issue_depth_write() {
3079  const DepthWriteAttrib *target_depth_write = DCAST(DepthWriteAttrib, _target_rs->get_attrib_def(DepthWriteAttrib::get_class_slot()));
3080  DepthWriteAttrib::Mode mode = target_depth_write->get_mode();
3081  if (mode == DepthWriteAttrib::M_on) {
3082  set_render_state(D3DRS_ZWRITEENABLE, TRUE);
3083  } else {
3084  set_render_state(D3DRS_ZWRITEENABLE, FALSE);
3085  }
3086 }
3087 
3088 ////////////////////////////////////////////////////////////////////
3089 // Function: DXGraphicsStateGuardian9::do_issue_cull_face
3090 // Access: Protected
3091 // Description:
3092 ////////////////////////////////////////////////////////////////////
3093 void DXGraphicsStateGuardian9::
3094 do_issue_cull_face() {
3095  const CullFaceAttrib *target_cull_face = DCAST(CullFaceAttrib, _target_rs->get_attrib_def(CullFaceAttrib::get_class_slot()));
3096  _cull_face_mode = target_cull_face->get_effective_mode();
3097 
3098  switch (_cull_face_mode) {
3099  case CullFaceAttrib::M_cull_none:
3100  set_render_state(D3DRS_CULLMODE, D3DCULL_NONE);
3101 
3102 // printf ("------------------- D3DCULL_NONE\n");
3103 
3104  break;
3105  case CullFaceAttrib::M_cull_clockwise:
3106  set_render_state(D3DRS_CULLMODE, D3DCULL_CW);
3107 
3108 // printf ("------------------- D3DCULL_CW -- CLOCKWISE \n");
3109 
3110  break;
3111  case CullFaceAttrib::M_cull_counter_clockwise:
3112  set_render_state(D3DRS_CULLMODE, D3DCULL_CCW);
3113 
3114 // printf ("------------------- D3DCULL_CCW\n");
3115 
3116  break;
3117  default:
3118  dxgsg9_cat.error()
3119  << "invalid cull face mode " << (int)_cull_face_mode << endl;
3120  break;
3121  }
3122 }
3123 
3124 ////////////////////////////////////////////////////////////////////
3125 // Function: DXGraphicsStateGuardian9::do_issue_fog
3126 // Access: Protected
3127 // Description:
3128 ////////////////////////////////////////////////////////////////////
3129 void DXGraphicsStateGuardian9::
3130 do_issue_fog() {
3131  const FogAttrib *target_fog = DCAST(FogAttrib, _target_rs->get_attrib_def(FogAttrib::get_class_slot()));
3132  if (!target_fog->is_off()) {
3133  set_render_state(D3DRS_FOGENABLE, TRUE);
3134  Fog *fog = target_fog->get_fog();
3135  nassertv(fog != (Fog *)NULL);
3136  apply_fog(fog);
3137  } else {
3138  set_render_state(D3DRS_FOGENABLE, FALSE);
3139  }
3140 }
3141 
3142 ////////////////////////////////////////////////////////////////////
3143 // Function: DXGraphicsStateGuardian9::do_issue_depth_offset
3144 // Access: Protected
3145 // Description:
3146 ////////////////////////////////////////////////////////////////////
3147 void DXGraphicsStateGuardian9::
3148 do_issue_depth_offset() {
3149  const DepthOffsetAttrib *target_depth_offset = DCAST(DepthOffsetAttrib, _target_rs->get_attrib_def(DepthOffsetAttrib::get_class_slot()));
3150  int offset = target_depth_offset->get_offset();
3151 
3152  if (_supports_depth_bias && !dx_broken_depth_bias) {
3153  set_render_state(D3DRS_DEPTHBIAS, offset);
3154  set_render_state(D3DRS_SLOPESCALEDEPTHBIAS, offset);
3155 
3156  } else {
3157  // DirectX depth bias isn't directly supported by the driver.
3158  // Cheese a depth bias effect by sliding the viewport backward a
3159  // bit.
3160  static const PN_stdfloat bias_scale = dx_depth_bias_scale;
3161  D3DVIEWPORT9 vp = _current_viewport;
3162  vp.MinZ -= bias_scale * offset;
3163  vp.MaxZ -= bias_scale * offset;
3164  _d3d_device->SetViewport(&vp);
3165  }
3166 }
3167 
3168 ////////////////////////////////////////////////////////////////////
3169 // Function: DXGraphicsStateGuardian9::do_issue_shade_model
3170 // Access: Protected
3171 // Description:
3172 ////////////////////////////////////////////////////////////////////
3173 void DXGraphicsStateGuardian9::
3174 do_issue_shade_model() {
3175  const ShadeModelAttrib *target_shade_model = DCAST(ShadeModelAttrib, _target_rs->get_attrib_def(ShadeModelAttrib::get_class_slot()));
3176  switch (target_shade_model->get_mode()) {
3177  case ShadeModelAttrib::M_smooth:
3178  set_render_state(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
3179  break;
3180 
3181  case ShadeModelAttrib::M_flat:
3182  set_render_state(D3DRS_SHADEMODE, D3DSHADE_FLAT);
3183  break;
3184  }
3185 }
3186 
3187 ////////////////////////////////////////////////////////////////////
3188 // Function: DXGraphicsStateGuardian9::set_state_and_transform
3189 // Access: Public, Virtual
3190 // Description: Simultaneously resets the render state and the
3191 // transform state.
3192 //
3193 // This transform specified is the "internal" net
3194 // transform, already converted into the GSG's internal
3195 // coordinate space by composing it to
3196 // get_cs_transform(). (Previously, this used to be the
3197 // "external" net transform, with the assumption that
3198 // that GSG would convert it internally, but that is no
3199 // longer the case.)
3200 //
3201 // Special case: if (state==NULL), then the target
3202 // state is already stored in _target.
3203 ////////////////////////////////////////////////////////////////////
3206  const TransformState *transform) {
3207 #ifndef NDEBUG
3208  if (gsg_cat.is_spam()) {
3209  gsg_cat.spam() << "Setting GSG state to " << (void *)target << ":\n";
3210  target->write(gsg_cat.spam(false), 2);
3211  }
3212 #endif
3213  _state_pcollector.add_level(1);
3214  PStatTimer timer1(_draw_set_state_pcollector);
3215 
3216  if (transform != _internal_transform) {
3217  //PStatTimer timer(_draw_set_state_transform_pcollector);
3218  _state_pcollector.add_level(1);
3219  _internal_transform = transform;
3220  do_issue_transform();
3221  }
3222 
3223  if (target == _state_rs && (_state_mask | _inv_state_mask).is_all_on()) {
3224  return;
3225  }
3226  _target_rs = target;
3227 
3228  _target_shader = DCAST(ShaderAttrib, _target_rs->get_attrib_def(ShaderAttrib::get_class_slot()));
3229 
3230  int alpha_test_slot = AlphaTestAttrib::get_class_slot();
3231  if (_target_rs->get_attrib(alpha_test_slot) != _state_rs->get_attrib(alpha_test_slot) ||
3232  !_state_mask.get_bit(alpha_test_slot)) {
3233  //PStatTimer timer(_draw_set_state_alpha_test_pcollector);
3234  do_issue_alpha_test();
3235  _state_mask.set_bit(alpha_test_slot);
3236  }
3237 
3238  int clip_plane_slot = ClipPlaneAttrib::get_class_slot();
3239  if (_target_rs->get_attrib(clip_plane_slot) != _state_rs->get_attrib(clip_plane_slot) ||
3240  !_state_mask.get_bit(clip_plane_slot)) {
3241  //PStatTimer timer(_draw_set_state_clip_plane_pcollector);
3242  do_issue_clip_plane();
3243  _state_mask.set_bit(clip_plane_slot);
3244  }
3245 
3246  int color_slot = ColorAttrib::get_class_slot();
3247  int color_scale_slot = ColorScaleAttrib::get_class_slot();
3248  if (_target_rs->get_attrib(color_slot) != _state_rs->get_attrib(color_slot) ||
3249  _target_rs->get_attrib(color_scale_slot) != _state_rs->get_attrib(color_scale_slot) ||
3250  !_state_mask.get_bit(color_slot) ||
3251  !_state_mask.get_bit(color_scale_slot)) {
3252  //PStatTimer timer(_draw_set_state_color_pcollector);
3253  do_issue_color();
3254  do_issue_color_scale();
3255  _state_mask.set_bit(color_slot);
3256  _state_mask.set_bit(color_scale_slot);
3257  if (_current_shader_context) {
3258  _current_shader_context->issue_parameters(this, Shader::SSD_color);
3259  _current_shader_context->issue_parameters(this, Shader::SSD_colorscale);
3260  }
3261  }
3262 
3263  int cull_face_slot = CullFaceAttrib::get_class_slot();
3264  if (_target_rs->get_attrib(cull_face_slot) != _state_rs->get_attrib(cull_face_slot) ||
3265  !_state_mask.get_bit(cull_face_slot)) {
3266  //PStatTimer timer(_draw_set_state_cull_face_pcollector);
3267  do_issue_cull_face();
3268  _state_mask.set_bit(cull_face_slot);
3269  }
3270 
3271  int depth_offset_slot = DepthOffsetAttrib::get_class_slot();
3272  if (_target_rs->get_attrib(depth_offset_slot) != _state_rs->get_attrib(depth_offset_slot) ||
3273  !_state_mask.get_bit(depth_offset_slot)) {
3274  //PStatTimer timer(_draw_set_state_depth_offset_pcollector);
3275  do_issue_depth_offset();
3276  _state_mask.set_bit(depth_offset_slot);
3277  }
3278 
3279  int depth_test_slot = DepthTestAttrib::get_class_slot();
3280  if (_target_rs->get_attrib(depth_test_slot) != _state_rs->get_attrib(depth_test_slot) ||
3281  !_state_mask.get_bit(depth_test_slot)) {
3282  //PStatTimer timer(_draw_set_state_depth_test_pcollector);
3283  do_issue_depth_test();
3284  _state_mask.set_bit(depth_test_slot);
3285  }
3286 
3287  int depth_write_slot = DepthWriteAttrib::get_class_slot();
3288  if (_target_rs->get_attrib(depth_write_slot) != _state_rs->get_attrib(depth_write_slot) ||
3289  !_state_mask.get_bit(depth_write_slot)) {
3290  //PStatTimer timer(_draw_set_state_depth_write_pcollector);
3291  do_issue_depth_write();
3292  _state_mask.set_bit(depth_write_slot);
3293  }
3294 
3295  int render_mode_slot = RenderModeAttrib::get_class_slot();
3296  if (_target_rs->get_attrib(render_mode_slot) != _state_rs->get_attrib(render_mode_slot) ||
3297  !_state_mask.get_bit(render_mode_slot)) {
3298  //PStatTimer timer(_draw_set_state_render_mode_pcollector);
3299  do_issue_render_mode();
3300  _state_mask.set_bit(render_mode_slot);
3301  }
3302 
3303  int rescale_normal_slot = RescaleNormalAttrib::get_class_slot();
3304  if (_target_rs->get_attrib(rescale_normal_slot) != _state_rs->get_attrib(rescale_normal_slot) ||
3305  !_state_mask.get_bit(rescale_normal_slot)) {
3306  //PStatTimer timer(_draw_set_state_rescale_normal_pcollector);
3307  do_issue_rescale_normal();
3308  _state_mask.set_bit(rescale_normal_slot);
3309  }
3310 
3311  int shade_model_slot = ShadeModelAttrib::get_class_slot();
3312  if (_target_rs->get_attrib(shade_model_slot) != _state_rs->get_attrib(shade_model_slot) ||
3313  !_state_mask.get_bit(shade_model_slot)) {
3314  //PStatTimer timer(_draw_set_state_shade_model_pcollector);
3315  do_issue_shade_model();
3316  _state_mask.set_bit(shade_model_slot);
3317  }
3318 
3319  int transparency_slot = TransparencyAttrib::get_class_slot();
3320  int color_write_slot = ColorWriteAttrib::get_class_slot();
3321  int color_blend_slot = ColorBlendAttrib::get_class_slot();
3322  if (_target_rs->get_attrib(transparency_slot) != _state_rs->get_attrib(transparency_slot) ||
3323  _target_rs->get_attrib(color_write_slot) != _state_rs->get_attrib(color_write_slot) ||
3324  _target_rs->get_attrib(color_blend_slot) != _state_rs->get_attrib(color_blend_slot) ||
3325  !_state_mask.get_bit(transparency_slot) ||
3326  !_state_mask.get_bit(color_write_slot) ||
3327  !_state_mask.get_bit(color_blend_slot) ||
3328  (_target_shader->get_flag(ShaderAttrib::F_disable_alpha_write) !=
3329  _state_shader->get_flag(ShaderAttrib::F_disable_alpha_write))) {
3330  //PStatTimer timer(_draw_set_state_blending_pcollector);
3331  do_issue_blending();
3332  _state_mask.set_bit(transparency_slot);
3333  _state_mask.set_bit(color_write_slot);
3334  _state_mask.set_bit(color_blend_slot);
3335  }
3336 
3337  if (_target_shader != _state_shader) {
3338  //PStatTimer timer(_draw_set_state_shader_pcollector);
3339  do_issue_shader();
3340  _state_shader = _target_shader;
3341  _state_mask.clear_bit(TextureAttrib::get_class_slot());
3342  }
3343 
3344  int texture_slot = TextureAttrib::get_class_slot();
3345  int tex_matrix_slot = TexMatrixAttrib::get_class_slot();
3346  int tex_gen_slot = TexGenAttrib::get_class_slot();
3347  if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) ||
3348  _target_rs->get_attrib(tex_matrix_slot) != _state_rs->get_attrib(tex_matrix_slot) ||
3349  _target_rs->get_attrib(tex_gen_slot) != _state_rs->get_attrib(tex_gen_slot) ||
3350  !_state_mask.get_bit(texture_slot) ||
3351  !_state_mask.get_bit(tex_matrix_slot) ||
3352  !_state_mask.get_bit(tex_gen_slot)) {
3353  //PStatTimer timer(_draw_set_state_texture_pcollector);
3354  determine_target_texture();
3355  do_issue_texture();
3356 
3357  _state_texture = _target_texture;
3358  _state_mask.set_bit(texture_slot);
3359  _state_mask.set_bit(tex_matrix_slot);
3360  _state_mask.set_bit(tex_gen_slot);
3361  }
3362 
3363  int material_slot = MaterialAttrib::get_class_slot();
3364  if (_target_rs->get_attrib(material_slot) != _state_rs->get_attrib(material_slot) ||
3365  !_state_mask.get_bit(material_slot)) {
3366  //PStatTimer timer(_draw_set_state_material_pcollector);
3367  do_issue_material();
3368  _state_mask.set_bit(material_slot);
3369  if (_current_shader_context) {
3370  _current_shader_context->issue_parameters(this, Shader::SSD_material);
3371  }
3372  }
3373 
3374  int light_slot = LightAttrib::get_class_slot();
3375  if (_target_rs->get_attrib(light_slot) != _state_rs->get_attrib(light_slot) ||
3376  !_state_mask.get_bit(light_slot)) {
3377  //PStatTimer timer(_draw_set_state_light_pcollector);
3378  do_issue_light();
3379  _state_mask.set_bit(light_slot);
3380  }
3381 
3382  int stencil_slot = StencilAttrib::get_class_slot();
3383  if (_target_rs->get_attrib(stencil_slot) != _state_rs->get_attrib(stencil_slot) ||
3384  !_state_mask.get_bit(stencil_slot)) {
3385  //PStatTimer timer(_draw_set_state_stencil_pcollector);
3386  do_issue_stencil();
3387  _state_mask.set_bit(stencil_slot);
3388  }
3389 
3390  int fog_slot = FogAttrib::get_class_slot();
3391  if (_target_rs->get_attrib(fog_slot) != _state_rs->get_attrib(fog_slot) ||
3392  !_state_mask.get_bit(fog_slot)) {
3393  //PStatTimer timer(_draw_set_state_fog_pcollector);
3394  do_issue_fog();
3395  _state_mask.set_bit(fog_slot);
3396  if (_current_shader_context) {
3397  _current_shader_context->issue_parameters(this, Shader::SSD_fog);
3398  }
3399  }
3400 
3401  int scissor_slot = ScissorAttrib::get_class_slot();
3402  if (_target_rs->get_attrib(scissor_slot) != _state_rs->get_attrib(scissor_slot) ||
3403  !_state_mask.get_bit(scissor_slot)) {
3404  //PStatTimer timer(_draw_set_state_scissor_pcollector);
3405  do_issue_scissor();
3406  _state_mask.set_bit(scissor_slot);
3407  }
3408 
3409  _state_rs = _target_rs;
3410 }
3411 
3412 ////////////////////////////////////////////////////////////////////
3413 // Function: DXGraphicsStateGuardian9::bind_light
3414 // Access: Public, Virtual
3415 // Description: Called the first time a particular light has been
3416 // bound to a given id within a frame, this should set
3417 // up the associated hardware light with the light's
3418 // properties.
3419 ////////////////////////////////////////////////////////////////////
3421 bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
3422  // Get the light in "world coordinates" (actually, view
3423  // coordinates). This means the light in the coordinate space of
3424  // the camera, converted to DX's coordinate system.
3425  CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
3426  const LMatrix4 &light_mat = transform->get_mat();
3427  LMatrix4 rel_mat = light_mat * LMatrix4::convert_mat(CS_yup_left, CS_default);
3428  LPoint3f pos = LCAST(float, light_obj->get_point() * rel_mat);
3429 
3430  D3DCOLORVALUE black;
3431  black.r = black.g = black.b = black.a = 0.0f;
3432  D3DLIGHT9 alight;
3433  alight.Type = D3DLIGHT_POINT;
3434  alight.Diffuse = get_light_color(light_obj);
3435  alight.Ambient = black ;
3436  LColorf color = LCAST(float, light_obj->get_specular_color());
3437  alight.Specular = *(D3DCOLORVALUE *)(color.get_data());
3438 
3439  // Position needs to specify x, y, z, and w
3440  // w == 1 implies non-infinite position
3441  alight.Position = *(D3DVECTOR *)pos.get_data();
3442 
3443  alight.Range = __D3DLIGHT_RANGE_MAX;
3444  alight.Falloff = 1.0f;
3445 
3446  const LVecBase3 &att = light_obj->get_attenuation();
3447  alight.Attenuation0 = att[0];
3448  alight.Attenuation1 = att[1];
3449  alight.Attenuation2 = att[2];
3450 
3451  HRESULT hr = _d3d_device->SetLight(light_id, &alight);
3452  if (FAILED(hr)) {
3453  wdxdisplay9_cat.warning()
3454  << "Could not set light properties for " << light
3455  << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n";
3456  }
3457 }
3458 
3459 ////////////////////////////////////////////////////////////////////
3460 // Function: DXGraphicsStateGuardian9::bind_light
3461 // Access: Public, Virtual
3462 // Description: Called the first time a particular light has been
3463 // bound to a given id within a frame, this should set
3464 // up the associated hardware light with the light's
3465 // properties.
3466 ////////////////////////////////////////////////////////////////////
3468 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
3469  static PStatCollector _draw_set_state_light_bind_directional_pcollector("Draw:Set State:Light:Bind:Directional");
3470  //PStatTimer timer(_draw_set_state_light_bind_directional_pcollector);
3471 
3472  pair<DirectionalLights::iterator, bool> lookup = _dlights.insert(DirectionalLights::value_type(light, D3DLIGHT9()));
3473  D3DLIGHT9 &fdata = (*lookup.first).second;
3474  if (lookup.second) {
3475  // Get the light in "world coordinates" (actually, view
3476  // coordinates). This means the light in the coordinate space of
3477  // the camera, converted to DX's coordinate system.
3478  CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
3479  const LMatrix4 &light_mat = transform->get_mat();
3480  LMatrix4 rel_mat = light_mat * LMatrix4::convert_mat(CS_yup_left, CS_default);
3481  LVector3f dir = LCAST(float, light_obj->get_direction() * rel_mat);
3482 
3483  D3DCOLORVALUE black;
3484  black.r = black.g = black.b = black.a = 0.0f;
3485 
3486  ZeroMemory(&fdata, sizeof(D3DLIGHT9));
3487 
3488  fdata.Type = D3DLIGHT_DIRECTIONAL;
3489  fdata.Ambient = black ;
3490  LColorf color = LCAST(float, light_obj->get_specular_color());
3491  fdata.Specular = *(D3DCOLORVALUE *)(color.get_data());
3492 
3493  fdata.Direction = *(D3DVECTOR *)dir.get_data();
3494 
3495  fdata.Range = __D3DLIGHT_RANGE_MAX;
3496  fdata.Falloff = 1.0f;
3497 
3498  fdata.Attenuation0 = 1.0f; // constant
3499  fdata.Attenuation1 = 0.0f; // linear
3500  fdata.Attenuation2 = 0.0f; // quadratic
3501  }
3502 
3503  // We have to reset the Diffuse color at each call, because it might
3504  // have changed independently of the light object itself (due to
3505  // color_scale_via_lighting being in effect).
3506  fdata.Diffuse = get_light_color(light_obj);
3507 
3508  HRESULT hr = _d3d_device->SetLight(light_id, &fdata);
3509  if (FAILED(hr)) {
3510  wdxdisplay9_cat.warning()
3511  << "Could not set light properties for " << light
3512  << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n";
3513  }
3514 }
3515 
3516 ////////////////////////////////////////////////////////////////////
3517 // Function: DXGraphicsStateGuardian9::bind_light
3518 // Access: Public, Virtual
3519 // Description: Called the first time a particular light has been
3520 // bound to a given id within a frame, this should set
3521 // up the associated hardware light with the light's
3522 // properties.
3523 ////////////////////////////////////////////////////////////////////
3525 bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
3526  Lens *lens = light_obj->get_lens();
3527  nassertv(lens != (Lens *)NULL);
3528 
3529  // Get the light in "world coordinates" (actually, view
3530  // coordinates). This means the light in the coordinate space of
3531  // the camera, converted to DX's coordinate system.
3532  CPT(TransformState) transform = light.get_transform(_scene_setup->get_camera_path());
3533  const LMatrix4 &light_mat = transform->get_mat();
3534  LMatrix4 rel_mat = light_mat * LMatrix4::convert_mat(CS_yup_left, CS_default);
3535  LPoint3f pos = LCAST(float, lens->get_nodal_point() * rel_mat);
3536  LVector3f dir = LCAST(float, lens->get_view_vector() * rel_mat);
3537 
3538  D3DCOLORVALUE black;
3539  black.r = black.g = black.b = black.a = 0.0f;
3540 
3541  D3DLIGHT9 alight;
3542  ZeroMemory(&alight, sizeof(D3DLIGHT9));
3543 
3544  alight.Type = D3DLIGHT_SPOT;
3545  alight.Ambient = black ;
3546  alight.Diffuse = get_light_color(light_obj);
3547  LColorf color = LCAST(float, light_obj->get_specular_color());
3548  alight.Specular = *(D3DCOLORVALUE *)(color.get_data());
3549 
3550  alight.Position = *(D3DVECTOR *)pos.get_data();
3551 
3552  alight.Direction = *(D3DVECTOR *)dir.get_data();
3553 
3554  alight.Range = __D3DLIGHT_RANGE_MAX;
3555 
3556  // I determined this formular empirically. It seems to mostly
3557  // approximate the OpenGL spotlight equation, for a reasonable range
3558  // of values for FOV.
3559  PN_stdfloat fov = lens->get_hfov();
3560  alight.Falloff = light_obj->get_exponent() * (fov * fov * fov) / 1620000.0f;
3561 
3562  alight.Theta = 0.0f;
3563  alight.Phi = deg_2_rad(fov);
3564 
3565  const LVecBase3 &att = light_obj->get_attenuation();
3566  alight.Attenuation0 = att[0];
3567  alight.Attenuation1 = att[1];
3568  alight.Attenuation2 = att[2];
3569 
3570  HRESULT hr = _d3d_device->SetLight(light_id, &alight);
3571  if (FAILED(hr)) {
3572  wdxdisplay9_cat.warning()
3573  << "Could not set light properties for " << light
3574  << " to id " << light_id << ": " << D3DERRORSTRING(hr) << "\n";
3575  }
3576 }
3577 
3578 ////////////////////////////////////////////////////////////////////
3579 // Function: DXGraphicsStateGuardian9::get_index_type
3580 // Access: Protected, Static
3581 // Description: Maps from the Geom's internal numeric type symbols
3582 // to DirectX's.
3583 ////////////////////////////////////////////////////////////////////
3585 get_index_type(Geom::NumericType numeric_type) {
3586  switch (numeric_type) {
3587  // NT_uint8 is automatically promoted to uint16.
3588  case Geom::NT_uint8:
3589  case Geom::NT_uint16:
3590  return D3DFMT_INDEX16;
3591 
3592  case Geom::NT_uint32:
3593  return D3DFMT_INDEX32;
3594  }
3595 
3596  dxgsg9_cat.error()
3597  << "Invalid index NumericType value (" << (int)numeric_type << ")\n";
3598  return D3DFMT_INDEX16;
3599 }
3600 
3601 ////////////////////////////////////////////////////////////////////
3602 // Function: DXGraphicsStateGuardian9::do_issue_material
3603 // Access: Public, Virtual
3604 // Description:
3605 ////////////////////////////////////////////////////////////////////
3606 void DXGraphicsStateGuardian9::
3607 do_issue_material() {
3608  static Material empty;
3609  const Material *material;
3610  const MaterialAttrib *target_material = DCAST(MaterialAttrib, _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()));
3611  if (target_material->is_off()) {
3612  material = &empty;
3613  } else {
3614  material = target_material->get_material();
3615  }
3616 
3617  D3DMATERIAL9 cur_material;
3618  LColorf color = LCAST(float, material->get_diffuse());
3619  cur_material.Diffuse = *(D3DCOLORVALUE *)(color.get_data());
3620  color = LCAST(float, material->get_ambient());
3621  cur_material.Ambient = *(D3DCOLORVALUE *)(color.get_data());
3622  color = LCAST(float, material->get_specular());
3623  cur_material.Specular = *(D3DCOLORVALUE *)(color.get_data());
3624  color = LCAST(float, material->get_emission());
3625  cur_material.Emissive = *(D3DCOLORVALUE *)(color.get_data());
3626  cur_material.Power = material->get_shininess();
3627 
3628  if (material->has_diffuse()) {
3629  // If the material specifies an diffuse color, use it.
3630  set_render_state(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
3631  } else {
3632  // Otherwise, the diffuse color comes from the object color.
3633  if (_has_material_force_color) {
3634  color = LCAST(float, _material_force_color);
3635  cur_material.Diffuse = *(D3DCOLORVALUE *)color.get_data();
3636  set_render_state(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
3637  } else {
3638  set_render_state(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
3639  }
3640  }
3641  if (material->has_ambient()) {
3642  // If the material specifies an ambient color, use it.
3643  set_render_state(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
3644  } else {
3645  // Otherwise, the ambient color comes from the object color.
3646  if (_has_material_force_color) {
3647  color = LCAST(float, _material_force_color);
3648  cur_material.Ambient = *(D3DCOLORVALUE *)color.get_data();
3649  set_render_state(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
3650  } else {
3651  set_render_state(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1);
3652  }
3653  }
3654 
3655  if (material->has_specular()) {
3656  set_render_state(D3DRS_SPECULARENABLE, TRUE);
3657  } else {
3658  set_render_state(D3DRS_SPECULARENABLE, FALSE);
3659  }
3660 
3661  if (material->get_local()) {
3662  set_render_state(D3DRS_LOCALVIEWER, TRUE);
3663  } else {
3664  set_render_state(D3DRS_LOCALVIEWER, FALSE);
3665  }
3666 
3667  _d3d_device->SetMaterial(&cur_material);
3668 }
3669 
3670 ////////////////////////////////////////////////////////////////////
3671 // Function: DXGraphicsStateGuardian9::do_issue_texture
3672 // Access: Protected
3673 // Description:
3674 ////////////////////////////////////////////////////////////////////
3675 void DXGraphicsStateGuardian9::
3676 do_issue_texture() {
3677  DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
3678 
3679  if (_texture_binding_shader_context==0) {
3680  if (_current_shader_context==0) {
3681  update_standard_texture_bindings();
3682  } else {
3683  disable_standard_texture_bindings();
3684  _current_shader_context->update_shader_texture_bindings(NULL,this);
3685  }
3686  } else {
3687  if (_current_shader_context==0) {
3688  _texture_binding_shader_context->disable_shader_texture_bindings(this);
3689  update_standard_texture_bindings();
3690  } else {
3691  _current_shader_context->
3692  update_shader_texture_bindings(_texture_binding_shader_context,this);
3693  }
3694  }
3695  _texture_binding_shader = _current_shader;
3696  _texture_binding_shader_context = _current_shader_context;
3697 }
3698 
3699 ////////////////////////////////////////////////////////////////////
3700 // Function: DXGraphicsStateGuardian9::disable_standard_texture_bindings
3701 // Access: Private
3702 // Description:
3703 ////////////////////////////////////////////////////////////////////
3704 void DXGraphicsStateGuardian9::
3705 disable_standard_texture_bindings() {
3706  // Disable the texture stages that are no longer used.
3707  for (int i = 0; i < _num_active_texture_stages; i++) {
3708  HRESULT hr;
3709 
3710  hr = _d3d_device -> SetTexture (i, NULL);
3711  if (FAILED (hr)) {
3712  dxgsg9_cat.error()
3713  << "SetTexture ("
3714  << i
3715  << ", NULL) failed "
3716  << D3DERRORSTRING(hr);
3717  }
3718  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
3719  }
3720 
3721  _num_active_texture_stages = 0;
3722 }
3723 
3724 ////////////////////////////////////////////////////////////////////
3725 // Function: DXGraphicsStateGuardian9::update_standard_texture_bindings
3726 // Access: Protected
3727 // Description:
3728 ////////////////////////////////////////////////////////////////////
3729 void DXGraphicsStateGuardian9::
3730 update_standard_texture_bindings() {
3731  DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
3732 
3733  int num_stages = _target_texture->get_num_on_ff_stages();
3734  int num_old_stages = _max_texture_stages;
3735  if (_state_texture != (TextureAttrib *)NULL) {
3736  num_old_stages = _state_texture->get_num_on_ff_stages();
3737  }
3738 
3739  nassertv(num_stages <= _max_texture_stages &&
3740  _num_active_texture_stages <= _max_texture_stages);
3741 
3742  _texture_involves_color_scale = false;
3743 
3744  // We have to match up the texcoord stage index to the order written
3745  // out by the DXGeomMunger. This means the texcoord names are
3746  // written in the order indicated by the TextureAttrib.
3747 
3748  int si;
3749  for (si = 0; si < num_stages; si++) {
3750  TextureStage *stage = _target_texture->get_on_ff_stage(si);
3751  int texcoord_index = _target_texture->get_ff_tc_index(si);
3752 
3753  Texture *texture = _target_texture->get_on_texture(stage);
3754  nassertv(texture != (Texture *)NULL);
3755  const SamplerState &sampler = _target_texture->get_on_sampler(stage);
3756 
3757  // We always reissue every stage in DX, just in case the texcoord
3758  // index or texgen mode or some other property has changed.
3759  int view = get_current_tex_view_offset() + stage->get_tex_view_offset();
3760  TextureContext *tc = texture->prepare_now(view, _prepared_objects, this);
3761  apply_texture(si, tc, sampler);
3762  set_texture_blend_mode(si, stage);
3763 
3764  int texcoord_dimensions = 2;
3765 
3766  CPT(TransformState) tex_mat = TransformState::make_identity();
3767  const TexMatrixAttrib *target_tex_matrix = DCAST(TexMatrixAttrib, _target_rs->get_attrib_def(TexMatrixAttrib::get_class_slot()));
3768  if (target_tex_matrix->has_stage(stage)) {
3769  tex_mat = target_tex_matrix->get_transform(stage);
3770  }
3771 
3772  // Issue the texgen mode.
3773  TexGenAttrib::Mode mode = _target_tex_gen->get_mode(stage);
3774  bool any_point_sprite = false;
3775 
3776  switch (mode) {
3777  case TexGenAttrib::M_off:
3778  case TexGenAttrib::M_unused2:
3779  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX, texcoord_index);
3780  break;
3781 
3782  case TexGenAttrib::M_eye_sphere_map:
3783  {
3784  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3785  texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
3786  // This texture matrix, applied on top of the texcoord
3787  // computed by D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR,
3788  // approximates the effect produced by OpenGL's GL_SPHERE_MAP.
3789  static CPT(TransformState) sphere_map =
3790  TransformState::make_mat(LMatrix4(0.33, 0.0f, 0.0f, 0.0f,
3791  0.0f, 0.33, 0.0f, 0.0f,
3792  0.0f, 0.0f, 1.0f, 0.0f,
3793  0.5f, 0.5f, 0.0f, 1.0f));
3794  tex_mat = tex_mat->compose(sphere_map);
3795  texcoord_dimensions = 3;
3796  }
3797  break;
3798 
3799  case TexGenAttrib::M_world_cube_map:
3800  // To achieve world reflection vector, we must transform camera
3801  // coordinates to world coordinates; i.e. apply the camera
3802  // transform. In the case of a vector, we should not apply the
3803  // pos component of the transform.
3804  {
3805  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3806  texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
3807  texcoord_dimensions = 3;
3808  CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
3809  tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3::zero()));
3810  }
3811  break;
3812 
3813  case TexGenAttrib::M_eye_cube_map:
3814  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3815  texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
3816  tex_mat = tex_mat->compose(_inv_cs_transform);
3817  texcoord_dimensions = 3;
3818  break;
3819 
3820  case TexGenAttrib::M_world_normal:
3821  // To achieve world normal, we must transform camera coordinates
3822  // to world coordinates; i.e. apply the camera transform. In
3823  // the case of a normal, we should not apply the pos component
3824  // of the transform.
3825  {
3826  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3827  texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
3828  texcoord_dimensions = 3;
3829  CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
3830  tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3::zero()));
3831  }
3832  break;
3833 
3834  case TexGenAttrib::M_eye_normal:
3835  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3836  texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
3837  texcoord_dimensions = 3;
3838  tex_mat = tex_mat->compose(_inv_cs_transform);
3839  break;
3840 
3841  case TexGenAttrib::M_world_position:
3842  // To achieve world position, we must transform camera
3843  // coordinates to world coordinates; i.e. apply the
3844  // camera transform.
3845  {
3846  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3847  texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
3848  texcoord_dimensions = 3;
3849  CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
3850  tex_mat = tex_mat->compose(camera_transform);
3851  }
3852  break;
3853 
3854  case TexGenAttrib::M_eye_position:
3855  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3856  texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
3857  texcoord_dimensions = 3;
3858  tex_mat = tex_mat->compose(_inv_cs_transform);
3859  break;
3860 
3861  case TexGenAttrib::M_point_sprite:
3862  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX, texcoord_index);
3863  any_point_sprite = true;
3864  break;
3865 
3866  case TexGenAttrib::M_constant:
3867  // To generate a constant UV(w) coordinate everywhere, we use
3868  // CAMERASPACEPOSITION coordinates, but we construct a special
3869  // matrix that flattens the existing values to zero and then
3870  // adds our desired value.
3871 
3872  // The only reason we need to specify CAMERASPACEPOSITION at
3873  // all, instead of using whatever texture coordinates (if any)
3874  // happen to be on the vertices, is because we need to guarantee
3875  // that there are 3-d texture coordinates, because of the
3876  // 3-component texture coordinate in get_constant_value().
3877  {
3878  set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
3879  texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
3880  texcoord_dimensions = 3;
3881 
3882  const LTexCoord3 &v = _target_tex_gen->get_constant_value(stage);
3883  CPT(TransformState) squash =
3884  TransformState::make_pos_hpr_scale(v, LVecBase3::zero(),
3885  LVecBase3::zero());
3886  tex_mat = tex_mat->compose(squash);
3887  }
3888  break;
3889  }
3890 
3891  set_render_state(D3DRS_POINTSPRITEENABLE, any_point_sprite);
3892 
3893  if (!tex_mat->is_identity()) {
3894  if (/*tex_mat->is_2d() &&*/ texcoord_dimensions <= 2) {
3895  // For 2-d texture coordinates, we have to reorder the matrix.
3896  LMatrix4 m = tex_mat->get_mat();
3897  LMatrix4f mf;
3898  mf.set(m(0, 0), m(0, 1), m(0, 3), 0.0f,
3899  m(1, 0), m(1, 1), m(1, 3), 0.0f,
3900  m(3, 0), m(3, 1), m(3, 3), 0.0f,
3901  0.0f, 0.0f, 0.0f, 1.0f);
3902  _d3d_device->SetTransform(get_tex_mat_sym(si), (D3DMATRIX *)mf.get_data());
3903  set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
3904  D3DTTFF_COUNT2);
3905  } else {
3906  LMatrix4f mf = LCAST(float, tex_mat->get_mat());
3907  _d3d_device->SetTransform(get_tex_mat_sym(si), (D3DMATRIX *)mf.get_data());
3908  DWORD transform_flags = texcoord_dimensions;
3909  if (mf.get_col(3) != LVecBase4f(0.0f, 0.0f, 0.0f, 1.0f)) {
3910  // If we have a projected texture matrix, we also need to
3911  // set D3DTTFF_COUNT4.
3912  transform_flags = D3DTTFF_COUNT4 | D3DTTFF_PROJECTED;
3913  }
3914  set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
3915  transform_flags);
3916  }
3917 
3918  } else {
3919  set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
3920  D3DTTFF_DISABLE);
3921  // For some reason, "disabling" texture coordinate transforms
3922  // doesn't seem to be sufficient. We'll load an identity matrix
3923  // to underscore the point.
3924  _d3d_device->SetTransform(get_tex_mat_sym(si), &_d3d_ident_mat);
3925  }
3926  }
3927 
3928  // Disable the texture stages that are no longer used.
3929  for (si = num_stages; si < _num_active_texture_stages; si++) {
3930  set_texture_stage_state(si, D3DTSS_COLOROP, D3DTOP_DISABLE);
3931  _d3d_device->SetTexture(si, NULL);
3932  }
3933 
3934  // Save the count of texture stages for next time.
3935  _num_active_texture_stages = num_stages;
3936 }
3937 
3938 ////////////////////////////////////////////////////////////////////
3939 // Function: DXGraphicsStateGuardian9::do_issue_blending
3940 // Access: Protected, Virtual
3941 // Description: Called after any of the things that might change
3942 // blending state have changed, this function is
3943 // responsible for setting the appropriate color
3944 // blending mode based on the current properties.
3945 ////////////////////////////////////////////////////////////////////
3946 void DXGraphicsStateGuardian9::
3947 do_issue_blending() {
3948  // Handle the color_write attrib. If color_write is off, then
3949  // all the other blending-related stuff doesn't matter. If the
3950  // device doesn't support color-write, we use blending tricks
3951  // to effectively disable color write.
3952  const ColorWriteAttrib *target_color_write = DCAST(ColorWriteAttrib, _target_rs->get_attrib_def(ColorWriteAttrib::get_class_slot()));
3953  unsigned int color_channels =
3954  target_color_write->get_channels() & _color_write_mask;
3955  if (_target_shader->get_flag(ShaderAttrib::F_disable_alpha_write)) {
3956  color_channels &= ~(ColorWriteAttrib::C_alpha);
3957  }
3958  if (color_channels == ColorWriteAttrib::C_off) {
3959  if (_screen->_can_direct_disable_color_writes) {
3960  set_render_state(D3DRS_ALPHABLENDENABLE, FALSE);
3961  set_render_state(D3DRS_COLORWRITEENABLE, (DWORD)0x0);
3962  } else {
3963  set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
3964  set_render_state(D3DRS_SRCBLEND, D3DBLEND_ZERO);
3965  set_render_state(D3DRS_DESTBLEND, D3DBLEND_ONE);
3966  }
3967  return;
3968  } else {
3969  if (_screen->_can_direct_disable_color_writes) {
3970  set_render_state(D3DRS_COLORWRITEENABLE, color_channels);
3971  }
3972  }
3973 
3974  const ColorBlendAttrib *target_color_blend = DCAST(ColorBlendAttrib, _target_rs->get_attrib_def(ColorBlendAttrib::get_class_slot()));
3975  CPT(ColorBlendAttrib) color_blend = target_color_blend;
3976  ColorBlendAttrib::Mode color_blend_mode = target_color_blend->get_mode();
3977 
3978  const TransparencyAttrib *target_transparency = DCAST(TransparencyAttrib, _target_rs->get_attrib_def(TransparencyAttrib::get_class_slot()));
3979  TransparencyAttrib::Mode transparency_mode = target_transparency->get_mode();
3980 
3981  // Is there a color blend set?
3982  if (color_blend_mode != ColorBlendAttrib::M_none) {
3983  set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
3984 
3985  switch (color_blend_mode) {
3986  case ColorBlendAttrib::M_add:
3987  set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
3988  break;
3989 
3990  case ColorBlendAttrib::M_subtract:
3991  set_render_state(D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3992  break;
3993 
3994  case ColorBlendAttrib::M_inv_subtract:
3995  set_render_state(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT);
3996  break;
3997 
3998  case ColorBlendAttrib::M_min:
3999  set_render_state(D3DRS_BLENDOP, D3DBLENDOP_MIN);
4000  break;
4001 
4002  case ColorBlendAttrib::M_max:
4003  set_render_state(D3DRS_BLENDOP, D3DBLENDOP_MAX);
4004  break;
4005  }
4006 
4007  set_render_state(D3DRS_SRCBLEND,
4008  get_blend_func(color_blend->get_operand_a()));
4009  set_render_state(D3DRS_DESTBLEND,
4010  get_blend_func(color_blend->get_operand_b()));
4011  return;
4012  }
4013 
4014  // No color blend; is there a transparency set?
4015  switch (transparency_mode) {
4016  case TransparencyAttrib::M_none:
4017  case TransparencyAttrib::M_binary:
4018  break;
4019 
4020  case TransparencyAttrib::M_alpha:
4021  case TransparencyAttrib::M_multisample:
4022  case TransparencyAttrib::M_multisample_mask:
4023  case TransparencyAttrib::M_dual:
4024  set_render_state(D3DRS_ALPHABLENDENABLE, TRUE);
4025  set_render_state(D3DRS_BLENDOP, D3DBLENDOP_ADD);
4026  set_render_state(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
4027  set_render_state(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
4028  return;
4029 
4030  default:
4031  dxgsg9_cat.error()
4032  << "invalid transparency mode " << (int)transparency_mode << endl;
4033  break;
4034  }
4035 
4036  // Nothing's set, so disable blending.
4037  set_render_state(D3DRS_ALPHABLENDENABLE, FALSE);
4038 }
4039 
4040 ////////////////////////////////////////////////////////////////////
4041 // Function: DXGraphicsStateGuardian9::reissue_transforms
4042 // Access: Protected, Virtual
4043 // Description: Called by clear_state_and_transform() to ensure that
4044 // the current modelview and projection matrices are
4045 // properly loaded in the graphics state, after a
4046 // callback might have mucked them up.
4047 ////////////////////////////////////////////////////////////////////
4048 void DXGraphicsStateGuardian9::
4049 reissue_transforms() {
4050  prepare_lens();
4051  do_issue_transform();
4052 }
4053 
4054 ////////////////////////////////////////////////////////////////////
4055 // Function: DXGraphicsStateGuardian9::enable_lighting
4056 // Access: Protected, Virtual
4057 // Description: Intended to be overridden by a derived class to
4058 // enable or disable the use of lighting overall. This
4059 // is called by issue_light() according to whether any
4060 // lights are in use or not.
4061 ////////////////////////////////////////////////////////////////////
4062 void DXGraphicsStateGuardian9::
4063 enable_lighting(bool enable) {
4064  set_render_state(D3DRS_LIGHTING, (DWORD)enable);
4065 }
4066 
4067 ////////////////////////////////////////////////////////////////////
4068 // Function: DXGraphicsStateGuardian9::set_ambient_light
4069 // Access: Protected, Virtual
4070 // Description: Intended to be overridden by a derived class to
4071 // indicate the color of the ambient light that should
4072 // be in effect. This is called by issue_light() after
4073 // all other lights have been enabled or disabled.
4074 ////////////////////////////////////////////////////////////////////
4075 void DXGraphicsStateGuardian9::
4076 set_ambient_light(const LColor &color) {
4077  LColor c = color;
4078  c.set(c[0] * _light_color_scale[0],
4079  c[1] * _light_color_scale[1],
4080  c[2] * _light_color_scale[2],
4081  c[3] * _light_color_scale[3]);
4082 
4083  set_render_state(D3DRS_AMBIENT, LColor_to_D3DCOLOR(c));
4084 }
4085 
4086 ////////////////////////////////////////////////////////////////////
4087 // Function: DXGraphicsStateGuardian9::enable_light
4088 // Access: Protected, Virtual
4089 // Description: Intended to be overridden by a derived class to
4090 // enable the indicated light id. A specific Light will
4091 // already have been bound to this id via bind_light().
4092 ////////////////////////////////////////////////////////////////////
4093 void DXGraphicsStateGuardian9::
4094 enable_light(int light_id, bool enable) {
4095  HRESULT hr = _d3d_device->LightEnable(light_id, enable);
4096 
4097  if (FAILED(hr)) {
4098  wdxdisplay9_cat.warning()
4099  << "Could not enable light " << light_id << ": "
4100  << D3DERRORSTRING(hr) << "\n";
4101  }
4102 }
4103 
4104 ////////////////////////////////////////////////////////////////////
4105 // Function: DXGraphicsStateGuardian9::enable_clip_plane
4106 // Access: Protected, Virtual
4107 // Description: Intended to be overridden by a derived class to
4108 // enable the indicated clip_plane id. A specific
4109 // PlaneNode will already have been bound to this id via
4110 // bind_clip_plane().
4111 ////////////////////////////////////////////////////////////////////
4112 void DXGraphicsStateGuardian9::
4113 enable_clip_plane(int plane_id, bool enable) {
4114  if (enable) {
4115  _clip_plane_bits |= ((DWORD)1 << plane_id);
4116  } else {
4117  _clip_plane_bits &= ~((DWORD)1 << plane_id);
4118  }
4119  set_render_state(D3DRS_CLIPPLANEENABLE, _clip_plane_bits);
4120 }
4121 
4122 ////////////////////////////////////////////////////////////////////
4123 // Function: DXGraphicsStateGuardian9::bind_clip_plane
4124 // Access: Protected, Virtual
4125 // Description: Called the first time a particular clip_plane has been
4126 // bound to a given id within a frame, this should set
4127 // up the associated hardware clip_plane with the clip_plane's
4128 // properties.
4129 ////////////////////////////////////////////////////////////////////
4130 void DXGraphicsStateGuardian9::
4131 bind_clip_plane(const NodePath &plane, int plane_id) {
4132  // Get the plane in "world coordinates" (actually, view
4133  // coordinates). This means the plane in the coordinate space of
4134  // the camera, converted to DX's coordinate system.
4135  CPT(TransformState) transform = plane.get_transform(_scene_setup->get_camera_path());
4136  const LMatrix4 &plane_mat = transform->get_mat();
4137  LMatrix4 rel_mat = plane_mat * LMatrix4::convert_mat(CS_yup_left, CS_default);
4138  const PlaneNode *plane_node;
4139  DCAST_INTO_V(plane_node, plane.node());
4140  LPlanef world_plane = LCAST(float, plane_node->get_plane() * rel_mat);
4141 
4142  HRESULT hr = _d3d_device->SetClipPlane(plane_id, world_plane.get_data());
4143  if (FAILED(hr)) {
4144  wdxdisplay9_cat.warning()
4145  << "Could not set clip plane for " << plane
4146  << " to id " << plane_id << ": " << D3DERRORSTRING(hr) << "\n";
4147  }
4148 }
4149 
4150 ////////////////////////////////////////////////////////////////////
4151 // Function: DXGraphicsStateGuardian9::close_gsg
4152 // Access: Protected, Virtual
4153 // Description: This is called by the associated GraphicsWindow when
4154 // close_window() is called. It should null out the
4155 // _win pointer and possibly free any open resources
4156 // associated with the GSG.
4157 ////////////////////////////////////////////////////////////////////
4158 void DXGraphicsStateGuardian9::
4159 close_gsg() {
4160  GraphicsStateGuardian::close_gsg();
4161 
4162  if (dxgsg9_cat.is_debug()) {
4163  dxgsg9_cat.debug()
4164  << "Closing GSG, prepared_objects count = "
4165  << _prepared_objects->get_ref_count() << "\n";
4166  }
4167 
4168  // Unlike in OpenGL, in DX9 it is safe to try to explicitly release
4169  // any textures here. And it may even be a good idea.
4170  if (_prepared_objects->get_ref_count() == 1) {
4171  release_all();
4172 
4173  // Now we need to actually delete all of the objects we just
4174  // released.
4175  Thread *current_thread = Thread::get_current_thread();
4176  _prepared_objects->begin_frame(this, current_thread);
4177  _prepared_objects->end_frame(current_thread);
4178  }
4179 }
4180 
4181 ////////////////////////////////////////////////////////////////////
4182 // Function: DXGraphicsStateGuardian9::free_nondx_resources
4183 // Access: Public
4184 // Description: Frees some memory that was explicitly allocated
4185 // within the dxgsg.
4186 ////////////////////////////////////////////////////////////////////
4187 void DXGraphicsStateGuardian9::
4188 free_nondx_resources() {
4189 #ifdef HAVE_CG
4190  if (_cg_context) {
4191  cgDestroyContext(_cg_context);
4192  _cg_context = 0;
4193  }
4194 #endif
4195 }
4196 
4197 ////////////////////////////////////////////////////////////////////
4198 // Function: DXGraphicsStateGuardian9::free_d3d_device
4199 // Access: Public
4200 // Description: setup for re-calling dx_init(), this is not the final
4201 // exit cleanup routine (see dx_cleanup)
4202 ////////////////////////////////////////////////////////////////////
4203 void DXGraphicsStateGuardian9::
4204 free_d3d_device() {
4205  // dont want a full reset of gsg, just a state clear
4206  _state_rs = RenderState::make_empty();
4207  _state_mask.clear();
4208 
4209  // want gsg to pass all state settings through
4210 
4211  _dx_is_ready = false;
4212 
4213  if (_d3d_device != NULL) {
4214  for(int i = 0; i < D3D_MAXTEXTURESTAGES; i++) {
4215  // d3d should release this stuff internally anyway, but whatever
4216  _d3d_device->SetTexture(i, NULL);
4217  }
4218  }
4219 
4220  release_all();
4221 
4222  if (_d3d_device != NULL) {
4223  RELEASE(_d3d_device, dxgsg9, "d3dDevice", RELEASE_DOWN_TO_ZERO);
4224  }
4225 
4226  free_nondx_resources();
4227 
4228  // obviously we dont release ID3D9, just ID3DDevice9
4229 }
4230 
4231 ////////////////////////////////////////////////////////////////////
4232 // Function: DXGraphicsStateGuardian9::set_draw_buffer
4233 // Access: Protected
4234 // Description: Sets up the glDrawBuffer to render into the buffer
4235 // indicated by the RenderBuffer object. This only sets
4236 // up the color bits; it does not affect the depth,
4237 // stencil, accum layers.
4238 ////////////////////////////////////////////////////////////////////
4239 void DXGraphicsStateGuardian9::
4240 set_draw_buffer(const RenderBuffer &rb) {
4241  dxgsg9_cat.fatal() << "DX set_draw_buffer unimplemented!!!";
4242  return;
4243 }
4244 
4245 ////////////////////////////////////////////////////////////////////
4246 // Function: DXGraphicsStateGuardian9::set_read_buffer
4247 // Access: Protected
4248 // Description: Vestigial analog of glReadBuffer
4249 ////////////////////////////////////////////////////////////////////
4250 void DXGraphicsStateGuardian9::
4251 set_read_buffer(const RenderBuffer &rb) {
4252  if (rb._buffer_type & RenderBuffer::T_front) {
4253  _cur_read_pixel_buffer = RenderBuffer::T_front;
4254  } else if (rb._buffer_type & RenderBuffer::T_back) {
4255  _cur_read_pixel_buffer = RenderBuffer::T_back;
4256  } else if (rb._buffer_type & RenderBuffer::T_aux_rgba_ALL) {
4257  _cur_read_pixel_buffer = RenderBuffer::T_back;
4258  } else {
4259  dxgsg9_cat.error() << "Invalid or unimplemented Argument to set_read_buffer!\n";
4260  }
4261  return;
4262 }
4263 
4264 ////////////////////////////////////////////////////////////////////
4265 // Function: DXGraphicsStateGuardian9::do_auto_rescale_normal
4266 // Access: Protected
4267 // Description: Issues the appropriate DX commands to either rescale
4268 // or normalize the normals according to the current
4269 // transform.
4270 ////////////////////////////////////////////////////////////////////
4271 void DXGraphicsStateGuardian9::
4272 do_auto_rescale_normal() {
4273  if (_internal_transform->has_identity_scale()) {
4274  // If there's no scale, don't normalize anything.
4275  set_render_state(D3DRS_NORMALIZENORMALS, false);
4276  } else {
4277  // If there is a scale, turn on normalization.
4278  set_render_state(D3DRS_NORMALIZENORMALS, true);
4279  }
4280 }
4281 
4282 ////////////////////////////////////////////////////////////////////
4283 // Function: DXGraphicsStateGuardian9::get_light_color
4284 // Access: Public
4285 // Description: Returns the array of four floats that should be
4286 // issued as the light's color, as scaled by the current
4287 // value of _light_color_scale, in the case of
4288 // color_scale_via_lighting.
4289 ////////////////////////////////////////////////////////////////////
4290 const D3DCOLORVALUE &DXGraphicsStateGuardian9::
4291 get_light_color(Light *light) const {
4292  LColor c = light->get_color();
4293  static LColorf cf;
4294  cf.set(c[0] * _light_color_scale[0],
4295  c[1] * _light_color_scale[1],
4296  c[2] * _light_color_scale[2],
4297  c[3] * _light_color_scale[3]);
4298  return *(D3DCOLORVALUE *)cf.get_data();
4299 }
4300 
4301 ////////////////////////////////////////////////////////////////////
4302 // Function: DXGraphicsStateGuardian9::get_blend_func
4303 // Access: Protected, Static
4304 // Description: Maps from ColorBlendAttrib::Operand to D3DBLEND
4305 // value.
4306 ////////////////////////////////////////////////////////////////////
4307 D3DBLEND DXGraphicsStateGuardian9::
4308 get_blend_func(ColorBlendAttrib::Operand operand) {
4309  switch (operand) {
4310  case ColorBlendAttrib::O_zero:
4311  return D3DBLEND_ZERO;
4312 
4313  case ColorBlendAttrib::O_one:
4314  return D3DBLEND_ONE;
4315 
4316  case ColorBlendAttrib::O_incoming_color:
4317  return D3DBLEND_SRCCOLOR;
4318 
4319  case ColorBlendAttrib::O_one_minus_incoming_color:
4320  return D3DBLEND_INVSRCCOLOR;
4321 
4322  case ColorBlendAttrib::O_fbuffer_color:
4323  return D3DBLEND_DESTCOLOR;
4324 
4325  case ColorBlendAttrib::O_one_minus_fbuffer_color:
4326  return D3DBLEND_INVDESTCOLOR;
4327 
4328  case ColorBlendAttrib::O_incoming_alpha:
4329  return D3DBLEND_SRCALPHA;
4330 
4331  case ColorBlendAttrib::O_one_minus_incoming_alpha:
4332  return D3DBLEND_INVSRCALPHA;
4333 
4334  case ColorBlendAttrib::O_fbuffer_alpha:
4335  return D3DBLEND_DESTALPHA;
4336 
4337  case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
4338  return D3DBLEND_INVDESTALPHA;
4339 
4340  case ColorBlendAttrib::O_constant_color:
4341  // Not supported by DX.
4342  return D3DBLEND_SRCCOLOR;
4343 
4344  case ColorBlendAttrib::O_one_minus_constant_color:
4345  // Not supported by DX.
4346  return D3DBLEND_INVSRCCOLOR;
4347 
4348  case ColorBlendAttrib::O_constant_alpha:
4349  // Not supported by DX.
4350  return D3DBLEND_SRCALPHA;
4351 
4352  case ColorBlendAttrib::O_one_minus_constant_alpha:
4353  // Not supported by DX.
4354  return D3DBLEND_INVSRCALPHA;
4355 
4356  case ColorBlendAttrib::O_incoming_color_saturate:
4357  return D3DBLEND_SRCALPHASAT;
4358  }
4359 
4360  dxgsg9_cat.error()
4361  << "Unknown color blend operand " << (int)operand << endl;
4362  return D3DBLEND_ZERO;
4363 }
4364 
4365 ////////////////////////////////////////////////////////////////////
4366 // Function: DXGraphicsStateGuardian9::report_texmgr_stats
4367 // Access: Protected
4368 // Description: Reports the DX texture manager's activity to PStats.
4369 ////////////////////////////////////////////////////////////////////
4370 void DXGraphicsStateGuardian9::
4371 report_texmgr_stats() {
4372 
4373 #ifdef DO_PSTATS
4374  HRESULT hr;
4375  hr = 0;
4376 
4377 #ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM
4378  DWORD dwTexTotal, dwTexFree, dwVidTotal, dwVidFree;
4379 
4380  if (_total_texmem_pcollector.is_active()) {
4381  DDSCAPS2 ddsCaps;
4382 
4383  ZeroMemory(&ddsCaps, sizeof(ddsCaps));
4384 
4385  ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
4386  if (FAILED( hr = _d3d_device->GetAvailableVidMem(&ddsCaps, &dwVidTotal, &dwVidFree))) {
4387  dxgsg9_cat.fatal() << "report_texmgr GetAvailableVidMem for VIDMEM failed : result = " << D3DERRORSTRING(hr);
4388  throw_event("panda3d-render-error");
4389  return;
4390  }
4391 
4392  ddsCaps.dwCaps = DDSCAPS_TEXTURE;
4393  if (FAILED( hr = _d3d_device->GetAvailableVidMem(&ddsCaps, &dwTexTotal, &dwTexFree))) {
4394  dxgsg9_cat.fatal() << "report_texmgr GetAvailableVidMem for TEXTURE failed : result = " << D3DERRORSTRING(hr);
4395  throw_event("panda3d-render-error");
4396  return;
4397  }
4398  }
4399 #endif // TEXMGRSTATS_USES_GETAVAILVIDMEM
4400 
4401  D3DDEVINFO_RESOURCEMANAGER all_resource_stats;
4402  ZeroMemory(&all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER));
4403 
4404 /* ***** DX9, GetInfo ( ) NOT IN DX9 */
4405 /*
4406  if (!_tex_stats_retrieval_impossible) {
4407  hr = _d3d_device->GetInfo(D3DDEVINFOID_RESOURCEMANAGER, &all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER));
4408  if (hr != D3D_OK) {
4409  if (hr == S_FALSE) {
4410  static int PrintedMsg = 2;
4411  if (PrintedMsg>0) {
4412  if (dxgsg9_cat.is_debug()) {
4413  dxgsg9_cat.debug()
4414  << "texstats GetInfo() requires debug DX DLLs to be installed!!\n";
4415  }
4416  ZeroMemory(&all_resource_stats, sizeof(D3DDEVINFO_RESOURCEMANAGER));
4417  _tex_stats_retrieval_impossible = true;
4418  }
4419  } else {
4420  dxgsg9_cat.error() << "GetInfo(RESOURCEMANAGER) failed to get tex stats: result = " << D3DERRORSTRING(hr);
4421  return;
4422  }
4423  }
4424  }
4425 */
4426 
4427  // Tell PStats about the state of the texture memory.
4428 
4429  if (_texmgrmem_total_pcollector.is_active()) {
4430  // report zero if no debug dlls, to signal this info is invalid
4431  _texmgrmem_total_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].TotalBytes);
4432  _texmgrmem_resident_pcollector.set_level(all_resource_stats.stats[D3DRTYPE_TEXTURE].WorkingSetBytes);
4433  }
4434 #ifdef TEXMGRSTATS_USES_GETAVAILVIDMEM
4435  if (_total_texmem_pcollector.is_active()) {
4436  _total_texmem_pcollector.set_level(dwTexTotal);
4437  _used_texmem_pcollector.set_level(dwTexTotal - dwTexFree);
4438  }
4439 #endif // TEXMGRSTATS_USES_GETAVAILVIDMEM
4440 #endif // DO_PSTATS
4441 }
4442 
4443 ////////////////////////////////////////////////////////////////////
4444 // Function: DXGraphicsStateGuardian9::set_context
4445 // Access: Protected
4446 // Description:
4447 ////////////////////////////////////////////////////////////////////
4448 void DXGraphicsStateGuardian9::
4449 set_context(DXScreenData *new_context) {
4450  nassertv(new_context != NULL);
4451  _screen = new_context;
4452  _d3d_device = _screen->_d3d_device; //copy this one field for speed of deref
4453  _swap_chain = _screen->_swap_chain; //copy this one field for speed of deref
4454 
4455  _screen->_dxgsg9 = this;
4456  set_cg_device(_d3d_device);
4457 }
4458 
4459 ////////////////////////////////////////////////////////////////////
4460 // Function: DXGraphicsStateGuardian9::set_render_target
4461 // Access: Protected
4462 // Description: Set render target to the backbuffer of current swap
4463 // chain.
4464 ////////////////////////////////////////////////////////////////////
4465 void DXGraphicsStateGuardian9::
4466 set_render_target() {
4467  if (_d3d_device == NULL) {
4468  return;
4469  }
4470 
4471  LPDIRECT3DSURFACE9 back = NULL, stencil = NULL;
4472 
4473  UINT swap_chain;
4474 
4475  /* ***** DX9 swap_chain ??? */
4476  swap_chain = 0;
4477 
4478  if (!_swap_chain) //maybe fullscreen mode or main/single window
4479  _d3d_device->GetBackBuffer(swap_chain, 0, D3DBACKBUFFER_TYPE_MONO, &back);
4480  else
4481  _swap_chain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &back);
4482 
4483  //wdxdisplay9_cat.debug() << "swapchain is " << _swap_chain << "\n";
4484  //wdxdisplay9_cat.debug() << "back buffer is " << back << "\n";
4485 
4486  _d3d_device->GetDepthStencilSurface(&stencil);
4487 
4488 // _d3d_device->SetRenderTarget(back, stencil);
4489  DWORD render_target_index;
4490  render_target_index = 0;
4491  _d3d_device->SetRenderTarget(render_target_index, back);
4492 
4493  if (back) {
4494  back->Release();
4495  }
4496  if (stencil) {
4497  stencil->Release();
4498  }
4499 }
4500 
4501 ////////////////////////////////////////////////////////////////////
4502 // Function: DXGraphicsStateGuardian9::set_texture_blend_mode
4503 // Access: Protected
4504 // Description:
4505 ////////////////////////////////////////////////////////////////////
4506 void DXGraphicsStateGuardian9::
4507 set_texture_blend_mode(int i, const TextureStage *stage) {
4508  switch (stage->get_mode()) {
4509  case TextureStage::M_modulate:
4510  case TextureStage::M_modulate_glow:
4511  case TextureStage::M_modulate_gloss:
4512  // emulates GL_MODULATE glTexEnv mode
4513  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_MODULATE);
4514  set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
4515  set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
4516  set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
4517  set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
4518  set_texture_stage_state(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
4519  break;
4520 
4521  case TextureStage::M_decal:
4522  // emulates GL_DECAL glTexEnv mode
4523  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA);
4524  set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
4525  set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
4526 
4527  set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
4528  set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
4529  break;
4530 
4531  case TextureStage::M_replace:
4532  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
4533  set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
4534 
4535  set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
4536  set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
4537  break;
4538 
4539  case TextureStage::M_add:
4540  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_ADD);
4541  set_texture_stage_state(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
4542  set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
4543 
4544  set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
4545  set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
4546  set_texture_stage_state(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
4547  break;
4548 
4549  case TextureStage::M_blend:
4550  case TextureStage::M_blend_color_scale:
4551  {
4552  set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_LERP);
4553  set_texture_stage_state(i, D3DTSS_COLORARG0, D3DTA_TEXTURE);
4554  set_texture_stage_state(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
4555  set_texture_stage_state(i, D3DTSS_COLORARG1, _constant_color_operand);
4556 
4557  set_texture_stage_state(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
4558  set_texture_stage_state(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
4559  set_texture_stage_state(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
4560  }
4561  break;
4562 
4563  case TextureStage::M_combine:
4564  // M_combine mode begins a collection of more sophisticated modes,
4565  // which match up more closely with DirectX's built-in modes.
4566  set_texture_stage_state
4567  (i, D3DTSS_COLOROP,
4568  get_texture_operation(stage->get_combine_rgb_mode(),
4569  stage->get_rgb_scale()));
4570 
4571  switch (stage->get_num_combine_rgb_operands()) {
4572  case 3:
4573  set_texture_stage_state
4574  (i, D3DTSS_COLORARG0,
4575  get_texture_argument(stage->get_combine_rgb_source2(),
4576  stage->get_combine_rgb_operand2()));
4577  // fall through
4578 
4579  case 2:
4580  set_texture_stage_state
4581  (i, D3DTSS_COLORARG2,
4582  get_texture_argument(stage->get_combine_rgb_source1(),
4583  stage->get_combine_rgb_operand1()));
4584  // fall through
4585 
4586  case 1:
4587  set_texture_stage_state
4588  (i, D3DTSS_COLORARG1,
4589  get_texture_argument(stage->get_combine_rgb_source0(),
4590  stage->get_combine_rgb_operand0()));
4591  // fall through
4592 
4593  default:
4594  break;
4595  }
4596 
4597  set_texture_stage_state
4598  (i, D3DTSS_ALPHAOP,
4599  get_texture_operation(stage->get_combine_alpha_mode(),
4600  stage->get_alpha_scale()));
4601 
4602  switch (stage->get_num_combine_alpha_operands()) {
4603  case 3:
4604  set_texture_stage_state
4605  (i, D3DTSS_ALPHAARG0,
4606  get_texture_argument(stage->get_combine_alpha_source2(),
4607  stage->get_combine_alpha_operand2()));
4608  // fall through
4609 
4610  case 2:
4611  set_texture_stage_state
4612  (i, D3DTSS_ALPHAARG2,
4613  get_texture_argument(stage->get_combine_alpha_source1(),
4614  stage->get_combine_alpha_operand1()));
4615  // fall through
4616 
4617  case 1:
4618  set_texture_stage_state
4619  (i, D3DTSS_ALPHAARG1,
4620  get_texture_argument(stage->get_combine_alpha_source0(),
4621  stage->get_combine_alpha_operand0()));
4622  // fall through
4623 
4624  default:
4625  break;
4626  }
4627  break;
4628 
4629  default:
4630  dxgsg9_cat.error()
4631  << "Unknown texture mode " << (int)stage->get_mode() << endl;
4632  break;
4633  }
4634 
4635  if (stage->get_saved_result()) {
4636  set_texture_stage_state(i, D3DTSS_RESULTARG, D3DTA_TEMP);
4637  } else {
4638  set_texture_stage_state(i, D3DTSS_RESULTARG, D3DTA_CURRENT);
4639  }
4640 
4641  if (stage->uses_color()) {
4642  // Set up the constant color for this stage.
4643 
4644  D3DCOLOR constant_color;
4645  if (stage->involves_color_scale() && _color_scale_enabled) {
4646  LColor color = stage->get_color();
4647  color.set(color[0] * _current_color_scale[0],
4648  color[1] * _current_color_scale[1],
4649  color[2] * _current_color_scale[2],
4650  color[3] * _current_color_scale[3]);
4651  _texture_involves_color_scale = true;
4652  constant_color = LColor_to_D3DCOLOR(color);
4653  } else {
4654  constant_color = LColor_to_D3DCOLOR(stage->get_color());
4655  }
4656  if (_supports_texture_constant_color) {
4657  set_texture_stage_state(i, D3DTSS_CONSTANT, constant_color);
4658  } else {
4659  // This device doesn't supoprt a per-stage constant color, so we
4660  // have to fall back to a single constant color for the overall
4661  // texture pipeline.
4662  set_render_state(D3DRS_TEXTUREFACTOR, constant_color);
4663  }
4664  }
4665 }
4666 
4667 ////////////////////////////////////////////////////////////////////
4668 // Function: DXGraphicsStateGuardian9::dx_cleanup
4669 // Access: Protected
4670 // Description: Clean up the DirectX environment, accounting for exit()
4671 ////////////////////////////////////////////////////////////////////
4672 void DXGraphicsStateGuardian9::
4673 dx_cleanup() {
4674  if (!_d3d_device) {
4675  return;
4676  }
4677 
4678  free_nondx_resources();
4679  PRINT_REFCNT(dxgsg9, _d3d_device);
4680 
4681  // Do a safe check for releasing the D3DDEVICE. RefCount should be zero.
4682  // if we're called from exit(), _d3d_device may already have been released
4683  RELEASE(_d3d_device, dxgsg9, "d3dDevice", RELEASE_DOWN_TO_ZERO);
4684  _screen->_d3d_device = NULL;
4685 
4686  // Releasing pD3D is now the responsibility of the GraphicsPipe destructor
4687 }
4688 
4689 ////////////////////////////////////////////////////////////////////
4690 // Function: DXGraphicsStateGuardian9::reset_d3d_device
4691 // Access: Protected
4692 // Description: This function checks current device's framebuffer
4693 // dimension against passed p_presentation_params backbuffer
4694 // dimension to determine a device reset if there is
4695 // only one window or it is the main window or
4696 // fullscreen mode then, it resets the device. Finally
4697 // it returns the new DXScreenData through parameter
4698 // screen
4699 ////////////////////////////////////////////////////////////////////
4700 HRESULT DXGraphicsStateGuardian9::
4701 reset_d3d_device(D3DPRESENT_PARAMETERS *presentation_params,
4702  DXScreenData **screen) {
4703  HRESULT hr;
4704 
4705  nassertr(IS_VALID_PTR(presentation_params), E_FAIL);
4706  nassertr(IS_VALID_PTR(_screen->_d3d9), E_FAIL);
4707  nassertr(IS_VALID_PTR(_d3d_device), E_FAIL);
4708 
4709  // for windowed mode make sure our format matches the desktop fmt,
4710  // in case the desktop mode has been changed
4711  _screen->_d3d9->GetAdapterDisplayMode(_screen->_card_id, &_screen->_display_mode);
4712  presentation_params->BackBufferFormat = _screen->_display_mode.Format;
4713 
4714  // here we have to look at the _presentation_reset frame buffer dimension
4715  // if current window's dimension is bigger than _presentation_reset
4716  // we have to reset the device before creating new swapchain.
4717  // inorder to reset properly, we need to release all swapchains
4718 
4719  if (true || !(_screen->_swap_chain)
4720  || (_presentation_reset.BackBufferWidth < presentation_params->BackBufferWidth)
4721  || (_presentation_reset.BackBufferHeight < presentation_params->BackBufferHeight)) {
4722  if (wdxdisplay9_cat.is_debug()) {
4723  wdxdisplay9_cat.debug()
4724  << "swap_chain = " << _screen->_swap_chain << " _presentation_reset = "
4725  << _presentation_reset.BackBufferWidth << "x" << _presentation_reset.BackBufferHeight
4726  << " presentation_params = "
4727  << presentation_params->BackBufferWidth << "x" << presentation_params->BackBufferHeight << "\n";
4728  }
4729 
4730  get_engine()->reset_all_windows(false);// reset old swapchain by releasing
4731 
4732  if (_screen->_swap_chain) { //other windows might be using bigger buffers
4733  _presentation_reset.BackBufferWidth = max(_presentation_reset.BackBufferWidth, presentation_params->BackBufferWidth);
4734  _presentation_reset.BackBufferHeight = max(_presentation_reset.BackBufferHeight, presentation_params->BackBufferHeight);
4735 
4736  } else { // single window, must reset to the new presentation_params dimension
4737  _presentation_reset.BackBufferWidth = presentation_params->BackBufferWidth;
4738  _presentation_reset.BackBufferHeight = presentation_params->BackBufferHeight;
4739  }
4740 
4741  // Calling this forces all of the textures and vbuffers to be
4742  // regenerated, a prerequisite to calling Reset().
4743  release_all();
4744 
4745  // Just to be extra-conservative for now, we'll go ahead and
4746  // release the vbuffers and ibuffers at least; they're relatively
4747  // cheap to replace.
4748  release_all_vertex_buffers();
4749  release_all_index_buffers();
4750 
4751  // must be called before reset
4752  Thread *current_thread = Thread::get_current_thread();
4753  _prepared_objects->begin_frame(this, current_thread);
4754 
4755  // release graphics buffer surfaces
4756  {
4757  wdxGraphicsBuffer9 *graphics_buffer;
4758  list <wdxGraphicsBuffer9 **>::iterator graphics_buffer_iterator;
4759 
4760  for (graphics_buffer_iterator = _graphics_buffer_list.begin( ); graphics_buffer_iterator != _graphics_buffer_list.end( ); graphics_buffer_iterator++)
4761  {
4762  graphics_buffer = **graphics_buffer_iterator;
4763  if (graphics_buffer -> _color_backing_store)
4764  {
4765  graphics_buffer -> _color_backing_store -> Release ( );
4766  graphics_buffer -> _color_backing_store = 0;
4767  }
4768  if (graphics_buffer -> _depth_backing_store)
4769  {
4770  graphics_buffer -> _depth_backing_store -> Release ( );
4771  graphics_buffer -> _depth_backing_store = 0;
4772  }
4773  }
4774  }
4775 
4776  this -> mark_new();
4777  hr = _d3d_device->Reset(&_presentation_reset);
4778  if (FAILED(hr) && hr != D3DERR_DEVICELOST) {
4779  return hr;
4780  }
4781 
4782  get_engine()->reset_all_windows(true);// reset with new swapchains by creating
4783  if (screen) {
4784  *screen = NULL;
4785  }
4786 
4787  if (presentation_params != &_screen->_presentation_params) {
4788  memcpy(&_screen->_presentation_params, presentation_params, sizeof(D3DPRESENT_PARAMETERS));
4789  }
4790 
4791  return hr;
4792  }
4793 
4794  // release the old swapchain and create a new one
4795  if (_screen && _screen->_swap_chain) {
4796  _screen->_swap_chain->Release();
4797  wdxdisplay9_cat.debug()
4798  << "swap chain " << _screen->_swap_chain << " is released\n";
4799  _screen->_swap_chain = NULL;
4800  hr = _d3d_device->CreateAdditionalSwapChain(presentation_params, &_screen->_swap_chain);
4801  }
4802  if (SUCCEEDED(hr)) {
4803  if (presentation_params != &_screen->_presentation_params) {
4804  memcpy(&_screen->_presentation_params, presentation_params, sizeof(D3DPRESENT_PARAMETERS));
4805  }
4806  if (screen) {
4807  *screen = _screen;
4808  }
4809  }
4810  return hr;
4811 }
4812 
4813 ////////////////////////////////////////////////////////////////////
4814 // Function: DXGraphicsStateGuardian9::check_cooperative_level
4815 // Access: Protected
4816 // Description:
4817 ////////////////////////////////////////////////////////////////////
4818 bool DXGraphicsStateGuardian9::
4819 check_cooperative_level() {
4820  bool bDoReactivateWindow = false;
4821  if (_d3d_device == NULL) {
4822  return false;
4823  }
4824 
4825  HRESULT hr = _d3d_device->TestCooperativeLevel();
4826 
4827  if (SUCCEEDED(hr)) {
4828  nassertr(SUCCEEDED(_last_testcooplevel_result), false);
4829  return true;
4830  }
4831 
4832  switch (hr) {
4833  case D3DERR_DEVICENOTRESET:
4834  _dx_is_ready = false;
4835 
4836  // call this just in case
4837  _prepared_objects->begin_frame(this, Thread::get_current_thread());
4838 
4839  hr = reset_d3d_device(&_screen->_presentation_params);
4840  if (FAILED(hr)) {
4841  // I think this shouldnt fail unless I've screwed up the
4842  // _presentation_params from the original working ones somehow
4843  dxgsg9_cat.error()
4844  << "check_cooperative_level Reset() failed, hr = " << D3DERRORSTRING(hr);
4845  }
4846 
4847  hr = _d3d_device->TestCooperativeLevel();
4848  if (FAILED(hr)) {
4849  // internal chk, shouldnt fail
4850  dxgsg9_cat.error()
4851  << "TestCooperativeLevel following Reset() failed, hr = " << D3DERRORSTRING(hr);
4852 
4853  }
4854 
4855  _dx_is_ready = TRUE;
4856  break;
4857 
4858  case D3DERR_DEVICELOST:
4859  // sleep while the device is lost to free up the CPU
4860  Sleep (10);
4861 
4862  if (SUCCEEDED(_last_testcooplevel_result)) {
4863  if (_dx_is_ready) {
4864  _dx_is_ready = false;
4865  if (dxgsg9_cat.is_debug()) {
4866  dxgsg9_cat.debug() << "D3D Device was Lost, waiting...\n";
4867  }
4868  }
4869  }
4870  }
4871 
4872  _last_testcooplevel_result = hr;
4873  return SUCCEEDED(hr);
4874 }
4875 
4876 ////////////////////////////////////////////////////////////////////
4877 // Function: DXGraphicsStateGuardian9::show_frame
4878 // Access: Protected
4879 // Description: redraw primary buffer
4880 ////////////////////////////////////////////////////////////////////
4881 void DXGraphicsStateGuardian9::
4882 show_frame() {
4883  if (_d3d_device == NULL) {
4884  return;
4885  }
4886 
4887  HRESULT hr;
4888 
4889  if (_swap_chain) {
4890  DWORD flags;
4891  flags = 0;
4892 
4893  hr = _swap_chain->Present((CONST RECT*)NULL, (CONST RECT*)NULL, (HWND)NULL, NULL, flags);
4894  } else {
4895  hr = _d3d_device->Present((CONST RECT*)NULL, (CONST RECT*)NULL, (HWND)NULL, NULL);
4896  }
4897 
4898  if (FAILED(hr)) {
4899  if (hr == D3DERR_DEVICELOST) {
4900  check_cooperative_level();
4901  } else {
4902  dxgsg9_cat.error()
4903  << "show_frame() - Present() failed" << D3DERRORSTRING(hr);
4904  throw_event("panda3d-render-error");
4905  }
4906  }
4907 }
4908 
4909 ////////////////////////////////////////////////////////////////////
4910 // Function: DXGraphicsStateGuardian9::create_swap_chain
4911 // Access: Protected
4912 // Description:
4913 ////////////////////////////////////////////////////////////////////
4914 bool DXGraphicsStateGuardian9::
4915 create_swap_chain(DXScreenData *new_context) {
4916  // Instead of creating a device and rendering as d3ddevice->present()
4917  // we should render using SwapChain->present(). This is done to support
4918  // multiple windows rendering. For that purpose, we need to set additional
4919  // swap chains here.
4920 
4921  HRESULT hr;
4922  hr = new_context->_d3d_device->CreateAdditionalSwapChain(&new_context->_presentation_params, &new_context->_swap_chain);
4923  if (FAILED(hr)) {
4924  wdxdisplay9_cat.debug() << "Swapchain creation failed :"<<D3DERRORSTRING(hr)<<"\n";
4925  return false;
4926  }
4927  return true;
4928 }
4929 
4930 ////////////////////////////////////////////////////////////////////
4931 // Function: DXGraphicsStateGuardian9::release_swap_chain
4932 // Access: Protected
4933 // Description: Release the swap chain on this DXScreenData
4934 ////////////////////////////////////////////////////////////////////
4935 bool DXGraphicsStateGuardian9::
4936 release_swap_chain(DXScreenData *new_context) {
4937  HRESULT hr;
4938  if (new_context->_swap_chain) {
4939  hr = new_context->_swap_chain->Release();
4940  if (FAILED(hr)) {
4941  wdxdisplay9_cat.debug() << "Swapchain release failed:" << D3DERRORSTRING(hr) << "\n";
4942  return false;
4943  }
4944  }
4945  return true;
4946 }
4947 
4948 ////////////////////////////////////////////////////////////////////
4949 // Function: DXGraphicsStateGuardian9::copy_pres_reset
4950 // Access: Protected
4951 // Description: copies the PresReset from passed DXScreenData
4952 ////////////////////////////////////////////////////////////////////
4953 void DXGraphicsStateGuardian9::
4954 copy_pres_reset(DXScreenData *screen) {
4955  memcpy(&_presentation_reset, &_screen->_presentation_params, sizeof(D3DPRESENT_PARAMETERS));
4956 }
4957 
4958 ////////////////////////////////////////////////////////////////////
4959 // Function: DXGraphicsStateGuardian9::get_d3d_min_type
4960 // Access: Protected, Static
4961 // Description:
4962 ////////////////////////////////////////////////////////////////////
4963 D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian9::
4964 get_d3d_min_type(SamplerState::FilterType filter_type) {
4965  switch (filter_type) {
4966  case SamplerState::FT_nearest:
4967  return D3DTEXF_POINT;
4968 
4969  case SamplerState::FT_linear:
4970  return D3DTEXF_LINEAR;
4971 
4972  case SamplerState::FT_nearest_mipmap_nearest:
4973  return D3DTEXF_POINT;
4974 
4975  case SamplerState::FT_linear_mipmap_nearest:
4976  return D3DTEXF_LINEAR;
4977 
4978  case SamplerState::FT_nearest_mipmap_linear:
4979  return D3DTEXF_POINT;
4980 
4981  case SamplerState::FT_linear_mipmap_linear:
4982  return D3DTEXF_LINEAR;
4983 
4984  case SamplerState::FT_shadow:
4985  case SamplerState::FT_default:
4986  return D3DTEXF_LINEAR;
4987  }
4988 
4989  dxgsg9_cat.error()
4990  << "Invalid FilterType value (" << (int)filter_type << ")\n";
4991  return D3DTEXF_POINT;
4992 }
4993 
4994 ////////////////////////////////////////////////////////////////////
4995 // Function: DXGraphicsStateGuardian9::get_d3d_mip_type
4996 // Access: Protected, Static
4997 // Description:
4998 ////////////////////////////////////////////////////////////////////
4999 D3DTEXTUREFILTERTYPE DXGraphicsStateGuardian9::
5000 get_d3d_mip_type(SamplerState::FilterType filter_type) {
5001  switch (filter_type) {
5002  case SamplerState::FT_nearest:
5003  return D3DTEXF_NONE;
5004 
5005  case SamplerState::FT_linear:
5006  return D3DTEXF_NONE;
5007 
5008  case SamplerState::FT_nearest_mipmap_nearest:
5009  return D3DTEXF_POINT;
5010 
5011  case SamplerState::FT_linear_mipmap_nearest:
5012  return D3DTEXF_POINT;
5013 
5014  case SamplerState::FT_nearest_mipmap_linear:
5015  return D3DTEXF_LINEAR;
5016 
5017  case SamplerState::FT_linear_mipmap_linear:
5018  return D3DTEXF_LINEAR;
5019 
5020  case SamplerState::FT_shadow:
5021  case SamplerState::FT_default:
5022  return D3DTEXF_NONE;
5023  }
5024 
5025  dxgsg9_cat.error()
5026  << "Invalid FilterType value (" << (int)filter_type << ")\n";
5027  return D3DTEXF_NONE;
5028 }
5029 
5030 ////////////////////////////////////////////////////////////////////
5031 // Function: DXGraphicsStateGuardian9::get_texture_operation
5032 // Access: Protected, Static
5033 // Description: Returns the D3DTEXTUREOP value corresponding to the
5034 // indicated TextureStage::CombineMode enumerated type.
5035 ////////////////////////////////////////////////////////////////////
5036 D3DTEXTUREOP DXGraphicsStateGuardian9::
5037 get_texture_operation(TextureStage::CombineMode mode, int scale) {
5038  switch (mode) {
5039  case TextureStage::CM_undefined:
5040  case TextureStage::CM_replace:
5041  return D3DTOP_SELECTARG1;
5042 
5043  case TextureStage::CM_modulate:
5044  if (scale < 2) {
5045  return D3DTOP_MODULATE;
5046  } else if (scale < 4) {
5047  return D3DTOP_MODULATE2X;
5048  } else {
5049  return D3DTOP_MODULATE4X;
5050  }
5051 
5052  case TextureStage::CM_add:
5053  return D3DTOP_ADD;
5054 
5055  case TextureStage::CM_add_signed:
5056  if (scale < 2) {
5057  return D3DTOP_ADDSIGNED;
5058  } else {
5059  return D3DTOP_ADDSIGNED2X;
5060  }
5061 
5062  case TextureStage::CM_interpolate:
5063  return D3DTOP_LERP;
5064 
5065  case TextureStage::CM_subtract:
5066  return D3DTOP_SUBTRACT;
5067 
5068  case TextureStage::CM_dot3_rgb:
5069  case TextureStage::CM_dot3_rgba:
5070  return D3DTOP_DOTPRODUCT3;
5071  }
5072 
5073  dxgsg9_cat.error()
5074  << "Invalid TextureStage::CombineMode value (" << (int)mode << ")\n";
5075  return D3DTOP_DISABLE;
5076 }
5077 
5078 ////////////////////////////////////////////////////////////////////
5079 // Function: DXGraphicsStateGuardian9::get_texture_argument
5080 // Access: Protected
5081 // Description: Returns the D3DTA value corresponding to the
5082 // indicated TextureStage::CombineSource and
5083 // TextureStage::CombineOperand enumerated types.
5084 ////////////////////////////////////////////////////////////////////
5085 DWORD DXGraphicsStateGuardian9::
5086 get_texture_argument(TextureStage::CombineSource source,
5087  TextureStage::CombineOperand operand) const {
5088  switch (source) {
5089  case TextureStage::CS_undefined:
5090  case TextureStage::CS_texture:
5091  return D3DTA_TEXTURE | get_texture_argument_modifier(operand);
5092 
5093  case TextureStage::CS_constant:
5094  case TextureStage::CS_constant_color_scale:
5095  return _constant_color_operand | get_texture_argument_modifier(operand);
5096 
5097  case TextureStage::CS_primary_color:
5098  return D3DTA_DIFFUSE | get_texture_argument_modifier(operand);
5099 
5100  case TextureStage::CS_previous:
5101  return D3DTA_CURRENT | get_texture_argument_modifier(operand);
5102 
5103  case TextureStage::CS_last_saved_result:
5104  return D3DTA_TEMP | get_texture_argument_modifier(operand);
5105  }
5106  dxgsg9_cat.error()
5107  << "Invalid TextureStage::CombineSource value (" << (int)source << ")\n";
5108  return D3DTA_CURRENT;
5109 }
5110 
5111 ////////////////////////////////////////////////////////////////////
5112 // Function: DXGraphicsStateGuardian9::get_texture_argument_modifier
5113 // Access: Protected, Static
5114 // Description: Returns the extra bits that modify the D3DTA
5115 // argument, according to the indicated
5116 // TextureStage::CombineOperand enumerated type.
5117 ////////////////////////////////////////////////////////////////////
5118 DWORD DXGraphicsStateGuardian9::
5119 get_texture_argument_modifier(TextureStage::CombineOperand operand) {
5120  switch (operand) {
5121  case TextureStage::CO_src_color:
5122  return 0;
5123 
5124  case TextureStage::CO_one_minus_src_color:
5125  return D3DTA_COMPLEMENT;
5126 
5127  case TextureStage::CO_src_alpha:
5128  return D3DTA_ALPHAREPLICATE;
5129 
5130  case TextureStage::CO_one_minus_src_alpha:
5131  return D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT;
5132 
5133  case TextureStage::CO_undefined:
5134  break;
5135  }
5136  dxgsg9_cat.error()
5137  << "Invalid TextureStage::CombineOperand value (" << (int)operand << ")\n";
5138  return 0;
5139 }
5140 
5141 ////////////////////////////////////////////////////////////////////
5142 // Function: DXGraphicsStateGuardian9::draw_primitive_up
5143 // Access: Protected
5144 // Description: Issues the DrawPrimitiveUP call to draw the indicated
5145 // primitive_type from the given buffer. We add the
5146 // num_vertices parameter, so we can determine the size
5147 // of the buffer.
5148 ////////////////////////////////////////////////////////////////////
5149 void DXGraphicsStateGuardian9::
5150 draw_primitive_up(D3DPRIMITIVETYPE primitive_type,
5151  unsigned int primitive_count,
5152  unsigned int first_vertex,
5153  unsigned int num_vertices,
5154  const unsigned char *buffer, size_t stride) {
5155 
5156  // It appears that the common ATI driver seems to fail to draw
5157  // anything in the DrawPrimitiveUP() call if the address range of
5158  // the buffer supplied crosses over a multiple of 0x10000. That's
5159  // incredibly broken, yet it undeniably appears to be true. We'll
5160  // have to hack around it.
5161 
5162  const unsigned char *buffer_start = buffer + stride * first_vertex;
5163  const unsigned char *buffer_end = buffer_start + stride * num_vertices;
5164 
5165  if (buffer_end - buffer_start > 0x10000) {
5166  // Actually, the buffer doesn't fit within the required limit
5167  // anyway. Go ahead and draw it and hope for the best.
5168  _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count,
5169  buffer_start, stride);
5170 
5171  } else if ((((long)buffer_end ^ (long)buffer_start) & ~0xffff) == 0) {
5172  // No problem; we can draw the buffer directly.
5173  _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count,
5174  buffer_start, stride);
5175 
5176  } else {
5177  // We have a problem--the buffer crosses over a 0x10000 boundary.
5178  // We have to copy the buffer to a temporary buffer that we can
5179  // draw from.
5180  unsigned char *safe_buffer_start = get_safe_buffer_start();
5181  memcpy(safe_buffer_start, buffer_start, buffer_end - buffer_start);
5182  _d3d_device->DrawPrimitiveUP(primitive_type, primitive_count,
5183  safe_buffer_start, stride);
5184 
5185  }
5186 }
5187 
5188 ////////////////////////////////////////////////////////////////////
5189 // Function: DXGraphicsStateGuardian9::draw_indexed_primitive_up
5190 // Access: Protected
5191 // Description: Issues the DrawIndexedPrimitiveUP call to draw the
5192 // indicated primitive_type from the given buffer. As
5193 // in draw_primitive_up(), above, the parameter list is
5194 // not exactly one-for-one with the
5195 // DrawIndexedPrimitiveUP() call, but it's similar (in
5196 // particular, we pass max_index instead of NumVertices,
5197 // which always seemed ambiguous to me).
5198 ////////////////////////////////////////////////////////////////////
5199 void DXGraphicsStateGuardian9::
5200 draw_indexed_primitive_up(D3DPRIMITIVETYPE primitive_type,
5201  unsigned int min_index, unsigned int max_index,
5202  unsigned int num_primitives,
5203  const unsigned char *index_data,
5204  D3DFORMAT index_type,
5205  const unsigned char *buffer, size_t stride) {
5206  // As above, we'll hack the case of the buffer crossing the 0x10000
5207  // boundary.
5208  const unsigned char *buffer_start = buffer + stride * min_index;
5209  const unsigned char *buffer_end = buffer + stride * (max_index + 1);
5210 
5211  if (buffer_end - buffer_start > 0x10000) {
5212  // Actually, the buffer doesn't fit within the required limit
5213  // anyway. Go ahead and draw it and hope for the best.
5214  _d3d_device->DrawIndexedPrimitiveUP
5215  (primitive_type, min_index, max_index - min_index + 1, num_primitives,
5216  index_data, index_type, buffer, stride);
5217 
5218  } else if ((((long)buffer_end ^ (long)buffer_start) & ~0xffff) == 0) {
5219  // No problem; we can draw the buffer directly.
5220  _d3d_device->DrawIndexedPrimitiveUP
5221  (primitive_type, min_index, max_index - min_index + 1, num_primitives,
5222  index_data, index_type, buffer, stride);
5223 
5224  } else {
5225  // We have a problem--the buffer crosses over a 0x10000 boundary.
5226  // We have to copy the buffer to a temporary buffer that we can
5227  // draw from.
5228  unsigned char *safe_buffer_start = get_safe_buffer_start();
5229  memcpy(safe_buffer_start, buffer_start, buffer_end - buffer_start);
5230  _d3d_device->DrawIndexedPrimitiveUP
5231  (primitive_type, min_index, max_index - min_index + 1, num_primitives,
5232  index_data, index_type, safe_buffer_start - stride * min_index, stride);
5233  }
5234 }
5235 
5236 ////////////////////////////////////////////////////////////////////
5237 // Function: DXGraphicsStateGuardian9::check_dx_allocation
5238 // Access:
5239 // Description: This function is called after the creation of
5240 // textures, vertex buffers, and index buffers to
5241 // check if DirectX is out of memory. If DirectX is
5242 // out of memory and the LRU is being used, then
5243 // page out some memory. This function is a fail-safe
5244 // just in case another process allocates video
5245 // memory, DirectX is fragmented, or there are some
5246 // borderline memory allocation cases, ...
5247 ////////////////////////////////////////////////////////////////////
5249 check_dx_allocation (HRESULT result, int allocation_size, int attempts)
5250 {
5251  bool retry;
5252 
5253  retry = false;
5254  if (attempts <= 4)
5255  {
5256  switch (result) {
5257  case D3D_OK:
5258  break;
5259 
5260  case D3DERR_OUTOFVIDEOMEMORY:
5261  case E_OUTOFMEMORY:
5262  // increase the page out size as the number of attempts increases
5263  {
5264  size_t current_size = _prepared_objects->_graphics_memory_lru.get_total_size();
5265  size_t target_size = max(current_size - allocation_size * attempts, (size_t) 0);
5266  _prepared_objects->_graphics_memory_lru.evict_to(target_size);
5267  dxgsg9_cat.info()
5268  << "Evicted " << current_size - _prepared_objects->_graphics_memory_lru.get_total_size() << " bytes of texture memory to make room for more.\n";
5269  if (_prepared_objects->_graphics_memory_lru.get_total_size() < current_size) {
5270  retry = true;
5271  }
5272  }
5273  break;
5274 
5275  default:
5276  break;
5277  }
5278  }
5279 
5280  return retry;
5281 }
5282 
5283 ////////////////////////////////////////////////////////////////////
5284 // DX stencil code section
5285 ////////////////////////////////////////////////////////////////////
5286 static int dx_stencil_comparison_function_array[] = {
5287  D3DCMP_NEVER,
5288  D3DCMP_LESS,
5289  D3DCMP_EQUAL,
5290  D3DCMP_LESSEQUAL,
5291  D3DCMP_GREATER,
5292  D3DCMP_NOTEQUAL,
5293  D3DCMP_GREATEREQUAL,
5294  D3DCMP_ALWAYS,
5295 };
5296 
5297 static int dx_stencil_operation_array[] = {
5298  D3DSTENCILOP_KEEP,
5299  D3DSTENCILOP_ZERO,
5300  D3DSTENCILOP_REPLACE,
5301  D3DSTENCILOP_INCR,
5302  D3DSTENCILOP_DECR,
5303  D3DSTENCILOP_INVERT,
5304 
5305  D3DSTENCILOP_INCRSAT,
5306  D3DSTENCILOP_DECRSAT,
5307 };
5308 
5309 ////////////////////////////////////////////////////////////////////
5310 // Function: DXGraphicsStateGuardian9::do_issue_stencil
5311 // Access: Protected
5312 // Description: Set stencil render states.
5313 ////////////////////////////////////////////////////////////////////
5314 void DXGraphicsStateGuardian9::
5315 do_issue_stencil() {
5316  if (!_supports_stencil) {
5317  return;
5318  }
5319 
5320  const StencilAttrib *stencil = DCAST(StencilAttrib, _target_rs->get_attrib(StencilAttrib::get_class_slot()));
5321 
5322  if (stencil != (const StencilAttrib *)NULL) {
5323  // DEBUG
5324  if (false) {
5325  dxgsg9_cat.debug() << "STENCIL STATE CHANGE\n";
5326  dxgsg9_cat.debug() << "\n"
5327  << "SRS_front_comparison_function " << stencil->get_render_state(StencilAttrib::SRS_front_comparison_function) << "\n"
5328  << "SRS_front_stencil_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation) << "\n"
5329  << "SRS_front_stencil_pass_z_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation) << "\n"
5330  << "SRS_front_stencil_pass_z_pass_operation " << stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation) << "\n"
5331  << "SRS_reference " << stencil->get_render_state(StencilAttrib::SRS_reference) << "\n"
5332  << "SRS_read_mask " << stencil->get_render_state(StencilAttrib::SRS_read_mask) << "\n"
5333  << "SRS_write_mask " << stencil->get_render_state(StencilAttrib::SRS_write_mask) << "\n"
5334  << "SRS_back_comparison_function " << stencil->get_render_state(StencilAttrib::SRS_back_comparison_function) << "\n"
5335  << "SRS_back_stencil_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_back_stencil_fail_operation) << "\n"
5336  << "SRS_back_stencil_pass_z_fail_operation " << stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_fail_operation) << "\n"
5337  << "SRS_back_stencil_pass_z_pass_operation " << stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_pass_operation) << "\n";
5338  }
5339 
5340  bool on = false;
5341 
5342  unsigned int front_compare;
5343  front_compare = stencil->get_render_state(StencilAttrib::SRS_front_comparison_function);
5344 
5345  if (front_compare != RenderAttrib::M_none) {
5346  set_render_state(D3DRS_STENCILENABLE, TRUE);
5347  set_render_state(D3DRS_STENCILFUNC, dx_stencil_comparison_function_array[front_compare]);
5348  set_render_state(D3DRS_STENCILFAIL, dx_stencil_operation_array[
5349  stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation)]);
5350  set_render_state(D3DRS_STENCILZFAIL, dx_stencil_operation_array[
5351  stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation)]);
5352  set_render_state(D3DRS_STENCILPASS, dx_stencil_operation_array[
5353  stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation)]);
5354  on = true;
5355  } else {
5356  set_render_state(D3DRS_STENCILENABLE, FALSE);
5357  }
5358 
5359  if (_supports_two_sided_stencil) {
5360  unsigned int back_compare;
5361  back_compare = stencil->get_render_state(StencilAttrib::SRS_back_comparison_function);
5362 
5363  if (back_compare != RenderAttrib::M_none) {
5364  set_render_state(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
5365  set_render_state(D3DRS_CCW_STENCILFUNC, dx_stencil_comparison_function_array[back_compare]);
5366  set_render_state(D3DRS_CCW_STENCILFAIL, dx_stencil_operation_array[
5367  stencil->get_render_state(StencilAttrib::SRS_back_stencil_fail_operation)]);
5368  set_render_state(D3DRS_CCW_STENCILZFAIL, dx_stencil_operation_array[
5369  stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_fail_operation)]);
5370  set_render_state(D3DRS_CCW_STENCILPASS, dx_stencil_operation_array[
5371  stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_pass_operation)]);
5372  on = true;
5373  } else {
5374  set_render_state(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
5375  }
5376  }
5377 
5378  if (on) {
5379  set_render_state(D3DRS_STENCILREF, stencil->get_render_state(StencilAttrib::SRS_reference));
5380  set_render_state(D3DRS_STENCILMASK, stencil->get_render_state(StencilAttrib::SRS_read_mask));
5381  set_render_state(D3DRS_STENCILWRITEMASK, stencil->get_render_state(StencilAttrib::SRS_write_mask));
5382  }
5383 
5384  if (stencil->get_render_state(StencilAttrib::SRS_clear)) {
5385  _d3d_device->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0.0f, stencil->get_render_state(StencilAttrib::SRS_clear_value));
5386  }
5387 
5388  } else {
5389  // DEBUG
5390  if (false) {
5391  dxgsg9_cat.debug() << "STENCIL STATE CHANGE TO OFF\n";
5392  }
5393 
5394  set_render_state(D3DRS_STENCILENABLE, FALSE);
5395  if (_supports_two_sided_stencil) {
5396  set_render_state(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
5397  }
5398  }
5399 }
5400 
5401 ////////////////////////////////////////////////////////////////////
5402 // Function: dxGraphicsStateGuardian9::do_issue_scissor
5403 // Access: Protected
5404 // Description:
5405 ////////////////////////////////////////////////////////////////////
5406 void DXGraphicsStateGuardian9::
5407 do_issue_scissor() {
5408  const ScissorAttrib *target_scissor = DCAST(ScissorAttrib, _target_rs->get_attrib_def(ScissorAttrib::get_class_slot()));
5409  const LVecBase4 &frame = target_scissor->get_frame();
5410 
5411  RECT r;
5412  r.left = _current_viewport.X + _current_viewport.Width * frame[0];
5413  r.top = _current_viewport.Y + _current_viewport.Height * (1.0f - frame[3]);
5414  r.right = _current_viewport.X + _current_viewport.Width * frame[1];
5415  r.bottom = _current_viewport.Y + _current_viewport.Height * (1.0f - frame[2]);
5416  _d3d_device->SetScissorRect(&r);
5417  set_render_state(D3DRS_SCISSORTESTENABLE, TRUE);
5418 }
5419 
5420 ////////////////////////////////////////////////////////////////////
5421 // Function: dxGraphicsStateGuardian9::calc_fb_properties
5422 // Access: Public
5423 // Description: Convert DirectX framebuffer format ids into a
5424 // FrameBufferProperties structure.
5425 ////////////////////////////////////////////////////////////////////
5427 calc_fb_properties(DWORD cformat, DWORD dformat,
5428  DWORD multisampletype, DWORD multisamplequality) {
5429  FrameBufferProperties props;
5430  int index=0;
5431  int r=0, g=0, b=0, a=0;
5432  switch (cformat) {
5433  case D3DFMT_R8G8B8: r=8; g=8; b=8; a=0; break;
5434  case D3DFMT_A8R8G8B8: r=8; g=8; b=8; a=8; break;
5435  case D3DFMT_X8R8G8B8: r=8; g=8; b=8; a=0; break;
5436  case D3DFMT_R5G6B5: r=5; g=6; b=5; a=0; break;
5437  case D3DFMT_X1R5G5B5: r=5; g=5; b=5; a=0; break;
5438  case D3DFMT_A1R5G5B5: r=5; g=5; b=5; a=1; break;
5439  case D3DFMT_A4R4G4B4: r=4; g=4; b=4; a=4; break;
5440  case D3DFMT_R3G3B2: r=3; g=3; b=2; a=0; break;
5441  case D3DFMT_A8R3G3B2: r=3; g=3; b=2; a=8; break;
5442  case D3DFMT_X4R4G4B4: r=4; g=4; b=4; a=0; break;
5443  case D3DFMT_A2B10G10R10: r=10;g=10;b=10;a=2; break;
5444  case D3DFMT_A8P8: index=8; a=8; break;
5445  case D3DFMT_P8: index=8; a=0; break;
5446  default: break;
5447  }
5448  if (index > 0) {
5449  props.set_rgb_color(0);
5450  props.set_indexed_color(1);
5451  props.set_color_bits(index);
5452  } else if (r + g + b > 0) {
5453  props.set_rgb_color(1);
5454  props.set_indexed_color(0);
5455  props.set_rgba_bits(r, g, b, a);
5456  }
5457  props.set_alpha_bits(a);
5458 
5459  int depth=0;
5460  int stencil=0;
5461  switch (dformat) {
5462  case D3DFMT_D32: depth=32; stencil=0; break;
5463  case D3DFMT_D15S1: depth=15; stencil=1; break;
5464  case D3DFMT_D24S8: depth=24; stencil=8; break;
5465  case D3DFMT_D16: depth=16; stencil=0; break;
5466  case D3DFMT_D24X8: depth=24; stencil=0; break;
5467  case D3DFMT_D24X4S4: depth=24; stencil=4; break;
5468  default: break;
5469  }
5470  props.set_depth_bits(depth);
5471  props.set_stencil_bits(stencil);
5472  if (multisampletype == D3DMULTISAMPLE_NONMASKABLE) {
5473  props.set_multisamples(2);
5474  } else {
5475  props.set_multisamples(multisampletype);
5476  }
5477  return props;
5478 }
5479 
5480 
5481 #define GAMMA_1 (255.0 * 256.0)
5482 
5483 static bool _gamma_table_initialized = false;
5484 static unsigned short _orignial_gamma_table [256 * 3];
5485 
5486 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) {
5487  int i;
5488  double gamma_correction;
5489 
5490  if (gamma <= 0.0) {
5491  // avoid divide by zero and negative exponents
5492  gamma = 1.0;
5493  }
5494  gamma_correction = 1.0 / (double) gamma;
5495 
5496  for (i = 0; i < 256; i++) {
5497  double r;
5498  double g;
5499  double b;
5500 
5501  if (original_red_table) {
5502  r = (double) original_red_table [i] / GAMMA_1;
5503  g = (double) original_green_table [i] / GAMMA_1;
5504  b = (double) original_blue_table [i] / GAMMA_1;
5505  }
5506  else {
5507  r = ((double) i / 255.0);
5508  g = r;
5509  b = r;
5510  }
5511 
5512  r = pow (r, gamma_correction);
5513  g = pow (g, gamma_correction);
5514  b = pow (b, gamma_correction);
5515 
5516  if (r > 1.00) {
5517  r = 1.0;
5518  }
5519  if (g > 1.00) {
5520  g = 1.0;
5521  }
5522  if (b > 1.00) {
5523  b = 1.0;
5524  }
5525 
5526  r = r * GAMMA_1;
5527  g = g * GAMMA_1;
5528  b = b * GAMMA_1;
5529 
5530  red_table [i] = r;
5531  green_table [i] = g;
5532  blue_table [i] = b;
5533  }
5534 }
5535 
5536 ////////////////////////////////////////////////////////////////////
5537 // Function: DXGraphicsStateGuardian9::get_gamma_table
5538 // Access: Public, Static
5539 // Description: Static function for getting the original gamma.
5540 ////////////////////////////////////////////////////////////////////
5543  bool get;
5544 
5545  get = false;
5546  if (_gamma_table_initialized == false) {
5547  HDC hdc = GetDC(NULL);
5548 
5549  if (hdc) {
5550  if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) {
5551  _gamma_table_initialized = true;
5552  get = true;
5553  }
5554 
5555  ReleaseDC (NULL, hdc);
5556  }
5557  }
5558 
5559  return get;
5560 }
5561 
5562 ////////////////////////////////////////////////////////////////////
5563 // Function: DXGraphicsStateGuardian9::static_set_gamma
5564 // Access: Public, Static
5565 // Description: Static function for setting gamma which is needed
5566 // for atexit.
5567 ////////////////////////////////////////////////////////////////////
5569 static_set_gamma(bool restore, PN_stdfloat gamma) {
5570  bool set;
5571  HDC hdc = GetDC(NULL);
5572 
5573  set = false;
5574  if (hdc) {
5575  unsigned short ramp [256 * 3];
5576 
5577  if (restore && _gamma_table_initialized) {
5578  _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]);
5579  }
5580  else {
5581  _create_gamma_table (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]);
5582  }
5583 
5584  if (SetDeviceGammaRamp (hdc, ramp)) {
5585  set = true;
5586  }
5587 
5588  ReleaseDC (NULL, hdc);
5589  }
5590 
5591  return set;
5592 }
5593 
5594 ////////////////////////////////////////////////////////////////////
5595 // Function: DXGraphicsStateGuardian9::set_gamma
5596 // Access: Published
5597 // Description: Non static version of setting gamma. Returns true
5598 // on success.
5599 ////////////////////////////////////////////////////////////////////
5601 set_gamma(PN_stdfloat gamma) {
5602  bool set;
5603 
5604  set = static_set_gamma(false, gamma);
5605  if (set) {
5606  _gamma = gamma;
5607  }
5608 
5609  return set;
5610 }
5611 
5612 ////////////////////////////////////////////////////////////////////
5613 // Function: DXGraphicsStateGuardian9::restore_gamma
5614 // Access: Published
5615 // Description: Restore original gamma.
5616 ////////////////////////////////////////////////////////////////////
5619  static_set_gamma(true, 1.0f);
5620 }
5621 
5622 ////////////////////////////////////////////////////////////////////
5623 // Function: DXGraphicsStateGuardian9::atexit_function
5624 // Access: Public, Static
5625 // Description: This function is passed to the atexit function.
5626 ////////////////////////////////////////////////////////////////////
5629  set_cg_device(NULL);
5630  static_set_gamma(true, 1.0f);
5631 }
5632 
5633 ////////////////////////////////////////////////////////////////////
5634 // Function: DXGraphicsStateGuardian9::get_supports_cg_profile
5635 // Access: Public, Virtual
5636 // Description: Returns true if this particular GSG supports the
5637 // specified Cg Shader Profile.
5638 ////////////////////////////////////////////////////////////////////
5640 get_supports_cg_profile(const string &name) const {
5641 #ifndef HAVE_CG
5642  return false;
5643 #else
5644  CGprofile profile = cgGetProfile(name.c_str());
5645 
5646  if (profile == CG_PROFILE_UNKNOWN) {
5647  dxgsg9_cat.error() << name <<", unknown Cg-profile\n";
5648  return false;
5649  }
5650  return cgD3D9IsProfileSupported(cgGetProfile(name.c_str())) != 0;
5651 #endif // HAVE_CG
5652 }
5653 
5654 ////////////////////////////////////////////////////////////////////
5655 // Function: DXGraphicsStateGuardian9::set_cg_device
5656 // Access: Protected, Static
5657 // Description: Sets the global Cg device pointer. TODO: make this
5658 // thread-safe somehow. Maybe Cg is inherently not
5659 // thread-safe.
5660 ////////////////////////////////////////////////////////////////////
5662 set_cg_device(LPDIRECT3DDEVICE9 cg_device) {
5663 #ifdef HAVE_CG
5664  if (_cg_device != cg_device) {
5665  cgD3D9SetDevice(cg_device);
5666  _cg_device = cg_device;
5667  }
5668 #endif // HAVE_CG
5669 }
5670 
5671 typedef string KEY;
5672 
5673 typedef struct _KEY_ELEMENT
5674 {
5675  KEY key;
5676  int count;
5677  int secondary_count;
5678 
5679  struct _KEY_ELEMENT *next;
5680 }
5681 KEY_ELEMENT;
5682 
5683 typedef struct _KEY_LIST
5684 {
5685  int total_key_elements;
5686  KEY_ELEMENT *key_element;
5687 }
5688 KEY_LIST;
5689 
5690 KEY_ELEMENT *new_key_element (KEY key, KEY_LIST *key_list)
5691 {
5692  KEY_ELEMENT *key_element;
5693 
5694  key_element = new KEY_ELEMENT;
5695  key_element -> key = key;
5696  key_element -> count = 1;
5697  key_element -> secondary_count = 0;
5698  key_element -> next = 0;
5699 
5700  key_list -> total_key_elements++;
5701 
5702  return key_element;
5703 }
5704 
5705 KEY_ELEMENT *first_key_element (KEY_LIST *key_list)
5706 {
5707  return key_list -> key_element;
5708 }
5709 
5710 KEY_ELEMENT *next_key_element (KEY_ELEMENT *key_element)
5711 {
5712  return key_element -> next;
5713 }
5714 
5715 void delete_key_list (KEY_LIST *key_list)
5716 {
5717  if (key_list)
5718  {
5719  KEY_ELEMENT *key_element;
5720  KEY_ELEMENT *key_element_next;
5721 
5722  key_element = first_key_element (key_list);
5723  while (key_element)
5724  {
5725  key_element_next = next_key_element (key_element);
5726  delete key_element;
5727  key_element = key_element_next;
5728  }
5729 
5730  delete key_list;
5731  }
5732 }
5733 
5734 KEY_LIST *new_key_list (void)
5735 {
5736  KEY_LIST *key_list;
5737 
5738  key_list = new KEY_LIST;
5739  memset (key_list, 0, sizeof (KEY_LIST));
5740 
5741  return key_list;
5742 }
5743 
5744 KEY_ELEMENT *add_to_key_list (KEY key, KEY_LIST *key_list)
5745 {
5746  KEY_ELEMENT *key_element;
5747  KEY_ELEMENT *last_key_element;
5748  KEY_ELEMENT *current_key_element;
5749 
5750  key_element = 0;
5751  last_key_element = 0;
5752  current_key_element = key_list -> key_element;
5753  if (current_key_element == 0)
5754  {
5755  key_element = new_key_element (key, key_list);
5756  key_list -> key_element = key_element;
5757  }
5758  else
5759  {
5760  while (current_key_element)
5761  {
5762  if (key < current_key_element -> key)
5763  {
5764  key_element = new_key_element (key, key_list);
5765  key_element -> next = current_key_element;
5766 
5767  if (last_key_element == 0)
5768  {
5769  key_list -> key_element = key_element;
5770  }
5771  else
5772  {
5773  last_key_element -> next = key_element;
5774  }
5775  break;
5776  }
5777  else
5778  {
5779  if (key > current_key_element -> key)
5780  {
5781  if (current_key_element -> next == 0)
5782  {
5783  key_element = new_key_element (key, key_list);
5784  current_key_element -> next = key_element;
5785  break;
5786  }
5787  else
5788  {
5789 
5790  }
5791  }
5792  else
5793  {
5794  current_key_element -> count++;
5795  break;
5796  }
5797  }
5798 
5799  last_key_element = current_key_element;
5800  current_key_element = current_key_element -> next;
5801  }
5802  }
5803 
5804  return key_element;
5805 }
CombineSource get_combine_alpha_source2() const
Get source2 of combine_alpha_mode.
Definition: textureStage.I:667
void get_linear_range(PN_stdfloat &onset, PN_stdfloat &opaque)
Retrieves the current onset and offset ranges.
Definition: fog.cxx:197
virtual bool is_linear() const
Returns true if the lens represents a linear projection (e.g.
Definition: lens.cxx:615
IDirect3DTexture9 * get_d3d_2d_texture() const
Returns the Direct3D object that represents the texture, in the case of a 1-d or 2-d texture...
A light shining from infinitely far away in a particular direction, like sunlight.
static bool is_srgb(Format format)
Returns true if the indicated format is in the sRGB color space, false otherwise. ...
Definition: texture.cxx:2466
Fog * get_fog() const
If the FogAttrib is not an &#39;off&#39; FogAttrib, returns the fog that is associated.
Definition: fogAttrib.I:45
Format get_format() const
Returns the format of the texture, which represents both the semantic meaning of the texels and...
Definition: texture.I:872
Texture * get_texture() const
Returns the pointer to the associated Texture object.
int get_offset() const
Returns the depth offset represented by this attrib.
The abstract interface to all kinds of lights.
Definition: light.h:42
virtual void end_frame(Thread *current_thread)
Called after each frame is rendered, to allow the GSG a chance to do any internal cleanup after rende...
Encapsulates the data from a DisplayRegion, pre-fetched for one stage of the pipeline.
This is the base class for all three-component vectors and points.
Definition: lvecBase3.h:105
void release_shader(ShaderContext *sc)
Releases the resources allocated by prepare_shader.
const float * get_data() const
Returns the address of the first of the four data elements in the vector.
Definition: lvecBase4.h:746
int get_z_size() const
Returns the depth of the texture image in texels.
Definition: texture.I:663
Mode get_mode() const
Returns the colorBlend mode.
Mode get_mode() const
Returns the render mode.
bool get_local() const
Returns the local viewer flag.
Definition: material.I:242
bool do_framebuffer_copy_to_ram(Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb, bool inverted)
This is the implementation of framebuffer_copy_to_ram(); it adds one additional parameter, which should be true if the framebuffer is to be inverted during the copy (as in the same way it copies to texture memory).
This is a base class for GraphicsWindow (actually, GraphicsOutput) and DisplayRegion, both of which are conceptually rectangular regions into which drawing commands may be issued.
Enables or disables writing to the depth buffer.
Material * get_material() const
If the MaterialAttrib is not an &#39;off&#39; MaterialAttrib, returns the material that is associated...
Mode get_mode() const
Returns the shade mode.
virtual void clear(DrawableRegion *clearable)
Clears all of the indicated buffers to their assigned colors.
static LMatrix4f scale_mat(const LVecBase3f &scale)
Returns a matrix that applies the indicated scale in each of the three axes.
Definition: lmatrix.h:2456
LColor get_color() const
return the color for this stage
Definition: textureStage.I:238
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:45
CombineOperand get_combine_alpha_operand0() const
Get operand0 of combine_alpha_mode.
Definition: textureStage.I:637
int get_rgb_scale() const
See set_rgb_scale().
Definition: textureStage.I:264
TextureType get_texture_type() const
Returns the overall interpretation of the texture.
Definition: texture.I:859
static bool static_set_gamma(bool restore, PN_stdfloat gamma)
Static function for setting gamma which is needed for atexit.
Enables or disables writing to the color buffer.
virtual bool extract_texture_data(Texture *tex)
This method should only be called by the GraphicsEngine.
bool might_have_ram_image() const
Returns true if the texture&#39;s image contents are currently available in main RAM, or there is reason ...
Definition: texture.I:1494
void get_region_pixels_i(int &xo, int &yo, int &w, int &h) const
Similar to get_region_pixels(), but returns the upper left corner, and the pixel numbers are numbered...
Indicates which, if any, material should be applied to geometry.
This object describes how the vertex animation, if any, represented in a GeomVertexData is encoded...
bool has_ambient() const
Returns true if the ambient color has been explicitly set for this material, false otherwise...
Definition: material.I:70
Enables or disables writing to the depth buffer.
virtual void prepare_display_region(DisplayRegionPipelineReader *dr)
Makes the specified DisplayRegion current.
LPoint3 get_nodal_point() const
Returns the center point of the lens: the point from which the lens is viewing.
Definition: lens.cxx:277
virtual void end_draw_primitives()
Called after a sequence of draw_primitive() functions are called, this should do whatever cleanup is ...
PN_stdfloat get_shininess() const
Returns the shininess exponent of the material.
Definition: material.I:217
This controls the enabling of transparency.
virtual bool draw_triangles(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of disconnected triangles.
Objects of this class are used to convert vertex data from a Geom into a format suitable for passing ...
Definition: geomMunger.h:57
This is a special class object that holds all the information returned by a particular GSG to indicat...
PN_stdfloat get_clear_depth() const
Returns the current clear depth value.
unsigned int get_channels() const
Returns the mask of color channels that are enabled by this attrib.
Mode get_mode() const
Returns the transparency mode.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
void setup_texture(TextureType texture_type, int x_size, int y_size, int z_size, ComponentType component_type, Format format)
Sets the texture to the indicated type and dimensions, presumably in preparation for calling read() o...
Definition: texture.I:62
PandaCompareFunc get_mode() const
Returns the alpha write mode.
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:63
virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader, const GeomMunger *munger, const GeomVertexDataPipelineReader *data_reader, bool force)
Called before a sequence of draw_primitive() functions are called, this should prepare the vertex dat...
Specifies whether flat shading (per-polygon) or smooth shading (per-vertex) is in effect...
Definition: shader.h:50
void apply_texture(int i, TextureContext *tc, const SamplerState &sampler)
Makes the texture the currently available texture for rendering on the ith stage. ...
int get_num_transforms() const
This is only meaningful for animation_type AT_hardware.
This is a special class object that holds all the information returned by a particular GSG to indicat...
bool create_texture(DXScreenData &scrn)
Use panda texture&#39;s pixelbuffer to create a texture for the specified device.
static D3DFORMAT get_index_type(Geom::NumericType numeric_type)
Maps from the Geom&#39;s internal numeric type symbols to DirectX&#39;s.
bool get_indexed_transforms() const
This is only meaningful for animation_type AT_hardware.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:34
int get_alpha_scale() const
See set_alpha_scale().
Definition: textureStage.I:289
Caches a GeomPrimitive in the DirectX device as an index buffer.
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
bool was_simple_image_modified() const
Returns true if the texture&#39;s "simple" image has been modified since the last time mark_simple_loaded...
Mode get_mode() const
Return the mode of this stage.
Definition: textureStage.I:206
PN_stdfloat get_hfov() const
Returns the horizontal component of fov only.
Definition: lens.I:435
int get_num_combine_alpha_operands() const
Returns the number of meaningful operands that may be retrieved via get_combine_alpha_sourceN() and g...
Definition: textureStage.I:617
bool get_perspective() const
Returns the perspective flag.
virtual void set_state_and_transform(const RenderState *state, const TransformState *transform)
Simultaneously resets the render state and the transform state.
CombineOperand get_combine_rgb_operand1() const
Get operand1 of combine_rgb_mode.
Definition: textureStage.I:493
static const LVecBase3f & zero()
Returns a zero-length vector.
Definition: lvecBase3.h:382
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
Encapsulates the data from a Geom, pre-fetched for one stage of the pipeline.
Definition: geom.h:401
static const LMatrix4f & convert_mat(CoordinateSystem from, CoordinateSystem to)
Returns a matrix that transforms from the indicated coordinate system to the indicated coordinate sys...
Definition: lmatrix.cxx:656
bool has_ram_image() const
Returns true if the Texture has its image contents available in main RAM, false if it exists only in ...
Definition: texture.I:1465
ComponentType get_component_type() const
Returns the numeric interpretation of each component of the texture.
Definition: texture.I:884
PN_stdfloat get_exponent() const FINAL
Returns the exponent that controls the amount of light falloff from the center of the spotlight...
Definition: spotlight.I:50
bool has_mipmaps() const
Returns true if the texture was created with mipmaps, false otherwise.
virtual void end_scene()
Called between begin_frame() and end_frame() to mark the end of drawing commands for a "scene" (usual...
ShaderLanguage get_language() const
Returns the shader language in which this shader was written.
Definition: shader.I:154
static bool get_gamma_table(void)
Static function for getting the original gamma.
virtual bool framebuffer_copy_to_texture(Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb)
Copy the pixels within the indicated display region from the framebuffer into texture memory...
Mode get_mode() const
Returns the depth write mode.
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
CombineSource get_combine_rgb_source1() const
Get source1 of combine_rgb_mode.
Definition: textureStage.I:483
static void atexit_function(void)
This function is passed to the atexit function.
The ShaderContext is meant to contain the compiled version of a shader string.
Definition: shaderContext.h:35
const LColor & get_specular_color() const FINAL
Returns the color of specular highlights generated by the light.
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:34
void enqueue_lru(AdaptiveLru *lru)
Adds the page to the LRU for the first time, or marks it recently-accessed if it has already been add...
Lens * get_lens(int index=0) const
Returns a pointer to the particular Lens associated with this LensNode, or NULL if there is not yet a...
Definition: lensNode.I:60
Indicates which faces should be culled based on their vertex ordering.
FilterType get_effective_minfilter() const
Returns the filter mode of the texture for minification, with special treatment for FT_default...
const LColor & get_diffuse() const
Returns the diffuse color setting, if it has been set.
Definition: material.I:119
Applies a Fog to the geometry at and below this node.
Definition: fogAttrib.h:27
void set_size_padded(int x=1, int y=1, int z=1)
Changes the size of the texture, padding if necessary, and setting the pad region as well...
Definition: texture.cxx:1759
const LColor & get_ambient() const
Returns the ambient color setting, if it has been set.
Definition: material.I:82
A lightweight class that represents a single element that may be timed and/or counted via stats...
int get_num_transforms() const
Returns the number of transforms in the table.
int get_effective_anisotropic_degree() const
Returns the degree of anisotropic filtering that should be applied to the texture.
Definition: samplerState.I:257
PN_stdfloat get_thickness() const
Returns the line width or point thickness.
CombineSource get_combine_alpha_source0() const
Get source0 of combine_alpha_mode.
Definition: textureStage.I:627
bool was_modified(const GeomPrimitivePipelineReader *reader) const
Returns true if the data has been modified since the last time mark_loaded() was called.
An offscreen render buffer.
bool check_dx_allocation(HRESULT result, int allocation_size, int attempts)
This function is called after the creation of textures, vertex buffers, and index buffers to check if...
A StencilAttrib is a collection of all stencil render states.
Definition: stencilAttrib.h:32
const LVecBase4 & get_frame() const
Returns the left, right, bottom, top coordinates of the scissor frame.
Definition: scissorAttrib.I:51
bool extract_texture_data(DXScreenData &scrn)
This method will be called in the draw thread to download the texture memory&#39;s image into its ram_ima...
CombineSource get_combine_rgb_source2() const
Get source2 of combine_rgb_mode.
Definition: textureStage.I:503
void restore_gamma()
Restore original gamma.
IDirect3DBaseTexture9 * get_d3d_texture() const
Returns the Direct3D object that represents the texture, whatever kind of texture it is...
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
static void set_cg_device(LPDIRECT3DDEVICE9 cg_device)
Sets the global Cg device pointer.
const LPlane & get_plane() const
Returns the plane represented by the PlaneNode.
Definition: planeNode.I:65
virtual void reset()
Resets all internal state as if the gsg were newly created.
virtual bool draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of line strips.
const LPoint3 & get_point() const
Returns the point in space at which the light is located.
Definition: pointLight.I:102
Specifies how atmospheric fog effects are applied to geometry.
Definition: fog.h:46
const LColor & get_border_color() const
Returns the solid color of the texture&#39;s border.
Definition: samplerState.I:273
virtual void mult_matrix(LMatrix4 &result, const LMatrix4 &previous) const
Premultiplies this transform&#39;s matrix with the indicated previous matrix, so that the result is the n...
bool get_clear_color_active() const
Returns the current setting of the flag that indicates whether the color buffer should be cleared eve...
CombineOperand get_combine_rgb_operand0() const
Get operand0 of combine_rgb_mode.
Definition: textureStage.I:473
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:58
bool get_clear_depth_active() const
Returns the current setting of the flag that indicates whether the depth buffer should be cleared eve...
bool has_simple_ram_image() const
Returns true if the Texture has a "simple" image available in main RAM.
Definition: texture.I:2053
ShaderContext * prepare_shader(Shader *se)
Compile a vertex/fragment shader body.
const LColor & get_specular_color() const FINAL
Returns the color of specular highlights generated by the light.
Definition: pointLight.I:49
virtual void begin_occlusion_query()
Begins a new occlusion query.
This specialization on GeomMunger finesses vertices for DirectX rendering.
Definition: dxGeomMunger9.h:32
const LColor & get_clear_color() const
Returns the current clear color value.
AnimationType get_animation_type() const
Returns the type of animation represented by this spec.
A light originating from a single point in space, and shining in a particular direction, with a cone-shaped falloff.
Definition: spotlight.h:37
int get_num_combine_rgb_operands() const
Returns the number of meaningful operands that may be retrieved via get_combine_rgb_sourceN() and get...
Definition: textureStage.I:453
void get_region_pixels_i(int &xo, int &yo, int &w, int &h) const
Similar to get_region_pixels(), but returns the upper left corner, and the pixel numbers are numbered...
bool apply_index_buffer(IndexBufferContext *ibc, const GeomPrimitivePipelineReader *reader, bool force)
Updates the index buffer with the current data, and makes it the current index buffer for rendering...
bool has_specular() const
Returns true if the specular color has been explicitly set for this material, false otherwise...
Definition: material.I:144
bool get_clear_stencil_active() const
Returns the current setting of the flag that indicates whether the color buffer should be cleared eve...
bool set_gamma(PN_stdfloat gamma)
Non static version of setting gamma.
void set_render_to_texture(bool render_to_texture)
Sets a flag on the texture that indicates whether the texture is intended to be used as a direct-rend...
Definition: texture.I:1056
CombineMode get_combine_alpha_mode() const
Get combine_alpha_mode.
Definition: textureStage.I:605
int get_tex_view_offset() const
Returns the current setting of the tex_view_offset.
Definition: textureStage.I:349
virtual void end_frame(Thread *current_thread)
Called after each frame is rendered, to allow the GSG a chance to do any internal cleanup after rende...
virtual void end_draw_primitives()
Called after a sequence of draw_primitive() functions are called, this should do whatever cleanup is ...
const LColor & get_specular_color() const FINAL
Returns the color of specular highlights generated by the light.
Definition: spotlight.I:79
Enables or disables writing of pixel to framebuffer based on its alpha value relative to a reference ...
CombineOperand get_combine_alpha_operand1() const
Get operand1 of combine_alpha_mode.
Definition: textureStage.I:657
virtual bool update_texture(TextureContext *tc, bool force)
Ensures that the current Texture data is refreshed onto the GSG.
Defines the way an object appears in the presence of lighting.
Definition: material.h:34
const GeomVertexArrayFormat * get_array_format() const
Returns the format object that describes this array.
bool upload_data(const GeomPrimitivePipelineReader *reader, bool force)
Copies the latest data from the client store to DirectX.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
const float * get_data() const
Returns the address of the first of the nine data elements in the matrix.
Definition: lmatrix.h:1468
PN_stdfloat get_exp_density() const
Returns the density of the fog for exponential calculations.
Definition: fog.I:228
const LVecBase3 & get_attenuation() const FINAL
Returns the terms of the attenuation equation for the light.
Definition: pointLight.I:75
Represents a set of settings that indicate how a texture is sampled.
Definition: samplerState.h:39
void mark_loaded(const GeomPrimitivePipelineReader *reader)
Should be called after the IndexBufferContext has been loaded into graphics memory, this updates the internal flags for changed_size() and modified().
virtual TextureContext * prepare_texture(Texture *tex, int view)
Creates a new retained-mode representation of the given texture, and returns a newly-allocated Textur...
TextureContext * prepare_now(int view, PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the texture on the particular GSG, if it does not already exist.
Definition: texture.cxx:1815
virtual void bind_light(PointLight *light_obj, const NodePath &light, int light_id)
Called the first time a particular light has been bound to a given id within a frame, this should set up the associated hardware light with the light&#39;s properties.
PN_stdfloat get_reference_alpha() const
Returns the alpha reference value.
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
const unsigned char * get_read_pointer(bool force) const
Returns a readable pointer to the beginning of the actual data stream, or NULL if the data is not cur...
virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader, const GeomMunger *munger, const GeomVertexDataPipelineReader *data_reader, bool force)
Called before a sequence of draw_primitive() functions are called, this should prepare the vertex dat...
const VertexTransform * get_transform(int n) const
Returns the nth transform in the table.
Applies a transform matrix to UV&#39;s before they are rendered.
CompressionMode get_ram_image_compression() const
Returns the compression mode in which the ram image is already stored pre-compressed.
Definition: texture.I:1624
unsigned int get_clear_stencil() const
Returns the current clear stencil value.
const LMatrix4 & get_projection_mat(StereoChannel channel=SC_mono) const
Returns the complete transformation matrix from a 3-d point in space to a point on the film...
Definition: lens.I:717
const LVector3 & get_direction() const
Returns the direction in which the light is aimed.
virtual bool prepare_lens()
Makes the current lens (whichever lens was most recently specified with set_scene()) active...
Stores the total set of VertexTransforms that the vertices in a particular GeomVertexData object migh...
int get_num_rows() const
Returns the number of rows stored in the array, based on the number of bytes and the stride...
This specifies how colors are blended into the frame buffer, for special effects. ...
CombineMode get_combine_rgb_mode() const
Get the combine_rgb_mode.
Definition: textureStage.I:441
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:284
CombineSource get_combine_rgb_source0() const
Get source0 of combine_rgb_mode.
Definition: textureStage.I:463
void set_rgba_bits(int r, int g, int b, int a)
Convenience method for setting the red, green, blue and alpha bits in one go.
PandaCompareFunc get_mode() const
Returns the depth write mode.
virtual bool draw_lines(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of disconnected line segments.
A thread; that is, a lightweight process.
Definition: thread.h:51
void update_data_size_bytes(size_t new_data_size_bytes)
Should be called (usually by a derived class) when the on-card size of this object has changed...
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
virtual void prepare_display_region(DisplayRegionPipelineReader *dr)
Prepare a display region for rendering (set up scissor region and viewport)
This is a special kind of attribute that instructs the graphics driver to apply an offset or bias to ...
int get_y_size() const
Returns the height of the texture image in texels.
Definition: texture.I:650
virtual bool begin_frame(Thread *current_thread)
Called before each frame is rendered, to allow the GSG a chance to do any internal cleanup before beg...
bool involves_color_scale() const
Returns true if the TextureStage is affected by the setting of the current ColorScaleAttrib, false otherwise.
Definition: textureStage.I:689
void mark_loaded()
Should be called after the texture has been loaded into graphics memory, this updates the internal fl...
This is a special class object that holds all the information returned by a particular GSG to indicat...
Encapsulates all the communication with a particular instance of a given rendering backend...
Specifies how polygons are to be drawn.
unsigned int get_render_state(StencilRenderState render_state_identifier) const
Returns render state.
Definition: stencilAttrib.I:21
void set_active(bool flag)
Changes the active flag associated with this object.
Definition: bufferContext.I:73
bool is_off() const
Returns true if the MaterialAttrib is an &#39;off&#39; MaterialAttrib, indicating that it should disable the ...
const LColor & get_color() const
Returns the color of the fog.
Definition: fog.I:53
LVecBase4f get_col(int col) const
Retrieves the indicated column of the matrix as a 4-component vector.
Definition: lmatrix.h:1294
virtual void end_scene()
Called between begin_frame() and end_frame() to mark the end of drawing commands for a "scene" (usual...
int get_num_views() const
Returns the number of "views" in the texture.
Definition: texture.I:683
FrameBufferProperties calc_fb_properties(DWORD cformat, DWORD dformat, DWORD multisampletype, DWORD multisamplequality)
Convert DirectX framebuffer format ids into a FrameBufferProperties structure.
Specifies how polygons are to be drawn.
A rectangular subregion within a window for rendering into.
Definition: displayRegion.h:61
CombineOperand get_combine_rgb_operand2() const
Get operand2 of combine_rgb_mode.
Definition: textureStage.I:513
virtual bool draw_trifans(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of triangle fans.
Encapsulates the data from a GeomVertexData, pre-fetched for one stage of the pipeline.
const LVecBase3 & get_attenuation() const FINAL
Returns the terms of the attenuation equation for the light.
Definition: spotlight.I:105
CombineSource get_combine_alpha_source1() const
Get source1 of combine_alpha_mode.
Definition: textureStage.I:647
CombineOperand get_combine_alpha_operand2() const
Get operand2 of combine_alpha_mode.
Definition: textureStage.I:677
void set_color_bits(int n)
Sets the number of requested color bits as a single number that represents the sum of the individual ...
This restricts rendering to within a rectangular region of the scene, without otherwise affecting the...
Definition: scissorAttrib.h:41
bool uses_color() const
Returns true if the TextureStage makes use of whatever color is specified in set_color(), false otherwise.
Definition: textureStage.I:701
virtual void release_texture(TextureContext *tc)
Frees the GL resources previously allocated for the texture.
const LColor & get_color() const
Returns the basic color of the light.
Definition: light.I:70
Mode get_effective_mode() const
Returns the effective culling mode.
Returned from a GSG in response to begin_occlusion_query() .
This class is the main interface to controlling the render process.
const LColor & get_emission() const
Returns the emission color setting, if it has been set.
Definition: material.I:193
WrapMode get_wrap_w() const
Returns the wrap mode of the texture in the W direction.
Definition: samplerState.I:204
virtual bool get_supports_cg_profile(const string &name) const
Returns true if this particular GSG supports the specified Cg Shader Profile.
virtual void reset()
Resets all internal state as if the gsg were newly created.
void mark_unloaded()
Should be called after the texture has been forced out of texture memory.
virtual bool begin_scene()
Called between begin_frame() and end_frame() to mark the beginning of drawing commands for a "scene" ...
Mode get_mode() const
Returns the render mode.
virtual bool begin_frame(Thread *current_thread)
Called before each frame is rendered, to allow the GSG a chance to do any internal cleanup before beg...
void create_ibuffer(DXScreenData &scrn, const GeomPrimitivePipelineReader *reader)
Creates a new index buffer (but does not upload data to it).
virtual IndexBufferContext * prepare_index_buffer(GeomPrimitive *data)
Creates a new retained-mode representation of the given data, and returns a newly-allocated IndexBuff...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:925
bool has_diffuse() const
Returns true if the diffuse color has been explicitly set for this material, false otherwise...
Definition: material.I:107
virtual bool draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of triangle strips.
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
bool is_off() const
Returns true if the FogAttrib is an &#39;off&#39; FogAttrib, indicating that it should disable fog...
Definition: fogAttrib.I:33
Encapsulates the data from a GeomPrimitive, pre-fetched for one stage of the pipeline.
bool changed_size(const GeomPrimitivePipelineReader *reader) const
Returns true if the data has changed size since the last time mark_loaded() was called.
PN_stdfloat get_lod_bias() const
Returns the bias that will be added to the texture level of detail when sampling this texture...
Definition: samplerState.I:306
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:38
const float * get_data() const
Returns the address of the first of the three data elements in the vector.
Definition: lvecBase3.h:637
bool upload_texture(DXTextureContext9 *dtc, bool force)
Creates a texture surface on the graphics card and fills it with its pixel data.
ShaderContext * prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the shader on the particular GSG, if it does not already exist.
Definition: shader.cxx:3025
WrapMode get_wrap_v() const
Returns the wrap mode of the texture in the V direction.
Definition: samplerState.I:192
A RenderBuffer is an arbitrary subset of the various layers (depth buffer, color buffer, etc.) of a drawing region.
Definition: renderBuffer.h:30
bool was_modified() const
Returns true if the texture properties or image have been modified since the last time mark_loaded() ...
virtual bool framebuffer_copy_to_ram(Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb)
Copy the pixels within the indicated display region from the framebuffer into system memory...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
virtual bool draw_points(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of disconnected points.
const LVector3 & get_view_vector() const
Returns the axis along which the lens is facing.
Definition: lens.cxx:247
WrapMode get_wrap_u() const
Returns the wrap mode of the texture in the U direction.
Definition: samplerState.I:181
const LColor & get_specular() const
Returns the specular color setting, if it has been set.
Definition: material.I:156
A light originating from a single point in space, and shining in all directions.
Definition: pointLight.h:27
void delete_texture()
Release the surface used to store the texture.
A node that contains a plane.
Definition: planeNode.h:39
int get_data_size_bytes() const
Returns the number of bytes stored in the array.
Similar to PointerToArray, except that its contents may not be modified.
int get_x_size() const
Returns the width of the texture image in texels.
Definition: texture.I:638
This is the data for one array of a GeomVertexData structure.
virtual bool begin_scene()
Called between begin_frame() and end_frame() to mark the beginning of drawing commands for a "scene" ...
FilterType get_effective_magfilter() const
Returns the filter mode of the texture for magnification, with special treatment for FT_default...
static HRESULT d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface, bool inverted, Texture *result, int view, int z)
copies source_rect in pD3DSurf to upper left of texture
virtual void release_index_buffer(IndexBufferContext *ibc)
Frees the GL resources previously allocated for the data.
bool has_uncompressed_ram_image() const
Returns true if the Texture has its image contents available in main RAM and is uncompressed, false otherwise.
Definition: texture.I:1478
bool get_saved_result() const
Returns the current setting of the saved_result flag.
Definition: textureStage.I:321