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