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