hardware animation

This commit is contained in:
David Rose 2005-03-30 01:51:27 +00:00
parent bbe0a62001
commit f77ea5156a
55 changed files with 1851 additions and 305 deletions

View File

@ -27,3 +27,18 @@ INLINE const CharacterJoint *JointVertexTransform::
get_joint() const {
return _joint;
}
////////////////////////////////////////////////////////////////////
// Function: JointVertexTransform::check_matrix
// Access: Private
// Description: Recomputes _matrix if it needs it.
////////////////////////////////////////////////////////////////////
INLINE void JointVertexTransform::
check_matrix() const {
if (_matrix_stale) {
((JointVertexTransform *)this)->_matrix =
_joint->_initial_net_transform_inverse *
_joint->_net_transform;
((JointVertexTransform *)this)->_matrix_stale = false;
}
}

View File

@ -70,16 +70,59 @@ JointVertexTransform::
////////////////////////////////////////////////////////////////////
void JointVertexTransform::
get_matrix(LMatrix4f &matrix) const {
if (_matrix_stale) {
((JointVertexTransform *)this)->_matrix =
_joint->_initial_net_transform_inverse *
_joint->_net_transform;
((JointVertexTransform *)this)->_matrix_stale = false;
}
check_matrix();
matrix = _matrix;
}
////////////////////////////////////////////////////////////////////
// Function: JointVertexTransform::mult_matrix
// Access: Published, Virtual
// Description: Premultiplies this transform's matrix with the
// indicated previous matrix, so that the result is the
// net composition of the given transform with this
// transform. The result is stored in the parameter
// "result", which should not be the same matrix as
// previous.
////////////////////////////////////////////////////////////////////
void JointVertexTransform::
mult_matrix(LMatrix4f &result, const LMatrix4f &previous) const {
check_matrix();
result.multiply(_matrix, previous);
}
////////////////////////////////////////////////////////////////////
// Function: JointVertexTransform::accumulate_matrix
// Access: Published, Virtual
// Description: Adds the value of this transform's matrix, modified
// by the indicated weight, into the indicated
// accumulation matrix. This is used to compute the
// result of several blended transforms.
////////////////////////////////////////////////////////////////////
void JointVertexTransform::
accumulate_matrix(LMatrix4f &accum, float weight) const {
check_matrix();
accum._m.m._00 += _matrix._m.m._00 * weight;
accum._m.m._01 += _matrix._m.m._01 * weight;
accum._m.m._02 += _matrix._m.m._02 * weight;
accum._m.m._03 += _matrix._m.m._03 * weight;
accum._m.m._10 += _matrix._m.m._10 * weight;
accum._m.m._11 += _matrix._m.m._11 * weight;
accum._m.m._12 += _matrix._m.m._12 * weight;
accum._m.m._13 += _matrix._m.m._13 * weight;
accum._m.m._20 += _matrix._m.m._20 * weight;
accum._m.m._21 += _matrix._m.m._21 * weight;
accum._m.m._22 += _matrix._m.m._22 * weight;
accum._m.m._23 += _matrix._m.m._23 * weight;
accum._m.m._30 += _matrix._m.m._30 * weight;
accum._m.m._31 += _matrix._m.m._31 * weight;
accum._m.m._32 += _matrix._m.m._32 * weight;
accum._m.m._33 += _matrix._m.m._33 * weight;
}
////////////////////////////////////////////////////////////////////
// Function: JointVertexTransform::output
// Access: Published, Virtual

View File

@ -51,10 +51,14 @@ PUBLISHED:
INLINE const CharacterJoint *get_joint() const;
virtual void get_matrix(LMatrix4f &matrix) const;
virtual void mult_matrix(LMatrix4f &result, const LMatrix4f &previous) const;
virtual void accumulate_matrix(LMatrix4f &accum, float weight) const;
virtual void output(ostream &out) const;
private:
INLINE void check_matrix() const;
PT(CharacterJoint) _joint;
LMatrix4f _matrix;

View File

@ -11,7 +11,7 @@
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
colorMunger.I colorMunger.h \
standardMunger.I standardMunger.h \
config_display.h \
drawableRegion.I drawableRegion.h \
displayRegion.I displayRegion.h \
@ -35,7 +35,7 @@
lensStack.I lensStack.h
#define INCLUDED_SOURCES \
colorMunger.cxx \
standardMunger.cxx \
config_display.cxx \
drawableRegion.cxx \
displayRegion.cxx \
@ -53,7 +53,7 @@
windowProperties.cxx
#define INSTALL_HEADERS \
colorMunger.I colorMunger.h \
standardMunger.I standardMunger.h \
config_display.h \
drawableRegion.I drawableRegion.h \
displayRegion.I displayRegion.h displayRegionStack.I \

View File

@ -18,7 +18,7 @@
#include "config_display.h"
#include "colorMunger.h"
#include "standardMunger.h"
#include "graphicsStateGuardian.h"
#include "graphicsPipe.h"
#include "graphicsOutput.h"
@ -248,7 +248,7 @@ init_libdisplay() {
}
initialized = true;
ColorMunger::init_type();
StandardMunger::init_type();
GraphicsStateGuardian::init_type();
GraphicsPipe::init_type();
GraphicsOutput::init_type();

View File

@ -1,4 +1,4 @@
#include "colorMunger.cxx"
#include "standardMunger.cxx"
#include "drawableRegion.cxx"
#include "displayRegion.cxx"
#include "graphicsEngine.cxx"

View File

@ -201,6 +201,44 @@ get_max_cube_map_dimension() const {
return _max_cube_map_dimension;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_max_vertex_transforms
// Access: Published
// Description: Returns the maximum number of transform matrices that
// may be simultaneously used to transform any one
// vertex by the graphics hardware. If this number is
// 0, then the hardware (or the graphics backend)
// doesn't support soft-skinned vertices (in which case
// Panda will animate the vertices in software).
//
// The value returned may not be meaningful until after
// the graphics context has been fully created (e.g. the
// window has been opened).
////////////////////////////////////////////////////////////////////
INLINE int GraphicsStateGuardian::
get_max_vertex_transforms() const {
return _max_vertex_transforms;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_max_vertex_transform_indices
// Access: Published
// Description: Returns the maximum number of transforms there may be
// in a single TransformPalette for this graphics
// hardware. If this number is 0 (but
// get_max_transforms() is nonzero), then the graphics
// hardware (or API) doesn't support indexed transforms,
// but can support direct transform references.
//
// The value returned may not be meaningful until after
// the graphics context has been fully created (e.g. the
// window has been opened).
////////////////////////////////////////////////////////////////////
INLINE int GraphicsStateGuardian::
get_max_vertex_transform_indices() const {
return _max_vertex_transform_indices;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::get_copy_texture_inverted
// Access: Published

View File

@ -104,6 +104,10 @@ GraphicsStateGuardian(const FrameBufferProperties &properties,
_max_3d_texture_dimension = 0;
_max_cube_map_dimension = 0;
// Assume no vertex blending capability.
_max_vertex_transforms = 0;
_max_vertex_transform_indices = 0;
// Initially, we set this to false; a GSG that knows it has this
// property should set it to true.
_copy_texture_inverted = false;

View File

@ -88,6 +88,9 @@ PUBLISHED:
INLINE int get_max_3d_texture_dimension() const;
INLINE int get_max_cube_map_dimension() const;
INLINE int get_max_vertex_transforms() const;
INLINE int get_max_vertex_transform_indices() const;
INLINE bool get_copy_texture_inverted() const;
virtual bool get_supports_multisample() const;
INLINE bool get_supports_generate_mipmap() const;
@ -314,6 +317,9 @@ protected:
int _max_3d_texture_dimension;
int _max_cube_map_dimension;
int _max_vertex_transforms;
int _max_vertex_transform_indices;
bool _copy_texture_inverted;
bool _supports_multisample;
bool _supports_generate_mipmap;

View File

@ -1,4 +1,4 @@
// Filename: colorMunger.I
// Filename: standardMunger.I
// Created by: drose (21Mar05)
//
////////////////////////////////////////////////////////////////////

View File

@ -1,4 +1,4 @@
// Filename: colorMunger.cxx
// Filename: standardMunger.cxx
// Created by: drose (21Mar05)
//
////////////////////////////////////////////////////////////////////
@ -16,47 +16,53 @@
//
////////////////////////////////////////////////////////////////////
#include "colorMunger.h"
#include "standardMunger.h"
#include "renderState.h"
#include "graphicsStateGuardian.h"
#include "dcast.h"
#include "config_gobj.h"
TypeHandle ColorMunger::_type_handle;
TypeHandle StandardMunger::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: ColorMunger::Constructor
// Function: StandardMunger::Constructor
// Access: Public
// Description:
// Description: The StandardMunger constructor accepts additional
// parameters that specify the GSG's preferred color
// format (since we might be munging the color anyway,
// we might as well convert it as we munge).
////////////////////////////////////////////////////////////////////
ColorMunger::
ColorMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state,
int num_components,
qpGeomVertexDataType::NumericType numeric_type,
qpGeomVertexDataType::Contents contents) :
StandardMunger::
StandardMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state,
int num_components,
qpGeomVertexDataType::NumericType numeric_type,
qpGeomVertexDataType::Contents contents) :
qpGeomMunger(gsg, state),
_num_components(num_components),
_numeric_type(numeric_type),
_contents(contents)
{
_gsg = DCAST(GraphicsStateGuardian, gsg);
_color = state->get_color();
_color_scale = state->get_color_scale();
}
////////////////////////////////////////////////////////////////////
// Function: ColorMunger::Destructor
// Function: StandardMunger::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
ColorMunger::
~ColorMunger() {
StandardMunger::
~StandardMunger() {
}
////////////////////////////////////////////////////////////////////
// Function: ColorMunger::munge_data_impl
// Function: StandardMunger::munge_data_impl
// Access: Protected, Virtual
// Description: Given a source GeomVertexData, converts it as
// necessary for rendering.
////////////////////////////////////////////////////////////////////
CPT(qpGeomVertexData) ColorMunger::
CPT(qpGeomVertexData) StandardMunger::
munge_data_impl(const qpGeomVertexData *data) {
CPT(qpGeomVertexData) new_data = data;
@ -81,20 +87,62 @@ munge_data_impl(const qpGeomVertexData *data) {
_contents);
}
return qpGeomMunger::munge_data_impl(new_data);
qpGeomVertexAnimationSpec animation = data->get_format()->get_animation();
if (hardware_animated_vertices &&
animation.get_animation_type() == qpGeomVertexAnimationSpec::AT_panda &&
data->get_slider_table() == (SliderTable *)NULL) {
// Maybe we can animate the vertices with hardware.
const TransformBlendPalette *palette = data->get_transform_blend_palette();
if (palette != (TransformBlendPalette *)NULL &&
palette->get_max_simultaneous_transforms() <=
_gsg->get_max_vertex_transforms()) {
if (palette->get_num_transforms() <=
_gsg->get_max_vertex_transform_indices()) {
if (palette->get_num_transforms() == palette->get_max_simultaneous_transforms()) {
// We can support an indexed palette, but since that won't
// save us any per-vertex blends, go ahead and do a plain
// old nonindexed palette instead.
animation.set_hardware(palette->get_num_transforms(), false);
} else {
// We can support an indexed palette, and that means we can
// reduce the number of blends we have to specify for each
// vertex.
animation.set_hardware(palette->get_max_simultaneous_transforms(), true);
}
} else if (palette->get_num_transforms() <=
_gsg->get_max_vertex_transforms()) {
// We can't support an indexed palette, but we have few enough
// transforms that we can do a nonindexed palette.
animation.set_hardware(palette->get_num_transforms(), false);
}
}
}
CPT(qpGeomVertexFormat) orig_format = data->get_format();
CPT(qpGeomVertexFormat) new_format = munge_format(orig_format, animation);
if (new_format == orig_format) {
// Trivial case.
return data;
}
return data->convert_to(new_format);
}
////////////////////////////////////////////////////////////////////
// Function: ColorMunger::compare_to_impl
// Function: StandardMunger::compare_to_impl
// Access: Protected, Virtual
// Description: Called to compare two GeomMungers who are known to be
// of the same type, for an apples-to-apples comparison.
// This will never be called on two pointers of a
// different type.
////////////////////////////////////////////////////////////////////
int ColorMunger::
int StandardMunger::
compare_to_impl(const qpGeomMunger *other) const {
const ColorMunger *om = DCAST(ColorMunger, other);
const StandardMunger *om = DCAST(StandardMunger, other);
if (_color != om->_color) {
return _color < om->_color ? -1 : 1;
}
@ -106,16 +154,16 @@ compare_to_impl(const qpGeomMunger *other) const {
}
////////////////////////////////////////////////////////////////////
// Function: ColorMunger::geom_compare_to_impl
// Function: StandardMunger::geom_compare_to_impl
// Access: Protected, Virtual
// Description: Called to compare two GeomMungers who are known to be
// of the same type, for an apples-to-apples comparison.
// This will never be called on two pointers of a
// different type.
////////////////////////////////////////////////////////////////////
int ColorMunger::
int StandardMunger::
geom_compare_to_impl(const qpGeomMunger *other) const {
const ColorMunger *om = DCAST(ColorMunger, other);
const StandardMunger *om = DCAST(StandardMunger, other);
if (_color != om->_color) {
return _color < om->_color ? -1 : 1;
}

View File

@ -1,4 +1,4 @@
// Filename: colorMunger.h
// Filename: standardMunger.h
// Created by: drose (21Mar05)
//
////////////////////////////////////////////////////////////////////
@ -16,29 +16,32 @@
//
////////////////////////////////////////////////////////////////////
#ifndef COLORMUNGER_H
#define COLORMUNGER_H
#ifndef STANDARDMUNGER_H
#define STANDARDMUNGER_H
#include "pandabase.h"
#include "qpgeomMunger.h"
#include "graphicsStateGuardian.h"
#include "colorAttrib.h"
#include "colorScaleAttrib.h"
#include "pointerTo.h"
////////////////////////////////////////////////////////////////////
// Class : ColorMunger
// Description : Applies ColorAttrib and ColorScaleAttrib by munging
// the vertex data.
// Class : StandardMunger
// Description : Performs some generic munging that is appropriate for
// all GSG types; for instance, applies ColorAttrib and
// ColorScaleAttrib to the vertices, and checks for
// hardware-accelerated animation capabilities.
//
// This is part of the experimental Geom rewrite.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA ColorMunger : public qpGeomMunger {
class EXPCL_PANDA StandardMunger : public qpGeomMunger {
public:
ColorMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state,
int num_components,
qpGeomVertexDataType::NumericType numeric_type,
qpGeomVertexDataType::Contents contents);
virtual ~ColorMunger();
StandardMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state,
int num_components,
qpGeomVertexDataType::NumericType numeric_type,
qpGeomVertexDataType::Contents contents);
virtual ~StandardMunger();
protected:
virtual CPT(qpGeomVertexData) munge_data_impl(const qpGeomVertexData *data);
@ -49,6 +52,7 @@ private:
int _num_components;
qpGeomVertexDataType::NumericType _numeric_type;
qpGeomVertexDataType::Contents _contents;
CPT(GraphicsStateGuardian) _gsg;
CPT(ColorAttrib) _color;
CPT(ColorScaleAttrib) _color_scale;
@ -58,7 +62,7 @@ public:
}
static void init_type() {
qpGeomMunger::init_type();
register_type(_type_handle, "ColorMunger",
register_type(_type_handle, "StandardMunger",
qpGeomMunger::get_class_type());
}
virtual TypeHandle get_type() const {
@ -70,7 +74,7 @@ private:
static TypeHandle _type_handle;
};
#include "colorMunger.I"
#include "standardMunger.I"
#endif

View File

@ -24,7 +24,7 @@
////////////////////////////////////////////////////////////////////
INLINE DXGeomMunger8::
DXGeomMunger8(GraphicsStateGuardian *gsg, const RenderState *state) :
ColorMunger(gsg, state, 1, qpGeomVertexDataType::NT_packed_8888,
StandardMunger(gsg, state, 1, qpGeomVertexDataType::NT_packed_8888,
qpGeomVertexDataType::C_argb)
{
}
@ -38,5 +38,5 @@ DXGeomMunger8(GraphicsStateGuardian *gsg, const RenderState *state) :
////////////////////////////////////////////////////////////////////
INLINE void *DXGeomMunger8::
operator new(size_t size) {
return do_operator_new(size, _deleted_chain);
return do_operator_new(size, &_deleted_chain);
}

View File

@ -17,6 +17,9 @@
////////////////////////////////////////////////////////////////////
#include "dxGeomMunger8.h"
#include "qpgeomVertexReader.h"
#include "qpgeomVertexWriter.h"
#include "config_dxgsg8.h"
qpGeomMunger *DXGeomMunger8::_deleted_chain = NULL;
TypeHandle DXGeomMunger8::_type_handle;
@ -28,11 +31,19 @@ TypeHandle DXGeomMunger8::_type_handle;
// necessary to the appropriate format for rendering.
////////////////////////////////////////////////////////////////////
CPT(qpGeomVertexFormat) DXGeomMunger8::
munge_format_impl(const qpGeomVertexFormat *orig) {
munge_format_impl(const qpGeomVertexFormat *orig,
const qpGeomVertexAnimationSpec &animation) {
if (dxgsg8_cat.is_debug()) {
if (animation.get_animation_type() != qpGeomVertexAnimationSpec::AT_none) {
dxgsg8_cat.debug()
<< "preparing animation type " << animation << "\n";
}
}
// We have to build a completely new format that includes only the
// appropriate components, in the appropriate order, in just one
// array.
PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(*orig);
new_format->set_animation(animation);
PT(qpGeomVertexArrayFormat) new_array_format = new qpGeomVertexArrayFormat;
const qpGeomVertexDataType *vertex_type =
@ -54,6 +65,23 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
return orig;
}
if (animation.get_animation_type() == qpGeomVertexAnimationSpec::AT_hardware &&
animation.get_num_transforms() > 0) {
// If we want hardware animation, we need to reserve space for the
// blend weights.
new_array_format->add_data_type
(InternalName::get_transform_weight(), animation.get_num_transforms() - 1,
qpGeomVertexDataType::NT_float32, qpGeomVertexDataType::C_other);
if (animation.get_indexed_transforms()) {
// Also, if we'll be indexing into the transfom palette, reserve
// space for the index.
new_array_format->add_data_type
(InternalName::get_transform_index(), 1,
qpGeomVertexDataType::NT_packed_8888, qpGeomVertexDataType::C_index);
}
}
if (normal_type != (const qpGeomVertexDataType *)NULL) {
new_array_format->add_data_type
(InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float32,
@ -89,27 +117,3 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
new_format->insert_array(0, new_array_format);
return qpGeomVertexFormat::register_format(new_format);
}
////////////////////////////////////////////////////////////////////
// Function: DXGeomMunger8::munge_geom_impl
// Access: Protected, Virtual
// Description: Converts a Geom and/or its data as necessary.
////////////////////////////////////////////////////////////////////
void DXGeomMunger8::
munge_geom_impl(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data) {
}
////////////////////////////////////////////////////////////////////
// Function: DXGeomMunger8::compare_to_impl
// Access: Protected, Virtual
// Description: Called to compare two GeomMungers who are known to be
// of the same type, for an apples-to-apples comparison.
// This will never be called on two pointers of a
// different type.
////////////////////////////////////////////////////////////////////
int DXGeomMunger8::
compare_to_impl(const qpGeomMunger *other) const {
// const DXGeomMunger8 *om = DCAST(DXGeomMunger8, other);
return ColorMunger::compare_to_impl(other);
}

View File

@ -20,7 +20,7 @@
#define DXGEOMMUNGER8_H
#include "pandabase.h"
#include "colorMunger.h"
#include "standardMunger.h"
#include "graphicsStateGuardian.h"
////////////////////////////////////////////////////////////////////
@ -31,14 +31,13 @@
// and that all relevant components are packed into a
// single array, in the correct order.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDADX DXGeomMunger8 : public ColorMunger {
class EXPCL_PANDADX DXGeomMunger8 : public StandardMunger {
public:
INLINE DXGeomMunger8(GraphicsStateGuardian *gsg, const RenderState *state);
protected:
virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig);
virtual void munge_geom_impl(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data);
virtual int compare_to_impl(const qpGeomMunger *other) const;
virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig,
const qpGeomVertexAnimationSpec &animation);
public:
INLINE void *operator new(size_t size);
@ -51,9 +50,9 @@ public:
return _type_handle;
}
static void init_type() {
ColorMunger::init_type();
StandardMunger::init_type();
register_type(_type_handle, "DXGeomMunger8",
ColorMunger::get_class_type());
StandardMunger::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -196,6 +196,7 @@ DXGraphicsStateGuardian8(const FrameBufferProperties &properties) :
_pD3DDevice = NULL;
_bDXisReady = false;
_transform_stale = false;
_overlay_windows_supported = false;
_pFvfBufBasePtr = NULL;
@ -287,10 +288,16 @@ free_d3d_device(void) {
////////////////////////////////////////////////////////////////////
void DXGraphicsStateGuardian8::
free_nondx_resources() {
// this must not release any objects associated with D3D/DX!
// those should be released in free_dxgsg_objects instead
// this must not release any objects associated with D3D/DX!
// those should be released in free_dxgsg_objects instead
if (_index_buf != NULL) {
SAFE_DELETE_ARRAY(_index_buf);
_index_buf = NULL;
}
if (_pFvfBufBasePtr != NULL) {
SAFE_DELETE_ARRAY(_pFvfBufBasePtr);
_pFvfBufBasePtr = NULL;
}
}
////////////////////////////////////////////////////////////////////
@ -310,6 +317,34 @@ dx_init(void) {
assert(_pScrn->pD3D8!=NULL);
assert(_pD3DDevice!=NULL);
D3DCAPS8 d3dCaps;
_pD3DDevice->GetDeviceCaps(&d3dCaps);
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "\nHwTransformAndLight = " << ((d3dCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) != 0)
<< "\nMaxTextureWidth = " << d3dCaps.MaxTextureWidth
<< "\nMaxTextureHeight = " << d3dCaps.MaxTextureHeight
<< "\nMaxVolumeExtent = " << d3dCaps.MaxVolumeExtent
<< "\nMaxTextureAspectRatio = " << d3dCaps.MaxTextureAspectRatio
<< "\nTexCoordCount = " << (d3dCaps.FVFCaps & D3DFVFCAPS_TEXCOORDCOUNTMASK)
<< "\nMaxTextureBlendStages = " << d3dCaps.MaxTextureBlendStages
<< "\nMaxSimultaneousTextures = " << d3dCaps.MaxSimultaneousTextures
<< "\nMaxActiveLights = " << d3dCaps.MaxActiveLights
<< "\nMaxUserClipPlanes = " << d3dCaps.MaxUserClipPlanes
<< "\nMaxVertexBlendMatrices = " << d3dCaps.MaxVertexBlendMatrices
<< "\nMaxVertexBlendMatrixIndex = " << d3dCaps.MaxVertexBlendMatrixIndex
<< "\nMaxPointSize = " << d3dCaps.MaxPointSize
<< "\nMaxPrimitiveCount = " << d3dCaps.MaxPrimitiveCount
<< "\nMaxVertexIndex = " << d3dCaps.MaxVertexIndex
<< "\nMaxStreams = " << d3dCaps.MaxStreams
<< "\nMaxStreamStride = " << d3dCaps.MaxStreamStride
<< "\n";
}
_max_vertex_transforms = d3dCaps.MaxVertexBlendMatrices;
_max_vertex_transform_indices = d3dCaps.MaxVertexBlendMatrixIndex;
ZeroMemory(&_lmodel_ambient,sizeof(Colorf));
_pD3DDevice->SetRenderState(D3DRS_AMBIENT, 0x0);
@ -2616,14 +2651,64 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
const qpGeomVertexFormat *format = _vertex_data->get_format();
// The munger should have put the "vertex" data at the beginning of
// the first array.
// The munger should have put the FVF data in the first array.
const qpGeomVertexArrayData *data = _vertex_data->get_array(0);
VertexBufferContext *vbc = ((qpGeomVertexArrayData *)data)->prepare_now(get_prepared_objects(), this);
nassertr(vbc != (VertexBufferContext *)NULL, false);
apply_vertex_buffer(vbc);
const qpGeomVertexAnimationSpec &animation =
vertex_data->get_format()->get_animation();
if (animation.get_animation_type() == qpGeomVertexAnimationSpec::AT_hardware) {
// Set up vertex blending.
switch (animation.get_num_transforms()) {
case 1:
_pD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_0WEIGHTS);
break;
case 2:
_pD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS);
break;
case 3:
_pD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_2WEIGHTS);
break;
case 4:
_pD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_3WEIGHTS);
break;
}
if (animation.get_indexed_transforms()) {
// Set up indexed vertex blending.
_pD3DDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE);
} else {
_pD3DDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
}
const TransformPalette *palette = vertex_data->get_transform_palette();
if (palette != (TransformPalette *)NULL) {
for (int i = 0; i < palette->get_num_transforms(); i++) {
LMatrix4f mat;
palette->get_transform(i)->mult_matrix(mat, _transform->get_mat());
const D3DMATRIX *d3d_mat = (const D3DMATRIX *)mat.get_data();
_pD3DDevice->SetTransform(D3DTS_WORLDMATRIX(i), d3d_mat);
}
// Setting the palette transforms steps on the world matrix, so
// we have to set a flag to reload the world matrix later.
_transform_stale = true;
}
} else {
// We're not using vertex blending.
_pD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
if (_transform_stale) {
const D3DMATRIX *d3d_mat = (const D3DMATRIX *)_transform->get_mat().get_data();
_pD3DDevice->SetTransform(D3DTS_WORLD, d3d_mat);
}
}
return true;
}
@ -2938,16 +3023,18 @@ release_texture(TextureContext *tc) {
////////////////////////////////////////////////////////////////////
VertexBufferContext *DXGraphicsStateGuardian8::
prepare_vertex_buffer(qpGeomVertexArrayData *data) {
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "prepare_vertex_buffer(" << (void *)data << ")\n";
}
DXVertexBufferContext8 *dvbc = new DXVertexBufferContext8(data);
if (vertex_buffers) {
dvbc->create_vbuffer(*_pScrn);
dvbc->mark_loaded();
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "creating vertex buffer " << dvbc->_vbuffer << ": "
<< data->get_num_vertices() << " vertices "
<< *data->get_array_format() << "\n";
}
}
return dvbc;
@ -2967,10 +3054,6 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
add_to_vertex_buffer_record(dvbc);
if (dvbc->was_modified()) {
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "apply_vertex_buffer(" << (void *)vbc->get_data() << ")\n";
}
if (dvbc->changed_size()) {
// Here we have to destroy the old vertex buffer and create a
// new one.
@ -3005,11 +3088,6 @@ apply_vertex_buffer(VertexBufferContext *vbc) {
////////////////////////////////////////////////////////////////////
void DXGraphicsStateGuardian8::
release_vertex_buffer(VertexBufferContext *vbc) {
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "release_vertex_buffer(" << (void *)vbc->get_data() << ")\n";
}
DXVertexBufferContext8 *dvbc = DCAST(DXVertexBufferContext8, vbc);
delete dvbc;
}
@ -3029,16 +3107,16 @@ release_vertex_buffer(VertexBufferContext *vbc) {
////////////////////////////////////////////////////////////////////
IndexBufferContext *DXGraphicsStateGuardian8::
prepare_index_buffer(qpGeomPrimitive *data) {
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "prepare_index_buffer(" << (void *)data << ")\n";
}
DXIndexBufferContext8 *dibc = new DXIndexBufferContext8(data);
dibc->create_ibuffer(*_pScrn);
dibc->mark_loaded();
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "creating index buffer " << dibc->_ibuffer << "\n";
}
return dibc;
}
@ -3056,10 +3134,6 @@ apply_index_buffer(IndexBufferContext *ibc) {
add_to_index_buffer_record(dibc);
if (dibc->was_modified()) {
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "apply_index_buffer(" << (void *)ibc->get_data() << ")\n";
}
if (dibc->changed_size()) {
// Here we have to destroy the old index buffer and create a
// new one.
@ -3092,11 +3166,6 @@ apply_index_buffer(IndexBufferContext *ibc) {
////////////////////////////////////////////////////////////////////
void DXGraphicsStateGuardian8::
release_index_buffer(IndexBufferContext *ibc) {
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "release_index_buffer(" << (void *)ibc->get_data() << ")\n";
}
DXIndexBufferContext8 *dibc = DCAST(DXIndexBufferContext8, ibc);
delete dibc;
}
@ -3419,9 +3488,9 @@ void DXGraphicsStateGuardian8::
issue_transform(const TransformState *transform) {
DO_PSTATS_STUFF(_transform_state_pcollector.add_level(1));
// if we're using ONLY vertex shaders, could get avoid calling SetTrans
D3DMATRIX *pMat = (D3DMATRIX*)transform->get_mat().get_data();
_pD3DDevice->SetTransform(D3DTS_WORLD,pMat);
const D3DMATRIX *d3d_mat = (const D3DMATRIX *)transform->get_mat().get_data();
_pD3DDevice->SetTransform(D3DTS_WORLD, d3d_mat);
_transform_stale = false;
_transform = transform;
if (_auto_rescale_normal) {

View File

@ -185,8 +185,7 @@ protected:
HRESULT _last_testcooplevel_result;
DXTextureContext8 *_pCurTexContext;
bool _bTransformIssued; // decaling needs to tell when a transform has been issued
D3DMATRIX _SavedTransform;
bool _transform_stale;
RenderBuffer::Type _cur_read_pixel_buffer; // source for copy_pixel_buffer operation
bool _auto_rescale_normal;

View File

@ -43,6 +43,11 @@ DXIndexBufferContext8(qpGeomPrimitive *data) :
DXIndexBufferContext8::
~DXIndexBufferContext8() {
if (_ibuffer != NULL) {
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "deleting index buffer " << _ibuffer << "\n";
}
RELEASE(_ibuffer, dxgsg8, "index buffer", RELEASE_ONCE);
_ibuffer = NULL;
}
@ -84,6 +89,12 @@ upload_data() {
nassertv(_ibuffer != NULL);
int data_size = get_data()->get_data_size_bytes();
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "copying " << data_size
<< " bytes into index buffer " << _ibuffer << "\n";
}
BYTE *local_pointer;
HRESULT hr = _ibuffer->Lock(0, data_size, &local_pointer, 0);

View File

@ -47,9 +47,52 @@ DXVertexBufferContext8(qpGeomVertexArrayData *data) :
if (n < num_data_types &&
array_format->get_data_type(n)->get_name() == InternalName::get_vertex()) {
_fvf |= D3DFVF_XYZ;
++n;
int num_blend_values = 0;
if (n < num_data_types &&
array_format->get_data_type(n)->get_name() == InternalName::get_transform_weight()) {
// We have hardware vertex animation.
num_blend_values = array_format->get_data_type(n)->get_num_values();
++n;
if (n < num_data_types &&
array_format->get_data_type(n)->get_name() == InternalName::get_transform_index()) {
// Furthermore, it's indexed vertex animation.
_fvf |= D3DFVF_LASTBETA_UBYTE4;
++num_blend_values;
++n;
}
}
switch (num_blend_values) {
case 0:
_fvf |= D3DFVF_XYZ;
break;
case 1:
_fvf |= D3DFVF_XYZB1;
break;
case 2:
_fvf |= D3DFVF_XYZB2;
break;
case 3:
_fvf |= D3DFVF_XYZB3;
break;
case 4:
_fvf |= D3DFVF_XYZB4;
break;
case 5:
_fvf |= D3DFVF_XYZB5;
break;
}
}
if (n < num_data_types &&
array_format->get_data_type(n)->get_name() == InternalName::get_normal()) {
_fvf |= D3DFVF_NORMAL;
@ -95,6 +138,11 @@ DXVertexBufferContext8(qpGeomVertexArrayData *data) :
DXVertexBufferContext8::
~DXVertexBufferContext8() {
if (_vbuffer != NULL) {
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "deleting vertex buffer " << _vbuffer << "\n";
}
RELEASE(_vbuffer, dxgsg8, "vertex buffer", RELEASE_ONCE);
_vbuffer = NULL;
}
@ -136,6 +184,12 @@ upload_data() {
nassertv(_vbuffer != NULL);
int data_size = get_data()->get_data_size_bytes();
if (dxgsg8_cat.is_debug()) {
dxgsg8_cat.debug()
<< "copying " << data_size
<< " bytes into vertex buffer " << _vbuffer << "\n";
}
BYTE *local_pointer;
HRESULT hr = _vbuffer->Lock(0, data_size, &local_pointer, 0);

View File

@ -1960,6 +1960,13 @@ make_vertex_data(const EggRenderState *render_state,
// maybe a SliderTable, and additional columns in the vertex data:
// one that indexes into the blend palette per vertex, and also
// one for each different type of morph delta.
// Tell the format that we're setting it up for Panda-based
// animation.
qpGeomVertexAnimationSpec animation;
animation.set_panda();
temp_format->set_animation(animation);
blend_palette = new TransformBlendPalette;
PT(qpGeomVertexArrayFormat) anim_array_format = new qpGeomVertexArrayFormat;

View File

@ -24,7 +24,7 @@
////////////////////////////////////////////////////////////////////
INLINE CLP(GeomMunger)::
CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state) :
ColorMunger(gsg, state, 4, qpGeomVertexDataType::NT_uint8,
StandardMunger(gsg, state, 4, qpGeomVertexDataType::NT_uint8,
qpGeomVertexDataType::C_rgba),
_gsg(gsg),
_texture(state->get_texture()),
@ -52,5 +52,5 @@ get_gsg() const {
////////////////////////////////////////////////////////////////////
INLINE void *CLP(GeomMunger)::
operator new(size_t size) {
return do_operator_new(size, _deleted_chain);
return do_operator_new(size, &_deleted_chain);
}

View File

@ -44,33 +44,33 @@ CLP(GeomMunger)::
// necessary to the appropriate format for rendering.
////////////////////////////////////////////////////////////////////
CPT(qpGeomVertexFormat) CLP(GeomMunger)::
munge_format_impl(const qpGeomVertexFormat *orig) {
CPT(qpGeomVertexFormat) format = orig;
munge_format_impl(const qpGeomVertexFormat *orig,
const qpGeomVertexAnimationSpec &animation) {
PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(*orig);
new_format->set_animation(animation);
const qpGeomVertexDataType *color_type =
format->get_data_type(InternalName::get_color());
orig->get_data_type(InternalName::get_color());
if (color_type != (qpGeomVertexDataType *)NULL &&
(color_type->get_numeric_type() == qpGeomVertexDataType::NT_packed_8888 ||
color_type->get_contents() != qpGeomVertexDataType::C_rgba)) {
// We need to convert the color format; OpenGL doesn't support the
// byte order of DirectX's packed ARGB format.
int color_array = format->get_array_with(InternalName::get_color());
int color_array = orig->get_array_with(InternalName::get_color());
PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(*format);
PT(qpGeomVertexArrayFormat) new_array_format = new_format->modify_array(color_array);
// Replace the existing color format with the new format.
new_array_format->add_data_type
(InternalName::get_color(), 4, qpGeomVertexDataType::NT_uint8,
qpGeomVertexDataType::C_rgba, color_type->get_start());
format = qpGeomVertexFormat::register_format(new_format);
}
/*
if (true) {
// Split out the interleaved array into n parallel arrays.
PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat;
CPT(qpGeomVertexFormat) format = new_format;
new_format = new qpGeomVertexFormat;
for (int i = 0; i < format->get_num_data_types(); i++) {
const qpGeomVertexDataType *data_type = format->get_data_type(i);
PT(qpGeomVertexArrayFormat) new_array_format = new qpGeomVertexArrayFormat;
@ -78,11 +78,10 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
data_type->get_numeric_type());
new_format->add_array(new_array_format);
}
format = qpGeomVertexFormat::register_format(new_format);
}
*/
return format;
return qpGeomVertexFormat::register_format(new_format);
}
////////////////////////////////////////////////////////////////////
@ -103,7 +102,7 @@ compare_to_impl(const qpGeomMunger *other) const {
return _tex_gen < om->_tex_gen ? -1 : 1;
}
return ColorMunger::compare_to_impl(other);
return StandardMunger::compare_to_impl(other);
}
////////////////////////////////////////////////////////////////////
@ -119,5 +118,5 @@ geom_compare_to_impl(const qpGeomMunger *other) const {
// We don't consider _texture and _tex_gen for this purpose; they
// affect only whether the GL display list should be regenerated or
// not, and don't require reconverting the vertices.
return ColorMunger::geom_compare_to_impl(other);
return StandardMunger::geom_compare_to_impl(other);
}

View File

@ -17,7 +17,7 @@
////////////////////////////////////////////////////////////////////
#include "pandabase.h"
#include "colorMunger.h"
#include "standardMunger.h"
#include "graphicsStateGuardian.h"
#include "textureAttrib.h"
#include "texGenAttrib.h"
@ -31,7 +31,7 @@ class CLP(GeomContext);
// for OpenGL rendering. In particular, it makes sure
// colors aren't stored in DirectX's packed_argb format.
////////////////////////////////////////////////////////////////////
class EXPCL_GL CLP(GeomMunger) : public ColorMunger {
class EXPCL_GL CLP(GeomMunger) : public StandardMunger {
public:
INLINE CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state);
virtual ~CLP(GeomMunger)();
@ -39,7 +39,8 @@ public:
INLINE GraphicsStateGuardian *get_gsg() const;
protected:
virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig);
virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig,
const qpGeomVertexAnimationSpec &animation);
virtual int compare_to_impl(const qpGeomMunger *other) const;
virtual int geom_compare_to_impl(const qpGeomMunger *other) const;
@ -61,9 +62,9 @@ public:
return _type_handle;
}
static void init_type() {
ColorMunger::init_type();
StandardMunger::init_type();
register_type(_type_handle, CLASSPREFIX_QUOTED "GeomMunger",
ColorMunger::get_class_type());
StandardMunger::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -32,6 +32,7 @@
qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
qpgeomCacheEntry.h qpgeomCacheEntry.I \
qpgeomCacheManager.h qpgeomCacheManager.I \
qpgeomVertexAnimationSpec.h qpgeomVertexAnimationSpec.I \
qpgeomVertexData.h qpgeomVertexData.I \
qpgeomVertexDataType.h qpgeomVertexDataType.I \
qpgeomVertexFormat.h qpgeomVertexFormat.I \
@ -82,6 +83,7 @@
qpgeomVertexArrayFormat.cxx \
qpgeomCacheEntry.cxx \
qpgeomCacheManager.cxx \
qpgeomVertexAnimationSpec.cxx \
qpgeomVertexData.cxx \
qpgeomVertexDataType.cxx \
qpgeomVertexFormat.cxx \
@ -131,6 +133,7 @@
qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
qpgeomCacheEntry.h qpgeomCacheEntry.I \
qpgeomCacheManager.h qpgeomCacheManager.I \
qpgeomVertexAnimationSpec.h qpgeomVertexAnimationSpec.I \
qpgeomVertexData.h qpgeomVertexData.I \
qpgeomVertexDataType.h qpgeomVertexDataType.I \
qpgeomVertexFormat.h qpgeomVertexFormat.I \

View File

@ -113,9 +113,21 @@ ConfigVariableBool display_lists
"rendering static geometry. On some systems, this can result "
"in a performance improvement over vertex buffers alone; on "
"other systems (particularly low-end systems) it makes little to "
"no difference. This has no effect on DirectX rendering. If "
"vertex-buffers is also enabled, then OpenGL buffer objects "
"will also be created for dynamic geometry."));
"no difference. On some systems, using display lists can actually "
"reduce performance. This has no effect on DirectX rendering or "
"on dynamic geometry (e.g. soft-skinned animation)."));
ConfigVariableBool hardware_animated_vertices
("hardware-animated-vertices", false,
PRC_DESC("Set this true to allow the transforming of soft-skinned "
"animated vertices via hardware, if supported, or false always "
"to perform the vertex animation via software within Panda. "
"If you have a card that supports this, and your scene does "
"not contain too many vertices already, this can provide a "
"performance boost by offloading some work from your CPU onto "
"your graphics card. It may also help by reducing the bandwidth "
"necessary on your computer's bus. However, in some cases it "
"may actually reduce performance."));
ConfigVariableBool use_qpgeom
("use-qpgeom", false,

View File

@ -53,6 +53,7 @@ extern EXPCL_PANDA ConfigVariableBool keep_geom_ram;
extern EXPCL_PANDA ConfigVariableBool retained_mode;
extern EXPCL_PANDA ConfigVariableBool vertex_buffers;
extern EXPCL_PANDA ConfigVariableBool display_lists;
extern EXPCL_PANDA ConfigVariableBool hardware_animated_vertices;
extern EXPCL_PANDA ConfigVariableBool use_qpgeom;

View File

@ -24,6 +24,7 @@
#include "qpgeomVertexArrayFormat.cxx"
#include "qpgeomCacheEntry.cxx"
#include "qpgeomCacheManager.cxx"
#include "qpgeomVertexAnimationSpec.cxx"
#include "qpgeomVertexData.cxx"
#include "qpgeomVertexDataType.cxx"
#include "qpgeomVertexFormat.cxx"

View File

@ -191,6 +191,32 @@ get_transform_blend() {
return _transform_blend;
}
////////////////////////////////////////////////////////////////////
// Function: InternalName::get_transform_weight
// Access: Published, Static
// Description: Returns the standard InternalName "transform_weight".
////////////////////////////////////////////////////////////////////
INLINE PT(InternalName) InternalName::
get_transform_weight() {
if (_transform_weight == (InternalName *)NULL) {
_transform_weight = InternalName::make("transform_weight");
}
return _transform_weight;
}
////////////////////////////////////////////////////////////////////
// Function: InternalName::get_transform_index
// Access: Published, Static
// Description: Returns the standard InternalName "transform_index".
////////////////////////////////////////////////////////////////////
INLINE PT(InternalName) InternalName::
get_transform_index() {
if (_transform_index == (InternalName *)NULL) {
_transform_index = InternalName::make("transform_index");
}
return _transform_index;
}
////////////////////////////////////////////////////////////////////
// Function: InternalName::get_morph
// Access: Published, Static

View File

@ -33,6 +33,8 @@ PT(InternalName) InternalName::_binormal;
PT(InternalName) InternalName::_texcoord;
PT(InternalName) InternalName::_color;
PT(InternalName) InternalName::_transform_blend;
PT(InternalName) InternalName::_transform_weight;
PT(InternalName) InternalName::_transform_index;
TypeHandle InternalName::_type_handle;
TypeHandle InternalName::_texcoord_type_handle;

View File

@ -72,6 +72,8 @@ PUBLISHED:
INLINE static PT(InternalName) get_texcoord_name(const string &name);
INLINE static PT(InternalName) get_color();
INLINE static PT(InternalName) get_transform_blend();
INLINE static PT(InternalName) get_transform_weight();
INLINE static PT(InternalName) get_transform_index();
INLINE static PT(InternalName) get_morph(InternalName *data_type, const string &slider);
private:
@ -91,6 +93,8 @@ private:
static PT(InternalName) _texcoord;
static PT(InternalName) _color;
static PT(InternalName) _transform_blend;
static PT(InternalName) _transform_weight;
static PT(InternalName) _transform_index;
public:
// Datagram stuff

View File

@ -19,7 +19,7 @@
////////////////////////////////////////////////////////////////////
// Function: qpGeomMunger::is_registered
// Access: Published
// Access: Public
// Description: Returns true if this munger has been registered,
// false if it has not. It may not be used for a Geom
// until it has been registered, but once registered, it
@ -32,7 +32,7 @@ is_registered() const {
////////////////////////////////////////////////////////////////////
// Function: qpGeomMunger::register_munger
// Access: Published, Static
// Access: Public, Static
// Description: Adds the indicated munger to the registry, if there
// is not an equivalent munger already there; in either
// case, returns the pointer to the equivalent munger
@ -100,13 +100,19 @@ geom_compare_to(const qpGeomMunger &other) const {
// Access: Public
// Description: Given a source GeomVertexFormat, converts it if
// necessary to the appropriate format for rendering.
//
// If the GeomVertexAnimationSpec so indicates, then the
// format will be chosen to convert CPU-based animation
// tables to HW-based animation tables, reserving space
// for the specified number of transforms per vertex.
////////////////////////////////////////////////////////////////////
INLINE CPT(qpGeomVertexFormat) qpGeomMunger::
munge_format(const qpGeomVertexFormat *format) const {
munge_format(const qpGeomVertexFormat *format,
const qpGeomVertexAnimationSpec &animation) const {
// We cast away the const pointer, because do_munge_format() needs
// to update caches and stuff, but we trust it not to change any
// user-definable parameters.
return ((qpGeomMunger *)this)->do_munge_format(format);
return ((qpGeomMunger *)this)->do_munge_format(format, animation);
}
////////////////////////////////////////////////////////////////////
@ -123,6 +129,22 @@ munge_data(const qpGeomVertexData *data) const {
return ((qpGeomMunger *)this)->munge_data_impl(data);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomMunger::operator new
// Access: Public
// Description: This implementation of operator new isn't really
// supposed to be called, but it's provided in case
// someone screws up and doesn't define a more
// appropriate operator new (that passes up a valid
// _deleted_chain) for a derived class. Having this
// operator new that passes NULL for _deleted_chain will
// at least allow us to detect the error.
////////////////////////////////////////////////////////////////////
INLINE void *qpGeomMunger::
operator new(size_t size) {
return do_operator_new(size, NULL);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomMunger::operator delete
// Access: Public
@ -133,7 +155,14 @@ munge_data(const qpGeomVertexData *data) const {
INLINE void qpGeomMunger::
operator delete(void *ptr) {
qpGeomMunger *obj = (qpGeomMunger *)ptr;
nassertv(obj->_deleted_chain != (qpGeomMunger **)NULL);
#ifndef NDEBUG
nassertd(obj->_deleted_chain != (qpGeomMunger **)NULL) {
delete obj;
return;
}
#endif
nassertv(obj->_next == (qpGeomMunger *)NULL);
obj->_next = (*obj->_deleted_chain);
(*obj->_deleted_chain) = obj;
@ -153,15 +182,24 @@ operator delete(void *ptr) {
// there when it is deleted.
////////////////////////////////////////////////////////////////////
INLINE void *qpGeomMunger::
do_operator_new(size_t size, qpGeomMunger *&deleted_chain) {
do_operator_new(size_t size, qpGeomMunger **deleted_chain) {
qpGeomMunger *obj;
if (deleted_chain != (qpGeomMunger *)NULL) {
obj = deleted_chain;
deleted_chain = deleted_chain->_next;
#ifndef NDEBUG
nassertd(deleted_chain != (qpGeomMunger **)NULL) {
obj = (qpGeomMunger *)::operator new(size);
obj->_deleted_chain = NULL;
return obj;
}
#endif
if ((*deleted_chain) != (qpGeomMunger *)NULL) {
obj = (*deleted_chain);
(*deleted_chain) = (*deleted_chain)->_next;
} else {
obj = (qpGeomMunger *)::operator new(size);
}
obj->_deleted_chain = &deleted_chain;
obj->_deleted_chain = deleted_chain;
return obj;
}

View File

@ -76,36 +76,7 @@ qpGeomMunger::
if (is_registered()) {
get_registry()->unregister_munger(this);
}
nassertv(_formats.empty());
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomMunger::remove_format
// Access: Public
// Description: Removes a prepared GeomVertexFormat from the cache.
////////////////////////////////////////////////////////////////////
void qpGeomMunger::
remove_format(const qpGeomVertexFormat *format) {
// If this assertion is triggered, maybe we accidentally deleted a
// GeomVertexFormat while we were in the process of unregistering,
// causing a recursive re-entry.
nassertv(_is_registered);
Formats::iterator fi;
fi = _formats.find(format);
nassertv(fi != _formats.end());
// We can't save this in a CPT, because it might be the same pointer
// as format, which might be in the middle of its destructor.
// Putting it in a CPT would bump up its reference count again, and
// end up calling the destructor twice.
const qpGeomVertexFormat *derived_format = (*fi).second;
_formats.erase(fi);
// We need to unref the derived format, if we reffed it earlier.
if (derived_format != format) {
unref_delete(derived_format);
}
nassertv(_formats_by_animation.empty());
}
////////////////////////////////////////////////////////////////////
@ -128,43 +99,29 @@ remove_data(const qpGeomVertexData *data) {
// exists just to cast away the const pointer.
////////////////////////////////////////////////////////////////////
CPT(qpGeomVertexFormat) qpGeomMunger::
do_munge_format(const qpGeomVertexFormat *format) {
do_munge_format(const qpGeomVertexFormat *format,
const qpGeomVertexAnimationSpec &animation) {
nassertr(_is_registered, NULL);
nassertr(format->is_registered(), NULL);
Formats &formats = _formats_by_animation[animation];
Formats::iterator fi;
fi = _formats.find(format);
if (fi != _formats.end()) {
fi = formats.find(format);
if (fi != formats.end()) {
// This format was previously munged, so the answer will be the
// same.
return (*fi).second;
}
// We have to munge this format for the first time.
CPT(qpGeomVertexFormat) derived_format = munge_format_impl(format);
CPT(qpGeomVertexFormat) derived_format = munge_format_impl(format, animation);
nassertr(derived_format->is_registered(), NULL);
// Store the answer in the map, so we can quickly get it next time.
bool inserted = _formats.insert(Formats::value_type(format, derived_format)).second;
bool inserted = formats.insert(Formats::value_type(format, derived_format)).second;
nassertr(inserted, NULL);
// Tell the source format that we have its pointer.
{
qpGeomVertexFormat *f = (qpGeomVertexFormat *)format;
MutexHolder holder(f->_cache_lock);
nassertr(f->is_registered(), NULL);
inserted = f->_mungers.insert(this).second;
nassertr(inserted, NULL);
}
// We also want to keep a reference count on the derived format, but
// only if it is actually a different pointer from the original
// format--otherwise it would cause a self-referential reference
// count.
if (derived_format != format) {
derived_format->ref();
}
return derived_format;
}
@ -175,7 +132,7 @@ do_munge_format(const qpGeomVertexFormat *format) {
// necessary to the appropriate format for rendering.
////////////////////////////////////////////////////////////////////
CPT(qpGeomVertexFormat) qpGeomMunger::
munge_format_impl(const qpGeomVertexFormat *orig) {
munge_format_impl(const qpGeomVertexFormat *orig, const qpGeomVertexAnimationSpec &) {
return orig;
}
@ -190,7 +147,8 @@ munge_data_impl(const qpGeomVertexData *data) {
nassertr(_is_registered, NULL);
CPT(qpGeomVertexFormat) orig_format = data->get_format();
CPT(qpGeomVertexFormat) new_format = munge_format(orig_format);
CPT(qpGeomVertexFormat) new_format =
munge_format(orig_format, orig_format->get_animation());
if (new_format == orig_format) {
// Trivial case.
@ -208,7 +166,7 @@ munge_data_impl(const qpGeomVertexData *data) {
void qpGeomMunger::
munge_geom_impl(CPT(qpGeom) &, CPT(qpGeomVertexData) &) {
// The default implementation does nothing (the work has already
// been done in munge_format_impl).
// been done in munge_format_impl() and munge_data_impl()).
}
////////////////////////////////////////////////////////////////////
@ -261,7 +219,7 @@ do_register() {
<< "GeomMunger::do_register(): " << (void *)this << "\n";
}
nassertv(!_is_registered);
nassertv(_formats.empty());
nassertv(_formats_by_animation.empty());
// Tell the cache manager to hang on to this new GeomMunger, so we
// don't waste our time re-registering the same GeomMunger over and
@ -288,22 +246,7 @@ do_unregister() {
_is_registered = false;
// Unregistering means we should blow away the cache.
Formats::iterator fi;
for (fi = _formats.begin(); fi != _formats.end(); ++fi) {
qpGeomVertexFormat *format = (qpGeomVertexFormat *)(*fi).first;
CPT(qpGeomVertexFormat) derived_format = (*fi).second;
{
MutexHolder holder(format->_cache_lock);
size_t num_erased = format->_mungers.erase(this);
nassertv(num_erased == 1);
}
if (derived_format != format) {
derived_format->unref();
}
}
_formats.clear();
_formats_by_animation.clear();
}
////////////////////////////////////////////////////////////////////

View File

@ -21,6 +21,7 @@
#include "pandabase.h"
#include "typedReferenceCount.h"
#include "qpgeomVertexAnimationSpec.h"
#include "qpgeomVertexFormat.h"
#include "qpgeomVertexData.h"
#include "qpgeomCacheEntry.h"
@ -67,8 +68,8 @@ public:
INLINE bool is_registered() const;
INLINE static CPT(qpGeomMunger) register_munger(qpGeomMunger *munger);
INLINE CPT(qpGeomVertexFormat) munge_format(const qpGeomVertexFormat *format) const;
void remove_format(const qpGeomVertexFormat *format);
INLINE CPT(qpGeomVertexFormat) munge_format(const qpGeomVertexFormat *format,
const qpGeomVertexAnimationSpec &animation) const;
INLINE CPT(qpGeomVertexData) munge_data(const qpGeomVertexData *data) const;
void remove_data(const qpGeomVertexData *data);
@ -80,9 +81,11 @@ public:
INLINE int geom_compare_to(const qpGeomMunger &other) const;
protected:
CPT(qpGeomVertexFormat) do_munge_format(const qpGeomVertexFormat *format);
CPT(qpGeomVertexFormat) do_munge_format(const qpGeomVertexFormat *format,
const qpGeomVertexAnimationSpec &animation);
virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig);
virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig,
const qpGeomVertexAnimationSpec &animation);
virtual CPT(qpGeomVertexData) munge_data_impl(const qpGeomVertexData *data);
virtual void munge_geom_impl(CPT(qpGeom) &geom, CPT(qpGeomVertexData) &data);
virtual int compare_to_impl(const qpGeomMunger *other) const;
@ -93,10 +96,11 @@ public:
// and delete using their own deleted_chain. This is the base class
// implementation, which requires a pointer to deleted_chain be
// stored on each instance.
INLINE void *operator new(size_t size);
INLINE void operator delete(void *ptr);
protected:
INLINE static void *do_operator_new(size_t size, qpGeomMunger *&_deleted_chain);
INLINE static void *do_operator_new(size_t size, qpGeomMunger **_deleted_chain);
private:
qpGeomMunger **_deleted_chain;
@ -120,8 +124,9 @@ private:
PT(qpGeomMunger) _munger;
};
typedef pmap<const qpGeomVertexFormat *, const qpGeomVertexFormat *> Formats;
Formats _formats;
typedef pmap<CPT(qpGeomVertexFormat), CPT(qpGeomVertexFormat) > Formats;
typedef pmap<qpGeomVertexAnimationSpec, Formats> FormatsByAnimation;
FormatsByAnimation _formats_by_animation;
bool _is_registered;
typedef pset<qpGeomMunger *, IndirectCompareTo<qpGeomMunger> > Mungers;

View File

@ -0,0 +1,198 @@
// Filename: qpgeomVertexAnimationSpec.I
// Created by: drose (29Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpGeomVertexAnimationSpec::
qpGeomVertexAnimationSpec() :
_animation_type(AT_none),
_num_transforms(0),
_indexed_transforms(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::Copy Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE qpGeomVertexAnimationSpec::
qpGeomVertexAnimationSpec(const qpGeomVertexAnimationSpec &other) :
_animation_type(other._animation_type),
_num_transforms(other._num_transforms),
_indexed_transforms(other._indexed_transforms)
{
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::Copy Assignment Operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexAnimationSpec::
operator = (const qpGeomVertexAnimationSpec &other) {
_animation_type = other._animation_type;
_num_transforms = other._num_transforms;
_indexed_transforms = other._indexed_transforms;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::get_animation_type
// Access: Published
// Description: Returns the type of animation represented by this
// spec.
////////////////////////////////////////////////////////////////////
INLINE qpGeomVertexAnimationSpec::AnimationType qpGeomVertexAnimationSpec::
get_animation_type() const {
return _animation_type;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::get_num_transforms
// Access: Published
// Description: This is only meaningful for animation_type
// AT_hardware. It specifies the maximum number of
// transforms that might be simultaneously applied to
// any one vertex by the data in this format.
////////////////////////////////////////////////////////////////////
INLINE int qpGeomVertexAnimationSpec::
get_num_transforms() const {
return _num_transforms;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::get_indexed_transforms
// Access: Published
// Description: This is only meaningful for animation_type
// AT_hardware. If true, it indicates that the format
// uses indexed animation palettes. It is false if each
// vertex will reference the first _num_transforms
// palette entries only.
////////////////////////////////////////////////////////////////////
INLINE bool qpGeomVertexAnimationSpec::
get_indexed_transforms() const {
return _indexed_transforms;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::set_none
// Access: Published
// Description: Specifies that no vertex animation is represented by
// this spec.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexAnimationSpec::
set_none() {
_animation_type = AT_none;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::set_panda
// Access: Published
// Description: Specifies that vertex animation is to be performed by
// Panda. This is the most general setting and can
// handle any kind of vertex animation represented.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexAnimationSpec::
set_panda() {
_animation_type = AT_panda;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::set_hardware
// Access: Published
// Description: Specifies that vertex animation is to be performed by
// the graphics hardware (or at least by the graphics
// backend API, which is actually still free to animate
// the vertices on the CPU).
//
// This is only legal if the graphics hardware can
// support the specified limits on number of transforms
// and/or indexed transforms. Also, no current graphics
// API's support morphing.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexAnimationSpec::
set_hardware(int num_transforms, bool indexed_transforms) {
_animation_type = AT_hardware;
_num_transforms = num_transforms;
_indexed_transforms = indexed_transforms;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::operator <
// Access: Public
// Description: Provides an arbitrary ordering between different
// animation specs.
////////////////////////////////////////////////////////////////////
INLINE bool qpGeomVertexAnimationSpec::
operator < (const qpGeomVertexAnimationSpec &other) const {
return (compare_to(other) < 0);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::operator ==
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool qpGeomVertexAnimationSpec::
operator == (const qpGeomVertexAnimationSpec &other) const {
return (compare_to(other) == 0);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::operator !=
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool qpGeomVertexAnimationSpec::
operator != (const qpGeomVertexAnimationSpec &other) const {
return (compare_to(other) != 0);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::compare_to
// Access: Public
// Description: Provides an arbitrary ordering between different
// animation specs.
////////////////////////////////////////////////////////////////////
INLINE int qpGeomVertexAnimationSpec::
compare_to(const qpGeomVertexAnimationSpec &other) const {
if (_animation_type != other._animation_type) {
return (int)_animation_type - (int)other._animation_type;
}
if (_animation_type == AT_hardware) {
if (_num_transforms != other._num_transforms) {
return _num_transforms - other._num_transforms;
}
if (_indexed_transforms != other._indexed_transforms) {
return (int)_indexed_transforms - (int)other._indexed_transforms;
}
}
return 0;
}
INLINE ostream &
operator << (ostream &out, const qpGeomVertexAnimationSpec &animation) {
animation.output(out);
return out;
}

View File

@ -0,0 +1,42 @@
// Filename: qpgeomVertexAnimationSpec.cxx
// Created by: drose (29Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "qpgeomVertexAnimationSpec.h"
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexAnimationSpec::output
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void qpGeomVertexAnimationSpec::
output(ostream &out) const {
switch (_animation_type) {
case AT_none:
out << "none";
break;
case AT_panda:
out << "panda";
break;
case AT_hardware:
out << "hardware(" << _num_transforms << ", "
<< _indexed_transforms << ")";
break;
}
}

View File

@ -0,0 +1,83 @@
// Filename: qpgeomVertexAnimationSpec.h
// Created by: drose (29Mar05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef qpGEOMVERTEXANIMATIONSPEC_H
#define qpGEOMVERTEXANIMATIONSPEC_H
#include "pandabase.h"
////////////////////////////////////////////////////////////////////
// Class : qpGeomVertexAnimationSpec
// Description : This object describes how the vertex animation, if
// any, represented in a GeomVertexData is encoded.
//
// Vertex animation includes soft-skinned skeleton
// animation and morphs (blend shapes), and might be
// performed on the CPU by Panda, or passed down to the
// graphics backed to be performed on the hardware
// (depending on the hardware's advertised
// capabilities).
//
// Changing this setting doesn't by itself change the
// way the animation is actually performed; this just
// specifies how the vertices are set up to be animated.
//
// This is part of the experimental Geom rewrite.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA qpGeomVertexAnimationSpec {
PUBLISHED:
INLINE qpGeomVertexAnimationSpec();
INLINE qpGeomVertexAnimationSpec(const qpGeomVertexAnimationSpec &other);
INLINE void operator = (const qpGeomVertexAnimationSpec &other);
enum AnimationType {
AT_none, // No vertex animation.
AT_panda, // Vertex animation calculated on the CPU by Panda.
AT_hardware, // Hardware-accelerated animation on the graphics card.
};
INLINE AnimationType get_animation_type() const;
INLINE int get_num_transforms() const;
INLINE bool get_indexed_transforms() const;
INLINE void set_none();
INLINE void set_panda();
INLINE void set_hardware(int num_transforms, bool indexed_transforms);
void output(ostream &out) const;
public:
INLINE bool operator < (const qpGeomVertexAnimationSpec &other) const;
INLINE bool operator == (const qpGeomVertexAnimationSpec &other) const;
INLINE bool operator != (const qpGeomVertexAnimationSpec &other) const;
INLINE int compare_to(const qpGeomVertexAnimationSpec &other) const;
private:
AnimationType _animation_type;
int _num_transforms;
bool _indexed_transforms;
};
INLINE ostream &
operator << (ostream &out, const qpGeomVertexAnimationSpec &animation);
#include "qpgeomVertexAnimationSpec.I"
#endif

View File

@ -118,6 +118,40 @@ get_array(int i) const {
return cdata->_arrays[i];
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexData::get_transform_palette
// Access: Published
// Description: Returns a const pointer to the TransformPalette
// assigned to this data. Vertices within the table
// will index into this palette to indicate their
// dynamic skinning information; this table is used when
// the vertex animation is to be performed by the
// graphics hardware (but also see
// get_transform_blend_palette()).
//
// This will return NULL if the vertex data does not
// have a TransformPalette assigned (which implies the
// vertices will not be animated by the graphics
// hardware).
////////////////////////////////////////////////////////////////////
INLINE const TransformPalette *qpGeomVertexData::
get_transform_palette() const {
CDReader cdata(_cycler);
return cdata->_transform_palette;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexData::clear_transform_palette
// Access: Published
// Description: Sets the TransformPalette pointer to NULL,
// removing the palette from the vertex data. This
// disables hardware-driven vertex animation.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexData::
clear_transform_palette() {
set_transform_palette(NULL);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexData::get_transform_blend_palette
// Access: Published
@ -288,6 +322,24 @@ unpack_8888_d(PN_uint32 data) {
return data & 0xff;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexData::add_transform
// Access: Private, Static
// Description: Adds the indicated transform to the palette, if it is
// not already there, and returns its index number.
////////////////////////////////////////////////////////////////////
INLINE int qpGeomVertexData::
add_transform(TransformPalette *palette, const VertexTransform *transform,
TransformMap &already_added) {
pair<TransformMap::iterator, bool> result = already_added.insert(TransformMap::value_type(transform, palette->get_num_transforms()));
if (result.second) {
palette->add_transform(transform);
}
return (*(result.first)).second;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexData::CData::Constructor
// Access: Public

View File

@ -201,6 +201,47 @@ set_array(int i, const qpGeomVertexArrayData *array) {
cdata->_animated_vertices_modified = UpdateSeq();
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexData::modify_transform_palette
// Access: Published
// Description: Returns a modifiable pointer to the current
// TransformPalette on this vertex data, if any, or
// NULL if there is not a TransformPalette. See
// get_transform_palette().
////////////////////////////////////////////////////////////////////
TransformPalette *qpGeomVertexData::
modify_transform_palette() {
// Perform copy-on-write: if the reference count on the palette is
// greater than 1, assume some other GeomVertexData has the same
// pointer, so make a copy of it first.
CDWriter cdata(_cycler);
if (cdata->_transform_palette->get_ref_count() > 1) {
cdata->_transform_palette = new TransformPalette(*cdata->_transform_palette);
}
cdata->_modified = qpGeom::get_next_modified();
cdata->_animated_vertices_modified = UpdateSeq();
return cdata->_transform_palette;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexData::set_transform_palette
// Access: Published
// Description: Replaces the TransformPalette on this vertex
// data with the indicated palette. The length of this
// palette should be consistent with the maximum palette
// index assigned to the vertices under the
// "transform_index" name.
////////////////////////////////////////////////////////////////////
void qpGeomVertexData::
set_transform_palette(const TransformPalette *palette) {
CDWriter cdata(_cycler);
cdata->_transform_palette = (TransformPalette *)palette;
cdata->_modified = qpGeom::get_next_modified();
cdata->_animated_vertices_modified = UpdateSeq();
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexData::modify_transform_blend_palette
// Access: Published
@ -442,6 +483,65 @@ copy_from(const qpGeomVertexData &source, bool keep_data_objects) {
}
}
}
// Also convert the animation tables as necessary.
const qpGeomVertexAnimationSpec &source_animation = source_format->get_animation();
const qpGeomVertexAnimationSpec &dest_animation = dest_format->get_animation();
if (source_animation != dest_animation) {
if (dest_animation.get_animation_type() == qpGeomVertexAnimationSpec::AT_hardware) {
// Convert Panda-style animation tables to hardware-style
// animation tables.
CPT(TransformBlendPalette) blend_palette = source.get_transform_blend_palette();
if (blend_palette != (TransformBlendPalette *)NULL) {
PT(TransformPalette) transform_palette = new TransformPalette;
TransformMap already_added;
if (dest_animation.get_indexed_transforms()) {
// Build an indexed transform array. This is easier; this
// means we can put the blends in any order.
qpGeomVertexWriter weight(this, InternalName::get_transform_weight());
qpGeomVertexWriter index(this, InternalName::get_transform_index());
qpGeomVertexReader from(&source, InternalName::get_transform_blend());
while (!from.is_at_end()) {
const TransformBlend &blend = blend_palette->get_blend(from.get_data1i());
LVecBase4f weights = LVecBase4f::zero();
int indices[4] = {0, 0, 0, 0};
nassertv(blend.get_num_transforms() <= 4);
for (int i = 0; i < blend.get_num_transforms(); i++) {
weights[i] = blend.get_weight(i);
indices[i] = add_transform(transform_palette, blend.get_transform(i),
already_added);
}
weight.set_data4f(weights);
index.set_data4i(indices[3], indices[2], indices[1], indices[0]);
}
} else {
// Build a nonindexed transform array. This means we have to
// use the same n transforms, in the same order, for each vertex.
qpGeomVertexWriter weight(this, InternalName::get_transform_weight());
qpGeomVertexReader from(&source, InternalName::get_transform_blend());
while (!from.is_at_end()) {
const TransformBlend &blend = blend_palette->get_blend(from.get_data1i());
LVecBase4f weights = LVecBase4f::zero();
for (int i = 0; i < blend.get_num_transforms(); i++) {
int index = add_transform(transform_palette, blend.get_transform(i),
already_added);
nassertv(index <= 4);
weights[index] = blend.get_weight(i);
}
weight.set_data4f(weights);
}
}
clear_transform_blend_palette();
set_transform_palette(transform_palette);
}
}
}
}
////////////////////////////////////////////////////////////////////
@ -725,6 +825,11 @@ CPT(qpGeomVertexData) qpGeomVertexData::
do_animate_vertices(bool from_app) const {
CDReader cdata(_cycler);
if (_format->get_animation().get_animation_type() !=
qpGeomVertexAnimationSpec::AT_panda) {
return this;
}
UpdateSeq modified;
if (cdata->_transform_blend_palette != (TransformBlendPalette *)NULL) {
if (cdata->_slider_table != (SliderTable *)NULL) {

View File

@ -25,6 +25,7 @@
#include "qpgeomVertexDataType.h"
#include "qpgeomVertexArrayData.h"
#include "qpgeomUsageHint.h"
#include "transformPalette.h"
#include "transformBlendPalette.h"
#include "sliderTable.h"
#include "internalName.h"
@ -87,6 +88,11 @@ PUBLISHED:
qpGeomVertexArrayData *modify_array(int i);
void set_array(int i, const qpGeomVertexArrayData *array);
INLINE const TransformPalette *get_transform_palette() const;
TransformPalette *modify_transform_palette();
void set_transform_palette(const TransformPalette *palette);
INLINE void clear_transform_palette();
INLINE const TransformBlendPalette *get_transform_blend_palette() const;
TransformBlendPalette *modify_transform_blend_palette();
void set_transform_blend_palette(const TransformBlendPalette *palette);
@ -154,6 +160,11 @@ private:
uint8_rgba_to_packed_argb(unsigned char *to, int to_stride,
const unsigned char *from, int from_stride,
int num_records);
typedef pmap<const VertexTransform *, int> TransformMap;
INLINE static int
add_transform(TransformPalette *palette, const VertexTransform *transform,
TransformMap &already_added);
private:
string _name;
@ -173,6 +184,7 @@ private:
virtual void fillin(DatagramIterator &scan, BamReader *manager);
Arrays _arrays;
PT(TransformPalette) _transform_palette;
PT(TransformBlendPalette) _transform_blend_palette;
PT(SliderTable) _slider_table;
PT(qpGeomVertexData) _animated_vertices;

View File

@ -67,6 +67,34 @@ register_format(qpGeomVertexArrayFormat *format) {
return get_registry()->register_format(format);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexFormat::get_animation
// Access: Published
// Description: Returns the GeomVertexAnimationSpec that indicates
// how this format's vertices are set up for animation.
////////////////////////////////////////////////////////////////////
INLINE const qpGeomVertexAnimationSpec &qpGeomVertexFormat::
get_animation() const {
return _animation;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexFormat::set_animation
// Access: Published
// Description: Resets the GeomVertexAnimationSpec that indicates
// how this format's vertices are set up for animation.
// You should also, of course, change the columns in the
// tables accordingly.
//
// This may not be called once the format has been
// registered.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexFormat::
set_animation(const qpGeomVertexAnimationSpec &animation) {
nassertv(!_is_registered);
_animation = animation;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexFormat::get_num_arrays
// Access: Published

View File

@ -58,6 +58,7 @@ qpGeomVertexFormat(qpGeomVertexArrayFormat *array_format) :
qpGeomVertexFormat::
qpGeomVertexFormat(const qpGeomVertexFormat &copy) :
_is_registered(false),
_animation(copy._animation),
_arrays(copy._arrays)
{
}
@ -71,6 +72,7 @@ void qpGeomVertexFormat::
operator = (const qpGeomVertexFormat &copy) {
nassertv(!_is_registered);
_animation = copy._animation;
_arrays = copy._arrays;
}
@ -84,8 +86,6 @@ qpGeomVertexFormat::
if (is_registered()) {
get_registry()->unregister_format(this);
}
nassertv(_mungers.empty());
}
////////////////////////////////////////////////////////////////////
@ -379,6 +379,10 @@ output(ostream &out) const {
++ai;
}
}
if (_animation.get_animation_type() != qpGeomVertexAnimationSpec::AT_none) {
out << ", anim " << _animation;
}
}
////////////////////////////////////////////////////////////////////
@ -446,6 +450,11 @@ get_array_info(const InternalName *name, int &array_index,
////////////////////////////////////////////////////////////////////
int qpGeomVertexFormat::
compare_to(const qpGeomVertexFormat &other) const {
int compare = _animation.compare_to(other._animation);
if (compare != 0) {
return compare;
}
if (_arrays.size() != other._arrays.size()) {
return (int)_arrays.size() - (int)other._arrays.size();
}
@ -481,7 +490,6 @@ void qpGeomVertexFormat::
do_register() {
nassertv(!_is_registered);
nassertv(_data_types_by_name.empty());
nassertv(_mungers.empty());
for (int array = 0; array < (int)_arrays.size(); ++array) {
const qpGeomVertexArrayFormat *array_format = _arrays[array];
@ -556,13 +564,6 @@ do_unregister() {
_is_registered = false;
_data_types_by_name.clear();
MutexHolder holder(_cache_lock);
Mungers::iterator mi;
for (mi = _mungers.begin(); mi != _mungers.end(); ++mi) {
(*mi)->remove_format(this);
}
_mungers.clear();
}
////////////////////////////////////////////////////////////////////

View File

@ -21,6 +21,7 @@
#include "pandabase.h"
#include "typedWritableReferenceCount.h"
#include "qpgeomVertexAnimationSpec.h"
#include "qpgeomVertexArrayFormat.h"
#include "internalName.h"
#include "luse.h"
@ -66,6 +67,9 @@ PUBLISHED:
INLINE static CPT(qpGeomVertexFormat) register_format(qpGeomVertexFormat *format);
INLINE static CPT(qpGeomVertexFormat) register_format(qpGeomVertexArrayFormat *format);
INLINE const qpGeomVertexAnimationSpec &get_animation() const;
INLINE void set_animation(const qpGeomVertexAnimationSpec &animation);
INLINE int get_num_arrays() const;
INLINE const qpGeomVertexArrayFormat *get_array(int array) const;
qpGeomVertexArrayFormat *modify_array(int array);
@ -140,6 +144,8 @@ private:
bool _is_registered;
qpGeomVertexAnimationSpec _animation;
typedef pvector< PT(qpGeomVertexArrayFormat) > Arrays;
Arrays _arrays;
@ -161,12 +167,6 @@ private:
typedef pvector<MorphRecord> Morphs;
Morphs _morphs;
// This set keeps track of things that need to be told when we
// destruct, and it is protected by the mutex.
Mutex _cache_lock;
typedef pset<qpGeomMunger *> Mungers;
Mungers _mungers;
// This is the global registry of all currently-in-use formats.
typedef pset<qpGeomVertexFormat *, IndirectCompareTo<qpGeomVertexFormat> > Formats;
class EXPCL_PANDA Registry {

View File

@ -320,6 +320,45 @@ get_data1i() {
return _reader->get_data1i(inc_pointer());
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexReader::get_data2i
// Access: Published
// Description: Returns the data associated with the read vertex,
// expressed as a 2-component value, and advances the
// read vertex.
////////////////////////////////////////////////////////////////////
INLINE const int *qpGeomVertexReader::
get_data2i() {
nassertr(_data_type != (qpGeomVertexDataType *)NULL, 0);
return _reader->get_data2i(inc_pointer());
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexReader::get_data3i
// Access: Published
// Description: Returns the data associated with the read vertex,
// expressed as a 3-component value, and advances the
// read vertex.
////////////////////////////////////////////////////////////////////
INLINE const int *qpGeomVertexReader::
get_data3i() {
nassertr(_data_type != (qpGeomVertexDataType *)NULL, 0);
return _reader->get_data3i(inc_pointer());
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexReader::get_data4i
// Access: Published
// Description: Returns the data associated with the read vertex,
// expressed as a 4-component value, and advances the
// read vertex.
////////////////////////////////////////////////////////////////////
INLINE const int *qpGeomVertexReader::
get_data4i() {
nassertr(_data_type != (qpGeomVertexDataType *)NULL, 0);
return _reader->get_data4i(inc_pointer());
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexReader::set_pointer
// Access: Private

View File

@ -423,6 +423,215 @@ get_data1i(const unsigned char *pointer) {
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexReader::Reader::get_data2i
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
const int *qpGeomVertexReader::Reader::
get_data2i(const unsigned char *pointer) {
switch (_data_type->get_num_values()) {
case 1:
_i[0] = get_data1i(pointer);
_i[1] = 0;
return _i;
default:
switch (_data_type->get_numeric_type()) {
case qpGeomVertexDataType::NT_uint8:
_i[0] = pointer[0];
_i[1] = pointer[1];
return _i;
case qpGeomVertexDataType::NT_uint16:
{
const PN_uint16 *pi = (const PN_uint16 *)pointer;
_i[0] = pi[0];
_i[1] = pi[1];
}
return _i;
case qpGeomVertexDataType::NT_packed_8888:
{
PN_uint32 dword = *(const PN_uint32 *)pointer;
if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) {
_i[0] = qpGeomVertexData::unpack_8888_b(dword);
_i[1] = qpGeomVertexData::unpack_8888_c(dword);
} else {
_i[0] = qpGeomVertexData::unpack_8888_a(dword);
_i[1] = qpGeomVertexData::unpack_8888_b(dword);
}
}
return _i;
case qpGeomVertexDataType::NT_float32:
{
const PN_float32 *pi = (const PN_float32 *)pointer;
_i[0] = (int)pi[0];
_i[1] = (int)pi[1];
}
return _i;
}
}
return _i;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexReader::Reader::get_data3i
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
const int *qpGeomVertexReader::Reader::
get_data3i(const unsigned char *pointer) {
switch (_data_type->get_num_values()) {
case 1:
_i[0] = get_data1i(pointer);
_i[1] = 0;
_i[2] = 0;
return _i;
case 2:
{
const int *i = get_data2i(pointer);
_i[0] = i[0];
_i[1] = i[1];
_i[2] = 0;
}
return _i;
default:
switch (_data_type->get_numeric_type()) {
case qpGeomVertexDataType::NT_uint8:
_i[0] = pointer[0];
_i[1] = pointer[1];
_i[2] = pointer[2];
return _i;
case qpGeomVertexDataType::NT_uint16:
{
const PN_uint16 *pi = (const PN_uint16 *)pointer;
_i[0] = pi[0];
_i[1] = pi[1];
_i[2] = pi[2];
}
return _i;
case qpGeomVertexDataType::NT_packed_8888:
{
PN_uint32 dword = *(const PN_uint32 *)pointer;
if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) {
_i[0] = qpGeomVertexData::unpack_8888_b(dword);
_i[1] = qpGeomVertexData::unpack_8888_c(dword);
_i[2] = qpGeomVertexData::unpack_8888_d(dword);
} else {
_i[0] = qpGeomVertexData::unpack_8888_a(dword);
_i[1] = qpGeomVertexData::unpack_8888_b(dword);
_i[2] = qpGeomVertexData::unpack_8888_c(dword);
}
}
return _i;
case qpGeomVertexDataType::NT_float32:
{
const PN_float32 *pi = (const PN_float32 *)pointer;
_i[0] = (int)pi[0];
_i[1] = (int)pi[1];
_i[2] = (int)pi[2];
}
return _i;
}
}
return _i;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexReader::Reader::get_data4i
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
const int *qpGeomVertexReader::Reader::
get_data4i(const unsigned char *pointer) {
switch (_data_type->get_num_values()) {
case 1:
_i[0] = get_data1i(pointer);
_i[1] = 0;
_i[2] = 0;
_i[3] = 0;
return _i;
case 2:
{
const int *i = get_data2i(pointer);
_i[0] = i[0];
_i[1] = i[1];
_i[2] = 0;
_i[3] = 0;
}
return _i;
case 3:
{
const int *i = get_data3i(pointer);
_i[0] = i[0];
_i[1] = i[1];
_i[2] = i[2];
_i[3] = 0;
}
return _i;
default:
switch (_data_type->get_numeric_type()) {
case qpGeomVertexDataType::NT_uint8:
_i[0] = pointer[0];
_i[1] = pointer[1];
_i[2] = pointer[2];
_i[3] = pointer[3];
return _i;
case qpGeomVertexDataType::NT_uint16:
{
const PN_uint16 *pi = (const PN_uint16 *)pointer;
_i[0] = pi[0];
_i[1] = pi[1];
_i[2] = pi[2];
_i[3] = pi[3];
}
return _i;
case qpGeomVertexDataType::NT_packed_8888:
{
PN_uint32 dword = *(const PN_uint32 *)pointer;
if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) {
_i[0] = qpGeomVertexData::unpack_8888_b(dword);
_i[1] = qpGeomVertexData::unpack_8888_c(dword);
_i[2] = qpGeomVertexData::unpack_8888_d(dword);
_i[3] = qpGeomVertexData::unpack_8888_a(dword);
} else {
_i[0] = qpGeomVertexData::unpack_8888_a(dword);
_i[1] = qpGeomVertexData::unpack_8888_b(dword);
_i[2] = qpGeomVertexData::unpack_8888_c(dword);
_i[3] = qpGeomVertexData::unpack_8888_d(dword);
}
}
return _i;
case qpGeomVertexDataType::NT_float32:
{
const PN_float32 *pi = (const PN_float32 *)pointer;
_i[0] = (int)pi[0];
_i[1] = (int)pi[1];
_i[2] = (int)pi[2];
_i[3] = (int)pi[3];
}
return _i;
}
}
return _i;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexReader::Reader_point::get_data1f
// Access: Public, Virtual

View File

@ -91,6 +91,9 @@ PUBLISHED:
INLINE const LVecBase4f &get_data4f();
INLINE int get_data1i();
INLINE const int *get_data2i();
INLINE const int *get_data3i();
INLINE const int *get_data4i();
private:
class Reader;
@ -124,6 +127,9 @@ private:
virtual const LVecBase3f &get_data3f(const unsigned char *pointer);
virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
virtual int get_data1i(const unsigned char *pointer);
virtual const int *get_data2i(const unsigned char *pointer);
virtual const int *get_data3i(const unsigned char *pointer);
virtual const int *get_data4i(const unsigned char *pointer);
INLINE float maybe_scale_color(unsigned int value);
INLINE void maybe_scale_color(unsigned int a, unsigned int b);
@ -136,6 +142,7 @@ private:
LVecBase2f _v2;
LVecBase3f _v3;
LVecBase4f _v4;
int _i[4];
};
// This is a specialization on the generic Reader that handles

View File

@ -372,6 +372,93 @@ set_data1i(int data) {
_writer->set_data1i(inc_pointer(), data);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::set_data2i
// Access: Published
// Description: Sets the write vertex to a particular 2-component
// value, and advances the write vertex.
//
// It is an error for the write vertex to advance past
// the end of data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
set_data2i(int a, int b) {
nassertv(_data_type != (qpGeomVertexDataType *)NULL);
_writer->set_data2i(inc_pointer(), a, b);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::set_data2i
// Access: Published
// Description: Sets the write vertex to a particular 2-component
// value, and advances the write vertex.
//
// It is an error for the write vertex to advance past
// the end of data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
set_data2i(const int data[2]) {
set_data2i(data[0], data[1]);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::set_data3i
// Access: Published
// Description: Sets the write vertex to a particular 3-component
// value, and advances the write vertex.
//
// It is an error for the write vertex to advance past
// the end of data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
set_data3i(int a, int b, int c) {
nassertv(_data_type != (qpGeomVertexDataType *)NULL);
_writer->set_data3i(inc_pointer(), a, b, c);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::set_data3i
// Access: Published
// Description: Sets the write vertex to a particular 3-component
// value, and advances the write vertex.
//
// It is an error for the write vertex to advance past
// the end of data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
set_data3i(const int data[3]) {
set_data3i(data[0], data[1], data[2]);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::set_data4i
// Access: Published
// Description: Sets the write vertex to a particular 4-component
// value, and advances the write vertex.
//
// It is an error for the write vertex to advance past
// the end of data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
set_data4i(int a, int b, int c, int d) {
nassertv(_data_type != (qpGeomVertexDataType *)NULL);
_writer->set_data4i(inc_pointer(), a, b, c, d);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::set_data4i
// Access: Published
// Description: Sets the write vertex to a particular 4-component
// value, and advances the write vertex.
//
// It is an error for the write vertex to advance past
// the end of data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
set_data4i(const int data[4]) {
set_data4i(data[0], data[1], data[2], data[3]);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::add_data1f
// Access: Published
@ -489,6 +576,93 @@ add_data1i(int data) {
_writer->set_data1i(inc_add_pointer(), data);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::add_data2i
// Access: Published
// Description: Sets the write vertex to a particular 2-component
// value, and advances the write vertex.
//
// If the write vertex advances past the end of data,
// implicitly adds a new vertex to the data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
add_data2i(int a, int b) {
nassertv(_data_type != (qpGeomVertexDataType *)NULL);
_writer->set_data2i(inc_add_pointer(), a, b);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::add_data2i
// Access: Published
// Description: Sets the write vertex to a particular 2-component
// value, and advances the write vertex.
//
// If the write vertex advances past the end of data,
// implicitly adds a new vertex to the data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
add_data2i(const int data[2]) {
add_data2i(data[0], data[1]);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::add_data3i
// Access: Published
// Description: Sets the write vertex to a particular 3-component
// value, and advances the write vertex.
//
// If the write vertex advances past the end of data,
// implicitly adds a new vertex to the data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
add_data3i(int a, int b, int c) {
nassertv(_data_type != (qpGeomVertexDataType *)NULL);
_writer->set_data3i(inc_add_pointer(), a, b, c);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::add_data3i
// Access: Published
// Description: Sets the write vertex to a particular 3-component
// value, and advances the write vertex.
//
// If the write vertex advances past the end of data,
// implicitly adds a new vertex to the data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
add_data3i(const int data[3]) {
add_data3i(data[0], data[1], data[2]);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::add_data4i
// Access: Published
// Description: Sets the write vertex to a particular 4-component
// value, and advances the write vertex.
//
// If the write vertex advances past the end of data,
// implicitly adds a new vertex to the data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
add_data4i(int a, int b, int c, int d) {
nassertv(_data_type != (qpGeomVertexDataType *)NULL);
_writer->set_data4i(inc_add_pointer(), a, b, c, d);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::add_data4i
// Access: Published
// Description: Sets the write vertex to a particular 4-component
// value, and advances the write vertex.
//
// If the write vertex advances past the end of data,
// implicitly adds a new vertex to the data.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomVertexWriter::
add_data4i(const int data[4]) {
add_data4i(data[0], data[1], data[2], data[3]);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::set_pointer
// Access: Private

View File

@ -185,14 +185,7 @@ set_data1f(unsigned char *pointer, float data) {
break;
case qpGeomVertexDataType::NT_packed_8888:
{
maybe_scale_color(data);
if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) {
*(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(0, _a, 0, 0);
} else {
*(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_a, 0, 0, 0);
}
}
nassertv(false);
break;
case qpGeomVertexDataType::NT_float32:
@ -243,14 +236,7 @@ set_data2f(unsigned char *pointer, const LVecBase2f &data) {
break;
case qpGeomVertexDataType::NT_packed_8888:
{
maybe_scale_color(data);
if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) {
*(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(0, _a, _b, 0);
} else {
*(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_a, _b, 0, 0);
}
}
nassertv(false);
break;
case qpGeomVertexDataType::NT_float32:
@ -308,14 +294,7 @@ set_data3f(unsigned char *pointer, const LVecBase3f &data) {
break;
case qpGeomVertexDataType::NT_packed_8888:
{
maybe_scale_color(data);
if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) {
*(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(0, _a, _b, _c);
} else {
*(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_a, _b, _c, 0);
}
}
nassertv(false);
break;
case qpGeomVertexDataType::NT_float32:
@ -406,28 +385,206 @@ set_data4f(unsigned char *pointer, const LVecBase4f &data) {
// Description:
////////////////////////////////////////////////////////////////////
void qpGeomVertexWriter::Writer::
set_data1i(unsigned char *pointer, int data) {
switch (_data_type->get_numeric_type()) {
case qpGeomVertexDataType::NT_uint8:
*pointer = data;
break;
case qpGeomVertexDataType::NT_uint16:
*(PN_uint16 *)pointer = data;
break;
case qpGeomVertexDataType::NT_packed_8888:
{
if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) {
*(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(0, data, 0, 0);
} else {
*(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_a, data, 0, 0);
}
set_data1i(unsigned char *pointer, int a) {
switch (_data_type->get_num_values()) {
case 1:
switch (_data_type->get_numeric_type()) {
case qpGeomVertexDataType::NT_uint8:
*pointer = a;
break;
case qpGeomVertexDataType::NT_uint16:
*(PN_uint16 *)pointer = a;
break;
case qpGeomVertexDataType::NT_packed_8888:
nassertv(false);
break;
case qpGeomVertexDataType::NT_float32:
*(PN_float32 *)pointer = (float)a;
break;
}
break;
case qpGeomVertexDataType::NT_float32:
*(PN_float32 *)pointer = (float)data;
case 2:
set_data2i(pointer, a, 0);
break;
case 3:
set_data3i(pointer, a, 0, 0);
break;
default:
set_data4i(pointer, a, 0, 0, 0);
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::Writer::set_data2i
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void qpGeomVertexWriter::Writer::
set_data2i(unsigned char *pointer, int a, int b) {
switch (_data_type->get_num_values()) {
case 1:
set_data1i(pointer, a);
break;
case 2:
switch (_data_type->get_numeric_type()) {
case qpGeomVertexDataType::NT_uint8:
pointer[0] = a;
pointer[1] = b;
break;
case qpGeomVertexDataType::NT_uint16:
{
PN_uint16 *pi = (PN_uint16 *)pointer;
pi[0] = a;
pi[1] = b;
}
break;
case qpGeomVertexDataType::NT_packed_8888:
nassertv(false);
break;
case qpGeomVertexDataType::NT_float32:
{
PN_float32 *pi = (PN_float32 *)pointer;
pi[0] = a;
pi[1] = b;
}
break;
}
break;
case 3:
set_data3i(pointer, a, b, 0);
break;
default:
set_data4i(pointer, a, b, 0, 0);
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::Writer::set_data3i
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void qpGeomVertexWriter::Writer::
set_data3i(unsigned char *pointer, int a, int b, int c) {
switch (_data_type->get_num_values()) {
case 1:
set_data1i(pointer, a);
break;
case 2:
set_data2i(pointer, a, b);
break;
case 3:
switch (_data_type->get_numeric_type()) {
case qpGeomVertexDataType::NT_uint8:
pointer[0] = a;
pointer[1] = b;
pointer[2] = c;
break;
case qpGeomVertexDataType::NT_uint16:
{
PN_uint16 *pi = (PN_uint16 *)pointer;
pi[0] = a;
pi[1] = b;
pi[2] = c;
}
break;
case qpGeomVertexDataType::NT_packed_8888:
nassertv(false);
break;
case qpGeomVertexDataType::NT_float32:
{
PN_float32 *pi = (PN_float32 *)pointer;
pi[0] = a;
pi[1] = b;
pi[2] = c;
}
break;
}
break;
default:
set_data4i(pointer, a, b, c, 0);
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexWriter::Writer::set_data4i
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void qpGeomVertexWriter::Writer::
set_data4i(unsigned char *pointer, int a, int b, int c, int d) {
switch (_data_type->get_num_values()) {
case 1:
set_data1i(pointer, a);
break;
case 2:
set_data2i(pointer, a, b);
break;
case 3:
set_data3i(pointer, a, b, c);
break;
default:
switch (_data_type->get_numeric_type()) {
case qpGeomVertexDataType::NT_uint8:
pointer[0] = a;
pointer[1] = b;
pointer[2] = c;
pointer[3] = d;
break;
case qpGeomVertexDataType::NT_uint16:
{
PN_uint16 *pi = (PN_uint16 *)pointer;
pi[0] = a;
pi[1] = b;
pi[2] = c;
pi[3] = d;
}
break;
case qpGeomVertexDataType::NT_packed_8888:
{
if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) {
*(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(d, a, b, c);
} else {
*(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(a, b, c, d);
}
}
break;
case qpGeomVertexDataType::NT_float32:
{
PN_float32 *pi = (PN_float32 *)pointer;
pi[0] = a;
pi[1] = b;
pi[2] = c;
pi[3] = d;
}
break;
}
break;
}
}

View File

@ -106,6 +106,12 @@ PUBLISHED:
INLINE void set_data4f(const LVecBase4f &data);
INLINE void set_data1i(int data);
INLINE void set_data2i(int a, int b);
INLINE void set_data2i(const int data[2]);
INLINE void set_data3i(int a, int b, int c);
INLINE void set_data3i(const int data[3]);
INLINE void set_data4i(int a, int b, int c, int d);
INLINE void set_data4i(const int data[4]);
INLINE void add_data1f(float data);
INLINE void add_data2f(float x, float y);
@ -116,6 +122,12 @@ PUBLISHED:
INLINE void add_data4f(const LVecBase4f &data);
INLINE void add_data1i(int data);
INLINE void add_data2i(int a, int b);
INLINE void add_data2i(const int data[2]);
INLINE void add_data3i(int a, int b, int c);
INLINE void add_data3i(const int data[3]);
INLINE void add_data4i(int a, int b, int c, int d);
INLINE void add_data4i(const int data[4]);
private:
class Writer;
@ -150,7 +162,10 @@ private:
virtual void set_data3f(unsigned char *pointer, const LVecBase3f &data);
virtual void set_data4f(unsigned char *pointer, const LVecBase4f &data);
virtual void set_data1i(unsigned char *pointer, int data);
virtual void set_data1i(unsigned char *pointer, int a);
virtual void set_data2i(unsigned char *pointer, int a, int b);
virtual void set_data3i(unsigned char *pointer, int a, int b, int c);
virtual void set_data4i(unsigned char *pointer, int a, int b, int c, int d);
INLINE unsigned int maybe_scale_color(float data);
INLINE void maybe_scale_color(const LVecBase2f &data);

View File

@ -58,6 +58,49 @@ get_modified() const {
}
}
////////////////////////////////////////////////////////////////////
// Function: TransformBlendPalette::get_num_transforms
// Access: Published
// Description: Returns the number of unique VertexTransform objects
// represented in the palette. This will correspond to
// the size of the TransformPalette object that would
// represent the same table. This is also the same
// limit reflected by
// GraphicsStateGuardian::get_max_vertex_transform_indices().
////////////////////////////////////////////////////////////////////
INLINE int TransformBlendPalette::
get_num_transforms() const {
consider_rebuild_index();
return _num_transforms;
}
////////////////////////////////////////////////////////////////////
// Function: TransformBlendPalette::get_max_simultaneous_transforms
// Access: Published
// Description: Returns the maximum number of unique VertexTransform
// objects that are applied to any one vertex
// simultaneously. This is the same limit reflected by
// GraphicsStateGuardian::get_max_vertex_transforms().
////////////////////////////////////////////////////////////////////
INLINE int TransformBlendPalette::
get_max_simultaneous_transforms() const {
consider_rebuild_index();
return _max_simultaneous_transforms;
}
////////////////////////////////////////////////////////////////////
// Function: TransformBlendPalette::consider_rebuild_index
// Access: Private
// Description: Calls rebuild_index() if the index needs to be
// rebuilt.
////////////////////////////////////////////////////////////////////
INLINE void TransformBlendPalette::
consider_rebuild_index() const {
if (_blend_index.empty()) {
((TransformBlendPalette *)this)->rebuild_index();
}
}
////////////////////////////////////////////////////////////////////
// Function: TransformBlendPalette::CData::Constructor
// Access: Public

View File

@ -95,9 +95,7 @@ remove_blend(int n) {
////////////////////////////////////////////////////////////////////
int TransformBlendPalette::
add_blend(const TransformBlend &blend) {
if (_blend_index.empty()) {
rebuild_index();
}
consider_rebuild_index();
BlendIndex::iterator bi;
bi = _blend_index.find(&blend);
@ -148,9 +146,25 @@ void TransformBlendPalette::
rebuild_index() {
_blend_index.clear();
for (int i = 0; i < (int)_blends.size(); i++) {
_blend_index[&_blends[i]] = i;
// We'll also count up these two statistics while we rebuild the
// index.
_num_transforms = 0;
_max_simultaneous_transforms = 0;
pset<const VertexTransform *> transforms;
for (int i = 0; i < (int)_blends.size(); ++i) {
const TransformBlend &blend = _blends[i];
_blend_index[&blend] = i;
for (int ti = 0; ti < blend.get_num_transforms(); ++ti) {
transforms.insert(blend.get_transform(ti));
}
_max_simultaneous_transforms = max(_max_simultaneous_transforms,
blend.get_num_transforms());
}
_num_transforms = transforms.size();
}
////////////////////////////////////////////////////////////////////

View File

@ -64,10 +64,14 @@ PUBLISHED:
void remove_blend(int n);
int add_blend(const TransformBlend &blend);
INLINE int get_num_transforms() const;
INLINE int get_max_simultaneous_transforms() const;
void write(ostream &out, int indent_level) const;
private:
void clear_index();
INLINE void consider_rebuild_index() const;
void rebuild_index();
private:
@ -84,6 +88,8 @@ private:
// invalidating all the pointers into it).
typedef pmap<const TransformBlend *, int, IndirectLess<TransformBlend> > BlendIndex;
BlendIndex _blend_index;
int _num_transforms;
int _max_simultaneous_transforms;
// Even though we don't store the actual blend palette data in a
// CycleData structure, we do need to keep a local cache of the

View File

@ -75,7 +75,7 @@ TransformPalette::
// unregistered palettes.
////////////////////////////////////////////////////////////////////
void TransformPalette::
set_transform(int n, VertexTransform *transform) {
set_transform(int n, const VertexTransform *transform) {
nassertv(!_is_registered);
nassertv(n >= 0 && n < (int)_transforms.size());
_transforms[n] = transform;
@ -102,7 +102,7 @@ remove_transform(int n) {
// unregistered palettes.
////////////////////////////////////////////////////////////////////
int TransformPalette::
add_transform(VertexTransform *transform) {
add_transform(const VertexTransform *transform) {
nassertr(!_is_registered, -1);
int new_index = (int)_transforms.size();
_transforms.push_back(transform);
@ -132,7 +132,8 @@ do_register() {
Transforms::iterator ti;
for (ti = _transforms.begin(); ti != _transforms.end(); ++ti) {
bool inserted = (*ti)->_palettes.insert(this).second;
VertexTransform *transform = (VertexTransform *)(*ti).p();
bool inserted = transform->_palettes.insert(this).second;
nassertv(inserted);
}
_is_registered = true;
@ -150,7 +151,8 @@ do_unregister() {
Transforms::iterator ti;
for (ti = _transforms.begin(); ti != _transforms.end(); ++ti) {
(*ti)->_palettes.erase(this);
VertexTransform *transform = (VertexTransform *)(*ti).p();
transform->_palettes.erase(this);
}
_is_registered = false;
}

View File

@ -58,9 +58,9 @@ PUBLISHED:
INLINE const VertexTransform *get_transform(int n) const;
INLINE UpdateSeq get_modified() const;
void set_transform(int n, VertexTransform *transform);
void set_transform(int n, const VertexTransform *transform);
void remove_transform(int n);
int add_transform(VertexTransform *transform);
int add_transform(const VertexTransform *transform);
void write(ostream &out) const;
@ -72,7 +72,7 @@ private:
private:
bool _is_registered;
typedef pvector< PT(VertexTransform) > Transforms;
typedef pvector< CPT(VertexTransform) > Transforms;
Transforms _transforms;
// This is the data that must be cycled between pipeline stages.

View File

@ -47,6 +47,24 @@ VertexTransform::
nassertv(_palettes.empty());
}
////////////////////////////////////////////////////////////////////
// Function: VertexTransform::mult_matrix
// Access: Published, Virtual
// Description: Premultiplies this transform's matrix with the
// indicated previous matrix, so that the result is the
// net composition of the given transform with this
// transform. The result is stored in the parameter
// "result", which should not be the same matrix as
// previous.
////////////////////////////////////////////////////////////////////
void VertexTransform::
mult_matrix(LMatrix4f &result, const LMatrix4f &previous) const {
nassertv(&result != &previous);
LMatrix4f me;
get_matrix(me);
result.multiply(me, previous);
}
////////////////////////////////////////////////////////////////////
// Function: VertexTransform::accumulate_matrix
// Access: Published, Virtual

View File

@ -48,6 +48,7 @@ PUBLISHED:
virtual ~VertexTransform();
virtual void get_matrix(LMatrix4f &matrix) const=0;
virtual void mult_matrix(LMatrix4f &result, const LMatrix4f &previous) const;
virtual void accumulate_matrix(LMatrix4f &accum, float weight) const;
INLINE UpdateSeq get_modified() const;