runtime: CMake-ify
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
project(runtime_blitz3d)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC
|
||||
"animation.cpp"
|
||||
"animation.hpp"
|
||||
"animator.cpp"
|
||||
"animator.hpp"
|
||||
"blitz3d.hpp"
|
||||
"brush.cpp"
|
||||
"brush.hpp"
|
||||
"cachedtexture.cpp"
|
||||
"cachedtexture.hpp"
|
||||
"camera.cpp"
|
||||
"camera.hpp"
|
||||
"collision.cpp"
|
||||
"collision.hpp"
|
||||
"entity.cpp"
|
||||
"entity.hpp"
|
||||
"frustum.cpp"
|
||||
"frustum.hpp"
|
||||
"geom.cpp"
|
||||
"geom.hpp"
|
||||
"light.cpp"
|
||||
"light.hpp"
|
||||
"listener.cpp"
|
||||
"listener.hpp"
|
||||
"loader_3ds.cpp"
|
||||
"loader_3ds.hpp"
|
||||
"loader_b3d.cpp"
|
||||
"loader_b3d.hpp"
|
||||
# "loader_x.cpp"
|
||||
# "loader_x.hpp"
|
||||
"md2model.cpp"
|
||||
"md2model.hpp"
|
||||
"md2norms.cpp"
|
||||
"md2norms.hpp"
|
||||
"md2rep.cpp"
|
||||
"md2rep.hpp"
|
||||
"meshcollider.cpp"
|
||||
"meshcollider.hpp"
|
||||
"meshloader.cpp"
|
||||
"meshloader.hpp"
|
||||
"meshmodel.cpp"
|
||||
"meshmodel.hpp"
|
||||
"meshutil.cpp"
|
||||
"meshutil.hpp"
|
||||
"mirror.cpp"
|
||||
"mirror.hpp"
|
||||
"model.cpp"
|
||||
"model.hpp"
|
||||
"object.cpp"
|
||||
"object.hpp"
|
||||
"pivot.cpp"
|
||||
"pivot.hpp"
|
||||
"planemodel.cpp"
|
||||
"planemodel.hpp"
|
||||
"q3bspmodel.cpp"
|
||||
"q3bspmodel.hpp"
|
||||
"q3bsprep.cpp"
|
||||
"q3bsprep.hpp"
|
||||
"rendercontext.hpp"
|
||||
"sprite.cpp"
|
||||
"sprite.hpp"
|
||||
"std.cpp"
|
||||
"std.hpp"
|
||||
"surface.cpp"
|
||||
"surface.hpp"
|
||||
"terrain.cpp"
|
||||
"terrain.hpp"
|
||||
"terrainrep.cpp"
|
||||
"terrainrep.hpp"
|
||||
"texture.cpp"
|
||||
"texture.hpp"
|
||||
"world.cpp"
|
||||
"world.hpp"
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
config
|
||||
gxruntime
|
||||
stdutil
|
||||
PUBLIC
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC ${PROJECT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
target_compile_definitions(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
# windows.h
|
||||
WIN32_LEAN_AND_MEAN
|
||||
NOGPICAPMASKS
|
||||
NOVIRTUALKEYCODES
|
||||
NOWINMESSAGES
|
||||
NOWINSTYLES
|
||||
NOSYSMETRICS
|
||||
NOMENUS
|
||||
NOICONS
|
||||
NOKEYSTATES
|
||||
NOSYSCOMMANDS
|
||||
NORASTEROPS
|
||||
NOSHOWWINDOW
|
||||
NOATOM
|
||||
NOCLIPBOARD
|
||||
NOCOLOR
|
||||
NOCTLMGR
|
||||
NODRAWTEXT
|
||||
#NOGDI
|
||||
NOKERNEL
|
||||
#NOUSER
|
||||
NONLS
|
||||
NOMB
|
||||
NOMEMMGR
|
||||
NOMETAFILE
|
||||
NOMINMAX
|
||||
#NOMSG
|
||||
NOOPENFILE
|
||||
NOSCROLL
|
||||
NOSERVICE
|
||||
NOSOUND
|
||||
NOTEXTMETRIC
|
||||
NOWH
|
||||
NOWINOFFSETS
|
||||
NOCOMM
|
||||
NOKANJI
|
||||
NOHELP
|
||||
NOPROFILER
|
||||
NODEFERWINDOWPOS
|
||||
NOMCX
|
||||
NOIME
|
||||
NOMDI
|
||||
NOINOUT
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,288 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "animation.hpp"
|
||||
|
||||
struct Animation::Rep{
|
||||
|
||||
int ref_cnt;
|
||||
|
||||
typedef map<int,Quat> KeyList;
|
||||
|
||||
KeyList scale_anim,rot_anim,pos_anim;
|
||||
|
||||
Rep():
|
||||
ref_cnt(1){
|
||||
}
|
||||
|
||||
Rep( const Rep &t ):
|
||||
ref_cnt(1),
|
||||
scale_anim(t.scale_anim),rot_anim(t.rot_anim),pos_anim(t.pos_anim){
|
||||
}
|
||||
|
||||
Vector getLinearValue( const KeyList &keys,float time )const{
|
||||
KeyList::const_iterator next,curr;
|
||||
|
||||
//for( next=keys.begin();next!=keys.end() && time>=next->first;++next ){}
|
||||
next=keys.upper_bound( (int)time );
|
||||
|
||||
if( next==keys.begin() ) return next->second.v;
|
||||
curr=next;--curr;
|
||||
if( next==keys.end() ) return curr->second.v;
|
||||
|
||||
float delta=( time-curr->first )/( next->first-curr->first );
|
||||
return ( next->second.v-curr->second.v )*delta+curr->second.v;
|
||||
}
|
||||
|
||||
Quat getSlerpValue( const KeyList &keys,float time )const{
|
||||
KeyList::const_iterator next,curr;
|
||||
|
||||
//for( next=keys.begin();next!=keys.end() && time>=next->first;++next ){}
|
||||
next=keys.upper_bound( (int)time );
|
||||
|
||||
if( next==keys.begin() ) return next->second;
|
||||
curr=next;--curr;
|
||||
if( next==keys.end() ) return curr->second;
|
||||
|
||||
float delta=( time-curr->first )/( next->first-curr->first );
|
||||
return curr->second.slerpTo( next->second,delta );
|
||||
}
|
||||
|
||||
void setKey( KeyList &keys,int time,const Quat &value ){
|
||||
keys[time]=value;
|
||||
}
|
||||
};
|
||||
|
||||
Animation::Animation():
|
||||
rep( new Rep() ){
|
||||
}
|
||||
|
||||
Animation::Animation( const Animation &t ):
|
||||
rep( t.rep ){
|
||||
++rep->ref_cnt;
|
||||
}
|
||||
|
||||
Animation::Animation( const Animation &t,int first,int last ):
|
||||
rep( new Rep() ){
|
||||
Rep::KeyList::const_iterator it;
|
||||
for( it=t.rep->pos_anim.begin();it!=t.rep->pos_anim.end();++it ){
|
||||
if( it->first<first || it->first>last ) continue;
|
||||
rep->setKey( rep->pos_anim,it->first-first,it->second );
|
||||
}
|
||||
for( it=t.rep->scale_anim.begin();it!=t.rep->scale_anim.end();++it ){
|
||||
if( it->first<first || it->first>last ) continue;
|
||||
rep->setKey( rep->scale_anim,it->first-first,it->second );
|
||||
}
|
||||
for( it=t.rep->rot_anim.begin();it!=t.rep->rot_anim.end();++it ){
|
||||
if( it->first<first || it->first>last ) continue;
|
||||
rep->setKey( rep->rot_anim,it->first-first,it->second );
|
||||
}
|
||||
}
|
||||
|
||||
Animation::~Animation(){
|
||||
if( !--rep->ref_cnt ) delete rep;
|
||||
}
|
||||
|
||||
Animation &Animation::operator=( const Animation &t ){
|
||||
++t.rep->ref_cnt;
|
||||
if( !--rep->ref_cnt ) delete rep;
|
||||
rep=t.rep;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Animation::Rep *Animation::write(){
|
||||
if( rep->ref_cnt>1 ){
|
||||
--rep->ref_cnt;
|
||||
rep=new Rep( *rep );
|
||||
}
|
||||
return rep;
|
||||
}
|
||||
|
||||
void Animation::setScaleKey( int time,const Vector &q ){
|
||||
write();
|
||||
rep->setKey( rep->scale_anim,time,Quat( 0,q ) );
|
||||
}
|
||||
|
||||
void Animation::setPositionKey( int time,const Vector &q ){
|
||||
write();
|
||||
rep->setKey( rep->pos_anim,time,Quat( 0,q ) );
|
||||
}
|
||||
|
||||
void Animation::setRotationKey( int time,const Quat &q ){
|
||||
write();
|
||||
rep->setKey( rep->rot_anim,time,q );
|
||||
}
|
||||
|
||||
int Animation::numScaleKeys()const{
|
||||
return rep->scale_anim.size();
|
||||
}
|
||||
|
||||
int Animation::numRotationKeys()const{
|
||||
return rep->rot_anim.size();
|
||||
}
|
||||
|
||||
int Animation::numPositionKeys()const{
|
||||
return rep->pos_anim.size();
|
||||
}
|
||||
|
||||
Vector Animation::getScale( float time )const{
|
||||
if( !rep->scale_anim.size() ) return Vector(1,1,1);
|
||||
return rep->getLinearValue( rep->scale_anim,time );
|
||||
}
|
||||
|
||||
Vector Animation::getPosition( float time )const{
|
||||
if( !rep->pos_anim.size() ) return Vector(0,0,0);
|
||||
return rep->getLinearValue( rep->pos_anim,time );
|
||||
}
|
||||
|
||||
Quat Animation::getRotation( float time )const{
|
||||
if( !rep->rot_anim.size() ) return Quat();
|
||||
return rep->getSlerpValue( rep->rot_anim,time );
|
||||
}
|
||||
|
||||
/*
|
||||
struct Animation::Rep{
|
||||
|
||||
int ref_cnt;
|
||||
|
||||
struct Key{
|
||||
int time;
|
||||
Quat value;
|
||||
};
|
||||
typedef list<Key> KeyList;
|
||||
|
||||
KeyList scale_anim,rot_anim,pos_anim;
|
||||
|
||||
Rep():
|
||||
ref_cnt(1){
|
||||
}
|
||||
|
||||
Rep( const Rep &t ):
|
||||
ref_cnt(1),
|
||||
scale_anim(t.scale_anim),rot_anim(t.rot_anim),pos_anim(t.pos_anim){
|
||||
}
|
||||
|
||||
Vector getLinearValue( const KeyList &keys,float time )const{
|
||||
if( keys.size()==1 ) return keys.front().value.v;
|
||||
if( time>=keys.back().time ) return keys.back().value.v;
|
||||
if( time<=keys.front().time ) return keys.front().value.v;
|
||||
KeyList::const_iterator it;
|
||||
for( it=keys.begin();time>=it->time;++it ){}
|
||||
const Key *next=&*it;
|
||||
const Key *curr=&*--it;
|
||||
float delta=( time-curr->time )/( next->time-curr->time );
|
||||
return (next->value.v-curr->value.v)*delta+curr->value.v;
|
||||
}
|
||||
|
||||
Quat getSlerpValue( const KeyList &keys,float time )const{
|
||||
if( keys.size()==1 ) return keys.front().value;
|
||||
if( time>=keys.back().time ) return keys.back().value;
|
||||
if( time<=keys.front().time ) return keys.front().value;
|
||||
KeyList::const_iterator it;
|
||||
for( it=keys.begin();time>=it->time;++it ){}
|
||||
const Key *next=&*it;
|
||||
const Key *curr=&*--it;
|
||||
float delta=(time-curr->time)/(next->time-curr->time);
|
||||
return curr->value.slerpTo( next->value,delta );
|
||||
}
|
||||
|
||||
void setKey( KeyList &keys,int time,const Quat &value ){
|
||||
KeyList::iterator it;
|
||||
for( it=keys.begin();it!=keys.end() && time>it->time;++it ){}
|
||||
if( it==keys.end() || time<it->time ){
|
||||
it=keys.insert( it );
|
||||
it->time=time;
|
||||
}
|
||||
it->value=value;
|
||||
}
|
||||
};
|
||||
|
||||
Animation::Animation():
|
||||
rep( new Rep() ){
|
||||
}
|
||||
|
||||
Animation::Animation( const Animation &t ):
|
||||
rep( t.rep ){
|
||||
++rep->ref_cnt;
|
||||
}
|
||||
|
||||
Animation::Animation( const Animation &t,int first,int last ):
|
||||
rep( new Rep() ){
|
||||
Rep::KeyList::const_iterator it;
|
||||
for( it=t.rep->pos_anim.begin();it!=t.rep->pos_anim.end();++it ){
|
||||
const Rep::Key &key=*it;
|
||||
if( key.time<first || key.time>last ) continue;
|
||||
rep->setKey( rep->pos_anim,key.time-first,key.value );
|
||||
}
|
||||
for( it=t.rep->scale_anim.begin();it!=t.rep->scale_anim.end();++it ){
|
||||
const Rep::Key &key=*it;
|
||||
if( key.time<first || key.time>last ) continue;
|
||||
rep->setKey( rep->scale_anim,key.time-first,key.value );
|
||||
}
|
||||
for( it=t.rep->rot_anim.begin();it!=t.rep->rot_anim.end();++it ){
|
||||
const Rep::Key &key=*it;
|
||||
if( key.time<first || key.time>last ) continue;
|
||||
rep->setKey( rep->rot_anim,key.time-first,key.value );
|
||||
}
|
||||
}
|
||||
|
||||
Animation::~Animation(){
|
||||
if( !--rep->ref_cnt ) delete rep;
|
||||
}
|
||||
|
||||
Animation &Animation::operator=( const Animation &t ){
|
||||
++t.rep->ref_cnt;
|
||||
if( !--rep->ref_cnt ) delete rep;
|
||||
rep=t.rep;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Animation::Rep *Animation::write(){
|
||||
if( rep->ref_cnt>1 ){
|
||||
--rep->ref_cnt;
|
||||
rep=new Rep( *rep );
|
||||
}
|
||||
return rep;
|
||||
}
|
||||
|
||||
void Animation::setScaleKey( int time,const Vector &q ){
|
||||
write();
|
||||
rep->setKey( rep->scale_anim,time,Quat( 0,q ) );
|
||||
}
|
||||
|
||||
void Animation::setPositionKey( int time,const Vector &q ){
|
||||
write();
|
||||
rep->setKey( rep->pos_anim,time,Quat( 0,q ) );
|
||||
}
|
||||
|
||||
void Animation::setRotationKey( int time,const Quat &q ){
|
||||
write();
|
||||
rep->setKey( rep->rot_anim,time,q );
|
||||
}
|
||||
|
||||
int Animation::numScaleKeys()const{
|
||||
return rep->scale_anim.size();
|
||||
}
|
||||
|
||||
int Animation::numRotationKeys()const{
|
||||
return rep->rot_anim.size();
|
||||
}
|
||||
|
||||
int Animation::numPositionKeys()const{
|
||||
return rep->pos_anim.size();
|
||||
}
|
||||
|
||||
Vector Animation::getScale( float time )const{
|
||||
if( !rep->scale_anim.size() ) return Vector(1,1,1);
|
||||
return rep->getLinearValue( rep->scale_anim,time );
|
||||
}
|
||||
|
||||
Vector Animation::getPosition( float time )const{
|
||||
if( !rep->pos_anim.size() ) return Vector(0,0,0);
|
||||
return rep->getLinearValue( rep->pos_anim,time );
|
||||
}
|
||||
|
||||
Quat Animation::getRotation( float time )const{
|
||||
if( !rep->rot_anim.size() ) return Quat();
|
||||
return rep->getSlerpValue( rep->rot_anim,time );
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
#ifndef ANIMATION_H
|
||||
#define ANIMATION_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "geom.hpp"
|
||||
|
||||
class Animation{
|
||||
public:
|
||||
Animation();
|
||||
Animation( const Animation &t );
|
||||
Animation( const Animation &t,int first,int last );
|
||||
~Animation();
|
||||
|
||||
Animation &operator=( const Animation &t );
|
||||
|
||||
void setScaleKey( int frame,const Vector &q );
|
||||
void setPositionKey( int frame,const Vector &p );
|
||||
void setRotationKey( int frame,const Quat &q );
|
||||
|
||||
int numScaleKeys()const;
|
||||
int numRotationKeys()const;
|
||||
int numPositionKeys()const;
|
||||
|
||||
Vector getScale( float time )const;
|
||||
Vector getPosition( float time )const;
|
||||
Quat getRotation( float time )const;
|
||||
|
||||
private:
|
||||
struct Rep;
|
||||
Rep *rep;
|
||||
|
||||
Rep *write();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,218 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "animator.hpp"
|
||||
#include "object.hpp"
|
||||
|
||||
Animator::Animator( Animator *t ):_seqs( t->_seqs ){
|
||||
|
||||
_objs.resize( t->_objs.size() );
|
||||
_anims.resize( t->_anims.size() );
|
||||
|
||||
for( int k=0;k<t->_objs.size();++k ){
|
||||
_objs[k]=t->_objs[k]->getLastCopy();
|
||||
_anims[k].keys=t->_anims[k].keys;
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
Animator::Animator( Object *obj,int frames ){
|
||||
addObjs( obj );
|
||||
_anims.resize( _objs.size() );
|
||||
addSeq( frames );
|
||||
reset();
|
||||
}
|
||||
|
||||
Animator::Animator( const vector<Object*> &objs,int frames ):_objs(objs){
|
||||
_anims.resize( _objs.size() );
|
||||
addSeq( frames );
|
||||
reset();
|
||||
}
|
||||
|
||||
void Animator::reset(){
|
||||
_seq=_mode=_seq_len=_time=_speed=_trans_time=_trans_speed=0;
|
||||
}
|
||||
|
||||
void Animator::addObjs( Object *obj ){
|
||||
_objs.push_back( obj );
|
||||
for( Entity *e=obj->GetChildren();e;e=e->GetSuccessor() ){
|
||||
addObjs( e->getObject() );
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::addSeq( int frames ){
|
||||
Seq seq;
|
||||
seq.frames=frames;
|
||||
_seqs.push_back( seq );
|
||||
for( int k=0;k<_objs.size();++k ){
|
||||
Object *obj=_objs[k];
|
||||
_anims[k].keys.push_back( obj->getAnimation() );
|
||||
obj->setAnimation( Animation() );
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::addSeqs( Animator *t ){
|
||||
for( int n=0;n<t->_seqs.size();++n ){
|
||||
_seqs.push_back( t->_seqs[n] );
|
||||
for( int k=0;k<_objs.size();++k ){
|
||||
int j;
|
||||
for( j=0;j<t->_objs.size();++j ){
|
||||
if( _objs[k]->getName()==t->_objs[j]->getName() ) break;
|
||||
}
|
||||
if( j==t->_objs.size() ){
|
||||
_anims[k].keys.push_back( Animation() );
|
||||
continue;
|
||||
}
|
||||
_anims[k].keys.push_back( t->_anims[j].keys[n] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::extractSeq( int first,int last,int seq ){
|
||||
Seq sq;
|
||||
sq.frames=last-first;
|
||||
_seqs.push_back( sq );
|
||||
|
||||
for( int k=0;k<_objs.size();++k ){
|
||||
Animation &keys=_anims[k].keys[seq];
|
||||
_anims[k].keys.push_back( Animation( keys,first,last ) );
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::updateAnim(){
|
||||
|
||||
for( int k=0;k<_objs.size();++k ){
|
||||
|
||||
Object *obj=_objs[k];
|
||||
const Animation &keys=_anims[k].keys[_seq];
|
||||
|
||||
if( keys.numPositionKeys() ){
|
||||
obj->SetLocalPosition( keys.getPosition( _time ) );
|
||||
}
|
||||
if( keys.numScaleKeys() ){
|
||||
obj->SetLocalScale( keys.getScale( _time ) );
|
||||
}
|
||||
if( keys.numRotationKeys() ){
|
||||
obj->SetLocalRotation( keys.getRotation( _time ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::updateTrans(){
|
||||
|
||||
for( int k=0;k<_objs.size();++k ){
|
||||
|
||||
Object *obj=_objs[k];
|
||||
const Anim &anim=_anims[k];
|
||||
|
||||
if( anim.pos ) obj->SetLocalPosition( (anim.dest_pos-anim.src_pos)*_trans_time+anim.src_pos );
|
||||
if( anim.scl ) obj->SetLocalScale( (anim.dest_scl-anim.src_scl)*_trans_time+anim.src_scl );
|
||||
if( anim.rot ) obj->SetLocalRotation( anim.src_rot.slerpTo( anim.dest_rot,_trans_time ) );
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::beginTrans(){
|
||||
|
||||
for( int k=0;k<_objs.size();++k ){
|
||||
|
||||
Object *obj=_objs[k];
|
||||
Anim &anim=_anims[k];
|
||||
const Animation &keys=_anims[k].keys[_seq];
|
||||
|
||||
if( anim.pos=!!keys.numPositionKeys() ){
|
||||
anim.src_pos=obj->GetLocalPosition();
|
||||
anim.dest_pos=keys.getPosition( _time );
|
||||
}
|
||||
if( anim.scl=!!keys.numScaleKeys() ){
|
||||
anim.src_scl=obj->GetLocalScale();
|
||||
anim.dest_scl=keys.getScale( _time );
|
||||
}
|
||||
if( anim.rot=!!keys.numRotationKeys() ){
|
||||
anim.src_rot=obj->GetLocalRotation();
|
||||
anim.dest_rot=keys.getRotation( _time );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::setAnimTime( float time,int seq ){
|
||||
if( seq<0 || seq>_seqs.size() ) return;
|
||||
|
||||
_mode=0;
|
||||
_speed=0;
|
||||
_seq=seq;
|
||||
_seq_len=_seqs[_seq].frames;
|
||||
|
||||
//Ok, mod the anim time!
|
||||
_time=fmod( time,_seq_len );
|
||||
|
||||
//if( time<0 || time>_seq_len ) time=fmod( time,_seq_len );
|
||||
//_time=time;
|
||||
|
||||
if( _time<0 ) _time+=+_seq_len;
|
||||
|
||||
updateAnim();
|
||||
}
|
||||
|
||||
void Animator::animate( int mode,float speed,int seq,float trans ){
|
||||
if( !mode && !speed ){ _mode=0;return; }
|
||||
|
||||
if( seq<0 || seq>=_seqs.size() ) return;
|
||||
|
||||
_seq=seq;
|
||||
_mode=mode;
|
||||
_seq_len=_seqs[_seq].frames;
|
||||
_speed=speed;
|
||||
_time=_speed>=0 ? 0 : _seq_len;
|
||||
|
||||
if( trans<=0 ){
|
||||
updateAnim();
|
||||
if( !_speed ) _mode=0;
|
||||
return;
|
||||
}
|
||||
|
||||
_mode|=0x8000;
|
||||
_trans_time=0;
|
||||
_trans_speed=1/trans;
|
||||
beginTrans();
|
||||
}
|
||||
|
||||
void Animator::update( float elapsed ){
|
||||
|
||||
if( !_mode ) return;
|
||||
|
||||
if( _mode&0x8000 ){
|
||||
_trans_time+=_trans_speed*elapsed;
|
||||
if( _trans_time<1 ){
|
||||
updateTrans();
|
||||
return;
|
||||
}
|
||||
_mode&=0x7fff;
|
||||
if( !_mode || !_speed ){
|
||||
updateAnim();
|
||||
_mode=0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//do anim...
|
||||
_time+=_speed*elapsed;
|
||||
|
||||
switch( _mode ){
|
||||
case ANIM_MODE_LOOP:
|
||||
_time=fmod( _time,_seq_len );
|
||||
if( _time<0 ) _time+=_seq_len;
|
||||
break;
|
||||
case ANIM_MODE_PINGPONG:
|
||||
_time=fmod( _time,_seq_len*2 );
|
||||
if( _time<0 ) _time+=_seq_len*2;
|
||||
if( _time>=_seq_len ){ _time=_seq_len-(_time-_seq_len);_speed=-_speed; }
|
||||
break;
|
||||
case ANIM_MODE_ONESHOT:
|
||||
if( _time<0 ){ _time=0;_mode=0; }
|
||||
else if( _time>=_seq_len ){ _time=_seq_len;_mode=0; }
|
||||
break;
|
||||
}
|
||||
|
||||
updateAnim();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
#ifndef ANIMATOR_H
|
||||
#define ANIMATOR_H
|
||||
|
||||
#include "animation.hpp"
|
||||
|
||||
class Object;
|
||||
|
||||
class Animator{
|
||||
public:
|
||||
enum{
|
||||
ANIM_MODE_LOOP=1,
|
||||
ANIM_MODE_PINGPONG=2,
|
||||
ANIM_MODE_ONESHOT=3
|
||||
};
|
||||
|
||||
Animator( Animator *animator );
|
||||
|
||||
Animator( Object *tree,int frames );
|
||||
|
||||
Animator( const vector<Object*> &objs,int frames );
|
||||
|
||||
void addSeq( int frames );
|
||||
|
||||
void addSeqs( Animator *t );
|
||||
|
||||
void extractSeq( int first,int last,int seq );
|
||||
|
||||
void setAnimTime( float time,int seq );
|
||||
|
||||
void animate( int mode,float speed,int seq,float trans );
|
||||
|
||||
void update( float elapsed );
|
||||
|
||||
int animSeq()const{ return _seq; }
|
||||
int animLen()const{ return _seq_len; }
|
||||
float animTime()const{ return _time; }
|
||||
bool animating()const{ return !!_mode; }
|
||||
|
||||
int numSeqs()const{ return _seqs.size(); }
|
||||
const vector<Object*> &getObjects()const{ return _objs; }
|
||||
|
||||
private:
|
||||
struct Seq{
|
||||
int frames;
|
||||
};
|
||||
|
||||
struct Anim{
|
||||
//anim keys
|
||||
vector<Animation> keys;
|
||||
//for transitions...
|
||||
bool pos,scl,rot;
|
||||
Vector src_pos,dest_pos;
|
||||
Vector src_scl,dest_scl;
|
||||
Quat src_rot,dest_rot;
|
||||
Anim():pos(false),scl(false),rot(false){}
|
||||
};
|
||||
|
||||
vector<Seq> _seqs;
|
||||
|
||||
vector<Anim> _anims;
|
||||
vector<Object*> _objs;
|
||||
|
||||
int _seq,_mode,_seq_len;
|
||||
float _time,_speed,_trans_time,_trans_speed;
|
||||
|
||||
void reset();
|
||||
void addObjs( Object *obj );
|
||||
void updateAnim();
|
||||
void beginTrans();
|
||||
void updateTrans();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
#include "bd2model.hpp"
|
||||
|
||||
struct BD2Vert{
|
||||
unsigned char x,y,z,n,u,v;
|
||||
};
|
||||
|
||||
struct BD2Tri{
|
||||
unsigned short v0,v1,v2;
|
||||
};
|
||||
|
||||
struct BD2Frame{
|
||||
float x_scale,y_scale,z_scale;
|
||||
float x_offset,y_offset,z_offset;
|
||||
BD2Vert verts[1];
|
||||
};
|
||||
|
||||
struct BD2File{
|
||||
int id; //'BD2F'
|
||||
float u_scale,v_scale;
|
||||
int n_verts,n_tris,n_frames;
|
||||
BD2Tri tris[1];
|
||||
BD2Frame frames[1];
|
||||
};
|
||||
|
||||
struct BD2Model::Rep{
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
#ifndef BD2MODEL_H
|
||||
#define BD2MODEL_H
|
||||
|
||||
class BD2Model : public Model{
|
||||
public:
|
||||
private:
|
||||
struct Rep;
|
||||
Rep *rep;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
#ifndef BLITZ3D_H
|
||||
#define BLITZ3D_H
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "world.hpp"
|
||||
#include <cfloat>
|
||||
|
||||
static World *w;
|
||||
|
||||
struct Face{
|
||||
Vector verts[4];
|
||||
|
||||
Face( const Vector &v0,const Vector &v1,const Vector &v2,const Vector &v3 ){
|
||||
verts[0]=v0;
|
||||
verts[1]=v1;
|
||||
verts[2]=v2;
|
||||
verts[3]=v3;
|
||||
}
|
||||
};
|
||||
|
||||
static int face_verts[][4]={
|
||||
2,3,1,0,
|
||||
3,7,5,1,
|
||||
7,6,4,5,
|
||||
6,2,0,4,
|
||||
6,7,3,2,
|
||||
0,1,5,4
|
||||
};
|
||||
|
||||
struct Coll{
|
||||
int obj,surf,tri;
|
||||
Coll( const ObjCollision &t ):obj((int)t.with),surf((int)t.collision.surface),tri(t.collision.index){
|
||||
}
|
||||
};
|
||||
|
||||
struct CollCmp{
|
||||
bool operator()( const Coll &a,const Coll &b )const{
|
||||
if( a.obj<b.obj ) return true;
|
||||
if( b.obj<a.obj ) return false;
|
||||
if( a.surf<b.surf ) return true;
|
||||
if( b.surf<a.surf ) return false;
|
||||
if( a.tri<b.tri ) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef set<Coll,CollCmp> CollSet;
|
||||
|
||||
//returns: 1 for visible, 0 for hidden, -1 for don't know
|
||||
static int faceVis( const Face &src,const Face &dest ){
|
||||
|
||||
static CollSet all;
|
||||
static CollSet colls[16];
|
||||
|
||||
all.clear();
|
||||
|
||||
for( int k=0;k<4;++k ){
|
||||
for( int j=0;j<4;++j ){
|
||||
int n=k*4+j;
|
||||
colls[n].clear();
|
||||
|
||||
Vector sv=src.verts[k];
|
||||
Vector dv=dest.verts[j];
|
||||
Vector adj=(dv-sv).normalized()*.01f;
|
||||
dv-=adj;
|
||||
|
||||
for(;;){
|
||||
sv+=adj;
|
||||
Line line( sv,dv-sv );
|
||||
|
||||
ObjCollision c;
|
||||
if( !w->traceRay( line,EPSILON,&c ) ) break;
|
||||
|
||||
Coll t( c );
|
||||
all.insert( t );
|
||||
colls[n].insert( t );
|
||||
|
||||
sv=c.coords;
|
||||
}
|
||||
if( !colls[n].size() ) return 1;
|
||||
}
|
||||
}
|
||||
CollSet::const_iterator it;
|
||||
for( it=all.begin();it!=all.end();++it ){
|
||||
int k=0;
|
||||
for( ;k<16;++k ){
|
||||
if( !colls[k].count( *it ) ) break;
|
||||
}
|
||||
if( k==16 ) return 0; //definitely hidden!
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void subdivide( list<Face> &lst ){
|
||||
int n=lst.size();
|
||||
while( n-- ){
|
||||
const Face &f=lst.front();
|
||||
Vector a( (f.verts[0]+f.verts[1])/2 );
|
||||
Vector b( (f.verts[1]+f.verts[2])/2 );
|
||||
Vector c( (f.verts[2]+f.verts[3])/2 );
|
||||
Vector d( (f.verts[3]+f.verts[0])/2 );
|
||||
Vector e( (f.verts[0]+f.verts[1]+f.verts[2]+f.verts[3])/4 );
|
||||
lst.push_back( Face( f.verts[0],a,e,d ) );
|
||||
lst.push_back( Face( a,f.verts[1],b,e ) );
|
||||
lst.push_back( Face( e,b,f.verts[2],c ) );
|
||||
lst.push_back( Face( d,e,c,f.verts[3] ) );
|
||||
lst.erase( lst.begin() );
|
||||
}
|
||||
}
|
||||
|
||||
static int faceVis( const Face &src,const Face &dest,int recurs_limit ){
|
||||
|
||||
static list<Face> src_faces,dest_faces;
|
||||
|
||||
src_faces.clear();
|
||||
dest_faces.clear();
|
||||
|
||||
src_faces.push_back( src );
|
||||
dest_faces.push_back( dest );
|
||||
|
||||
while( recurs_limit-- ){
|
||||
list<Face>::iterator src_it,dest_it;
|
||||
for( src_it=src_faces.begin();src_it!=src_faces.end();++src_it ){
|
||||
int cnt=0;
|
||||
for( dest_it=dest_faces.begin();dest_it!=dest_faces.end();++dest_it ){
|
||||
int n=faceVis( *src_it,*dest_it );
|
||||
if( n==1 ) return 1;
|
||||
if( !n ) ++cnt;
|
||||
}
|
||||
if( cnt==dest_faces.size() ){
|
||||
//source can't see ANY dest faces
|
||||
src_it=src_faces.erase( src_it );
|
||||
--src_it;
|
||||
}
|
||||
}
|
||||
if( !src_faces.size() ) return 0;
|
||||
//ok, subdivide!
|
||||
subdivide( src_faces );
|
||||
subdivide( dest_faces );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool World::boxVis( const Box &src,const Box &dest,int recurs_limit ){
|
||||
|
||||
w=this;
|
||||
|
||||
Box big;
|
||||
|
||||
big.update( src );
|
||||
big.update( dest );
|
||||
|
||||
Plane planes[6];
|
||||
|
||||
for( int n=0;n<6;++n ){
|
||||
planes[n]=Plane(
|
||||
big.corner( face_verts[n][0] ),
|
||||
big.corner( face_verts[n][1] ),
|
||||
big.corner( face_verts[n][2] ));
|
||||
}
|
||||
|
||||
for( int k=0;k<6;++k ){
|
||||
Vector v0=src.corner( face_verts[k][0] );
|
||||
Vector v1=src.corner( face_verts[k][1] );
|
||||
Vector v2=src.corner( face_verts[k][2] );
|
||||
Vector v3=src.corner( face_verts[k][3] );
|
||||
|
||||
int n;
|
||||
for( n=0;n<6;++n ){
|
||||
const Plane &p=planes[n];
|
||||
if( fabs(p.distance(v0))<=EPSILON &&
|
||||
fabs(p.distance(v1))<=EPSILON &&
|
||||
fabs(p.distance(v2))<=EPSILON &&
|
||||
fabs(p.distance(v3))<=EPSILON ) break;
|
||||
}
|
||||
if( n<6 ) continue;
|
||||
|
||||
Face src_face( v0,v1,v2,v3 );
|
||||
|
||||
for( int j=0;j<6;++j ){
|
||||
Vector v0=dest.corner( face_verts[j][0] );
|
||||
Vector v1=dest.corner( face_verts[j][1] );
|
||||
Vector v2=dest.corner( face_verts[j][2] );
|
||||
Vector v3=dest.corner( face_verts[j][3] );
|
||||
|
||||
int n;
|
||||
for( n=0;n<6;++n ){
|
||||
const Plane &p=planes[n];
|
||||
if( fabs(p.distance(v0))<=EPSILON &&
|
||||
fabs(p.distance(v1))<=EPSILON &&
|
||||
fabs(p.distance(v2))<=EPSILON &&
|
||||
fabs(p.distance(v3))<=EPSILON ) break;
|
||||
}
|
||||
if( n<6 ) continue;
|
||||
|
||||
Face dest_face( v0,v1,v2,v3 );
|
||||
|
||||
int t=faceVis( src_face,dest_face,recurs_limit );
|
||||
|
||||
if( t ) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "brush.hpp"
|
||||
|
||||
#include "../gxruntime/gxgraphics.hpp"
|
||||
|
||||
struct Brush::Rep{
|
||||
union{ int ref_cnt;Rep *next; };
|
||||
int blend,max_tex;
|
||||
bool blend_valid;
|
||||
gxScene::RenderState rs;
|
||||
Texture texs[gxScene::MAX_TEXTURES];
|
||||
|
||||
static Rep *pool;
|
||||
|
||||
Rep():
|
||||
ref_cnt(1),blend(0),max_tex(0),blend_valid(true){
|
||||
memset( &rs,0,sizeof(rs) );
|
||||
rs.blend=gxScene::BLEND_REPLACE;
|
||||
rs.color[0]=rs.color[1]=rs.color[2]=rs.alpha=1;
|
||||
}
|
||||
|
||||
Rep( const Rep &t ):
|
||||
ref_cnt(1),blend(t.blend),max_tex(t.max_tex),rs(t.rs),blend_valid(t.blend_valid){
|
||||
for( int k=0;k<max_tex;++k ) texs[k]=t.texs[k];
|
||||
}
|
||||
|
||||
void *operator new( size_t sz ){
|
||||
static const int GROW=64;
|
||||
if( !pool ){
|
||||
pool=new Rep[GROW];
|
||||
for( int k=0;k<GROW-1;++k ) pool[k].next=&pool[k+1];
|
||||
pool[GROW-1].next=0;
|
||||
}
|
||||
Rep *p=pool;
|
||||
pool=p->next;
|
||||
return p;
|
||||
}
|
||||
|
||||
void operator delete( void *q ){
|
||||
Rep *p=(Rep*)q;
|
||||
p->next=pool;
|
||||
pool=p;
|
||||
}
|
||||
};
|
||||
|
||||
Brush::Rep *Brush::Rep::pool;
|
||||
|
||||
Brush::Brush():
|
||||
rep( new Rep() ){
|
||||
}
|
||||
|
||||
Brush::Brush( const Brush &t ):
|
||||
rep( t.rep ){
|
||||
++rep->ref_cnt;
|
||||
}
|
||||
|
||||
Brush::Brush( const Brush &a,const Brush &b ):
|
||||
rep( new Rep( *a.rep ) ){
|
||||
|
||||
*(Vector*)rep->rs.color*=*(Vector*)b.rep->rs.color;
|
||||
|
||||
rep->rs.alpha*=b.rep->rs.alpha;
|
||||
rep->rs.shininess+=b.rep->rs.shininess;
|
||||
|
||||
if( b.rep->blend ) rep->blend=b.rep->blend;
|
||||
|
||||
rep->rs.fx|=b.rep->rs.fx;
|
||||
|
||||
if( b.rep->max_tex>rep->max_tex ) rep->max_tex=b.rep->max_tex;
|
||||
|
||||
for( int k=0;k<rep->max_tex;++k ){
|
||||
if( b.rep->rs.tex_states[k].canvas ){
|
||||
rep->rs.tex_states[k].canvas=b.rep->rs.tex_states[k].canvas;
|
||||
rep->texs[k]=b.rep->texs[k];
|
||||
}
|
||||
}
|
||||
|
||||
rep->blend_valid=false;
|
||||
}
|
||||
|
||||
Brush::~Brush(){
|
||||
if( !--rep->ref_cnt ) delete rep;
|
||||
}
|
||||
|
||||
Brush &Brush::operator=( const Brush &t ){
|
||||
++t.rep->ref_cnt;
|
||||
if( !--rep->ref_cnt ) delete rep;
|
||||
rep=t.rep;return *this;
|
||||
}
|
||||
|
||||
Brush::Rep *Brush::write()const{
|
||||
if( rep->ref_cnt>1 ){
|
||||
--rep->ref_cnt;
|
||||
rep=new Rep( *rep );
|
||||
}
|
||||
return rep;
|
||||
}
|
||||
|
||||
void Brush::setColor( const Vector &color ){
|
||||
*(Vector*)write()->rs.color=color;
|
||||
}
|
||||
|
||||
void Brush::setAlpha( float alpha ){
|
||||
float a=rep->rs.alpha;
|
||||
write()->rs.alpha=alpha;
|
||||
if( (a<1)!=(alpha<1) ) rep->blend_valid=false;
|
||||
}
|
||||
|
||||
void Brush::setShininess( float n ){
|
||||
write()->rs.shininess=n;
|
||||
}
|
||||
|
||||
void Brush::setBlend( int blend ){
|
||||
write()->blend=blend;
|
||||
rep->blend_valid=false;
|
||||
}
|
||||
|
||||
void Brush::setFX( int fx ){
|
||||
write()->rs.fx=fx;
|
||||
rep->blend_valid=false;
|
||||
}
|
||||
|
||||
void Brush::setTexture( int index,const Texture &t,int n ){
|
||||
write();
|
||||
gxScene::RenderState &rs=rep->rs;
|
||||
|
||||
rep->texs[index]=t;
|
||||
rs.tex_states[index].canvas=t.getCanvas( n );
|
||||
|
||||
rep->max_tex=0;
|
||||
for( int k=0;k<gxScene::MAX_TEXTURES;++k ){
|
||||
if( rs.tex_states[k].canvas ) rep->max_tex=k+1;
|
||||
}
|
||||
rep->blend_valid=false;
|
||||
}
|
||||
|
||||
const Vector &Brush::getColor()const{
|
||||
return *(Vector*)rep->rs.color;
|
||||
}
|
||||
|
||||
float Brush::getAlpha()const{
|
||||
return rep->rs.alpha;
|
||||
}
|
||||
|
||||
float Brush::getShininess()const{
|
||||
return rep->rs.shininess;
|
||||
}
|
||||
|
||||
int Brush::getBlend()const{
|
||||
if( rep->blend_valid ) return rep->rs.blend;
|
||||
|
||||
rep->blend_valid=true; //well, it will be...
|
||||
|
||||
gxScene::RenderState &rs=rep->rs;
|
||||
|
||||
//alphatest
|
||||
if( rep->texs[0].getCanvasFlags() & gxCanvas::CANVAS_TEX_MASK ){
|
||||
rs.fx|=gxScene::FX_ALPHATEST;
|
||||
}else{
|
||||
rs.fx&=~gxScene::FX_ALPHATEST;
|
||||
}
|
||||
|
||||
//0 = default/replace
|
||||
//1 = alpha
|
||||
//2 = multiply
|
||||
//3 = add
|
||||
if( rep->blend ){
|
||||
if( rep->blend!=gxScene::BLEND_ALPHA ){
|
||||
return rs.blend=rep->blend;
|
||||
}
|
||||
for( int k=0;k<rep->max_tex;++k ){
|
||||
if( rep->texs[k].isTransparent() ){
|
||||
return rs.blend=gxScene::BLEND_ALPHA;
|
||||
}
|
||||
}
|
||||
}else if( rep->max_tex==1 && rep->texs[0].isTransparent() ){
|
||||
//single transparent texture?
|
||||
return rs.blend=gxScene::BLEND_ALPHA;
|
||||
}
|
||||
|
||||
//vertex alpha or entityalpha?
|
||||
if( (rs.fx&gxScene::FX_VERTEXALPHA) || rs.alpha<1 ){
|
||||
return rs.blend=gxScene::BLEND_ALPHA;
|
||||
}
|
||||
|
||||
return rs.blend=gxScene::BLEND_REPLACE;
|
||||
}
|
||||
|
||||
int Brush::getFX()const{
|
||||
return rep->rs.fx;
|
||||
}
|
||||
|
||||
Texture Brush::getTexture( int index )const{
|
||||
return rep->texs[index];
|
||||
}
|
||||
|
||||
const gxScene::RenderState &Brush::getRenderState()const{
|
||||
getBlend();
|
||||
for( int k=0;k<rep->max_tex;++k ){
|
||||
gxScene::RenderState::TexState *ts=&rep->rs.tex_states[k];
|
||||
ts->matrix=rep->texs[k].getMatrix();
|
||||
ts->blend=rep->texs[k].getBlend();
|
||||
ts->flags=rep->texs[k].getFlags();
|
||||
}
|
||||
return rep->rs;
|
||||
}
|
||||
|
||||
bool Brush::operator<( const Brush &t )const{
|
||||
return memcmp( &getRenderState(),&t.getRenderState(),sizeof(gxScene::RenderState) )<0;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
#ifndef BRUSH_H
|
||||
#define BRUSH_H
|
||||
|
||||
#include "geom.hpp"
|
||||
#include "texture.hpp"
|
||||
|
||||
class Brush{
|
||||
public:
|
||||
Brush();
|
||||
Brush( const Brush &t );
|
||||
Brush( const Brush &a,const Brush &b );
|
||||
~Brush();
|
||||
|
||||
Brush &operator=( const Brush &t );
|
||||
|
||||
void setColor( const Vector &color );
|
||||
void setAlpha( float alpha );
|
||||
void setShininess( float shininess );
|
||||
void setBlend( int blend );
|
||||
void setFX( int fx );
|
||||
void setTexture( int index,const Texture &t,int frame );
|
||||
|
||||
const Vector &getColor()const;
|
||||
float getAlpha()const;
|
||||
float getShininess()const;
|
||||
int getBlend()const;
|
||||
int getFX()const;
|
||||
Texture getTexture( int index )const;
|
||||
|
||||
const gxScene::RenderState &getRenderState()const;
|
||||
|
||||
bool operator<( const Brush &b )const;
|
||||
|
||||
private:
|
||||
struct Rep;
|
||||
mutable Rep *rep;
|
||||
|
||||
Rep *write()const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,165 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "cachedtexture.hpp"
|
||||
|
||||
int active_texs;
|
||||
|
||||
extern gxRuntime *gx_runtime;
|
||||
extern gxGraphics *gx_graphics;
|
||||
|
||||
set<CachedTextureFactory::CachedTexture*> CachedTextureFactory::rep_set;
|
||||
|
||||
static string path;
|
||||
|
||||
struct CachedTextureFactory::CachedTexture{
|
||||
int ref_cnt;
|
||||
string file;
|
||||
int flags,w,h,first;
|
||||
vector<gxCanvas*> frames;
|
||||
|
||||
CachedTexture( int w,int h,int flags,int cnt ):
|
||||
ref_cnt(1),flags(flags),w(w),h(h),first(0){
|
||||
++active_texs;
|
||||
while( cnt-->0 ){
|
||||
if( gxCanvas *t=gx_graphics->createCanvas( w,h,flags ) ){
|
||||
frames.push_back( t );
|
||||
}else break;
|
||||
}
|
||||
}
|
||||
|
||||
CachedTexture( const string &f,int flags,int w,int h,int first,int cnt ):
|
||||
ref_cnt(1),file(f),flags(flags),w(w),h(h),first(first){
|
||||
++active_texs;
|
||||
if( !(flags & gxCanvas::CANVAS_TEX_CUBE) ){
|
||||
if( w<=0 || h<=0 || first<0 || cnt<=0 ){
|
||||
w=h=first=0;
|
||||
if( gxCanvas *t=gx_graphics->loadCanvas( f,flags ) ){
|
||||
frames.push_back( t );
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int t_flags=flags & (
|
||||
gxCanvas::CANVAS_TEX_RGB|
|
||||
gxCanvas::CANVAS_TEX_ALPHA|
|
||||
gxCanvas::CANVAS_TEX_MASK|
|
||||
gxCanvas::CANVAS_TEX_HICOLOR ) | gxCanvas::CANVAS_NONDISPLAY;
|
||||
|
||||
gxCanvas *t=gx_graphics->loadCanvas( f,t_flags );
|
||||
if( !t ) return;
|
||||
if( !t->getDepth() ){
|
||||
gx_graphics->freeCanvas( t );
|
||||
return;
|
||||
}
|
||||
|
||||
if( flags & gxCanvas::CANVAS_TEX_CUBE ){
|
||||
int w=t->getWidth()/6;
|
||||
if( w*6!=t->getWidth() ) return;
|
||||
int h=t->getHeight();
|
||||
|
||||
gxCanvas *tex=gx_graphics->createCanvas( w,h,flags );
|
||||
if( tex ){
|
||||
frames.push_back( tex );
|
||||
|
||||
for( int face=0;face<6;++face ){
|
||||
tex->setCubeFace(face);
|
||||
gx_graphics->copy( tex,0,0,tex->getWidth(),tex->getHeight(),t,face*w,0,w,h );
|
||||
}
|
||||
tex->setCubeFace(1);
|
||||
}
|
||||
}else{
|
||||
int x_tiles=t->getWidth()/w;
|
||||
int y_tiles=t->getHeight()/h;
|
||||
if( first+cnt>x_tiles*y_tiles ){
|
||||
gx_graphics->freeCanvas( t );
|
||||
return;
|
||||
}
|
||||
int x=(first%x_tiles)*w;
|
||||
int y=(first/x_tiles)*h;
|
||||
while( cnt-- ){
|
||||
gxCanvas *p=gx_graphics->createCanvas( w,h,flags );
|
||||
gx_graphics->copy( p,0,0,p->getWidth(),p->getHeight(),t,x,y,w,h );
|
||||
frames.push_back(p);
|
||||
x=x+w;if( x+w>t->getWidth() ){ x=0;y=y+h; }
|
||||
}
|
||||
}
|
||||
gx_graphics->freeCanvas( t );
|
||||
}
|
||||
|
||||
~CachedTexture(){
|
||||
--active_texs;
|
||||
for( int k=0;k<frames.size();++k ) gx_graphics->freeCanvas( frames[k] );
|
||||
}
|
||||
};
|
||||
|
||||
CachedTextureFactory::CachedTexture *CachedTextureFactory::findRep( const string &f,int flags,int w,int h,int first,int cnt ){
|
||||
set<CachedTexture*>::const_iterator it;
|
||||
for( it=rep_set.begin();it!=rep_set.end();++it ){
|
||||
CachedTexture *rep=*it;
|
||||
if( rep->file==f && rep->flags==flags && rep->w==w && rep->h==h && rep->first==first && rep->frames.size()==cnt ){
|
||||
++rep->ref_cnt;return rep;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
CachedTextureFactory::CachedTextureFactory( int w,int h,int flags,int cnt ):
|
||||
rep(new CachedTexture(w,h,flags,cnt)){
|
||||
}
|
||||
|
||||
CachedTextureFactory::CachedTextureFactory( const string &f_,int flags,int w,int h,int first,int cnt ){
|
||||
string f=f_;
|
||||
if( f.substr(0,2)==".\\" ) f=f.substr(2);
|
||||
if( path.size() ){
|
||||
string t=path+tolower( filenamefile( f ) );
|
||||
if( rep=findRep( t,flags,w,h,first,cnt ) ) return;
|
||||
rep=new CachedTexture( t,flags,w,h,first,cnt );
|
||||
if( rep->frames.size() ){
|
||||
rep_set.insert( rep );
|
||||
return;
|
||||
}
|
||||
delete rep;
|
||||
}
|
||||
string t=tolower( fullfilename( f ) );
|
||||
if( rep=findRep( t,flags,w,h,first,cnt ) ) return;
|
||||
rep=new CachedTexture( t,flags,w,h,first,cnt );
|
||||
rep_set.insert( rep );
|
||||
}
|
||||
|
||||
CachedTextureFactory::CachedTextureFactory( const CachedTextureFactory &t ):
|
||||
rep(t.rep){
|
||||
++rep->ref_cnt;
|
||||
}
|
||||
|
||||
CachedTextureFactory::~CachedTextureFactory(){
|
||||
if( !--rep->ref_cnt ){
|
||||
rep_set.erase( rep );
|
||||
delete rep;
|
||||
}
|
||||
}
|
||||
|
||||
CachedTextureFactory &CachedTextureFactory::operator=( const CachedTextureFactory &t ){
|
||||
++t.rep->ref_cnt;
|
||||
if( !--rep->ref_cnt ){
|
||||
rep_set.erase( rep );
|
||||
delete rep;
|
||||
}
|
||||
rep=t.rep;
|
||||
return *this;
|
||||
}
|
||||
|
||||
string CachedTextureFactory::getName()const{
|
||||
return rep->file;
|
||||
}
|
||||
|
||||
const vector<gxCanvas*> &CachedTextureFactory::getFrames()const{
|
||||
return rep->frames;
|
||||
}
|
||||
|
||||
void CachedTextureFactory::setPath( const string &t ){
|
||||
path=tolower(t);
|
||||
if( int sz=path.size() ){
|
||||
if( path[sz-1]!='/' && path[sz-1]!='\\' ) path+='\\';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
#ifndef CACHEDTEXTURE_H
|
||||
#define CACHEDTEXTURE_H
|
||||
|
||||
#include "../gxruntime/gxcanvas.hpp"
|
||||
|
||||
class CachedTextureFactory{
|
||||
public:
|
||||
CachedTextureFactory( int w,int h,int flags,int cnt );
|
||||
CachedTextureFactory( const string &f,int flags,int w,int h,int first,int cnt );
|
||||
CachedTextureFactory( const CachedTextureFactory &t );
|
||||
~CachedTextureFactory();
|
||||
|
||||
CachedTextureFactory &operator=( const CachedTextureFactory &t );
|
||||
|
||||
string getName()const;
|
||||
|
||||
const vector<gxCanvas*> &getFrames()const;
|
||||
|
||||
bool operator<( const CachedTextureFactory &t )const{ return rep<t.rep; }
|
||||
|
||||
static void setPath( const string &t );
|
||||
|
||||
private:
|
||||
struct CachedTexture;
|
||||
CachedTexture *rep;
|
||||
|
||||
CachedTexture *findRep( const string &f,int flags,int w,int h,int first,int cnt );
|
||||
|
||||
static set<CachedTexture*> rep_set;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,103 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "camera.hpp"
|
||||
|
||||
extern gxScene *gx_scene;
|
||||
|
||||
Camera::Camera(){
|
||||
setZoom( 1 );
|
||||
setRange( 1,1000 );
|
||||
setViewport( 0,0,0,0 );
|
||||
setClsColor( Vector() );
|
||||
setClsMode( true,true );
|
||||
setProjMode( PROJ_PERSP );
|
||||
setFogRange( 1,1000 );
|
||||
setFogColor( Vector() );
|
||||
setFogMode( gxScene::FOG_NONE );
|
||||
}
|
||||
|
||||
void Camera::setZoom( float z ){
|
||||
zoom=z;
|
||||
local_valid=false;
|
||||
}
|
||||
|
||||
void Camera::setRange( float n,float f ){
|
||||
frustum_nr=n;frustum_fr=f;
|
||||
local_valid=false;
|
||||
}
|
||||
|
||||
void Camera::setViewport( int x,int y,int w,int h ){
|
||||
vp_x=x;vp_y=y;vp_w=w;vp_h=h;
|
||||
local_valid=false;
|
||||
}
|
||||
|
||||
void Camera::setClsColor( const Vector &v ){
|
||||
cls_color=v;
|
||||
}
|
||||
|
||||
void Camera::setClsMode( bool c,bool z ){
|
||||
cls_argb=c;cls_z=z;
|
||||
}
|
||||
|
||||
void Camera::setProjMode( int mode ){
|
||||
proj_mode=mode;
|
||||
}
|
||||
|
||||
void Camera::setFogColor( const Vector &v ){
|
||||
fog_color=v;
|
||||
}
|
||||
|
||||
void Camera::setFogRange( float nr,float fr ){
|
||||
fog_nr=nr;fog_fr=fr;
|
||||
}
|
||||
|
||||
void Camera::setFogMode( int mode ){
|
||||
fog_mode=mode;
|
||||
}
|
||||
|
||||
const Frustum &Camera::getFrustum()const{
|
||||
if( !local_valid ){
|
||||
float ar=(float)vp_h/vp_w;
|
||||
frustum_w=frustum_nr*2/zoom;
|
||||
frustum_h=frustum_nr*2/zoom*ar;
|
||||
new( &local_frustum ) Frustum( frustum_nr,frustum_fr,frustum_w,frustum_h );
|
||||
local_valid=true;
|
||||
}
|
||||
return local_frustum;
|
||||
}
|
||||
|
||||
float Camera::getFrustumNear()const{
|
||||
return frustum_nr;
|
||||
}
|
||||
|
||||
float Camera::getFrustumFar()const{
|
||||
return frustum_fr;
|
||||
}
|
||||
|
||||
float Camera::getFrustumWidth()const{
|
||||
getFrustum();return frustum_w;
|
||||
}
|
||||
|
||||
float Camera::getFrustumHeight()const{
|
||||
getFrustum();return frustum_h;
|
||||
}
|
||||
|
||||
void Camera::getViewport( int *x,int *y,int *w,int *h )const{
|
||||
*x=vp_x;*y=vp_y;*w=vp_w;*h=vp_h;
|
||||
}
|
||||
|
||||
bool Camera::beginRenderFrame(){
|
||||
if( !proj_mode ) return false;
|
||||
getFrustum();
|
||||
gx_scene->setViewport( vp_x,vp_y,vp_w,vp_h );
|
||||
gx_scene->clear( &(cls_color.x),1,1,cls_argb,cls_z );
|
||||
if( proj_mode==PROJ_ORTHO ){
|
||||
gx_scene->setOrthoProj( frustum_nr,frustum_fr,frustum_w,frustum_h );
|
||||
}else{
|
||||
gx_scene->setPerspProj( frustum_nr,frustum_fr,frustum_w,frustum_h );
|
||||
}
|
||||
gx_scene->setFogRange( fog_nr,fog_fr );
|
||||
gx_scene->setFogColor( (float*)&fog_color.x );
|
||||
gx_scene->setFogMode( fog_mode );
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include "model.hpp"
|
||||
#include "frustum.hpp"
|
||||
#include "mirror.hpp"
|
||||
|
||||
class Camera : public Object{
|
||||
public:
|
||||
enum{
|
||||
PROJ_NONE=0,PROJ_PERSP=1,PROJ_ORTHO=2
|
||||
};
|
||||
|
||||
Camera();
|
||||
Camera *getCamera(){ return this; }
|
||||
|
||||
//called by user
|
||||
void setZoom( float z );
|
||||
void setRange( float nr,float fr );
|
||||
void setViewport( int x,int y,int w,int h );
|
||||
void setClsColor( const Vector &v );
|
||||
void setClsMode( bool cls_argb,bool cls_z );
|
||||
void setProjMode( int mode );
|
||||
void setFogColor( const Vector &v );
|
||||
void setFogRange( float nr,float fr );
|
||||
void setFogMode( int mode );
|
||||
|
||||
//called by world
|
||||
bool beginRenderFrame();
|
||||
|
||||
//Camera frustum...
|
||||
float getFrustumNear()const;
|
||||
float getFrustumFar()const;
|
||||
float getFrustumWidth()const;
|
||||
float getFrustumHeight()const;
|
||||
const Frustum &getFrustum()const;
|
||||
void getViewport( int *x,int *y,int *w,int *h )const;
|
||||
int getProjMode()const{ return proj_mode; }
|
||||
|
||||
private:
|
||||
float zoom;
|
||||
int vp_x,vp_y,vp_w,vp_h;
|
||||
Vector cls_color;
|
||||
bool cls_argb,cls_z;
|
||||
int proj_mode;
|
||||
Vector fog_color;
|
||||
float fog_nr,fog_fr;
|
||||
int fog_mode;
|
||||
float frustum_nr,frustum_fr;
|
||||
mutable float frustum_w,frustum_h;
|
||||
mutable Frustum local_frustum;
|
||||
mutable bool local_valid;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,361 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "collision.hpp"
|
||||
|
||||
const float COLLISION_FLT_EPSILON=.001f;
|
||||
|
||||
/*
|
||||
//
|
||||
// OLD VERSION
|
||||
//
|
||||
bool Collision::sphereCollide( const Line &line,float radius,const Vector &dest,float dest_radius ){
|
||||
|
||||
radius+=dest_radius;
|
||||
Line l( line.o-dest,line.d );
|
||||
|
||||
float a=l.d.dot(l.d);
|
||||
if( !a ) return false;
|
||||
float b=l.o.dot(l.d)*2;
|
||||
float c=l.o.dot(l.o)-radius*radius;
|
||||
float d=b*b-4*a*c;
|
||||
if( d<0 ) return false;
|
||||
float t1=(-b+sqrt(d))/(2*a);
|
||||
float t2=(-b-sqrt(d))/(2*a);
|
||||
|
||||
float t=t1<t2 ? t1 : t2;
|
||||
if( t<0 || t>=time ) return false;
|
||||
|
||||
time=t;
|
||||
normal=(l*t).normalized();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Collision::sphereCollide( const Line &line,float radius,const Vector &dest,const Vector &radii ){
|
||||
|
||||
radius+=radii.x;
|
||||
|
||||
Line l( line.o-dest,line.d );
|
||||
|
||||
// float y_scale=1;
|
||||
// if( radii.x!=radii.y ){
|
||||
// y_scale=radii.x/radii.y;
|
||||
// l.o.y*=y_scale;
|
||||
// l.d.y*=y_scale;
|
||||
// }
|
||||
|
||||
float a=l.d.dot(l.d);
|
||||
if( !a ) return false;
|
||||
float b=l.o.dot(l.d)*2;
|
||||
float c=l.o.dot(l.o)-radius*radius;
|
||||
float d=b*b-4*a*c;
|
||||
if( d<0 ) return false;
|
||||
float t1=(-b+sqrt(d))/(2*a);
|
||||
float t2=(-b-sqrt(d))/(2*a);
|
||||
|
||||
float t=t1<t2 ? t1 : t2;
|
||||
if( t<0 || t>=time ) return false;
|
||||
|
||||
time=t;
|
||||
normal=(l*t).normalized();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//v0,v1 = edge verts
|
||||
//pn = poly normal
|
||||
//en = edge normal
|
||||
static bool edgeTest( const Vector &v0,const Vector &v1,const Vector &pn,const Vector &en,const Line &line,float radius,Collision *curr_coll ){
|
||||
|
||||
Matrix tm=~Matrix( en,(v1-v0).normalized(),pn );
|
||||
Vector sv=tm*(line.o-v0),dv=tm*(line.o+line.d-v0);
|
||||
Line l( sv,dv-sv );
|
||||
//do cylinder test...
|
||||
float a,b,c,d,t1,t2,t;
|
||||
a=(l.d.x*l.d.x+l.d.z*l.d.z);
|
||||
if( !a ) return false; //ray parallel to cylinder
|
||||
b=(l.o.x*l.d.x+l.o.z*l.d.z)*2;
|
||||
c=(l.o.x*l.o.x+l.o.z*l.o.z)-radius*radius;
|
||||
d=b*b-4*a*c;
|
||||
if( d<0 ) return false; //ray misses cylinder
|
||||
t1=(-b+sqrt(d))/(2*a);
|
||||
t2=(-b-sqrt(d))/(2*a);
|
||||
t=t1<t2 ? t1 : t2;
|
||||
if( t>curr_coll->time ) return false; //intersects too far away
|
||||
Vector i=l*t,p;
|
||||
if( i.y>v0.distance(v1) ) return false; //intersection above cylinder
|
||||
if( i.y>=0 ){
|
||||
if( t<0 ) return false;
|
||||
p.y=i.y;
|
||||
}else{
|
||||
//below bottom of cylinder...do sphere test...
|
||||
a=l.d.dot(l.d);
|
||||
if( !a ) return false; //ray parallel to sphere
|
||||
b=l.o.dot(l.d)*2;
|
||||
c=l.o.dot(l.o)-radius*radius;
|
||||
d=b*b-4*a*c;
|
||||
if( d<0 ) return false; //ray misses sphere
|
||||
t1=(-b+sqrt(d))/(2*a);
|
||||
t2=(-b-sqrt(d))/(2*a);
|
||||
t=t1<t2 ? t1 : t2;
|
||||
if( t<0 || t>curr_coll->time ) return false; //intersects behind or too far away
|
||||
i=l*t;
|
||||
}
|
||||
curr_coll->time=t;
|
||||
curr_coll->normal=~tm*(i-p);
|
||||
curr_coll->normal.normalize();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Collision::triangleCollide( const Line &line,float radius,const Vector &v0,const Vector &v1,const Vector &v2 ){
|
||||
|
||||
//triangle plane
|
||||
Plane p( v0,v1,v2 );
|
||||
if( p.n.dot( line.d )>=0 ) return false;
|
||||
|
||||
//intersection time
|
||||
Plane tp=p;tp.d-=radius;
|
||||
float t=tp.t_intersect( line );
|
||||
if( t>time ) return false;
|
||||
|
||||
//intersection point
|
||||
Plane p0( v0+p.n,v1,v0 ),p1( v1+p.n,v2,v1 ),p2( v2+p.n,v0,v2 );
|
||||
|
||||
if( t>=0 ){
|
||||
Vector i=line*t;
|
||||
if( p0.distance(i)>=0 && p1.distance(i)>=0 && p2.distance(i)>=0 ){
|
||||
time=t;
|
||||
normal=p.n;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if( radius<=0 ) return false;
|
||||
|
||||
return
|
||||
edgeTest( v0,v1,p.n,p0.n,line,radius,this )|
|
||||
edgeTest( v1,v2,p.n,p1.n,line,radius,this )|
|
||||
edgeTest( v2,v0,p.n,p2.n,line,radius,this );
|
||||
}
|
||||
|
||||
bool Collision::boxCollide( const Line &line,float radius,const Box &box ){
|
||||
|
||||
static int quads[]={
|
||||
2,3,1,0,
|
||||
3,7,5,1,
|
||||
7,6,4,5,
|
||||
6,2,0,4,
|
||||
6,7,3,2,
|
||||
0,1,5,4
|
||||
};
|
||||
|
||||
bool hit=false;
|
||||
|
||||
for( int n=0;n<24;n+=4 ){
|
||||
Vector
|
||||
v0( box.corner( quads[n] ) ),
|
||||
v1( box.corner( quads[n+1] ) ),
|
||||
v2( box.corner( quads[n+2] ) ),
|
||||
v3( box.corner( quads[n+3] ) );
|
||||
|
||||
//quad plane
|
||||
Plane p( v0,v1,v2 );
|
||||
if( p.n.dot( line.d )>=0 ) continue;
|
||||
|
||||
p.d-=radius;
|
||||
float t=p.t_intersect( line );
|
||||
if( t>time ) continue;
|
||||
|
||||
//intersection point
|
||||
Plane
|
||||
p0( v0+p.n,v1,v0 ),
|
||||
p1( v1+p.n,v2,v1 ),
|
||||
p2( v2+p.n,v3,v2 ),
|
||||
p3( v3+p.n,v0,v3 );
|
||||
|
||||
if( t>=0 ){
|
||||
Vector i=line*t;
|
||||
if( p0.distance(i)>=0 && p1.distance(i)>=0 && p2.distance(i)>=0 && p3.distance(i)>=0 ){
|
||||
time=t;
|
||||
normal=p.n;
|
||||
hit=true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( radius<=0 ) continue;
|
||||
|
||||
hit|=
|
||||
edgeTest( v0,v1,p.n,p0.n,line,radius,this )|
|
||||
edgeTest( v1,v2,p.n,p1.n,line,radius,this )|
|
||||
edgeTest( v2,v3,p.n,p2.n,line,radius,this )|
|
||||
edgeTest( v3,v0,p.n,p3.n,line,radius,this );
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
*/
|
||||
|
||||
bool Collision::update( const Line &line,float t,const Vector &n ){
|
||||
|
||||
// if( t<0 || t>time ) return false;
|
||||
|
||||
if( t>time ) return false;
|
||||
Plane p(line*t,n);
|
||||
if( p.n.dot( line.d )>=0 ) return false;
|
||||
if( p.distance(line.o)<-COLLISION_FLT_EPSILON ) return false;
|
||||
|
||||
time=t;
|
||||
normal=n;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// NEW VERSION
|
||||
//
|
||||
extern gxRuntime *gx_runtime;
|
||||
|
||||
bool Collision::sphereCollide( const Line &line,float radius,const Vector &dest,float dest_radius ){
|
||||
|
||||
radius+=dest_radius;
|
||||
Line l( line.o-dest,line.d );
|
||||
|
||||
float a=l.d.dot(l.d);
|
||||
if( !a ) return false;
|
||||
float b=l.o.dot(l.d)*2;
|
||||
float c=l.o.dot(l.o)-radius*radius;
|
||||
float d=b*b-4*a*c;
|
||||
if( d<0 ) return false;
|
||||
|
||||
float t1=(-b+sqrt(d))/(2*a);
|
||||
float t2=(-b-sqrt(d))/(2*a);
|
||||
|
||||
float t=t1<t2 ? t1 : t2;
|
||||
|
||||
if( t>time ) return false;
|
||||
|
||||
return update( line,t,(l*t).normalized() );
|
||||
}
|
||||
|
||||
//v0,v1 = edge verts
|
||||
//pn = poly normal
|
||||
//en = edge normal
|
||||
static bool edgeTest( const Vector &v0,const Vector &v1,const Vector &pn,const Vector &en,const Line &line,float radius,Collision *curr_coll ){
|
||||
|
||||
Matrix tm=~Matrix( en,(v1-v0).normalized(),pn );
|
||||
Vector sv=tm*(line.o-v0),dv=tm*(line.o+line.d-v0);
|
||||
Line l( sv,dv-sv );
|
||||
//do cylinder test...
|
||||
float a,b,c,d,t1,t2,t;
|
||||
a=(l.d.x*l.d.x+l.d.z*l.d.z);
|
||||
if( !a ) return false; //ray parallel to cylinder
|
||||
b=(l.o.x*l.d.x+l.o.z*l.d.z)*2;
|
||||
c=(l.o.x*l.o.x+l.o.z*l.o.z)-radius*radius;
|
||||
d=b*b-4*a*c;
|
||||
if( d<0 ) return false; //ray misses cylinder
|
||||
t1=(-b+sqrt(d))/(2*a);
|
||||
t2=(-b-sqrt(d))/(2*a);
|
||||
t=t1<t2 ? t1 : t2;
|
||||
if( t>curr_coll->time ) return false; //intersects too far away
|
||||
Vector i=l*t,p;
|
||||
if( i.y>v0.distance(v1) ) return false; //intersection above cylinder
|
||||
if( i.y>=0 ){
|
||||
p.y=i.y;
|
||||
}else{
|
||||
//below bottom of cylinder...do sphere test...
|
||||
a=l.d.dot(l.d);
|
||||
if( !a ) return false; //ray parallel to sphere
|
||||
b=l.o.dot(l.d)*2;
|
||||
c=l.o.dot(l.o)-radius*radius;
|
||||
d=b*b-4*a*c;
|
||||
if( d<0 ) return false; //ray misses sphere
|
||||
t1=(-b+sqrt(d))/(2*a);
|
||||
t2=(-b-sqrt(d))/(2*a);
|
||||
t=t1<t2 ? t1 : t2;
|
||||
if( t>curr_coll->time ) return false;
|
||||
i=l*t;
|
||||
}
|
||||
|
||||
return curr_coll->update( line,t,(~tm*(i-p)).normalized() );
|
||||
}
|
||||
|
||||
bool Collision::triangleCollide( const Line &line,float radius,const Vector &v0,const Vector &v1,const Vector &v2 ){
|
||||
|
||||
//triangle plane
|
||||
Plane p( v0,v1,v2 );
|
||||
if( p.n.dot( line.d )>=0 ) return false;
|
||||
|
||||
//move plane out
|
||||
p.d-=radius;
|
||||
float t=p.t_intersect( line );
|
||||
if( t>time ) return false;
|
||||
|
||||
//edge planes
|
||||
Plane p0( v0+p.n,v1,v0 ),p1( v1+p.n,v2,v1 ),p2( v2+p.n,v0,v2 );
|
||||
|
||||
//intersects triangle?
|
||||
Vector i=line*t;
|
||||
if( p0.distance(i)>=0 && p1.distance(i)>=0 && p2.distance(i)>=0 ){
|
||||
return update( line,t,p.n );
|
||||
}
|
||||
|
||||
if( radius<=0 ) return false;
|
||||
|
||||
return
|
||||
edgeTest( v0,v1,p.n,p0.n,line,radius,this )|
|
||||
edgeTest( v1,v2,p.n,p1.n,line,radius,this )|
|
||||
edgeTest( v2,v0,p.n,p2.n,line,radius,this );
|
||||
}
|
||||
|
||||
bool Collision::boxCollide( const Line &line,float radius,const Box &box ){
|
||||
|
||||
static int quads[]={
|
||||
2,3,1,0,
|
||||
3,7,5,1,
|
||||
7,6,4,5,
|
||||
6,2,0,4,
|
||||
6,7,3,2,
|
||||
0,1,5,4
|
||||
};
|
||||
|
||||
bool hit=false;
|
||||
|
||||
for( int n=0;n<24;n+=4 ){
|
||||
Vector
|
||||
v0( box.corner( quads[n] ) ),
|
||||
v1( box.corner( quads[n+1] ) ),
|
||||
v2( box.corner( quads[n+2] ) ),
|
||||
v3( box.corner( quads[n+3] ) );
|
||||
|
||||
//quad plane
|
||||
Plane p( v0,v1,v2 );
|
||||
if( p.n.dot( line.d )>=0 ) continue;
|
||||
|
||||
//move plane out
|
||||
p.d-=radius;
|
||||
float t=p.t_intersect( line );
|
||||
if( t>time ) return false;
|
||||
|
||||
//edge planes
|
||||
Plane
|
||||
p0( v0+p.n,v1,v0 ),
|
||||
p1( v1+p.n,v2,v1 ),
|
||||
p2( v2+p.n,v3,v2 ),
|
||||
p3( v3+p.n,v0,v3 );
|
||||
|
||||
//intersects triangle?
|
||||
Vector i=line*t;
|
||||
if( p0.distance(i)>=0 && p1.distance(i)>=0 && p2.distance(i)>=0 && p3.distance(i)>=0 ){
|
||||
hit|=update( line,t,p.n );
|
||||
continue;
|
||||
}
|
||||
|
||||
if( radius<=0 ) continue;
|
||||
|
||||
hit|=
|
||||
edgeTest( v0,v1,p.n,p0.n,line,radius,this )|
|
||||
edgeTest( v1,v2,p.n,p1.n,line,radius,this )|
|
||||
edgeTest( v2,v3,p.n,p2.n,line,radius,this )|
|
||||
edgeTest( v3,v0,p.n,p3.n,line,radius,this );
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef COLLISION_H
|
||||
#define COLLISION_H
|
||||
|
||||
#include "geom.hpp"
|
||||
|
||||
extern const float COLLISION_FLT_EPSILON;
|
||||
|
||||
struct Collision{
|
||||
float time;
|
||||
Vector normal;
|
||||
void *surface;
|
||||
unsigned short index;
|
||||
|
||||
Collision():time(1),surface(0),index(~0){}
|
||||
|
||||
bool update( const Line &line,float time,const Vector &normal );
|
||||
|
||||
bool sphereCollide( const Line &src_line,float src_radius,const Vector &dest,float dest_radius );
|
||||
bool sphereCollide( const Line &line,float radius,const Vector &dest,const Vector &radii );
|
||||
|
||||
bool triangleCollide( const Line &src_line,float src_radius,const Vector &v0,const Vector &v1,const Vector &v2 );
|
||||
|
||||
bool boxCollide( const Line &src_line,float src_radius,const Box &box );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "emitter.hpp"
|
||||
|
||||
Emitter::Emitter(){
|
||||
}
|
||||
|
||||
Emitter::Emitter( const Emitter &t ){
|
||||
}
|
||||
|
||||
Emitter::~Emitter(){
|
||||
}
|
||||
|
||||
void Emitter::beginRender( float tween ){
|
||||
Object::beginRender( tween );
|
||||
|
||||
vel=getRenderTform().v-pos;
|
||||
pos=getRenderTform().v;
|
||||
|
||||
for( int k=0;k<channels.size();++k ){
|
||||
gxChannel *chan=channels[k];
|
||||
if( !chan->isPlaying() ){
|
||||
channels[k]=0;
|
||||
continue;
|
||||
}
|
||||
chan->set3d( &pos.x,&vel.x );
|
||||
}
|
||||
}
|
||||
|
||||
gxChannel *Emitter::emitSound( gxSound *sound ){
|
||||
|
||||
gxChannel *chan=sound->play3d( &pos.x,&vel.x );
|
||||
|
||||
for( int k=0;k<channels.size();++k ){
|
||||
if( chan=channels[k] ) return chan;
|
||||
if( channels[k] ) continue;
|
||||
channels[k]=chan;
|
||||
return chan;
|
||||
}
|
||||
channels.push_back( chan );
|
||||
return chan;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
#ifndef EMITTER_H
|
||||
#define EMITTER_H
|
||||
|
||||
#include "object.hpp"
|
||||
|
||||
class gxSound;
|
||||
class gxChannel;
|
||||
|
||||
class Emitter : public Object{
|
||||
public:
|
||||
Emitter();
|
||||
Emitter( const Emitter &t );
|
||||
~Emitter();
|
||||
|
||||
//Entity interface
|
||||
Entity *clone(){ return d_new Emitter( *this ); }
|
||||
Emitter *getEmitter(){ return this; }
|
||||
|
||||
//Object interface
|
||||
void beginRender( float tween );
|
||||
|
||||
//Public interface
|
||||
gxChannel *emitSound( gxSound *sound );
|
||||
|
||||
private:
|
||||
Vector pos,vel;
|
||||
|
||||
vector<gxChannel*> channels;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,197 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "entity.hpp"
|
||||
|
||||
//#include "stats.hpp"
|
||||
|
||||
Entity *Entity::_orphans, *Entity::_last_orphan;
|
||||
|
||||
enum {
|
||||
INVALID_LOCALTFORM = 1,
|
||||
INVALID_WORLDTFORM = 2
|
||||
};
|
||||
|
||||
void Entity::RemoveParent() {
|
||||
if (m_parent) {
|
||||
if (m_parent->m_children == this) m_parent->m_children = m_listNext;
|
||||
if (m_parent->m_last_child == this) m_parent->m_last_child = m_listPrev;
|
||||
} else {
|
||||
if (_orphans == this) _orphans = m_listNext;
|
||||
if (_last_orphan == this) _last_orphan = m_listPrev;
|
||||
}
|
||||
if (m_listNext) m_listNext->m_listPrev = m_listPrev;
|
||||
if (m_listPrev) m_listPrev->m_listNext = m_listNext;
|
||||
}
|
||||
|
||||
void Entity::InsertChildToParent() {
|
||||
m_listNext = 0;
|
||||
if (m_parent) {
|
||||
if (m_listPrev = m_parent->m_last_child) m_listPrev->m_listNext = this;
|
||||
else m_parent->m_children = this;
|
||||
m_parent->m_last_child = this;
|
||||
} else {
|
||||
if (m_listPrev = _last_orphan) m_listPrev->m_listNext = this;
|
||||
else _orphans = this;
|
||||
_last_orphan = this;
|
||||
}
|
||||
}
|
||||
|
||||
Entity::Entity() :
|
||||
m_listNext(0), m_listPrev(0), m_parent(0), m_children(0), m_last_child(0),
|
||||
m_isVisible(true), m_isEnabled(true),
|
||||
m_localScale(1, 1, 1),
|
||||
invalid(0) {
|
||||
InsertChildToParent();
|
||||
}
|
||||
|
||||
Entity::Entity(const Entity &e) :
|
||||
m_listNext(0), m_listPrev(0), m_parent(0), m_children(0), m_last_child(0),
|
||||
m_name(e.m_name), m_isVisible(e.m_isVisible), m_isEnabled(e.m_isEnabled),
|
||||
m_localPosition(e.m_localPosition),
|
||||
m_localScale(e.m_localScale),
|
||||
m_localRotation(e.m_localRotation),
|
||||
invalid(INVALID_LOCALTFORM | INVALID_WORLDTFORM) {
|
||||
InsertChildToParent();
|
||||
}
|
||||
|
||||
Entity::~Entity() {
|
||||
while (GetChildren()) delete GetChildren();
|
||||
RemoveParent();
|
||||
}
|
||||
|
||||
void Entity::InvalidateWorldTransform() {
|
||||
if (invalid & INVALID_WORLDTFORM) return;
|
||||
invalid |= INVALID_WORLDTFORM;
|
||||
for (Entity *e = m_children; e; e = e->m_listNext) {
|
||||
e->InvalidateWorldTransform();
|
||||
}
|
||||
}
|
||||
|
||||
void Entity::invalidateLocal() {
|
||||
invalid |= INVALID_LOCALTFORM;
|
||||
InvalidateWorldTransform();
|
||||
}
|
||||
|
||||
const Transform &Entity::GetLocalTransform()const {
|
||||
if (invalid&INVALID_LOCALTFORM) {
|
||||
m_localTransform.m = Matrix(m_localRotation);
|
||||
m_localTransform.m.i *= m_localScale.x;
|
||||
m_localTransform.m.j *= m_localScale.y;
|
||||
m_localTransform.m.k *= m_localScale.z;
|
||||
m_localTransform.v = m_localPosition;
|
||||
invalid &= ~INVALID_LOCALTFORM;
|
||||
}
|
||||
return m_localTransform;
|
||||
}
|
||||
|
||||
const Transform &Entity::GetWorldTransform()const {
|
||||
if (invalid&INVALID_WORLDTFORM) {
|
||||
m_worldTransform = m_parent ? m_parent->GetWorldTransform() * GetLocalTransform() : GetLocalTransform();
|
||||
invalid &= ~INVALID_WORLDTFORM;
|
||||
}
|
||||
return m_worldTransform;
|
||||
}
|
||||
|
||||
void Entity::SetParent(Entity *p) {
|
||||
if (m_parent == p) return;
|
||||
|
||||
RemoveParent();
|
||||
|
||||
m_parent = p;
|
||||
|
||||
InsertChildToParent();
|
||||
|
||||
InvalidateWorldTransform();
|
||||
}
|
||||
|
||||
void Entity::SetName(const string &t) {
|
||||
m_name = t;
|
||||
}
|
||||
|
||||
void Entity::SetVisible(bool visible) {
|
||||
m_isVisible = visible;
|
||||
}
|
||||
|
||||
void Entity::SetEnabled(bool enabled) {
|
||||
m_isEnabled = enabled;
|
||||
}
|
||||
|
||||
void Entity::EnumerateVisible(std::list<Object*> &out) {
|
||||
if (!m_isVisible) return;
|
||||
if (Object *o = getObject()) out.push_back(o);
|
||||
for (Entity *e = m_children; e; e = e->m_listNext) {
|
||||
e->EnumerateVisible(out);
|
||||
}
|
||||
}
|
||||
|
||||
void Entity::EnumerateEnabled(std::list<Object*> &out) {
|
||||
if (!m_isEnabled) return;
|
||||
if (Object *o = getObject()) out.push_back(o);
|
||||
for (Entity *e = m_children; e; e = e->m_listNext) {
|
||||
e->EnumerateEnabled(out);
|
||||
}
|
||||
}
|
||||
|
||||
void Entity::SetLocalPosition(const Vector &v) {
|
||||
m_localPosition = v;
|
||||
invalidateLocal();
|
||||
}
|
||||
|
||||
void Entity::SetLocalScale(const Vector &v) {
|
||||
m_localScale = v;
|
||||
invalidateLocal();
|
||||
}
|
||||
|
||||
void Entity::SetLocalRotation(const Quat &q) {
|
||||
m_localRotation = q.normalized();
|
||||
invalidateLocal();
|
||||
}
|
||||
|
||||
void Entity::SetLocalTransform(const Transform &t) {
|
||||
m_localPosition = t.v;
|
||||
m_localScale = Vector(t.m.i.length(), t.m.j.length(), t.m.k.length());
|
||||
m_localRotation = matrixQuat(t.m);
|
||||
invalidateLocal();
|
||||
}
|
||||
|
||||
void Entity::SetWorldPosition(const Vector &v) {
|
||||
SetLocalPosition(m_parent ? -m_parent->GetWorldTransform() * v : v);
|
||||
}
|
||||
|
||||
void Entity::SetWorldScale(const Vector &v) {
|
||||
SetLocalScale(m_parent ? v / m_parent->GetWorldScale() : v);
|
||||
}
|
||||
|
||||
void Entity::SetWorldRotation(const Quat &q) {
|
||||
SetLocalRotation(m_parent ? -m_parent->GetWorldRotation() * q : q);
|
||||
}
|
||||
|
||||
void Entity::SetWorldTransform(const Transform &t) {
|
||||
SetLocalTransform(m_parent ? -m_parent->GetWorldTransform() * t : t);
|
||||
}
|
||||
|
||||
const Vector &Entity::GetLocalPosition()const {
|
||||
return m_localPosition;
|
||||
}
|
||||
|
||||
const Vector &Entity::GetLocalScale()const {
|
||||
return m_localScale;
|
||||
}
|
||||
|
||||
const Quat &Entity::GetLocalRotation()const {
|
||||
return m_localRotation;
|
||||
}
|
||||
|
||||
const Vector &Entity::GetWorldPosition()const {
|
||||
return GetWorldTransform().v;
|
||||
}
|
||||
|
||||
const Vector &Entity::GetWorldScale()const {
|
||||
m_worldScale = m_parent ? m_parent->GetWorldScale() * m_localScale : m_localScale;
|
||||
return m_worldScale;
|
||||
}
|
||||
|
||||
const Quat &Entity::GetWorldRotation()const {
|
||||
m_worldRotation = m_parent ? m_parent->GetWorldRotation() * m_localRotation : m_localRotation;
|
||||
return m_worldRotation;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
|
||||
#ifndef ENTITY_H
|
||||
#define ENTITY_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "geom.hpp"
|
||||
|
||||
class Entity;
|
||||
class Object;
|
||||
class Camera;
|
||||
class Light;
|
||||
class Model;
|
||||
class Mirror;
|
||||
class Listener;
|
||||
class MeshModel;
|
||||
class MD2Model;
|
||||
|
||||
class Entity {
|
||||
public:
|
||||
|
||||
Entity();
|
||||
Entity(const Entity &e);
|
||||
virtual ~Entity();
|
||||
|
||||
virtual Entity *clone() = 0;
|
||||
|
||||
//ugly casts!
|
||||
virtual Object *getObject() { return nullptr; }
|
||||
virtual Camera *getCamera() { return nullptr; }
|
||||
virtual Light *getLight() { return nullptr; }
|
||||
virtual Model *getModel() { return nullptr; }
|
||||
virtual Mirror *getMirror() { return nullptr; }
|
||||
virtual Listener *getListener() { return nullptr; }
|
||||
|
||||
void SetName(const std::string &t);
|
||||
std::string getName()const { return m_name; }
|
||||
|
||||
void SetParent(Entity *parent);
|
||||
Entity *getParent()const { return m_parent; }
|
||||
|
||||
void SetVisible(bool vis);
|
||||
bool IsVisible()const { return m_isVisible; }
|
||||
void EnumerateVisible(std::list<Object*> &out);
|
||||
|
||||
void SetEnabled(bool ena);
|
||||
bool IsEnabled()const { return m_isEnabled; }
|
||||
void EnumerateEnabled(std::list<Object*> &out);
|
||||
|
||||
void SetLocalPosition(const Vector &v);
|
||||
const Vector &GetLocalPosition()const;
|
||||
void SetLocalScale(const Vector & v);
|
||||
const Vector &GetLocalScale()const;
|
||||
void SetLocalRotation(const Quat &q);
|
||||
const Quat &GetLocalRotation()const;
|
||||
void SetLocalTransform(const Transform &t);
|
||||
const Transform &GetLocalTransform()const;
|
||||
|
||||
void SetWorldPosition(const Vector &v);
|
||||
const Vector &GetWorldPosition()const;
|
||||
void SetWorldScale(const Vector &v);
|
||||
const Vector &GetWorldScale()const;
|
||||
void SetWorldRotation(const Quat &q);
|
||||
const Quat &GetWorldRotation()const;
|
||||
void SetWorldTransform(const Transform &t);
|
||||
const Transform &GetWorldTransform()const;
|
||||
|
||||
Entity* GetChildren()const { return m_children; }
|
||||
Entity* GetSuccessor()const { return m_listNext; }
|
||||
|
||||
|
||||
static Entity* GetEntityOrphans() { return _orphans; }
|
||||
|
||||
private:
|
||||
Entity *m_listNext, *m_listPrev, *m_parent, *m_children, *m_last_child;
|
||||
|
||||
static Entity *_orphans, *_last_orphan;
|
||||
|
||||
bool m_isVisible, m_isEnabled;
|
||||
|
||||
std::string m_name;
|
||||
|
||||
mutable int invalid;
|
||||
|
||||
Quat m_localRotation;
|
||||
Vector m_localPosition, m_localScale;
|
||||
mutable Transform m_localTransform;
|
||||
|
||||
mutable Quat m_worldRotation;
|
||||
mutable Vector m_worldPosition, m_worldScale;
|
||||
mutable Transform m_worldTransform;
|
||||
|
||||
void InsertChildToParent();
|
||||
void RemoveParent();
|
||||
void invalidateLocal();
|
||||
void InvalidateWorldTransform();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "frustum.hpp"
|
||||
|
||||
Frustum::Frustum(){
|
||||
}
|
||||
|
||||
Frustum::Frustum( float nr,float fr,float w,float h ){
|
||||
verts[VERT_TLNEAR]=Vector( w*-.5f,h*+.5f,nr );
|
||||
verts[VERT_TRNEAR]=Vector( w*+.5f,h*+.5f,nr );
|
||||
verts[VERT_BRNEAR]=Vector( w*+.5f,h*-.5f,nr );
|
||||
verts[VERT_BLNEAR]=Vector( w*-.5f,h*-.5f,nr );
|
||||
float t=fr/nr;
|
||||
verts[VERT_TLFAR]=verts[VERT_TLNEAR] * t;
|
||||
verts[VERT_TRFAR]=verts[VERT_TRNEAR] * t;
|
||||
verts[VERT_BRFAR]=verts[VERT_BRNEAR] * t;
|
||||
verts[VERT_BLFAR]=verts[VERT_BLNEAR] * t;
|
||||
verts[VERT_EYE]=Vector();
|
||||
makePlanes();
|
||||
}
|
||||
|
||||
Frustum::Frustum( const Frustum &f,const Transform &t ){
|
||||
for( int k=0;k<9;++k ){
|
||||
verts[k]=t*f.verts[k];
|
||||
}
|
||||
makePlanes();
|
||||
}
|
||||
|
||||
bool Frustum::cull( const Vector v[],int cnt )const{
|
||||
for( int n=0;n<6;++n ){
|
||||
int k;
|
||||
for( k=0;k<cnt && planes[n].distance( v[k] )<0;++k ){}
|
||||
if( k==cnt ) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Frustum::cull( const Box &b )const{
|
||||
Vector v[8];
|
||||
for( int k=0;k<8;++k ) v[k]=b.corner(k);
|
||||
return cull( v,8 );
|
||||
}
|
||||
|
||||
void Frustum::makePlanes(){
|
||||
planes[PLANE_TOP]=Plane( verts[VERT_EYE],verts[VERT_TRFAR],verts[VERT_TLFAR] );
|
||||
planes[PLANE_LEFT]=Plane( verts[VERT_EYE],verts[VERT_TLFAR],verts[VERT_BLFAR] );
|
||||
planes[PLANE_BOTTOM]=Plane( verts[VERT_EYE],verts[VERT_BLFAR],verts[VERT_BRFAR] );
|
||||
planes[PLANE_RIGHT]=Plane( verts[VERT_EYE],verts[VERT_BRFAR],verts[VERT_TRFAR] );
|
||||
planes[PLANE_NEAR]=Plane( verts[VERT_TRNEAR],verts[VERT_TLNEAR],verts[VERT_BLNEAR] );
|
||||
planes[PLANE_FAR]=Plane( verts[VERT_TLFAR],verts[VERT_TRFAR],verts[VERT_BRFAR] );
|
||||
if( planes[PLANE_NEAR].distance( verts[VERT_EYE] )>0 ){
|
||||
for( int k=0;k<6;++k ) planes[k]=-planes[k];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
#ifndef FRUSTUM_H
|
||||
#define FRUSTUM_H
|
||||
|
||||
#include "geom.hpp"
|
||||
|
||||
class Frustum{
|
||||
public:
|
||||
enum{
|
||||
VERT_TLNEAR=0,VERT_TRNEAR,VERT_BRNEAR,VERT_BLNEAR,
|
||||
VERT_TLFAR,VERT_TRFAR,VERT_BRFAR,VERT_BLFAR,VERT_EYE
|
||||
};
|
||||
enum{
|
||||
PLANE_TOP=0,PLANE_LEFT,PLANE_BOTTOM,PLANE_RIGHT,PLANE_NEAR,PLANE_FAR
|
||||
};
|
||||
Frustum();
|
||||
Frustum( float nr,float fr,float w,float h );
|
||||
Frustum( const Frustum &f,const Transform &t );
|
||||
|
||||
bool cull( const Box &box )const;
|
||||
bool cull( const Vector vecs[],int cnt )const;
|
||||
|
||||
const Plane &getPlane( int n )const{ return planes[n]; }
|
||||
const Vector &getVertex( int n )const{ return verts[n]; }
|
||||
|
||||
private:
|
||||
Plane planes[6];
|
||||
Vector verts[9];
|
||||
void makePlanes();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "geom.hpp"
|
||||
|
||||
Matrix Matrix::tmps[64];
|
||||
Transform Transform::tmps[64];
|
||||
|
||||
Quat rotationQuat( float p,float y,float r ){
|
||||
return yawQuat(y)*pitchQuat(p)*rollQuat(r);
|
||||
}
|
||||
|
||||
/*
|
||||
Quat rotationQuat( float p,float y,float r ){
|
||||
float sp=sin(p/-2),cp=cos(p/-2);
|
||||
float sy=sin(y/ 2),cy=cos(y/ 2);
|
||||
float sr=sin(r/-2),cr=cos(r/-2);
|
||||
float qw=cr*cp*cy + sr*sp*sy;
|
||||
float qx=cr*sp*cy + sr*cp*sy;
|
||||
float qy=cr*cp*sy - sr*sp*cy;
|
||||
float qz=sr*cp*cy - cr*sp*sy;
|
||||
return Quat( qw,Vector(-qx,-qy,qz) );
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,556 @@
|
||||
|
||||
#ifndef GEOM_H
|
||||
#define GEOM_H
|
||||
|
||||
#include <math.h>
|
||||
|
||||
class Vector;
|
||||
class Line;
|
||||
class Plane;
|
||||
class Matrix;
|
||||
class Transform;
|
||||
|
||||
static float PI = 3.14159265359f; //180 degrees
|
||||
static float TWOPI = PI*2.0f; //360 degrees
|
||||
static float HALFPI = PI*.5f; //90 degrees
|
||||
static float QUARTERPI = PI*.25f; //45 degrees
|
||||
|
||||
class Vector {
|
||||
public:
|
||||
float x, y, z;
|
||||
|
||||
Vector() :x(0), y(0), z(0) {
|
||||
}
|
||||
Vector(float x, float y, float z) :x(x), y(y), z(z) {
|
||||
}
|
||||
operator float*() {
|
||||
return &x;
|
||||
}
|
||||
operator const float *() {
|
||||
return &x;
|
||||
}
|
||||
float &operator[](int n) {
|
||||
return (&x)[n];
|
||||
}
|
||||
float operator[](int n)const {
|
||||
return (&x)[n];
|
||||
}
|
||||
Vector operator-()const {
|
||||
return Vector(-x, -y, -z);
|
||||
}
|
||||
Vector operator*(float scale)const {
|
||||
return Vector(x*scale, y*scale, z*scale);
|
||||
}
|
||||
Vector operator*(const Vector &q)const {
|
||||
return Vector(x*q.x, y*q.y, z*q.z);
|
||||
}
|
||||
Vector operator/(float scale)const {
|
||||
return Vector(x / scale, y / scale, z / scale);
|
||||
}
|
||||
Vector operator/(const Vector &q)const {
|
||||
return Vector(x / q.x, y / q.y, z / q.z);
|
||||
}
|
||||
Vector operator+(const Vector &q)const {
|
||||
return Vector(x + q.x, y + q.y, z + q.z);
|
||||
}
|
||||
Vector operator-(const Vector &q)const {
|
||||
return Vector(x - q.x, y - q.y, z - q.z);
|
||||
}
|
||||
Vector &operator*=(float scale) {
|
||||
x *= scale; y *= scale; z *= scale; return *this;
|
||||
}
|
||||
Vector &operator*=(const Vector &q) {
|
||||
x *= q.x; y *= q.y; z *= q.z; return *this;
|
||||
}
|
||||
Vector &operator/=(float scale) {
|
||||
x /= scale; y /= scale; z /= scale; return *this;
|
||||
}
|
||||
Vector &operator/=(const Vector &q) {
|
||||
x /= q.x; y /= q.y; z /= q.z; return *this;
|
||||
}
|
||||
Vector &operator+=(const Vector &q) {
|
||||
x += q.x; y += q.y; z += q.z; return *this;
|
||||
}
|
||||
Vector &operator-=(const Vector &q) {
|
||||
x -= q.x; y -= q.y; z -= q.z; return *this;
|
||||
}
|
||||
bool operator<(const Vector &q)const {
|
||||
if (fabs(x - q.x) > FLT_EPSILON) return x < q.x ? true : false;
|
||||
if (fabs(y - q.y) > FLT_EPSILON) return y < q.y ? true : false;
|
||||
return fabs(z - q.z) > FLT_EPSILON && z < q.z;
|
||||
}
|
||||
bool operator==(const Vector &q)const {
|
||||
return fabs(x - q.x) <= FLT_EPSILON && fabs(y - q.y) <= FLT_EPSILON && fabs(z - q.z) <= FLT_EPSILON;
|
||||
}
|
||||
bool operator!=(const Vector &q)const {
|
||||
return fabs(x - q.x) > FLT_EPSILON || fabs(y - q.y) > FLT_EPSILON || fabs(z - q.z) > FLT_EPSILON;
|
||||
}
|
||||
float dot(const Vector &q)const {
|
||||
return x*q.x + y*q.y + z*q.z;
|
||||
}
|
||||
Vector cross(const Vector &q)const {
|
||||
return Vector(y*q.z - z*q.y, z*q.x - x*q.z, x*q.y - y*q.x);
|
||||
}
|
||||
float length()const {
|
||||
return sqrtf(x*x + y*y + z*z);
|
||||
}
|
||||
float distance(const Vector &q)const {
|
||||
float dx = x - q.x, dy = y - q.y, dz = z - q.z; return sqrtf(dx*dx + dy*dy + dz*dz);
|
||||
}
|
||||
Vector normalized()const {
|
||||
float l = length(); return Vector(x / l, y / l, z / l);
|
||||
}
|
||||
void normalize() {
|
||||
float l = length(); x /= l; y /= l; z /= l;
|
||||
}
|
||||
float yaw()const {
|
||||
return -atan2f(x, z);
|
||||
}
|
||||
float pitch()const {
|
||||
return -atan2f(y, sqrtf(x*x + z*z));
|
||||
}
|
||||
void clear() {
|
||||
x = y = z = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class Line {
|
||||
public:
|
||||
Vector o, d;
|
||||
Line() {
|
||||
}
|
||||
Line(const Vector &o, const Vector &d) :o(o), d(d) {
|
||||
}
|
||||
Line operator+(const Vector &q)const {
|
||||
return Line(o + q, d);
|
||||
}
|
||||
Line operator-(const Vector &q)const {
|
||||
return Line(o - q, d);
|
||||
}
|
||||
Vector operator*(float q)const {
|
||||
return o + d*q;
|
||||
}
|
||||
Vector nearest(const Vector &q)const {
|
||||
return o + d*(d.dot(q - o) / d.dot(d));
|
||||
}
|
||||
};
|
||||
|
||||
class Plane {
|
||||
public:
|
||||
Vector n;
|
||||
float d;
|
||||
|
||||
Plane() :d(0) {
|
||||
}
|
||||
//normal/offset form
|
||||
Plane(const Vector &n, float d) :n(n), d(d) {
|
||||
}
|
||||
//point/normal form
|
||||
Plane(const Vector &p, const Vector &n) :n(n), d(-n.dot(p)) {
|
||||
}
|
||||
//create plane from tri
|
||||
Plane(const Vector &v0, const Vector &v1, const Vector &v2) {
|
||||
n = (v1 - v0).cross(v2 - v0).normalized(); d = -n.dot(v0);
|
||||
}
|
||||
Plane operator-()const {
|
||||
return Plane(-n, -d);
|
||||
}
|
||||
float t_intersect(const Line &q)const {
|
||||
return -distance(q.o) / n.dot(q.d);
|
||||
}
|
||||
Vector intersect(const Line &q)const {
|
||||
return q*t_intersect(q);
|
||||
}
|
||||
Line intersect(const Plane &q)const {
|
||||
Vector lv = n.cross(q.n).normalized();
|
||||
return Line(q.intersect(Line(nearest(n*-d), n.cross(lv))), lv);
|
||||
}
|
||||
Vector nearest(const Vector &q)const {
|
||||
return q - n*distance(q);
|
||||
}
|
||||
void negate() {
|
||||
n = -n; d = -d;
|
||||
}
|
||||
float distance(const Vector &q)const {
|
||||
return n.dot(q) + d;
|
||||
}
|
||||
};
|
||||
|
||||
struct Quat {
|
||||
float w;
|
||||
Vector v;
|
||||
Quat() :w(1) {
|
||||
}
|
||||
Quat(float w, const Vector &v) :w(w), v(v) {
|
||||
}
|
||||
Quat operator-()const {
|
||||
return Quat(w, -v);
|
||||
}
|
||||
Quat operator+(const Quat &q)const {
|
||||
return Quat(w + q.w, v + q.v);
|
||||
}
|
||||
Quat operator-(const Quat &q)const {
|
||||
return Quat(w - q.w, v - q.v);
|
||||
}
|
||||
Quat operator*(const Quat &q)const {
|
||||
return Quat(w*q.w - v.dot(q.v), q.v.cross(v) + q.v*w + v*q.w);
|
||||
}
|
||||
Vector operator*(const Vector &q)const {
|
||||
return (*this * Quat(0, q) * -*this).v;
|
||||
}
|
||||
Quat operator*(float q)const {
|
||||
return Quat(w*q, v*q);
|
||||
}
|
||||
Quat operator/(float q)const {
|
||||
return Quat(w / q, v / q);
|
||||
}
|
||||
float dot(const Quat &q)const {
|
||||
return v.x*q.v.x + v.y*q.v.y + v.z*q.v.z + w*q.w;
|
||||
}
|
||||
float length()const {
|
||||
return sqrtf(w*w + v.x*v.x + v.y*v.y + v.z*v.z);
|
||||
}
|
||||
void normalize() {
|
||||
*this = *this / length();
|
||||
}
|
||||
Quat normalized()const {
|
||||
return *this / length();
|
||||
}
|
||||
Quat slerpTo(const Quat &q, float a)const {
|
||||
Quat t = q;
|
||||
float d = dot(q), b = 1 - a;
|
||||
if (d < 0) { t.w = -t.w; t.v = -t.v; d = -d; }
|
||||
if (d < 1 - FLT_EPSILON) {
|
||||
float om = acosf(d);
|
||||
float si = sinf(om);
|
||||
a = sinf(a*om) / si;
|
||||
b = sinf(b*om) / si;
|
||||
}
|
||||
return *this*b + t*a;
|
||||
}
|
||||
Vector i()const {
|
||||
float xz = v.x*v.z, wy = w*v.y;
|
||||
float xy = v.x*v.y, wz = w*v.z;
|
||||
float yy = v.y*v.y, zz = v.z*v.z;
|
||||
return Vector(1 - 2 * (yy + zz), 2 * (xy - wz), 2 * (xz + wy));
|
||||
}
|
||||
Vector j()const {
|
||||
float yz = v.y*v.z, wx = w*v.x;
|
||||
float xy = v.x*v.y, wz = w*v.z;
|
||||
float xx = v.x*v.x, zz = v.z*v.z;
|
||||
return Vector(2 * (xy + wz), 1 - 2 * (xx + zz), 2 * (yz - wx));
|
||||
}
|
||||
Vector k()const {
|
||||
float xz = v.x*v.z, wy = w*v.y;
|
||||
float yz = v.y*v.z, wx = w*v.x;
|
||||
float xx = v.x*v.x, yy = v.y*v.y;
|
||||
return Vector(2 * (xz - wy), 2 * (yz + wx), 1 - 2 * (xx + yy));
|
||||
}
|
||||
};
|
||||
|
||||
class Matrix {
|
||||
static Matrix tmps[64];
|
||||
static Matrix &alloc_tmp() { static int tmp = 0; return tmps[tmp++ & 63]; }
|
||||
friend class Transform;
|
||||
public:
|
||||
Vector i, j, k;
|
||||
|
||||
Matrix() :i(Vector(1, 0, 0)), j(Vector(0, 1, 0)), k(Vector(0, 0, 1)) {
|
||||
}
|
||||
Matrix(const Vector &i, const Vector &j, const Vector &k) :i(i), j(j), k(k) {
|
||||
}
|
||||
Matrix(const Quat &q) {
|
||||
float xx = q.v.x*q.v.x, yy = q.v.y*q.v.y, zz = q.v.z*q.v.z;
|
||||
float xy = q.v.x*q.v.y, xz = q.v.x*q.v.z, yz = q.v.y*q.v.z;
|
||||
float wx = q.w*q.v.x, wy = q.w*q.v.y, wz = q.w*q.v.z;
|
||||
i = Vector(1 - 2 * (yy + zz), 2 * (xy - wz), 2 * (xz + wy)),
|
||||
j = Vector(2 * (xy + wz), 1 - 2 * (xx + zz), 2 * (yz - wx)),
|
||||
k = Vector(2 * (xz - wy), 2 * (yz + wx), 1 - 2 * (xx + yy));
|
||||
}
|
||||
Matrix(float angle, const Vector &axis) {
|
||||
const Vector &u = axis;
|
||||
float c = cosf(angle), s = sinf(angle);
|
||||
float x2 = axis.x*axis.x, y2 = axis.y*axis.y, z2 = axis.z*axis.z;
|
||||
i = Vector(x2 + c*(1 - x2), u.x*u.y*(1 - c) - u.z*s, u.z*u.x*(1 - c) + u.y*s);
|
||||
j = Vector(u.x*u.y*(1 - c) + u.z*s, y2 + c*(1 - y2), u.y*u.z*(1 - c) - u.x*s);
|
||||
k = Vector(u.z*u.x*(1 - c) - u.y*s, u.y*u.z*(1 - c) + u.x*s, z2 + c*(1 - z2));
|
||||
}
|
||||
Vector &operator[](int n) {
|
||||
return (&i)[n];
|
||||
}
|
||||
const Vector &operator[](int n)const {
|
||||
return (&i)[n];
|
||||
}
|
||||
Matrix &operator~()const {
|
||||
Matrix &m = alloc_tmp();
|
||||
m.i.x = i.x; m.i.y = j.x; m.i.z = k.x;
|
||||
m.j.x = i.y; m.j.y = j.y; m.j.z = k.y;
|
||||
m.k.x = i.z; m.k.y = j.z; m.k.z = k.z;
|
||||
return m;
|
||||
}
|
||||
float determinant()const {
|
||||
return i.x*(j.y*k.z - j.z*k.y) - i.y*(j.x*k.z - j.z*k.x) + i.z*(j.x*k.y - j.y*k.x);
|
||||
}
|
||||
Matrix &operator-()const {
|
||||
Matrix &m = alloc_tmp();
|
||||
float t = 1.0f / determinant();
|
||||
m.i.x = t*(j.y*k.z - j.z*k.y); m.i.y = -t*(i.y*k.z - i.z*k.y); m.i.z = t*(i.y*j.z - i.z*j.y);
|
||||
m.j.x = -t*(j.x*k.z - j.z*k.x); m.j.y = t*(i.x*k.z - i.z*k.x); m.j.z = -t*(i.x*j.z - i.z*j.x);
|
||||
m.k.x = t*(j.x*k.y - j.y*k.x); m.k.y = -t*(i.x*k.y - i.y*k.x); m.k.z = t*(i.x*j.y - i.y*j.x);
|
||||
return m;
|
||||
}
|
||||
Matrix &cofactor()const {
|
||||
Matrix &m = alloc_tmp();
|
||||
m.i.x = (j.y*k.z - j.z*k.y); m.i.y = -(j.x*k.z - j.z*k.x); m.i.z = (j.x*k.y - j.y*k.x);
|
||||
m.j.x = -(i.y*k.z - i.z*k.y); m.j.y = (i.x*k.z - i.z*k.x); m.j.z = -(i.x*k.y - i.y*k.x);
|
||||
m.k.x = (i.y*j.z - i.z*j.y); m.k.y = -(i.x*j.z - i.z*j.x); m.k.z = (i.x*j.y - i.y*j.x);
|
||||
return m;
|
||||
}
|
||||
bool operator==(const Matrix &q)const {
|
||||
return i == q.i && j == q.j && k == q.k;
|
||||
}
|
||||
bool operator!=(const Matrix &q)const {
|
||||
return i != q.i || j != q.j || k != q.k;
|
||||
}
|
||||
Vector operator*(const Vector &q)const {
|
||||
return Vector(i.x*q.x + j.x*q.y + k.x*q.z, i.y*q.x + j.y*q.y + k.y*q.z, i.z*q.x + j.z*q.y + k.z*q.z);
|
||||
}
|
||||
Matrix &operator*(const Matrix &q)const {
|
||||
Matrix &m = alloc_tmp();
|
||||
m.i.x = i.x*q.i.x + j.x*q.i.y + k.x*q.i.z; m.i.y = i.y*q.i.x + j.y*q.i.y + k.y*q.i.z; m.i.z = i.z*q.i.x + j.z*q.i.y + k.z*q.i.z;
|
||||
m.j.x = i.x*q.j.x + j.x*q.j.y + k.x*q.j.z; m.j.y = i.y*q.j.x + j.y*q.j.y + k.y*q.j.z; m.j.z = i.z*q.j.x + j.z*q.j.y + k.z*q.j.z;
|
||||
m.k.x = i.x*q.k.x + j.x*q.k.y + k.x*q.k.z; m.k.y = i.y*q.k.x + j.y*q.k.y + k.y*q.k.z; m.k.z = i.z*q.k.x + j.z*q.k.y + k.z*q.k.z;
|
||||
return m;
|
||||
}
|
||||
void orthogonalize() {
|
||||
k.normalize();
|
||||
i = j.cross(k).normalized();
|
||||
j = k.cross(i);
|
||||
}
|
||||
Matrix &orthogonalized()const {
|
||||
Matrix &m = alloc_tmp();
|
||||
m = *this; m.orthogonalize();
|
||||
return m;
|
||||
}
|
||||
};
|
||||
|
||||
class Box {
|
||||
public:
|
||||
Vector a, b;
|
||||
Box() :a(Vector(INFINITY, INFINITY, INFINITY)), b(Vector(-INFINITY, -INFINITY, -INFINITY)) {
|
||||
}
|
||||
Box(const Vector &q) :a(q), b(q) {
|
||||
}
|
||||
Box(const Vector &a, const Vector &b) :a(a), b(b) {
|
||||
}
|
||||
Box(const Line &l) :a(l.o), b(l.o) {
|
||||
update(l.o + l.d);
|
||||
}
|
||||
void clear() {
|
||||
a.x = a.y = a.z = INFINITY;
|
||||
b.x = b.y = b.z = -INFINITY;
|
||||
}
|
||||
bool empty()const {
|
||||
return b.x < a.x || b.y < a.y || b.z < a.z;
|
||||
}
|
||||
Vector centre()const {
|
||||
return Vector((a.x + b.x)*.5f, (a.y + b.y)*.5f, (a.z + b.z)*.5f);
|
||||
}
|
||||
Vector corner(int n)const {
|
||||
return Vector(((n & 1) ? b : a).x, ((n & 2) ? b : a).y, ((n & 4) ? b : a).z);
|
||||
}
|
||||
void update(const Vector &q) {
|
||||
if (q.x < a.x) a.x = q.x; if (q.y < a.y) a.y = q.y; if (q.z < a.z) a.z = q.z;
|
||||
if (q.x > b.x) b.x = q.x; if (q.y > b.y) b.y = q.y; if (q.z > b.z) b.z = q.z;
|
||||
}
|
||||
void update(const Box &q) {
|
||||
if (q.a.x < a.x) a.x = q.a.x; if (q.a.y < a.y) a.y = q.a.y; if (q.a.z < a.z) a.z = q.a.z;
|
||||
if (q.b.x > b.x) b.x = q.b.x; if (q.b.y > b.y) b.y = q.b.y; if (q.b.z > b.z) b.z = q.b.z;
|
||||
}
|
||||
bool overlaps(const Box &q)const {
|
||||
return
|
||||
(b.x < q.b.x ? b.x : q.b.x) >= (a.x > q.a.x ? a.x : q.a.x) &&
|
||||
(b.y < q.b.y ? b.y : q.b.y) >= (a.y > q.a.y ? a.y : q.a.y) &&
|
||||
(b.z < q.b.z ? b.z : q.b.z) >= (a.z > q.a.z ? a.z : q.a.z);
|
||||
}
|
||||
void expand(float n) {
|
||||
a.x -= n; a.y -= n; a.z -= n; b.x += n; b.y += n; b.z += n;
|
||||
}
|
||||
float width()const {
|
||||
return b.x - a.x;
|
||||
}
|
||||
float height()const {
|
||||
return b.y - a.y;
|
||||
}
|
||||
float depth()const {
|
||||
return b.z - a.z;
|
||||
}
|
||||
bool contains(const Vector &q) {
|
||||
return q.x >= a.x && q.x <= b.x && q.y >= a.y && q.y <= b.y && q.z >= a.z && q.z <= b.z;
|
||||
}
|
||||
};
|
||||
|
||||
class Transform {
|
||||
static Transform tmps[64];
|
||||
static Transform &alloc_tmp() { static int tmp = 0; return tmps[tmp++ & 63]; }
|
||||
public:
|
||||
Matrix m;
|
||||
Vector v;
|
||||
|
||||
Transform() {
|
||||
}
|
||||
Transform(const Matrix &m) :m(m) {
|
||||
}
|
||||
Transform(const Vector &v) :v(v) {
|
||||
}
|
||||
Transform(const Matrix &m, const Vector &v) :m(m), v(v) {
|
||||
}
|
||||
Transform &operator-()const {
|
||||
Transform &t = alloc_tmp();
|
||||
t.m = -m; t.v = t.m*-v;
|
||||
return t;
|
||||
}
|
||||
Transform &operator~()const {
|
||||
Transform &t = alloc_tmp();
|
||||
t.m = ~m; t.v = t.m*-v;
|
||||
return t;
|
||||
}
|
||||
Vector operator*(const Vector &q)const {
|
||||
return m*q + v;
|
||||
}
|
||||
Line operator*(const Line &q)const {
|
||||
Vector t = (*this)*q.o;
|
||||
return Line(t, (*this)*(q.o + q.d) - t);
|
||||
}
|
||||
Box operator*(const Box &q)const {
|
||||
Box t((*this*q.corner(0)));
|
||||
for (int k = 1; k < 8; ++k) t.update(*this*q.corner(k));
|
||||
return t;
|
||||
}
|
||||
Transform &operator*(const Transform &q)const {
|
||||
Transform &t = alloc_tmp();
|
||||
t.m = m*q.m; t.v = m*q.v + v;
|
||||
return t;
|
||||
}
|
||||
bool operator==(const Transform &q)const {
|
||||
return m == q.m && v == q.v;
|
||||
}
|
||||
bool operator!=(const Transform &q)const {
|
||||
return !operator==(q);
|
||||
}
|
||||
};
|
||||
|
||||
inline float transformRadius(float r, const Matrix &t) {
|
||||
static const float sq_3 = sqrtf(1.0f / 3.0f);
|
||||
return (t * Vector(sq_3, sq_3, sq_3)).length()*r;
|
||||
}
|
||||
|
||||
inline Matrix pitchMatrix(float q) {
|
||||
return Matrix(Vector(1, 0, 0), Vector(0, cosf(q), sinf(q)), Vector(0, -sinf(q), cosf(q)));
|
||||
}
|
||||
|
||||
inline Matrix yawMatrix(float q) {
|
||||
return Matrix(Vector(cosf(q), 0, sinf(q)), Vector(0, 1, 0), Vector(-sinf(q), 0, cosf(q)));
|
||||
}
|
||||
|
||||
inline Matrix rollMatrix(float q) {
|
||||
return Matrix(Vector(cosf(q), sinf(q), 0), Vector(-sinf(q), cosf(q), 0), Vector(0, 0, 1));
|
||||
}
|
||||
|
||||
inline float matrixPitch(const Matrix &m) {
|
||||
return m.k.pitch();
|
||||
// return asinf( -m.k.y );
|
||||
}
|
||||
|
||||
inline float matrixYaw(const Matrix &m) {
|
||||
return m.k.yaw();
|
||||
//return atan2f( -m.k.x,m.k.z );
|
||||
}
|
||||
|
||||
inline float matrixRoll(const Matrix &m) {
|
||||
return atan2f(m.i.y, m.j.y);
|
||||
//Matrix t=pitchMatrix( -matrixPitch(m) )*yawMatrix( -matrixYaw(m) )*m;
|
||||
//return atan2f( t.i.y,t.i.x );
|
||||
}
|
||||
|
||||
inline Matrix scaleMatrix(float x, float y, float z) {
|
||||
return Matrix(Vector(x, 0, 0), Vector(0, y, 0), Vector(0, 0, z));
|
||||
}
|
||||
|
||||
inline Matrix scaleMatrix(const Vector &scale) {
|
||||
return Matrix(Vector(scale.x, 0, 0), Vector(0, scale.y, 0), Vector(0, 0, scale.z));
|
||||
}
|
||||
|
||||
inline Quat pitchQuat(float p) {
|
||||
return Quat(cosf(p / -2), Vector(sinf(p / -2), 0, 0));
|
||||
}
|
||||
|
||||
inline Quat yawQuat(float y) {
|
||||
return Quat(cosf(y / 2), Vector(0, sinf(y / 2), 0));
|
||||
}
|
||||
|
||||
inline Quat rollQuat(float r) {
|
||||
return Quat(cosf(r / -2), Vector(0, 0, sinf(r / -2)));
|
||||
}
|
||||
|
||||
//inline Quat rotationQuat( float p,float y,float r ){
|
||||
// return yawQuat(y)*pitchQuat(p)*rollQuat(r);
|
||||
//}
|
||||
|
||||
Quat rotationQuat(float p, float y, float r);
|
||||
|
||||
inline Matrix rotationMatrix(float p, float y, float r) {
|
||||
return yawMatrix(y)*pitchMatrix(p)*rollMatrix(r);
|
||||
}
|
||||
|
||||
inline Matrix rotationMatrix(const Vector &rot) {
|
||||
return yawMatrix(rot.y)*pitchMatrix(rot.x)*rollMatrix(rot.z);
|
||||
}
|
||||
|
||||
inline float quatPitch(const Quat &q) {
|
||||
return q.k().pitch();
|
||||
}
|
||||
|
||||
inline float quatYaw(const Quat &q) {
|
||||
return q.k().yaw();
|
||||
}
|
||||
|
||||
inline float quatRoll(const Quat &q) {
|
||||
// Vector i=q.i(),j=q.j();
|
||||
// return atan2f( i.y,j.y );
|
||||
return matrixRoll(q);
|
||||
}
|
||||
|
||||
inline Quat matrixQuat(const Matrix &p) {
|
||||
Matrix m = p;
|
||||
m.orthogonalize();
|
||||
float t = m.i.x + m.j.y + m.k.z, w, x, y, z;
|
||||
if (t > FLT_EPSILON) {
|
||||
t = sqrtf(t + 1) * 2;
|
||||
x = (m.k.y - m.j.z) / t;
|
||||
y = (m.i.z - m.k.x) / t;
|
||||
z = (m.j.x - m.i.y) / t;
|
||||
w = t / 4;
|
||||
} else if (m.i.x > m.j.y && m.i.x > m.k.z) {
|
||||
t = sqrtf(m.i.x - m.j.y - m.k.z + 1) * 2;
|
||||
x = t / 4;
|
||||
y = (m.j.x + m.i.y) / t;
|
||||
z = (m.i.z + m.k.x) / t;
|
||||
w = (m.k.y - m.j.z) / t;
|
||||
} else if (m.j.y > m.k.z) {
|
||||
t = sqrtf(m.j.y - m.k.z - m.i.x + 1) * 2;
|
||||
x = (m.j.x + m.i.y) / t;
|
||||
y = t / 4;
|
||||
z = (m.k.y + m.j.z) / t;
|
||||
w = (m.i.z - m.k.x) / t;
|
||||
} else {
|
||||
t = sqrtf(m.k.z - m.j.y - m.i.x + 1) * 2;
|
||||
x = (m.i.z + m.k.x) / t;
|
||||
y = (m.k.y + m.j.z) / t;
|
||||
z = t / 4;
|
||||
w = (m.j.x - m.i.y) / t;
|
||||
}
|
||||
return Quat(w, Vector(x, y, z));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
#ifndef GROUP_H
|
||||
#define GROUP_H
|
||||
|
||||
class Group{
|
||||
|
||||
vector<Object*> _objs;
|
||||
|
||||
public:
|
||||
Group( Object *obj );
|
||||
~Group();
|
||||
|
||||
const vector<Object*> objs()const{ return _objs; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "light.hpp"
|
||||
#include "../gxruntime/gxscene.hpp"
|
||||
|
||||
extern gxScene *gx_scene;
|
||||
|
||||
Light::Light( int type ){
|
||||
light=gx_scene->createLight( type );
|
||||
}
|
||||
|
||||
Light::~Light(){
|
||||
gx_scene->freeLight( light );
|
||||
}
|
||||
|
||||
void Light::setRange( float r ){
|
||||
light->setRange( r );
|
||||
}
|
||||
|
||||
void Light::setColor( const Vector &v ){
|
||||
light->setColor( (float*)&v.x );
|
||||
}
|
||||
|
||||
void Light::setConeAngles( float inner,float outer ){
|
||||
light->setConeAngles( inner,outer );
|
||||
}
|
||||
|
||||
bool Light::beginRender( float tween ){
|
||||
Object::beginRender( tween );
|
||||
light->setPosition( &getRenderTform().v.x );
|
||||
light->setDirection( &getRenderTform().m.k.x );
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
#ifndef LIGHT_H
|
||||
#define LIGHT_H
|
||||
|
||||
#include "geom.hpp"
|
||||
#include "object.hpp"
|
||||
#include "../gxruntime/gxlight.hpp"
|
||||
|
||||
class World;
|
||||
|
||||
class Light : public Object{
|
||||
public:
|
||||
Light( int type );
|
||||
~Light();
|
||||
|
||||
Light *getLight(){ return this; }
|
||||
|
||||
void setRange( float r );
|
||||
void setColor( const Vector &v );
|
||||
void setConeAngles( float inner,float outer );
|
||||
|
||||
bool beginRender( float tween );
|
||||
|
||||
gxLight *getGxLight()const{ return light; }
|
||||
|
||||
private:
|
||||
friend class World;
|
||||
gxLight *light;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "listener.hpp"
|
||||
|
||||
extern gxAudio *gx_audio;
|
||||
|
||||
Listener::Listener( float roll,float dopp,float dist ){
|
||||
if( !gx_audio ) return;
|
||||
|
||||
gx_audio->set3dOptions( roll,dopp,dist );
|
||||
renderListener();
|
||||
}
|
||||
|
||||
Listener::Listener( const Listener &t ):
|
||||
Object(t){
|
||||
}
|
||||
|
||||
Listener::~Listener(){
|
||||
if( !gx_audio ) return;
|
||||
|
||||
Vector pos,vel,up(0,1,1),forward(0,0,1);
|
||||
gx_audio->set3dListener( &pos.x,&vel.x,&forward.x,&up.x );
|
||||
}
|
||||
|
||||
void Listener::renderListener(){
|
||||
if( !gx_audio ) return;
|
||||
|
||||
const Vector &pos=GetWorldTransform().v;
|
||||
const Vector &vel=getVelocity();
|
||||
const Vector &forward=GetWorldTransform().m.k.normalized();
|
||||
const Vector &up=GetWorldTransform().m.j.normalized();
|
||||
|
||||
gx_audio->set3dListener( &pos.x,&vel.x,&forward.x,&up.x );
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
#ifndef LISTENER_H
|
||||
#define LISTENER_H
|
||||
|
||||
#include "object.hpp"
|
||||
|
||||
class Listener : public Object{
|
||||
public:
|
||||
Listener( float roll,float dopp,float dist );
|
||||
Listener( const Listener &t );
|
||||
~Listener();
|
||||
|
||||
//Entity interface
|
||||
Entity *clone(){ return new Listener( *this ); }
|
||||
Listener *getListener(){ return this; }
|
||||
|
||||
//Listener interface
|
||||
void renderListener();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "meshloader.hpp"
|
||||
#include "meshmodel.hpp"
|
||||
|
||||
struct Surf{
|
||||
vector<Surface::Triangle> tris;
|
||||
};
|
||||
|
||||
static map<Brush,Surf*> brush_map;
|
||||
static vector<Surface::Vertex> verts;
|
||||
|
||||
void MeshLoader::clear(){
|
||||
map<Brush,Surf*>::const_iterator it;
|
||||
for( it=brush_map.begin();it!=brush_map.end();++it ){
|
||||
delete it->second;
|
||||
}
|
||||
brush_map.clear();
|
||||
verts.clear();
|
||||
}
|
||||
|
||||
int MeshLoader::numVertices(){
|
||||
return verts.size();
|
||||
}
|
||||
|
||||
void MeshLoader::addVertex( const Surface::Vertex &v ){
|
||||
verts.push_back( v );
|
||||
}
|
||||
|
||||
Surface::Vertex &refVertex( int n ){
|
||||
return verts[n];
|
||||
}
|
||||
|
||||
void MeshLoader::addTriangle( const int verts[3],const Brush &b ){
|
||||
addTriangle( verts[0],verts[1],verts[2],b );
|
||||
}
|
||||
|
||||
void MeshLoader::addTriangle( int v0,int v1,int v2,const Brush &b ){
|
||||
//find surface
|
||||
Surf *surf;
|
||||
map<Brush,Surf*>::const_iterator it=brush_map.find( b );
|
||||
if( it!=brush_map.end() ) surf=it->second;
|
||||
else{
|
||||
surf=d_new Surf;
|
||||
brush_map.insert( make_pair( b,surf ) );
|
||||
}
|
||||
|
||||
Surface::Triangle tri;
|
||||
tri.verts[0]=v0;tri.verts[1]=v1;tri.verts[2]=v2;
|
||||
surf->tris.push_back( tri );
|
||||
}
|
||||
|
||||
void MeshLoader::updateMesh( MeshModel *mesh ){
|
||||
map<int,int> vert_map;
|
||||
map<Brush,Surf*>::iterator it;
|
||||
for( it=brush_map.begin();it!=brush_map.end();++it ){
|
||||
vert_map.clear();
|
||||
Brush b=it->first;
|
||||
Surf *t=it->second;
|
||||
Surface *surf=mesh->findSurface( b );
|
||||
if( !surf ) surf=mesh->createSurface( b );
|
||||
for( int k=0;k<t->tris.size();++k ){
|
||||
for( int j=0;j<3;++j ){
|
||||
int n=t->tris[k].verts[j],id;
|
||||
map<int,int>::const_iterator it=vert_map.find( n );
|
||||
if( it!=vert_map.end() ) id=it->second;
|
||||
else{
|
||||
id=surf->numVertices();
|
||||
surf->addVertex( verts[n] );
|
||||
vert_map.insert( make_pair( n,id ) );
|
||||
}
|
||||
t->tris[k].verts[j]=id;
|
||||
}
|
||||
surf->addTriangle( t->tris[k] );
|
||||
}
|
||||
}
|
||||
clear();
|
||||
}
|
||||
@@ -0,0 +1,521 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "loader_3ds.hpp"
|
||||
#include "meshmodel.hpp"
|
||||
#include "animation.hpp"
|
||||
|
||||
extern gxRuntime *gx_runtime;
|
||||
|
||||
#ifdef BETA
|
||||
#define _log( X ) gx_runtime->debugLog( (string(X)).c_str() );
|
||||
#else
|
||||
#define _log( X )
|
||||
#endif
|
||||
|
||||
class Box;
|
||||
|
||||
static filebuf in;
|
||||
static int chunk_end;
|
||||
static vector<int> parent_end;
|
||||
static unsigned short anim_len;
|
||||
|
||||
static bool conv,flip_tris;
|
||||
static Transform conv_tform;
|
||||
static bool collapse,animonly;
|
||||
|
||||
struct Face3DS{
|
||||
int verts[3];
|
||||
Brush brush;
|
||||
};
|
||||
|
||||
static vector<Face3DS> faces;
|
||||
//static vector<Surface::Vertex> vertices;
|
||||
|
||||
static map<string,Brush> materials_map;
|
||||
static map<string,MeshModel*> name_map;
|
||||
static map<int,MeshModel*> id_map;
|
||||
|
||||
static int nextChunk(){
|
||||
in.pubseekoff( chunk_end,ios_base::beg );
|
||||
if( chunk_end==parent_end.back() ) return 0;
|
||||
unsigned short id;int len;
|
||||
in.sgetn( (char*)&id,2 );
|
||||
in.sgetn( (char*)&len,4 );
|
||||
chunk_end=(int)in.pubseekoff( 0,ios_base::cur )+len-6;
|
||||
return id;
|
||||
}
|
||||
|
||||
static void enterChunk(){
|
||||
parent_end.push_back( chunk_end );
|
||||
chunk_end=(int)in.pubseekoff( 0,ios_base::cur );
|
||||
}
|
||||
|
||||
static void leaveChunk(){
|
||||
chunk_end=parent_end.back();
|
||||
parent_end.pop_back();
|
||||
}
|
||||
|
||||
static string parseString(){
|
||||
string t;
|
||||
while( int c=in.sbumpc() ) t+=char(c);
|
||||
return t;
|
||||
}
|
||||
|
||||
enum {
|
||||
CHUNK_RGBF = 0x0010,
|
||||
CHUNK_RGBB = 0x0011,
|
||||
// CHUNK_RBGB2 = 0x0012, // ?? NOT HLS.
|
||||
CHUNK_MAIN = 0x4D4D,
|
||||
CHUNK_SCENE = 0x3D3D,
|
||||
CHUNK_BKGCOLOR = 0x1200,
|
||||
CHUNK_AMBCOLOR = 0x2100,
|
||||
CHUNK_OBJECT = 0x4000,
|
||||
CHUNK_TRIMESH = 0x4100,
|
||||
CHUNK_VERTLIST = 0x4110,
|
||||
CHUNK_FACELIST = 0x4120,
|
||||
CHUNK_FACEMAT = 0x4130,
|
||||
CHUNK_MAPLIST = 0x4140,
|
||||
CHUNK_SMOOLIST = 0x4150,
|
||||
CHUNK_TRMATRIX = 0x4160,
|
||||
CHUNK_LIGHT = 0x4600,
|
||||
CHUNK_SPOTLIGHT = 0x4610,
|
||||
CHUNK_CAMERA = 0x4700,
|
||||
CHUNK_MATERIAL = 0xAFFF,
|
||||
CHUNK_MATNAME = 0xA000,
|
||||
CHUNK_AMBIENT = 0xA010,
|
||||
CHUNK_DIFFUSE = 0xA020,
|
||||
CHUNK_SPECULAR = 0xA030,
|
||||
CHUNK_TEXTURE = 0xA200,
|
||||
CHUNK_BUMPMAP = 0xA230,
|
||||
CHUNK_MAPFILE = 0xA300,
|
||||
CHUNK_KEYFRAMER = 0xB000,
|
||||
CHUNK_MESHINFO = 0xB002,
|
||||
CHUNK_HIERPOS = 0xB030,
|
||||
CHUNK_HIERINFO = 0xB010,
|
||||
CHUNK_FRAMES = 0xB008
|
||||
};
|
||||
|
||||
static Vector parseColor(){
|
||||
Vector v;
|
||||
unsigned char rgb[3];
|
||||
enterChunk();
|
||||
while( int id=nextChunk() ){
|
||||
switch( id ){
|
||||
case CHUNK_RGBF:
|
||||
in.sgetn( (char*)&v,12 );
|
||||
break;
|
||||
case CHUNK_RGBB:
|
||||
in.sgetn( (char*)rgb,3 );
|
||||
v=Vector( rgb[0]/255.0f,rgb[1]/255.0f,rgb[2]/255.0f );
|
||||
}
|
||||
}
|
||||
leaveChunk();
|
||||
return v;
|
||||
}
|
||||
|
||||
static void parseVertList(){
|
||||
unsigned short cnt;
|
||||
in.sgetn( (char*)&cnt,2 );
|
||||
_log( "VertList cnt="+itoa(cnt) );
|
||||
while( cnt-- ){
|
||||
Surface::Vertex v;
|
||||
in.sgetn( (char*)&v.coords,12 );
|
||||
if( conv ) v.coords=conv_tform * v.coords;
|
||||
MeshLoader::addVertex( v );
|
||||
}
|
||||
}
|
||||
|
||||
static void parseFaceMat(){
|
||||
string name=parseString();
|
||||
_log( "FaceMat: "+name );
|
||||
Brush mat=materials_map[name];
|
||||
unsigned short cnt;
|
||||
in.sgetn( (char*)&cnt,2 );
|
||||
while( cnt-- ){
|
||||
unsigned short face;
|
||||
in.sgetn( (char*)&face,2 );
|
||||
faces[face].brush=mat;
|
||||
}
|
||||
}
|
||||
|
||||
static void parseFaceList(){
|
||||
unsigned short cnt;
|
||||
in.sgetn( (char*)&cnt,2 );
|
||||
_log( "FaceList cnt="+itoa(cnt) );
|
||||
while( cnt-- ){
|
||||
unsigned short v[4];
|
||||
in.sgetn( (char*)v,8 );
|
||||
Face3DS face;
|
||||
face.verts[0]=v[0];
|
||||
face.verts[1]=v[1];
|
||||
face.verts[2]=v[2];
|
||||
if( flip_tris ) std::swap( face.verts[1],face.verts[2] );
|
||||
faces.push_back( face );
|
||||
}
|
||||
enterChunk();
|
||||
while( int id=nextChunk() ){
|
||||
switch( id ){
|
||||
case CHUNK_FACEMAT:
|
||||
parseFaceMat();
|
||||
break;
|
||||
}
|
||||
}
|
||||
leaveChunk();
|
||||
}
|
||||
|
||||
static void parseMapList(){
|
||||
_log( "MapList" );
|
||||
unsigned short cnt;
|
||||
in.sgetn( (char*)&cnt,2 );
|
||||
for( int k=0;k<cnt;++k ){
|
||||
float uv[2];
|
||||
in.sgetn( (char*)uv,8 );
|
||||
Surface::Vertex &v=MeshLoader::refVertex( k );
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=uv[0];
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=1-uv[1];
|
||||
// v->tex_coords[0]=v->tex_coords[1]=Vector( uv[0],1-uv[1],1 );
|
||||
}
|
||||
}
|
||||
|
||||
static void parseTriMesh( MeshModel *mesh ){
|
||||
_log( "TriMesh" );
|
||||
enterChunk();
|
||||
Transform tform;
|
||||
|
||||
faces.clear();
|
||||
|
||||
MeshLoader::beginMesh();
|
||||
|
||||
while( int id=nextChunk() ){
|
||||
switch( id ){
|
||||
case CHUNK_VERTLIST:
|
||||
if( !animonly ) parseVertList();
|
||||
break;
|
||||
case CHUNK_MAPLIST:
|
||||
if( !animonly ) parseMapList();
|
||||
break;
|
||||
case CHUNK_FACELIST:
|
||||
if( !animonly ) parseFaceList();
|
||||
break;
|
||||
case CHUNK_TRMATRIX:
|
||||
in.sgetn( (char*)&tform,48 );
|
||||
if( conv ) tform=conv_tform * tform * -conv_tform;
|
||||
break;
|
||||
}
|
||||
}
|
||||
leaveChunk();
|
||||
|
||||
//should really do something here...
|
||||
// bool neg_x=tform.m.j.cross(tform.m.k).dot(tform.m.i)<0;
|
||||
|
||||
int k;
|
||||
|
||||
mesh->SetWorldTransform( tform );
|
||||
|
||||
if( animonly ){
|
||||
MeshLoader::endMesh( 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
Transform inv_tform=-tform;
|
||||
for( k=0;k<MeshLoader::numVertices();++k ){
|
||||
Surface::Vertex &v=MeshLoader::refVertex( k );
|
||||
v.coords=inv_tform * v.coords;
|
||||
}
|
||||
|
||||
for( k=0;k<faces.size();++k ){
|
||||
const Face3DS &f=faces[k];
|
||||
MeshLoader::addTriangle( f.verts,f.brush );
|
||||
}
|
||||
|
||||
MeshLoader::endMesh( mesh );
|
||||
mesh->updateNormals();
|
||||
|
||||
faces.clear();
|
||||
}
|
||||
|
||||
static void parseObject( MeshModel *root ){
|
||||
//skip name
|
||||
string name=parseString();
|
||||
_log( "Object:"+name );
|
||||
MeshModel *mesh=0;
|
||||
|
||||
enterChunk();
|
||||
while( int id=nextChunk() ){
|
||||
switch( id ){
|
||||
case CHUNK_TRIMESH:
|
||||
mesh=new MeshModel();
|
||||
mesh->SetName( name );
|
||||
mesh->SetParent( root );
|
||||
name_map[name]=mesh;
|
||||
parseTriMesh( mesh );
|
||||
break;
|
||||
}
|
||||
}
|
||||
leaveChunk();
|
||||
}
|
||||
|
||||
static void parseMaterial(){
|
||||
_log( "Material" );
|
||||
Brush mat;
|
||||
string name,tex_name;
|
||||
enterChunk();
|
||||
while( int id=nextChunk() ){
|
||||
switch( id ){
|
||||
case CHUNK_MATNAME:
|
||||
name=parseString();
|
||||
break;
|
||||
case CHUNK_DIFFUSE:
|
||||
mat.setColor( parseColor() );
|
||||
break;
|
||||
case CHUNK_AMBIENT:
|
||||
break;
|
||||
case CHUNK_SPECULAR:
|
||||
break;
|
||||
case CHUNK_TEXTURE:
|
||||
enterChunk();
|
||||
while( int id=nextChunk() ){
|
||||
switch( id ){
|
||||
case CHUNK_MAPFILE:
|
||||
tex_name=parseString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
leaveChunk();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( tex_name.size() ){
|
||||
mat.setTexture( 0,Texture( tex_name,0 ),0 );
|
||||
mat.setColor( Vector( 1,1,1 ) );
|
||||
}
|
||||
if( name.size() ){
|
||||
materials_map[name]=mat;
|
||||
}
|
||||
leaveChunk();
|
||||
}
|
||||
|
||||
static void parseScene( MeshModel *root ){
|
||||
_log( "Scene" );
|
||||
enterChunk();
|
||||
while( int id=nextChunk() ){
|
||||
switch( id ){
|
||||
case CHUNK_OBJECT:
|
||||
parseObject( root );
|
||||
break;
|
||||
case CHUNK_MATERIAL:
|
||||
if( !animonly ) parseMaterial();
|
||||
break;
|
||||
}
|
||||
}
|
||||
leaveChunk();
|
||||
}
|
||||
|
||||
static void parseAnimKeys( Animation *anim,int type ){
|
||||
|
||||
int cnt=0;
|
||||
short t_flags;
|
||||
in.sgetn( (char*)&t_flags,2 );
|
||||
in.pubseekoff( 8,ios_base::cur );
|
||||
in.sgetn( (char*)&cnt,2 );
|
||||
in.pubseekoff( 2,ios_base::cur );
|
||||
_log( "ANIM_TRACK: frames="+itoa( cnt ) );
|
||||
Vector pos,axis,scale;
|
||||
float angle;
|
||||
Quat quat;
|
||||
for( int k=0;k<cnt;++k ){
|
||||
int time;
|
||||
short flags;
|
||||
in.sgetn( (char*)&time,4 );
|
||||
in.sgetn( (char*)&flags,2 );
|
||||
float tens=0,cont=0,bias=0,ease_to=0,ease_from=0;
|
||||
if( flags & 1 ) in.sgetn( (char*)&tens,4 );
|
||||
if( flags & 2 ) in.sgetn( (char*)&cont,4 );
|
||||
if( flags & 4 ) in.sgetn( (char*)&bias,4 );
|
||||
if( flags & 8 ) in.sgetn( (char*)&ease_to,4 );
|
||||
if( flags & 16 ) in.sgetn( (char*)&ease_from,4 );
|
||||
switch( type ){
|
||||
case 0xb020: //POS_TRACK_TAG
|
||||
in.sgetn( (char*)&pos,12 );
|
||||
if( conv ) pos=conv_tform*pos;
|
||||
// _log( "POS_KEY: time="+itoa(time)+" pos="+ftoa( pos.x )+","+ftoa( pos.y )+","+ftoa( pos.z ) );
|
||||
if( time<=anim_len ) anim->setPositionKey( time,pos );
|
||||
break;
|
||||
case 0xb021: //ROT_TRACK_TAG
|
||||
in.sgetn( (char*)&angle,4 );
|
||||
in.sgetn( (char*)&axis,12 );
|
||||
// _log( "ROT_KEY: time="+itoa(time)+" angle="+ftoa(angle)+" axis="+ftoa(axis.x)+","+ftoa(axis.y)+","+ftoa(axis.z) );
|
||||
if( axis.length()>FLT_EPSILON ){
|
||||
if( flip_tris ) angle=-angle;
|
||||
if( conv ) axis=conv_tform.m*axis;
|
||||
quat=Quat( cosf( angle/2 ),axis.normalized()*sinf( angle/2 ) )*quat;
|
||||
quat.normalize();
|
||||
}
|
||||
if( time<=anim_len ) anim->setRotationKey( time,quat );
|
||||
break;
|
||||
case 0xb022: //SCL_TRACK_TAG
|
||||
in.sgetn( (char*)&scale,12 );
|
||||
if( conv ) scale=conv_tform.m*scale;
|
||||
// scale.x=fabs(scale.x);scale.y=fabs(scale.y);scale.z=fabs(scale.z);
|
||||
_log( "SCL_KEY: time="+itoa(time)+" scale="+ftoa( scale.x )+","+ftoa( scale.y )+","+ftoa( scale.z ) );
|
||||
if( time<=anim_len ) anim->setScaleKey( time,scale );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parseMeshInfo( MeshModel *root,float curr_time ){
|
||||
_log( "OBJECT_NODE_TAG" );
|
||||
enterChunk();
|
||||
string name,inst;
|
||||
Vector pivot;
|
||||
Animation anim;
|
||||
unsigned short id=65535,parent=65535,flags1,flags2;
|
||||
Box box = Box( Vector(),Vector() );
|
||||
Vector box_centre;
|
||||
while( int chunk_id=nextChunk() ){
|
||||
switch( chunk_id ){
|
||||
case 0xb030: //NODE_ID
|
||||
in.sgetn( (char*)&id,2 );
|
||||
_log( "NODE_ID: "+itoa(id) );
|
||||
break;
|
||||
case 0xb010: //NODE_HDR
|
||||
name=parseString();
|
||||
in.sgetn( (char*)&flags1,2 );
|
||||
in.sgetn( (char*)&flags2,2 );
|
||||
in.sgetn( (char*)&parent,2 );
|
||||
_log( "NODE_HDR: name="+name+" parent="+itoa(parent) );
|
||||
break;
|
||||
case 0xb011: //INSTANCE NAME
|
||||
inst=parseString();
|
||||
_log( "INSTANCE_NAME: "+inst );
|
||||
break;
|
||||
case 0xb013: //PIVOT
|
||||
in.sgetn( (char*)&pivot,12 );
|
||||
if( conv ) pivot=conv_tform * pivot;
|
||||
_log( "PIVOT: "+ftoa(pivot.x)+","+ftoa(pivot.y)+","+ftoa(pivot.z) );
|
||||
break;
|
||||
case 0xb014: //BOUNDBOX
|
||||
in.sgetn( (char*)&(box.a),12 );
|
||||
in.sgetn( (char*)&(box.b),12 );
|
||||
box_centre=box.centre();
|
||||
if( conv ) box_centre=conv_tform * box_centre;
|
||||
_log( "BOUNDBOX: min="+ftoa(box.a.x)+","+ftoa(box.a.y)+","+ftoa(box.a.z)+" max="+ftoa(box.b.x)+","+ftoa(box.b.y)+","+ftoa(box.b.z) );
|
||||
break;
|
||||
case 0xb020: //POS_TRACK_TAG
|
||||
case 0xb021: //ROT_TRACK_TAG
|
||||
case 0xb022: //SCALE_TRACK_TAG
|
||||
if( !collapse ) parseAnimKeys( &anim,chunk_id );
|
||||
break;
|
||||
}
|
||||
}
|
||||
leaveChunk();
|
||||
|
||||
MeshModel *p=root;
|
||||
if( parent!=65535 ){
|
||||
map<int,MeshModel*>::const_iterator it=id_map.find( parent );
|
||||
if( it==id_map.end() ) return;
|
||||
p=it->second;
|
||||
}
|
||||
MeshModel *mesh=0;
|
||||
if( name=="$$$DUMMY" ){
|
||||
mesh=new MeshModel();
|
||||
mesh->SetName( inst );
|
||||
mesh->SetParent( p );
|
||||
}else{
|
||||
map<string,MeshModel*>::const_iterator it=name_map.find( name );
|
||||
if( it==name_map.end() ) return;
|
||||
mesh=it->second;
|
||||
name_map.erase( name );
|
||||
if( pivot!=Vector() ){
|
||||
mesh->transform( -pivot );
|
||||
}
|
||||
Transform t=
|
||||
mesh->GetWorldTransform();
|
||||
mesh->SetParent( p );
|
||||
mesh->SetWorldTransform( t );
|
||||
}
|
||||
|
||||
mesh->setAnimation( anim );
|
||||
|
||||
if( id!=65535 ) id_map[id]=mesh;
|
||||
}
|
||||
|
||||
static void parseKeyFramer( MeshModel *root ){
|
||||
_log( "KeyFramer" );
|
||||
enterChunk();
|
||||
string file_3ds;
|
||||
unsigned short rev,curr_time=0;
|
||||
while( int id=nextChunk() ){
|
||||
switch( id ){
|
||||
case 0xb009: //CURR_TIME
|
||||
in.sgetn( (char*)&curr_time,2 );
|
||||
_log( "CURR_TIME: "+itoa(curr_time) );
|
||||
break;
|
||||
case 0xb00a: //KFHDR
|
||||
in.sgetn( (char*)&rev,2 );
|
||||
file_3ds=parseString();
|
||||
in.sgetn( (char*)&anim_len,2 );
|
||||
_log( "KFHDR: revision="+itoa(rev)+" 3dsfile="+file_3ds+" anim_len="+itoa(anim_len) );
|
||||
break;
|
||||
case 0xb002: //object keyframer data...
|
||||
parseMeshInfo( root,curr_time );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !collapse ){
|
||||
root->setAnimator( new Animator( root,anim_len ) );
|
||||
}
|
||||
|
||||
leaveChunk();
|
||||
}
|
||||
|
||||
static MeshModel *parseFile(){
|
||||
unsigned short id;int len;
|
||||
in.sgetn( (char*)&id,2 );
|
||||
in.sgetn( (char*)&len,4 );
|
||||
if( id!=CHUNK_MAIN ) return 0;
|
||||
chunk_end=(int)in.pubseekoff( 0,ios_base::cur )+len-6;
|
||||
|
||||
enterChunk();
|
||||
MeshModel *root=new MeshModel();
|
||||
while( int id=nextChunk() ){
|
||||
switch( id ){
|
||||
case CHUNK_SCENE:
|
||||
parseScene( root );
|
||||
break;
|
||||
case CHUNK_KEYFRAMER:
|
||||
parseKeyFramer( root );
|
||||
break;
|
||||
}
|
||||
}
|
||||
leaveChunk();
|
||||
return root;
|
||||
}
|
||||
|
||||
MeshModel *Loader_3DS::load( const string &filename,const Transform &t,int hint ){
|
||||
|
||||
conv_tform=t;
|
||||
conv=flip_tris=false;
|
||||
if( conv_tform!=Transform() ){
|
||||
conv=true;
|
||||
if( conv_tform.m.i.cross(conv_tform.m.j).dot(conv_tform.m.k)<0 ) flip_tris=true;
|
||||
}
|
||||
|
||||
collapse=!!(hint&MeshLoader::HINT_COLLAPSE);
|
||||
animonly=!!(hint&MeshLoader::HINT_ANIMONLY);
|
||||
|
||||
if( !in.open( filename.c_str(),ios_base::in|ios_base::binary ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
MeshModel *root=parseFile();
|
||||
in.close();
|
||||
|
||||
materials_map.clear();
|
||||
name_map.clear();
|
||||
id_map.clear();
|
||||
|
||||
return root;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
#ifndef LOADER_3DS_H
|
||||
#define LOADER_3DS_H
|
||||
|
||||
#include "meshloader.hpp"
|
||||
|
||||
class Loader_3DS : public MeshLoader{
|
||||
public:
|
||||
MeshModel *load( const string &f,const Transform &conv,int hint );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,360 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "loader_b3d.hpp"
|
||||
#include "meshmodel.hpp"
|
||||
#include "pivot.hpp"
|
||||
#include "meshutil.hpp"
|
||||
|
||||
//#define SHOW_BONES
|
||||
|
||||
static FILE *in;
|
||||
static vector<int> chunk_stack;
|
||||
static vector<Texture> textures;
|
||||
static vector<Brush> brushes;
|
||||
static vector<Object*> bones;
|
||||
|
||||
static bool collapse;
|
||||
static bool animonly;
|
||||
|
||||
static int swap_endian( int n ){
|
||||
return ((n&0xff)<<24)|((n&0xff00)<<8)|((n&0xff0000)>>8)|((n&0xff000000)>>24);
|
||||
}
|
||||
|
||||
static void clear(){
|
||||
bones.clear();
|
||||
brushes.clear();
|
||||
textures.clear();
|
||||
chunk_stack.clear();
|
||||
}
|
||||
|
||||
static int readChunk(){
|
||||
int header[2];
|
||||
if( fread( header,8,1,in )<1 ) return 0;
|
||||
chunk_stack.push_back( ftell( in )+header[1] );
|
||||
return swap_endian( header[0] );
|
||||
}
|
||||
|
||||
static void exitChunk(){
|
||||
fseek( in,chunk_stack.back(),SEEK_SET );
|
||||
chunk_stack.pop_back();
|
||||
}
|
||||
|
||||
static int chunkSize(){
|
||||
return chunk_stack.back()-ftell( in );
|
||||
}
|
||||
|
||||
static void read( void *buf,int n ){
|
||||
fread( buf,n,1,in );
|
||||
}
|
||||
|
||||
static void skip( int n ){
|
||||
fseek( in,n,SEEK_CUR );
|
||||
}
|
||||
|
||||
static int readInt(){
|
||||
int n;
|
||||
read( &n,4 );
|
||||
return n;
|
||||
}
|
||||
|
||||
static void readIntArray( int t[],int n ){
|
||||
read( t,n*4 );
|
||||
}
|
||||
|
||||
static float readFloat(){
|
||||
float n;
|
||||
read( &n,4 );
|
||||
return n;
|
||||
}
|
||||
|
||||
static void readFloatArray( float t[],int n ){
|
||||
read( t,n*4 );
|
||||
}
|
||||
|
||||
static void readColor( unsigned *t ){
|
||||
float r=readFloat();if(r<0) r=0;else if(r>1) r=1;
|
||||
float g=readFloat();if(g<0) g=0;else if(g>1) g=1;
|
||||
float b=readFloat();if(b<0) b=0;else if(b>1) b=1;
|
||||
float a=readFloat();if(a<0) a=0;else if(a>1) a=1;
|
||||
*t=(int(a*255)<<24)|(int(r*255)<<16)|(int(g*255)<<8)|int(b*255);
|
||||
}
|
||||
|
||||
static string readString(){
|
||||
string t;
|
||||
for(;;){
|
||||
char c;
|
||||
read( &c,1 );
|
||||
if( !c ) return t;
|
||||
t+=c;
|
||||
}
|
||||
}
|
||||
|
||||
static void readTextures(){
|
||||
while( chunkSize() ){
|
||||
string name=readString();
|
||||
int flags=readInt();
|
||||
int blend=readInt();
|
||||
float pos[2],scl[2];
|
||||
readFloatArray( pos,2 );
|
||||
readFloatArray( scl,2 );
|
||||
float rot=readFloat();
|
||||
|
||||
//create texture
|
||||
Texture tex( name,flags & 0xffff );
|
||||
|
||||
tex.setBlend( blend );
|
||||
if( flags & 0x10000 ) tex.setFlags( gxScene::TEX_COORDS2 );
|
||||
|
||||
if( pos[0]!=0 || pos[1]!=0 ) tex.setPosition( pos[0],pos[1] );
|
||||
if( scl[0]!=1 || scl[1]!=1 ) tex.setScale( scl[0],scl[1] );
|
||||
if( rot!=0 ) tex.setRotation( rot );
|
||||
|
||||
textures.push_back( tex );
|
||||
}
|
||||
}
|
||||
|
||||
static void readBrushes(){
|
||||
int n_texs=readInt();
|
||||
|
||||
int tex_id[8]={-1,-1,-1,-1,-1,-1,-1,-1};
|
||||
|
||||
while( chunkSize() ){
|
||||
string name=readString();
|
||||
float col[4];
|
||||
readFloatArray( col,4 );
|
||||
float shi=readFloat();
|
||||
int blend=readInt();
|
||||
int fx=readInt();
|
||||
readIntArray( tex_id,n_texs );
|
||||
|
||||
Brush bru;
|
||||
|
||||
bru.setColor( Vector( col[0],col[1],col[2] ) );
|
||||
bru.setAlpha( col[3] );
|
||||
bru.setShininess( shi );
|
||||
bru.setBlend( blend );
|
||||
bru.setFX( fx );
|
||||
|
||||
for( int k=0;k<8;++k ){
|
||||
if( tex_id[k]<0 ) continue;
|
||||
bru.setTexture( k,textures[tex_id[k]],0 );
|
||||
}
|
||||
|
||||
brushes.push_back( bru );
|
||||
}
|
||||
}
|
||||
|
||||
static int readVertices(){
|
||||
|
||||
int flags=readInt();
|
||||
int tc_sets=readInt();
|
||||
int tc_size=readInt();
|
||||
|
||||
float tc[4]={0};
|
||||
|
||||
Surface::Vertex t;
|
||||
while( chunkSize() ){
|
||||
readFloatArray( t.coords,3 );
|
||||
if( flags&1 ){
|
||||
readFloatArray( t.normal,3 );
|
||||
}
|
||||
if( flags&2 ){
|
||||
readColor( &t.color );
|
||||
}
|
||||
for( int k=0;k<tc_sets;++k ){
|
||||
readFloatArray( tc,tc_size );
|
||||
if( k<2 ) memcpy( t.tex_coords[k],tc,8 );
|
||||
}
|
||||
MeshLoader::addVertex( t );
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void readTriangles(){
|
||||
int brush_id=readInt();
|
||||
Brush b=brush_id>=0 ? brushes[brush_id] : Brush();
|
||||
while( chunkSize() ){
|
||||
int verts[3];
|
||||
readIntArray( verts,3 );
|
||||
MeshLoader::addTriangle( verts,b );
|
||||
}
|
||||
}
|
||||
|
||||
static int readMesh(){
|
||||
int flags=0;
|
||||
while( chunkSize() ){
|
||||
switch( readChunk() ){
|
||||
case 'VRTS':
|
||||
flags=readVertices();
|
||||
break;
|
||||
case 'TRIS':
|
||||
readTriangles();
|
||||
break;
|
||||
}
|
||||
exitChunk();
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
static Object *readBone(){
|
||||
|
||||
#ifdef SHOW_BONES
|
||||
Brush b;
|
||||
b.setColor( Vector( 1,0,0 ) );
|
||||
b.setAlpha( .75f );
|
||||
MeshModel *bone=MeshUtil::createSphere( b,16 );
|
||||
Transform t;
|
||||
t.m.i.x=.1f;
|
||||
t.m.j.y=.1f;
|
||||
t.m.k.z=.1f;
|
||||
bone->transform( t );
|
||||
#else
|
||||
Pivot *bone=new Pivot();
|
||||
#endif
|
||||
|
||||
bones.push_back( bone );
|
||||
|
||||
while( chunkSize() ){
|
||||
int vert=readInt();
|
||||
float weight=readFloat();
|
||||
MeshLoader::addBone( vert,weight,bones.size() );
|
||||
}
|
||||
return bone;
|
||||
}
|
||||
|
||||
static void readKeys( Animation &anim ){
|
||||
int flags=readInt();
|
||||
while( chunkSize() ){
|
||||
int frame=readInt();
|
||||
if( flags&1 ){
|
||||
float pos[3];
|
||||
readFloatArray( pos,3 );
|
||||
anim.setPositionKey( frame,Vector(pos[0],pos[1],pos[2]) );
|
||||
}
|
||||
if( flags&2 ){
|
||||
float scl[3];
|
||||
readFloatArray( scl,3 );
|
||||
anim.setScaleKey( frame,Vector(scl[0],scl[1],scl[2]) );
|
||||
}
|
||||
if( flags&4 ){
|
||||
float rot[4];
|
||||
readFloatArray( rot,4 );
|
||||
anim.setRotationKey( frame,Quat(rot[0],Vector(rot[1],rot[2],rot[3])) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Object *readObject( Object *parent ){
|
||||
|
||||
Object *obj=0;
|
||||
|
||||
string name=readString();
|
||||
float pos[3],scl[3],rot[4];
|
||||
readFloatArray( pos,3 );
|
||||
readFloatArray( scl,3 );
|
||||
readFloatArray( rot,4 );
|
||||
|
||||
Animation keys;
|
||||
int anim_len=0;
|
||||
MeshModel *mesh=0;
|
||||
int mesh_flags,mesh_brush;
|
||||
|
||||
while( chunkSize() ){
|
||||
switch( readChunk() ){
|
||||
case 'MESH':
|
||||
MeshLoader::beginMesh();
|
||||
obj=mesh=new MeshModel();
|
||||
mesh_brush=readInt();
|
||||
mesh_flags=readMesh();
|
||||
break;
|
||||
case 'BONE':
|
||||
obj=readBone();
|
||||
break;
|
||||
case 'KEYS':
|
||||
readKeys( keys );
|
||||
break;
|
||||
case 'ANIM':
|
||||
readInt();
|
||||
anim_len=readInt();
|
||||
readFloat();
|
||||
break;
|
||||
case 'NODE':
|
||||
if( !obj ) obj=new MeshModel();
|
||||
readObject( obj );
|
||||
break;
|
||||
}
|
||||
exitChunk();
|
||||
}
|
||||
|
||||
if( !obj ) obj=new MeshModel();
|
||||
|
||||
obj->SetName( name );
|
||||
obj->SetLocalPosition( Vector( pos[0],pos[1],pos[2] ) );
|
||||
obj->SetLocalScale( Vector( scl[0],scl[1],scl[2] ) );
|
||||
obj->SetLocalRotation( Quat( rot[0],Vector( rot[1],rot[2],rot[3] ) ) );
|
||||
obj->setAnimation( keys );
|
||||
|
||||
if( mesh ){
|
||||
MeshLoader::endMesh( mesh );
|
||||
if( !(mesh_flags&1) ) mesh->updateNormals();
|
||||
if( mesh_brush!=-1 ) mesh->setBrush( brushes[mesh_brush] );
|
||||
}
|
||||
|
||||
if( mesh && bones.size() ){
|
||||
bones.insert( bones.begin(),mesh );
|
||||
mesh->setAnimator( new Animator( bones,anim_len ) );
|
||||
mesh->createBones();
|
||||
bones.clear();
|
||||
}else if( anim_len ){
|
||||
obj->setAnimator( new Animator( obj,anim_len ) );
|
||||
}
|
||||
|
||||
if( parent ) obj->SetParent( parent );
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
MeshModel *Loader_B3D::load( const string &f,const Transform &conv,int hint ){
|
||||
|
||||
collapse=!!(hint&MeshLoader::HINT_COLLAPSE);
|
||||
animonly=!!(hint&MeshLoader::HINT_ANIMONLY);
|
||||
|
||||
in=fopen( f.c_str(),"rb" );
|
||||
if( !in ) return 0;
|
||||
|
||||
::clear();
|
||||
|
||||
int tag=readChunk();
|
||||
if( tag!='BB3D' ){
|
||||
fclose( in );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int version=readInt();
|
||||
if( version>1 ){
|
||||
fclose( in );
|
||||
return 0;
|
||||
}
|
||||
|
||||
Object *obj=0;
|
||||
while( chunkSize() ){
|
||||
switch( readChunk() ){
|
||||
case 'TEXS':
|
||||
readTextures();
|
||||
break;
|
||||
case 'BRUS':
|
||||
readBrushes();
|
||||
break;
|
||||
case 'NODE':
|
||||
obj=readObject( 0 );
|
||||
break;
|
||||
}
|
||||
exitChunk();
|
||||
}
|
||||
fclose( in );
|
||||
|
||||
::clear();
|
||||
|
||||
return obj ? obj->getModel()->getMeshModel() : 0;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
#ifndef LOADER_B3D_H
|
||||
#define LOADER_B3D_H
|
||||
|
||||
#include "meshloader.hpp"
|
||||
|
||||
class Loader_B3D : public MeshLoader{
|
||||
public:
|
||||
MeshModel *load( const string &f,const Transform &conv,int hint );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,389 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "loader_x.hpp"
|
||||
#include "meshmodel.hpp"
|
||||
#include "animation.hpp"
|
||||
#include "pivot.hpp"
|
||||
|
||||
#include <windows.h>
|
||||
//#include <dxfile.h>
|
||||
#include "../gxruntime/GraphicsRuntime.hpp"
|
||||
#include <d3d9types.h>
|
||||
#include <d3dx9xof.h>
|
||||
#include <rmxfguid.h>
|
||||
#include <rmxftmpl.h>
|
||||
|
||||
extern gxRuntime *gx_runtime;
|
||||
static map<string,MeshModel*> frames_map;
|
||||
static int anim_len;
|
||||
|
||||
static bool conv,flip_tris;
|
||||
static Transform conv_tform;
|
||||
static bool collapse,animonly;
|
||||
|
||||
static void parseAnimKey(ID3DXFileData *fileData, MeshModel *e) {
|
||||
|
||||
DWORD sz;int *data;
|
||||
if( fileData->GetData( 0,&sz,(void**)&data )<0 ) return;
|
||||
|
||||
int type=*data++;
|
||||
int cnt=*data++;
|
||||
Animation anim=e->getAnimation();
|
||||
for( int k=0;k<cnt;++k ){
|
||||
int time=*data++;
|
||||
int n=*data++;
|
||||
if( time>anim_len ) anim_len=time;
|
||||
switch( type ){
|
||||
case 0:
|
||||
if( n==4 ){
|
||||
Quat rot=*(Quat*)data;
|
||||
if( conv ){
|
||||
if( fabs(rot.w)<1-FLT_EPSILON ){
|
||||
rot.normalize();
|
||||
//quat-to-axis/angle
|
||||
float half=acosf( rot.w );
|
||||
if( flip_tris ) half=-half;
|
||||
rot=Quat( cosf( half ),(conv_tform.m*rot.v).normalized()*sinf( half ) );
|
||||
}else rot=Quat();
|
||||
}
|
||||
anim.setRotationKey( time,rot );
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if( n==3 ){
|
||||
Vector scl=*(Vector*)data;
|
||||
if( conv ) scl=conv_tform.m * scl;
|
||||
scl.x=fabs(scl.x);scl.y=fabs(scl.y);scl.z=fabs(scl.z);
|
||||
anim.setScaleKey( time,scl );
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if( n==3 ){
|
||||
Vector pos=*(Vector*)data;
|
||||
if( conv ) pos=conv_tform*pos;
|
||||
anim.setPositionKey( time,pos );
|
||||
}
|
||||
break;
|
||||
}
|
||||
data+=n;
|
||||
}
|
||||
e->setAnimation( anim );
|
||||
}
|
||||
|
||||
static void parseAnim(ID3DXFileData *fileData) {
|
||||
const GUID *guid;
|
||||
IDirectXFileObject *childObj;
|
||||
IDirectXFileData *childData;
|
||||
IDirectXFileDataReference *childRef;
|
||||
MeshModel *frame=0;
|
||||
|
||||
//find the frame reference
|
||||
for( ;fileData->GetNextObject( &childObj )>=0;childObj->Release() ){
|
||||
if( childObj->QueryInterface( IID_IDirectXFileDataReference,(void**)&childRef )>=0 ){
|
||||
if( childRef->Resolve( &childData )>=0 ){
|
||||
if( childData->GetType( &guid )>=0 ){
|
||||
if( *guid==TID_D3DRMFrame ){
|
||||
char name[80];DWORD len=80;
|
||||
if( childData->GetName( name,&len )>=0 ){
|
||||
map<string,MeshModel*>::iterator it=frames_map.find( name );
|
||||
if( it!=frames_map.end() ) frame=it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
childData->Release();
|
||||
}
|
||||
childRef->Release();
|
||||
}else if( frame && childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )>=0 ){
|
||||
if( childData->GetType( &guid )>=0 ){
|
||||
if( *guid==TID_D3DRMAnimationKey ){
|
||||
parseAnimKey( childData,frame );
|
||||
}
|
||||
}
|
||||
childData->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parseAnimSet( IDirectXFileData *fileData ){
|
||||
const GUID *guid;
|
||||
IDirectXFileObject *childObj;
|
||||
IDirectXFileData *childData;
|
||||
|
||||
for( ;fileData->GetNextObject( &childObj )>=0;childObj->Release() ){
|
||||
if( childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )<0 ) continue;
|
||||
if( childData->GetType( &guid )>=0 ){
|
||||
if( *guid==TID_D3DRMAnimation ){
|
||||
parseAnim( childData );
|
||||
}
|
||||
}
|
||||
childData->Release();
|
||||
}
|
||||
}
|
||||
|
||||
static Brush parseMaterial( IDirectXFileData *fileData ){
|
||||
const GUID *guid;
|
||||
IDirectXFileObject *childObj;
|
||||
IDirectXFileData *childData;
|
||||
|
||||
Brush brush;
|
||||
|
||||
DWORD sz;float *data;
|
||||
if( fileData->GetData( 0,&sz,(void**)&data )<0 ) return brush;
|
||||
|
||||
brush.setColor( Vector( data[0],data[1],data[2] ) );
|
||||
if( data[3] ) brush.setAlpha( data[3] );
|
||||
|
||||
for( ;fileData->GetNextObject( &childObj )>=0;childObj->Release() ){
|
||||
if( childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )<0 ) continue;
|
||||
if( childData->GetType( &guid )>=0 ){
|
||||
if( *guid==TID_D3DRMTextureFilename ){
|
||||
DWORD sz;char **data;
|
||||
if( childData->GetData( 0,&sz,(void**)&data )>=0 ){
|
||||
brush.setTexture( 0,Texture( *data,0 ),0 );
|
||||
brush.setColor( Vector( 1,1,1 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
childData->Release();
|
||||
}
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
||||
static void parseMaterialList( IDirectXFileData *fileData,vector<Brush> &mats ){
|
||||
|
||||
const GUID *guid;
|
||||
IDirectXFileObject *childObj;
|
||||
IDirectXFileData *childData;
|
||||
IDirectXFileDataReference *childRef;
|
||||
|
||||
//iterate through child objects...
|
||||
for( ;fileData->GetNextObject( &childObj )>=0;childObj->Release() ){
|
||||
if( childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )>=0 ){
|
||||
if( childData->GetType( &guid )>=0 ){
|
||||
if( *guid==TID_D3DRMMaterial ){
|
||||
mats.push_back( parseMaterial( childData ) );
|
||||
}
|
||||
}
|
||||
childData->Release();
|
||||
}else if( childObj->QueryInterface( IID_IDirectXFileDataReference,(void**)&childRef )>=0 ){
|
||||
if( childRef->Resolve( &childData )>=0 ){
|
||||
if( childData->GetType( &guid )>=0 ){
|
||||
if( *guid==TID_D3DRMMaterial ){
|
||||
mats.push_back( parseMaterial( childData ) );
|
||||
}
|
||||
}
|
||||
childData->Release();
|
||||
}
|
||||
childRef->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FaceX{
|
||||
int *data,mat_index;
|
||||
FaceX( int *d ):data(d),mat_index(0){}
|
||||
};
|
||||
|
||||
static void parseMesh( IDirectXFileData *fileData,MeshModel *mesh ){
|
||||
|
||||
const GUID *guid;
|
||||
IDirectXFileObject *childObj;
|
||||
IDirectXFileData *childData;
|
||||
|
||||
DWORD sz;int *data;
|
||||
if( fileData->GetData( 0,&sz,(void**)&data )<0 ) return;
|
||||
|
||||
//stuff...
|
||||
vector<FaceX> faces;
|
||||
vector<Brush> mats;
|
||||
|
||||
MeshLoader::beginMesh();
|
||||
|
||||
//setup vertices
|
||||
int num_verts=*data++;
|
||||
int k;
|
||||
for( k=0;k<num_verts;++k ){
|
||||
Surface::Vertex v;
|
||||
v.coords=*(Vector*)data;
|
||||
if( conv ) v.coords=conv_tform * v.coords;
|
||||
v.color=0xffffffff;//Vector(1,1,1);
|
||||
MeshLoader::addVertex( v );
|
||||
data+=3;
|
||||
}
|
||||
|
||||
//setup faces
|
||||
int num_faces=*data++;
|
||||
for( k=0;k<num_faces;++k ){
|
||||
faces.push_back( FaceX( data ) );
|
||||
data+=*data+1;
|
||||
}
|
||||
|
||||
bool normals=false;
|
||||
|
||||
//get material and texture info
|
||||
for( ;fileData->GetNextObject( &childObj )>=0;childObj->Release() ){
|
||||
if( childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )<0 ) continue;
|
||||
if( childData->GetType( &guid )>=0 ){
|
||||
DWORD sz;int *data;
|
||||
if( childData->GetData( 0,&sz,(void**)&data )>=0 ){
|
||||
if( *guid==TID_D3DRMMeshMaterialList ){
|
||||
int num_mats=*data++;
|
||||
int num_faces=*data++;
|
||||
for( int k=0;k<num_faces;++k ){
|
||||
faces[k].mat_index=*data++;
|
||||
}
|
||||
parseMaterialList( childData,mats );
|
||||
}else if( *guid==TID_D3DRMMeshTextureCoords ){
|
||||
int num_coords=*data++;
|
||||
if( num_coords==num_verts ){
|
||||
float *coords=(float*)data;
|
||||
for( int k=0;k<num_coords;++k ){
|
||||
Surface::Vertex &v=MeshLoader::refVertex(k);
|
||||
float tu=*coords++;float tv=*coords++;
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=tu;
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=tv;
|
||||
}
|
||||
}
|
||||
}else if( *guid==TID_D3DRMMeshVertexColors ){
|
||||
int num_colors=*data++;
|
||||
if( num_colors==num_verts ){
|
||||
for( int k=0;k<num_colors;++k ){
|
||||
Surface::Vertex &v=MeshLoader::refVertex(*data++);
|
||||
float *t=(float*)data;
|
||||
v.color=0xff000000|(int(t[0]*255)<<16)|(int(t[1]*255)<<8)|int(t[2]*255);
|
||||
// v.color=Vector( t[0],t[1],t[2] );
|
||||
data+=4;
|
||||
}
|
||||
}
|
||||
}else if( *guid==TID_D3DRMMeshNormals ){
|
||||
int num_normals=*data++;
|
||||
if( num_normals==num_verts ){
|
||||
Matrix co=conv_tform.m.cofactor();
|
||||
for( int k=0;k<num_normals;++k ){
|
||||
Surface::Vertex &v=MeshLoader::refVertex(k);
|
||||
v.normal=(co * *(Vector*)data).normalized();
|
||||
data+=3;
|
||||
}
|
||||
normals=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
childData->Release();
|
||||
}
|
||||
if( !mats.size() ) mats.push_back( Brush() );
|
||||
|
||||
for( size_t k=0;k<faces.size();++k ){
|
||||
const FaceX &f=faces[k];
|
||||
int *data=f.data;
|
||||
int cnt=*data++;if( cnt<3 ) continue;
|
||||
int tri[3];
|
||||
tri[0]=data[0];
|
||||
for( int j=2;j<cnt;++j ){
|
||||
tri[1]=data[j-1+flip_tris];
|
||||
tri[2]=data[j-flip_tris];
|
||||
MeshLoader::addTriangle( tri,mats[f.mat_index] );
|
||||
}
|
||||
}
|
||||
|
||||
MeshLoader::endMesh( mesh );
|
||||
|
||||
if( !normals ) mesh->updateNormals();
|
||||
}
|
||||
|
||||
static MeshModel *parseFrame( IDirectXFileData *fileData ){
|
||||
|
||||
MeshModel *e=new MeshModel();
|
||||
|
||||
const GUID *guid;
|
||||
IDirectXFileObject *childObj;
|
||||
IDirectXFileData *childData;
|
||||
|
||||
char name[80];DWORD len=80;
|
||||
if( fileData->GetName( name,&len )<0 ) return e;
|
||||
|
||||
e->SetName( name );
|
||||
frames_map[name]=e;
|
||||
|
||||
//iterate through child objects...
|
||||
for( ;fileData->GetNextObject( &childObj )>=0;childObj->Release() ){
|
||||
if( childObj->QueryInterface( IID_IDirectXFileData,(void**)&childData )<0 ) continue;
|
||||
if( childData->GetType( &guid )>=0 ){
|
||||
if( *guid==TID_D3DRMFrameTransformMatrix ){
|
||||
DWORD size;D3DMATRIX *data;
|
||||
if( childData->GetData( 0,&size,(void**)&data )>=0 ){
|
||||
Transform tform=Transform( Matrix(
|
||||
Vector( data->_11,data->_12,data->_13 ),
|
||||
Vector( data->_21,data->_22,data->_23 ),
|
||||
Vector( data->_31,data->_32,data->_33 ) ),
|
||||
Vector( data->_41,data->_42,data->_43 ) );
|
||||
if( conv ) tform=conv_tform * tform * -conv_tform;
|
||||
e->SetLocalTransform( tform );
|
||||
}
|
||||
}else if( *guid==TID_D3DRMMesh ){
|
||||
if( !animonly ) parseMesh( childData,e );
|
||||
}else if( *guid==TID_D3DRMFrame ){
|
||||
MeshModel *t=parseFrame( childData );
|
||||
t->SetParent( e );
|
||||
}
|
||||
}
|
||||
childData->Release();
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static MeshModel *parseFile( const string &file ){
|
||||
|
||||
const GUID *guid;
|
||||
IDirectXFile *xfile;
|
||||
IDirectXFileData *fileData;
|
||||
IDirectXFileEnumObject *enumObj;
|
||||
|
||||
if( DirectXFileCreate( &xfile )<0 ) return 0;
|
||||
|
||||
if( xfile->RegisterTemplates( (VOID*)D3DRM_XTEMPLATES,D3DRM_XTEMPLATE_BYTES )<0 ){
|
||||
xfile->Release();return 0;
|
||||
}
|
||||
if( xfile->CreateEnumObject( (void*)file.c_str(),DXFILELOAD_FROMFILE,&enumObj )<0 ){
|
||||
xfile->Release();return 0;
|
||||
}
|
||||
|
||||
anim_len=0;
|
||||
MeshModel *e=new MeshModel();
|
||||
for( ;enumObj->GetNextDataObject( &fileData )>=0;fileData->Release() ){
|
||||
if( fileData->GetType( &guid )<0 ) continue;
|
||||
|
||||
if( *guid==TID_D3DRMMesh ){
|
||||
if( !animonly) parseMesh( fileData,e );
|
||||
}else if( *guid==TID_D3DRMFrame ){
|
||||
MeshModel *t=parseFrame( fileData );
|
||||
t->SetParent( e );
|
||||
}else if( *guid==TID_D3DRMAnimationSet ){
|
||||
if( !collapse ) parseAnimSet( fileData );
|
||||
}
|
||||
}
|
||||
|
||||
if( !collapse ){
|
||||
e->setAnimator( new Animator( e,anim_len ) );
|
||||
}
|
||||
|
||||
enumObj->Release();
|
||||
xfile->Release();
|
||||
return e;
|
||||
}
|
||||
|
||||
MeshModel *Loader_X::load( const string &filename,const Transform &t,int hint ){
|
||||
conv_tform=t;
|
||||
conv=flip_tris=false;
|
||||
if( conv_tform!=Transform() ){
|
||||
conv=true;
|
||||
if( conv_tform.m.i.cross(conv_tform.m.j).dot(conv_tform.m.k)<0 ) flip_tris=true;
|
||||
}
|
||||
collapse=!!(hint&MeshLoader::HINT_COLLAPSE);
|
||||
animonly=!!(hint&MeshLoader::HINT_ANIMONLY);
|
||||
|
||||
MeshModel *e=parseFile( filename );
|
||||
frames_map.clear();
|
||||
return e;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
#ifndef LOADER_X_H
|
||||
#define LOADER_X_H
|
||||
|
||||
#include "meshloader.hpp"
|
||||
|
||||
class Loader_X : public MeshLoader{
|
||||
public:
|
||||
MeshModel *load( const string &f,const Transform &conv,int hint );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "md2rep.hpp"
|
||||
#include "md2model.hpp"
|
||||
|
||||
struct MD2Model::Rep : public MD2Rep{
|
||||
int ref_cnt;
|
||||
|
||||
Rep( const string &f):MD2Rep( f ),
|
||||
ref_cnt(1){
|
||||
}
|
||||
};
|
||||
|
||||
MD2Model::MD2Model( const string &f ):
|
||||
rep( new Rep( f ) ),
|
||||
anim_mode(0),anim_time(0),
|
||||
render_a(0),render_b(0),render_t(0),trans_verts(0){
|
||||
}
|
||||
|
||||
MD2Model::MD2Model( const MD2Model &t ):
|
||||
Model(t),rep( t.rep ),
|
||||
anim_mode(0),anim_time(0),
|
||||
render_a(0),render_b(0),render_t(0),trans_verts(0){
|
||||
++rep->ref_cnt;
|
||||
}
|
||||
|
||||
MD2Model::~MD2Model(){
|
||||
if( !--rep->ref_cnt ) delete rep;
|
||||
if( trans_verts ) delete[] trans_verts;
|
||||
}
|
||||
|
||||
void MD2Model::startMD2Anim( int first,int last,int mode,float speed,float trans ){
|
||||
|
||||
if( last<first ) std::swap( first,last );
|
||||
|
||||
if( first<0 ) first=0;
|
||||
else if( first>=rep->numFrames() ) first=rep->numFrames()-1;
|
||||
|
||||
if( last<0 ) last=0;
|
||||
else if( last>=rep->numFrames() ) last=rep->numFrames()-1;
|
||||
|
||||
if( trans>0 ){
|
||||
if( !trans_verts ) trans_verts=new MD2Rep::Vert[rep->numVertices()];
|
||||
|
||||
if( anim_mode & 0x8000 ) rep->render( trans_verts,anim_time,trans_time );
|
||||
else rep->render( trans_verts,render_a,render_b,render_t );
|
||||
trans_speed=1.0f/trans;
|
||||
trans_time=0;
|
||||
mode|=0x8000;
|
||||
}
|
||||
|
||||
anim_first=first;
|
||||
anim_last=last;
|
||||
anim_len=last-first;
|
||||
anim_speed=speed;
|
||||
anim_time=((mode&0x7fff)==Animator::ANIM_MODE_LOOP || anim_speed>=0) ? anim_first : anim_last;
|
||||
anim_mode=mode;
|
||||
|
||||
if( !anim_speed || !anim_len ){
|
||||
render_a=render_b=anim_time;
|
||||
render_t=0;
|
||||
anim_mode&=0x8000;
|
||||
}
|
||||
}
|
||||
|
||||
void MD2Model::animate( float e ){
|
||||
Model::animate( e );
|
||||
if( !anim_mode ) return;
|
||||
if( anim_mode & 0x8000 ){
|
||||
trans_time+=trans_speed;
|
||||
if( trans_time<1 ) return;
|
||||
anim_mode&=~0x8000;
|
||||
if( !anim_mode ) return;
|
||||
}
|
||||
anim_time=anim_time+anim_speed * e;
|
||||
if( anim_time<anim_first ){
|
||||
switch( anim_mode ){
|
||||
case Animator::ANIM_MODE_LOOP:
|
||||
anim_time+=anim_len;
|
||||
break;
|
||||
case Animator::ANIM_MODE_PINGPONG:
|
||||
anim_time=anim_first+(anim_first-anim_time);
|
||||
anim_speed=-anim_speed;
|
||||
break;
|
||||
default:
|
||||
anim_time=anim_first;
|
||||
anim_mode=0;
|
||||
break;
|
||||
}
|
||||
}else if( anim_time>=anim_last ){
|
||||
switch( anim_mode ){
|
||||
case Animator::ANIM_MODE_LOOP:
|
||||
anim_time-=anim_len;
|
||||
break;
|
||||
case Animator::ANIM_MODE_PINGPONG:
|
||||
anim_time=anim_last-(anim_time-anim_last);
|
||||
anim_speed=-anim_speed;
|
||||
break;
|
||||
default:
|
||||
anim_time=anim_last;
|
||||
anim_mode=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
render_a=floor(anim_time);render_b=render_a+1;
|
||||
if( anim_mode==Animator::ANIM_MODE_LOOP && render_b==anim_last ) render_b=anim_first;
|
||||
render_t=anim_time-render_a;
|
||||
}
|
||||
|
||||
bool MD2Model::render( const RenderContext &rc ){
|
||||
static Frustum f;
|
||||
new( &f ) Frustum( rc.getWorldFrustum(),-getRenderTform() );
|
||||
if( !f.cull( rep->getBox() ) ) return false;
|
||||
|
||||
if( anim_mode & 0x8000 ){
|
||||
rep->render( this,trans_verts,anim_time,trans_time );
|
||||
}else{
|
||||
rep->render( this,render_a,render_b,render_t );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int MD2Model::getMD2AnimLength()const{
|
||||
return rep->numFrames();
|
||||
}
|
||||
|
||||
bool MD2Model::getValid()const{
|
||||
return rep->numFrames()>0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
#ifndef MD2MODEL_H
|
||||
#define MD2MODEL_H
|
||||
|
||||
#include "model.hpp"
|
||||
#include "md2rep.hpp"
|
||||
|
||||
class MD2Model : public Model{
|
||||
public:
|
||||
MD2Model( const string &filename );
|
||||
MD2Model( const MD2Model &t );
|
||||
~MD2Model();
|
||||
|
||||
//Entity interface
|
||||
Entity *clone(){ return new MD2Model( *this ); }
|
||||
MD2Model *getMD2Model(){ return this; }
|
||||
|
||||
//Object interface
|
||||
void animate( float elapsed );
|
||||
|
||||
//Model interface
|
||||
bool render( const RenderContext &rc );
|
||||
|
||||
//MD2 interface
|
||||
void startMD2Anim( int first,int last,int mode,float speed,float trans );
|
||||
|
||||
int getMD2AnimLength()const;
|
||||
bool getMD2Animating()const{ return !!anim_mode; }
|
||||
float getMD2AnimTime()const{ return anim_time; }
|
||||
|
||||
bool getValid()const;
|
||||
|
||||
private:
|
||||
struct Rep;
|
||||
Rep *rep;
|
||||
|
||||
int anim_mode;
|
||||
float anim_time,anim_speed;
|
||||
int anim_first,anim_last,anim_len;
|
||||
|
||||
float render_t;
|
||||
int render_a,render_b;
|
||||
|
||||
float trans_time,trans_speed;
|
||||
MD2Rep::Vert *trans_verts;
|
||||
|
||||
//Unimplemented
|
||||
MD2Model &operator=( const MD2Model & );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,473 @@
|
||||
|
||||
#include "std.h"
|
||||
#include "md2model.h"
|
||||
#include "md2norms.h"
|
||||
|
||||
static Vector *normals;
|
||||
static float white[]={1,1,1};
|
||||
|
||||
extern gxRuntime *gx_runtime;
|
||||
extern gxGraphics *gx_graphics;
|
||||
|
||||
struct MD2Model::Rep{
|
||||
|
||||
struct md2_header{
|
||||
int magic;
|
||||
int version;
|
||||
int skinWidth;
|
||||
int skinHeight;
|
||||
int frameSize;
|
||||
int numSkins;
|
||||
int numVertices;
|
||||
int numTexCoords;
|
||||
int numTriangles;
|
||||
int numGlCommands;
|
||||
int numFrames;
|
||||
int offsetSkins;
|
||||
int offsetTexCoords;
|
||||
int offsetTriangles;
|
||||
int offsetFrames;
|
||||
int offsetGlCommands;
|
||||
int offsetEnd;
|
||||
};
|
||||
|
||||
struct md2_vertex{
|
||||
unsigned char x,y,z,n;
|
||||
};
|
||||
|
||||
struct md2_texcoord{
|
||||
unsigned short s,t;
|
||||
};
|
||||
|
||||
struct md2_triangle{
|
||||
unsigned short verts[3],tex_coords[3];
|
||||
};
|
||||
|
||||
struct Frame{
|
||||
Vector scale,trans;
|
||||
vector<md2_vertex> verts;
|
||||
};
|
||||
|
||||
struct TexCoords{
|
||||
float u,v;
|
||||
};
|
||||
|
||||
int ref_cnt;
|
||||
|
||||
int num_verts,num_frames;
|
||||
|
||||
vector<Frame> frames;
|
||||
vector<TexCoords> tex_coords;
|
||||
gxMesh *mesh;
|
||||
|
||||
Box box;
|
||||
|
||||
ModelModel::Rep( const string &file ):
|
||||
ref_cnt(1),mesh(0){
|
||||
|
||||
filebuf in;
|
||||
Header header;
|
||||
|
||||
if( !in.open( file.c_str(),ios_base::in|ios_base::binary ) ) return;
|
||||
if( in.sgetn( (char*)&header,sizeof(header) )!=sizeof(header) ) return;
|
||||
if( header.magic!='2PDI' || header.version!=8 ) return;
|
||||
|
||||
//read tex coords
|
||||
in.pubseekpos( header.offsetTexCoords );
|
||||
TexCoord *coords=d_new TexCoord[header.numTexCoords];
|
||||
in.sgetn( (char*)coords,header.numTexCoords*sizeof(TexCoord) );
|
||||
|
||||
vector<VertInfo> verts;
|
||||
map<VertInfo,int> info_map;
|
||||
|
||||
//build triangles
|
||||
vector<Triangle> triangles;
|
||||
in.pubseekpos( header.offsetTriangles );
|
||||
triangles.resize( header.numTriangles );
|
||||
for( k=0;k<triangles.size();++k ){
|
||||
unsigned short v[3],t[3];
|
||||
in.sgetn( (char*)v,6 );
|
||||
in.sgetn( (char*)t,6 );
|
||||
for( int j=0;j<3;++j ){
|
||||
unsigned char tu=coords[ t[j] ].s*256.0f/header.skinWidth;
|
||||
unsigned char tv=coords[ t[j] ].t*256.0f/header.skinHeight;
|
||||
VertInfo i( v[j],tu,tv );
|
||||
map<VertInfo,int>::iterator it=info_map.find( i );
|
||||
if( it==info_map.end() ){
|
||||
info_map[i]=triangles[k].v[j]=verts.size();
|
||||
verts.push_back( i );
|
||||
}else{
|
||||
triangles[k].v[j]=it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete coords;
|
||||
|
||||
//load frames
|
||||
string tt="MD2 Frames:"+itoa( header.numFrames );
|
||||
gx_runtime->debugLog( tt.c_str() );
|
||||
|
||||
in.pubseekpos( header.offsetFrames );
|
||||
frames.resize( header.numFrames );
|
||||
MD2Vertex *md2_verts=d_new MD2Vertex[header.numVertices];
|
||||
|
||||
for( k=0;k<frames.size();++k ){
|
||||
|
||||
Frame &frame=frames[k];
|
||||
|
||||
//read frame header;
|
||||
in.sgetn( (char*)&frame.scale,12 );
|
||||
in.sgetn( (char*)&frame.trans,12 );
|
||||
in.sgetn( frame.name,16 );
|
||||
|
||||
frame.trans=Vector(frame.trans.y,frame.trans.z,frame.trans.x);
|
||||
frame.scale=Vector(frame.scale.y,frame.scale.z,frame.scale.x);
|
||||
|
||||
//read frame verts...
|
||||
in.sgetn( (char*)md2_verts,header.numVertices*4 );
|
||||
|
||||
frame.vertices.resize( verts.size() );
|
||||
for( int j=0;j<verts.size();++j ){
|
||||
Vertex &v=frame.vertices[j];
|
||||
const VertInfo &i=verts[j];
|
||||
const MD2Vertex &m=md2_verts[i.index];
|
||||
v.x=m.y;v.y=m.z;v.z=m.x;
|
||||
v.u=i.u;v.v=i.v;v.n=m.n;
|
||||
}
|
||||
}
|
||||
delete md2_verts;
|
||||
|
||||
//create initial mesh
|
||||
mesh=gx_graphics->createMesh( verts.size(),triangles.size(),0 );
|
||||
mesh->lock();
|
||||
for( k=0;k<triangles.size();++k ){
|
||||
const Triangle &t=triangles[k];
|
||||
mesh->setTriangle( k,t.v[0],t.v[2],t.v[1] );
|
||||
}
|
||||
mesh->unlock();
|
||||
|
||||
//calculate bounding box.
|
||||
for( k=0;k<header.numFrames;++k ){
|
||||
const Frame &frame=frames[k];
|
||||
const Vector &scale=frame.scale;
|
||||
const Vector &trans=frame.trans;
|
||||
for( int n=0;n<frame.vertices.size();++n ){
|
||||
const Vertex &v=frame.vertices[n];
|
||||
box.update( Vector( v.x,v.y,v.z ) * scale + trans );
|
||||
}
|
||||
}
|
||||
|
||||
if( !normals ){
|
||||
normals=(Vector*)md2norms;
|
||||
for( int k=0;k<sizeof(md2norms)/12;++k ){
|
||||
normals[k]=Vector(normals[k].y,normals[k].z,normals[k].x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma pack( push,1 )
|
||||
|
||||
struct Header{
|
||||
int magic;
|
||||
int version;
|
||||
int skinWidth;
|
||||
int skinHeight;
|
||||
int frameSize;
|
||||
int numSkins;
|
||||
int numVertices;
|
||||
int numTexCoords;
|
||||
int numTriangles;
|
||||
int numGlCommands;
|
||||
int numFrames;
|
||||
int offsetSkins;
|
||||
int offsetTexCoords;
|
||||
int offsetTriangles;
|
||||
int offsetFrames;
|
||||
int offsetGlCommands;
|
||||
int offsetEnd;
|
||||
};
|
||||
|
||||
struct MD2Vertex{
|
||||
unsigned char x,y,z,n;
|
||||
};
|
||||
|
||||
struct Vertex{
|
||||
unsigned char x,y,z,u,v,n;
|
||||
};
|
||||
|
||||
struct Triangle{
|
||||
unsigned short v[3]; //index into vertices
|
||||
};
|
||||
|
||||
struct Frame{
|
||||
Vector scale;
|
||||
Vector trans;
|
||||
char name[16];
|
||||
vector<Vertex> vertices;
|
||||
};
|
||||
|
||||
struct TexCoord{
|
||||
short s,t;
|
||||
};
|
||||
|
||||
struct VertInfo{
|
||||
unsigned short index;
|
||||
unsigned char u,v;
|
||||
VertInfo( unsigned short i,char u,char v ):index(i),u(u),v(v){
|
||||
}
|
||||
bool operator<( const VertInfo &t )const{
|
||||
if( index<t.index ) return true;
|
||||
if( t.index<index ) return false;
|
||||
if( u<t.u ) return true;
|
||||
if( t.u<u ) return false;
|
||||
return v<t.v;
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack( pop )
|
||||
|
||||
int ref_cnt;
|
||||
Header header;
|
||||
vector<Frame> frames;
|
||||
gxMesh *mesh;
|
||||
Box box;
|
||||
|
||||
Rep( const string &file );
|
||||
~Rep();
|
||||
|
||||
void render( MD2Model *model,float render_t,int render_a,int render_b );
|
||||
};
|
||||
|
||||
MD2Model::Rep::Rep( const string &file ):
|
||||
ref_cnt(1),mesh(0){
|
||||
|
||||
filebuf in;
|
||||
if( !in.open( file.c_str(),ios_base::in|ios_base::binary ) ){
|
||||
return;
|
||||
}
|
||||
|
||||
if( in.sgetn( (char*)&header,sizeof(header) )!=sizeof(header) ){
|
||||
return;
|
||||
}
|
||||
|
||||
if( header.magic!='2PDI' || header.version!=8 ){
|
||||
return;
|
||||
}
|
||||
|
||||
int k;
|
||||
|
||||
//read tex coords
|
||||
in.pubseekpos( header.offsetTexCoords );
|
||||
TexCoord *coords=d_new TexCoord[header.numTexCoords];
|
||||
in.sgetn( (char*)coords,header.numTexCoords*sizeof(TexCoord) );
|
||||
|
||||
vector<VertInfo> verts;
|
||||
map<VertInfo,int> info_map;
|
||||
|
||||
//build triangles
|
||||
vector<Triangle> triangles;
|
||||
in.pubseekpos( header.offsetTriangles );
|
||||
triangles.resize( header.numTriangles );
|
||||
for( k=0;k<triangles.size();++k ){
|
||||
unsigned short v[3],t[3];
|
||||
in.sgetn( (char*)v,6 );
|
||||
in.sgetn( (char*)t,6 );
|
||||
for( int j=0;j<3;++j ){
|
||||
unsigned char tu=coords[ t[j] ].s*256.0f/header.skinWidth;
|
||||
unsigned char tv=coords[ t[j] ].t*256.0f/header.skinHeight;
|
||||
VertInfo i( v[j],tu,tv );
|
||||
map<VertInfo,int>::iterator it=info_map.find( i );
|
||||
if( it==info_map.end() ){
|
||||
info_map[i]=triangles[k].v[j]=verts.size();
|
||||
verts.push_back( i );
|
||||
}else{
|
||||
triangles[k].v[j]=it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete coords;
|
||||
|
||||
//load frames
|
||||
string tt="MD2 Frames:"+itoa( header.numFrames );
|
||||
gx_runtime->debugLog( tt.c_str() );
|
||||
|
||||
in.pubseekpos( header.offsetFrames );
|
||||
frames.resize( header.numFrames );
|
||||
MD2Vertex *md2_verts=d_new MD2Vertex[header.numVertices];
|
||||
|
||||
for( k=0;k<frames.size();++k ){
|
||||
|
||||
Frame &frame=frames[k];
|
||||
|
||||
//read frame header;
|
||||
in.sgetn( (char*)&frame.scale,12 );
|
||||
in.sgetn( (char*)&frame.trans,12 );
|
||||
in.sgetn( frame.name,16 );
|
||||
|
||||
frame.trans=Vector(frame.trans.y,frame.trans.z,frame.trans.x);
|
||||
frame.scale=Vector(frame.scale.y,frame.scale.z,frame.scale.x);
|
||||
|
||||
//read frame verts...
|
||||
in.sgetn( (char*)md2_verts,header.numVertices*4 );
|
||||
|
||||
frame.vertices.resize( verts.size() );
|
||||
for( int j=0;j<verts.size();++j ){
|
||||
Vertex &v=frame.vertices[j];
|
||||
const VertInfo &i=verts[j];
|
||||
const MD2Vertex &m=md2_verts[i.index];
|
||||
v.x=m.y;v.y=m.z;v.z=m.x;
|
||||
v.u=i.u;v.v=i.v;v.n=m.n;
|
||||
}
|
||||
}
|
||||
delete md2_verts;
|
||||
|
||||
//create initial mesh
|
||||
mesh=gx_graphics->createMesh( verts.size(),triangles.size(),0 );
|
||||
mesh->lock();
|
||||
for( k=0;k<triangles.size();++k ){
|
||||
const Triangle &t=triangles[k];
|
||||
mesh->setTriangle( k,t.v[0],t.v[2],t.v[1] );
|
||||
}
|
||||
mesh->unlock();
|
||||
|
||||
//calculate bounding box.
|
||||
for( k=0;k<header.numFrames;++k ){
|
||||
const Frame &frame=frames[k];
|
||||
const Vector &scale=frame.scale;
|
||||
const Vector &trans=frame.trans;
|
||||
for( int n=0;n<frame.vertices.size();++n ){
|
||||
const Vertex &v=frame.vertices[n];
|
||||
box.update( Vector( v.x,v.y,v.z ) * scale + trans );
|
||||
}
|
||||
}
|
||||
|
||||
if( !normals ){
|
||||
normals=(Vector*)md2norms;
|
||||
for( int k=0;k<sizeof(md2norms)/12;++k ){
|
||||
normals[k]=Vector(normals[k].y,normals[k].z,normals[k].x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MD2Model::Rep::~Rep(){
|
||||
if( mesh ) gx_graphics->freeMesh( mesh );
|
||||
}
|
||||
|
||||
void MD2Model::Rep::render( MD2Model *model,float render_t,int render_a,int render_b ){
|
||||
|
||||
const Frame &frame_a=frames[render_a];
|
||||
const Vector &scale_a=frame_a.scale;
|
||||
const Vector &trans_a=frame_a.trans;
|
||||
|
||||
const Frame &frame_b=frames[render_b];
|
||||
const Vector &scale_b=frame_b.scale;
|
||||
const Vector &trans_b=frame_b.trans;
|
||||
|
||||
mesh->lock();
|
||||
int k;
|
||||
for( k=0;k<frame_a.vertices.size();++k ){
|
||||
const Vertex &v_a=frame_a.vertices[k];
|
||||
const Vector &n_a=normals[v_a.n];
|
||||
Vector t_a( v_a.x*scale_a.x+trans_a.x,v_a.y*scale_a.y+trans_a.y,v_a.z*scale_a.z+trans_a.z );
|
||||
|
||||
const Vertex &v_b=frame_b.vertices[k];
|
||||
const Vector &n_b=normals[v_b.n];
|
||||
Vector t_b( v_b.x*scale_b.x+trans_b.x,v_b.y*scale_b.y+trans_b.y,v_b.z*scale_b.z+trans_b.z );
|
||||
|
||||
Vector t=(t_b-t_a)*render_t+t_a;
|
||||
Vector n=(n_b-n_a)*render_t+n_a;
|
||||
float tex_coords[]={ v_a.u/256.0f,v_a.v/256.0f,1,0,0,1 };
|
||||
mesh->setVertex( k,&t.x,&n.x,white,tex_coords );
|
||||
}
|
||||
mesh->unlock();
|
||||
|
||||
model->enqueue( mesh,0,frame_a.vertices.size(),0,header.numTriangles );
|
||||
}
|
||||
|
||||
MD2Model::MD2Model( const string &f ):
|
||||
rep( d_new Rep( f ) ),
|
||||
anim_mode(0),anim_time(0),
|
||||
render_a(0),render_b(0),render_t(0){
|
||||
}
|
||||
|
||||
MD2Model::MD2Model( const MD2Model &t ):
|
||||
Model(t),rep( t.rep ),
|
||||
anim_mode(0),anim_time(0),
|
||||
render_a(0),render_b(0),render_t(0){
|
||||
++rep->ref_cnt;
|
||||
}
|
||||
|
||||
MD2Model::~MD2Model(){
|
||||
if( !--rep->ref_cnt ) delete rep;
|
||||
}
|
||||
|
||||
void MD2Model::startMD2Anim( int first,int last,int mode,float speed ){
|
||||
if( !speed && !mode ){ anim_mode=0;return; }
|
||||
if( first<0 ) first=0;
|
||||
else if( first>=rep->header.numFrames ) first=rep->header.numFrames-1;
|
||||
if( last<0 ) last=0;
|
||||
else if( last>=rep->header.numFrames ) last=rep->header.numFrames-1;
|
||||
if( first==last ){ anim_mode=0;render_a=render_b=first;render_t=0;return; }
|
||||
if( last<first ) std::swap( first,last );
|
||||
anim_first=first;
|
||||
anim_last=last;
|
||||
anim_len=last-first;
|
||||
anim_speed=speed;
|
||||
anim_time=speed>0 ? first : last;
|
||||
anim_mode=mode;
|
||||
}
|
||||
|
||||
void MD2Model::animate( float e ){
|
||||
Model::animate( e );
|
||||
if( !anim_mode ) return;
|
||||
anim_time=anim_time+anim_speed * e;
|
||||
if( anim_time<anim_first ){
|
||||
switch( anim_mode ){
|
||||
case ANIM_MODE_LOOP:
|
||||
anim_time+=anim_len;
|
||||
break;
|
||||
case ANIM_MODE_PINGPONG:
|
||||
anim_time=anim_first+(anim_first-anim_time);
|
||||
anim_speed=-anim_speed;
|
||||
break;
|
||||
default:
|
||||
anim_time=anim_first;
|
||||
anim_mode=0;
|
||||
break;
|
||||
}
|
||||
}else if( anim_time>=anim_last ){
|
||||
switch( anim_mode ){
|
||||
case ANIM_MODE_LOOP:
|
||||
anim_time-=anim_len;
|
||||
break;
|
||||
case ANIM_MODE_PINGPONG:
|
||||
anim_time=anim_last-(anim_time-anim_last);
|
||||
anim_speed=-anim_speed;
|
||||
break;
|
||||
default:
|
||||
anim_time=anim_last;
|
||||
anim_mode=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
render_a=floor(anim_time);render_b=render_a+1;
|
||||
if( anim_mode==ANIM_MODE_LOOP && render_b==anim_last ) render_b=anim_first;
|
||||
render_t=anim_time-render_a;
|
||||
}
|
||||
|
||||
void MD2Model::render( const RenderContext &rc ){
|
||||
static Frustum f;
|
||||
new( &f ) Frustum( rc.getWorldFrustum(),-getRenderTform() );
|
||||
if( !f.cull( rep->box ) ) return;
|
||||
|
||||
rep->render( this,render_t,render_a,render_b );
|
||||
}
|
||||
|
||||
int MD2Model::getMD2AnimLength()const{
|
||||
return rep->frames.size();
|
||||
}
|
||||
|
||||
bool MD2Model::getValid()const{
|
||||
return rep->mesh!=0;
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "md2norms.hpp"
|
||||
|
||||
float md2norms[162][3]={
|
||||
{-0.525731f, 0.000000f, 0.850651f},
|
||||
{-0.442863f, 0.238856f, 0.864188f},
|
||||
{-0.295242f, 0.000000f, 0.955423f},
|
||||
{-0.309017f, 0.500000f, 0.809017f},
|
||||
{-0.162460f, 0.262866f, 0.951056f},
|
||||
{0.000000f, 0.000000f, 1.000000f},
|
||||
{0.000000f, 0.850651f, 0.525731f},
|
||||
{-0.147621f, 0.716567f, 0.681718f},
|
||||
{0.147621f, 0.716567f, 0.681718f},
|
||||
{0.000000f, 0.525731f, 0.850651f},
|
||||
{0.309017f, 0.500000f, 0.809017f},
|
||||
{0.525731f, 0.000000f, 0.850651f},
|
||||
{0.295242f, 0.000000f, 0.955423f},
|
||||
{0.442863f, 0.238856f, 0.864188f},
|
||||
{0.162460f, 0.262866f, 0.951056f},
|
||||
{-0.681718f, 0.147621f, 0.716567f},
|
||||
{-0.809017f, 0.309017f, 0.500000f},
|
||||
{-0.587785f, 0.425325f, 0.688191f},
|
||||
{-0.850651f, 0.525731f, 0.000000f},
|
||||
{-0.864188f, 0.442863f, 0.238856f},
|
||||
{-0.716567f, 0.681718f, 0.147621f},
|
||||
{-0.688191f, 0.587785f, 0.425325f},
|
||||
{-0.500000f, 0.809017f, 0.309017f},
|
||||
{-0.238856f, 0.864188f, 0.442863f},
|
||||
{-0.425325f, 0.688191f, 0.587785f},
|
||||
{-0.716567f, 0.681718f, -0.147621f},
|
||||
{-0.500000f, 0.809017f, -0.309017f},
|
||||
{-0.525731f, 0.850651f, 0.000000f},
|
||||
{0.000000f, 0.850651f, -0.525731f},
|
||||
{-0.238856f, 0.864188f, -0.442863f},
|
||||
{0.000000f, 0.955423f, -0.295242f},
|
||||
{-0.262866f, 0.951056f, -0.162460f},
|
||||
{0.000000f, 1.000000f, 0.000000f},
|
||||
{0.000000f, 0.955423f, 0.295242f},
|
||||
{-0.262866f, 0.951056f, 0.162460f},
|
||||
{0.238856f, 0.864188f, 0.442863f},
|
||||
{0.262866f, 0.951056f, 0.162460f},
|
||||
{0.500000f, 0.809017f, 0.309017f},
|
||||
{0.238856f, 0.864188f, -0.442863f},
|
||||
{0.262866f, 0.951056f, -0.162460f},
|
||||
{0.500000f, 0.809017f, -0.309017f},
|
||||
{0.850651f, 0.525731f, 0.000000f},
|
||||
{0.716567f, 0.681718f, 0.147621f},
|
||||
{0.716567f, 0.681718f, -0.147621f},
|
||||
{0.525731f, 0.850651f, 0.000000f},
|
||||
{0.425325f, 0.688191f, 0.587785f},
|
||||
{0.864188f, 0.442863f, 0.238856f},
|
||||
{0.688191f, 0.587785f, 0.425325f},
|
||||
{0.809017f, 0.309017f, 0.500000f},
|
||||
{0.681718f, 0.147621f, 0.716567f},
|
||||
{0.587785f, 0.425325f, 0.688191f},
|
||||
{0.955423f, 0.295242f, 0.000000f},
|
||||
{1.000000f, 0.000000f, 0.000000f},
|
||||
{0.951056f, 0.162460f, 0.262866f},
|
||||
{0.850651f, -0.525731f, 0.000000f},
|
||||
{0.955423f, -0.295242f, 0.000000f},
|
||||
{0.864188f, -0.442863f, 0.238856f},
|
||||
{0.951056f, -0.162460f, 0.262866f},
|
||||
{0.809017f, -0.309017f, 0.500000f},
|
||||
{0.681718f, -0.147621f, 0.716567f},
|
||||
{0.850651f, 0.000000f, 0.525731f},
|
||||
{0.864188f, 0.442863f, -0.238856f},
|
||||
{0.809017f, 0.309017f, -0.500000f},
|
||||
{0.951056f, 0.162460f, -0.262866f},
|
||||
{0.525731f, 0.000000f, -0.850651f},
|
||||
{0.681718f, 0.147621f, -0.716567f},
|
||||
{0.681718f, -0.147621f, -0.716567f},
|
||||
{0.850651f, 0.000000f, -0.525731f},
|
||||
{0.809017f, -0.309017f, -0.500000f},
|
||||
{0.864188f, -0.442863f, -0.238856f},
|
||||
{0.951056f, -0.162460f, -0.262866f},
|
||||
{0.147621f, 0.716567f, -0.681718f},
|
||||
{0.309017f, 0.500000f, -0.809017f},
|
||||
{0.425325f, 0.688191f, -0.587785f},
|
||||
{0.442863f, 0.238856f, -0.864188f},
|
||||
{0.587785f, 0.425325f, -0.688191f},
|
||||
{0.688191f, 0.587785f, -0.425325f},
|
||||
{-0.147621f, 0.716567f, -0.681718f},
|
||||
{-0.309017f, 0.500000f, -0.809017f},
|
||||
{0.000000f, 0.525731f, -0.850651f},
|
||||
{-0.525731f, 0.000000f, -0.850651f},
|
||||
{-0.442863f, 0.238856f, -0.864188f},
|
||||
{-0.295242f, 0.000000f, -0.955423f},
|
||||
{-0.162460f, 0.262866f, -0.951056f},
|
||||
{0.000000f, 0.000000f, -1.000000f},
|
||||
{0.295242f, 0.000000f, -0.955423f},
|
||||
{0.162460f, 0.262866f, -0.951056f},
|
||||
{-0.442863f, -0.238856f, -0.864188f},
|
||||
{-0.309017f, -0.500000f, -0.809017f},
|
||||
{-0.162460f, -0.262866f, -0.951056f},
|
||||
{0.000000f, -0.850651f, -0.525731f},
|
||||
{-0.147621f, -0.716567f, -0.681718f},
|
||||
{0.147621f, -0.716567f, -0.681718f},
|
||||
{0.000000f, -0.525731f, -0.850651f},
|
||||
{0.309017f, -0.500000f, -0.809017f},
|
||||
{0.442863f, -0.238856f, -0.864188f},
|
||||
{0.162460f, -0.262866f, -0.951056f},
|
||||
{0.238856f, -0.864188f, -0.442863f},
|
||||
{0.500000f, -0.809017f, -0.309017f},
|
||||
{0.425325f, -0.688191f, -0.587785f},
|
||||
{0.716567f, -0.681718f, -0.147621f},
|
||||
{0.688191f, -0.587785f, -0.425325f},
|
||||
{0.587785f, -0.425325f, -0.688191f},
|
||||
{0.000000f, -0.955423f, -0.295242f},
|
||||
{0.000000f, -1.000000f, 0.000000f},
|
||||
{0.262866f, -0.951056f, -0.162460f},
|
||||
{0.000000f, -0.850651f, 0.525731f},
|
||||
{0.000000f, -0.955423f, 0.295242f},
|
||||
{0.238856f, -0.864188f, 0.442863f},
|
||||
{0.262866f, -0.951056f, 0.162460f},
|
||||
{0.500000f, -0.809017f, 0.309017f},
|
||||
{0.716567f, -0.681718f, 0.147621f},
|
||||
{0.525731f, -0.850651f, 0.000000f},
|
||||
{-0.238856f, -0.864188f, -0.442863f},
|
||||
{-0.500000f, -0.809017f, -0.309017f},
|
||||
{-0.262866f, -0.951056f, -0.162460f},
|
||||
{-0.850651f, -0.525731f, 0.000000f},
|
||||
{-0.716567f, -0.681718f, -0.147621f},
|
||||
{-0.716567f, -0.681718f, 0.147621f},
|
||||
{-0.525731f, -0.850651f, 0.000000f},
|
||||
{-0.500000f, -0.809017f, 0.309017f},
|
||||
{-0.238856f, -0.864188f, 0.442863f},
|
||||
{-0.262866f, -0.951056f, 0.162460f},
|
||||
{-0.864188f, -0.442863f, 0.238856f},
|
||||
{-0.809017f, -0.309017f, 0.500000f},
|
||||
{-0.688191f, -0.587785f, 0.425325f},
|
||||
{-0.681718f, -0.147621f, 0.716567f},
|
||||
{-0.442863f, -0.238856f, 0.864188f},
|
||||
{-0.587785f, -0.425325f, 0.688191f},
|
||||
{-0.309017f, -0.500000f, 0.809017f},
|
||||
{-0.147621f, -0.716567f, 0.681718f},
|
||||
{-0.425325f, -0.688191f, 0.587785f},
|
||||
{-0.162460f, -0.262866f, 0.951056f},
|
||||
{0.442863f, -0.238856f, 0.864188f},
|
||||
{0.162460f, -0.262866f, 0.951056f},
|
||||
{0.309017f, -0.500000f, 0.809017f},
|
||||
{0.147621f, -0.716567f, 0.681718f},
|
||||
{0.000000f, -0.525731f, 0.850651f},
|
||||
{0.425325f, -0.688191f, 0.587785f},
|
||||
{0.587785f, -0.425325f, 0.688191f},
|
||||
{0.688191f, -0.587785f, 0.425325f},
|
||||
{-0.955423f, 0.295242f, 0.000000f},
|
||||
{-0.951056f, 0.162460f, 0.262866f},
|
||||
{-1.000000f, 0.000000f, 0.000000f},
|
||||
{-0.850651f, 0.000000f, 0.525731f},
|
||||
{-0.955423f, -0.295242f, 0.000000f},
|
||||
{-0.951056f, -0.162460f, 0.262866f},
|
||||
{-0.864188f, 0.442863f, -0.238856f},
|
||||
{-0.951056f, 0.162460f, -0.262866f},
|
||||
{-0.809017f, 0.309017f, -0.500000f},
|
||||
{-0.864188f, -0.442863f, -0.238856f},
|
||||
{-0.951056f, -0.162460f, -0.262866f},
|
||||
{-0.809017f, -0.309017f, -0.500000f},
|
||||
{-0.681718f, 0.147621f, -0.716567f},
|
||||
{-0.681718f, -0.147621f, -0.716567f},
|
||||
{-0.850651f, 0.000000f, -0.525731f},
|
||||
{-0.688191f, 0.587785f, -0.425325f},
|
||||
{-0.587785f, 0.425325f, -0.688191f},
|
||||
{-0.425325f, 0.688191f, -0.587785f},
|
||||
{-0.425325f, -0.688191f, -0.587785f},
|
||||
{-0.587785f, -0.425325f, -0.688191f},
|
||||
{-0.688191f, -0.587785f, -0.425325f} };
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
#ifndef MD2NORMS_H
|
||||
#define MD2NORMS_H
|
||||
|
||||
extern float md2norms[162][3];
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,309 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "md2rep.hpp"
|
||||
#include "md2norms.hpp"
|
||||
|
||||
extern gxRuntime *gx_runtime;
|
||||
extern gxGraphics *gx_graphics;
|
||||
|
||||
static Vector *normals = 0;
|
||||
static float tex_coords[2][2] = { {0,0},{0,0} };
|
||||
|
||||
#pragma pack( push,1 )
|
||||
|
||||
struct md2_header {
|
||||
int magic;
|
||||
int version;
|
||||
int skinWidth;
|
||||
int skinHeight;
|
||||
int frameSize;
|
||||
int numSkins;
|
||||
int numVertices;
|
||||
int numTexCoords;
|
||||
int numTriangles;
|
||||
int numGlCommands;
|
||||
int numFrames;
|
||||
int offsetSkins;
|
||||
int offsetTexCoords;
|
||||
int offsetTriangles;
|
||||
int offsetFrames;
|
||||
int offsetGlCommands;
|
||||
int offsetEnd;
|
||||
};
|
||||
|
||||
struct md2_uv {
|
||||
short u, v;
|
||||
};
|
||||
|
||||
struct md2_vert {
|
||||
unsigned char x, y, z, n;
|
||||
};
|
||||
|
||||
struct md2_tri {
|
||||
unsigned short verts[3], uvs[3];
|
||||
};
|
||||
|
||||
#pragma pack( pop )
|
||||
|
||||
struct t_vert {
|
||||
unsigned short i, uv;
|
||||
bool operator<(const t_vert &t)const {
|
||||
return memcmp(&i, &t.i, 4) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct t_tri {
|
||||
unsigned short verts[3];
|
||||
};
|
||||
|
||||
MD2Rep::MD2Rep(const string &f) :
|
||||
mesh(0), n_verts(0), n_tris(0), n_frames(0) {
|
||||
|
||||
filebuf in;
|
||||
md2_header header;
|
||||
|
||||
if (!in.open(f.c_str(), ios_base::in | ios_base::binary)) return;
|
||||
if (in.sgetn((char*)&header, sizeof(header)) != sizeof(header)) return;
|
||||
if (header.magic != '2PDI' || header.version != 8) return;
|
||||
|
||||
n_frames = header.numFrames;
|
||||
n_tris = header.numTriangles;
|
||||
|
||||
//read in tex coords
|
||||
vector<md2_uv> md2_uvs;
|
||||
md2_uvs.resize(header.numTexCoords);
|
||||
in.pubseekpos(header.offsetTexCoords);
|
||||
in.sgetn((char*)(&md2_uvs.begin()[0]), header.numTexCoords * sizeof(md2_uv));
|
||||
|
||||
//read in triangles
|
||||
vector<md2_tri> md2_tris;
|
||||
md2_tris.resize(n_tris);
|
||||
in.pubseekpos(header.offsetTriangles);
|
||||
in.sgetn((char*)(&md2_tris.begin()[0]), n_tris * sizeof(md2_tri));
|
||||
|
||||
vector<t_tri> t_tris;
|
||||
vector<t_vert> t_verts;
|
||||
map<t_vert, int> t_map;
|
||||
|
||||
int k;
|
||||
for (k = 0; k < n_tris; ++k) {
|
||||
t_tri tr;
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
t_vert t;
|
||||
t.i = md2_tris[k].verts[j];
|
||||
t.uv = md2_tris[k].uvs[j];
|
||||
map<t_vert, int>::iterator it = t_map.find(t);
|
||||
if (it == t_map.end()) {
|
||||
//create new vert
|
||||
tr.verts[j] = t_map[t] = t_verts.size();
|
||||
t_verts.push_back(t);
|
||||
//add UVs
|
||||
VertexUV uv;
|
||||
uv.u = md2_uvs[t.uv].u / (float)(header.skinWidth);
|
||||
uv.v = md2_uvs[t.uv].v / (float)(header.skinHeight);
|
||||
uvs.push_back(uv);
|
||||
} else {
|
||||
//reuse vert
|
||||
tr.verts[j] = it->second;
|
||||
}
|
||||
}
|
||||
t_tris.push_back(tr);
|
||||
}
|
||||
n_verts = t_verts.size();
|
||||
|
||||
frames.resize(n_frames);
|
||||
in.pubseekpos(header.offsetFrames);
|
||||
|
||||
vector<md2_vert> md2_verts;
|
||||
md2_verts.resize(header.numVertices);
|
||||
|
||||
//read in frames
|
||||
for (k = 0; k < n_frames; ++k) {
|
||||
char t_buff[16];
|
||||
Frame *fr = &frames[k];
|
||||
in.sgetn((char*)&fr->scale, 12);
|
||||
in.sgetn((char*)&fr->trans, 12);
|
||||
in.sgetn(t_buff, 16);
|
||||
|
||||
fr->scale = Vector(fr->scale.y, fr->scale.z, fr->scale.x);
|
||||
fr->trans = Vector(fr->trans.y, fr->trans.z, fr->trans.x);
|
||||
|
||||
//read vertices
|
||||
in.sgetn((char*)&md2_verts.begin()[0], header.numVertices * sizeof(md2_vert));
|
||||
|
||||
fr->verts.resize(n_verts);
|
||||
for (int j = 0; j < n_verts; ++j) {
|
||||
Vertex *v = &fr->verts[j];
|
||||
const t_vert &tv = t_verts[j];
|
||||
const md2_vert &mv = md2_verts[tv.i];
|
||||
v->x = mv.y;
|
||||
v->y = mv.z;
|
||||
v->z = mv.x;
|
||||
v->n = mv.n;
|
||||
box.update(Vector(v->x, v->y, v->z) * fr->scale + fr->trans);
|
||||
}
|
||||
}
|
||||
|
||||
//create mesh and setup tris
|
||||
mesh = gx_graphics->createMesh(n_verts, n_tris, 0);
|
||||
mesh->lock(true);
|
||||
for (k = 0; k < n_tris; ++k) {
|
||||
const t_tri &t = t_tris[k];
|
||||
mesh->setTriangle(k, t.verts[0], t.verts[2], t.verts[1]);
|
||||
}
|
||||
mesh->unlock();
|
||||
|
||||
//build normals
|
||||
if (!normals) {
|
||||
normals = (Vector*)md2norms;
|
||||
for (int k = 0; k < sizeof(md2norms) / 12; ++k) {
|
||||
normals[k] = Vector(normals[k].y, normals[k].z, normals[k].x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MD2Rep::~MD2Rep() {
|
||||
if (mesh) gx_graphics->freeMesh(mesh);
|
||||
}
|
||||
|
||||
/*
|
||||
void MD2Rep::render( Vert *v,int frame ){
|
||||
|
||||
const Frame &frame_a=frames[frame];
|
||||
const Vertex *v_a=frame_a.verts.begin();
|
||||
const Vector scale_a=frame_a.scale,trans_a=frame_a.trans;
|
||||
|
||||
for( int k=0;k<n_verts;++v,++v_a,++k ){
|
||||
v->coords=Vector( v_a->x*scale_a.x+trans_a.x,v_a->y*scale_a.y+trans_a.y,v_a->z*scale_a.z+trans_a.z );
|
||||
v->normal=normals[ v_a->n ];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void MD2Rep::render(Vert *v, int frame, float time) {
|
||||
|
||||
const Frame &frame_b = frames[frame];
|
||||
const Vertex *v_b = (Vertex*)(&frame_b.verts.begin()[0]);
|
||||
const Vector scale_b = frame_b.scale, trans_b = frame_b.trans;
|
||||
|
||||
for (int k = 0; k < n_verts; ++v, ++v_b, ++k) {
|
||||
|
||||
const Vector t_b(v_b->x*scale_b.x + trans_b.x, v_b->y*scale_b.y + trans_b.y, v_b->z*scale_b.z + trans_b.z);
|
||||
const Vector &n_b = normals[v_b->n];
|
||||
|
||||
v->coords += (t_b - v->coords)*time;
|
||||
v->normal += (n_b - v->normal)*time;
|
||||
}
|
||||
}
|
||||
|
||||
void MD2Rep::render(Vert *v, int render_a, int render_b, float render_t) {
|
||||
const Frame &frame_a = frames[render_a];
|
||||
const Vector scale_a = frame_a.scale, trans_a = frame_a.trans;
|
||||
|
||||
const Frame &frame_b = frames[render_b];
|
||||
const Vector scale_b = frame_b.scale, trans_b = frame_b.trans;
|
||||
|
||||
const Vertex *v_a = (Vertex*)(&frame_a.verts.begin()[0]);
|
||||
const Vertex *v_b = (Vertex*)(&frame_b.verts.begin()[0]);
|
||||
|
||||
for (int k = 0; k < n_verts; ++v, ++v_a, ++v_b, ++k) {
|
||||
|
||||
const Vector t_a(v_a->x*scale_a.x + trans_a.x, v_a->y*scale_a.y + trans_a.y, v_a->z*scale_a.z + trans_a.z);
|
||||
const Vector t_b(v_b->x*scale_b.x + trans_b.x, v_b->y*scale_b.y + trans_b.y, v_b->z*scale_b.z + trans_b.z);
|
||||
v->coords = (t_b - t_a)*render_t + t_a;
|
||||
|
||||
const Vector &n_a = normals[v_a->n];
|
||||
const Vector &n_b = normals[v_b->n];
|
||||
v->normal = (n_b - n_a)*render_t + n_a;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void MD2Rep::render( Vert *v,const Vert *v_a,const Vert *v_b,float render_t ){
|
||||
for( int k=0;k<n_verts;++v,++v_a,++v_b,++k ){
|
||||
v->coords=(v_b->coords-v_a->coords)*render_t+v_a->coords;
|
||||
v->normal=(v_b->normal-v_a->normal)*render_t+v_a->normal;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void MD2Rep::render(Model *model, int render_a, int render_b, float render_t) {
|
||||
const Frame &frame_a = frames[render_a];
|
||||
const Vector scale_a = frame_a.scale, trans_a = frame_a.trans;
|
||||
|
||||
const Frame &frame_b = frames[render_b];
|
||||
const Vector scale_b = frame_b.scale, trans_b = frame_b.trans;
|
||||
|
||||
const VertexUV *uv = (VertexUV*)&uvs.begin()[0];
|
||||
const Vertex *v_a = (Vertex*)(&frame_a.verts.begin()[0]);
|
||||
const Vertex *v_b = (Vertex*)(&frame_b.verts.begin()[0]);
|
||||
|
||||
mesh->lock(true);
|
||||
for (int k = 0; k < n_verts; ++uv, ++v_a, ++v_b, ++k) {
|
||||
|
||||
const Vector t_a(v_a->x*scale_a.x + trans_a.x, v_a->y*scale_a.y + trans_a.y, v_a->z*scale_a.z + trans_a.z);
|
||||
const Vector t_b(v_b->x*scale_b.x + trans_b.x, v_b->y*scale_b.y + trans_b.y, v_b->z*scale_b.z + trans_b.z);
|
||||
const Vector t((t_b - t_a)*render_t + t_a);
|
||||
|
||||
const Vector &n_a = normals[v_a->n];
|
||||
const Vector &n_b = normals[v_b->n];
|
||||
const Vector n((n_b - n_a)*render_t + n_a);
|
||||
|
||||
tex_coords[0][0] = uv->u;
|
||||
tex_coords[0][1] = uv->v;
|
||||
|
||||
mesh->setVertex(k, &t.x, &n.x, tex_coords);
|
||||
}
|
||||
mesh->unlock();
|
||||
|
||||
model->enqueue(mesh, 0, n_verts, 0, n_tris);
|
||||
}
|
||||
/*
|
||||
void MD2Rep::render( Model *model,const Vert *v_a,const Vert *v_b,float render_t ){
|
||||
|
||||
const VertexUV *uv=uvs.begin();
|
||||
|
||||
mesh->lock();
|
||||
for( int k=0;k<n_verts;++uv,++v_a,++v_b,++k ){
|
||||
|
||||
const Vector t( ( v_b->coords-v_a->coords)*render_t+v_a->coords );
|
||||
const Vector n( ( v_b->normal-v_a->normal)*render_t+v_a->normal );
|
||||
|
||||
tex_coords[0]=uv->u;
|
||||
tex_coords[1]=uv->v;
|
||||
|
||||
mesh->setVertex( k,&t.x,&n.x,tex_coords );
|
||||
}
|
||||
mesh->unlock();
|
||||
|
||||
model->enqueue( mesh,0,n_verts,0,n_tris );
|
||||
}
|
||||
*/
|
||||
|
||||
void MD2Rep::render(Model *model, const Vert *v_a, int render_b, float render_t) {
|
||||
|
||||
const Frame &frame_b = frames[render_b];
|
||||
const Vector scale_b = frame_b.scale, trans_b = frame_b.trans;
|
||||
|
||||
const VertexUV *uv = (VertexUV*)&uvs.begin()[0];
|
||||
const Vertex *v_b = (Vertex*)&frame_b.verts.begin()[0];
|
||||
|
||||
mesh->lock(true);
|
||||
for (int k = 0; k < n_verts; ++uv, ++v_a, ++v_b, ++k) {
|
||||
|
||||
const Vector t_b(v_b->x*scale_b.x + trans_b.x, v_b->y*scale_b.y + trans_b.y, v_b->z*scale_b.z + trans_b.z);
|
||||
const Vector t((t_b - v_a->coords)*render_t + v_a->coords);
|
||||
|
||||
const Vector &n_b = normals[v_b->n];
|
||||
const Vector n((n_b - v_a->normal)*render_t + v_a->normal);
|
||||
|
||||
tex_coords[0][0] = uv->u;
|
||||
tex_coords[0][1] = uv->v;
|
||||
|
||||
mesh->setVertex(k, &t.x, &n.x, tex_coords);
|
||||
}
|
||||
mesh->unlock();
|
||||
|
||||
model->enqueue(mesh, 0, n_verts, 0, n_tris);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
#ifndef MD2REP_H
|
||||
#define MD2REP_H
|
||||
|
||||
#include "model.hpp"
|
||||
|
||||
class MD2Rep{
|
||||
public:
|
||||
struct Vert{
|
||||
Vector coords,normal;
|
||||
};
|
||||
|
||||
MD2Rep( const string &f );
|
||||
virtual ~MD2Rep();
|
||||
|
||||
void render( Vert *verts,int frame );
|
||||
void render( Vert *verts,int frame,float time );
|
||||
void render( Vert *verts,int frame_a,int frame_b,float time );
|
||||
void render( Vert *verts,const Vert *verts_a,const Vert *verts_b,float time );
|
||||
|
||||
void render( Model *model,int frame_a,int frame_b,float time );
|
||||
void render( Model *model,const Vert *verts_a,const Vert *verts_b,float time );
|
||||
void render( Model *model,const Vert *verts_a,int frame_b,float time );
|
||||
|
||||
const Box &getBox()const{ return box; }
|
||||
const int numFrames()const{ return n_frames; }
|
||||
const int numVertices()const{ return n_verts; }
|
||||
|
||||
private:
|
||||
struct Vertex{
|
||||
unsigned char x,y,z,n;
|
||||
};
|
||||
|
||||
struct VertexUV{
|
||||
float u,v;
|
||||
};
|
||||
|
||||
struct Frame{
|
||||
Vector scale,trans;
|
||||
vector<Vertex> verts;
|
||||
};
|
||||
|
||||
Box box;
|
||||
gxMesh *mesh;
|
||||
int n_frames;
|
||||
int n_verts,n_tris;
|
||||
vector<Frame> frames;
|
||||
vector<VertexUV> uvs;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "meshcollider.hpp"
|
||||
|
||||
static const int MAX_COLL_TRIS=16;
|
||||
static vector<Vector> tri_centres;
|
||||
|
||||
extern float stats3d[10];
|
||||
|
||||
extern gxRuntime *gx_runtime;
|
||||
|
||||
static bool triTest( const Vector a[3],const Vector b[3] ){
|
||||
bool pb0=false,pb1=false,pb2=false;
|
||||
Plane p( a[0],a[1],a[2] ),p0,p1,p2;
|
||||
for( int k=0;k<3;++k ){
|
||||
Line l( b[k],b[(k+1)%3]-b[k] );
|
||||
float t=p.t_intersect( l );
|
||||
if( t<0 || t>1 ) continue;
|
||||
Vector i=l*t;
|
||||
if( !pb0 ){ p0=Plane( a[0]+p.n,a[1],a[0] );pb0=true; }
|
||||
if( p0.distance( i )<0 ) continue;
|
||||
if( !pb1 ){ p1=Plane( a[1]+p.n,a[2],a[1] );pb1=true; }
|
||||
if( p1.distance( i )<0 ) continue;
|
||||
if( !pb2 ){ p2=Plane( a[2]+p.n,a[0],a[2] );pb2=true; }
|
||||
if( p2.distance( i )<0 ) continue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool trisIntersect( const Vector a[3],const Vector b[3] ){
|
||||
return triTest( a,b ) || triTest( b,a );
|
||||
}
|
||||
|
||||
MeshCollider::MeshCollider( const vector<Vertex> &verts,const vector<Triangle> &tris ):
|
||||
vertices(verts),triangles(tris){
|
||||
vector<int> ts;
|
||||
tri_centres.clear();
|
||||
for( int k=0;k<triangles.size();++k ){
|
||||
const MeshCollider::Triangle &t=triangles[k];
|
||||
const Vector &v0=vertices[t.verts[0]].coords;
|
||||
const Vector &v1=vertices[t.verts[1]].coords;
|
||||
const Vector &v2=vertices[t.verts[2]].coords;
|
||||
tri_centres.push_back( (v0+v1+v2)/3 );
|
||||
ts.push_back( k );
|
||||
}
|
||||
tree=createNode( ts );
|
||||
}
|
||||
|
||||
MeshCollider::~MeshCollider(){
|
||||
delete tree;
|
||||
}
|
||||
|
||||
bool MeshCollider::collide( const Line &line,float radius,Collision *curr_coll,const Transform &t ){
|
||||
|
||||
if( !tree ) return false;
|
||||
|
||||
//create local box
|
||||
Box box( line );
|
||||
box.expand( radius );
|
||||
Box local_box=-t * box;
|
||||
|
||||
return collide( local_box,line,radius,t,curr_coll,tree );
|
||||
}
|
||||
|
||||
bool MeshCollider::collide( const Box &line_box,const Line &line,float radius,const Transform &tform,Collision *curr_coll,MeshCollider::Node *node ){
|
||||
if( !line_box.overlaps( node->box ) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hit=false;
|
||||
if( !node->triangles.size() ){
|
||||
if( node->left ) hit|=collide( line_box,line,radius,tform,curr_coll,node->left );
|
||||
if( node->right ) hit|=collide( line_box,line,radius,tform,curr_coll,node->right );
|
||||
return hit;
|
||||
}
|
||||
|
||||
stats3d[0]+=node->triangles.size();
|
||||
|
||||
for( int k=0;k<node->triangles.size();++k ){
|
||||
|
||||
const Triangle &tri=triangles[node->triangles[k]];
|
||||
const Vector &t_v0=vertices[ tri.verts[0] ].coords;
|
||||
const Vector &t_v1=vertices[ tri.verts[1] ].coords;
|
||||
const Vector &t_v2=vertices[ tri.verts[2] ].coords;
|
||||
|
||||
//tri box
|
||||
Box tri_box( t_v0 );
|
||||
tri_box.update( t_v1 );
|
||||
tri_box.update( t_v2 );
|
||||
if( !tri_box.overlaps( line_box ) ) continue;
|
||||
|
||||
if( !curr_coll->triangleCollide( line,radius,tform*t_v0,tform*t_v1,tform*t_v2 ) ) continue;
|
||||
|
||||
curr_coll->surface=tri.surface;
|
||||
curr_coll->index=tri.index;
|
||||
|
||||
hit=true;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
Box MeshCollider::nodeBox( const vector<int> &tris ){
|
||||
Box box;
|
||||
for( int k=0;k<tris.size();++k ){
|
||||
const Triangle &t=triangles[ tris[k] ];
|
||||
for( int j=0;j<3;++j ) box.update( vertices[t.verts[j]].coords );
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
MeshCollider::Node *MeshCollider::createLeaf( const vector<int> &tris ){
|
||||
|
||||
Node *c=new Node;
|
||||
c->box=nodeBox( tris );
|
||||
c->triangles=tris;
|
||||
leaves.push_back( c );
|
||||
return c;
|
||||
}
|
||||
|
||||
MeshCollider::Node *MeshCollider::createNode( const vector<int> &tris ){
|
||||
|
||||
if( tris.size()<=MAX_COLL_TRIS ) return createLeaf( tris );
|
||||
|
||||
Node *c=new Node;
|
||||
c->box=nodeBox( tris );
|
||||
|
||||
//find longest axis
|
||||
//
|
||||
float max=c->box.width();
|
||||
if( c->box.height()>max ) max=c->box.height();
|
||||
if( c->box.depth()>max ) max=c->box.depth();
|
||||
int axis=0;
|
||||
if( max==c->box.height() ) axis=1;
|
||||
else if( max==c->box.depth() ) axis=2;
|
||||
|
||||
//sort by axis
|
||||
//
|
||||
int k;
|
||||
multimap<float,int> axis_map;
|
||||
for( k=0;k<tris.size();++k ){
|
||||
pair<float,int> p( tri_centres[tris[k]][axis],tris[k] );
|
||||
axis_map.insert( p );
|
||||
}
|
||||
|
||||
//generate left node
|
||||
//
|
||||
vector<int> new_tris;
|
||||
multimap<float,int>::iterator it=axis_map.begin();
|
||||
for( k=axis_map.size()/2;k--;++it ){
|
||||
new_tris.push_back( it->second );
|
||||
}
|
||||
c->left=createNode( new_tris );
|
||||
|
||||
//generate right node
|
||||
//
|
||||
new_tris.clear();
|
||||
for( ;it!=axis_map.end();++it ){
|
||||
new_tris.push_back( it->second );
|
||||
}
|
||||
c->right=createNode( new_tris );
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
bool MeshCollider::intersects( const MeshCollider &c,const Transform &t )const{
|
||||
|
||||
static Vector a[MAX_COLL_TRIS][3],b[3];
|
||||
|
||||
if( !(t * tree->box).overlaps( c.tree->box ) ) return false;
|
||||
for( int k=0;k<leaves.size();++k ){
|
||||
Node *p=leaves[k];
|
||||
Box box=t*p->box;
|
||||
bool tformed=false;
|
||||
for( int j=0;j<c.leaves.size();++j ){
|
||||
Node *q=c.leaves[j];
|
||||
if( !box.overlaps( q->box ) ) continue;
|
||||
if( !tformed ){
|
||||
for( int n=0;n<p->triangles.size();++n ){
|
||||
const Triangle &tri=triangles[p->triangles[n]];
|
||||
a[n][0]=t * vertices[tri.verts[0]].coords;
|
||||
a[n][1]=t * vertices[tri.verts[1]].coords;
|
||||
a[n][2]=t * vertices[tri.verts[2]].coords;
|
||||
}
|
||||
tformed=true;
|
||||
}
|
||||
for( int n=0;n<q->triangles.size();++n ){
|
||||
const Triangle &tri=c.triangles[q->triangles[n]];
|
||||
b[0]=c.vertices[tri.verts[0]].coords;
|
||||
b[1]=c.vertices[tri.verts[1]].coords;
|
||||
b[2]=c.vertices[tri.verts[2]].coords;
|
||||
for( int t=0;t<p->triangles.size();++t ){
|
||||
if( trisIntersect( a[t],b ) ) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
#ifndef MESHCOLLIDER_H
|
||||
#define MESHCOLLIDER_H
|
||||
|
||||
#include "collision.hpp"
|
||||
|
||||
class MeshCollider{
|
||||
public:
|
||||
struct Vertex{
|
||||
Vector coords;
|
||||
};
|
||||
struct Triangle{
|
||||
void *surface;
|
||||
int verts[3],index;
|
||||
};
|
||||
MeshCollider( const vector<Vertex> &verts,const vector<Triangle> &tris );
|
||||
~MeshCollider();
|
||||
|
||||
//sphere collision
|
||||
bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &tform );
|
||||
|
||||
bool intersects( const MeshCollider &c,const Transform &t )const;
|
||||
|
||||
private:
|
||||
vector<Vertex> vertices;
|
||||
vector<Triangle> triangles;
|
||||
|
||||
struct Node{
|
||||
Box box;
|
||||
Node *left,*right;
|
||||
vector<int> triangles;
|
||||
Node():left(0),right(0){}
|
||||
~Node(){ delete left;delete right; }
|
||||
};
|
||||
|
||||
Node *tree;
|
||||
vector<Node*> leaves;
|
||||
|
||||
Box nodeBox( const vector<int> &tris );
|
||||
Node *createLeaf( const vector<int> &tris );
|
||||
Node *createNode( const vector<int> &tris );
|
||||
bool collide( const Box &box,const Line &line,float radius,const Transform &tform,Collision *curr_coll,Node *node );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "meshloader.hpp"
|
||||
#include "meshmodel.hpp"
|
||||
|
||||
struct Tri{
|
||||
int verts[3];
|
||||
};
|
||||
|
||||
struct Surf{
|
||||
vector<Tri> tris;
|
||||
};
|
||||
|
||||
struct MLMesh{
|
||||
map<Brush,Surf*> brush_map;
|
||||
vector<Surface::Vertex> verts;
|
||||
|
||||
MLMesh(){
|
||||
}
|
||||
|
||||
~MLMesh(){
|
||||
map<Brush,Surf*>::const_iterator it;
|
||||
for( it=brush_map.begin();it!=brush_map.end();++it ){
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static MLMesh *ml_mesh;
|
||||
static vector<MLMesh*> mesh_stack;
|
||||
|
||||
void MeshLoader::beginMesh(){
|
||||
mesh_stack.push_back( ml_mesh );
|
||||
ml_mesh=new MLMesh();
|
||||
}
|
||||
|
||||
int MeshLoader::numVertices(){
|
||||
return ml_mesh->verts.size();
|
||||
}
|
||||
|
||||
void MeshLoader::addVertex( const Surface::Vertex &v ){
|
||||
ml_mesh->verts.push_back( v );
|
||||
}
|
||||
|
||||
void MeshLoader::addTriangle( const int verts[3],const Brush &b ){
|
||||
addTriangle( verts[0],verts[1],verts[2],b );
|
||||
}
|
||||
|
||||
void MeshLoader::addBone( int n,float w,int b ){
|
||||
Surface::Vertex &v=ml_mesh->verts[n];
|
||||
int i;
|
||||
for( i=0;i<MAX_SURFACE_BONES;++i ){
|
||||
if( v.bone_bones[i]==255 || w>v.bone_weights[i] ) break;
|
||||
}
|
||||
if( i==MAX_SURFACE_BONES ) return;
|
||||
for( int k=MAX_SURFACE_BONES-1;k>i;--k ){
|
||||
v.bone_bones[k]=v.bone_bones[k-1];
|
||||
v.bone_weights[k]=v.bone_weights[k-1];
|
||||
}
|
||||
v.bone_bones[i]=b;
|
||||
v.bone_weights[i]=w;
|
||||
}
|
||||
|
||||
Surface::Vertex &MeshLoader::refVertex( int n ){
|
||||
return ml_mesh->verts[n];
|
||||
}
|
||||
|
||||
void MeshLoader::addTriangle( int v0,int v1,int v2,const Brush &b ){
|
||||
//find surface
|
||||
Surf *surf;
|
||||
map<Brush,Surf*>::const_iterator it=ml_mesh->brush_map.find( b );
|
||||
if( it!=ml_mesh->brush_map.end() ) surf=it->second;
|
||||
else{
|
||||
surf=new Surf;
|
||||
ml_mesh->brush_map.insert( make_pair( b,surf ) );
|
||||
}
|
||||
|
||||
Tri tri;
|
||||
tri.verts[0]=v0;tri.verts[1]=v1;tri.verts[2]=v2;
|
||||
surf->tris.push_back( tri );
|
||||
}
|
||||
|
||||
void MeshLoader::endMesh( MeshModel *mesh ){
|
||||
if( mesh ){
|
||||
//fix bone weights
|
||||
int k,max_bones=0;
|
||||
for( k=0;k<ml_mesh->verts.size();++k ){
|
||||
Surface::Vertex &v=ml_mesh->verts[k];
|
||||
if( v.bone_bones[0]==255 ) continue;
|
||||
int j;
|
||||
float t=0;
|
||||
for( j=0;j<MAX_SURFACE_BONES;++j ){
|
||||
if( v.bone_bones[j]==255 ) break;
|
||||
t+=v.bone_weights[j];
|
||||
}
|
||||
if( j>max_bones ) max_bones=j;
|
||||
t=1.0f/t;
|
||||
for( j=0;j<MAX_SURFACE_BONES;++j ){
|
||||
v.bone_weights[j]*=t;
|
||||
}
|
||||
}
|
||||
map<int,int> vert_map;
|
||||
map<Brush,Surf*>::iterator it;
|
||||
for( it=ml_mesh->brush_map.begin();it!=ml_mesh->brush_map.end();++it ){
|
||||
vert_map.clear();
|
||||
Brush b=it->first;
|
||||
Surf *t=it->second;
|
||||
Surface *surf=mesh->findSurface( b );
|
||||
if( !surf ) surf=mesh->createSurface( b );
|
||||
for( int k=0;k<t->tris.size();++k ){
|
||||
Surface::Triangle tri;
|
||||
for( int j=0;j<3;++j ){
|
||||
int n=t->tris[k].verts[j],id;
|
||||
map<int,int>::const_iterator it=vert_map.find( n );
|
||||
if( it!=vert_map.end() ) id=it->second;
|
||||
else{
|
||||
id=surf->numVertices();
|
||||
surf->addVertex( ml_mesh->verts[n] );
|
||||
vert_map.insert( make_pair( n,id ) );
|
||||
}
|
||||
tri.verts[j]=id;
|
||||
}
|
||||
surf->addTriangle( tri );
|
||||
}
|
||||
}
|
||||
}
|
||||
delete ml_mesh;
|
||||
ml_mesh=mesh_stack.back();
|
||||
mesh_stack.pop_back();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
#ifndef MESHLOADER_H
|
||||
#define MESHLOADER_H
|
||||
|
||||
#include "model.hpp"
|
||||
#include "surface.hpp"
|
||||
|
||||
class MeshLoader{
|
||||
public:
|
||||
enum{
|
||||
HINT_COLLAPSE=1,
|
||||
HINT_ANIMONLY=2
|
||||
};
|
||||
|
||||
virtual MeshModel *load( const string &f,const Transform &conv,int hint )=0;
|
||||
|
||||
//clear
|
||||
static void beginMesh();
|
||||
|
||||
//add a vertex
|
||||
static void addVertex( const Surface::Vertex &v );
|
||||
|
||||
//add a triangle
|
||||
static void addTriangle( const int verts[3],const Brush &b );
|
||||
|
||||
//also add a triangle
|
||||
static void addTriangle( int v0,int v1,int v2,const Brush &b );
|
||||
|
||||
//add a bone
|
||||
static void addBone( int vert,float weight,int bone );
|
||||
|
||||
//reference a vertex
|
||||
static Surface::Vertex &refVertex( int vert );
|
||||
|
||||
//number of verts
|
||||
static int numVertices();
|
||||
|
||||
//finally, update the mesh...
|
||||
static void endMesh( MeshModel *mesh );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,320 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "meshmodel.hpp"
|
||||
#include "meshcollider.hpp"
|
||||
|
||||
extern gxGraphics *gx_graphics;
|
||||
|
||||
struct MeshModel::Rep : public Surface::Monitor {
|
||||
|
||||
int ref_cnt;
|
||||
mutable Box box, cullBox;
|
||||
mutable MeshCollider *collider;
|
||||
mutable int box_valid, coll_valid, norms_valid;
|
||||
|
||||
SurfaceList surfaces;
|
||||
vector<Transform> bone_tforms;
|
||||
|
||||
Rep() :
|
||||
ref_cnt(1), collider(0), box_valid(-1), coll_valid(-1), norms_valid(-1) {
|
||||
geom_changes = brush_changes = 0;
|
||||
}
|
||||
|
||||
~Rep() {
|
||||
delete collider;
|
||||
for (int k = 0; k < surfaces.size(); ++k) delete surfaces[k];
|
||||
}
|
||||
|
||||
Surface *createSurface(const Brush &b) {
|
||||
Surface *t = new Surface(this);
|
||||
surfaces.push_back(t);
|
||||
t->setBrush(b);
|
||||
return t;
|
||||
}
|
||||
|
||||
Surface *findSurface(const Brush &b) {
|
||||
for (int k = 0; k < surfaces.size(); ++k) {
|
||||
Surface *s = surfaces[k];
|
||||
if (s->getBrush() < b || b < s->getBrush()) continue;
|
||||
return s;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void paint(const Brush &b) {
|
||||
for (int k = 0; k < surfaces.size(); ++k) {
|
||||
Surface *s = surfaces[k];
|
||||
s->setBrush(b);
|
||||
}
|
||||
}
|
||||
|
||||
void add(Rep *t) {
|
||||
if (cullBox.empty() && !t->cullBox.empty()) {
|
||||
setCullBox(t->cullBox);
|
||||
}
|
||||
for (int k = 0; k < t->surfaces.size(); ++k) {
|
||||
Surface *src = t->surfaces[k];
|
||||
Surface *dest = findSurface(src->getBrush());
|
||||
if (!dest) dest = createSurface(src->getBrush());
|
||||
int j;
|
||||
for (j = 0; j < src->numTriangles(); ++j) {
|
||||
Surface::Triangle t = src->getTriangle(j);
|
||||
t.verts[0] += dest->numVertices();
|
||||
t.verts[1] += dest->numVertices();
|
||||
t.verts[2] += dest->numVertices();
|
||||
dest->addTriangle(t);
|
||||
}
|
||||
for (j = 0; j < src->numVertices(); ++j) {
|
||||
dest->addVertex(src->getVertex(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void transform(const Transform &t) {
|
||||
Matrix co = t.m.cofactor();
|
||||
for (int k = 0; k < surfaces.size(); ++k) {
|
||||
Surface *s = surfaces[k];
|
||||
for (int j = 0; j < s->numVertices(); ++j) {
|
||||
const Vector &v = s->getVertex(j).coords;
|
||||
const Vector &n = s->getVertex(j).normal;
|
||||
s->setCoords(j, t*v);
|
||||
s->setNormal(j, co*n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flip() {
|
||||
for (int k = 0; k < surfaces.size(); ++k) {
|
||||
Surface *s = surfaces[k];
|
||||
int j;
|
||||
for (j = 0; j < s->numVertices(); ++j) {
|
||||
s->setNormal(j, -s->getVertex(j).normal);
|
||||
}
|
||||
for (j = 0; j < s->numTriangles(); ++j) {
|
||||
Surface::Triangle t = s->getTriangle(j);
|
||||
std::swap(t.verts[1], t.verts[2]);
|
||||
s->setTriangle(j, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setCullBox(const Box &t) {
|
||||
cullBox = t;
|
||||
}
|
||||
|
||||
void updateNormals() {
|
||||
if (norms_valid != geom_changes) {
|
||||
for (int k = 0; k < surfaces.size(); ++k) {
|
||||
Surface *s = surfaces[k];
|
||||
s->updateNormals();
|
||||
}
|
||||
norms_valid = geom_changes;
|
||||
}
|
||||
}
|
||||
|
||||
const Box &getBox()const {
|
||||
if (box_valid != geom_changes) {
|
||||
box.clear();
|
||||
for (int k = 0; k < surfaces.size(); ++k) {
|
||||
Surface *s = surfaces[k];
|
||||
for (int j = 0; j < s->numVertices(); ++j) {
|
||||
box.update(s->getVertex(j).coords);
|
||||
}
|
||||
}
|
||||
box_valid = geom_changes;
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
const Box &getCullBox()const {
|
||||
return cullBox.empty() ? getBox() : cullBox;
|
||||
}
|
||||
|
||||
MeshCollider *getCollider()const {
|
||||
if (coll_valid != geom_changes) {
|
||||
delete collider;
|
||||
vector<MeshCollider::Vertex> verts;
|
||||
vector<MeshCollider::Triangle> tris;
|
||||
for (int k = 0; k < surfaces.size(); ++k) {
|
||||
Surface *s = surfaces[k];
|
||||
int j;
|
||||
for (j = 0; j < s->numTriangles(); ++j) {
|
||||
MeshCollider::Triangle q;
|
||||
q.verts[0] = s->getTriangle(j).verts[0] + verts.size();
|
||||
q.verts[1] = s->getTriangle(j).verts[1] + verts.size();
|
||||
q.verts[2] = s->getTriangle(j).verts[2] + verts.size();
|
||||
q.surface = s;
|
||||
q.index = j;
|
||||
tris.push_back(q);
|
||||
}
|
||||
for (j = 0; j < s->numVertices(); ++j) {
|
||||
MeshCollider::Vertex q;
|
||||
q.coords = s->getVertex(j).coords;
|
||||
verts.push_back(q);
|
||||
}
|
||||
}
|
||||
collider = new MeshCollider(verts, tris);
|
||||
coll_valid = geom_changes;
|
||||
}
|
||||
return collider;
|
||||
}
|
||||
};
|
||||
|
||||
MeshModel::MeshModel() :
|
||||
rep(new Rep()), brush_changes(0) {}
|
||||
|
||||
MeshModel::MeshModel(const MeshModel &t) : Model(t),
|
||||
rep(t.rep), brush_changes(rep->brush_changes - 1) {
|
||||
++rep->ref_cnt;
|
||||
surf_bones.resize(t.surf_bones.size());
|
||||
/*
|
||||
if( t.surf_bones.size() ){
|
||||
surf_bones.resize( t.surf_bones.size() );
|
||||
if( rep->bone_tforms.size() ){
|
||||
setRenderSpace( RENDER_SPACE_WORLD );
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
MeshModel::~MeshModel() {
|
||||
if (!--rep->ref_cnt) delete rep;
|
||||
}
|
||||
|
||||
void MeshModel::updateNormals() {
|
||||
rep->updateNormals();
|
||||
}
|
||||
|
||||
void MeshModel::setCullBox(const Box &box) {
|
||||
rep->setCullBox(box);
|
||||
}
|
||||
|
||||
void MeshModel::setRenderBrush(const Brush &b) {
|
||||
--brush_changes;
|
||||
render_brush = b;
|
||||
}
|
||||
|
||||
void MeshModel::createBones() {
|
||||
setRenderSpace(RENDER_SPACE_WORLD);
|
||||
const vector<Object*> &bones = getAnimator()->getObjects();
|
||||
|
||||
surf_bones.resize(bones.size());
|
||||
|
||||
rep->bone_tforms.resize(bones.size());
|
||||
|
||||
for (int k = 0; k < bones.size(); ++k) {
|
||||
rep->bone_tforms[k] = -bones[k]->GetWorldTransform();
|
||||
}
|
||||
}
|
||||
|
||||
bool MeshModel::render(const RenderContext &rc) {
|
||||
|
||||
const Box &b = rep->getCullBox();
|
||||
if (b.empty()) return false;
|
||||
|
||||
static Frustum model_frustum;
|
||||
new(&model_frustum) Frustum(rc.getWorldFrustum(), -getRenderTform());
|
||||
if (!model_frustum.cull(b)) return false;
|
||||
|
||||
if (brush_changes != rep->brush_changes) {
|
||||
brushes.clear();
|
||||
for (int k = 0; k < rep->surfaces.size(); ++k) {
|
||||
Surface *s = rep->surfaces[k];
|
||||
brushes.push_back(Brush(s->getBrush(), render_brush));
|
||||
}
|
||||
brush_changes = rep->brush_changes;
|
||||
}
|
||||
|
||||
if (!surf_bones.size()) {
|
||||
for (int k = 0; k < rep->surfaces.size(); ++k) {
|
||||
Surface *s = rep->surfaces[k];
|
||||
if (gxMesh *mesh = s->getMesh()) {
|
||||
enqueue(mesh, 0, s->numVertices(), 0, s->numTriangles(), brushes[k]);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//OK, its boned!
|
||||
const vector<Object*> &bones = getAnimator()->getObjects();
|
||||
|
||||
int k;
|
||||
for (k = 0; k < bones.size(); ++k) {
|
||||
Transform t =
|
||||
bones[k]->getRenderTform() * rep->bone_tforms[k];
|
||||
surf_bones[k].coord_tform = t;
|
||||
surf_bones[k].normal_tform = t.m.cofactor();
|
||||
}
|
||||
|
||||
bool trans = false;
|
||||
for (k = 0; k < rep->surfaces.size(); ++k) {
|
||||
Surface *s = rep->surfaces[k];
|
||||
if (brushes[k].getBlend() == gxScene::BLEND_REPLACE) {
|
||||
if (gxMesh *mesh = s->getMesh(surf_bones)) {
|
||||
enqueue(mesh, 0, s->numVertices(), 0, s->numTriangles(), brushes[k]);
|
||||
}
|
||||
} else {
|
||||
trans = true;
|
||||
}
|
||||
}
|
||||
return trans;
|
||||
}
|
||||
|
||||
void MeshModel::renderQueue(int type) {
|
||||
if (type == QUEUE_TRANSPARENT && surf_bones.size()) {
|
||||
for (int k = 0; k < rep->surfaces.size(); ++k) {
|
||||
Surface *s = rep->surfaces[k];
|
||||
if (brushes[k].getBlend() != gxScene::BLEND_REPLACE) {
|
||||
if (gxMesh *mesh = s->getMesh(surf_bones)) {
|
||||
enqueue(mesh, 0, s->numVertices(), 0, s->numTriangles(), brushes[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Model::renderQueue(type);
|
||||
}
|
||||
|
||||
Surface *MeshModel::createSurface(const Brush &b) {
|
||||
return rep->createSurface(b);
|
||||
--brush_changes;
|
||||
}
|
||||
|
||||
void MeshModel::flipTriangles() {
|
||||
rep->flip();
|
||||
}
|
||||
|
||||
void MeshModel::transform(const Transform &t) {
|
||||
rep->transform(t);
|
||||
}
|
||||
|
||||
void MeshModel::add(const MeshModel &t) {
|
||||
rep->add(t.rep);
|
||||
}
|
||||
|
||||
const MeshModel::SurfaceList &MeshModel::getSurfaces()const {
|
||||
return rep->surfaces;
|
||||
}
|
||||
|
||||
void MeshModel::paint(const Brush &b) {
|
||||
rep->paint(b);
|
||||
}
|
||||
|
||||
const Box &MeshModel::getBox()const {
|
||||
return rep->getBox();
|
||||
}
|
||||
|
||||
MeshCollider *MeshModel::getCollider()const {
|
||||
return rep->getCollider();
|
||||
}
|
||||
|
||||
Surface *MeshModel::findSurface(const Brush &b)const {
|
||||
return rep->findSurface(b);
|
||||
}
|
||||
|
||||
bool MeshModel::collide(const Line &line, float radius, Collision *curr_coll, const Transform &t) {
|
||||
return getCollider()->collide(line, radius, curr_coll, t);
|
||||
}
|
||||
|
||||
bool MeshModel::intersects(const MeshModel &m)const {
|
||||
return getCollider()->intersects(*m.getCollider(), -m.GetWorldTransform()*GetWorldTransform());
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
#ifndef MESHMODEL_H
|
||||
#define MESHMODEL_H
|
||||
|
||||
#include "model.hpp"
|
||||
#include "surface.hpp"
|
||||
|
||||
class MeshCollider;
|
||||
|
||||
class MeshModel : public Model{
|
||||
public:
|
||||
typedef vector<Surface*> SurfaceList;
|
||||
|
||||
MeshModel();
|
||||
MeshModel( const MeshModel &t );
|
||||
~MeshModel();
|
||||
|
||||
//Entity interface
|
||||
virtual MeshModel *getMeshModel(){ return this; }
|
||||
virtual Entity *clone(){ return new MeshModel( *this ); }
|
||||
|
||||
//Object interface
|
||||
virtual bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &t );
|
||||
|
||||
//Model interface
|
||||
virtual void setRenderBrush( const Brush &b );
|
||||
virtual bool render( const RenderContext &rc );
|
||||
virtual void renderQueue( int type );
|
||||
|
||||
//boned mesh!
|
||||
void createBones();
|
||||
|
||||
//MeshModel interface
|
||||
Surface *createSurface( const Brush &b );
|
||||
void setCullBox( const Box &box );
|
||||
void updateNormals();
|
||||
void flipTriangles();
|
||||
void transform( const Transform &t );
|
||||
void paint( const Brush &b );
|
||||
void add( const MeshModel &t );
|
||||
void optimize();
|
||||
|
||||
//accessors
|
||||
const SurfaceList &getSurfaces()const;
|
||||
Surface *findSurface( const Brush &b )const;
|
||||
bool intersects( const MeshModel &m )const;
|
||||
MeshCollider *getCollider()const;
|
||||
const Box &getBox()const;
|
||||
|
||||
private:
|
||||
struct Rep;
|
||||
|
||||
Rep *rep;
|
||||
int brush_changes;
|
||||
Brush render_brush;
|
||||
vector<Brush> brushes;
|
||||
|
||||
vector<Surface::Bone> surf_bones;
|
||||
|
||||
MeshModel &operator=(const MeshModel &);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
#ifndef MESHRENDERER_H
|
||||
#define MESHRENDERER_H
|
||||
|
||||
#include "mesh.hpp"
|
||||
#include "model.hpp"
|
||||
|
||||
class MeshRenderer{
|
||||
public:
|
||||
MeshRenderer( const Mesh &t );
|
||||
~MeshRenderer();
|
||||
|
||||
void render( Camera *c,Model *m )const;
|
||||
|
||||
private:
|
||||
Box box;
|
||||
struct Surface;
|
||||
vector<Surface*> surfs;
|
||||
|
||||
MeshRenderer( const MeshRenderer &t );
|
||||
MeshRenderer &operator=(const MeshRenderer&);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,229 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "meshutil.hpp"
|
||||
|
||||
MeshModel *MeshUtil::createCube( const Brush &b ){
|
||||
static Vector norms[]={
|
||||
Vector(0,0,-1),Vector(1,0,0),Vector(0,0,1),
|
||||
Vector(-1,0,0),Vector(0,1,0),Vector(0,-1,0)
|
||||
};
|
||||
static Vector tex_coords[]={
|
||||
Vector(0,0,1),Vector(1,0,1),Vector(1,1,1),Vector(0,1,1)
|
||||
};
|
||||
static int verts[]={
|
||||
2,3,1,0,3,7,5,1,7,6,4,5,6,2,0,4,6,7,3,2,0,1,5,4
|
||||
};
|
||||
static Box box( Vector(-1,-1,-1),Vector(1,1,1) );
|
||||
|
||||
MeshModel *m=new MeshModel();
|
||||
Surface *s=m->createSurface( b );
|
||||
Surface::Vertex v;
|
||||
Surface::Triangle t;
|
||||
for( int k=0;k<24;k+=4 ){
|
||||
const Vector &normal=norms[k/4];
|
||||
for( int j=0;j<4;++j ){
|
||||
v.coords=box.corner( verts[k+j] );
|
||||
v.normal=normal;
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=tex_coords[j].x;
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=tex_coords[j].y;
|
||||
s->addVertex( v );
|
||||
}
|
||||
t.verts[0]=k;t.verts[1]=k+1;t.verts[2]=k+2;s->addTriangle(t);
|
||||
t.verts[1]=k+2;t.verts[2]=k+3;s->addTriangle(t);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
MeshModel *MeshUtil::createSphere( const Brush &b,int segs ){
|
||||
|
||||
int h_segs=segs*2,v_segs=segs;
|
||||
|
||||
MeshModel *m=new MeshModel();
|
||||
Surface *s=m->createSurface( b );
|
||||
|
||||
Surface::Vertex v;
|
||||
Surface::Triangle t;
|
||||
|
||||
v.coords=v.normal=Vector(0,1,0);
|
||||
int k;
|
||||
for( k=0;k<h_segs;++k ){
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=(k+.5f)/h_segs;
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=0;
|
||||
s->addVertex( v );
|
||||
}
|
||||
for( k=1;k<v_segs;++k ){
|
||||
float pitch=k*PI/v_segs-HALFPI;
|
||||
for( int j=0;j<=h_segs;++j ){
|
||||
float yaw=(j%h_segs)*TWOPI/h_segs;
|
||||
v.coords=v.normal=rotationMatrix( pitch,yaw,0 ).k;
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=float(j)/float(h_segs);
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=float(k)/float(v_segs);
|
||||
s->addVertex( v );
|
||||
}
|
||||
}
|
||||
v.coords=v.normal=Vector(0,-1,0);
|
||||
for( k=0;k<h_segs;++k ){
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=(k+.5f)/h_segs;
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=1;
|
||||
s->addVertex( v );
|
||||
}
|
||||
for( k=0;k<h_segs;++k ){
|
||||
t.verts[0]=k;
|
||||
t.verts[1]=t.verts[0]+h_segs+1;
|
||||
t.verts[2]=t.verts[1]-1;
|
||||
s->addTriangle( t );
|
||||
}
|
||||
for( k=1;k<v_segs-1;++k ){
|
||||
for( int j=0;j<h_segs;++j ){
|
||||
t.verts[0]=k*(h_segs+1)+j-1;
|
||||
t.verts[1]=t.verts[0]+1;
|
||||
t.verts[2]=t.verts[1]+h_segs+1;
|
||||
s->addTriangle( t );
|
||||
t.verts[1]=t.verts[2];
|
||||
t.verts[2]=t.verts[1]-1;
|
||||
s->addTriangle( t );
|
||||
}
|
||||
}
|
||||
for( k=0;k<h_segs;++k ){
|
||||
t.verts[0]=(h_segs+1)*(v_segs-1)+k-1;
|
||||
t.verts[1]=t.verts[0]+1;
|
||||
t.verts[2]=t.verts[1]+h_segs;
|
||||
s->addTriangle( t );
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
MeshModel *MeshUtil::createCylinder( const Brush &b,int segs,bool solid ){
|
||||
|
||||
MeshModel *m=new MeshModel();
|
||||
Surface::Vertex v;
|
||||
Surface::Triangle t;
|
||||
|
||||
Surface *s=m->createSurface( b );
|
||||
int k;
|
||||
for( k=0;k<=segs;++k ){
|
||||
float yaw=(k%segs)*TWOPI/segs;
|
||||
v.coords=rotationMatrix( 0,yaw,0 ).k;
|
||||
v.coords.y=1;
|
||||
v.normal=Vector(v.coords.x,0,v.coords.z);
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=float(k)/segs;
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=0;
|
||||
s->addVertex( v );
|
||||
v.coords.y=-1;
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=float(k)/segs;
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=1;
|
||||
s->addVertex( v );
|
||||
}
|
||||
for( k=0;k<segs;++k ){
|
||||
t.verts[0]=k*2;
|
||||
t.verts[1]=t.verts[0]+2;
|
||||
t.verts[2]=t.verts[1]+1;
|
||||
s->addTriangle( t );
|
||||
t.verts[1]=t.verts[2];
|
||||
t.verts[2]=t.verts[1]-2;
|
||||
s->addTriangle( t );
|
||||
}
|
||||
|
||||
if( !solid ) return m;
|
||||
|
||||
s=m->createSurface( b );
|
||||
|
||||
for( k=0;k<segs;++k ){
|
||||
float yaw=k*TWOPI/segs;
|
||||
v.coords=rotationMatrix( 0,yaw,0 ).k;
|
||||
v.coords.y=1;v.normal=Vector(0,1,0);
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=v.coords.x*.5f+.5f;
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=v.coords.z*.5f+.5f;
|
||||
s->addVertex(v);
|
||||
v.coords.y=-1;v.normal=Vector( 0,-1,0 );
|
||||
s->addVertex(v);
|
||||
}
|
||||
for( k=2;k<segs;++k ){
|
||||
t.verts[0]=0;
|
||||
t.verts[1]=k*2;
|
||||
t.verts[2]=(k-1)*2;
|
||||
s->addTriangle( t );
|
||||
t.verts[0]=1;
|
||||
t.verts[1]=(k-1)*2+1;
|
||||
t.verts[2]=k*2+1;
|
||||
s->addTriangle( t );
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
MeshModel *MeshUtil::createCone( const Brush &b,int segs,bool solid ){
|
||||
MeshModel *m=new MeshModel();
|
||||
Surface::Vertex v;
|
||||
Surface::Triangle t;
|
||||
|
||||
Surface *s;
|
||||
s=m->createSurface( b );
|
||||
int k;
|
||||
v.coords=v.normal=Vector(0,1,0);
|
||||
for( k=0;k<segs;++k ){
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=(k+.5f)/segs;
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=0;
|
||||
s->addVertex( v );
|
||||
}
|
||||
for( k=0;k<=segs;++k ){
|
||||
float yaw=(k%segs)*TWOPI/segs;
|
||||
v.coords=yawMatrix( yaw ).k;v.coords.y=-1;
|
||||
v.normal=Vector( v.coords.x,0,v.coords.z );
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=float(k)/segs;
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=1;
|
||||
s->addVertex( v );
|
||||
}
|
||||
for( k=0;k<segs;++k ){
|
||||
t.verts[0]=k;
|
||||
t.verts[1]=k+segs+1;
|
||||
t.verts[2]=k+segs;
|
||||
s->addTriangle( t );
|
||||
}
|
||||
if( !solid ) return m;
|
||||
s=m->createSurface( b );
|
||||
for( k=0;k<segs;++k ){
|
||||
float yaw=k*TWOPI/segs;
|
||||
v.coords=yawMatrix( yaw ).k;v.coords.y=-1;
|
||||
v.normal=Vector( v.coords.x,0,v.coords.z );
|
||||
v.tex_coords[0][0]=v.tex_coords[1][0]=v.coords.x*.5f+.5f;
|
||||
v.tex_coords[0][1]=v.tex_coords[1][1]=v.coords.z*.5f+.5f;
|
||||
s->addVertex( v );
|
||||
}
|
||||
t.verts[0]=0;
|
||||
for( k=2;k<segs;++k ){
|
||||
t.verts[1]=k-1;
|
||||
t.verts[2]=k;
|
||||
s->addTriangle( t );
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void MeshUtil::lightMesh( MeshModel *m,const Vector &pos,const Vector &rgb,float range ){
|
||||
if( range ){
|
||||
float att=1.0f/range;
|
||||
const MeshModel::SurfaceList &surfs=m->getSurfaces();
|
||||
for( int k=0;k<surfs.size();++k ){
|
||||
Surface *s=surfs[k];
|
||||
for( int j=0;j<s->numVertices();++j ){
|
||||
const Surface::Vertex &v=s->getVertex( j );
|
||||
Vector lv=pos-v.coords;
|
||||
float dp=v.normal.normalized().dot( lv );
|
||||
if( dp<=0 ) continue;
|
||||
float d=lv.length();
|
||||
float i=1/(d*att)*(dp/d);
|
||||
s->setColor( j,s->getColor(j)+rgb*i );
|
||||
}
|
||||
}
|
||||
}else{
|
||||
const MeshModel::SurfaceList &surfs=m->getSurfaces();
|
||||
for( int k=0;k<surfs.size();++k ){
|
||||
Surface *s=surfs[k];
|
||||
for( int j=0;j<s->numVertices();++j ){
|
||||
const Surface::Vertex &v=s->getVertex( j );
|
||||
s->setColor( j,s->getColor(j)+rgb );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
#ifndef MESHUTIL_H
|
||||
#define MESHUTIL_H
|
||||
|
||||
#include "meshmodel.hpp"
|
||||
|
||||
struct MeshUtil{
|
||||
|
||||
static MeshModel *createCube( const Brush &b );
|
||||
static MeshModel *createSphere( const Brush &b,int segs );
|
||||
static MeshModel *createCylinder( const Brush &b,int segs,bool solid );
|
||||
static MeshModel *createCone( const Brush &b,int segs,bool solid );
|
||||
|
||||
static void lightMesh( MeshModel *m,const Vector &pos,const Vector &rgb,float range );
|
||||
|
||||
/*
|
||||
static void flipMesh( Mesh *m );
|
||||
static void fitMesh( Mesh *m,const Box &b );
|
||||
static void paintMesh( Mesh *m,const Brush &b );
|
||||
static void transformMesh( Mesh *m,const Transform &t );
|
||||
static void lightMesh( Mesh *m,const Vector &pos,const Vector &rgb,float range );
|
||||
static void lightMapMesh( Mesh *m,const Mesh &l );
|
||||
|
||||
static Mesh createCube( const Brush &b,int segs );
|
||||
static Mesh createSphere( const Brush &b,int segs );
|
||||
static Mesh createCylinder( const Brush &b,int segs );
|
||||
*/
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "mirror.hpp"
|
||||
|
||||
Mirror::Mirror(){
|
||||
}
|
||||
|
||||
Mirror::Mirror( const Mirror &t ):
|
||||
Object(t){
|
||||
}
|
||||
|
||||
Mirror::~Mirror(){
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
#ifndef MIRROR_H
|
||||
#define MIRROR_H
|
||||
|
||||
#include "object.hpp"
|
||||
|
||||
class Mirror : public Object{
|
||||
public:
|
||||
Mirror();
|
||||
Mirror( const Mirror &t );
|
||||
~Mirror();
|
||||
|
||||
//Entity interface
|
||||
Entity *clone(){ return new Mirror( *this ); }
|
||||
Mirror *getMirror(){ return this; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "model.hpp"
|
||||
|
||||
extern gxScene *gx_scene;
|
||||
|
||||
class Model::MeshQueue{
|
||||
union{
|
||||
gxMesh *mesh;
|
||||
MeshQueue *next;
|
||||
};
|
||||
int fv,vc,ft,tc;
|
||||
Brush brush;
|
||||
int q_type;
|
||||
// bool opaque;
|
||||
|
||||
static MeshQueue *pool;
|
||||
|
||||
public:
|
||||
MeshQueue(){}
|
||||
|
||||
MeshQueue( gxMesh *m,int fv,int vc,int ft,int tc,const Brush &b ):
|
||||
mesh(m),fv(fv),vc(vc),ft(ft),tc(tc),brush(b){
|
||||
int n=brush.getBlend();
|
||||
q_type=(n==gxScene::BLEND_REPLACE) ? QUEUE_OPAQUE : QUEUE_TRANSPARENT;
|
||||
}
|
||||
|
||||
int getQueueType()const{
|
||||
return q_type;
|
||||
}
|
||||
void render(){
|
||||
gx_scene->setRenderState( brush.getRenderState() );
|
||||
gx_scene->render( mesh,fv,vc,ft,tc );
|
||||
}
|
||||
void *operator new( size_t sz ){
|
||||
static const int GROW=256;
|
||||
if( !pool ){
|
||||
pool=new MeshQueue[GROW];
|
||||
for( int k=0;k<GROW-1;++k ) pool[k].next=&pool[k+1];
|
||||
pool[GROW-1].next=0;
|
||||
}
|
||||
MeshQueue *t=pool;
|
||||
pool=t->next;
|
||||
return t;
|
||||
}
|
||||
void operator delete( void *q ){
|
||||
MeshQueue *t=(MeshQueue*)q;
|
||||
t->next=pool;
|
||||
pool=t;
|
||||
}
|
||||
};
|
||||
|
||||
Model::MeshQueue *Model::MeshQueue::pool;
|
||||
|
||||
Model::Model():
|
||||
space( RENDER_SPACE_LOCAL ),
|
||||
auto_fade(false),
|
||||
captured_alpha(1),w_brush(true){
|
||||
}
|
||||
|
||||
Model::Model( const Model &t ):Object(t),
|
||||
space(t.space),brush(t.brush),
|
||||
auto_fade(t.auto_fade),auto_fade_nr(t.auto_fade_nr),auto_fade_fr(t.auto_fade_fr),
|
||||
captured_alpha(t.captured_alpha),w_brush(true){
|
||||
}
|
||||
|
||||
void Model::capture(){
|
||||
Object::capture();
|
||||
captured_alpha=brush.getAlpha();
|
||||
}
|
||||
|
||||
bool Model::beginRender( float t ){
|
||||
Object::beginRender( t );
|
||||
tweened_alpha=brush.getAlpha();
|
||||
if( t!=1 && tweened_alpha!=captured_alpha ){
|
||||
//
|
||||
//render tweening of alpha
|
||||
//
|
||||
tweened_alpha=(tweened_alpha-captured_alpha)*t+captured_alpha;
|
||||
}
|
||||
return tweened_alpha>0;
|
||||
}
|
||||
|
||||
bool Model::doAutoFade( const Vector &eye ){
|
||||
float alpha=tweened_alpha;
|
||||
if( auto_fade ){
|
||||
//
|
||||
//autofading of alpha
|
||||
//
|
||||
float d=eye.distance( getRenderTform().v );
|
||||
if( d>=auto_fade_fr ) return false;
|
||||
if( d>=auto_fade_nr ){
|
||||
float t=1-(d-auto_fade_nr)/(auto_fade_fr-auto_fade_nr );
|
||||
alpha*=t;if( alpha<=0 ) return false;
|
||||
}
|
||||
}
|
||||
if( w_brush ) render_brush=brush;
|
||||
|
||||
if( alpha!=render_brush.getAlpha() ){
|
||||
render_brush.setAlpha( alpha );
|
||||
}else if( !w_brush ){
|
||||
return true;
|
||||
}
|
||||
|
||||
setRenderBrush( render_brush );
|
||||
w_brush=false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Model::enqueue( MeshQueue *q ){
|
||||
queues[q->getQueueType()].push_back( q );
|
||||
}
|
||||
|
||||
void Model::enqueue( gxMesh *mesh,int fv,int vc,int ft,int tc ){
|
||||
enqueue( new MeshQueue( mesh,fv,vc,ft,tc,render_brush ) );
|
||||
}
|
||||
|
||||
void Model::enqueue( gxMesh *mesh,int fv,int vc,int ft,int tc,const Brush &brush ){
|
||||
enqueue( new MeshQueue( mesh,fv,vc,ft,tc,brush ) );
|
||||
}
|
||||
|
||||
void Model::renderQueue( int type ){
|
||||
vector<MeshQueue*> *que=&queues[type];
|
||||
for( ;que->size();que->pop_back() ){
|
||||
MeshQueue *q=que->back();
|
||||
q->render();
|
||||
delete q;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
|
||||
#ifndef MODEL_H
|
||||
#define MODEL_H
|
||||
|
||||
#include "brush.hpp"
|
||||
#include "object.hpp"
|
||||
#include "rendercontext.hpp"
|
||||
|
||||
class Sprite;
|
||||
class Terrain;
|
||||
class PlaneModel;
|
||||
class Q3BSPModel;
|
||||
|
||||
class Model : public Object{
|
||||
public:
|
||||
enum{
|
||||
RENDER_SPACE_LOCAL=0,
|
||||
RENDER_SPACE_WORLD=1
|
||||
};
|
||||
enum{
|
||||
COLLISION_GEOMETRY_DEFAULT=0,
|
||||
COLLISION_GEOMETRY_TRIS=1,
|
||||
COLLISION_GEOMETRY_BOX=2,
|
||||
COLLISION_GEOMETRY_SPHERE=3
|
||||
};
|
||||
enum{
|
||||
QUEUE_OPAQUE=0,
|
||||
QUEUE_TRANSPARENT=1
|
||||
};
|
||||
|
||||
Model();
|
||||
Model( const Model &m );
|
||||
|
||||
//Entity interface
|
||||
Model *getModel(){ return this; }
|
||||
|
||||
//Object interface
|
||||
void capture();
|
||||
bool beginRender( float tween );
|
||||
|
||||
//Model interface
|
||||
virtual void setRenderBrush( const Brush &b ){}
|
||||
virtual bool render( const RenderContext &rc ){ return false; }
|
||||
virtual void renderQueue( int type );
|
||||
|
||||
virtual Sprite *getSprite(){ return 0; }
|
||||
virtual Terrain *getTerrain(){ return 0; }
|
||||
virtual PlaneModel *getPlaneModel(){ return 0; }
|
||||
virtual MeshModel *getMeshModel(){ return 0; }
|
||||
virtual MD2Model *getMD2Model(){ return 0; }
|
||||
virtual Q3BSPModel *getBSPModel(){ return 0; }
|
||||
|
||||
virtual void setBrush( const Brush &b ){ brush=b;w_brush=true; }
|
||||
virtual void setColor( const Vector &c ){ brush.setColor(c);w_brush=true; }
|
||||
virtual void setAlpha( float a ){ brush.setAlpha(a);w_brush=true; }
|
||||
virtual void setShininess( float t ){ brush.setShininess(t);w_brush=true; }
|
||||
virtual void setTexture( int i,const Texture &t,int f ){ brush.setTexture(i,t,f);w_brush=true; }
|
||||
virtual void setBlend( int n ){ brush.setBlend(n);w_brush=true; }
|
||||
virtual void setFX( int n ){ brush.setFX(n);w_brush=true; }
|
||||
|
||||
const Brush &getBrush()const{ return brush; }
|
||||
|
||||
void setRenderSpace( int n ){ space=n; }
|
||||
int getRenderSpace()const{ return space; }
|
||||
|
||||
void setAutoFade( float nr,float fr ){ auto_fade_nr=nr;auto_fade_fr=fr;auto_fade=true; }
|
||||
|
||||
bool doAutoFade( const Vector &eye );
|
||||
|
||||
void enqueue( gxMesh *mesh,int first_vert,int vert_cnt,int first_tri,int tri_cnt );
|
||||
void enqueue( gxMesh *mesh,int first_vert,int vert_cnt,int first_tri,int tri_cnt,const Brush &b );
|
||||
|
||||
int queueSize( int type )const{ return queues[type].size(); }
|
||||
|
||||
private:
|
||||
class MeshQueue;
|
||||
|
||||
int space;
|
||||
Brush brush,render_brush;
|
||||
|
||||
mutable bool w_brush;
|
||||
float captured_alpha,tweened_alpha;
|
||||
|
||||
bool auto_fade;
|
||||
float auto_fade_nr,auto_fade_fr;
|
||||
|
||||
vector<MeshQueue*> queues[2];
|
||||
|
||||
void enqueue( MeshQueue *q );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,162 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "object.hpp"
|
||||
|
||||
extern gxRuntime *gx_runtime;
|
||||
|
||||
Object::Object():
|
||||
order(0),animator(0),last_copy(0),
|
||||
coll_type(0),coll_radii(Vector(1,1,1)),coll_box(Box(Vector(-1,-1,-1),Vector(1,1,1))),
|
||||
pick_geom(0),obscurer(false),captured(false){
|
||||
reset();
|
||||
}
|
||||
|
||||
Object::Object( const Object &o ):
|
||||
Entity(o),
|
||||
order(o.order),animator(0),last_copy(0),
|
||||
coll_type(o.coll_type),coll_radii(o.coll_radii),coll_box(o.coll_box),
|
||||
pick_geom(o.pick_geom),obscurer(o.obscurer),captured(false){
|
||||
reset();
|
||||
}
|
||||
|
||||
Object::~Object(){
|
||||
delete animator;
|
||||
velocity=Vector();
|
||||
updateSounds();
|
||||
}
|
||||
|
||||
Object *Object::copy(){
|
||||
last_copy=clone()->getObject();
|
||||
for( Entity *e=GetChildren();e;e=e->GetSuccessor() ){
|
||||
Object *cpy=e->getObject()->copy();
|
||||
cpy->SetParent( last_copy );
|
||||
}
|
||||
if( animator ) last_copy->setAnimator( new Animator( animator ) );
|
||||
return last_copy;
|
||||
}
|
||||
|
||||
void Object::reset(){
|
||||
colls.clear();
|
||||
velocity=Vector();
|
||||
prev_tform=GetWorldTransform();
|
||||
}
|
||||
|
||||
void Object::setCollisionType( int type ){
|
||||
coll_type=type;
|
||||
}
|
||||
|
||||
void Object::setCollisionRadii( const Vector &radii ){
|
||||
coll_radii=radii;
|
||||
}
|
||||
|
||||
void Object::setCollisionBox( const Box &box ){
|
||||
coll_box=box;
|
||||
}
|
||||
|
||||
void Object::setAnimator( Animator *t ){
|
||||
if( animator ) delete animator;
|
||||
animator=t;
|
||||
}
|
||||
|
||||
void Object::beginUpdate( float e ){
|
||||
elapsed=e;
|
||||
colls.clear();
|
||||
animate( e );
|
||||
}
|
||||
|
||||
void Object::animate( float e ){
|
||||
if( animator ) animator->update( e );
|
||||
}
|
||||
|
||||
void Object::addCollision( const ObjCollision *c ){
|
||||
colls.push_back( c );
|
||||
}
|
||||
|
||||
void Object::endUpdate(){
|
||||
velocity=(GetWorldTransform().v-prev_tform.v)/elapsed;
|
||||
prev_tform=GetWorldTransform();
|
||||
}
|
||||
|
||||
void Object::capture(){
|
||||
capt_pos=GetLocalPosition();
|
||||
capt_scl=GetLocalScale();
|
||||
capt_rot=GetLocalRotation();
|
||||
captured=true;
|
||||
}
|
||||
|
||||
bool Object::beginRender( float tween ){
|
||||
updateSounds();
|
||||
if( tween==1 || !captured ){
|
||||
render_tform=GetWorldTransform();
|
||||
render_tform_valid=true;
|
||||
}else{
|
||||
Vector pos=(GetLocalPosition()-capt_pos)*tween+capt_pos;
|
||||
Vector scl=(GetLocalScale()-capt_scl)*tween+capt_scl;
|
||||
Quat rot=capt_rot.slerpTo( GetLocalRotation(),tween );
|
||||
tween_tform.m=Matrix( rot );
|
||||
tween_tform.m.i*=scl.x;
|
||||
tween_tform.m.j*=scl.y;
|
||||
tween_tform.m.k*=scl.z;
|
||||
tween_tform.v=pos;
|
||||
render_tform_valid=false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Object::endRender(){
|
||||
}
|
||||
|
||||
int Object::getCollisionType()const{
|
||||
return coll_type;
|
||||
}
|
||||
|
||||
const Vector &Object::getCollisionRadii()const{
|
||||
return coll_radii;
|
||||
}
|
||||
|
||||
const Box &Object::getCollisionBox()const{
|
||||
return coll_box;
|
||||
}
|
||||
|
||||
const Vector &Object::getVelocity()const{
|
||||
return velocity;
|
||||
}
|
||||
|
||||
const Object::Collisions &Object::getCollisions()const{
|
||||
return colls;
|
||||
}
|
||||
|
||||
const Transform &Object::getRenderTform()const{
|
||||
if( render_tform_valid ) return render_tform;
|
||||
|
||||
Object *parent=(Object*)getParent();
|
||||
render_tform=parent ? parent->getRenderTform() * tween_tform : tween_tform;
|
||||
render_tform_valid=true;
|
||||
|
||||
return render_tform;
|
||||
}
|
||||
|
||||
const Transform &Object::getPrevWorldTform()const{
|
||||
return prev_tform;
|
||||
}
|
||||
|
||||
gxChannel *Object::emitSound( gxSound *sound ){
|
||||
if( !sound ) return 0;
|
||||
|
||||
gxChannel *chan=sound->play3d( &GetWorldTransform().v.x,&velocity.x );
|
||||
for( int k=0;k<channels.size();++k ){
|
||||
if( chan==channels[k] ) return chan;
|
||||
if( !channels[k] ) return channels[k]=chan;
|
||||
}
|
||||
channels.push_back( chan );
|
||||
return chan;
|
||||
}
|
||||
|
||||
void Object::updateSounds(){
|
||||
for( int k=0;k<channels.size();++k ){
|
||||
if( gxChannel *chan=channels[k] ){
|
||||
if( chan->isPlaying() ) chan->set3d( &GetWorldTransform().v.x,&velocity.x );
|
||||
else channels[k]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
|
||||
#ifndef OBJECT_H
|
||||
#define OBJECT_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "entity.hpp"
|
||||
#include "animator.hpp"
|
||||
#include "collision.hpp"
|
||||
|
||||
class gxSound;
|
||||
|
||||
struct ObjCollision{
|
||||
Object *with;
|
||||
Vector coords;
|
||||
Collision collision;
|
||||
};
|
||||
|
||||
class Object : public Entity{
|
||||
public:
|
||||
typedef std::vector<const ObjCollision*> Collisions;
|
||||
|
||||
Object();
|
||||
Object( const Object &object );
|
||||
~Object();
|
||||
|
||||
//Entity interface
|
||||
Object *getObject(){ return this; }
|
||||
Entity *clone(){ return new Object( *this ); }
|
||||
|
||||
//deep object copy!
|
||||
Object *copy();
|
||||
|
||||
//called by user
|
||||
void reset();
|
||||
void setCollisionType( int type );
|
||||
void setCollisionRadii( const Vector &radii );
|
||||
void setCollisionBox( const Box &box );
|
||||
void setOrder( int n ){ order=n; }
|
||||
void setPickGeometry( int n ){ pick_geom=n; }
|
||||
void setObscurer( bool t ){ obscurer=t; }
|
||||
void setAnimation( const Animation &t ){ anim=t; }
|
||||
void setAnimator( Animator *t );
|
||||
|
||||
gxChannel *emitSound( gxSound *sound );
|
||||
|
||||
//overridables!
|
||||
virtual bool collide( const Line &line,float radius,::Collision *curr_coll,const Transform &t ){ return false; }
|
||||
virtual void capture();
|
||||
virtual void animate( float e );
|
||||
virtual bool beginRender( float tween );
|
||||
virtual void endRender();
|
||||
|
||||
//for use by world
|
||||
void beginUpdate( float elapsed );
|
||||
void addCollision( const ObjCollision *c );
|
||||
void endUpdate();
|
||||
|
||||
//accessors
|
||||
int getCollisionType()const;
|
||||
const Vector &getCollisionRadii()const;
|
||||
const Box &getCollisionBox()const;
|
||||
int getOrder()const{ return order; }
|
||||
const Vector &getVelocity()const;
|
||||
const Collisions &getCollisions()const;
|
||||
const Transform &getRenderTform()const;
|
||||
const Transform &getPrevWorldTform()const;
|
||||
int getPickGeometry()const{ return pick_geom; }
|
||||
int getObscurer()const{ return obscurer; }
|
||||
Animation getAnimation()const{ return anim; }
|
||||
Animator *getAnimator()const{ return animator; }
|
||||
Object *getLastCopy()const{ return last_copy; }
|
||||
|
||||
private:
|
||||
int coll_type;
|
||||
int order;
|
||||
Vector coll_radii;
|
||||
Collisions colls;
|
||||
bool captured;
|
||||
Box coll_box;
|
||||
int pick_geom;
|
||||
bool obscurer;
|
||||
float elapsed;
|
||||
Vector velocity;
|
||||
vector<gxChannel*> channels;
|
||||
Vector capt_pos,capt_scl;
|
||||
Quat capt_rot;
|
||||
mutable Object *last_copy;
|
||||
|
||||
Transform prev_tform;
|
||||
Transform captured_tform,tween_tform;
|
||||
mutable Transform render_tform;
|
||||
mutable bool render_tform_valid;
|
||||
|
||||
Animation anim;
|
||||
Animator *animator;
|
||||
|
||||
void updateSounds();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "pivot.hpp"
|
||||
|
||||
Pivot::Pivot(){
|
||||
}
|
||||
|
||||
Pivot::Pivot( const Object &t ):
|
||||
Object(t){
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
#ifndef PIVOT_H
|
||||
#define PIVOT_H
|
||||
|
||||
#include "object.hpp"
|
||||
|
||||
class Pivot : public Object{
|
||||
public:
|
||||
Pivot();
|
||||
Pivot( const Object &t );
|
||||
|
||||
//Entity interface
|
||||
Entity *clone(){ return new Pivot( *this ); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,136 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "planemodel.hpp"
|
||||
#include "frustum.hpp"
|
||||
#include "camera.hpp"
|
||||
|
||||
static Vector vts[17][17];
|
||||
|
||||
extern gxGraphics *gx_graphics;
|
||||
|
||||
struct PlaneModel::Rep{
|
||||
|
||||
int ref_cnt;
|
||||
gxMesh *mesh;
|
||||
int sub_divs;
|
||||
|
||||
Rep( int n ):
|
||||
ref_cnt(1),sub_divs(n){
|
||||
mesh=gx_graphics->createMesh( 5*sub_divs*sub_divs,3*sub_divs*sub_divs,0 );
|
||||
}
|
||||
~Rep(){
|
||||
gx_graphics->freeMesh( mesh );
|
||||
}
|
||||
void render( PlaneModel *model,const RenderContext &rc ){
|
||||
|
||||
static Frustum f;
|
||||
new( &f ) Frustum( rc.getWorldFrustum(),-model->getRenderTform() );
|
||||
const Vector &eye=f.getVertex( Frustum::VERT_EYE );
|
||||
|
||||
if( eye.y<=0 ) return;
|
||||
|
||||
const Vector &tl=f.getVertex( Frustum::VERT_TLFAR );
|
||||
const Vector &tr=f.getVertex( Frustum::VERT_TRFAR );
|
||||
const Vector &br=f.getVertex( Frustum::VERT_BRFAR );
|
||||
const Vector &bl=f.getVertex( Frustum::VERT_BLFAR );
|
||||
|
||||
Transform tex_t( model->getRenderTform().m );
|
||||
|
||||
int x;
|
||||
for( x=0;x<=sub_divs;++x ){
|
||||
float t=float(x)/float(sub_divs);
|
||||
Vector tx=(tr-tl)*t+tl;
|
||||
Vector bx=(br-bl)*t+bl;
|
||||
for( int y=0;y<=sub_divs;++y ){
|
||||
float t=float(y)/float(sub_divs);
|
||||
vts[x][y]=(bx-tx)*t+tx;
|
||||
}
|
||||
}
|
||||
|
||||
Plane plane( Vector( 0,1,0 ),0 );
|
||||
|
||||
mesh->lock( true );
|
||||
int v_cnt=0,t_cnt=0;
|
||||
for( x=0;x<sub_divs;++x ){
|
||||
for( int y=0;y<sub_divs;++y ){
|
||||
|
||||
Vector in_verts[4],out_verts[5];
|
||||
|
||||
in_verts[0]=vts[x][y];
|
||||
in_verts[1]=vts[x+1][y];
|
||||
in_verts[2]=vts[x+1][y+1];
|
||||
in_verts[3]=vts[x][y+1];
|
||||
|
||||
int k,out_cnt=0;
|
||||
for( k=0;k<4;++k ){
|
||||
|
||||
const Vector &vert=in_verts[k];
|
||||
const Vector &prev_vert=in_verts[(k-1)&3];
|
||||
|
||||
if( vert.y>0 ){
|
||||
if( prev_vert.y<=0 ){
|
||||
float t=prev_vert.y/(prev_vert.y-vert.y);
|
||||
out_verts[out_cnt++]=(vert-prev_vert)*t+prev_vert;
|
||||
}
|
||||
}else{
|
||||
if( prev_vert.y>0 ){
|
||||
float t=prev_vert.y/(prev_vert.y-vert.y);
|
||||
out_verts[out_cnt++]=(vert-prev_vert)*t+prev_vert;
|
||||
}
|
||||
out_verts[out_cnt++]=plane.intersect( Line( eye,vert-eye ) );
|
||||
}
|
||||
}
|
||||
if( out_cnt<3 || out_cnt>5 ) continue;
|
||||
|
||||
for( k=0;k<out_cnt;++k ){
|
||||
const Vector &v=out_verts[k];
|
||||
float tex_coords[2][2]={ {v.x,v.z},{v.x,v.z} };
|
||||
mesh->setVertex( v_cnt+k,&v.x,&plane.n.x,tex_coords );
|
||||
}
|
||||
for( k=2;k<out_cnt;++k ){
|
||||
mesh->setTriangle( t_cnt++,v_cnt,v_cnt+k-1,v_cnt+k );
|
||||
}
|
||||
v_cnt+=out_cnt;
|
||||
}
|
||||
}
|
||||
mesh->unlock();
|
||||
if( v_cnt<3 ) return;
|
||||
model->enqueue( mesh,0,v_cnt,0,t_cnt );
|
||||
}
|
||||
};
|
||||
|
||||
PlaneModel::PlaneModel( int sub_divs ):
|
||||
rep( new Rep(sub_divs) ){
|
||||
}
|
||||
|
||||
PlaneModel::PlaneModel( const PlaneModel &t ):
|
||||
Model( t ),rep( t.rep ){
|
||||
++rep->ref_cnt;
|
||||
}
|
||||
|
||||
PlaneModel::~PlaneModel(){
|
||||
if( !--rep->ref_cnt ) delete rep;
|
||||
}
|
||||
|
||||
Plane PlaneModel::getRenderPlane()const{
|
||||
return Plane( getRenderTform().v,getRenderTform().m.j.normalized() );
|
||||
}
|
||||
|
||||
bool PlaneModel::render( const RenderContext &rc ){
|
||||
rep->render( this,rc );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlaneModel::collide( const Line &l,float radius,Collision *curr_coll,const Transform &tf ){
|
||||
|
||||
Line line( -tf * l );
|
||||
|
||||
Plane p( Vector( 0,1,0 ),0 );
|
||||
p.d-=radius;
|
||||
float t=p.t_intersect( line );
|
||||
if( t>=curr_coll->time ) return false;
|
||||
|
||||
Vector n=(tf.m.cofactor() * p.n).normalized();
|
||||
|
||||
return curr_coll->update( l,t,n );
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
#ifndef PLANEMODEL_H
|
||||
#define PLANEMODEL_H
|
||||
|
||||
#include "model.hpp"
|
||||
#include "brush.hpp"
|
||||
|
||||
class PlaneModel : public Model{
|
||||
public:
|
||||
PlaneModel( int sub_divs );
|
||||
PlaneModel( const PlaneModel &t );
|
||||
~PlaneModel();
|
||||
Entity *clone(){ return new PlaneModel( *this ); }
|
||||
|
||||
//model interface
|
||||
bool render( const RenderContext &rc );
|
||||
|
||||
//object interface
|
||||
bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &tf );
|
||||
|
||||
Plane getRenderPlane()const;
|
||||
|
||||
private:
|
||||
struct Rep;
|
||||
|
||||
Rep *rep;
|
||||
|
||||
virtual PlaneModel *getPlaneModel(){ return this; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "q3bspmodel.hpp"
|
||||
#include "q3bsprep.hpp"
|
||||
|
||||
struct Q3BSPModel::Rep : public Q3BSPRep{
|
||||
int ref_cnt;
|
||||
|
||||
Rep( const string &f,float gam ):Q3BSPRep( f,gam ),
|
||||
ref_cnt(1){
|
||||
}
|
||||
};
|
||||
|
||||
Q3BSPModel::Q3BSPModel( const string &f,float gam ):
|
||||
rep( new Rep( f,gam ) ){
|
||||
}
|
||||
|
||||
Q3BSPModel::Q3BSPModel( const Q3BSPModel &t ):Model(t),
|
||||
rep( t.rep ){
|
||||
++rep->ref_cnt;
|
||||
}
|
||||
|
||||
Q3BSPModel::~Q3BSPModel(){
|
||||
if( !--rep->ref_cnt ) delete rep;
|
||||
}
|
||||
|
||||
bool Q3BSPModel::collide( const Line &line,float radius,Collision *curr_coll,const Transform &t ){
|
||||
return rep->collide( line,radius,curr_coll,t );
|
||||
}
|
||||
|
||||
bool Q3BSPModel::render( const RenderContext &rc ){
|
||||
rep->render( this,rc );
|
||||
return false;
|
||||
}
|
||||
|
||||
void Q3BSPModel::setAmbient( const Vector &t ){
|
||||
rep->setAmbient( t );
|
||||
}
|
||||
|
||||
void Q3BSPModel::setLighting( bool l ){
|
||||
rep->setLighting( l );
|
||||
}
|
||||
|
||||
bool Q3BSPModel::isValid()const{
|
||||
return rep->isValid();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
#ifndef Q3BSPMODEL_H
|
||||
#define Q3BSPMODEL_H
|
||||
|
||||
#include "model.hpp"
|
||||
|
||||
class Q3BSPModel : public Model{
|
||||
public:
|
||||
Q3BSPModel( const string &f,float gamma_adj );
|
||||
Q3BSPModel( const Q3BSPModel &m );
|
||||
~Q3BSPModel();
|
||||
|
||||
//Entity interface
|
||||
Entity *clone(){ return new Q3BSPModel( *this ); }
|
||||
|
||||
//Object interface
|
||||
virtual bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &t );
|
||||
|
||||
//Model interface
|
||||
Q3BSPModel *getBSPModel(){ return this; }
|
||||
|
||||
bool render( const RenderContext &rc );
|
||||
|
||||
void setAmbient( const Vector &t );
|
||||
void setLighting( bool use_lmap );
|
||||
|
||||
bool isValid()const;
|
||||
|
||||
private:
|
||||
struct Rep;
|
||||
Rep *rep;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,762 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "q3bsprep.hpp"
|
||||
|
||||
/* Quake3 File format types */
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
struct q3_plane {
|
||||
Vector normal;
|
||||
float distance;
|
||||
};
|
||||
|
||||
struct q3_tex {
|
||||
char name[64];
|
||||
int flags, contents;
|
||||
};
|
||||
|
||||
struct q3_vertex {
|
||||
Vector coords;
|
||||
float tex_coords[4];
|
||||
Vector normal;
|
||||
unsigned char color[4];
|
||||
};
|
||||
|
||||
struct q3_node {
|
||||
int plane;
|
||||
int children[2];
|
||||
int mins[3];
|
||||
int maxs[3];
|
||||
};
|
||||
|
||||
struct q3_face {
|
||||
int texture;
|
||||
int effect;
|
||||
int type;
|
||||
int vertex;
|
||||
int n_verts;
|
||||
int meshvert;
|
||||
int n_meshverts;
|
||||
int lm_index;
|
||||
int lm_start[2];
|
||||
int lm_size[2];
|
||||
float lm_origin[3];
|
||||
float lm_vecs[2][3];
|
||||
float normal[3];
|
||||
int patch_size[2];
|
||||
};
|
||||
|
||||
struct q3_leaf {
|
||||
int cluster;
|
||||
int area;
|
||||
int mins[3];
|
||||
int maxs[3];
|
||||
int leafface;
|
||||
int n_leaffaces;
|
||||
int leafbrush;
|
||||
int n_leafbrushes;
|
||||
};
|
||||
|
||||
struct q3_brush {
|
||||
int brushside;
|
||||
int n_brushsides;
|
||||
int texture;
|
||||
};
|
||||
|
||||
struct q3_brushside {
|
||||
int plane;
|
||||
int texture;
|
||||
};
|
||||
|
||||
struct q3_direntry {
|
||||
union {
|
||||
int offset;
|
||||
void *lump;
|
||||
};
|
||||
int length;
|
||||
};
|
||||
|
||||
struct q3_header {
|
||||
unsigned magic;
|
||||
int version;
|
||||
q3_direntry dir[17];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* Loading reps */
|
||||
struct Surf {
|
||||
Q3BSPSurf *surf;
|
||||
int texture, lm_index;
|
||||
vector<int> verts, tris;
|
||||
};
|
||||
|
||||
struct FaceCmp {
|
||||
bool operator()(const q3_face *a, const q3_face *b)const {
|
||||
if (a->texture < b->texture) return true;
|
||||
if (b->texture < a->texture) return false;
|
||||
if (a->lm_index < b->lm_index) return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef map<q3_face*, Surf*, FaceCmp> FaceMap;
|
||||
|
||||
/* render reps */
|
||||
|
||||
struct Q3BSPFace;
|
||||
|
||||
struct Q3BSPSurf {
|
||||
Brush brush;
|
||||
gxMesh *mesh;
|
||||
vector<Q3BSPFace*> r_faces;
|
||||
int texture, lm_index;
|
||||
};
|
||||
|
||||
struct Q3BSPFace {
|
||||
union {
|
||||
Surf *t_surf;
|
||||
Q3BSPSurf *surf;
|
||||
};
|
||||
int vert, n_verts, tri, n_tris;
|
||||
};
|
||||
|
||||
struct Q3BSPBrush {
|
||||
vector<Plane> planes;
|
||||
};
|
||||
|
||||
struct Q3BSPLeaf {
|
||||
int cluster;
|
||||
Box box;
|
||||
vector<Q3BSPFace*> faces;
|
||||
};
|
||||
|
||||
struct Q3BSPNode {
|
||||
Box box;
|
||||
Plane plane;
|
||||
Q3BSPNode *nodes[2];
|
||||
Q3BSPLeaf *leafs[2];
|
||||
|
||||
~Q3BSPNode() { delete nodes[0]; delete nodes[1]; delete leafs[0]; delete leafs[1]; }
|
||||
};
|
||||
|
||||
static q3_header header;
|
||||
static FaceMap face_map;
|
||||
static vector<Surf*> t_surfs;
|
||||
static vector<q3_vertex> p_verts; //patch vertices
|
||||
static vector<Vector> p_coll_verts;
|
||||
static vector<MeshCollider::Triangle> coll_tris;
|
||||
|
||||
static float gamma_adj;
|
||||
|
||||
static Vector r_eye;
|
||||
static int r_cluster;
|
||||
static Frustum r_frustum;
|
||||
static Vector r_frustedges[12];
|
||||
static map<int, Q3BSPFace*> q3face_map;
|
||||
|
||||
extern gxScene *gx_scene;
|
||||
extern gxRuntime *gx_runtime;
|
||||
extern gxGraphics *gx_graphics;
|
||||
|
||||
//#define SWAPTRIS
|
||||
Vector static tf(const Vector &v) {
|
||||
return Vector(-v.y, v.z, v.x);
|
||||
}
|
||||
|
||||
#ifdef BETA
|
||||
static void debuglog(const string &t) {
|
||||
gx_runtime->debugLog(t.c_str());
|
||||
}
|
||||
#else
|
||||
static void debuglog(const string &t) {}
|
||||
#endif
|
||||
|
||||
static Surf *findSurf(q3_face *f) {
|
||||
FaceMap::const_iterator it = face_map.find(f);
|
||||
if (it != face_map.end()) return it->second;
|
||||
Surf *s = new Surf;
|
||||
s->texture = f->texture;
|
||||
s->lm_index = f->lm_index;
|
||||
face_map.insert(make_pair(f, s));
|
||||
t_surfs.push_back(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
void Q3BSPRep::createTextures() {
|
||||
int n_texs = header.dir[1].length / sizeof(q3_tex);
|
||||
q3_tex *q3tex = (q3_tex*)header.dir[1].lump;
|
||||
for (int k = 0; k < n_texs; ++k) {
|
||||
string t = string(q3tex->name);
|
||||
char fl[32], co[32];
|
||||
_itoa(q3tex->flags, fl, 16);
|
||||
_itoa(q3tex->contents, co, 16);
|
||||
debuglog(t + ", flags=0x" + fl + ", contents=0x" + co);
|
||||
Texture tex(t + ".tga", 1);
|
||||
if (!tex.getCanvas(0)) {
|
||||
tex = Texture(t + ".jpg", 1);
|
||||
if (!tex.getCanvas(0)) {
|
||||
tex = Texture(t + ".png", 1);
|
||||
if (!tex.getCanvas(0)) {
|
||||
tex = Texture(t + ".dds", 1);
|
||||
if (!tex.getCanvas(0)) debuglog("Failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
tex.setFlags(1);
|
||||
textures.push_back(tex);
|
||||
++q3tex;
|
||||
}
|
||||
}
|
||||
|
||||
void Q3BSPRep::createLightMaps() {
|
||||
int n_lmaps = header.dir[14].length / (128 * 128 * 3);
|
||||
unsigned char *rgb = (unsigned char*)header.dir[14].lump;
|
||||
unsigned char adj[256];
|
||||
int k;
|
||||
for (k = 0; k < 256; ++k) adj[k] = pow(k / 255.0f, gamma_adj)*255.0f;
|
||||
|
||||
for (k = 0; k < n_lmaps; ++k) {
|
||||
Texture tex(128, 128, 1 + 8 + 16 + 32, 1);
|
||||
tex.setBlend(gxScene::BLEND_ADD);
|
||||
gxCanvas *c = tex.getCanvas(0);
|
||||
c->lock();
|
||||
for (int y = 0; y < 128; ++y) {
|
||||
for (int x = 0; x < 128; ++x) {
|
||||
unsigned argb = 0xff000000 | (adj[rgb[0]] << 16) | (adj[rgb[1]] << 8) | adj[rgb[2]];
|
||||
c->setPixelFast(x, y, argb);
|
||||
rgb += 3;
|
||||
}
|
||||
}
|
||||
c->unlock();
|
||||
light_maps.push_back(tex);
|
||||
}
|
||||
}
|
||||
|
||||
void Q3BSPRep::createVis() {
|
||||
int *vis = (int*)header.dir[16].lump;
|
||||
int n_vecs = *vis++;
|
||||
vis_sz = *vis++;
|
||||
debuglog("vis: " + itoa(n_vecs) + "," + itoa(vis_sz));
|
||||
vis_data = new char[n_vecs*vis_sz];
|
||||
memcpy(vis_data, vis, n_vecs*vis_sz);
|
||||
}
|
||||
|
||||
void Q3BSPRep::createCollider() {
|
||||
vector<MeshCollider::Vertex> coll_verts;
|
||||
int n_verts = header.dir[10].length / sizeof(q3_vertex);
|
||||
q3_vertex *t = (q3_vertex*)header.dir[10].lump;
|
||||
MeshCollider::Vertex cv;
|
||||
int k;
|
||||
for (k = 0; k < n_verts; ++k) {
|
||||
cv.coords = tf(t->coords);
|
||||
coll_verts.push_back(cv);
|
||||
++t;
|
||||
}
|
||||
for (k = 0; k < p_coll_verts.size(); ++k) {
|
||||
cv.coords = p_coll_verts[k];
|
||||
coll_verts.push_back(cv);
|
||||
}
|
||||
#ifdef SWAPTRIS
|
||||
for (k = 0; k < coll_tris.size(); ++k) {
|
||||
std::swap(coll_tris[k].verts[1], coll_tris[k].verts[2]);
|
||||
}
|
||||
#endif
|
||||
collider = new MeshCollider(coll_verts, coll_tris);
|
||||
p_coll_verts.clear();
|
||||
coll_verts.clear();
|
||||
coll_tris.clear();
|
||||
}
|
||||
|
||||
void Q3BSPRep::createSurfs() {
|
||||
int k;
|
||||
for (k = 0; k < t_surfs.size(); ++k) {
|
||||
Surf *s = t_surfs[k];
|
||||
gxMesh *mesh = gx_graphics->createMesh(s->verts.size(), s->tris.size() / 3, 0);
|
||||
|
||||
mesh->lock(true);
|
||||
int j;
|
||||
for (j = 0; j < s->verts.size(); ++j) {
|
||||
q3_vertex *t;
|
||||
int n = s->verts[j];
|
||||
if (n >= 0) {
|
||||
t = (q3_vertex*)header.dir[10].lump + n;
|
||||
} else {
|
||||
t = &p_verts[-n - 1];
|
||||
}
|
||||
float tex_coords[2][2] = { {t->tex_coords[2],t->tex_coords[3]},{t->tex_coords[0],t->tex_coords[1]} };
|
||||
unsigned argb = 0xff000000 | (t->color[0] << 16) | (t->color[1] << 8) | t->color[2];
|
||||
mesh->setVertex(j, tf(t->coords), tf(t->normal), argb, tex_coords);
|
||||
}
|
||||
for (j = 0; j < s->tris.size(); j += 3) {
|
||||
#ifdef SWAPTRIS
|
||||
mesh->setTriangle(j / 3, s->tris[j], s->tris[j + 2], s->tris[j + 1]);
|
||||
#else
|
||||
mesh->setTriangle(j / 3, s->tris[j], s->tris[j + 1], s->tris[j + 2]);
|
||||
#endif
|
||||
}
|
||||
mesh->unlock();
|
||||
|
||||
Q3BSPSurf *surf = new Q3BSPSurf;
|
||||
surf->texture = s->texture;
|
||||
surf->lm_index = s->lm_index;
|
||||
surf->mesh = mesh;
|
||||
surfs.push_back(surf);
|
||||
s->surf = surf;
|
||||
}
|
||||
for (k = 0; k < faces.size(); ++k) {
|
||||
Q3BSPFace *f = faces[k];
|
||||
f->surf = f->t_surf->surf;
|
||||
f->tri /= 3; f->n_tris /= 3;
|
||||
}
|
||||
for (k = 0; k < t_surfs.size(); ++k) {
|
||||
delete t_surfs[k];
|
||||
}
|
||||
face_map.clear();
|
||||
t_surfs.clear();
|
||||
p_verts.clear();
|
||||
}
|
||||
|
||||
static void average(const q3_vertex &a, const q3_vertex &b, q3_vertex *c) {
|
||||
c->coords = (a.coords + b.coords)*.5f;
|
||||
c->normal = (a.normal + b.normal)*.5f;
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
c->color[k] = (a.color[k] + b.color[k] + 1) / 2;
|
||||
c->tex_coords[k] = (a.tex_coords[k] + b.tex_coords[k])*.5f;
|
||||
}
|
||||
}
|
||||
|
||||
static void subdivide(vector<q3_vertex> &verts, int level, int index, int step) {
|
||||
if (!level) {
|
||||
q3_vertex t1, t2;
|
||||
average(verts[index], verts[index + step], &t1);
|
||||
average(verts[index + step], verts[index + step * 2], &t2);
|
||||
average(t1, t2, &verts[index + step]);
|
||||
return;
|
||||
}
|
||||
average(verts[index], verts[index + step], &verts[index + step / 2]);
|
||||
average(verts[index + step], verts[index + step * 2], &verts[index + step + step / 2]);
|
||||
average(verts[index + step / 2], verts[index + step + step / 2], &verts[index + step]);
|
||||
subdivide(verts, level - 1, index, step / 2);
|
||||
subdivide(verts, level - 1, index + step, step / 2);
|
||||
}
|
||||
|
||||
static void patchFace(Q3BSPFace *face, q3_face *q3face, bool draw, bool solid, int level) {
|
||||
|
||||
int k, x, y;
|
||||
vector<q3_vertex> verts;
|
||||
|
||||
if (draw) {
|
||||
int step = 1 << level;
|
||||
int size_x = (q3face->patch_size[0] - 1)*step + 1;
|
||||
int size_y = (q3face->patch_size[1] - 1)*step + 1;
|
||||
verts.resize(size_x*size_y);
|
||||
|
||||
//seed initial verts
|
||||
q3_vertex *t = (q3_vertex*)header.dir[10].lump + q3face->vertex;
|
||||
for (y = 0; y < size_y; y += step) {
|
||||
for (x = 0; x < size_x; x += step) {
|
||||
verts[y*size_x + x] = *t++;
|
||||
}
|
||||
}
|
||||
//subdivide!
|
||||
for (y = 0; y < size_y; y += step) {
|
||||
for (x = 0; x < size_x - 1; x += step * 2) {
|
||||
subdivide(verts, level, y*size_x + x, step);
|
||||
}
|
||||
}
|
||||
for (x = 0; x < size_x; ++x) {
|
||||
for (y = 0; y < size_y - 1; y += step * 2) {
|
||||
subdivide(verts, level, y*size_x + x, size_x*step);
|
||||
}
|
||||
}
|
||||
|
||||
Surf *surf = face->t_surf;
|
||||
int vert = surf->verts.size() - face->vert;
|
||||
|
||||
//generate patch verts
|
||||
for (k = 0; k < size_x*size_y; ++k) {
|
||||
p_verts.push_back(verts[k]);
|
||||
surf->verts.push_back(p_verts.size()); // Why was there a - here
|
||||
}
|
||||
face->n_verts += size_x*size_y;
|
||||
|
||||
//generate tris...
|
||||
for (y = 0; y < size_y - 1; ++y) {
|
||||
int n = y*size_x + vert;
|
||||
for (x = 0; x < size_x - 1; ++n, ++x) {
|
||||
surf->tris.push_back(n);
|
||||
surf->tris.push_back(n + size_x);
|
||||
surf->tris.push_back(n + 1);
|
||||
surf->tris.push_back(n + size_x + 1);
|
||||
surf->tris.push_back(n + 1);
|
||||
surf->tris.push_back(n + size_x);
|
||||
}
|
||||
}
|
||||
face->n_tris += (size_x - 1)*(size_y - 1) * 6;
|
||||
}
|
||||
|
||||
if (solid) {
|
||||
vector<q3_vertex> verts;
|
||||
int step = 1;
|
||||
int size_x = q3face->patch_size[0];
|
||||
int size_y = q3face->patch_size[1];
|
||||
verts.resize(size_x*size_y);
|
||||
|
||||
//seed initial verts
|
||||
q3_vertex *t = (q3_vertex*)header.dir[10].lump + q3face->vertex;
|
||||
for (k = 0; k < size_x*size_y; ++k) verts[k] = *t++;
|
||||
//subdivide!
|
||||
for (y = 0; y < size_y; y += step) {
|
||||
for (x = 0; x < size_x - 1; x += step * 2) {
|
||||
subdivide(verts, 0, y*size_x + x, step);
|
||||
}
|
||||
}
|
||||
for (x = 0; x < size_x; ++x) {
|
||||
for (y = 0; y < size_y - 1; y += step * 2) {
|
||||
subdivide(verts, 0, y*size_x + x, size_x*step);
|
||||
}
|
||||
}
|
||||
|
||||
int vert = header.dir[10].length / sizeof(q3_vertex) + p_coll_verts.size();
|
||||
|
||||
//generate patch verts
|
||||
for (k = 0; k < size_x*size_y; ++k) p_coll_verts.push_back(tf(verts[k].coords));
|
||||
|
||||
MeshCollider::Triangle ct;
|
||||
ct.surface = 0; ct.index = 0;
|
||||
//generate tris...
|
||||
for (y = 0; y < size_y - 1; ++y) {
|
||||
int n = y*size_x + vert;
|
||||
for (x = 0; x < size_x - 1; ++n, ++x) {
|
||||
ct.verts[0] = n;
|
||||
ct.verts[1] = n + size_x;
|
||||
ct.verts[2] = n + 1;
|
||||
coll_tris.push_back(ct);
|
||||
ct.verts[0] = n + size_x + 1;
|
||||
ct.verts[1] = n + 1;
|
||||
ct.verts[2] = n + size_x;
|
||||
coll_tris.push_back(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void meshFace(Q3BSPFace *face, q3_face *q3face, bool draw, bool solid) {
|
||||
static map<int, int> vert_map;
|
||||
vert_map.clear();
|
||||
int *meshverts = (int*)header.dir[11].lump + q3face->meshvert;
|
||||
MeshCollider::Triangle ct;
|
||||
ct.surface = 0; ct.index = 0;
|
||||
for (int j = 0; j < q3face->n_meshverts; j += 3) {
|
||||
for (int q = 0; q < 3; ++q) {
|
||||
int n = meshverts[j + q] + q3face->vertex;
|
||||
if (draw) {
|
||||
if (!vert_map.count(n)) {
|
||||
vert_map[n] = face->t_surf->verts.size() - face->vert;
|
||||
face->t_surf->verts.push_back(n);
|
||||
++face->n_verts;
|
||||
}
|
||||
face->t_surf->tris.push_back(vert_map[n]);
|
||||
++face->n_tris;
|
||||
}
|
||||
ct.verts[q] = n;
|
||||
}
|
||||
if (solid) coll_tris.push_back(ct);
|
||||
}
|
||||
}
|
||||
|
||||
static Q3BSPBrush *createBrush(int n) {
|
||||
Q3BSPBrush *brush = new Q3BSPBrush;
|
||||
q3_brush *q3brush = (q3_brush*)header.dir[8].lump + n;
|
||||
q3_brushside *q3brushside = (q3_brushside*)header.dir[9].lump + q3brush->brushside;
|
||||
Plane p;
|
||||
for (int j = 0; j < q3brush->n_brushsides; ++j) {
|
||||
q3_plane *q3plane = (q3_plane*)header.dir[2].lump + q3brushside[j].plane;
|
||||
p.n = tf(q3plane->normal);
|
||||
p.d = -q3plane->distance;
|
||||
brush->planes.push_back(p);
|
||||
}
|
||||
return brush;
|
||||
}
|
||||
|
||||
Q3BSPLeaf *Q3BSPRep::createLeaf(int n) {
|
||||
q3_leaf *q3leaf = (q3_leaf*)header.dir[4].lump + n;
|
||||
|
||||
Q3BSPLeaf *leaf = new Q3BSPLeaf;
|
||||
|
||||
leaf->cluster = q3leaf->cluster;
|
||||
|
||||
Vector mins(q3leaf->mins[0], q3leaf->mins[1], q3leaf->mins[2]);
|
||||
Vector maxs(q3leaf->maxs[0], q3leaf->maxs[1], q3leaf->maxs[2]);
|
||||
leaf->box = Box(tf(mins));
|
||||
leaf->box.update(tf(maxs));
|
||||
int *leaffaces = (int*)header.dir[5].lump + q3leaf->leafface;
|
||||
|
||||
for (int k = 0; k < q3leaf->n_leaffaces; ++k) {
|
||||
|
||||
int face_n = leaffaces[k];
|
||||
|
||||
map<int, Q3BSPFace*>::const_iterator it = q3face_map.find(face_n);
|
||||
if (it != q3face_map.end()) {
|
||||
if (it->second) leaf->faces.push_back(it->second);
|
||||
continue;
|
||||
}
|
||||
|
||||
q3_face *q3face = (q3_face*)header.dir[13].lump + leaffaces[k];
|
||||
|
||||
if (q3face->type == 1 || q3face->type == 3) {
|
||||
if (!q3face->n_meshverts || (q3face->n_meshverts % 3)) continue;
|
||||
} else if (q3face->type != 2) continue;
|
||||
|
||||
bool draw = true, solid = true;
|
||||
|
||||
if (q3face->texture >= 0) {
|
||||
q3_tex *q3tex = (q3_tex*)header.dir[1].lump + q3face->texture;
|
||||
if (!(q3tex->contents & 1)) continue;
|
||||
if (q3tex->flags & 0x84) draw = false;
|
||||
}
|
||||
|
||||
if (!draw && !solid) continue;
|
||||
|
||||
Q3BSPFace *face = 0;
|
||||
if (draw) {
|
||||
Surf *surf = findSurf(q3face);
|
||||
face = new Q3BSPFace;
|
||||
face->t_surf = surf;
|
||||
face->vert = surf->verts.size();
|
||||
face->tri = surf->tris.size();
|
||||
face->n_verts = face->n_tris = 0;
|
||||
leaf->faces.push_back(face);
|
||||
faces.push_back(face);
|
||||
q3face_map.insert(make_pair(face_n, face));
|
||||
}
|
||||
|
||||
if (q3face->type == 2) {
|
||||
patchFace(face, q3face, draw, solid, 1);
|
||||
} else {
|
||||
meshFace(face, q3face, draw, solid);
|
||||
}
|
||||
}
|
||||
|
||||
return leaf;
|
||||
}
|
||||
|
||||
Q3BSPNode *Q3BSPRep::createNode(int n) {
|
||||
q3_node *q3node = (q3_node*)header.dir[3].lump + n;
|
||||
q3_plane *q3plane = (q3_plane*)header.dir[2].lump + q3node->plane;
|
||||
|
||||
Q3BSPNode *node = new Q3BSPNode;
|
||||
|
||||
Vector mins(q3node->mins[0], q3node->mins[1], q3node->mins[2]);
|
||||
Vector maxs(q3node->maxs[0], q3node->maxs[1], q3node->maxs[2]);
|
||||
|
||||
node->box = Box(tf(mins));
|
||||
node->box.update(tf(maxs));
|
||||
node->plane.n = tf(q3plane->normal);
|
||||
node->plane.d = -q3plane->distance;
|
||||
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
if (q3node->children[k] >= 0) {
|
||||
node->nodes[k] = createNode(q3node->children[k]);
|
||||
node->leafs[k] = 0;
|
||||
} else {
|
||||
node->leafs[k] = createLeaf(-q3node->children[k] - 1);
|
||||
node->nodes[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
Q3BSPRep::Q3BSPRep(const string &f, float gam) :root_node(0), vis_sz(0), vis_data(0), use_lmap(true) {
|
||||
|
||||
gamma_adj = 1 - gam;
|
||||
|
||||
FILE *buf = fopen(f.c_str(), "rb"); if (!buf) return;
|
||||
|
||||
fread(&header, sizeof(header), 1, buf);
|
||||
if (header.magic != 'PSBI' || header.version != 0x2e) {
|
||||
fclose(buf); return;
|
||||
}
|
||||
|
||||
debuglog("Header OK");
|
||||
|
||||
int k;
|
||||
//load all lumps...
|
||||
for (k = 0; k < 17; ++k) {
|
||||
if (header.dir[k].offset && header.dir[k].length) {
|
||||
fseek(buf, header.dir[k].offset, SEEK_SET);
|
||||
header.dir[k].lump = new char[header.dir[k].length];
|
||||
fread(header.dir[k].lump, header.dir[k].length, 1, buf);
|
||||
} else {
|
||||
header.dir[k].lump = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//create root of BSP tree
|
||||
root_node = createNode(0);
|
||||
|
||||
createCollider();
|
||||
|
||||
createTextures();
|
||||
|
||||
createLightMaps();
|
||||
|
||||
createSurfs();
|
||||
|
||||
createVis();
|
||||
|
||||
//unload all lumps...
|
||||
for (k = 0; k < 17; ++k) {
|
||||
delete[] header.dir[k].lump;
|
||||
}
|
||||
|
||||
fclose(buf);
|
||||
|
||||
use_lmap = false;
|
||||
setLighting(true);
|
||||
|
||||
q3face_map.clear();
|
||||
}
|
||||
|
||||
Q3BSPRep::~Q3BSPRep() {
|
||||
delete root_node;
|
||||
delete[] vis_data;
|
||||
int k;
|
||||
for (k = 0; k < surfs.size(); ++k) {
|
||||
gx_graphics->freeMesh(surfs[k]->mesh);
|
||||
delete surfs[k];
|
||||
}
|
||||
for (k = 0; k < faces.size(); ++k) {
|
||||
delete faces[k];
|
||||
}
|
||||
}
|
||||
|
||||
void Q3BSPRep::vis(Q3BSPNode *n) {
|
||||
int i = n->plane.distance(r_eye) < 0;
|
||||
if (n->nodes[i]) vis(n->nodes[i]);
|
||||
else r_cluster = n->leafs[i]->cluster;
|
||||
}
|
||||
|
||||
static bool cull(const Box &b, int *clip) {
|
||||
for (int n = 0; n < 6; ++n) {
|
||||
int mask = 1 << n;
|
||||
if (!(*clip & mask)) continue;
|
||||
const Plane &p = r_frustum.getPlane(n);
|
||||
int q =
|
||||
(p.distance(b.corner(0)) >= 0) + (p.distance(b.corner(1)) >= 0) +
|
||||
(p.distance(b.corner(2)) >= 0) + (p.distance(b.corner(3)) >= 0) +
|
||||
(p.distance(b.corner(4)) >= 0) + (p.distance(b.corner(5)) >= 0) +
|
||||
(p.distance(b.corner(6)) >= 0) + (p.distance(b.corner(7)) >= 0);
|
||||
if (!q) return false;
|
||||
if (q == 8) *clip &= ~mask;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Q3BSPRep::render(Q3BSPLeaf *l, int clip) {
|
||||
int cluster = l->cluster;
|
||||
if (cluster < 0) return;
|
||||
|
||||
if (r_cluster >= 0) {
|
||||
if (!(vis_data[cluster*vis_sz + r_cluster / 8] & (1 << (r_cluster & 7)))) return;
|
||||
}
|
||||
|
||||
if (clip && !cull(l->box, &clip)) return;
|
||||
|
||||
for (int k = 0; k < l->faces.size(); ++k) {
|
||||
Q3BSPFace *f = l->faces[k];
|
||||
if (Q3BSPSurf *s = f->surf) {
|
||||
if (!s->r_faces.size()) r_surfs.push_back(s);
|
||||
s->r_faces.push_back(f);
|
||||
f->surf = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Q3BSPRep::render(Q3BSPNode *n, int clip) {
|
||||
if (clip && !cull(n->box, &clip)) return;
|
||||
|
||||
//draw front to back...
|
||||
int i = n->plane.distance(r_eye) < 0;
|
||||
if (n->nodes[i]) render(n->nodes[i], clip);
|
||||
else render(n->leafs[i], clip);
|
||||
i ^= 1;
|
||||
if (n->nodes[i]) render(n->nodes[i], clip);
|
||||
else render(n->leafs[i], clip);
|
||||
}
|
||||
|
||||
void Q3BSPRep::render(Model *model, const RenderContext &rc) {
|
||||
r_eye = -model->getRenderTform() * rc.getCameraTform().v;
|
||||
new(&r_frustum) Frustum(rc.getWorldFrustum(), -model->getRenderTform());
|
||||
|
||||
vis(root_node);
|
||||
if (r_cluster == -1) debuglog("No cluster!");
|
||||
render(root_node, 0x3f);
|
||||
|
||||
if (!r_surfs.size()) return;
|
||||
|
||||
gx_scene->setAmbient2(&ambient.x);
|
||||
gx_scene->setWorldMatrix((gxScene::Matrix*)&model->getRenderTform());
|
||||
|
||||
int k;
|
||||
for (k = 0; k < r_surfs.size(); ++k) {
|
||||
Q3BSPSurf *s = r_surfs[k];
|
||||
gx_scene->setRenderState(s->brush.getRenderState());
|
||||
int j;
|
||||
for (j = 0; j < s->r_faces.size(); ++j) {
|
||||
Q3BSPFace *f = s->r_faces[j];
|
||||
gx_scene->render(s->mesh, f->vert, f->n_verts, f->tri, f->n_tris);
|
||||
f->surf = s;
|
||||
}
|
||||
s->r_faces.clear();
|
||||
}
|
||||
r_surfs.clear();
|
||||
}
|
||||
|
||||
bool Q3BSPRep::collide(const Line &line, float radius, Collision *curr_coll, const Transform &t) {
|
||||
return collider->collide(line, radius, curr_coll, t);
|
||||
}
|
||||
|
||||
void Q3BSPRep::setAmbient(const Vector &t) {
|
||||
ambient = t;
|
||||
}
|
||||
|
||||
void Q3BSPRep::setLighting(bool lmap) {
|
||||
if (lmap == use_lmap) return;
|
||||
int fx = gxScene::FX_CONDLIGHT;
|
||||
if (use_lmap = lmap) {
|
||||
int k;
|
||||
for (k = 0; k < surfs.size(); ++k) {
|
||||
Q3BSPSurf *s = surfs[k];
|
||||
if (s->lm_index >= 0) {
|
||||
//has a lightmap...
|
||||
s->brush.setFX(fx);
|
||||
s->brush.setTexture(0, light_maps[s->lm_index], 0);
|
||||
if (s->texture >= 0) {
|
||||
s->brush.setTexture(1, textures[s->texture], 0);
|
||||
}
|
||||
} else {
|
||||
s->brush.setFX(fx | gxScene::FX_EMISSIVE);
|
||||
if (s->texture >= 0) {
|
||||
s->brush.setTexture(0, textures[s->texture], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int k;
|
||||
Texture tex;
|
||||
for (k = 0; k < surfs.size(); ++k) {
|
||||
Q3BSPSurf *s = surfs[k];
|
||||
s->brush.setFX(fx | gxScene::FX_EMISSIVE);
|
||||
if (s->texture >= 0) {
|
||||
s->brush.setTexture(0, textures[s->texture], 0);
|
||||
} else {
|
||||
s->brush.setTexture(0, tex, 0);
|
||||
}
|
||||
s->brush.setTexture(1, tex, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
#ifndef Q3BSPREP_H
|
||||
#define Q3BSPREP_H
|
||||
|
||||
#include "model.hpp"
|
||||
#include "meshcollider.hpp"
|
||||
|
||||
struct Q3BSPSurf;
|
||||
struct Q3BSPFace;
|
||||
struct Q3BSPLeaf;
|
||||
struct Q3BSPNode;
|
||||
|
||||
class Q3BSPRep{
|
||||
public:
|
||||
//constructor
|
||||
Q3BSPRep( const string &f,float gamma_adj );
|
||||
~Q3BSPRep();
|
||||
|
||||
void render( Model *model,const RenderContext &rc );
|
||||
bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &t );
|
||||
|
||||
void setAmbient( const Vector &t );
|
||||
void setLighting( bool use_lmap );
|
||||
|
||||
bool isValid()const{ return root_node!=0; }
|
||||
|
||||
private:
|
||||
Q3BSPNode *root_node;
|
||||
|
||||
Vector ambient;
|
||||
|
||||
vector<Q3BSPFace*> faces;
|
||||
vector<Q3BSPSurf*> surfs,r_surfs;
|
||||
vector<Texture> textures,light_maps;
|
||||
|
||||
int vis_sz;
|
||||
char *vis_data;
|
||||
bool use_lmap;
|
||||
|
||||
MeshCollider *collider;
|
||||
|
||||
void createVis();
|
||||
void createSurfs();
|
||||
void createCollider();
|
||||
|
||||
void createTextures();
|
||||
void createLightMaps();
|
||||
Q3BSPLeaf *createLeaf( int n );
|
||||
Q3BSPNode *createNode( int n );
|
||||
|
||||
void vis( Q3BSPNode *node );
|
||||
void render( Q3BSPLeaf *l,int clip );
|
||||
void render( Q3BSPNode *n,int clip );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
#ifndef RENDERCONTEXT_H
|
||||
#define RENDERCONTEXT_H
|
||||
|
||||
#include "frustum.hpp"
|
||||
|
||||
class RenderContext{
|
||||
public:
|
||||
RenderContext( const Transform &t,const Frustum &f,bool r ):
|
||||
camera_tform( t ),camera_frustum(f),ref(r){
|
||||
new( &world_frustum ) Frustum( f,t );
|
||||
}
|
||||
|
||||
bool isReflected()const{ return ref; }
|
||||
const Transform &getCameraTform()const{ return camera_tform; }
|
||||
const Frustum &getWorldFrustum()const{ return world_frustum; }
|
||||
const Frustum &getCameraFrustum()const{ return camera_frustum; }
|
||||
|
||||
private:
|
||||
Transform camera_tform;
|
||||
Frustum world_frustum,camera_frustum;
|
||||
bool ref;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "skinmodel.hpp"
|
||||
|
||||
SkinModel::SkinModel(){
|
||||
setRenderSpace( RENDER_SPACE_WORLD );
|
||||
}
|
||||
|
||||
void SkinModel::setBones( const vector<Object*> &bones ){
|
||||
_bones=bones;
|
||||
_surf_bones.resize( _bones.size() );
|
||||
}
|
||||
|
||||
void SkinModel::render( const RenderContext &rc ){
|
||||
|
||||
int k;
|
||||
for( k=0;k<_bones.size();++k ){
|
||||
Object *obj=_bones[k];
|
||||
_surf_bones[k].coord_tform=obj->getRenderTform();
|
||||
_surf_bones[k].normal_tform=_surf_bones[k].coord_tform.m.cofactor();
|
||||
}
|
||||
|
||||
const MeshModel::SurfaceList &_surfs=getSurfaces();
|
||||
|
||||
for( k=0;k<_surfs.size();++k ){
|
||||
Surface *surf=_surfs[k];
|
||||
if( gxMesh *mesh=surf->getMesh( _surf_bones ) ){
|
||||
enqueue( mesh,0,surf->numVertices(),0,surf->numTriangles(),surf->getBrush() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
#ifndef SKINMODEL_H
|
||||
#define SKINMODEL_H
|
||||
|
||||
#include "meshmodel.hpp"
|
||||
|
||||
class SkinModel : public MeshModel{
|
||||
vector<Object*> _bones;
|
||||
vector<Surface::Bone> _surf_bones;
|
||||
public:
|
||||
SkinModel();
|
||||
|
||||
void setBones( const vector<Object*> &bones );
|
||||
|
||||
//Model interface
|
||||
virtual void render( const RenderContext &rc );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,139 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "sprite.hpp"
|
||||
|
||||
extern float stats3d[];
|
||||
|
||||
static float null[]={0,0,0};
|
||||
|
||||
static float tex_coords0[2][2]={ {0,0},{0,0} };
|
||||
static float tex_coords1[2][2]={ {1,0},{1,0} };
|
||||
static float tex_coords2[2][2]={ {1,1},{1,1} };
|
||||
static float tex_coords3[2][2]={ {0,1},{0,1} };
|
||||
|
||||
extern gxRuntime *gx_runtime;
|
||||
extern gxGraphics *gx_graphics;
|
||||
|
||||
static gxMesh *mesh;
|
||||
static int mesh_size;
|
||||
static vector<int> mesh_indices;
|
||||
|
||||
static int allocIndex(){
|
||||
if( !mesh_indices.size() ){
|
||||
if( mesh_size ) gx_graphics->freeMesh( mesh );
|
||||
for( int k=0;k<256;++k ){
|
||||
mesh_indices.push_back( mesh_size++ );
|
||||
}
|
||||
mesh=gx_graphics->createMesh( mesh_size*4,mesh_size*2,0 );
|
||||
}
|
||||
int n=mesh_indices.back();
|
||||
mesh_indices.pop_back();
|
||||
return n;
|
||||
}
|
||||
|
||||
static void freeIndex( int n ){
|
||||
mesh_indices.push_back( n );
|
||||
if( mesh_indices.size()!=mesh_size ) return;
|
||||
gx_graphics->freeMesh( mesh );
|
||||
mesh_indices.clear();
|
||||
mesh_size=0;
|
||||
}
|
||||
|
||||
Sprite::Sprite():
|
||||
view_mode(VIEW_MODE_FREE),
|
||||
xhandle(0),yhandle(0),
|
||||
rot(0),xscale(1),yscale(1),captured(false){
|
||||
setRenderSpace( RENDER_SPACE_WORLD );
|
||||
mesh_index=allocIndex();
|
||||
}
|
||||
|
||||
Sprite::Sprite( const Sprite &t ):
|
||||
Model(t),
|
||||
view_mode(t.view_mode),
|
||||
xhandle(t.xhandle),yhandle(t.yhandle),
|
||||
rot(t.rot),xscale(t.xscale),yscale(t.yscale),captured(false){
|
||||
mesh_index=allocIndex();
|
||||
}
|
||||
|
||||
Sprite::~Sprite(){
|
||||
freeIndex( mesh_index );
|
||||
}
|
||||
|
||||
void Sprite::setRotation( float angle ){
|
||||
rot=angle;
|
||||
}
|
||||
|
||||
void Sprite::setScale( float x,float y ){
|
||||
xscale=x;yscale=y;
|
||||
}
|
||||
|
||||
void Sprite::setHandle( float x,float y ){
|
||||
xhandle=x;yhandle=y;
|
||||
}
|
||||
|
||||
void Sprite::setViewmode( int mode ){
|
||||
view_mode=mode;
|
||||
}
|
||||
|
||||
void Sprite::capture(){
|
||||
Model::capture();
|
||||
r_rot=rot;
|
||||
r_xscale=xscale;
|
||||
r_yscale=yscale;
|
||||
captured=true;
|
||||
}
|
||||
|
||||
bool Sprite::beginRender( float tween ){
|
||||
Model::beginRender( tween );
|
||||
if( tween==1 || !captured ){
|
||||
r_rot=rot;
|
||||
r_xscale=xscale;
|
||||
r_yscale=yscale;
|
||||
}else{
|
||||
r_rot=(rot-r_rot)*tween+r_rot;
|
||||
r_xscale=(xscale-r_xscale)*tween+r_xscale;
|
||||
r_yscale=(yscale-r_yscale)*tween+r_yscale;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sprite::render( const RenderContext &rc ){
|
||||
|
||||
Transform t=getRenderTform();
|
||||
|
||||
if( view_mode==VIEW_MODE_FREE ){
|
||||
t.m=rc.getCameraTform().m;
|
||||
}else if( view_mode==VIEW_MODE_UPRIGHT ){
|
||||
t.m.k=rc.getCameraTform().m.k;t.m.orthogonalize();
|
||||
}else if( view_mode==VIEW_MODE_UPRIGHT2 ){
|
||||
t.m=yawMatrix( matrixYaw( rc.getCameraTform().m ) ) * t.m;
|
||||
}
|
||||
|
||||
t.m=t.m * rollMatrix( r_rot ) * scaleMatrix( r_xscale,r_yscale,1 );
|
||||
|
||||
static Vector verts[4];
|
||||
verts[0]=t * Vector( -1-xhandle, 1-yhandle,0 );
|
||||
verts[1]=t * Vector( 1-xhandle, 1-yhandle,0 );
|
||||
verts[2]=t * Vector( 1-xhandle,-1-yhandle,0 );
|
||||
verts[3]=t * Vector( -1-xhandle,-1-yhandle,0 );
|
||||
|
||||
if( !rc.getWorldFrustum().cull( verts,4 ) ) return false;
|
||||
|
||||
mesh->lock( false );
|
||||
int fv=mesh_index*4,ft=mesh_index*2;
|
||||
mesh->setVertex( fv+0,&verts[0].x,null,tex_coords0 );
|
||||
mesh->setVertex( fv+1,&verts[1].x,null,tex_coords1 );
|
||||
mesh->setVertex( fv+2,&verts[2].x,null,tex_coords2 );
|
||||
mesh->setVertex( fv+3,&verts[3].x,null,tex_coords3 );
|
||||
if( rc.isReflected() ){
|
||||
mesh->setTriangle( ft+0,0,2,1 );
|
||||
mesh->setTriangle( ft+1,0,3,2 );
|
||||
}else{
|
||||
mesh->setTriangle( ft+0,0,1,2 );
|
||||
mesh->setTriangle( ft+1,0,2,3 );
|
||||
}
|
||||
mesh->unlock();
|
||||
|
||||
enqueue( mesh,fv,4,ft,2 );
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
#ifndef SPRITE_H
|
||||
#define SPRITE_H
|
||||
|
||||
#include "model.hpp"
|
||||
#include "brush.hpp"
|
||||
#include "../gxruntime/gxmesh.hpp"
|
||||
|
||||
class Sprite : public Model{
|
||||
public:
|
||||
enum{
|
||||
VIEW_MODE_FREE=1, //visible from any angle
|
||||
VIEW_MODE_FIXED=2, //visible only from front
|
||||
VIEW_MODE_UPRIGHT=3, //upright tree-style
|
||||
VIEW_MODE_UPRIGHT2=4 //better upright tree-style
|
||||
};
|
||||
|
||||
Sprite();
|
||||
Sprite( const Sprite &t );
|
||||
~Sprite();
|
||||
|
||||
Sprite *getSprite(){ return this; }
|
||||
|
||||
Entity *clone(){ return new Sprite( *this ); }
|
||||
|
||||
void capture();
|
||||
bool beginRender( float tween );
|
||||
|
||||
void setRotation( float angle );
|
||||
void setScale( float x_scale,float y_scale );
|
||||
void setHandle( float x,float y );
|
||||
void setViewmode( int mode );
|
||||
|
||||
bool render( const RenderContext &rc );
|
||||
|
||||
private:
|
||||
float xhandle,yhandle;
|
||||
float rot,xscale,yscale;
|
||||
float r_rot,r_xscale,r_yscale;
|
||||
int view_mode,mesh_index;
|
||||
bool captured;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
#include "std.hpp"
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
#ifndef STD_H
|
||||
#define STD_H
|
||||
|
||||
#pragma warning( disable:4786 )
|
||||
|
||||
#include "config.hpp"
|
||||
#include "stdutil.hpp"
|
||||
#include "gxruntime.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,238 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "surface.hpp"
|
||||
|
||||
extern gxGraphics *gx_graphics;
|
||||
|
||||
static Surface::Monitor nop_mon;
|
||||
|
||||
Surface::Surface():
|
||||
mesh(0),mesh_vs(0),mesh_ts(0),valid_vs(0),valid_ts(0),mon( &nop_mon ){
|
||||
}
|
||||
|
||||
Surface::Surface( Monitor *m ):
|
||||
mesh(0),mesh_vs(0),mesh_ts(0),valid_vs(0),valid_ts(0),mon(m){
|
||||
}
|
||||
|
||||
Surface::~Surface(){
|
||||
if( mesh ) gx_graphics->freeMesh( mesh );
|
||||
}
|
||||
|
||||
void Surface::setBrush( const Brush &b ){
|
||||
brush=b;
|
||||
++mon->brush_changes;
|
||||
}
|
||||
|
||||
void Surface::setName( const string &n ){
|
||||
name=n;
|
||||
}
|
||||
|
||||
void Surface::clear( bool verts,bool tris ){
|
||||
if( verts ){ vertices.clear();valid_vs=0; }
|
||||
if( tris ){ triangles.clear();valid_ts=0; }
|
||||
++mon->geom_changes;
|
||||
}
|
||||
|
||||
void Surface::addVertices( const vector<Vertex> &verts ){
|
||||
vertices.insert( vertices.end(),verts.begin(),verts.end() );
|
||||
++mon->geom_changes;
|
||||
}
|
||||
|
||||
void Surface::setColor( int n,const Vector &v ){
|
||||
int r=floor(v.x*255);if(r<0)r=0;else if(r>255)r=255;
|
||||
int g=floor(v.y*255);if(g<0)g=0;else if(g>255)g=255;
|
||||
int b=floor(v.z*255);if(b<0)b=0;else if(b>255)b=255;
|
||||
|
||||
unsigned argb=0xff000000|(r<<16)|(g<<8)|b;
|
||||
|
||||
vertices[n].color=argb;
|
||||
if( n<valid_vs ) valid_vs=n;
|
||||
}
|
||||
|
||||
Vector Surface::getColor( int n )const{
|
||||
float r=(vertices[n].color&0x00ff0000)>>16;
|
||||
float g=(vertices[n].color&0x0000ff00)>>8;
|
||||
float b= vertices[n].color&0x000000ff;
|
||||
return Vector( r/255.0f,g/255.0f,b/255.0f );
|
||||
}
|
||||
|
||||
void Surface::addTriangles( const vector<Triangle> &tris ){
|
||||
triangles.insert( triangles.end(),tris.begin(),tris.end() );
|
||||
}
|
||||
|
||||
void Surface::updateNormals(){
|
||||
int k;
|
||||
map<Vector,Vector> norm_map;
|
||||
for( k=0;k<triangles.size();++k ){
|
||||
const Triangle &t=triangles[k];
|
||||
const Vector &v0=vertices[t.verts[0]].coords;
|
||||
const Vector &v1=vertices[t.verts[1]].coords;
|
||||
const Vector &v2=vertices[t.verts[2]].coords;
|
||||
Vector n=(v1-v0).cross(v2-v0);
|
||||
if( n.length()<= FLT_EPSILON ) continue;
|
||||
n.normalize();
|
||||
norm_map[v0]+=n;
|
||||
norm_map[v1]+=n;
|
||||
norm_map[v2]+=n;
|
||||
}
|
||||
for( k=0;k<vertices.size();++k ){
|
||||
Vertex *v=&vertices[k];
|
||||
v->normal=norm_map[v->coords].normalized();
|
||||
}
|
||||
}
|
||||
|
||||
gxMesh *Surface::getMesh(){
|
||||
if( mesh && mesh->dirty() ) valid_vs=0;
|
||||
|
||||
if( valid_vs==vertices.size() && valid_ts==triangles.size() ) return mesh;
|
||||
|
||||
valid_vs=valid_ts=0;
|
||||
|
||||
if( mesh_vs<vertices.size() || mesh_ts<triangles.size() ){
|
||||
if( mesh ){
|
||||
gx_graphics->freeMesh( mesh );
|
||||
mesh_vs=vertices.size()+mesh_vs/2;
|
||||
mesh_ts=triangles.size()+mesh_ts/2;
|
||||
}else{
|
||||
mesh_vs=vertices.size();
|
||||
mesh_ts=triangles.size();
|
||||
}
|
||||
mesh=gx_graphics->createMesh( mesh_vs,mesh_ts,0 );
|
||||
}
|
||||
|
||||
mesh->lock( true );
|
||||
for( ;valid_vs<vertices.size();++valid_vs ){
|
||||
mesh->setVertex( valid_vs,&vertices[valid_vs] );
|
||||
}
|
||||
for( ;valid_ts<triangles.size();++valid_ts ){
|
||||
const Triangle &t=triangles[valid_ts];
|
||||
mesh->setTriangle( valid_ts,t.verts[0],t.verts[1],t.verts[2] );
|
||||
}
|
||||
mesh->unlock();
|
||||
return mesh;
|
||||
}
|
||||
|
||||
gxMesh *Surface::getMesh( const vector<Bone> &bones ){
|
||||
|
||||
valid_vs=valid_ts=0;
|
||||
|
||||
if( mesh_vs<vertices.size() || mesh_ts<triangles.size() ){
|
||||
if( mesh ) gx_graphics->freeMesh( mesh );
|
||||
mesh_vs=vertices.size();
|
||||
mesh_ts=triangles.size();
|
||||
mesh=gx_graphics->createMesh( mesh_vs,mesh_ts,0 );
|
||||
}
|
||||
|
||||
mesh->lock( true );
|
||||
for( ;valid_vs<vertices.size();++valid_vs ){
|
||||
const Vertex &v=vertices[valid_vs];
|
||||
if( v.bone_bones[0]==255 ){
|
||||
//no bone!
|
||||
const Bone &bone=bones[0];
|
||||
mesh->setVertex( valid_vs,bone.coord_tform * v.coords,bone.normal_tform * v.normal,v.color,v.tex_coords );
|
||||
}else if( v.bone_bones[1]==255 ){
|
||||
//one bone only
|
||||
const Bone &bone=bones[v.bone_bones[0]];
|
||||
mesh->setVertex( valid_vs,bone.coord_tform * v.coords,bone.normal_tform * v.normal,v.color,v.tex_coords );
|
||||
}else{
|
||||
const Vertex &v=vertices[valid_vs];
|
||||
//two or more bones
|
||||
Vector tv,tn;
|
||||
for( int n=0;n<MAX_SURFACE_BONES;++n ){
|
||||
if( v.bone_bones[n]==255 ) break;
|
||||
const Bone &bone=bones[v.bone_bones[n]];
|
||||
tv+=bone.coord_tform * v.coords * v.bone_weights[n];
|
||||
tn+=bone.normal_tform * v.normal * v.bone_weights[n];
|
||||
}
|
||||
mesh->setVertex( valid_vs,tv,tn.normalized(),v.color,v.tex_coords );
|
||||
}
|
||||
}
|
||||
for( ;valid_ts<triangles.size();++valid_ts ){
|
||||
const Triangle &t=triangles[valid_ts];
|
||||
mesh->setTriangle( valid_ts,t.verts[0],t.verts[1],t.verts[2] );
|
||||
}
|
||||
mesh->unlock();
|
||||
return mesh;
|
||||
}
|
||||
|
||||
/*
|
||||
gxMesh *Surface::getMesh(){
|
||||
if( mesh && mesh->dirty() ) valid_vs=0;
|
||||
|
||||
if( valid_vs==vertices.size() && valid_ts==triangles.size() ) return mesh;
|
||||
|
||||
valid_vs=0;
|
||||
valid_ts=0;
|
||||
|
||||
if( mesh ){
|
||||
int maxvs=mesh->maxVerts(),maxts=mesh->maxTris();
|
||||
if( maxvs<vertices.size() || maxts<triangles.size() ){
|
||||
gx_graphics->freeMesh( mesh );
|
||||
mesh=gx_graphics->createMesh( vertices.size()+maxvs/2,triangles.size()+maxts/2,0 );
|
||||
}
|
||||
}else if( vertices.size() || triangles.size() ){
|
||||
mesh=gx_graphics->createMesh( vertices.size(),triangles.size(),0 );
|
||||
}
|
||||
|
||||
mesh->lock( true );
|
||||
for( ;valid_vs<vertices.size();++valid_vs ){
|
||||
mesh->setVertex( valid_vs,&vertices[valid_vs] );
|
||||
}
|
||||
for( ;valid_ts<triangles.size();++valid_ts ){
|
||||
const Triangle &t=triangles[valid_ts];
|
||||
mesh->setTriangle( valid_ts,t.verts[0],t.verts[1],t.verts[2] );
|
||||
}
|
||||
mesh->unlock();
|
||||
return mesh;
|
||||
}
|
||||
|
||||
gxMesh *Surface::getMesh( const vector<Bone> &bones,gxMesh *mesh ){
|
||||
|
||||
valid_vs=0;
|
||||
valid_ts=0;
|
||||
|
||||
if( mesh ){
|
||||
int maxvs=mesh->maxVerts(),maxts=mesh->maxTris();
|
||||
if( maxvs<vertices.size() || maxts<triangles.size() ){
|
||||
gx_graphics->freeMesh( mesh );
|
||||
mesh=gx_graphics->createMesh( vertices.size(),triangles.size(),0 );
|
||||
|
||||
}
|
||||
}else if( vertices.size() || triangles.size() ){
|
||||
mesh=gx_graphics->createMesh( vertices.size(),triangles.size(),0 );
|
||||
}
|
||||
|
||||
mesh->lock( true );
|
||||
for( ;valid_vs<vertices.size();++valid_vs ){
|
||||
const Vertex &v=vertices[valid_vs];
|
||||
if( v.bone_bones[0]==255 ){
|
||||
//no bone!
|
||||
const Bone &bone=bones[0];
|
||||
mesh->setVertex( valid_vs,bone.coord_tform * v.coords,bone.normal_tform * v.normal,v.color,v.tex_coords );
|
||||
}else if( v.bone_bones[1]==255 ){
|
||||
//one bone only
|
||||
const Bone &bone=bones[v.bone_bones[0]];
|
||||
mesh->setVertex( valid_vs,bone.coord_tform * v.coords,bone.normal_tform * v.normal,v.color,v.tex_coords );
|
||||
}else{
|
||||
const Vertex &v=vertices[valid_vs];
|
||||
//two or more bones
|
||||
Vector tv,tn;
|
||||
for( int n=0;n<MAX_SURFACE_BONES;++n ){
|
||||
if( v.bone_bones[n]==255 ) break;
|
||||
const Bone &bone=bones[v.bone_bones[n]];
|
||||
tv+=bone.coord_tform * v.coords * v.bone_weights[n];
|
||||
tn+=bone.normal_tform * v.normal * v.bone_weights[n];
|
||||
}
|
||||
mesh->setVertex( valid_vs,tv,tn.normalized(),v.color,v.tex_coords );
|
||||
}
|
||||
}
|
||||
for( ;valid_ts<triangles.size();++valid_ts ){
|
||||
const Triangle &t=triangles[valid_ts];
|
||||
mesh->setTriangle( valid_ts,t.verts[0],t.verts[1],t.verts[2] );
|
||||
}
|
||||
mesh->unlock();
|
||||
return mesh;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
|
||||
#ifndef SURFACE_H
|
||||
#define SURFACE_H
|
||||
|
||||
#include "model.hpp"
|
||||
|
||||
#define MAX_SURFACE_BONES 4
|
||||
|
||||
class Surface{
|
||||
public:
|
||||
struct Vertex{
|
||||
Vector coords;
|
||||
Vector normal;
|
||||
unsigned color;
|
||||
float tex_coords[2][2];
|
||||
unsigned char bone_bones[MAX_SURFACE_BONES];
|
||||
float bone_weights[MAX_SURFACE_BONES];
|
||||
|
||||
Vertex():color(~0){
|
||||
bone_bones[0]=255;
|
||||
memset(tex_coords,0,sizeof(tex_coords));
|
||||
}
|
||||
|
||||
bool operator<( const Vertex &t )const{
|
||||
return memcmp( this,&t,sizeof(*this) )==-1;
|
||||
}
|
||||
};
|
||||
|
||||
struct Triangle{
|
||||
unsigned short verts[3];
|
||||
};
|
||||
|
||||
struct Bone{
|
||||
Transform coord_tform;
|
||||
Matrix normal_tform;
|
||||
};
|
||||
|
||||
struct Monitor{
|
||||
int brush_changes,geom_changes;
|
||||
};
|
||||
|
||||
Surface();
|
||||
Surface( Monitor *mon );
|
||||
~Surface();
|
||||
|
||||
void setName( const string &t );
|
||||
void setBrush( const Brush &b );
|
||||
|
||||
void clear( bool verts,bool tris );
|
||||
|
||||
void addVertex( const Vertex &v ){
|
||||
vertices.push_back(v);
|
||||
++mon->geom_changes;
|
||||
}
|
||||
void setVertex( int n,const Vertex &v ){
|
||||
vertices[n]=v;
|
||||
if( n<valid_vs ) valid_vs=n;
|
||||
++mon->geom_changes;
|
||||
}
|
||||
void setCoords( int n,const Vector &v ){
|
||||
vertices[n].coords=v;
|
||||
if( n<valid_vs ) valid_vs=n;
|
||||
++mon->geom_changes;
|
||||
}
|
||||
void setNormal( int n,const Vector &v ){
|
||||
vertices[n].normal=v;
|
||||
if( n<valid_vs ) valid_vs=n;
|
||||
}
|
||||
void setColor( int n,unsigned argb ){
|
||||
vertices[n].color=argb;
|
||||
if( n<valid_vs ) valid_vs=n;
|
||||
}
|
||||
void setTexCoords( int n,const Vector &v,int i ){
|
||||
vertices[n].tex_coords[i][0]=v.x;
|
||||
vertices[n].tex_coords[i][1]=v.y;
|
||||
if( n<valid_vs ) valid_vs=n;
|
||||
}
|
||||
void addTriangle( const Triangle &t ){
|
||||
triangles.push_back(t);
|
||||
++mon->geom_changes;
|
||||
}
|
||||
void setTriangle( int n,const Triangle &t ){
|
||||
triangles[n]=t;
|
||||
if( n<valid_ts ) valid_ts=n;
|
||||
++mon->geom_changes;
|
||||
}
|
||||
|
||||
Vector getColor( int index )const;
|
||||
void setColor( int index,const Vector &v );
|
||||
void addVertices( const vector<Vertex> &verts );
|
||||
void addTriangles( const vector<Triangle> &tris );
|
||||
|
||||
void updateNormals();
|
||||
|
||||
gxMesh *getMesh();
|
||||
gxMesh *getMesh( const vector<Bone> &bones );
|
||||
|
||||
string getName()const{ return name; }
|
||||
const Brush &getBrush()const{ return brush; }
|
||||
int numVertices()const{ return vertices.size(); }
|
||||
int numTriangles()const{ return triangles.size(); }
|
||||
const Vertex &getVertex( int n )const{ return vertices[n]; }
|
||||
const Triangle &getTriangle( int n )const{ return triangles[n]; }
|
||||
|
||||
private:
|
||||
Brush brush;
|
||||
string name;
|
||||
gxMesh *mesh;
|
||||
vector<Vertex> vertices;
|
||||
vector<Triangle> triangles;
|
||||
int mesh_vs,mesh_ts;
|
||||
int valid_vs,valid_ts;
|
||||
Monitor *mon;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "terrain.hpp"
|
||||
#include "terrainrep.hpp"
|
||||
|
||||
Terrain::Terrain( int size_shift ):
|
||||
rep( new TerrainRep( size_shift ) ){
|
||||
}
|
||||
|
||||
Terrain::~Terrain(){
|
||||
delete rep;
|
||||
}
|
||||
|
||||
void Terrain::setDetail( int n,bool m ){
|
||||
rep->setDetail( n,m );
|
||||
}
|
||||
|
||||
void Terrain::setShading( bool t ){
|
||||
rep->setShading( t );
|
||||
}
|
||||
|
||||
void Terrain::setHeight( int x,int z,float h,bool realtime ){
|
||||
if( x>=0 && z>=0 && x<=rep->getSize() && z<=rep->getSize() ) rep->setHeight( x,z,h,realtime );
|
||||
}
|
||||
|
||||
int Terrain::getSize()const{
|
||||
return rep->getSize();
|
||||
}
|
||||
|
||||
float Terrain::getHeight( int x,int z )const{
|
||||
return (x>=0 && z>=0 && x<=rep->getSize() && z<=rep->getSize() ) ? rep->getHeight( x,z ) : 0;
|
||||
}
|
||||
|
||||
bool Terrain::render( const RenderContext &rc ){
|
||||
rep->render( this,rc );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Terrain::collide( const Line &line,float radius,Collision *curr_coll,const Transform &tf ){
|
||||
return rep->collide( line,radius,curr_coll,tf );
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
|
||||
#ifndef TERRAIN_H
|
||||
#define TERRAIN_H
|
||||
|
||||
#include "model.hpp"
|
||||
|
||||
struct TerrainRep;
|
||||
|
||||
class Terrain : public Model{
|
||||
public:
|
||||
Terrain( int size_shift );
|
||||
~Terrain();
|
||||
|
||||
Terrain *getTerrain(){ return this; }
|
||||
|
||||
void setDetail( int n,bool morph );
|
||||
void setHeight( int x,int z,float h,bool realtime );
|
||||
void setShading( bool shading );
|
||||
|
||||
int getSize()const;
|
||||
float getHeight( int x,int z )const;
|
||||
|
||||
//model interface
|
||||
bool render( const RenderContext &rc );
|
||||
|
||||
//object interface
|
||||
bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &tf );
|
||||
|
||||
private:
|
||||
TerrainRep *rep;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,582 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "terrainrep.hpp"
|
||||
#include <queue>
|
||||
|
||||
extern gxRuntime *gx_runtime;
|
||||
extern gxGraphics *gx_graphics;
|
||||
extern float stats3d[10];
|
||||
|
||||
static Vector eye_vec;
|
||||
static Plane eye_plane;
|
||||
static const Vector up_normal( 0,1,0 );
|
||||
static TerrainRep::Tri *tri_pool;
|
||||
static const TerrainRep *curr;
|
||||
static Frustum frustum;
|
||||
static int out_cnt,proc_cnt,clip_cnt;
|
||||
|
||||
static float proj_epsilon= FLT_EPSILON; //.01f;
|
||||
|
||||
struct TerrainRep::Cell{
|
||||
unsigned char height;
|
||||
};
|
||||
|
||||
struct TerrainRep::Error{
|
||||
unsigned char error,bound;
|
||||
};
|
||||
|
||||
int TerrainRep::getSize()const{
|
||||
return cell_size;
|
||||
}
|
||||
|
||||
float TerrainRep::getHeight( int x,int z )const{
|
||||
return cells[((z&cell_mask)<<cell_shift)|(x&cell_mask)].height/255.0f;
|
||||
}
|
||||
|
||||
struct TerrainRep::Vert{
|
||||
short x,z;
|
||||
Vector v;
|
||||
float src_y;
|
||||
|
||||
Vert(){
|
||||
}
|
||||
Vert( int x,int z ):x(x),z(z),v( (float)x,curr->getHeight(x,z),(float)z){
|
||||
src_y=v.y;
|
||||
}
|
||||
Vert(int x, int z, float sy) :x(x), z(z), v((float)x, curr->getHeight(x, z), (float)z), src_y(sy) {
|
||||
}
|
||||
};
|
||||
|
||||
static int vert_cnt,max_verts;
|
||||
static TerrainRep::Vert *verts,*next_vert;
|
||||
|
||||
struct TerrainRep::Tri{
|
||||
int id;
|
||||
short clip,v0,v1,v2;
|
||||
Tri *e0,*e1,*e2;
|
||||
float proj_err;
|
||||
|
||||
Tri(){
|
||||
}
|
||||
Tri( int id,int clip,int v0,int v1,int v2,Tri *e0=0,Tri *e1=0,Tri *e2=0 ):
|
||||
id(id),clip(clip),
|
||||
v0(v0),v1(v1),v2(v2),
|
||||
e0(e0),e1(e1),e2(e2),proj_err(0){
|
||||
}
|
||||
|
||||
void *operator new( size_t sz ){
|
||||
static const int GROW=64;
|
||||
if( !tri_pool ){
|
||||
tri_pool=new Tri[GROW];
|
||||
for( int k=0;k<GROW-1;++k ) tri_pool[k].e0=&tri_pool[k+1];
|
||||
tri_pool[GROW-1].e0=0;
|
||||
}
|
||||
Tri *t=tri_pool;
|
||||
tri_pool=t->e0;
|
||||
return t;
|
||||
}
|
||||
void operator delete( void *q ){
|
||||
Tri *t=(Tri*)q;
|
||||
t->e0=tri_pool;
|
||||
tri_pool=t;
|
||||
}
|
||||
void unlink(){
|
||||
if( e0 ){
|
||||
if( e0->e0==this ) e0->e0=0;
|
||||
else if( e0->e1==this ) e0->e1=0;
|
||||
else e0->e2=0;
|
||||
}
|
||||
if( e1 ){
|
||||
if( e1->e0==this ) e1->e0=0;
|
||||
else if( e1->e1==this ) e1->e1=0;
|
||||
else e1->e2=0;
|
||||
}
|
||||
if( e2 ){
|
||||
if( e2->e0==this ) e2->e0=0;
|
||||
else if( e2->e1==this ) e2->e1=0;
|
||||
else e2->e2=0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct TriComp{
|
||||
bool operator()( TerrainRep::Tri *a,TerrainRep::Tri *b )const{ return a->proj_err<b->proj_err; }
|
||||
};
|
||||
|
||||
struct TriQue : public priority_queue<TerrainRep::Tri*,vector<TerrainRep::Tri*>,TriComp>{
|
||||
vector<TerrainRep::Tri*> &getVector(){ return c; }
|
||||
const vector<TerrainRep::Tri*> &getVector()const{ return c; }
|
||||
};
|
||||
|
||||
static TriQue tri_que;
|
||||
static vector<TerrainRep::Tri*> tris;
|
||||
|
||||
static bool clip( const Line &l,const Box &box ){
|
||||
static const Vector normals[]={
|
||||
Vector( 1,0,0 ),
|
||||
Vector( 0,0,1 ),
|
||||
Vector( 0,-1,0 ),
|
||||
Vector( -1,0,0 ),
|
||||
Vector( 0,0,-1 ),
|
||||
Vector( 0,1,0 )
|
||||
};
|
||||
Vector v0=l.o,v1=l.o+l.d;
|
||||
for( int k=0;k<6;++k ){
|
||||
Vector t=box.corner(k);
|
||||
const Vector &n=normals[k];
|
||||
float d0=n.dot( v0-t ),d1=n.dot( v1-t );
|
||||
if( d0<0 ){
|
||||
if( d1<0 ) return false;
|
||||
v0+=(v1-v0)*( d0/(d0-d1) );
|
||||
}else if( d1<0 ){
|
||||
v1+=(v0-v1)*( d1/(d1-d0) );
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TerrainRep::TerrainRep( int n ):
|
||||
cell_shift(n),cell_size(1<<n),cell_mask((1<<n)-1),
|
||||
end_tri_id( (1<<n)*(1<<n)*2 ),
|
||||
shading(false),mesh(0),detail(0),morph(true){
|
||||
cells=new Cell[cell_size*cell_size];
|
||||
errors=new Error[end_tri_id];
|
||||
setDetail( 2000,false );
|
||||
clear();
|
||||
}
|
||||
|
||||
TerrainRep::~TerrainRep(){
|
||||
if( mesh ) gx_graphics->freeMesh( mesh );
|
||||
delete[] errors;
|
||||
delete[] cells;
|
||||
}
|
||||
|
||||
void TerrainRep::clear(){
|
||||
memset( cells,0,cell_size*cell_size*sizeof(Cell) );
|
||||
memset( errors,0,end_tri_id*sizeof(Error) );
|
||||
errs_valid=true;
|
||||
}
|
||||
|
||||
void TerrainRep::setDetail( int n,bool m ){
|
||||
morph=m;
|
||||
if( n==detail ) return;
|
||||
detail=n;
|
||||
|
||||
n+=32;
|
||||
if( n>max_verts ){
|
||||
delete[] verts;
|
||||
max_verts=n;
|
||||
verts=new Vert[max_verts];
|
||||
}
|
||||
if( mesh ) gx_graphics->freeMesh( mesh );
|
||||
mesh_verts=mesh_tris=n;
|
||||
mesh=gx_graphics->createMesh( mesh_verts,mesh_tris,0 );
|
||||
}
|
||||
|
||||
void TerrainRep::setShading( bool t ){
|
||||
shading=t;
|
||||
}
|
||||
|
||||
void TerrainRep::setHeight( int x,int z,float h,bool realtime ){
|
||||
cells[((z&cell_mask)<<cell_shift)|(x&cell_mask)].height=h*255.0f;
|
||||
if( !errs_valid ) return;
|
||||
if( realtime ){
|
||||
Vert v0(0,0),v1(cell_size,0),v2(cell_size,cell_size),v3(0,cell_size);
|
||||
calcErr( 2,x,z,v1,v2,v0 );
|
||||
calcErr( 3,x,z,v3,v0,v2 );
|
||||
return;
|
||||
}
|
||||
errs_valid=false;
|
||||
}
|
||||
|
||||
Vector TerrainRep::getNormal( int x,int z )const{
|
||||
Vector
|
||||
vt( x,getHeight(x,z),z ),
|
||||
v0( x,getHeight(x,z-1),z-1 ),
|
||||
v1( x+1,getHeight(x+1,z),z ),
|
||||
v2( x,getHeight(x,z+1),z+1 ),
|
||||
v3( x-1,getHeight(x-1,z),z );
|
||||
return (
|
||||
Plane( vt,v1,v0 ).n+
|
||||
Plane( vt,v2,v1 ).n+
|
||||
Plane( vt,v3,v2 ).n+
|
||||
Plane( vt,v0,v3 ).n ).normalized();
|
||||
}
|
||||
|
||||
void TerrainRep::insert( Tri *t ){
|
||||
++proc_cnt;
|
||||
|
||||
//quicker clip check for 'thin' triangles...
|
||||
if( t->id>=end_tri_id || !errors[t->id].error ){
|
||||
if( t->clip & 63 ){
|
||||
++clip_cnt;
|
||||
Vector e0( verts[t->v0].v ),e1( verts[t->v1].v ),e2( verts[t->v2].v );
|
||||
for( int n=0;n<6;++n ){
|
||||
if( !( t->clip & (1<<n) ) ) continue;
|
||||
const Plane &p=frustum.getPlane( n );
|
||||
if( p.distance(e0)<0 && p.distance(e1)<0 && p.distance(e2)<0 ){
|
||||
t->unlink();
|
||||
delete t;
|
||||
++out_cnt;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
t->clip|=128;
|
||||
tris.push_back( t );
|
||||
++out_cnt;
|
||||
return;
|
||||
}
|
||||
|
||||
//clip?
|
||||
if( t->id<end_tri_id/2 && (t->clip & 63) ){
|
||||
++clip_cnt;
|
||||
Vector e0( verts[t->v0].v ),e1( verts[t->v1].v ),e2( verts[t->v2].v );
|
||||
Vector e3(e0),e4(e1),e5(e2);
|
||||
e0.y=e1.y=e2.y=0;
|
||||
e3.y=e4.y=e5.y=errors[t->id].bound/255.0f;
|
||||
for( int n=0;n<6;++n ){
|
||||
int mask=1<<n;
|
||||
if( !(t->clip & mask) ) continue;
|
||||
const Plane &p=frustum.getPlane( n );
|
||||
int q=
|
||||
(p.distance( e0 )>=0)+(p.distance( e1 )>=0)+(p.distance( e2 )>=0)+
|
||||
(p.distance( e3 )>=0)+(p.distance( e4 )>=0)+(p.distance( e5 )>=0);
|
||||
if( !q ){
|
||||
t->unlink();
|
||||
delete t;
|
||||
++out_cnt;
|
||||
return;
|
||||
}
|
||||
if( q==6 ) t->clip&=~mask;
|
||||
}
|
||||
}
|
||||
|
||||
if( t->clip & 128 ){
|
||||
t->clip|=128;
|
||||
tris.push_back( t );
|
||||
}else{
|
||||
Vector v=Vector( verts[t->v1].v+verts[t->v2].v )/2;
|
||||
// float d=eye_plane.distance( v );
|
||||
float d=eye_vec.distance( v );
|
||||
if( d<FLT_EPSILON ) d= FLT_EPSILON;
|
||||
t->proj_err=errors[t->id].error/d;
|
||||
if( t->proj_err>proj_epsilon ){
|
||||
tri_que.push( t );
|
||||
}else{
|
||||
t->clip|=128;
|
||||
tris.push_back( t );
|
||||
}
|
||||
}
|
||||
++out_cnt;
|
||||
}
|
||||
|
||||
void TerrainRep::split( Tri *t ){
|
||||
|
||||
if( t->e2 && t->e2->e2!=t ) split( t->e2 );
|
||||
|
||||
int tv=vert_cnt++;
|
||||
if( tv>=max_verts ){
|
||||
max_verts+=max_verts/2+32;
|
||||
Vert *t=verts;
|
||||
verts=new Vert[max_verts];
|
||||
memcpy( verts,t,sizeof(Vert)*tv );
|
||||
next_vert=verts+tv;
|
||||
}
|
||||
Vert *vert=next_vert++;
|
||||
vert->v.x=vert->x=(verts[t->v1].x+verts[t->v2].x)/2;
|
||||
vert->v.z=vert->z=(verts[t->v1].z+verts[t->v2].z)/2;
|
||||
vert->src_y=(verts[t->v1].v.y+verts[t->v2].v.y)/2;
|
||||
vert->v.y=getHeight( vert->x,vert->z );
|
||||
|
||||
Tri *tl=new Tri( t->id*2,t->clip,tv,t->v2,t->v0,0,0,t->e0 );
|
||||
if( Tri *p=tl->e2 ){
|
||||
if( p->e0==t ) p->e0=tl;
|
||||
else if( p->e1==t ) p->e1=tl;
|
||||
else p->e2=tl;
|
||||
}
|
||||
Tri *tr=new Tri( t->id*2+1,t->clip,tv,t->v0,t->v1,0,tl,t->e1 );
|
||||
tl->e0=tr;
|
||||
if( Tri *p=tr->e2 ){
|
||||
if( p->e0==t ) p->e0=tr;
|
||||
else if( p->e1==t ) p->e1=tr;
|
||||
else p->e2=tr;
|
||||
}
|
||||
|
||||
if( Tri *b=t->e2 ){
|
||||
Tri *br=new Tri( b->id*2,b->clip,tv,b->v2,b->v0,0,tr,b->e0 );
|
||||
tr->e0=br;
|
||||
if( Tri *p=br->e2 ){
|
||||
if( p->e0==b ) p->e0=br;
|
||||
else if( p->e1==b ) p->e1=br;
|
||||
else p->e2=br;
|
||||
}
|
||||
Tri *bl=new Tri( b->id*2+1,b->clip,tv,b->v0,b->v1,tl,br,b->e1 );
|
||||
tl->e1=br->e0=bl;
|
||||
if( Tri *p=bl->e2 ){
|
||||
if( p->e0==b ) p->e0=bl;
|
||||
else if( p->e1==b ) p->e1=bl;
|
||||
else p->e2=bl;
|
||||
}
|
||||
b->id=0;
|
||||
--out_cnt;
|
||||
insert( br );
|
||||
insert( bl );
|
||||
}
|
||||
t->id=0;
|
||||
--out_cnt;
|
||||
insert( tl );
|
||||
insert( tr );
|
||||
}
|
||||
|
||||
TerrainRep::Error TerrainRep::calcErr( int id,const Vert &v0,const Vert &v1,const Vert &v2 )const{
|
||||
|
||||
Error et;
|
||||
|
||||
float y=v0.v.y;
|
||||
if( v1.v.y>y ) y=v1.v.y;
|
||||
if( v2.v.y>y ) y=v2.v.y;
|
||||
|
||||
et.error = 0;
|
||||
et.bound = y>=1 ? 255 : ceil(y*255.0f);
|
||||
|
||||
if( id>=end_tri_id ) return et;
|
||||
|
||||
Vert tv( (v1.x+v2.x)/2,(v1.z+v2.z)/2 );
|
||||
float e=fabs(tv.v.y-(v1.v.y+v2.v.y)/2);
|
||||
et.error= e>=1 ? 255 : ceil( (e- FLT_EPSILON)*255.0f );
|
||||
|
||||
Error el=calcErr( id*2,tv,v2,v0 );
|
||||
Error er=calcErr( id*2+1,tv,v0,v1 );
|
||||
|
||||
if( el.error>et.error ) et.error=el.error;
|
||||
if( er.error>et.error ) et.error=er.error;
|
||||
|
||||
if( el.bound>et.bound ) et.bound=el.bound;
|
||||
if( er.bound>et.bound ) et.bound=er.bound;
|
||||
|
||||
return errors[id]=et;
|
||||
}
|
||||
|
||||
TerrainRep::Error TerrainRep::calcErr( int id,int x,int z,const Vert &v0,const Vert &v1,const Vert &v2 )const{
|
||||
|
||||
Error et;
|
||||
|
||||
float y=v0.v.y;
|
||||
if( v1.v.y>y ) y=v1.v.y;
|
||||
if( v2.v.y>y ) y=v2.v.y;
|
||||
|
||||
et.error = 0;
|
||||
et.bound = y>=1 ? 255 : ceil(y*255.0f);
|
||||
|
||||
if( id>=end_tri_id ) return et;
|
||||
|
||||
//is x/z inside this triangle?
|
||||
int dx,dz;
|
||||
dx=-(v1.z-v0.z);dz=(v1.x-v0.x);
|
||||
if( (x-v0.x)*dx+(z-v0.z)*dz<0 ) return errors[id];
|
||||
dx=-(v2.z-v1.z);dz=(v2.x-v1.x);
|
||||
if( (x-v1.x)*dx+(z-v1.z)*dz<0 ) return errors[id];
|
||||
dx=-(v0.z-v2.z);dz=(v0.x-v2.x);
|
||||
if( (x-v2.x)*dx+(z-v2.z)*dz<0 ) return errors[id];
|
||||
|
||||
Vert tv( (v1.x+v2.x)/2,(v1.z+v2.z)/2 );
|
||||
float e=fabs(tv.v.y-(v1.v.y+v2.v.y)/2);
|
||||
et.error= e>=1 ? 255 : ceil( (e- FLT_EPSILON)*255.0f );
|
||||
|
||||
Error el=calcErr( id*2,x,z,tv,v2,v0 );
|
||||
Error er=calcErr( id*2+1,x,z,tv,v0,v1 );
|
||||
|
||||
if( el.error>et.error ) et.error=el.error;
|
||||
if( er.error>et.error ) et.error=er.error;
|
||||
|
||||
if( el.bound>et.bound ) et.bound=el.bound;
|
||||
if( er.bound>et.bound ) et.bound=er.bound;
|
||||
|
||||
return errors[id]=et;
|
||||
}
|
||||
|
||||
void TerrainRep::validateErrs()const{
|
||||
if( errs_valid ) return;
|
||||
Vert v0(0,0),v1(cell_size,0),v2(cell_size,cell_size),v3(0,cell_size);
|
||||
calcErr( 2,v1,v2,v0 );
|
||||
calcErr( 3,v3,v0,v2 );
|
||||
errs_valid=true;
|
||||
}
|
||||
|
||||
void TerrainRep::render( Model *model,const RenderContext &rc ){
|
||||
|
||||
curr=this;
|
||||
validateErrs();
|
||||
|
||||
new( &frustum ) Frustum( rc.getWorldFrustum(),-model->getRenderTform() );
|
||||
eye_plane=frustum.getPlane( Frustum::PLANE_NEAR );
|
||||
eye_vec=frustum.getVertex( Frustum::VERT_EYE );
|
||||
|
||||
vert_cnt=4;next_vert=verts;
|
||||
out_cnt=proc_cnt=clip_cnt=0;
|
||||
tri_que.getVector().clear();
|
||||
tris.clear();
|
||||
|
||||
new(next_vert++) Vert(0,0);
|
||||
new(next_vert++) Vert(cell_size,0);
|
||||
new(next_vert++) Vert(cell_size,cell_size);
|
||||
new(next_vert++) Vert(0,cell_size);
|
||||
|
||||
Tri *t0=new Tri( 2,0x3f,1,2,0 );
|
||||
Tri *t1=new Tri( 3,0x3f,3,0,2 );
|
||||
t0->e2=t1;t1->e2=t0;
|
||||
|
||||
insert( t0 );
|
||||
insert( t1 );
|
||||
|
||||
while( tri_que.size() && out_cnt<detail ){
|
||||
|
||||
Tri *t=tri_que.top();
|
||||
tri_que.pop();
|
||||
if( t->id ) split( t );
|
||||
delete t;
|
||||
}
|
||||
|
||||
int k;
|
||||
const vector<Tri*> &q_tris=tri_que.getVector();
|
||||
|
||||
if( !mesh ) out_cnt=0;
|
||||
|
||||
if( !out_cnt ){
|
||||
for( k=0;k<tris.size();++k ) delete tris[k];
|
||||
for( k=0;k<q_tris.size();++k ) delete q_tris[k];
|
||||
return;
|
||||
}
|
||||
|
||||
int err_cnt=0;
|
||||
for( k=0;k<q_tris.size();++k ){
|
||||
Tri *t=q_tris[k];
|
||||
if( t->id ){ tris.push_back( t );++err_cnt; }
|
||||
else delete t;
|
||||
}
|
||||
|
||||
if( morph ){
|
||||
if( int morph_cnt=err_cnt/4 ){
|
||||
if( morph_cnt>vert_cnt ) morph_cnt=vert_cnt;
|
||||
float t=0,morph_step=1.0f/morph_cnt;
|
||||
for( int vn=vert_cnt-morph_cnt;vn<vert_cnt;++vn ){
|
||||
verts[vn].v.y+=(verts[vn].src_y-verts[vn].v.y)*t;
|
||||
t+=morph_step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int tri_cnt=tris.size();
|
||||
|
||||
if( vert_cnt>mesh_verts || tri_cnt>mesh_tris ){
|
||||
int vc=vert_cnt+32;if( vc>mesh_verts ) mesh_verts=vc;
|
||||
int tc=tri_cnt+32;if( tc>mesh_tris ) mesh_tris=tc;
|
||||
if( mesh ) gx_graphics->freeMesh( mesh );
|
||||
mesh=gx_graphics->createMesh( mesh_verts,mesh_tris,0 );
|
||||
}
|
||||
|
||||
mesh->lock( true );
|
||||
int tc=0,vc=0;
|
||||
if( !shading ){
|
||||
for( k=0;k<vert_cnt;++k ){
|
||||
const Vert &t=verts[k];
|
||||
const Vector &v=t.v;
|
||||
float tex_coords[2][2]={ {v.x,cell_size-v.z},{v.x,cell_size-v.z} };
|
||||
mesh->setVertex( vc++,&v.x,&up_normal.x,tex_coords );
|
||||
}
|
||||
}else{
|
||||
for( k=0;k<vert_cnt;++k ){
|
||||
const Vert &t=verts[k];
|
||||
const Vector &v=t.v;
|
||||
float tex_coords[2][2]={ {v.x,cell_size-v.z},{v.x,cell_size-v.z} };
|
||||
Vector normal=getNormal( v.x,v.z );
|
||||
mesh->setVertex( vc++,&v.x,&normal.x,tex_coords );
|
||||
}
|
||||
}
|
||||
for( k=0;k<tri_cnt;++k ){
|
||||
Tri *t=tris[k];
|
||||
if( t->id ) mesh->setTriangle( tc++,t->v0,t->v2,t->v1 );
|
||||
delete t;
|
||||
}
|
||||
mesh->unlock();
|
||||
|
||||
static int mvc,mtc;
|
||||
if( vc>mvc ) mvc=vc;
|
||||
if( tc>mtc ) mtc=tc;
|
||||
stats3d[1]=mvc;
|
||||
stats3d[2]=mtc;
|
||||
|
||||
model->enqueue( mesh,0,vc,0,tc );
|
||||
}
|
||||
|
||||
bool TerrainRep::collide( const Line &line,Collision *curr_coll,const Transform &tform,int id,const Vert &v0,const Vert &v1,const Vert &v2,const Line &l )const{
|
||||
Box b( v0.v );
|
||||
b.update( v1.v );
|
||||
b.update( v2.v );
|
||||
|
||||
if( id>=end_tri_id || !errors[id].error ){
|
||||
return ::clip( l,b ) ?
|
||||
curr_coll->triangleCollide( line,0,tform*v0.v,tform*v2.v,tform*v1.v )
|
||||
: false;
|
||||
}
|
||||
|
||||
b.a.y=0;
|
||||
b.b.y=errors[id].bound/255.0f;
|
||||
if( !::clip( l,b ) ) return false;
|
||||
|
||||
Vert tv( (v1.x+v2.x)/2,(v1.z+v2.z)/2 );
|
||||
|
||||
return
|
||||
collide( line,curr_coll,tform,id*2,tv,v2,v0,l )|
|
||||
collide( line,curr_coll,tform,id*2+1,tv,v0,v1,l );
|
||||
}
|
||||
|
||||
bool TerrainRep::collide( const Line &line,float radius,Collision *curr_coll,const Transform &tform,int id,const Vert &v0,const Vert &v1,const Vert &v2,const Box &box )const{
|
||||
Box b( v0.v );
|
||||
b.update( v1.v );
|
||||
b.update( v2.v );
|
||||
|
||||
if( id>=end_tri_id || !errors[id].error ){
|
||||
if( v0.v==v1.v || v0.v==v2.v || v1.v==v2.v ){
|
||||
gx_runtime->debugLog( "OUCH!" );
|
||||
}
|
||||
return b.overlaps(box) ?
|
||||
curr_coll->triangleCollide( line,radius,tform*v0.v,tform*v2.v,tform*v1.v )
|
||||
: false;
|
||||
}
|
||||
|
||||
b.a.y=0;
|
||||
b.b.y=errors[id].bound/255.0f;
|
||||
if( !b.overlaps( box ) ) return false;
|
||||
|
||||
Vert tv( (v1.x+v2.x)/2,(v1.z+v2.z)/2 );
|
||||
return
|
||||
collide( line,radius,curr_coll,tform,id*2,tv,v2,v0,box )|
|
||||
collide( line,radius,curr_coll,tform,id*2+1,tv,v0,v1,box );
|
||||
}
|
||||
|
||||
bool TerrainRep::collide( const Line &line,float radius,Collision *curr_coll,const Transform &tform )const{
|
||||
|
||||
curr=this;
|
||||
validateErrs();
|
||||
|
||||
Vert v0(0,0),v1(cell_size,0),v2(cell_size,cell_size),v3(0,cell_size);
|
||||
|
||||
if( !radius ){
|
||||
Line l=-tform * line;
|
||||
return
|
||||
collide( line,curr_coll,tform,2,v1,v2,v0,l )|
|
||||
collide( line,curr_coll,tform,3,v3,v0,v2,l );
|
||||
}
|
||||
|
||||
//create local box
|
||||
Box b( line );
|
||||
b.expand( radius );
|
||||
Box box=-tform * b;
|
||||
|
||||
return
|
||||
collide( line,radius,curr_coll,tform,2,v1,v2,v0,box )|
|
||||
collide( line,radius,curr_coll,tform,3,v3,v0,v2,box );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
#ifndef TERRAINREP_H
|
||||
#define TERRAINREP_H
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "model.hpp"
|
||||
|
||||
struct TerrainRep{
|
||||
public:
|
||||
TerrainRep( int cell_shift );
|
||||
~TerrainRep();
|
||||
|
||||
void clear();
|
||||
void setShading( bool shading );
|
||||
void setDetail( int n,bool morph );
|
||||
void setHeight( int x,int z,float h,bool realtime );
|
||||
void setTile( int x,int z,const Brush &brush );
|
||||
void render( Model *model,const RenderContext &rc );
|
||||
|
||||
int getSize()const;
|
||||
float getHeight( int x,int z )const;
|
||||
bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &tform )const;
|
||||
|
||||
struct Tri;
|
||||
struct Vert;
|
||||
|
||||
private:
|
||||
struct Cell;
|
||||
struct Error;
|
||||
|
||||
friend struct Tri;
|
||||
friend struct Vert;
|
||||
|
||||
Cell *cells;
|
||||
Error *errors;
|
||||
gxMesh *mesh;
|
||||
|
||||
int cell_size,cell_shift,cell_mask;
|
||||
int end_tri_id,detail,mesh_verts,mesh_tris;
|
||||
bool morph,shading;
|
||||
mutable bool errs_valid;
|
||||
|
||||
void insert( Tri *t );
|
||||
void split( Tri *t );
|
||||
|
||||
void validateErrs()const;
|
||||
Vector getNormal( int x,int z )const;
|
||||
Error calcErr( int id,const Vert &v0,const Vert &v1,const Vert &v2 )const;
|
||||
Error calcErr( int id,int x,int z,const Vert &v0,const Vert &v1,const Vert &v2 )const;
|
||||
bool collide( const Line &line,Collision *curr_coll,const Transform &tform,int id,const Vert &v0,const Vert &v1,const Vert &v2,const Line &l )const;
|
||||
bool collide( const Line &line,float radius,Collision *curr_coll,const Transform &tform,int id,const Vert &v0,const Vert &v1,const Vert &v2,const Box &box )const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,195 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include "geom.hpp"
|
||||
#include "texture.hpp"
|
||||
#include "cachedtexture.hpp"
|
||||
|
||||
#include "../gxruntime/gxgraphics.hpp"
|
||||
|
||||
extern gxScene *gx_scene;
|
||||
extern gxGraphics *gx_graphics;
|
||||
|
||||
struct Filter {
|
||||
string t;
|
||||
int flags;
|
||||
Filter(const string &t, int flags) :t(t), flags(flags) {
|
||||
}
|
||||
};
|
||||
|
||||
static vector<Filter> filters;
|
||||
|
||||
static int filterFile(const string &t, int flags) {
|
||||
//check filters...
|
||||
string l = tolower(t);
|
||||
for (size_t k = 0; k < filters.size(); ++k) {
|
||||
if (l.find(filters[k].t) != string::npos) {
|
||||
flags |= filters[k].flags;
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
struct Texture::Rep {
|
||||
|
||||
int ref_cnt;
|
||||
CachedTextureFactory cached_tex;
|
||||
vector<gxCanvas*> tex_frames;
|
||||
|
||||
int tex_blend, tex_flags;
|
||||
bool transparent;
|
||||
|
||||
float sx, sy, tx, ty, rot;
|
||||
bool mat_used, mat_valid;
|
||||
gxScene::Matrix matrix;
|
||||
|
||||
Rep(int w, int h, int flags, int cnt) :
|
||||
ref_cnt(1), cached_tex(w, h, flags, cnt),
|
||||
tex_blend(gxScene::BLEND_MULTIPLY), tex_flags(0),
|
||||
sx(1), sy(1), tx(0), ty(0), rot(0), mat_used(false) {
|
||||
tex_frames = cached_tex.getFrames();
|
||||
transparent =
|
||||
(flags & gxCanvas::CANVAS_TEX_ALPHA) &&
|
||||
!(flags & gxCanvas::CANVAS_TEX_MASK);
|
||||
memset(&matrix, 0, sizeof(matrix));
|
||||
}
|
||||
|
||||
Rep(const string &f, int flags, int w, int h, int first, int cnt) :
|
||||
ref_cnt(1), cached_tex(f, flags, w, h, first, cnt),
|
||||
tex_blend(gxScene::BLEND_MULTIPLY), tex_flags(0),
|
||||
sx(1), sy(1), tx(0), ty(0), rot(0), mat_used(false) {
|
||||
tex_frames = cached_tex.getFrames();
|
||||
transparent =
|
||||
(flags & gxCanvas::CANVAS_TEX_ALPHA) &&
|
||||
!(flags & gxCanvas::CANVAS_TEX_MASK);
|
||||
memset(&matrix, 0, sizeof(matrix));
|
||||
}
|
||||
|
||||
Rep(const Rep &t) :
|
||||
ref_cnt(1), cached_tex(t.cached_tex), tex_frames(t.tex_frames),
|
||||
tex_blend(t.tex_blend), tex_flags(t.tex_flags),
|
||||
sx(t.sx), sy(t.sy), tx(t.tx), ty(t.ty), rot(t.rot),
|
||||
mat_used(t.mat_used), mat_valid(t.mat_valid), matrix(t.matrix),
|
||||
transparent(t.transparent) {
|
||||
}
|
||||
};
|
||||
|
||||
Texture::Texture() :rep(0) {
|
||||
}
|
||||
|
||||
Texture::Texture(const string &f, int flags) {
|
||||
flags = filterFile(f, flags) | gxCanvas::CANVAS_TEXTURE;
|
||||
if (flags & gxCanvas::CANVAS_TEX_MASK) flags |= gxCanvas::CANVAS_TEX_RGB | gxCanvas::CANVAS_TEX_ALPHA;
|
||||
rep = new Rep(f, flags, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
Texture::Texture(const string &f, int flags, int w, int h, int first, int cnt) {
|
||||
flags = filterFile(f, flags) | gxCanvas::CANVAS_TEXTURE;
|
||||
if (flags & gxCanvas::CANVAS_TEX_MASK) flags |= gxCanvas::CANVAS_TEX_RGB | gxCanvas::CANVAS_TEX_ALPHA;
|
||||
rep = new Rep(f, flags, w, h, first, cnt);
|
||||
}
|
||||
|
||||
Texture::Texture(int w, int h, int flags, int cnt) {
|
||||
flags |= gxCanvas::CANVAS_TEXTURE;
|
||||
if (flags & gxCanvas::CANVAS_TEX_MASK) flags |= gxCanvas::CANVAS_TEX_RGB | gxCanvas::CANVAS_TEX_ALPHA;
|
||||
rep = new Rep(w, h, flags, cnt);
|
||||
}
|
||||
|
||||
Texture::Texture(const Texture &t) :
|
||||
rep(t.rep) {
|
||||
if (rep) ++rep->ref_cnt;
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
if (rep && !--rep->ref_cnt) delete rep;
|
||||
}
|
||||
|
||||
Texture &Texture::operator=(const Texture &t) {
|
||||
if (t.rep) ++t.rep->ref_cnt;
|
||||
if (rep && !--rep->ref_cnt) delete rep;
|
||||
rep = t.rep;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Texture::setScale(float u_scale, float v_scale) {
|
||||
if (!rep) return;
|
||||
rep->sx = u_scale; rep->sy = v_scale;
|
||||
rep->mat_valid = false;
|
||||
rep->mat_used = true;
|
||||
}
|
||||
|
||||
void Texture::setRotation(float angle) {
|
||||
if (!rep) return;
|
||||
rep->rot = angle;
|
||||
rep->mat_valid = false;
|
||||
rep->mat_used = true;
|
||||
}
|
||||
|
||||
void Texture::setPosition(float u_pos, float v_pos) {
|
||||
if (!rep) return;
|
||||
rep->tx = u_pos;
|
||||
rep->ty = v_pos;
|
||||
rep->mat_valid = false;
|
||||
rep->mat_used = true;
|
||||
}
|
||||
|
||||
void Texture::setBlend(int blend) {
|
||||
if (!rep) return;
|
||||
rep->tex_blend = blend;
|
||||
}
|
||||
|
||||
void Texture::setFlags(int flags) {
|
||||
if (!rep) return;
|
||||
rep->tex_flags = flags;
|
||||
}
|
||||
|
||||
bool Texture::isTransparent()const {
|
||||
return rep ? rep->transparent : false;
|
||||
}
|
||||
|
||||
gxCanvas *Texture::getCanvas(int n)const {
|
||||
return rep && n >= 0 && n < rep->tex_frames.size() ? rep->tex_frames[n] : 0;
|
||||
}
|
||||
|
||||
int Texture::getCanvasFlags()const {
|
||||
return rep && rep->tex_frames.size() ? rep->tex_frames[0]->getFlags() : 0;
|
||||
}
|
||||
|
||||
CachedTextureFactory *Texture::getCachedTexture()const {
|
||||
return rep ? &rep->cached_tex : 0;
|
||||
}
|
||||
|
||||
int Texture::getBlend()const {
|
||||
return rep ? rep->tex_blend : 0;
|
||||
}
|
||||
|
||||
int Texture::getFlags()const {
|
||||
return rep ? rep->tex_flags : 0;
|
||||
}
|
||||
|
||||
const gxScene::Matrix *Texture::getMatrix()const {
|
||||
if (!rep || !rep->mat_used) return 0;
|
||||
if (!rep->mat_valid) {
|
||||
float c = cos(rep->rot), s = sin(rep->rot);
|
||||
rep->matrix.elements[0][0] = c*rep->sx;
|
||||
rep->matrix.elements[1][0] = s*rep->sx;
|
||||
rep->matrix.elements[0][1] = -s*rep->sy;
|
||||
rep->matrix.elements[1][1] = c*rep->sy;
|
||||
rep->matrix.elements[2][0] = rep->tx;
|
||||
rep->matrix.elements[2][1] = rep->ty;
|
||||
rep->mat_valid = true;
|
||||
}
|
||||
return &rep->matrix;
|
||||
}
|
||||
|
||||
bool Texture::operator<(const Texture &t)const {
|
||||
if (rep && t.rep) return rep->cached_tex < t.rep->cached_tex;
|
||||
return rep < t.rep;
|
||||
}
|
||||
|
||||
void Texture::clearFilters() {
|
||||
filters.clear();
|
||||
}
|
||||
|
||||
void Texture::addFilter(const string &t, int flags) {
|
||||
filters.push_back(Filter(tolower(t), flags));
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
#ifndef TEXTURE_H
|
||||
#define TEXTURE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "cachedtexture.hpp"
|
||||
|
||||
#include "../gxruntime/gxcanvas.hpp"
|
||||
|
||||
class Texture{
|
||||
public:
|
||||
Texture();
|
||||
Texture( const std::string &file,int flags );
|
||||
Texture( const std::string &file,int flags,int w,int h,int first,int cnt );
|
||||
Texture( int width,int height,int flags,int cnt );
|
||||
Texture( const Texture &texture );
|
||||
~Texture();
|
||||
|
||||
Texture &operator=( const Texture &texture );
|
||||
|
||||
void setScale( float u_scale,float v_scale );
|
||||
void setRotation( float rot );
|
||||
void setPosition( float u_pos,float v_pos );
|
||||
void setBlend( int blend );
|
||||
void setFlags( int flags );
|
||||
|
||||
int getCanvasFlags()const;
|
||||
gxCanvas *getCanvas( int frame )const;
|
||||
const gxScene::Matrix *getMatrix()const;
|
||||
int getBlend()const;
|
||||
int getFlags()const;
|
||||
CachedTextureFactory *getCachedTexture()const;
|
||||
|
||||
bool isTransparent()const;
|
||||
bool operator<( const Texture &t )const;
|
||||
|
||||
static void clearFilters();
|
||||
static void addFilter( const std::string &filter,int flags );
|
||||
|
||||
private:
|
||||
struct Rep;
|
||||
Rep *rep;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
Blitz 3D User Guide.
|
||||
|
||||
Welcome to the wonder world of 3D!
|
||||
|
||||
Entities
|
||||
********
|
||||
|
||||
At the heart of Blitz3D lies the concept of an 'Entity'.
|
||||
|
||||
An Entity is a 'thing' in the 3D world that has a position and an orientation.
|
||||
|
||||
Blitz3D supports many kinds of entities:
|
||||
|
||||
* Camera
|
||||
* Light
|
||||
* Pivot
|
||||
* Mesh
|
||||
* Sprite
|
||||
* Plane
|
||||
* Mirror
|
||||
* Terrain
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,649 @@
|
||||
|
||||
#include "std.hpp"
|
||||
#include <queue>
|
||||
#include "world.hpp"
|
||||
|
||||
//0=tris compared for collision
|
||||
//1=max proj err of terrain
|
||||
float stats3d[10];
|
||||
|
||||
extern gxScene *gx_scene;
|
||||
extern gxRuntime *gx_runtime;
|
||||
|
||||
static std::list<Object*> s_objectsEnabled, s_objectsVisible;
|
||||
|
||||
static void StaticEnumerateEnabled() {
|
||||
s_objectsEnabled.clear();
|
||||
for (Entity *e = Entity::GetEntityOrphans(); e; e = e->GetSuccessor()) {
|
||||
e->EnumerateEnabled(s_objectsEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
static void StaticEnumerateVisible() {
|
||||
s_objectsVisible.clear();
|
||||
for (Entity *e = Entity::GetEntityOrphans(); e; e = e->GetSuccessor()) {
|
||||
e->EnumerateVisible(s_objectsVisible);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************* Update *******************************/
|
||||
|
||||
static vector<Object*> _objsByType[1000];
|
||||
|
||||
static vector<ObjCollision*> free_colls, used_colls;
|
||||
|
||||
static ObjCollision *allocObjColl(Object *with, const Vector &coords, const Collision &coll) {
|
||||
ObjCollision *c;
|
||||
if (free_colls.size()) {
|
||||
c = free_colls.back();
|
||||
free_colls.pop_back();
|
||||
} else {
|
||||
c = new ObjCollision();
|
||||
}
|
||||
used_colls.push_back(c);
|
||||
c->with = with;
|
||||
c->coords = coords;
|
||||
c->collision = coll;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void collided(Object *src, Object *dest, const Line &line, const Collision &coll, float y_scale) {
|
||||
|
||||
ObjCollision *c;
|
||||
const Vector &coords = line*coll.time - coll.normal*src->getCollisionRadii().x;
|
||||
|
||||
c = allocObjColl(dest, coords, coll);
|
||||
c->coords.y *= y_scale;
|
||||
src->addCollision(c);
|
||||
|
||||
c = allocObjColl(src, coords, coll);
|
||||
c->coords.y *= y_scale;
|
||||
dest->addCollision(c);
|
||||
}
|
||||
|
||||
void World::clearCollisions() {
|
||||
for (int k = 0; k < 1000; ++k) {
|
||||
_collInfo[k].clear();
|
||||
}
|
||||
}
|
||||
|
||||
void World::addCollision(int src_type, int dst_type, int method, int response) {
|
||||
|
||||
vector<CollInfo> &info = _collInfo[src_type];
|
||||
for (size_t k = 0; k < info.size(); ++k) {
|
||||
const CollInfo &t = info[k];
|
||||
if (dst_type == t.dst_type) return;
|
||||
}
|
||||
|
||||
CollInfo co = { dst_type,method,response };
|
||||
_collInfo[src_type].push_back(co);
|
||||
}
|
||||
|
||||
bool World::hitTest(const Line &line, float radius, Object *obj, const Transform &tf, int method, Collision *curr_coll) {
|
||||
switch (method) {
|
||||
case COLLISION_METHOD_SPHERE:
|
||||
return curr_coll->sphereCollide(line, radius, tf.v, obj->getCollisionRadii().x);
|
||||
case COLLISION_METHOD_POLYGON:
|
||||
return obj->collide(line, radius, curr_coll, tf);
|
||||
case COLLISION_METHOD_BOX:
|
||||
Transform t = tf;
|
||||
t.m.i.normalize(); t.m.j.normalize(); t.m.k.normalize();
|
||||
if (curr_coll->boxCollide(~t*line, radius, obj->getCollisionBox())) {
|
||||
curr_coll->normal = t.m*curr_coll->normal;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool World::CheckLineOfSight(Object *src, Object *dest) {
|
||||
|
||||
StaticEnumerateEnabled();
|
||||
|
||||
Object *coll_obj = 0;
|
||||
Collision curr_coll;
|
||||
|
||||
Line line(src->GetWorldPosition(), dest->GetWorldPosition() - src->GetWorldPosition());
|
||||
|
||||
for (Object* obj : s_objectsEnabled) {
|
||||
if (obj == src || obj == dest || !obj->getPickGeometry() || !obj->getObscurer()) continue;
|
||||
|
||||
if (hitTest(line, 0, obj, obj->GetWorldTransform(), obj->getPickGeometry(), &curr_coll)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Object *World::traceRay(const Line &line, float radius, ObjCollision *curr_coll) {
|
||||
|
||||
StaticEnumerateEnabled();
|
||||
|
||||
Object *coll_obj = 0;
|
||||
|
||||
for (Object* obj : s_objectsEnabled) {
|
||||
|
||||
if (!obj->getPickGeometry()) continue;
|
||||
|
||||
if (hitTest(line, radius, obj, obj->GetWorldTransform(), obj->getPickGeometry(), &curr_coll->collision)) {
|
||||
coll_obj = obj;
|
||||
}
|
||||
}
|
||||
if (curr_coll->with = coll_obj) {
|
||||
curr_coll->coords = line*curr_coll->collision.time - curr_coll->collision.normal*radius;
|
||||
}
|
||||
return coll_obj;
|
||||
}
|
||||
|
||||
//
|
||||
// NEW VERSION
|
||||
//
|
||||
void World::collide(Object *src) {
|
||||
Vector dv = src->GetWorldTransform().v;
|
||||
Vector sv = src->getPrevWorldTform().v;
|
||||
|
||||
if (sv == dv) {
|
||||
if (dv.x != sv.x || dv.y != sv.y || dv.z != sv.z) {
|
||||
src->SetWorldPosition(sv);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Vector panic = sv;
|
||||
|
||||
static Transform y_tform;
|
||||
|
||||
const Vector &radii = src->getCollisionRadii();
|
||||
|
||||
float radius = radii.x, inv_y_scale;
|
||||
float y_scale = inv_y_scale = y_tform.m.j.y = 1;
|
||||
|
||||
if (radii.x != radii.y) {
|
||||
y_scale = y_tform.m.j.y = radius / radii.y;
|
||||
inv_y_scale = 1 / y_scale;
|
||||
sv.y *= y_scale;
|
||||
dv.y *= y_scale;
|
||||
}
|
||||
|
||||
int n_hit = 0;
|
||||
Plane planes[2];
|
||||
Line coll_line(sv, dv - sv);
|
||||
Vector dir = coll_line.d;
|
||||
|
||||
float td = coll_line.d.length();
|
||||
float td_xz = Vector(coll_line.d.x, 0, coll_line.d.z).length();
|
||||
|
||||
const vector<CollInfo> &collinfos = _collInfo[src->getCollisionType()];
|
||||
|
||||
int hits = 0;
|
||||
for (;;) {
|
||||
Collision coll;
|
||||
Object *coll_obj = 0;
|
||||
vector<CollInfo>::const_iterator coll_it, coll_info;
|
||||
|
||||
for (coll_it = collinfos.begin(); coll_it != collinfos.end(); ++coll_it) {
|
||||
// const std::list<Object*> &dst_objs = _objsByType[coll_it->dst_type];
|
||||
for (Object* dst : /*dst_objs*/_objsByType[coll_it->dst_type]) {
|
||||
|
||||
if (src == dst) continue;
|
||||
|
||||
const Transform &dst_tform = dst->getPrevWorldTform();
|
||||
|
||||
if (y_scale == 1) {
|
||||
if (hitTest(
|
||||
coll_line, radius, dst, dst_tform,
|
||||
coll_it->method, &coll)) {
|
||||
coll_obj = dst;
|
||||
coll_info = coll_it;
|
||||
}
|
||||
} else {
|
||||
if (hitTest(
|
||||
coll_line, radius, dst, y_tform * dst_tform,
|
||||
coll_it->method, &coll)) {
|
||||
coll_obj = dst;
|
||||
coll_info = coll_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!coll_obj) break;
|
||||
|
||||
//register collision
|
||||
if (++hits == WORLD_COLLISION_HITS) {
|
||||
// exit(0);
|
||||
break;
|
||||
}
|
||||
|
||||
collided(src, coll_obj, coll_line, coll, inv_y_scale);
|
||||
|
||||
Plane coll_plane(coll_line*coll.time, coll.normal);
|
||||
|
||||
coll_plane.d -= COLLISION_FLT_EPSILON;
|
||||
coll.time = coll_plane.t_intersect(coll_line);
|
||||
|
||||
if (coll.time > 0) {// && fabs(coll.normal.dot( coll_line.d ))>FLT_EPSILON ){
|
||||
//update source position - ONLY IF AHEAD!
|
||||
sv = coll_line*coll.time;
|
||||
td *= 1 - coll.time;
|
||||
td_xz *= 1 - coll.time;
|
||||
}
|
||||
|
||||
if (coll_info->response == COLLISION_RESPONSE_STOP) {
|
||||
dv = sv;
|
||||
break;
|
||||
}
|
||||
|
||||
//find nearest point on plane to dest
|
||||
Vector nv = coll_plane.nearest(dv);
|
||||
|
||||
if (n_hit == 0) {
|
||||
dv = nv;
|
||||
} else if (n_hit == 1) {
|
||||
if (planes[0].distance(nv) >= 0) {
|
||||
dv = nv; n_hit = 0;
|
||||
} else if (fabs(planes[0].n.dot(coll_plane.n)) < 1 - FLT_EPSILON) {
|
||||
dv = coll_plane.intersect(planes[0]).nearest(dv);
|
||||
} else {
|
||||
//SQUISHED!
|
||||
//exit(0);
|
||||
hits = WORLD_COLLISION_HITS; break;
|
||||
}
|
||||
} else if (planes[0].distance(nv) >= 0 && planes[1].distance(nv) >= 0) {
|
||||
dv = nv; n_hit = 0;
|
||||
} else {
|
||||
dv = sv; break;
|
||||
}
|
||||
|
||||
Vector dd(dv - sv);
|
||||
|
||||
//going behind initial direction? really necessary?
|
||||
if (dd.dot(dir) <= 0) { dv = sv; break; }
|
||||
|
||||
if (coll_info->response == COLLISION_RESPONSE_SLIDE) {
|
||||
float d = dd.length();
|
||||
if (d <= FLT_EPSILON) { dv = sv; break; }
|
||||
if (d > td) dd *= td / d;
|
||||
} else if (coll_info->response == COLLISION_RESPONSE_SLIDEXZ) {
|
||||
float d = Vector(dd.x, 0, dd.z).length();
|
||||
if (d <= FLT_EPSILON) { dv = sv; break; }
|
||||
if (d > td_xz) dd *= td_xz / d;
|
||||
}
|
||||
|
||||
coll_line.o = sv;
|
||||
coll_line.d = dd; dv = sv + dd;
|
||||
planes[n_hit++] = coll_plane;
|
||||
}
|
||||
|
||||
if (hits) {
|
||||
if (hits < WORLD_COLLISION_HITS) {
|
||||
dv.y *= inv_y_scale;
|
||||
src->SetWorldPosition(dv);
|
||||
} else {
|
||||
src->SetWorldPosition(panic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
//
|
||||
// OLD VERSION
|
||||
//
|
||||
void World::collide( Object *src ){
|
||||
|
||||
static const int MAX_HITS=100;
|
||||
|
||||
Vector dv=src->getWorldTform().v;
|
||||
Vector sv=src->getPrevWorldTform().v;
|
||||
|
||||
if( sv==dv ){
|
||||
if( dv.x!=sv.x || dv.y!=sv.y || dv.z!=sv.z ){
|
||||
src->setWorldPosition( sv );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Vector panic=sv;
|
||||
|
||||
static Transform y_tform;
|
||||
|
||||
const Vector &radii=src->getCollisionRadii();
|
||||
|
||||
float radius=radii.x,inv_y_scale;
|
||||
float y_scale=inv_y_scale=y_tform.m.j.y=1;
|
||||
|
||||
if( radii.x!=radii.y ){
|
||||
y_scale=y_tform.m.j.y=radius/radii.y;
|
||||
inv_y_scale=1/y_scale;
|
||||
sv.y*=y_scale;
|
||||
dv.y*=y_scale;
|
||||
}
|
||||
|
||||
int n_hit=0;
|
||||
Plane planes[2];
|
||||
Line coll_line( sv,dv-sv );
|
||||
Vector dir=coll_line.d;
|
||||
|
||||
float td=coll_line.d.length();
|
||||
float td_xz=Vector( coll_line.d.x,0,coll_line.d.z ).length();
|
||||
|
||||
const vector<CollInfo> &collinfos=_collInfo[src->getCollisionType()];
|
||||
|
||||
int hits=0;
|
||||
while( hits<MAX_HITS ){
|
||||
|
||||
Collision coll;
|
||||
Object *coll_obj=0;
|
||||
vector<CollInfo>::const_iterator coll_it,coll_info;
|
||||
|
||||
for( coll_it=collinfos.begin();coll_it!=collinfos.end();++coll_it ){
|
||||
|
||||
vector<Object*>::const_iterator dst_it;
|
||||
|
||||
const vector<Object*> &dst_objs=_objsByType[coll_it->dst_type];
|
||||
|
||||
for( dst_it=dst_objs.begin();dst_it!=dst_objs.end();++dst_it ){
|
||||
|
||||
Object *dst=*dst_it;
|
||||
|
||||
if( src==dst ) continue;
|
||||
|
||||
const Transform &dst_tform=dst->getPrevWorldTform();
|
||||
|
||||
if( y_scale==1 ){
|
||||
|
||||
if( hitTest(
|
||||
coll_line,radius,dst,dst_tform,
|
||||
coll_it->method,&coll ) ){
|
||||
coll_obj=dst;
|
||||
coll_info=coll_it;
|
||||
}
|
||||
}else{
|
||||
|
||||
if( hitTest(
|
||||
coll_line,radius,dst,y_tform * dst_tform,
|
||||
coll_it->method,&coll ) ){
|
||||
coll_obj=dst;
|
||||
coll_info=coll_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( !coll_obj ) break;
|
||||
|
||||
//register collision
|
||||
++hits;
|
||||
collided( src,coll_obj,coll_line,coll,inv_y_scale );
|
||||
|
||||
//create collision plane
|
||||
Plane coll_plane( coll_line*coll.time,coll.normal );
|
||||
|
||||
//move plane out a bit (cough)
|
||||
coll_plane.d-=.001f;
|
||||
|
||||
if( fabs(coll.normal.dot( coll_line.d ))>FLT_EPSILON ){
|
||||
float t=coll_plane.t_intersect( coll_line );
|
||||
//update source position - ONLY IF AHEAD!
|
||||
if( t>0 ){
|
||||
sv=coll_line*t;
|
||||
td*=1-coll.time;
|
||||
td_xz*=1-coll.time;
|
||||
}
|
||||
}
|
||||
|
||||
//STOP?
|
||||
if( coll_info->response==COLLISION_RESPONSE_STOP ){
|
||||
dv=sv;
|
||||
break;
|
||||
}
|
||||
|
||||
//find nearest point on plane to dest
|
||||
Vector nv=coll_plane.nearest( dv );
|
||||
|
||||
//SLIDE!
|
||||
if( n_hit==0 ){
|
||||
dv=nv;
|
||||
}else if( n_hit==1 ){
|
||||
if( planes[0].distance(nv)>=0 ){
|
||||
dv=nv;n_hit=0;
|
||||
}else if( fabs( planes[0].n.dot( coll_plane.n ) )<1-FLT_EPSILON ){
|
||||
dv=coll_plane.intersect( planes[0] ).nearest( dv );
|
||||
}else{
|
||||
hits=MAX_HITS;break;
|
||||
}
|
||||
}else if( planes[0].distance(nv)>=0 && planes[1].distance(nv)>=0 ){
|
||||
dv=nv;n_hit=0;
|
||||
}else{
|
||||
dv=sv;break;
|
||||
}
|
||||
|
||||
Vector dd( dv-sv );
|
||||
|
||||
//going behind initial direction? really necessary?
|
||||
if( dd.dot( dir )<=0 ){ dv=sv;break; }
|
||||
|
||||
if( coll_info->response==COLLISION_RESPONSE_SLIDE ){
|
||||
float d=dd.length();
|
||||
if( d<=FLT_EPSILON ){ dv=sv;break; }
|
||||
if( d>td ) dd*=td/d;
|
||||
}else if( coll_info->response==COLLISION_RESPONSE_SLIDEXZ ){
|
||||
float d=Vector( dd.x,0,dd.z ).length();
|
||||
if( d<=FLT_EPSILON ){ dv=sv;break; }
|
||||
if( d>td_xz ) dd*=td_xz/d;
|
||||
}
|
||||
|
||||
coll_line.o=sv;
|
||||
coll_line.d=dd;dv=sv+dd;
|
||||
planes[n_hit++]=coll_plane;
|
||||
}
|
||||
|
||||
if( hits ){
|
||||
if( hits<MAX_HITS ){
|
||||
dv.y*=inv_y_scale;
|
||||
src->setWorldPosition( dv );
|
||||
}else{
|
||||
src->setWorldPosition( panic );
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void World::update(float elapsed) {
|
||||
|
||||
stats3d[0] = 0;
|
||||
|
||||
for (; used_colls.size(); used_colls.pop_back()) {
|
||||
free_colls.push_back(used_colls.back());
|
||||
}
|
||||
|
||||
StaticEnumerateEnabled();
|
||||
|
||||
for (Object* o : s_objectsEnabled) {
|
||||
if (int n = o->getCollisionType()) {
|
||||
_objsByTypeSwappable[n].push_back(o);
|
||||
}
|
||||
|
||||
o->beginUpdate(elapsed);
|
||||
if (o->getCollisionType()) collide(o);
|
||||
o->endUpdate();
|
||||
}
|
||||
|
||||
for (int k = 0; k < WORLD_COLLISION_TYPES; ++k) {
|
||||
_objsByTypeSwappable[k].swap(_objsByType[k]);
|
||||
_objsByTypeSwappable[k].clear();
|
||||
}
|
||||
}
|
||||
|
||||
/****************************** Render *********************************/
|
||||
|
||||
static Transform cam_tform; //current camera transform
|
||||
|
||||
static vector<gxLight*> _lights;
|
||||
static vector<Mirror*> _mirrors;
|
||||
static vector<Listener*> _listeners;
|
||||
|
||||
struct OrderComp {
|
||||
bool operator()(Object *a, Object *b) {
|
||||
return a->getOrder() < b->getOrder();
|
||||
}
|
||||
};
|
||||
|
||||
struct TransComp {
|
||||
bool operator()(Model *a, Model *b)const {
|
||||
return
|
||||
cam_tform.v.distance(a->getRenderTform().v) <
|
||||
cam_tform.v.distance(b->getRenderTform().v);
|
||||
}
|
||||
};
|
||||
|
||||
static vector<Model*> ord_mods, unord_mods;
|
||||
|
||||
static priority_queue<Model*, vector<Model*>, OrderComp> ord_que;
|
||||
|
||||
static priority_queue<Camera*, vector<Camera*>, OrderComp> cam_que;
|
||||
|
||||
static priority_queue<Model*, vector<Model*>, TransComp> transparents;
|
||||
|
||||
void World::capture() {
|
||||
|
||||
StaticEnumerateVisible();
|
||||
|
||||
for (Object* o : s_objectsVisible) {
|
||||
o->capture();
|
||||
}
|
||||
}
|
||||
|
||||
void World::render(float tween) {
|
||||
|
||||
//set render tweens, and build ordered and unordered model lists...
|
||||
ord_mods.clear();
|
||||
unord_mods.clear();
|
||||
|
||||
s_objectsVisible.clear();
|
||||
_lights.clear();
|
||||
_mirrors.clear();
|
||||
_listeners.clear();
|
||||
|
||||
StaticEnumerateVisible();
|
||||
|
||||
for (Object* o : s_objectsVisible) {
|
||||
if (!o->beginRender(tween)) continue;
|
||||
|
||||
if (Light *t = o->getLight()) _lights.push_back(t->getGxLight());
|
||||
else if (Camera *t = o->getCamera()) cam_que.push(t);
|
||||
else if (Mirror *t = o->getMirror()) _mirrors.push_back(t);
|
||||
else if (Listener *t = o->getListener()) _listeners.push_back(t);
|
||||
else if (Model *t = o->getModel()) {
|
||||
if (t->getOrder()) ord_que.push(t);
|
||||
else unord_mods.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
for (; ord_que.size(); ord_que.pop()) ord_mods.push_back(ord_que.top());
|
||||
|
||||
// gx_runtime->debugLog( "RenderWorld" );
|
||||
|
||||
if (!gx_scene->begin(_lights)) return;
|
||||
|
||||
for (; cam_que.size(); cam_que.pop()) {
|
||||
|
||||
Camera *cam = cam_que.top();
|
||||
|
||||
if (!cam->beginRenderFrame()) continue;
|
||||
|
||||
vector<Mirror*>::const_iterator mir_it;
|
||||
for (mir_it = _mirrors.begin(); mir_it != _mirrors.end(); ++mir_it) {
|
||||
render(cam, *mir_it);
|
||||
}
|
||||
|
||||
render(cam, 0);
|
||||
}
|
||||
|
||||
gx_scene->end();
|
||||
|
||||
// gx_runtime->debugLog( "End RenderWorld" );
|
||||
|
||||
vector<Listener*>::const_iterator lis_it;
|
||||
for (lis_it = _listeners.begin(); lis_it != _listeners.end(); ++lis_it) {
|
||||
(*lis_it)->renderListener();
|
||||
}
|
||||
}
|
||||
|
||||
void World::render(Camera *cam, Mirror *mirror) {
|
||||
|
||||
if (mirror) {
|
||||
const Transform &t = mirror->getRenderTform();
|
||||
cam_tform = t * Transform(scaleMatrix(1, -1, 1)) * -t * cam->getRenderTform();
|
||||
gx_scene->setFlippedTris(true);
|
||||
} else {
|
||||
cam_tform = cam->getRenderTform();
|
||||
gx_scene->setFlippedTris(false);
|
||||
}
|
||||
|
||||
//set camera matrix
|
||||
gx_scene->setViewMatrix((gxScene::Matrix*)&(-cam_tform));
|
||||
|
||||
//initialize render context
|
||||
RenderContext rc(cam_tform, cam->getFrustum(), mirror != 0);
|
||||
|
||||
//draw everything in order
|
||||
size_t ord = 0;
|
||||
gx_scene->setZMode(gxScene::ZMODE_DISABLE);
|
||||
while (ord < ord_mods.size() && ord_mods[ord]->getOrder()>0) {
|
||||
Model *mod = ord_mods[ord++];
|
||||
if (!mod->doAutoFade(cam_tform.v)) continue;
|
||||
render(mod, rc);
|
||||
flushTransparent();
|
||||
}
|
||||
|
||||
gx_scene->setZMode(gxScene::ZMODE_NORMAL);
|
||||
for (size_t k = 0; k < unord_mods.size(); ++k) {
|
||||
Model *mod = unord_mods[k];
|
||||
if (!mod->doAutoFade(cam_tform.v)) continue;
|
||||
render(mod, rc);
|
||||
}
|
||||
gx_scene->setZMode(gxScene::ZMODE_CMPONLY);
|
||||
flushTransparent();
|
||||
|
||||
gx_scene->setZMode(gxScene::ZMODE_DISABLE);
|
||||
while (ord < ord_mods.size()) {
|
||||
Model *mod = ord_mods[ord++];
|
||||
if (!mod->doAutoFade(cam_tform.v)) continue;
|
||||
render(mod, rc);
|
||||
flushTransparent();
|
||||
}
|
||||
}
|
||||
|
||||
void World::render(Model *mod, const RenderContext &rc) {
|
||||
|
||||
bool trans = mod->render(rc);
|
||||
|
||||
if (mod->queueSize(Model::QUEUE_OPAQUE)) {
|
||||
if (mod->getRenderSpace() == Model::RENDER_SPACE_LOCAL) {
|
||||
gx_scene->setWorldMatrix((gxScene::Matrix*)&mod->getRenderTform());
|
||||
} else {
|
||||
gx_scene->setWorldMatrix(0);
|
||||
}
|
||||
mod->renderQueue(Model::QUEUE_OPAQUE);
|
||||
}
|
||||
|
||||
if (trans || mod->queueSize(Model::QUEUE_TRANSPARENT)) {
|
||||
transparents.push(mod);
|
||||
}
|
||||
}
|
||||
|
||||
void World::flushTransparent() {
|
||||
|
||||
bool local = true;
|
||||
|
||||
for (; transparents.size(); transparents.pop()) {
|
||||
Model *mod = transparents.top();
|
||||
if (mod->getRenderSpace() == Model::RENDER_SPACE_LOCAL) {
|
||||
gx_scene->setWorldMatrix((gxScene::Matrix*)&mod->getRenderTform());
|
||||
local = true;
|
||||
} else if (local) {
|
||||
gx_scene->setWorldMatrix(0);
|
||||
local = false;
|
||||
}
|
||||
mod->renderQueue(Model::QUEUE_TRANSPARENT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
#ifndef WORLD_H
|
||||
#define WORLD_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "model.hpp"
|
||||
#include "camera.hpp"
|
||||
#include "light.hpp"
|
||||
#include "mirror.hpp"
|
||||
#include "listener.hpp"
|
||||
|
||||
#define WORLD_COLLISION_TYPES 16
|
||||
#define WORLD_COLLISION_HITS 4
|
||||
|
||||
class World{
|
||||
public:
|
||||
//collision methods
|
||||
enum{
|
||||
COLLISION_METHOD_SPHERE=1,
|
||||
COLLISION_METHOD_POLYGON=2,
|
||||
COLLISION_METHOD_BOX=3
|
||||
};
|
||||
|
||||
//collision actions
|
||||
enum{
|
||||
COLLISION_RESPONSE_NONE=0,
|
||||
COLLISION_RESPONSE_STOP=1,
|
||||
COLLISION_RESPONSE_SLIDE=2,
|
||||
COLLISION_RESPONSE_SLIDEXZ=3,
|
||||
};
|
||||
|
||||
void clearCollisions();
|
||||
void addCollision( int src_type,int dest_type,int method,int response );
|
||||
|
||||
void update( float elapsed );
|
||||
void capture();
|
||||
void render( float tween );
|
||||
|
||||
bool CheckLineOfSight( Object *src,Object *dest );
|
||||
bool hitTest( const Line &line,float radius,Object *obj,const Transform &tf,int method,Collision *curr_coll );
|
||||
Object *traceRay( const Line &line,float radius,ObjCollision *curr_coll );
|
||||
|
||||
private:
|
||||
struct CollInfo{
|
||||
int dst_type,method,response;
|
||||
};
|
||||
|
||||
vector<CollInfo> _collInfo[WORLD_COLLISION_TYPES];
|
||||
std::list<Object*> _objsByType[WORLD_COLLISION_TYPES];
|
||||
std::list<Object*> _objsByTypeSwappable[WORLD_COLLISION_TYPES];
|
||||
|
||||
void collide( Object *src );
|
||||
void render( Camera *c,Mirror *m );
|
||||
void render( Model *m,const RenderContext &rc );
|
||||
void flushTransparent();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user