support flat-shading properly in new geom
This commit is contained in:
parent
e58313c806
commit
d72e2da5c5
|
|
@ -274,12 +274,12 @@ release_geom(GeomContext *) {
|
|||
// appropriate to this GSG for the indicated state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(qpGeomMunger) GraphicsStateGuardian::
|
||||
get_geom_munger(const RenderState *) {
|
||||
get_geom_munger(const RenderState *state) {
|
||||
// The default implementation returns a munger that does nothing,
|
||||
// but presumably, every kind of GSG needs some special munging
|
||||
// action, so real GSG's will override this to return something more
|
||||
// useful.
|
||||
return qpGeomMunger::register_munger(new qpGeomMunger);
|
||||
return qpGeomMunger::register_munger(new qpGeomMunger(this, state));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -632,7 +632,7 @@ begin_draw_primitives(const qpGeomVertexData *data) {
|
|||
// Description: Draws a series of disconnected triangles.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsStateGuardian::
|
||||
draw_triangles(qpGeomTriangles *) {
|
||||
draw_triangles(const qpGeomTriangles *) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -641,8 +641,8 @@ draw_triangles(qpGeomTriangles *) {
|
|||
// Description: Draws a series of triangle strips.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsStateGuardian::
|
||||
draw_tristrips(qpGeomTristrips *primitive) {
|
||||
PT(qpGeomPrimitive) new_prim = primitive->decompose();
|
||||
draw_tristrips(const qpGeomTristrips *primitive) {
|
||||
CPT(qpGeomPrimitive) new_prim = primitive->decompose();
|
||||
if (!new_prim->is_of_type(qpGeomTristrips::get_class_type())) {
|
||||
new_prim->draw(this);
|
||||
}
|
||||
|
|
@ -654,8 +654,8 @@ draw_tristrips(qpGeomTristrips *primitive) {
|
|||
// Description: Draws a series of triangle fans.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsStateGuardian::
|
||||
draw_trifans(qpGeomTrifans *primitive) {
|
||||
PT(qpGeomPrimitive) new_prim = primitive->decompose();
|
||||
draw_trifans(const qpGeomTrifans *primitive) {
|
||||
CPT(qpGeomPrimitive) new_prim = primitive->decompose();
|
||||
if (!new_prim->is_of_type(qpGeomTrifans::get_class_type())) {
|
||||
new_prim->draw(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,9 +144,9 @@ public:
|
|||
virtual void finish_decal();
|
||||
|
||||
virtual bool begin_draw_primitives(const qpGeomVertexData *vertex_data);
|
||||
virtual void draw_triangles(qpGeomTriangles *primitive);
|
||||
virtual void draw_tristrips(qpGeomTristrips *primitive);
|
||||
virtual void draw_trifans(qpGeomTrifans *primitive);
|
||||
virtual void draw_triangles(const qpGeomTriangles *primitive);
|
||||
virtual void draw_tristrips(const qpGeomTristrips *primitive);
|
||||
virtual void draw_trifans(const qpGeomTrifans *primitive);
|
||||
virtual void end_draw_primitives();
|
||||
|
||||
virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex);
|
||||
|
|
|
|||
|
|
@ -23,5 +23,7 @@
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE DXGeomMunger8::
|
||||
DXGeomMunger8() {
|
||||
DXGeomMunger8(GraphicsStateGuardian *gsg, const RenderState *state) :
|
||||
qpGeomMunger(gsg, state)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,3 +72,27 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
|
|||
PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(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 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "pandabase.h"
|
||||
#include "qpgeomMunger.h"
|
||||
#include "graphicsStateGuardian.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : DXGeomMunger8
|
||||
|
|
@ -32,10 +33,12 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDADX DXGeomMunger8 : public qpGeomMunger {
|
||||
public:
|
||||
INLINE DXGeomMunger8();
|
||||
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;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
|
|
|
|||
|
|
@ -188,19 +188,6 @@ set_color_writemask(UINT color_writemask) {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGraphicsStateGuardian8::enable_blend
|
||||
// Access:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void DXGraphicsStateGuardian8::
|
||||
enable_gouraud_shading(bool val) {
|
||||
if (_bGouraudShadingOn != val) {
|
||||
_bGouraudShadingOn = val;
|
||||
_pD3DDevice->SetRenderState(D3DRS_SHADEMODE, (val ? D3DSHADE_GOURAUD : D3DSHADE_FLAT));
|
||||
}
|
||||
}
|
||||
|
||||
INLINE void DXGraphicsStateGuardian8::
|
||||
enable_primitive_clipping(bool val) {
|
||||
if (_clipping_enabled != val) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "textureAttrib.h"
|
||||
#include "texGenAttrib.h"
|
||||
#include "lightAttrib.h"
|
||||
#include "shadeModelAttrib.h"
|
||||
#include "cullFaceAttrib.h"
|
||||
#include "transparencyAttrib.h"
|
||||
#include "alphaTestAttrib.h"
|
||||
|
|
@ -323,8 +324,8 @@ dx_init(void) {
|
|||
_color_writemask = 0xFFFFFFFF;
|
||||
_CurFVFType = 0x0; // guards SetVertexShader fmt
|
||||
|
||||
_bGouraudShadingOn = false;
|
||||
_pD3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
|
||||
_bGouraudShadingOn = true;
|
||||
_pD3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||
|
||||
// this specifies if lighting model uses material color or vertex color
|
||||
// (not related to gouraud/flat shading)
|
||||
|
|
@ -520,21 +521,8 @@ dx_init(void) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
if(dx_force_backface_culling!=0) {
|
||||
if((dx_force_backface_culling > 0) &&
|
||||
(dx_force_backface_culling < D3DCULL_FORCE_DWORD)) {
|
||||
_pD3DDevice->SetRenderState(D3DRS_CULLMODE, dx_force_backface_culling);
|
||||
} else {
|
||||
dx_force_backface_culling=0;
|
||||
if(dxgsg8_cat.is_debug())
|
||||
dxgsg8_cat.debug() << "error, invalid value for dx-force-backface-culling\n";
|
||||
}
|
||||
}
|
||||
_pD3DDevice->SetRenderState(D3DRS_CULLMODE, dx_force_backface_culling);
|
||||
#else
|
||||
_cull_face_mode = CullFaceAttrib::M_cull_none;
|
||||
_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||
#endif
|
||||
|
||||
_alpha_func = D3DCMP_ALWAYS;
|
||||
_alpha_func_refval = 1.0f;
|
||||
|
|
@ -730,6 +718,22 @@ prepare_lens() {
|
|||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGraphicsStateGuardian8::enable_gouraud_shading
|
||||
// Access:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DXGraphicsStateGuardian8::
|
||||
enable_gouraud_shading(bool val) {
|
||||
if (_bGouraudShadingOn != val) {
|
||||
if (val) {
|
||||
modify_state(get_smooth_state());
|
||||
} else {
|
||||
modify_state(get_flat_state());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGraphicsStateGuardian8::get_blend_func
|
||||
// Access: Protected, Static
|
||||
|
|
@ -1053,9 +1057,6 @@ draw_prim_setup(const Geom *geom) {
|
|||
vertex_size += sizeof(float) * 2;
|
||||
}
|
||||
|
||||
// If we have per-vertex colors or normals, we need smooth shading.
|
||||
// Otherwise we want flat shading for performance reasons.
|
||||
|
||||
// Note on fogging:
|
||||
// the fogging expression should really be || (_fog_enabled && (_doFogType==PerVertexFog))
|
||||
// instead of just || (_fog_enabled), since GOURAUD shading should not be required for PerPixel
|
||||
|
|
@ -1063,10 +1064,17 @@ draw_prim_setup(const Geom *geom) {
|
|||
// but dont force the shading mode to gouraud internally, so you end up with flat-shaded fog colors
|
||||
// (note, TNT does the right thing tho). So I guess we must do gouraud shading for all fog rendering for now
|
||||
// note that if _doFogType==None, _fog_enabled will always be false
|
||||
|
||||
bool need_gouraud_shading = ((_perVertex & (PER_COLOR | (wants_normals() ? PER_NORMAL : 0))) || _fog_enabled);
|
||||
|
||||
enable_gouraud_shading(need_gouraud_shading);
|
||||
|
||||
if ((_perVertex & (PER_COLOR | (wants_normals() ? PER_NORMAL : 0))) || _fog_enabled) {
|
||||
// We definitely need gouraud shading.
|
||||
enable_gouraud_shading(true);
|
||||
} else if ((_perComp & (PER_COLOR | (wants_normals() ? PER_NORMAL : 0)))) {
|
||||
// We definitely need flat shading.
|
||||
enable_gouraud_shading(false);
|
||||
} else {
|
||||
// Don't care about gouraud shading.
|
||||
}
|
||||
|
||||
set_vertex_format(newFVFflags);
|
||||
|
||||
return vertex_size;
|
||||
|
|
@ -1517,6 +1525,12 @@ draw_sprite(GeomSprite *geom, GeomContext *gc) {
|
|||
|
||||
|
||||
// Note: for DX8, try to use the PointSprite primitive instead of doing all the stuff below
|
||||
|
||||
// see note on fog and gouraud-shading in draw_prim_setup
|
||||
bool bUseGouraudShadedColor=_fog_enabled;
|
||||
if (_fog_enabled) {
|
||||
enable_gouraud_shading(true);
|
||||
}
|
||||
|
||||
#ifdef GSG_VERBOSE
|
||||
dxgsg8_cat.debug() << "draw_sprite()" << endl;
|
||||
|
|
@ -1727,9 +1741,6 @@ draw_sprite(GeomSprite *geom, GeomContext *gc) {
|
|||
CurColor = _curD3Dcolor;
|
||||
}
|
||||
|
||||
// see note on fog and gouraud-shading in draw_prim_setup
|
||||
bool bUseGouraudShadedColor=_fog_enabled;
|
||||
enable_gouraud_shading(_fog_enabled);
|
||||
set_vertex_format(FVFType);
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
|
@ -2665,13 +2676,13 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) {
|
|||
// Description: Draws a series of disconnected triangles.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DXGraphicsStateGuardian8::
|
||||
draw_triangles(qpGeomTriangles *primitive) {
|
||||
draw_triangles(const qpGeomTriangles *primitive) {
|
||||
HRESULT hr = _pD3DDevice->DrawIndexedPrimitiveUP
|
||||
(D3DPT_TRIANGLELIST,
|
||||
primitive->get_min_vertex(),
|
||||
primitive->get_max_vertex() - primitive->get_min_vertex() + 1,
|
||||
primitive->get_num_primitives(),
|
||||
primitive->get_vertices(),
|
||||
primitive->get_flat_first_vertices(),
|
||||
D3DFMT_INDEX16,
|
||||
_vertex_data->get_array_data(0),
|
||||
_vertex_data->get_format()->get_array(0)->get_stride());
|
||||
|
|
@ -2903,8 +2914,8 @@ release_texture(TextureContext *tc) {
|
|||
// appropriate to this GSG for the indicated state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(qpGeomMunger) DXGraphicsStateGuardian8::
|
||||
get_geom_munger(const RenderState *) {
|
||||
PT(DXGeomMunger8) munger = new DXGeomMunger8;
|
||||
get_geom_munger(const RenderState *state) {
|
||||
PT(DXGeomMunger8) munger = new DXGeomMunger8(this, state);
|
||||
return qpGeomMunger::register_munger(munger);
|
||||
}
|
||||
|
||||
|
|
@ -3304,6 +3315,26 @@ issue_tex_gen(const TexGenAttrib *attrib) {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGraphicsStateGuardian8::issue_shade_model
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DXGraphicsStateGuardian8::
|
||||
issue_shade_model(const ShadeModelAttrib *attrib) {
|
||||
switch (attrib->get_mode()) {
|
||||
case ShadeModelAttrib::M_smooth:
|
||||
_pD3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||
_bGouraudShadingOn = true;
|
||||
break;
|
||||
|
||||
case ShadeModelAttrib::M_flat:
|
||||
_pD3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
|
||||
_bGouraudShadingOn = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGraphicsStateGuardian8::issue_texture
|
||||
// Access: Public, Virtual
|
||||
|
|
@ -3464,9 +3495,9 @@ issue_depth_write(const DepthWriteAttrib *attrib) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DXGraphicsStateGuardian8::
|
||||
issue_cull_face(const CullFaceAttrib *attrib) {
|
||||
CullFaceAttrib::Mode mode = attrib->get_effective_mode();
|
||||
_cull_face_mode = attrib->get_effective_mode();
|
||||
|
||||
switch (mode) {
|
||||
switch (_cull_face_mode) {
|
||||
case CullFaceAttrib::M_cull_none:
|
||||
_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||
break;
|
||||
|
|
@ -3478,7 +3509,7 @@ issue_cull_face(const CullFaceAttrib *attrib) {
|
|||
break;
|
||||
default:
|
||||
dxgsg8_cat.error()
|
||||
<< "invalid cull face mode " << (int)mode << endl;
|
||||
<< "invalid cull face mode " << (int)_cull_face_mode << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -3881,6 +3912,36 @@ set_read_buffer(const RenderBuffer &rb) {
|
|||
return;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGraphicsStateGuardian8::get_smooth_state
|
||||
// Access: Protected, Static
|
||||
// Description: Returns a RenderState object that represents
|
||||
// smooth, per-vertex shading.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderState) DXGraphicsStateGuardian8::
|
||||
get_smooth_state() {
|
||||
static CPT(RenderState) state;
|
||||
if (state == (RenderState *)NULL) {
|
||||
state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_smooth));
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGraphicsStateGuardian8::get_flat_state
|
||||
// Access: Protected, Static
|
||||
// Description: Returns a RenderState object that represents
|
||||
// flat, per-primitive shading.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderState) DXGraphicsStateGuardian8::
|
||||
get_flat_state() {
|
||||
static CPT(RenderState) state;
|
||||
if (state == (RenderState *)NULL) {
|
||||
state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_flat));
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGraphicsStateGuardian8::do_auto_rescale_normal
|
||||
// Access: Protected
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "displayRegion.h"
|
||||
#include "material.h"
|
||||
#include "depthTestAttrib.h"
|
||||
#include "cullFaceAttrib.h"
|
||||
#include "renderModeAttrib.h"
|
||||
#include "textureApplyAttrib.h"
|
||||
#include "fog.h"
|
||||
|
|
@ -90,7 +91,7 @@ public:
|
|||
virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
|
||||
|
||||
virtual bool begin_draw_primitives(const qpGeomVertexData *vertex_data);
|
||||
virtual void draw_triangles(qpGeomTriangles *primitive);
|
||||
virtual void draw_triangles(const qpGeomTriangles *primitive);
|
||||
virtual void end_draw_primitives();
|
||||
|
||||
virtual TextureContext *prepare_texture(Texture *tex);
|
||||
|
|
@ -122,6 +123,7 @@ public:
|
|||
virtual void issue_fog(const FogAttrib *attrib);
|
||||
virtual void issue_depth_offset(const DepthOffsetAttrib *attrib);
|
||||
virtual void issue_tex_gen(const TexGenAttrib *attrib);
|
||||
virtual void issue_shade_model(const ShadeModelAttrib *attrib);
|
||||
|
||||
virtual void bind_light(PointLight *light, int light_id);
|
||||
virtual void bind_light(DirectionalLight *light, int light_id);
|
||||
|
|
@ -163,6 +165,9 @@ protected:
|
|||
|
||||
INLINE void add_to_FVFBuf(void *data, size_t bytes) ;
|
||||
|
||||
static CPT(RenderState) get_smooth_state();
|
||||
static CPT(RenderState) get_flat_state();
|
||||
|
||||
void do_auto_rescale_normal();
|
||||
|
||||
bool _bDXisReady;
|
||||
|
|
@ -194,7 +199,7 @@ protected:
|
|||
INLINE void enable_fog(bool val);
|
||||
INLINE void enable_zwritemask(bool val);
|
||||
INLINE void set_color_writemask(UINT color_writemask);
|
||||
INLINE void enable_gouraud_shading(bool val);
|
||||
void enable_gouraud_shading(bool val);
|
||||
INLINE void set_vertex_format(DWORD NewFvfType);
|
||||
|
||||
INLINE D3DTEXTUREADDRESS get_texture_wrap_mode(Texture::WrapMode wm) const;
|
||||
|
|
@ -291,6 +296,7 @@ protected:
|
|||
bool _depth_write_enabled;
|
||||
bool _alpha_test_enabled;
|
||||
DWORD _clip_plane_bits;
|
||||
CullFaceAttrib::Mode _cull_face_mode;
|
||||
|
||||
RenderModeAttrib::Mode _current_fill_mode; //poinr/wireframe/solid
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,41 @@ clear_normal() {
|
|||
_flags &= ~F_has_normal;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggAttributes::matches_normal
|
||||
// Access: Published
|
||||
// Description: Returns true if this normal matches that of the other
|
||||
// EggAttributes object, include the morph list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool EggAttributes::
|
||||
matches_normal(const EggAttributes &other) const {
|
||||
if (((_flags ^ other._flags) & F_has_normal) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (!has_normal()) {
|
||||
return true;
|
||||
}
|
||||
return (get_normal() == other.get_normal() &&
|
||||
_dnormals.compare_to(other._dnormals) == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggAttributes::copy_normal
|
||||
// Access: Published
|
||||
// Description: Sets this normal to be the same as the other's,
|
||||
// include morphs. If the other has no normal, this
|
||||
// clears the normal.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggAttributes::
|
||||
copy_normal(const EggAttributes &other) {
|
||||
if (!other.has_normal()) {
|
||||
clear_normal();
|
||||
} else {
|
||||
set_normal(other.get_normal());
|
||||
_dnormals = other._dnormals;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggAttributes::has_color
|
||||
// Access: Published
|
||||
|
|
@ -105,6 +140,41 @@ clear_color() {
|
|||
_flags &= ~F_has_color;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggAttributes::matches_color
|
||||
// Access: Published
|
||||
// Description: Returns true if this color matches that of the other
|
||||
// EggAttributes object, include the morph list.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool EggAttributes::
|
||||
matches_color(const EggAttributes &other) const {
|
||||
if (((_flags ^ other._flags) & F_has_color) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (!has_color()) {
|
||||
return true;
|
||||
}
|
||||
return (get_color() == other.get_color() &&
|
||||
_drgbas.compare_to(other._drgbas) == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggAttributes::copy_color
|
||||
// Access: Published
|
||||
// Description: Sets this color to be the same as the other's,
|
||||
// include morphs. If the other has no color, this
|
||||
// clears the color.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggAttributes::
|
||||
copy_color(const EggAttributes &other) {
|
||||
if (!other.has_color()) {
|
||||
clear_color();
|
||||
} else {
|
||||
set_color(other.get_color());
|
||||
_drgbas = other._drgbas;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggAttributes::sorts_less_than
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -49,11 +49,15 @@ PUBLISHED:
|
|||
INLINE const Normald &get_normal() const;
|
||||
INLINE void set_normal(const Normald &normal);
|
||||
INLINE void clear_normal();
|
||||
INLINE bool matches_normal(const EggAttributes &other) const;
|
||||
INLINE void copy_normal(const EggAttributes &other);
|
||||
|
||||
INLINE bool has_color() const;
|
||||
INLINE Colorf get_color() const;
|
||||
INLINE void set_color(const Colorf &Color);
|
||||
INLINE void clear_color();
|
||||
INLINE bool matches_color(const EggAttributes &other) const;
|
||||
INLINE void copy_color(const EggAttributes &other);
|
||||
|
||||
void write(ostream &out, int indent_level) const;
|
||||
INLINE bool sorts_less_than(const EggAttributes &other) const;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,72 @@
|
|||
TypeHandle EggCompositePrimitive::_type_handle;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggCompositePrimitive::get_shading
|
||||
// Access: Published, Virtual
|
||||
// Description: Returns the shading properties apparent on this
|
||||
// particular primitive. This returns S_per_vertex if
|
||||
// the vertices have colors or normals (and they are not
|
||||
// all the same values), or for a simple primitive,
|
||||
// S_overall otherwise. A composite primitive may also
|
||||
// return S_per_face if the individual component
|
||||
// primitives have colors or normals that are not all
|
||||
// the same values.
|
||||
//
|
||||
// To get the most accurate results, you should call
|
||||
// clear_shading() on all connected primitives (or on
|
||||
// all primitives in the egg file), followed by
|
||||
// determine_shading() on each primitive. You may find
|
||||
// it easiest to call these methods on the EggData root
|
||||
// node (they are defined on EggGroupNode).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
EggPrimitive::Shading EggCompositePrimitive::
|
||||
get_shading() const {
|
||||
Shading basic_shading = EggPrimitive::get_shading();
|
||||
if (basic_shading == S_per_vertex) {
|
||||
return basic_shading;
|
||||
}
|
||||
if (_components.empty()) {
|
||||
return S_overall;
|
||||
}
|
||||
|
||||
// Check if the components all have the same normal.
|
||||
{
|
||||
const EggAttributes *first_component = get_component(0);
|
||||
if (!first_component->has_normal()) {
|
||||
first_component = this;
|
||||
}
|
||||
for (int i = 1; i < get_num_components(); i++) {
|
||||
const EggAttributes *component = get_component(i);
|
||||
if (!component->has_normal()) {
|
||||
component = this;
|
||||
}
|
||||
if (!component->matches_normal(*first_component)) {
|
||||
return S_per_face;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the components all have the same color.
|
||||
{
|
||||
const EggAttributes *first_component = get_component(0);
|
||||
if (!first_component->has_color()) {
|
||||
first_component = this;
|
||||
}
|
||||
for (int i = 1; i < get_num_components(); i++) {
|
||||
const EggAttributes *component = get_component(i);
|
||||
if (!component->has_color()) {
|
||||
component = this;
|
||||
}
|
||||
if (!component->matches_color(*first_component)) {
|
||||
return S_per_face;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return S_overall;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggCompositePrimitive::triangulate_in_place
|
||||
// Access: Published
|
||||
|
|
@ -52,10 +118,19 @@ triangulate_in_place() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggCompositePrimitive::unify_attributes
|
||||
// Access: Published, Virtual
|
||||
// Description: Applies per-vertex normal and color to all vertices,
|
||||
// if they are in fact per-vertex (and actually
|
||||
// different for each vertex), or moves them to the
|
||||
// primitive if they are all the same.
|
||||
// Description: If the shading property is S_per_vertex, ensures that
|
||||
// all vertices have a normal and a color, and the
|
||||
// overall primitive does not.
|
||||
//
|
||||
// If the shading property is S_per_face, and this is a
|
||||
// composite primitive, ensures that all components have
|
||||
// a normal and a color, and the vertices and overall
|
||||
// primitive do not. (If this is a simple primitive,
|
||||
// S_per_face works the same as S_overall, below).
|
||||
//
|
||||
// If the shading property is S_overall, ensures that no
|
||||
// vertices or components have a normal or a color, and
|
||||
// the overall primitive does (if any exists at all).
|
||||
//
|
||||
// After this call, either the primitive will have
|
||||
// normals or its vertices will, but not both. Ditto
|
||||
|
|
@ -65,188 +140,114 @@ triangulate_in_place() {
|
|||
// pool.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggCompositePrimitive::
|
||||
unify_attributes() {
|
||||
// A composite primitive wants to do the same sort of thing with
|
||||
// components that the fundamental primitive does with vertices.
|
||||
// But first, we want to make sure that the primitive overall
|
||||
// attributes have been correctly moved from the vertices, so call
|
||||
// up to the base class.
|
||||
EggPrimitive::unify_attributes();
|
||||
|
||||
// Now the rest of this body is more or less what an EggPrimitive
|
||||
// does for vertices, modified to work on components.
|
||||
|
||||
Components components;
|
||||
|
||||
// First, go through the components and apply the primitive overall
|
||||
// attributes to any component that omits them.
|
||||
bool all_have_normal = true;
|
||||
bool all_have_color = true;
|
||||
Components::iterator ci;
|
||||
for (ci = _components.begin(); ci != _components.end(); ++ci) {
|
||||
EggAttributes *orig_component = (*ci);
|
||||
EggAttributes *component = new EggAttributes(*orig_component);
|
||||
|
||||
if (!component->has_normal()) {
|
||||
if (has_normal()) {
|
||||
component->set_normal(get_normal());
|
||||
component->_dnormals = _dnormals;
|
||||
} else {
|
||||
all_have_normal = false;
|
||||
}
|
||||
}
|
||||
if (!component->has_color()) {
|
||||
if (has_color()) {
|
||||
component->set_color(get_color());
|
||||
component->_drgbas = _drgbas;
|
||||
} else {
|
||||
all_have_color = false;
|
||||
}
|
||||
}
|
||||
|
||||
components.push_back(component);
|
||||
unify_attributes(EggPrimitive::Shading shading) {
|
||||
if (shading == S_unknown) {
|
||||
shading = get_shading();
|
||||
}
|
||||
|
||||
clear_normal();
|
||||
clear_color();
|
||||
switch (shading) {
|
||||
case S_per_vertex:
|
||||
// Propagate everything to the vertices.
|
||||
{
|
||||
iterator pi;
|
||||
for (pi = begin(); pi != end(); ++pi) {
|
||||
EggVertex *orig_vertex = (*pi);
|
||||
PT(EggVertex) vertex = new EggVertex(*orig_vertex);
|
||||
if (!vertex->has_normal() && has_normal()) {
|
||||
vertex->copy_normal(*this);
|
||||
}
|
||||
if (!vertex->has_color() && has_color()) {
|
||||
vertex->copy_color(*this);
|
||||
}
|
||||
|
||||
// Now see if any ended up different.
|
||||
EggAttributes overall;
|
||||
bool normal_different = false;
|
||||
bool color_different = false;
|
||||
vertex = vertex->get_pool()->create_unique_vertex(*vertex);
|
||||
replace(pi, vertex);
|
||||
}
|
||||
Components::iterator ci;
|
||||
for (ci = _components.begin(); ci != _components.end(); ++ci) {
|
||||
(*ci)->clear_normal();
|
||||
(*ci)->clear_color();
|
||||
}
|
||||
clear_normal();
|
||||
clear_color();
|
||||
}
|
||||
break;
|
||||
|
||||
Components::iterator vi;
|
||||
for (vi = components.begin(); vi != components.end(); ++vi) {
|
||||
EggAttributes *component = (*vi);
|
||||
if (!all_have_normal) {
|
||||
component->clear_normal();
|
||||
} else if (!normal_different) {
|
||||
if (!overall.has_normal()) {
|
||||
overall.set_normal(component->get_normal());
|
||||
overall._dnormals = component->_dnormals;
|
||||
} else if (overall.get_normal() != component->get_normal() ||
|
||||
overall._dnormals.compare_to(component->_dnormals) != 0) {
|
||||
normal_different = true;
|
||||
case S_per_face:
|
||||
// Propagate everything to the components.
|
||||
{
|
||||
Components::iterator ci;
|
||||
for (ci = _components.begin(); ci != _components.end(); ++ci) {
|
||||
EggAttributes *component = (*ci);
|
||||
if (!component->has_normal() && has_normal()) {
|
||||
component->copy_normal(*this);
|
||||
}
|
||||
if (!component->has_color() && has_color()) {
|
||||
component->copy_color(*this);
|
||||
}
|
||||
}
|
||||
iterator pi;
|
||||
for (pi = begin(); pi != end(); ++pi) {
|
||||
EggVertex *orig_vertex = (*pi);
|
||||
if (orig_vertex->has_normal() || orig_vertex->has_color()) {
|
||||
PT(EggVertex) vertex = new EggVertex(*orig_vertex);
|
||||
vertex->clear_normal();
|
||||
vertex->clear_color();
|
||||
|
||||
vertex = vertex->get_pool()->create_unique_vertex(*vertex);
|
||||
replace(pi, vertex);
|
||||
}
|
||||
}
|
||||
clear_normal();
|
||||
clear_color();
|
||||
}
|
||||
break;
|
||||
|
||||
case S_overall:
|
||||
// Remove everything from the vertices and components.
|
||||
{
|
||||
iterator pi;
|
||||
for (pi = begin(); pi != end(); ++pi) {
|
||||
EggVertex *vertex = (*pi);
|
||||
if (vertex->has_normal()) {
|
||||
if (!has_normal()) {
|
||||
copy_normal(*vertex);
|
||||
}
|
||||
vertex->clear_normal();
|
||||
}
|
||||
if (vertex->has_color()) {
|
||||
if (!has_color()) {
|
||||
copy_color(*vertex);
|
||||
}
|
||||
vertex->clear_color();
|
||||
}
|
||||
}
|
||||
Components::iterator ci;
|
||||
for (ci = _components.begin(); ci != _components.end(); ++ci) {
|
||||
EggAttributes *component = (*ci);
|
||||
if (component->has_normal()) {
|
||||
if (!has_normal()) {
|
||||
copy_normal(*component);
|
||||
}
|
||||
component->clear_normal();
|
||||
}
|
||||
if (component->has_color()) {
|
||||
if (!has_color()) {
|
||||
copy_color(*component);
|
||||
}
|
||||
component->clear_color();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!all_have_color) {
|
||||
component->clear_color();
|
||||
} else if (!color_different) {
|
||||
if (!overall.has_color()) {
|
||||
overall.set_color(component->get_color());
|
||||
overall._drgbas = component->_drgbas;
|
||||
} else if (overall.get_color() != component->get_color() ||
|
||||
overall._drgbas.compare_to(component->_drgbas) != 0) {
|
||||
color_different = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
if (!color_different || !normal_different) {
|
||||
// Ok, it's flat-shaded after all. Go back through and remove
|
||||
// this stuff from the components.
|
||||
if (!normal_different) {
|
||||
set_normal(overall.get_normal());
|
||||
_dnormals = overall._dnormals;
|
||||
}
|
||||
if (!color_different) {
|
||||
set_color(overall.get_color());
|
||||
_drgbas = overall._drgbas;
|
||||
}
|
||||
for (vi = components.begin(); vi != components.end(); ++vi) {
|
||||
EggAttributes *component = (*vi);
|
||||
if (!normal_different) {
|
||||
component->clear_normal();
|
||||
}
|
||||
if (!color_different) {
|
||||
component->clear_color();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, assign the new components.
|
||||
for (size_t i = 0; i < components.size(); i++) {
|
||||
EggAttributes *component = components[i];
|
||||
set_component(i, component);
|
||||
delete component;
|
||||
case S_unknown:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggCompositePrimitive::apply_last_attribute
|
||||
// Access: Published, Virtual
|
||||
// Description: Sets the last vertex of the triangle (or each
|
||||
// component) to the primitive normal and/or color, if
|
||||
// they exist. This reflects the Panda convention of
|
||||
// storing flat-shaded properties on the last vertex,
|
||||
// although it is not usually a convention in Egg.
|
||||
//
|
||||
// This may introduce redundant vertices to the vertex
|
||||
// pool.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggCompositePrimitive::
|
||||
apply_last_attribute() {
|
||||
// The first component gets applied to the third vertex, and so on
|
||||
// from there.
|
||||
for (int i = 0; i < get_num_components(); i++) {
|
||||
EggAttributes *component = get_component(i);
|
||||
|
||||
// The significant_change flag is set if we have changed the
|
||||
// vertex in some important way, that will invalidate it for other
|
||||
// primitives that might share it. We don't consider *adding* a
|
||||
// normal where there wasn't one before to be significant, but we
|
||||
// do consider it significant to change a vertex's normal to
|
||||
// something different. Similarly for color.
|
||||
bool significant_change = false;
|
||||
|
||||
EggVertex *orig_vertex = get_vertex(i + 2);
|
||||
nassertv(orig_vertex != (EggVertex *)NULL);
|
||||
PT(EggVertex) new_vertex = new EggVertex(*orig_vertex);
|
||||
|
||||
if (component->has_normal() || has_normal()) {
|
||||
if (component->has_normal()) {
|
||||
new_vertex->set_normal(component->get_normal());
|
||||
new_vertex->_dnormals = component->_dnormals;
|
||||
} else {
|
||||
new_vertex->set_normal(get_normal());
|
||||
new_vertex->_dnormals = _dnormals;
|
||||
}
|
||||
|
||||
if (orig_vertex->has_normal() &&
|
||||
(orig_vertex->get_normal() != new_vertex->get_normal() ||
|
||||
orig_vertex->_dnormals.compare_to(new_vertex->_dnormals) != 0)) {
|
||||
significant_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (component->has_color() || has_color()) {
|
||||
if (component->has_color()) {
|
||||
new_vertex->set_color(component->get_color());
|
||||
new_vertex->_drgbas = component->_drgbas;
|
||||
} else {
|
||||
new_vertex->set_color(get_color());
|
||||
new_vertex->_drgbas = _drgbas;
|
||||
}
|
||||
|
||||
if (orig_vertex->has_color() &&
|
||||
(orig_vertex->get_color() != new_vertex->get_color() ||
|
||||
orig_vertex->_drgbas.compare_to(new_vertex->_drgbas) != 0)) {
|
||||
significant_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (significant_change) {
|
||||
new_vertex = get_pool()->create_unique_vertex(*new_vertex);
|
||||
set_vertex(i + 2, new_vertex);
|
||||
} else {
|
||||
// Just copy the new attributes back into the pool.
|
||||
((EggAttributes *)orig_vertex)->operator = (*new_vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggCompositePrimitive::post_apply_last_attribute
|
||||
// Function: EggCompositePrimitive::post_apply_flat_attribute
|
||||
// Access: Published, Virtual
|
||||
// Description: Intended as a followup to apply_last_attribute(),
|
||||
// this also sets an attribute on the first vertices of
|
||||
|
|
@ -254,12 +255,16 @@ apply_last_attribute() {
|
|||
// attribute set, just so they end up with *something*.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggCompositePrimitive::
|
||||
post_apply_last_attribute() {
|
||||
post_apply_flat_attribute() {
|
||||
if (!empty()) {
|
||||
for (int i = 0; i < (int)size(); i++) {
|
||||
EggVertex *vertex = get_vertex(i);
|
||||
EggAttributes *component = get_component(max(i - 2, 0));
|
||||
|
||||
// Use set_normal() instead of copy_normal(), to avoid getting
|
||||
// the morphs--we don't want them here, since we're just putting
|
||||
// a bogus value on the normal anyway.
|
||||
|
||||
if (component->has_normal() && !vertex->has_normal()) {
|
||||
vertex->set_normal(component->get_normal());
|
||||
} else if (has_normal() && !vertex->has_normal()) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ PUBLISHED:
|
|||
INLINE EggCompositePrimitive &operator = (const EggCompositePrimitive ©);
|
||||
INLINE ~EggCompositePrimitive();
|
||||
|
||||
virtual Shading get_shading() const;
|
||||
|
||||
INLINE int get_num_components() const;
|
||||
INLINE const EggAttributes *get_component(int i) const;
|
||||
INLINE EggAttributes *get_component(int i);
|
||||
|
|
@ -45,9 +47,8 @@ PUBLISHED:
|
|||
INLINE bool triangulate_into(EggGroupNode *container) const;
|
||||
PT(EggCompositePrimitive) triangulate_in_place();
|
||||
|
||||
virtual void unify_attributes();
|
||||
virtual void apply_last_attribute();
|
||||
virtual void post_apply_last_attribute();
|
||||
virtual void unify_attributes(Shading shading);
|
||||
virtual void post_apply_flat_attribute();
|
||||
virtual bool cleanup();
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -784,7 +784,7 @@ mesh_triangles(int flags) {
|
|||
// appear anywhere in the hierarchy.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int EggGroupNode::
|
||||
remove_unused_vertices() {
|
||||
remove_unused_vertices(bool recurse) {
|
||||
int num_removed = 0;
|
||||
|
||||
Children::iterator ci, cnext;
|
||||
|
|
@ -805,7 +805,9 @@ remove_unused_vertices() {
|
|||
}
|
||||
|
||||
} else if (child->is_of_type(EggGroupNode::get_class_type())) {
|
||||
num_removed += DCAST(EggGroupNode, child)->remove_unused_vertices();
|
||||
if (recurse) {
|
||||
num_removed += DCAST(EggGroupNode, child)->remove_unused_vertices(recurse);
|
||||
}
|
||||
}
|
||||
|
||||
ci = cnext;
|
||||
|
|
@ -823,7 +825,7 @@ remove_unused_vertices() {
|
|||
// primitives removed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int EggGroupNode::
|
||||
remove_invalid_primitives() {
|
||||
remove_invalid_primitives(bool recurse) {
|
||||
int num_removed = 0;
|
||||
|
||||
Children::iterator ci, cnext;
|
||||
|
|
@ -841,7 +843,9 @@ remove_invalid_primitives() {
|
|||
}
|
||||
|
||||
} else if (child->is_of_type(EggGroupNode::get_class_type())) {
|
||||
num_removed += DCAST(EggGroupNode, child)->remove_invalid_primitives();
|
||||
if (recurse) {
|
||||
num_removed += DCAST(EggGroupNode, child)->remove_invalid_primitives(recurse);
|
||||
}
|
||||
}
|
||||
|
||||
ci = cnext;
|
||||
|
|
@ -850,6 +854,56 @@ remove_invalid_primitives() {
|
|||
return num_removed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggGroupNode::clear_connected_shading
|
||||
// Access: Published
|
||||
// Description: Resets the connected_shading information on all
|
||||
// primitives at this node and below, so that it may be
|
||||
// accurately rederived by the next call to
|
||||
// get_connected_shading().
|
||||
//
|
||||
// It may be a good idea to call
|
||||
// remove_unused_vertices() at the same time, to
|
||||
// establish the correct connectivity.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggGroupNode::
|
||||
clear_connected_shading() {
|
||||
Children::iterator ci;
|
||||
for (ci = _children.begin(); ci != _children.end(); ++ci) {
|
||||
EggNode *child = *ci;
|
||||
|
||||
if (child->is_of_type(EggPrimitive::get_class_type())) {
|
||||
EggPrimitive *prim = DCAST(EggPrimitive, child);
|
||||
prim->clear_connected_shading();
|
||||
} else if (child->is_of_type(EggGroupNode::get_class_type())) {
|
||||
DCAST(EggGroupNode, child)->clear_connected_shading();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggGroupNode::get_connected_shading
|
||||
// Access: Published
|
||||
// Description: Queries the connected_shading information on all
|
||||
// primitives at this node and below, to ensure that it
|
||||
// has been completely filled in before we start mucking
|
||||
// around with vertices.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggGroupNode::
|
||||
get_connected_shading() {
|
||||
Children::iterator ci;
|
||||
for (ci = _children.begin(); ci != _children.end(); ++ci) {
|
||||
EggNode *child = *ci;
|
||||
|
||||
if (child->is_of_type(EggPrimitive::get_class_type())) {
|
||||
EggPrimitive *prim = DCAST(EggPrimitive, child);
|
||||
prim->get_connected_shading();
|
||||
} else if (child->is_of_type(EggGroupNode::get_class_type())) {
|
||||
DCAST(EggGroupNode, child)->get_connected_shading();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggGroupNode::rebuild_vertex_pool
|
||||
// Access: Published
|
||||
|
|
@ -904,22 +958,31 @@ rebuild_vertex_pool(EggVertexPool *vertex_pool, bool recurse) {
|
|||
// normals or its vertices will, but not both. Ditto
|
||||
// for colors.
|
||||
//
|
||||
// If use_connected_shading is true, each polygon is
|
||||
// considered in conjunction with all connected
|
||||
// polygons; otherwise, each polygon is considered
|
||||
// individually.
|
||||
//
|
||||
// This may create redundant vertices in the vertex
|
||||
// pool, so it may be a good idea to follow this up with
|
||||
// remove_unused_vertices().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggGroupNode::
|
||||
unify_attributes(bool recurse) {
|
||||
unify_attributes(bool use_connected_shading, bool recurse) {
|
||||
Children::iterator ci;
|
||||
for (ci = _children.begin(); ci != _children.end(); ++ci) {
|
||||
EggNode *child = *ci;
|
||||
|
||||
if (child->is_of_type(EggPrimitive::get_class_type())) {
|
||||
EggPrimitive *prim = DCAST(EggPrimitive, child);
|
||||
prim->unify_attributes();
|
||||
if (use_connected_shading) {
|
||||
prim->unify_attributes(prim->get_connected_shading());
|
||||
} else {
|
||||
prim->unify_attributes(prim->get_shading());
|
||||
}
|
||||
} else if (child->is_of_type(EggGroupNode::get_class_type())) {
|
||||
if (recurse) {
|
||||
DCAST(EggGroupNode, child)->unify_attributes(recurse);
|
||||
DCAST(EggGroupNode, child)->unify_attributes(use_connected_shading, recurse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -930,9 +993,10 @@ unify_attributes(bool recurse) {
|
|||
// Access: Published
|
||||
// Description: Sets the last vertex of the triangle (or each
|
||||
// component) to the primitive normal and/or color, if
|
||||
// they exist. This reflects the Panda convention of
|
||||
// storing flat-shaded properties on the last vertex,
|
||||
// although it is not usually a convention in Egg.
|
||||
// the primitive is flat-shaded. This reflects the
|
||||
// OpenGL convention of storing flat-shaded properties on
|
||||
// the last vertex, although it is not usually a
|
||||
// convention in Egg.
|
||||
//
|
||||
// This may create redundant vertices in the vertex
|
||||
// pool, so it may be a good idea to follow this up with
|
||||
|
|
@ -956,7 +1020,38 @@ apply_last_attribute(bool recurse) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggGroupNode::post_apply_last_attribute
|
||||
// Function: EggGroupNode::apply_first_attribute
|
||||
// Access: Published
|
||||
// Description: Sets the first vertex of the triangle (or each
|
||||
// component) to the primitive normal and/or color, if
|
||||
// the primitive is flat-shaded. This reflects the
|
||||
// DirectX convention of storing flat-shaded properties on
|
||||
// the first vertex, although it is not usually a
|
||||
// convention in Egg.
|
||||
//
|
||||
// This may create redundant vertices in the vertex
|
||||
// pool, so it may be a good idea to follow this up with
|
||||
// remove_unused_vertices().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggGroupNode::
|
||||
apply_first_attribute(bool recurse) {
|
||||
Children::iterator ci;
|
||||
for (ci = _children.begin(); ci != _children.end(); ++ci) {
|
||||
EggNode *child = *ci;
|
||||
|
||||
if (child->is_of_type(EggPrimitive::get_class_type())) {
|
||||
EggPrimitive *prim = DCAST(EggPrimitive, child);
|
||||
prim->apply_first_attribute();
|
||||
} else if (child->is_of_type(EggGroupNode::get_class_type())) {
|
||||
if (recurse) {
|
||||
DCAST(EggGroupNode, child)->apply_first_attribute(recurse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggGroupNode::post_apply_flat_attribute
|
||||
// Access: Published
|
||||
// Description: Intended as a followup to apply_last_attribute(),
|
||||
// this also sets an attribute on the first vertices of
|
||||
|
|
@ -964,17 +1059,17 @@ apply_last_attribute(bool recurse) {
|
|||
// attribute set, just so they end up with *something*.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggGroupNode::
|
||||
post_apply_last_attribute(bool recurse) {
|
||||
post_apply_flat_attribute(bool recurse) {
|
||||
Children::iterator ci;
|
||||
for (ci = _children.begin(); ci != _children.end(); ++ci) {
|
||||
EggNode *child = *ci;
|
||||
|
||||
if (child->is_of_type(EggPrimitive::get_class_type())) {
|
||||
EggPrimitive *prim = DCAST(EggPrimitive, child);
|
||||
prim->post_apply_last_attribute();
|
||||
prim->post_apply_flat_attribute();
|
||||
} else if (child->is_of_type(EggGroupNode::get_class_type())) {
|
||||
if (recurse) {
|
||||
DCAST(EggGroupNode, child)->post_apply_last_attribute(recurse);
|
||||
DCAST(EggGroupNode, child)->post_apply_flat_attribute(recurse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,12 +140,15 @@ PUBLISHED:
|
|||
int triangulate_polygons(int flags);
|
||||
void mesh_triangles(int flags);
|
||||
|
||||
int remove_unused_vertices();
|
||||
int remove_invalid_primitives();
|
||||
int remove_unused_vertices(bool recurse);
|
||||
int remove_invalid_primitives(bool recurse);
|
||||
void clear_connected_shading();
|
||||
void get_connected_shading();
|
||||
void rebuild_vertex_pool(EggVertexPool *vertex_pool, bool recurse);
|
||||
void unify_attributes(bool recurse);
|
||||
void unify_attributes(bool use_connected_shading, bool recurse);
|
||||
void apply_last_attribute(bool recurse);
|
||||
void post_apply_last_attribute(bool recurse);
|
||||
void apply_first_attribute(bool recurse);
|
||||
void post_apply_flat_attribute(bool recurse);
|
||||
virtual bool has_primitives() const;
|
||||
virtual bool joint_has_primitives() const;
|
||||
virtual bool has_normals() const;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
INLINE EggPrimitive::
|
||||
EggPrimitive(const string &name): EggNode(name) {
|
||||
_bface = false;
|
||||
_connected_shading = S_unknown;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -41,6 +42,7 @@ EggPrimitive(const EggPrimitive ©) :
|
|||
_bface(copy._bface)
|
||||
{
|
||||
copy_vertices(copy);
|
||||
_connected_shading = S_unknown;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -56,6 +58,7 @@ operator = (const EggPrimitive ©) {
|
|||
_textures = copy._textures;
|
||||
_material = copy._material;
|
||||
_bface = copy._bface;
|
||||
_connected_shading = S_unknown;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +72,44 @@ INLINE EggPrimitive::
|
|||
clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggPrimitive::clear_connected_shading
|
||||
// Access: Published
|
||||
// Description: Resets the connected_shading member in this
|
||||
// primitive, so that get_connected_shading() will
|
||||
// recompute a new value.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggPrimitive::
|
||||
clear_connected_shading() {
|
||||
_connected_shading = S_unknown;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggPrimitive::get_connected_shading
|
||||
// Access: Published
|
||||
// Description: Determines what sort of shading properties this
|
||||
// primitive's connected neighbors have.
|
||||
//
|
||||
// To get the most accurate results, you should first
|
||||
// call clear_connected_shading() on all connected
|
||||
// primitives (or on all primitives in the egg file).
|
||||
// It might also be a good idea to call
|
||||
// remove_unused_vertices() to ensure proper
|
||||
// connectivity.
|
||||
//
|
||||
// You may find it easiest to call these other methods
|
||||
// on the EggData root node (they are defined on
|
||||
// EggGroupNode).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE EggPrimitive::Shading EggPrimitive::
|
||||
get_connected_shading() {
|
||||
if (_connected_shading == S_unknown) {
|
||||
set_connected_shading(S_unknown, this);
|
||||
}
|
||||
|
||||
return _connected_shading;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggPrimitive::set_texture
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -190,6 +190,69 @@ determine_bin() {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggPrimitive::get_shading
|
||||
// Access: Published, Virtual
|
||||
// Description: Returns the shading properties apparent on this
|
||||
// particular primitive. This returns S_per_vertex if
|
||||
// the vertices have colors or normals (and they are not
|
||||
// all the same values), or for a simple primitive,
|
||||
// S_overall otherwise. A composite primitive may also
|
||||
// return S_per_face if the individual component
|
||||
// primitives have colors or normals that are not all
|
||||
// the same values.
|
||||
//
|
||||
// To get the most accurate results, you should call
|
||||
// clear_shading() on all connected primitives (or on
|
||||
// all primitives in the egg file), followed by
|
||||
// determine_shading() on each primitive. You may find
|
||||
// it easiest to call these methods on the EggData root
|
||||
// node (they are defined on EggGroupNode).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
EggPrimitive::Shading EggPrimitive::
|
||||
get_shading() const {
|
||||
if (empty()) {
|
||||
return S_overall;
|
||||
}
|
||||
|
||||
if (has_vertex_normal()) {
|
||||
// Check if the vertices all have the same normal.
|
||||
const EggAttributes *first_vertex = get_vertex(0);
|
||||
if (!first_vertex->has_normal()) {
|
||||
first_vertex = this;
|
||||
}
|
||||
for (int i = 1; i < get_num_vertices(); i++) {
|
||||
const EggAttributes *vertex = get_vertex(i);
|
||||
if (!vertex->has_normal()) {
|
||||
vertex = this;
|
||||
}
|
||||
if (!vertex->matches_normal(*first_vertex)) {
|
||||
return S_per_vertex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_vertex_color()) {
|
||||
// Check if the vertices all have the same color.
|
||||
const EggAttributes *first_vertex = get_vertex(0);
|
||||
if (!first_vertex->has_color()) {
|
||||
first_vertex = this;
|
||||
}
|
||||
for (int i = 1; i < get_num_vertices(); i++) {
|
||||
const EggAttributes *vertex = get_vertex(i);
|
||||
if (!vertex->has_color()) {
|
||||
vertex = this;
|
||||
}
|
||||
if (!vertex->matches_color(*first_vertex)) {
|
||||
return S_per_vertex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return S_overall;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggPrimitive::copy_attributes
|
||||
// Access: Published
|
||||
|
|
@ -221,8 +284,10 @@ copy_attributes(const EggPrimitive &other) {
|
|||
// Description: Returns true if any vertex on the primitive has a
|
||||
// specific normal set, false otherwise.
|
||||
//
|
||||
// For the most accurate measure of this, call
|
||||
// unify_attributes() first.
|
||||
// If you call unify_attributes() first, this will also
|
||||
// return false even if all the vertices were set to the
|
||||
// same value (since unify_attributes() removes
|
||||
// redundant vertex properties).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggPrimitive::
|
||||
has_vertex_normal() const {
|
||||
|
|
@ -241,8 +306,10 @@ has_vertex_normal() const {
|
|||
// Description: Returns true if any vertex on the primitive has a
|
||||
// specific color set, false otherwise.
|
||||
//
|
||||
// For the most accurate measure of this, call
|
||||
// unify_attributes() first.
|
||||
// If you call unify_attributes() first, this will also
|
||||
// return false even if all the vertices were set to the
|
||||
// same value (since unify_attributes() removes
|
||||
// redundant vertex properties).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggPrimitive::
|
||||
has_vertex_color() const {
|
||||
|
|
@ -255,29 +322,22 @@ has_vertex_color() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggPrimitive::is_flat_shaded
|
||||
// Access: Published
|
||||
// Description: Returns true if the primitive is flat shaded, meaning
|
||||
// it has no per-vertex normal and no per-vertex color
|
||||
// (but in the case of a composite primitive, it may
|
||||
// still have per-component normal and color).
|
||||
//
|
||||
// For the most accurate measure of this, call
|
||||
// unify_attributes() first.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggPrimitive::
|
||||
is_flat_shaded() const {
|
||||
return !has_vertex_normal() && !has_vertex_color();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggPrimitive::unify_attributes
|
||||
// Access: Published, Virtual
|
||||
// Description: Applies per-vertex normal and color to all vertices,
|
||||
// if they are in fact per-vertex (and actually
|
||||
// different for each vertex), or moves them to the
|
||||
// primitive if they are all the same.
|
||||
// Description: If the shading property is S_per_vertex, ensures that
|
||||
// all vertices have a normal and a color, and the
|
||||
// overall primitive does not.
|
||||
//
|
||||
// If the shading property is S_per_face, and this is a
|
||||
// composite primitive, ensures that all components have
|
||||
// a normal and a color, and the vertices and overall
|
||||
// primitive do not. (If this is a simple primitive,
|
||||
// S_per_face works the same as S_overall, below).
|
||||
//
|
||||
// If the shading property is S_overall, ensures that no
|
||||
// vertices or components have a normal or a color, and
|
||||
// the overall primitive does (if any exists at all).
|
||||
//
|
||||
// After this call, either the primitive will have
|
||||
// normals or its vertices will, but not both. Ditto
|
||||
|
|
@ -287,109 +347,59 @@ is_flat_shaded() const {
|
|||
// pool.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggPrimitive::
|
||||
unify_attributes() {
|
||||
typedef pvector< PT(EggVertex) > Vertices;
|
||||
Vertices vertices;
|
||||
|
||||
// First, go through the vertices and apply the primitive overall
|
||||
// attributes to any vertex that omits them.
|
||||
bool all_have_normal = true;
|
||||
bool all_have_color = true;
|
||||
iterator pi;
|
||||
for (pi = begin(); pi != end(); ++pi) {
|
||||
EggVertex *orig_vertex = (*pi);
|
||||
PT(EggVertex) vertex = new EggVertex(*orig_vertex);
|
||||
|
||||
if (!vertex->has_normal()) {
|
||||
if (has_normal()) {
|
||||
vertex->set_normal(get_normal());
|
||||
vertex->_dnormals = _dnormals;
|
||||
} else {
|
||||
all_have_normal = false;
|
||||
}
|
||||
}
|
||||
if (!vertex->has_color()) {
|
||||
if (has_color()) {
|
||||
vertex->set_color(get_color());
|
||||
vertex->_drgbas = _drgbas;
|
||||
} else {
|
||||
all_have_color = false;
|
||||
}
|
||||
}
|
||||
|
||||
vertices.push_back(vertex);
|
||||
unify_attributes(EggPrimitive::Shading shading) {
|
||||
if (shading == S_unknown) {
|
||||
shading = get_shading();
|
||||
}
|
||||
|
||||
clear_normal();
|
||||
clear_color();
|
||||
switch (shading) {
|
||||
case S_per_vertex:
|
||||
// Propagate everything to the vertices.
|
||||
{
|
||||
iterator pi;
|
||||
for (pi = begin(); pi != end(); ++pi) {
|
||||
EggVertex *orig_vertex = (*pi);
|
||||
PT(EggVertex) vertex = new EggVertex(*orig_vertex);
|
||||
if (!vertex->has_normal() && has_normal()) {
|
||||
vertex->copy_normal(*this);
|
||||
}
|
||||
if (!vertex->has_color() && has_color()) {
|
||||
vertex->copy_color(*this);
|
||||
}
|
||||
|
||||
// Now see if any ended up different.
|
||||
EggAttributes overall;
|
||||
bool normal_different = false;
|
||||
bool color_different = false;
|
||||
vertex = vertex->get_pool()->create_unique_vertex(*vertex);
|
||||
replace(pi, vertex);
|
||||
}
|
||||
clear_normal();
|
||||
clear_color();
|
||||
}
|
||||
break;
|
||||
|
||||
Vertices::iterator vi;
|
||||
for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
|
||||
EggVertex *vertex = (*vi);
|
||||
if (!all_have_normal) {
|
||||
vertex->clear_normal();
|
||||
} else if (!normal_different) {
|
||||
if (!overall.has_normal()) {
|
||||
overall.set_normal(vertex->get_normal());
|
||||
overall._dnormals = vertex->_dnormals;
|
||||
} else if (overall.get_normal() != vertex->get_normal() ||
|
||||
overall._dnormals.compare_to(vertex->_dnormals) != 0) {
|
||||
normal_different = true;
|
||||
case S_per_face:
|
||||
case S_overall:
|
||||
// Remove everything from the vertices.
|
||||
{
|
||||
iterator pi;
|
||||
for (pi = begin(); pi != end(); ++pi) {
|
||||
EggVertex *vertex = (*pi);
|
||||
if (vertex->has_normal()) {
|
||||
if (!has_normal()) {
|
||||
copy_normal(*vertex);
|
||||
}
|
||||
vertex->clear_normal();
|
||||
}
|
||||
if (vertex->has_color()) {
|
||||
if (!has_color()) {
|
||||
copy_color(*vertex);
|
||||
}
|
||||
vertex->clear_color();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!all_have_color) {
|
||||
vertex->clear_color();
|
||||
} else if (!color_different) {
|
||||
if (!overall.has_color()) {
|
||||
overall.set_color(vertex->get_color());
|
||||
overall._drgbas = vertex->_drgbas;
|
||||
} else if (overall.get_color() != vertex->get_color() ||
|
||||
overall._drgbas.compare_to(vertex->_drgbas) != 0) {
|
||||
color_different = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
if (!overall.has_normal()) {
|
||||
normal_different = true;
|
||||
}
|
||||
if (!overall.has_color()) {
|
||||
color_different = true;
|
||||
}
|
||||
|
||||
if (!color_different || !normal_different) {
|
||||
// Ok, it's flat-shaded after all. Go back through and remove
|
||||
// this stuff from the vertices.
|
||||
if (!normal_different) {
|
||||
set_normal(overall.get_normal());
|
||||
_dnormals = overall._dnormals;
|
||||
}
|
||||
if (!color_different) {
|
||||
set_color(overall.get_color());
|
||||
_drgbas = overall._drgbas;
|
||||
}
|
||||
for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
|
||||
EggVertex *vertex = (*vi);
|
||||
if (!normal_different) {
|
||||
vertex->clear_normal();
|
||||
}
|
||||
if (!color_different) {
|
||||
vertex->clear_color();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, move the new vertices to the vertex pool.
|
||||
EggVertexPool *vertex_pool = get_pool();
|
||||
for (size_t i = 0; i < vertices.size(); i++) {
|
||||
EggVertex *vertex = vertices[i];
|
||||
vertex = vertex_pool->create_unique_vertex(*vertex);
|
||||
set_vertex(i, vertex);
|
||||
case S_unknown:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -399,7 +409,7 @@ unify_attributes() {
|
|||
// Description: Sets the last vertex of the triangle (or each
|
||||
// component) to the primitive normal and/or color, if
|
||||
// the primitive is flat-shaded. This reflects the
|
||||
// Panda convention of storing flat-shaded properties on
|
||||
// OpenGL convention of storing flat-shaded properties on
|
||||
// the last vertex, although it is not usually a
|
||||
// convention in Egg.
|
||||
//
|
||||
|
|
@ -409,50 +419,32 @@ unify_attributes() {
|
|||
void EggPrimitive::
|
||||
apply_last_attribute() {
|
||||
if (!empty()) {
|
||||
// The significant_change flag is set if we have changed the
|
||||
// vertex in some important way, that will invalidate it for other
|
||||
// primitives that might share it. We don't consider *adding* a
|
||||
// normal where there wasn't one before to be significant, but we
|
||||
// do consider it significant to change a vertex's normal to
|
||||
// something different. Similarly for color.
|
||||
bool significant_change = false;
|
||||
|
||||
EggVertex *orig_vertex = get_vertex(size() - 1);
|
||||
PT(EggVertex) new_vertex = new EggVertex(*orig_vertex);
|
||||
|
||||
if (has_normal()) {
|
||||
new_vertex->set_normal(get_normal());
|
||||
new_vertex->_dnormals = _dnormals;
|
||||
|
||||
if (orig_vertex->has_normal() &&
|
||||
(orig_vertex->get_normal() != new_vertex->get_normal() ||
|
||||
orig_vertex->_dnormals.compare_to(new_vertex->_dnormals) != 0)) {
|
||||
significant_change = true;
|
||||
}
|
||||
}
|
||||
if (has_color()) {
|
||||
new_vertex->set_color(get_color());
|
||||
new_vertex->_drgbas = _drgbas;
|
||||
|
||||
if (orig_vertex->has_color() &&
|
||||
(orig_vertex->get_color() != new_vertex->get_color() ||
|
||||
orig_vertex->_drgbas.compare_to(new_vertex->_drgbas) != 0)) {
|
||||
significant_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (significant_change) {
|
||||
new_vertex = get_pool()->create_unique_vertex(*new_vertex);
|
||||
set_vertex(size() - 1, new_vertex);
|
||||
} else {
|
||||
// Just copy the new attributes back into the pool.
|
||||
((EggAttributes *)orig_vertex)->operator = (*new_vertex);
|
||||
}
|
||||
do_apply_flat_attribute(size() - 1, this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggPrimitive::post_apply_last_attribute
|
||||
// Function: EggPrimitive::apply_first_attribute
|
||||
// Access: Published, Virtual
|
||||
// Description: Sets the first vertex of the triangle (or each
|
||||
// component) to the primitive normal and/or color, if
|
||||
// the primitive is flat-shaded. This reflects the
|
||||
// DirectX convention of storing flat-shaded properties on
|
||||
// the first vertex, although it is not usually a
|
||||
// convention in Egg.
|
||||
//
|
||||
// This may introduce redundant vertices to the vertex
|
||||
// pool.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggPrimitive::
|
||||
apply_first_attribute() {
|
||||
if (!empty()) {
|
||||
do_apply_flat_attribute(0, this);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggPrimitive::post_apply_flat_attribute
|
||||
// Access: Published, Virtual
|
||||
// Description: Intended as a followup to apply_last_attribute(),
|
||||
// this also sets an attribute on the first vertices of
|
||||
|
|
@ -460,11 +452,15 @@ apply_last_attribute() {
|
|||
// attribute set, just so they end up with *something*.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggPrimitive::
|
||||
post_apply_last_attribute() {
|
||||
post_apply_flat_attribute() {
|
||||
if (!empty()) {
|
||||
for (int i = 0; i < (int)size(); i++) {
|
||||
EggVertex *vertex = get_vertex(i);
|
||||
|
||||
// Use set_normal() instead of copy_normal(), to avoid getting
|
||||
// the morphs--we don't want them here, since we're just putting
|
||||
// a bogus value on the normal anyway.
|
||||
|
||||
if (has_normal() && !vertex->has_normal()) {
|
||||
vertex->set_normal(get_normal());
|
||||
}
|
||||
|
|
@ -1042,3 +1038,111 @@ r_apply_texmats(EggTextureCollection &textures) {
|
|||
|
||||
_textures.swap(new_textures);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggPrimitive::apply_attribute_to_vertex
|
||||
// Access: Protected
|
||||
// Description: This is used to implement apply_first_attribute() and
|
||||
// apply_last_attribute(). It copies the indicated
|
||||
// attributes to the specified vertex.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggPrimitive::
|
||||
do_apply_flat_attribute(int vertex_index, EggAttributes *attrib) {
|
||||
// The significant_change flag is set if we have changed the
|
||||
// vertex in some important way, that will invalidate it for other
|
||||
// primitives that might share it. We don't consider *adding* a
|
||||
// normal where there wasn't one before to be significant, but we
|
||||
// do consider it significant to change a vertex's normal to
|
||||
// something different. Similarly for color.
|
||||
bool significant_change = false;
|
||||
|
||||
EggVertex *orig_vertex = get_vertex(vertex_index);
|
||||
PT(EggVertex) new_vertex = new EggVertex(*orig_vertex);
|
||||
|
||||
if (attrib->has_normal()) {
|
||||
new_vertex->copy_normal(*attrib);
|
||||
|
||||
if (orig_vertex->has_normal() &&
|
||||
!orig_vertex->matches_normal(*new_vertex)) {
|
||||
significant_change = true;
|
||||
}
|
||||
} else if (has_normal()) {
|
||||
new_vertex->copy_normal(*this);
|
||||
|
||||
if (orig_vertex->has_normal() &&
|
||||
!orig_vertex->matches_normal(*new_vertex)) {
|
||||
significant_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (attrib->has_color()) {
|
||||
new_vertex->copy_color(*attrib);
|
||||
|
||||
if (orig_vertex->has_color() &&
|
||||
!orig_vertex->matches_color(*new_vertex)) {
|
||||
significant_change = true;
|
||||
}
|
||||
} else if (has_color()) {
|
||||
new_vertex->copy_color(*this);
|
||||
|
||||
if (orig_vertex->has_color() &&
|
||||
!orig_vertex->matches_color(*new_vertex)) {
|
||||
significant_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (significant_change) {
|
||||
new_vertex = get_pool()->create_unique_vertex(*new_vertex);
|
||||
set_vertex(vertex_index, new_vertex);
|
||||
} else {
|
||||
// Just copy the new attributes back into the pool.
|
||||
((EggAttributes *)orig_vertex)->operator = (*new_vertex);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggPrimitive::set_connected_shading
|
||||
// Access: Private
|
||||
// Description: Recursively updates the connected_shading member in
|
||||
// all connected primitives.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggPrimitive::
|
||||
set_connected_shading(EggPrimitive::Shading shading,
|
||||
const EggAttributes *neighbor) {
|
||||
bool propagate = false;
|
||||
|
||||
if (_connected_shading == S_unknown) {
|
||||
// We haven't visited this node before; propagate now.
|
||||
_connected_shading = get_shading();
|
||||
propagate = true;
|
||||
}
|
||||
|
||||
if (shading > _connected_shading) {
|
||||
// More specific information just came in. Save it, and propagate
|
||||
// it to all connected primitives.
|
||||
_connected_shading = shading;
|
||||
propagate = true;
|
||||
|
||||
} else if (shading == S_overall && _connected_shading == S_overall) {
|
||||
// If both neighbors are overall shaded, check if the two
|
||||
// neighbors have different properties. If they do, elevate to
|
||||
// per_face.
|
||||
if (!matches_normal(*neighbor) || !matches_color(*neighbor)) {
|
||||
_connected_shading = S_per_face;
|
||||
propagate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (propagate) {
|
||||
Vertices::const_iterator vi;
|
||||
for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
|
||||
EggVertex *vertex = (*vi);
|
||||
EggVertex::PrimitiveRef::const_iterator pi;
|
||||
for (pi = vertex->pref_begin();
|
||||
pi != vertex->pref_end();
|
||||
++pi) {
|
||||
(*pi)->set_connected_shading(_connected_shading, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,15 @@ private:
|
|||
// Here begins the actual public interface to EggPrimitive.
|
||||
|
||||
PUBLISHED:
|
||||
enum Shading {
|
||||
// The order here is important. The later choices are more
|
||||
// specific than the earlier ones.
|
||||
S_unknown,
|
||||
S_overall,
|
||||
S_per_face,
|
||||
S_per_vertex
|
||||
};
|
||||
|
||||
INLINE EggPrimitive(const string &name = "");
|
||||
INLINE EggPrimitive(const EggPrimitive ©);
|
||||
INLINE EggPrimitive &operator = (const EggPrimitive ©);
|
||||
|
|
@ -78,6 +87,10 @@ PUBLISHED:
|
|||
virtual EggRenderMode *determine_draw_order();
|
||||
virtual EggRenderMode *determine_bin();
|
||||
|
||||
virtual Shading get_shading() const;
|
||||
INLINE void clear_connected_shading();
|
||||
INLINE Shading get_connected_shading();
|
||||
|
||||
INLINE void set_texture(EggTexture *texture);
|
||||
INLINE bool has_texture() const;
|
||||
INLINE bool has_texture(EggTexture *texture) const;
|
||||
|
|
@ -101,11 +114,11 @@ PUBLISHED:
|
|||
|
||||
bool has_vertex_normal() const;
|
||||
bool has_vertex_color() const;
|
||||
bool is_flat_shaded() const;
|
||||
|
||||
virtual void unify_attributes();
|
||||
virtual void unify_attributes(Shading shading);
|
||||
virtual void apply_last_attribute();
|
||||
virtual void post_apply_last_attribute();
|
||||
virtual void apply_first_attribute();
|
||||
virtual void post_apply_flat_attribute();
|
||||
virtual void reverse_vertex_ordering();
|
||||
virtual bool cleanup();
|
||||
|
||||
|
|
@ -180,7 +193,6 @@ protected:
|
|||
virtual void prepare_add_vertex(EggVertex *vertex, int i, int n);
|
||||
virtual void prepare_remove_vertex(EggVertex *vertex, int i, int n);
|
||||
|
||||
|
||||
protected:
|
||||
void write_body(ostream &out, int indent_level) const;
|
||||
|
||||
|
|
@ -190,12 +202,17 @@ protected:
|
|||
virtual void r_flatten_transforms();
|
||||
virtual void r_apply_texmats(EggTextureCollection &textures);
|
||||
|
||||
void do_apply_flat_attribute(int vertex_index, EggAttributes *attrib);
|
||||
|
||||
private:
|
||||
void set_connected_shading(Shading shading, const EggAttributes *neighbor);
|
||||
|
||||
private:
|
||||
typedef vector_PT_EggTexture Textures;
|
||||
Textures _textures;
|
||||
PT_EggMaterial _material;
|
||||
bool _bface;
|
||||
Shading _connected_shading;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,52 @@
|
|||
TypeHandle EggTriangleStrip::_type_handle;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggTriangleStrip::apply_last_attribute
|
||||
// Access: Published, Virtual
|
||||
// Description: Sets the last vertex of the triangle (or each
|
||||
// component) to the primitive normal and/or color, if
|
||||
// the primitive is flat-shaded. This reflects the
|
||||
// OpenGL convention of storing flat-shaded properties on
|
||||
// the last vertex, although it is not usually a
|
||||
// convention in Egg.
|
||||
//
|
||||
// This may introduce redundant vertices to the vertex
|
||||
// pool.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggTriangleStrip::
|
||||
apply_last_attribute() {
|
||||
// The first component gets applied to the third vertex, and so on
|
||||
// from there.
|
||||
for (int i = 0; i < get_num_components(); i++) {
|
||||
EggAttributes *component = get_component(i);
|
||||
do_apply_flat_attribute(i + 2, component);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggTriangleStrip::apply_first_attribute
|
||||
// Access: Published, Virtual
|
||||
// Description: Sets the first vertex of the triangle (or each
|
||||
// component) to the primitive normal and/or color, if
|
||||
// the primitive is flat-shaded. This reflects the
|
||||
// DirectX convention of storing flat-shaded properties
|
||||
// on the first vertex, although it is not usually a
|
||||
// convention in Egg.
|
||||
//
|
||||
// This may introduce redundant vertices to the vertex
|
||||
// pool.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggTriangleStrip::
|
||||
apply_first_attribute() {
|
||||
// The first component gets applied to the first vertex, and so on
|
||||
// from there.
|
||||
for (int i = 0; i < get_num_components(); i++) {
|
||||
EggAttributes *component = get_component(i);
|
||||
do_apply_flat_attribute(i, component);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggTriangleStrip::write
|
||||
// Access: Published, Virtual
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ PUBLISHED:
|
|||
INLINE EggTriangleStrip(const EggTriangleStrip ©);
|
||||
INLINE EggTriangleStrip &operator = (const EggTriangleStrip ©);
|
||||
|
||||
virtual void apply_last_attribute();
|
||||
virtual void apply_first_attribute();
|
||||
|
||||
virtual void write(ostream &out, int indent_level) const;
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -95,15 +95,6 @@ sorts_less(int bin_number, const EggNode *a, const EggNode *b) {
|
|||
return (compare < 0);
|
||||
}
|
||||
|
||||
// If the render state indicates indexed, meaning we keep the
|
||||
// existing vertex pools, then different pools get sorted
|
||||
// separately.
|
||||
if (rsa->_indexed) {
|
||||
if (pa->get_pool() != pb->get_pool()) {
|
||||
return pa->get_pool() < pb->get_pool();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,32 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::PrimitiveUnifier::operator <
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE EggLoader::PrimitiveUnifier::
|
||||
PrimitiveUnifier(const qpGeomPrimitive *prim) :
|
||||
_type(prim->get_type()),
|
||||
_shade_model(prim->get_shade_model())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::PrimitiveUnifier::operator <
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool EggLoader::PrimitiveUnifier::
|
||||
operator < (const PrimitiveUnifier &other) const {
|
||||
if (_type != other._type) {
|
||||
return _type < other._type;
|
||||
}
|
||||
return _shade_model < other._shade_model;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::VertexPoolTransform::operator <
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -157,8 +157,13 @@ build_graph() {
|
|||
// First, load up all of the textures.
|
||||
load_textures();
|
||||
|
||||
// Clean up the vertices.
|
||||
_data->clear_connected_shading();
|
||||
_data->remove_unused_vertices(true);
|
||||
_data->unify_attributes(true, true);
|
||||
|
||||
// Then bin up the polysets and LOD nodes.
|
||||
_data->remove_invalid_primitives();
|
||||
_data->remove_invalid_primitives(true);
|
||||
EggBinner binner(*this);
|
||||
binner.make_bins(_data);
|
||||
|
||||
|
|
@ -1439,19 +1444,11 @@ make_polyset(EggBin *egg_bin, PandaNode *parent) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// In the normal case--not indexed--we can generate an optimal
|
||||
// vertex pool for the polygons in the bin (which translates
|
||||
// directly to an optimal GeomVertexData structure). However, if
|
||||
// the indexed flag is set on these polygons, we don't do this,
|
||||
// since the indexed flag means to use the supplied vertex pool
|
||||
// exactly as it is.
|
||||
PT(EggVertexPool) vertex_pool;
|
||||
if (!render_state->_indexed) {
|
||||
vertex_pool = new EggVertexPool("bin");
|
||||
egg_bin->rebuild_vertex_pool(vertex_pool, false);
|
||||
} else {
|
||||
vertex_pool = first_prim->get_pool();
|
||||
}
|
||||
// Generate an optimal vertex pool for the polygons within just the
|
||||
// bin (which translates directly to an optimal GeomVertexData
|
||||
// structure).
|
||||
PT(EggVertexPool) vertex_pool = new EggVertexPool("bin");
|
||||
egg_bin->rebuild_vertex_pool(vertex_pool, false);
|
||||
|
||||
if (egg_mesh) {
|
||||
// If we're using the mesher, mesh now.
|
||||
|
|
@ -1463,13 +1460,11 @@ make_polyset(EggBin *egg_bin, PandaNode *parent) {
|
|||
egg_bin->triangulate_polygons(EggGroupNode::T_polygon | EggGroupNode::T_convex);
|
||||
}
|
||||
|
||||
if (!render_state->_indexed) {
|
||||
// Now that we've meshed, apply the per-prim attributes onto the
|
||||
// vertices, so we can copy them to the GeomVertexData.
|
||||
egg_bin->apply_last_attribute(false);
|
||||
egg_bin->post_apply_last_attribute(false);
|
||||
vertex_pool->remove_unused_vertices();
|
||||
}
|
||||
// Now that we've meshed, apply the per-prim attributes onto the
|
||||
// vertices, so we can copy them to the GeomVertexData.
|
||||
egg_bin->apply_first_attribute(false);
|
||||
egg_bin->post_apply_flat_attribute(false);
|
||||
vertex_pool->remove_unused_vertices();
|
||||
|
||||
// vertex_pool->write(cerr, 0);
|
||||
// egg_bin->write(cerr, 0);
|
||||
|
|
@ -1480,7 +1475,7 @@ make_polyset(EggBin *egg_bin, PandaNode *parent) {
|
|||
for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
|
||||
EggPrimitive *egg_prim;
|
||||
DCAST_INTO_R(egg_prim, (*ci), NULL);
|
||||
make_primitive(egg_prim, primitives);
|
||||
make_primitive(render_state, egg_prim, primitives);
|
||||
}
|
||||
|
||||
if (!primitives.empty()) {
|
||||
|
|
@ -1977,7 +1972,8 @@ make_vertex_data(EggVertexPool *vertex_pool, const LMatrix4d &transform) {
|
|||
// indicated EggPrimitive, and adds it to the set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggLoader::
|
||||
make_primitive(EggPrimitive *egg_prim, EggLoader::Primitives &primitives) {
|
||||
make_primitive(const EggRenderState *render_state, EggPrimitive *egg_prim,
|
||||
EggLoader::Primitives &primitives) {
|
||||
PT(qpGeomPrimitive) primitive;
|
||||
if (egg_prim->is_of_type(EggPolygon::get_class_type())) {
|
||||
if (egg_prim->size() == 3) {
|
||||
|
|
@ -1989,13 +1985,26 @@ make_primitive(EggPrimitive *egg_prim, EggLoader::Primitives &primitives) {
|
|||
|
||||
if (primitive == (qpGeomPrimitive *)NULL) {
|
||||
// Don't know how to make this kind of primitive.
|
||||
egg2pg_cat.warning()
|
||||
<< "Ignoring " << egg_prim->get_class_type() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (render_state->_flat_shaded) {
|
||||
primitive->set_shade_model(qpGeomPrimitive::SM_flat_first_vertex);
|
||||
|
||||
} else if (egg_prim->get_shading() == EggPrimitive::S_overall) {
|
||||
primitive->set_shade_model(qpGeomPrimitive::SM_uniform);
|
||||
|
||||
} else {
|
||||
primitive->set_shade_model(qpGeomPrimitive::SM_smooth);
|
||||
}
|
||||
|
||||
// Insert the primitive into the set, but if we already have a
|
||||
// primitive of that type, reset the pointer to that one instead.
|
||||
PrimitiveUnifier pu(primitive);
|
||||
pair<Primitives::iterator, bool> result =
|
||||
primitives.insert(Primitives::value_type(primitive->get_type(), primitive));
|
||||
primitives.insert(Primitives::value_type(pu, primitive));
|
||||
primitive = (*result.first).second;
|
||||
|
||||
// Now add the vertices.
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class CollisionPlane;
|
|||
class CollisionPolygon;
|
||||
class PortalNode;
|
||||
class PolylightNode;
|
||||
class EggRenderState;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Class : EggLoader
|
||||
|
|
@ -99,7 +100,15 @@ private:
|
|||
typedef pmap<CPT(InternalName), const EggTexture *> BakeInUVs;
|
||||
|
||||
// This is used by make_primitive().
|
||||
typedef pmap<TypeHandle, PT(qpGeomPrimitive) > Primitives;
|
||||
class PrimitiveUnifier {
|
||||
public:
|
||||
INLINE PrimitiveUnifier(const qpGeomPrimitive *prim);
|
||||
INLINE bool operator < (const PrimitiveUnifier &other) const;
|
||||
|
||||
TypeHandle _type;
|
||||
qpGeomPrimitive::ShadeModel _shade_model;
|
||||
};
|
||||
typedef pmap<PrimitiveUnifier, PT(qpGeomPrimitive) > Primitives;
|
||||
|
||||
void make_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent,
|
||||
const LMatrix4d &mat);
|
||||
|
|
@ -130,7 +139,8 @@ private:
|
|||
bool &any_hidden);
|
||||
PT(qpGeomVertexData) make_vertex_data(EggVertexPool *vertex_pool,
|
||||
const LMatrix4d &transform);
|
||||
void make_primitive(EggPrimitive *egg_prim, Primitives &primitives);
|
||||
void make_primitive(const EggRenderState *render_state,
|
||||
EggPrimitive *egg_prim, Primitives &primitives);
|
||||
|
||||
void set_portal_polygon(EggGroup *egg_group, PortalNode *pnode);
|
||||
PT(EggPolygon) find_first_polygon(EggGroup *egg_group);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ EggRenderState::
|
|||
EggRenderState(EggLoader &loader) :
|
||||
_state(RenderState::make_empty()),
|
||||
_hidden(false),
|
||||
_indexed(false),
|
||||
_flat_shaded(false),
|
||||
_loader(loader)
|
||||
{
|
||||
}
|
||||
|
|
@ -57,8 +57,8 @@ compare_to(const EggRenderState &other) const {
|
|||
if (_hidden != other._hidden) {
|
||||
return (int)_hidden - (int)other._hidden;
|
||||
}
|
||||
if (_indexed != other._indexed) {
|
||||
return (int)_indexed - (int)other._indexed;
|
||||
if (_flat_shaded != other._flat_shaded) {
|
||||
return (int)_flat_shaded - (int)other._flat_shaded;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -340,24 +340,11 @@ fill_state(EggPrimitive *egg_prim) {
|
|||
break;
|
||||
}
|
||||
|
||||
_indexed = egg_prim->determine_indexed();
|
||||
|
||||
bool flat_shaded;
|
||||
|
||||
if (!_indexed) {
|
||||
// If the primitive is not indexed, we're allowed to call
|
||||
// unify_attributes(), which will modify the vertex pool.
|
||||
egg_prim->unify_attributes();
|
||||
flat_shaded = egg_prim->is_flat_shaded();
|
||||
|
||||
} else {
|
||||
// If the primitive *is* indexed, we're not allowed to modify the
|
||||
// vertex pool, and so we won't have flat shading anyway.
|
||||
flat_shaded = false;
|
||||
}
|
||||
_flat_shaded =
|
||||
(egg_prim->get_connected_shading() == EggPrimitive::S_per_face);
|
||||
|
||||
if (use_qpgeom) {
|
||||
if (flat_shaded) {
|
||||
if (_flat_shaded) {
|
||||
add_attrib(ShadeModelAttrib::make(ShadeModelAttrib::M_flat));
|
||||
} else {
|
||||
add_attrib(ShadeModelAttrib::make(ShadeModelAttrib::M_smooth));
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ private:
|
|||
public:
|
||||
CPT(RenderState) _state;
|
||||
bool _hidden;
|
||||
bool _indexed;
|
||||
bool _flat_shaded;
|
||||
|
||||
typedef EggLoader::BakeInUVs BakeInUVs;
|
||||
typedef EggLoader::TextureDef TextureDef;
|
||||
|
|
|
|||
|
|
@ -23,5 +23,7 @@
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CLP(GeomMunger)::
|
||||
CLP(GeomMunger)() {
|
||||
CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state) :
|
||||
qpGeomMunger(gsg, state)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "pandabase.h"
|
||||
#include "qpgeomMunger.h"
|
||||
#include "graphicsStateGuardian.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : GLGeomMunger
|
||||
|
|
@ -27,7 +28,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_GL CLP(GeomMunger) : public qpGeomMunger {
|
||||
public:
|
||||
INLINE CLP(GeomMunger)();
|
||||
INLINE CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state);
|
||||
|
||||
protected:
|
||||
virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig);
|
||||
|
|
|
|||
|
|
@ -2058,14 +2058,14 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) {
|
|||
// Description: Draws a series of disconnected triangles.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CLP(GraphicsStateGuardian)::
|
||||
draw_triangles(qpGeomTriangles *primitive) {
|
||||
draw_triangles(const qpGeomTriangles *primitive) {
|
||||
setup_antialias_polygon();
|
||||
|
||||
_glDrawRangeElements(GL_TRIANGLES,
|
||||
primitive->get_min_vertex(),
|
||||
primitive->get_max_vertex(),
|
||||
primitive->get_num_vertices(),
|
||||
GL_UNSIGNED_SHORT, primitive->get_vertices());
|
||||
GL_UNSIGNED_SHORT, primitive->get_flat_last_vertices());
|
||||
|
||||
report_my_gl_errors();
|
||||
}
|
||||
|
|
@ -2283,8 +2283,8 @@ static int binary_log_cap(const int x) {
|
|||
// appropriate to this GSG for the indicated state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(qpGeomMunger) CLP(GraphicsStateGuardian)::
|
||||
get_geom_munger(const RenderState *) {
|
||||
PT(CLP(GeomMunger)) munger = new CLP(GeomMunger);
|
||||
get_geom_munger(const RenderState *state) {
|
||||
PT(CLP(GeomMunger)) munger = new CLP(GeomMunger)(this, state);
|
||||
return qpGeomMunger::register_munger(munger);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public:
|
|||
virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
|
||||
|
||||
virtual bool begin_draw_primitives(const qpGeomVertexData *vertex_data);
|
||||
virtual void draw_triangles(qpGeomTriangles *primitive);
|
||||
virtual void draw_triangles(const qpGeomTriangles *primitive);
|
||||
virtual void end_draw_primitives();
|
||||
|
||||
INLINE bool draw_display_list(GeomContext *gc);
|
||||
|
|
|
|||
|
|
@ -1221,11 +1221,6 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
|||
CPT(InternalName) tc = DCAST(InternalName, p_list[pi++]);
|
||||
TexCoordDef *def = (*ci);
|
||||
_texcoords_by_name[tc] = *def;
|
||||
/*
|
||||
cerr << "InternalName from Geom " << (void *)this
|
||||
<< " complete pointers " << tc << " " << *tc
|
||||
<< " = " << def->_texcoords << " and " << def->_tindex << "\n";
|
||||
*/
|
||||
delete def;
|
||||
if (tc == InternalName::get_texcoord()) {
|
||||
_bind[G_TEXCOORD] = G_PER_VERTEX;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ get_primitive(int i) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomPrimitive *qpGeom::
|
||||
modify_primitive(int i) {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
nassertr(i >= 0 && i < (int)cdata->_primitives.size(), NULL);
|
||||
return cdata->_primitives[i];
|
||||
|
|
@ -80,10 +81,11 @@ modify_primitive(int i) {
|
|||
// the Geom with the new object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeom::
|
||||
set_primitive(int i, qpGeomPrimitive *primitive) {
|
||||
set_primitive(int i, const qpGeomPrimitive *primitive) {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
nassertv(i >= 0 && i < (int)cdata->_primitives.size());
|
||||
cdata->_primitives[i] = primitive;
|
||||
cdata->_primitives[i] = (qpGeomPrimitive *)primitive;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qpgeom.h"
|
||||
#include "qpgeomVertexCacheManager.h"
|
||||
#include "pStatTimer.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
|
||||
|
|
@ -58,6 +60,7 @@ operator = (const qpGeom ©) {
|
|||
TypedWritableReferenceCount::operator = (copy);
|
||||
BoundedObject::operator = (copy);
|
||||
*/
|
||||
clear_cache();
|
||||
Geom::operator = (copy);
|
||||
_cycler = copy._cycler;
|
||||
mark_bound_stale();
|
||||
|
|
@ -70,6 +73,25 @@ operator = (const qpGeom ©) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
qpGeom::
|
||||
~qpGeom() {
|
||||
// When we destruct, we should ensure that all of our cached
|
||||
// entries, across all pipeline stages, are properly removed from
|
||||
// the cache manager.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
|
||||
int num_stages = _cycler.get_num_stages();
|
||||
for (int i = 0; i < num_stages; i++) {
|
||||
if (_cycler.is_stage_unique(i)) {
|
||||
CData *cdata = _cycler.write_stage(i);
|
||||
for (MungedCache::iterator ci = cdata->_munged_cache.begin();
|
||||
ci != cdata->_munged_cache.end();
|
||||
++ci) {
|
||||
cache_mgr->remove_geom(this, (*ci).first);
|
||||
}
|
||||
cdata->_munged_cache.clear();
|
||||
_cycler.release_write_stage(i, cdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -94,7 +116,7 @@ modify_vertex_data() {
|
|||
// Perform copy-on-write: if the reference count on the vertex data
|
||||
// is greater than 1, assume some other Geom has the same pointer,
|
||||
// so make a copy of it first.
|
||||
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
if (cdata->_data->get_ref_count() > 1) {
|
||||
cdata->_data = new qpGeomVertexData(*cdata->_data);
|
||||
|
|
@ -110,9 +132,10 @@ modify_vertex_data() {
|
|||
// a completely new table.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeom::
|
||||
set_vertex_data(PT(qpGeomVertexData) data) {
|
||||
set_vertex_data(const qpGeomVertexData *data) {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_data = data;
|
||||
cdata->_data = (qpGeomVertexData *)data;
|
||||
mark_bound_stale();
|
||||
}
|
||||
|
||||
|
|
@ -125,9 +148,10 @@ set_vertex_data(PT(qpGeomVertexData) data) {
|
|||
// of the indicated type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeom::
|
||||
add_primitive(qpGeomPrimitive *primitive) {
|
||||
add_primitive(const qpGeomPrimitive *primitive) {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_primitives.push_back(primitive);
|
||||
cdata->_primitives.push_back((qpGeomPrimitive *)primitive);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -137,6 +161,7 @@ add_primitive(qpGeomPrimitive *primitive) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeom::
|
||||
remove_primitive(int i) {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
nassertv(i >= 0 && i < (int)cdata->_primitives.size());
|
||||
cdata->_primitives.erase(cdata->_primitives.begin() + i);
|
||||
|
|
@ -152,10 +177,97 @@ remove_primitive(int i) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeom::
|
||||
clear_primitives() {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_primitives.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::get_num_bytes
|
||||
// Access: Published
|
||||
// Description: Returns the number of bytes consumed by the geom and
|
||||
// its primitives (but not including its vertex table).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int qpGeom::
|
||||
get_num_bytes() const {
|
||||
CDReader cdata(_cycler);
|
||||
|
||||
int num_bytes = sizeof(qpGeom);
|
||||
Primitives::const_iterator pi;
|
||||
for (pi = cdata->_primitives.begin();
|
||||
pi != cdata->_primitives.end();
|
||||
++pi) {
|
||||
num_bytes += (*pi)->get_num_bytes();
|
||||
}
|
||||
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::munge_geom
|
||||
// Access: Published
|
||||
// Description: Applies the indicated munger to the geom and its
|
||||
// data, and returns a (possibly different) geom and
|
||||
// data, according to the munger's whim.
|
||||
//
|
||||
// The assumption is that for a particular geom and a
|
||||
// particular munger, the result will always be the
|
||||
// same; so this result may be cached.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeom::
|
||||
munge_geom(const qpGeomMunger *munger,
|
||||
CPT(qpGeom) &result, CPT(qpGeomVertexData) &data) const {
|
||||
// Look up the format in our cache--maybe we've recently applied the
|
||||
// indicated munger.
|
||||
{
|
||||
// Use read() and release_read() instead of CDReader, because the
|
||||
// call to record_geom() might recursively call back into this
|
||||
// object, and require a write.
|
||||
const CData *cdata = _cycler.read();
|
||||
MungedCache::const_iterator ci = cdata->_munged_cache.find(munger);
|
||||
if (ci != cdata->_munged_cache.end()) {
|
||||
_cycler.release_read(cdata);
|
||||
// Record a cache hit, so this element will stay in the cache a
|
||||
// while longer.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
cache_mgr->record_geom(this, munger,
|
||||
(*ci).second._geom->get_num_bytes() +
|
||||
(*ci).second._data->get_num_bytes());
|
||||
|
||||
result = (*ci).second._geom;
|
||||
data = (*ci).second._data;
|
||||
return;
|
||||
}
|
||||
_cycler.release_read(cdata);
|
||||
}
|
||||
|
||||
// Ok, invoke the munger.
|
||||
PStatTimer timer(qpGeomMunger::_munge_pcollector);
|
||||
|
||||
result = this;
|
||||
data = munger->munge_data(get_vertex_data());
|
||||
((qpGeomMunger *)munger)->munge_geom_impl(result, data);
|
||||
|
||||
if (result.p() != this) {
|
||||
// Record the new result in the cache.
|
||||
{
|
||||
CDWriter cdata(((qpGeom *)this)->_cycler);
|
||||
MungeResult &mr = cdata->_munged_cache[munger];
|
||||
mr._geom = result;
|
||||
mr._data = data;
|
||||
}
|
||||
|
||||
// And tell the cache manager about the new entry. (It might
|
||||
// immediately request a delete from the cache of the thing we just
|
||||
// added.)
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
cache_mgr->record_geom(this, munger,
|
||||
result->get_num_bytes() + data->get_num_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::output
|
||||
// Access: Published
|
||||
|
|
@ -200,6 +312,28 @@ write(ostream &out, int indent_level) const {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::clear_cache
|
||||
// Access: Published
|
||||
// Description: Removes all of the previously-cached results of
|
||||
// munge_geom().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeom::
|
||||
clear_cache() {
|
||||
// Probably we shouldn't do anything at all here unless we are
|
||||
// running in pipeline stage 0.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
|
||||
CData *cdata = CDWriter(_cycler);
|
||||
for (MungedCache::iterator ci = cdata->_munged_cache.begin();
|
||||
ci != cdata->_munged_cache.end();
|
||||
++ci) {
|
||||
cache_mgr->remove_geom(this, (*ci).first);
|
||||
}
|
||||
cdata->_munged_cache.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::draw
|
||||
// Access: Public
|
||||
|
|
@ -291,6 +425,27 @@ recompute_bound() {
|
|||
return bound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::remove_cache_entry
|
||||
// Access: Private
|
||||
// Description: Removes a particular entry from the local cache; it
|
||||
// has already been removed from the cache manager.
|
||||
// This is only called from GeomVertexCacheManager.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeom::
|
||||
remove_cache_entry(const qpGeomMunger *modifier) const {
|
||||
// We have to operate on stage 0 of the pipeline, since that's where
|
||||
// the cache really counts. Because of the multistage pipeline, we
|
||||
// might not actually have a cache entry there (it might have been
|
||||
// added to stage 1 instead). No big deal if we don't.
|
||||
CData *cdata = ((qpGeom *)this)->_cycler.write_stage(0);
|
||||
MungedCache::iterator ci = cdata->_munged_cache.find(modifier);
|
||||
if (ci != cdata->_munged_cache.end()) {
|
||||
cdata->_munged_cache.erase(ci);
|
||||
}
|
||||
((qpGeom *)this)->_cycler.release_write_stage(0, cdata);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeom::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "pipelineCycler.h"
|
||||
#include "qpgeomVertexData.h"
|
||||
#include "qpgeomPrimitive.h"
|
||||
#include "qpgeomMunger.h"
|
||||
#include "pointerTo.h"
|
||||
#include "geom.h"
|
||||
|
||||
|
|
@ -62,19 +63,26 @@ PUBLISHED:
|
|||
|
||||
INLINE CPT(qpGeomVertexData) get_vertex_data() const;
|
||||
PT(qpGeomVertexData) modify_vertex_data();
|
||||
void set_vertex_data(PT(qpGeomVertexData) data);
|
||||
void set_vertex_data(const qpGeomVertexData *data);
|
||||
|
||||
INLINE int get_num_primitives() const;
|
||||
INLINE const qpGeomPrimitive *get_primitive(int i) const;
|
||||
INLINE qpGeomPrimitive *modify_primitive(int i);
|
||||
INLINE void set_primitive(int i, qpGeomPrimitive *primitive);
|
||||
void add_primitive(qpGeomPrimitive *primitive);
|
||||
INLINE void set_primitive(int i, const qpGeomPrimitive *primitive);
|
||||
void add_primitive(const qpGeomPrimitive *primitive);
|
||||
void remove_primitive(int i);
|
||||
void clear_primitives();
|
||||
|
||||
int get_num_bytes() const;
|
||||
|
||||
void munge_geom(const qpGeomMunger *munger,
|
||||
CPT(qpGeom) &result, CPT(qpGeomVertexData) &data) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
void clear_cache();
|
||||
|
||||
public:
|
||||
void draw(GraphicsStateGuardianBase *gsg,
|
||||
const qpGeomVertexData *vertex_data) const;
|
||||
|
|
@ -82,9 +90,24 @@ public:
|
|||
protected:
|
||||
virtual BoundingVolume *recompute_bound();
|
||||
|
||||
private:
|
||||
void remove_cache_entry(const qpGeomMunger *modifier) const;
|
||||
|
||||
private:
|
||||
typedef pvector<PT(qpGeomPrimitive) > Primitives;
|
||||
|
||||
// We have to use reference-counting pointers here instead of having
|
||||
// explicit cleanup in the GeomVertexFormat destructor, because the
|
||||
// cache needs to be stored in the CycleData, which makes accurate
|
||||
// cleanup more difficult. We use the GeomVertexCacheManager class
|
||||
// to avoid cache bloat.
|
||||
class MungeResult {
|
||||
public:
|
||||
CPT(qpGeom) _geom;
|
||||
CPT(qpGeomVertexData) _data;
|
||||
};
|
||||
typedef pmap<CPT(qpGeomMunger), MungeResult> MungedCache;
|
||||
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
public:
|
||||
|
|
@ -97,6 +120,7 @@ private:
|
|||
|
||||
PT(qpGeomVertexData) _data;
|
||||
Primitives _primitives;
|
||||
MungedCache _munged_cache;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
|
|
@ -131,6 +155,8 @@ public:
|
|||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class qpGeomVertexCacheManager;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const qpGeom &obj);
|
||||
|
|
|
|||
|
|
@ -71,20 +71,6 @@ compare_to(const qpGeomMunger &other) const {
|
|||
return compare_to_impl(&other);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::munge_data
|
||||
// Access: Public
|
||||
// Description: Given a source GeomVertexData, converts it if
|
||||
// necessary to the appropriate data for rendering.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CPT(qpGeomVertexData) qpGeomMunger::
|
||||
munge_data(const qpGeomVertexData *data) const {
|
||||
// We cast away the const pointer, because do_munge_data() needs to
|
||||
// update caches and stuff, but we trust it not to change any
|
||||
// user-definable parameters.
|
||||
return ((qpGeomMunger *)this)->do_munge_data(data);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::munge_format
|
||||
// Access: Public
|
||||
|
|
@ -99,6 +85,20 @@ munge_format(const qpGeomVertexFormat *format) const {
|
|||
return ((qpGeomMunger *)this)->do_munge_format(format);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::munge_data
|
||||
// Access: Public
|
||||
// Description: Given a source GeomVertexData, converts it if
|
||||
// necessary to the appropriate data for rendering.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CPT(qpGeomVertexData) qpGeomMunger::
|
||||
munge_data(const qpGeomVertexData *data) const {
|
||||
// We cast away the const pointer, because do_munge_data() needs to
|
||||
// update caches and stuff, but we trust it not to change any
|
||||
// user-definable parameters.
|
||||
return ((qpGeomMunger *)this)->do_munge_data(data);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::get_registry
|
||||
// Access: Private
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ PStatCollector qpGeomMunger::_munge_pcollector("Cull:Munge");
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomMunger::
|
||||
qpGeomMunger() :
|
||||
qpGeomMunger(const GraphicsStateGuardianBase *, const RenderState *) :
|
||||
_is_registered(false)
|
||||
{
|
||||
}
|
||||
|
|
@ -92,28 +92,6 @@ remove_data(const qpGeomVertexData *data) {
|
|||
nassertv(_is_registered);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::do_munge_data
|
||||
// Access: Protected
|
||||
// Description: The protected implementation of munge_data(). This
|
||||
// exists just to cast away the const pointer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(qpGeomVertexData) qpGeomMunger::
|
||||
do_munge_data(const qpGeomVertexData *data) {
|
||||
nassertr(_is_registered, NULL);
|
||||
PStatTimer timer(_munge_pcollector);
|
||||
|
||||
CPT(qpGeomVertexFormat) orig_format = data->get_format();
|
||||
CPT(qpGeomVertexFormat) new_format = munge_format(orig_format);
|
||||
|
||||
if (new_format == orig_format) {
|
||||
// Trivial case.
|
||||
return data;
|
||||
}
|
||||
|
||||
return data->convert_to(new_format);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::do_munge_format
|
||||
// Access: Protected
|
||||
|
|
@ -161,6 +139,28 @@ do_munge_format(const qpGeomVertexFormat *format) {
|
|||
return derived_format;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::do_munge_data
|
||||
// Access: Protected
|
||||
// Description: The protected implementation of munge_data(). This
|
||||
// exists just to cast away the const pointer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(qpGeomVertexData) qpGeomMunger::
|
||||
do_munge_data(const qpGeomVertexData *data) {
|
||||
nassertr(_is_registered, NULL);
|
||||
PStatTimer timer(_munge_pcollector);
|
||||
|
||||
CPT(qpGeomVertexFormat) orig_format = data->get_format();
|
||||
CPT(qpGeomVertexFormat) new_format = munge_format(orig_format);
|
||||
|
||||
if (new_format == orig_format) {
|
||||
// Trivial case.
|
||||
return data;
|
||||
}
|
||||
|
||||
return data->convert_to(new_format);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::munge_format_impl
|
||||
// Access: Protected, Virtual
|
||||
|
|
@ -172,6 +172,16 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
|
|||
return orig;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::munge_geom_impl
|
||||
// Access: Protected, Virtual
|
||||
// Description: Converts a Geom and/or its data as necessary.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomMunger::
|
||||
munge_geom_impl(CPT(qpGeom) &, CPT(qpGeomVertexData) &) {
|
||||
// The default implementation does nothing.
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomMunger::compare_to_impl
|
||||
// Access: Protected, Virtual
|
||||
|
|
|
|||
|
|
@ -22,11 +22,17 @@
|
|||
#include "pandabase.h"
|
||||
#include "typedReferenceCount.h"
|
||||
#include "qpgeomVertexFormat.h"
|
||||
#include "qpgeomVertexData.h"
|
||||
#include "indirectCompareTo.h"
|
||||
#include "pStatCollector.h"
|
||||
#include "pointerTo.h"
|
||||
#include "pmap.h"
|
||||
#include "pset.h"
|
||||
|
||||
class GraphicsStateGuardianBase;
|
||||
class RenderState;
|
||||
class qpGeom;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : qpGeomMunger
|
||||
// Description : Objects of this class are used to convert vertex data
|
||||
|
|
@ -52,7 +58,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpGeomMunger : public TypedReferenceCount {
|
||||
public:
|
||||
qpGeomMunger();
|
||||
qpGeomMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state);
|
||||
virtual ~qpGeomMunger();
|
||||
|
||||
INLINE bool is_registered() const;
|
||||
|
|
@ -64,6 +70,8 @@ public:
|
|||
INLINE CPT(qpGeomVertexData) munge_data(const qpGeomVertexData *data) const;
|
||||
void remove_data(const qpGeomVertexData *data);
|
||||
|
||||
// Also see Geom::munge_geom() for the primary interface.
|
||||
|
||||
public:
|
||||
INLINE int compare_to(const qpGeomMunger &other) const;
|
||||
|
||||
|
|
@ -72,6 +80,7 @@ protected:
|
|||
CPT(qpGeomVertexData) do_munge_data(const qpGeomVertexData *data);
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
|
|
@ -116,6 +125,8 @@ public:
|
|||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class qpGeom;
|
||||
};
|
||||
|
||||
#include "qpgeomMunger.I"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,37 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::get_shade_model
|
||||
// Access: Published
|
||||
// Description: Returns the ShadeModel hint for this primitive.
|
||||
// This is intended as a hint to the renderer to tell it
|
||||
// how the per-vertex colors and normals are applied.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomPrimitive::ShadeModel qpGeomPrimitive::
|
||||
get_shade_model() const {
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_shade_model;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::set_shade_model
|
||||
// Access: Published
|
||||
// Description: Changes the ShadeModel hint for this primitive.
|
||||
// This is different from the ShadeModelAttrib that
|
||||
// might also be applied from the scene graph. This
|
||||
// does not affect the shade model that is in effect
|
||||
// when rendering, but rather serves as a hint to the
|
||||
// renderer to tell it how the per-vertex colors and
|
||||
// normals on this primitive are applied.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomPrimitive::
|
||||
set_shade_model(qpGeomPrimitive::ShadeModel shade_model) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_shade_model = shade_model;
|
||||
cdata->_rotated_vertices.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::get_num_vertices
|
||||
// Access: Published
|
||||
|
|
@ -55,6 +86,64 @@ get_vertices() const {
|
|||
return cdata->_vertices;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::get_flat_first_vertices
|
||||
// Access: Published
|
||||
// Description: Returns a const pointer to the vertex index array,
|
||||
// suitable for traversing for a renderer that expects
|
||||
// the key vertex of each triangle in a flat-shaded
|
||||
// model to be the triangle's first vertex (as DirectX
|
||||
// does).
|
||||
//
|
||||
// The result of this is dependent on the value
|
||||
// specified to set_shade_model(). If the shade model
|
||||
// indicates flat_last_vertex, this will return the
|
||||
// vertices rotated to bring them into first_vertex
|
||||
// compliance; otherwise, it will be the unmodified
|
||||
// result from get_vertices().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CPTA_ushort qpGeomPrimitive::
|
||||
get_flat_first_vertices() const {
|
||||
CDReader cdata(_cycler);
|
||||
if (cdata->_shade_model == SM_flat_last_vertex) {
|
||||
if (cdata->_rotated_vertices == (const ushort *)NULL) {
|
||||
((qpGeomPrimitive *)this)->do_rotate();
|
||||
}
|
||||
return cdata->_rotated_vertices;
|
||||
} else {
|
||||
return cdata->_vertices;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::get_flat_last_vertices
|
||||
// Access: Published
|
||||
// Description: Returns a const pointer to the vertex index array,
|
||||
// suitable for traversing for a renderer that expects
|
||||
// the key vertex of each triangle in a flat-shaded
|
||||
// model to be the triangle's last vertex (as OpenGL
|
||||
// does).
|
||||
//
|
||||
// The result of this is dependent on the value
|
||||
// specified to set_shade_model(). If the shade model
|
||||
// indicates flat_first_vertex, this will return the
|
||||
// vertices rotated to bring them into last_vertex
|
||||
// compliance; otherwise, it will be the unmodified
|
||||
// result from get_vertices().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CPTA_ushort qpGeomPrimitive::
|
||||
get_flat_last_vertices() const {
|
||||
CDReader cdata(_cycler);
|
||||
if (cdata->_shade_model == SM_flat_first_vertex) {
|
||||
if (cdata->_rotated_vertices == (const ushort *)NULL) {
|
||||
((qpGeomPrimitive *)this)->do_rotate();
|
||||
}
|
||||
return cdata->_rotated_vertices;
|
||||
} else {
|
||||
return cdata->_vertices;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::get_vertices
|
||||
// Access: Published
|
||||
|
|
@ -103,6 +192,17 @@ get_max_vertex() const {
|
|||
return cdata->_max_vertex;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::get_primitive_end
|
||||
// Access: Published
|
||||
// Description: Returns the element within the _vertices list at which
|
||||
// the ith primitive ends.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpGeomPrimitive::
|
||||
get_primitive_end(int i) const {
|
||||
return get_primitive_start(i + 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::CData::Constructor
|
||||
// Access: Public
|
||||
|
|
@ -110,6 +210,7 @@ get_max_vertex() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomPrimitive::CData::
|
||||
CData() :
|
||||
_shade_model(SM_smooth),
|
||||
_got_minmax(true),
|
||||
_min_vertex(0),
|
||||
_max_vertex(0)
|
||||
|
|
@ -123,7 +224,9 @@ CData() :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomPrimitive::CData::
|
||||
CData(const qpGeomPrimitive::CData ©) :
|
||||
_shade_model(copy._shade_model),
|
||||
_vertices(copy._vertices),
|
||||
_rotated_vertices(copy._rotated_vertices),
|
||||
_ends(copy._ends),
|
||||
_got_minmax(copy._got_minmax),
|
||||
_min_vertex(copy._min_vertex),
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
TypeHandle qpGeomPrimitive::_type_handle;
|
||||
|
||||
PStatCollector qpGeomPrimitive::_rotate_pcollector("Cull:Rotate");
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::Constructor
|
||||
// Access: Published
|
||||
|
|
@ -67,7 +69,7 @@ qpGeomPrimitive::
|
|||
if (_cycler.is_stage_unique(i)) {
|
||||
CData *cdata = _cycler.write_stage(i);
|
||||
if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
|
||||
cache_mgr->remove_decompose(this);
|
||||
cache_mgr->remove_primitive(this);
|
||||
cdata->_decomposed = NULL;
|
||||
}
|
||||
_cycler.release_write_stage(i, cdata);
|
||||
|
|
@ -93,6 +95,7 @@ add_vertex(int vertex) {
|
|||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_vertices.push_back(short_vertex);
|
||||
cdata->_rotated_vertices.clear();
|
||||
|
||||
if (cdata->_got_minmax) {
|
||||
cdata->_min_vertex = min(cdata->_min_vertex, short_vertex);
|
||||
|
|
@ -118,6 +121,7 @@ add_consecutive_vertices(int start, int num_vertices) {
|
|||
for (unsigned short v = short_start; v <= short_end; ++v) {
|
||||
cdata->_vertices.push_back(v);
|
||||
}
|
||||
cdata->_rotated_vertices.clear();
|
||||
|
||||
if (cdata->_got_minmax) {
|
||||
cdata->_min_vertex = min(cdata->_min_vertex, short_start);
|
||||
|
|
@ -171,6 +175,7 @@ clear_vertices() {
|
|||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_vertices.clear();
|
||||
cdata->_rotated_vertices.clear();
|
||||
cdata->_ends.clear();
|
||||
}
|
||||
|
||||
|
|
@ -186,6 +191,7 @@ PTA_ushort qpGeomPrimitive::
|
|||
modify_vertices() {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_rotated_vertices.clear();
|
||||
return cdata->_vertices;
|
||||
}
|
||||
|
||||
|
|
@ -201,6 +207,7 @@ set_vertices(PTA_ushort vertices) {
|
|||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_vertices = vertices;
|
||||
cdata->_rotated_vertices.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -244,14 +251,14 @@ set_ends(PTA_int ends) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::get_num_bytes
|
||||
// Access: Published
|
||||
// Description: Records the number of bytes consumed by the primitive
|
||||
// Description: Returns the number of bytes consumed by the primitive
|
||||
// and its index table(s).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int qpGeomPrimitive::
|
||||
get_num_bytes() const {
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_vertices.size() * sizeof(short) +
|
||||
cdata->_ends.size() * sizeof(int);
|
||||
cdata->_ends.size() * sizeof(int) + sizeof(qpGeomPrimitive);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -309,7 +316,7 @@ get_num_primitives() const {
|
|||
// Function: qpGeomPrimitive::get_primitive_start
|
||||
// Access: Published
|
||||
// Description: Returns the element within the _vertices list at which
|
||||
// the ith primitive ends.
|
||||
// the ith primitive starts.
|
||||
//
|
||||
// If i is one more than the highest valid primitive
|
||||
// vertex, the return value will be one more than the
|
||||
|
|
@ -382,12 +389,12 @@ get_primitive_num_vertices(int i) const {
|
|||
// primitive without having to write handlers for each
|
||||
// possible kind of primitive type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomPrimitive) qpGeomPrimitive::
|
||||
decompose() {
|
||||
PT(qpGeomPrimitive) result;
|
||||
CPT(qpGeomPrimitive) qpGeomPrimitive::
|
||||
decompose() const {
|
||||
CPT(qpGeomPrimitive) result;
|
||||
{
|
||||
// Use read() and release_read() instead of CDReader, because the
|
||||
// call to record_decompose() might recursively call back into
|
||||
// call to record_primitive() might recursively call back into
|
||||
// this object, and require a write.
|
||||
const CData *cdata = _cycler.read();
|
||||
if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
|
||||
|
|
@ -397,7 +404,7 @@ decompose() {
|
|||
// while longer.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
cache_mgr->record_decompose(this, result->get_num_bytes());
|
||||
cache_mgr->record_primitive(this, result->get_num_bytes());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -405,8 +412,8 @@ decompose() {
|
|||
}
|
||||
|
||||
result = decompose_impl();
|
||||
if (result.p() == this) {
|
||||
// decomposing this primitive has no effect.
|
||||
if (result.p() == this || result.p() == NULL) {
|
||||
// decomposing this primitive has no effect or cannot be done.
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -416,13 +423,13 @@ decompose() {
|
|||
}
|
||||
|
||||
// Record the result for the future.
|
||||
CDWriter cdata(_cycler);
|
||||
CDWriter cdata(((qpGeomPrimitive *)this)->_cycler);
|
||||
cdata->_decomposed = result;
|
||||
|
||||
// And add *this* object to the cache manager.
|
||||
qpGeomVertexCacheManager *cache_mgr =
|
||||
qpGeomVertexCacheManager::get_global_ptr();
|
||||
cache_mgr->record_decompose(this, result->get_num_bytes());
|
||||
cache_mgr->record_primitive(this, result->get_num_bytes());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -464,7 +471,7 @@ write(ostream &out, int indent_level) const {
|
|||
// Function: qpGeomPrimitive::clear_cache
|
||||
// Access: Published
|
||||
// Description: Removes all of the previously-cached results of
|
||||
// convert_to().
|
||||
// decompose().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::
|
||||
clear_cache() {
|
||||
|
|
@ -475,7 +482,7 @@ clear_cache() {
|
|||
|
||||
CData *cdata = CDWriter(_cycler);
|
||||
if (cdata->_decomposed != (qpGeomPrimitive *)NULL) {
|
||||
cache_mgr->remove_decompose(this);
|
||||
cache_mgr->remove_primitive(this);
|
||||
cdata->_decomposed = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -538,7 +545,7 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::decompose_impl
|
||||
// Access: Protected
|
||||
// Access: Protected, Virtual
|
||||
// Description: Decomposes a complex primitive type into a simpler
|
||||
// primitive type, for instance triangle strips to
|
||||
// triangles, and returns a pointer to the new primitive
|
||||
|
|
@ -550,11 +557,51 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
|
|||
// primitive without having to write handlers for each
|
||||
// possible kind of primitive type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomPrimitive) qpGeomPrimitive::
|
||||
decompose_impl() {
|
||||
CPT(qpGeomPrimitive) qpGeomPrimitive::
|
||||
decompose_impl() const {
|
||||
return this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::rotate_impl
|
||||
// Access: Protected, Virtual
|
||||
// Description: The virtual implementation of do_rotate().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPTA_ushort qpGeomPrimitive::
|
||||
rotate_impl() const {
|
||||
// The default implementation doesn't even try to do anything.
|
||||
nassertr(false, get_vertices());
|
||||
return get_vertices();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::do_rotate
|
||||
// Access: Private
|
||||
// Description: Fills _rotated_vertices by rotating the individual
|
||||
// primitives to bring each flat-colored vertex to the
|
||||
// opposite position. If the current shade_model
|
||||
// indicates flat_vertex_last, this should bring the
|
||||
// last vertex to the first position; if it indicates
|
||||
// flat_vertex_first, this should bring the first vertex
|
||||
// to the last position. This is used internally to
|
||||
// implement get_flat_first_vertices() and
|
||||
// get_flat_last_vertices().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::
|
||||
do_rotate() {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "Rotating " << get_type() << ": " << (void *)this << "\n";
|
||||
}
|
||||
|
||||
PStatTimer timer(_rotate_pcollector);
|
||||
CDReader cdata(_cycler);
|
||||
CPTA_ushort rotated_vertices = rotate_impl();
|
||||
|
||||
CDWriter cdataw(_cycler, cdata);
|
||||
cdataw->_rotated_vertices = rotated_vertices;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomPrimitive::remove_cache_entry
|
||||
// Access: Private
|
||||
|
|
@ -570,6 +617,7 @@ remove_cache_entry() const {
|
|||
// added to stage 1 instead). No big deal if we don't.
|
||||
CData *cdata = ((qpGeomPrimitive *)this)->_cycler.write_stage(0);
|
||||
cdata->_decomposed = NULL;
|
||||
((qpGeomPrimitive *)this)->_cycler.release_write_stage(0, cdata);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "pointerTo.h"
|
||||
#include "pta_ushort.h"
|
||||
#include "pta_int.h"
|
||||
#include "pStatCollector.h"
|
||||
#include "cycleData.h"
|
||||
#include "cycleDataReader.h"
|
||||
#include "cycleDataWriter.h"
|
||||
|
|
@ -64,6 +65,18 @@ PUBLISHED:
|
|||
qpGeomPrimitive(const qpGeomPrimitive ©);
|
||||
virtual ~qpGeomPrimitive();
|
||||
|
||||
virtual PT(qpGeomPrimitive) make_copy() const=0;
|
||||
|
||||
enum ShadeModel {
|
||||
SM_smooth,
|
||||
SM_uniform,
|
||||
SM_flat_first_vertex,
|
||||
SM_flat_last_vertex,
|
||||
};
|
||||
|
||||
INLINE ShadeModel get_shade_model() const;
|
||||
INLINE void set_shade_model(ShadeModel shade_model);
|
||||
|
||||
INLINE int get_num_vertices() const;
|
||||
INLINE int get_vertex(int i) const;
|
||||
void add_vertex(int vertex);
|
||||
|
|
@ -72,6 +85,8 @@ PUBLISHED:
|
|||
void clear_vertices();
|
||||
|
||||
INLINE CPTA_ushort get_vertices() const;
|
||||
INLINE CPTA_ushort get_flat_first_vertices() const;
|
||||
INLINE CPTA_ushort get_flat_last_vertices() const;
|
||||
PTA_ushort modify_vertices();
|
||||
void set_vertices(PTA_ushort vertices);
|
||||
|
||||
|
|
@ -88,9 +103,10 @@ PUBLISHED:
|
|||
virtual int get_min_num_vertices_per_primitive() const;
|
||||
int get_num_primitives() const;
|
||||
int get_primitive_start(int i) const;
|
||||
INLINE int get_primitive_end(int i) const;
|
||||
int get_primitive_num_vertices(int i) const;
|
||||
|
||||
PT(qpGeomPrimitive) decompose();
|
||||
CPT(qpGeomPrimitive) decompose() const;
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
virtual void write(ostream &out, int indent_level) const;
|
||||
|
|
@ -98,18 +114,23 @@ PUBLISHED:
|
|||
void clear_cache();
|
||||
|
||||
public:
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg)=0;
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg) const=0;
|
||||
|
||||
virtual void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
|
||||
bool &found_any,
|
||||
const qpGeomVertexData *vertex_data) const;
|
||||
|
||||
protected:
|
||||
virtual PT(qpGeomPrimitive) decompose_impl();
|
||||
virtual CPT(qpGeomPrimitive) decompose_impl() const;
|
||||
virtual CPTA_ushort rotate_impl() const;
|
||||
|
||||
private:
|
||||
private:
|
||||
void do_rotate();
|
||||
void remove_cache_entry() const;
|
||||
|
||||
protected:
|
||||
static PStatCollector _rotate_pcollector;
|
||||
|
||||
private:
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
|
|
@ -121,14 +142,16 @@ private:
|
|||
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
|
||||
virtual void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
ShadeModel _shade_model;
|
||||
PTA_ushort _vertices;
|
||||
CPTA_ushort _rotated_vertices;
|
||||
PTA_int _ends;
|
||||
|
||||
bool _got_minmax;
|
||||
unsigned short _min_vertex;
|
||||
unsigned short _max_vertex;
|
||||
|
||||
PT(qpGeomPrimitive) _decomposed;
|
||||
CPT(qpGeomPrimitive) _decomposed;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "qpgeomTriangles.h"
|
||||
#include "pStatTimer.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
|
||||
|
|
@ -51,6 +52,16 @@ qpGeomTriangles::
|
|||
~qpGeomTriangles() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTriangles::make_copy
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomPrimitive) qpGeomTriangles::
|
||||
make_copy() const {
|
||||
return new qpGeomTriangles(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTriangles::get_num_vertices_per_primitive
|
||||
// Access: Published, Virtual
|
||||
|
|
@ -74,10 +85,58 @@ get_num_vertices_per_primitive() const {
|
|||
// primitive.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomTriangles::
|
||||
draw(GraphicsStateGuardianBase *gsg) {
|
||||
draw(GraphicsStateGuardianBase *gsg) const {
|
||||
gsg->draw_triangles(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTriangles::rotate_impl
|
||||
// Access: Protected, Virtual
|
||||
// Description: The virtual implementation of do_rotate().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPTA_ushort qpGeomTriangles::
|
||||
rotate_impl() const {
|
||||
// To rotate triangles, we just move one vertex from the front to
|
||||
// the back, or vice-versa; but we have to know what direction we're
|
||||
// going.
|
||||
CPTA_ushort vertices = get_vertices();
|
||||
ShadeModel shade_model = get_shade_model();
|
||||
|
||||
PTA_ushort new_vertices;
|
||||
new_vertices.reserve(vertices.size());
|
||||
|
||||
switch (shade_model) {
|
||||
case SM_flat_first_vertex:
|
||||
// Move the first vertex to the end.
|
||||
{
|
||||
for (int begin = 0; begin < (int)vertices.size(); begin += 3) {
|
||||
new_vertices.push_back(vertices[begin + 1]);
|
||||
new_vertices.push_back(vertices[begin + 2]);
|
||||
new_vertices.push_back(vertices[begin]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SM_flat_last_vertex:
|
||||
// Move the last vertex to the front.
|
||||
{
|
||||
for (int begin = 0; begin < (int)vertices.size(); begin += 3) {
|
||||
new_vertices.push_back(vertices[begin + 2]);
|
||||
new_vertices.push_back(vertices[begin]);
|
||||
new_vertices.push_back(vertices[begin + 1]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// This shouldn't get called with any other shade model.
|
||||
nassertr(false, vertices);
|
||||
}
|
||||
|
||||
nassertr(new_vertices.size() == vertices.size(), vertices);
|
||||
return new_vertices;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTriangles::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
|
|
|||
|
|
@ -34,10 +34,15 @@ PUBLISHED:
|
|||
qpGeomTriangles(const qpGeomTriangles ©);
|
||||
virtual ~qpGeomTriangles();
|
||||
|
||||
virtual PT(qpGeomPrimitive) make_copy() const;
|
||||
|
||||
virtual int get_num_vertices_per_primitive() const;
|
||||
|
||||
public:
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg);
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg) const;
|
||||
|
||||
protected:
|
||||
virtual CPTA_ushort rotate_impl() const;
|
||||
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
|
|
|
|||
|
|
@ -52,6 +52,16 @@ qpGeomTrifans::
|
|||
~qpGeomTrifans() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTrifans::make_copy
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomPrimitive) qpGeomTrifans::
|
||||
make_copy() const {
|
||||
return new qpGeomTrifans(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTrifans::draw
|
||||
// Access: Public, Virtual
|
||||
|
|
@ -59,13 +69,13 @@ qpGeomTrifans::
|
|||
// primitive.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomTrifans::
|
||||
draw(GraphicsStateGuardianBase *gsg) {
|
||||
draw(GraphicsStateGuardianBase *gsg) const {
|
||||
gsg->draw_trifans(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTrifans::decompose_impl
|
||||
// Access: Published, Virtual
|
||||
// Access: Protected, Virtual
|
||||
// Description: Decomposes a complex primitive type into a simpler
|
||||
// primitive type, for instance triangle strips to
|
||||
// triangles, and returns a pointer to the new primitive
|
||||
|
|
@ -77,9 +87,10 @@ draw(GraphicsStateGuardianBase *gsg) {
|
|||
// primitive without having to write handlers for each
|
||||
// possible kind of primitive type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomPrimitive) qpGeomTrifans::
|
||||
decompose_impl() {
|
||||
CPT(qpGeomPrimitive) qpGeomTrifans::
|
||||
decompose_impl() const {
|
||||
PT(qpGeomTriangles) triangles = new qpGeomTriangles;
|
||||
triangles->set_shade_model(get_shade_model());
|
||||
CPTA_ushort vertices = get_vertices();
|
||||
CPTA_int ends = get_ends();
|
||||
|
||||
|
|
@ -109,6 +120,19 @@ decompose_impl() {
|
|||
return triangles.p();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTrifans::rotate_impl
|
||||
// Access: Protected, Virtual
|
||||
// Description: The virtual implementation of do_rotate().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPTA_ushort qpGeomTrifans::
|
||||
rotate_impl() const {
|
||||
// Actually, we can't rotate fans without chaging the winding order.
|
||||
// It's an error to define a flat shade model for a GeomTrifan.
|
||||
nassertr(false, get_vertices());
|
||||
return get_vertices();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTrifans::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
|
|
|||
|
|
@ -34,11 +34,14 @@ PUBLISHED:
|
|||
qpGeomTrifans(const qpGeomTrifans ©);
|
||||
virtual ~qpGeomTrifans();
|
||||
|
||||
virtual PT(qpGeomPrimitive) make_copy() const;
|
||||
|
||||
public:
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg);
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg) const;
|
||||
|
||||
protected:
|
||||
virtual PT(qpGeomPrimitive) decompose_impl();
|
||||
virtual CPT(qpGeomPrimitive) decompose_impl() const;
|
||||
virtual CPTA_ushort rotate_impl() const;
|
||||
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "qpgeomTristrips.h"
|
||||
#include "qpgeomTriangles.h"
|
||||
#include "pStatTimer.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
|
||||
|
|
@ -52,6 +53,16 @@ qpGeomTristrips::
|
|||
~qpGeomTristrips() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTristrips::make_copy
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomPrimitive) qpGeomTristrips::
|
||||
make_copy() const {
|
||||
return new qpGeomTristrips(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTristrips::draw
|
||||
// Access: Public, Virtual
|
||||
|
|
@ -59,13 +70,13 @@ qpGeomTristrips::
|
|||
// primitive.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomTristrips::
|
||||
draw(GraphicsStateGuardianBase *gsg) {
|
||||
draw(GraphicsStateGuardianBase *gsg) const {
|
||||
gsg->draw_tristrips(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTristrips::decompose_impl
|
||||
// Access: Published, Virtual
|
||||
// Access: Protected, Virtual
|
||||
// Description: Decomposes a complex primitive type into a simpler
|
||||
// primitive type, for instance triangle strips to
|
||||
// triangles, and returns a pointer to the new primitive
|
||||
|
|
@ -77,49 +88,137 @@ draw(GraphicsStateGuardianBase *gsg) {
|
|||
// primitive without having to write handlers for each
|
||||
// possible kind of primitive type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomPrimitive) qpGeomTristrips::
|
||||
decompose_impl() {
|
||||
CPT(qpGeomPrimitive) qpGeomTristrips::
|
||||
decompose_impl() const {
|
||||
PT(qpGeomTriangles) triangles = new qpGeomTriangles;
|
||||
triangles->set_shade_model(get_shade_model());
|
||||
CPTA_ushort vertices = get_vertices();
|
||||
CPTA_int ends = get_ends();
|
||||
|
||||
int vi = 0;
|
||||
int li = 0;
|
||||
while (li < (int)ends.size()) {
|
||||
int end = ends[li];
|
||||
nassertr(vi + 2 <= end, triangles.p());
|
||||
nassertr(vi < (int)vertices.size(), this);
|
||||
int v0 = vertices[vi];
|
||||
++vi;
|
||||
nassertr(vi < (int)vertices.size(), this);
|
||||
int v1 = vertices[vi];
|
||||
++vi;
|
||||
bool reversed = false;
|
||||
while (vi < end) {
|
||||
if (reversed) {
|
||||
triangles->add_vertex(v1);
|
||||
triangles->add_vertex(v0);
|
||||
reversed = false;
|
||||
} else {
|
||||
triangles->add_vertex(v0);
|
||||
triangles->add_vertex(v1);
|
||||
reversed = true;
|
||||
}
|
||||
triangles->add_vertex(vertices[vi]);
|
||||
v0 = v1;
|
||||
// We need a slightly different algorithm for SM_flat_first_vertex
|
||||
// than for SM_flat_last_vertex, to preserve the key vertex in the
|
||||
// right place. The remaining shade models can either either
|
||||
// algorithm.
|
||||
if (get_shade_model() == SM_flat_first_vertex) {
|
||||
// Preserve the first vertex of each component triangle as the
|
||||
// first vertex of each generated triangle.
|
||||
int vi = 0;
|
||||
int li = 0;
|
||||
while (li < (int)ends.size()) {
|
||||
int end = ends[li];
|
||||
nassertr(vi + 2 <= end, triangles.p());
|
||||
nassertr(vi < (int)vertices.size(), this);
|
||||
v1 = vertices[vi];
|
||||
triangles->close_primitive();
|
||||
int v0 = vertices[vi];
|
||||
++vi;
|
||||
nassertr(vi < (int)vertices.size(), this);
|
||||
int v1 = vertices[vi];
|
||||
++vi;
|
||||
bool reversed = false;
|
||||
while (vi < end) {
|
||||
triangles->add_vertex(v0);
|
||||
if (reversed) {
|
||||
triangles->add_vertex(vertices[vi]);
|
||||
triangles->add_vertex(v1);
|
||||
reversed = false;
|
||||
} else {
|
||||
triangles->add_vertex(v1);
|
||||
triangles->add_vertex(vertices[vi]);
|
||||
reversed = true;
|
||||
}
|
||||
v0 = v1;
|
||||
nassertr(vi < (int)vertices.size(), this);
|
||||
v1 = vertices[vi];
|
||||
triangles->close_primitive();
|
||||
++vi;
|
||||
}
|
||||
++li;
|
||||
}
|
||||
++li;
|
||||
nassertr(vi == (int)vertices.size(), triangles.p());
|
||||
|
||||
} else {
|
||||
// Preserve the last vertex of each component triangle as the
|
||||
// last vertex of each generated triangle.
|
||||
int vi = 0;
|
||||
int li = 0;
|
||||
while (li < (int)ends.size()) {
|
||||
int end = ends[li];
|
||||
nassertr(vi + 2 <= end, triangles.p());
|
||||
nassertr(vi < (int)vertices.size(), this);
|
||||
int v0 = vertices[vi];
|
||||
++vi;
|
||||
nassertr(vi < (int)vertices.size(), this);
|
||||
int v1 = vertices[vi];
|
||||
++vi;
|
||||
bool reversed = false;
|
||||
while (vi < end) {
|
||||
if (reversed) {
|
||||
triangles->add_vertex(v1);
|
||||
triangles->add_vertex(v0);
|
||||
reversed = false;
|
||||
} else {
|
||||
triangles->add_vertex(v0);
|
||||
triangles->add_vertex(v1);
|
||||
reversed = true;
|
||||
}
|
||||
triangles->add_vertex(vertices[vi]);
|
||||
v0 = v1;
|
||||
nassertr(vi < (int)vertices.size(), this);
|
||||
v1 = vertices[vi];
|
||||
triangles->close_primitive();
|
||||
++vi;
|
||||
}
|
||||
++li;
|
||||
}
|
||||
nassertr(vi == (int)vertices.size(), triangles.p());
|
||||
}
|
||||
|
||||
nassertr(vi == (int)vertices.size(), triangles.p());
|
||||
|
||||
return triangles.p();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTristrips::rotate_impl
|
||||
// Access: Protected, Virtual
|
||||
// Description: The virtual implementation of do_rotate().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPTA_ushort qpGeomTristrips::
|
||||
rotate_impl() const {
|
||||
// To rotate a triangle strip with an even number of vertices, we
|
||||
// just reverse the vertices. But if we have an odd number of
|
||||
// vertices, that doesn't work--in fact, nothing works (without also
|
||||
// changing the winding order), so we don't allow an odd number of
|
||||
// vertices in a flat-shaded tristrip.
|
||||
CPTA_ushort vertices = get_vertices();
|
||||
CPTA_int ends = get_ends();
|
||||
PTA_ushort new_vertices;
|
||||
new_vertices.reserve(vertices.size());
|
||||
|
||||
bool any_odd = false;
|
||||
|
||||
int begin = 0;
|
||||
CPTA_int::const_iterator ei;
|
||||
for (ei = ends.begin(); ei != ends.end(); ++ei) {
|
||||
int end = (*ei);
|
||||
int num_vertices = end - begin;
|
||||
|
||||
if ((num_vertices & 1) == 0) {
|
||||
for (int vi = end - 1; vi >= begin; --vi) {
|
||||
new_vertices.push_back(vertices[vi]);
|
||||
}
|
||||
} else {
|
||||
any_odd = true;
|
||||
}
|
||||
|
||||
begin = end;
|
||||
}
|
||||
nassertr(new_vertices.size() == vertices.size(), vertices);
|
||||
|
||||
// If this assertion is triggered, there was a triangle strip with
|
||||
// an odd number of vertices and either SM_flat_first_vertex or
|
||||
// SM_flat_last_vertex specified--which is not allowed.
|
||||
nassertr(!any_odd, new_vertices);
|
||||
return new_vertices;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomTristrips::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
|
|
|||
|
|
@ -34,11 +34,14 @@ PUBLISHED:
|
|||
qpGeomTristrips(const qpGeomTristrips ©);
|
||||
virtual ~qpGeomTristrips();
|
||||
|
||||
virtual PT(qpGeomPrimitive) make_copy() const;
|
||||
|
||||
public:
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg);
|
||||
virtual void draw(GraphicsStateGuardianBase *gsg) const;
|
||||
|
||||
protected:
|
||||
virtual PT(qpGeomPrimitive) decompose_impl();
|
||||
virtual CPT(qpGeomPrimitive) decompose_impl() const;
|
||||
virtual CPTA_ushort rotate_impl() const;
|
||||
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
|
|
|
|||
|
|
@ -69,18 +69,12 @@ get_total_size() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
record_munger(const qpGeomMunger *munger) {
|
||||
Entry entry;
|
||||
entry._munger = munger;
|
||||
entry._primitive = NULL;
|
||||
entry._source = NULL;
|
||||
entry._format = NULL;
|
||||
entry._result_size = 100; // Make up a nominal number.
|
||||
|
||||
record_entry(entry);
|
||||
// Make up a nominal result_size for a munger.
|
||||
record_entry(Entry(munger, 100));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::record_decompose
|
||||
// Function: qpGeomVertexCacheManager::record_primitive
|
||||
// Access: Private
|
||||
// Description: Records a new entry in the cache, or marks a cache
|
||||
// hit for a previous entry in the cache. This should
|
||||
|
|
@ -88,34 +82,23 @@ record_munger(const qpGeomMunger *munger) {
|
|||
//
|
||||
// The cache manager will not hold a reference on the
|
||||
// GeomPrimitive pointer; if it destructs, it should
|
||||
// call remove_decompose() to remove itself from the cache.
|
||||
// call remove_primitive() to remove itself from the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
record_decompose(const qpGeomPrimitive *primitive, int result_size) {
|
||||
Entry entry;
|
||||
entry._primitive = primitive;
|
||||
entry._source = NULL;
|
||||
entry._format = NULL;
|
||||
entry._result_size = result_size;
|
||||
|
||||
record_entry(entry);
|
||||
record_primitive(const qpGeomPrimitive *primitive, int result_size) {
|
||||
record_entry(Entry(primitive, result_size));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::remove_decompose
|
||||
// Function: qpGeomVertexCacheManager::remove_primitive
|
||||
// Access: Private
|
||||
// Description: Removes an entry from the cache, if it is there.
|
||||
// Quietly ignores it if it is not. This should only be
|
||||
// called by GeomPrimitive.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
remove_decompose(const qpGeomPrimitive *primitive) {
|
||||
Entry entry;
|
||||
entry._primitive = primitive;
|
||||
entry._source = NULL;
|
||||
entry._format = NULL;
|
||||
|
||||
remove_entry(entry);
|
||||
remove_primitive(const qpGeomPrimitive *primitive) {
|
||||
remove_entry(Entry(primitive, 0));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -130,15 +113,9 @@ remove_decompose(const qpGeomPrimitive *primitive) {
|
|||
// call remove_data() to remove itself from the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
record_data(const qpGeomVertexData *source, const qpGeomVertexFormat *format,
|
||||
record_data(const qpGeomVertexData *source, const qpGeomVertexFormat *modifier,
|
||||
int result_size) {
|
||||
Entry entry;
|
||||
entry._primitive = NULL;
|
||||
entry._source = source;
|
||||
entry._format = format;
|
||||
entry._result_size = result_size;
|
||||
|
||||
record_entry(entry);
|
||||
record_entry(Entry(source, modifier, result_size));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -150,13 +127,139 @@ record_data(const qpGeomVertexData *source, const qpGeomVertexFormat *format,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
remove_data(const qpGeomVertexData *source,
|
||||
const qpGeomVertexFormat *format) {
|
||||
Entry entry;
|
||||
entry._primitive = NULL;
|
||||
entry._source = source;
|
||||
entry._format = format;
|
||||
const qpGeomVertexFormat *modifier) {
|
||||
remove_entry(Entry(source, modifier, 0));
|
||||
}
|
||||
|
||||
remove_entry(entry);
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::record_geom
|
||||
// Access: Private
|
||||
// Description: Records a new entry in the cache, or marks a cache
|
||||
// hit for a previous entry in the cache. This should
|
||||
// only be called by Geom.
|
||||
//
|
||||
// The cache manager will not hold a reference on the
|
||||
// Geom pointer; if it destructs, it should
|
||||
// call remove_geom() to remove itself from the cache.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
record_geom(const qpGeom *source, const qpGeomMunger *modifier,
|
||||
int result_size) {
|
||||
record_entry(Entry(source, modifier, result_size));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::remove_geom
|
||||
// Access: Private
|
||||
// Description: Removes an entry from the cache, if it is there.
|
||||
// Quietly ignores it if it is not. This should only be
|
||||
// called by Geom.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::
|
||||
remove_geom(const qpGeom *source, const qpGeomMunger *modifier) {
|
||||
remove_entry(Entry(source, modifier, 0));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
Entry(const qpGeomMunger *munger, int result_size) :
|
||||
_cache_type(CT_munger),
|
||||
_result_size(result_size)
|
||||
{
|
||||
_u._munger = munger;
|
||||
_u._munger->ref();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
Entry(const qpGeomPrimitive *primitive, int result_size) :
|
||||
_cache_type(CT_primitive),
|
||||
_result_size(result_size)
|
||||
{
|
||||
_u._primitive = primitive;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
Entry(const qpGeomVertexData *source, const qpGeomVertexFormat *modifier,
|
||||
int result_size) :
|
||||
_cache_type(CT_data),
|
||||
_result_size(result_size)
|
||||
{
|
||||
_u._data._source = source;
|
||||
_u._data._modifier = modifier;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
Entry(const qpGeom *source, const qpGeomMunger *modifier, int result_size) :
|
||||
_cache_type(CT_geom),
|
||||
_result_size(result_size)
|
||||
{
|
||||
_u._geom._source = source;
|
||||
_u._geom._modifier = modifier;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
Entry(const qpGeomVertexCacheManager::Entry ©) :
|
||||
_cache_type(copy._cache_type),
|
||||
_result_size(copy._result_size)
|
||||
{
|
||||
_u = copy._u;
|
||||
if (_cache_type == CT_munger) {
|
||||
_u._munger->ref();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexCacheManager::Entry::
|
||||
operator = (const qpGeomVertexCacheManager::Entry ©) {
|
||||
if (_cache_type == CT_munger) {
|
||||
unref_delete(_u._munger);
|
||||
}
|
||||
_cache_type = copy._cache_type;
|
||||
_result_size = copy._result_size;
|
||||
_u = copy._u;
|
||||
if (_cache_type == CT_munger) {
|
||||
_u._munger->ref();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE qpGeomVertexCacheManager::Entry::
|
||||
~Entry() {
|
||||
if (_cache_type == CT_munger) {
|
||||
unref_delete(_u._munger);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -166,14 +269,32 @@ remove_data(const qpGeomVertexData *source,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpGeomVertexCacheManager::Entry::
|
||||
operator < (const qpGeomVertexCacheManager::Entry &other) const {
|
||||
if (_munger != other._munger) {
|
||||
return _munger < other._munger;
|
||||
switch (_cache_type) {
|
||||
case CT_munger:
|
||||
return _u._munger < other._u._munger;
|
||||
|
||||
case CT_primitive:
|
||||
return _u._primitive < other._u._primitive;
|
||||
|
||||
case CT_data:
|
||||
if (_u._data._source != other._u._data._source) {
|
||||
return _u._data._source < other._u._data._source;
|
||||
}
|
||||
return _u._data._modifier < other._u._data._modifier;
|
||||
|
||||
case CT_geom:
|
||||
if (_u._geom._source != other._u._geom._source) {
|
||||
return _u._geom._source < other._u._geom._source;
|
||||
}
|
||||
return _u._geom._modifier < other._u._geom._modifier;
|
||||
}
|
||||
if (_primitive != other._primitive) {
|
||||
return _primitive < other._primitive;
|
||||
}
|
||||
if (_source != other._source) {
|
||||
return _source < other._source;
|
||||
}
|
||||
return _format < other._format;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const qpGeomVertexCacheManager::Entry &entry) {
|
||||
entry.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,13 +62,6 @@ get_global_ptr() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexCacheManager::
|
||||
record_entry(const qpGeomVertexCacheManager::Entry &entry) {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "record_entry(" << entry._munger << ", "
|
||||
<< entry._primitive << ", " << entry._source << ", "
|
||||
<< entry._format << ", " << entry._result_size << ")\n";
|
||||
}
|
||||
|
||||
MutexHolder holder(_lock);
|
||||
EntriesIndex::iterator ii = _entries_index.find(&entry);
|
||||
if (ii != _entries_index.end()) {
|
||||
|
|
@ -77,6 +70,17 @@ record_entry(const qpGeomVertexCacheManager::Entry &entry) {
|
|||
_total_size -= (*ei)._result_size;
|
||||
_entries_index.erase(ii);
|
||||
_entries.erase(ei);
|
||||
|
||||
if (gobj_cat.is_spam()) {
|
||||
gobj_cat.spam()
|
||||
<< "refreshing cache entry: " << entry << "\n";
|
||||
}
|
||||
} else {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "recording cache entry: " << entry << ", total_size = "
|
||||
<< _total_size + entry._result_size << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new entry at the end of the list, so it will be the last
|
||||
|
|
@ -97,30 +101,41 @@ record_entry(const qpGeomVertexCacheManager::Entry &entry) {
|
|||
// is set to 0.
|
||||
int max_size = get_max_size();
|
||||
while (_total_size > max_size) {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "total_size = " << _total_size << ", max_size = "
|
||||
<< max_size << ", flushing\n";
|
||||
}
|
||||
nassertv(!_entries.empty());
|
||||
ei = _entries.begin();
|
||||
entry_pointer = &(*ei);
|
||||
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "cache total_size = " << _total_size << ", max_size = "
|
||||
<< max_size << ", removing " << *entry_pointer << "\n";
|
||||
}
|
||||
|
||||
ii = _entries_index.find(entry_pointer);
|
||||
nassertv(ii != _entries_index.end());
|
||||
|
||||
if (entry_pointer->_source != (qpGeomVertexData *)NULL) {
|
||||
entry_pointer->_source->remove_cache_entry(entry_pointer->_format);
|
||||
switch (entry_pointer->_cache_type) {
|
||||
case CT_data:
|
||||
entry_pointer->_u._data._source->remove_cache_entry
|
||||
(entry_pointer->_u._data._modifier);
|
||||
break;
|
||||
|
||||
case CT_primitive:
|
||||
entry_pointer->_u._primitive->remove_cache_entry();
|
||||
break;
|
||||
|
||||
case CT_geom:
|
||||
entry_pointer->_u._geom._source->remove_cache_entry
|
||||
(entry_pointer->_u._geom._modifier);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_total_size -= entry_pointer->_result_size;
|
||||
_entries_index.erase(ii);
|
||||
_entries.erase(ei);
|
||||
}
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "total_size = " << _total_size << ", max_size = "
|
||||
<< max_size << ", done\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -133,8 +148,7 @@ void qpGeomVertexCacheManager::
|
|||
remove_entry(const qpGeomVertexCacheManager::Entry &entry) {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "remove_entry(" << entry._munger << ", "
|
||||
<< entry._source << ", " << entry._format << ")\n";
|
||||
<< "remove_entry(" << entry << ")\n";
|
||||
}
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
|
|
@ -146,3 +160,35 @@ remove_entry(const qpGeomVertexCacheManager::Entry &entry) {
|
|||
_entries.erase(ei);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexCacheManager::Entry::output
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexCacheManager::Entry::
|
||||
output(ostream &out) const {
|
||||
out << "[ ";
|
||||
switch (_cache_type) {
|
||||
case CT_munger:
|
||||
out << "munger " << (void *)_u._munger << ":"
|
||||
<< _u._munger->get_ref_count();
|
||||
break;
|
||||
|
||||
case CT_primitive:
|
||||
out << "primitive " << (void *)_u._primitive;
|
||||
break;
|
||||
|
||||
case CT_data:
|
||||
out << "data " << (void *)_u._data._source << ", "
|
||||
<< (void *)_u._data._modifier;
|
||||
break;
|
||||
|
||||
case CT_geom:
|
||||
out << "geom " << (void *)_u._geom._source << ", "
|
||||
<< (void *)_u._geom._modifier;
|
||||
break;
|
||||
}
|
||||
|
||||
out << ", result_size = " << _result_size << " ]";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "plist.h"
|
||||
#include "pmap.h"
|
||||
|
||||
class qpGeom;
|
||||
class qpGeomPrimitive;
|
||||
class qpGeomVertexData;
|
||||
class qpGeomVertexFormat;
|
||||
|
|
@ -44,6 +45,12 @@ class qpGeomVertexFormat;
|
|||
// GeomVertexData source objects. This allows the cache
|
||||
// data to propagate through the multiprocess pipeline.
|
||||
//
|
||||
// This structure actually caches any of a number of
|
||||
// different types of pointers, and mixes them all up in
|
||||
// the same LRU cache list. Some of them (such as
|
||||
// GeomMunger) are reference-counted here in the cache;
|
||||
// most are not.
|
||||
//
|
||||
// This is part of the experimental Geom rewrite.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA qpGeomVertexCacheManager {
|
||||
|
|
@ -51,6 +58,9 @@ protected:
|
|||
qpGeomVertexCacheManager();
|
||||
~qpGeomVertexCacheManager();
|
||||
|
||||
public:
|
||||
class Entry;
|
||||
|
||||
PUBLISHED:
|
||||
INLINE void set_max_size(int max_size) const;
|
||||
INLINE int get_max_size() const;
|
||||
|
|
@ -61,16 +71,18 @@ PUBLISHED:
|
|||
|
||||
private:
|
||||
INLINE void record_munger(const qpGeomMunger *munger);
|
||||
INLINE void record_decompose(const qpGeomPrimitive *primitive,
|
||||
INLINE void record_primitive(const qpGeomPrimitive *primitive,
|
||||
int result_size);
|
||||
INLINE void remove_decompose(const qpGeomPrimitive *primitive);
|
||||
INLINE void remove_primitive(const qpGeomPrimitive *primitive);
|
||||
INLINE void record_data(const qpGeomVertexData *source,
|
||||
const qpGeomVertexFormat *format,
|
||||
const qpGeomVertexFormat *modifier,
|
||||
int result_size);
|
||||
INLINE void remove_data(const qpGeomVertexData *source,
|
||||
const qpGeomVertexFormat *format);
|
||||
|
||||
class Entry;
|
||||
const qpGeomVertexFormat *modifier);
|
||||
INLINE void record_geom(const qpGeom *source,
|
||||
const qpGeomMunger *modifier,
|
||||
int result_size);
|
||||
INLINE void remove_geom(const qpGeom *geom, const qpGeomMunger *modifier);
|
||||
|
||||
void record_entry(const Entry &entry);
|
||||
void remove_entry(const Entry &entry);
|
||||
|
|
@ -81,17 +93,52 @@ private:
|
|||
|
||||
int _total_size;
|
||||
|
||||
class Entry {
|
||||
public:
|
||||
INLINE bool operator < (const Entry &other) const;
|
||||
|
||||
CPT(qpGeomMunger) _munger;
|
||||
const qpGeomPrimitive *_primitive;
|
||||
const qpGeomVertexData *_source;
|
||||
const qpGeomVertexFormat *_format;
|
||||
int _result_size;
|
||||
enum CacheType {
|
||||
CT_munger,
|
||||
CT_primitive,
|
||||
CT_data,
|
||||
CT_geom,
|
||||
};
|
||||
|
||||
public:
|
||||
// This class is public only so we can declare the global ostream
|
||||
// output operator. It doesn't need to be visible outside this
|
||||
// class. It contains a single cache entry, which might actually be
|
||||
// any of a handful of different pointer types. The enumerated type
|
||||
// declared above, and the union declared below, serve to implement
|
||||
// this C-style polymorphism.
|
||||
class Entry {
|
||||
public:
|
||||
INLINE Entry(const qpGeomMunger *munger, int result_size);
|
||||
INLINE Entry(const qpGeomPrimitive *primitive, int result_size);
|
||||
INLINE Entry(const qpGeomVertexData *source,
|
||||
const qpGeomVertexFormat *modifier, int result_size);
|
||||
INLINE Entry(const qpGeom *source, const qpGeomMunger *modifier,
|
||||
int result_size);
|
||||
INLINE Entry(const Entry ©);
|
||||
INLINE void operator = (const Entry ©);
|
||||
INLINE ~Entry();
|
||||
INLINE bool operator < (const Entry &other) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
CacheType _cache_type;
|
||||
int _result_size;
|
||||
union {
|
||||
const qpGeomMunger *_munger;
|
||||
const qpGeomPrimitive *_primitive;
|
||||
struct {
|
||||
const qpGeomVertexData *_source;
|
||||
const qpGeomVertexFormat *_modifier;
|
||||
} _data;
|
||||
struct {
|
||||
const qpGeom *_source;
|
||||
const qpGeomMunger *_modifier;
|
||||
} _geom;
|
||||
} _u;
|
||||
};
|
||||
|
||||
private:
|
||||
// This list keeps the cache entries in least-recently-used order:
|
||||
// the items at the head of the list are ready to be flushed.
|
||||
typedef plist<Entry> Entries;
|
||||
|
|
@ -106,8 +153,11 @@ private:
|
|||
friend class qpGeomMunger;
|
||||
friend class qpGeomPrimitive;
|
||||
friend class qpGeomVertexData;
|
||||
friend class qpGeom;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const qpGeomVertexCacheManager::Entry &entry);
|
||||
|
||||
#include "qpgeomVertexCacheManager.I"
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ int qpGeomVertexData::
|
|||
get_num_bytes() const {
|
||||
CDReader cdata(_cycler);
|
||||
|
||||
int num_bytes = 0;
|
||||
int num_bytes = sizeof(qpGeomVertexData);
|
||||
|
||||
Arrays::const_iterator ai;
|
||||
for (ai = cdata->_arrays.begin(); ai != cdata->_arrays.end(); ++ai) {
|
||||
|
|
@ -738,13 +738,13 @@ unpack_argb(float data[4], unsigned int packed_argb) {
|
|||
// This is only called from GeomVertexCacheManager.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexData::
|
||||
remove_cache_entry(const qpGeomVertexFormat *format) const {
|
||||
remove_cache_entry(const qpGeomVertexFormat *modifier) const {
|
||||
// We have to operate on stage 0 of the pipeline, since that's where
|
||||
// the cache really counts. Because of the multistage pipeline, we
|
||||
// might not actually have a cache entry there (it might have been
|
||||
// added to stage 1 instead). No big deal if we don't.
|
||||
CData *cdata = ((qpGeomVertexData *)this)->_cycler.write_stage(0);
|
||||
ConvertedCache::iterator ci = cdata->_converted_cache.find(format);
|
||||
ConvertedCache::iterator ci = cdata->_converted_cache.find(modifier);
|
||||
if (ci != cdata->_converted_cache.end()) {
|
||||
cdata->_converted_cache.erase(ci);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ public:
|
|||
static void unpack_argb(float data[4], unsigned int packed_argb);
|
||||
|
||||
private:
|
||||
void remove_cache_entry(const qpGeomVertexFormat *format) const;
|
||||
void remove_cache_entry(const qpGeomVertexFormat *modifier) const;
|
||||
|
||||
private:
|
||||
CPT(qpGeomVertexFormat) _format;
|
||||
|
|
|
|||
|
|
@ -174,9 +174,9 @@ public:
|
|||
virtual void draw_sphere(GeomSphere *geom, GeomContext *gc)=0;
|
||||
|
||||
virtual bool begin_draw_primitives(const qpGeomVertexData *vertex_data)=0;
|
||||
virtual void draw_triangles(qpGeomTriangles *primitive)=0;
|
||||
virtual void draw_tristrips(qpGeomTristrips *primitive)=0;
|
||||
virtual void draw_trifans(qpGeomTrifans *primitive)=0;
|
||||
virtual void draw_triangles(const qpGeomTriangles *primitive)=0;
|
||||
virtual void draw_tristrips(const qpGeomTristrips *primitive)=0;
|
||||
virtual void draw_trifans(const qpGeomTrifans *primitive)=0;
|
||||
virtual void end_draw_primitives()=0;
|
||||
|
||||
virtual void framebuffer_copy_to_texture
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ add_object(CullableObject *object) {
|
|||
get_dual_transparent_state_decals() :
|
||||
get_dual_transparent_state();
|
||||
transparent_part->_state = state->compose(transparent_state);
|
||||
transparent_part->munge_vertices(_gsg);
|
||||
transparent_part->munge_geom(_gsg);
|
||||
CullBin *bin = get_bin(transparent_part->_state->get_bin_index());
|
||||
nassertv(bin != (CullBin *)NULL);
|
||||
bin->add_object(transparent_part);
|
||||
|
|
@ -155,7 +155,7 @@ add_object(CullableObject *object) {
|
|||
|
||||
// Munge vertices as needed for the GSG's requirements, and the
|
||||
// object's current state.
|
||||
object->munge_vertices(_gsg);
|
||||
object->munge_geom(_gsg);
|
||||
|
||||
CullBin *bin = get_bin(object->_state->get_bin_index());
|
||||
nassertv(bin != (CullBin *)NULL);
|
||||
|
|
|
|||
|
|
@ -104,23 +104,15 @@ has_decals() const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullableObject::munge_vertices
|
||||
// Function: CullableObject::munge_geom
|
||||
// Access: Public
|
||||
// Description: Gets a GeomMunger from the GSG to transform the
|
||||
// vertices to meet the GSG's vertex requirements for
|
||||
// the current state.
|
||||
// geom and/or its vertices to meet the GSG's vertex
|
||||
// requirements for the current state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CullableObject::
|
||||
munge_vertices(GraphicsStateGuardianBase *gsg) {
|
||||
// Temporary test until the experimental Geom rewrite becomes the
|
||||
// actual Geom implementation.
|
||||
if (_geom == (Geom *)NULL || _geom->is_exact_type(qpGeom::get_class_type())) {
|
||||
CPT(qpGeomMunger) munger = gsg->get_geom_munger(_state);
|
||||
_munged_data = munger->munge_data(((const qpGeom *)_geom.p())->get_vertex_data());
|
||||
if (_next != (CullableObject *)NULL) {
|
||||
_next->munge_vertices(gsg);
|
||||
}
|
||||
}
|
||||
munge_geom(GraphicsStateGuardianBase *gsg) {
|
||||
munge_geom(gsg->get_geom_munger(_state));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -23,6 +23,28 @@ CullableObject *CullableObject::_deleted_chain = (CullableObject *)NULL;
|
|||
int CullableObject::_num_ever_allocated = 0;
|
||||
TypeHandle CullableObject::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullableObject::munge_geom
|
||||
// Access: Public
|
||||
// Description: Uses the indicated GeomMunger to transform the geom
|
||||
// and/or its vertices.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CullableObject::
|
||||
munge_geom(const qpGeomMunger *munger) {
|
||||
if (_geom != (Geom *)NULL) {
|
||||
// Temporary test and dcast until the experimental Geom rewrite
|
||||
// becomes the actual Geom rewrite.
|
||||
if (_geom->is_exact_type(qpGeom::get_class_type())) {
|
||||
CPT(qpGeom) qpgeom = DCAST(qpGeom, _geom);
|
||||
qpgeom->munge_geom(munger, qpgeom, _munged_data);
|
||||
_geom = qpgeom;
|
||||
}
|
||||
}
|
||||
if (_next != (CullableObject *)NULL) {
|
||||
_next->munge_geom(munger);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CullableObject::Destructor
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ public:
|
|||
|
||||
INLINE bool has_decals() const;
|
||||
|
||||
INLINE void munge_vertices(GraphicsStateGuardianBase *gsg);
|
||||
INLINE void munge_geom(GraphicsStateGuardianBase *gsg);
|
||||
void munge_geom(const qpGeomMunger *munger);
|
||||
INLINE void draw(GraphicsStateGuardianBase *gsg);
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ void DrawCullHandler::
|
|||
record_object(CullableObject *object) {
|
||||
// Munge vertices as needed for the GSG's requirements, and the
|
||||
// object's current state.
|
||||
object->munge_vertices(_gsg);
|
||||
object->munge_geom(_gsg);
|
||||
|
||||
// And draw the object, then dispense with it.
|
||||
draw(object, _gsg);
|
||||
|
|
|
|||
|
|
@ -154,6 +154,24 @@ get_bin_index() const {
|
|||
return _bin_index;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::is_flat_shaded
|
||||
// Access: Published
|
||||
// Description: Returns true if this RenderState specifies a flat
|
||||
// shading model (that is, per-vertex color applies to
|
||||
// entire triangles), or false if it specifies a smooth
|
||||
// shading model or does not specify.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool RenderState::
|
||||
is_flat_shaded() const {
|
||||
if ((_flags & F_checked_flat_shaded) == 0) {
|
||||
// We pretend this function is const, even though it transparently
|
||||
// modifies the internal flat_shaded cache.
|
||||
((RenderState *)this)->determine_flat_shaded();
|
||||
}
|
||||
return ((_flags & F_flat_shaded) != 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::set_destructing
|
||||
// Access: Private
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "cullBinManager.h"
|
||||
#include "fogAttrib.h"
|
||||
#include "transparencyAttrib.h"
|
||||
#include "shadeModelAttrib.h"
|
||||
#include "pStatTimer.h"
|
||||
#include "config_pgraph.h"
|
||||
#include "bamReader.h"
|
||||
|
|
@ -1511,6 +1512,26 @@ determine_transparency() {
|
|||
_flags |= F_checked_transparency;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::determine_flat_shaded
|
||||
// Access: Private
|
||||
// Description: This is the private implementation of
|
||||
// is_flat_shaded().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RenderState::
|
||||
determine_flat_shaded() {
|
||||
const RenderAttrib *attrib =
|
||||
get_attrib(ShadeModelAttrib::get_class_type());
|
||||
if (attrib != (const RenderAttrib *)NULL) {
|
||||
const ShadeModelAttrib *sma = DCAST(ShadeModelAttrib, attrib);
|
||||
if (sma->get_mode() == ShadeModelAttrib::M_flat) {
|
||||
_flags |= F_flat_shaded;
|
||||
}
|
||||
}
|
||||
|
||||
_flags |= F_checked_flat_shaded;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: RenderState::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ PUBLISHED:
|
|||
INLINE const CullBinAttrib *get_bin() const;
|
||||
INLINE const TransparencyAttrib *get_transparency() const;
|
||||
INLINE int get_bin_index() const;
|
||||
INLINE bool is_flat_shaded() const;
|
||||
|
||||
public:
|
||||
CPT(RenderState) issue_delta_modify(const RenderState *other,
|
||||
|
|
@ -150,6 +151,7 @@ private:
|
|||
void determine_fog();
|
||||
void determine_bin();
|
||||
void determine_transparency();
|
||||
void determine_flat_shaded();
|
||||
|
||||
INLINE void set_destructing();
|
||||
INLINE bool is_destructing() const;
|
||||
|
|
@ -229,6 +231,8 @@ private:
|
|||
F_checked_fog = 0x0002,
|
||||
F_checked_bin = 0x0004,
|
||||
F_checked_transparency = 0x0008,
|
||||
F_checked_flat_shaded = 0x0010,
|
||||
F_flat_shaded = 0x0020,
|
||||
F_is_destructing = 0x8000,
|
||||
};
|
||||
unsigned short _flags;
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ static TimeCollectorProperties time_properties[] = {
|
|||
{ 1, "Cull:Show fps", { 0.5, 0.8, 1.0 } },
|
||||
{ 1, "Cull:Bins", { 0.3, 0.6, 0.3 } },
|
||||
{ 1, "Cull:Munge", { 0.3, 0.3, 0.9 } },
|
||||
{ 1, "Cull:Rotate", { 0.9, 0.8, 0.5 } },
|
||||
{ 1, "Draw", { 1.0, 0.0, 0.0 }, 1.0 / 30.0 },
|
||||
{ 1, "Draw:Make current", { 0.4, 0.2, 0.6 } },
|
||||
{ 1, "Draw:Copy texture", { 0.2, 0.6, 0.4 } },
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ run() {
|
|||
// vertices.
|
||||
_surfaces.clear();
|
||||
|
||||
_data->remove_unused_vertices();
|
||||
_data->remove_unused_vertices(true);
|
||||
write_egg_file();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ post_process_egg_files() {
|
|||
nout << "Stripping normals.\n";
|
||||
for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
|
||||
(*ei)->strip_normals();
|
||||
(*ei)->remove_unused_vertices();
|
||||
(*ei)->remove_unused_vertices(true);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ post_process_egg_files() {
|
|||
nout << "Recomputing polygon normals.\n";
|
||||
for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
|
||||
(*ei)->recompute_polygon_normals();
|
||||
(*ei)->remove_unused_vertices();
|
||||
(*ei)->remove_unused_vertices(true);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ post_process_egg_files() {
|
|||
nout << "Recomputing vertex normals.\n";
|
||||
for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
|
||||
(*ei)->recompute_vertex_normals(_normals_threshold);
|
||||
(*ei)->remove_unused_vertices();
|
||||
(*ei)->remove_unused_vertices(true);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -142,19 +142,19 @@ post_process_egg_file() {
|
|||
case NM_strip:
|
||||
nout << "Stripping normals.\n";
|
||||
_data->strip_normals();
|
||||
_data->remove_unused_vertices();
|
||||
_data->remove_unused_vertices(true);
|
||||
break;
|
||||
|
||||
case NM_polygon:
|
||||
nout << "Recomputing polygon normals.\n";
|
||||
_data->recompute_polygon_normals();
|
||||
_data->remove_unused_vertices();
|
||||
_data->remove_unused_vertices(true);
|
||||
break;
|
||||
|
||||
case NM_vertex:
|
||||
nout << "Recomputing vertex normals.\n";
|
||||
_data->recompute_vertex_normals(_normals_threshold);
|
||||
_data->remove_unused_vertices();
|
||||
_data->remove_unused_vertices(true);
|
||||
break;
|
||||
|
||||
case NM_preserve:
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ run() {
|
|||
int num_removed = strip_prims(_data);
|
||||
nout << "Removed " << num_removed << " primitives.\n";
|
||||
|
||||
_data->remove_unused_vertices();
|
||||
_data->remove_unused_vertices(true);
|
||||
write_egg_file();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ EggToC() :
|
|||
void EggToC::
|
||||
run() {
|
||||
nout << "Removing invalid primitives.\n";
|
||||
int num_removed = _data->remove_invalid_primitives();
|
||||
int num_removed = _data->remove_invalid_primitives(true);
|
||||
nout << " (" << num_removed << " removed.)\n";
|
||||
|
||||
if (_triangulate_polygons) {
|
||||
|
|
@ -106,7 +106,7 @@ run() {
|
|||
|
||||
_data->apply_texmats();
|
||||
_data->flatten_transforms();
|
||||
_data->remove_unused_vertices();
|
||||
_data->remove_unused_vertices(true);
|
||||
|
||||
// Collect all the polygons together into polysets.
|
||||
EggPolysetMaker pmaker;
|
||||
|
|
|
|||
|
|
@ -89,9 +89,9 @@ void EggTrans::
|
|||
run() {
|
||||
if (_remove_invalid_primitives) {
|
||||
nout << "Removing invalid primitives.\n";
|
||||
int num_removed = _data->remove_invalid_primitives();
|
||||
int num_removed = _data->remove_invalid_primitives(true);
|
||||
nout << " (" << num_removed << " removed.)\n";
|
||||
_data->remove_unused_vertices();
|
||||
_data->remove_unused_vertices(true);
|
||||
}
|
||||
|
||||
if (_triangulate_polygons) {
|
||||
|
|
@ -108,7 +108,7 @@ run() {
|
|||
if (_apply_texmats) {
|
||||
nout << "Applying texture matrices.\n";
|
||||
_data->apply_texmats();
|
||||
_data->remove_unused_vertices();
|
||||
_data->remove_unused_vertices(true);
|
||||
}
|
||||
|
||||
if (_collapse_equivalent_textures) {
|
||||
|
|
@ -120,7 +120,7 @@ run() {
|
|||
if (_flatten_transforms) {
|
||||
nout << "Flattening transforms.\n";
|
||||
_data->flatten_transforms();
|
||||
_data->remove_unused_vertices();
|
||||
_data->remove_unused_vertices(true);
|
||||
}
|
||||
|
||||
if (_standardize_names) {
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ convert_lwo(const LwoHeader *lwo_header) {
|
|||
make_egg();
|
||||
connect_egg();
|
||||
|
||||
_egg_data->remove_unused_vertices();
|
||||
_egg_data->remove_unused_vertices(true);
|
||||
cleanup();
|
||||
|
||||
return !had_error();
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ add_bin(EggBin *egg_bin, XFileNode *x_parent) {
|
|||
bool XFileMaker::
|
||||
add_polyset(EggBin *egg_bin, XFileNode *x_parent) {
|
||||
// Make sure that all our polygons are reasonable.
|
||||
egg_bin->remove_invalid_primitives();
|
||||
egg_bin->remove_invalid_primitives(true);
|
||||
|
||||
XFileMesh *mesh = get_mesh(x_parent);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue