Panda3D
graphicsStateGuardian.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file graphicsStateGuardian.cxx
10  * @author drose
11  * @date 1999-02-02
12  * @author fperazzi, PandaSE
13  * @date 2010-05-05
14  * _max_2d_texture_array_layers, _supports_2d_texture_array,
15  * get_supports_cg_profile)
16  */
17 
18 #include "graphicsStateGuardian.h"
19 #include "graphicsEngine.h"
20 #include "config_display.h"
21 #include "textureContext.h"
22 #include "vertexBufferContext.h"
23 #include "indexBufferContext.h"
24 #include "renderBuffer.h"
25 #include "light.h"
26 #include "planeNode.h"
27 #include "throw_event.h"
28 #include "clockObject.h"
29 #include "pStatTimer.h"
30 #include "pStatGPUTimer.h"
31 #include "geomTristrips.h"
32 #include "geomTrifans.h"
33 #include "geomLinestrips.h"
34 #include "colorWriteAttrib.h"
35 #include "shader.h"
36 #include "pnotify.h"
37 #include "drawableRegion.h"
38 #include "displayRegion.h"
39 #include "graphicsOutput.h"
40 #include "texturePool.h"
41 #include "geomMunger.h"
42 #include "stateMunger.h"
43 #include "ambientLight.h"
44 #include "directionalLight.h"
45 #include "pointLight.h"
46 #include "sphereLight.h"
47 #include "spotlight.h"
48 #include "textureReloadRequest.h"
49 #include "shaderAttrib.h"
50 #include "materialAttrib.h"
51 #include "depthWriteAttrib.h"
52 #include "lightAttrib.h"
53 #include "texGenAttrib.h"
54 #include "shaderGenerator.h"
55 #include "lightLensNode.h"
56 #include "colorAttrib.h"
57 #include "colorScaleAttrib.h"
58 #include "clipPlaneAttrib.h"
59 #include "fogAttrib.h"
60 #include "config_pstatclient.h"
61 
62 #include <limits.h>
63 
64 using std::string;
65 
66 PStatCollector GraphicsStateGuardian::_vertex_buffer_switch_pcollector("Buffer switch:Vertex");
67 PStatCollector GraphicsStateGuardian::_index_buffer_switch_pcollector("Buffer switch:Index");
68 PStatCollector GraphicsStateGuardian::_shader_buffer_switch_pcollector("Buffer switch:Shader");
69 PStatCollector GraphicsStateGuardian::_load_vertex_buffer_pcollector("Draw:Transfer data:Vertex buffer");
70 PStatCollector GraphicsStateGuardian::_load_index_buffer_pcollector("Draw:Transfer data:Index buffer");
71 PStatCollector GraphicsStateGuardian::_load_shader_buffer_pcollector("Draw:Transfer data:Shader buffer");
72 PStatCollector GraphicsStateGuardian::_create_vertex_buffer_pcollector("Draw:Transfer data:Create Vertex buffer");
73 PStatCollector GraphicsStateGuardian::_create_index_buffer_pcollector("Draw:Transfer data:Create Index buffer");
74 PStatCollector GraphicsStateGuardian::_create_shader_buffer_pcollector("Draw:Transfer data:Create Shader buffer");
75 PStatCollector GraphicsStateGuardian::_load_texture_pcollector("Draw:Transfer data:Texture");
76 PStatCollector GraphicsStateGuardian::_data_transferred_pcollector("Data transferred");
77 PStatCollector GraphicsStateGuardian::_texmgrmem_total_pcollector("Texture manager");
78 PStatCollector GraphicsStateGuardian::_texmgrmem_resident_pcollector("Texture manager:Resident");
79 PStatCollector GraphicsStateGuardian::_primitive_batches_pcollector("Primitive batches");
80 PStatCollector GraphicsStateGuardian::_primitive_batches_tristrip_pcollector("Primitive batches:Triangle strips");
81 PStatCollector GraphicsStateGuardian::_primitive_batches_trifan_pcollector("Primitive batches:Triangle fans");
82 PStatCollector GraphicsStateGuardian::_primitive_batches_tri_pcollector("Primitive batches:Triangles");
83 PStatCollector GraphicsStateGuardian::_primitive_batches_patch_pcollector("Primitive batches:Patches");
84 PStatCollector GraphicsStateGuardian::_primitive_batches_other_pcollector("Primitive batches:Other");
85 PStatCollector GraphicsStateGuardian::_vertices_tristrip_pcollector("Vertices:Triangle strips");
86 PStatCollector GraphicsStateGuardian::_vertices_trifan_pcollector("Vertices:Triangle fans");
87 PStatCollector GraphicsStateGuardian::_vertices_tri_pcollector("Vertices:Triangles");
88 PStatCollector GraphicsStateGuardian::_vertices_patch_pcollector("Vertices:Patches");
89 PStatCollector GraphicsStateGuardian::_vertices_other_pcollector("Vertices:Other");
90 PStatCollector GraphicsStateGuardian::_state_pcollector("State changes");
91 PStatCollector GraphicsStateGuardian::_transform_state_pcollector("State changes:Transforms");
92 PStatCollector GraphicsStateGuardian::_texture_state_pcollector("State changes:Textures");
93 PStatCollector GraphicsStateGuardian::_draw_primitive_pcollector("Draw:Primitive:Draw");
94 PStatCollector GraphicsStateGuardian::_draw_set_state_pcollector("Draw:Set State");
95 PStatCollector GraphicsStateGuardian::_flush_pcollector("Draw:Flush");
96 PStatCollector GraphicsStateGuardian::_compute_dispatch_pcollector("Draw:Compute dispatch");
97 
98 PStatCollector GraphicsStateGuardian::_wait_occlusion_pcollector("Wait:Occlusion");
99 PStatCollector GraphicsStateGuardian::_wait_timer_pcollector("Wait:Timer Queries");
100 PStatCollector GraphicsStateGuardian::_timer_queries_pcollector("Timer queries");
101 PStatCollector GraphicsStateGuardian::_command_latency_pcollector("Command latency");
102 
103 PStatCollector GraphicsStateGuardian::_prepare_pcollector("Draw:Prepare");
104 PStatCollector GraphicsStateGuardian::_prepare_texture_pcollector("Draw:Prepare:Texture");
105 PStatCollector GraphicsStateGuardian::_prepare_sampler_pcollector("Draw:Prepare:Sampler");
106 PStatCollector GraphicsStateGuardian::_prepare_geom_pcollector("Draw:Prepare:Geom");
107 PStatCollector GraphicsStateGuardian::_prepare_shader_pcollector("Draw:Prepare:Shader");
108 PStatCollector GraphicsStateGuardian::_prepare_vertex_buffer_pcollector("Draw:Prepare:Vertex buffer");
109 PStatCollector GraphicsStateGuardian::_prepare_index_buffer_pcollector("Draw:Prepare:Index buffer");
110 PStatCollector GraphicsStateGuardian::_prepare_shader_buffer_pcollector("Draw:Prepare:Shader buffer");
111 
112 PStatCollector GraphicsStateGuardian::_draw_set_state_transform_pcollector("Draw:Set State:Transform");
113 PStatCollector GraphicsStateGuardian::_draw_set_state_alpha_test_pcollector("Draw:Set State:Alpha test");
114 PStatCollector GraphicsStateGuardian::_draw_set_state_antialias_pcollector("Draw:Set State:Antialias");
115 PStatCollector GraphicsStateGuardian::_draw_set_state_clip_plane_pcollector("Draw:Set State:Clip plane");
116 PStatCollector GraphicsStateGuardian::_draw_set_state_color_pcollector("Draw:Set State:Color");
117 PStatCollector GraphicsStateGuardian::_draw_set_state_cull_face_pcollector("Draw:Set State:Cull face");
118 PStatCollector GraphicsStateGuardian::_draw_set_state_depth_offset_pcollector("Draw:Set State:Depth offset");
119 PStatCollector GraphicsStateGuardian::_draw_set_state_depth_test_pcollector("Draw:Set State:Depth test");
120 PStatCollector GraphicsStateGuardian::_draw_set_state_depth_write_pcollector("Draw:Set State:Depth write");
121 PStatCollector GraphicsStateGuardian::_draw_set_state_render_mode_pcollector("Draw:Set State:Render mode");
122 PStatCollector GraphicsStateGuardian::_draw_set_state_rescale_normal_pcollector("Draw:Set State:Rescale normal");
123 PStatCollector GraphicsStateGuardian::_draw_set_state_shade_model_pcollector("Draw:Set State:Shade model");
124 PStatCollector GraphicsStateGuardian::_draw_set_state_blending_pcollector("Draw:Set State:Blending");
125 PStatCollector GraphicsStateGuardian::_draw_set_state_shader_pcollector("Draw:Set State:Shader");
126 PStatCollector GraphicsStateGuardian::_draw_set_state_shader_parameters_pcollector("Draw:Set State:Shader Parameters");
127 PStatCollector GraphicsStateGuardian::_draw_set_state_texture_pcollector("Draw:Set State:Texture");
128 PStatCollector GraphicsStateGuardian::_draw_set_state_tex_matrix_pcollector("Draw:Set State:Tex matrix");
129 PStatCollector GraphicsStateGuardian::_draw_set_state_tex_gen_pcollector("Draw:Set State:Tex gen");
130 PStatCollector GraphicsStateGuardian::_draw_set_state_material_pcollector("Draw:Set State:Material");
131 PStatCollector GraphicsStateGuardian::_draw_set_state_light_pcollector("Draw:Set State:Light");
132 PStatCollector GraphicsStateGuardian::_draw_set_state_stencil_pcollector("Draw:Set State:Stencil");
133 PStatCollector GraphicsStateGuardian::_draw_set_state_fog_pcollector("Draw:Set State:Fog");
134 PStatCollector GraphicsStateGuardian::_draw_set_state_scissor_pcollector("Draw:Set State:Scissor");
135 
136 PT(TextureStage) GraphicsStateGuardian::_alpha_scale_texture_stage = nullptr;
137 
138 TypeHandle GraphicsStateGuardian::_type_handle;
139 
140 /**
141  *
142  */
143 
144 GraphicsStateGuardian::
145 GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
146  GraphicsEngine *engine, GraphicsPipe *pipe) :
147  _internal_coordinate_system(internal_coordinate_system),
148  _pipe(pipe),
149  _engine(engine)
150 {
151  _coordinate_system = CS_invalid;
152  _internal_transform = TransformState::make_identity();
153 
154  if (_internal_coordinate_system == CS_default) {
155  _internal_coordinate_system = get_default_coordinate_system();
156  }
157 
158  set_coordinate_system(get_default_coordinate_system());
159 
160  _data_reader = nullptr;
161  _current_display_region = nullptr;
162  _current_stereo_channel = Lens::SC_mono;
163  _current_tex_view_offset = 0;
164  _current_lens = nullptr;
165  _projection_mat = TransformState::make_identity();
166  _projection_mat_inv = TransformState::make_identity();
167 
168  _needs_reset = true;
169  _is_valid = false;
170  _current_properties = nullptr;
171  _closing_gsg = false;
172  _active = true;
173  _prepared_objects = new PreparedGraphicsObjects;
174  _stereo_buffer_mask = ~0;
175  _incomplete_render = allow_incomplete_render;
176  _effective_incomplete_render = false;
177  _loader = Loader::get_global_ptr();
178 
179  _is_hardware = false;
180  _prefers_triangle_strips = false;
181  _max_vertices_per_array = INT_MAX;
182  _max_vertices_per_primitive = INT_MAX;
183 
184  // Initially, we set this to 1 (the default--no multitexturing supported).
185  // A derived GSG may set this differently if it supports multitexturing.
186  _max_texture_stages = 1;
187 
188  // Also initially, we assume there are no limits on texture sizes, and that
189  // 3-d and cube-map textures are not supported.
190  _max_texture_dimension = -1;
191  _max_3d_texture_dimension = 0;
192  _max_2d_texture_array_layers = 0;
193  _max_cube_map_dimension = 0;
194  _max_buffer_texture_size = 0;
195 
196  // Assume we don't support these fairly advanced texture combiner modes.
197  _supports_texture_combine = false;
198  _supports_texture_saved_result = false;
199  _supports_texture_dot3 = false;
200 
201  _supports_3d_texture = false;
202  _supports_2d_texture_array = false;
203  _supports_cube_map = false;
204  _supports_buffer_texture = false;
205  _supports_cube_map_array = false;
206  _supports_tex_non_pow2 = false;
207  _supports_texture_srgb = false;
208  _supports_compressed_texture = false;
209  _compressed_texture_formats.clear();
210  _compressed_texture_formats.set_bit(Texture::CM_off);
211 
212  // Assume no limits on number of lights or clip planes.
213  _max_lights = -1;
214  _max_clip_planes = -1;
215 
216  // Assume no vertex blending capability.
217  _max_vertex_transforms = 0;
218  _max_vertex_transform_indices = 0;
219 
220  _supports_occlusion_query = false;
221  _supports_timer_query = false;
222 
223 #ifdef DO_PSTATS
224  _timer_queries_active = false;
225  _last_query_frame = 0;
226  _last_num_queried = 0;
227  // _timer_delta = 0.0;
228 
229  _pstats_gpu_thread = -1;
230 #endif
231 
232  // Initially, we set this to false; a GSG that knows it has this property
233  // should set it to true.
234  _copy_texture_inverted = false;
235 
236  // Similarly with these capabilities flags.
237  _supports_multisample = false;
238  _supports_generate_mipmap = false;
239  _supports_depth_texture = false;
240  _supports_depth_stencil = false;
241  _supports_shadow_filter = false;
242  _supports_sampler_objects = false;
243  _supports_basic_shaders = false;
244  _supports_geometry_shaders = false;
245  _supports_tessellation_shaders = false;
246  _supports_compute_shaders = false;
247  _supports_glsl = false;
248  _supports_hlsl = false;
249 
250  _supports_stencil = false;
251  _supports_stencil_wrap = false;
252  _supports_two_sided_stencil = false;
253  _supports_geometry_instancing = false;
254  _supports_indirect_draw = false;
255 
256  // We are safe assuming it has luminance support
257  _supports_luminance_texture = true;
258 
259  // Assume a maximum of 1 render target in absence of MRT.
260  _max_color_targets = 1;
261  _supports_dual_source_blending = false;
262 
263  _supported_geom_rendering = 0;
264 
265  // If this is true, then we can apply a color andor color scale by twiddling
266  // the material andor ambient light (which could mean enabling lighting even
267  // without a LightAttrib).
268  _color_scale_via_lighting = color_scale_via_lighting;
269 
270  // Similarly for applying a texture to achieve uniform alpha scaling.
271  _alpha_scale_via_texture = alpha_scale_via_texture;
272 
273  // Few GSG's can do this, since it requires touching each vertex as it is
274  // rendered.
275  _runtime_color_scale = false;
276 
277  // The default is no shader support.
278  _auto_detect_shader_model = SM_00;
279  _shader_model = SM_00;
280 
281  _gamma = 1.0f;
282  _texture_quality_override = Texture::QL_default;
283 
284  // Give it a unique identifier. Unlike a pointer, we can guarantee that
285  // this value will never be reused.
286  static size_t next_index = 0;
287  _id = next_index++;
288 }
289 
290 /**
291  *
292  */
293 GraphicsStateGuardian::
294 ~GraphicsStateGuardian() {
295  remove_gsg(this);
297 
298  // Remove the munged states for this GSG. This requires going through all
299  // states, although destructing a GSG should be rare enough for this not to
300  // matter too much.
301  // Note that if uniquify-states is false, we can't iterate over all the
302  // states, and some GSGs will linger. Let's hope this isn't a problem.
303  LightReMutexHolder holder(*RenderState::_states_lock);
304  size_t size = RenderState::_states->get_num_entries();
305  for (size_t si = 0; si < size; ++si) {
306  const RenderState *state = RenderState::_states->get_key(si);
307  state->_mungers.remove(_id);
308  state->_munged_states.remove(_id);
309  }
310 }
311 
312 /**
313  * Returns the graphics engine that created this GSG. Since there is normally
314  * only one GraphicsEngine object in an application, this is usually the same
315  * as the global GraphicsEngine.
316  */
318 get_engine() const {
319  nassertr(_engine != nullptr, GraphicsEngine::get_global_ptr());
320  return _engine;
321 }
322 
323 /**
324  * Returns true if this particular GSG supports using the multisample bits to
325  * provide antialiasing, and also supports M_multisample and
326  * M_multisample_mask transparency modes. If this is not true for a
327  * particular GSG, Panda will map the M_multisample modes to M_binary.
328  *
329  * This method is declared virtual solely so that it can be queried from
330  * cullResult.cxx.
331  */
333 get_supports_multisample() const {
334  return _supports_multisample;
335 }
336 
337 /**
338  * Returns the union of Geom::GeomRendering values that this particular GSG
339  * can support directly. If a Geom needs to be rendered that requires some
340  * additional properties, the StandardMunger and/or the CullableObject will
341  * convert it as needed.
342  *
343  * This method is declared virtual solely so that it can be queried from
344  * cullableObject.cxx.
345  */
348  return _supported_geom_rendering;
349 }
350 
351 /**
352  * Returns true if this particular GSG supports the specified Cg Shader
353  * Profile.
354  */
356 get_supports_cg_profile(const string &name) const {
357  return false;
358 }
359 
360 /**
361  * Changes the coordinate system in effect on this particular gsg. This is
362  * also called the "external" coordinate system, since it is the coordinate
363  * system used by the scene graph, external to to GSG.
364  *
365  * Normally, this will be the default coordinate system, but it might be set
366  * differently at runtime. It will automatically be copied from the current
367  * lens's coordinate system as each DisplayRegion is rendered.
368  */
370 set_coordinate_system(CoordinateSystem cs) {
371  if (cs == CS_default) {
372  cs = get_default_coordinate_system();
373  }
374  if (_coordinate_system == cs) {
375  return;
376  }
377  _coordinate_system = cs;
378 
379  // Changing the external coordinate system changes the cs_transform.
380  if (_internal_coordinate_system == CS_default ||
381  _internal_coordinate_system == _coordinate_system) {
382  _cs_transform = TransformState::make_identity();
383  _inv_cs_transform = TransformState::make_identity();
384 
385  } else {
386  _cs_transform =
387  TransformState::make_mat
388  (LMatrix4::convert_mat(_coordinate_system,
389  _internal_coordinate_system));
390  _inv_cs_transform =
391  TransformState::make_mat
392  (LMatrix4::convert_mat(_internal_coordinate_system,
393  _coordinate_system));
394  }
395 }
396 
397 /**
398  * Returns the coordinate system used internally by the GSG. This may be the
399  * same as the external coordinate system reported by get_coordinate_system(),
400  * or it may be something different.
401  *
402  * In any case, vertices that have been transformed before being handed to the
403  * GSG (that is, vertices with a contents value of C_clip_point) will be
404  * expected to be in this coordinate system.
405  */
406 CoordinateSystem GraphicsStateGuardian::
408  return _internal_coordinate_system;
409 }
410 
411 /**
412  * Returns the set of texture and geom objects that have been prepared with
413  * this GSG (and possibly other GSG's that share objects).
414  */
417  return _prepared_objects;
418 }
419 
420 /**
421  * Set gamma. Returns true on success.
422  */
424 set_gamma(PN_stdfloat gamma) {
425  _gamma = gamma;
426 
427  return false;
428 }
429 
430 /**
431  * Get the current gamma setting.
432  */
433 PN_stdfloat GraphicsStateGuardian::
434 get_gamma() const {
435  return _gamma;
436 }
437 
438 /**
439  * Restore original gamma setting.
440  */
442 restore_gamma() {
443 }
444 
445 /**
446  * Calls the indicated function on all currently-prepared textures, or until
447  * the callback function returns false.
448  */
450 traverse_prepared_textures(GraphicsStateGuardian::TextureCallback *func,
451  void *callback_arg) {
452  ReMutexHolder holder(_prepared_objects->_lock);
453  PreparedGraphicsObjects::Textures::const_iterator ti;
454  for (ti = _prepared_objects->_prepared_textures.begin();
455  ti != _prepared_objects->_prepared_textures.end();
456  ++ti) {
457  bool result = (*func)(*ti, callback_arg);
458  if (!result) {
459  return;
460  }
461  }
462 }
463 
464 /**
465  * Sets the "flash texture". This is a debug feature; when enabled, the
466  * specified texture will begin flashing in the scene, helping you to find it
467  * visually.
468  *
469  * The texture also flashes with a color code: blue for mipmap level 0, yellow
470  * for mipmap level 1, and red for mipmap level 2 or higher (even for textures
471  * that don't have mipmaps). This gives you an idea of the choice of the
472  * texture size. If it is blue, the texture is being drawn the proper size or
473  * magnified; if it is yellow, it is being minified a little bit; and if it
474  * red, it is being minified considerably. If you see a red texture when you
475  * are right in front of it, you should consider reducing the size of the
476  * texture to avoid wasting texture memory.
477  *
478  * Not all rendering backends support the flash_texture feature. Presently,
479  * it is only supported by OpenGL.
480  */
483 #ifndef NDEBUG
484  _flash_texture = tex;
485 #endif
486 }
487 
488 /**
489  * Resets the "flash texture", so that no textures will flash. See
490  * set_flash_texture().
491  */
494 #ifndef NDEBUG
495  _flash_texture = nullptr;
496 #endif
497 }
498 
499 /**
500  * Returns the current "flash texture", if any, or NULL if none. See
501  * set_flash_texture().
502  */
504 get_flash_texture() const {
505 #ifndef NDEBUG
506  return _flash_texture;
507 #else
508  return nullptr;
509 #endif
510 }
511 
512 /**
513  * Sets the SceneSetup object that indicates the initial camera position, etc.
514  * This must be called before traversal begins. Returns true if the scene is
515  * acceptable, false if something's wrong. This should be called in the draw
516  * thread only.
517  */
519 set_scene(SceneSetup *scene_setup) {
520  _scene_setup = scene_setup;
521  _current_lens = scene_setup->get_lens();
522  if (_current_lens == nullptr) {
523  return false;
524  }
525 
526  set_coordinate_system(_current_lens->get_coordinate_system());
527 
528  _projection_mat = calc_projection_mat(_current_lens);
529  if (_projection_mat == nullptr) {
530  return false;
531  }
532  _projection_mat_inv = _projection_mat->get_inverse();
533  return prepare_lens();
534 }
535 
536 /**
537  * Returns the current SceneSetup object.
538  */
540 get_scene() const {
541  return _scene_setup;
542 }
543 
544 /**
545  * Creates whatever structures the GSG requires to represent the texture
546  * internally, and returns a newly-allocated TextureContext object with this
547  * data. It is the responsibility of the calling function to later call
548  * release_texture() with this same pointer (which will also delete the
549  * pointer).
550  *
551  * This function should not be called directly to prepare a texture. Instead,
552  * call Texture::prepare().
553  */
555 prepare_texture(Texture *, int view) {
556  return nullptr;
557 }
558 
559 /**
560  * Ensures that the current Texture data is refreshed onto the GSG. This
561  * means updating the texture properties and/or re-uploading the texture
562  * image, if necessary. This should only be called within the draw thread.
563  *
564  * If force is true, this function will not return until the texture has been
565  * fully uploaded. If force is false, the function may choose to upload a
566  * simple version of the texture instead, if the texture is not fully resident
567  * (and if get_incomplete_render() is true).
568  */
571  return true;
572 }
573 
574 /**
575  * Frees the resources previously allocated via a call to prepare_texture(),
576  * including deleting the TextureContext itself, if it is non-NULL.
577  */
580 }
581 
582 /**
583  * This method should only be called by the GraphicsEngine. Do not call it
584  * directly; call GraphicsEngine::extract_texture_data() instead.
585  *
586  * This method will be called in the draw thread to download the texture
587  * memory's image into its ram_image value. It returns true on success, false
588  * otherwise.
589  */
592  return false;
593 }
594 
595 /**
596  * Creates whatever structures the GSG requires to represent the sampler
597  * internally, and returns a newly-allocated SamplerContext object with this
598  * data. It is the responsibility of the calling function to later call
599  * release_sampler() with this same pointer (which will also delete the
600  * pointer).
601  *
602  * This function should not be called directly to prepare a sampler. Instead,
603  * call Texture::prepare().
604  */
606 prepare_sampler(const SamplerState &sampler) {
607  return nullptr;
608 }
609 
610 /**
611  * Frees the resources previously allocated via a call to prepare_sampler(),
612  * including deleting the SamplerContext itself, if it is non-NULL.
613  */
616 }
617 
618 /**
619  * Prepares the indicated Geom for retained-mode rendering, by creating
620  * whatever structures are necessary in the GSG (for instance, vertex
621  * buffers). Returns the newly-allocated GeomContext that can be used to
622  * render the geom.
623  */
625 prepare_geom(Geom *) {
626  return nullptr;
627 }
628 
629 /**
630  * Frees the resources previously allocated via a call to prepare_geom(),
631  * including deleting the GeomContext itself, if it is non-NULL.
632  *
633  * This function should not be called directly to prepare a Geom. Instead,
634  * call Geom::prepare().
635  */
638 }
639 
640 /**
641  * Compile a vertex/fragment shader body.
642  */
644 prepare_shader(Shader *shader) {
645  return nullptr;
646 }
647 
648 /**
649  * Releases the resources allocated by prepare_shader
650  */
653 }
654 
655 /**
656  * Prepares the indicated buffer for retained-mode rendering.
657  */
660  return nullptr;
661 }
662 
663 /**
664  * Frees the resources previously allocated via a call to prepare_data(),
665  * including deleting the VertexBufferContext itself, if necessary.
666  */
669 }
670 
671 /**
672  * Prepares the indicated buffer for retained-mode rendering.
673  */
676  return nullptr;
677 }
678 
679 /**
680  * Frees the resources previously allocated via a call to prepare_data(),
681  * including deleting the IndexBufferContext itself, if necessary.
682  */
685 }
686 
687 /**
688  * Prepares the indicated buffer for retained-mode rendering.
689  */
692  return nullptr;
693 }
694 
695 /**
696  * Frees the resources previously allocated via a call to prepare_data(),
697  * including deleting the BufferContext itself, if necessary.
698  */
701 }
702 
703 /**
704  * Begins a new occlusion query. After this call, you may call
705  * begin_draw_primitives() and draw_triangles()/draw_whatever() repeatedly.
706  * Eventually, you should call end_occlusion_query() before the end of the
707  * frame; that will return a new OcclusionQueryContext object that will tell
708  * you how many pixels represented by the bracketed geometry passed the depth
709  * test.
710  *
711  * It is not valid to call begin_occlusion_query() between another
712  * begin_occlusion_query() .. end_occlusion_query() sequence.
713  */
716  nassertv(_current_occlusion_query == nullptr);
717 }
718 
719 /**
720  * Ends a previous call to begin_occlusion_query(). This call returns the
721  * OcclusionQueryContext object that will (eventually) report the number of
722  * pixels that passed the depth test between the call to
723  * begin_occlusion_query() and end_occlusion_query().
724  */
725 PT(OcclusionQueryContext) GraphicsStateGuardian::
726 end_occlusion_query() {
727  nassertr(_current_occlusion_query != nullptr, nullptr);
728  PT(OcclusionQueryContext) result = _current_occlusion_query;
729  _current_occlusion_query = nullptr;
730  return result;
731 }
732 
733 /**
734  * Adds a timer query to the command stream, associated with the given PStats
735  * collector index.
736  */
737 PT(TimerQueryContext) GraphicsStateGuardian::
738 issue_timer_query(int pstats_index) {
739  return nullptr;
740 }
741 
742 /**
743  * Dispatches a currently bound compute shader using the given work group
744  * counts.
745  */
747 dispatch_compute(int num_groups_x, int num_groups_y, int num_groups_z) {
748  nassert_raise("Compute shaders not supported by GSG");
749 }
750 
751 /**
752  * Looks up or creates a GeomMunger object to munge vertices appropriate to
753  * this GSG for the indicated state.
754  */
755 PT(GeomMunger) GraphicsStateGuardian::
756 get_geom_munger(const RenderState *state, Thread *current_thread) {
757  RenderState::Mungers &mungers = state->_mungers;
758 
759  if (!mungers.is_empty()) {
760  // Before we even look up the map, see if the _last_mi value points to
761  // this GSG. This is likely because we tend to visit the same state
762  // multiple times during a frame. Also, this might well be the only GSG
763  // in the world anyway.
764  int mi = state->_last_mi;
765  if (mi >= 0 && (size_t)mi < mungers.get_num_entries() && mungers.get_key(mi) == _id) {
766  PT(GeomMunger) munger = mungers.get_data(mi);
767  if (munger->is_registered()) {
768  return munger;
769  }
770  }
771 
772  // Nope, we have to look it up in the map.
773  mi = mungers.find(_id);
774  if (mi >= 0) {
775  PT(GeomMunger) munger = mungers.get_data(mi);
776  if (munger->is_registered()) {
777  state->_last_mi = mi;
778  return munger;
779  } else {
780  // This GeomMunger is no longer registered. Remove it from the map.
781  mungers.remove_element(mi);
782  }
783  }
784  }
785 
786  // Nothing in the map; create a new entry.
787  PT(GeomMunger) munger = make_geom_munger(state, current_thread);
788  nassertr(munger != nullptr && munger->is_registered(), munger);
789  nassertr(munger->is_of_type(StateMunger::get_class_type()), munger);
790 
791  state->_last_mi = mungers.store(_id, munger);
792  return munger;
793 }
794 
795 /**
796  * Creates a new GeomMunger object to munge vertices appropriate to this GSG
797  * for the indicated state.
798  */
799 PT(GeomMunger) GraphicsStateGuardian::
800 make_geom_munger(const RenderState *state, Thread *current_thread) {
801  // The default implementation returns no munger at all, but presumably,
802  // every kind of GSG needs some special munging action, so real GSG's will
803  // override this to return something more useful.
804  return nullptr;
805 }
806 
807 /**
808  * This function will compute the distance to the indicated point, assumed to
809  * be in eye coordinates, from the camera plane. The point is assumed to be
810  * in the GSG's internal coordinate system.
811  */
813 compute_distance_to(const LPoint3 &point) const {
814  switch (_internal_coordinate_system) {
815  case CS_zup_right:
816  return point[1];
817 
818  case CS_yup_right:
819  return -point[2];
820 
821  case CS_zup_left:
822  return -point[1];
823 
824  case CS_yup_left:
825  return point[2];
826 
827  default:
828  gsg_cat.error()
829  << "Invalid coordinate system in compute_distance_to: "
830  << (int)_internal_coordinate_system << "\n";
831  return 0.0f;
832  }
833 }
834 
835 /**
836  * The gsg contains a large number of useful matrices:
837  *
838  * * the world transform, * the modelview matrix, * the cs_transform, * etc,
839  * etc.
840  *
841  * A shader can request any of these values, and furthermore, it can request
842  * that various compositions, inverses, and transposes be performed. The
843  * ShaderMatSpec is a data structure indicating what datum is desired and what
844  * conversions to perform. This routine, fetch_specified_value, is
845  * responsible for doing the actual retrieval and conversions.
846  *
847  * Some values, like the following, aren't matrices:
848  *
849  * * window size * texture coordinates of card center
850  *
851  * This routine can fetch these values as well, by shoehorning them into a
852  * matrix. In this way, we avoid the need for a separate routine to fetch
853  * these values.
854  *
855  * The "altered" bits indicate what parts of the state_and_transform have
856  * changed since the last time this particular ShaderMatSpec was evaluated.
857  * This may allow data to be cached and not reevaluated.
858  *
859  */
860 const LMatrix4 *GraphicsStateGuardian::
861 fetch_specified_value(Shader::ShaderMatSpec &spec, int altered) {
862  LVecBase3 v;
863 
864  if (altered & spec._dep[0]) {
865  const LMatrix4 *t = fetch_specified_part(spec._part[0], spec._arg[0], spec._cache[0], spec._index);
866  if (t != &spec._cache[0]) {
867  spec._cache[0] = *t;
868  }
869  }
870  if (altered & spec._dep[1]) {
871  const LMatrix4 *t = fetch_specified_part(spec._part[1], spec._arg[1], spec._cache[1], spec._index);
872  if (t != &spec._cache[1]) {
873  spec._cache[1] = *t;
874  }
875  }
876 
877  switch(spec._func) {
878  case Shader::SMF_compose:
879  spec._value.multiply(spec._cache[0], spec._cache[1]);
880  return &spec._value;
881  case Shader::SMF_transform_dlight:
882  spec._value = spec._cache[0];
883  v = spec._cache[1].xform_vec(spec._cache[0].get_row3(2));
884  v.normalize();
885  spec._value.set_row(2, v);
886  v = spec._cache[1].xform_vec(spec._cache[0].get_row3(3));
887  v.normalize();
888  spec._value.set_row(3, v);
889  return &spec._value;
890  case Shader::SMF_transform_plight:
891  {
892  // Careful not to touch the w component, which contains the near value.
893  spec._value = spec._cache[0];
894  LPoint3 point = spec._cache[1].xform_point(spec._cache[0].get_row3(2));
895  spec._value(2, 0) = point[0];
896  spec._value(2, 1) = point[1];
897  spec._value(2, 2) = point[2];
898  return &spec._value;
899  }
900  case Shader::SMF_transform_slight:
901  spec._value = spec._cache[0];
902  spec._value.set_row(2, spec._cache[1].xform_point(spec._cache[0].get_row3(2)));
903  v = spec._cache[1].xform_vec(spec._cache[0].get_row3(3));
904  v.normalize();
905  spec._value.set_row(3, v);
906  return &spec._value;
907  case Shader::SMF_first:
908  return &spec._cache[0];
909  default:
910  // should never get here
911  spec._value = LMatrix4::ident_mat();
912  return &spec._value;
913  }
914 }
915 
916 /**
917  * See fetch_specified_value
918  */
919 const LMatrix4 *GraphicsStateGuardian::
920 fetch_specified_part(Shader::ShaderMatInput part, InternalName *name,
921  LMatrix4 &t, int index) {
922  switch (part) {
923  case Shader::SMO_identity: {
924  return &LMatrix4::ident_mat();
925  }
926  case Shader::SMO_window_size:
927  case Shader::SMO_pixel_size: {
928  LVecBase2i pixel_size = _current_display_region->get_pixel_size();
929  t = LMatrix4::translate_mat(pixel_size[0], pixel_size[1], 0);
930  return &t;
931  }
932  case Shader::SMO_frame_time: {
933  PN_stdfloat time = ClockObject::get_global_clock()->get_frame_time();
934  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, time, time, time, time);
935  return &t;
936  }
937  case Shader::SMO_frame_delta: {
938  PN_stdfloat dt = ClockObject::get_global_clock()->get_dt();
939  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dt, dt, dt, dt);
940  return &t;
941  }
942  case Shader::SMO_texpad_x: {
943  Texture *tex = _target_shader->get_shader_input_texture(name);
944  nassertr(tex != nullptr, &LMatrix4::zeros_mat());
945  int sx = tex->get_x_size() - tex->get_pad_x_size();
946  int sy = tex->get_y_size() - tex->get_pad_y_size();
947  int sz = tex->get_z_size() - tex->get_pad_z_size();
948  double cx = (sx * 0.5) / tex->get_x_size();
949  double cy = (sy * 0.5) / tex->get_y_size();
950  double cz = (sz * 0.5) / tex->get_z_size();
951  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cx, cy, cz, 0);
952  return &t;
953  }
954  case Shader::SMO_texpix_x: {
955  Texture *tex = _target_shader->get_shader_input_texture(name);
956  nassertr(tex != nullptr, &LMatrix4::zeros_mat());
957  double px = 1.0 / tex->get_x_size();
958  double py = 1.0 / tex->get_y_size();
959  double pz = 1.0 / tex->get_z_size();
960  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, px, py, pz, 0);
961  return &t;
962  }
963  case Shader::SMO_attr_material: {
964  const MaterialAttrib *target_material = (const MaterialAttrib *)
965  _target_rs->get_attrib_def(MaterialAttrib::get_class_slot());
966  // Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS
967  if (target_material->is_off()) {
968  t.set(1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0);
969  return &t;
970  }
971  Material *m = target_material->get_material();
972  LVecBase4 const &amb = m->get_ambient();
973  LVecBase4 const &dif = m->get_diffuse();
974  LVecBase4 const &emm = m->get_emission();
975  LVecBase4 spc = m->get_specular();
976  spc[3] = m->get_shininess();
977  t.set(amb[0], amb[1], amb[2], amb[3],
978  dif[0], dif[1], dif[2], dif[3],
979  emm[0], emm[1], emm[2], emm[3],
980  spc[0], spc[1], spc[2], spc[3]);
981  return &t;
982  }
983  case Shader::SMO_attr_material2: {
984  const MaterialAttrib *target_material = (const MaterialAttrib *)
985  _target_rs->get_attrib_def(MaterialAttrib::get_class_slot());
986  if (target_material->is_off()) {
987  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
988  return &t;
989  }
990  Material *m = target_material->get_material();
991  t.set_row(0, m->get_base_color());
992  t.set_row(3, LVecBase4(m->get_metallic(), m->get_refractive_index(), 0, m->get_roughness()));
993  return &t;
994  }
995  case Shader::SMO_attr_color: {
996  const ColorAttrib *target_color = (const ColorAttrib *)
997  _target_rs->get_attrib_def(ColorAttrib::get_class_slot());
998  if (target_color->get_color_type() != ColorAttrib::T_flat) {
999  return &LMatrix4::ones_mat();
1000  }
1001  LVecBase4 c = target_color->get_color();
1002  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]);
1003  return &t;
1004  }
1005  case Shader::SMO_attr_colorscale: {
1006  const ColorScaleAttrib *target_color = (const ColorScaleAttrib *)
1007  _target_rs->get_attrib_def(ColorScaleAttrib::get_class_slot());
1008  if (target_color->is_identity()) {
1009  return &LMatrix4::ones_mat();
1010  }
1011  LVecBase4 cs = target_color->get_scale();
1012  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cs[0], cs[1], cs[2], cs[3]);
1013  return &t;
1014  }
1015  case Shader::SMO_attr_fog: {
1016  const FogAttrib *target_fog = (const FogAttrib *)
1017  _target_rs->get_attrib_def(FogAttrib::get_class_slot());
1018  Fog *fog = target_fog->get_fog();
1019  if (fog == nullptr) {
1020  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1);
1021  return &t;
1022  }
1023  PN_stdfloat start, end;
1024  fog->get_linear_range(start, end);
1025  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1026  fog->get_exp_density(), start, end, 1.0f / (end - start));
1027  return &t;
1028  }
1029  case Shader::SMO_attr_fogcolor: {
1030  const FogAttrib *target_fog = (const FogAttrib *)
1031  _target_rs->get_attrib_def(FogAttrib::get_class_slot());
1032  Fog *fog = target_fog->get_fog();
1033  if (fog == nullptr) {
1034  return &LMatrix4::ones_mat();
1035  }
1036  LVecBase4 c = fog->get_color();
1037  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]);
1038  return &t;
1039  }
1040  case Shader::SMO_alight_x: {
1041  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1042  nassertr(!np.is_empty(), &LMatrix4::zeros_mat());
1043  AmbientLight *lt;
1044  DCAST_INTO_R(lt, np.node(), &LMatrix4::zeros_mat());
1045  LColor const &c = lt->get_color();
1046  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]);
1047  return &t;
1048  }
1049  case Shader::SMO_satten_x: {
1050  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1051  nassertr(!np.is_empty(), &LMatrix4::ones_mat());
1052  Spotlight *lt;
1053  DCAST_INTO_R(lt, np.node(), &LMatrix4::ones_mat());
1054  LVecBase3 const &a = lt->get_attenuation();
1055  PN_stdfloat x = lt->get_exponent();
1056  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a[0], a[1], a[2], x);
1057  return &t;
1058  }
1059  case Shader::SMO_dlight_x: {
1060  // The dlight matrix contains COLOR, SPECULAR, DIRECTION, PSEUDOHALFANGLE
1061  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1062  nassertr(!np.is_empty(), &LMatrix4::zeros_mat());
1063  DirectionalLight *lt;
1064  DCAST_INTO_R(lt, np.node(), &LMatrix4::zeros_mat());
1065  LColor const &c = lt->get_color();
1066  LColor const &s = lt->get_specular_color();
1067  t = np.get_net_transform()->get_mat() *
1068  _scene_setup->get_world_transform()->get_mat();
1069  LVecBase3 d = -(t.xform_vec(lt->get_direction()));
1070  d.normalize();
1071  LVecBase3 h = d + LVecBase3(0,-1,0);
1072  h.normalize();
1073  t.set(c[0], c[1], c[2], c[3],
1074  s[0], s[1], s[2], c[3],
1075  d[0], d[1], d[2], 0,
1076  h[0], h[1], h[2], 0);
1077  return &t;
1078  }
1079  case Shader::SMO_plight_x: {
1080  // The plight matrix contains COLOR, SPECULAR, POINT, ATTENUATION
1081  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1082  nassertr(!np.is_empty(), &LMatrix4::ones_mat());
1083  PointLight *lt;
1084  DCAST_INTO_R(lt, np.node(), &LMatrix4::zeros_mat());
1085  LColor const &c = lt->get_color();
1086  LColor const &s = lt->get_specular_color();
1087  t = np.get_net_transform()->get_mat() *
1088  _scene_setup->get_world_transform()->get_mat();
1089  LVecBase3 p = (t.xform_point(lt->get_point()));
1090  LVecBase3 a = lt->get_attenuation();
1091  Lens *lens = lt->get_lens(0);
1092  PN_stdfloat lnear = lens->get_near();
1093  PN_stdfloat lfar = lens->get_far();
1094  t.set(c[0], c[1], c[2], c[3],
1095  s[0], s[1], s[2], s[3],
1096  p[0], p[1], p[2], lnear,
1097  a[0], a[1], a[2], lfar);
1098  return &t;
1099  }
1100  case Shader::SMO_slight_x: {
1101  // The slight matrix contains COLOR, SPECULAR, POINT, DIRECTION
1102  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1103  nassertr(!np.is_empty(), &LMatrix4::zeros_mat());
1104  Spotlight *lt;
1105  DCAST_INTO_R(lt, np.node(), &LMatrix4::zeros_mat());
1106  Lens *lens = lt->get_lens();
1107  nassertr(lens != nullptr, &LMatrix4::zeros_mat());
1108  LColor const &c = lt->get_color();
1109  LColor const &s = lt->get_specular_color();
1110  PN_stdfloat cutoff = ccos(deg_2_rad(lens->get_hfov() * 0.5f));
1111  t = np.get_net_transform()->get_mat() *
1112  _scene_setup->get_world_transform()->get_mat();
1113  LVecBase3 p = t.xform_point(lens->get_nodal_point());
1114  LVecBase3 d = -(t.xform_vec(lens->get_view_vector()));
1115  t.set(c[0], c[1], c[2], c[3],
1116  s[0], s[1], s[2], s[3],
1117  p[0], p[1], p[2], 0,
1118  d[0], d[1], d[2], cutoff);
1119  return &t;
1120  }
1121  case Shader::SMO_light_ambient: {
1122  LColor cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f);
1123  const LightAttrib *target_light = (const LightAttrib *)
1124  _target_rs->get_attrib_def(LightAttrib::get_class_slot());
1125 
1126  if (!target_light->has_any_on_light()) {
1127  // There are no lights at all. This means, to follow the fixed-
1128  // function model, we pretend there is an all-white ambient light.
1129  t.set_row(3, LVecBase4(1, 1, 1, 1));
1130  } else {
1131  t.set_row(3, target_light->get_ambient_contribution());
1132  }
1133  return &t;
1134  }
1135  case Shader::SMO_texmat_i: {
1136  const TexMatrixAttrib *tma;
1137  const TextureAttrib *ta;
1138  if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma) &&
1139  index < ta->get_num_on_stages()) {
1140  return &tma->get_mat(ta->get_on_stage(index));
1141  } else {
1142  return &LMatrix4::ident_mat();
1143  }
1144  }
1145  case Shader::SMO_inv_texmat_i: {
1146  const TexMatrixAttrib *tma;
1147  const TextureAttrib *ta;
1148  if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma) &&
1149  index < ta->get_num_on_stages()) {
1150  t = tma->get_transform(ta->get_on_stage(index))->get_inverse()->get_mat();
1151  return &t;
1152  } else {
1153  return &LMatrix4::ident_mat();
1154  }
1155  }
1156  case Shader::SMO_texscale_i: {
1157  const TexMatrixAttrib *tma;
1158  const TextureAttrib *ta;
1159  if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma) &&
1160  index < ta->get_num_on_stages()) {
1161  LVecBase3 scale = tma->get_transform(ta->get_on_stage(index))->get_scale();
1162  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, scale[0], scale[1], scale[2], 0);
1163  return &t;
1164  } else {
1165  return &LMatrix4::ident_mat();
1166  }
1167  }
1168  case Shader::SMO_texcolor_i: {
1169  const TextureAttrib *ta;
1170  if (_target_rs->get_attrib(ta) && index < ta->get_num_on_stages()) {
1171  TextureStage *ts = ta->get_on_stage(index);
1172  t.set_row(3, ts->get_color());
1173  return &t;
1174  } else {
1175  return &LMatrix4::zeros_mat();
1176  }
1177  }
1178  case Shader::SMO_tex_is_alpha_i: {
1179  // This is a hack so we can support both F_alpha and other formats in the
1180  // default shader, to fix font rendering in GLES2
1181  const TextureAttrib *ta;
1182  if (_target_rs->get_attrib(ta) &&
1183  index < ta->get_num_on_stages()) {
1184  TextureStage *ts = ta->get_on_stage(index);
1185  PN_stdfloat v = (ta->get_on_texture(ts)->get_format() == Texture::F_alpha);
1186  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, v, v, v, 0);
1187  return &t;
1188  } else {
1189  return &LMatrix4::zeros_mat();
1190  }
1191  }
1192  case Shader::SMO_plane_x: {
1193  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1194  nassertr(!np.is_empty(), &LMatrix4::zeros_mat());
1195  const PlaneNode *plane_node;
1196  DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat());
1197  LPlane p = plane_node->get_plane();
1198  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, p[0], p[1], p[2], p[3]);
1199  return &t;
1200  }
1201  case Shader::SMO_clipplane_x: {
1202  const ClipPlaneAttrib *cpa;
1203  _target_rs->get_attrib_def(cpa);
1204  int planenr = atoi(name->get_name().c_str());
1205  if (planenr >= cpa->get_num_on_planes()) {
1206  return &LMatrix4::zeros_mat();
1207  }
1208  const NodePath &np = cpa->get_on_plane(planenr);
1209  nassertr(!np.is_empty(), &LMatrix4::zeros_mat());
1210  const PlaneNode *plane_node;
1211  DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat());
1212 
1213  // Transform plane to world space
1214  CPT(TransformState) transform = np.get_net_transform();
1215  LPlane plane = plane_node->get_plane();
1216  if (!transform->is_identity()) {
1217  plane.xform(transform->get_mat());
1218  }
1219  t.set_row(3, plane);
1220  return &t;
1221  }
1222  case Shader::SMO_apiview_clipplane_i: {
1223  const ClipPlaneAttrib *cpa;
1224  _target_rs->get_attrib_def(cpa);
1225  if (index >= cpa->get_num_on_planes()) {
1226  return &LMatrix4::zeros_mat();
1227  }
1228 
1229  const NodePath &plane = cpa->get_on_plane(index);
1230  nassertr(!plane.is_empty(), &LMatrix4::zeros_mat());
1231  const PlaneNode *plane_node;
1232  DCAST_INTO_R(plane_node, plane.node(), &LMatrix4::zeros_mat());
1233 
1234  CPT(TransformState) transform =
1235  _scene_setup->get_cs_world_transform()->compose(
1236  plane.get_transform(_scene_setup->get_scene_root().get_parent()));
1237 
1238  LPlane xformed_plane = plane_node->get_plane() * transform->get_mat();
1239  t.set_row(3, xformed_plane);
1240  return &t;
1241  }
1242  case Shader::SMO_mat_constant_x: {
1243  return &_target_shader->get_shader_input_matrix(name, t);
1244  }
1245  case Shader::SMO_vec_constant_x: {
1246  const LVecBase4 &input = _target_shader->get_shader_input_vector(name);
1247  const PN_stdfloat *data = input.get_data();
1248  t.set(data[0], data[1], data[2], data[3],
1249  data[0], data[1], data[2], data[3],
1250  data[0], data[1], data[2], data[3],
1251  data[0], data[1], data[2], data[3]);
1252  return &t;
1253  }
1254  case Shader::SMO_world_to_view: {
1255  return &(_scene_setup->get_world_transform()->get_mat());
1256  }
1257  case Shader::SMO_view_to_world: {
1258  return &(_scene_setup->get_camera_transform()->get_mat());
1259  }
1260  case Shader::SMO_model_to_view: {
1261  t = _inv_cs_transform->compose(_internal_transform)->get_mat();
1262  return &t;
1263  }
1264  case Shader::SMO_model_to_apiview: {
1265  return &(_internal_transform->get_mat());
1266  }
1267  case Shader::SMO_view_to_model: {
1268  t = _internal_transform->invert_compose(_cs_transform)->get_mat();
1269  return &t;
1270  }
1271  case Shader::SMO_apiview_to_model: {
1272  t = _internal_transform->get_inverse()->get_mat();
1273  return &t;
1274  }
1275  case Shader::SMO_apiview_to_view: {
1276  return &(_inv_cs_transform->get_mat());
1277  }
1278  case Shader::SMO_view_to_apiview: {
1279  return &(_cs_transform->get_mat());
1280  }
1281  case Shader::SMO_clip_to_view: {
1282  if (_current_lens->get_coordinate_system() == _coordinate_system) {
1283  return &(_current_lens->get_projection_mat_inv(_current_stereo_channel));
1284  } else {
1285  t = _current_lens->get_projection_mat_inv(_current_stereo_channel) *
1286  LMatrix4::convert_mat(_current_lens->get_coordinate_system(), _coordinate_system);
1287  return &t;
1288  }
1289  }
1290  case Shader::SMO_view_to_clip: {
1291  if (_current_lens->get_coordinate_system() == _coordinate_system) {
1292  return &(_current_lens->get_projection_mat(_current_stereo_channel));
1293  } else {
1294  t = LMatrix4::convert_mat(_coordinate_system, _current_lens->get_coordinate_system()) *
1295  _current_lens->get_projection_mat(_current_stereo_channel);
1296  return &t;
1297  }
1298  }
1299  case Shader::SMO_apiclip_to_view: {
1300  t = _projection_mat_inv->get_mat() * _inv_cs_transform->get_mat();
1301  return &t;
1302  }
1303  case Shader::SMO_view_to_apiclip: {
1304  t = _cs_transform->get_mat() * _projection_mat->get_mat();
1305  return &t;
1306  }
1307  case Shader::SMO_apiclip_to_apiview: {
1308  return &(_projection_mat_inv->get_mat());
1309  }
1310  case Shader::SMO_apiview_to_apiclip: {
1311  return &(_projection_mat->get_mat());
1312  }
1313  case Shader::SMO_view_x_to_view: {
1314  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1315  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1316  t = np.get_net_transform()->get_mat() *
1317  _scene_setup->get_world_transform()->get_mat();
1318  return &t;
1319  }
1320  case Shader::SMO_view_to_view_x: {
1321  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1322  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1323  t = _scene_setup->get_camera_transform()->get_mat() *
1324  np.get_net_transform()->get_inverse()->get_mat();
1325  return &t;
1326  }
1327  case Shader::SMO_apiview_x_to_view: {
1328  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1329  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1330  t = LMatrix4::convert_mat(_internal_coordinate_system, _coordinate_system) *
1331  np.get_net_transform()->get_mat() *
1332  _scene_setup->get_world_transform()->get_mat();
1333  return &t;
1334  }
1335  case Shader::SMO_view_to_apiview_x: {
1336  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1337  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1338  t = (_scene_setup->get_camera_transform()->get_mat() *
1339  np.get_net_transform()->get_inverse()->get_mat() *
1340  LMatrix4::convert_mat(_coordinate_system, _internal_coordinate_system));
1341  return &t;
1342  }
1343  case Shader::SMO_clip_x_to_view: {
1344  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1345  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1346  const LensNode *node;
1347  DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat());
1348  const Lens *lens = node->get_lens();
1349  t = lens->get_projection_mat_inv(_current_stereo_channel) *
1350  LMatrix4::convert_mat(lens->get_coordinate_system(), _coordinate_system) *
1351  np.get_net_transform()->get_mat() *
1352  _scene_setup->get_world_transform()->get_mat();
1353  return &t;
1354  }
1355  case Shader::SMO_view_to_clip_x: {
1356  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1357  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1358  const LensNode *node;
1359  DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat());
1360  const Lens *lens = node->get_lens();
1361  t = _scene_setup->get_camera_transform()->get_mat() *
1362  np.get_net_transform()->get_inverse()->get_mat() *
1363  LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system()) *
1364  lens->get_projection_mat(_current_stereo_channel);
1365  return &t;
1366  }
1367  case Shader::SMO_apiclip_x_to_view: {
1368  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1369  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1370  const LensNode *node;
1371  DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat());
1372  const Lens *lens = node->get_lens();
1373  t = calc_projection_mat(lens)->get_inverse()->get_mat() *
1374  get_cs_transform_for(lens->get_coordinate_system())->get_inverse()->get_mat() *
1375  np.get_net_transform()->get_mat() *
1376  _scene_setup->get_world_transform()->get_mat();
1377  return &t;
1378  }
1379  case Shader::SMO_view_to_apiclip_x: {
1380  const NodePath &np = _target_shader->get_shader_input_nodepath(name);
1381  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1382  const LensNode *node;
1383  DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat());
1384  const Lens *lens = node->get_lens();
1385  t = _scene_setup->get_camera_transform()->get_mat() *
1386  np.get_net_transform()->get_inverse()->get_mat() *
1387  get_cs_transform_for(lens->get_coordinate_system())->get_mat() *
1388  calc_projection_mat(lens)->get_mat();
1389  return &t;
1390  }
1391  case Shader::SMO_mat_constant_x_attrib: {
1392  if (_target_shader->has_shader_input(name)) {
1393  // There is an input specifying precisely this whole thing, with dot and
1394  // all. Support this, even if only for backward compatibility.
1395  return &_target_shader->get_shader_input_matrix(name, t);
1396  }
1397 
1398  const NodePath &np = _target_shader->get_shader_input_nodepath(name->get_parent());
1399  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1400 
1401  return fetch_specified_member(np, name->get_basename(), t);
1402  }
1403  case Shader::SMO_vec_constant_x_attrib: {
1404  if (_target_shader->has_shader_input(name)) {
1405  // There is an input specifying precisely this whole thing, with dot and
1406  // all. Support this, even if only for backward compatibility.
1407  const LVecBase4 &data = _target_shader->get_shader_input_vector(name);
1408  t.set(data[0], data[1], data[2], data[3],
1409  data[0], data[1], data[2], data[3],
1410  data[0], data[1], data[2], data[3],
1411  data[0], data[1], data[2], data[3]);
1412  return &t;
1413  }
1414 
1415  const NodePath &np = _target_shader->get_shader_input_nodepath(name->get_parent());
1416  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1417 
1418  return fetch_specified_member(np, name->get_basename(), t);
1419  }
1420  case Shader::SMO_light_source_i_attrib: {
1421  const LightAttrib *target_light;
1422  _target_rs->get_attrib_def(target_light);
1423 
1424  // We don't count ambient lights, which would be pretty silly to handle
1425  // via this mechanism.
1426  size_t num_lights = target_light->get_num_non_ambient_lights();
1427  if (index >= 0 && (size_t)index < num_lights) {
1428  NodePath light = target_light->get_on_light((size_t)index);
1429  nassertr(!light.is_empty(), &LMatrix4::ident_mat());
1430  Light *light_obj = light.node()->as_light();
1431  nassertr(light_obj != nullptr, &LMatrix4::ident_mat());
1432 
1433  return fetch_specified_member(light, name, t);
1434 
1435  } else if (index == 0) {
1436  // Apply the default OpenGL lights otherwise.
1437  // Special exception for light 0, which defaults to white.
1438  string basename = name->get_basename();
1439  return &LMatrix4::ones_mat();
1440  }
1441  return fetch_specified_member(NodePath(), name, t);
1442  }
1443  case Shader::SMO_light_source_i_packed: {
1444  // The light matrix contains COLOR, ATTENUATION, POSITION, VIEWVECTOR
1445  const LightAttrib *target_light;
1446  _target_rs->get_attrib_def(target_light);
1447 
1448  // We don't count ambient lights, which would be pretty silly to handle
1449  // via this mechanism.
1450  size_t num_lights = target_light->get_num_non_ambient_lights();
1451  if (index >= 0 && (size_t)index < num_lights) {
1452  NodePath np = target_light->get_on_light((size_t)index);
1453  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1454  PandaNode *node = np.node();
1455  Light *light = node->as_light();
1456  nassertr(light != nullptr, &LMatrix4::zeros_mat());
1457  t.set_row(0, light->get_color());
1458  t.set_row(1, light->get_attenuation());
1459 
1460  LMatrix4 mat = np.get_net_transform()->get_mat() *
1461  _scene_setup->get_world_transform()->get_mat();
1462 
1463  if (node->is_of_type(DirectionalLight::get_class_type())) {
1464  LVecBase3 d = mat.xform_vec(((const DirectionalLight *)node)->get_direction());
1465  d.normalize();
1466  t.set_row(2, LVecBase4(d, 0));
1467  t.set_row(3, LVecBase4(-d, 0));
1468 
1469  } else if (node->is_of_type(LightLensNode::get_class_type())) {
1470  const Lens *lens = ((const LightLensNode *)node)->get_lens();
1471 
1472  LPoint3 p = mat.xform_point(lens->get_nodal_point());
1473  t.set_row(3, LVecBase4(p));
1474 
1475  // For shadowed point light we need to store near/far.
1476  // For spotlight we need to store cutoff angle.
1477  if (node->is_of_type(Spotlight::get_class_type())) {
1478  PN_stdfloat cutoff = ccos(deg_2_rad(lens->get_hfov() * 0.5f));
1479  LVecBase3 d = -(mat.xform_vec(lens->get_view_vector()));
1480  t.set_cell(1, 3, ((const Spotlight *)node)->get_exponent());
1481  t.set_row(2, LVecBase4(d, cutoff));
1482 
1483  } else if (node->is_of_type(PointLight::get_class_type())) {
1484  t.set_cell(1, 3, lens->get_far());
1485  t.set_cell(3, 3, lens->get_near());
1486 
1487  if (node->is_of_type(SphereLight::get_class_type())) {
1488  t.set_cell(2, 3, ((const SphereLight *)node)->get_radius());
1489  }
1490  }
1491  }
1492  } else if (index == 0) {
1493  // Apply the default OpenGL lights otherwise.
1494  // Special exception for light 0, which defaults to white.
1495  t.set_row(0, LVecBase4(1, 1, 1, 1));
1496  }
1497  return &t;
1498  }
1499  default:
1500  nassertr(false /*should never get here*/, &LMatrix4::ident_mat());
1501  return &LMatrix4::ident_mat();
1502  }
1503 }
1504 
1505 /**
1506  * Given a NodePath passed into a shader input that is a structure, fetches
1507  * the value for the given member.
1508  */
1510 fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) {
1511  // This system is not ideal. It will be improved in the future.
1512  static const CPT_InternalName IN_color("color");
1513  static const CPT_InternalName IN_ambient("ambient");
1514  static const CPT_InternalName IN_diffuse("diffuse");
1515  static const CPT_InternalName IN_specular("specular");
1516  static const CPT_InternalName IN_position("position");
1517  static const CPT_InternalName IN_halfVector("halfVector");
1518  static const CPT_InternalName IN_spotDirection("spotDirection");
1519  static const CPT_InternalName IN_spotCutoff("spotCutoff");
1520  static const CPT_InternalName IN_spotCosCutoff("spotCosCutoff");
1521  static const CPT_InternalName IN_spotExponent("spotExponent");
1522  static const CPT_InternalName IN_attenuation("attenuation");
1523  static const CPT_InternalName IN_constantAttenuation("constantAttenuation");
1524  static const CPT_InternalName IN_linearAttenuation("linearAttenuation");
1525  static const CPT_InternalName IN_quadraticAttenuation("quadraticAttenuation");
1526  static const CPT_InternalName IN_shadowViewMatrix("shadowViewMatrix");
1527 
1528  PandaNode *node = nullptr;
1529  if (!np.is_empty()) {
1530  node = np.node();
1531  }
1532 
1533  if (attrib == IN_color) {
1534  if (node == nullptr) {
1535  return &LMatrix4::ident_mat();
1536  }
1537  Light *light = node->as_light();
1538  nassertr(light != nullptr, &LMatrix4::ident_mat());
1539  LColor c = light->get_color();
1540  t.set_row(3, c);
1541  return &t;
1542 
1543  } else if (attrib == IN_ambient) {
1544  if (node == nullptr) {
1545  return &LMatrix4::ident_mat();
1546  }
1547  Light *light = node->as_light();
1548  nassertr(light != nullptr, &LMatrix4::ident_mat());
1549  if (node->is_ambient_light()) {
1550  LColor c = light->get_color();
1551  t.set_row(3, c);
1552  } else {
1553  // Non-ambient lights don't currently have an ambient color in Panda3D.
1554  t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
1555  }
1556  return &t;
1557 
1558  } else if (attrib == IN_diffuse) {
1559  if (node == nullptr) {
1560  return &LMatrix4::ident_mat();
1561  }
1562  Light *light = node->as_light();
1563  nassertr(light != nullptr, &LMatrix4::ones_mat());
1564  if (node->is_ambient_light()) {
1565  // Ambient light has no diffuse color.
1566  t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
1567  } else {
1568  LColor c = light->get_color();
1569  t.set_row(3, c);
1570  }
1571  return &t;
1572 
1573  } else if (attrib == IN_specular) {
1574  if (node == nullptr) {
1575  return &LMatrix4::ident_mat();
1576  }
1577  Light *light = node->as_light();
1578  nassertr(light != nullptr, &LMatrix4::ones_mat());
1579  t.set_row(3, light->get_specular_color());
1580  return &t;
1581 
1582  } else if (attrib == IN_position) {
1583  if (np.is_empty()) {
1584  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);
1585  return &t;
1586  } else if (node->is_ambient_light()) {
1587  // Ambient light has no position.
1588  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1589  return &t;
1590  } else if (node->is_of_type(DirectionalLight::get_class_type())) {
1591  DirectionalLight *light;
1592  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1593 
1594  CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent());
1595  LVector3 dir = -(light->get_direction() * transform->get_mat());
1596  dir *= _scene_setup->get_cs_world_transform()->get_mat();
1597  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 0);
1598  return &t;
1599  } else {
1600  LightLensNode *light;
1601  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1602  Lens *lens = light->get_lens();
1603  nassertr(lens != nullptr, &LMatrix4::ident_mat());
1604 
1605  CPT(TransformState) transform =
1606  _scene_setup->get_cs_world_transform()->compose(
1607  np.get_transform(_scene_setup->get_scene_root().get_parent()));
1608 
1609  const LMatrix4 &light_mat = transform->get_mat();
1610  LPoint3 pos = lens->get_nodal_point() * light_mat;
1611  t = LMatrix4::translate_mat(pos);
1612  return &t;
1613  }
1614 
1615  } else if (attrib == IN_halfVector) {
1616  if (np.is_empty()) {
1617  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);
1618  return &t;
1619  } else if (node->is_ambient_light()) {
1620  // Ambient light has no half-vector.
1621  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1622  return &t;
1623  } else if (node->is_of_type(DirectionalLight::get_class_type())) {
1624  DirectionalLight *light;
1625  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1626 
1627  CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent());
1628  LVector3 dir = -(light->get_direction() * transform->get_mat());
1629  dir *= _scene_setup->get_cs_world_transform()->get_mat();
1630  dir.normalize();
1631  dir += LVector3(0, 0, 1);
1632  dir.normalize();
1633  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 1);
1634  return &t;
1635  } else {
1636  LightLensNode *light;
1637  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1638  Lens *lens = light->get_lens();
1639  nassertr(lens != nullptr, &LMatrix4::ident_mat());
1640 
1641  CPT(TransformState) transform =
1642  _scene_setup->get_cs_world_transform()->compose(
1643  np.get_transform(_scene_setup->get_scene_root().get_parent()));
1644 
1645  const LMatrix4 &light_mat = transform->get_mat();
1646  LPoint3 pos = lens->get_nodal_point() * light_mat;
1647  pos.normalize();
1648  pos += LVector3(0, 0, 1);
1649  pos.normalize();
1650  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pos[0],pos[1],pos[2], 1);
1651  return &t;
1652  }
1653 
1654  } else if (attrib == IN_spotDirection) {
1655  if (node == nullptr) {
1656  t.set_row(3, LVector3(0.0f, 0.0f, -1.0f));
1657  return &t;
1658  } else if (node->is_ambient_light()) {
1659  // Ambient light has no spot direction.
1660  t.set_row(3, LVector3(0.0f, 0.0f, 0.0f));
1661  return &t;
1662  } else {
1663  LightLensNode *light;
1664  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1665  Lens *lens = light->get_lens();
1666  nassertr(lens != nullptr, &LMatrix4::ident_mat());
1667 
1668  CPT(TransformState) transform =
1669  _scene_setup->get_cs_world_transform()->compose(
1670  np.get_transform(_scene_setup->get_scene_root().get_parent()));
1671 
1672  const LMatrix4 &light_mat = transform->get_mat();
1673  LVector3 dir = lens->get_view_vector() * light_mat;
1674  t.set_row(3, dir);
1675  return &t;
1676  }
1677 
1678  } else if (attrib == IN_spotCutoff) {
1679  if (node != nullptr &&
1680  node->is_of_type(Spotlight::get_class_type())) {
1681  LightLensNode *light;
1682  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1683  Lens *lens = light->get_lens();
1684  nassertr(lens != nullptr, &LMatrix4::ident_mat());
1685 
1686  float cutoff = lens->get_hfov() * 0.5f;
1687  t.set_row(3, LVecBase4(cutoff));
1688  return &t;
1689  } else {
1690  // Other lights have no cut-off.
1691  t.set_row(3, LVecBase4(180));
1692  return &t;
1693  }
1694 
1695  } else if (attrib == IN_spotCosCutoff) {
1696  if (node != nullptr &&
1697  node->is_of_type(Spotlight::get_class_type())) {
1698  LightLensNode *light;
1699  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1700  Lens *lens = light->get_lens();
1701  nassertr(lens != nullptr, &LMatrix4::ident_mat());
1702 
1703  float cutoff = lens->get_hfov() * 0.5f;
1704  t.set_row(3, LVecBase4(ccos(deg_2_rad(cutoff))));
1705  return &t;
1706  } else {
1707  // Other lights have no cut-off.
1708  t.set_row(3, LVecBase4(-1));
1709  return &t;
1710  }
1711 
1712  } else if (attrib == IN_spotExponent) {
1713  if (node == nullptr) {
1714  return &LMatrix4::zeros_mat();
1715  }
1716  Light *light = node->as_light();
1717  nassertr(light != nullptr, &LMatrix4::ident_mat());
1718 
1719  t.set_row(3, LVecBase4(light->get_exponent()));
1720  return &t;
1721 
1722  } else if (attrib == IN_attenuation) {
1723  if (node != nullptr) {
1724  Light *light = node->as_light();
1725  nassertr(light != nullptr, &LMatrix4::ones_mat());
1726 
1727  t.set_row(3, LVecBase4(light->get_attenuation(), 0));
1728  } else {
1729  t.set_row(3, LVecBase4(1, 0, 0, 0));
1730  }
1731  return &t;
1732 
1733  } else if (attrib == IN_constantAttenuation) {
1734  if (node == nullptr) {
1735  return &LMatrix4::ones_mat();
1736  }
1737  Light *light = node->as_light();
1738  nassertr(light != nullptr, &LMatrix4::ones_mat());
1739 
1740  t.set_row(3, LVecBase4(light->get_attenuation()[0]));
1741  return &t;
1742 
1743  } else if (attrib == IN_linearAttenuation) {
1744  if (node == nullptr) {
1745  return &LMatrix4::zeros_mat();
1746  }
1747  Light *light = node->as_light();
1748  nassertr(light != nullptr, &LMatrix4::ident_mat());
1749 
1750  t.set_row(3, LVecBase4(light->get_attenuation()[1]));
1751  return &t;
1752 
1753  } else if (attrib == IN_quadraticAttenuation) {
1754  if (node == nullptr) {
1755  return &LMatrix4::zeros_mat();
1756  }
1757  Light *light = node->as_light();
1758  nassertr(light != nullptr, &LMatrix4::ident_mat());
1759 
1760  t.set_row(3, LVecBase4(light->get_attenuation()[2]));
1761  return &t;
1762 
1763  } else if (attrib == IN_shadowViewMatrix) {
1764  static const LMatrix4 biasmat(0.5f, 0.0f, 0.0f, 0.0f,
1765  0.0f, 0.5f, 0.0f, 0.0f,
1766  0.0f, 0.0f, 0.5f, 0.0f,
1767  0.5f, 0.5f, 0.5f, 1.0f);
1768 
1769  if (node == nullptr) {
1770  return &biasmat;
1771  }
1772 
1773  LensNode *lnode;
1774  DCAST_INTO_R(lnode, node, &LMatrix4::ident_mat());
1775  Lens *lens = lnode->get_lens();
1776 
1777  t = _inv_cs_transform->get_mat() *
1778  _scene_setup->get_camera_transform()->get_mat() *
1779  np.get_net_transform()->get_inverse()->get_mat() *
1780  LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system());
1781 
1782  if (!node->is_of_type(PointLight::get_class_type())) {
1783  t *= lens->get_projection_mat() * biasmat;
1784  }
1785  return &t;
1786 
1787  } else {
1788  display_cat.error()
1789  << "Shader input requests invalid attribute " << *attrib
1790  << " from node " << np << "\n";
1791  return &LMatrix4::ident_mat();
1792  }
1793 }
1794 
1795 /**
1796  * Like fetch_specified_value, but for texture inputs.
1797  */
1798 PT(Texture) GraphicsStateGuardian::
1799 fetch_specified_texture(Shader::ShaderTexSpec &spec, SamplerState &sampler,
1800  int &view) {
1801 
1802  static PT(Texture) default_add_tex;
1803  static PT(Texture) default_normal_height_tex;
1804 
1805  switch (spec._part) {
1806  case Shader::STO_named_input:
1807  // Named texture input.
1808  if (!_target_shader->has_shader_input(spec._name)) {
1809  // Is this a member of something, like a node?
1810  const InternalName *parent = spec._name->get_parent();
1811  if (parent != InternalName::get_root() &&
1812  _target_shader->has_shader_input(parent)) {
1813 
1814  // Yes, grab the node.
1815  const string &basename = spec._name->get_basename();
1816  NodePath np = _target_shader->get_shader_input_nodepath(parent);
1817 
1818  if (basename == "shadowMap") {
1819  PT(Texture) tex = get_shadow_map(np);
1820  if (tex != nullptr) {
1821  sampler = tex->get_default_sampler();
1822  }
1823  return tex;
1824 
1825  } else {
1826  if (spec._stage == 0) {
1827  display_cat.error()
1828  << "Shader input " << *parent
1829  << " has no member named " << basename << ".\n";
1830  spec._stage = -1;
1831  }
1832  }
1833  } else {
1834  // This used to be legal for some reason, so don't trigger the assert.
1835  // Prevent flood, though, so abuse the _stage flag to indicate whether
1836  // we've already errored about this.
1837  if (spec._stage == 0) {
1838  display_cat.error()
1839  << "Shader input " << *spec._name << " is not present.\n";
1840  spec._stage = -1;
1841  }
1842  }
1843  } else {
1844  // Just a regular texture input.
1845  return _target_shader->get_shader_input_texture(spec._name, &sampler);
1846  }
1847  break;
1848 
1849  case Shader::STO_stage_i:
1850  {
1851  // We get the TextureAttrib directly from the _target_rs, not the
1852  // filtered TextureAttrib in _target_texture.
1853  const TextureAttrib *texattrib;
1854  _target_rs->get_attrib_def(texattrib);
1855 
1856  if (spec._stage < texattrib->get_num_on_stages()) {
1857  TextureStage *stage = texattrib->get_on_stage(spec._stage);
1858  sampler = texattrib->get_on_sampler(stage);
1859  view += stage->get_tex_view_offset();
1860  return texattrib->get_on_texture(stage);
1861  }
1862  }
1863  break;
1864 
1865  case Shader::STO_light_i_shadow_map:
1866  {
1867  const LightAttrib *target_light;
1868  _target_rs->get_attrib_def(target_light);
1869 
1870  // We don't count ambient lights, which would be pretty silly to handle
1871  // via this mechanism.
1872  size_t num_lights = target_light->get_num_non_ambient_lights();
1873  if (spec._stage >= 0 && (size_t)spec._stage < num_lights) {
1874  NodePath light = target_light->get_on_light((size_t)spec._stage);
1875  nassertr(!light.is_empty(), nullptr);
1876  Light *light_obj = light.node()->as_light();
1877  nassertr(light_obj != nullptr, nullptr);
1878 
1879  PT(Texture) tex;
1880  LightLensNode *lln = DCAST(LightLensNode, light.node());
1881  if (lln != nullptr && lln->_shadow_caster) {
1882  tex = get_shadow_map(light);
1883  } else {
1884  tex = get_dummy_shadow_map((Texture::TextureType)spec._desired_type);
1885  }
1886 
1887  if (tex != nullptr) {
1888  sampler = tex->get_default_sampler();
1889  }
1890  return tex;
1891  } else {
1892  // There is no such light assigned. Bind a dummy shadow map.
1893  PT(Texture) tex = get_dummy_shadow_map((Texture::TextureType)spec._desired_type);
1894  if (tex != nullptr) {
1895  sampler = tex->get_default_sampler();
1896  }
1897  return tex;
1898  }
1899  }
1900  break;
1901 
1902  case Shader::STO_ff_stage_i:
1903  {
1904  // We get the TextureAttrib directly from the _target_rs, not the
1905  // filtered TextureAttrib in _target_texture.
1906  const TextureAttrib *texattrib;
1907  _target_rs->get_attrib_def(texattrib);
1908 
1909  if (spec._stage < texattrib->get_num_on_ff_stages()) {
1910  TextureStage *stage = texattrib->get_on_ff_stage(spec._stage);
1911  sampler = texattrib->get_on_sampler(stage);
1912  view += stage->get_tex_view_offset();
1913  return texattrib->get_on_texture(stage);
1914  }
1915  }
1916  break;
1917 
1918  case Shader::STO_stage_modulate_i:
1919  {
1920  const TextureAttrib *texattrib;
1921  if (_target_rs->get_attrib(texattrib)) {
1922  size_t si = 0;
1923  for (int i = 0; i < texattrib->get_num_on_stages(); ++i) {
1924  TextureStage *stage = texattrib->get_on_stage(i);
1925  TextureStage::Mode mode = stage->get_mode();
1926 
1927  if (mode == TextureStage::M_modulate ||
1928  mode == TextureStage::M_modulate_glow ||
1929  mode == TextureStage::M_modulate_gloss) {
1930  if (si++ == spec._stage) {
1931  sampler = texattrib->get_on_sampler(stage);
1932  view += stage->get_tex_view_offset();
1933  return texattrib->get_on_texture(stage);
1934  }
1935  }
1936  }
1937  }
1938  }
1939  break;
1940 
1941  case Shader::STO_stage_add_i:
1942  {
1943  const TextureAttrib *texattrib;
1944  if (_target_rs->get_attrib(texattrib)) {
1945  size_t si = 0;
1946  for (int i = 0; i < texattrib->get_num_on_stages(); ++i) {
1947  TextureStage *stage = texattrib->get_on_stage(i);
1948  TextureStage::Mode mode = stage->get_mode();
1949 
1950  if (mode == TextureStage::M_add) {
1951  if (si++ == spec._stage) {
1952  sampler = texattrib->get_on_sampler(stage);
1953  view += stage->get_tex_view_offset();
1954  return texattrib->get_on_texture(stage);
1955  }
1956  }
1957  }
1958  }
1959 
1960  if (default_add_tex == nullptr) {
1961  PT(Texture) tex = new Texture("default-add");
1962  tex->setup_2d_texture(1, 1, Texture::T_unsigned_byte, Texture::F_luminance);
1963  tex->set_clear_color(LColor(0, 0, 0, 1));
1964  default_add_tex = std::move(tex);
1965  }
1966  return default_add_tex;
1967  }
1968  break;
1969 
1970  case Shader::STO_stage_normal_i:
1971  {
1972  const TextureAttrib *texattrib;
1973  if (_target_rs->get_attrib(texattrib)) {
1974  size_t si = 0;
1975  for (int i = 0; i < texattrib->get_num_on_stages(); ++i) {
1976  TextureStage *stage = texattrib->get_on_stage(i);
1977  TextureStage::Mode mode = stage->get_mode();
1978 
1979  if (mode == TextureStage::M_normal ||
1980  mode == TextureStage::M_normal_height) {
1981  if (si++ == spec._stage) {
1982  sampler = texattrib->get_on_sampler(stage);
1983  view += stage->get_tex_view_offset();
1984  return texattrib->get_on_texture(stage);
1985  }
1986  }
1987  }
1988  }
1989 
1990  if (default_normal_height_tex == nullptr) {
1991  PT(Texture) tex = new Texture("default-normal-height");
1992  tex->setup_2d_texture(1, 1, Texture::T_unsigned_byte, Texture::F_rgba);
1993  tex->set_clear_color(LColor(0.5, 0.5, 1, 0));
1994  default_normal_height_tex = std::move(tex);
1995  }
1996  return default_normal_height_tex;
1997  }
1998  break;
1999 
2000  case Shader::STO_stage_gloss_i:
2001  {
2002  const TextureAttrib *texattrib;
2003  if (_target_rs->get_attrib(texattrib)) {
2004  size_t si = 0;
2005  for (int i = 0; i < texattrib->get_num_on_stages(); ++i) {
2006  TextureStage *stage = texattrib->get_on_stage(i);
2007  TextureStage::Mode mode = stage->get_mode();
2008 
2009  if (mode == TextureStage::M_gloss ||
2010  mode == TextureStage::M_modulate_gloss ||
2011  mode == TextureStage::M_normal_gloss) {
2012  if (si++ == spec._stage) {
2013  sampler = texattrib->get_on_sampler(stage);
2014  view += stage->get_tex_view_offset();
2015  return texattrib->get_on_texture(stage);
2016  }
2017  }
2018  }
2019  }
2020  }
2021  break;
2022 
2023  case Shader::STO_stage_height_i:
2024  {
2025  const TextureAttrib *texattrib;
2026  if (_target_rs->get_attrib(texattrib)) {
2027  size_t si = 0;
2028  for (int i = 0; i < texattrib->get_num_on_stages(); ++i) {
2029  TextureStage *stage = texattrib->get_on_stage(i);
2030  TextureStage::Mode mode = stage->get_mode();
2031 
2032  if (mode == TextureStage::M_height ||
2033  mode == TextureStage::M_normal_height) {
2034  if (si++ == spec._stage) {
2035  sampler = texattrib->get_on_sampler(stage);
2036  view += stage->get_tex_view_offset();
2037  return texattrib->get_on_texture(stage);
2038  }
2039  }
2040  }
2041  }
2042 
2043  if (default_normal_height_tex == nullptr) {
2044  PT(Texture) tex = new Texture("default-normal-height");
2045  tex->setup_2d_texture(1, 1, Texture::T_unsigned_byte, Texture::F_rgba);
2046  tex->set_clear_color(LColor(0.5, 0.5, 1, 0));
2047  default_normal_height_tex = std::move(tex);
2048  }
2049  return default_normal_height_tex;
2050  }
2051  break;
2052 
2053  case Shader::STO_stage_selector_i:
2054  {
2055  const TextureAttrib *texattrib;
2056  if (_target_rs->get_attrib(texattrib)) {
2057  size_t si = 0;
2058  for (int i = 0; i < texattrib->get_num_on_stages(); ++i) {
2059  TextureStage *stage = texattrib->get_on_stage(i);
2060  TextureStage::Mode mode = stage->get_mode();
2061 
2062  if (mode == TextureStage::M_selector) {
2063  if (si++ == spec._stage) {
2064  sampler = texattrib->get_on_sampler(stage);
2065  view += stage->get_tex_view_offset();
2066  return texattrib->get_on_texture(stage);
2067  }
2068  }
2069  }
2070  }
2071  }
2072  break;
2073 
2074  case Shader::STO_stage_emission_i:
2075  {
2076  const TextureAttrib *texattrib;
2077  if (_target_rs->get_attrib(texattrib)) {
2078  size_t si = 0;
2079  for (int i = 0; i < texattrib->get_num_on_stages(); ++i) {
2080  TextureStage *stage = texattrib->get_on_stage(i);
2081  TextureStage::Mode mode = stage->get_mode();
2082 
2083  if (mode == TextureStage::M_emission) {
2084  if (si++ == spec._stage) {
2085  sampler = texattrib->get_on_sampler(stage);
2086  view += stage->get_tex_view_offset();
2087  return texattrib->get_on_texture(stage);
2088  }
2089  }
2090  }
2091  }
2092  }
2093  break;
2094 
2095  default:
2096  nassertr(false, nullptr);
2097  break;
2098  }
2099 
2100  return nullptr;
2101 }
2102 
2103 /**
2104  * Return a pointer to struct ShaderPtrData
2105  */
2106 const Shader::ShaderPtrData *GraphicsStateGuardian::
2107 fetch_ptr_parameter(const Shader::ShaderPtrSpec& spec) {
2108  return (_target_shader->get_shader_input_ptr(spec._arg));
2109 }
2110 
2111 /**
2112  * Makes the specified DisplayRegion current. All future drawing and clear
2113  * operations will be constrained within the given DisplayRegion.
2114  */
2117  _current_display_region = dr->get_object();
2118  _current_stereo_channel = dr->get_stereo_channel();
2119  _current_tex_view_offset = dr->get_tex_view_offset();
2120  _effective_incomplete_render = _incomplete_render && _current_display_region->get_incomplete_render();
2121 
2122  _stereo_buffer_mask = ~0;
2123 
2124  Lens::StereoChannel output_channel = dr->get_stereo_channel();
2125  if (dr->get_window()->get_swap_eyes()) {
2126  // Reverse the output channel.
2127  switch (output_channel) {
2128  case Lens::SC_left:
2129  output_channel = Lens::SC_right;
2130  break;
2131 
2132  case Lens::SC_right:
2133  output_channel = Lens::SC_left;
2134  break;
2135 
2136  default:
2137  break;
2138  }
2139  }
2140 
2141  switch (output_channel) {
2142  case Lens::SC_left:
2143  _color_write_mask = dr->get_window()->get_left_eye_color_mask();
2144  if (_current_properties->is_stereo()) {
2145  _stereo_buffer_mask = ~RenderBuffer::T_right;
2146  }
2147  break;
2148 
2149  case Lens::SC_right:
2150  _color_write_mask = dr->get_window()->get_right_eye_color_mask();
2151  if (_current_properties->is_stereo()) {
2152  _stereo_buffer_mask = ~RenderBuffer::T_left;
2153  }
2154  break;
2155 
2156  case Lens::SC_mono:
2157  case Lens::SC_stereo:
2158  _color_write_mask = ColorWriteAttrib::C_all;
2159  }
2160 }
2161 
2162 /**
2163  * Resets any non-standard graphics state that might give a callback apoplexy.
2164  * Some drivers require that the graphics state be restored to neutral before
2165  * performing certain operations. In OpenGL, for instance, this closes any
2166  * open vertex buffers.
2167  */
2170 }
2171 
2172 /**
2173  * Forgets the current graphics state and current transform, so that the next
2174  * call to set_state_and_transform() will have to reload everything. This is
2175  * a good thing to call when you are no longer sure what the graphics state
2176  * is. This should only be called from the draw thread.
2177  */
2180  // Re-issue the modelview and projection transforms.
2181  reissue_transforms();
2182 
2183  // Now clear the state flags to unknown.
2184  _state_rs = RenderState::make_empty();
2185  _state_mask.clear();
2186 }
2187 
2188 /**
2189  * This is simply a transparent call to GraphicsEngine::remove_window(). It
2190  * exists primary to support removing a window from that compiles before the
2191  * display module, and therefore has no knowledge of a GraphicsEngine object.
2192  */
2195  nassertv(_engine != nullptr);
2196  GraphicsOutput *win;
2197  DCAST_INTO_V(win, window);
2198  _engine->remove_window(win);
2199 }
2200 
2201 /**
2202  * Makes the current lens (whichever lens was most recently specified with
2203  * set_scene()) active, so that it will transform future rendered geometry.
2204  * Normally this is only called from the draw process, and usually it is
2205  * called by set_scene().
2206  *
2207  * The return value is true if the lens is acceptable, false if it is not.
2208  */
2210 prepare_lens() {
2211  return false;
2212 }
2213 
2214 /**
2215  * Given a lens, this function calculates the appropriate projection matrix
2216  * for this gsg. The result depends on the peculiarities of the rendering
2217  * API.
2218  */
2219 CPT(TransformState) GraphicsStateGuardian::
2220 calc_projection_mat(const Lens *lens) {
2221  if (lens == nullptr) {
2222  return nullptr;
2223  }
2224 
2225  if (!lens->is_linear()) {
2226  return nullptr;
2227  }
2228 
2229  return TransformState::make_identity();
2230 }
2231 
2232 /**
2233  * Called before each frame is rendered, to allow the GSG a chance to do any
2234  * internal cleanup before beginning the frame.
2235  *
2236  * The return value is true if successful (in which case the frame will be
2237  * drawn and end_frame() will be called later), or false if unsuccessful (in
2238  * which case nothing will be drawn and end_frame() will not be called).
2239  */
2241 begin_frame(Thread *current_thread) {
2242  _prepared_objects->begin_frame(this, current_thread);
2243 
2244  // We should reset the state to the default at the beginning of every frame.
2245  // Although this will incur additional overhead, particularly in a simple
2246  // scene, it helps ensure that states that have changed properties since
2247  // last time without changing attribute pointers--like textures, lighting,
2248  // or fog--will still be accurately updated.
2249  _state_rs = RenderState::make_empty();
2250  _state_mask.clear();
2251 
2252 #ifdef DO_PSTATS
2253  // We have to do this here instead of in GraphicsEngine because we need a
2254  // current context to issue timer queries.
2256  if (_last_query_frame < frame) {
2257  _last_query_frame = frame;
2258  _timer_queries_pcollector.clear_level();
2259 
2260  // Now is a good time to flush previous frame's queries. We may not
2261  // actually have all of the previous frame's results in yet, but that's
2262  // okay; the GPU data is allowed to lag a few frames behind.
2264 
2265  if (_timer_queries_active) {
2266  // Issue a stop and start event for collector 0, marking the beginning
2267  // of the new frame.
2268  issue_timer_query(0x8000);
2269  issue_timer_query(0x0000);
2270  }
2271  }
2272 #endif
2273 
2274  return !_needs_reset;
2275 }
2276 
2277 /**
2278  * Called between begin_frame() and end_frame() to mark the beginning of
2279  * drawing commands for a "scene" (usually a particular DisplayRegion) within
2280  * a frame. All 3-D drawing commands, except the clear operation, must be
2281  * enclosed within begin_scene() .. end_scene(). This must be called in the
2282  * draw thread.
2283  *
2284  * The return value is true if successful (in which case the scene will be
2285  * drawn and end_scene() will be called later), or false if unsuccessful (in
2286  * which case nothing will be drawn and end_scene() will not be called).
2287  */
2289 begin_scene() {
2290  return true;
2291 }
2292 
2293 /**
2294  * Called between begin_frame() and end_frame() to mark the end of drawing
2295  * commands for a "scene" (usually a particular DisplayRegion) within a frame.
2296  * All 3-D drawing commands, except the clear operation, must be enclosed
2297  * within begin_scene() .. end_scene().
2298  */
2300 end_scene() {
2301  // We should clear this pointer now, so that we don't keep unneeded
2302  // reference counts dangling. We keep around a "null" scene setup object
2303  // instead of using a null pointer to avoid special-case code in
2304  // set_state_and_transform.
2305  _scene_setup = _scene_null;
2306 
2307  // Undo any lighting we had enabled last scene, to force the lights to be
2308  // reissued, in case their parameters or positions have changed between
2309  // scenes.
2310  int i;
2311  for (i = 0; i < _num_lights_enabled; ++i) {
2312  enable_light(i, false);
2313  }
2314  _num_lights_enabled = 0;
2315 
2316  // Ditto for the clipping planes.
2317  for (i = 0; i < _num_clip_planes_enabled; ++i) {
2318  enable_clip_plane(i, false);
2319  }
2320  _num_clip_planes_enabled = 0;
2321 
2322  // Put the state into the 'unknown' state, forcing a reload.
2323  _state_rs = RenderState::make_empty();
2324  _state_mask.clear();
2325 }
2326 
2327 /**
2328  * Called after each frame is rendered, to allow the GSG a chance to do any
2329  * internal cleanup after rendering the frame, and before the window flips.
2330  */
2332 end_frame(Thread *current_thread) {
2333  _prepared_objects->end_frame(current_thread);
2334 
2335  // Flush any PStatCollectors.
2336  _data_transferred_pcollector.flush_level();
2337 
2338  _primitive_batches_pcollector.flush_level();
2339  _primitive_batches_tristrip_pcollector.flush_level();
2340  _primitive_batches_trifan_pcollector.flush_level();
2341  _primitive_batches_tri_pcollector.flush_level();
2342  _primitive_batches_patch_pcollector.flush_level();
2343  _primitive_batches_other_pcollector.flush_level();
2344  _vertices_tristrip_pcollector.flush_level();
2345  _vertices_trifan_pcollector.flush_level();
2346  _vertices_tri_pcollector.flush_level();
2347  _vertices_patch_pcollector.flush_level();
2348  _vertices_other_pcollector.flush_level();
2349 
2350  _state_pcollector.flush_level();
2351  _texture_state_pcollector.flush_level();
2352  _transform_state_pcollector.flush_level();
2353  _draw_primitive_pcollector.flush_level();
2354 
2355  // Evict any textures andor vbuffers that exceed our texture memory.
2356  _prepared_objects->_graphics_memory_lru.begin_epoch();
2357 }
2358 
2359 /**
2360  * Called by the graphics engine on the draw thread to check the status of the
2361  * running timer queries and submit their results to the PStats server.
2362  */
2365 #ifdef DO_PSTATS
2366  // This uses the lower-level PStats interfaces for now because of all the
2367  // unnecessary overhead that would otherwise be incurred when adding such a
2368  // large amount of data at once.
2369 
2370  PStatClient *client = PStatClient::get_global_pstats();
2371 
2372  if (!client->client_is_connected()) {
2373  _timer_queries_active = false;
2374  return;
2375  }
2376 
2377  if (!_timer_queries_active) {
2378  if (pstats_gpu_timing && _supports_timer_query) {
2379  // Check if timer queries should be enabled.
2380  _timer_queries_active = true;
2381  } else {
2382  return;
2383  }
2384  }
2385 
2386  // Currently, we use one thread per GSG, for convenience. In the future, we
2387  // may want to try and use one thread per graphics card.
2388  if (_pstats_gpu_thread == -1) {
2389  _pstats_gpu_thread = client->make_gpu_thread(get_driver_renderer()).get_index();
2390  }
2391  PStatThread gpu_thread(client, _pstats_gpu_thread);
2392 
2393  // Get the results of all the timer queries.
2394  int first = 0;
2395  if (!_pending_timer_queries.empty()) {
2396  int count = _pending_timer_queries.size();
2397  if (count == 0) {
2398  return;
2399  }
2400 
2401  PStatGPUTimer timer(this, _wait_timer_pcollector);
2402 
2403  if (_last_num_queried > 0) {
2404  // We know how many queries were available last frame, and this usually
2405  // stays fairly constant, so use this as a starting point.
2406  int i = std::min(_last_num_queried, count) - 1;
2407 
2408  if (_pending_timer_queries[i]->is_answer_ready()) {
2409  first = count;
2410  while (i < count - 1) {
2411  if (!_pending_timer_queries[++i]->is_answer_ready()) {
2412  first = i;
2413  break;
2414  }
2415  }
2416  } else {
2417  first = 0;
2418  while (i > 0) {
2419  if (_pending_timer_queries[--i]->is_answer_ready()) {
2420  first = i + 1;
2421  break;
2422  }
2423  }
2424  }
2425  } else {
2426  // We figure out which tasks the GPU has already finished by doing a
2427  // binary search for the first query that does not have an answer ready.
2428  // We know then that everything before that must be ready.
2429  while (count > 0) {
2430  int step = count / 2;
2431  int i = first + step;
2432  if (_pending_timer_queries[i]->is_answer_ready()) {
2433  first += step + 1;
2434  count -= step + 1;
2435  } else {
2436  count = step;
2437  }
2438  }
2439  }
2440 
2441  if (first <= 0) {
2442  return;
2443  }
2444 
2445  _last_num_queried = first;
2446 
2447  for (int i = 0; i < first; ++i) {
2448  CPT(TimerQueryContext) query = _pending_timer_queries[i];
2449 
2450  double time_data = query->get_timestamp(); // + _timer_delta;
2451 
2452  if (query->_pstats_index == _command_latency_pcollector.get_index()) {
2453  // Special case for the latency pcollector.
2454  PStatCollectorDef *cdef;
2455  cdef = client->get_collector_ptr(query->_pstats_index)->get_def(client, query->_pstats_index);
2456  _pstats_gpu_data.add_level(query->_pstats_index, time_data * cdef->_factor);
2457 
2458  } else if (query->_pstats_index & 0x8000) {
2459  _pstats_gpu_data.add_stop(query->_pstats_index & 0x7fff, time_data);
2460 
2461  } else {
2462  _pstats_gpu_data.add_start(query->_pstats_index & 0x7fff, time_data);
2463  }
2464 
2465  // We found an end-frame marker (a stop event for collector 0). This
2466  // means that the GPU actually caught up with that frame, and we can
2467  // flush the GPU thread's frame data to the pstats server.
2468  if (query->_pstats_index == 0x8000) {
2469  gpu_thread.add_frame(_pstats_gpu_data);
2470  _pstats_gpu_data.clear();
2471  }
2472  }
2473  }
2474 
2475  if (first > 0) {
2476  // Do this out of the scope of _wait_timer_pcollector.
2477  _pending_timer_queries.erase(
2478  _pending_timer_queries.begin(),
2479  _pending_timer_queries.begin() + first
2480  );
2481  _timer_queries_pcollector.add_level_now(first);
2482  }
2483 #endif
2484 }
2485 
2486 /**
2487  * Returns true if this GSG can implement decals using a DepthOffsetAttrib, or
2488  * false if that is unreliable and the three-step rendering process should be
2489  * used instead.
2490  */
2493  return true;
2494 }
2495 
2496 /**
2497  * Called during draw to begin a three-step rendering phase to draw decals.
2498  * The first step, begin_decal_base_first(), is called prior to drawing the
2499  * base geometry. It should set up whatever internal state is appropriate, as
2500  * well as returning a RenderState object that should be applied to the base
2501  * geometry for rendering.
2502  */
2503 CPT(RenderState) GraphicsStateGuardian::
2504 begin_decal_base_first() {
2505  // Turn off writing the depth buffer to render the base geometry.
2506  static CPT(RenderState) decal_base_first;
2507  if (decal_base_first == nullptr) {
2508  decal_base_first = RenderState::make
2509  (DepthWriteAttrib::make(DepthWriteAttrib::M_off),
2510  RenderState::get_max_priority());
2511  }
2512  return decal_base_first;
2513 }
2514 
2515 /**
2516  * Called during draw to begin a three-step rendering phase to draw decals.
2517  * The second step, begin_decal_nested(), is called after drawing the base
2518  * geometry and prior to drawing any of the nested decal geometry that is to
2519  * be applied to the base geometry.
2520  */
2521 CPT(RenderState) GraphicsStateGuardian::
2522 begin_decal_nested() {
2523  // We should keep the depth buffer off during this operation, so that decals
2524  // on decals will render properly.
2525  static CPT(RenderState) decal_nested;
2526  if (decal_nested == nullptr) {
2527  decal_nested = RenderState::make
2528  (DepthWriteAttrib::make(DepthWriteAttrib::M_off),
2529  RenderState::get_max_priority());
2530  }
2531  return decal_nested;
2532 }
2533 
2534 /**
2535  * Called during draw to begin a three-step rendering phase to draw decals.
2536  * The third step, begin_decal_base_second(), is called after drawing the base
2537  * geometry and the nested decal geometry, and prior to drawing the base
2538  * geometry one more time (if needed).
2539  *
2540  * It should return a RenderState object appropriate for rendering the base
2541  * geometry the second time, or NULL if it is not necessary to re-render the
2542  * base geometry.
2543  */
2544 CPT(RenderState) GraphicsStateGuardian::
2545 begin_decal_base_second() {
2546  // Now let the depth buffer go back on, but turn off writing the color
2547  // buffer to render the base geometry after the second pass. Also, turn off
2548  // texturing since there's no need for it now.
2549  static CPT(RenderState) decal_base_second;
2550  if (decal_base_second == nullptr) {
2551  decal_base_second = RenderState::make
2552  (ColorWriteAttrib::make(ColorWriteAttrib::C_off),
2553  // On reflection, we need to leave texturing on so the alpha test
2554  // mechanism can work (if it is enabled, e.g. we are rendering an
2555  // object with M_dual transparency). TextureAttrib::make_off(),
2556  RenderState::get_max_priority());
2557  }
2558  return decal_base_second;
2559 }
2560 
2561 /**
2562  * Called during draw to clean up after decals are finished.
2563  */
2565 finish_decal() {
2566  // No need to do anything special here.
2567 }
2568 
2569 /**
2570  * Called before a sequence of draw_primitive() functions are called, this
2571  * should prepare the vertex data for rendering. It returns true if the
2572  * vertices are ok, false to abort this group of primitives.
2573  */
2575 begin_draw_primitives(const GeomPipelineReader *geom_reader,
2576  const GeomVertexDataPipelineReader *data_reader,
2577  bool force) {
2578  _data_reader = data_reader;
2579 
2580  // Always draw if we have a shader, since the shader might use a different
2581  // mechanism for fetching vertex data.
2582  return _data_reader->has_vertex() || (_target_shader && _target_shader->has_shader());
2583 }
2584 
2585 /**
2586  * Draws a series of disconnected triangles.
2587  */
2590  return false;
2591 }
2592 
2593 
2594 /**
2595  * Draws a series of disconnected triangles with adjacency information.
2596  */
2599  return false;
2600 }
2601 
2602 /**
2603  * Draws a series of triangle strips.
2604  */
2607  return false;
2608 }
2609 
2610 /**
2611  * Draws a series of triangle strips with adjacency information.
2612  */
2615  return false;
2616 }
2617 
2618 /**
2619  * Draws a series of triangle fans.
2620  */
2623  return false;
2624 }
2625 
2626 /**
2627  * Draws a series of "patches", which can only be processed by a tessellation
2628  * shader.
2629  */
2632  return false;
2633 }
2634 
2635 /**
2636  * Draws a series of disconnected line segments.
2637  */
2639 draw_lines(const GeomPrimitivePipelineReader *, bool) {
2640  return false;
2641 }
2642 
2643 /**
2644  * Draws a series of disconnected line segments with adjacency information.
2645  */
2648  return false;
2649 }
2650 
2651 /**
2652  * Draws a series of line strips.
2653  */
2656  return false;
2657 }
2658 
2659 /**
2660  * Draws a series of line strips with adjacency information.
2661  */
2664  return false;
2665 }
2666 
2667 /**
2668  * Draws a series of disconnected points.
2669  */
2672  return false;
2673 }
2674 
2675 /**
2676  * Called after a sequence of draw_primitive() functions are called, this
2677  * should do whatever cleanup is appropriate.
2678  */
2681  _data_reader = nullptr;
2682 }
2683 
2684 /**
2685  * Resets all internal state as if the gsg were newly created.
2686  */
2688 reset() {
2689  _needs_reset = false;
2690  _is_valid = false;
2691 
2692  _state_rs = RenderState::make_empty();
2693  _target_rs = nullptr;
2694  _state_mask.clear();
2695  _internal_transform = _cs_transform;
2696  _scene_null = new SceneSetup;
2697  _scene_setup = _scene_null;
2698 
2699  _color_write_mask = ColorWriteAttrib::C_all;
2700 
2701  _has_scene_graph_color = false;
2702  _scene_graph_color.set(1.0f, 1.0f, 1.0f, 1.0f);
2703  _transform_stale = true;
2704  _color_blend_involves_color_scale = false;
2705  _texture_involves_color_scale = false;
2706  _vertex_colors_enabled = true;
2707  _lighting_enabled = false;
2708  _num_lights_enabled = 0;
2709  _num_clip_planes_enabled = 0;
2710  _clip_planes_enabled = false;
2711 
2712  _color_scale_enabled = false;
2713  _current_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
2714  _has_texture_alpha_scale = false;
2715 
2716  _has_material_force_color = false;
2717  _material_force_color.set(1.0f, 1.0f, 1.0f, 1.0f);
2718  _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
2719 
2720  _tex_gen_modifies_mat = false;
2721  _last_max_stage_index = 0;
2722 
2723  _is_valid = true;
2724 }
2725 
2726 /**
2727  * Simultaneously resets the render state and the transform state.
2728  *
2729  * This transform specified is the "internal" net transform, already converted
2730  * into the GSG's internal coordinate space by composing it to
2731  * get_cs_transform(). (Previously, this used to be the "external" net
2732  * transform, with the assumption that that GSG would convert it internally,
2733  * but that is no longer the case.)
2734  *
2735  * Special case: if (state==NULL), then the target state is already stored in
2736  * _target.
2737  */
2740  const TransformState *trans) {
2741 }
2742 
2743 /**
2744  * Clears the framebuffer within the current DisplayRegion, according to the
2745  * flags indicated by the given DrawableRegion object.
2746  *
2747  * This does not set the DisplayRegion first. You should call
2748  * prepare_display_region() to specify the region you wish the clear operation
2749  * to apply to.
2750  */
2752 clear(DrawableRegion *clearable) {
2753 }
2754 
2755 /**
2756  * Returns a RenderBuffer object suitable for operating on the requested set
2757  * of buffers. buffer_type is the union of all the desired RenderBuffer::Type
2758  * values.
2759  */
2761 get_render_buffer(int buffer_type, const FrameBufferProperties &prop) {
2762  return RenderBuffer(this, buffer_type & prop.get_buffer_mask() & _stereo_buffer_mask);
2763 }
2764 
2765 /**
2766  * Returns what the cs_transform would be set to after a call to
2767  * set_coordinate_system(cs). This is another way of saying the cs_transform
2768  * when rendering the scene for a camera with the indicated coordinate system.
2769  */
2770 CPT(TransformState) GraphicsStateGuardian::
2771 get_cs_transform_for(CoordinateSystem cs) const {
2772  if (_coordinate_system == cs) {
2773  // We've already calculated this.
2774  return _cs_transform;
2775 
2776  } else if (_internal_coordinate_system == CS_default ||
2777  _internal_coordinate_system == cs) {
2778  return TransformState::make_identity();
2779 
2780  } else {
2781  return TransformState::make_mat
2782  (LMatrix4::convert_mat(cs, _internal_coordinate_system));
2783  }
2784 }
2785 
2786 /**
2787  * Returns a transform that converts from the GSG's external coordinate system
2788  * (as returned by get_coordinate_system()) to its internal coordinate system
2789  * (as returned by get_internal_coordinate_system()). This is used for
2790  * rendering.
2791  */
2792 CPT(TransformState) GraphicsStateGuardian::
2793 get_cs_transform() const {
2794  return _cs_transform;
2795 }
2796 
2797 /**
2798  * This is fundametically similar to do_issue_light(), with calls to
2799  * apply_clip_plane() and enable_clip_planes(), as appropriate.
2800  */
2801 void GraphicsStateGuardian::
2802 do_issue_clip_plane() {
2803  int num_enabled = 0;
2804  int num_on_planes = 0;
2805 
2806  const ClipPlaneAttrib *target_clip_plane = (const ClipPlaneAttrib *)
2807  _target_rs->get_attrib_def(ClipPlaneAttrib::get_class_slot());
2808 
2809  if (target_clip_plane != nullptr) {
2810  CPT(ClipPlaneAttrib) new_plane = target_clip_plane->filter_to_max(_max_clip_planes);
2811 
2812  num_on_planes = new_plane->get_num_on_planes();
2813  for (int li = 0; li < num_on_planes; li++) {
2814  NodePath plane = new_plane->get_on_plane(li);
2815  nassertv(!plane.is_empty());
2816  PlaneNode *plane_node;
2817  DCAST_INTO_V(plane_node, plane.node());
2818  if ((plane_node->get_clip_effect() & PlaneNode::CE_visible) != 0) {
2819  // Clipping should be enabled before we apply any planes.
2820  if (!_clip_planes_enabled) {
2821  enable_clip_planes(true);
2822  _clip_planes_enabled = true;
2823  }
2824 
2825  enable_clip_plane(num_enabled, true);
2826  if (num_enabled == 0) {
2827  begin_bind_clip_planes();
2828  }
2829 
2830  bind_clip_plane(plane, num_enabled);
2831  num_enabled++;
2832  }
2833  }
2834  }
2835 
2836  int i;
2837  for (i = num_enabled; i < _num_clip_planes_enabled; ++i) {
2838  enable_clip_plane(i, false);
2839  }
2840  _num_clip_planes_enabled = num_enabled;
2841 
2842  // If no planes were set, disable clipping
2843  if (num_enabled == 0) {
2844  if (_clip_planes_enabled) {
2845  enable_clip_planes(false);
2846  _clip_planes_enabled = false;
2847  }
2848  } else {
2849  end_bind_clip_planes();
2850  }
2851 }
2852 
2853 /**
2854  * This method is defined in the base class because it is likely that this
2855  * functionality will be used for all (or at least most) kinds of
2856  * GraphicsStateGuardians--it's not specific to any one rendering backend.
2857  *
2858  * The ColorAttribute just changes the interpretation of the color on the
2859  * vertices, and fiddles with _vertex_colors_enabled, etc.
2860  */
2862 do_issue_color() {
2863  const ColorAttrib *target_color = (const ColorAttrib *)
2864  _target_rs->get_attrib_def(ColorAttrib::get_class_slot());
2865 
2866  switch (target_color->get_color_type()) {
2867  case ColorAttrib::T_flat:
2868  // Color attribute flat: it specifies a scene graph color that overrides
2869  // the vertex color.
2870  _scene_graph_color = target_color->get_color();
2871  _has_scene_graph_color = true;
2872  _vertex_colors_enabled = false;
2873  break;
2874 
2875  case ColorAttrib::T_off:
2876  // Color attribute off: it specifies that no scene graph color is in
2877  // effect, and vertex color is not important either.
2878  _scene_graph_color.set(1.0f, 1.0f, 1.0f, 1.0f);
2879  _has_scene_graph_color = false;
2880  _vertex_colors_enabled = false;
2881  break;
2882 
2883  case ColorAttrib::T_vertex:
2884  // Color attribute vertex: it specifies that vertex color should be
2885  // revealed.
2886  _scene_graph_color.set(1.0f, 1.0f, 1.0f, 1.0f);
2887  _has_scene_graph_color = false;
2888  _vertex_colors_enabled = true;
2889  break;
2890  }
2891 
2892  if (_color_scale_via_lighting) {
2893  _state_mask.clear_bit(LightAttrib::get_class_slot());
2894  _state_mask.clear_bit(MaterialAttrib::get_class_slot());
2895 
2896  determine_light_color_scale();
2897  }
2898 }
2899 
2900 /**
2901  *
2902  */
2903 void GraphicsStateGuardian::
2904 do_issue_color_scale() {
2905  // If the previous color scale had set a special texture, clear the texture
2906  // now.
2907  if (_has_texture_alpha_scale) {
2908  _state_mask.clear_bit(TextureAttrib::get_class_slot());
2909  }
2910 
2911  const ColorScaleAttrib *target_color_scale = (const ColorScaleAttrib *)
2912  _target_rs->get_attrib_def(ColorScaleAttrib::get_class_slot());
2913 
2914  _color_scale_enabled = target_color_scale->has_scale();
2915  _current_color_scale = target_color_scale->get_scale();
2916  _has_texture_alpha_scale = false;
2917 
2918  if (_color_blend_involves_color_scale) {
2919  _state_mask.clear_bit(TransparencyAttrib::get_class_slot());
2920  }
2921  if (_texture_involves_color_scale) {
2922  _state_mask.clear_bit(TextureAttrib::get_class_slot());
2923  }
2924  if (_color_scale_via_lighting) {
2925  _state_mask.clear_bit(LightAttrib::get_class_slot());
2926  _state_mask.clear_bit(MaterialAttrib::get_class_slot());
2927 
2928  determine_light_color_scale();
2929  }
2930 
2931  if (_alpha_scale_via_texture && !_has_scene_graph_color &&
2932  _vertex_colors_enabled && target_color_scale->has_alpha_scale()) {
2933  // This color scale will set a special texture--so again, clear the
2934  // texture.
2935  _state_mask.clear_bit(TextureAttrib::get_class_slot());
2936  _state_mask.clear_bit(TexMatrixAttrib::get_class_slot());
2937 
2938  _has_texture_alpha_scale = true;
2939  }
2940 }
2941 
2942 /**
2943  * This implementation of do_issue_light() assumes we have a limited number of
2944  * hardware lights available. This function assigns each light to a different
2945  * hardware light id, trying to keep each light associated with the same id
2946  * where possible, but reusing id's when necessary. When it is no longer
2947  * possible to reuse existing id's (e.g. all id's are in use), the next
2948  * sequential id is assigned (if available).
2949  *
2950  * It will call apply_light() each time a light is assigned to a particular id
2951  * for the first time in a given frame, and it will subsequently call
2952  * enable_light() to enable or disable each light as the frame is rendered, as
2953  * well as enable_lighting() to enable or disable overall lighting.
2954  */
2956 do_issue_light() {
2957  // Initialize the current ambient light total and newly enabled light list
2958  LColor cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f);
2959  int i;
2960 
2961  int num_enabled = 0;
2962  bool any_on_lights = false;
2963 
2964  const LightAttrib *target_light;
2965  _target_rs->get_attrib_def(target_light);
2966 
2967  if (display_cat.is_spam()) {
2968  display_cat.spam()
2969  << "do_issue_light: " << target_light << "\n";
2970  }
2971  if (target_light != nullptr) {
2972  // LightAttrib guarantees that the on lights are sorted, and that
2973  // non-ambient lights come before ambient lights.
2974  any_on_lights = target_light->has_any_on_light();
2975  size_t filtered_lights = std::min((size_t)_max_lights, target_light->get_num_non_ambient_lights());
2976  for (size_t li = 0; li < filtered_lights; ++li) {
2977  NodePath light = target_light->get_on_light(li);
2978  nassertv(!light.is_empty());
2979  Light *light_obj = light.node()->as_light();
2980  nassertv(light_obj != nullptr);
2981 
2982  // Lighting should be enabled before we apply any lights.
2983  if (!_lighting_enabled) {
2984  enable_lighting(true);
2985  _lighting_enabled = true;
2986  }
2987 
2988  const LColor &color = light_obj->get_color();
2989  // Don't bother binding the light if it has no color to contribute.
2990  if (color[0] != 0.0 || color[1] != 0.0 || color[2] != 0.0) {
2991  enable_light(num_enabled, true);
2992  if (num_enabled == 0) {
2993  begin_bind_lights();
2994  }
2995 
2996  light_obj->bind(this, light, num_enabled);
2997  num_enabled++;
2998  }
2999  }
3000  }
3001 
3002  for (i = num_enabled; i < _num_lights_enabled; ++i) {
3003  enable_light(i, false);
3004  }
3005  _num_lights_enabled = num_enabled;
3006 
3007  // If no lights were set, disable lighting
3008  if (!any_on_lights) {
3009  if (_color_scale_via_lighting && (_has_material_force_color || _light_color_scale != LVecBase4(1.0f, 1.0f, 1.0f, 1.0f))) {
3010  // Unless we need lighting anyway to apply a color or color scale.
3011  if (!_lighting_enabled) {
3012  enable_lighting(true);
3013  _lighting_enabled = true;
3014  }
3015  set_ambient_light(LColor(1.0f, 1.0f, 1.0f, 1.0f));
3016 
3017  } else {
3018  if (_lighting_enabled) {
3019  enable_lighting(false);
3020  _lighting_enabled = false;
3021  }
3022  }
3023 
3024  } else {
3025  // Don't forget to still enable lighting if we have only an ambient light.
3026  if (!_lighting_enabled) {
3027  enable_lighting(true);
3028  _lighting_enabled = true;
3029  }
3030 
3031  set_ambient_light(target_light->get_ambient_contribution());
3032  }
3033 
3034  if (num_enabled != 0) {
3035  end_bind_lights();
3036  }
3037 }
3038 
3039 /**
3040  * Copy the pixels within the indicated display region from the framebuffer
3041  * into texture memory.
3042  *
3043  * If z > -1, it is the cube map index into which to copy.
3044  */
3047  const RenderBuffer &) {
3048  return false;
3049 }
3050 
3051 
3052 /**
3053  * Copy the pixels within the indicated display region from the framebuffer
3054  * into system memory, not texture memory. Returns true on success, false on
3055  * failure.
3056  *
3057  * This completely redefines the ram image of the indicated texture.
3058  */
3060 framebuffer_copy_to_ram(Texture *, int, int, const DisplayRegion *,
3061  const RenderBuffer &) {
3062  return false;
3063 }
3064 
3065 /**
3066  * Called the first time a particular light has been bound to a given id
3067  * within a frame, this should set up the associated hardware light with the
3068  * light's properties.
3069  */
3071 bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
3072 }
3073 
3074 /**
3075  * Called the first time a particular light has been bound to a given id
3076  * within a frame, this should set up the associated hardware light with the
3077  * light's properties.
3078  */
3080 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
3081 }
3082 
3083 /**
3084  * Called the first time a particular light has been bound to a given id
3085  * within a frame, this should set up the associated hardware light with the
3086  * light's properties.
3087  */
3089 bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
3090 }
3091 
3092 #ifdef DO_PSTATS
3093 /**
3094  * Initializes the relevant PStats data at the beginning of the frame.
3095  */
3096 void GraphicsStateGuardian::
3097 init_frame_pstats() {
3098  if (PStatClient::is_connected()) {
3099  _data_transferred_pcollector.clear_level();
3100  _vertex_buffer_switch_pcollector.clear_level();
3101  _index_buffer_switch_pcollector.clear_level();
3102 
3103  _primitive_batches_pcollector.clear_level();
3104  _primitive_batches_tristrip_pcollector.clear_level();
3105  _primitive_batches_trifan_pcollector.clear_level();
3106  _primitive_batches_tri_pcollector.clear_level();
3107  _primitive_batches_patch_pcollector.clear_level();
3108  _primitive_batches_other_pcollector.clear_level();
3109  _vertices_tristrip_pcollector.clear_level();
3110  _vertices_trifan_pcollector.clear_level();
3111  _vertices_tri_pcollector.clear_level();
3112  _vertices_patch_pcollector.clear_level();
3113  _vertices_other_pcollector.clear_level();
3114 
3115  _state_pcollector.clear_level();
3116  _transform_state_pcollector.clear_level();
3117  _texture_state_pcollector.clear_level();
3118  }
3119 }
3120 #endif // DO_PSTATS
3121 
3122 
3123 /**
3124  * Create a gamma table.
3125  */
3127 create_gamma_table (PN_stdfloat gamma, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
3128  int i;
3129 
3130  if (gamma <= 0.0) {
3131  // avoid divide by zero and negative exponents
3132  gamma = 1.0;
3133  }
3134 
3135  for (i = 0; i < 256; i++) {
3136  double g;
3137  double x;
3138  PN_stdfloat gamma_correction;
3139 
3140  x = ((double) i / 255.0);
3141  gamma_correction = 1.0 / gamma;
3142  x = pow (x, (double) gamma_correction);
3143  if (x > 1.00) {
3144  x = 1.0;
3145  }
3146 
3147  g = x * 65535.0;
3148  red_table [i] = (int)g;
3149  green_table [i] = (int)g;
3150  blue_table [i] = (int)g;
3151  }
3152 }
3153 
3154 /**
3155  * Called by clear_state_and_transform() to ensure that the current modelview
3156  * and projection matrices are properly loaded in the graphics state, after a
3157  * callback might have mucked them up.
3158  */
3159 void GraphicsStateGuardian::
3160 reissue_transforms() {
3161 }
3162 
3163 /**
3164  * Intended to be overridden by a derived class to enable or disable the use
3165  * of lighting overall. This is called by do_issue_light() according to
3166  * whether any lights are in use or not.
3167  */
3168 void GraphicsStateGuardian::
3169 enable_lighting(bool enable) {
3170 }
3171 
3172 /**
3173  * Intended to be overridden by a derived class to indicate the color of the
3174  * ambient light that should be in effect. This is called by do_issue_light()
3175  * after all other lights have been enabled or disabled.
3176  */
3177 void GraphicsStateGuardian::
3178 set_ambient_light(const LColor &color) {
3179 }
3180 
3181 /**
3182  * Intended to be overridden by a derived class to enable the indicated light
3183  * id. A specific Light will already have been bound to this id via
3184  * bind_light().
3185  */
3186 void GraphicsStateGuardian::
3187 enable_light(int light_id, bool enable) {
3188 }
3189 
3190 /**
3191  * Called immediately before bind_light() is called, this is intended to
3192  * provide the derived class a hook in which to set up some state (like
3193  * transform) that might apply to several lights.
3194  *
3195  * The sequence is: begin_bind_lights() will be called, then one or more
3196  * bind_light() calls, then end_bind_lights().
3197  */
3198 void GraphicsStateGuardian::
3199 begin_bind_lights() {
3200 }
3201 
3202 /**
3203  * Called after before bind_light() has been called one or more times (but
3204  * before any geometry is issued or additional state is changed), this is
3205  * intended to clean up any temporary changes to the state that may have been
3206  * made by begin_bind_lights().
3207  */
3208 void GraphicsStateGuardian::
3209 end_bind_lights() {
3210 }
3211 
3212 /**
3213  * Intended to be overridden by a derived class to enable or disable the use
3214  * of clipping planes overall. This is called by do_issue_clip_plane()
3215  * according to whether any planes are in use or not.
3216  */
3217 void GraphicsStateGuardian::
3218 enable_clip_planes(bool enable) {
3219 }
3220 
3221 /**
3222  * Intended to be overridden by a derived class to enable the indicated plane
3223  * id. A specific PlaneNode will already have been bound to this id via
3224  * bind_clip_plane().
3225  */
3226 void GraphicsStateGuardian::
3227 enable_clip_plane(int plane_id, bool enable) {
3228 }
3229 
3230 /**
3231  * Called immediately before bind_clip_plane() is called, this is intended to
3232  * provide the derived class a hook in which to set up some state (like
3233  * transform) that might apply to several planes.
3234  *
3235  * The sequence is: begin_bind_clip_planes() will be called, then one or more
3236  * bind_clip_plane() calls, then end_bind_clip_planes().
3237  */
3238 void GraphicsStateGuardian::
3239 begin_bind_clip_planes() {
3240 }
3241 
3242 /**
3243  * Called the first time a particular clipping plane has been bound to a given
3244  * id within a frame, this should set up the associated hardware (or API)
3245  * clipping plane with the plane's properties.
3246  */
3247 void GraphicsStateGuardian::
3248 bind_clip_plane(const NodePath &plane, int plane_id) {
3249 }
3250 
3251 /**
3252  * Called after before bind_clip_plane() has been called one or more times
3253  * (but before any geometry is issued or additional state is changed), this is
3254  * intended to clean up any temporary changes to the state that may have been
3255  * made by begin_bind_clip_planes().
3256  */
3257 void GraphicsStateGuardian::
3258 end_bind_clip_planes() {
3259 }
3260 
3261 /**
3262  * Assigns _target_texture and _target_tex_gen based on the _target_rs.
3263  */
3264 void GraphicsStateGuardian::
3265 determine_target_texture() {
3266  const TextureAttrib *target_texture = (const TextureAttrib *)
3267  _target_rs->get_attrib_def(TextureAttrib::get_class_slot());
3268  const TexGenAttrib *target_tex_gen = (const TexGenAttrib *)
3269  _target_rs->get_attrib_def(TexGenAttrib::get_class_slot());
3270 
3271  nassertv(target_texture != nullptr &&
3272  target_tex_gen != nullptr);
3273  _target_texture = target_texture;
3274  _target_tex_gen = target_tex_gen;
3275 
3276  if (_has_texture_alpha_scale) {
3278  PT(Texture) texture = TexturePool::get_alpha_scale_map();
3279 
3280  _target_texture = DCAST(TextureAttrib, _target_texture->add_on_stage(stage, texture));
3281  _target_tex_gen = DCAST(TexGenAttrib, _target_tex_gen->add_stage
3282  (stage, TexGenAttrib::M_constant, LTexCoord3(_current_color_scale[3], 0.0f, 0.0f)));
3283  }
3284 
3285  int max_texture_stages = get_max_texture_stages();
3286  _target_texture = _target_texture->filter_to_max(max_texture_stages);
3287  nassertv(_target_texture->get_num_on_stages() <= max_texture_stages);
3288 }
3289 
3290 /**
3291  * Assigns _target_shader based on the _target_rs.
3292  */
3293 void GraphicsStateGuardian::
3294 determine_target_shader() {
3295  if (_target_rs->_generated_shader != nullptr) {
3296  _target_shader = (const ShaderAttrib *)_target_rs->_generated_shader.p();
3297  } else {
3298  _target_shader = (const ShaderAttrib *)
3299  _target_rs->get_attrib_def(ShaderAttrib::get_class_slot());
3300  }
3301 }
3302 
3303 /**
3304  * Frees some memory that was explicitly allocated within the glgsg.
3305  */
3306 void GraphicsStateGuardian::
3307 free_pointers() {
3308 }
3309 
3310 /**
3311  * This is called by the associated GraphicsWindow when close_window() is
3312  * called. It should null out the _win pointer and possibly free any open
3313  * resources associated with the GSG.
3314  */
3315 void GraphicsStateGuardian::
3316 close_gsg() {
3317  // Protect from multiple calls, and also inform any other functions not to
3318  // try to create new stuff while we're going down.
3319  if (_closing_gsg) {
3320  return;
3321  }
3322  _closing_gsg = true;
3323 
3324  if (display_cat.is_debug()) {
3325  display_cat.debug()
3326  << this << " close_gsg " << get_type() << "\n";
3327  }
3328 
3329  // As tempting as it may be to try to release all the textures and geoms
3330  // now, we can't, because we might not be the currently-active GSG (this is
3331  // particularly important in OpenGL, which maintains one currently-active GL
3332  // state in each thread). If we start deleting textures, we'll be
3333  // inadvertently deleting textures from some other OpenGL state.
3334 
3335  // Fortunately, it doesn't really matter, since the graphics API will be
3336  // responsible for cleaning up anything we don't clean up explicitly. We'll
3337  // just let them drop.
3338 
3339  // Make sure that all the contexts belonging to the GSG are deleted.
3340  _prepared_objects.clear();
3341 #ifdef DO_PSTATS
3342  _pending_timer_queries.clear();
3343 #endif
3344 
3345  free_pointers();
3346 }
3347 
3348 /**
3349  * This is called internally when it is determined that things are just fubar.
3350  * It temporarily deactivates the GSG just so things don't get out of hand,
3351  * and throws an event so the application can deal with this if it needs to.
3352  */
3353 void GraphicsStateGuardian::
3354 panic_deactivate() {
3355  if (_active) {
3356  display_cat.error()
3357  << "Deactivating " << get_type() << ".\n";
3358  set_active(false);
3359  throw_event("panic-deactivate-gsg", this);
3360  }
3361 }
3362 
3363 /**
3364  * Called whenever the color or color scale is changed, if
3365  * _color_scale_via_lighting is true. This will rederive
3366  * _material_force_color and _light_color_scale appropriately.
3367  */
3368 void GraphicsStateGuardian::
3369 determine_light_color_scale() {
3370  if (_has_scene_graph_color) {
3371  // If we have a scene graph color, it, plus the color scale, goes directly
3372  // into the material; we don't color scale the lights--this allows an
3373  // alpha color scale to work properly.
3374  _has_material_force_color = true;
3375  _material_force_color = _scene_graph_color;
3376  _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
3377  if (!_color_blend_involves_color_scale && _color_scale_enabled) {
3378  _material_force_color.set(_scene_graph_color[0] * _current_color_scale[0],
3379  _scene_graph_color[1] * _current_color_scale[1],
3380  _scene_graph_color[2] * _current_color_scale[2],
3381  _scene_graph_color[3] * _current_color_scale[3]);
3382  }
3383 
3384  } else if (!_vertex_colors_enabled) {
3385  // We don't have a scene graph color, but we don't want to enable vertex
3386  // colors either, so we still need to force a white material color in
3387  // absence of any other color.
3388  _has_material_force_color = true;
3389  _material_force_color.set(1.0f, 1.0f, 1.0f, 1.0f);
3390  _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
3391  if (!_color_blend_involves_color_scale && _color_scale_enabled) {
3392  _material_force_color.componentwise_mult(_current_color_scale);
3393  }
3394 
3395  } else {
3396  // Otherise, leave the materials alone, but we might still scale the
3397  // lights.
3398  _has_material_force_color = false;
3399  _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
3400  if (!_color_blend_involves_color_scale && _color_scale_enabled) {
3401  _light_color_scale = _current_color_scale;
3402  }
3403  }
3404 }
3405 
3406 /**
3407  *
3408  */
3409 CPT(RenderState) GraphicsStateGuardian::
3410 get_unlit_state() {
3411  static CPT(RenderState) state = nullptr;
3412  if (state == nullptr) {
3413  state = RenderState::make(LightAttrib::make_all_off());
3414  }
3415  return state;
3416 }
3417 
3418 /**
3419  *
3420  */
3421 CPT(RenderState) GraphicsStateGuardian::
3422 get_unclipped_state() {
3423  static CPT(RenderState) state = nullptr;
3424  if (state == nullptr) {
3425  state = RenderState::make(ClipPlaneAttrib::make_all_off());
3426  }
3427  return state;
3428 }
3429 
3430 /**
3431  *
3432  */
3433 CPT(RenderState) GraphicsStateGuardian::
3434 get_untextured_state() {
3435  static CPT(RenderState) state = nullptr;
3436  if (state == nullptr) {
3437  state = RenderState::make(TextureAttrib::make_off());
3438  }
3439  return state;
3440 }
3441 
3442 /**
3443  * Should be called when a texture is encountered that needs to have its RAM
3444  * image reloaded, and get_incomplete_render() is true. This will fire off a
3445  * thread on the current Loader object that will request the texture to load
3446  * its image. The image will be available at some point in the future.
3447  * @returns a future object that can be used to check its status.
3448  */
3449 AsyncFuture *GraphicsStateGuardian::
3450 async_reload_texture(TextureContext *tc) {
3451  nassertr(_loader != nullptr, nullptr);
3452 
3453  int priority = 0;
3454  if (_current_display_region != nullptr) {
3455  priority = _current_display_region->get_texture_reload_priority();
3456  }
3457 
3458  string task_name = string("reload:") + tc->get_texture()->get_name();
3459  PT(AsyncTaskManager) task_mgr = _loader->get_task_manager();
3460 
3461  // See if we are already loading this task.
3462  AsyncTaskCollection orig_tasks = task_mgr->find_tasks(task_name);
3463  size_t num_tasks = orig_tasks.get_num_tasks();
3464  for (size_t ti = 0; ti < num_tasks; ++ti) {
3465  AsyncTask *task = orig_tasks.get_task(ti);
3466  if (task->is_exact_type(TextureReloadRequest::get_class_type()) &&
3467  ((TextureReloadRequest *)task)->get_texture() == tc->get_texture()) {
3468  // This texture is already queued to be reloaded. Don't queue it again,
3469  // just make sure the priority is updated, and return.
3470  task->set_priority(std::max(task->get_priority(), priority));
3471  return (AsyncFuture *)task;
3472  }
3473  }
3474 
3475  // This texture has not yet been queued to be reloaded. Queue it up now.
3476  PT(AsyncTask) request =
3477  new TextureReloadRequest(task_name,
3478  _prepared_objects, tc->get_texture(),
3479  _supports_compressed_texture);
3480  request->set_priority(priority);
3481  _loader->load_async(request);
3482  return (AsyncFuture *)request.p();
3483 }
3484 
3485 /**
3486  * Returns a shadow map for the given light source. If none exists, it is
3487  * created, using the given host window to create the buffer, or the current
3488  * window if that is set to NULL.
3489  */
3490 PT(Texture) GraphicsStateGuardian::
3491 get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host) {
3492  PandaNode *node = light_np.node();
3493  bool is_point = node->is_of_type(PointLight::get_class_type());
3494  nassertr(node->is_of_type(DirectionalLight::get_class_type()) ||
3495  node->is_of_type(Spotlight::get_class_type()) ||
3496  is_point, nullptr);
3497 
3498  LightLensNode *light = (LightLensNode *)node;
3499  if (light == nullptr || !light->_shadow_caster) {
3500  // This light does not have a shadow caster. Return a dummy shadow map
3501  // that is filled with a depth value of 1.
3502  if (node->is_of_type(PointLight::get_class_type())) {
3503  return get_dummy_shadow_map(Texture::TT_cube_map);
3504  } else {
3505  return get_dummy_shadow_map(Texture::TT_2d_texture);
3506  }
3507  }
3508 
3509  // The light's shadow map should have been created by set_shadow_caster().
3510  nassertr(light->_shadow_map != nullptr, nullptr);
3511 
3512  // See if we already have a buffer. If not, create one.
3513  if (light->_sbuffers.count(this) != 0) {
3514  // There's already a buffer - use that.
3515  return light->_shadow_map;
3516  }
3517 
3518  if (display_cat.is_debug()) {
3519  display_cat.debug()
3520  << "Constructing shadow buffer for light '" << light->get_name()
3521  << "', size=" << light->_sb_size[0] << "x" << light->_sb_size[1]
3522  << ", sort=" << light->_sb_sort << "\n";
3523  }
3524 
3525  if (host == nullptr) {
3526  nassertr(_current_display_region != nullptr, nullptr);
3527  host = _current_display_region->get_window();
3528  }
3529  nassertr(host != nullptr, nullptr);
3530 
3531  // Nope, the light doesn't have a buffer for our GSG. Make one.
3532  GraphicsOutput *sbuffer = make_shadow_buffer(light, light->_shadow_map,
3533  DCAST(GraphicsOutput, host));
3534 
3535  // Assign display region(s) to the buffer and camera
3536  if (is_point) {
3537  for (int i = 0; i < 6; ++i) {
3538  PT(DisplayRegion) dr = sbuffer->make_mono_display_region(0, 1, 0, 1);
3539  dr->set_lens_index(i);
3540  dr->set_target_tex_page(i);
3541  dr->set_camera(light_np);
3542  dr->set_clear_depth_active(true);
3543  }
3544  } else {
3545  PT(DisplayRegion) dr = sbuffer->make_mono_display_region(0, 1, 0, 1);
3546  dr->set_camera(light_np);
3547  dr->set_clear_depth_active(true);
3548  }
3549 
3550  light->_sbuffers[this] = sbuffer;
3551  return light->_shadow_map;
3552 }
3553 
3554 /**
3555  * Returns a dummy shadow map that can be used for a light of the given type
3556  * that does not cast shadows.
3557  */
3558 PT(Texture) GraphicsStateGuardian::
3559 get_dummy_shadow_map(Texture::TextureType texture_type) const {
3560  if (texture_type != Texture::TT_cube_map) {
3561  static PT(Texture) dummy_2d;
3562  if (dummy_2d == nullptr) {
3563  dummy_2d = new Texture("dummy-shadow-2d");
3564  dummy_2d->setup_2d_texture(1, 1, Texture::T_unsigned_byte, Texture::F_depth_component);
3565  dummy_2d->set_clear_color(1);
3567  // If we have the ARB_shadow extension, enable shadow filtering.
3568  dummy_2d->set_minfilter(SamplerState::FT_shadow);
3569  dummy_2d->set_magfilter(SamplerState::FT_shadow);
3570  } else {
3571  dummy_2d->set_minfilter(SamplerState::FT_linear);
3572  dummy_2d->set_magfilter(SamplerState::FT_linear);
3573  }
3574  }
3575  return dummy_2d;
3576  } else {
3577  static PT(Texture) dummy_cube;
3578  if (dummy_cube == nullptr) {
3579  dummy_cube = new Texture("dummy-shadow-cube");
3580  dummy_cube->setup_cube_map(1, Texture::T_unsigned_byte, Texture::F_depth_component);
3581  dummy_cube->set_clear_color(1);
3582  // Note: cube map shadow filtering doesn't seem to work in Cg.
3583  dummy_cube->set_minfilter(SamplerState::FT_linear);
3584  dummy_cube->set_magfilter(SamplerState::FT_linear);
3585  }
3586  return dummy_cube;
3587  }
3588 }
3589 
3590 /**
3591  * Creates a depth buffer for shadow mapping. A derived GSG can override this
3592  * if it knows that a particular buffer type works best for shadow rendering.
3593  */
3594 GraphicsOutput *GraphicsStateGuardian::
3595 make_shadow_buffer(LightLensNode *light, Texture *tex, GraphicsOutput *host) {
3596  bool is_point = light->is_of_type(PointLight::get_class_type());
3597 
3598  // Determine the properties for creating the depth buffer.
3600  fbp.set_depth_bits(shadow_depth_bits);
3601 
3602  WindowProperties props = WindowProperties::size(light->_sb_size);
3603  int flags = GraphicsPipe::BF_refuse_window;
3604  if (is_point) {
3605  flags |= GraphicsPipe::BF_size_square;
3606  }
3607 
3608  // Create the buffer. This is a bit tricky because make_output() can only
3609  // be called from the app thread, but it won't cause issues as long as the
3610  // pipe can precertify the buffer, which it can in most cases.
3612  light->get_name(), light->_sb_sort, fbp, props, flags, this, host);
3613 
3614  if (sbuffer != nullptr) {
3615  sbuffer->add_render_texture(tex, GraphicsOutput::RTM_bind_or_copy, GraphicsOutput::RTP_depth);
3616  }
3617  return sbuffer;
3618 }
3619 
3620 /**
3621  * Ensures that an appropriate shader has been generated for the given state.
3622  * This is stored in the _generated_shader field on the RenderState.
3623  */
3625 ensure_generated_shader(const RenderState *state) {
3626 #ifdef HAVE_CG
3627  const ShaderAttrib *shader_attrib;
3628  state->get_attrib_def(shader_attrib);
3629 
3630  if (shader_attrib->auto_shader()) {
3631  if (_shader_generator == nullptr) {
3632  if (!_supports_basic_shaders) {
3633  return;
3634  }
3635  _shader_generator = new ShaderGenerator(this);
3636  }
3637  if (state->_generated_shader == nullptr ||
3638  state->_generated_shader_seq != _generated_shader_seq) {
3640 
3641  // Currently we overload this flag to request vertex animation for the
3642  // shader generator.
3643  const ShaderAttrib *sattr;
3644  state->get_attrib_def(sattr);
3645  if (sattr->get_flag(ShaderAttrib::F_hardware_skinning)) {
3646  spec.set_hardware(4, true);
3647  }
3648 
3649  // Cache the generated ShaderAttrib on the shader state.
3650  state->_generated_shader = _shader_generator->synthesize_shader(state, spec);
3651  state->_generated_shader_seq = _generated_shader_seq;
3652  }
3653  }
3654 #endif
3655 }
3656 
3657 /**
3658  * Returns true if the GSG implements the extension identified by the given
3659  * string. This currently is only implemented by the OpenGL back-end.
3660  */
3662 has_extension(const string &extension) const {
3663  return false;
3664 }
3665 
3666 /**
3667  * Returns the vendor of the video card driver
3668  */
3671  return string();
3672 }
3673 
3674 /**
3675  * Returns GL_Renderer
3676  */
3678  return string();
3679 }
3680 
3681 /**
3682  * Returns driver version This has an implementation-defined meaning, and may
3683  * be "" if the particular graphics implementation does not provide a way to
3684  * query this information.
3685  */
3688  return string();
3689 }
3690 
3691 /**
3692  * Returns major version of the video driver. This has an implementation-
3693  * defined meaning, and may be -1 if the particular graphics implementation
3694  * does not provide a way to query this information.
3695  */
3698  return -1;
3699 }
3700 
3701 /**
3702  * Returns the minor version of the video driver. This has an implementation-
3703  * defined meaning, and may be -1 if the particular graphics implementation
3704  * does not provide a way to query this information.
3705  */
3708  return -1;
3709 }
3710 
3711 /**
3712  * Returns the major version of the shader model.
3713  */
3716  return -1;
3717 }
3718 
3719 /**
3720  * Returns the minor version of the shader model.
3721  */
3724  return -1;
3725 }
3726 
3727 std::ostream &
3728 operator << (std::ostream &out, GraphicsStateGuardian::ShaderModel sm) {
3729  static const char *sm_strings[] = {"none", "1.1", "2.0", "2.x", "3.0", "4.0", "5.0", "5.1"};
3730  nassertr(sm >= 0 && sm <= GraphicsStateGuardian::SM_51, out);
3731  out << sm_strings[sm];
3732  return out;
3733 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A light source that seems to illuminate all points in space at once.
Definition: ambientLight.h:26
This class represents a thread-safe handle to a promised future result of an asynchronous operation,...
Definition: asyncFuture.h:61
A list of tasks, for instance as returned by some of the AsyncTaskManager query functions.
get_num_tasks
Returns the number of AsyncTasks in the collection.
get_task
Returns the nth AsyncTask in the collection.
A class to manage a loose queue of isolated tasks, which can be performed either synchronously (in th...
This class represents a concrete task performed by an AsyncManager.
Definition: asyncTask.h:32
get_priority
Returns the task's current priority value.
Definition: asyncTask.h:116
set_priority
Specifies a priority value for this task.
Definition: asyncTask.h:116
void clear_bit(int index)
Sets the nth bit off.
Definition: bitMask.I:129
void clear()
Sets all the bits in the BitMask off.
Definition: bitMask.I:395
This is a base class for those kinds of SavedContexts that occupy an easily-measured (and substantial...
Definition: bufferContext.h:38
This is a const pointer to an InternalName, and should be used in lieu of a CPT(InternalName) in func...
Definition: internalName.h:193
This functions similarly to a LightAttrib.
get_on_plane
Returns the nth plane enabled by the attribute, sorted in render order.
get_num_on_planes
Returns the number of planes that are enabled by the attribute.
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.h:91
get_dt
Returns the elapsed time for the previous frame: the number of seconds elapsed between the last two c...
Definition: clockObject.h:99
get_frame_count
Returns the number of times tick() has been called since the ClockObject was created,...
Definition: clockObject.h:94
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
Indicates what color should be applied to renderable geometry.
Definition: colorAttrib.h:27
get_color
If the type is T_flat or T_off, this returns the color that will be applied to geometry.
Definition: colorAttrib.h:47
get_color_type
Returns the type of color specified by this ColorAttrib.
Definition: colorAttrib.h:46
Applies a scale to colors in the scene graph and on vertices.
bool has_alpha_scale() const
Returns true if the ColorScaleAttrib has a non-identity scale in the alpha component (ignoring RGB),...
has_scale
Returns true if the ColorScaleAttrib has a non-identity scale, false otherwise (in which case it migh...
get_scale
Returns the scale to be applied to colors.
bool is_identity() const
Returns true if the ColorScaleAttrib is an identity attrib, false if it is either an off attrib or it...
A light shining from infinitely far away in a particular direction, like sunlight.
get_direction
Returns the direction in which the light is aimed.
get_specular_color
Returns the color of specular highlights generated by the light.
Encapsulates the data from a DisplayRegion, pre-fetched for one stage of the pipeline.
GraphicsOutput * get_window() const
Returns the GraphicsOutput that this DisplayRegion is ultimately associated with, or NULL if no windo...
int get_tex_view_offset()
Returns the current texture view offset for this DisplayRegion.
Lens::StereoChannel get_stereo_channel() const
Returns whether the DisplayRegion is specified as the left or right channel of a stereo pair,...
A rectangular subregion within a window for rendering into.
Definition: displayRegion.h:57
set_camera
Sets the camera that is associated with this DisplayRegion.
Definition: displayRegion.h:94
set_lens_index
Sets the lens index, allows for multiple lenses to be attached to a camera.
This is a base class for GraphicsWindow (actually, GraphicsOutput) and DisplayRegion,...
Applies a Fog to the geometry at and below this node.
Definition: fogAttrib.h:25
get_fog
If the FogAttrib is not an 'off' FogAttrib, returns the fog that is associated.
Definition: fogAttrib.h:38
Specifies how atmospheric fog effects are applied to geometry.
Definition: fog.h:41
get_color
Returns the color of the fog.
Definition: fog.h:68
get_exp_density
Returns the density of the fog for exponential calculations.
Definition: fog.h:86
void get_linear_range(PN_stdfloat &onset, PN_stdfloat &opaque)
Retrieves the current onset and offset ranges.
Definition: fog.cxx:173
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
int get_buffer_mask() const
Converts the non-aux bitplanes of the framebuffer into a RenderBuffer::Type.
This is a special class object that holds all the information returned by a particular GSG to indicat...
Definition: geomContext.h:34
Objects of this class are used to convert vertex data from a Geom into a format suitable for passing ...
Definition: geomMunger.h:50
static void unregister_mungers_for_gsg(GraphicsStateGuardianBase *gsg)
Removes all the mungers from the registry that are associated with the indicated GSG.
Definition: geomMunger.I:52
Encapsulates the data from a Geom, pre-fetched for one stage of the pipeline.
Definition: geom.h:405
Encapsulates the data from a GeomPrimitive, pre-fetched for one stage of the pipeline.
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
This object describes how the vertex animation, if any, represented in a GeomVertexData is encoded.
void set_hardware(int num_transforms, bool indexed_transforms)
Specifies that vertex animation is to be performed by the graphics hardware (or at least by the graph...
This is the data for one array of a GeomVertexData structure.
Encapsulates the data from a GeomVertexData, pre-fetched for one stage of the pipeline.
A container for geometry primitives.
Definition: geom.h:54
This class is the main interface to controlling the render process.
bool remove_window(GraphicsOutput *window)
Removes the indicated window or offscreen buffer from the set of windows that will be processed when ...
GraphicsOutput * make_output(GraphicsPipe *pipe, const std::string &name, int sort, const FrameBufferProperties &fb_prop, const WindowProperties &win_prop, int flags, GraphicsStateGuardian *gsg=nullptr, GraphicsOutput *host=nullptr)
Creates a new window (or buffer) and returns it.
An abstract base class for GraphicsOutput, for all the usual reasons.
This is a base class for the various different classes that represent the result of a frame of render...
void add_render_texture(Texture *tex, RenderTextureMode mode, RenderTexturePlane bitplane=RTP_COUNT)
Creates a new Texture object, suitable for rendering the contents of this buffer into,...
DisplayRegion * make_mono_display_region()
Creates a new DisplayRegion that covers the entire window.
unsigned int get_right_eye_color_mask() const
Returns the color mask in effect when rendering a right-eye view in red_blue stereo mode.
get_swap_eyes
Returns the current setting of the "swap eyes" flag.
unsigned int get_left_eye_color_mask() const
Returns the color mask in effect when rendering a left-eye view in red_blue stereo mode.
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
static void remove_gsg(GraphicsStateGuardianBase *gsg)
Called by a GSG destructor to remove a GSG from the available list.
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,...
virtual bool draw_points(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of disconnected points.
virtual bool draw_trifans(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of triangle fans.
virtual void clear_before_callback()
Resets any non-standard graphics state that might give a callback apoplexy.
get_pipe
Returns the graphics pipe on which this GSG was created.
virtual bool depth_offset_decals()
Returns true if this GSG can implement decals using a DepthOffsetAttrib, or false if that is unreliab...
get_gamma
Get the current gamma setting.
virtual bool begin_draw_primitives(const GeomPipelineReader *geom_reader, const GeomVertexDataPipelineReader *data_reader, bool force)
Called before a sequence of draw_primitive() functions are called, this should prepare the vertex dat...
virtual bool update_texture(TextureContext *tc, bool force)
Ensures that the current Texture data is refreshed onto the GSG.
set_scene
Sets the SceneSetup object that indicates the initial camera position, etc.
GraphicsEngine * get_engine() const
Returns the graphics engine that created this GSG.
static TextureStage * get_alpha_scale_texture_stage()
Returns the TextureStage that will be used to apply an alpha scale, if get_alpha_scale_via_texture() ...
virtual TextureContext * prepare_texture(Texture *tex, int view)
Creates whatever structures the GSG requires to represent the texture internally, and returns a newly...
get_supports_multisample
Returns true if this particular GSG supports using the multisample bits to provide antialiasing,...
virtual bool draw_triangles(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of disconnected triangles.
get_driver_version_minor
Returns the minor version of the video driver.
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,...
virtual bool draw_lines(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of disconnected line segments.
virtual void release_shader_buffer(BufferContext *ibc)
Frees the resources previously allocated via a call to prepare_data(), including deleting the BufferC...
set_active
Sets the active flag associated with the GraphicsStateGuardian.
void traverse_prepared_textures(TextureCallback *func, void *callback_arg)
Calls the indicated function on all currently-prepared textures, or until the callback function retur...
get_flash_texture
Returns the current "flash texture", if any, or NULL if none.
virtual bool prepare_lens()
Makes the current lens (whichever lens was most recently specified with set_scene()) active,...
static void create_gamma_table(PN_stdfloat gamma, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table)
Create a gamma table.
virtual void clear_state_and_transform()
Forgets the current graphics state and current transform, so that the next call to set_state_and_tran...
get_driver_vendor
Returns the vendor of the video card driver.
virtual VertexBufferContext * prepare_vertex_buffer(GeomVertexArrayData *data)
Prepares the indicated buffer for retained-mode rendering.
virtual bool draw_patches(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of "patches", which can only be processed by a tessellation shader.
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.
virtual void prepare_display_region(DisplayRegionPipelineReader *dr)
Makes the specified DisplayRegion current.
get_driver_shader_version_minor
Returns the minor version of the shader model.
virtual void release_sampler(SamplerContext *sc)
Frees the resources previously allocated via a call to prepare_sampler(), including deleting the Samp...
get_prepared_objects
Returns the set of texture and geom objects that have been prepared with this GSG (and possibly other...
virtual void do_issue_light()
This implementation of do_issue_light() assumes we have a limited number of hardware lights available...
get_driver_renderer
Returns GL_Renderer.
void flush_timer_queries()
Called by the graphics engine on the draw thread to check the status of the running timer queries and...
virtual void release_vertex_buffer(VertexBufferContext *vbc)
Frees the resources previously allocated via a call to prepare_data(), including deleting the VertexB...
void do_issue_color()
This method is defined in the base class because it is likely that this functionality will be used fo...
const LMatrix4 * fetch_specified_part(Shader::ShaderMatInput input, InternalName *name, LMatrix4 &t, int index)
See fetch_specified_value.
virtual CoordinateSystem get_internal_coordinate_system() const
Returns the coordinate system used internally by the GSG.
virtual bool extract_texture_data(Texture *tex)
This method should only be called by the GraphicsEngine.
const LMatrix4 * fetch_specified_member(const NodePath &np, CPT_InternalName member, LMatrix4 &t)
Given a NodePath passed into a shader input that is a structure, fetches the value for the given memb...
get_driver_version_major
Returns major version of the video driver.
get_driver_shader_version_major
Returns the major version of the shader model.
virtual void release_geom(GeomContext *gc)
Frees the resources previously allocated via a call to prepare_geom(), including deleting the GeomCon...
get_supports_shadow_filter
Returns true if this particular GSG supports the filter mode FT_shadow for depth textures.
virtual SamplerContext * prepare_sampler(const SamplerState &sampler)
Creates whatever structures the GSG requires to represent the sampler internally, and returns a newly...
RenderBuffer get_render_buffer(int buffer_type, const FrameBufferProperties &prop)
Returns a RenderBuffer object suitable for operating on the requested set of buffers.
virtual void ensure_generated_shader(const RenderState *state)
Ensures that an appropriate shader has been generated for the given state.
get_max_texture_stages
Returns the maximum number of simultaneous textures that may be applied to geometry with multitexturi...
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 bool draw_lines_adj(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of disconnected line segments with adjacency information.
virtual bool has_extension(const std::string &extension) const
Returns true if the GSG implements the extension identified by the given string.
virtual bool draw_linestrips_adj(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of line strips with adjacency information.
virtual void end_scene()
Called between begin_frame() and end_frame() to mark the end of drawing commands for a "scene" (usual...
virtual void release_shader(ShaderContext *sc)
Releases the resources allocated by prepare_shader.
virtual GeomContext * prepare_geom(Geom *geom)
Prepares the indicated Geom for retained-mode rendering, by creating whatever structures are necessar...
virtual void reset()
Resets all internal state as if the gsg were newly created.
virtual int get_supported_geom_rendering() const
Returns the union of Geom::GeomRendering values that this particular GSG can support directly.
virtual void release_texture(TextureContext *tc)
Frees the resources previously allocated via a call to prepare_texture(), including deleting the Text...
get_driver_version
Returns driver version This has an implementation-defined meaning, and may be "" if the particular gr...
PN_stdfloat compute_distance_to(const LPoint3 &point) const
This function will compute the distance to the indicated point, assumed to be in eye coordinates,...
virtual void begin_occlusion_query()
Begins a new occlusion query.
const LMatrix4 * fetch_specified_value(Shader::ShaderMatSpec &spec, int altered)
The gsg contains a large number of useful matrices:
virtual IndexBufferContext * prepare_index_buffer(GeomPrimitive *data)
Prepares the indicated buffer for retained-mode rendering.
virtual void finish_decal()
Called during draw to clean up after decals are finished.
virtual bool draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of triangle strips.
get_scene
Returns the current SceneSetup object.
set_flash_texture
Sets the "flash texture".
virtual bool draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of line strips.
virtual void set_state_and_transform(const RenderState *state, const TransformState *transform)
Simultaneously resets the render state and the transform state.
virtual bool get_supports_cg_profile(const std::string &name) const
Returns true if this particular GSG supports the specified Cg Shader Profile.
virtual bool draw_tristrips_adj(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of triangle strips with adjacency information.
virtual void clear(DrawableRegion *clearable)
Clears the framebuffer within the current DisplayRegion, according to the flags indicated by the give...
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...
set_coordinate_system
Changes the coordinate system in effect on this particular gsg.
virtual BufferContext * prepare_shader_buffer(ShaderBuffer *data)
Prepares the indicated buffer for retained-mode rendering.
virtual void remove_window(GraphicsOutputBase *window)
This is simply a transparent call to GraphicsEngine::remove_window().
virtual void restore_gamma()
Restore original gamma setting.
virtual bool draw_triangles_adj(const GeomPrimitivePipelineReader *reader, bool force)
Draws a series of disconnected triangles with adjacency information.
virtual void dispatch_compute(int size_x, int size_y, int size_z)
Dispatches a currently bound compute shader using the given work group counts.
virtual void release_index_buffer(IndexBufferContext *ibc)
Frees the resources previously allocated via a call to prepare_data(), including deleting the IndexBu...
void clear_flash_texture()
Resets the "flash texture", so that no textures will flash.
virtual void end_draw_primitives()
Called after a sequence of draw_primitive() functions are called, this should do whatever cleanup is ...
virtual ShaderContext * prepare_shader(Shader *shader)
Compile a vertex/fragment shader body.
virtual bool begin_scene()
Called between begin_frame() and end_frame() to mark the beginning of drawing commands for a "scene" ...
This is a special class object that holds all the information returned by a particular GSG to indicat...
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
get_basename
Return the name represented by just this particular InternalName object, ignoring its parents names.
Definition: internalName.h:62
get_name
Returns the complete name represented by the InternalName and all of its parents.
Definition: internalName.h:61
get_parent
Return the parent of this InternalName.
Definition: internalName.h:60
A node that contains a Lens.
Definition: lensNode.h:29
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:47
A base class for any number of different kinds of lenses, linear and otherwise.
Definition: lens.h:41
virtual bool is_linear() const
Returns true if the lens represents a linear projection (e.g.
Definition: lens.cxx:540
get_far
Returns the position of the far plane (or cylinder, sphere, whatever).
Definition: lens.h:114
get_near
Returns the position of the near plane (or cylinder, sphere, whatever).
Definition: lens.h:113
const LMatrix4 & get_projection_mat_inv(StereoChannel channel=SC_mono) const
Returns the matrix that transforms from a 2-d point on the film to a 3-d vector in space,...
Definition: lens.I:573
PN_stdfloat get_hfov() const
Returns the horizontal component of fov only.
Definition: lens.I:344
get_nodal_point
Returns the center point of the lens: the point from which the lens is viewing.
Definition: lens.h:129
get_coordinate_system
Returns the coordinate system that all 3-d computations are performed within for this Lens.
Definition: lens.h:74
const LVector3 & get_view_vector() const
Returns the axis along which the lens is facing.
Definition: lens.cxx:214
const LMatrix4 & get_projection_mat(StereoChannel channel=SC_mono) const
Returns the complete transformation matrix from a 3-d point in space to a point on the film,...
Definition: lens.I:563
Indicates which set of lights should be considered "on" to illuminate geometry at this level and belo...
Definition: lightAttrib.h:30
bool has_any_on_light() const
Returns true if any light is turned on by the attrib, false otherwise.
Definition: lightAttrib.I:63
size_t get_num_non_ambient_lights() const
Returns the number of non-ambient lights that are turned on by this attribute.
Definition: lightAttrib.I:35
get_on_light
Returns the nth light turned on by the attribute, sorted in render order.
Definition: lightAttrib.h:74
A derivative of Light and of Camera.
Definition: lightLensNode.h:33
Similar to MutexHolder, but for a light reentrant mutex.
The abstract interface to all kinds of lights.
Definition: light.h:38
virtual PN_stdfloat get_exponent() const
For spotlights, returns the exponent that controls the amount of light falloff from the center of the...
Definition: light.cxx:137
virtual const LVecBase3 & get_attenuation() const
Returns the terms of the attenuation equation for the light.
Definition: light.cxx:157
get_color
Returns the basic color of the light.
Definition: light.h:49
virtual const LColor & get_specular_color() const
Returns the color of specular highlights generated by the light.
Definition: light.cxx:146
static Loader * get_global_ptr()
Returns a pointer to the global Loader.
Definition: loader.I:212
Indicates which, if any, material should be applied to geometry.
bool is_off() const
Returns true if the MaterialAttrib is an 'off' MaterialAttrib, indicating that it should disable the ...
get_material
If the MaterialAttrib is not an 'off' MaterialAttrib, returns the material that is associated.
Defines the way an object appears in the presence of lighting.
Definition: material.h:43
get_ambient
Returns the ambient color setting, if it has been set.
Definition: material.h:114
get_emission
Returns the emission color setting, if it has been set.
Definition: material.h:120
get_base_color
Returns the base_color color setting, if it has been set.
Definition: material.h:112
get_refractive_index
Returns the index of refraction, or 1 if none has been set for this material.
Definition: material.h:126
get_specular
Returns the specular color setting, if it has been set.
Definition: material.h:118
get_metallic
Returns the metallic setting, if it has been set.
Definition: material.h:124
get_roughness
Returns the roughness previously specified by set_roughness.
Definition: material.h:123
get_shininess
Returns the shininess exponent of the material.
Definition: material.h:122
get_diffuse
Returns the diffuse color setting, if it has been set.
Definition: material.h:116
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
Definition: nodePath.I:776
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:795
Returned from a GSG in response to begin_occlusion_query() .
Manages the communications to report statistics via a network connection to a remote PStatServer.
Definition: pStatClient.h:263
static bool is_connected()
Returns true if the client believes it is connected to a working PStatServer, false otherwise.
Definition: pStatClient.h:291
Defines the details about the Collectors: the name, the suggested color, etc.
A lightweight class that represents a single element that may be timed and/or counted via stats.
This is a special type of PStatTimer that also uses a timer query on the GSG to measure how long a ta...
Definition: pStatGPUTimer.h:36
A lightweight class that represents a single thread of execution to PStats.
Definition: pStatThread.h:28
void add_frame(const PStatFrameData &frame_data)
This is a slightly lower-level version of new_frame that also specifies the data to send for this fra...
Definition: pStatThread.cxx:38
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
virtual bool is_ambient_light() const
Returns true if this is an AmbientLight, false if it is not a light, or it is some other kind of ligh...
Definition: pandaNode.cxx:2104
virtual Light * as_light()
Cross-casts the node to a Light pointer, if it is one of the four kinds of Light nodes,...
Definition: pandaNode.cxx:2095
A node that contains a plane.
Definition: planeNode.h:36
const LPlane & get_plane() const
Returns the plane represented by the PlaneNode.
Definition: planeNode.I:54
int get_clip_effect() const
Returns the clip_effect bits for this clip plane.
Definition: planeNode.I:128
A light originating from a single point in space, and shining in all directions.
Definition: pointLight.h:25
get_specular_color
Returns the color of specular highlights generated by the light.
Definition: pointLight.h:45
get_point
Returns the point in space at which the light is located.
Definition: pointLight.h:57
get_attenuation
Returns the terms of the attenuation equation for the light.
Definition: pointLight.h:49
A table of objects that are saved within the graphics context for reference by handle later.
Similar to MutexHolder, but for a reentrant mutex.
Definition: reMutexHolder.h:25
A RenderBuffer is an arbitrary subset of the various layers (depth buffer, color buffer,...
Definition: renderBuffer.h:27
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
This is a special class object that holds a handle to the sampler state object given by the graphics ...
Represents a set of settings that indicate how a texture is sampled.
Definition: samplerState.h:36
This object holds the camera position, etc., and other general setup information for rendering a part...
Definition: sceneSetup.h:32
const Lens * get_lens() const
Returns the particular Lens used for rendering.
Definition: sceneSetup.I:131
bool auto_shader() const
If true, then this ShaderAttrib does not contain an explicit shader - instead, it requests the automa...
Definition: shaderAttrib.I:71
This is a generic buffer object that lives in graphics memory.
Definition: shaderBuffer.h:33
The ShaderContext is meant to contain the compiled version of a shader string.
Definition: shaderContext.h:31
Definition: shader.h:49
const Key & get_key(size_t n) const
Returns the key in the nth entry of the table.
int store(const Key &key, const Value &data)
Records the indicated key/data pair in the map.
const Value & get_data(size_t n) const
Returns the data in the nth entry of the table.
int find(const Key &key) const
Searches for the indicated key in the table.
bool remove(const Key &key)
Removes the indicated key and its associated data from the table.
void remove_element(size_t n)
Removes the nth entry from the table.
bool is_empty() const
Returns true if the table is empty; i.e.
size_t get_num_entries() const
Returns the number of active entries in the table.
A sphere light is like a point light, except that it represents a sphere with a radius,...
Definition: sphereLight.h:28
A light originating from a single point in space, and shining in a particular direction,...
Definition: spotlight.h:32
get_specular_color
Returns the color of specular highlights generated by the light.
Definition: spotlight.h:56
get_exponent
Returns the exponent that controls the amount of light falloff from the center of the spotlight.
Definition: spotlight.h:51
get_attenuation
Returns the terms of the attenuation equation for the light.
Definition: spotlight.h:60
Computes texture coordinates for geometry automatically based on vertex position and/or normal.
Definition: texGenAttrib.h:32
Applies a transform matrix to UV's before they are rendered.
Indicates the set of TextureStages and their associated Textures that should be applied to (or remove...
Definition: textureAttrib.h:31
get_num_on_ff_stages
Returns the number of on-stages that are relevant to the classic fixed function pipeline.
Definition: textureAttrib.h:58
get_num_on_stages
Returns the number of stages that are turned on by the attribute.
Definition: textureAttrib.h:55
get_on_texture
Returns the texture associated with the indicated stage, or NULL if no texture is associated.
Definition: textureAttrib.h:69
get_on_stage
Returns the nth stage turned on by the attribute, sorted in render order.
Definition: textureAttrib.h:55
get_on_sampler
Returns the sampler associated with the indicated stage, or the one associated with its texture if no...
Definition: textureAttrib.h:72
get_on_ff_stage
Returns the nth stage turned on by the attribute, sorted in render order, including only those releva...
Definition: textureAttrib.h:58
This is a special class object that holds all the information returned by a particular GSG to indicat...
Texture * get_texture() const
Returns the pointer to the associated Texture object.
static Texture * get_alpha_scale_map()
Returns a standard Texture object that has been created with Texture::generate_alpha_scale_map().
Definition: texturePool.I:144
This loader request will call Texture::get_ram_image() in a sub-thread, to force the texture's image ...
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
get_color
return the color for this stage
Definition: textureStage.h:200
get_tex_view_offset
Returns the current setting of the tex_view_offset.
Definition: textureStage.h:205
get_mode
Return the mode of this stage.
Definition: textureStage.h:198
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
int get_pad_y_size() const
Returns size of the pad region.
Definition: texture.I:629
get_y_size
Returns the height of the texture image in texels.
Definition: texture.h:346
get_z_size
Returns the depth of the texture image in texels.
Definition: texture.h:350
int get_pad_x_size() const
Returns size of the pad region.
Definition: texture.I:620
int get_pad_z_size() const
Returns size of the pad region.
Definition: texture.I:638
get_x_size
Returns the width of the texture image in texels.
Definition: texture.h:342
A thread; that is, a lightweight process.
Definition: thread.h:46
Indicates a coordinate-system transform on vertices.
get_mat
Returns the matrix that describes the transform.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:38
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
This is a special class object that holds all the information returned by a particular GSG to indicat...
A container for the various kinds of properties we might ask to have on a graphics window before we o...
static WindowProperties size(const LVecBase2i &size)
Returns a WindowProperties structure with only the size specified.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT(OcclusionQueryContext) GraphicsStateGuardian
Ends a previous call to begin_occlusion_query().
CPT(TransformState) GraphicsStateGuardian
Given a lens, this function calculates the appropriate projection matrix for this gsg.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.