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