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 "colorScaleAttrib.h"
#include "lightAttrib.h" #include "lightAttrib.h"
#include "textureAttrib.h" #include "textureAttrib.h"
#include "texGenAttrib.h"
#include "renderState.h" #include "renderState.h"
#include "depthWriteAttrib.h" #include "depthWriteAttrib.h"
#include "colorWriteAttrib.h" #include "colorWriteAttrib.h"

View File

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

View File

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

View File

@ -132,6 +132,11 @@ PUBLISHED:
// The union of the above shade model types. // The union of the above shade model types.
GR_shade_model_bits = 0x6000, 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 // 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, setup_texture(Texture::TextureType texture_type, int x_size, int y_size,
int z_size, Texture::ComponentType component_type, int z_size, Texture::ComponentType component_type,
Texture::Format format) { Texture::Format format) {
#ifndef NDEBUG
if (texture_type == TT_cube_map) { if (texture_type == TT_cube_map) {
// Cube maps must always consist of six square images. // Cube maps must always consist of six square images.
nassertv(x_size == y_size && z_size == 6); 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; _texture_type = texture_type;
_x_size = x_size; _x_size = x_size;
@ -110,6 +115,109 @@ setup_texture(Texture::TextureType texture_type, int x_size, int y_size,
_loaded_from_disk = false; _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 // Function: Texture::read
// Access: Published // Access: Published

View File

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

View File

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

View File

@ -18,6 +18,7 @@
#include "cullableObject.h" #include "cullableObject.h"
#include "textureAttrib.h" #include "textureAttrib.h"
#include "texGenAttrib.h"
#include "renderState.h" #include "renderState.h"
#include "clockObject.h" #include "clockObject.h"
#include "cullTraverser.h" #include "cullTraverser.h"
@ -28,8 +29,10 @@
#include "geomVertexWriter.h" #include "geomVertexWriter.h"
#include "geomVertexReader.h" #include "geomVertexReader.h"
#include "geomTriangles.h" #include "geomTriangles.h"
#include "light.h"
PStatCollector CullableObject::_munge_points_pcollector("*:Munge:Points"); PStatCollector CullableObject::_munge_points_pcollector("*:Munge:Points");
PStatCollector CullableObject::_munge_light_vector_pcollector("*:Munge:Light Vector");
CullableObject *CullableObject::_deleted_chain = (CullableObject *)NULL; CullableObject *CullableObject::_deleted_chain = (CullableObject *)NULL;
int CullableObject::_num_ever_allocated = 0; int CullableObject::_num_ever_allocated = 0;
@ -75,6 +78,9 @@ munge_geom(GraphicsStateGuardianBase *gsg,
} }
munge_points_to_quads(traverser); 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 // Now invoke the munger to ensure the resulting geometry is in
// a GSG-friendly form. // a GSG-friendly form.
@ -439,3 +445,91 @@ munge_points_to_quads(const CullTraverser *traverser) {
_geom = new_geom.p(); _geom = new_geom.p();
_munged_data = new_data; _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: private:
void munge_points_to_quads(const CullTraverser *traverser); void munge_points_to_quads(const CullTraverser *traverser);
void munge_texcoord_light_vector(const CullTraverser *traverser);
private: private:
// This class is used internally by munge_points_to_quads(). // This class is used internally by munge_points_to_quads().
@ -105,6 +106,7 @@ private:
static int _num_ever_allocated; static int _num_ever_allocated;
static PStatCollector _munge_points_pcollector; static PStatCollector _munge_points_pcollector;
static PStatCollector _munge_light_vector_pcollector;
public: public:
static TypeHandle get_class_type() { static TypeHandle get_class_type() {

View File

@ -133,6 +133,32 @@ write(ostream &out, int indent_level) const {
<< "direction " << get_direction() << "\n"; << "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 // Function: DirectionalLight::bind
// Access: Public, Virtual // Access: Public, Virtual

View File

@ -40,6 +40,10 @@ public:
virtual void xform(const LMatrix4f &mat); virtual void xform(const LMatrix4f &mat);
virtual void write(ostream &out, int indent_level) const; 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: PUBLISHED:
INLINE const Colorf &get_specular_color() const; INLINE const Colorf &get_specular_color() const;
INLINE void set_specular_color(const Colorf &color); INLINE void set_specular_color(const Colorf &color);

View File

@ -67,6 +67,28 @@ Light::
~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 // Function: Light::get_viz
// Access: Public // Access: Public

View File

@ -62,6 +62,10 @@ public:
virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light, virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,
int light_id)=0; 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(); GeomNode *get_viz();
protected: protected:

View File

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

View File

@ -26,6 +26,7 @@
#include "cullBinAttrib.h" #include "cullBinAttrib.h"
#include "textureAttrib.h" #include "textureAttrib.h"
#include "texMatrixAttrib.h" #include "texMatrixAttrib.h"
#include "texGenAttrib.h"
#include "materialAttrib.h" #include "materialAttrib.h"
#include "lightAttrib.h" #include "lightAttrib.h"
#include "clipPlaneAttrib.h" #include "clipPlaneAttrib.h"
@ -3226,7 +3227,7 @@ get_tex_transform(const NodePath &other, TextureStage *stage) const {
// the indicated texture stage. // the indicated texture stage.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void NodePath:: 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()); nassertv_always(!is_empty());
const RenderAttrib *attrib = 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); 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 // Function: NodePath::clear_tex_gen
// Access: Published // Access: Published
@ -3311,7 +3342,7 @@ has_tex_gen(TextureStage *stage) const {
// the given stage, or M_off if there is no explicit // the given stage, or M_off if there is no explicit
// mode set for the given stage. // mode set for the given stage.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
TexGenAttrib::Mode NodePath:: RenderAttrib::TexGenMode NodePath::
get_tex_gen(TextureStage *stage) const { get_tex_gen(TextureStage *stage) const {
nassertr_always(!is_empty(), TexGenAttrib::M_off); nassertr_always(!is_empty(), TexGenAttrib::M_off);
@ -3325,6 +3356,28 @@ get_tex_gen(TextureStage *stage) const {
return TexGenAttrib::M_off; 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 // Function: NodePath::set_tex_projector
// Access: Published // Access: Published

View File

@ -24,7 +24,6 @@
#include "pandaNode.h" #include "pandaNode.h"
#include "renderState.h" #include "renderState.h"
#include "transformState.h" #include "transformState.h"
#include "texGenAttrib.h"
#include "renderModeAttrib.h" #include "renderModeAttrib.h"
#include "transparencyAttrib.h" #include "transparencyAttrib.h"
#include "nodePathComponent.h" #include "nodePathComponent.h"
@ -581,11 +580,13 @@ PUBLISHED:
INLINE float get_tex_rotate(const NodePath &other, TextureStage *stage) const; INLINE float get_tex_rotate(const NodePath &other, TextureStage *stage) const;
INLINE LVecBase2f get_tex_scale(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();
void clear_tex_gen(TextureStage *stage); void clear_tex_gen(TextureStage *stage);
bool has_tex_gen(TextureStage *stage) const; 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 set_tex_projector(TextureStage *stage, const NodePath &from, const NodePath &to);
void clear_tex_projector(TextureStage *stage); void clear_tex_projector(TextureStage *stage);

View File

@ -132,6 +132,33 @@ write(ostream &out, int indent_level) const {
<< "attenuation " << get_attenuation() << "\n"; << "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 // Function: PointLight::bind
// Access: Public, Virtual // Access: Public, Virtual

View File

@ -40,6 +40,10 @@ public:
virtual void xform(const LMatrix4f &mat); virtual void xform(const LMatrix4f &mat);
virtual void write(ostream &out, int indent_level) const; 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: PUBLISHED:
INLINE const Colorf &get_specular_color() const; INLINE const Colorf &get_specular_color() const;
INLINE void set_specular_color(const Colorf &color); INLINE void set_specular_color(const Colorf &color);

View File

@ -92,6 +92,74 @@ PUBLISHED:
M_always // Always draw. 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: protected:
static CPT(RenderAttrib) return_new(RenderAttrib *attrib); static CPT(RenderAttrib) return_new(RenderAttrib *attrib);
virtual int compare_to_impl(const RenderAttrib *other) const; virtual int compare_to_impl(const RenderAttrib *other) const;

View File

@ -336,29 +336,6 @@ get_render_mode() const {
return _render_mode; 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 // Function: RenderState::set_destructing
// Access: Private // Access: Private

View File

@ -930,6 +930,29 @@ validate_states() {
return true; 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 // Function: RenderState::issue_delta_modify
// Access: Public // Access: Public

View File

@ -28,7 +28,6 @@
#include "updateSeq.h" #include "updateSeq.h"
#include "pStatCollector.h" #include "pStatCollector.h"
#include "renderModeAttrib.h" #include "renderModeAttrib.h"
#include "texGenAttrib.h"
#include "texMatrixAttrib.h" #include "texMatrixAttrib.h"
#include "geomMunger.h" #include "geomMunger.h"
#include "weakPointerTo.h" #include "weakPointerTo.h"
@ -40,6 +39,7 @@ class TransparencyAttrib;
class ColorAttrib; class ColorAttrib;
class ColorScaleAttrib; class ColorScaleAttrib;
class TextureAttrib; class TextureAttrib;
class TexGenAttrib;
class FactoryParams; class FactoryParams;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -134,7 +134,7 @@ PUBLISHED:
INLINE const TexMatrixAttrib *get_tex_matrix() const; INLINE const TexMatrixAttrib *get_tex_matrix() const;
INLINE const RenderModeAttrib *get_render_mode() 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: public:
CPT(RenderState) issue_delta_modify(const RenderState *other, 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 // Function: Spotlight::make_spot
// Access: Published, Static // Access: Published, Static

View File

@ -51,6 +51,10 @@ public:
virtual void xform(const LMatrix4f &mat); virtual void xform(const LMatrix4f &mat);
virtual void write(ostream &out, int indent_level) const; 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: PUBLISHED:
INLINE float get_exponent() const; INLINE float get_exponent() const;
INLINE void set_exponent(float exponent); INLINE void set_exponent(float exponent);

View File

@ -25,7 +25,10 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE TexGenAttrib:: INLINE TexGenAttrib::
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) : TexGenAttrib(const TexGenAttrib &copy) :
_stages(copy._stages), _stages(copy._stages),
_no_texcoords(copy._no_texcoords), _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:: INLINE int TexGenAttrib::
get_geom_rendering(int geom_rendering) const { get_geom_rendering(int geom_rendering) const {
if ((geom_rendering & Geom::GR_point) != 0) { if ((geom_rendering & Geom::GR_point) != 0) {
if (_num_point_sprites > 0) { geom_rendering |= _point_geom_rendering;
geom_rendering |= Geom::GR_point_sprite;
}
} }
return geom_rendering; return geom_rendering | _geom_rendering;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -75,3 +79,40 @@ INLINE const Geom::NoTexCoordStages &TexGenAttrib::
get_no_texcoords() const { get_no_texcoords() const {
return _no_texcoords; 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. // indicated stage.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) TexGenAttrib:: CPT(RenderAttrib) TexGenAttrib::
make(TextureStage *stage, TexGenAttrib::Mode mode) { make(TextureStage *stage, TexGenAttrib::Mode mode, const NodePath &light) {
return DCAST(TexGenAttrib, make())->add_stage(stage, mode); return DCAST(TexGenAttrib, make())->add_stage(stage, mode, light);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -74,14 +74,44 @@ make(TextureStage *stage, TexGenAttrib::Mode mode) {
// replaced. // replaced.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
CPT(RenderAttrib) TexGenAttrib:: CPT(RenderAttrib) TexGenAttrib::
add_stage(TextureStage *stage, TexGenAttrib::Mode mode) const { add_stage(TextureStage *stage, TexGenAttrib::Mode mode, const NodePath &light) const {
TexGenAttrib *attrib = new TexGenAttrib(*this); CPT(RenderAttrib) removed = remove_stage(stage);
attrib->_stages[stage] = mode; TexGenAttrib *attrib = new TexGenAttrib(*DCAST(TexGenAttrib, removed));
if (mode != M_off) {
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); attrib->_no_texcoords.insert(stage);
if (mode == M_point_sprite) { attrib->_point_geom_rendering |= Geom::GR_point_sprite;
attrib->_num_point_sprites++; 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); return return_new(attrib);
} }
@ -100,12 +130,21 @@ remove_stage(TextureStage *stage) const {
return this; return this;
} }
Mode mode = (*si).second; Mode mode = (*si).second._mode;
TexGenAttrib *attrib = new TexGenAttrib(*this); TexGenAttrib *attrib = new TexGenAttrib(*this);
attrib->_stages.erase(stage); attrib->_stages.erase(stage);
attrib->_no_texcoords.erase(stage); attrib->_no_texcoords.erase(stage);
if (mode == M_point_sprite) { if (mode == M_point_sprite) {
attrib->_num_point_sprites--; 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); return return_new(attrib);
} }
@ -145,11 +184,28 @@ TexGenAttrib::Mode TexGenAttrib::
get_mode(TextureStage *stage) const { get_mode(TextureStage *stage) const {
Stages::const_iterator mi = _stages.find(stage); Stages::const_iterator mi = _stages.find(stage);
if (mi != _stages.end()) { if (mi != _stages.end()) {
return (*mi).second; return (*mi).second._mode;
} }
return M_off; 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 // Function: TexGenAttrib::issue
// Access: Public, Virtual // Access: Public, Virtual
@ -176,9 +232,9 @@ output(ostream &out) const {
Stages::const_iterator mi; Stages::const_iterator mi;
for (mi = _stages.begin(); mi != _stages.end(); ++mi) { for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
TextureStage *stage = (*mi).first; TextureStage *stage = (*mi).first;
Mode mode = (*mi).second; const ModeDef &mode_def = (*mi).second;
out << " " << stage->get_name() << "("; out << " " << stage->get_name() << "(";
switch (mode) { switch (mode_def._mode) {
case M_off: case M_off:
out << "off"; out << "off";
break; break;
@ -214,6 +270,10 @@ output(ostream &out) const {
case M_point_sprite: case M_point_sprite:
out << "point_sprite"; out << "point_sprite";
break; break;
case M_light_vector:
out << "light_vector: " << mode_def._light;
break;
} }
out << ")"; out << ")";
} }
@ -253,8 +313,9 @@ compare_to_impl(const RenderAttrib *other) const {
} else { } else {
// This stage is in both; compare the stages. // This stage is in both; compare the stages.
if ((*ai).second != (*bi).second) { int compare = (*ai).second.compare_to((*bi).second);
return (int)(*ai).second < (int)(*bi).second ? -1 : 1; if (compare != 0) {
return compare;
} }
++ai; ++ai;
++bi; ++bi;
@ -338,8 +399,29 @@ compose_impl(const RenderAttrib *other) const {
// Now copy from _stages to _no_texcoords. // Now copy from _stages to _no_texcoords.
Stages::const_iterator ri; Stages::const_iterator ri;
for (ri = attrib->_stages.begin(); ri != attrib->_stages.end(); ++ri) { for (ri = attrib->_stages.begin(); ri != attrib->_stages.end(); ++ri) {
if ((*ri).second != M_off) { TextureStage *stage = (*ri).first;
attrib->_no_texcoords.insert((*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()) { while (ai != _stages.end() && bi != ta->_stages.end()) {
if ((*ai).first < (*bi).first) { if ((*ai).first < (*bi).first) {
// This stage is in a but not in b. Turn a off. // 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; ++ai;
} else if ((*bi).first < (*ai).first) { } else if ((*bi).first < (*ai).first) {
@ -389,7 +471,7 @@ invert_compose_impl(const RenderAttrib *other) const {
while (ai != _stages.end()) { while (ai != _stages.end()) {
// This stage is in a but not in b. // 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; ++ai;
} }
@ -402,8 +484,29 @@ invert_compose_impl(const RenderAttrib *other) const {
// Now copy from _stages to _no_texcoords. // Now copy from _stages to _no_texcoords.
Stages::const_iterator ri; Stages::const_iterator ri;
for (ri = attrib->_stages.begin(); ri != attrib->_stages.end(); ++ri) { for (ri = attrib->_stages.begin(); ri != attrib->_stages.end(); ++ri) {
if ((*ri).second != M_off) { TextureStage *stage = (*ri).first;
attrib->_no_texcoords.insert((*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; Stages::const_iterator si;
for (si = _stages.begin(); si != _stages.end(); ++si) { for (si = _stages.begin(); si != _stages.end(); ++si) {
TextureStage *stage = (*si).first; TextureStage *stage = (*si).first;
Mode mode = (*si).second; Mode mode = (*si).second._mode;
manager->write_pointer(dg, stage); manager->write_pointer(dg, stage);
dg.add_uint8((unsigned int)mode); dg.add_uint8((unsigned int)mode);
@ -475,7 +578,7 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
Mode mode = (*mi); Mode mode = (*mi);
TextureStage *stage = DCAST(TextureStage, p_list[pi++]); TextureStage *stage = DCAST(TextureStage, p_list[pi++]);
_stages[stage] = mode; _stages[stage]._mode = mode;
if (mode != M_off) { if (mode != M_off) {
_no_texcoords.insert(stage); _no_texcoords.insert(stage);

View File

@ -26,6 +26,7 @@
#include "textureStage.h" #include "textureStage.h"
#include "texture.h" #include "texture.h"
#include "pointerTo.h" #include "pointerTo.h"
#include "nodePath.h"
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : TexGenAttrib // Class : TexGenAttrib
@ -38,59 +39,11 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TexGenAttrib : public RenderAttrib { class EXPCL_PANDA TexGenAttrib : public RenderAttrib {
PUBLISHED: PUBLISHED:
enum Mode { // We inherit the definition of our Mode enumerated type from
M_off, // RenderAttrib. Normally, Mode would be defined here, but we
// define it in the base class instead as a hack to avoid a problem
// In the types below, "eye" means the coordinate space of the // with circular includes.
// observing camera, "object" means the local coordinate space of typedef RenderAttrib::TexGenMode Mode;
// 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,
};
protected: protected:
INLINE TexGenAttrib(); INLINE TexGenAttrib();
@ -101,20 +54,24 @@ public:
PUBLISHED: PUBLISHED:
static CPT(RenderAttrib) make(); 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; CPT(RenderAttrib) remove_stage(TextureStage *stage) const;
bool is_empty() const; bool is_empty() const;
bool has_stage(TextureStage *stage) const; bool has_stage(TextureStage *stage) const;
Mode get_mode(TextureStage *stage) const; Mode get_mode(TextureStage *stage) const;
NodePath get_light(TextureStage *stage) const;
INLINE int get_geom_rendering(int geom_rendering) const; INLINE int get_geom_rendering(int geom_rendering) const;
public: public:
INLINE const Geom::NoTexCoordStages &get_no_texcoords() const; 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 issue(GraphicsStateGuardianBase *gsg) const;
virtual void output(ostream &out) const; virtual void output(ostream &out) const;
@ -125,21 +82,40 @@ protected:
virtual RenderAttrib *make_default_impl() const; virtual RenderAttrib *make_default_impl() const;
private: 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; Stages _stages;
// This is a set of TextureStage pointers for which texture // This is a set of TextureStage pointers for which texture
// coordinates will not be needed from the Geom. It's redundant; // 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 // it's almost the same set that is listed in _stages, above. It's
// just here as an optimization to pass to // just here as an optimization during rendering.
// Geom::setup_multitexcoord_iterator() during rendering.
Geom::NoTexCoordStages _no_texcoords; 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 // This element is only used during reading from a bam file. It has
// no meaningful value any other time. // no meaningful value any other time.
pvector<Mode> _read_modes; pvector<Mode> _read_modes;
int _num_point_sprites; 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; static CPT(RenderAttrib) _empty_attrib;