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