new egg2pg

This commit is contained in:
David Rose 2002-02-27 03:13:06 +00:00
parent 12491ac116
commit 2268aa2adc
31 changed files with 2931 additions and 150 deletions

View File

@ -8,7 +8,7 @@
#define BUILDING_DLL BUILDING_PANDAEGG
#define COMPONENT_LIBS \
egg2sg egg builder
egg2pg egg2sg egg builder
#define LOCAL_LIBS putil express
#define OTHER_LIBS dtoolconfig dtool

View File

@ -18,12 +18,14 @@
#include "builderFuncs.h"
#include "builderMisc.h"
#include <notify.h>
#include <namedNode.h>
#include <geomNode.h>
#include "notify.h"
#include "namedNode.h"
#include "geomNode.h"
#include "pmap.h"
#include "builder.h"
#include <renderRelation.h>
#include "renderRelation.h"
#include "pandaNode.h"
#include "qpgeomNode.h"
////////////////////////////////////////////////////////////////////
@ -92,6 +94,31 @@ public:
const BuilderBucket *_bucket;
};
class qpNodeMap : public Namable {
public:
qpNodeMap(PandaNode *node, const BuilderBucket *bucket)
: _node(node), _bucket(bucket) { }
bool operator < (const qpNodeMap &other) const {
if (_node != other._node) {
return _node < other._node;
}
if (_bucket->get_name() != other._bucket->get_name()) {
return _bucket->get_name() < other._bucket->get_name();
}
return (_bucket->_state < other._bucket->_state);
}
PandaNode *_node;
// Although a bucket pointer is stored here in the NodeMap class,
// you should not use it except to extract the name and/or the
// _trans member. Remember, this bucket pointer stands for any of
// possibly several bucket pointers, all different, except that they
// share the same name.
const BuilderBucket *_bucket;
};
////////////////////////////////////////////////////////////////////
@ -215,6 +242,126 @@ build(const string &default_name) {
return base_geom_node;
}
////////////////////////////////////////////////////////////////////
// Function: Builder::build
// Access: Public
// Description: Creates Geoms for all the primitives added to all
// buckets, and adds them where appropriate to place
// them in the scene graph under their respective
// parents, and/or returns a single GeomNode that
// contains all geometry whose bucket did not reference
// a particular scene graph node to parent them to.
//
// If a bucket's _node pointer was a GeomNode, the
// geometry will be added directly to that node. If the
// _node pointer was any other kind of node, a GeomNode
// will be created and parented to that node, and its
// name will be the name of the bucket. In this case,
// the name of the bucket can also be used to different
// nodes: if two buckets reference the same node, but
// have different names, then two different GeomNodes
// are created, one with each name.
////////////////////////////////////////////////////////////////////
qpGeomNode *Builder::
qpbuild(const string &default_name) {
typedef pmap<qpNodeMap, qpGeomNode *> GeomNodeMap;
GeomNodeMap geom_nodes;
// First, build all the Geoms and create GeomNodes for them. Each
// unique Node gets its own GeomNode. If the Node is itself a
// GeomNode, that GeomNode is used directly.
Buckets::iterator i;
for (i = _buckets.begin();
i != _buckets.end();
++i) {
BuilderBucket *bucket = (*i).get_bucket();
PandaNode *node = bucket->_qpnode;
// const string &name = bucket->get_name();
qpGeomNode *geom_node = NULL;
if (node!=NULL && node->is_of_type(qpGeomNode::get_class_type())) {
// The node is a GeomNode. In this case, we simply use that
// node. We can't separate them out by name in this case; we'll
// just assign to it the first nonempty name we encounter.
geom_node = DCAST(qpGeomNode, node);
// Since the caller already created this GeomNode and passed it
// in, we'll leave it up to the caller to name the node and set
// up the state transitions leading into it.
} else {
// The node is not a GeomNode, so look it up in the map.
GeomNodeMap::iterator f = geom_nodes.find(qpNodeMap(node, bucket));
if (f != geom_nodes.end()) {
geom_node = (*f).second;
} else {
// No such node/name combination. Create a new one.
geom_node = bucket->qpmake_geom_node();
if (geom_node != NULL) {
geom_nodes[qpNodeMap(node, bucket)] = geom_node;
}
}
}
if (geom_node != NULL) {
(*i).build(geom_node);
}
}
// Now go through and parent the geom_nodes under their respective
// group nodes. Save out the geom_node associated with a NULL Node;
// this one is returned from this function.
qpGeomNode *base_geom_node = NULL;
GeomNodeMap::iterator gi;
for (gi = geom_nodes.begin();
gi != geom_nodes.end();
++gi) {
const qpNodeMap &nm = (*gi).first;
qpGeomNode *geom_node = (*gi).second;
PandaNode *node = nm._node;
const string &name = nm._bucket->get_name();
CPT(RenderState) state = nm._bucket->_state;
// Assign the name to the geom, if it doesn't have one already.
if (!geom_node->has_name()) {
if (!name.empty()) {
geom_node->set_name(name);
} else if (!default_name.empty()) {
geom_node->set_name(default_name);
}
}
// Only reparent the geom_node if it has no parent already.
int num_parents = geom_node->get_num_parents();
if (num_parents == 0) {
if (geom_node->get_num_geoms() == 0) {
// If there was nothing added, never mind.
delete geom_node;
} else if (node==NULL) {
nassertr(base_geom_node == NULL, NULL);
base_geom_node = geom_node;
} else {
node->add_child(geom_node);
// Now, this is our only opportunity to apply the scene-graph
// state specified in the bucket to the node: we have created
// our own geom_node for these buckets, and we have parented
// it to the scene graph.
geom_node->set_state(state);
}
}
}
return base_geom_node;
}
////////////////////////////////////////////////////////////////////
// Function: Builder::add_bucket

View File

@ -176,6 +176,7 @@
class GeomNode;
class qpGeomNode;
///////////////////////////////////////////////////////////////////
@ -196,6 +197,7 @@ public:
const BuilderPrimI &prim);
GeomNode *build(const string &default_name = "");
qpGeomNode *qpbuild(const string &default_name = "");
protected:
void add_bucket(const BuilderBucket &bucket);

View File

@ -21,8 +21,9 @@
#include "builderBucket.h"
#include "builderFuncs.h"
#include "builderMisc.h"
#include <namedNode.h>
#include <geomNode.h>
#include "namedNode.h"
#include "geomNode.h"
#include "qpgeomNode.h"
BuilderBucket *BuilderBucket::_default_bucket = NULL;
@ -36,6 +37,7 @@ BuilderBucket *BuilderBucket::_default_bucket = NULL;
BuilderBucket::
BuilderBucket() {
_node = NULL;
_qpnode = NULL;
(*this) = (*get_default_bucket());
}
@ -48,6 +50,7 @@ BuilderBucket() {
BuilderBucket::
BuilderBucket(const BuilderBucket &copy) {
_node = NULL;
_qpnode = NULL;
(*this) = copy;
}
@ -69,10 +72,12 @@ operator = (const BuilderBucket &copy) {
set_colors(copy._colors);
_node = copy._node;
_qpnode = copy._qpnode;
_drawBin = copy._drawBin;
_drawOrder = copy._drawOrder;
_trans = copy._trans;
_state = copy._state;
return *this;
}
@ -117,6 +122,20 @@ make_geom_node() {
return new GeomNode;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::qpmake_geom_node
// Access: Public, Virtual
// Description: Called by the builder when it is time to create a new
// GeomNode. This function should allocate and return a
// new GeomNode suitable for adding geometry to. You
// may redefine it to return a subclass of GeomNode, or
// to do some initialization to the node.
////////////////////////////////////////////////////////////////////
qpGeomNode *BuilderBucket::
qpmake_geom_node() {
return new qpGeomNode("");
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucket::done_geom
// Access: Public, Virtual
@ -231,6 +250,7 @@ output(ostream &out) const {
BuilderBucket::
BuilderBucket(int) {
_node = NULL;
_qpnode = NULL;
_drawBin = -1;
_drawOrder = 0;
@ -251,4 +271,6 @@ BuilderBucket(int) {
_consider_fans = true;
_max_tfan_angle = 40.0;
_min_tfan_tris = 0;
_state = RenderState::make_empty();
}

View File

@ -19,25 +19,28 @@
#ifndef BUILDERBUCKET_H
#define BUILDERBUCKET_H
#include <pandabase.h>
#include "pandabase.h"
#include "builderProperties.h"
#include <namable.h>
#include <pointerToArray.h>
#include <luse.h>
#include <nodeTransitions.h>
#include <pta_Vertexf.h>
#include <pta_Normalf.h>
#include <pta_Colorf.h>
#include <pta_TexCoordf.h>
#include "namable.h"
#include "pointerToArray.h"
#include "luse.h"
#include "nodeTransitions.h"
#include "pta_Vertexf.h"
#include "pta_Normalf.h"
#include "pta_Colorf.h"
#include "pta_TexCoordf.h"
#include "renderState.h"
#include <stdlib.h>
#include "stdlib.h"
class NamedNode;
class Geom;
class GeomNode;
class PandaNode;
class qpGeomNode;
///////////////////////////////////////////////////////////////////
@ -67,6 +70,7 @@ public:
virtual BuilderBucket *make_copy() const;
virtual GeomNode *make_geom_node();
virtual qpGeomNode *qpmake_geom_node();
virtual Geom *done_geom(Geom *geom);
virtual bool operator < (const BuilderBucket &other) const;
@ -88,11 +92,13 @@ public:
virtual void output(ostream &out) const;
NamedNode *_node;
PandaNode *_qpnode;
short _drawBin;
unsigned int _drawOrder;
NodeTransitions _trans;
CPT(RenderState) _state;
protected:
PTA_Vertexf _coords;

View File

@ -17,9 +17,11 @@
////////////////////////////////////////////////////////////////////
#include "builderFuncs.h"
#include <geomNode.h>
#include "builderBucketNode.h"
#include "geomNode.h"
#include "qpgeomNode.h"
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::add_prim
// Access: Public
@ -98,3 +100,54 @@ build(GeomNode *geom_node) const {
return count;
}
////////////////////////////////////////////////////////////////////
// Function: BuilderBucketNode::build
// Access: Public
// Description: Builds all the geometry assigned to this particular
// bucket, and assigns it to the indicated GeomNode.
// Returns the number of Geoms created.
////////////////////////////////////////////////////////////////////
int BuilderBucketNode::
build(qpGeomNode *geom_node) const {
int count = 0;
{
// First, the nonindexed.
Prims::const_iterator pi, last_pi;
last_pi = _prims.begin();
for (pi = _prims.begin();
pi != _prims.end();
++pi) {
if ((*last_pi) < (*pi)) {
count += mesh_and_build(last_pi, pi, *_bucket, geom_node,
(BuilderPrim *)0);
last_pi = pi;
}
}
count += mesh_and_build(last_pi, pi, *_bucket, geom_node,
(BuilderPrim *)0);
}
{
// Then, the indexed.
IPrims::const_iterator pi, last_pi;
last_pi = _iprims.begin();
for (pi = _iprims.begin();
pi != _iprims.end();
++pi) {
if ((*last_pi) < (*pi)) {
count += mesh_and_build(last_pi, pi, *_bucket, geom_node,
(BuilderPrimI *)0);
last_pi = pi;
}
}
count += mesh_and_build(last_pi, pi, *_bucket, geom_node,
(BuilderPrimI *)0);
}
return count;
}

View File

@ -27,6 +27,7 @@
#include "pset.h"
class GeomNode;
class qpGeomNode;
///////////////////////////////////////////////////////////////////
@ -57,6 +58,7 @@ public:
INLINE bool operator != (const BuilderBucketNode &other) const;
int build(GeomNode *geom_node) const;
int build(qpGeomNode *geom_node) const;
protected:
typedef pmultiset<BuilderPrim, less<BuilderPrim> > Prims;

View File

@ -23,7 +23,6 @@
#include <geom.h>
#include <geomprimitives.h>
#include <geomNode.h>
#include <algorithm>
@ -485,7 +484,7 @@ expand(const PrimType &prim, BuilderBucket &bucket, OutputIterator result) {
// creates corresponding geometry for them in the
// indicated GeomNode.
////////////////////////////////////////////////////////////////////
template<class InputIterator, class PrimType>
template<class InputIterator, class PrimType, class GeomNode>
static int
build_geoms(InputIterator first, InputIterator last,
BuilderBucket &bucket, GeomNode *geom_node,
@ -796,7 +795,7 @@ public:
// to infer the PrimType (BuilderPrim or BuilderPrimI)
// from the iterator's value type, and template on that.
////////////////////////////////////////////////////////////////////
template<class InputIterator, class PrimType>
template<class InputIterator, class PrimType, class GeomNode>
static int
__mesh_and_build(InputIterator first, InputIterator last,
BuilderBucket &bucket, GeomNode *geom_node,
@ -879,7 +878,7 @@ __mesh_and_build(InputIterator first, InputIterator last,
// runs them through the mesher if specified by the
// bucket, and builds them into the indicated GeomNode.
////////////////////////////////////////////////////////////////////
template<class InputIterator, class value_type>
template<class InputIterator, class value_type, class GeomNode>
int
mesh_and_build(InputIterator first, InputIterator last,
BuilderBucket &bucket, GeomNode *geom_node,

View File

@ -25,7 +25,6 @@
#include <string>
class BuilderBucket;
class GeomNode;
////////////////////////////////////////////////////////////////////
@ -57,7 +56,7 @@ expand(const PrimType &prim, BuilderBucket &bucket,
// runs them through the mesher if specified by the
// bucket, and builds them into the indicated GeomNode.
////////////////////////////////////////////////////////////////////
template<class InputIterator>
template<class InputIterator, class GeomNode>
int
mesh_and_build(InputIterator first, InputIterator last,
BuilderBucket &bucket, GeomNode *geom_node);

View File

@ -18,6 +18,8 @@
#include "builderFuncs.h"
#include "builderNormalVisualizer.h"
#include "geomNode.h"
#include "qpgeomNode.h"
#ifdef SUPPORT_SHOW_NORMALS
@ -61,6 +63,12 @@ show_normals(GeomNode *node) {
mesh_and_build(_lines.begin(), _lines.end(), _bucket, node, (BuilderPrim *)0);
}
void BuilderNormalVisualizer::
show_normals(qpGeomNode *node) {
// Ok, now we've got a bunch of normals saved up; create some geometry.
mesh_and_build(_lines.begin(), _lines.end(), _bucket, node, (BuilderPrim *)0);
}
void BuilderNormalVisualizer::
add_normal(const BuilderV &center, const BuilderN &normal) {
BuilderV to = center + normal * _bucket._normal_scale;

View File

@ -48,6 +48,7 @@ public:
void add_prim(const BuilderPrimI &prim);
void show_normals(GeomNode *node);
void show_normals(qpGeomNode *node);
private:
void add_normal(const BuilderV &center, const BuilderN &normal);

View File

@ -20,6 +20,7 @@
#include "pipeline.h"
#include "drawCullHandler.h"
#include "qpcullTraverser.h"
#include "clockObject.h"
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::Constructor
@ -77,6 +78,10 @@ remove_window(GraphicsWindow *window) {
void GraphicsEngine::
render_frame() {
cull_and_draw_together();
// **** This doesn't belong here; it really belongs in the Pipeline,
// but here it is for now.
ClockObject::get_global_clock()->tick();
}
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,107 @@
// Filename: config_egg2pg.cxx
// Created by: drose (26Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "config_egg2pg.h"
#include "dconfig.h"
#include "get_config_path.h"
ConfigureDef(config_egg2pg);
NotifyCategoryDef(egg2pg, "");
bool egg_mesh = config_egg2pg.GetBool("egg-mesh", true);
bool egg_retesselate_coplanar = config_egg2pg.GetBool("egg-retesselate-coplanar", true);
bool egg_unroll_fans = config_egg2pg.GetBool("egg-unroll-fans", true);
bool egg_show_tstrips = config_egg2pg.GetBool("egg-show-tstrips", false);
bool egg_show_qsheets = config_egg2pg.GetBool("egg-show-qsheets", false);
bool egg_show_quads = config_egg2pg.GetBool("egg-show-quads", false);
bool egg_false_color = (egg_show_tstrips | egg_show_qsheets | egg_show_quads);
bool egg_show_normals = config_egg2pg.GetBool("egg-show-normals", false);
double egg_normal_scale = config_egg2pg.GetDouble("egg-normal-scale", 1.0);
bool egg_subdivide_polys = config_egg2pg.GetBool("egg-subdivide-polys", true);
bool egg_consider_fans = config_egg2pg.GetBool("egg-consider-fans", true);
double egg_max_tfan_angle = config_egg2pg.GetDouble("egg-max-tfan-angle", 40.0);
int egg_min_tfan_tris = config_egg2pg.GetInt("egg-min-tfan-tris", 4);
double egg_coplanar_threshold = config_egg2pg.GetDouble("egg-coplanar-threshold", 0.01);
bool egg_ignore_mipmaps = config_egg2pg.GetBool("egg-ignore-mipmaps", false);
bool egg_ignore_filters = config_egg2pg.GetBool("egg-ignore-filters", false);
bool egg_ignore_clamp = config_egg2pg.GetBool("egg-ignore-clamp", false);
bool egg_always_decal_textures = config_egg2pg.GetBool("egg-always-decal-textures", false);
bool egg_ignore_decals = config_egg2pg.GetBool("egg-ignore-decals", false);
bool egg_flatten = config_egg2pg.GetBool("egg-flatten", true);
// It is almost always a bad idea to set this true.
bool egg_flatten_siblings = config_egg2pg.GetBool("egg-flatten-siblings", false);
bool egg_show_collision_solids = config_egg2pg.GetBool("egg-show-collision-solids", false);
// When this is true, keep texture pathnames exactly the same as they
// appeared in the egg file, in particular leaving them as relative
// paths, rather than letting them reflect the full path at which they
// were found. This is particularly useful when generating bam files.
// However, if the same texture is named by two different relative
// paths, these will still be collapsed into one texture (using one of
// the relative paths, chosen arbitrarily).
bool egg_keep_texture_pathnames = config_egg2pg.GetBool("egg-keep-texture-pathnames", false);
// When this is true, a <NurbsCurve> entry appearing in an egg file
// will load a ClassicNurbsCurve object instead of the default, a
// NurbsCurve object. This only makes a difference when the NURBS++
// library is available, in which case the default, NurbsCurve, is
// actually a NurbsPPCurve object.
bool egg_load_classic_nurbs_curves = config_egg2pg.GetBool("egg-load-classic-nurbs-curves", false);
// When this is true, certain kinds of recoverable errors (not syntax
// errors) in an egg file will be allowed and ignored when an egg file
// is loaded. When it is false, only perfectly pristine egg files may
// be loaded.
bool egg_accept_errors = config_egg2pg.GetBool("egg-accept-errors", true);
CoordinateSystem egg_coordinate_system;
ConfigureFn(config_egg2pg) {
init_libegg2pg();
}
////////////////////////////////////////////////////////////////////
// Function: init_libegg2pg
// Description: Initializes the library. This must be called at
// least once before any of the functions or classes in
// this library can be used. Normally it will be
// called by the static initializers and need not be
// called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libegg2pg() {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
string csstr = config_egg2pg.GetString("egg-coordinate-system", "default");
CoordinateSystem cs = parse_coordinate_system_string(csstr);
if (cs == CS_invalid) {
egg2pg_cat.error()
<< "Unexpected egg-coordinate-system string: " << csstr << "\n";
cs = CS_default;
}
egg_coordinate_system = (cs == CS_default) ?
default_coordinate_system : cs;
}

View File

@ -0,0 +1,60 @@
// Filename: config_egg2pg.h
// Created by: drose (26Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef CONFIG_EGG2PG_H
#define CONFIG_EGG2PG_H
#include "pandabase.h"
#include "coordinateSystem.h"
#include "notifyCategoryProxy.h"
#include "dconfig.h"
ConfigureDecl(config_egg2pg, EXPCL_PANDAEGG, EXPTP_PANDAEGG);
NotifyCategoryDecl(egg2pg, EXPCL_PANDAEGG, EXPTP_PANDAEGG);
extern EXPCL_PANDAEGG bool egg_mesh;
extern EXPCL_PANDAEGG bool egg_retesselate_coplanar;
extern EXPCL_PANDAEGG bool egg_unroll_fans;
extern EXPCL_PANDAEGG bool egg_show_tstrips;
extern EXPCL_PANDAEGG bool egg_show_qsheets;
extern EXPCL_PANDAEGG bool egg_show_quads;
extern EXPCL_PANDAEGG bool egg_false_color;
extern EXPCL_PANDAEGG bool egg_show_normals;
extern EXPCL_PANDAEGG double egg_normal_scale;
extern EXPCL_PANDAEGG bool egg_subdivide_polys;
extern EXPCL_PANDAEGG bool egg_consider_fans;
extern EXPCL_PANDAEGG double egg_max_tfan_angle;
extern EXPCL_PANDAEGG int egg_min_tfan_tris;
extern EXPCL_PANDAEGG double egg_coplanar_threshold;
extern EXPCL_PANDAEGG CoordinateSystem egg_coordinate_system;
extern EXPCL_PANDAEGG bool egg_ignore_mipmaps;
extern EXPCL_PANDAEGG bool egg_ignore_filters;
extern EXPCL_PANDAEGG bool egg_ignore_clamp;
extern EXPCL_PANDAEGG bool egg_always_decal_textures;
extern EXPCL_PANDAEGG bool egg_ignore_decals;
extern EXPCL_PANDAEGG bool egg_flatten;
extern EXPCL_PANDAEGG bool egg_flatten_siblings;
extern EXPCL_PANDAEGG bool egg_show_collision_solids;
extern EXPCL_PANDAEGG bool egg_keep_texture_pathnames;
extern EXPCL_PANDAEGG bool egg_load_classic_nurbs_curves;
extern EXPCL_PANDAEGG bool egg_accept_errors;
extern EXPCL_PANDAEGG void init_libegg2pg();
#endif

View File

@ -0,0 +1,2 @@
#include "config_egg2pg.cxx"
#include "qpeggLoader.cxx"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,159 @@
// Filename: qpeggLoader.h
// Created by: drose (26Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef qpEGGLOADER_H
#define qpEGGLOADER_H
#include "pandabase.h"
#include "eggData.h"
#include "eggTexture.h"
#include "pt_EggTexture.h"
#include "eggGroup.h"
#include "eggMaterial.h"
#include "pt_EggMaterial.h"
#include "texture.h"
#include "pandaNode.h"
#include "pointerTo.h"
#include "builder.h"
#include "lmatrix.h"
#include "indirectCompareTo.h"
#include "textureAttrib.h"
class EggNode;
class EggBin;
class EggTable;
class EggNurbsCurve;
class EggPrimitive;
class EggPolygon;
class EggMaterial;
class ComputedVerticesMaker;
class RenderRelation;
class CollisionSolid;
class CollisionNode;
class CollisionPlane;
class CollisionPolygon;
///////////////////////////////////////////////////////////////////
// Class : qpEggLoader
// Description : Converts an egg data structure, possibly read from an
// egg file but not necessarily, into a scene graph
// suitable for rendering.
//
// This class isn't exported from this package.
////////////////////////////////////////////////////////////////////
class qpEggLoader {
public:
qpEggLoader();
qpEggLoader(const EggData &data);
void build_graph();
void reparent_decals();
void reset_directs();
void make_nonindexed_primitive(EggPrimitive *egg_prim, PandaNode *parent,
const LMatrix4d *transform = NULL);
void make_indexed_primitive(EggPrimitive *egg_prim, PandaNode *parent,
const LMatrix4d *transform,
ComputedVerticesMaker &_comp_verts_maker);
private:
class TextureDef {
public:
CPT(RenderAttrib) _texture;
// PT(TextureApplyTransition) _apply;
};
void load_textures();
bool load_texture(TextureDef &def, const EggTexture *egg_tex);
void apply_texture_attributes(Texture *tex, const EggTexture *egg_tex);
void apply_texture_apply_attributes(TextureApplyTransition *apply,
const EggTexture *egg_tex);
/*
MaterialTransition *get_material_transition(const EggMaterial *egg_mat,
bool bface);
*/
void setup_bucket(BuilderBucket &bucket, PandaNode *parent,
EggPrimitive *egg_prim);
PandaNode *make_node(EggNode *egg_node, PandaNode *parent);
PandaNode *make_node(EggNurbsCurve *egg_curve, PandaNode *parent);
PandaNode *make_node(EggPrimitive *egg_prim, PandaNode *parent);
PandaNode *make_node(EggBin *egg_bin, PandaNode *parent);
PandaNode *make_node(EggGroup *egg_group, PandaNode *parent);
PandaNode *create_group_arc(EggGroup *egg_group, PandaNode *parent,
PandaNode *node);
PandaNode *make_node(EggTable *egg_table, PandaNode *parent);
PandaNode *make_node(EggGroupNode *egg_group, PandaNode *parent);
/*
void make_collision_solids(EggGroup *start_group, EggGroup *egg_group,
CollisionNode *cnode);
void make_collision_plane(EggGroup *egg_group, CollisionNode *cnode,
EggGroup::CollideFlags flags);
void make_collision_polygon(EggGroup *egg_group, CollisionNode *cnode,
EggGroup::CollideFlags flags);
void make_collision_polyset(EggGroup *egg_group, CollisionNode *cnode,
EggGroup::CollideFlags flags);
void make_collision_sphere(EggGroup *egg_group, CollisionNode *cnode,
EggGroup::CollideFlags flags);
void apply_collision_flags(CollisionSolid *solid,
EggGroup::CollideFlags flags);
EggGroup *find_collision_geometry(EggGroup *egg_group);
CollisionPlane *create_collision_plane(EggPolygon *egg_poly,
EggGroup *parent_group);
void create_collision_polygons(CollisionNode *cnode, EggPolygon *egg_poly,
EggGroup *parent_group,
EggGroup::CollideFlags flags);
void apply_deferred_arcs(PandaNode *root);
*/
Builder _builder;
typedef pmap<PT_EggTexture, TextureDef> Textures;
Textures _textures;
/*
typedef pmap<CPT_EggMaterial, PT(MaterialTransition) > Materials;
Materials _materials;
Materials _materials_bface;
*/
/*
typedef pset<PandaNode *> Decals;
Decals _decals;
typedef pset<PandaNode *> Directs;
Directs _directs;
DeferredArcs _deferred_arcs;
*/
public:
PT(PandaNode) _root;
EggData _data;
bool _error;
};
#endif

View File

@ -0,0 +1,112 @@
// Filename: qpload_egg_file.cxx
// Created by: drose (26Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "qpload_egg_file.h"
#include "qpeggLoader.h"
#include "config_egg2pg.h"
/*
#include "sceneGraphReducer.h"
#include "renderRelation.h"
*/
static PT(PandaNode)
load_from_loader(qpEggLoader &loader) {
loader._data.resolve_externals();
loader.build_graph();
if (loader._error && !egg_accept_errors) {
egg2pg_cat.error()
<< "Errors in egg file.\n";
return NULL;
}
/*
if (loader._root != (NamedNode *)NULL && egg_flatten) {
SceneGraphReducer gr(RenderRelation::get_class_type());
int num_reduced = gr.flatten(loader._root, egg_flatten_siblings);
egg2pg_cat.info() << "Flattened " << num_reduced << " arcs.\n";
}
*/
return loader._root;
}
////////////////////////////////////////////////////////////////////
// Function: load_egg_file
// Description: A convenience function. Loads up the indicated egg
// file, and returns the root of a scene graph. Returns
// NULL if the file cannot be read for some reason.
// Does not search along the egg path for the filename
// first; use EggData::resolve_egg_filename() if this is
// required.
////////////////////////////////////////////////////////////////////
PT(PandaNode)
qpload_egg_file(const string &filename, CoordinateSystem cs) {
Filename egg_filename = Filename::text_filename(filename);
if (!egg_filename.exists()) {
egg2pg_cat.error()
<< "Could not find " << egg_filename << "\n";
return NULL;
}
egg2pg_cat.info()
<< "Reading " << egg_filename << "\n";
ifstream file;
if (!egg_filename.open_read(file)) {
egg2pg_cat.error()
<< "Could not open " << egg_filename << " for reading.\n";
return NULL;
}
qpEggLoader loader;
loader._data.set_egg_filename(egg_filename);
if (cs != CS_default) {
loader._data.set_coordinate_system(cs);
}
if (!loader._data.read(file)) {
egg2pg_cat.error()
<< "Error reading " << egg_filename << "\n";
return NULL;
}
return load_from_loader(loader);
}
////////////////////////////////////////////////////////////////////
// Function: load_egg_data
// Description: Another convenience function; works like
// load_egg_file() but starts from an already-filled
// EggData structure. The structure is destroyed in the
// loading.
////////////////////////////////////////////////////////////////////
PT(PandaNode)
qpload_egg_data(EggData &data) {
// We temporarily shuttle the children to a holding node so we can
// copy them into the EggLoader's structure without it complaining.
EggGroupNode children_holder;
children_holder.steal_children(data);
qpEggLoader loader(data);
loader._data.steal_children(children_holder);
return load_from_loader(loader);
}

View File

@ -0,0 +1,52 @@
// Filename: qpload_egg_file.h
// Created by: drose (26Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef qpLOAD_EGG_FILE_H
#define qpLOAD_EGG_FILE_H
#include "pandabase.h"
#include "pandaNode.h"
#include "coordinateSystem.h"
class EggData;
////////////////////////////////////////////////////////////////////
// Function: load_egg_file
// Description: A convenience function; the primary interface to this
// package. Loads up the indicated egg file, and
// returns the root of a scene graph. Returns NULL if
// the file cannot be read for some reason.
//
// Also see the EggLoader class, which can exercise a
// bit more manual control over the loading process.
////////////////////////////////////////////////////////////////////
EXPCL_PANDAEGG PT(PandaNode)
qpload_egg_file(const string &filename, CoordinateSystem cs = CS_default);
////////////////////////////////////////////////////////////////////
// Function: load_egg_data
// Description: Another convenience function; works like
// load_egg_file() but starts from an already-filled
// EggData structure. The structure is destroyed in the
// loading.
////////////////////////////////////////////////////////////////////
EXPCL_PANDAEGG PT(PandaNode)
qpload_egg_data(EggData &data);
#endif

View File

@ -6,7 +6,7 @@
#begin lib_target
#define TARGET egg2sg
#define LOCAL_LIBS \
parametrics cull collide egg builder loader chan char switchnode
parametrics cull collide egg2pg egg builder loader chan char switchnode
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx

View File

@ -26,56 +26,6 @@
ConfigureDef(config_egg2sg);
NotifyCategoryDef(egg2sg, "");
bool egg_mesh = config_egg2sg.GetBool("egg-mesh", true);
bool egg_retesselate_coplanar = config_egg2sg.GetBool("egg-retesselate-coplanar", true);
bool egg_unroll_fans = config_egg2sg.GetBool("egg-unroll-fans", true);
bool egg_show_tstrips = config_egg2sg.GetBool("egg-show-tstrips", false);
bool egg_show_qsheets = config_egg2sg.GetBool("egg-show-qsheets", false);
bool egg_show_quads = config_egg2sg.GetBool("egg-show-quads", false);
bool egg_false_color = (egg_show_tstrips | egg_show_qsheets | egg_show_quads);
bool egg_show_normals = config_egg2sg.GetBool("egg-show-normals", false);
double egg_normal_scale = config_egg2sg.GetDouble("egg-normal-scale", 1.0);
bool egg_subdivide_polys = config_egg2sg.GetBool("egg-subdivide-polys", true);
bool egg_consider_fans = config_egg2sg.GetBool("egg-consider-fans", true);
double egg_max_tfan_angle = config_egg2sg.GetDouble("egg-max-tfan-angle", 40.0);
int egg_min_tfan_tris = config_egg2sg.GetInt("egg-min-tfan-tris", 4);
double egg_coplanar_threshold = config_egg2sg.GetDouble("egg-coplanar-threshold", 0.01);
bool egg_ignore_mipmaps = config_egg2sg.GetBool("egg-ignore-mipmaps", false);
bool egg_ignore_filters = config_egg2sg.GetBool("egg-ignore-filters", false);
bool egg_ignore_clamp = config_egg2sg.GetBool("egg-ignore-clamp", false);
bool egg_always_decal_textures = config_egg2sg.GetBool("egg-always-decal-textures", false);
bool egg_ignore_decals = config_egg2sg.GetBool("egg-ignore-decals", false);
bool egg_flatten = config_egg2sg.GetBool("egg-flatten", true);
// It is almost always a bad idea to set this true.
bool egg_flatten_siblings = config_egg2sg.GetBool("egg-flatten-siblings", false);
bool egg_show_collision_solids = config_egg2sg.GetBool("egg-show-collision-solids", false);
// When this is true, keep texture pathnames exactly the same as they
// appeared in the egg file, in particular leaving them as relative
// paths, rather than letting them reflect the full path at which they
// were found. This is particularly useful when generating bam files.
// However, if the same texture is named by two different relative
// paths, these will still be collapsed into one texture (using one of
// the relative paths, chosen arbitrarily).
bool egg_keep_texture_pathnames = config_egg2sg.GetBool("egg-keep-texture-pathnames", false);
// When this is true, a <NurbsCurve> entry appearing in an egg file
// will load a ClassicNurbsCurve object instead of the default, a
// NurbsCurve object. This only makes a difference when the NURBS++
// library is available, in which case the default, NurbsCurve, is
// actually a NurbsPPCurve object.
bool egg_load_classic_nurbs_curves = config_egg2sg.GetBool("egg-load-classic-nurbs-curves", false);
// When this is true, certain kinds of recoverable errors (not syntax
// errors) in an egg file will be allowed and ignored when an egg file
// is loaded. When it is false, only perfectly pristine egg files may
// be loaded.
bool egg_accept_errors = config_egg2sg.GetBool("egg-accept-errors", true);
CoordinateSystem egg_coordinate_system;
ConfigureFn(config_egg2sg) {
init_libegg2sg();
}
@ -98,17 +48,6 @@ init_libegg2sg() {
LoaderFileTypeEgg::init_type();
string csstr = config_egg2sg.GetString("egg-coordinate-system", "default");
CoordinateSystem cs = parse_coordinate_system_string(csstr);
if (cs == CS_invalid) {
egg2sg_cat.error()
<< "Unexpected egg-coordinate-system string: " << csstr << "\n";
cs = CS_default;
}
egg_coordinate_system = (cs == CS_default) ?
default_coordinate_system : cs;
LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_ptr();
reg->register_type(new LoaderFileTypeEgg);

View File

@ -26,36 +26,11 @@
#include <notifyCategoryProxy.h>
#include <dconfig.h>
#include "config_egg2pg.h" // temp to declare the global consts
ConfigureDecl(config_egg2sg, EXPCL_PANDAEGG, EXPTP_PANDAEGG);
NotifyCategoryDecl(egg2sg, EXPCL_PANDAEGG, EXPTP_PANDAEGG);
extern EXPCL_PANDAEGG bool egg_mesh;
extern EXPCL_PANDAEGG bool egg_retesselate_coplanar;
extern EXPCL_PANDAEGG bool egg_unroll_fans;
extern EXPCL_PANDAEGG bool egg_show_tstrips;
extern EXPCL_PANDAEGG bool egg_show_qsheets;
extern EXPCL_PANDAEGG bool egg_show_quads;
extern EXPCL_PANDAEGG bool egg_false_color;
extern EXPCL_PANDAEGG bool egg_show_normals;
extern EXPCL_PANDAEGG double egg_normal_scale;
extern EXPCL_PANDAEGG bool egg_subdivide_polys;
extern EXPCL_PANDAEGG bool egg_consider_fans;
extern EXPCL_PANDAEGG double egg_max_tfan_angle;
extern EXPCL_PANDAEGG int egg_min_tfan_tris;
extern EXPCL_PANDAEGG double egg_coplanar_threshold;
extern EXPCL_PANDAEGG CoordinateSystem egg_coordinate_system;
extern EXPCL_PANDAEGG bool egg_ignore_mipmaps;
extern EXPCL_PANDAEGG bool egg_ignore_filters;
extern EXPCL_PANDAEGG bool egg_ignore_clamp;
extern EXPCL_PANDAEGG bool egg_always_decal_textures;
extern EXPCL_PANDAEGG bool egg_ignore_decals;
extern EXPCL_PANDAEGG bool egg_flatten;
extern EXPCL_PANDAEGG bool egg_flatten_siblings;
extern EXPCL_PANDAEGG bool egg_show_collision_solids;
extern EXPCL_PANDAEGG bool egg_keep_texture_pathnames;
extern EXPCL_PANDAEGG bool egg_load_classic_nurbs_curves;
extern EXPCL_PANDAEGG bool egg_accept_errors;
extern EXPCL_PANDAEGG void init_libegg2sg();
#endif

View File

@ -369,6 +369,28 @@ clear_transform() {
cdata->_transform = TransformState::make_identity();
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::ls
// Access: Published
// Description: Lists all the nodes at and below the current path
// hierarchically.
////////////////////////////////////////////////////////////////////
INLINE void PandaNode::
ls() const {
ls(nout);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::ls
// Access: Published
// Description: Lists all the nodes at and below the current path
// hierarchically.
////////////////////////////////////////////////////////////////////
INLINE void PandaNode::
ls(ostream &out, int indent_level) const {
r_list_descendants(out, indent_level);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_children
// Access: Public

View File

@ -349,7 +349,7 @@ write(ostream &out, int indent_level) const {
out << " T";
}
if (!cdata->_state->is_empty()) {
out << " (" << *cdata->_state << ")";
out << " " << *cdata->_state;
}
out << "\n";
}
@ -650,6 +650,30 @@ fix_chain_lengths() {
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::r_list_descendants
// Access: Private
// Description: The recursive implementation of ls().
////////////////////////////////////////////////////////////////////
void PandaNode::
r_list_descendants(ostream &out, int indent_level) const {
write(out, indent_level);
CDReader cdata(_cycler);
Down::const_iterator di;
for (di = cdata->_down.begin(); di != cdata->_down.end(); ++di) {
(*di).get_child()->r_list_descendants(out, indent_level + 2);
}
// Also report the number of stashed nodes at this level.
/*
int num_stashed = get_num_stashed();
if (num_stashed != 0) {
indent(out, indent_level) << "(" << num_stashed << " stashed)\n";
}
*/
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::register_with_read_factory
// Access: Public, Static

View File

@ -35,6 +35,7 @@
#include "luse.h"
#include "ordered_vector.h"
#include "pointerTo.h"
#include "notify.h"
class NodeChainComponent;
@ -90,6 +91,9 @@ PUBLISHED:
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level) const;
INLINE void ls() const;
INLINE void ls(ostream &out, int indent_level = 0) const;
public:
virtual bool is_geom_node() const;
@ -107,6 +111,7 @@ private:
PT(NodeChainComponent) get_generic_component();
void delete_component(NodeChainComponent *component);
void fix_chain_lengths();
void r_list_descendants(ostream &out, int indent_level) const;
private:
class EXPCL_PANDA DownConnection {

View File

@ -79,7 +79,7 @@ get_geom_state(int n) const {
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::set_state
// Function: qpGeomNode::set_geom_state
// Access: Public
// Description: Changes the RenderState associated with the nth geom
// of the node. This is just the RenderState directly
@ -89,7 +89,7 @@ get_geom_state(int n) const {
// above this GeomNode.
////////////////////////////////////////////////////////////////////
INLINE void qpGeomNode::
set_state(int n, const RenderState *state) {
set_geom_state(int n, const RenderState *state) {
CDWriter cdata(_cycler);
nassertv(n >= 0 && n < (int)cdata->_geoms.size());
cdata->_geoms[n]._state = state;

View File

@ -96,6 +96,24 @@ qpGeomNode::
~qpGeomNode() {
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::write_geoms
// Access: Published
// Description: Writes a short description of all the Geoms in the
// node.
////////////////////////////////////////////////////////////////////
void qpGeomNode::
write_geoms(ostream &out, int indent_level) const {
CDReader cdata(_cycler);
write(out, indent_level);
Geoms::const_iterator gi;
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
const GeomEntry &entry = (*gi);
indent(out, indent_level + 2)
<< *entry._geom << " (" << *entry._state << ")\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::write_verbose
// Access: Published
@ -105,7 +123,7 @@ qpGeomNode::
void qpGeomNode::
write_verbose(ostream &out, int indent_level) const {
CDReader cdata(_cycler);
PandaNode::write(out, indent_level);
write(out, indent_level);
Geoms::const_iterator gi;
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
const GeomEntry &entry = (*gi);
@ -126,23 +144,6 @@ output(ostream &out) const {
out << " (" << get_num_geoms() << " geoms)";
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::write
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void qpGeomNode::
write(ostream &out, int indent_level) const {
CDReader cdata(_cycler);
PandaNode::write(out, indent_level);
Geoms::const_iterator gi;
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
const GeomEntry &entry = (*gi);
indent(out, indent_level + 2)
<< *entry._geom << " (" << *entry._state << ")\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomNode::is_geom_node
// Access: Public, Virtual

View File

@ -48,17 +48,17 @@ PUBLISHED:
INLINE int get_num_geoms() const;
INLINE Geom *get_geom(int n) const;
INLINE const RenderState *get_geom_state(int n) const;
INLINE void set_state(int n, const RenderState *state);
INLINE void set_geom_state(int n, const RenderState *state);
INLINE int add_geom(Geom *geom, const RenderState *state);
INLINE int add_geom(Geom *geom, const RenderState *state = RenderState::make_empty());
INLINE void remove_geom(int n);
INLINE void remove_all_geoms();
void write_geoms(ostream &out, int indent_level) const;
void write_verbose(ostream &out, int indent_level) const;
public:
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level) const;
virtual bool is_geom_node() const;

View File

@ -423,6 +423,14 @@ add(const RenderAttrib *attrib, int override) const {
*result = new_attribute;
++result;
if (ai != _attributes.end() && !(new_attribute < (*ai))) {
// At this point we know:
// !((*ai) < new_attribute) && !(new_attribute < (*ai))
// which means (*ai) == new_attribute--so we should leave it out,
// to avoid duplicating attributes in the set.
++ai;
}
while (ai != _attributes.end()) {
*result = *ai;
++ai;

View File

@ -32,7 +32,7 @@
#define SOURCES \
pview.cxx
#define LOCAL_LIBS pgraph $[LOCAL_LIBS]
#define LOCAL_LIBS egg2pg pgraph $[LOCAL_LIBS]
#end test_bin_target
#begin test_bin_target

View File

@ -33,6 +33,10 @@
#include "texture.h"
#include "texturePool.h"
// To load egg files directly.
#include "qpload_egg_file.h"
#include "eggData.h"
// These are in support of legacy data graph operations.
#include "namedNode.h"
#include "mouse.h"
@ -59,6 +63,28 @@ static const int win_height = config_pview.GetInt("win-height", 480);
// As long as this is true, the main loop will continue running.
bool run_flag = true;
// These are used by report_frame_rate().
static double start_time = 0.0;
static int start_frame_count = 0;
void
report_frame_rate() {
double now = ClockObject::get_global_clock()->get_frame_time();
double delta = now - start_time;
int frame_count = ClockObject::get_global_clock()->get_frame_count();
int num_frames = frame_count - start_frame_count;
if (num_frames > 0) {
nout << endl << num_frames << " frames in " << delta << " seconds" << endl;
double x = ((double)num_frames) / delta;
nout << x << " fps average (" << 1000.0 / x << "ms)" << endl;
// Reset the frame rate counter for the next press of 'f'.
start_time = now;
start_frame_count = frame_count;
}
}
PT(GraphicsPipe)
make_pipe() {
// We use the GraphicsPipe factory to make us a renderable pipe
@ -166,22 +192,28 @@ make_default_geometry(PandaNode *parent) {
void
get_models(PandaNode *parent, int argc, char *argv[]) {
make_default_geometry(parent);
/*
Loader loader;
if (argc < 2) {
// In the absence of any models on the command line, load up a
// default triangle so we at least have something to look at.
make_default_geometry(parent);
for (int i = 1; i < argc; i++) {
Filename filename = argv[i];
} else {
cerr << "Loading " << filename << "\n";
PT_Node node = loader.load_sync(filename);
if (node == (Node *)NULL) {
cerr << "Unable to load " << filename << "\n";
} else {
new RenderRelation(parent, node);
for (int i = 1; i < argc; i++) {
Filename filename = argv[i];
cerr << "Loading " << filename << "\n";
EggData::resolve_egg_filename(filename);
PT(PandaNode) node = qpload_egg_file(filename);
if (node == (PandaNode *)NULL) {
cerr << "Unable to load " << filename << "\n";
} else {
node->ls();
parent->add_child(node);
}
}
}
*/
}
NamedNode *
@ -218,6 +250,11 @@ event_esc(CPT_Event) {
run_flag = false;
}
void
event_f(CPT_Event) {
report_frame_rate();
}
int
main(int argc, char *argv[]) {
// First, we need a GraphicsPipe, before we can open a window.
@ -245,11 +282,18 @@ main(int argc, char *argv[]) {
EventHandler event_handler(EventQueue::get_global_event_queue());
event_handler.add_hook("escape", event_esc);
event_handler.add_hook("q", event_esc);
event_handler.add_hook("f", event_f);
// Put something in the scene graph to look at.
get_models(render, argc, argv);
// Tick the clock once so we won't count the time spent loading up
// files, above, in our frame rate average.
ClockObject::get_global_clock()->tick();
start_time = ClockObject::get_global_clock()->get_frame_time();
start_frame_count = ClockObject::get_global_clock()->get_frame_count();
// This is our main update loop. Loop here until someone
// (e.g. event_esc) sets run_flag to false.
@ -261,6 +305,7 @@ main(int argc, char *argv[]) {
engine->render_frame();
}
report_frame_rate();
delete engine;
return (0);
}