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  if (basename == "color" || basename == "diffuse") {
1437  t.set_row(3, _light_color_scale);
1438  return &t;
1439  } else if (basename == "specular") {
1440  return &LMatrix4::ones_mat();
1441  }
1442  }
1443  return fetch_specified_member(NodePath(), name, t);
1444  }
1445  case Shader::SMO_light_source_i_packed: {
1446  // The light matrix contains COLOR, ATTENUATION, POSITION, VIEWVECTOR
1447  const LightAttrib *target_light;
1448  _target_rs->get_attrib_def(target_light);
1449 
1450  // We don't count ambient lights, which would be pretty silly to handle
1451  // via this mechanism.
1452  size_t num_lights = target_light->get_num_non_ambient_lights();
1453  if (index >= 0 && (size_t)index < num_lights) {
1454  NodePath np = target_light->get_on_light((size_t)index);
1455  nassertr(!np.is_empty(), &LMatrix4::ident_mat());
1456  PandaNode *node = np.node();
1457  Light *light = node->as_light();
1458  nassertr(light != nullptr, &LMatrix4::zeros_mat());
1459  t.set_row(0, light->get_color());
1460  t.set_row(1, light->get_attenuation());
1461 
1462  LMatrix4 mat = np.get_net_transform()->get_mat() *
1463  _scene_setup->get_world_transform()->get_mat();
1464 
1465  if (node->is_of_type(DirectionalLight::get_class_type())) {
1466  LVecBase3 d = mat.xform_vec(((const DirectionalLight *)node)->get_direction());
1467  d.normalize();
1468  t.set_row(2, LVecBase4(d, 0));
1469  t.set_row(3, LVecBase4(-d, 0));
1470 
1471  } else if (node->is_of_type(LightLensNode::get_class_type())) {
1472  const Lens *lens = ((const LightLensNode *)node)->get_lens();
1473 
1474  LPoint3 p = mat.xform_point(lens->get_nodal_point());
1475  t.set_row(3, LVecBase4(p));
1476 
1477  // For shadowed point light we need to store near/far.
1478  // For spotlight we need to store cutoff angle.
1479  if (node->is_of_type(Spotlight::get_class_type())) {
1480  PN_stdfloat cutoff = ccos(deg_2_rad(lens->get_hfov() * 0.5f));
1481  LVecBase3 d = -(mat.xform_vec(lens->get_view_vector()));
1482  t.set_cell(1, 3, ((const Spotlight *)node)->get_exponent());
1483  t.set_row(2, LVecBase4(d, cutoff));
1484 
1485  } else if (node->is_of_type(PointLight::get_class_type())) {
1486  t.set_cell(1, 3, lens->get_far());
1487  t.set_cell(3, 3, lens->get_near());
1488 
1489  if (node->is_of_type(SphereLight::get_class_type())) {
1490  t.set_cell(2, 3, ((const SphereLight *)node)->get_radius());
1491  }
1492  }
1493  }
1494  } else if (index == 0) {
1495  // Apply the default OpenGL lights otherwise.
1496  // Special exception for light 0, which defaults to white.
1497  t.set_row(0, _light_color_scale);
1498  }
1499  return &t;
1500  }
1501  default:
1502  nassertr(false /*should never get here*/, &LMatrix4::ident_mat());
1503  return &LMatrix4::ident_mat();
1504  }
1505 }
1506 
1507 /**
1508  * Given a NodePath passed into a shader input that is a structure, fetches
1509  * the value for the given member.
1510  */
1511 const LMatrix4 *GraphicsStateGuardian::
1512 fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) {
1513  // This system is not ideal. It will be improved in the future.
1514  static const CPT_InternalName IN_color("color");
1515  static const CPT_InternalName IN_ambient("ambient");
1516  static const CPT_InternalName IN_diffuse("diffuse");
1517  static const CPT_InternalName IN_specular("specular");
1518  static const CPT_InternalName IN_position("position");
1519  static const CPT_InternalName IN_halfVector("halfVector");
1520  static const CPT_InternalName IN_spotDirection("spotDirection");
1521  static const CPT_InternalName IN_spotCutoff("spotCutoff");
1522  static const CPT_InternalName IN_spotCosCutoff("spotCosCutoff");
1523  static const CPT_InternalName IN_spotExponent("spotExponent");
1524  static const CPT_InternalName IN_attenuation("attenuation");
1525  static const CPT_InternalName IN_constantAttenuation("constantAttenuation");
1526  static const CPT_InternalName IN_linearAttenuation("linearAttenuation");
1527  static const CPT_InternalName IN_quadraticAttenuation("quadraticAttenuation");
1528  static const CPT_InternalName IN_shadowViewMatrix("shadowViewMatrix");
1529 
1530  PandaNode *node = nullptr;
1531  if (!np.is_empty()) {
1532  node = np.node();
1533  }
1534 
1535  if (attrib == IN_color) {
1536  if (node == nullptr) {
1537  return &LMatrix4::ident_mat();
1538  }
1539  Light *light = node->as_light();
1540  nassertr(light != nullptr, &LMatrix4::ident_mat());
1541  LColor c = light->get_color();
1542  c.componentwise_mult(_light_color_scale);
1543  t.set_row(3, c);
1544  return &t;
1545 
1546  } else if (attrib == IN_ambient) {
1547  if (node == nullptr) {
1548  return &LMatrix4::ident_mat();
1549  }
1550  Light *light = node->as_light();
1551  nassertr(light != nullptr, &LMatrix4::ident_mat());
1552  if (node->is_ambient_light()) {
1553  LColor c = light->get_color();
1554  c.componentwise_mult(_light_color_scale);
1555  t.set_row(3, c);
1556  } else {
1557  // Non-ambient lights don't currently have an ambient color in Panda3D.
1558  t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
1559  }
1560  return &t;
1561 
1562  } else if (attrib == IN_diffuse) {
1563  if (node == nullptr) {
1564  return &LMatrix4::ident_mat();
1565  }
1566  Light *light = node->as_light();
1567  nassertr(light != nullptr, &LMatrix4::ones_mat());
1568  if (node->is_ambient_light()) {
1569  // Ambient light has no diffuse color.
1570  t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f));
1571  } else {
1572  LColor c = light->get_color();
1573  c.componentwise_mult(_light_color_scale);
1574  t.set_row(3, c);
1575  }
1576  return &t;
1577 
1578  } else if (attrib == IN_specular) {
1579  if (node == nullptr) {
1580  return &LMatrix4::ident_mat();
1581  }
1582  Light *light = node->as_light();
1583  nassertr(light != nullptr, &LMatrix4::ones_mat());
1584  t.set_row(3, light->get_specular_color());
1585  return &t;
1586 
1587  } else if (attrib == IN_position) {
1588  if (np.is_empty()) {
1589  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);
1590  return &t;
1591  } else if (node->is_ambient_light()) {
1592  // Ambient light has no position.
1593  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1594  return &t;
1595  } else if (node->is_of_type(DirectionalLight::get_class_type())) {
1596  DirectionalLight *light;
1597  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1598 
1599  CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent());
1600  LVector3 dir = -(light->get_direction() * transform->get_mat());
1601  dir *= _scene_setup->get_cs_world_transform()->get_mat();
1602  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 0);
1603  return &t;
1604  } else {
1605  LightLensNode *light;
1606  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1607  Lens *lens = light->get_lens();
1608  nassertr(lens != nullptr, &LMatrix4::ident_mat());
1609 
1610  CPT(TransformState) transform =
1611  _scene_setup->get_cs_world_transform()->compose(
1612  np.get_transform(_scene_setup->get_scene_root().get_parent()));
1613 
1614  const LMatrix4 &light_mat = transform->get_mat();
1615  LPoint3 pos = lens->get_nodal_point() * light_mat;
1616  t = LMatrix4::translate_mat(pos);
1617  return &t;
1618  }
1619 
1620  } else if (attrib == IN_halfVector) {
1621  if (np.is_empty()) {
1622  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);
1623  return &t;
1624  } else if (node->is_ambient_light()) {
1625  // Ambient light has no half-vector.
1626  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1627  return &t;
1628  } else if (node->is_of_type(DirectionalLight::get_class_type())) {
1629  DirectionalLight *light;
1630  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1631 
1632  CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent());
1633  LVector3 dir = -(light->get_direction() * transform->get_mat());
1634  dir *= _scene_setup->get_cs_world_transform()->get_mat();
1635  dir.normalize();
1636  dir += LVector3(0, 0, 1);
1637  dir.normalize();
1638  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 1);
1639  return &t;
1640  } else {
1641  LightLensNode *light;
1642  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1643  Lens *lens = light->get_lens();
1644  nassertr(lens != nullptr, &LMatrix4::ident_mat());
1645 
1646  CPT(TransformState) transform =
1647  _scene_setup->get_cs_world_transform()->compose(
1648  np.get_transform(_scene_setup->get_scene_root().get_parent()));
1649 
1650  const LMatrix4 &light_mat = transform->get_mat();
1651  LPoint3 pos = lens->get_nodal_point() * light_mat;
1652  pos.normalize();
1653  pos += LVector3(0, 0, 1);
1654  pos.normalize();
1655  t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pos[0],pos[1],pos[2], 1);
1656  return &t;
1657  }
1658 
1659  } else if (attrib == IN_spotDirection) {
1660  if (node == nullptr) {
1661  t.set_row(3, LVector3(0.0f, 0.0f, -1.0f));
1662  return &t;
1663  } else if (node->is_ambient_light()) {
1664  // Ambient light has no spot direction.
1665  t.set_row(3, LVector3(0.0f, 0.0f, 0.0f));
1666  return &t;
1667  } else {
1668  LightLensNode *light;
1669  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1670  Lens *lens = light->get_lens();
1671  nassertr(lens != nullptr, &LMatrix4::ident_mat());
1672 
1673  CPT(TransformState) transform =
1674  _scene_setup->get_cs_world_transform()->compose(
1675  np.get_transform(_scene_setup->get_scene_root().get_parent()));
1676 
1677  const LMatrix4 &light_mat = transform->get_mat();
1678  LVector3 dir = lens->get_view_vector() * light_mat;
1679  t.set_row(3, dir);
1680  return &t;
1681  }
1682 
1683  } else if (attrib == IN_spotCutoff) {
1684  if (node != nullptr &&
1685  node->is_of_type(Spotlight::get_class_type())) {
1686  LightLensNode *light;
1687  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1688  Lens *lens = light->get_lens();
1689  nassertr(lens != nullptr, &LMatrix4::ident_mat());
1690 
1691  float cutoff = lens->get_hfov() * 0.5f;
1692  t.set_row(3, LVecBase4(cutoff));
1693  return &t;
1694  } else {
1695  // Other lights have no cut-off.
1696  t.set_row(3, LVecBase4(180));
1697  return &t;
1698  }
1699 
1700  } else if (attrib == IN_spotCosCutoff) {
1701  if (node != nullptr &&
1702  node->is_of_type(Spotlight::get_class_type())) {
1703  LightLensNode *light;
1704  DCAST_INTO_R(light, node, &LMatrix4::ident_mat());
1705  Lens *lens = light->get_lens();
1706  nassertr(lens != nullptr, &LMatrix4::ident_mat());
1707 
1708  float cutoff = lens->get_hfov() * 0.5f;
1709  t.set_row(3, LVecBase4(ccos(deg_2_rad(cutoff))));
1710  return &t;
1711  } else {
1712  // Other lights have no cut-off.
1713  t.set_row(3, LVecBase4(-1));
1714  return &t;
1715  }
1716 
1717  } else if (attrib == IN_spotExponent) {
1718  if (node == nullptr) {
1719  return &LMatrix4::zeros_mat();
1720  }
1721  Light *light = node->as_light();
1722  nassertr(light != nullptr, &LMatrix4::ident_mat());
1723 
1724  t.set_row(3, LVecBase4(light->get_exponent()));
1725  return &t;
1726 
1727  } else if (attrib == IN_attenuation) {
1728  if (node != nullptr) {
1729  Light *light = node->as_light();
1730  nassertr(light != nullptr, &LMatrix4::ones_mat());
1731 
1732  t.set_row(3, LVecBase4(light->get_attenuation(), 0));
1733  } else {
1734  t.set_row(3, LVecBase4(1, 0, 0, 0));
1735  }
1736  return &t;
1737 
1738  } else if (attrib == IN_constantAttenuation) {
1739  if (node == nullptr) {
1740  return &LMatrix4::ones_mat();
1741  }
1742  Light *light = node->as_light();
1743  nassertr(light != nullptr, &LMatrix4::ones_mat());
1744 
1745  t.set_row(3, LVecBase4(light->get_attenuation()[0]));
1746  return &t;
1747 
1748  } else if (attrib == IN_linearAttenuation) {
1749  if (node == nullptr) {
1750  return &LMatrix4::zeros_mat();
1751  }
1752  Light *light = node->as_light();
1753  nassertr(light != nullptr, &LMatrix4::ident_mat());
1754 
1755  t.set_row(3, LVecBase4(light->get_attenuation()[1]));
1756  return &t;
1757 
1758  } else if (attrib == IN_quadraticAttenuation) {
1759  if (node == nullptr) {
1760  return &LMatrix4::zeros_mat();
1761  }
1762  Light *light = node->as_light();
1763  nassertr(light != nullptr, &LMatrix4::ident_mat());
1764 
1765  t.set_row(3, LVecBase4(light->get_attenuation()[2]));
1766  return &t;
1767 
1768  } else if (attrib == IN_shadowViewMatrix) {
1769  static const LMatrix4 biasmat(0.5f, 0.0f, 0.0f, 0.0f,
1770  0.0f, 0.5f, 0.0f, 0.0f,
1771  0.0f, 0.0f, 0.5f, 0.0f,
1772  0.5f, 0.5f, 0.5f, 1.0f);
1773 
1774  if (node == nullptr) {
1775  return &biasmat;
1776  }
1777 
1778  LensNode *lnode;
1779  DCAST_INTO_R(lnode, node, &LMatrix4::ident_mat());
1780  Lens *lens = lnode->get_lens();
1781 
1782  t = _inv_cs_transform->get_mat() *
1783  _scene_setup->get_camera_transform()->get_mat() *
1784  np.get_net_transform()->get_inverse()->get_mat() *
1785  LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system());
1786 
1787  if (!node->is_of_type(PointLight::get_class_type())) {
1788  t *= lens->get_projection_mat() * biasmat;
1789  }
1790  return &t;
1791 
1792  } else {
1793  display_cat.error()
1794  << "Shader input requests invalid attribute " << *attrib
1795  << " from node " << np << "\n";
1796  return &LMatrix4::ident_mat();
1797  }
1798 }
1799 
1800 /**
1801  * Like fetch_specified_value, but for texture inputs.
1802  */
1803 PT(Texture) GraphicsStateGuardian::
1804 fetch_specified_texture(Shader::ShaderTexSpec &spec, SamplerState &sampler,
1805  int &view) {
1806  switch (spec._part) {
1807  case Shader::STO_named_input:
1808  // Named texture input.
1809  if (!_target_shader->has_shader_input(spec._name)) {
1810  // Is this a member of something, like a node?
1811  const InternalName *parent = spec._name->get_parent();
1812  if (parent != InternalName::get_root() &&
1813  _target_shader->has_shader_input(parent)) {
1814 
1815  // Yes, grab the node.
1816  const string &basename = spec._name->get_basename();
1817  NodePath np = _target_shader->get_shader_input_nodepath(parent);
1818 
1819  if (basename == "shadowMap") {
1820  PT(Texture) tex = get_shadow_map(np);
1821  if (tex != nullptr) {
1822  sampler = tex->get_default_sampler();
1823  }
1824  return tex;
1825 
1826  } else {
1827  if (spec._stage == 0) {
1828  display_cat.error()
1829  << "Shader input " << *parent
1830  << " has no member named " << basename << ".\n";
1831  spec._stage = -1;
1832  }
1833  }
1834  } else {
1835  // This used to be legal for some reason, so don't trigger the assert.
1836  // Prevent flood, though, so abuse the _stage flag to indicate whether
1837  // we've already errored about this.
1838  if (spec._stage == 0) {
1839  display_cat.error()
1840  << "Shader input " << *spec._name << " is not present.\n";
1841  spec._stage = -1;
1842  }
1843  }
1844  } else {
1845  // Just a regular texture input.
1846  return _target_shader->get_shader_input_texture(spec._name, &sampler);
1847  }
1848  break;
1849 
1850  case Shader::STO_stage_i:
1851  {
1852  // We get the TextureAttrib directly from the _target_rs, not the
1853  // filtered TextureAttrib in _target_texture.
1854  const TextureAttrib *texattrib;
1855  _target_rs->get_attrib_def(texattrib);
1856 
1857  if (spec._stage < texattrib->get_num_on_stages()) {
1858  TextureStage *stage = texattrib->get_on_stage(spec._stage);
1859  sampler = texattrib->get_on_sampler(stage);
1860  view += stage->get_tex_view_offset();
1861  return texattrib->get_on_texture(stage);
1862  }
1863  }
1864  break;
1865 
1866  case Shader::STO_light_i_shadow_map:
1867  {
1868  const LightAttrib *target_light;
1869  _target_rs->get_attrib_def(target_light);
1870 
1871  // We don't count ambient lights, which would be pretty silly to handle
1872  // via this mechanism.
1873  size_t num_lights = target_light->get_num_non_ambient_lights();
1874  if (spec._stage >= 0 && (size_t)spec._stage < num_lights) {
1875  NodePath light = target_light->get_on_light((size_t)spec._stage);
1876  nassertr(!light.is_empty(), nullptr);
1877  Light *light_obj = light.node()->as_light();
1878  nassertr(light_obj != nullptr, nullptr);
1879 
1880  PT(Texture) tex = get_shadow_map(light);
1881  if (tex != nullptr) {
1882  sampler = tex->get_default_sampler();
1883  }
1884  return tex;
1885  } else {
1886  // There is no such light assigned. Bind a dummy shadow map.
1887  PT(Texture) tex = get_dummy_shadow_map((Texture::TextureType)spec._desired_type);
1888  if (tex != nullptr) {
1889  sampler = tex->get_default_sampler();
1890  }
1891  return tex;
1892  }
1893  }
1894  break;
1895 
1896  default:
1897  nassertr(false, nullptr);
1898  break;
1899  }
1900 
1901  return nullptr;
1902 }
1903 
1904 /**
1905  * Return a pointer to struct ShaderPtrData
1906  */
1907 const Shader::ShaderPtrData *GraphicsStateGuardian::
1908 fetch_ptr_parameter(const Shader::ShaderPtrSpec& spec) {
1909  return (_target_shader->get_shader_input_ptr(spec._arg));
1910 }
1911 
1912 /**
1913  * Makes the specified DisplayRegion current. All future drawing and clear
1914  * operations will be constrained within the given DisplayRegion.
1915  */
1918  _current_display_region = dr->get_object();
1919  _current_stereo_channel = dr->get_stereo_channel();
1920  _current_tex_view_offset = dr->get_tex_view_offset();
1921  _effective_incomplete_render = _incomplete_render && _current_display_region->get_incomplete_render();
1922 
1923  _stereo_buffer_mask = ~0;
1924 
1925  Lens::StereoChannel output_channel = dr->get_stereo_channel();
1926  if (dr->get_window()->get_swap_eyes()) {
1927  // Reverse the output channel.
1928  switch (output_channel) {
1929  case Lens::SC_left:
1930  output_channel = Lens::SC_right;
1931  break;
1932 
1933  case Lens::SC_right:
1934  output_channel = Lens::SC_left;
1935  break;
1936 
1937  default:
1938  break;
1939  }
1940  }
1941 
1942  switch (output_channel) {
1943  case Lens::SC_left:
1944  _color_write_mask = dr->get_window()->get_left_eye_color_mask();
1945  if (_current_properties->is_stereo()) {
1946  _stereo_buffer_mask = ~RenderBuffer::T_right;
1947  }
1948  break;
1949 
1950  case Lens::SC_right:
1951  _color_write_mask = dr->get_window()->get_right_eye_color_mask();
1952  if (_current_properties->is_stereo()) {
1953  _stereo_buffer_mask = ~RenderBuffer::T_left;
1954  }
1955  break;
1956 
1957  case Lens::SC_mono:
1958  case Lens::SC_stereo:
1959  _color_write_mask = ColorWriteAttrib::C_all;
1960  }
1961 }
1962 
1963 /**
1964  * Resets any non-standard graphics state that might give a callback apoplexy.
1965  * Some drivers require that the graphics state be restored to neutral before
1966  * performing certain operations. In OpenGL, for instance, this closes any
1967  * open vertex buffers.
1968  */
1971 }
1972 
1973 /**
1974  * Forgets the current graphics state and current transform, so that the next
1975  * call to set_state_and_transform() will have to reload everything. This is
1976  * a good thing to call when you are no longer sure what the graphics state
1977  * is. This should only be called from the draw thread.
1978  */
1981  // Re-issue the modelview and projection transforms.
1982  reissue_transforms();
1983 
1984  // Now clear the state flags to unknown.
1985  _state_rs = RenderState::make_empty();
1986  _state_mask.clear();
1987 }
1988 
1989 /**
1990  * This is simply a transparent call to GraphicsEngine::remove_window(). It
1991  * exists primary to support removing a window from that compiles before the
1992  * display module, and therefore has no knowledge of a GraphicsEngine object.
1993  */
1996  nassertv(_engine != nullptr);
1997  GraphicsOutput *win;
1998  DCAST_INTO_V(win, window);
1999  _engine->remove_window(win);
2000 }
2001 
2002 /**
2003  * Makes the current lens (whichever lens was most recently specified with
2004  * set_scene()) active, so that it will transform future rendered geometry.
2005  * Normally this is only called from the draw process, and usually it is
2006  * called by set_scene().
2007  *
2008  * The return value is true if the lens is acceptable, false if it is not.
2009  */
2012  return false;
2013 }
2014 
2015 /**
2016  * Given a lens, this function calculates the appropriate projection matrix
2017  * for this gsg. The result depends on the peculiarities of the rendering
2018  * API.
2019  */
2020 CPT(TransformState) GraphicsStateGuardian::
2021 calc_projection_mat(const Lens *lens) {
2022  if (lens == nullptr) {
2023  return nullptr;
2024  }
2025 
2026  if (!lens->is_linear()) {
2027  return nullptr;
2028  }
2029 
2030  return TransformState::make_identity();
2031 }
2032 
2033 /**
2034  * Called before each frame is rendered, to allow the GSG a chance to do any
2035  * internal cleanup before beginning the frame.
2036  *
2037  * The return value is true if successful (in which case the frame will be
2038  * drawn and end_frame() will be called later), or false if unsuccessful (in
2039  * which case nothing will be drawn and end_frame() will not be called).
2040  */
2042 begin_frame(Thread *current_thread) {
2043  _prepared_objects->begin_frame(this, current_thread);
2044 
2045  // We should reset the state to the default at the beginning of every frame.
2046  // Although this will incur additional overhead, particularly in a simple
2047  // scene, it helps ensure that states that have changed properties since
2048  // last time without changing attribute pointers--like textures, lighting,
2049  // or fog--will still be accurately updated.
2050  _state_rs = RenderState::make_empty();
2051  _state_mask.clear();
2052 
2053 #ifdef DO_PSTATS
2054  // We have to do this here instead of in GraphicsEngine because we need a
2055  // current context to issue timer queries.
2057  if (_last_query_frame < frame) {
2058  _last_query_frame = frame;
2059  _timer_queries_pcollector.clear_level();
2060 
2061  // Now is a good time to flush previous frame's queries. We may not
2062  // actually have all of the previous frame's results in yet, but that's
2063  // okay; the GPU data is allowed to lag a few frames behind.
2065 
2066  if (_timer_queries_active) {
2067  // Issue a stop and start event for collector 0, marking the beginning
2068  // of the new frame.
2069  issue_timer_query(0x8000);
2070  issue_timer_query(0x0000);
2071  }
2072  }
2073 #endif
2074 
2075  return !_needs_reset;
2076 }
2077 
2078 /**
2079  * Called between begin_frame() and end_frame() to mark the beginning of
2080  * drawing commands for a "scene" (usually a particular DisplayRegion) within
2081  * a frame. All 3-D drawing commands, except the clear operation, must be
2082  * enclosed within begin_scene() .. end_scene(). This must be called in the
2083  * draw thread.
2084  *
2085  * The return value is true if successful (in which case the scene will be
2086  * drawn and end_scene() will be called later), or false if unsuccessful (in
2087  * which case nothing will be drawn and end_scene() will not be called).
2088  */
2091  return true;
2092 }
2093 
2094 /**
2095  * Called between begin_frame() and end_frame() to mark the end of drawing
2096  * commands for a "scene" (usually a particular DisplayRegion) within a frame.
2097  * All 3-D drawing commands, except the clear operation, must be enclosed
2098  * within begin_scene() .. end_scene().
2099  */
2102  // We should clear this pointer now, so that we don't keep unneeded
2103  // reference counts dangling. We keep around a "null" scene setup object
2104  // instead of using a null pointer to avoid special-case code in
2105  // set_state_and_transform.
2106  _scene_setup = _scene_null;
2107 
2108  // Undo any lighting we had enabled last scene, to force the lights to be
2109  // reissued, in case their parameters or positions have changed between
2110  // scenes.
2111  int i;
2112  for (i = 0; i < _num_lights_enabled; ++i) {
2113  enable_light(i, false);
2114  }
2115  _num_lights_enabled = 0;
2116 
2117  // Ditto for the clipping planes.
2118  for (i = 0; i < _num_clip_planes_enabled; ++i) {
2119  enable_clip_plane(i, false);
2120  }
2121  _num_clip_planes_enabled = 0;
2122 
2123  // Put the state into the 'unknown' state, forcing a reload.
2124  _state_rs = RenderState::make_empty();
2125  _state_mask.clear();
2126 }
2127 
2128 /**
2129  * Called after each frame is rendered, to allow the GSG a chance to do any
2130  * internal cleanup after rendering the frame, and before the window flips.
2131  */
2133 end_frame(Thread *current_thread) {
2134  _prepared_objects->end_frame(current_thread);
2135 
2136  // Flush any PStatCollectors.
2137  _data_transferred_pcollector.flush_level();
2138 
2139  _primitive_batches_pcollector.flush_level();
2140  _primitive_batches_tristrip_pcollector.flush_level();
2141  _primitive_batches_trifan_pcollector.flush_level();
2142  _primitive_batches_tri_pcollector.flush_level();
2143  _primitive_batches_patch_pcollector.flush_level();
2144  _primitive_batches_other_pcollector.flush_level();
2145  _vertices_tristrip_pcollector.flush_level();
2146  _vertices_trifan_pcollector.flush_level();
2147  _vertices_tri_pcollector.flush_level();
2148  _vertices_patch_pcollector.flush_level();
2149  _vertices_other_pcollector.flush_level();
2150 
2151  _state_pcollector.flush_level();
2152  _texture_state_pcollector.flush_level();
2153  _transform_state_pcollector.flush_level();
2154  _draw_primitive_pcollector.flush_level();
2155 
2156  // Evict any textures andor vbuffers that exceed our texture memory.
2157  _prepared_objects->_graphics_memory_lru.begin_epoch();
2158 }
2159 
2160 /**
2161  * Called by the graphics engine on the draw thread to check the status of the
2162  * running timer queries and submit their results to the PStats server.
2163  */
2166 #ifdef DO_PSTATS
2167  // This uses the lower-level PStats interfaces for now because of all the
2168  // unnecessary overhead that would otherwise be incurred when adding such a
2169  // large amount of data at once.
2170 
2171  PStatClient *client = PStatClient::get_global_pstats();
2172 
2173  if (!client->client_is_connected()) {
2174  _timer_queries_active = false;
2175  return;
2176  }
2177 
2178  if (!_timer_queries_active) {
2179  if (pstats_gpu_timing && _supports_timer_query) {
2180  // Check if timer queries should be enabled.
2181  _timer_queries_active = true;
2182  } else {
2183  return;
2184  }
2185  }
2186 
2187  // Currently, we use one thread per GSG, for convenience. In the future, we
2188  // may want to try and use one thread per graphics card.
2189  if (_pstats_gpu_thread == -1) {
2190  _pstats_gpu_thread = client->make_gpu_thread(get_driver_renderer()).get_index();
2191  }
2192  PStatThread gpu_thread(client, _pstats_gpu_thread);
2193 
2194  // Get the results of all the timer queries.
2195  int first = 0;
2196  if (!_pending_timer_queries.empty()) {
2197  int count = _pending_timer_queries.size();
2198  if (count == 0) {
2199  return;
2200  }
2201 
2202  PStatGPUTimer timer(this, _wait_timer_pcollector);
2203 
2204  if (_last_num_queried > 0) {
2205  // We know how many queries were available last frame, and this usually
2206  // stays fairly constant, so use this as a starting point.
2207  int i = std::min(_last_num_queried, count) - 1;
2208 
2209  if (_pending_timer_queries[i]->is_answer_ready()) {
2210  first = count;
2211  while (i < count - 1) {
2212  if (!_pending_timer_queries[++i]->is_answer_ready()) {
2213  first = i;
2214  break;
2215  }
2216  }
2217  } else {
2218  first = 0;
2219  while (i > 0) {
2220  if (_pending_timer_queries[--i]->is_answer_ready()) {
2221  first = i + 1;
2222  break;
2223  }
2224  }
2225  }
2226  } else {
2227  // We figure out which tasks the GPU has already finished by doing a
2228  // binary search for the first query that does not have an answer ready.
2229  // We know then that everything before that must be ready.
2230  while (count > 0) {
2231  int step = count / 2;
2232  int i = first + step;
2233  if (_pending_timer_queries[i]->is_answer_ready()) {
2234  first += step + 1;
2235  count -= step + 1;
2236  } else {
2237  count = step;
2238  }
2239  }
2240  }
2241 
2242  if (first <= 0) {
2243  return;
2244  }
2245 
2246  _last_num_queried = first;
2247 
2248  for (int i = 0; i < first; ++i) {
2249  CPT(TimerQueryContext) query = _pending_timer_queries[i];
2250 
2251  double time_data = query->get_timestamp(); // + _timer_delta;
2252 
2253  if (query->_pstats_index == _command_latency_pcollector.get_index()) {
2254  // Special case for the latency pcollector.
2255  PStatCollectorDef *cdef;
2256  cdef = client->get_collector_ptr(query->_pstats_index)->get_def(client, query->_pstats_index);
2257  _pstats_gpu_data.add_level(query->_pstats_index, time_data * cdef->_factor);
2258 
2259  } else if (query->_pstats_index & 0x8000) {
2260  _pstats_gpu_data.add_stop(query->_pstats_index & 0x7fff, time_data);
2261 
2262  } else {
2263  _pstats_gpu_data.add_start(query->_pstats_index & 0x7fff, time_data);
2264  }
2265 
2266  // We found an end-frame marker (a stop event for collector 0). This
2267  // means that the GPU actually caught up with that frame, and we can
2268  // flush the GPU thread's frame data to the pstats server.
2269  if (query->_pstats_index == 0x8000) {
2270  gpu_thread.add_frame(_pstats_gpu_data);
2271  _pstats_gpu_data.clear();
2272  }
2273  }
2274  }
2275 
2276  if (first > 0) {
2277  // Do this out of the scope of _wait_timer_pcollector.
2278  _pending_timer_queries.erase(
2279  _pending_timer_queries.begin(),
2280  _pending_timer_queries.begin() + first
2281  );
2282  _timer_queries_pcollector.add_level_now(first);
2283  }
2284 #endif
2285 }
2286 
2287 /**
2288  * Returns true if this GSG can implement decals using a DepthOffsetAttrib, or
2289  * false if that is unreliable and the three-step rendering process should be
2290  * used instead.
2291  */
2294  return true;
2295 }
2296 
2297 /**
2298  * Called during draw to begin a three-step rendering phase to draw decals.
2299  * The first step, begin_decal_base_first(), is called prior to drawing the
2300  * base geometry. It should set up whatever internal state is appropriate, as
2301  * well as returning a RenderState object that should be applied to the base
2302  * geometry for rendering.
2303  */
2304 CPT(RenderState) GraphicsStateGuardian::
2305 begin_decal_base_first() {
2306  // Turn off writing the depth buffer to render the base geometry.
2307  static CPT(RenderState) decal_base_first;
2308  if (decal_base_first == nullptr) {
2309  decal_base_first = RenderState::make
2310  (DepthWriteAttrib::make(DepthWriteAttrib::M_off),
2311  RenderState::get_max_priority());
2312  }
2313  return decal_base_first;
2314 }
2315 
2316 /**
2317  * Called during draw to begin a three-step rendering phase to draw decals.
2318  * The second step, begin_decal_nested(), is called after drawing the base
2319  * geometry and prior to drawing any of the nested decal geometry that is to
2320  * be applied to the base geometry.
2321  */
2322 CPT(RenderState) GraphicsStateGuardian::
2323 begin_decal_nested() {
2324  // We should keep the depth buffer off during this operation, so that decals
2325  // on decals will render properly.
2326  static CPT(RenderState) decal_nested;
2327  if (decal_nested == nullptr) {
2328  decal_nested = RenderState::make
2329  (DepthWriteAttrib::make(DepthWriteAttrib::M_off),
2330  RenderState::get_max_priority());
2331  }
2332  return decal_nested;
2333 }
2334 
2335 /**
2336  * Called during draw to begin a three-step rendering phase to draw decals.
2337  * The third step, begin_decal_base_second(), is called after drawing the base
2338  * geometry and the nested decal geometry, and prior to drawing the base
2339  * geometry one more time (if needed).
2340  *
2341  * It should return a RenderState object appropriate for rendering the base
2342  * geometry the second time, or NULL if it is not necessary to re-render the
2343  * base geometry.
2344  */
2345 CPT(RenderState) GraphicsStateGuardian::
2346 begin_decal_base_second() {
2347  // Now let the depth buffer go back on, but turn off writing the color
2348  // buffer to render the base geometry after the second pass. Also, turn off
2349  // texturing since there's no need for it now.
2350  static CPT(RenderState) decal_base_second;
2351  if (decal_base_second == nullptr) {
2352  decal_base_second = RenderState::make
2353  (ColorWriteAttrib::make(ColorWriteAttrib::C_off),
2354  // On reflection, we need to leave texturing on so the alpha test
2355  // mechanism can work (if it is enabled, e.g. we are rendering an
2356  // object with M_dual transparency). TextureAttrib::make_off(),
2357  RenderState::get_max_priority());
2358  }
2359  return decal_base_second;
2360 }
2361 
2362 /**
2363  * Called during draw to clean up after decals are finished.
2364  */
2367  // No need to do anything special here.
2368 }
2369 
2370 /**
2371  * Called before a sequence of draw_primitive() functions are called, this
2372  * should prepare the vertex data for rendering. It returns true if the
2373  * vertices are ok, false to abort this group of primitives.
2374  */
2377  const GeomVertexDataPipelineReader *data_reader,
2378  bool force) {
2379  _data_reader = data_reader;
2380 
2381  // Always draw if we have a shader, since the shader might use a different
2382  // mechanism for fetching vertex data.
2383  return _data_reader->has_vertex() || (_target_shader && _target_shader->has_shader());
2384 }
2385 
2386 /**
2387  * Draws a series of disconnected triangles.
2388  */
2391  return false;
2392 }
2393 
2394 
2395 /**
2396  * Draws a series of disconnected triangles with adjacency information.
2397  */
2400  return false;
2401 }
2402 
2403 /**
2404  * Draws a series of triangle strips.
2405  */
2408  return false;
2409 }
2410 
2411 /**
2412  * Draws a series of triangle strips with adjacency information.
2413  */
2416  return false;
2417 }
2418 
2419 /**
2420  * Draws a series of triangle fans.
2421  */
2424  return false;
2425 }
2426 
2427 /**
2428  * Draws a series of "patches", which can only be processed by a tessellation
2429  * shader.
2430  */
2433  return false;
2434 }
2435 
2436 /**
2437  * Draws a series of disconnected line segments.
2438  */
2441  return false;
2442 }
2443 
2444 /**
2445  * Draws a series of disconnected line segments with adjacency information.
2446  */
2449  return false;
2450 }
2451 
2452 /**
2453  * Draws a series of line strips.
2454  */
2457  return false;
2458 }
2459 
2460 /**
2461  * Draws a series of line strips with adjacency information.
2462  */
2465  return false;
2466 }
2467 
2468 /**
2469  * Draws a series of disconnected points.
2470  */
2473  return false;
2474 }
2475 
2476 /**
2477  * Called after a sequence of draw_primitive() functions are called, this
2478  * should do whatever cleanup is appropriate.
2479  */
2482  _data_reader = nullptr;
2483 }
2484 
2485 /**
2486  * Resets all internal state as if the gsg were newly created.
2487  */
2490  _needs_reset = false;
2491  _is_valid = false;
2492 
2493  _state_rs = RenderState::make_empty();
2494  _target_rs = nullptr;
2495  _state_mask.clear();
2496  _internal_transform = _cs_transform;
2497  _scene_null = new SceneSetup;
2498  _scene_setup = _scene_null;
2499 
2500  _color_write_mask = ColorWriteAttrib::C_all;
2501 
2502  _has_scene_graph_color = false;
2503  _scene_graph_color.set(1.0f, 1.0f, 1.0f, 1.0f);
2504  _transform_stale = true;
2505  _color_blend_involves_color_scale = false;
2506  _texture_involves_color_scale = false;
2507  _vertex_colors_enabled = true;
2508  _lighting_enabled = false;
2509  _num_lights_enabled = 0;
2510  _num_clip_planes_enabled = 0;
2511  _clip_planes_enabled = false;
2512 
2513  _color_scale_enabled = false;
2514  _current_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
2515  _has_texture_alpha_scale = false;
2516 
2517  _has_material_force_color = false;
2518  _material_force_color.set(1.0f, 1.0f, 1.0f, 1.0f);
2519  _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
2520 
2521  _tex_gen_modifies_mat = false;
2522  _last_max_stage_index = 0;
2523 
2524  _is_valid = true;
2525 }
2526 
2527 /**
2528  * Simultaneously resets the render state and the transform state.
2529  *
2530  * This transform specified is the "internal" net transform, already converted
2531  * into the GSG's internal coordinate space by composing it to
2532  * get_cs_transform(). (Previously, this used to be the "external" net
2533  * transform, with the assumption that that GSG would convert it internally,
2534  * but that is no longer the case.)
2535  *
2536  * Special case: if (state==NULL), then the target state is already stored in
2537  * _target.
2538  */
2541  const TransformState *trans) {
2542 }
2543 
2544 /**
2545  * Clears the framebuffer within the current DisplayRegion, according to the
2546  * flags indicated by the given DrawableRegion object.
2547  *
2548  * This does not set the DisplayRegion first. You should call
2549  * prepare_display_region() to specify the region you wish the clear operation
2550  * to apply to.
2551  */
2553 clear(DrawableRegion *clearable) {
2554 }
2555 
2556 /**
2557  * Returns a RenderBuffer object suitable for operating on the requested set
2558  * of buffers. buffer_type is the union of all the desired RenderBuffer::Type
2559  * values.
2560  */
2562 get_render_buffer(int buffer_type, const FrameBufferProperties &prop) {
2563  return RenderBuffer(this, buffer_type & prop.get_buffer_mask() & _stereo_buffer_mask);
2564 }
2565 
2566 /**
2567  * Returns what the cs_transform would be set to after a call to
2568  * set_coordinate_system(cs). This is another way of saying the cs_transform
2569  * when rendering the scene for a camera with the indicated coordinate system.
2570  */
2571 CPT(TransformState) GraphicsStateGuardian::
2572 get_cs_transform_for(CoordinateSystem cs) const {
2573  if (_coordinate_system == cs) {
2574  // We've already calculated this.
2575  return _cs_transform;
2576 
2577  } else if (_internal_coordinate_system == CS_default ||
2578  _internal_coordinate_system == cs) {
2579  return TransformState::make_identity();
2580 
2581  } else {
2582  return TransformState::make_mat
2583  (LMatrix4::convert_mat(cs, _internal_coordinate_system));
2584  }
2585 }
2586 
2587 /**
2588  * Returns a transform that converts from the GSG's external coordinate system
2589  * (as returned by get_coordinate_system()) to its internal coordinate system
2590  * (as returned by get_internal_coordinate_system()). This is used for
2591  * rendering.
2592  */
2593 CPT(TransformState) GraphicsStateGuardian::
2594 get_cs_transform() const {
2595  return _cs_transform;
2596 }
2597 
2598 /**
2599  * This is fundametically similar to do_issue_light(), with calls to
2600  * apply_clip_plane() and enable_clip_planes(), as appropriate.
2601  */
2602 void GraphicsStateGuardian::
2603 do_issue_clip_plane() {
2604  int num_enabled = 0;
2605  int num_on_planes = 0;
2606 
2607  const ClipPlaneAttrib *target_clip_plane = (const ClipPlaneAttrib *)
2608  _target_rs->get_attrib_def(ClipPlaneAttrib::get_class_slot());
2609 
2610  if (target_clip_plane != nullptr) {
2611  CPT(ClipPlaneAttrib) new_plane = target_clip_plane->filter_to_max(_max_clip_planes);
2612 
2613  num_on_planes = new_plane->get_num_on_planes();
2614  for (int li = 0; li < num_on_planes; li++) {
2615  NodePath plane = new_plane->get_on_plane(li);
2616  nassertv(!plane.is_empty());
2617  PlaneNode *plane_node;
2618  DCAST_INTO_V(plane_node, plane.node());
2619  if ((plane_node->get_clip_effect() & PlaneNode::CE_visible) != 0) {
2620  // Clipping should be enabled before we apply any planes.
2621  if (!_clip_planes_enabled) {
2622  enable_clip_planes(true);
2623  _clip_planes_enabled = true;
2624  }
2625 
2626  enable_clip_plane(num_enabled, true);
2627  if (num_enabled == 0) {
2628  begin_bind_clip_planes();
2629  }
2630 
2631  bind_clip_plane(plane, num_enabled);
2632  num_enabled++;
2633  }
2634  }
2635  }
2636 
2637  int i;
2638  for (i = num_enabled; i < _num_clip_planes_enabled; ++i) {
2639  enable_clip_plane(i, false);
2640  }
2641  _num_clip_planes_enabled = num_enabled;
2642 
2643  // If no planes were set, disable clipping
2644  if (num_enabled == 0) {
2645  if (_clip_planes_enabled) {
2646  enable_clip_planes(false);
2647  _clip_planes_enabled = false;
2648  }
2649  } else {
2650  end_bind_clip_planes();
2651  }
2652 }
2653 
2654 /**
2655  * This method is defined in the base class because it is likely that this
2656  * functionality will be used for all (or at least most) kinds of
2657  * GraphicsStateGuardians--it's not specific to any one rendering backend.
2658  *
2659  * The ColorAttribute just changes the interpretation of the color on the
2660  * vertices, and fiddles with _vertex_colors_enabled, etc.
2661  */
2664  const ColorAttrib *target_color = (const ColorAttrib *)
2665  _target_rs->get_attrib_def(ColorAttrib::get_class_slot());
2666 
2667  switch (target_color->get_color_type()) {
2668  case ColorAttrib::T_flat:
2669  // Color attribute flat: it specifies a scene graph color that overrides
2670  // the vertex color.
2671  _scene_graph_color = target_color->get_color();
2672  _has_scene_graph_color = true;
2673  _vertex_colors_enabled = false;
2674  break;
2675 
2676  case ColorAttrib::T_off:
2677  // Color attribute off: it specifies that no scene graph color is in
2678  // effect, and vertex color is not important either.
2679  _scene_graph_color.set(1.0f, 1.0f, 1.0f, 1.0f);
2680  _has_scene_graph_color = false;
2681  _vertex_colors_enabled = false;
2682  break;
2683 
2684  case ColorAttrib::T_vertex:
2685  // Color attribute vertex: it specifies that vertex color should be
2686  // revealed.
2687  _scene_graph_color.set(1.0f, 1.0f, 1.0f, 1.0f);
2688  _has_scene_graph_color = false;
2689  _vertex_colors_enabled = true;
2690  break;
2691  }
2692 
2693  if (_color_scale_via_lighting) {
2694  _state_mask.clear_bit(LightAttrib::get_class_slot());
2695  _state_mask.clear_bit(MaterialAttrib::get_class_slot());
2696 
2697  determine_light_color_scale();
2698  }
2699 }
2700 
2701 /**
2702  *
2703  */
2704 void GraphicsStateGuardian::
2705 do_issue_color_scale() {
2706  // If the previous color scale had set a special texture, clear the texture
2707  // now.
2708  if (_has_texture_alpha_scale) {
2709  _state_mask.clear_bit(TextureAttrib::get_class_slot());
2710  }
2711 
2712  const ColorScaleAttrib *target_color_scale = (const ColorScaleAttrib *)
2713  _target_rs->get_attrib_def(ColorScaleAttrib::get_class_slot());
2714 
2715  _color_scale_enabled = target_color_scale->has_scale();
2716  _current_color_scale = target_color_scale->get_scale();
2717  _has_texture_alpha_scale = false;
2718 
2719  if (_color_blend_involves_color_scale) {
2720  _state_mask.clear_bit(TransparencyAttrib::get_class_slot());
2721  }
2722  if (_texture_involves_color_scale) {
2723  _state_mask.clear_bit(TextureAttrib::get_class_slot());
2724  }
2725  if (_color_scale_via_lighting) {
2726  _state_mask.clear_bit(LightAttrib::get_class_slot());
2727  _state_mask.clear_bit(MaterialAttrib::get_class_slot());
2728 
2729  determine_light_color_scale();
2730  }
2731 
2732  if (_alpha_scale_via_texture && !_has_scene_graph_color &&
2733  _vertex_colors_enabled && target_color_scale->has_alpha_scale()) {
2734  // This color scale will set a special texture--so again, clear the
2735  // texture.
2736  _state_mask.clear_bit(TextureAttrib::get_class_slot());
2737  _state_mask.clear_bit(TexMatrixAttrib::get_class_slot());
2738 
2739  _has_texture_alpha_scale = true;
2740  }
2741 }
2742 
2743 /**
2744  * This implementation of do_issue_light() assumes we have a limited number of
2745  * hardware lights available. This function assigns each light to a different
2746  * hardware light id, trying to keep each light associated with the same id
2747  * where possible, but reusing id's when necessary. When it is no longer
2748  * possible to reuse existing id's (e.g. all id's are in use), the next
2749  * sequential id is assigned (if available).
2750  *
2751  * It will call apply_light() each time a light is assigned to a particular id
2752  * for the first time in a given frame, and it will subsequently call
2753  * enable_light() to enable or disable each light as the frame is rendered, as
2754  * well as enable_lighting() to enable or disable overall lighting.
2755  */
2758  // Initialize the current ambient light total and newly enabled light list
2759  LColor cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f);
2760  int i;
2761 
2762  int num_enabled = 0;
2763  bool any_on_lights = false;
2764 
2765  const LightAttrib *target_light;
2766  _target_rs->get_attrib_def(target_light);
2767 
2768  if (display_cat.is_spam()) {
2769  display_cat.spam()
2770  << "do_issue_light: " << target_light << "\n";
2771  }
2772  if (target_light != nullptr) {
2773  // LightAttrib guarantees that the on lights are sorted, and that
2774  // non-ambient lights come before ambient lights.
2775  any_on_lights = target_light->has_any_on_light();
2776  size_t filtered_lights = std::min((size_t)_max_lights, target_light->get_num_non_ambient_lights());
2777  for (size_t li = 0; li < filtered_lights; ++li) {
2778  NodePath light = target_light->get_on_light(li);
2779  nassertv(!light.is_empty());
2780  Light *light_obj = light.node()->as_light();
2781  nassertv(light_obj != nullptr);
2782 
2783  // Lighting should be enabled before we apply any lights.
2784  if (!_lighting_enabled) {
2785  enable_lighting(true);
2786  _lighting_enabled = true;
2787  }
2788 
2789  const LColor &color = light_obj->get_color();
2790  // Don't bother binding the light if it has no color to contribute.
2791  if (color[0] != 0.0 || color[1] != 0.0 || color[2] != 0.0) {
2792  enable_light(num_enabled, true);
2793  if (num_enabled == 0) {
2794  begin_bind_lights();
2795  }
2796 
2797  light_obj->bind(this, light, num_enabled);
2798  num_enabled++;
2799  }
2800  }
2801  }
2802 
2803  for (i = num_enabled; i < _num_lights_enabled; ++i) {
2804  enable_light(i, false);
2805  }
2806  _num_lights_enabled = num_enabled;
2807 
2808  // If no lights were set, disable lighting
2809  if (!any_on_lights) {
2810  if (_color_scale_via_lighting && (_has_material_force_color || _light_color_scale != LVecBase4(1.0f, 1.0f, 1.0f, 1.0f))) {
2811  // Unless we need lighting anyway to apply a color or color scale.
2812  if (!_lighting_enabled) {
2813  enable_lighting(true);
2814  _lighting_enabled = true;
2815  }
2816  set_ambient_light(LColor(1.0f, 1.0f, 1.0f, 1.0f));
2817 
2818  } else {
2819  if (_lighting_enabled) {
2820  enable_lighting(false);
2821  _lighting_enabled = false;
2822  }
2823  }
2824 
2825  } else {
2826  set_ambient_light(target_light->get_ambient_contribution());
2827  }
2828 
2829  if (num_enabled != 0) {
2830  end_bind_lights();
2831  }
2832 }
2833 
2834 /**
2835  * Copy the pixels within the indicated display region from the framebuffer
2836  * into texture memory.
2837  *
2838  * If z > -1, it is the cube map index into which to copy.
2839  */
2842  const RenderBuffer &) {
2843  return false;
2844 }
2845 
2846 
2847 /**
2848  * Copy the pixels within the indicated display region from the framebuffer
2849  * into system memory, not texture memory. Returns true on success, false on
2850  * failure.
2851  *
2852  * This completely redefines the ram image of the indicated texture.
2853  */
2856  const RenderBuffer &) {
2857  return false;
2858 }
2859 
2860 /**
2861  * Called the first time a particular light has been bound to a given id
2862  * within a frame, this should set up the associated hardware light with the
2863  * light's properties.
2864  */
2866 bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
2867 }
2868 
2869 /**
2870  * Called the first time a particular light has been bound to a given id
2871  * within a frame, this should set up the associated hardware light with the
2872  * light's properties.
2873  */
2875 bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
2876 }
2877 
2878 /**
2879  * Called the first time a particular light has been bound to a given id
2880  * within a frame, this should set up the associated hardware light with the
2881  * light's properties.
2882  */
2884 bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
2885 }
2886 
2887 #ifdef DO_PSTATS
2888 /**
2889  * Initializes the relevant PStats data at the beginning of the frame.
2890  */
2891 void GraphicsStateGuardian::
2892 init_frame_pstats() {
2893  if (PStatClient::is_connected()) {
2894  _data_transferred_pcollector.clear_level();
2895  _vertex_buffer_switch_pcollector.clear_level();
2896  _index_buffer_switch_pcollector.clear_level();
2897 
2898  _primitive_batches_pcollector.clear_level();
2899  _primitive_batches_tristrip_pcollector.clear_level();
2900  _primitive_batches_trifan_pcollector.clear_level();
2901  _primitive_batches_tri_pcollector.clear_level();
2902  _primitive_batches_patch_pcollector.clear_level();
2903  _primitive_batches_other_pcollector.clear_level();
2904  _vertices_tristrip_pcollector.clear_level();
2905  _vertices_trifan_pcollector.clear_level();
2906  _vertices_tri_pcollector.clear_level();
2907  _vertices_patch_pcollector.clear_level();
2908  _vertices_other_pcollector.clear_level();
2909 
2910  _state_pcollector.clear_level();
2911  _transform_state_pcollector.clear_level();
2912  _texture_state_pcollector.clear_level();
2913  }
2914 }
2915 #endif // DO_PSTATS
2916 
2917 
2918 /**
2919  * Create a gamma table.
2920  */
2922 create_gamma_table (PN_stdfloat gamma, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
2923  int i;
2924 
2925  if (gamma <= 0.0) {
2926  // avoid divide by zero and negative exponents
2927  gamma = 1.0;
2928  }
2929 
2930  for (i = 0; i < 256; i++) {
2931  double g;
2932  double x;
2933  PN_stdfloat gamma_correction;
2934 
2935  x = ((double) i / 255.0);
2936  gamma_correction = 1.0 / gamma;
2937  x = pow (x, (double) gamma_correction);
2938  if (x > 1.00) {
2939  x = 1.0;
2940  }
2941 
2942  g = x * 65535.0;
2943  red_table [i] = (int)g;
2944  green_table [i] = (int)g;
2945  blue_table [i] = (int)g;
2946  }
2947 }
2948 
2949 /**
2950  * Called by clear_state_and_transform() to ensure that the current modelview
2951  * and projection matrices are properly loaded in the graphics state, after a
2952  * callback might have mucked them up.
2953  */
2954 void GraphicsStateGuardian::
2955 reissue_transforms() {
2956 }
2957 
2958 /**
2959  * Intended to be overridden by a derived class to enable or disable the use
2960  * of lighting overall. This is called by do_issue_light() according to
2961  * whether any lights are in use or not.
2962  */
2963 void GraphicsStateGuardian::
2964 enable_lighting(bool enable) {
2965 }
2966 
2967 /**
2968  * Intended to be overridden by a derived class to indicate the color of the
2969  * ambient light that should be in effect. This is called by do_issue_light()
2970  * after all other lights have been enabled or disabled.
2971  */
2972 void GraphicsStateGuardian::
2973 set_ambient_light(const LColor &color) {
2974 }
2975 
2976 /**
2977  * Intended to be overridden by a derived class to enable the indicated light
2978  * id. A specific Light will already have been bound to this id via
2979  * bind_light().
2980  */
2981 void GraphicsStateGuardian::
2982 enable_light(int light_id, bool enable) {
2983 }
2984 
2985 /**
2986  * Called immediately before bind_light() is called, this is intended to
2987  * provide the derived class a hook in which to set up some state (like
2988  * transform) that might apply to several lights.
2989  *
2990  * The sequence is: begin_bind_lights() will be called, then one or more
2991  * bind_light() calls, then end_bind_lights().
2992  */
2993 void GraphicsStateGuardian::
2994 begin_bind_lights() {
2995 }
2996 
2997 /**
2998  * Called after before bind_light() has been called one or more times (but
2999  * before any geometry is issued or additional state is changed), this is
3000  * intended to clean up any temporary changes to the state that may have been
3001  * made by begin_bind_lights().
3002  */
3003 void GraphicsStateGuardian::
3004 end_bind_lights() {
3005 }
3006 
3007 /**
3008  * Intended to be overridden by a derived class to enable or disable the use
3009  * of clipping planes overall. This is called by do_issue_clip_plane()
3010  * according to whether any planes are in use or not.
3011  */
3012 void GraphicsStateGuardian::
3013 enable_clip_planes(bool enable) {
3014 }
3015 
3016 /**
3017  * Intended to be overridden by a derived class to enable the indicated plane
3018  * id. A specific PlaneNode will already have been bound to this id via
3019  * bind_clip_plane().
3020  */
3021 void GraphicsStateGuardian::
3022 enable_clip_plane(int plane_id, bool enable) {
3023 }
3024 
3025 /**
3026  * Called immediately before bind_clip_plane() is called, this is intended to
3027  * provide the derived class a hook in which to set up some state (like
3028  * transform) that might apply to several planes.
3029  *
3030  * The sequence is: begin_bind_clip_planes() will be called, then one or more
3031  * bind_clip_plane() calls, then end_bind_clip_planes().
3032  */
3033 void GraphicsStateGuardian::
3034 begin_bind_clip_planes() {
3035 }
3036 
3037 /**
3038  * Called the first time a particular clipping plane has been bound to a given
3039  * id within a frame, this should set up the associated hardware (or API)
3040  * clipping plane with the plane's properties.
3041  */
3042 void GraphicsStateGuardian::
3043 bind_clip_plane(const NodePath &plane, int plane_id) {
3044 }
3045 
3046 /**
3047  * Called after before bind_clip_plane() has been called one or more times
3048  * (but before any geometry is issued or additional state is changed), this is
3049  * intended to clean up any temporary changes to the state that may have been
3050  * made by begin_bind_clip_planes().
3051  */
3052 void GraphicsStateGuardian::
3053 end_bind_clip_planes() {
3054 }
3055 
3056 /**
3057  * Assigns _target_texture and _target_tex_gen based on the _target_rs.
3058  */
3059 void GraphicsStateGuardian::
3060 determine_target_texture() {
3061  const TextureAttrib *target_texture = (const TextureAttrib *)
3062  _target_rs->get_attrib_def(TextureAttrib::get_class_slot());
3063  const TexGenAttrib *target_tex_gen = (const TexGenAttrib *)
3064  _target_rs->get_attrib_def(TexGenAttrib::get_class_slot());
3065 
3066  nassertv(target_texture != nullptr &&
3067  target_tex_gen != nullptr);
3068  _target_texture = target_texture;
3069  _target_tex_gen = target_tex_gen;
3070 
3071  if (_has_texture_alpha_scale) {
3073  PT(Texture) texture = TexturePool::get_alpha_scale_map();
3074 
3075  _target_texture = DCAST(TextureAttrib, _target_texture->add_on_stage(stage, texture));
3076  _target_tex_gen = DCAST(TexGenAttrib, _target_tex_gen->add_stage
3077  (stage, TexGenAttrib::M_constant, LTexCoord3(_current_color_scale[3], 0.0f, 0.0f)));
3078  }
3079 
3080  int max_texture_stages = get_max_texture_stages();
3081  _target_texture = _target_texture->filter_to_max(max_texture_stages);
3082  nassertv(_target_texture->get_num_on_stages() <= max_texture_stages);
3083 }
3084 
3085 /**
3086  * Assigns _target_shader based on the _target_rs.
3087  */
3088 void GraphicsStateGuardian::
3089 determine_target_shader() {
3090  if (_target_rs->_generated_shader != nullptr) {
3091  _target_shader = (const ShaderAttrib *)_target_rs->_generated_shader.p();
3092  } else {
3093  _target_shader = (const ShaderAttrib *)
3094  _target_rs->get_attrib_def(ShaderAttrib::get_class_slot());
3095  }
3096 }
3097 
3098 /**
3099  * Frees some memory that was explicitly allocated within the glgsg.
3100  */
3101 void GraphicsStateGuardian::
3102 free_pointers() {
3103 }
3104 
3105 /**
3106  * This is called by the associated GraphicsWindow when close_window() is
3107  * called. It should null out the _win pointer and possibly free any open
3108  * resources associated with the GSG.
3109  */
3110 void GraphicsStateGuardian::
3111 close_gsg() {
3112  // Protect from multiple calls, and also inform any other functions not to
3113  // try to create new stuff while we're going down.
3114  if (_closing_gsg) {
3115  return;
3116  }
3117  _closing_gsg = true;
3118 
3119  if (display_cat.is_debug()) {
3120  display_cat.debug()
3121  << this << " close_gsg " << get_type() << "\n";
3122  }
3123 
3124  // As tempting as it may be to try to release all the textures and geoms
3125  // now, we can't, because we might not be the currently-active GSG (this is
3126  // particularly important in OpenGL, which maintains one currently-active GL
3127  // state in each thread). If we start deleting textures, we'll be
3128  // inadvertently deleting textures from some other OpenGL state.
3129 
3130  // Fortunately, it doesn't really matter, since the graphics API will be
3131  // responsible for cleaning up anything we don't clean up explicitly. We'll
3132  // just let them drop.
3133 
3134  // Make sure that all the contexts belonging to the GSG are deleted.
3135  _prepared_objects.clear();
3136 #ifdef DO_PSTATS
3137  _pending_timer_queries.clear();
3138 #endif
3139 
3140  free_pointers();
3141 }
3142 
3143 /**
3144  * This is called internally when it is determined that things are just fubar.
3145  * It temporarily deactivates the GSG just so things don't get out of hand,
3146  * and throws an event so the application can deal with this if it needs to.
3147  */
3148 void GraphicsStateGuardian::
3149 panic_deactivate() {
3150  if (_active) {
3151  display_cat.error()
3152  << "Deactivating " << get_type() << ".\n";
3153  set_active(false);
3154  throw_event("panic-deactivate-gsg", this);
3155  }
3156 }
3157 
3158 /**
3159  * Called whenever the color or color scale is changed, if
3160  * _color_scale_via_lighting is true. This will rederive
3161  * _material_force_color and _light_color_scale appropriately.
3162  */
3163 void GraphicsStateGuardian::
3164 determine_light_color_scale() {
3165  if (_has_scene_graph_color) {
3166  // If we have a scene graph color, it, plus the color scale, goes directly
3167  // into the material; we don't color scale the lights--this allows an
3168  // alpha color scale to work properly.
3169  _has_material_force_color = true;
3170  _material_force_color = _scene_graph_color;
3171  _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
3172  if (!_color_blend_involves_color_scale && _color_scale_enabled) {
3173  _material_force_color.set(_scene_graph_color[0] * _current_color_scale[0],
3174  _scene_graph_color[1] * _current_color_scale[1],
3175  _scene_graph_color[2] * _current_color_scale[2],
3176  _scene_graph_color[3] * _current_color_scale[3]);
3177  }
3178 
3179  } else if (!_vertex_colors_enabled) {
3180  // We don't have a scene graph color, but we don't want to enable vertex
3181  // colors either, so we still need to force a white material color in
3182  // absence of any other color.
3183  _has_material_force_color = true;
3184  _material_force_color.set(1.0f, 1.0f, 1.0f, 1.0f);
3185  _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
3186  if (!_color_blend_involves_color_scale && _color_scale_enabled) {
3187  _material_force_color.componentwise_mult(_current_color_scale);
3188  }
3189 
3190  } else {
3191  // Otherise, leave the materials alone, but we might still scale the
3192  // lights.
3193  _has_material_force_color = false;
3194  _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
3195  if (!_color_blend_involves_color_scale && _color_scale_enabled) {
3196  _light_color_scale = _current_color_scale;
3197  }
3198  }
3199 }
3200 
3201 /**
3202  *
3203  */
3204 CPT(RenderState) GraphicsStateGuardian::
3205 get_unlit_state() {
3206  static CPT(RenderState) state = nullptr;
3207  if (state == nullptr) {
3208  state = RenderState::make(LightAttrib::make_all_off());
3209  }
3210  return state;
3211 }
3212 
3213 /**
3214  *
3215  */
3216 CPT(RenderState) GraphicsStateGuardian::
3217 get_unclipped_state() {
3218  static CPT(RenderState) state = nullptr;
3219  if (state == nullptr) {
3220  state = RenderState::make(ClipPlaneAttrib::make_all_off());
3221  }
3222  return state;
3223 }
3224 
3225 /**
3226  *
3227  */
3228 CPT(RenderState) GraphicsStateGuardian::
3229 get_untextured_state() {
3230  static CPT(RenderState) state = nullptr;
3231  if (state == nullptr) {
3232  state = RenderState::make(TextureAttrib::make_off());
3233  }
3234  return state;
3235 }
3236 
3237 /**
3238  * Should be called when a texture is encountered that needs to have its RAM
3239  * image reloaded, and get_incomplete_render() is true. This will fire off a
3240  * thread on the current Loader object that will request the texture to load
3241  * its image. The image will be available at some point in the future.
3242  * @returns a future object that can be used to check its status.
3243  */
3244 AsyncFuture *GraphicsStateGuardian::
3245 async_reload_texture(TextureContext *tc) {
3246  nassertr(_loader != nullptr, nullptr);
3247 
3248  int priority = 0;
3249  if (_current_display_region != nullptr) {
3250  priority = _current_display_region->get_texture_reload_priority();
3251  }
3252 
3253  string task_name = string("reload:") + tc->get_texture()->get_name();
3254  PT(AsyncTaskManager) task_mgr = _loader->get_task_manager();
3255 
3256  // See if we are already loading this task.
3257  AsyncTaskCollection orig_tasks = task_mgr->find_tasks(task_name);
3258  size_t num_tasks = orig_tasks.get_num_tasks();
3259  for (size_t ti = 0; ti < num_tasks; ++ti) {
3260  AsyncTask *task = orig_tasks.get_task(ti);
3261  if (task->is_exact_type(TextureReloadRequest::get_class_type()) &&
3262  ((TextureReloadRequest *)task)->get_texture() == tc->get_texture()) {
3263  // This texture is already queued to be reloaded. Don't queue it again,
3264  // just make sure the priority is updated, and return.
3265  task->set_priority(std::max(task->get_priority(), priority));
3266  return (AsyncFuture *)task;
3267  }
3268  }
3269 
3270  // This texture has not yet been queued to be reloaded. Queue it up now.
3271  PT(AsyncTask) request =
3272  new TextureReloadRequest(task_name,
3273  _prepared_objects, tc->get_texture(),
3274  _supports_compressed_texture);
3275  request->set_priority(priority);
3276  _loader->load_async(request);
3277  return (AsyncFuture *)request.p();
3278 }
3279 
3280 /**
3281  * Returns a shadow map for the given light source. If none exists, it is
3282  * created, using the given host window to create the buffer, or the current
3283  * window if that is set to NULL.
3284  */
3285 PT(Texture) GraphicsStateGuardian::
3286 get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host) {
3287  PandaNode *node = light_np.node();
3288  bool is_point = node->is_of_type(PointLight::get_class_type());
3289  nassertr(node->is_of_type(DirectionalLight::get_class_type()) ||
3290  node->is_of_type(Spotlight::get_class_type()) ||
3291  is_point, nullptr);
3292 
3293  LightLensNode *light = (LightLensNode *)node;
3294  if (light == nullptr || !light->_shadow_caster) {
3295  // This light does not have a shadow caster. Return a dummy shadow map
3296  // that is filled with a depth value of 1.
3297  if (node->is_of_type(PointLight::get_class_type())) {
3298  return get_dummy_shadow_map(Texture::TT_cube_map);
3299  } else {
3300  return get_dummy_shadow_map(Texture::TT_2d_texture);
3301  }
3302  }
3303 
3304  // The light's shadow map should have been created by set_shadow_caster().
3305  nassertr(light->_shadow_map != nullptr, nullptr);
3306 
3307  // See if we already have a buffer. If not, create one.
3308  if (light->_sbuffers.count(this) != 0) {
3309  // There's already a buffer - use that.
3310  return light->_shadow_map;
3311  }
3312 
3313  if (display_cat.is_debug()) {
3314  display_cat.debug()
3315  << "Constructing shadow buffer for light '" << light->get_name()
3316  << "', size=" << light->_sb_size[0] << "x" << light->_sb_size[1]
3317  << ", sort=" << light->_sb_sort << "\n";
3318  }
3319 
3320  if (host == nullptr) {
3321  nassertr(_current_display_region != nullptr, nullptr);
3322  host = _current_display_region->get_window();
3323  }
3324  nassertr(host != nullptr, nullptr);
3325 
3326  // Nope, the light doesn't have a buffer for our GSG. Make one.
3327  GraphicsOutput *sbuffer = make_shadow_buffer(light, light->_shadow_map,
3328  DCAST(GraphicsOutput, host));
3329 
3330  // Assign display region(s) to the buffer and camera
3331  if (is_point) {
3332  for (int i = 0; i < 6; ++i) {
3333  PT(DisplayRegion) dr = sbuffer->make_mono_display_region(0, 1, 0, 1);
3334  dr->set_lens_index(i);
3335  dr->set_target_tex_page(i);
3336  dr->set_camera(light_np);
3337  dr->set_clear_depth_active(true);
3338  }
3339  } else {
3340  PT(DisplayRegion) dr = sbuffer->make_mono_display_region(0, 1, 0, 1);
3341  dr->set_camera(light_np);
3342  dr->set_clear_depth_active(true);
3343  }
3344 
3345  light->_sbuffers[this] = sbuffer;
3346  return light->_shadow_map;
3347 }
3348 
3349 /**
3350  * Returns a dummy shadow map that can be used for a light of the given type
3351  * that does not cast shadows.
3352  */
3353 PT(Texture) GraphicsStateGuardian::
3354 get_dummy_shadow_map(Texture::TextureType texture_type) const {
3355  if (texture_type != Texture::TT_cube_map) {
3356  static PT(Texture) dummy_2d;
3357  if (dummy_2d == nullptr) {
3358  dummy_2d = new Texture("dummy-shadow-2d");
3359  dummy_2d->setup_2d_texture(1, 1, Texture::T_unsigned_byte, Texture::F_depth_component);
3360  dummy_2d->set_clear_color(1);
3362  // If we have the ARB_shadow extension, enable shadow filtering.
3363  dummy_2d->set_minfilter(SamplerState::FT_shadow);
3364  dummy_2d->set_magfilter(SamplerState::FT_shadow);
3365  } else {
3366  dummy_2d->set_minfilter(SamplerState::FT_linear);
3367  dummy_2d->set_magfilter(SamplerState::FT_linear);
3368  }
3369  }
3370  return dummy_2d;
3371  } else {
3372  static PT(Texture) dummy_cube;
3373  if (dummy_cube == nullptr) {
3374  dummy_cube = new Texture("dummy-shadow-cube");
3375  dummy_cube->setup_cube_map(1, Texture::T_unsigned_byte, Texture::F_depth_component);
3376  dummy_cube->set_clear_color(1);
3377  // Note: cube map shadow filtering doesn't seem to work in Cg.
3378  dummy_cube->set_minfilter(SamplerState::FT_linear);
3379  dummy_cube->set_magfilter(SamplerState::FT_linear);
3380  }
3381  return dummy_cube;
3382  }
3383 }
3384 
3385 /**
3386  * Creates a depth buffer for shadow mapping. A derived GSG can override this
3387  * if it knows that a particular buffer type works best for shadow rendering.
3388  */
3389 GraphicsOutput *GraphicsStateGuardian::
3390 make_shadow_buffer(LightLensNode *light, Texture *tex, GraphicsOutput *host) {
3391  bool is_point = light->is_of_type(PointLight::get_class_type());
3392 
3393  // Determine the properties for creating the depth buffer.
3395  fbp.set_depth_bits(shadow_depth_bits);
3396 
3397  WindowProperties props = WindowProperties::size(light->_sb_size);
3398  int flags = GraphicsPipe::BF_refuse_window;
3399  if (is_point) {
3400  flags |= GraphicsPipe::BF_size_square;
3401  }
3402 
3403  // Create the buffer. This is a bit tricky because make_output() can only
3404  // be called from the app thread, but it won't cause issues as long as the
3405  // pipe can precertify the buffer, which it can in most cases.
3407  light->get_name(), light->_sb_sort, fbp, props, flags, this, host);
3408 
3409  if (sbuffer != nullptr) {
3410  sbuffer->add_render_texture(tex, GraphicsOutput::RTM_bind_or_copy, GraphicsOutput::RTP_depth);
3411  }
3412  return sbuffer;
3413 }
3414 
3415 /**
3416  * Ensures that an appropriate shader has been generated for the given state.
3417  * This is stored in the _generated_shader field on the RenderState.
3418  */
3421 #ifdef HAVE_CG
3422  const ShaderAttrib *shader_attrib;
3423  state->get_attrib_def(shader_attrib);
3424 
3425  if (shader_attrib->auto_shader()) {
3426  if (_shader_generator == nullptr) {
3427  if (!_supports_basic_shaders) {
3428  return;
3429  }
3430  _shader_generator = new ShaderGenerator(this);
3431  }
3432  if (state->_generated_shader == nullptr ||
3433  state->_generated_shader_seq != _generated_shader_seq) {
3435 
3436  // Currently we overload this flag to request vertex animation for the
3437  // shader generator.
3438  const ShaderAttrib *sattr;
3439  state->get_attrib_def(sattr);
3440  if (sattr->get_flag(ShaderAttrib::F_hardware_skinning)) {
3441  spec.set_hardware(4, true);
3442  }
3443 
3444  // Cache the generated ShaderAttrib on the shader state.
3445  state->_generated_shader = _shader_generator->synthesize_shader(state, spec);
3446  state->_generated_shader_seq = _generated_shader_seq;
3447  }
3448  }
3449 #endif
3450 }
3451 
3452 /**
3453  * Returns true if the GSG implements the extension identified by the given
3454  * string. This currently is only implemented by the OpenGL back-end.
3455  */
3457 has_extension(const string &extension) const {
3458  return false;
3459 }
3460 
3461 /**
3462  * Returns the vendor of the video card driver
3463  */
3464 string GraphicsStateGuardian::
3465 get_driver_vendor() {
3466  return string();
3467 }
3468 
3469 /**
3470  * Returns GL_Renderer
3471  */
3473  return string();
3474 }
3475 
3476 /**
3477  * Returns driver version This has an implementation-defined meaning, and may
3478  * be "" if the particular graphics implementation does not provide a way to
3479  * query this information.
3480  */
3481 string GraphicsStateGuardian::
3482 get_driver_version() {
3483  return string();
3484 }
3485 
3486 /**
3487  * Returns major version of the video driver. This has an implementation-
3488  * defined meaning, and may be -1 if the particular graphics implementation
3489  * does not provide a way to query this information.
3490  */
3491 int GraphicsStateGuardian::
3492 get_driver_version_major() {
3493  return -1;
3494 }
3495 
3496 /**
3497  * Returns the minor version of the video driver. This has an implementation-
3498  * defined meaning, and may be -1 if the particular graphics implementation
3499  * does not provide a way to query this information.
3500  */
3501 int GraphicsStateGuardian::
3502 get_driver_version_minor() {
3503  return -1;
3504 }
3505 
3506 /**
3507  * Returns the major version of the shader model.
3508  */
3509 int GraphicsStateGuardian::
3510 get_driver_shader_version_major() {
3511  return -1;
3512 }
3513 
3514 /**
3515  * Returns the minor version of the shader model.
3516  */
3517 int GraphicsStateGuardian::
3518 get_driver_shader_version_minor() {
3519  return -1;
3520 }
3521 
3522 std::ostream &
3523 operator << (std::ostream &out, GraphicsStateGuardian::ShaderModel sm) {
3524  static const char *sm_strings[] = {"none", "1.1", "2.0", "2.x", "3.0", "4.0", "5.0", "5.1"};
3525  nassertr(sm >= 0 && sm <= GraphicsStateGuardian::SM_51, out);
3526  out << sm_strings[sm];
3527  return out;
3528 }
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.