mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
2249 lines
89 KiB
C++
2249 lines
89 KiB
C++
// Filename: graphicsStateGuardian.cxx
|
|
// Created by: drose (02Feb99)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "graphicsStateGuardian.h"
|
|
#include "config_display.h"
|
|
#include "textureContext.h"
|
|
#include "vertexBufferContext.h"
|
|
#include "indexBufferContext.h"
|
|
#include "renderBuffer.h"
|
|
#include "attribSlots.h"
|
|
#include "light.h"
|
|
#include "planeNode.h"
|
|
#include "ambientLight.h"
|
|
#include "throw_event.h"
|
|
#include "clockObject.h"
|
|
#include "pStatTimer.h"
|
|
#include "geomTristrips.h"
|
|
#include "geomTrifans.h"
|
|
#include "geomLinestrips.h"
|
|
#include "colorWriteAttrib.h"
|
|
#include "shader.h"
|
|
#include "pnotify.h"
|
|
#include "drawableRegion.h"
|
|
#include "displayRegion.h"
|
|
#include "graphicsOutput.h"
|
|
#include "texturePool.h"
|
|
#include "geomMunger.h"
|
|
#include "ambientLight.h"
|
|
#include "directionalLight.h"
|
|
#include "pointLight.h"
|
|
#include "spotlight.h"
|
|
#include "textureReloadRequest.h"
|
|
|
|
#include <algorithm>
|
|
#include <limits.h>
|
|
|
|
PStatCollector GraphicsStateGuardian::_vertex_buffer_switch_pcollector("Vertex buffer switch:Vertex");
|
|
PStatCollector GraphicsStateGuardian::_index_buffer_switch_pcollector("Vertex buffer switch:Index");
|
|
PStatCollector GraphicsStateGuardian::_load_vertex_buffer_pcollector("Draw:Transfer data:Vertex buffer");
|
|
PStatCollector GraphicsStateGuardian::_load_index_buffer_pcollector("Draw:Transfer data:Index buffer");
|
|
PStatCollector GraphicsStateGuardian::_create_vertex_buffer_pcollector("Draw:Transfer data:Create Vertex buffer");
|
|
PStatCollector GraphicsStateGuardian::_create_index_buffer_pcollector("Draw:Transfer data:Create Index buffer");
|
|
PStatCollector GraphicsStateGuardian::_load_texture_pcollector("Draw:Transfer data:Texture");
|
|
PStatCollector GraphicsStateGuardian::_data_transferred_pcollector("Data transferred");
|
|
PStatCollector GraphicsStateGuardian::_texmgrmem_total_pcollector("Texture manager");
|
|
PStatCollector GraphicsStateGuardian::_texmgrmem_resident_pcollector("Texture manager:Resident");
|
|
PStatCollector GraphicsStateGuardian::_primitive_batches_pcollector("Primitive batches");
|
|
PStatCollector GraphicsStateGuardian::_primitive_batches_tristrip_pcollector("Primitive batches:Triangle strips");
|
|
PStatCollector GraphicsStateGuardian::_primitive_batches_trifan_pcollector("Primitive batches:Triangle fans");
|
|
PStatCollector GraphicsStateGuardian::_primitive_batches_tri_pcollector("Primitive batches:Triangles");
|
|
PStatCollector GraphicsStateGuardian::_primitive_batches_other_pcollector("Primitive batches:Other");
|
|
PStatCollector GraphicsStateGuardian::_vertices_tristrip_pcollector("Vertices:Triangle strips");
|
|
PStatCollector GraphicsStateGuardian::_vertices_trifan_pcollector("Vertices:Triangle fans");
|
|
PStatCollector GraphicsStateGuardian::_vertices_tri_pcollector("Vertices:Triangles");
|
|
PStatCollector GraphicsStateGuardian::_vertices_other_pcollector("Vertices:Other");
|
|
PStatCollector GraphicsStateGuardian::_state_pcollector("State changes");
|
|
PStatCollector GraphicsStateGuardian::_transform_state_pcollector("State changes:Transforms");
|
|
PStatCollector GraphicsStateGuardian::_texture_state_pcollector("State changes:Textures");
|
|
PStatCollector GraphicsStateGuardian::_draw_primitive_pcollector("Draw:Primitive:Draw");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_pcollector("Draw:Set State");
|
|
PStatCollector GraphicsStateGuardian::_clear_pcollector("Draw:Clear");
|
|
PStatCollector GraphicsStateGuardian::_flush_pcollector("Draw:Flush");
|
|
|
|
PStatCollector GraphicsStateGuardian::_wait_occlusion_pcollector("Wait:Occlusion");
|
|
|
|
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_transform_pcollector("Draw:Set State:Transform");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_alpha_test_pcollector("Draw:Set State:Alpha test");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_antialias_pcollector("Draw:Set State:Antialias");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_clip_plane_pcollector("Draw:Set State:Clip plane");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_color_pcollector("Draw:Set State:Color");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_cull_face_pcollector("Draw:Set State:Cull face");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_depth_offset_pcollector("Draw:Set State:Depth offset");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_depth_test_pcollector("Draw:Set State:Depth test");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_depth_write_pcollector("Draw:Set State:Depth write");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_render_mode_pcollector("Draw:Set State:Render mode");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_rescale_normal_pcollector("Draw:Set State:Rescale normal");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_shade_model_pcollector("Draw:Set State:Shade model");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_blending_pcollector("Draw:Set State:Blending");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_shader_pcollector("Draw:Set State:Shader");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_shader_parameters_pcollector("Draw:Set State:Shader Parameters");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_texture_pcollector("Draw:Set State:Texture");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_tex_matrix_pcollector("Draw:Set State:Tex matrix");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_tex_gen_pcollector("Draw:Set State:Tex gen");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_material_pcollector("Draw:Set State:Material");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_light_pcollector("Draw:Set State:Light");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_stencil_pcollector("Draw:Set State:Stencil");
|
|
PStatCollector GraphicsStateGuardian::_draw_set_state_fog_pcollector("Draw:Set State:Fog");
|
|
|
|
|
|
PT(TextureStage) GraphicsStateGuardian::_alpha_scale_texture_stage = NULL;
|
|
|
|
TypeHandle GraphicsStateGuardian::_type_handle;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
GraphicsStateGuardian::
|
|
GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
|
|
GraphicsPipe *pipe) :
|
|
_internal_coordinate_system(internal_coordinate_system),
|
|
_pipe(pipe)
|
|
{
|
|
_coordinate_system = CS_invalid;
|
|
_internal_transform = TransformState::make_identity();
|
|
|
|
set_coordinate_system(get_default_coordinate_system());
|
|
|
|
_data_reader = (GeomVertexDataPipelineReader *)NULL;
|
|
_current_display_region = (DisplayRegion*)NULL;
|
|
_current_stereo_channel = Lens::SC_mono;
|
|
_current_lens = (Lens *)NULL;
|
|
_projection_mat = TransformState::make_identity();
|
|
_projection_mat_inv = TransformState::make_identity();
|
|
|
|
_needs_reset = true;
|
|
_is_valid = false;
|
|
_current_properties = NULL;
|
|
_closing_gsg = false;
|
|
_active = true;
|
|
_prepared_objects = new PreparedGraphicsObjects;
|
|
_stereo_buffer_mask = ~0;
|
|
_incomplete_render = allow_incomplete_render;
|
|
|
|
_is_hardware = false;
|
|
_prefers_triangle_strips = false;
|
|
_max_vertices_per_array = INT_MAX;
|
|
_max_vertices_per_primitive = INT_MAX;
|
|
|
|
// Initially, we set this to 1 (the default--no multitexturing
|
|
// supported). A derived GSG may set this differently if it
|
|
// supports multitexturing.
|
|
_max_texture_stages = 1;
|
|
|
|
// Also initially, we assume there are no limits on texture sizes,
|
|
// and that 3-d and cube-map textures are not supported.
|
|
_max_texture_dimension = -1;
|
|
_max_3d_texture_dimension = 0;
|
|
_max_cube_map_dimension = 0;
|
|
|
|
// Assume we don't support these fairly advanced texture combiner
|
|
// modes.
|
|
_supports_texture_combine = false;
|
|
_supports_texture_saved_result = false;
|
|
_supports_texture_dot3 = false;
|
|
|
|
_supports_3d_texture = false;
|
|
_supports_cube_map = false;
|
|
_supports_tex_non_pow2 = false;
|
|
_supports_compressed_texture = false;
|
|
_compressed_texture_formats.clear();
|
|
_compressed_texture_formats.set_bit(Texture::CM_off);
|
|
|
|
// Assume no limits on number of lights or clip planes.
|
|
_max_lights = -1;
|
|
_max_clip_planes = -1;
|
|
|
|
// Assume no vertex blending capability.
|
|
_max_vertex_transforms = 0;
|
|
_max_vertex_transform_indices = 0;
|
|
|
|
_supports_occlusion_query = false;
|
|
|
|
// Initially, we set this to false; a GSG that knows it has this
|
|
// property should set it to true.
|
|
_copy_texture_inverted = false;
|
|
|
|
// Similarly with these capabilities flags.
|
|
_supports_multisample = false;
|
|
_supports_generate_mipmap = false;
|
|
_supports_render_texture = false;
|
|
_supports_depth_texture = false;
|
|
_supports_depth_stencil = false;
|
|
_supports_shadow_filter = false;
|
|
_supports_basic_shaders = false;
|
|
|
|
_supports_stencil_wrap = false;
|
|
_supports_two_sided_stencil = false;
|
|
|
|
_maximum_simultaneous_render_targets = 1;
|
|
|
|
_supported_geom_rendering = 0;
|
|
|
|
// If this is true, then we can apply a color and/or color scale by
|
|
// twiddling the material and/or ambient light (which could mean
|
|
// enabling lighting even without a LightAttrib).
|
|
_color_scale_via_lighting = color_scale_via_lighting;
|
|
|
|
// Similarly for applying a texture to achieve uniform alpha
|
|
// scaling.
|
|
_alpha_scale_via_texture = alpha_scale_via_texture;
|
|
|
|
// Few GSG's can do this, since it requires touching each vertex as
|
|
// it is rendered.
|
|
_runtime_color_scale = false;
|
|
|
|
_stencil_render_states = 0;
|
|
|
|
// The default is no shader support.
|
|
_auto_detect_shader_model = SM_00;
|
|
_shader_model = SM_00;
|
|
|
|
_gamma = 1.0f;
|
|
_texture_quality_override = Texture::QL_default;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::Destructor
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
GraphicsStateGuardian::
|
|
~GraphicsStateGuardian() {
|
|
remove_gsg(this);
|
|
|
|
if (_stencil_render_states) {
|
|
delete _stencil_render_states;
|
|
_stencil_render_states = 0;
|
|
}
|
|
|
|
GeomMunger::unregister_mungers_for_gsg(this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_supports_multisample
|
|
// Access: Published, Virtual
|
|
// Description: Returns true if this particular GSG supports using
|
|
// the multisample bits to provide antialiasing, and
|
|
// also supports M_multisample and M_multisample_mask
|
|
// transparency modes. If this is not true for a
|
|
// particular GSG, Panda will map the M_multisample
|
|
// modes to M_binary.
|
|
//
|
|
// This method is declared virtual solely so that it can
|
|
// be queried from cullResult.cxx.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
get_supports_multisample() const {
|
|
return _supports_multisample;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_supported_geom_rendering
|
|
// Access: Published, Virtual
|
|
// Description: Returns the union of Geom::GeomRendering values that
|
|
// this particular GSG can support directly. If a Geom
|
|
// needs to be rendered that requires some additional
|
|
// properties, the StandardMunger and/or the
|
|
// CullableObject will convert it as needed.
|
|
//
|
|
// This method is declared virtual solely so that it can
|
|
// be queried from cullableObject.cxx.
|
|
////////////////////////////////////////////////////////////////////
|
|
int GraphicsStateGuardian::
|
|
get_supported_geom_rendering() const {
|
|
return _supported_geom_rendering;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::set_coordinate_system
|
|
// Access: Published
|
|
// Description: Changes the coordinate system in effect on this
|
|
// particular gsg. This is also called the "external"
|
|
// coordinate system, since it is the coordinate system
|
|
// used by the scene graph, external to to GSG.
|
|
//
|
|
// Normally, this will be the default coordinate system,
|
|
// but it might be set differently at runtime.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
set_coordinate_system(CoordinateSystem cs) {
|
|
_coordinate_system = cs;
|
|
|
|
// Changing the external coordinate system changes the cs_transform.
|
|
if (_internal_coordinate_system == CS_default ||
|
|
_internal_coordinate_system == _coordinate_system) {
|
|
_cs_transform = TransformState::make_identity();
|
|
_inv_cs_transform = TransformState::make_identity();
|
|
|
|
} else {
|
|
_cs_transform =
|
|
TransformState::make_mat
|
|
(LMatrix4f::convert_mat(_coordinate_system,
|
|
_internal_coordinate_system));
|
|
_inv_cs_transform =
|
|
TransformState::make_mat
|
|
(LMatrix4f::convert_mat(_internal_coordinate_system,
|
|
_coordinate_system));
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_internal_coordinate_system
|
|
// Access: Published, Virtual
|
|
// Description: Returns the coordinate system used internally by the
|
|
// GSG. This may be the same as the external coordinate
|
|
// system reported by get_coordinate_system(), or it may
|
|
// be something different.
|
|
//
|
|
// In any case, vertices that have been transformed
|
|
// before being handed to the GSG (that is, vertices
|
|
// with a contents value of C_clip_point) will be
|
|
// expected to be in this coordinate system.
|
|
////////////////////////////////////////////////////////////////////
|
|
CoordinateSystem GraphicsStateGuardian::
|
|
get_internal_coordinate_system() const {
|
|
return _internal_coordinate_system;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_prepared_objects
|
|
// Access: Public, Virtual
|
|
// Description: Returns the set of texture and geom objects that have
|
|
// been prepared with this GSG (and possibly other GSG's
|
|
// that share objects).
|
|
////////////////////////////////////////////////////////////////////
|
|
PreparedGraphicsObjects *GraphicsStateGuardian::
|
|
get_prepared_objects() {
|
|
return _prepared_objects;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::set_gamma
|
|
// Access: Published, Virtual
|
|
// Description: Set gamma. Returns true on success.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
set_gamma(float gamma) {
|
|
_gamma = gamma;
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_gamma
|
|
// Access: Published
|
|
// Description: Get the current gamma setting.
|
|
////////////////////////////////////////////////////////////////////
|
|
float GraphicsStateGuardian::
|
|
get_gamma(float gamma) {
|
|
return _gamma;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::restore_gamma
|
|
// Access: Published, Virtual
|
|
// Description: Restore original gamma setting.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
restore_gamma() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::set_scene
|
|
// Access: Public
|
|
// Description: Sets the SceneSetup object that indicates the initial
|
|
// camera position, etc. This must be called before
|
|
// traversal begins. Returns true if the scene is
|
|
// acceptable, false if something's wrong.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
set_scene(SceneSetup *scene_setup) {
|
|
_scene_setup = scene_setup;
|
|
_current_lens = scene_setup->get_lens();
|
|
if (_current_lens == (Lens *)NULL) {
|
|
return false;
|
|
}
|
|
|
|
_projection_mat = calc_projection_mat(_current_lens);
|
|
if (_projection_mat == 0) {
|
|
return false;
|
|
}
|
|
_projection_mat_inv = _projection_mat->get_inverse();
|
|
return prepare_lens();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_scene
|
|
// Access: Public, Virtual
|
|
// Description: Returns the current SceneSetup object.
|
|
////////////////////////////////////////////////////////////////////
|
|
SceneSetup *GraphicsStateGuardian::
|
|
get_scene() const {
|
|
return _scene_setup;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::prepare_texture
|
|
// Access: Public, Virtual
|
|
// Description: Creates whatever structures the GSG requires to
|
|
// represent the texture internally, and returns a
|
|
// newly-allocated TextureContext object with this data.
|
|
// It is the responsibility of the calling function to
|
|
// later call release_texture() with this same pointer
|
|
// (which will also delete the pointer).
|
|
//
|
|
// This function should not be called directly to
|
|
// prepare a texture. Instead, call Texture::prepare().
|
|
////////////////////////////////////////////////////////////////////
|
|
TextureContext *GraphicsStateGuardian::
|
|
prepare_texture(Texture *) {
|
|
return (TextureContext *)NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::update_texture
|
|
// Access: Public, Virtual
|
|
// Description: Ensures that the current Texture data is refreshed
|
|
// onto the GSG. This means updating the texture
|
|
// properties and/or re-uploading the texture image, if
|
|
// necessary. This should only be called within the
|
|
// draw thread.
|
|
//
|
|
// If force is true, this function will not return until
|
|
// the texture has been fully uploaded. If force is
|
|
// false, the function may choose to upload a simple
|
|
// version of the texture instead, if the texture is not
|
|
// fully resident (and if get_incomplete_render() is
|
|
// true).
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
update_texture(TextureContext *, bool) {
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::release_texture
|
|
// Access: Public, Virtual
|
|
// Description: Frees the resources previously allocated via a call
|
|
// to prepare_texture(), including deleting the
|
|
// TextureContext itself, if it is non-NULL.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
release_texture(TextureContext *) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::extract_texture_data
|
|
// Access: Public, Virtual
|
|
// Description: This method should only be called by the
|
|
// GraphicsEngine. Do not call it directly; call
|
|
// GraphicsEngine::extract_texture_data() instead.
|
|
//
|
|
// This method will be called in the draw thread to
|
|
// download the texture memory's image into its
|
|
// ram_image value. It returns true on success, false
|
|
// otherwise.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
extract_texture_data(Texture *) {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::prepare_geom
|
|
// Access: Public, Virtual
|
|
// Description: Prepares the indicated Geom for retained-mode
|
|
// rendering, by creating whatever structures are
|
|
// necessary in the GSG (for instance, vertex buffers).
|
|
// Returns the newly-allocated GeomContext that can be
|
|
// used to render the geom.
|
|
////////////////////////////////////////////////////////////////////
|
|
GeomContext *GraphicsStateGuardian::
|
|
prepare_geom(Geom *) {
|
|
return (GeomContext *)NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::release_geom
|
|
// Access: Public, Virtual
|
|
// Description: Frees the resources previously allocated via a call
|
|
// to prepare_geom(), including deleting the GeomContext
|
|
// itself, if it is non-NULL.
|
|
//
|
|
// This function should not be called directly to
|
|
// prepare a Geom. Instead, call Geom::prepare().
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
release_geom(GeomContext *) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::prepare_shader
|
|
// Access: Public, Virtual
|
|
// Description: Compile a vertex/fragment shader body.
|
|
////////////////////////////////////////////////////////////////////
|
|
ShaderContext *GraphicsStateGuardian::
|
|
prepare_shader(Shader *shader) {
|
|
return (ShaderContext *)NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::release_shader
|
|
// Access: Public, Virtual
|
|
// Description: Releases the resources allocated by prepare_shader
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
release_shader(ShaderContext *sc) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::prepare_vertex_buffer
|
|
// Access: Public, Virtual
|
|
// Description: Prepares the indicated buffer for retained-mode
|
|
// rendering.
|
|
////////////////////////////////////////////////////////////////////
|
|
VertexBufferContext *GraphicsStateGuardian::
|
|
prepare_vertex_buffer(GeomVertexArrayData *) {
|
|
return (VertexBufferContext *)NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::release_vertex_buffer
|
|
// Access: Public, Virtual
|
|
// Description: Frees the resources previously allocated via a call
|
|
// to prepare_data(), including deleting the
|
|
// VertexBufferContext itself, if necessary.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
release_vertex_buffer(VertexBufferContext *) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::prepare_index_buffer
|
|
// Access: Public, Virtual
|
|
// Description: Prepares the indicated buffer for retained-mode
|
|
// rendering.
|
|
////////////////////////////////////////////////////////////////////
|
|
IndexBufferContext *GraphicsStateGuardian::
|
|
prepare_index_buffer(GeomPrimitive *) {
|
|
return (IndexBufferContext *)NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::release_index_buffer
|
|
// Access: Public, Virtual
|
|
// Description: Frees the resources previously allocated via a call
|
|
// to prepare_data(), including deleting the
|
|
// IndexBufferContext itself, if necessary.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
release_index_buffer(IndexBufferContext *) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_supports_occlusion_query
|
|
// Access: Public, Virtual
|
|
// Description: Returns true if this GSG supports an occlusion query.
|
|
// If this is true, then begin_occlusion_query() and
|
|
// end_occlusion_query() may be called to bracket a
|
|
// sequence of draw_triangles() (or whatever) calls to
|
|
// measure pixels that pass the depth test.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
get_supports_occlusion_query() const {
|
|
return _supports_occlusion_query;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::begin_occlusion_query
|
|
// Access: Public, Virtual
|
|
// Description: Begins a new occlusion query. After this call, you
|
|
// may call begin_draw_primitives() and
|
|
// draw_triangles()/draw_whatever() repeatedly.
|
|
// Eventually, you should call end_occlusion_query()
|
|
// before the end of the frame; that will return a new
|
|
// OcclusionQueryContext object that will tell you how
|
|
// many pixels represented by the bracketed geometry
|
|
// passed the depth test.
|
|
//
|
|
// It is not valid to call begin_occlusion_query()
|
|
// between another begin_occlusion_query()
|
|
// .. end_occlusion_query() sequence.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
begin_occlusion_query() {
|
|
nassertv(_current_occlusion_query == (OcclusionQueryContext *)NULL);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::end_occlusion_query
|
|
// Access: Public, Virtual
|
|
// Description: Ends a previous call to begin_occlusion_query().
|
|
// This call returns the OcclusionQueryContext object
|
|
// that will (eventually) report the number of pixels
|
|
// that passed the depth test between the call to
|
|
// begin_occlusion_query() and end_occlusion_query().
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(OcclusionQueryContext) GraphicsStateGuardian::
|
|
end_occlusion_query() {
|
|
nassertr(_current_occlusion_query != (OcclusionQueryContext *)NULL, NULL);
|
|
PT(OcclusionQueryContext) result = _current_occlusion_query;
|
|
_current_occlusion_query = NULL;
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_geom_munger
|
|
// Access: Public, Virtual
|
|
// Description: Looks up or creates a GeomMunger object to munge
|
|
// vertices appropriate to this GSG for the indicated
|
|
// state.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(GeomMunger) GraphicsStateGuardian::
|
|
get_geom_munger(const RenderState *state, Thread *current_thread) {
|
|
// We can cast the RenderState to a non-const object because we are
|
|
// only updating a cache within the RenderState, not really changing
|
|
// any of its properties.
|
|
RenderState *nc_state = ((RenderState *)state);
|
|
|
|
// Before we even look up the map, see if the _last_mi value points
|
|
// to this GSG. This is likely because we tend to visit the same
|
|
// state multiple times during a frame. Also, this might well be
|
|
// the only GSG in the world anyway.
|
|
if (!nc_state->_mungers.empty()) {
|
|
RenderState::Mungers::const_iterator mi = nc_state->_last_mi;
|
|
if (!(*mi).first.was_deleted() && (*mi).first == this) {
|
|
if ((*mi).second->is_registered()) {
|
|
return (*mi).second;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Nope, we have to look it up in the map.
|
|
RenderState::Mungers::iterator mi = nc_state->_mungers.find(this);
|
|
if (mi != nc_state->_mungers.end() && !(*mi).first.was_deleted()) {
|
|
if ((*mi).second->is_registered()) {
|
|
nc_state->_last_mi = mi;
|
|
return (*mi).second;
|
|
}
|
|
// This GeomMunger is no longer registered. Remove it from the
|
|
// map.
|
|
nc_state->_mungers.erase(mi);
|
|
}
|
|
|
|
// Nothing in the map; create a new entry.
|
|
PT(GeomMunger) munger = make_geom_munger(nc_state, current_thread);
|
|
nassertr(munger != (GeomMunger *)NULL && munger->is_registered(), munger);
|
|
|
|
mi = nc_state->_mungers.insert(RenderState::Mungers::value_type(this, munger)).first;
|
|
nc_state->_last_mi = mi;
|
|
|
|
return munger;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::make_geom_munger
|
|
// Access: Public, Virtual
|
|
// Description: Creates a new GeomMunger object to munge vertices
|
|
// appropriate to this GSG for the indicated state.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(GeomMunger) GraphicsStateGuardian::
|
|
make_geom_munger(const RenderState *state, Thread *current_thread) {
|
|
// The default implementation returns no munger at all, but
|
|
// presumably, every kind of GSG needs some special munging action,
|
|
// so real GSG's will override this to return something more
|
|
// useful.
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::compute_distance_to
|
|
// Access: Public, Virtual
|
|
// Description: This function may only be called during a render
|
|
// traversal; it will compute the distance to the
|
|
// indicated point, assumed to be in eye coordinates,
|
|
// from the camera plane.
|
|
////////////////////////////////////////////////////////////////////
|
|
float GraphicsStateGuardian::
|
|
compute_distance_to(const LPoint3f &point) const {
|
|
switch (_coordinate_system) {
|
|
case CS_zup_right:
|
|
return point[1];
|
|
|
|
case CS_yup_right:
|
|
return -point[2];
|
|
|
|
case CS_zup_left:
|
|
return -point[1];
|
|
|
|
case CS_yup_left:
|
|
return point[2];
|
|
|
|
default:
|
|
gsg_cat.error()
|
|
<< "Invalid coordinate system in compute_distance_to: "
|
|
<< (int)_coordinate_system << "\n";
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::fetch_specified_value
|
|
// Access: Public
|
|
// Description: The gsg contains a large number of useful matrices:
|
|
//
|
|
// * the world transform,
|
|
// * the modelview matrix,
|
|
// * the cs_transform,
|
|
// * etc, etc.
|
|
//
|
|
// A shader can request any of these values, and
|
|
// furthermore, it can request that various compositions,
|
|
// inverses, and transposes be performed. The
|
|
// ShaderMatSpec is a data structure indicating what
|
|
// datum is desired and what conversions to perform.
|
|
// This routine, fetch_specified_value, is responsible for
|
|
// doing the actual retrieval and conversions.
|
|
//
|
|
// Some values, like the following, aren't matrices:
|
|
//
|
|
// * window size
|
|
// * texture coordinates of card center
|
|
//
|
|
// This routine can fetch these values as well, by
|
|
// shoehorning them into a matrix. In this way, we avoid
|
|
// the need for a separate routine to fetch these values.
|
|
//
|
|
// The "altered" bits indicate what parts of the
|
|
// state_and_transform have changed since the last
|
|
// time this particular ShaderMatSpec was evaluated.
|
|
// This may allow data to be cached and not reevaluated.
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
const LMatrix4f *GraphicsStateGuardian::
|
|
fetch_specified_value(Shader::ShaderMatSpec &spec, int altered) {
|
|
LVecBase3f v;
|
|
|
|
if (altered & spec._dep[0]) {
|
|
const LMatrix4f *t = fetch_specified_part(spec._part[0], spec._arg[0], spec._cache[0]);
|
|
if (t != &spec._cache[0]) {
|
|
spec._cache[0] = *t;
|
|
}
|
|
}
|
|
if (altered & spec._dep[1]) {
|
|
const LMatrix4f *t = fetch_specified_part(spec._part[1], spec._arg[1], spec._cache[1]);
|
|
if (t != &spec._cache[1]) {
|
|
spec._cache[1] = *t;
|
|
}
|
|
}
|
|
|
|
switch(spec._func) {
|
|
case Shader::SMF_compose:
|
|
spec._value.multiply(spec._cache[0], spec._cache[1]);
|
|
return &spec._value;
|
|
case Shader::SMF_transform_dlight:
|
|
spec._value = spec._cache[0];
|
|
v = spec._cache[1].xform_vec(spec._cache[0].get_row3(2));
|
|
v.normalize();
|
|
spec._value.set_row(2, v);
|
|
v = spec._cache[1].xform_vec(spec._cache[0].get_row3(3));
|
|
v.normalize();
|
|
spec._value.set_row(3, v);
|
|
return &spec._value;
|
|
case Shader::SMF_transform_plight:
|
|
spec._value = spec._cache[0];
|
|
spec._value.set_row(2, spec._cache[1].xform_point(spec._cache[0].get_row3(2)));
|
|
return &spec._value;
|
|
case Shader::SMF_transform_slight:
|
|
spec._value = spec._cache[0];
|
|
spec._value.set_row(2, spec._cache[1].xform_point(spec._cache[0].get_row3(2)));
|
|
v = spec._cache[1].xform_vec(spec._cache[0].get_row3(3));
|
|
v.normalize();
|
|
spec._value.set_row(3, v);
|
|
return &spec._value;
|
|
case Shader::SMF_first:
|
|
return &spec._cache[0];
|
|
default:
|
|
// should never get here
|
|
spec._value = LMatrix4f::ident_mat();
|
|
return &spec._value;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::fetch_specified_part
|
|
// Access: Public
|
|
// Description: See fetch_specified_value
|
|
////////////////////////////////////////////////////////////////////
|
|
const LMatrix4f *GraphicsStateGuardian::
|
|
fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LMatrix4f &t) {
|
|
switch(part) {
|
|
case Shader::SMO_identity: {
|
|
return &LMatrix4f::ident_mat();
|
|
}
|
|
case Shader::SMO_window_size: {
|
|
t = LMatrix4f::translate_mat(_current_display_region->get_pixel_width(),
|
|
_current_display_region->get_pixel_height(),
|
|
0.0);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_pixel_size: {
|
|
t = LMatrix4f::translate_mat(_current_display_region->get_pixel_width(),
|
|
_current_display_region->get_pixel_height(),
|
|
0.0);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_texpad_x: {
|
|
Texture *tex = _target._shader->get_shader_input_texture(name);
|
|
nassertr(tex != 0, &LMatrix4f::zeros_mat());
|
|
int sx = tex->get_x_size() - tex->get_pad_x_size();
|
|
int sy = tex->get_y_size() - tex->get_pad_y_size();
|
|
int sz = tex->get_z_size() - tex->get_pad_z_size();
|
|
double cx = (sx * 0.5) / tex->get_x_size();
|
|
double cy = (sy * 0.5) / tex->get_y_size();
|
|
double cz = (sz * 0.5) / tex->get_z_size();
|
|
t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,cx,cy,cz,0);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_texpix_x: {
|
|
Texture *tex = _target._shader->get_shader_input_texture(name);
|
|
nassertr(tex != 0, &LMatrix4f::zeros_mat());
|
|
double px = 1.0 / tex->get_x_size();
|
|
double py = 1.0 / tex->get_y_size();
|
|
double pz = 1.0 / tex->get_z_size();
|
|
t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,px,py,pz,0);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_attr_material: {
|
|
// Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS
|
|
if (_target._material->is_off()) {
|
|
t = LMatrix4f(1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0);
|
|
return &t;
|
|
}
|
|
Material *m = _target._material->get_material();
|
|
LVecBase4f const &amb = m->get_ambient();
|
|
LVecBase4f const &dif = m->get_diffuse();
|
|
LVecBase4f const &emm = m->get_emission();
|
|
LVecBase4f spc = m->get_specular();
|
|
spc[3] = m->get_shininess();
|
|
t = LMatrix4f(amb[0],amb[1],amb[2],amb[3],
|
|
dif[0],dif[1],dif[2],dif[3],
|
|
emm[0],emm[1],emm[2],emm[3],
|
|
spc[0],spc[1],spc[2],spc[3]);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_attr_color: {
|
|
if (_target._color->get_color_type() != ColorAttrib::T_flat) {
|
|
return &LMatrix4f::ones_mat();
|
|
}
|
|
LVecBase4f c = _target._color->get_color();
|
|
t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_alight_x: {
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::zeros_mat());
|
|
AmbientLight *lt;
|
|
DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
|
|
Colorf const &c = lt->get_color();
|
|
t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_satten_x: {
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::ones_mat());
|
|
Spotlight *lt;
|
|
DCAST_INTO_R(lt, np.node(), &LMatrix4f::ones_mat());
|
|
LVecBase3f const &a = lt->get_attenuation();
|
|
float x = lt->get_exponent();
|
|
t = LMatrix4f(0,0,0,0,0,0,0,0,0,0,0,0,a[0],a[1],a[2],x);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_dlight_x: {
|
|
// The dlight matrix contains COLOR, SPECULAR, DIRECTION, PSEUDOHALFANGLE
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::zeros_mat());
|
|
DirectionalLight *lt;
|
|
DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
|
|
Colorf const &c = lt->get_color();
|
|
Colorf const &s = lt->get_specular_color();
|
|
t = np.get_net_transform()->get_mat() *
|
|
get_scene()->get_world_transform()->get_mat();
|
|
LVecBase3f d = -(t.xform_vec(lt->get_direction()));
|
|
d.normalize();
|
|
LVecBase3f h = d + LVecBase3f(0,-1,0);
|
|
h.normalize();
|
|
t = LMatrix4f(c[0],c[1],c[2],c[3],s[0],s[1],s[2],c[3],d[0],d[1],d[2],0,h[0],h[1],h[2],0);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_plight_x: {
|
|
// The plight matrix contains COLOR, SPECULAR, POINT, ATTENUATION
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::ones_mat());
|
|
PointLight *lt;
|
|
DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
|
|
Colorf const &c = lt->get_color();
|
|
Colorf const &s = lt->get_specular_color();
|
|
t = np.get_net_transform()->get_mat() *
|
|
get_scene()->get_world_transform()->get_mat();
|
|
LVecBase3f p = (t.xform_point(lt->get_point()));
|
|
LVecBase3f a = lt->get_attenuation();
|
|
t = LMatrix4f(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,a[0],a[1],a[2],0);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_slight_x: {
|
|
// The slight matrix contains COLOR, SPECULAR, POINT, DIRECTION
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::zeros_mat());
|
|
Spotlight *lt;
|
|
DCAST_INTO_R(lt, np.node(), &LMatrix4f::zeros_mat());
|
|
Lens *lens = lt->get_lens();
|
|
nassertr(lens != (Lens *)NULL, &LMatrix4f::zeros_mat());
|
|
Colorf const &c = lt->get_color();
|
|
Colorf const &s = lt->get_specular_color();
|
|
float cutoff = cos(deg_2_rad(lens->get_hfov() * 0.5f));
|
|
t = np.get_net_transform()->get_mat() *
|
|
get_scene()->get_world_transform()->get_mat();
|
|
LVecBase3f p = t.xform_point(lens->get_nodal_point());
|
|
LVecBase3f d = -(t.xform_vec(lens->get_view_vector()));
|
|
t = LMatrix4f(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,d[0],d[1],d[2],cutoff);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_mat_constant_x: {
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::ident_mat());
|
|
return &(np.node()->get_transform()->get_mat());
|
|
}
|
|
case Shader::SMO_vec_constant_x: {
|
|
const LVector4f &input = _target._shader->get_shader_input_vector(name);
|
|
const float *data = input.get_data();
|
|
t = LMatrix4f(data[0],data[1],data[2],data[3],
|
|
data[0],data[1],data[2],data[3],
|
|
data[0],data[1],data[2],data[3],
|
|
data[0],data[1],data[2],data[3]);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_world_to_view: {
|
|
return &(get_scene()->get_world_transform()->get_mat());
|
|
break;
|
|
}
|
|
case Shader::SMO_view_to_world: {
|
|
return &(get_scene()->get_camera_transform()->get_mat());
|
|
}
|
|
case Shader::SMO_model_to_view: {
|
|
return &(get_external_transform()->get_mat());
|
|
}
|
|
case Shader::SMO_view_to_model: {
|
|
// DANGER: SLOW AND NOT CACHEABLE!
|
|
t.invert_from(get_external_transform()->get_mat());
|
|
return &t;
|
|
}
|
|
case Shader::SMO_apiview_to_view: {
|
|
return &(_inv_cs_transform->get_mat());
|
|
}
|
|
case Shader::SMO_view_to_apiview: {
|
|
return &(_cs_transform->get_mat());
|
|
}
|
|
case Shader::SMO_clip_to_view: {
|
|
if (_current_lens->get_coordinate_system() == _coordinate_system) {
|
|
return &(_current_lens->get_projection_mat_inv(_current_stereo_channel));
|
|
} else {
|
|
t = _current_lens->get_projection_mat_inv(_current_stereo_channel) *
|
|
LMatrix4f::convert_mat(_current_lens->get_coordinate_system(), _coordinate_system);
|
|
return &t;
|
|
}
|
|
}
|
|
case Shader::SMO_view_to_clip: {
|
|
if (_current_lens->get_coordinate_system() == _coordinate_system) {
|
|
return &(_current_lens->get_projection_mat(_current_stereo_channel));
|
|
} else {
|
|
t = LMatrix4f::convert_mat(_coordinate_system, _current_lens->get_coordinate_system()) *
|
|
_current_lens->get_projection_mat(_current_stereo_channel);
|
|
return &t;
|
|
}
|
|
}
|
|
case Shader::SMO_apiclip_to_view: {
|
|
t = _projection_mat_inv->get_mat() * _inv_cs_transform->get_mat();
|
|
return &t;
|
|
}
|
|
case Shader::SMO_view_to_apiclip: {
|
|
t = _cs_transform->get_mat() * _projection_mat->get_mat();
|
|
return &t;
|
|
}
|
|
case Shader::SMO_view_x_to_view: {
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::ident_mat());
|
|
t = np.get_net_transform()->get_mat() *
|
|
get_scene()->get_world_transform()->get_mat();
|
|
return &t;
|
|
}
|
|
case Shader::SMO_view_to_view_x: {
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::ident_mat());
|
|
t = get_scene()->get_camera_transform()->get_mat() *
|
|
invert(np.get_net_transform()->get_mat());
|
|
return &t;
|
|
}
|
|
case Shader::SMO_apiview_x_to_view: {
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::ident_mat());
|
|
t = LMatrix4f::convert_mat(_internal_coordinate_system, _coordinate_system) *
|
|
np.get_net_transform()->get_mat() *
|
|
get_scene()->get_world_transform()->get_mat();
|
|
return &t;
|
|
}
|
|
case Shader::SMO_view_to_apiview_x: {
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::ident_mat());
|
|
t = (get_scene()->get_camera_transform()->get_mat() *
|
|
invert(np.get_net_transform()->get_mat()) *
|
|
LMatrix4f::convert_mat(_coordinate_system, _internal_coordinate_system));
|
|
return &t;
|
|
}
|
|
case Shader::SMO_clip_x_to_view: {
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::ident_mat());
|
|
Lens *lens = DCAST(LensNode, np.node())->get_lens();
|
|
t = lens->get_projection_mat_inv(_current_stereo_channel) *
|
|
LMatrix4f::convert_mat(lens->get_coordinate_system(), _coordinate_system) *
|
|
np.get_net_transform()->get_mat() *
|
|
get_scene()->get_world_transform()->get_mat();
|
|
return &t;
|
|
}
|
|
case Shader::SMO_view_to_clip_x: {
|
|
const NodePath &np = _target._shader->get_shader_input_nodepath(name);
|
|
nassertr(!np.is_empty(), &LMatrix4f::ident_mat());
|
|
Lens *lens = DCAST(LensNode, np.node())->get_lens();
|
|
t = get_scene()->get_camera_transform()->get_mat() *
|
|
invert(np.get_net_transform()->get_mat()) *
|
|
LMatrix4f::convert_mat(_coordinate_system, lens->get_coordinate_system()) *
|
|
lens->get_projection_mat(_current_stereo_channel);
|
|
return &t;
|
|
}
|
|
case Shader::SMO_apiclip_x_to_view: {
|
|
// NOT IMPLEMENTED
|
|
return &LMatrix4f::ident_mat();
|
|
}
|
|
case Shader::SMO_view_to_apiclip_x: {
|
|
// NOT IMPLEMENTED
|
|
return &LMatrix4f::ident_mat();
|
|
}
|
|
default:
|
|
// should never get here
|
|
return &LMatrix4f::ident_mat();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::prepare_display_region
|
|
// Access: Public, Virtual
|
|
// Description: Makes the specified DisplayRegion current. All
|
|
// future drawing and clear operations will be
|
|
// constrained within the given DisplayRegion.
|
|
//
|
|
// The stereo_channel parameter further qualifies the
|
|
// channel that is to be rendered into, in the case of a
|
|
// stereo display region. Normally, in the monocular
|
|
// case, it is Lens::SC_mono.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
prepare_display_region(DisplayRegionPipelineReader *dr,
|
|
Lens::StereoChannel stereo_channel) {
|
|
_current_display_region = dr->get_object();
|
|
_current_stereo_channel = stereo_channel;
|
|
|
|
_stereo_buffer_mask = ~0;
|
|
|
|
switch (stereo_channel) {
|
|
case Lens::SC_left:
|
|
_color_write_mask = dr->get_window()->get_left_eye_color_mask();
|
|
if (_current_properties->is_stereo()) {
|
|
_stereo_buffer_mask = ~(RenderBuffer::T_front_right | RenderBuffer::T_back_right);
|
|
}
|
|
break;
|
|
|
|
case Lens::SC_right:
|
|
_color_write_mask = dr->get_window()->get_right_eye_color_mask();
|
|
if (_current_properties->is_stereo()) {
|
|
_stereo_buffer_mask = ~(RenderBuffer::T_front_left | RenderBuffer::T_back_left);
|
|
}
|
|
break;
|
|
|
|
case Lens::SC_mono:
|
|
case Lens::SC_stereo:
|
|
_color_write_mask = ColorWriteAttrib::C_all;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::prepare_lens
|
|
// Access: Public, Virtual
|
|
// Description: Makes the current lens (whichever lens was most
|
|
// recently specified with set_scene()) active, so
|
|
// that it will transform future rendered geometry.
|
|
// Normally this is only called from the draw process,
|
|
// and usually it is called by set_scene().
|
|
//
|
|
// The return value is true if the lens is acceptable,
|
|
// false if it is not.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
prepare_lens() {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::calc_projection_mat
|
|
// Access: Public, Virtual
|
|
// Description: Given a lens, this function calculates the appropriate
|
|
// projection matrix for this gsg. The result depends
|
|
// on the peculiarities of the rendering API.
|
|
////////////////////////////////////////////////////////////////////
|
|
CPT(TransformState) GraphicsStateGuardian::
|
|
calc_projection_mat(const Lens *lens) {
|
|
if (lens == (Lens *)NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!lens->is_linear()) {
|
|
return NULL;
|
|
}
|
|
|
|
return TransformState::make_identity();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::begin_frame
|
|
// Access: Public, Virtual
|
|
// Description: Called before each frame is rendered, to allow the
|
|
// GSG a chance to do any internal cleanup before
|
|
// beginning the frame.
|
|
//
|
|
// The return value is true if successful (in which case
|
|
// the frame will be drawn and end_frame() will be
|
|
// called later), or false if unsuccessful (in which
|
|
// case nothing will be drawn and end_frame() will not
|
|
// be called).
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
begin_frame(Thread *current_thread) {
|
|
_prepared_objects->begin_frame(this, current_thread);
|
|
|
|
// We should reset the state to the default at the beginning of
|
|
// every frame. Although this will incur additional overhead,
|
|
// particularly in a simple scene, it helps ensure that states that
|
|
// have changed properties since last time without changing
|
|
// attribute pointers--like textures, lighting, or fog--will still
|
|
// be accurately updated.
|
|
_state_rs = 0;
|
|
_state.clear_to_zero();
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::begin_scene
|
|
// Access: Public, Virtual
|
|
// Description: Called between begin_frame() and end_frame() to mark
|
|
// the beginning of drawing commands for a "scene"
|
|
// (usually a particular DisplayRegion) within a frame.
|
|
// All 3-D drawing commands, except the clear operation,
|
|
// must be enclosed within begin_scene() .. end_scene().
|
|
//
|
|
// The return value is true if successful (in which case
|
|
// the scene will be drawn and end_scene() will be
|
|
// called later), or false if unsuccessful (in which
|
|
// case nothing will be drawn and end_scene() will not
|
|
// be called).
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
begin_scene() {
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::end_scene
|
|
// Access: Public, Virtual
|
|
// Description: Called between begin_frame() and end_frame() to mark
|
|
// the end of drawing commands for a "scene" (usually a
|
|
// particular DisplayRegion) within a frame. All 3-D
|
|
// drawing commands, except the clear operation, must be
|
|
// enclosed within begin_scene() .. end_scene().
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
end_scene() {
|
|
// We should clear this pointer now, so that we don't keep unneeded
|
|
// reference counts dangling. We keep around a "null" scene setup
|
|
// object instead of using a null pointer to avoid special-case code
|
|
// in set_state_and_transform.
|
|
_scene_setup = _scene_null;
|
|
|
|
// Undo any lighting we had enabled last scene, to force the lights
|
|
// to be reissued, in case their parameters or positions have
|
|
// changed between scenes.
|
|
int i;
|
|
for (i = 0; i < _num_lights_enabled; ++i) {
|
|
enable_light(i, false);
|
|
}
|
|
_num_lights_enabled = 0;
|
|
|
|
// Ditto for the clipping planes.
|
|
for (i = 0; i < _num_clip_planes_enabled; ++i) {
|
|
enable_clip_plane(i, false);
|
|
}
|
|
_num_clip_planes_enabled = 0;
|
|
|
|
// Put the state into the 'unknown' state, forcing a reload.
|
|
_state_rs = 0;
|
|
_state.clear_to_zero();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::end_frame
|
|
// Access: Public, Virtual
|
|
// Description: Called after each frame is rendered, to allow the
|
|
// GSG a chance to do any internal cleanup after
|
|
// rendering the frame, and before the window flips.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
end_frame(Thread *current_thread) {
|
|
_prepared_objects->end_frame(current_thread);
|
|
|
|
// Flush any PStatCollectors.
|
|
_data_transferred_pcollector.flush_level();
|
|
|
|
_primitive_batches_pcollector.flush_level();
|
|
_primitive_batches_tristrip_pcollector.flush_level();
|
|
_primitive_batches_trifan_pcollector.flush_level();
|
|
_primitive_batches_tri_pcollector.flush_level();
|
|
_primitive_batches_other_pcollector.flush_level();
|
|
_vertices_tristrip_pcollector.flush_level();
|
|
_vertices_trifan_pcollector.flush_level();
|
|
_vertices_tri_pcollector.flush_level();
|
|
_vertices_other_pcollector.flush_level();
|
|
|
|
_state_pcollector.flush_level();
|
|
_texture_state_pcollector.flush_level();
|
|
_transform_state_pcollector.flush_level();
|
|
_draw_primitive_pcollector.flush_level();
|
|
|
|
// Evict any textures and/or vbuffers that exceed our texture memory.
|
|
_prepared_objects->_graphics_memory_lru.begin_epoch();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::depth_offset_decals
|
|
// Access: Public, Virtual
|
|
// Description: Returns true if this GSG can implement decals using a
|
|
// DepthOffsetAttrib, or false if that is unreliable
|
|
// and the three-step rendering process should be used
|
|
// instead.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
depth_offset_decals() {
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::begin_decal_base_first
|
|
// Access: Public, Virtual
|
|
// Description: Called during draw to begin a three-step rendering
|
|
// phase to draw decals. The first step,
|
|
// begin_decal_base_first(), is called prior to drawing the
|
|
// base geometry. It should set up whatever internal
|
|
// state is appropriate, as well as returning a
|
|
// RenderState object that should be applied to the base
|
|
// geometry for rendering.
|
|
////////////////////////////////////////////////////////////////////
|
|
CPT(RenderState) GraphicsStateGuardian::
|
|
begin_decal_base_first() {
|
|
// Turn off writing the depth buffer to render the base geometry.
|
|
static CPT(RenderState) decal_base_first;
|
|
if (decal_base_first == (const RenderState *)NULL) {
|
|
decal_base_first = RenderState::make
|
|
(DepthWriteAttrib::make(DepthWriteAttrib::M_off),
|
|
RenderState::get_max_priority());
|
|
}
|
|
return decal_base_first;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::begin_decal_nested
|
|
// Access: Public, Virtual
|
|
// Description: Called during draw to begin a three-step rendering
|
|
// phase to draw decals. The second step,
|
|
// begin_decal_nested(), is called after drawing the
|
|
// base geometry and prior to drawing any of the nested
|
|
// decal geometry that is to be applied to the base
|
|
// geometry.
|
|
////////////////////////////////////////////////////////////////////
|
|
CPT(RenderState) GraphicsStateGuardian::
|
|
begin_decal_nested() {
|
|
// We should keep the depth buffer off during this operation, so
|
|
// that decals on decals will render properly.
|
|
static CPT(RenderState) decal_nested;
|
|
if (decal_nested == (const RenderState *)NULL) {
|
|
decal_nested = RenderState::make
|
|
(DepthWriteAttrib::make(DepthWriteAttrib::M_off),
|
|
RenderState::get_max_priority());
|
|
}
|
|
return decal_nested;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::begin_decal_base_second
|
|
// Access: Public, Virtual
|
|
// Description: Called during draw to begin a three-step rendering
|
|
// phase to draw decals. The third step,
|
|
// begin_decal_base_second(), is called after drawing the
|
|
// base geometry and the nested decal geometry, and
|
|
// prior to drawing the base geometry one more time (if
|
|
// needed).
|
|
//
|
|
// It should return a RenderState object appropriate for
|
|
// rendering the base geometry the second time, or NULL
|
|
// if it is not necessary to re-render the base
|
|
// geometry.
|
|
////////////////////////////////////////////////////////////////////
|
|
CPT(RenderState) GraphicsStateGuardian::
|
|
begin_decal_base_second() {
|
|
// Now let the depth buffer go back on, but turn off writing the
|
|
// color buffer to render the base geometry after the second pass.
|
|
// Also, turn off texturing since there's no need for it now.
|
|
static CPT(RenderState) decal_base_second;
|
|
if (decal_base_second == (const RenderState *)NULL) {
|
|
decal_base_second = RenderState::make
|
|
(ColorWriteAttrib::make(ColorWriteAttrib::C_off),
|
|
// On reflection, we need to leave texturing on so the alpha
|
|
// test mechanism can work (if it is enabled, e.g. we are
|
|
// rendering an object with M_dual transparency).
|
|
// TextureAttrib::make_off(),
|
|
RenderState::get_max_priority());
|
|
}
|
|
return decal_base_second;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::finish_decal
|
|
// Access: Public, Virtual
|
|
// Description: Called during draw to clean up after decals are
|
|
// finished.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
finish_decal() {
|
|
// No need to do anything special here.
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::begin_draw_primitives()
|
|
// Access: Public, Virtual
|
|
// Description: Called before a sequence of draw_primitive()
|
|
// functions are called, this should prepare the vertex
|
|
// data for rendering. It returns true if the vertices
|
|
// are ok, false to abort this group of primitives.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
begin_draw_primitives(const GeomPipelineReader *geom_reader,
|
|
const GeomMunger *munger,
|
|
const GeomVertexDataPipelineReader *data_reader,
|
|
bool force) {
|
|
_munger = munger;
|
|
_data_reader = data_reader;
|
|
return _data_reader->has_vertex();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::draw_triangles
|
|
// Access: Public, Virtual
|
|
// Description: Draws a series of disconnected triangles.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
draw_triangles(const GeomPrimitivePipelineReader *, bool) {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::draw_tristrips
|
|
// Access: Public, Virtual
|
|
// Description: Draws a series of triangle strips.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
draw_tristrips(const GeomPrimitivePipelineReader *, bool) {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::draw_trifans
|
|
// Access: Public, Virtual
|
|
// Description: Draws a series of triangle fans.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
draw_trifans(const GeomPrimitivePipelineReader *, bool) {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::draw_lines
|
|
// Access: Public, Virtual
|
|
// Description: Draws a series of disconnected line segments.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
draw_lines(const GeomPrimitivePipelineReader *, bool) {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::draw_linestrips
|
|
// Access: Public, Virtual
|
|
// Description: Draws a series of line strips.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
draw_linestrips(const GeomPrimitivePipelineReader *, bool) {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::draw_points
|
|
// Access: Public, Virtual
|
|
// Description: Draws a series of disconnected points.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool GraphicsStateGuardian::
|
|
draw_points(const GeomPrimitivePipelineReader *, bool) {
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::end_draw_primitives()
|
|
// Access: Public, Virtual
|
|
// Description: Called after a sequence of draw_primitive()
|
|
// functions are called, this should do whatever cleanup
|
|
// is appropriate.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
end_draw_primitives() {
|
|
_munger = NULL;
|
|
_data_reader = NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::reset
|
|
// Access: Public, Virtual
|
|
// Description: Resets all internal state as if the gsg were newly
|
|
// created.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
reset() {
|
|
_needs_reset = false;
|
|
_is_valid = false;
|
|
|
|
_state_rs = NULL;
|
|
_target_rs = NULL;
|
|
_state.clear_to_zero();
|
|
_target.clear_to_defaults();
|
|
_internal_transform = _cs_transform;
|
|
_scene_null = new SceneSetup;
|
|
_scene_setup = _scene_null;
|
|
|
|
_color_write_mask = ColorWriteAttrib::C_all;
|
|
|
|
_has_scene_graph_color = false;
|
|
_scene_graph_color.set(1.0f, 1.0f, 1.0f, 1.0f);
|
|
_transform_stale = true;
|
|
_color_blend_involves_color_scale = false;
|
|
_texture_involves_color_scale = false;
|
|
_vertex_colors_enabled = true;
|
|
_lighting_enabled = false;
|
|
_num_lights_enabled = 0;
|
|
_num_clip_planes_enabled = 0;
|
|
|
|
_color_scale_enabled = false;
|
|
_current_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
|
|
_has_texture_alpha_scale = false;
|
|
|
|
_has_material_force_color = false;
|
|
_material_force_color.set(1.0f, 1.0f, 1.0f, 1.0f);
|
|
_light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
_tex_gen_modifies_mat = false;
|
|
_last_max_stage_index = 0;
|
|
|
|
_is_valid = true;
|
|
|
|
if (_stencil_render_states) {
|
|
delete _stencil_render_states;
|
|
_stencil_render_states = 0;
|
|
}
|
|
_stencil_render_states = new StencilRenderStates (this);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::set_state_and_transform
|
|
// Access: Public
|
|
// Description: Simultaneously resets the render state and the
|
|
// transform state.
|
|
//
|
|
// This transform specified is the "internal" net
|
|
// transform, already converted into the GSG's internal
|
|
// coordinate space by composing it to
|
|
// get_cs_transform(). (Previously, this used to be the
|
|
// "external" net transform, with the assumption that
|
|
// that GSG would convert it internally, but that is no
|
|
// longer the case.)
|
|
//
|
|
// Special case: if (state==NULL), then the target
|
|
// state is already stored in _target.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
set_state_and_transform(const RenderState *state,
|
|
const TransformState *trans) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::clear
|
|
// Access: Public
|
|
// Description: Clears the framebuffer within the current
|
|
// DisplayRegion, according to the flags indicated by
|
|
// the given DrawableRegion object.
|
|
//
|
|
// This does not set the DisplayRegion first. You
|
|
// should call prepare_display_region() to specify the
|
|
// region you wish the clear operation to apply to.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
clear(DrawableRegion *clearable) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_render_buffer
|
|
// Access: Public
|
|
// Description: Returns a RenderBuffer object suitable for operating
|
|
// on the requested set of buffers. buffer_type is the
|
|
// union of all the desired RenderBuffer::Type values.
|
|
////////////////////////////////////////////////////////////////////
|
|
RenderBuffer GraphicsStateGuardian::
|
|
get_render_buffer(int buffer_type, const FrameBufferProperties &prop) {
|
|
return RenderBuffer(this, buffer_type & prop.get_buffer_mask() & _stereo_buffer_mask);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_cs_transform
|
|
// Access: Public, Virtual
|
|
// Description: Returns a transform that converts from the GSG's
|
|
// external coordinate system (as returned by
|
|
// get_coordinate_system()) to its internal coordinate
|
|
// system (as returned by
|
|
// get_internal_coordinate_system()). This is used for
|
|
// rendering.
|
|
////////////////////////////////////////////////////////////////////
|
|
const TransformState *GraphicsStateGuardian::
|
|
get_cs_transform() const {
|
|
return _cs_transform;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::do_issue_clip_plane
|
|
// Access: Public
|
|
// Description: This is fundametically similar to do_issue_light(), with
|
|
// calls to apply_clip_plane() and enable_clip_planes(),
|
|
// as appropriate.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
do_issue_clip_plane() {
|
|
int num_enabled = 0;
|
|
int num_on_planes = 0;
|
|
|
|
if (_target._clip_plane != (ClipPlaneAttrib *)NULL) {
|
|
CPT(ClipPlaneAttrib) new_plane = _target._clip_plane->filter_to_max(_max_clip_planes);
|
|
|
|
num_on_planes = new_plane->get_num_on_planes();
|
|
for (int li = 0; li < num_on_planes; li++) {
|
|
NodePath plane = new_plane->get_on_plane(li);
|
|
nassertv(!plane.is_empty());
|
|
PlaneNode *plane_node;
|
|
DCAST_INTO_V(plane_node, plane.node());
|
|
if ((plane_node->get_clip_effect() & PlaneNode::CE_visible) != 0) {
|
|
// Clipping should be enabled before we apply any planes.
|
|
if (!_clip_planes_enabled) {
|
|
enable_clip_planes(true);
|
|
_clip_planes_enabled = true;
|
|
}
|
|
|
|
enable_clip_plane(num_enabled, true);
|
|
if (num_enabled == 0) {
|
|
begin_bind_clip_planes();
|
|
}
|
|
|
|
bind_clip_plane(plane, num_enabled);
|
|
num_enabled++;
|
|
}
|
|
}
|
|
}
|
|
|
|
int i;
|
|
for (i = num_enabled; i < _num_clip_planes_enabled; ++i) {
|
|
enable_clip_plane(i, false);
|
|
}
|
|
_num_clip_planes_enabled = num_enabled;
|
|
|
|
// If no planes were set, disable clipping
|
|
if (num_enabled == 0) {
|
|
if (_clip_planes_enabled) {
|
|
enable_clip_planes(false);
|
|
_clip_planes_enabled = false;
|
|
}
|
|
} else {
|
|
end_bind_clip_planes();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::do_issue_color
|
|
// Access: Public
|
|
// Description: This method is defined in the base class because it
|
|
// is likely that this functionality will be used for
|
|
// all (or at least most) kinds of
|
|
// GraphicsStateGuardians--it's not specific to any one
|
|
// rendering backend.
|
|
//
|
|
// The ColorAttribute just changes the interpretation of
|
|
// the color on the vertices, and fiddles with
|
|
// _vertex_colors_enabled, etc.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
do_issue_color() {
|
|
const ColorAttrib *attrib = _target._color;
|
|
switch (attrib->get_color_type()) {
|
|
case ColorAttrib::T_flat:
|
|
// Color attribute flat: it specifies a scene graph color that
|
|
// overrides the vertex color.
|
|
_scene_graph_color = attrib->get_color();
|
|
_has_scene_graph_color = true;
|
|
_vertex_colors_enabled = false;
|
|
break;
|
|
|
|
case ColorAttrib::T_off:
|
|
// Color attribute off: it specifies that no scene graph color is
|
|
// in effect, and vertex color is not important either.
|
|
_scene_graph_color.set(1.0f, 1.0f, 1.0f, 1.0f);
|
|
_has_scene_graph_color = false;
|
|
_vertex_colors_enabled = false;
|
|
break;
|
|
|
|
case ColorAttrib::T_vertex:
|
|
// Color attribute vertex: it specifies that vertex color should
|
|
// be revealed.
|
|
_scene_graph_color.set(1.0f, 1.0f, 1.0f, 1.0f);
|
|
_has_scene_graph_color = false;
|
|
_vertex_colors_enabled = true;
|
|
break;
|
|
}
|
|
|
|
if (_color_scale_via_lighting) {
|
|
_state_rs = 0;
|
|
_state._light = 0;
|
|
_state._material = 0;
|
|
|
|
determine_light_color_scale();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::do_issue_color_scale
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
do_issue_color_scale() {
|
|
// If the previous color scale had set a special texture, clear the
|
|
// texture now.
|
|
if (_has_texture_alpha_scale) {
|
|
_state._texture = 0;
|
|
}
|
|
|
|
const ColorScaleAttrib *attrib = _target._color_scale;
|
|
_color_scale_enabled = attrib->has_scale();
|
|
_current_color_scale = attrib->get_scale();
|
|
_has_texture_alpha_scale = false;
|
|
|
|
if (_color_blend_involves_color_scale) {
|
|
_state_rs = 0;
|
|
_state._transparency = 0;
|
|
}
|
|
if (_texture_involves_color_scale) {
|
|
_state_rs = 0;
|
|
_state._texture = 0;
|
|
}
|
|
if (_color_scale_via_lighting) {
|
|
_state_rs = 0;
|
|
_state._light = 0;
|
|
_state._material = 0;
|
|
|
|
determine_light_color_scale();
|
|
}
|
|
|
|
if (_alpha_scale_via_texture && !_has_scene_graph_color &&
|
|
attrib->has_alpha_scale()) {
|
|
// This color scale will set a special texture--so again, clear
|
|
// the texture.
|
|
_state._texture = 0;
|
|
_state._tex_matrix = 0;
|
|
|
|
_has_texture_alpha_scale = true;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::do_issue_light
|
|
// Access: Protected, Virtual
|
|
// Description: This implementation of do_issue_light() assumes
|
|
// we have a limited number of hardware lights
|
|
// available. This function assigns each light to a
|
|
// different hardware light id, trying to keep each
|
|
// light associated with the same id where possible, but
|
|
// reusing id's when necessary. When it is no longer
|
|
// possible to reuse existing id's (e.g. all id's are in
|
|
// use), the next sequential id is assigned (if
|
|
// available).
|
|
//
|
|
// It will call apply_light() each time a light is
|
|
// assigned to a particular id for the first time in a
|
|
// given frame, and it will subsequently call
|
|
// enable_light() to enable or disable each light as the
|
|
// frame is rendered, as well as enable_lighting() to
|
|
// enable or disable overall lighting.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
do_issue_light() {
|
|
// Initialize the current ambient light total and newly enabled
|
|
// light list
|
|
Colorf cur_ambient_light(0.0f, 0.0f, 0.0f, 0.0f);
|
|
int i;
|
|
|
|
int num_enabled = 0;
|
|
int num_on_lights = 0;
|
|
|
|
if (display_cat.is_spam()) {
|
|
display_cat.spam()
|
|
<< "do_issue_light: " << _target._light << "\n";
|
|
}
|
|
if (_target._light != (LightAttrib *)NULL) {
|
|
CPT(LightAttrib) new_light = _target._light->filter_to_max(_max_lights);
|
|
if (display_cat.is_spam()) {
|
|
new_light->write(display_cat.spam(false), 2);
|
|
}
|
|
|
|
num_on_lights = new_light->get_num_on_lights();
|
|
for (int li = 0; li < num_on_lights; li++) {
|
|
NodePath light = new_light->get_on_light(li);
|
|
nassertv(!light.is_empty());
|
|
Light *light_obj = light.node()->as_light();
|
|
nassertv(light_obj != (Light *)NULL);
|
|
|
|
// Lighting should be enabled before we apply any lights.
|
|
if (!_lighting_enabled) {
|
|
enable_lighting(true);
|
|
_lighting_enabled = true;
|
|
}
|
|
|
|
if (light_obj->get_type() == AmbientLight::get_class_type()) {
|
|
// Ambient lights don't require specific light ids; simply add
|
|
// in the ambient contribution to the current total
|
|
cur_ambient_light += light_obj->get_color();
|
|
|
|
} else {
|
|
enable_light(num_enabled, true);
|
|
if (num_enabled == 0) {
|
|
begin_bind_lights();
|
|
}
|
|
|
|
light_obj->bind(this, light, num_enabled);
|
|
num_enabled++;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = num_enabled; i < _num_lights_enabled; ++i) {
|
|
enable_light(i, false);
|
|
}
|
|
_num_lights_enabled = num_enabled;
|
|
|
|
// If no lights were set, disable lighting
|
|
if (num_on_lights == 0) {
|
|
if (_color_scale_via_lighting && (_has_material_force_color || _light_color_scale != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f))) {
|
|
// Unless we need lighting anyway to apply a color or color
|
|
// scale.
|
|
if (!_lighting_enabled) {
|
|
enable_lighting(true);
|
|
_lighting_enabled = true;
|
|
}
|
|
set_ambient_light(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
|
|
|
|
} else {
|
|
if (_lighting_enabled) {
|
|
enable_lighting(false);
|
|
_lighting_enabled = false;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
set_ambient_light(cur_ambient_light);
|
|
}
|
|
|
|
if (num_enabled != 0) {
|
|
end_bind_lights();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::bind_light
|
|
// Access: Public, Virtual
|
|
// Description: Called the first time a particular light has been
|
|
// bound to a given id within a frame, this should set
|
|
// up the associated hardware light with the light's
|
|
// properties.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::bind_light
|
|
// Access: Public, Virtual
|
|
// Description: Called the first time a particular light has been
|
|
// bound to a given id within a frame, this should set
|
|
// up the associated hardware light with the light's
|
|
// properties.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::bind_light
|
|
// Access: Public, Virtual
|
|
// Description: Called the first time a particular light has been
|
|
// bound to a given id within a frame, this should set
|
|
// up the associated hardware light with the light's
|
|
// properties.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
|
|
}
|
|
|
|
#ifdef DO_PSTATS
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::init_frame_pstats
|
|
// Access: Pubilc, Static
|
|
// Description: Initializes the relevant PStats data at the beginning
|
|
// of the frame.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
init_frame_pstats() {
|
|
if (PStatClient::is_connected()) {
|
|
_data_transferred_pcollector.clear_level();
|
|
_vertex_buffer_switch_pcollector.clear_level();
|
|
_index_buffer_switch_pcollector.clear_level();
|
|
|
|
_primitive_batches_pcollector.clear_level();
|
|
_primitive_batches_tristrip_pcollector.clear_level();
|
|
_primitive_batches_trifan_pcollector.clear_level();
|
|
_primitive_batches_tri_pcollector.clear_level();
|
|
_primitive_batches_other_pcollector.clear_level();
|
|
_vertices_tristrip_pcollector.clear_level();
|
|
_vertices_trifan_pcollector.clear_level();
|
|
_vertices_tri_pcollector.clear_level();
|
|
_vertices_other_pcollector.clear_level();
|
|
|
|
_state_pcollector.clear_level();
|
|
_transform_state_pcollector.clear_level();
|
|
_texture_state_pcollector.clear_level();
|
|
}
|
|
}
|
|
#endif // DO_PSTATS
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::create_gamma_table
|
|
// Access: Public, Static
|
|
// Description: Create a gamma table.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
create_gamma_table (float gamma, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) {
|
|
int i;
|
|
|
|
if (gamma <= 0.0) {
|
|
// avoid divide by zero and negative exponents
|
|
gamma = 1.0;
|
|
}
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
double g;
|
|
double x;
|
|
float gamma_correction;
|
|
|
|
x = ((double) i / 255.0);
|
|
gamma_correction = 1.0 / gamma;
|
|
x = pow (x, (double) gamma_correction);
|
|
if (x > 1.00) {
|
|
x = 1.0;
|
|
}
|
|
|
|
g = x * 65535.0;
|
|
red_table [i] = (int)g;
|
|
green_table [i] = (int)g;
|
|
blue_table [i] = (int)g;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::traverse_prepared_textures
|
|
// Access: Public
|
|
// Description: Calls the indicated function on all
|
|
// currently-prepared textures, or until the callback
|
|
// function returns false.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
traverse_prepared_textures(bool (*pertex_callbackfn)(TextureContext *,void *),void *callback_arg) {
|
|
PreparedGraphicsObjects::Textures::const_iterator ti;
|
|
for (ti = _prepared_objects->_prepared_textures.begin();
|
|
ti != _prepared_objects->_prepared_textures.end();
|
|
++ti) {
|
|
bool bResult=(*pertex_callbackfn)(*ti,callback_arg);
|
|
if(!bResult)
|
|
return;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::enable_lighting
|
|
// Access: Protected, Virtual
|
|
// Description: Intended to be overridden by a derived class to
|
|
// enable or disable the use of lighting overall. This
|
|
// is called by do_issue_light() according to whether any
|
|
// lights are in use or not.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
enable_lighting(bool enable) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::set_ambient_light
|
|
// Access: Protected, Virtual
|
|
// Description: Intended to be overridden by a derived class to
|
|
// indicate the color of the ambient light that should
|
|
// be in effect. This is called by do_issue_light() after
|
|
// all other lights have been enabled or disabled.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
set_ambient_light(const Colorf &color) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::enable_light
|
|
// Access: Protected, Virtual
|
|
// Description: Intended to be overridden by a derived class to
|
|
// enable the indicated light id. A specific Light will
|
|
// already have been bound to this id via bind_light().
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
enable_light(int light_id, bool enable) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::begin_bind_lights
|
|
// Access: Protected, Virtual
|
|
// Description: Called immediately before bind_light() is called,
|
|
// this is intended to provide the derived class a hook
|
|
// in which to set up some state (like transform) that
|
|
// might apply to several lights.
|
|
//
|
|
// The sequence is: begin_bind_lights() will be called,
|
|
// then one or more bind_light() calls, then
|
|
// end_bind_lights().
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
begin_bind_lights() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::end_bind_lights
|
|
// Access: Protected, Virtual
|
|
// Description: Called after before bind_light() has been called one
|
|
// or more times (but before any geometry is issued or
|
|
// additional state is changed), this is intended to
|
|
// clean up any temporary changes to the state that may
|
|
// have been made by begin_bind_lights().
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
end_bind_lights() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::enable_clip_planes
|
|
// Access: Protected, Virtual
|
|
// Description: Intended to be overridden by a derived class to
|
|
// enable or disable the use of clipping planes overall.
|
|
// This is called by do_issue_clip_plane() according to
|
|
// whether any planes are in use or not.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
enable_clip_planes(bool enable) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::enable_clip_plane
|
|
// Access: Protected, Virtual
|
|
// Description: Intended to be overridden by a derived class to
|
|
// enable the indicated plane id. A specific PlaneNode
|
|
// will already have been bound to this id via
|
|
// bind_clip_plane().
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
enable_clip_plane(int plane_id, bool enable) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::begin_bind_clip_planes
|
|
// Access: Protected, Virtual
|
|
// Description: Called immediately before bind_clip_plane() is called,
|
|
// this is intended to provide the derived class a hook
|
|
// in which to set up some state (like transform) that
|
|
// might apply to several planes.
|
|
//
|
|
// The sequence is: begin_bind_clip_planes() will be
|
|
// called, then one or more bind_clip_plane() calls,
|
|
// then end_bind_clip_planes().
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
begin_bind_clip_planes() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::bind_clip_plane
|
|
// Access: Public, Virtual
|
|
// Description: Called the first time a particular clipping plane has been
|
|
// bound to a given id within a frame, this should set
|
|
// up the associated hardware (or API) clipping plane
|
|
// with the plane's properties.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
bind_clip_plane(const NodePath &plane, int plane_id) {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::end_bind_clip_planes
|
|
// Access: Protected, Virtual
|
|
// Description: Called after before bind_clip_plane() has been called one
|
|
// or more times (but before any geometry is issued or
|
|
// additional state is changed), this is intended to
|
|
// clean up any temporary changes to the state that may
|
|
// have been made by begin_bind_clip_planes().
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
end_bind_clip_planes() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::determine_effective_texture
|
|
// Access: Protected
|
|
// Description: Assigns _effective_texture and _effective_tex_gen
|
|
// based on the current settings of _target._texture and
|
|
// _target._color_scale.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
determine_effective_texture() {
|
|
nassertv(_target._texture != (TextureAttrib *)NULL &&
|
|
_target._tex_gen != (TexGenAttrib *)NULL);
|
|
int max_texture_stages = get_max_texture_stages();
|
|
_effective_texture = _target._texture->filter_to_max(max_texture_stages);
|
|
_effective_tex_gen = _target._tex_gen;
|
|
|
|
if (_has_texture_alpha_scale) {
|
|
PT(TextureStage) stage = get_alpha_scale_texture_stage();
|
|
PT(Texture) texture = TexturePool::get_alpha_scale_map();
|
|
|
|
_effective_texture = DCAST(TextureAttrib, _effective_texture->add_on_stage(stage, texture));
|
|
_effective_tex_gen = DCAST(TexGenAttrib, _effective_tex_gen->add_stage
|
|
(stage, TexGenAttrib::M_constant, TexCoord3f(_current_color_scale[3], 0.0f, 0.0f)));
|
|
}
|
|
|
|
nassertv(_effective_texture->get_num_on_stages() <= max_texture_stages);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::free_pointers
|
|
// Access: Protected, Virtual
|
|
// Description: Frees some memory that was explicitly allocated
|
|
// within the glgsg.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
free_pointers() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::close_gsg
|
|
// Access: Protected, Virtual
|
|
// Description: This is called by the associated GraphicsWindow when
|
|
// close_window() is called. It should null out the
|
|
// _win pointer and possibly free any open resources
|
|
// associated with the GSG.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
close_gsg() {
|
|
if (display_cat.is_debug()) {
|
|
display_cat.debug()
|
|
<< this << " close_gsg " << get_type() << "\n";
|
|
}
|
|
_closing_gsg = true;
|
|
free_pointers();
|
|
|
|
// As tempting as it may be to try to release all the textures and
|
|
// geoms now, we can't, because we might not be the currently-active
|
|
// GSG (this is particularly important in OpenGL, which maintains
|
|
// one currently-active GL state in each thread). If we start
|
|
// deleting textures, we'll be inadvertently deleting textures from
|
|
// some other OpenGL state.
|
|
|
|
// Fortunately, it doesn't really matter, since the graphics API
|
|
// will be responsible for cleaning up anything we don't clean up
|
|
// explicitly. We'll just let them drop.
|
|
|
|
// However, if any objects have recently been released, we have to
|
|
// ensure they are actually deleted properly.
|
|
Thread *current_thread = Thread::get_current_thread();
|
|
_prepared_objects->begin_frame(this, current_thread);
|
|
_prepared_objects->end_frame(current_thread);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::panic_deactivate
|
|
// Access: Protected
|
|
// Description: This is called internally when it is determined that
|
|
// things are just fubar. It temporarily deactivates
|
|
// the GSG just so things don't get out of hand, and
|
|
// throws an event so the application can deal with this
|
|
// if it needs to.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
panic_deactivate() {
|
|
if (_active) {
|
|
display_cat.error()
|
|
<< "Deactivating " << get_type() << ".\n";
|
|
set_active(false);
|
|
throw_event("panic-deactivate-gsg", this);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::determine_light_color_scale
|
|
// Access: Protected
|
|
// Description: Called whenever the color or color scale is changed,
|
|
// if _color_scale_via_lighting is true. This will
|
|
// rederive _material_force_color and _light_color_scale
|
|
// appropriately.
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
determine_light_color_scale() {
|
|
if (_has_scene_graph_color) {
|
|
// If we have a scene graph color, it, plus the color scale, goes
|
|
// directly into the material; we don't color scale the
|
|
// lights--this allows an alpha color scale to work properly.
|
|
_has_material_force_color = true;
|
|
_material_force_color = _scene_graph_color;
|
|
_light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
|
|
if (!_color_blend_involves_color_scale && _color_scale_enabled) {
|
|
_material_force_color.set(_scene_graph_color[0] * _current_color_scale[0],
|
|
_scene_graph_color[1] * _current_color_scale[1],
|
|
_scene_graph_color[2] * _current_color_scale[2],
|
|
_scene_graph_color[3] * _current_color_scale[3]);
|
|
}
|
|
|
|
} else {
|
|
// Otherise, leave the materials alone, but we might still scale
|
|
// the lights.
|
|
_has_material_force_color = false;
|
|
_light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f);
|
|
if (!_color_blend_involves_color_scale && _color_scale_enabled) {
|
|
_light_color_scale = _current_color_scale;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_unlit_state
|
|
// Access: Protected, Static
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CPT(RenderState) GraphicsStateGuardian::
|
|
get_unlit_state() {
|
|
static CPT(RenderState) state = NULL;
|
|
if (state == (const RenderState *)NULL) {
|
|
state = RenderState::make(LightAttrib::make_all_off());
|
|
}
|
|
return state;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_unclipped_state
|
|
// Access: Protected, Static
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CPT(RenderState) GraphicsStateGuardian::
|
|
get_unclipped_state() {
|
|
static CPT(RenderState) state = NULL;
|
|
if (state == (const RenderState *)NULL) {
|
|
state = RenderState::make(ClipPlaneAttrib::make_all_off());
|
|
}
|
|
return state;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::get_untextured_state
|
|
// Access: Protected, Static
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CPT(RenderState) GraphicsStateGuardian::
|
|
get_untextured_state() {
|
|
static CPT(RenderState) state = NULL;
|
|
if (state == (const RenderState *)NULL) {
|
|
state = RenderState::make(TextureAttrib::make_off());
|
|
}
|
|
return state;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: GraphicsStateGuardian::async_reload_texture
|
|
// Access: Protected
|
|
// Description: Should be called when a texture is encountered that
|
|
// needs to have its RAM image reloaded, and
|
|
// get_incomplete_render() is true. This will fire off
|
|
// a thread on the current Loader object that will
|
|
// request the texture to load its image. The image
|
|
// will be available at some point in the future (no
|
|
// event will be generated).
|
|
////////////////////////////////////////////////////////////////////
|
|
void GraphicsStateGuardian::
|
|
async_reload_texture(TextureContext *tc) {
|
|
nassertv(_loader != (Loader *)NULL);
|
|
|
|
PT(AsyncTask) request =
|
|
new TextureReloadRequest(string("reload:") + tc->get_texture()->get_name(),
|
|
_prepared_objects, tc->get_texture(),
|
|
_supports_compressed_texture);
|
|
_loader->load_async(request);
|
|
}
|