mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
preliminary egg support for new geoms
This commit is contained in:
parent
96ffce27d2
commit
e20f73799c
@ -2593,7 +2593,10 @@ bool DXGraphicsStateGuardian8::
|
||||
begin_draw_primitives(const qpGeomVertexData *vertex_data) {
|
||||
DO_PSTATS_STUFF(_draw_primitive_pcollector.start());
|
||||
|
||||
GraphicsStateGuardian::begin_draw_primitives(vertex_data);
|
||||
if (!GraphicsStateGuardian::begin_draw_primitives(vertex_data)) {
|
||||
return false;
|
||||
}
|
||||
nassertr(_vertex_data != (qpGeomVertexData *)NULL, false);
|
||||
|
||||
const qpGeomVertexFormat *format = _vertex_data->get_format();
|
||||
|
||||
|
@ -92,6 +92,17 @@ make_bins(EggGroupNode *root_group) {
|
||||
return num_bins;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggBinMaker::prepare_node
|
||||
// Access: Public, Virtual
|
||||
// Description: May be overridden in derived classes to perform some
|
||||
// setup work as each node is encountered. This will be
|
||||
// called once for each node in the egg hierarchy.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggBinMaker::
|
||||
prepare_node(EggNode *) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggBinMaker::sorts_less
|
||||
// Access: Public, Virtual
|
||||
@ -153,6 +164,8 @@ collect_nodes(EggGroupNode *group) {
|
||||
EggNode *node = (*i);
|
||||
++next;
|
||||
|
||||
prepare_node(node);
|
||||
|
||||
if (get_bin_number(node) != 0) {
|
||||
// Ok, here's a node to be binned. Add it to the appropriate
|
||||
// bin.
|
||||
|
@ -96,6 +96,14 @@
|
||||
//
|
||||
// You may also redefine any or all of the following functions:
|
||||
//
|
||||
// virtual void prepare_node(EggNode *node);
|
||||
//
|
||||
// This method is called, once, on each node in the egg hierarchy
|
||||
// as it is visited the first time. It allows the subclass a
|
||||
// chance to analyze the node or do any other initial processing.
|
||||
// This is a fine opportunity to tag an EggUserData onto the node,
|
||||
// for instance.
|
||||
//
|
||||
// virtual bool sorts_less(int bin_number, const EggNode *a, const EggNode *b);
|
||||
//
|
||||
// Sometimes a simple bin number alone is not enough. For
|
||||
@ -254,6 +262,9 @@ PUBLISHED:
|
||||
|
||||
int make_bins(EggGroupNode *root_group);
|
||||
|
||||
virtual void
|
||||
prepare_node(EggNode *node);
|
||||
|
||||
virtual int
|
||||
get_bin_number(const EggNode *node)=0;
|
||||
|
||||
|
@ -61,9 +61,14 @@ operator = (const EggGroup ©) {
|
||||
EggTransform3d::operator = (copy);
|
||||
_flags = copy._flags;
|
||||
_flags2 = copy._flags2;
|
||||
_collide_mask = copy._collide_mask;
|
||||
_from_collide_mask = copy._from_collide_mask;
|
||||
_into_collide_mask = copy._into_collide_mask;
|
||||
_billboard_center = copy._billboard_center;
|
||||
_object_types = copy._object_types;
|
||||
_collision_name = copy._collision_name;
|
||||
_fps = copy._fps;
|
||||
_lod = copy._lod;
|
||||
|
||||
_tag_data = copy._tag_data;
|
||||
|
||||
|
@ -35,7 +35,8 @@ EggObject() {
|
||||
INLINE EggObject::
|
||||
EggObject(const EggObject ©) :
|
||||
TypedReferenceCount(copy),
|
||||
_user_data(copy._user_data)
|
||||
_user_data(copy._user_data),
|
||||
_default_user_data(copy._default_user_data)
|
||||
{
|
||||
}
|
||||
|
||||
@ -49,6 +50,7 @@ INLINE EggObject &EggObject::
|
||||
operator = (const EggObject ©) {
|
||||
TypedReferenceCount::operator = (copy);
|
||||
_user_data = copy._user_data;
|
||||
_default_user_data = copy._default_user_data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -61,54 +63,102 @@ operator = (const EggObject ©) {
|
||||
// hold its reference count and return the pointer on
|
||||
// request.
|
||||
//
|
||||
// The EggObject maintains multiple different
|
||||
// EggUserData pointers, one for each unique type (as
|
||||
// reported by get_type()). If you know that only one
|
||||
// type of EggUserData object will be added in your
|
||||
// application, you may use the query functions that
|
||||
// accept no parameters, but it is recommended that in
|
||||
// general you pass in the type of your particular user
|
||||
// data, to allow multiple applications to coexist in
|
||||
// the same egg data.
|
||||
//
|
||||
// This pointer is also copied by the copy assignment
|
||||
// operator and copy constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggObject::
|
||||
set_user_data(EggUserData *user_data) {
|
||||
_user_data = user_data;
|
||||
_user_data[user_data->get_type()] = user_data;
|
||||
_default_user_data = user_data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggObject::get_user_data
|
||||
// Access: Public
|
||||
// Description: Returns the user data pointer previously stored on
|
||||
// Description: Returns the user data pointer most recently stored on
|
||||
// this object, or NULL if nothing was previously
|
||||
// stored.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE EggUserData *EggObject::
|
||||
get_user_data() const {
|
||||
return _user_data;
|
||||
return _default_user_data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggObject::get_user_data
|
||||
// Access: Public
|
||||
// Description: Returns the user data pointer of the indicated type,
|
||||
// if it exists, or NULL if it does not.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE EggUserData *EggObject::
|
||||
get_user_data(TypeHandle type) const {
|
||||
UserData::const_iterator ui;
|
||||
ui = _user_data.find(type);
|
||||
if (ui != _user_data.end()) {
|
||||
return (*ui).second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggObject::has_user_data
|
||||
// Access: Public
|
||||
// Description: Returns true if the user data pointer has been set,
|
||||
// false otherwise.
|
||||
// Description: Returns true if a generic user data pointer has
|
||||
// recently been set and not yet cleared, false
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool EggObject::
|
||||
has_user_data() const {
|
||||
return !_user_data.is_null();
|
||||
return !_default_user_data.is_null();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggObject::has_user_data
|
||||
// Access: Public
|
||||
// Description: Returns true if the user data pointer has been set
|
||||
// and is of the indicated type, false otherwise.
|
||||
// Description: Returns true if the user data pointer of the
|
||||
// indicated type has been set, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool EggObject::
|
||||
has_user_data(TypeHandle type) const {
|
||||
return !_user_data.is_null() && _user_data->is_of_type(type);
|
||||
UserData::const_iterator ui;
|
||||
ui = _user_data.find(type);
|
||||
return (ui != _user_data.end());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggObject::clear_user_data
|
||||
// Access: Public
|
||||
// Description: Resets the user data pointer to NULL.
|
||||
// Description: Removes *all* user data pointers from the node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggObject::
|
||||
clear_user_data() {
|
||||
_user_data.clear();
|
||||
_default_user_data.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggObject::clear_user_data
|
||||
// Access: Public
|
||||
// Description: Removes the user data pointer of the indicated type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggObject::
|
||||
clear_user_data(TypeHandle type) {
|
||||
UserData::iterator ui;
|
||||
ui = _user_data.find(type);
|
||||
if (ui != _user_data.end()) {
|
||||
if ((*ui).second == _default_user_data) {
|
||||
_default_user_data.clear();
|
||||
}
|
||||
_user_data.erase(ui);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "eggUserData.h"
|
||||
#include "typedReferenceCount.h"
|
||||
#include "pointerTo.h"
|
||||
#include "pmap.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : EggObject
|
||||
@ -39,12 +40,16 @@ PUBLISHED:
|
||||
|
||||
INLINE void set_user_data(EggUserData *user_data);
|
||||
INLINE EggUserData *get_user_data() const;
|
||||
INLINE EggUserData *get_user_data(TypeHandle type) const;
|
||||
INLINE bool has_user_data() const;
|
||||
INLINE bool has_user_data(TypeHandle type) const;
|
||||
INLINE void clear_user_data();
|
||||
INLINE void clear_user_data(TypeHandle type);
|
||||
|
||||
private:
|
||||
PT(EggUserData) _user_data;
|
||||
typedef pmap<TypeHandle, PT(EggUserData) > UserData;
|
||||
UserData _user_data;
|
||||
PT(EggUserData) _default_user_data;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
|
@ -178,6 +178,108 @@ get_highest_index() const {
|
||||
return _highest_index;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggVertexPool::get_num_dimensions
|
||||
// Access: Public
|
||||
// Description: Returns the maximum number of dimensions used by any
|
||||
// vertex in the pool.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int EggVertexPool::
|
||||
get_num_dimensions() const {
|
||||
int num_dimensions = 0;
|
||||
|
||||
IndexVertices::const_iterator ivi;
|
||||
for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
|
||||
EggVertex *vertex = (*ivi).second;
|
||||
num_dimensions = max(num_dimensions, vertex->get_num_dimensions());
|
||||
}
|
||||
|
||||
return num_dimensions;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggVertexPool::has_normals
|
||||
// Access: Public
|
||||
// Description: Returns true if any vertex in the pool has a normal
|
||||
// defined, false if none of them do.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggVertexPool::
|
||||
has_normals() const {
|
||||
IndexVertices::const_iterator ivi;
|
||||
for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
|
||||
EggVertex *vertex = (*ivi).second;
|
||||
if (vertex->has_normal()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggVertexPool::has_colors
|
||||
// Access: Public
|
||||
// Description: Returns true if any vertex in the pool has a color
|
||||
// defined, false if none of them do.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggVertexPool::
|
||||
has_colors() const {
|
||||
IndexVertices::const_iterator ivi;
|
||||
for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
|
||||
EggVertex *vertex = (*ivi).second;
|
||||
if (vertex->has_color()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggVertexPool::has_uvs
|
||||
// Access: Public
|
||||
// Description: Returns true if any vertex in the pool has a uv
|
||||
// defined, false if none of them do.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggVertexPool::
|
||||
has_uvs() const {
|
||||
IndexVertices::const_iterator ivi;
|
||||
for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
|
||||
EggVertex *vertex = (*ivi).second;
|
||||
if (vertex->has_uv()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggVertexPool::get_uv_names
|
||||
// Access: Public
|
||||
// Description: Returns the list of UV names that are defined by any
|
||||
// vertices in the pool. It is the user's
|
||||
// responsibility to clear the vector before calling
|
||||
// this method.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggVertexPool::
|
||||
get_uv_names(vector_string &uv_names) const {
|
||||
pset<string> names;
|
||||
IndexVertices::const_iterator ivi;
|
||||
for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
|
||||
EggVertex *vertex = (*ivi).second;
|
||||
EggVertex::const_uv_iterator uvi;
|
||||
for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
|
||||
names.insert((*uvi)->get_name());
|
||||
}
|
||||
}
|
||||
|
||||
pset<string>::const_iterator si;
|
||||
for (si = names.begin(); si != names.end(); ++si) {
|
||||
uv_names.push_back(*si);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggVertexPool::begin()
|
||||
// Access: Public
|
||||
|
@ -92,6 +92,12 @@ PUBLISHED:
|
||||
// Returns 0 if the pool is empty.
|
||||
int get_highest_index() const;
|
||||
|
||||
int get_num_dimensions() const;
|
||||
bool has_normals() const;
|
||||
bool has_colors() const;
|
||||
bool has_uvs() const;
|
||||
void get_uv_names(vector_string &uv_names) const;
|
||||
|
||||
public:
|
||||
// Can be used to traverse all the vertices in index number order.
|
||||
iterator begin() const;
|
||||
|
@ -18,7 +18,8 @@
|
||||
config_egg2pg.h \
|
||||
deferredNodeProperty.h \
|
||||
eggBinner.h \
|
||||
eggLoader.h \
|
||||
eggLoader.h eggLoader.I \
|
||||
eggRenderState.h eggRenderState.I \
|
||||
egg_parametrics.h \
|
||||
load_egg_file.h \
|
||||
loaderFileTypeEgg.h
|
||||
@ -31,6 +32,7 @@
|
||||
deferredNodeProperty.cxx \
|
||||
eggBinner.cxx \
|
||||
eggLoader.cxx \
|
||||
eggRenderState.cxx \
|
||||
egg_parametrics.cxx \
|
||||
load_egg_file.cxx \
|
||||
loaderFileTypeEgg.cxx
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "loaderFileTypeRegistry.h"
|
||||
#include "configVariableManager.h"
|
||||
#include "configVariableCore.h"
|
||||
#include "eggRenderState.h"
|
||||
|
||||
ConfigureDef(config_egg2pg);
|
||||
NotifyCategoryDef(egg2pg, "");
|
||||
@ -153,6 +154,7 @@ init_libegg2pg() {
|
||||
"Defines egg syntax for the named object type.",
|
||||
ConfigVariableCore::F_dynamic);
|
||||
|
||||
EggRenderState::init_type();
|
||||
LoaderFileTypeEgg::init_type();
|
||||
|
||||
LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr();
|
||||
|
@ -3,3 +3,4 @@
|
||||
#include "computedVerticesMaker.cxx"
|
||||
#include "config_egg2pg.cxx"
|
||||
#include "egg_parametrics.cxx"
|
||||
#include "eggRenderState.cxx"
|
||||
|
@ -17,11 +17,40 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "eggBinner.h"
|
||||
|
||||
#include "eggRenderState.h"
|
||||
#include "eggPrimitive.h"
|
||||
#include "eggSwitchCondition.h"
|
||||
#include "eggGroup.h"
|
||||
#include "dcast.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggBinner::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
EggBinner::
|
||||
EggBinner(EggLoader &loader) :
|
||||
_loader(loader)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggBinner::prepare_node
|
||||
// Access: Public, Virtual
|
||||
// Description: May be overridden in derived classes to perform some
|
||||
// setup work as each node is encountered. This will be
|
||||
// called once for each node in the egg hierarchy.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggBinner::
|
||||
prepare_node(EggNode *node) {
|
||||
if (node->is_of_type(EggPrimitive::get_class_type())) {
|
||||
EggPrimitive *egg_prim = DCAST(EggPrimitive, node);
|
||||
PT(EggRenderState) render_state = new EggRenderState(_loader);
|
||||
render_state->fill_state(egg_prim);
|
||||
egg_prim->set_user_data(render_state);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggBinner::get_bin_number
|
||||
// Access: Public, Virtual
|
||||
@ -29,7 +58,10 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int EggBinner::
|
||||
get_bin_number(const EggNode *node) {
|
||||
if (node->is_of_type(EggGroup::get_class_type())) {
|
||||
if (node->is_of_type(EggPrimitive::get_class_type())) {
|
||||
return (int)BN_polyset;
|
||||
|
||||
} else if (node->is_of_type(EggGroup::get_class_type())) {
|
||||
const EggGroup *group = DCAST(EggGroup, node);
|
||||
if (group->has_lod()) {
|
||||
return (int)BN_lod;
|
||||
@ -47,36 +79,47 @@ get_bin_number(const EggNode *node) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggBinner::
|
||||
sorts_less(int bin_number, const EggNode *a, const EggNode *b) {
|
||||
assert((BinNumber)bin_number == BN_lod);
|
||||
switch (bin_number) {
|
||||
case BN_polyset:
|
||||
{
|
||||
const EggPrimitive *pa, *pb;
|
||||
DCAST_INTO_R(pa, a, false);
|
||||
DCAST_INTO_R(pb, b, false);
|
||||
|
||||
const EggGroup *ga = DCAST(EggGroup, a);
|
||||
const EggGroup *gb = DCAST(EggGroup, b);
|
||||
// Different vertex pools have to be binned separately.
|
||||
if (pa->get_pool() != pb->get_pool()) {
|
||||
return pa->get_pool() < pb->get_pool();
|
||||
}
|
||||
|
||||
// Otherwise, different render states are binned separately.
|
||||
const EggRenderState *rsa, *rsb;
|
||||
DCAST_INTO_R(rsa, a->get_user_data(EggRenderState::get_class_type()), false);
|
||||
DCAST_INTO_R(rsb, b->get_user_data(EggRenderState::get_class_type()), false);
|
||||
return (*rsa) < (*rsb);
|
||||
}
|
||||
|
||||
const EggSwitchCondition &swa = ga->get_lod();
|
||||
const EggSwitchCondition &swb = gb->get_lod();
|
||||
|
||||
// For now, this is the only kind of switch condition there is.
|
||||
const EggSwitchConditionDistance &swda =
|
||||
*DCAST(EggSwitchConditionDistance, &swa);
|
||||
const EggSwitchConditionDistance &swdb =
|
||||
*DCAST(EggSwitchConditionDistance, &swb);
|
||||
|
||||
// Group LOD nodes in order by switching center.
|
||||
return (swda._center.compare_to(swdb._center) < 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggBinner::collapse_group
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool EggBinner::
|
||||
collapse_group(const EggGroup *group, int) {
|
||||
if (group->get_dart_type() != EggGroup::DT_none) {
|
||||
// A group with the <Dart> flag set means to create a character.
|
||||
// We can't turn the top character node into an LOD.
|
||||
return false;
|
||||
case BN_lod:
|
||||
{
|
||||
const EggGroup *ga = DCAST(EggGroup, a);
|
||||
const EggGroup *gb = DCAST(EggGroup, b);
|
||||
|
||||
const EggSwitchCondition &swa = ga->get_lod();
|
||||
const EggSwitchCondition &swb = gb->get_lod();
|
||||
|
||||
// For now, this is the only kind of switch condition there is.
|
||||
const EggSwitchConditionDistance &swda =
|
||||
*DCAST(EggSwitchConditionDistance, &swa);
|
||||
const EggSwitchConditionDistance &swdb =
|
||||
*DCAST(EggSwitchConditionDistance, &swb);
|
||||
|
||||
// Group LOD nodes in order by switching center.
|
||||
return (swda._center.compare_to(swdb._center) < 0);
|
||||
}
|
||||
|
||||
case BN_none:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Shouldn't get here.
|
||||
return false;
|
||||
}
|
||||
|
@ -23,33 +23,40 @@
|
||||
|
||||
#include "eggBinMaker.h"
|
||||
|
||||
class EggLoader;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Class : EggBinner
|
||||
// Description : A special binner used only within this package to
|
||||
// pre-process the egg tree for the loader and group
|
||||
// things together as appropriate.
|
||||
//
|
||||
// Presently, it only groups related LOD children
|
||||
// It is used to collect similar polygons together for a
|
||||
// Geom, as well as to group related LOD children
|
||||
// together under a single LOD node.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EggBinner : public EggBinMaker {
|
||||
public:
|
||||
|
||||
// The BinNumber serves to identify why a particular EggBin was
|
||||
// created.
|
||||
enum BinNumber {
|
||||
BN_none = 0,
|
||||
BN_polyset,
|
||||
BN_lod,
|
||||
};
|
||||
|
||||
EggBinner(EggLoader &loader);
|
||||
|
||||
virtual void
|
||||
prepare_node(EggNode *node);
|
||||
|
||||
virtual int
|
||||
get_bin_number(const EggNode *node);
|
||||
|
||||
virtual bool
|
||||
sorts_less(int bin_number, const EggNode *a, const EggNode *b);
|
||||
|
||||
virtual bool
|
||||
collapse_group(const EggGroup *group, int bin_number);
|
||||
EggLoader &_loader;
|
||||
};
|
||||
|
||||
|
||||
|
31
panda/src/egg2pg/eggLoader.I
Normal file
31
panda/src/egg2pg/eggLoader.I
Normal file
@ -0,0 +1,31 @@
|
||||
// Filename: eggLoader.I
|
||||
// Created by: drose (13Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::VertexPoolTransform::operator <
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool EggLoader::VertexPoolTransform::
|
||||
operator < (const EggLoader::VertexPoolTransform &other) const {
|
||||
if (_vertex_pool != other._vertex_pool) {
|
||||
return _vertex_pool < other._vertex_pool;
|
||||
}
|
||||
return _transform.compare_to(other._transform, 0.001) < 0;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Filename: EggLoader.cxx
|
||||
// Filename: eggLoader.cxx
|
||||
// Created by: drose (26Feb02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -19,26 +19,25 @@
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "eggLoader.h"
|
||||
#include "eggRenderState.h"
|
||||
#include "egg_parametrics.h"
|
||||
#include "config_egg2pg.h"
|
||||
#include "nodePath.h"
|
||||
#include "renderState.h"
|
||||
#include "transformState.h"
|
||||
#include "textureAttrib.h"
|
||||
#include "textureApplyAttrib.h"
|
||||
#include "texturePool.h"
|
||||
#include "billboardEffect.h"
|
||||
#include "cullFaceAttrib.h"
|
||||
#include "cullBinAttrib.h"
|
||||
#include "transparencyAttrib.h"
|
||||
#include "decalEffect.h"
|
||||
#include "depthTestAttrib.h"
|
||||
#include "depthWriteAttrib.h"
|
||||
#include "materialAttrib.h"
|
||||
#include "texMatrixAttrib.h"
|
||||
#include "colorAttrib.h"
|
||||
#include "textureAttrib.h"
|
||||
#include "materialPool.h"
|
||||
#include "geomNode.h"
|
||||
#include "qpgeomVertexFormat.h"
|
||||
#include "qpgeomVertexArrayFormat.h"
|
||||
#include "qpgeomVertexData.h"
|
||||
#include "qpgeomVertexIterator.h"
|
||||
#include "qpgeom.h"
|
||||
#include "qpgeomTriangles.h"
|
||||
#include "sequenceNode.h"
|
||||
#include "switchNode.h"
|
||||
#include "portalNode.h"
|
||||
@ -150,13 +149,13 @@ void EggLoader::
|
||||
build_graph() {
|
||||
_deferred_nodes.clear();
|
||||
|
||||
// First, bin up the LOD nodes.
|
||||
EggBinner binner;
|
||||
binner.make_bins(&_data);
|
||||
|
||||
// Then load up all of the textures.
|
||||
// First, load up all of the textures.
|
||||
load_textures();
|
||||
|
||||
// Then bin up the polysets and LOD nodes.
|
||||
EggBinner binner(*this);
|
||||
binner.make_bins(&_data);
|
||||
|
||||
// Now build up the scene graph.
|
||||
_root = new ModelRoot(_data.get_egg_filename().get_basename());
|
||||
make_node(&_data, _root);
|
||||
@ -1276,61 +1275,6 @@ make_texture_stage(const EggTexture *egg_tex) {
|
||||
return stage;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::get_material_attrib
|
||||
// Access: Private
|
||||
// Description: Returns a RenderAttrib suitable for enabling the
|
||||
// material indicated by the given EggMaterial, and with
|
||||
// the indicated backface flag.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderAttrib) EggLoader::
|
||||
get_material_attrib(const EggMaterial *egg_mat, bool bface) {
|
||||
Materials &materials = bface ? _materials_bface : _materials;
|
||||
|
||||
// First, check whether we've seen this material before.
|
||||
Materials::const_iterator mi;
|
||||
mi = materials.find(egg_mat);
|
||||
if (mi != materials.end()) {
|
||||
return (*mi).second;
|
||||
}
|
||||
|
||||
// Ok, this is the first time we've seen this particular
|
||||
// EggMaterial. Create a new Material that matches it.
|
||||
PT(Material) mat = new Material;
|
||||
if (egg_mat->has_diff()) {
|
||||
mat->set_diffuse(egg_mat->get_diff());
|
||||
// By default, ambient is the same as diffuse, if diffuse is
|
||||
// specified but ambient is not.
|
||||
mat->set_ambient(egg_mat->get_diff());
|
||||
}
|
||||
if (egg_mat->has_amb()) {
|
||||
mat->set_ambient(egg_mat->get_amb());
|
||||
}
|
||||
if (egg_mat->has_emit()) {
|
||||
mat->set_emission(egg_mat->get_emit());
|
||||
}
|
||||
if (egg_mat->has_spec()) {
|
||||
mat->set_specular(egg_mat->get_spec());
|
||||
}
|
||||
if (egg_mat->has_shininess()) {
|
||||
mat->set_shininess(egg_mat->get_shininess());
|
||||
}
|
||||
if (egg_mat->has_local()) {
|
||||
mat->set_local(egg_mat->get_local());
|
||||
}
|
||||
|
||||
mat->set_twoside(bface);
|
||||
|
||||
// Now get a global Material pointer, shared with other models.
|
||||
const Material *shared_mat = MaterialPool::get_material(mat);
|
||||
|
||||
// And create a MaterialAttrib for this Material.
|
||||
CPT(RenderAttrib) mt = MaterialAttrib::make(shared_mat);
|
||||
materials.insert(Materials::value_type(egg_mat, mt));
|
||||
|
||||
return mt;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::setup_bucket
|
||||
@ -1363,315 +1307,12 @@ setup_bucket(BuilderBucket &bucket, EggLoader::BakeInUVs &bake_in_uvs,
|
||||
bucket.set_name(egg_prim->get_name());
|
||||
}
|
||||
|
||||
// Assign the appropriate properties to the bucket.
|
||||
EggRenderState render_state(*this);
|
||||
render_state.fill_state(egg_prim);
|
||||
|
||||
// The various EggRenderMode properties can be defined directly at
|
||||
// the primitive, at a group above the primitive, or an a texture
|
||||
// applied to the primitive. The EggNode::determine_*() functions
|
||||
// can find the right pointer to the level at which this is actually
|
||||
// defined for a given primitive.
|
||||
EggRenderMode::AlphaMode am = EggRenderMode::AM_unspecified;
|
||||
EggRenderMode::DepthWriteMode dwm = EggRenderMode::DWM_unspecified;
|
||||
EggRenderMode::DepthTestMode dtm = EggRenderMode::DTM_unspecified;
|
||||
EggRenderMode::VisibilityMode vm = EggRenderMode::VM_unspecified;
|
||||
bool implicit_alpha = false;
|
||||
bool has_draw_order = false;
|
||||
int draw_order = 0;
|
||||
bool has_bin = false;
|
||||
string bin;
|
||||
|
||||
EggRenderMode *render_mode;
|
||||
render_mode = egg_prim->determine_alpha_mode();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
am = render_mode->get_alpha_mode();
|
||||
}
|
||||
render_mode = egg_prim->determine_depth_write_mode();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
dwm = render_mode->get_depth_write_mode();
|
||||
}
|
||||
render_mode = egg_prim->determine_depth_test_mode();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
dtm = render_mode->get_depth_test_mode();
|
||||
}
|
||||
render_mode = egg_prim->determine_visibility_mode();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
vm = render_mode->get_visibility_mode();
|
||||
}
|
||||
render_mode = egg_prim->determine_draw_order();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
has_draw_order = true;
|
||||
draw_order = render_mode->get_draw_order();
|
||||
}
|
||||
render_mode = egg_prim->determine_bin();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
has_bin = true;
|
||||
bin = render_mode->get_bin();
|
||||
}
|
||||
|
||||
bucket.add_attrib(TextureAttrib::make_off());
|
||||
int num_textures = egg_prim->get_num_textures();
|
||||
CPT(RenderAttrib) texture_attrib = NULL;
|
||||
CPT(RenderAttrib) tex_gen_attrib = NULL;
|
||||
CPT(RenderAttrib) tex_mat_attrib = NULL;
|
||||
TexMats tex_mats;
|
||||
|
||||
for (int i = 0; i < num_textures; i++) {
|
||||
PT_EggTexture egg_tex = egg_prim->get_texture(i);
|
||||
|
||||
const TextureDef &def = _textures[egg_tex];
|
||||
if (def._texture != (const RenderAttrib *)NULL) {
|
||||
if (texture_attrib == (RenderAttrib *)NULL) {
|
||||
texture_attrib = def._texture;
|
||||
} else {
|
||||
texture_attrib = texture_attrib->compose(def._texture);
|
||||
}
|
||||
|
||||
// If neither the primitive nor the texture specified an alpha
|
||||
// mode, assume it should be alpha'ed if the texture has an
|
||||
// alpha channel (unless the texture environment type is one
|
||||
// that doesn't apply its alpha to the result).
|
||||
if (am == EggRenderMode::AM_unspecified) {
|
||||
const TextureAttrib *tex_attrib = DCAST(TextureAttrib, def._texture);
|
||||
Texture *tex = tex_attrib->get_texture();
|
||||
nassertv(tex != (Texture *)NULL);
|
||||
int num_components = tex->get_num_components();
|
||||
if (egg_tex->has_alpha_channel(num_components)) {
|
||||
switch (egg_tex->get_env_type()) {
|
||||
case EggTexture::ET_decal:
|
||||
case EggTexture::ET_add:
|
||||
break;
|
||||
|
||||
default:
|
||||
implicit_alpha = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for a texgen attrib.
|
||||
bool has_tex_gen = false;
|
||||
if (egg_tex->get_tex_gen() != EggTexture::TG_unspecified) {
|
||||
has_tex_gen = true;
|
||||
if (tex_gen_attrib == (const RenderAttrib *)NULL) {
|
||||
tex_gen_attrib = TexGenAttrib::make();
|
||||
}
|
||||
tex_gen_attrib = DCAST(TexGenAttrib, tex_gen_attrib)->
|
||||
add_stage(def._stage, get_tex_gen(egg_tex));
|
||||
}
|
||||
|
||||
// Record the texture's associated texture matrix, so we can see
|
||||
// if we can safely bake it into the UV's. (We need to get the
|
||||
// complete list of textures that share this same set of UV's
|
||||
// per each unique texture matrix. Whew!)
|
||||
CPT(InternalName) uv_name;
|
||||
if (egg_tex->has_uv_name() && egg_tex->get_uv_name() != string("default")) {
|
||||
uv_name = InternalName::get_texcoord_name(egg_tex->get_uv_name());
|
||||
} else {
|
||||
uv_name = InternalName::get_texcoord();
|
||||
}
|
||||
|
||||
if (has_tex_gen) {
|
||||
// If the texture has a texgen mode, we will always apply its
|
||||
// texture transform, never bake it in. In fact, we don't
|
||||
// even care about its UV's in this case, since we won't be
|
||||
// using them.
|
||||
tex_mat_attrib = apply_tex_mat(tex_mat_attrib, def._stage, egg_tex);
|
||||
|
||||
} else {
|
||||
// Otherwise, we need to record that there is at least one
|
||||
// texture on this particular UV name and with this particular
|
||||
// texture matrix. If there are no other textures, or if all
|
||||
// of the other textures use the same texture matrix, then
|
||||
// tex_mats[uv_name].size() will remain 1 (which tells us we
|
||||
// can bake in the texture matrix to the UV's). On the other
|
||||
// hand, if there is another texture on the same uv name but
|
||||
// with a different transform, it will increase
|
||||
// tex_mats[uv_name].size() to at least 2, indicating we can't
|
||||
// bake in the texture matrix.
|
||||
tex_mats[uv_name][egg_tex->get_transform()].push_back(&def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These parametric primitive types can't have their UV's baked in,
|
||||
// so if we have one of these we always need to apply the texture
|
||||
// matrix as a separate attribute, regardless of how many textures
|
||||
// share the particular UV set.
|
||||
bool needs_tex_mat = (egg_prim->is_of_type(EggCurve::get_class_type()) ||
|
||||
egg_prim->is_of_type(EggSurface::get_class_type()));
|
||||
|
||||
// Now that we've visited all of the textures in the above loop, we
|
||||
// can go back and see how many of them share the same UV name and
|
||||
// texture matrix.
|
||||
TexMats::const_iterator tmi;
|
||||
for (tmi = tex_mats.begin(); tmi != tex_mats.end(); ++tmi) {
|
||||
const InternalName *uv_name = (*tmi).first;
|
||||
const TexMatTransforms &tmt = (*tmi).second;
|
||||
|
||||
if (tmt.size() == 1 && !needs_tex_mat) {
|
||||
// Only one unique transform sharing this set of UV's. We can
|
||||
// bake in the transform!
|
||||
const TexMatTextures &tmtex = (*tmt.begin()).second;
|
||||
|
||||
// The first EggTexture on the list is sufficient, since we know
|
||||
// they all have the same transform.
|
||||
nassertv(!tmtex.empty());
|
||||
TexMatTextures::const_iterator tmtexi = tmtex.begin();
|
||||
const EggTexture *egg_tex = (*tmtexi)->_egg_tex;
|
||||
if (egg_tex->has_transform()) {
|
||||
// If there's no transform, it's an identity matrix; don't
|
||||
// bother recording it. Of course, it would do no harm to
|
||||
// record it if we felt like it.
|
||||
bake_in_uvs[uv_name] = egg_tex;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Multiple transforms on this UV set, or a geometry type that
|
||||
// doesn't support baking in UV's. We have to apply the
|
||||
// texture matrix to each stage.
|
||||
TexMatTransforms::const_iterator tmti;
|
||||
for (tmti = tmt.begin(); tmti != tmt.end(); ++tmti) {
|
||||
const TexMatTextures &tmtex = (*tmti).second;
|
||||
TexMatTextures::const_iterator tmtexi;
|
||||
for (tmtexi = tmtex.begin(); tmtexi != tmtex.end(); ++tmtexi) {
|
||||
const EggTexture *egg_tex = (*tmtexi)->_egg_tex;
|
||||
TextureStage *stage = (*tmtexi)->_stage;
|
||||
|
||||
tex_mat_attrib = apply_tex_mat(tex_mat_attrib, stage, egg_tex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (texture_attrib != (RenderAttrib *)NULL) {
|
||||
bucket.add_attrib(texture_attrib);
|
||||
}
|
||||
|
||||
if (tex_gen_attrib != (RenderAttrib *)NULL) {
|
||||
bucket.add_attrib(tex_gen_attrib);
|
||||
}
|
||||
|
||||
if (tex_mat_attrib != (RenderAttrib *)NULL) {
|
||||
bucket.add_attrib(tex_mat_attrib);
|
||||
}
|
||||
|
||||
if (egg_prim->has_material()) {
|
||||
CPT(RenderAttrib) mt =
|
||||
get_material_attrib(egg_prim->get_material(),
|
||||
egg_prim->get_bface_flag());
|
||||
bucket.add_attrib(mt);
|
||||
}
|
||||
|
||||
|
||||
// Also check the color of the primitive to see if we should assume
|
||||
// alpha based on the alpha values specified in the egg file.
|
||||
if (am == EggRenderMode::AM_unspecified) {
|
||||
if (egg_prim->has_color()) {
|
||||
if (egg_prim->get_color()[3] != 1.0) {
|
||||
implicit_alpha = true;
|
||||
}
|
||||
}
|
||||
EggPrimitive::const_iterator vi;
|
||||
for (vi = egg_prim->begin();
|
||||
!implicit_alpha && vi != egg_prim->end();
|
||||
++vi) {
|
||||
if ((*vi)->has_color()) {
|
||||
if ((*vi)->get_color()[3] != 1.0) {
|
||||
implicit_alpha = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (implicit_alpha) {
|
||||
am = EggRenderMode::AM_on;
|
||||
}
|
||||
}
|
||||
|
||||
if (am == EggRenderMode::AM_on &&
|
||||
egg_alpha_mode != EggRenderMode::AM_unspecified) {
|
||||
// Alpha type "on" means to get the default transparency type.
|
||||
am = egg_alpha_mode;
|
||||
}
|
||||
|
||||
switch (am) {
|
||||
case EggRenderMode::AM_on:
|
||||
case EggRenderMode::AM_blend:
|
||||
bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
||||
break;
|
||||
|
||||
case EggRenderMode::AM_blend_no_occlude:
|
||||
bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
||||
bucket.add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_off));
|
||||
break;
|
||||
|
||||
case EggRenderMode::AM_ms:
|
||||
bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_multisample));
|
||||
break;
|
||||
|
||||
case EggRenderMode::AM_ms_mask:
|
||||
bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_multisample_mask));
|
||||
break;
|
||||
|
||||
case EggRenderMode::AM_binary:
|
||||
bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_binary));
|
||||
break;
|
||||
|
||||
case EggRenderMode::AM_dual:
|
||||
bucket.add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_dual));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dwm) {
|
||||
case EggRenderMode::DWM_on:
|
||||
bucket.add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_on));
|
||||
break;
|
||||
|
||||
case EggRenderMode::DWM_off:
|
||||
bucket.add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_off));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dtm) {
|
||||
case EggRenderMode::DTM_on:
|
||||
bucket.add_attrib(DepthTestAttrib::make(DepthTestAttrib::M_less));
|
||||
break;
|
||||
|
||||
case EggRenderMode::DTM_off:
|
||||
bucket.add_attrib(DepthTestAttrib::make(DepthTestAttrib::M_none));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (vm) {
|
||||
case EggRenderMode::VM_hidden:
|
||||
bucket._hidden = true;
|
||||
break;
|
||||
|
||||
case EggRenderMode::VM_normal:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (has_bin) {
|
||||
bucket.add_attrib(CullBinAttrib::make(bin, draw_order));
|
||||
|
||||
} else if (has_draw_order) {
|
||||
bucket.add_attrib(CullBinAttrib::make("fixed", draw_order));
|
||||
}
|
||||
|
||||
|
||||
if (egg_prim->get_bface_flag()) {
|
||||
// The primitive is marked with backface culling disabled--we want
|
||||
// to see both sides.
|
||||
bucket.add_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_none));
|
||||
}
|
||||
bucket._state = render_state._state;
|
||||
bucket._hidden = render_state._hidden;
|
||||
bake_in_uvs = render_state._bake_in_uvs;
|
||||
}
|
||||
|
||||
|
||||
@ -1683,9 +1324,7 @@ setup_bucket(BuilderBucket &bucket, EggLoader::BakeInUVs &bake_in_uvs,
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *EggLoader::
|
||||
make_node(EggNode *egg_node, PandaNode *parent) {
|
||||
if (egg_node->is_of_type(EggPrimitive::get_class_type())) {
|
||||
return make_node(DCAST(EggPrimitive, egg_node), parent);
|
||||
} else if (egg_node->is_of_type(EggBin::get_class_type())) {
|
||||
if (egg_node->is_of_type(EggBin::get_class_type())) {
|
||||
return make_node(DCAST(EggBin, egg_node), parent);
|
||||
} else if (egg_node->is_of_type(EggGroup::get_class_type())) {
|
||||
return make_node(DCAST(EggGroup, egg_node), parent);
|
||||
@ -1698,6 +1337,7 @@ make_node(EggNode *egg_node, PandaNode *parent) {
|
||||
return (PandaNode *)NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::make_node (EggPrimitive)
|
||||
// Access: Private
|
||||
@ -1727,6 +1367,7 @@ make_node(EggPrimitive *egg_prim, PandaNode *parent) {
|
||||
}
|
||||
return (PandaNode *)NULL;
|
||||
}
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::make_node (EggBin)
|
||||
@ -1735,41 +1376,149 @@ make_node(EggPrimitive *egg_prim, PandaNode *parent) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *EggLoader::
|
||||
make_node(EggBin *egg_bin, PandaNode *parent) {
|
||||
// Presently, an EggBin can only mean an LOD node (i.e. a parent of
|
||||
// one or more EggGroups with LOD specifications). Later it might
|
||||
// mean other things as well.
|
||||
// An EggBin might mean an LOD node (i.e. a parent of one or more
|
||||
// EggGroups with LOD specifications), or it might mean a polyset
|
||||
// node (a parent of one or more similar EggPrimitives).
|
||||
switch (egg_bin->get_bin_number()) {
|
||||
case EggBinner::BN_polyset:
|
||||
return make_polyset(egg_bin, parent);
|
||||
|
||||
nassertr((EggBinner::BinNumber)egg_bin->get_bin_number() == EggBinner::BN_lod, NULL);
|
||||
case EggBinner::BN_lod:
|
||||
return make_lod(egg_bin, parent);
|
||||
|
||||
case EggBinner::BN_none:
|
||||
break;
|
||||
}
|
||||
|
||||
// Shouldn't get here.
|
||||
return (PandaNode *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::make_polyset
|
||||
// Access: Private
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *EggLoader::
|
||||
make_polyset(EggBin *egg_bin, PandaNode *parent) {
|
||||
if (egg_bin->empty()) {
|
||||
// If there are no children--no primitives--never mind.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We know that all of the primitives in the bin have the same
|
||||
// vertex pool and same render state, so we can get that information
|
||||
// from the first primitive.
|
||||
EggGroup::const_iterator ci = egg_bin->begin();
|
||||
nassertr(ci != egg_bin->end(), NULL);
|
||||
CPT(EggPrimitive) first_prim = DCAST(EggPrimitive, (*ci));
|
||||
nassertr(first_prim != (EggPrimitive *)NULL, NULL);
|
||||
const EggRenderState *render_state;
|
||||
DCAST_INTO_R(render_state, first_prim->get_user_data(EggRenderState::get_class_type()), NULL);
|
||||
|
||||
if (render_state->_hidden && egg_suppress_hidden) {
|
||||
// Eat this polyset.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!use_qpgeom) {
|
||||
// In the old Geom system, just send each primitive to the
|
||||
// Builder.
|
||||
for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
|
||||
EggPrimitive *egg_prim;
|
||||
DCAST_INTO_R(egg_prim, (*ci), NULL);
|
||||
make_nonindexed_primitive(egg_prim, parent, NULL, _comp_verts_maker);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Convert the primitives' vertex pool to a GeomVertexData.
|
||||
PT(qpGeomVertexData) vertex_data =
|
||||
make_vertex_data(first_prim->get_pool(), first_prim->get_vertex_to_node());
|
||||
nassertr(vertex_data != (qpGeomVertexData *)NULL, NULL);
|
||||
|
||||
// And now create a Geom to hold the primitives.
|
||||
PT(qpGeom) geom = new qpGeom;
|
||||
geom->set_vertex_data(vertex_data);
|
||||
|
||||
// Automatically triangulate any higher-order polygons we might have.
|
||||
egg_bin->triangulate_polygons(true);
|
||||
|
||||
// Now create a handful of GeomPrimitives corresponding to the
|
||||
// various types of primitives we have.
|
||||
Primitives primitives;
|
||||
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);
|
||||
}
|
||||
|
||||
if (!primitives.empty()) {
|
||||
// Add each new primitive to the Geom.
|
||||
Primitives::const_iterator pi;
|
||||
for (pi = primitives.begin(); pi != primitives.end(); ++pi) {
|
||||
qpGeomPrimitive *primitive = (*pi).second;
|
||||
geom->add_primitive(primitive);
|
||||
}
|
||||
|
||||
// Now, is our parent node a GeomNode, or just an ordinary
|
||||
// PandaNode? If it's a GeomNode, we can add the new Geom directly
|
||||
// to our parent; otherwise, we need to create a new node.
|
||||
if (parent->is_geom_node() && !render_state->_hidden) {
|
||||
DCAST(GeomNode, parent)->add_geom(geom, render_state->_state);
|
||||
|
||||
} else {
|
||||
PT(GeomNode) geom_node = new GeomNode(egg_bin->get_name());
|
||||
if (render_state->_hidden) {
|
||||
parent->add_stashed(geom_node);
|
||||
} else {
|
||||
parent->add_child(geom_node);
|
||||
}
|
||||
geom_node->add_geom(geom, render_state->_state);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::make_lod
|
||||
// Access: Private
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *EggLoader::
|
||||
make_lod(EggBin *egg_bin, PandaNode *parent) {
|
||||
LODNode *lod_node = new LODNode(egg_bin->get_name());
|
||||
|
||||
pvector<LODInstance> instances;
|
||||
|
||||
|
||||
EggGroup::const_iterator ci;
|
||||
for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
|
||||
LODInstance instance(*ci);
|
||||
instances.push_back(instance);
|
||||
}
|
||||
|
||||
|
||||
// Now that we've created all of our children, put them in the
|
||||
// proper order and tell the LOD node about them.
|
||||
sort(instances.begin(), instances.end());
|
||||
|
||||
|
||||
if (!instances.empty()) {
|
||||
// Set up the LOD node's center. All of the children should have
|
||||
// the same center, because that's how we binned them.
|
||||
lod_node->set_center(LCAST(float, instances[0]._d->_center));
|
||||
}
|
||||
|
||||
|
||||
for (size_t i = 0; i < instances.size(); i++) {
|
||||
// Create the children in the proper order within the scene graph.
|
||||
const LODInstance &instance = instances[i];
|
||||
make_node(instance._egg_node, lod_node);
|
||||
|
||||
|
||||
// All of the children should have the same center, because that's
|
||||
// how we binned them.
|
||||
nassertr(lod_node->get_center().almost_equal
|
||||
(LCAST(float, instance._d->_center), 0.01), NULL);
|
||||
|
||||
|
||||
// Tell the LOD node about this child's switching distances.
|
||||
lod_node->add_switch(instance._d->_switch_in, instance._d->_switch_out);
|
||||
}
|
||||
@ -1891,8 +1640,21 @@ make_node(EggGroup *egg_group, PandaNode *parent) {
|
||||
}
|
||||
|
||||
} else {
|
||||
// A normal group; just create a normal node, and traverse.
|
||||
node = new PandaNode(egg_group->get_name());
|
||||
// A normal group; just create a normal node, and traverse. But
|
||||
// if all of the children of this group are polysets, anticipate
|
||||
// this for the benefit of smaller grouping, and create a single
|
||||
// GeomNode for all of the children.
|
||||
bool all_polysets = false;
|
||||
bool any_hidden = false;
|
||||
if (use_qpgeom) {
|
||||
check_for_polysets(egg_group, all_polysets, any_hidden);
|
||||
}
|
||||
|
||||
if (all_polysets && !any_hidden) {
|
||||
node = new GeomNode(egg_group->get_name());
|
||||
} else {
|
||||
node = new PandaNode(egg_group->get_name());
|
||||
}
|
||||
|
||||
EggGroup::const_iterator ci;
|
||||
for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
|
||||
@ -2030,6 +1792,175 @@ make_node(EggGroupNode *egg_group, PandaNode *parent) {
|
||||
return node;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::check_for_polysets
|
||||
// Access: Private
|
||||
// Description: Sets all_polysets true if all of the children of this
|
||||
// node represent a polyset. Sets any_hidden true if
|
||||
// any of those polysets are flagged hidden.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggLoader::
|
||||
check_for_polysets(EggGroup *egg_group, bool &all_polysets, bool &any_hidden) {
|
||||
all_polysets = (!egg_group->empty());
|
||||
any_hidden = false;
|
||||
|
||||
EggGroup::const_iterator ci;
|
||||
for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
|
||||
if ((*ci)->is_of_type(EggBin::get_class_type())) {
|
||||
EggBin *egg_bin = DCAST(EggBin, (*ci));
|
||||
if (egg_bin->get_bin_number() == EggBinner::BN_polyset) {
|
||||
// We know that all of the primitives in the bin have the same
|
||||
// render state, so we can get that information from the first
|
||||
// primitive.
|
||||
EggGroup::const_iterator bci = egg_bin->begin();
|
||||
nassertv(bci != egg_bin->end());
|
||||
const EggPrimitive *first_prim;
|
||||
DCAST_INTO_V(first_prim, (*bci));
|
||||
const EggRenderState *render_state;
|
||||
DCAST_INTO_V(render_state, first_prim->get_user_data(EggRenderState::get_class_type()));
|
||||
|
||||
if (render_state->_hidden) {
|
||||
any_hidden = true;
|
||||
}
|
||||
} else {
|
||||
all_polysets = false;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
all_polysets = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::make_vertex_data
|
||||
// Access: Private
|
||||
// Description: Creates a GeomVertexData structure from the vertex
|
||||
// pool, for the indicated transform space. If a
|
||||
// GeomVertexData has already been created for this
|
||||
// transform, just returns it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(qpGeomVertexData) EggLoader::
|
||||
make_vertex_data(EggVertexPool *vertex_pool, const LMatrix4d &transform) {
|
||||
VertexPoolTransform vpt;
|
||||
vpt._vertex_pool = vertex_pool;
|
||||
vpt._transform = transform;
|
||||
|
||||
VertexPoolData::iterator di;
|
||||
di = _vertex_pool_data.find(vpt);
|
||||
if (di != _vertex_pool_data.end()) {
|
||||
return (*di).second;
|
||||
}
|
||||
|
||||
// Decide on the format for the vertices.
|
||||
PT(qpGeomVertexArrayFormat) array_format = new qpGeomVertexArrayFormat;
|
||||
array_format->add_data_type
|
||||
(InternalName::get_vertex(), vertex_pool->get_num_dimensions(),
|
||||
qpGeomVertexDataType::NT_float);
|
||||
|
||||
if (vertex_pool->has_normals()) {
|
||||
array_format->add_data_type
|
||||
(InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float);
|
||||
}
|
||||
|
||||
if (vertex_pool->has_colors()) {
|
||||
array_format->add_data_type
|
||||
(InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_argb);
|
||||
}
|
||||
|
||||
vector_string uv_names;
|
||||
vertex_pool->get_uv_names(uv_names);
|
||||
vector_string::const_iterator ni;
|
||||
for (ni = uv_names.begin(); ni != uv_names.end(); ++ni) {
|
||||
string name = (*ni);
|
||||
if (name == "default") {
|
||||
name = string();
|
||||
}
|
||||
array_format->add_data_type
|
||||
(InternalName::get_texcoord_name(name), 2,
|
||||
qpGeomVertexDataType::NT_float);
|
||||
}
|
||||
|
||||
CPT(qpGeomVertexFormat) format =
|
||||
qpGeomVertexFormat::register_format(new qpGeomVertexFormat(array_format));
|
||||
|
||||
// Now create a new GeomVertexData using the indicated format.
|
||||
PT(qpGeomVertexData) vertex_data = new qpGeomVertexData(format);
|
||||
|
||||
// And fill the data from the vertex pool.
|
||||
EggVertexPool::const_iterator vi;
|
||||
for (vi = vertex_pool->begin(); vi != vertex_pool->end(); ++vi) {
|
||||
qpGeomVertexIterator gvi(vertex_data);
|
||||
EggVertex *vertex = (*vi);
|
||||
gvi.set_vertex(vertex->get_index());
|
||||
|
||||
gvi.set_data_type(InternalName::get_vertex());
|
||||
gvi.set_data4(LCAST(float, vertex->get_pos4()));
|
||||
|
||||
if (vertex->has_normal()) {
|
||||
gvi.set_data_type(InternalName::get_normal());
|
||||
gvi.set_data3(LCAST(float, vertex->get_normal()));
|
||||
}
|
||||
|
||||
if (vertex->has_color()) {
|
||||
gvi.set_data_type(InternalName::get_color());
|
||||
gvi.set_data4(vertex->get_color());
|
||||
}
|
||||
|
||||
EggVertex::const_uv_iterator uvi;
|
||||
for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
|
||||
EggVertexUV *uv = (*uvi);
|
||||
string name = uv->get_name();
|
||||
if (name == "default") {
|
||||
name = string();
|
||||
}
|
||||
gvi.set_data_type(InternalName::get_texcoord_name(name));
|
||||
gvi.set_data2(LCAST(float, uv->get_uv()));
|
||||
}
|
||||
}
|
||||
|
||||
bool inserted = _vertex_pool_data.insert
|
||||
(VertexPoolData::value_type(vpt, vertex_data)).second;
|
||||
nassertr(inserted, vertex_data);
|
||||
|
||||
return vertex_data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::make_primitive
|
||||
// Access: Private
|
||||
// Description: Creates a GeomPrimitive corresponding to the
|
||||
// indicated EggPrimitive, and adds it to the set.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggLoader::
|
||||
make_primitive(EggPrimitive *egg_prim, EggLoader::Primitives &primitives) {
|
||||
PT(qpGeomPrimitive) primitive;
|
||||
if (egg_prim->is_of_type(EggPolygon::get_class_type())) {
|
||||
if (egg_prim->size() == 3) {
|
||||
primitive = new qpGeomTriangles;
|
||||
}
|
||||
}
|
||||
|
||||
if (primitive == NULL) {
|
||||
// Don't know how to make this kind of primitive.
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert the primitive into the set, but if we already have a
|
||||
// primitive of that type, reset the pointer to that one instead.
|
||||
pair<Primitives::iterator, bool> result =
|
||||
primitives.insert(Primitives::value_type(primitive->get_type(), primitive));
|
||||
primitive = (*result.first).second;
|
||||
|
||||
// Now add the vertices.
|
||||
EggPrimitive::const_iterator vi;
|
||||
for (vi = egg_prim->begin(); vi != egg_prim->end(); ++vi) {
|
||||
primitive->add_vertex((*vi)->get_index());
|
||||
}
|
||||
primitive->close_primitive();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::set_portal_polygon
|
||||
// Access: Private
|
||||
@ -3086,84 +3017,5 @@ get_combine_operand(const EggTexture *egg_tex,
|
||||
return TextureStage::CO_undefined;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::get_tex_gen
|
||||
// Access: Private, Static
|
||||
// Description: Extracts the tex_gen from the given egg texture,
|
||||
// and returns its corresponding TexGenAttrib mode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TexGenAttrib::Mode EggLoader::
|
||||
get_tex_gen(const EggTexture *egg_tex) {
|
||||
switch (egg_tex->get_tex_gen()) {
|
||||
case EggTexture::TG_unspecified:
|
||||
return TexGenAttrib::M_off;
|
||||
|
||||
case EggTexture::TG_eye_sphere_map:
|
||||
return TexGenAttrib::M_eye_sphere_map;
|
||||
|
||||
case EggTexture::TG_world_cube_map:
|
||||
return TexGenAttrib::M_world_cube_map;
|
||||
|
||||
case EggTexture::TG_eye_cube_map:
|
||||
return TexGenAttrib::M_eye_cube_map;
|
||||
|
||||
case EggTexture::TG_world_normal:
|
||||
return TexGenAttrib::M_world_normal;
|
||||
|
||||
case EggTexture::TG_eye_normal:
|
||||
return TexGenAttrib::M_eye_normal;
|
||||
|
||||
case EggTexture::TG_world_position:
|
||||
return TexGenAttrib::M_world_position;
|
||||
|
||||
case EggTexture::TG_object_position:
|
||||
return TexGenAttrib::M_object_position;
|
||||
|
||||
case EggTexture::TG_eye_position:
|
||||
return TexGenAttrib::M_eye_position;
|
||||
};
|
||||
|
||||
return TexGenAttrib::M_off;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::apply_tex_mat
|
||||
// Access: Private, Static
|
||||
// Description: Applies the texture matrix from the indicated egg
|
||||
// texture to the given TexMatrixAttrib, and returns the
|
||||
// new attrib.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderAttrib) EggLoader::
|
||||
apply_tex_mat(CPT(RenderAttrib) tex_mat_attrib,
|
||||
TextureStage *stage, const EggTexture *egg_tex) {
|
||||
if (egg_tex->has_transform()) {
|
||||
const LMatrix3d &tex_mat = egg_tex->get_transform();
|
||||
LMatrix4f mat4(tex_mat(0, 0), tex_mat(0, 1), 0.0f, tex_mat(0, 2),
|
||||
tex_mat(1, 0), tex_mat(1, 1), 0.0f, tex_mat(1, 2),
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
tex_mat(2, 0), tex_mat(2, 1), 0.0f, tex_mat(2, 2));
|
||||
CPT(TransformState) transform;
|
||||
|
||||
LVecBase3f scale, shear, hpr, translate;
|
||||
if (decompose_matrix(mat4, scale, shear, hpr, translate)) {
|
||||
// If the texture matrix can be represented componentwise, do
|
||||
// so.
|
||||
transform = TransformState::make_pos_hpr_scale_shear
|
||||
(translate, hpr, scale, shear);
|
||||
|
||||
} else {
|
||||
// Otherwise, make a matrix transform.
|
||||
transform = TransformState::make_mat(mat4);
|
||||
}
|
||||
|
||||
if (tex_mat_attrib == (const RenderAttrib *)NULL) {
|
||||
tex_mat_attrib = TexMatrixAttrib::make();
|
||||
}
|
||||
tex_mat_attrib = DCAST(TexMatrixAttrib, tex_mat_attrib)->
|
||||
add_stage(stage, transform);
|
||||
}
|
||||
|
||||
return tex_mat_attrib;
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,6 +39,8 @@
|
||||
#include "texGenAttrib.h"
|
||||
#include "eggTransform3d.h"
|
||||
#include "computedVerticesMaker.h"
|
||||
#include "qpgeomVertexData.h"
|
||||
#include "qpgeomPrimitive.h"
|
||||
|
||||
class EggNode;
|
||||
class EggBin;
|
||||
@ -95,6 +97,9 @@ private:
|
||||
|
||||
// This structure is returned by setup_bucket().
|
||||
typedef pmap<CPT(InternalName), const EggTexture *> BakeInUVs;
|
||||
|
||||
// This is used by make_primitive().
|
||||
typedef pmap<TypeHandle, PT(qpGeomPrimitive) > Primitives;
|
||||
|
||||
void make_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent,
|
||||
const LMatrix4d &mat);
|
||||
@ -108,21 +113,25 @@ private:
|
||||
void apply_texture_attributes(Texture *tex, const EggTexture *egg_tex);
|
||||
PT(TextureStage) make_texture_stage(const EggTexture *egg_tex);
|
||||
|
||||
CPT(RenderAttrib) get_material_attrib(const EggMaterial *egg_mat,
|
||||
bool bface);
|
||||
|
||||
void setup_bucket(BuilderBucket &bucket, BakeInUVs &bake_in_uvs,
|
||||
PandaNode *parent, EggPrimitive *egg_prim);
|
||||
|
||||
PandaNode *make_node(EggNode *egg_node, PandaNode *parent);
|
||||
PandaNode *make_node(EggPrimitive *egg_prim, PandaNode *parent);
|
||||
PandaNode *make_node(EggBin *egg_bin, PandaNode *parent);
|
||||
PandaNode *make_polyset(EggBin *egg_bin, PandaNode *parent);
|
||||
PandaNode *make_lod(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 check_for_polysets(EggGroup *egg_group, bool &all_polysets,
|
||||
bool &any_hidden);
|
||||
PT(qpGeomVertexData) make_vertex_data(EggVertexPool *vertex_pool,
|
||||
const LMatrix4d &transform);
|
||||
void make_primitive(EggPrimitive *egg_prim, Primitives &primitives);
|
||||
|
||||
void set_portal_polygon(EggGroup *egg_group, PortalNode *pnode);
|
||||
EggPolygon *find_first_polygon(EggGroup *egg_group);
|
||||
|
||||
@ -173,11 +182,6 @@ private:
|
||||
static TextureStage::CombineOperand
|
||||
get_combine_operand(const EggTexture *egg_tex,
|
||||
EggTexture::CombineChannel channel, int n);
|
||||
static TexGenAttrib::Mode get_tex_gen(const EggTexture *egg_tex);
|
||||
|
||||
static CPT(RenderAttrib)
|
||||
apply_tex_mat(CPT(RenderAttrib) tex_mat_attrib,
|
||||
TextureStage *stage, const EggTexture *egg_tex);
|
||||
|
||||
Builder _builder;
|
||||
|
||||
@ -191,6 +195,15 @@ private:
|
||||
typedef pset<PandaNode *> Decals;
|
||||
Decals _decals;
|
||||
|
||||
class VertexPoolTransform {
|
||||
public:
|
||||
INLINE bool operator < (const VertexPoolTransform &other) const;
|
||||
EggVertexPool *_vertex_pool;
|
||||
LMatrix4d _transform;
|
||||
};
|
||||
typedef pmap<VertexPoolTransform, PT(qpGeomVertexData) > VertexPoolData;
|
||||
VertexPoolData _vertex_pool_data;
|
||||
|
||||
DeferredNodes _deferred_nodes;
|
||||
|
||||
ComputedVerticesMaker _comp_verts_maker;
|
||||
@ -199,7 +212,10 @@ public:
|
||||
PT(PandaNode) _root;
|
||||
EggData _data;
|
||||
bool _error;
|
||||
|
||||
friend class EggRenderState;
|
||||
};
|
||||
|
||||
#include "eggLoader.I"
|
||||
|
||||
#endif
|
||||
|
58
panda/src/egg2pg/eggRenderState.I
Normal file
58
panda/src/egg2pg/eggRenderState.I
Normal file
@ -0,0 +1,58 @@
|
||||
// Filename: eggRenderState.I
|
||||
// Created by: drose (12Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggRenderState::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
EggRenderState::
|
||||
EggRenderState(EggLoader &loader) :
|
||||
_loader(loader),
|
||||
_state(RenderState::make_empty()),
|
||||
_hidden(false)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggRenderState::add_attrib
|
||||
// Access: Public
|
||||
// Description: A convenience function to add the indicated render
|
||||
// attribute to the aggregate state.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void EggRenderState::
|
||||
add_attrib(const RenderAttrib *attrib) {
|
||||
_state = _state->add_attrib(attrib);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggRenderState::operator <
|
||||
// Access: Public
|
||||
// Description: Provides a unique ordering for different
|
||||
// EggRenderState objects, so that primitives of similar
|
||||
// state can be grouped together by the EggBinner.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool EggRenderState::
|
||||
operator < (const EggRenderState &other) const {
|
||||
if (_state != other._state) {
|
||||
return _state < other._state;
|
||||
}
|
||||
|
||||
return (int)_hidden < (int)other._hidden;
|
||||
}
|
491
panda/src/egg2pg/eggRenderState.cxx
Normal file
491
panda/src/egg2pg/eggRenderState.cxx
Normal file
@ -0,0 +1,491 @@
|
||||
// Filename: eggRenderState.cxx
|
||||
// Created by: drose (12Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "eggRenderState.h"
|
||||
#include "eggRenderMode.h"
|
||||
#include "textureAttrib.h"
|
||||
#include "renderAttrib.h"
|
||||
#include "eggTexture.h"
|
||||
#include "texGenAttrib.h"
|
||||
#include "internalName.h"
|
||||
#include "eggCurve.h"
|
||||
#include "eggSurface.h"
|
||||
#include "cullBinAttrib.h"
|
||||
#include "cullFaceAttrib.h"
|
||||
#include "transparencyAttrib.h"
|
||||
#include "depthWriteAttrib.h"
|
||||
#include "depthTestAttrib.h"
|
||||
#include "texMatrixAttrib.h"
|
||||
#include "material.h"
|
||||
#include "materialAttrib.h"
|
||||
#include "materialPool.h"
|
||||
#include "config_gobj.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggRenderState::fill_state
|
||||
// Access: Public
|
||||
// Description: Sets up the state as appropriate for the indicated
|
||||
// primitive.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggRenderState::
|
||||
fill_state(EggPrimitive *egg_prim) {
|
||||
// The various EggRenderMode properties can be defined directly at
|
||||
// the primitive, at a group above the primitive, or an a texture
|
||||
// applied to the primitive. The EggNode::determine_*() functions
|
||||
// can find the right pointer to the level at which this is actually
|
||||
// defined for a given primitive.
|
||||
EggRenderMode::AlphaMode am = EggRenderMode::AM_unspecified;
|
||||
EggRenderMode::DepthWriteMode dwm = EggRenderMode::DWM_unspecified;
|
||||
EggRenderMode::DepthTestMode dtm = EggRenderMode::DTM_unspecified;
|
||||
EggRenderMode::VisibilityMode vm = EggRenderMode::VM_unspecified;
|
||||
bool implicit_alpha = false;
|
||||
bool has_draw_order = false;
|
||||
int draw_order = 0;
|
||||
bool has_bin = false;
|
||||
string bin;
|
||||
|
||||
EggRenderMode *render_mode;
|
||||
render_mode = egg_prim->determine_alpha_mode();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
am = render_mode->get_alpha_mode();
|
||||
}
|
||||
render_mode = egg_prim->determine_depth_write_mode();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
dwm = render_mode->get_depth_write_mode();
|
||||
}
|
||||
render_mode = egg_prim->determine_depth_test_mode();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
dtm = render_mode->get_depth_test_mode();
|
||||
}
|
||||
render_mode = egg_prim->determine_visibility_mode();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
vm = render_mode->get_visibility_mode();
|
||||
}
|
||||
render_mode = egg_prim->determine_draw_order();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
has_draw_order = true;
|
||||
draw_order = render_mode->get_draw_order();
|
||||
}
|
||||
render_mode = egg_prim->determine_bin();
|
||||
if (render_mode != (EggRenderMode *)NULL) {
|
||||
has_bin = true;
|
||||
bin = render_mode->get_bin();
|
||||
}
|
||||
|
||||
add_attrib(TextureAttrib::make_off());
|
||||
int num_textures = egg_prim->get_num_textures();
|
||||
CPT(RenderAttrib) texture_attrib = NULL;
|
||||
CPT(RenderAttrib) tex_gen_attrib = NULL;
|
||||
CPT(RenderAttrib) tex_mat_attrib = NULL;
|
||||
TexMats tex_mats;
|
||||
|
||||
for (int i = 0; i < num_textures; i++) {
|
||||
PT_EggTexture egg_tex = egg_prim->get_texture(i);
|
||||
|
||||
const TextureDef &def = _loader._textures[egg_tex];
|
||||
if (def._texture != (const RenderAttrib *)NULL) {
|
||||
if (texture_attrib == (RenderAttrib *)NULL) {
|
||||
texture_attrib = def._texture;
|
||||
} else {
|
||||
texture_attrib = texture_attrib->compose(def._texture);
|
||||
}
|
||||
|
||||
// If neither the primitive nor the texture specified an alpha
|
||||
// mode, assume it should be alpha'ed if the texture has an
|
||||
// alpha channel (unless the texture environment type is one
|
||||
// that doesn't apply its alpha to the result).
|
||||
if (am == EggRenderMode::AM_unspecified) {
|
||||
const TextureAttrib *tex_attrib = DCAST(TextureAttrib, def._texture);
|
||||
Texture *tex = tex_attrib->get_texture();
|
||||
nassertv(tex != (Texture *)NULL);
|
||||
int num_components = tex->get_num_components();
|
||||
if (egg_tex->has_alpha_channel(num_components)) {
|
||||
switch (egg_tex->get_env_type()) {
|
||||
case EggTexture::ET_decal:
|
||||
case EggTexture::ET_add:
|
||||
break;
|
||||
|
||||
default:
|
||||
implicit_alpha = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for a texgen attrib.
|
||||
bool has_tex_gen = false;
|
||||
if (egg_tex->get_tex_gen() != EggTexture::TG_unspecified) {
|
||||
has_tex_gen = true;
|
||||
if (tex_gen_attrib == (const RenderAttrib *)NULL) {
|
||||
tex_gen_attrib = TexGenAttrib::make();
|
||||
}
|
||||
tex_gen_attrib = DCAST(TexGenAttrib, tex_gen_attrib)->
|
||||
add_stage(def._stage, get_tex_gen(egg_tex));
|
||||
}
|
||||
|
||||
// Record the texture's associated texture matrix, so we can see
|
||||
// if we can safely bake it into the UV's. (We need to get the
|
||||
// complete list of textures that share this same set of UV's
|
||||
// per each unique texture matrix. Whew!)
|
||||
CPT(InternalName) uv_name;
|
||||
if (egg_tex->has_uv_name() && egg_tex->get_uv_name() != string("default")) {
|
||||
uv_name = InternalName::get_texcoord_name(egg_tex->get_uv_name());
|
||||
} else {
|
||||
uv_name = InternalName::get_texcoord();
|
||||
}
|
||||
|
||||
if (has_tex_gen) {
|
||||
// If the texture has a texgen mode, we will always apply its
|
||||
// texture transform, never bake it in. In fact, we don't
|
||||
// even care about its UV's in this case, since we won't be
|
||||
// using them.
|
||||
tex_mat_attrib = apply_tex_mat(tex_mat_attrib, def._stage, egg_tex);
|
||||
|
||||
} else {
|
||||
// Otherwise, we need to record that there is at least one
|
||||
// texture on this particular UV name and with this particular
|
||||
// texture matrix. If there are no other textures, or if all
|
||||
// of the other textures use the same texture matrix, then
|
||||
// tex_mats[uv_name].size() will remain 1 (which tells us we
|
||||
// can bake in the texture matrix to the UV's). On the other
|
||||
// hand, if there is another texture on the same uv name but
|
||||
// with a different transform, it will increase
|
||||
// tex_mats[uv_name].size() to at least 2, indicating we can't
|
||||
// bake in the texture matrix.
|
||||
tex_mats[uv_name][egg_tex->get_transform()].push_back(&def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These parametric primitive types can't have their UV's baked in,
|
||||
// so if we have one of these we always need to apply the texture
|
||||
// matrix as a separate attribute, regardless of how many textures
|
||||
// share the particular UV set.
|
||||
bool needs_tex_mat = (egg_prim->is_of_type(EggCurve::get_class_type()) ||
|
||||
egg_prim->is_of_type(EggSurface::get_class_type()));
|
||||
|
||||
// Now that we've visited all of the textures in the above loop, we
|
||||
// can go back and see how many of them share the same UV name and
|
||||
// texture matrix.
|
||||
TexMats::const_iterator tmi;
|
||||
for (tmi = tex_mats.begin(); tmi != tex_mats.end(); ++tmi) {
|
||||
const InternalName *uv_name = (*tmi).first;
|
||||
const TexMatTransforms &tmt = (*tmi).second;
|
||||
|
||||
if (tmt.size() == 1 && !needs_tex_mat && !use_qpgeom) {
|
||||
// Only one unique transform sharing this set of UV's. We can
|
||||
// bake in the transform!
|
||||
const TexMatTextures &tmtex = (*tmt.begin()).second;
|
||||
|
||||
// The first EggTexture on the list is sufficient, since we know
|
||||
// they all have the same transform.
|
||||
nassertv(!tmtex.empty());
|
||||
TexMatTextures::const_iterator tmtexi = tmtex.begin();
|
||||
const EggTexture *egg_tex = (*tmtexi)->_egg_tex;
|
||||
if (egg_tex->has_transform()) {
|
||||
// If there's no transform, it's an identity matrix; don't
|
||||
// bother recording it. Of course, it would do no harm to
|
||||
// record it if we felt like it.
|
||||
_bake_in_uvs[uv_name] = egg_tex;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Multiple transforms on this UV set, or a geometry type that
|
||||
// doesn't support baking in UV's. We have to apply the
|
||||
// texture matrix to each stage.
|
||||
TexMatTransforms::const_iterator tmti;
|
||||
for (tmti = tmt.begin(); tmti != tmt.end(); ++tmti) {
|
||||
const TexMatTextures &tmtex = (*tmti).second;
|
||||
TexMatTextures::const_iterator tmtexi;
|
||||
for (tmtexi = tmtex.begin(); tmtexi != tmtex.end(); ++tmtexi) {
|
||||
const EggTexture *egg_tex = (*tmtexi)->_egg_tex;
|
||||
TextureStage *stage = (*tmtexi)->_stage;
|
||||
|
||||
tex_mat_attrib = apply_tex_mat(tex_mat_attrib, stage, egg_tex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (texture_attrib != (RenderAttrib *)NULL) {
|
||||
add_attrib(texture_attrib);
|
||||
}
|
||||
|
||||
if (tex_gen_attrib != (RenderAttrib *)NULL) {
|
||||
add_attrib(tex_gen_attrib);
|
||||
}
|
||||
|
||||
if (tex_mat_attrib != (RenderAttrib *)NULL) {
|
||||
add_attrib(tex_mat_attrib);
|
||||
}
|
||||
|
||||
if (egg_prim->has_material()) {
|
||||
CPT(RenderAttrib) mt =
|
||||
get_material_attrib(egg_prim->get_material(),
|
||||
egg_prim->get_bface_flag());
|
||||
add_attrib(mt);
|
||||
}
|
||||
|
||||
|
||||
// Also check the color of the primitive to see if we should assume
|
||||
// alpha based on the alpha values specified in the egg file.
|
||||
if (am == EggRenderMode::AM_unspecified) {
|
||||
if (egg_prim->has_color()) {
|
||||
if (egg_prim->get_color()[3] != 1.0) {
|
||||
implicit_alpha = true;
|
||||
}
|
||||
}
|
||||
EggPrimitive::const_iterator vi;
|
||||
for (vi = egg_prim->begin();
|
||||
!implicit_alpha && vi != egg_prim->end();
|
||||
++vi) {
|
||||
if ((*vi)->has_color()) {
|
||||
if ((*vi)->get_color()[3] != 1.0) {
|
||||
implicit_alpha = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (implicit_alpha) {
|
||||
am = EggRenderMode::AM_on;
|
||||
}
|
||||
}
|
||||
|
||||
if (am == EggRenderMode::AM_on &&
|
||||
egg_alpha_mode != EggRenderMode::AM_unspecified) {
|
||||
// Alpha type "on" means to get the default transparency type.
|
||||
am = egg_alpha_mode;
|
||||
}
|
||||
|
||||
switch (am) {
|
||||
case EggRenderMode::AM_on:
|
||||
case EggRenderMode::AM_blend:
|
||||
add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
||||
break;
|
||||
|
||||
case EggRenderMode::AM_blend_no_occlude:
|
||||
add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
||||
add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_off));
|
||||
break;
|
||||
|
||||
case EggRenderMode::AM_ms:
|
||||
add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_multisample));
|
||||
break;
|
||||
|
||||
case EggRenderMode::AM_ms_mask:
|
||||
add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_multisample_mask));
|
||||
break;
|
||||
|
||||
case EggRenderMode::AM_binary:
|
||||
add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_binary));
|
||||
break;
|
||||
|
||||
case EggRenderMode::AM_dual:
|
||||
add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_dual));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dwm) {
|
||||
case EggRenderMode::DWM_on:
|
||||
add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_on));
|
||||
break;
|
||||
|
||||
case EggRenderMode::DWM_off:
|
||||
add_attrib(DepthWriteAttrib::make(DepthWriteAttrib::M_off));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (dtm) {
|
||||
case EggRenderMode::DTM_on:
|
||||
add_attrib(DepthTestAttrib::make(DepthTestAttrib::M_less));
|
||||
break;
|
||||
|
||||
case EggRenderMode::DTM_off:
|
||||
add_attrib(DepthTestAttrib::make(DepthTestAttrib::M_none));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (vm) {
|
||||
case EggRenderMode::VM_hidden:
|
||||
_hidden = true;
|
||||
break;
|
||||
|
||||
case EggRenderMode::VM_normal:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (has_bin) {
|
||||
add_attrib(CullBinAttrib::make(bin, draw_order));
|
||||
|
||||
} else if (has_draw_order) {
|
||||
add_attrib(CullBinAttrib::make("fixed", draw_order));
|
||||
}
|
||||
|
||||
|
||||
if (egg_prim->get_bface_flag()) {
|
||||
// The primitive is marked with backface culling disabled--we want
|
||||
// to see both sides.
|
||||
add_attrib(CullFaceAttrib::make(CullFaceAttrib::M_cull_none));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggRenderState::get_material_attrib
|
||||
// Access: Private
|
||||
// Description: Returns a RenderAttrib suitable for enabling the
|
||||
// material indicated by the given EggMaterial, and with
|
||||
// the indicated backface flag.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderAttrib) EggRenderState::
|
||||
get_material_attrib(const EggMaterial *egg_mat, bool bface) {
|
||||
Materials &materials =
|
||||
bface ? _loader._materials_bface : _loader._materials;
|
||||
|
||||
// First, check whether we've seen this material before.
|
||||
Materials::const_iterator mi;
|
||||
mi = materials.find(egg_mat);
|
||||
if (mi != materials.end()) {
|
||||
return (*mi).second;
|
||||
}
|
||||
|
||||
// Ok, this is the first time we've seen this particular
|
||||
// EggMaterial. Create a new Material that matches it.
|
||||
PT(Material) mat = new Material;
|
||||
if (egg_mat->has_diff()) {
|
||||
mat->set_diffuse(egg_mat->get_diff());
|
||||
// By default, ambient is the same as diffuse, if diffuse is
|
||||
// specified but ambient is not.
|
||||
mat->set_ambient(egg_mat->get_diff());
|
||||
}
|
||||
if (egg_mat->has_amb()) {
|
||||
mat->set_ambient(egg_mat->get_amb());
|
||||
}
|
||||
if (egg_mat->has_emit()) {
|
||||
mat->set_emission(egg_mat->get_emit());
|
||||
}
|
||||
if (egg_mat->has_spec()) {
|
||||
mat->set_specular(egg_mat->get_spec());
|
||||
}
|
||||
if (egg_mat->has_shininess()) {
|
||||
mat->set_shininess(egg_mat->get_shininess());
|
||||
}
|
||||
if (egg_mat->has_local()) {
|
||||
mat->set_local(egg_mat->get_local());
|
||||
}
|
||||
|
||||
mat->set_twoside(bface);
|
||||
|
||||
// Now get a global Material pointer, shared with other models.
|
||||
const Material *shared_mat = MaterialPool::get_material(mat);
|
||||
|
||||
// And create a MaterialAttrib for this Material.
|
||||
CPT(RenderAttrib) mt = MaterialAttrib::make(shared_mat);
|
||||
materials.insert(Materials::value_type(egg_mat, mt));
|
||||
|
||||
return mt;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggRenderState::get_tex_gen
|
||||
// Access: Private, Static
|
||||
// Description: Extracts the tex_gen from the given egg texture,
|
||||
// and returns its corresponding TexGenAttrib mode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TexGenAttrib::Mode EggRenderState::
|
||||
get_tex_gen(const EggTexture *egg_tex) {
|
||||
switch (egg_tex->get_tex_gen()) {
|
||||
case EggTexture::TG_unspecified:
|
||||
return TexGenAttrib::M_off;
|
||||
|
||||
case EggTexture::TG_eye_sphere_map:
|
||||
return TexGenAttrib::M_eye_sphere_map;
|
||||
|
||||
case EggTexture::TG_world_cube_map:
|
||||
return TexGenAttrib::M_world_cube_map;
|
||||
|
||||
case EggTexture::TG_eye_cube_map:
|
||||
return TexGenAttrib::M_eye_cube_map;
|
||||
|
||||
case EggTexture::TG_world_normal:
|
||||
return TexGenAttrib::M_world_normal;
|
||||
|
||||
case EggTexture::TG_eye_normal:
|
||||
return TexGenAttrib::M_eye_normal;
|
||||
|
||||
case EggTexture::TG_world_position:
|
||||
return TexGenAttrib::M_world_position;
|
||||
|
||||
case EggTexture::TG_object_position:
|
||||
return TexGenAttrib::M_object_position;
|
||||
|
||||
case EggTexture::TG_eye_position:
|
||||
return TexGenAttrib::M_eye_position;
|
||||
};
|
||||
|
||||
return TexGenAttrib::M_off;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggRenderState::apply_tex_mat
|
||||
// Access: Private, Static
|
||||
// Description: Applies the texture matrix from the indicated egg
|
||||
// texture to the given TexMatrixAttrib, and returns the
|
||||
// new attrib.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(RenderAttrib) EggRenderState::
|
||||
apply_tex_mat(CPT(RenderAttrib) tex_mat_attrib,
|
||||
TextureStage *stage, const EggTexture *egg_tex) {
|
||||
if (egg_tex->has_transform()) {
|
||||
const LMatrix3d &tex_mat = egg_tex->get_transform();
|
||||
LMatrix4f mat4(tex_mat(0, 0), tex_mat(0, 1), 0.0f, tex_mat(0, 2),
|
||||
tex_mat(1, 0), tex_mat(1, 1), 0.0f, tex_mat(1, 2),
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
tex_mat(2, 0), tex_mat(2, 1), 0.0f, tex_mat(2, 2));
|
||||
CPT(TransformState) transform;
|
||||
|
||||
LVecBase3f scale, shear, hpr, translate;
|
||||
if (decompose_matrix(mat4, scale, shear, hpr, translate)) {
|
||||
// If the texture matrix can be represented componentwise, do
|
||||
// so.
|
||||
transform = TransformState::make_pos_hpr_scale_shear
|
||||
(translate, hpr, scale, shear);
|
||||
|
||||
} else {
|
||||
// Otherwise, make a matrix transform.
|
||||
transform = TransformState::make_mat(mat4);
|
||||
}
|
||||
|
||||
if (tex_mat_attrib == (const RenderAttrib *)NULL) {
|
||||
tex_mat_attrib = TexMatrixAttrib::make();
|
||||
}
|
||||
tex_mat_attrib = DCAST(TexMatrixAttrib, tex_mat_attrib)->
|
||||
add_stage(stage, transform);
|
||||
}
|
||||
|
||||
return tex_mat_attrib;
|
||||
}
|
84
panda/src/egg2pg/eggRenderState.h
Normal file
84
panda/src/egg2pg/eggRenderState.h
Normal file
@ -0,0 +1,84 @@
|
||||
// Filename: eggRenderState.h
|
||||
// Created by: drose (12Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EGGRENDERSTATE_H
|
||||
#define EGGRENDERSTATE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "eggUserData.h"
|
||||
#include "eggLoader.h"
|
||||
#include "renderState.h"
|
||||
#include "renderAttrib.h"
|
||||
#include "internalName.h"
|
||||
#include "luse.h"
|
||||
#include "pointerTo.h"
|
||||
#include "pvector.h"
|
||||
#include "pmap.h"
|
||||
|
||||
class EggPrimitive;
|
||||
class EggTexture;
|
||||
class EggMaterial;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// Class : EggRenderState
|
||||
// Description : This class is used within this package only to record
|
||||
// the render state that should be assigned to each
|
||||
// primitive. It is assigned to EggPrimitive objects
|
||||
// via the EggBinner.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EggRenderState : public EggUserData {
|
||||
public:
|
||||
INLINE EggRenderState(EggLoader &loader);
|
||||
INLINE void add_attrib(const RenderAttrib *attrib);
|
||||
|
||||
void fill_state(EggPrimitive *egg_prim);
|
||||
|
||||
INLINE bool operator < (const EggRenderState &other) const;
|
||||
|
||||
private:
|
||||
CPT(RenderAttrib) get_material_attrib(const EggMaterial *egg_mat,
|
||||
bool bface);
|
||||
static TexGenAttrib::Mode get_tex_gen(const EggTexture *egg_tex);
|
||||
|
||||
static CPT(RenderAttrib)
|
||||
apply_tex_mat(CPT(RenderAttrib) tex_mat_attrib,
|
||||
TextureStage *stage, const EggTexture *egg_tex);
|
||||
|
||||
public:
|
||||
CPT(RenderState) _state;
|
||||
bool _hidden;
|
||||
|
||||
typedef EggLoader::BakeInUVs BakeInUVs;
|
||||
typedef EggLoader::TextureDef TextureDef;
|
||||
typedef EggLoader::Materials Materials;
|
||||
|
||||
BakeInUVs _bake_in_uvs;
|
||||
|
||||
private:
|
||||
EggLoader &_loader;
|
||||
|
||||
typedef pvector<const TextureDef *> TexMatTextures;
|
||||
typedef pmap<LMatrix3d, TexMatTextures> TexMatTransforms;
|
||||
typedef pmap<CPT(InternalName), TexMatTransforms> TexMats;
|
||||
};
|
||||
|
||||
#include "eggRenderState.I"
|
||||
|
||||
#endif
|
||||
|
@ -547,6 +547,12 @@ reset() {
|
||||
<< "max texture dimension = " << _max_texture_dimension
|
||||
<< ", max 3d texture = " << _max_3d_texture_dimension
|
||||
<< ", max cube map = " << _max_cube_map_dimension << "\n";
|
||||
GLint max_elements_vertices, max_elements_indices;
|
||||
GLP(GetIntegerv)(GL_MAX_ELEMENTS_VERTICES, &max_elements_vertices);
|
||||
GLP(GetIntegerv)(GL_MAX_ELEMENTS_INDICES, &max_elements_indices);
|
||||
GLCAT.debug()
|
||||
<< "max_elements_vertices = " << max_elements_vertices
|
||||
<< ", max_elements_indices = " << max_elements_indices << "\n";
|
||||
}
|
||||
|
||||
report_my_gl_errors();
|
||||
@ -2020,7 +2026,10 @@ bool CLP(GraphicsStateGuardian)::
|
||||
begin_draw_primitives(const qpGeomVertexData *vertex_data) {
|
||||
DO_PSTATS_STUFF(_draw_primitive_pcollector.start());
|
||||
|
||||
GraphicsStateGuardian::begin_draw_primitives(vertex_data);
|
||||
if (!GraphicsStateGuardian::begin_draw_primitives(vertex_data)) {
|
||||
return false;
|
||||
}
|
||||
nassertr(_vertex_data != (qpGeomVertexData *)NULL, false);
|
||||
|
||||
CPTA_uchar array_data;
|
||||
int num_components;
|
||||
|
@ -90,12 +90,13 @@ add_vertex(int vertex) {
|
||||
unsigned short short_vertex = vertex;
|
||||
nassertv((int)short_vertex == vertex);
|
||||
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_vertices.push_back(short_vertex);
|
||||
|
||||
if (cdata->_got_minmax) {
|
||||
cdata->_min_vertex = min(cdata->_min_vertex, short_vertex);
|
||||
cdata->_max_vertex = max(cdata->_min_vertex, short_vertex);
|
||||
cdata->_max_vertex = max(cdata->_max_vertex, short_vertex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,6 +108,7 @@ add_vertex(int vertex) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::
|
||||
add_consecutive_vertices(int start, int num_vertices) {
|
||||
clear_cache();
|
||||
int end = (start + num_vertices) - 1;
|
||||
unsigned short short_start = start;
|
||||
unsigned short short_end = end;
|
||||
@ -119,7 +121,7 @@ add_consecutive_vertices(int start, int num_vertices) {
|
||||
|
||||
if (cdata->_got_minmax) {
|
||||
cdata->_min_vertex = min(cdata->_min_vertex, short_start);
|
||||
cdata->_max_vertex = max(cdata->_min_vertex, short_end);
|
||||
cdata->_max_vertex = max(cdata->_max_vertex, short_end);
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +134,7 @@ add_consecutive_vertices(int start, int num_vertices) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::
|
||||
close_primitive() {
|
||||
clear_cache();
|
||||
int num_vertices_per_primitive = get_num_vertices_per_primitive();
|
||||
|
||||
CDWriter cdata(_cycler);
|
||||
@ -159,6 +162,7 @@ close_primitive() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::
|
||||
clear_vertices() {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_vertices.clear();
|
||||
cdata->_lengths.clear();
|
||||
@ -174,6 +178,7 @@ clear_vertices() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PTA_ushort qpGeomPrimitive::
|
||||
modify_vertices() {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
return cdata->_vertices;
|
||||
}
|
||||
@ -187,6 +192,7 @@ modify_vertices() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::
|
||||
set_vertices(PTA_ushort vertices) {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_vertices = vertices;
|
||||
}
|
||||
@ -205,6 +211,7 @@ set_vertices(PTA_ushort vertices) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PTA_int qpGeomPrimitive::
|
||||
modify_lengths() {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
return cdata->_lengths;
|
||||
}
|
||||
@ -223,6 +230,7 @@ modify_lengths() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomPrimitive::
|
||||
set_lengths(PTA_int lengths) {
|
||||
clear_cache();
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_lengths = lengths;
|
||||
}
|
||||
@ -565,7 +573,7 @@ recompute_minmax() {
|
||||
++ii;
|
||||
while (ii != cdata->_vertices.end()) {
|
||||
cdata->_min_vertex = min(cdata->_min_vertex, (*ii));
|
||||
cdata->_max_vertex = max(cdata->_min_vertex, (*ii));
|
||||
cdata->_max_vertex = max(cdata->_max_vertex, (*ii));
|
||||
|
||||
++ii;
|
||||
}
|
||||
|
@ -174,9 +174,6 @@ operator = (const qpGeomVertexArrayFormat ©) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
qpGeomVertexArrayFormat::
|
||||
~qpGeomVertexArrayFormat() {
|
||||
// Once registered, these things should not be deallocated.
|
||||
nassertv(!_is_registered);
|
||||
|
||||
DataTypes::iterator dti;
|
||||
for (dti = _data_types.begin(); dti != _data_types.end(); ++dti) {
|
||||
delete (*dti);
|
||||
|
@ -455,25 +455,61 @@ set_data(int array, const qpGeomVertexDataType *data_type,
|
||||
switch (data_type->get_numeric_type()) {
|
||||
case qpGeomVertexDataType::NT_uint8:
|
||||
{
|
||||
nassertv(num_values <= data_type->get_num_values());
|
||||
for (int i = 0; i < num_values; i++) {
|
||||
int i = 0;
|
||||
int min_values = min(num_values, data_type->get_num_values());
|
||||
while (i < min_values) {
|
||||
int value = (int)(data[i] * 255.0f);
|
||||
*(unsigned char *)&array_data[element] = value;
|
||||
array_data[element] = value;
|
||||
element += 1;
|
||||
++i;
|
||||
}
|
||||
while (i < data_type->get_num_values()) {
|
||||
array_data[element] = 0;
|
||||
element += 1;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_packed_argb:
|
||||
{
|
||||
nassertv(num_values == 4);
|
||||
*(PN_uint32 *)&array_data[element] = pack_argb(data);
|
||||
if (num_values == 4) {
|
||||
*(PN_uint32 *)&array_data[element] = pack_argb(data);
|
||||
} else {
|
||||
// Elevate (or truncate) to 4 components.
|
||||
float data4[4];
|
||||
memset(data4, 0, 4 * sizeof(float));
|
||||
memcpy(data4, data, min(4, num_values) * sizeof(float));
|
||||
*(PN_uint32 *)&array_data[element] = pack_argb(data4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_float:
|
||||
nassertv(num_values == data_type->get_num_values());
|
||||
memcpy(&array_data[element], data, data_type->get_total_bytes());
|
||||
if (num_values == 4 && sizeof(float) == sizeof(PN_float32)) {
|
||||
// The easy way: we can memcpy the data directly in.
|
||||
memcpy(&array_data[element], data, data_type->get_total_bytes());
|
||||
|
||||
} else {
|
||||
// Elevate or truncate to the right number of components.
|
||||
int i = 0;
|
||||
int min_values = min(num_values, data_type->get_num_values());
|
||||
while (i < min_values) {
|
||||
*(PN_float32 *)&array_data[element] = data[i];
|
||||
element += sizeof(PN_float32);
|
||||
++i;
|
||||
}
|
||||
while (i < data_type->get_num_values()) {
|
||||
if (i == 3 && data_type->get_num_values() == 4) {
|
||||
*(PN_float32 *)&array_data[element] = 1.0f;
|
||||
} else {
|
||||
*(PN_float32 *)&array_data[element] = 0.0f;
|
||||
}
|
||||
element += sizeof(PN_float32);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -500,25 +536,56 @@ get_data(int array, const qpGeomVertexDataType *data_type,
|
||||
switch (data_type->get_numeric_type()) {
|
||||
case qpGeomVertexDataType::NT_uint8:
|
||||
{
|
||||
nassertv(num_values <= data_type->get_num_values());
|
||||
for (int i = 0; i < num_values; i++) {
|
||||
int i = 0;
|
||||
int min_values = min(num_values, data_type->get_num_values());
|
||||
while (i < min_values) {
|
||||
int value = *(unsigned char *)&array_data[element];
|
||||
element += 1;
|
||||
data[i] = (float)value / 255.0f;
|
||||
++i;
|
||||
}
|
||||
while (i < num_values) {
|
||||
data[i] = 0.0f;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_packed_argb:
|
||||
{
|
||||
nassertv(num_values == 4);
|
||||
unpack_argb(data, *(PN_uint32 *)&array_data[element]);
|
||||
if (num_values == 4) {
|
||||
unpack_argb(data, *(PN_uint32 *)&array_data[element]);
|
||||
} else {
|
||||
float data4[4];
|
||||
unpack_argb(data4, *(PN_uint32 *)&array_data[element]);
|
||||
memset(data, 0, num_values * sizeof(float));
|
||||
memcpy(data, data4, min(num_values, 4) * sizeof(float));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case qpGeomVertexDataType::NT_float:
|
||||
nassertv(num_values <= data_type->get_num_values());
|
||||
memcpy(data, &array_data[element], num_values * sizeof(PN_float32));
|
||||
if (num_values == data_type->get_num_values() &&
|
||||
sizeof(float) == sizeof(PN_float32)) {
|
||||
memcpy(data, &array_data[element], num_values * sizeof(PN_float32));
|
||||
} else {
|
||||
int i = 0;
|
||||
int min_values = min(num_values, data_type->get_num_values());
|
||||
while (i < min_values) {
|
||||
data[i] = *(PN_float32 *)&array_data[element];
|
||||
element += sizeof(PN_float32);
|
||||
++i;
|
||||
}
|
||||
while (i < num_values) {
|
||||
if (i == 3 && num_values == 4) {
|
||||
data[i] = 1.0f;
|
||||
} else {
|
||||
data[i] = 0.0f;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -85,10 +85,6 @@ make_next() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CullResult::
|
||||
add_object(CullableObject *object) {
|
||||
// Munge vertices as needed for the GSG's requirements, and the
|
||||
// object's current state.
|
||||
object->munge_vertices(_gsg);
|
||||
|
||||
// Check to see if there's a special transparency setting.
|
||||
const RenderState *state = object->_state;
|
||||
nassertv(state != (const RenderState *)NULL);
|
||||
@ -132,6 +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);
|
||||
CullBin *bin = get_bin(transparent_part->_state->get_bin_index());
|
||||
nassertv(bin != (CullBin *)NULL);
|
||||
bin->add_object(transparent_part);
|
||||
@ -155,6 +152,10 @@ add_object(CullableObject *object) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Munge vertices as needed for the GSG's requirements, and the
|
||||
// object's current state.
|
||||
object->munge_vertices(_gsg);
|
||||
|
||||
CullBin *bin = get_bin(object->_state->get_bin_index());
|
||||
nassertv(bin != (CullBin *)NULL);
|
||||
|
@ -114,9 +114,12 @@ INLINE void CullableObject::
|
||||
munge_vertices(GraphicsStateGuardianBase *gsg) {
|
||||
// Temporary test until the experimental Geom rewrite becomes the
|
||||
// actual Geom implementation.
|
||||
if (_geom->is_exact_type(qpGeom::get_class_type())) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user