first pass at primitive bumpmapping support

This commit is contained in:
David Rose 2005-07-02 00:56:30 +00:00
parent 9b228c1321
commit 166e7414a6
27 changed files with 762 additions and 131 deletions

View File

@ -27,6 +27,7 @@
#include "colorScaleAttrib.h"
#include "lightAttrib.h"
#include "textureAttrib.h"
#include "texGenAttrib.h"
#include "renderState.h"
#include "depthWriteAttrib.h"
#include "colorWriteAttrib.h"

View File

@ -848,10 +848,10 @@ set_lighting(bool enable) {
if (!_got_lights) {
setup_lights();
}
render.node()->set_attrib(LightAttrib::make(LightAttrib::O_add,
_alight, _dlight));
render.set_light(_alight);
render.set_light(_dlight);
} else {
render.node()->clear_attrib(LightAttrib::get_class_type());
render.clear_light();
}
_lighting_enabled = enable;
@ -963,11 +963,12 @@ setup_lights() {
NodePath camera_group = get_camera_group();
NodePath light_group = camera_group.attach_new_node("lights");
_alight = new AmbientLight("ambient");
_alight->set_color(Colorf(0.2f, 0.2f, 0.2f, 1.0f));
_dlight = new DirectionalLight("directional");
light_group.attach_new_node(_alight);
light_group.attach_new_node(_dlight);
AmbientLight *alight = new AmbientLight("ambient");
alight->set_color(Colorf(0.2f, 0.2f, 0.2f, 1.0f));
DirectionalLight *dlight = new DirectionalLight("directional");
_alight = light_group.attach_new_node(alight);
_dlight = light_group.attach_new_node(dlight);
_got_lights = true;
}

View File

@ -144,8 +144,8 @@ private:
NodePath _mouse;
PT(Trackball) _trackball;
AmbientLight *_alight;
DirectionalLight *_dlight;
NodePath _alight;
NodePath _dlight;
bool _got_keyboard;
bool _got_trackball;

View File

@ -132,6 +132,11 @@ PUBLISHED:
// The union of the above shade model types.
GR_shade_model_bits = 0x6000,
// If there is a TexGenAttrib in effect with M_light_vector
// enabled, meaning we need to generate the tangent space light
// vector as the texture coordinates.
GR_texcoord_light_vector = 0x8000,
};
// The shade model specifies whether the per-vertex colors and

View File

@ -92,12 +92,17 @@ void Texture::
setup_texture(Texture::TextureType texture_type, int x_size, int y_size,
int z_size, Texture::ComponentType component_type,
Texture::Format format) {
#ifndef NDEBUG
if (texture_type == TT_cube_map) {
// Cube maps must always consist of six square images.
nassertv(x_size == y_size && z_size == 6);
// In principle the wrap mode shouldn't mean anything to a cube
// map, but some drivers seem to misbehave if it's other than
// WM_clamp.
_wrap_u = WM_clamp;
_wrap_v = WM_clamp;
_wrap_w = WM_clamp;
}
#endif
_texture_type = texture_type;
_x_size = x_size;
@ -110,6 +115,109 @@ setup_texture(Texture::TextureType texture_type, int x_size, int y_size,
_loaded_from_disk = false;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::generate_normalization_cube_map
// Access: Published
// Description: Generates a special cube map image in the texture
// that can be used to apply bump mapping effects: for
// each texel in the cube map that is indexed by the 3-d
// texture coordinates (x, y, z), the resulting value is
// the normalized vector (x, y, z) (compressed from
// -1..1 into 0..1).
//
// This also implicitly sets keep_ram_image to true.
////////////////////////////////////////////////////////////////////
void Texture::
generate_normalization_cube_map(int size) {
setup_cube_map(size, T_unsigned_byte, F_rgb);
PTA_uchar image = modify_ram_image();
float half_size = (float)size * 0.5f;
float center = half_size - 0.5f;
LMatrix4f scale
(127.5f, 0.0f, 0.0f, 0.0f,
0.0f, 127.5f, 0.0f, 0.0f,
0.0f, 0.0f, 127.5f, 0.0f,
127.5f, 127.5f, 127.5f, 1.0f);
unsigned char *p = image;
int xi, yi;
// Page 0: positive X.
for (yi = 0; yi < size; ++yi) {
for (xi = 0; xi < size; ++xi) {
LVector3f vec(half_size, center - yi, center - xi);
vec.normalize();
vec = scale.xform_point(vec);
*p++ = (unsigned char)vec[0];
*p++ = (unsigned char)vec[1];
*p++ = (unsigned char)vec[2];
}
}
// Page 1: negative X.
for (yi = 0; yi < size; ++yi) {
for (xi = 0; xi < size; ++xi) {
LVector3f vec(-half_size, center - yi, xi - center);
vec.normalize();
vec = scale.xform_point(vec);
*p++ = (unsigned char)vec[0];
*p++ = (unsigned char)vec[1];
*p++ = (unsigned char)vec[2];
}
}
// Page 2: positive Y.
for (yi = 0; yi < size; ++yi) {
for (xi = 0; xi < size; ++xi) {
LVector3f vec(xi - center, half_size, yi - center);
vec.normalize();
vec = scale.xform_point(vec);
*p++ = (unsigned char)vec[0];
*p++ = (unsigned char)vec[1];
*p++ = (unsigned char)vec[2];
}
}
// Page 3: negative Y.
for (yi = 0; yi < size; ++yi) {
for (xi = 0; xi < size; ++xi) {
LVector3f vec(xi - center, -half_size, center - yi);
vec.normalize();
vec = scale.xform_point(vec);
*p++ = (unsigned char)vec[0];
*p++ = (unsigned char)vec[1];
*p++ = (unsigned char)vec[2];
}
}
// Page 4: positive Z.
for (yi = 0; yi < size; ++yi) {
for (xi = 0; xi < size; ++xi) {
LVector3f vec(xi - center, center - yi, half_size);
vec.normalize();
vec = scale.xform_point(vec);
*p++ = (unsigned char)vec[0];
*p++ = (unsigned char)vec[1];
*p++ = (unsigned char)vec[2];
}
}
// Page 5: negative Z.
for (yi = 0; yi < size; ++yi) {
for (xi = 0; xi < size; ++xi) {
LVector3f vec(center - xi, center - yi, -half_size);
vec.normalize();
vec = scale.xform_point(vec);
*p++ = (unsigned char)vec[0];
*p++ = (unsigned char)vec[1];
*p++ = (unsigned char)vec[2];
}
}
}
////////////////////////////////////////////////////////////////////
// Function: Texture::read
// Access: Published

View File

@ -150,6 +150,8 @@ PUBLISHED:
INLINE void setup_cube_map(int size,
ComponentType component_type, Format format);
void generate_normalization_cube_map(int size);
bool read(const Filename &fullpath, int z = 0,
int primary_file_num_channels = 0);
bool read(const Filename &fullpath, const Filename &alpha_fullpath,

View File

@ -23,6 +23,7 @@
#include "bamWriter.h"
#include "datagram.h"
#include "datagramIterator.h"
#include "config_pgraph.h"
CPT(RenderAttrib) ClipPlaneAttrib::_empty_attrib;
CPT(RenderAttrib) ClipPlaneAttrib::_all_off_attrib;
@ -39,6 +40,9 @@ TypeHandle ClipPlaneAttrib::_type_handle;
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ClipPlaneAttrib::
make(ClipPlaneAttrib::Operation op, PlaneNode *plane) {
pgraph_cat.warning()
<< "Using deprecated ClipPlaneAttrib interface.\n";
CPT(RenderAttrib) attrib;
switch (op) {
@ -73,6 +77,9 @@ make(ClipPlaneAttrib::Operation op, PlaneNode *plane) {
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ClipPlaneAttrib::
make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2) {
pgraph_cat.warning()
<< "Using deprecated ClipPlaneAttrib interface.\n";
CPT(RenderAttrib) attrib;
switch (op) {
@ -111,6 +118,9 @@ make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2) {
CPT(RenderAttrib) ClipPlaneAttrib::
make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2,
PlaneNode *plane3) {
pgraph_cat.warning()
<< "Using deprecated ClipPlaneAttrib interface.\n";
CPT(RenderAttrib) attrib;
switch (op) {
@ -152,6 +162,9 @@ make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2,
CPT(RenderAttrib) ClipPlaneAttrib::
make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2,
PlaneNode *plane3, PlaneNode *plane4) {
pgraph_cat.warning()
<< "Using deprecated ClipPlaneAttrib interface.\n";
CPT(RenderAttrib) attrib;
switch (op) {
@ -202,6 +215,9 @@ make(ClipPlaneAttrib::Operation op, PlaneNode *plane1, PlaneNode *plane2,
////////////////////////////////////////////////////////////////////
ClipPlaneAttrib::Operation ClipPlaneAttrib::
get_operation() const {
pgraph_cat.warning()
<< "Using deprecated ClipPlaneAttrib interface.\n";
if (has_all_off()) {
return O_set;
@ -225,6 +241,9 @@ get_operation() const {
////////////////////////////////////////////////////////////////////
int ClipPlaneAttrib::
get_num_planes() const {
pgraph_cat.warning()
<< "Using deprecated ClipPlaneAttrib interface.\n";
if (get_num_off_planes() == 0) {
return get_num_on_planes();
} else {
@ -244,6 +263,9 @@ get_num_planes() const {
////////////////////////////////////////////////////////////////////
PlaneNode *ClipPlaneAttrib::
get_plane(int n) const {
pgraph_cat.warning()
<< "Using deprecated ClipPlaneAttrib interface.\n";
if (get_num_off_planes() == 0) {
return DCAST(PlaneNode, get_on_plane(n).node());
} else {
@ -264,6 +286,9 @@ get_plane(int n) const {
////////////////////////////////////////////////////////////////////
bool ClipPlaneAttrib::
has_plane(PlaneNode *plane) const {
pgraph_cat.warning()
<< "Using deprecated ClipPlaneAttrib interface.\n";
if (get_num_off_planes() == 0) {
return has_on_plane(NodePath(plane));
} else {
@ -282,6 +307,9 @@ has_plane(PlaneNode *plane) const {
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ClipPlaneAttrib::
add_plane(PlaneNode *plane) const {
pgraph_cat.warning()
<< "Using deprecated ClipPlaneAttrib interface.\n";
if (get_num_off_planes() == 0) {
return add_on_plane(NodePath(plane));
} else {
@ -301,6 +329,9 @@ add_plane(PlaneNode *plane) const {
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) ClipPlaneAttrib::
remove_plane(PlaneNode *plane) const {
pgraph_cat.warning()
<< "Using deprecated ClipPlaneAttrib interface.\n";
if (get_num_off_planes() == 0) {
return remove_on_plane(NodePath(plane));
} else {

View File

@ -18,6 +18,7 @@
#include "cullableObject.h"
#include "textureAttrib.h"
#include "texGenAttrib.h"
#include "renderState.h"
#include "clockObject.h"
#include "cullTraverser.h"
@ -28,8 +29,10 @@
#include "geomVertexWriter.h"
#include "geomVertexReader.h"
#include "geomTriangles.h"
#include "light.h"
PStatCollector CullableObject::_munge_points_pcollector("*:Munge:Points");
PStatCollector CullableObject::_munge_light_vector_pcollector("*:Munge:Light Vector");
CullableObject *CullableObject::_deleted_chain = (CullableObject *)NULL;
int CullableObject::_num_ever_allocated = 0;
@ -75,6 +78,9 @@ munge_geom(GraphicsStateGuardianBase *gsg,
}
munge_points_to_quads(traverser);
}
if (unsupported_bits & Geom::GR_texcoord_light_vector) {
munge_texcoord_light_vector(traverser);
}
// Now invoke the munger to ensure the resulting geometry is in
// a GSG-friendly form.
@ -370,7 +376,7 @@ munge_points_to_quads(const CullTraverser *traverser) {
LPoint2f c1(-scale_x, scale_y);
if (has_rotate) {
// If we have a rotate factor, apply it to those two corners.
// If we have a rotate factor, apply it to those two corners.
rotate.set_row(*vi);
float r = rotate.get_data1f();
LMatrix3f mat = LMatrix3f::rotate_mat(r);
@ -439,3 +445,91 @@ munge_points_to_quads(const CullTraverser *traverser) {
_geom = new_geom.p();
_munged_data = new_data;
}
////////////////////////////////////////////////////////////////////
// Function: CullableObject::munge_texcoord_light_vector
// Access: Private
// Description: Generates the vector from each vertex to the
// indicated light as a 3-d texture coordinate.
//
// This may replace _geom, _munged_data, and _state.
////////////////////////////////////////////////////////////////////
void CullableObject::
munge_texcoord_light_vector(const CullTraverser *traverser) {
PStatTimer timer(_munge_light_vector_pcollector);
if (_modelview_transform->is_singular()) {
// If we're under a singular transform, never mind.
return;
}
CPT(TransformState) net_transform =
traverser->get_camera_transform()->compose(_modelview_transform);
if (!_munged_data->has_column(InternalName::get_vertex()) ||
!_munged_data->has_column(InternalName::get_normal())) {
// No vertex or normal; can't compute light vector.
return;
}
CPT(TexGenAttrib) tex_gen = _state->get_tex_gen();
nassertv(tex_gen != (TexGenAttrib *)NULL);
const TexGenAttrib::LightVectors &light_vectors = tex_gen->get_light_vectors();
TexGenAttrib::LightVectors::const_iterator lvi;
for (lvi = light_vectors.begin();
lvi != light_vectors.end();
++lvi) {
TextureStage *stage = (*lvi).first;
const NodePath &light = (*lvi).second;
nassertv(!light.is_empty());
Light *light_obj = light.node()->as_light();
nassertv(light_obj != (Light *)NULL);
// Determine the names of the tangent and binormal columns
// associated with the stage's texcoord name.
CPT(InternalName) texcoord_name = stage->get_texcoord_name();
string basename;
if (texcoord_name != InternalName::get_texcoord()) {
basename = texcoord_name->get_basename();
}
CPT(InternalName) tangent_name = InternalName::get_tangent_name(basename);
CPT(InternalName) binormal_name = InternalName::get_binormal_name(basename);
if (_munged_data->has_column(tangent_name) &&
_munged_data->has_column(binormal_name)) {
// Create a new column for the new texcoords.
PT(GeomVertexData) new_data = _munged_data->replace_column
(texcoord_name, 3, Geom::NT_float32, Geom::C_texcoord);
_munged_data = new_data;
// Remove this TexGen stage from the state, since we're handling
// it now.
_state = _state->add_attrib(tex_gen->remove_stage(stage));
// Get the transform from the light to the object.
CPT(TransformState) light_transform =
net_transform->invert_compose(light.get_net_transform());
const LMatrix4f &light_mat = light_transform->get_mat();
GeomVertexWriter texcoord(new_data, texcoord_name);
GeomVertexReader vertex(new_data, InternalName::get_vertex());
GeomVertexReader tangent(new_data, tangent_name);
GeomVertexReader binormal(new_data, binormal_name);
GeomVertexReader normal(new_data, InternalName::get_normal());
while (!vertex.is_at_end()) {
LPoint3f p = vertex.get_data3f();
LVector3f t = tangent.get_data3f();
LVector3f b = binormal.get_data3f();
LVector3f n = normal.get_data3f();
LVector3f lv;
if (light_obj->get_vector_to_light(lv, p, light_mat)) {
texcoord.add_data3f(lv.dot(t), lv.dot(b), lv.dot(n));
}
}
}
}
}

View File

@ -85,6 +85,7 @@ public:
private:
void munge_points_to_quads(const CullTraverser *traverser);
void munge_texcoord_light_vector(const CullTraverser *traverser);
private:
// This class is used internally by munge_points_to_quads().
@ -105,6 +106,7 @@ private:
static int _num_ever_allocated;
static PStatCollector _munge_points_pcollector;
static PStatCollector _munge_light_vector_pcollector;
public:
static TypeHandle get_class_type() {

View File

@ -133,6 +133,32 @@ write(ostream &out, int indent_level) const {
<< "direction " << get_direction() << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: DirectionalLight::get_vector_to_light
// Access: Public, Virtual
// Description: Computes the vector from a particular vertex to this
// light. The exact vector depends on the type of light
// (e.g. point lights return a different result than
// directional lights).
//
// The input parameters are the vertex position in
// question, expressed in object space, and the matrix
// which converts from light space to object space. The
// result is expressed in object space.
//
// The return value is true if the result is successful,
// or false if it cannot be computed (e.g. for an
// ambient light).
////////////////////////////////////////////////////////////////////
bool DirectionalLight::
get_vector_to_light(LVector3f &result, const LPoint3f &,
const LMatrix4f &to_object_space) {
CDReader cdata(_cycler);
result = cdata->_direction * to_object_space;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: DirectionalLight::bind
// Access: Public, Virtual

View File

@ -40,6 +40,10 @@ public:
virtual void xform(const LMatrix4f &mat);
virtual void write(ostream &out, int indent_level) const;
virtual bool get_vector_to_light(LVector3f &result,
const LPoint3f &from_object_point,
const LMatrix4f &to_object_space);
PUBLISHED:
INLINE const Colorf &get_specular_color() const;
INLINE void set_specular_color(const Colorf &color);

View File

@ -67,6 +67,28 @@ Light::
~Light() {
}
////////////////////////////////////////////////////////////////////
// Function: Light::get_vector_to_light
// Access: Public, Virtual
// Description: Computes the vector from a particular vertex to this
// light. The exact vector depends on the type of light
// (e.g. point lights return a different result than
// directional lights).
//
// The input parameters are the vertex position in
// question, expressed in object space, and the matrix
// which converts from light space to object space. The
// result is expressed in object space.
//
// The return value is true if the result is successful,
// or false if it cannot be computed (e.g. for an
// ambient light).
////////////////////////////////////////////////////////////////////
bool Light::
get_vector_to_light(LVector3f &, const LPoint3f &, const LMatrix4f &) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: Light::get_viz
// Access: Public

View File

@ -62,6 +62,10 @@ public:
virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,
int light_id)=0;
virtual bool get_vector_to_light(LVector3f &result,
const LPoint3f &from_object_point,
const LMatrix4f &to_object_space);
GeomNode *get_viz();
protected:

View File

@ -24,6 +24,7 @@
#include "bamWriter.h"
#include "datagram.h"
#include "datagramIterator.h"
#include "config_pgraph.h"
CPT(RenderAttrib) LightAttrib::_empty_attrib;
CPT(RenderAttrib) LightAttrib::_all_off_attrib;
@ -40,6 +41,9 @@ TypeHandle LightAttrib::_type_handle;
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) LightAttrib::
make(LightAttrib::Operation op, Light *light) {
pgraph_cat.warning()
<< "Using deprecated LightAttrib interface.\n";
CPT(RenderAttrib) attrib;
switch (op) {
@ -74,6 +78,9 @@ make(LightAttrib::Operation op, Light *light) {
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) LightAttrib::
make(LightAttrib::Operation op, Light *light1, Light *light2) {
pgraph_cat.warning()
<< "Using deprecated LightAttrib interface.\n";
CPT(RenderAttrib) attrib;
switch (op) {
@ -112,6 +119,9 @@ make(LightAttrib::Operation op, Light *light1, Light *light2) {
CPT(RenderAttrib) LightAttrib::
make(LightAttrib::Operation op, Light *light1, Light *light2,
Light *light3) {
pgraph_cat.warning()
<< "Using deprecated LightAttrib interface.\n";
CPT(RenderAttrib) attrib;
switch (op) {
@ -153,6 +163,9 @@ make(LightAttrib::Operation op, Light *light1, Light *light2,
CPT(RenderAttrib) LightAttrib::
make(LightAttrib::Operation op, Light *light1, Light *light2,
Light *light3, Light *light4) {
pgraph_cat.warning()
<< "Using deprecated LightAttrib interface.\n";
CPT(RenderAttrib) attrib;
switch (op) {
@ -203,6 +216,9 @@ make(LightAttrib::Operation op, Light *light1, Light *light2,
////////////////////////////////////////////////////////////////////
LightAttrib::Operation LightAttrib::
get_operation() const {
pgraph_cat.warning()
<< "Using deprecated LightAttrib interface.\n";
if (has_all_off()) {
return O_set;
@ -226,6 +242,9 @@ get_operation() const {
////////////////////////////////////////////////////////////////////
int LightAttrib::
get_num_lights() const {
pgraph_cat.warning()
<< "Using deprecated LightAttrib interface.\n";
if (get_num_off_lights() == 0) {
return get_num_on_lights();
} else {
@ -245,6 +264,9 @@ get_num_lights() const {
////////////////////////////////////////////////////////////////////
Light *LightAttrib::
get_light(int n) const {
pgraph_cat.warning()
<< "Using deprecated LightAttrib interface.\n";
if (get_num_off_lights() == 0) {
return get_on_light(n).node()->as_light();
} else {
@ -265,6 +287,9 @@ get_light(int n) const {
////////////////////////////////////////////////////////////////////
bool LightAttrib::
has_light(Light *light) const {
pgraph_cat.warning()
<< "Using deprecated LightAttrib interface.\n";
if (get_num_off_lights() == 0) {
return has_on_light(NodePath(light->as_node()));
} else {
@ -283,6 +308,9 @@ has_light(Light *light) const {
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) LightAttrib::
add_light(Light *light) const {
pgraph_cat.warning()
<< "Using deprecated LightAttrib interface.\n";
if (get_num_off_lights() == 0) {
return add_on_light(NodePath(light->as_node()));
} else {
@ -302,6 +330,9 @@ add_light(Light *light) const {
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) LightAttrib::
remove_light(Light *light) const {
pgraph_cat.warning()
<< "Using deprecated LightAttrib interface.\n";
if (get_num_off_lights() == 0) {
return remove_on_light(NodePath(light->as_node()));
} else {

View File

@ -26,6 +26,7 @@
#include "cullBinAttrib.h"
#include "textureAttrib.h"
#include "texMatrixAttrib.h"
#include "texGenAttrib.h"
#include "materialAttrib.h"
#include "lightAttrib.h"
#include "clipPlaneAttrib.h"
@ -3226,7 +3227,7 @@ get_tex_transform(const NodePath &other, TextureStage *stage) const {
// the indicated texture stage.
////////////////////////////////////////////////////////////////////
void NodePath::
set_tex_gen(TextureStage *stage, TexGenAttrib::Mode mode, int priority) {
set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, int priority) {
nassertv_always(!is_empty());
const RenderAttrib *attrib =
@ -3246,6 +3247,36 @@ set_tex_gen(TextureStage *stage, TexGenAttrib::Mode mode, int priority) {
node()->set_attrib(tga->add_stage(stage, mode), priority);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_tex_gen
// Access: Published
// Description: Enables automatic texture coordinate generation for
// the indicated texture stage. This version of this
// method is useful when setting M_light_vector, which
// requires a specific light.
////////////////////////////////////////////////////////////////////
void NodePath::
set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode,
const NodePath &light, int priority) {
nassertv_always(!is_empty());
const RenderAttrib *attrib =
node()->get_attrib(TexGenAttrib::get_class_type());
CPT(TexGenAttrib) tga;
if (attrib != (const RenderAttrib *)NULL) {
priority = max(priority,
node()->get_state()->get_override(TextureAttrib::get_class_type()));
tga = DCAST(TexGenAttrib, attrib);
} else {
tga = DCAST(TexGenAttrib, TexGenAttrib::make());
}
node()->set_attrib(tga->add_stage(stage, mode, light), priority);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::clear_tex_gen
// Access: Published
@ -3311,7 +3342,7 @@ has_tex_gen(TextureStage *stage) const {
// the given stage, or M_off if there is no explicit
// mode set for the given stage.
////////////////////////////////////////////////////////////////////
TexGenAttrib::Mode NodePath::
RenderAttrib::TexGenMode NodePath::
get_tex_gen(TextureStage *stage) const {
nassertr_always(!is_empty(), TexGenAttrib::M_off);
@ -3325,6 +3356,28 @@ get_tex_gen(TextureStage *stage) const {
return TexGenAttrib::M_off;
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_tex_gen_light
// Access: Published
// Description: Returns the particular Light set for the indicated
// texgen mode's texture stage, or empty NodePath if no
// light is set. This is only meaningful if the texgen
// mode (returned by get_tex_gen()) is M_light_vector.
////////////////////////////////////////////////////////////////////
NodePath NodePath::
get_tex_gen_light(TextureStage *stage) const {
nassertr_always(!is_empty(), NodePath::fail());
const RenderAttrib *attrib =
node()->get_attrib(TexGenAttrib::get_class_type());
if (attrib != (const RenderAttrib *)NULL) {
const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib);
return tga->get_light(stage);
}
return NodePath();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_tex_projector
// Access: Published

View File

@ -24,7 +24,6 @@
#include "pandaNode.h"
#include "renderState.h"
#include "transformState.h"
#include "texGenAttrib.h"
#include "renderModeAttrib.h"
#include "transparencyAttrib.h"
#include "nodePathComponent.h"
@ -581,11 +580,13 @@ PUBLISHED:
INLINE float get_tex_rotate(const NodePath &other, TextureStage *stage) const;
INLINE LVecBase2f get_tex_scale(const NodePath &other, TextureStage *stage) const;
void set_tex_gen(TextureStage *stage, TexGenAttrib::Mode mode, int priority = 0);
void set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, int priority = 0);
void set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, const NodePath &light, int priority = 0);
void clear_tex_gen();
void clear_tex_gen(TextureStage *stage);
bool has_tex_gen(TextureStage *stage) const;
TexGenAttrib::Mode get_tex_gen(TextureStage *stage) const;
RenderAttrib::TexGenMode get_tex_gen(TextureStage *stage) const;
NodePath get_tex_gen_light(TextureStage *stage) const;
void set_tex_projector(TextureStage *stage, const NodePath &from, const NodePath &to);
void clear_tex_projector(TextureStage *stage);

View File

@ -132,6 +132,33 @@ write(ostream &out, int indent_level) const {
<< "attenuation " << get_attenuation() << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: PointLight::get_vector_to_light
// Access: Public, Virtual
// Description: Computes the vector from a particular vertex to this
// light. The exact vector depends on the type of light
// (e.g. point lights return a different result than
// directional lights).
//
// The input parameters are the vertex position in
// question, expressed in object space, and the matrix
// which converts from light space to object space. The
// result is expressed in object space.
//
// The return value is true if the result is successful,
// or false if it cannot be computed (e.g. for an
// ambient light).
////////////////////////////////////////////////////////////////////
bool PointLight::
get_vector_to_light(LVector3f &result, const LPoint3f &from_object_point,
const LMatrix4f &to_object_space) {
CDReader cdata(_cycler);
LPoint3f point = cdata->_point * to_object_space;
result = point - from_object_point;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PointLight::bind
// Access: Public, Virtual

View File

@ -40,6 +40,10 @@ public:
virtual void xform(const LMatrix4f &mat);
virtual void write(ostream &out, int indent_level) const;
virtual bool get_vector_to_light(LVector3f &result,
const LPoint3f &from_object_point,
const LMatrix4f &to_object_space);
PUBLISHED:
INLINE const Colorf &get_specular_color() const;
INLINE void set_specular_color(const Colorf &color);

View File

@ -92,6 +92,74 @@ PUBLISHED:
M_always // Always draw.
};
// This is the enumerated type for TexGenAttrib. It is inherited
// into TexGenAttrib. It is defined up at this level only to avoid
// circular dependencies in the header files.
enum TexGenMode {
M_off,
// In the types below, "eye" means the coordinate space of the
// observing camera, "object" means the local coordinate space of
// the object, and "world" means world coordinates, e.g. the
// coordinate space of the root of the graph.
// Sphere maps are classic static reflection maps. They are
// supported on just about any hardware, and require a precomputed
// 180-degree fisheye image. Sphere maps only make sense in eye
// coordinate space.
M_eye_sphere_map,
// Cube maps are a modern improvement on the sphere map; they
// don't suffer from any polar singularities, but they require six
// texture images. They can also be generated dynamically for
// real-time reflections (see GraphicsOutput::make_cube_map()).
// Typically, a statically-generated cube map will be in eye
// space, while a dynamically-generated map will be in world space
// or object space (depending on where the camera rig that
// generates the map is parented).
// Cube mapping is not supported on all hardware.
M_world_cube_map,
M_eye_cube_map,
// Normal maps are most useful for applying diffuse lighting
// effects via a pregenerated cube map.
M_world_normal,
M_eye_normal,
// Position maps convert XYZ coordinates directly to texture
// coordinates. This is particularly useful for implementing
// projective texturing (see NodePath::project_texture()).
M_world_position,
M_object_position,
M_eye_position,
// With M_point_sprite, texture coordinates will be generated for
// large points in the range (0,0) - (1,1) from upper-left to
// lower-right across the point's face. Without this, each point
// will have just a single uniform texture coordinate value across
// its face.
// Unfortunately, the generated texture coordinates are inverted
// (upside-down) from Panda's usual convention, but this is what
// the graphics card manufacturers decided to use. You could use
// a texture matrix to re-invert the texture, but that will
// probably force software rendering. You'll have to paint your
// textures upside-down if you want true hardware sprites.
M_point_sprite,
// M_light_vector generates special 3-d texture coordinates that
// represent the vector to a particular Light in the scene graph,
// expressed in each vertex's tangent space. This is used to
// implement bumpmapping.
// This requires a Light to be specified to the TexGenAttrib. It
// also requires each vertex to define a normal, as well as a
// tangent and binormal for the particular named texture
// coordinate set.
M_light_vector,
};
protected:
static CPT(RenderAttrib) return_new(RenderAttrib *attrib);
virtual int compare_to_impl(const RenderAttrib *other) const;

View File

@ -336,29 +336,6 @@ get_render_mode() const {
return _render_mode;
}
////////////////////////////////////////////////////////////////////
// Function: RenderState::get_geom_rendering
// Access: Published
// Description: Returns the union of the Geom::GeomRendering bits
// that will be required once this RenderState is
// applied to a geom which includes the indicated
// geom_rendering bits.
////////////////////////////////////////////////////////////////////
INLINE int RenderState::
get_geom_rendering(int geom_rendering) const {
if (get_render_mode() != (const RenderModeAttrib *)NULL) {
geom_rendering = _render_mode->get_geom_rendering(geom_rendering);
}
if (get_tex_gen() != (const TexGenAttrib *)NULL) {
geom_rendering = _tex_gen->get_geom_rendering(geom_rendering);
}
if (get_tex_matrix() != (const TexMatrixAttrib *)NULL) {
geom_rendering = _tex_matrix->get_geom_rendering(geom_rendering);
}
return geom_rendering;
}
////////////////////////////////////////////////////////////////////
// Function: RenderState::set_destructing
// Access: Private

View File

@ -930,6 +930,29 @@ validate_states() {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: RenderState::get_geom_rendering
// Access: Published
// Description: Returns the union of the Geom::GeomRendering bits
// that will be required once this RenderState is
// applied to a geom which includes the indicated
// geom_rendering bits.
////////////////////////////////////////////////////////////////////
int RenderState::
get_geom_rendering(int geom_rendering) const {
if (get_render_mode() != (const RenderModeAttrib *)NULL) {
geom_rendering = _render_mode->get_geom_rendering(geom_rendering);
}
if (get_tex_gen() != (const TexGenAttrib *)NULL) {
geom_rendering = _tex_gen->get_geom_rendering(geom_rendering);
}
if (get_tex_matrix() != (const TexMatrixAttrib *)NULL) {
geom_rendering = _tex_matrix->get_geom_rendering(geom_rendering);
}
return geom_rendering;
}
////////////////////////////////////////////////////////////////////
// Function: RenderState::issue_delta_modify
// Access: Public

View File

@ -28,7 +28,6 @@
#include "updateSeq.h"
#include "pStatCollector.h"
#include "renderModeAttrib.h"
#include "texGenAttrib.h"
#include "texMatrixAttrib.h"
#include "geomMunger.h"
#include "weakPointerTo.h"
@ -40,6 +39,7 @@ class TransparencyAttrib;
class ColorAttrib;
class ColorScaleAttrib;
class TextureAttrib;
class TexGenAttrib;
class FactoryParams;
////////////////////////////////////////////////////////////////////
@ -134,7 +134,7 @@ PUBLISHED:
INLINE const TexMatrixAttrib *get_tex_matrix() const;
INLINE const RenderModeAttrib *get_render_mode() const;
INLINE int get_geom_rendering(int geom_rendering) const;
int get_geom_rendering(int geom_rendering) const;
public:
CPT(RenderState) issue_delta_modify(const RenderState *other,

View File

@ -141,6 +141,29 @@ write(ostream &out, int indent_level) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: Spotlight::get_vector_to_light
// Access: Public, Virtual
// Description: Computes the vector from a particular vertex to this
// light. The exact vector depends on the type of light
// (e.g. point lights return a different result than
// directional lights).
//
// The input parameters are the vertex position in
// question, expressed in object space, and the matrix
// which converts from light space to object space. The
// result is expressed in object space.
//
// The return value is true if the result is successful,
// or false if it cannot be computed (e.g. for an
// ambient light).
////////////////////////////////////////////////////////////////////
bool Spotlight::
get_vector_to_light(LVector3f &result, const LPoint3f &from_object_point,
const LMatrix4f &to_object_space) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: Spotlight::make_spot
// Access: Published, Static

View File

@ -51,6 +51,10 @@ public:
virtual void xform(const LMatrix4f &mat);
virtual void write(ostream &out, int indent_level) const;
virtual bool get_vector_to_light(LVector3f &result,
const LPoint3f &from_object_point,
const LMatrix4f &to_object_space);
PUBLISHED:
INLINE float get_exponent() const;
INLINE void set_exponent(float exponent);

View File

@ -25,7 +25,10 @@
////////////////////////////////////////////////////////////////////
INLINE TexGenAttrib::
TexGenAttrib() :
_num_point_sprites(0)
_num_point_sprites(0),
_num_light_vectors(0),
_point_geom_rendering(0),
_geom_rendering(0)
{
}
@ -39,7 +42,10 @@ INLINE TexGenAttrib::
TexGenAttrib(const TexGenAttrib &copy) :
_stages(copy._stages),
_no_texcoords(copy._no_texcoords),
_num_point_sprites(copy._num_point_sprites)
_num_point_sprites(copy._num_point_sprites),
_num_light_vectors(copy._num_light_vectors),
_point_geom_rendering(copy._point_geom_rendering),
_geom_rendering(copy._geom_rendering)
{
}
@ -54,12 +60,10 @@ TexGenAttrib(const TexGenAttrib &copy) :
INLINE int TexGenAttrib::
get_geom_rendering(int geom_rendering) const {
if ((geom_rendering & Geom::GR_point) != 0) {
if (_num_point_sprites > 0) {
geom_rendering |= Geom::GR_point_sprite;
}
geom_rendering |= _point_geom_rendering;
}
return geom_rendering;
return geom_rendering | _geom_rendering;
}
////////////////////////////////////////////////////////////////////
@ -75,3 +79,40 @@ INLINE const Geom::NoTexCoordStages &TexGenAttrib::
get_no_texcoords() const {
return _no_texcoords;
}
////////////////////////////////////////////////////////////////////
// Function: TexGenAttrib::get_light_vectors
// Access: Public
// Description: Returns the set of TextureStages that have
// M_light_vector in effect, as well as the associated
// Lights.
////////////////////////////////////////////////////////////////////
INLINE const TexGenAttrib::LightVectors &TexGenAttrib::
get_light_vectors() const {
return _light_vectors;
}
////////////////////////////////////////////////////////////////////
// Function: TexGenAttrib::ModeDef::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE TexGenAttrib::ModeDef::
ModeDef() :
_mode(M_off)
{
}
////////////////////////////////////////////////////////////////////
// Function: TexGenAttrib::ModeDef::compare_to
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE int TexGenAttrib::ModeDef::
compare_to(const TexGenAttrib::ModeDef &other) const {
if (_mode != other._mode) {
return (int)_mode < (int)other._mode ? -1 : 1;
}
return _light.compare_to(other._light);
}

View File

@ -61,8 +61,8 @@ make() {
// indicated stage.
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) TexGenAttrib::
make(TextureStage *stage, TexGenAttrib::Mode mode) {
return DCAST(TexGenAttrib, make())->add_stage(stage, mode);
make(TextureStage *stage, TexGenAttrib::Mode mode, const NodePath &light) {
return DCAST(TexGenAttrib, make())->add_stage(stage, mode, light);
}
////////////////////////////////////////////////////////////////////
@ -74,14 +74,44 @@ make(TextureStage *stage, TexGenAttrib::Mode mode) {
// replaced.
////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) TexGenAttrib::
add_stage(TextureStage *stage, TexGenAttrib::Mode mode) const {
TexGenAttrib *attrib = new TexGenAttrib(*this);
attrib->_stages[stage] = mode;
if (mode != M_off) {
add_stage(TextureStage *stage, TexGenAttrib::Mode mode, const NodePath &light) const {
CPT(RenderAttrib) removed = remove_stage(stage);
TexGenAttrib *attrib = new TexGenAttrib(*DCAST(TexGenAttrib, removed));
ModeDef &mode_def = attrib->_stages[stage];
mode_def._mode = mode;
mode_def._light = light;
switch (mode) {
case M_point_sprite:
attrib->_no_texcoords.insert(stage);
if (mode == M_point_sprite) {
attrib->_num_point_sprites++;
attrib->_point_geom_rendering |= Geom::GR_point_sprite;
attrib->_num_point_sprites++;
break;
case M_light_vector:
{
Light *light_obj = NULL;
if (!light.is_empty()) {
light_obj = light.node()->as_light();
}
if (light_obj == (Light *)NULL) {
ostringstream strm;
strm << "Not a light: " << light;
nassert_raise(strm.str());
} else {
attrib->_light_vectors[stage] = light;
attrib->_geom_rendering |= Geom::GR_texcoord_light_vector;
attrib->_num_light_vectors++;
}
}
break;
case M_off:
break;
default:
attrib->_no_texcoords.insert(stage);
}
return return_new(attrib);
}
@ -100,12 +130,21 @@ remove_stage(TextureStage *stage) const {
return this;
}
Mode mode = (*si).second;
Mode mode = (*si).second._mode;
TexGenAttrib *attrib = new TexGenAttrib(*this);
attrib->_stages.erase(stage);
attrib->_no_texcoords.erase(stage);
if (mode == M_point_sprite) {
attrib->_num_point_sprites--;
if (attrib->_num_point_sprites == 0) {
attrib->_point_geom_rendering &= ~Geom::GR_point_sprite;
}
} else if (mode == M_light_vector) {
attrib->_light_vectors.erase(stage);
attrib->_num_light_vectors--;
if (attrib->_num_light_vectors == 0) {
attrib->_geom_rendering &= ~Geom::GR_texcoord_light_vector;
}
}
return return_new(attrib);
}
@ -145,11 +184,28 @@ TexGenAttrib::Mode TexGenAttrib::
get_mode(TextureStage *stage) const {
Stages::const_iterator mi = _stages.find(stage);
if (mi != _stages.end()) {
return (*mi).second;
return (*mi).second._mode;
}
return M_off;
}
////////////////////////////////////////////////////////////////////
// Function: TexGenAttrib::get_light
// Access: Published
// Description: Returns the Light associated with the named texture
// stage, or the empty NodePath if no light is
// associated with the indicated stage. This is only
// meaningful if the mode is M_light_vector.
////////////////////////////////////////////////////////////////////
NodePath TexGenAttrib::
get_light(TextureStage *stage) const {
Stages::const_iterator mi = _stages.find(stage);
if (mi != _stages.end()) {
return (*mi).second._light;
}
return NodePath();
}
////////////////////////////////////////////////////////////////////
// Function: TexGenAttrib::issue
// Access: Public, Virtual
@ -176,9 +232,9 @@ output(ostream &out) const {
Stages::const_iterator mi;
for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
TextureStage *stage = (*mi).first;
Mode mode = (*mi).second;
const ModeDef &mode_def = (*mi).second;
out << " " << stage->get_name() << "(";
switch (mode) {
switch (mode_def._mode) {
case M_off:
out << "off";
break;
@ -214,6 +270,10 @@ output(ostream &out) const {
case M_point_sprite:
out << "point_sprite";
break;
case M_light_vector:
out << "light_vector: " << mode_def._light;
break;
}
out << ")";
}
@ -253,8 +313,9 @@ compare_to_impl(const RenderAttrib *other) const {
} else {
// This stage is in both; compare the stages.
if ((*ai).second != (*bi).second) {
return (int)(*ai).second < (int)(*bi).second ? -1 : 1;
int compare = (*ai).second.compare_to((*bi).second);
if (compare != 0) {
return compare;
}
++ai;
++bi;
@ -338,8 +399,29 @@ compose_impl(const RenderAttrib *other) const {
// Now copy from _stages to _no_texcoords.
Stages::const_iterator ri;
for (ri = attrib->_stages.begin(); ri != attrib->_stages.end(); ++ri) {
if ((*ri).second != M_off) {
attrib->_no_texcoords.insert((*ri).first);
TextureStage *stage = (*ri).first;
const ModeDef &mode_def = (*ri).second;
Mode mode = mode_def._mode;
const NodePath &light = mode_def._light;
switch (mode) {
case M_point_sprite:
attrib->_no_texcoords.insert(stage);
attrib->_point_geom_rendering |= Geom::GR_point_sprite;
attrib->_num_point_sprites++;
break;
case M_light_vector:
attrib->_light_vectors[stage] = light;
attrib->_geom_rendering |= Geom::GR_texcoord_light_vector;
attrib->_num_light_vectors++;
break;
case M_off:
break;
default:
attrib->_no_texcoords.insert(stage);
}
}
@ -371,7 +453,7 @@ invert_compose_impl(const RenderAttrib *other) const {
while (ai != _stages.end() && bi != ta->_stages.end()) {
if ((*ai).first < (*bi).first) {
// This stage is in a but not in b. Turn a off.
attrib->_stages.insert(attrib->_stages.end(), Stages::value_type((*ai).first, M_off));
attrib->_stages.insert(attrib->_stages.end(), Stages::value_type((*ai).first, ModeDef()));
++ai;
} else if ((*bi).first < (*ai).first) {
@ -389,7 +471,7 @@ invert_compose_impl(const RenderAttrib *other) const {
while (ai != _stages.end()) {
// This stage is in a but not in b.
attrib->_stages.insert(attrib->_stages.end(), Stages::value_type((*ai).first, M_off));
attrib->_stages.insert(attrib->_stages.end(), Stages::value_type((*ai).first, ModeDef()));
++ai;
}
@ -402,8 +484,29 @@ invert_compose_impl(const RenderAttrib *other) const {
// Now copy from _stages to _no_texcoords.
Stages::const_iterator ri;
for (ri = attrib->_stages.begin(); ri != attrib->_stages.end(); ++ri) {
if ((*ri).second != M_off) {
attrib->_no_texcoords.insert((*ri).first);
TextureStage *stage = (*ri).first;
const ModeDef &mode_def = (*ri).second;
Mode mode = mode_def._mode;
const NodePath &light = mode_def._light;
switch (mode) {
case M_point_sprite:
attrib->_no_texcoords.insert(stage);
attrib->_point_geom_rendering |= Geom::GR_point_sprite;
attrib->_num_point_sprites++;
break;
case M_light_vector:
attrib->_light_vectors[stage] = light;
attrib->_geom_rendering |= Geom::GR_texcoord_light_vector;
attrib->_num_light_vectors++;
break;
case M_off:
break;
default:
attrib->_no_texcoords.insert(stage);
}
}
@ -452,7 +555,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
Stages::const_iterator si;
for (si = _stages.begin(); si != _stages.end(); ++si) {
TextureStage *stage = (*si).first;
Mode mode = (*si).second;
Mode mode = (*si).second._mode;
manager->write_pointer(dg, stage);
dg.add_uint8((unsigned int)mode);
@ -475,7 +578,7 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
Mode mode = (*mi);
TextureStage *stage = DCAST(TextureStage, p_list[pi++]);
_stages[stage] = mode;
_stages[stage]._mode = mode;
if (mode != M_off) {
_no_texcoords.insert(stage);

View File

@ -26,6 +26,7 @@
#include "textureStage.h"
#include "texture.h"
#include "pointerTo.h"
#include "nodePath.h"
////////////////////////////////////////////////////////////////////
// Class : TexGenAttrib
@ -38,59 +39,11 @@
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TexGenAttrib : public RenderAttrib {
PUBLISHED:
enum Mode {
M_off,
// In the types below, "eye" means the coordinate space of the
// observing camera, "object" means the local coordinate space of
// the object, and "world" means world coordinates, e.g. the
// coordinate space of the root of the graph.
// Sphere maps are classic static reflection maps. They are
// supported on just about any hardware, and require a precomputed
// 180-degree fisheye image. Sphere maps only make sense in eye
// coordinate space.
M_eye_sphere_map,
// Cube maps are a modern improvement on the sphere map; they
// don't suffer from any polar singularities, but they require six
// texture images. They can also be generated dynamically for
// real-time reflections (see GraphicsOutput::make_cube_map()).
// Typically, a statically-generated cube map will be in eye
// space, while a dynamically-generated map will be in world space
// or object space (depending on where the camera rig that
// generates the map is parented).
// Cube mapping is not supported on all hardware.
M_world_cube_map,
M_eye_cube_map,
// Normal maps are most useful for applying diffuse lighting
// effects via a pregenerated cube map.
M_world_normal,
M_eye_normal,
// Position maps convert XYZ coordinates directly to texture
// coordinates. This is particularly useful for implementing
// projective texturing (see NodePath::project_texture()).
M_world_position,
M_object_position,
M_eye_position,
// With M_point_sprite, texture coordinates will be generated for
// large points in the range (0,0) - (1,1) from upper-left to
// lower-right across the point's face. Without this, each point
// will have just a single uniform texture coordinate value across
// its face.
// Unfortunately, the generated texture coordinates are inverted
// (upside-down) from Panda's usual convention, but this is what
// the graphics card manufacturers decided to use. You could use
// a texture matrix to re-invert the texture, but that will
// probably force software rendering. You'll have to paint your
// textures upside-down if you want true hardware sprites.
M_point_sprite,
};
// We inherit the definition of our Mode enumerated type from
// RenderAttrib. Normally, Mode would be defined here, but we
// define it in the base class instead as a hack to avoid a problem
// with circular includes.
typedef RenderAttrib::TexGenMode Mode;
protected:
INLINE TexGenAttrib();
@ -101,20 +54,24 @@ public:
PUBLISHED:
static CPT(RenderAttrib) make();
static CPT(RenderAttrib) make(TextureStage *stage, Mode mode);
static CPT(RenderAttrib) make(TextureStage *stage, Mode mode, const NodePath &light = NodePath());
CPT(RenderAttrib) add_stage(TextureStage *stage, Mode mode) const;
CPT(RenderAttrib) add_stage(TextureStage *stage, Mode mode, const NodePath &light = NodePath()) const;
CPT(RenderAttrib) remove_stage(TextureStage *stage) const;
bool is_empty() const;
bool has_stage(TextureStage *stage) const;
Mode get_mode(TextureStage *stage) const;
NodePath get_light(TextureStage *stage) const;
INLINE int get_geom_rendering(int geom_rendering) const;
public:
INLINE const Geom::NoTexCoordStages &get_no_texcoords() const;
typedef pmap<TextureStage *, NodePath> LightVectors;
INLINE const LightVectors &get_light_vectors() const;
virtual void issue(GraphicsStateGuardianBase *gsg) const;
virtual void output(ostream &out) const;
@ -125,21 +82,40 @@ protected:
virtual RenderAttrib *make_default_impl() const;
private:
typedef pmap<PT(TextureStage), Mode> Stages;
class ModeDef {
public:
INLINE ModeDef();
INLINE int compare_to(const ModeDef &other) const;
Mode _mode;
NodePath _light;
};
typedef pmap<PT(TextureStage), ModeDef> Stages;
Stages _stages;
// This is a set of TextureStage pointers for which texture
// coordinates will not be needed from the Geom. It's redundant;
// it's almost the same set that is listed in _stages, above. It's
// just here as an optimization to pass to
// Geom::setup_multitexcoord_iterator() during rendering.
// just here as an optimization during rendering.
Geom::NoTexCoordStages _no_texcoords;
// This is another optimization during rendering; it lists the
// texture stages (if any) that use M_light_vector, and their
// associated lights.
LightVectors _light_vectors;
// This element is only used during reading from a bam file. It has
// no meaningful value any other time.
pvector<Mode> _read_modes;
int _num_point_sprites;
int _num_light_vectors;
// _point_geom_rendering is the GeomRendering bits that are added by
// the TexGenAttrib if there are any points in the Geom.
// _geom_rendering is the GeomRendering bits that are added
// regardless of the kind of Geom it is.
int _point_geom_rendering;
int _geom_rendering;
static CPT(RenderAttrib) _empty_attrib;