Commit d73a166d authored by IOhannes m zmölnig's avatar IOhannes m zmölnig
Browse files

re-implemented multimodel with the modelloader-plugins

it performs worse than the original code, though
(as the openGL-compilation is done whenever you switch to a new object, rather than once)
parent 8e0ab831
......@@ -13,13 +13,12 @@
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "multimodel.h"
#include "Gem/State.h"
#include <stdio.h>
#ifdef _MSC_VER
# define snprintf _snprintf
#endif
#include "plugins/modelloader.h"
#include <algorithm> // std::min
#include <string.h>
CPPEXTERN_NEW_WITH_FOUR_ARGS(multimodel, t_symbol *, A_DEFSYM, t_floatarg, A_DEFFLOAT, t_floatarg, A_DEFFLOAT, t_floatarg, A_DEFFLOAT);
......@@ -33,62 +32,224 @@ CPPEXTERN_NEW_WITH_FOUR_ARGS(multimodel, t_symbol *, A_DEFSYM, t_floatarg, A_DEF
/////////////////////////////////////////////////////////
multimodel :: multimodel(t_symbol *filename, t_floatarg baseModel,
t_floatarg topModel, t_floatarg skipRate)
: m_curModel(-1),
m_currentH(1.f), m_currentW(1.f)
: m_loader(NULL),
m_size_change_flag(false),
m_position(256,3),
m_texture (256,2),
m_color (256,4),
m_normal (256,3),
m_infoOut(gem::RTE::Outlet(this))
{
inlet_new(this->x_obj, &this->x_obj->ob_pd, &s_float, gensym("mdl_num"));
post("MULTIMODEL");
// make sure that there are some characters
if (filename->s_name[0])
if (filename&&filename->s_name&&*filename->s_name)
openMess(filename->s_name, baseModel, topModel, skipRate);
}
////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
multimodel :: ~multimodel()
multimodel :: ~multimodel(void)
{
cleanMultimodel();
close();
}
void multimodel :: openMess(const std::string&filename,
float baseModel, float topModel, float skipRate)
{
int skipRatei=static_cast<int>(skipRate);
int topModeli=static_cast<int>(topModel);
int baseModeli=static_cast<int>(baseModel);
if (skipRatei == 0) {
if (topModeli == 0)
open(filename, 0, baseModeli, 1);
else
open(filename, baseModeli, topModeli, 1);
}
else open(filename, baseModeli, topModeli, skipRatei);
}
/////////////////////////////////////////////////////////
// cleanMultimodel
// close
//
/////////////////////////////////////////////////////////
void multimodel :: cleanMultimodel(void)
void multimodel :: close(void)
{
unsigned int i;
for(i=0; i<m_loaders.size(); i++) {
if (m_loaders[i])
if (m_loaders[i]) {
m_loaders[i]->close();
delete m_loaders[i];
}
m_loaders[i]=NULL;
}
m_loaders.clear();
m_loader = NULL;
}
void multimodel :: applyProperties(void)
{
#if 0
std::vector<std::string>keys=m_properties.keys();
unsigned int i;
for(i=0; i<keys.size(); i++) {
post("key[%d]=%s ... %d", i, keys[i].c_str(), m_properties.type(keys[i]));
}
#endif
if(m_loader)
m_loader->setProperties(m_properties);
}
/////////////////////////////////////////////////////////
// open
// materialMess
//
/////////////////////////////////////////////////////////
void multimodel :: materialMess(int material)
{
gem::any value=material;
m_properties.set("usematerials", value);
applyProperties();
}
/////////////////////////////////////////////////////////
// materialMess
//
/////////////////////////////////////////////////////////
void multimodel :: textureMess(int state)
{
std::string textype;
switch(state) {
case 0:
textype="linear";
break;
case 1:
textype="spheremap";
break;
case 2:
textype="UV";
break;
default:
break;
}
if(textype.empty()) {
m_properties.erase("textype");
} else {
gem::any value=textype;
m_properties.set("textype", value);
}
applyProperties();
}
/////////////////////////////////////////////////////////
// smoothMess
//
/////////////////////////////////////////////////////////
void multimodel :: smoothMess(t_float fsmooth)
{
m_properties.set("smooth", fsmooth);
applyProperties();
}
/////////////////////////////////////////////////////////
// rescaleMess
//
/////////////////////////////////////////////////////////
void multimodel :: reverseMess(bool reverse)
{
gem::any value=(double)reverse;
m_properties.set("reverse", value);
applyProperties();
}
/////////////////////////////////////////////////////////
// matrialMess
//
/////////////////////////////////////////////////////////
void multimodel :: rescaleMess(bool state)
{
gem::any value=(double)state;
m_properties.set("rescale", value);
applyProperties();
}
/////////////////////////////////////////////////////////
// matrialMess
//
/////////////////////////////////////////////////////////
void multimodel :: groupMess(int state)
{
gem::any value=state;
m_properties.set("group", value);
applyProperties();
}
/////////////////////////////////////////////////////////
// backendMess
//
/////////////////////////////////////////////////////////
void multimodel :: backendMess(t_symbol*s, int argc, t_atom*argv)
{
#if 0
gem::any value=ids;
m_properties.set("backends", value);
applyProperties();
#endif
int i;
m_backends.clear();
if(argc) {
for(i=0; i<argc; i++) {
if(A_SYMBOL == argv->a_type) {
t_symbol *b=atom_getsymbol(argv+i);
m_backends.push_back(b->s_name);
} else {
error("%s must be symbolic", s->s_name);
}
}
} else {
/* no backend requested, just enumerate them */
if(m_loader) {
std::vector<gem::any>atoms;
gem::any value;
t_atom at;
t_atom*ap=&at;
gem::Properties props;
std::vector<std::string> backends;
props.set("backends", value);
m_loader->getProperties(props);
if(props.type("backends")!=gem::Properties::UNSET) {
props.get("backends", backends);
}
atoms.clear();
atoms.push_back(value=(int)(backends.size()));
m_infoOut.send("loaders", atoms);
if(!backends.empty()) {
for(i=0; i<backends.size(); i++) {
atoms.clear();
atoms.push_back(value=backends[i]);
post("loader[%d] %s", i, backends[i].c_str());
m_infoOut.send("loader", atoms);
}
} else {
post("no model-loading backends found!");
}
}
}
}
/////////////////////////////////////////////////////////
// openMess
//
/////////////////////////////////////////////////////////
void multimodel :: openMess(const std::string&filename,
float baseModel, float topModel, float skipRate)
{
int skipRatei=static_cast<int>(skipRate);
int topModeli=static_cast<int>(topModel);
int baseModeli=static_cast<int>(baseModel);
if (skipRatei == 0) {
if (topModeli == 0)
open(filename, 0, baseModeli, 1);
else
open(filename, baseModeli, topModeli, 1);
}
else open(filename, baseModeli, topModeli, skipRatei);
}
void multimodel :: open(const std::string&filename, int baseModel, int topModel, int skipRate)
{
gem::Properties wantProps = m_properties;
if(!m_backends.empty()) {
wantProps.set("backends", m_backends);
}
std::vector<gem::plugins::modelloader*>loaders;
if (!topModel) {
......@@ -137,7 +298,7 @@ void multimodel :: open(const std::string&filename, int baseModel, int topModel,
gem::plugins::modelloader*loader=gem::plugins::modelloader::getInstance();
if(!loader) break;
if(loader->open(newName, m_properties))
if(loader->open(newName, wantProps))
loaders.push_back(loader);
else {
delete loader;
......@@ -146,7 +307,7 @@ void multimodel :: open(const std::string&filename, int baseModel, int topModel,
}
if(loaders.size()!=numModels) {
/* outch, something went wrong! */
/* ouch, something went wrong! */
error("failed to load model#%d of %d (%s)...resetting to original models", i, numModels, newName);
unsigned int ui;
for(ui=0; ui<loaders.size(); ui++) {
......@@ -158,109 +319,96 @@ void multimodel :: open(const std::string&filename, int baseModel, int topModel,
return;
}
cleanMultimodel();
close();
m_loaders=loaders;
m_curModel = 0;
if(m_loaders.size()>0)
m_loader = m_loaders[0];
post("loaded models: %s %s from %d to %d skipping %d",
bufName, postName, baseModel, topModel, skipRate);
setModified();
}
void multimodel :: applyProperties(void)
{
unsigned int i;
for(i=0; i<m_loaders.size(); i++) {
if(m_loaders[i])
m_loaders[i]->setProperties(m_properties);
}
getVBOarray();
setModified();
}
/////////////////////////////////////////////////////////
// materialMess
// changeModel
//
/////////////////////////////////////////////////////////
void multimodel :: textureMess(int state)
void multimodel :: changeModel(int modelNum)
{
std::string textype;
switch(state) {
case 0:
textype="linear";
break;
case 1:
textype="spheremap";
break;
case 2:
textype="UV";
break;
default:
break;
}
if(textype.empty()) {
m_properties.erase("textype");
} else {
gem::any value=textype;
m_properties.set("textype", value);
if (modelNum < 0 || ((unsigned int)modelNum) >= m_loaders.size()) {
error("selection %d out of range: 0..%d", modelNum, m_loaders.size()-1);
return;
}
applyProperties();
}
m_loader = m_loaders[modelNum];
/////////////////////////////////////////////////////////
// smoothMess
//
/////////////////////////////////////////////////////////
void multimodel :: smoothMess(float fsmooth)
{
m_properties.set("smooth", fsmooth);
applyProperties();
getVBOarray();
setModified();
}
/////////////////////////////////////////////////////////
// matrialMess
//
/////////////////////////////////////////////////////////
void multimodel :: rescaleMess(bool state)
{
gem::any value=state;
m_properties.set("rescale", value);
applyProperties();
void multimodel :: startRendering() {
if (m_loader){
copyArray(m_loader->getVector("vertices"), m_position);
copyArray(m_loader->getVector("texcoords"), m_texture);
copyArray(m_loader->getVector("normals"), m_normal);
copyArray(m_loader->getVector("colors"), m_color);
}
}
/////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
void multimodel :: render(GemState *state)
{
if (0==m_loaders.size() || m_curModel<0 || ((unsigned int)m_curModel)>=m_loaders.size())
return;
if(!m_loader)return;
if ( !m_position.vbo || !m_texture.vbo || !m_color.vbo || !m_normal.vbo || m_size_change_flag ) {
createVBO();
m_size_change_flag = false;
}
getVBOarray();
if (state && (m_currentH != state->texCoordX(2) || m_currentW != state->texCoordY(2))) {
m_currentH = state->texCoordX(2);
m_currentW = state->texCoordY(2);
std::vector<unsigned int> sizeList;
m_properties.set("texwidth", m_currentW);
m_properties.set("texheight", m_currentH);
applyProperties();
if(m_position.render()) {
glVertexPointer(m_position.dimen, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
sizeList.push_back(m_position.size);
}
if(m_texture.render()) {
glTexCoordPointer(m_texture.dimen, GL_FLOAT, 0, 0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
sizeList.push_back(m_texture.size);
}
if(m_color.render()) {
glColorPointer(m_color.dimen, GL_FLOAT, 0, 0);
glEnableClientState(GL_COLOR_ARRAY);
sizeList.push_back(m_color.size);
}
if(m_normal.render()) {
glNormalPointer(GL_FLOAT, 0, 0);
glEnableClientState(GL_NORMAL_ARRAY);
sizeList.push_back(m_normal.size);
}
#warning multimodel.render
//m_loaders[m_curModel]->render();
}
/////////////////////////////////////////////////////////
// changeModel
//
/////////////////////////////////////////////////////////
void multimodel :: changeModel(int modelNum)
{
if (modelNum < 0 || ((unsigned int)modelNum) >= m_loaders.size()) {
error("selection %d out of range: 0..%d", modelNum, m_loaders.size()-1);
return;
if ( sizeList.size() > 0 ) {
unsigned int npoints = *std::min_element(sizeList.begin(),sizeList.end());
glDrawArrays(GL_TRIANGLES, 0, npoints);
}
if ( m_position.enabled ) {
glDisableClientState(GL_VERTEX_ARRAY);
}
if ( m_color.enabled ) {
glDisableClientState(GL_COLOR_ARRAY);
}
if ( m_texture.enabled ) {
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
if ( m_normal.enabled ) {
glDisableClientState(GL_NORMAL_ARRAY);
}
m_curModel = modelNum;
// setModified();
}
/////////////////////////////////////////////////////////
......@@ -271,14 +419,90 @@ void multimodel :: obj_setupCallback(t_class *classPtr)
{
class_addmethod(classPtr, reinterpret_cast<t_method>(&multimodel::openMessCallback),
gensym("open"), A_SYMBOL, A_FLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
CPPEXTERN_MSG1(classPtr, "mdl_num", changeModel, int);
CPPEXTERN_MSG1(classPtr, "rescale", rescaleMess, bool);
CPPEXTERN_MSG1(classPtr, "texture", textureMess, int);
CPPEXTERN_MSG1(classPtr, "smooth", smoothMess, float);
CPPEXTERN_MSG1(classPtr, "revert", reverseMess, bool);
CPPEXTERN_MSG1(classPtr, "material", materialMess, int);
CPPEXTERN_MSG1(classPtr, "texture", textureMess, int);
CPPEXTERN_MSG1(classPtr, "group", groupMess, int);
CPPEXTERN_MSG (classPtr, "loader", backendMess);
}
void multimodel :: openMessCallback(void *data, t_symbol *filesymbol, t_float baseModel,
t_floatarg topModel, t_floatarg skipRate)
{
GetMyClass(data)->openMess(filesymbol->s_name, baseModel, topModel, skipRate);
}
void multimodel :: createVBO(void)
{
m_position.create();
m_texture .create();
m_color .create();
m_normal .create();
}
void multimodel :: copyArray(const std::vector<std::vector<float> > tab, gem::VertexBuffer&vb)
{
unsigned int size(0), i(0), npts(0);
//~std::vector<std::vector<float> > tab = m_loader->getVector(vectorName);
if ( tab.empty() ) return;
size=tab.size();
if(size!=vb.size) {
vb.resize(size);
m_size_change_flag=true;
}
for ( i = 0 ; i < size ; i++ ) {
for ( int j=0 ; j< std::min(vb.dimen,(unsigned int)tab[i].size()) ; j++) {
vb.array[i*vb.dimen + j] = tab[i][j];
}
}
vb.dirty=true;
vb.enabled=true;
}
void multimodel :: copyAllArrays(){
if (m_loader && m_loader->needRefresh()){
copyArray(m_loader->getVector("vertices"), m_position);
copyArray(m_loader->getVector("texcoords"), m_texture);
copyArray(m_loader->getVector("normals"), m_normal);
copyArray(m_loader->getVector("colors"), m_color);
m_loader->unsetRefresh();
}
}
void multimodel :: getVBOarray(){
if (m_loader && m_loader->needRefresh()){
std::vector<gem::plugins::modelloader::VBOarray> vboArray = m_loader->getVBOarray();
if ( vboArray.empty() ){
copyAllArrays();
} else {
for (int i = 0; i<vboArray.size(); i++){
switch (vboArray[i].type){
case gem::VertexBuffer::GEM_VBO_VERTICES:
copyArray(*vboArray[i].data, m_position);
break;
case gem::VertexBuffer::GEM_VBO_TEXCOORDS:
copyArray(*vboArray[i].data, m_texture);
break;
case gem::VertexBuffer::GEM_VBO_NORMALS:
copyArray(*vboArray[i].data, m_normal);
break;
case gem::VertexBuffer::GEM_VBO_COLORS:
copyArray(*vboArray[i].data, m_color);
break;
default:
error("VBO type %d not supported\n",vboArray[i].type);
}
}
m_loader->unsetRefresh();
}
}
}
......@@ -2,7 +2,7 @@
LOG
GEM - Graphics Environment for Multimedia
Load multiple images
read in a model file
Copyright (c) 1997-1999 Mark Danks. mark@danks.org
Copyright (c) Günther Geiger. geiger@epy.co.at
......@@ -16,30 +16,31 @@
#define _INCLUDE__GEM_GEOS_MULTIMODEL_H_
#include "Base/GemBase.h"
#include <string.h>
#include "plugins/modelloader.h"
#include "Gem/Properties.h"
#include "Gem/VertexBuffer.h"
#include "RTE/Outlet.h"
/*-----------------------------------------------------------------
-------------------------------------------------------------------
CLASS
multimodel
Load multiple models
read in a model file
DESCRIPTION
Inlet for a list - "multimodel"
"open" - the multimodel to set the object to
"open" - the RGB model to set the object to
-----------------------------------------------------------------*/
namespace gem { namespace plugins { class modelloader; };};
class GEM_EXTERN multimodel : public GemBase
{
CPPEXTERN_HEADER(multimodel, GemBase);
public:
public:
//////////
// Constructor
......@@ -49,45 +50,71 @@ class GEM_EXTERN multimodel : public GemBase
//////////
// Destructor
virtual ~multimodel();
virtual ~multimodel(void);
//////////
// When an open is received
virtual void openMess(const std::string&filename, float baseModel, float topModel, float skipRate);
virtual void open(const std::string&filename, int baseModel, int topModel, int skipRate);
virtual void openMess(const std::string&filename, float baseModel, float topModel, float skipRate);
virtual void open(const std::string&filename, int baseModel, int topModel, int skipRate);
//////////
virtual void render(GemState *state);