Fix various issues in bam2egg:

* No longer inserts an extra root group for the ModelRoot
 * Support depth test, offset and cull bin attributes
 * Preserve non-GeomNodes under Character
 * Render attributes are applied on group level if possible
This commit is contained in:
rdb 2016-09-14 21:54:35 +02:00
parent 08ea4bf2e5
commit 0bdafe45ce
20 changed files with 261 additions and 158 deletions

View File

@ -17,7 +17,6 @@
TypeHandle EggLine::_type_handle;
/**
*
*/
@ -26,6 +25,14 @@ EggLine::
clear();
}
/**
* Makes a copy of this object.
*/
EggLine *EggLine::
make_copy() const {
return new EggLine(*this);
}
/**
* Writes the point to the indicated output stream in Egg format.
*/

View File

@ -29,6 +29,8 @@ PUBLISHED:
INLINE EggLine &operator = (const EggLine &copy);
virtual ~EggLine();
virtual EggLine *make_copy() const OVERRIDE;
virtual void write(ostream &out, int indent_level) const;
INLINE bool has_thick() const;

View File

@ -17,6 +17,14 @@
TypeHandle EggNurbsCurve::_type_handle;
/**
* Makes a copy of this object.
*/
EggNurbsCurve *EggNurbsCurve::
make_copy() const {
return new EggNurbsCurve(*this);
}
/**
* Prepares a new curve definition with the indicated order and number of
* knots. This also implies a particular number of vertices as well (the

View File

@ -29,6 +29,8 @@ PUBLISHED:
INLINE EggNurbsCurve(const EggNurbsCurve &copy);
INLINE EggNurbsCurve &operator = (const EggNurbsCurve &copy);
virtual EggNurbsCurve *make_copy() const OVERRIDE;
void setup(int order, int num_knots);
INLINE void set_order(int order);

View File

@ -17,6 +17,14 @@
TypeHandle EggNurbsSurface::_type_handle;
/**
* Makes a copy of this object.
*/
EggNurbsSurface *EggNurbsSurface::
make_copy() const {
return new EggNurbsSurface(*this);
}
/**
* Prepares a new surface definition with the indicated order and number of
* knots in each dimension. This also implies a particular number of vertices

View File

@ -36,6 +36,8 @@ PUBLISHED:
INLINE EggNurbsSurface(const EggNurbsSurface &copy);
INLINE EggNurbsSurface &operator = (const EggNurbsSurface &copy);
virtual EggNurbsSurface *make_copy() const OVERRIDE;
void setup(int u_order, int v_order,
int num_u_knots, int num_v_knots);

View File

@ -21,6 +21,13 @@
TypeHandle EggPatch::_type_handle;
/**
* Makes a copy of this object.
*/
EggPatch *EggPatch::
make_copy() const {
return new EggPatch(*this);
}
/**
* Writes the patch to the indicated output stream in Egg format.

View File

@ -28,6 +28,8 @@ PUBLISHED:
INLINE EggPatch(const EggPatch &copy);
INLINE EggPatch &operator = (const EggPatch &copy);
virtual EggPatch *make_copy() const OVERRIDE;
virtual void write(ostream &out, int indent_level) const;
public:

View File

@ -17,6 +17,13 @@
TypeHandle EggPoint::_type_handle;
/**
* Makes a copy of this object.
*/
EggPoint *EggPoint::
make_copy() const {
return new EggPoint(*this);
}
/**
* Cleans up modeling errors in whatever context this makes sense. For

View File

@ -28,6 +28,8 @@ PUBLISHED:
INLINE EggPoint(const EggPoint &copy);
INLINE EggPoint &operator = (const EggPoint &copy);
virtual EggPoint *make_copy() const OVERRIDE;
INLINE bool has_thick() const;
INLINE double get_thick() const;
INLINE void set_thick(double thick);

View File

@ -21,6 +21,13 @@
TypeHandle EggPolygon::_type_handle;
/**
* Makes a copy of this object.
*/
EggPolygon *EggPolygon::
make_copy() const {
return new EggPolygon(*this);
}
/**
* Cleans up modeling errors in whatever context this makes sense. For

View File

@ -27,6 +27,8 @@ PUBLISHED:
INLINE EggPolygon(const EggPolygon &copy);
INLINE EggPolygon &operator = (const EggPolygon &copy);
virtual EggPolygon *make_copy() const OVERRIDE;
virtual bool cleanup();
bool calculate_normal(LNormald &result, CoordinateSystem cs = CS_default) const;

View File

@ -72,6 +72,8 @@ PUBLISHED:
INLINE EggPrimitive &operator = (const EggPrimitive &copy);
INLINE ~EggPrimitive();
virtual EggPrimitive *make_copy() const=0;
virtual EggRenderMode *determine_alpha_mode();
virtual EggRenderMode *determine_depth_write_mode();
virtual EggRenderMode *determine_depth_test_mode();

View File

@ -18,7 +18,6 @@
TypeHandle EggTriangleFan::_type_handle;
/**
*
*/
@ -27,6 +26,14 @@ EggTriangleFan::
clear();
}
/**
* Makes a copy of this object.
*/
EggTriangleFan *EggTriangleFan::
make_copy() const {
return new EggTriangleFan(*this);
}
/**
* Writes the triangle fan to the indicated output stream in Egg format.
*/

View File

@ -29,6 +29,8 @@ PUBLISHED:
INLINE EggTriangleFan &operator = (const EggTriangleFan &copy);
virtual ~EggTriangleFan();
virtual EggTriangleFan *make_copy() const OVERRIDE;
virtual void write(ostream &out, int indent_level) const;
virtual void apply_first_attribute();

View File

@ -18,7 +18,6 @@
TypeHandle EggTriangleStrip::_type_handle;
/**
*
*/
@ -27,6 +26,14 @@ EggTriangleStrip::
clear();
}
/**
* Makes a copy of this object.
*/
EggTriangleStrip *EggTriangleStrip::
make_copy() const {
return new EggTriangleStrip(*this);
}
/**
* Writes the triangle strip to the indicated output stream in Egg format.
*/

View File

@ -29,6 +29,8 @@ PUBLISHED:
INLINE EggTriangleStrip &operator = (const EggTriangleStrip &copy);
virtual ~EggTriangleStrip();
virtual EggTriangleStrip *make_copy() const OVERRIDE;
virtual void write(ostream &out, int indent_level) const;
protected:

View File

@ -23,8 +23,11 @@
#include "colorAttrib.h"
#include "materialAttrib.h"
#include "textureAttrib.h"
#include "cullBinAttrib.h"
#include "cullFaceAttrib.h"
#include "transparencyAttrib.h"
#include "depthTestAttrib.h"
#include "depthOffsetAttrib.h"
#include "depthWriteAttrib.h"
#include "lodNode.h"
#include "switchNode.h"
@ -101,6 +104,26 @@ add_node(PandaNode *node) {
_vpool = NULL;
}
/**
* Adds the scene graph rooted at the indicated node (but without the node
* itself) to the accumulated egg data within this object. Call
* get_egg_data() to retrieve the result.
*/
void EggSaver::
add_subgraph(PandaNode *root) {
_vpool = new EggVertexPool(root->get_name());
_data->add_child(_vpool);
NodePath root_path(root);
recurse_nodes(root_path, _data, false, NULL);
// Remove the vertex pool if it has no vertices.
if (_vpool->empty()) {
_data->remove_child(_vpool);
}
_vpool = NULL;
}
/**
* Converts the indicated node to the corresponding Egg constructs, by first
* determining what kind of node it is.
@ -359,9 +382,12 @@ convert_character_node(Character *node, const WorkingNodePath &node_path,
EggGroupNode *egg_parent, bool has_decal) {
// A sequence node gets converted to an ordinary EggGroup, we only apply the
// appropriate switch attributes to turn it into a sequence
// appropriate switch attributes to turn it into a sequence.
// We have to use DT_structured since it is the only mode that preserves the
// node hierarchy, including LODNodes and CollisionNodes that may be under
// this Character node.
EggGroup *egg_group = new EggGroup(node->get_name());
egg_group->set_dart_type(EggGroup::DT_default);
egg_group->set_dart_type(EggGroup::DT_structured);
egg_parent->add_child(egg_group);
apply_node_properties(egg_group, node);
@ -611,7 +637,8 @@ convert_geom_node(GeomNode *node, const WorkingNodePath &node_path,
// Now get out all the various kinds of geometry.
int num_geoms = node->get_num_geoms();
for (int i = 0; i < num_geoms; ++i) {
CPT(RenderState) geom_state = net_state->compose(node->get_geom_state(i));
CPT(RenderState) geom_state = node->get_geom_state(i);
CPT(RenderState) geom_net_state = net_state->compose(geom_state);
const Geom *geom = node->get_geom(i);
int num_primitives = geom->get_num_primitives();
@ -620,7 +647,7 @@ convert_geom_node(GeomNode *node, const WorkingNodePath &node_path,
CPT(GeomPrimitive) simple = primitive->decompose();
CPT(GeomVertexData) vdata = geom->get_vertex_data();
// vdata = vdata->animate_vertices(true, Thread::get_current_thread());
convert_primitive(vdata, simple, geom_state,
convert_primitive(vdata, simple, geom_state, geom_net_state,
net_mat, egg_parent, joint_map);
}
}
@ -634,11 +661,29 @@ convert_geom_node(GeomNode *node, const WorkingNodePath &node_path,
void EggSaver::
convert_primitive(const GeomVertexData *vertex_data,
const GeomPrimitive *primitive,
const RenderState *net_state,
const RenderState *geom_state, const RenderState *net_state,
const LMatrix4 &net_mat, EggGroupNode *egg_parent,
CharacterJointMap *joint_map) {
GeomVertexReader reader(vertex_data);
// Make a zygote that will be duplicated for each primitive.
PT(EggPrimitive) egg_prim;
if (primitive->is_of_type(GeomTriangles::get_class_type())) {
egg_prim = new EggPolygon();
} else if (primitive->is_of_type(GeomPatches::get_class_type())) {
egg_prim = new EggPatch();
} else if (primitive->is_of_type(GeomPoints::get_class_type())) {
egg_prim = new EggPoint();
} else if (primitive->is_of_type(GeomLines::get_class_type())) {
egg_prim = new EggLine();
} else {
// Huh, an unknown geometry type.
return;
}
// Apply render attributes.
apply_state_properties(egg_prim, geom_state);
// Check for a color scale.
LVecBase4 color_scale(1.0f, 1.0f, 1.0f, 1.0f);
const ColorScaleAttrib *csa;
@ -670,19 +715,19 @@ convert_primitive(const GeomVertexData *vertex_data,
const MaterialAttrib *ma;
if (net_state->get_attrib(ma)) {
egg_mat = get_egg_material(ma->get_material());
if (egg_mat != (EggMaterial *)NULL) {
egg_prim->set_material(egg_mat);
}
}
// Check for a texture.
EggTexture *egg_tex = (EggTexture *)NULL;
const TextureAttrib *ta;
if (net_state->get_attrib(ta)) {
egg_tex = get_egg_texture(ta->get_texture());
}
EggTexture *egg_tex = get_egg_texture(ta->get_texture());
// Check the texture environment
if ((ta != (const TextureAttrib *)NULL) && (egg_tex != (const EggTexture *)NULL)) {
TextureStage* tex_stage = ta->get_on_stage(0);
if (tex_stage != (const TextureStage *)NULL) {
if (egg_tex != (EggTexture *)NULL) {
TextureStage *tex_stage = ta->get_on_stage(0);
if (tex_stage != (TextureStage *)NULL) {
switch (tex_stage->get_mode()) {
case TextureStage::M_modulate:
if (has_color_off == true) {
@ -710,6 +755,9 @@ convert_primitive(const GeomVertexData *vertex_data,
break;
}
}
egg_prim->set_texture(egg_tex);
}
}
// Check the backface flag.
@ -717,73 +765,22 @@ convert_primitive(const GeomVertexData *vertex_data,
const CullFaceAttrib *cfa;
if (net_state->get_attrib(cfa)) {
if (cfa->get_effective_mode() == CullFaceAttrib::M_cull_none) {
bface = true;
}
}
// Check the depth write flag - only needed for AM_blend_no_occlude
bool has_depthwrite = false;
DepthWriteAttrib::Mode depthwrite = DepthWriteAttrib::M_on;
const DepthWriteAttrib *dwa;
if (net_state->get_attrib(dwa)) {
depthwrite = dwa->get_mode();
has_depthwrite = true;
}
// Check the transparency flag.
bool has_transparency = false;
TransparencyAttrib::Mode transparency = TransparencyAttrib::M_none;
const TransparencyAttrib *tra;
if (net_state->get_attrib(tra)) {
transparency = tra->get_mode();
has_transparency = true;
}
if (has_transparency && (egg_tex != (EggTexture *)NULL)) {
EggRenderMode::AlphaMode tex_trans = EggRenderMode::AM_unspecified;
switch (transparency) {
case TransparencyAttrib::M_none:
tex_trans = EggRenderMode::AM_off;
break;
case TransparencyAttrib::M_alpha:
if (has_depthwrite && (depthwrite == DepthWriteAttrib::M_off)) {
tex_trans = EggRenderMode::AM_blend_no_occlude;
has_depthwrite = false;
} else {
tex_trans = EggRenderMode::AM_blend;
}
break;
case TransparencyAttrib::M_premultiplied_alpha:
tex_trans = EggRenderMode::AM_premultiplied;
break;
case TransparencyAttrib::M_multisample:
tex_trans = EggRenderMode::AM_ms;
break;
case TransparencyAttrib::M_multisample_mask:
tex_trans = EggRenderMode::AM_ms_mask;
break;
case TransparencyAttrib::M_binary:
tex_trans = EggRenderMode::AM_binary;
break;
case TransparencyAttrib::M_dual:
tex_trans = EggRenderMode::AM_dual;
break;
default: // intentional fall-through
break;
}
if (tex_trans != EggRenderMode::AM_unspecified) {
egg_tex->set_alpha_mode(tex_trans);
egg_prim->set_bface_flag(true);
}
}
// Check for line thickness and such.
bool has_render_mode = false;
bool perspective = false;
PN_stdfloat thickness = 1;
const RenderModeAttrib *rma;
if (net_state->get_attrib(rma)) {
has_render_mode = true;
thickness = rma->get_thickness();
perspective = rma->get_perspective();
if (egg_prim->is_of_type(EggPoint::get_class_type())) {
EggPoint *egg_point = (EggPoint *)egg_prim.p();
egg_point->set_thick(rma->get_thickness());
egg_point->set_perspective(rma->get_perspective());
} else if (egg_prim->is_of_type(EggLine::get_class_type())) {
EggLine *egg_line = (EggLine *)egg_prim.p();
egg_line->set_thick(rma->get_thickness());
}
}
LNormal normal;
@ -793,48 +790,9 @@ convert_primitive(const GeomVertexData *vertex_data,
int num_primitives = primitive->get_num_primitives();
int num_vertices = primitive->get_num_vertices_per_primitive();
EggPrimitive *(*make_func)(void);
if (primitive->is_of_type(GeomTriangles::get_class_type())) {
make_func = make_egg_polygon;
} else if (primitive->is_of_type(GeomPatches::get_class_type())) {
make_func = make_egg_patch;
} else if (primitive->is_of_type(GeomPoints::get_class_type())) {
make_func = make_egg_point;
} else if (primitive->is_of_type(GeomLines::get_class_type())) {
make_func = make_egg_line;
} else {
// Huh, an unknown geometry type.
return;
}
for (int i = 0; i < num_primitives; ++i) {
PT(EggPrimitive) egg_prim = (*make_func)();
egg_parent->add_child(egg_prim);
if (egg_mat != (EggMaterial *)NULL) {
egg_prim->set_material(egg_mat);
}
if (egg_tex != (EggTexture *)NULL) {
egg_prim->set_texture(egg_tex);
}
if (bface) {
egg_prim->set_bface_flag(true);
}
if (has_render_mode) {
if (egg_prim->is_of_type(EggPoint::get_class_type())) {
EggPoint *egg_point = (EggPoint *)egg_prim.p();
egg_point->set_thick(thickness);
egg_point->set_perspective(perspective);
} else if (egg_prim->is_of_type(EggLine::get_class_type())) {
EggLine *egg_line = (EggLine *)egg_prim.p();
egg_line->set_thick(thickness);
}
}
PT(EggPrimitive) egg_child = egg_prim->make_copy();
egg_parent->add_child(egg_child);
for (int j = 0; j < num_vertices; j++) {
EggVertex egg_vert;
@ -898,7 +856,7 @@ convert_primitive(const GeomVertexData *vertex_data,
}
}
egg_prim->add_vertex(new_egg_vert);
egg_child->add_vertex(new_egg_vert);
}
}
}
@ -1004,6 +962,97 @@ apply_node_properties(EggGroup *egg_group, PandaNode *node, bool allow_backstage
any_applied = true;
}
const RenderState *state = node->get_state();
if (apply_state_properties(egg_group, state)) {
return true;
}
return any_applied;
}
/**
* Applies any special render state settings on the primitive or group.
* Returns true if any were applied, false otherwise.
*/
bool EggSaver::
apply_state_properties(EggRenderMode *egg_render_mode, const RenderState *state) {
if (state->is_empty()) {
return false;
}
bool any_applied = false;
// Check the transparency mode.
const TransparencyAttrib *tra;
if (state->get_attrib(tra)) {
EggRenderMode::AlphaMode tex_trans = EggRenderMode::AM_unspecified;
switch (tra->get_mode()) {
case TransparencyAttrib::M_none:
tex_trans = EggRenderMode::AM_off;
break;
case TransparencyAttrib::M_alpha:
tex_trans = EggRenderMode::AM_blend;
break;
case TransparencyAttrib::M_premultiplied_alpha:
tex_trans = EggRenderMode::AM_premultiplied;
break;
case TransparencyAttrib::M_multisample:
tex_trans = EggRenderMode::AM_ms;
break;
case TransparencyAttrib::M_multisample_mask:
tex_trans = EggRenderMode::AM_ms_mask;
break;
case TransparencyAttrib::M_binary:
tex_trans = EggRenderMode::AM_binary;
break;
case TransparencyAttrib::M_dual:
tex_trans = EggRenderMode::AM_dual;
break;
default: // intentional fall-through
break;
}
egg_render_mode->set_alpha_mode(tex_trans);
}
const DepthWriteAttrib *dwa;
if (state->get_attrib(dwa)) {
if (dwa->get_mode() != DepthWriteAttrib::M_off) {
egg_render_mode->set_depth_write_mode(EggRenderMode::DWM_on);
} else if (egg_render_mode->get_alpha_mode() == EggRenderMode::AM_blend) {
// AM_blend_no_occlude is like AM_blend but also implies DWM_off.
egg_render_mode->set_alpha_mode(EggRenderMode::AM_blend_no_occlude);
} else {
egg_render_mode->set_depth_write_mode(EggRenderMode::DWM_off);
}
any_applied = true;
}
const DepthTestAttrib *dta;
if (state->get_attrib(dta)) {
RenderAttrib::PandaCompareFunc mode = dta->get_mode();
if (mode == DepthTestAttrib::M_none || mode == DepthTestAttrib::M_always) {
egg_render_mode->set_depth_test_mode(EggRenderMode::DTM_off);
} else {
egg_render_mode->set_depth_test_mode(EggRenderMode::DTM_on);
}
any_applied = true;
}
const DepthOffsetAttrib *doa;
if (state->get_attrib(doa)) {
egg_render_mode->set_depth_offset(doa->get_offset());
any_applied = true;
}
const CullBinAttrib *cba;
if (state->get_attrib(cba)) {
egg_render_mode->set_bin(cba->get_bin_name());
egg_render_mode->set_draw_order(cba->get_draw_order());
any_applied = true;
}
return any_applied;
}
@ -1250,35 +1299,3 @@ get_egg_texture(Texture *tex) {
return NULL;
}
/**
* A factory function to make a new EggPolygon instance.
*/
EggPrimitive *EggSaver::
make_egg_polygon() {
return new EggPolygon;
}
/**
* A factory function to make a new EggPatch instance.
*/
EggPrimitive *EggSaver::
make_egg_patch() {
return new EggPatch;
}
/**
* A factory function to make a new EggPoint instance.
*/
EggPrimitive *EggSaver::
make_egg_point() {
return new EggPoint;
}
/**
* A factory function to make a new EggLine instance.
*/
EggPrimitive *EggSaver::
make_egg_line() {
return new EggLine;
}

View File

@ -55,6 +55,7 @@ PUBLISHED:
EggSaver(EggData *data = NULL);
void add_node(PandaNode *node);
void add_subgraph(PandaNode *root);
INLINE EggData *get_egg_data() const;
private:
@ -84,6 +85,7 @@ private:
EggGroupNode *egg_parent, bool has_decal, CharacterJointMap *jointMap=NULL);
void convert_primitive(const GeomVertexData *vertex_data,
const GeomPrimitive *primitive,
const RenderState *geom_state,
const RenderState *net_state,
const LMatrix4 &net_mat, EggGroupNode *egg_parent,
CharacterJointMap *jointMap);
@ -91,17 +93,13 @@ private:
void recurse_nodes(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
bool has_decal, CharacterJointMap *joint_map);
bool apply_node_properties(EggGroup *egg_group, PandaNode *node, bool allow_backstage = true);
bool apply_state_properties(EggRenderMode *egg_render_mode, const RenderState *state);
bool apply_tags(EggGroup *egg_group, PandaNode *node);
bool apply_tag(EggGroup *egg_group, PandaNode *node, const string &tag);
EggMaterial *get_egg_material(Material *tex);
EggTexture *get_egg_texture(Texture *tex);
static EggPrimitive *make_egg_polygon();
static EggPrimitive *make_egg_patch();
static EggPrimitive *make_egg_point();
static EggPrimitive *make_egg_line();
PT(EggData) _data;
PT(EggVertexPool) _vpool;

View File

@ -31,7 +31,13 @@ save_egg_file(const Filename &filename, PandaNode *node, CoordinateSystem cs) {
data->set_coordinate_system(cs);
EggSaver saver(data);
if (node->is_of_type(ModelRoot::get_class_type())) {
// If this is a ModelRoot, only write the nodes below it. Otherwise we
// end up inserting a node when we do a bam2egg.
saver.add_subgraph(node);
} else {
saver.add_node(node);
}
return data->write_egg(filename);
}
@ -43,6 +49,12 @@ save_egg_file(const Filename &filename, PandaNode *node, CoordinateSystem cs) {
bool
save_egg_data(EggData *data, PandaNode *node) {
EggSaver saver(data);
if (node->is_of_type(ModelRoot::get_class_type())) {
// If this is a ModelRoot, only write the nodes below it. Otherwise we
// end up inserting a node when we do a bam2egg.
saver.add_subgraph(node);
} else {
saver.add_node(node);
}
return true;
}