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