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

implementing multimodel with modelloader

this currently lacks the caching
caching used to work like this:
 if multiple instances of [multimodel] where opening exactly the same set of models,
 the would use the very same models / displaylists
 this means, that you cannot change the 'smoothness' in one [multimodel] without affecting the others
parent fb140d33
......@@ -19,8 +19,6 @@
CPPEXTERN_NEW_WITH_FOUR_ARGS(multimodel, t_symbol *, A_DEFSYM, t_floatarg, A_DEFFLOAT, t_floatarg, A_DEFFLOAT, t_floatarg, A_DEFFLOAT);
multimodel::multiModelCache *multimodel::s_modelCache = NULL;
/////////////////////////////////////////////////////////
//
// multimodel
......@@ -31,15 +29,11 @@ multimodel::multiModelCache *multimodel::s_modelCache = NULL;
/////////////////////////////////////////////////////////
multimodel :: multimodel(t_symbol *filename, t_floatarg baseModel,
t_floatarg topModel, t_floatarg skipRate)
: m_loadedCache(NULL),
m_numModels(0), m_curModel(-1),
m_rescaleModel(1),
m_textype(GLM_TEX_DEFAULT),
m_rebuild(true),
: m_curModel(-1),
m_currentH(1.f), m_currentW(1.f)
{
inlet_new(this->x_obj, &this->x_obj->ob_pd, &s_float, gensym("mdl_num"));
// make sure that there are some characters
if (filename->s_name[0]) {
int skipRatei=static_cast<int>(skipRate);
......@@ -47,11 +41,11 @@ multimodel :: multimodel(t_symbol *filename, t_floatarg baseModel,
int baseModeli=static_cast<int>(baseModel);
if (skipRatei == 0) {
if (topModeli == 0)
openMess(filename, 0, baseModeli, 1);
openMess(filename->s_name, 0, baseModeli, 1);
else
openMess(filename, baseModeli, topModeli, 1);
openMess(filename->s_name, baseModeli, topModeli, 1);
}
else openMess(filename, baseModeli, topModeli, skipRatei);
else openMess(filename->s_name, baseModeli, topModeli, skipRatei);
}
}
......@@ -61,51 +55,30 @@ multimodel :: multimodel(t_symbol *filename, t_floatarg baseModel,
/////////////////////////////////////////////////////////
multimodel :: ~multimodel()
{
cleanMultimodel();
}
/////////////////////////////////////////////////////////
// cleanMultimodel
//
/////////////////////////////////////////////////////////
void multimodel :: cleanMultimodel()
void multimodel :: cleanMultimodel(void)
{
if (m_numModels) {
// decrement the reference count
m_loadedCache->refCount--;
// If the refCount == 0, then destroy the cache
if (m_loadedCache->refCount == 0) {
// find the cache
multiModelCache *ptr = s_modelCache;
// if the loaded cache is the first cache in the list
if (m_loadedCache == s_modelCache) {
s_modelCache = m_loadedCache->next;
delete m_loadedCache;
}
else {
while (ptr && ptr->next != m_loadedCache) ptr = ptr->next;
if (!ptr) error("unable to find model cache!");
else {
ptr->next = m_loadedCache->next;
delete m_loadedCache;
}
}
}
m_loadedCache = NULL;
m_numModels = 0;
unsigned int i;
for(i=0; i<m_loaders.size(); i++) {
if (m_loaders[i])
delete m_loaders[i];
m_loaders[i]=NULL;
}
m_loaders.clear();
}
/////////////////////////////////////////////////////////
// openMess
//
/////////////////////////////////////////////////////////
void multimodel :: openMess(t_symbol *filename, int baseModel, int topModel, int skipRate)
void multimodel :: openMess(const std::string&filename, int baseModel, int topModel, int skipRate)
{
cleanMultimodel();
std::vector<gem::plugins::modelloader*>loaders;
if (!topModel) {
error("requires an int for number of models");
......@@ -116,36 +89,11 @@ void multimodel :: openMess(t_symbol *filename, int baseModel, int topModel, int
return;
}
if (skipRate < 1) skipRate = 1;
// have we already loaded the model?
multiModelCache *cache = s_modelCache;
int found = 0;
while (!found && cache) {
if (baseModel == cache->baseModel &&
topModel == cache->topModel &&
skipRate == cache->skipRate &&
!strcmp(filename->s_name, cache->modelName)) found = 1;
else cache = cache->next;
}
// yep, we have it
if (found) {
m_loadedCache = cache;
m_loadedCache->refCount++;
m_curModel = 0;
m_numModels = m_loadedCache->numModels;
post("loaded models: %s from %d to %d skipping %d",
filename->s_name, baseModel, topModel, skipRate);
return;
}
// nope, so create the new cache
// find the * in the filename
char preName[256];
char postName[256];
int i = 0;
char *strPtr = filename->s_name;
const char *strPtr = filename.c_str();
while (strPtr[i] && strPtr[i] != '*') {
preName[i] = strPtr[i];
i++;
......@@ -160,144 +108,125 @@ void multimodel :: openMess(t_symbol *filename, int baseModel, int topModel, int
strcpy(postName, &(strPtr[i+1]));
// need to figure out how many filenames there are to load
m_numModels = (topModel + 1 - baseModel) / skipRate;
// create the new cache
multiModelCache *newCache = new multiModelCache(filename->s_name);
newCache->models = new GLint[m_numModels];
newCache->realmodels = new GLMmodel*[m_numModels];
newCache->numModels = m_numModels;
newCache->baseModel = baseModel;
newCache->topModel = topModel;
newCache->skipRate = skipRate;
int numModels = (topModel + 1 - baseModel) / skipRate;
int realNum = baseModel;
char bufName[MAXPDSTRING];
canvas_makefilename(const_cast<t_canvas*>(getCanvas()), preName, bufName, MAXPDSTRING);
for (i = 0; i < m_numModels; i++, realNum += skipRate) {
for (i = 0; i < numModels; i++, realNum += skipRate) {
char newName[256];
sprintf(newName, "%s%d%s", bufName, realNum, postName);
// read the object in
GLMmodel *m_model = glmReadOBJ(newName);
if (!m_model) {
// a load failed, blow away the cache
newCache->numModels = i;
delete newCache;
m_numModels = 0;
return;
}
// set the size to -1 to 1
//
if (m_rescaleModel)
glmUnitize(m_model);
// generate normals if this
// object doesn't have them.
//
glmFacetNormals (m_model);
glmVertexNormals(m_model, 90); /* SMOOTH */
glmTexture(m_model, m_textype, 1, 1);
newCache->realmodels[i]=m_model;
loaders.push_back(gem::plugins::modelloader::getInstance());
if(!loaders[i])
break;
if(!loaders[i]->open(newName, m_properties))
break;
}
m_curModel = 0;
m_loadedCache = newCache;
newCache->refCount++;
if(loaders.size()!=numModels) {
/* outch, something went wrong! */
error("failed to load model#%d of %d...resetting to original models", i, numModels);
// insert the cache at the end of the linked list
multiModelCache *ptr = s_modelCache;
if (!ptr) s_modelCache = newCache;
else {
while(ptr->next) ptr = ptr->next;
ptr->next = newCache;
for(i=0; i<loaders.size(); i++) {
if(loaders[i])
delete loaders[i];
loaders[i]=NULL;
}
loaders.clear();
return;
}
cleanMultimodel();
m_loaders=loaders;
m_curModel = 0;
post("loaded models: %s %s from %d to %d skipping %d",
bufName, postName, baseModel, topModel, skipRate);
setModified();
}
/////////////////////////////////////////////////////////
// buildList
//
/////////////////////////////////////////////////////////
void multimodel :: buildList()
{
int i = m_numModels;
if (m_numModels && m_loadedCache)
while(i--)glDeleteLists(m_loadedCache->models[i], 1);
i=0;
while(i<m_numModels){
glmTexture(m_loadedCache->realmodels[i], m_textype, m_currentW, m_currentH);
m_loadedCache->models[i]=glmList( m_loadedCache->realmodels[i], GLM_SMOOTH | GLM_TEXTURE);
i++;
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);
}
}
/////////////////////////////////////////////////////////
// materialMess
//
/////////////////////////////////////////////////////////
void multimodel :: textureMess(int state)
{
std::string textype;
switch(state) {
case 0:
m_textype=GLM_TEX_LINEAR;
textype="linear";
break;
case 1:
m_textype=GLM_TEX_SPHEREMAP;
textype="spheremap";
break;
case 2:
m_textype=GLM_TEX_UV;
textype="UV";
break;
default:
m_textype=GLM_TEX_DEFAULT;
break;
}
m_rebuild=true;
if(textype.empty()) {
m_properties.erase("textype");
} else {
gem::any value=textype;
m_properties.set("textype", value);
}
applyProperties();
}
/////////////////////////////////////////////////////////
// smoothMess
//
/////////////////////////////////////////////////////////
void multimodel :: smoothMess(float fsmooth)
{
m_properties.set("smooth", fsmooth);
applyProperties();
}
void multimodel :: startRendering()
/////////////////////////////////////////////////////////
// matrialMess
//
/////////////////////////////////////////////////////////
void multimodel :: rescaleMess(bool state)
{
// build a display list
// buildList();
m_rebuild=true;
gem::any value=state;
m_properties.set("rescale", value);
applyProperties();
}
/////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
void multimodel :: render(GemState *state)
{
if (!m_numModels || !m_loadedCache) return;
if (state && (m_currentW != state->texCoordX(2) || m_currentH != state->texCoordY(2)))
{
m_rebuild=true;
}
if(m_rebuild) {
m_currentW = state->texCoordX(2);
m_currentH = state->texCoordY(2);
buildList();
m_rebuild=false;
}
if (!m_loadedCache->models[m_curModel])return;
if (0==m_loaders.size() || m_curModel<0 || m_curModel>=m_loaders.size())
return;
if (state && (m_currentH != state->texCoordX(2) || m_currentW != state->texCoordY(2))) {
m_currentH = state->texCoordX(2);
m_currentW = state->texCoordY(2);
glCallList(m_loadedCache->models[m_curModel]);
}
m_properties.set("texwidth", m_currentW);
m_properties.set("texheight", m_currentH);
applyProperties();
}
/////////////////////////////////////////////////////////
// rescaleMess
//
/////////////////////////////////////////////////////////
void multimodel :: rescaleMess(int state)
{
m_rescaleModel = state;
m_loaders[m_curModel]->render();
}
/////////////////////////////////////////////////////////
......@@ -306,16 +235,10 @@ void multimodel :: rescaleMess(int state)
/////////////////////////////////////////////////////////
void multimodel :: changeModel(int modelNum)
{
if (modelNum >= m_numModels)
{
error("selection number too high: %d (max num is %d)", modelNum, m_numModels-1);
return;
}
else if (modelNum < 0)
{
error("selection number must be > 0");
return;
}
if (modelNum < 0 || modelNum >= m_loaders.size()) {
error("selection %d out of range: 0..%d", modelNum, m_loaders.size()-1);
return;
}
m_curModel = modelNum;
// setModified();
}
......@@ -335,12 +258,13 @@ void multimodel :: obj_setupCallback(t_class *classPtr)
class_addmethod(classPtr, reinterpret_cast<t_method>(&multimodel::textureMessCallback),
gensym("texture"), A_FLOAT, A_NULL);
}
void multimodel :: openMessCallback(void *data, t_symbol *filename, t_floatarg baseModel,
void multimodel :: openMessCallback(void *data, t_symbol *filesymbol, t_floatarg baseModel,
t_floatarg topModel, t_floatarg skipRate)
{
int skipRatei=static_cast<int>(skipRate);
int topModeli=static_cast<int>(topModel);
int baseModeli=static_cast<int>(baseModel);
std::string filename=filesymbol->s_name;
if (skipRatei == 0)
{
......
......@@ -17,13 +17,9 @@
#include "Base/GemBase.h"
#include <string.h>
#include "model_loader.h"
#include "plugins/modelloader.h"
#include "Gem/Properties.h"
#ifdef _MSC_VER
# if _MSC_VER >= 1500
# define strdup _strdup
# endif
#endif
/*-----------------------------------------------------------------
-------------------------------------------------------------------
......@@ -49,37 +45,6 @@ class GEM_EXTERN multimodel : public GemBase
// Constructor
multimodel(t_symbol *filename, t_floatarg baseModel, t_floatarg topModel, t_floatarg skipRate);
class multiModelCache
{
public:
multiModelCache(const char *_modelName)
: refCount(0), next(NULL), models(NULL),
numModels(0), baseModel(0), topModel(0),
skipRate(0)
{ modelName = strdup(_modelName); }
~multiModelCache()
{ delete modelName;
for (int i = 0; i < numModels; i++) {
glmDelete(realmodels[i]);
glDeleteLists(models[i], 1);
}
delete [] models;
}
int refCount;
multiModelCache *next;
GLint *models;
GLMmodel **realmodels;
int numModels;
char *modelName;
int baseModel;
int topModel;
int skipRate;
};
//////////
static multiModelCache *s_modelCache;
protected:
//////////
......@@ -88,16 +53,7 @@ class GEM_EXTERN multimodel : public GemBase
//////////
// When an open is received
virtual void openMess(t_symbol *filename, int baseModel, int topModel, int skipRate);
//////////
void cleanMultimodel();
//////////
virtual void buildList();
//////////
virtual void startRendering();
virtual void openMess(const std::string&filename, int baseModel, int topModel, int skipRate);
//////////
virtual void render(GemState *state);
......@@ -106,38 +62,26 @@ class GEM_EXTERN multimodel : public GemBase
// Change which model to display
void changeModel(int modelNum);
//////////
// Set the rescale state
void rescaleMess(int state);
//////////
multiModelCache *m_loadedCache;
void cleanMultimodel(void);
//-----------------------------------
// GROUP: Model data
//-----------------------------------
//////////
// The number of loaded models
int m_numModels;
//////////
// The current model
std::vector<gem::plugins::modelloader*>m_loaders;
int m_curModel;
//////////
// Rescale the models when loaded?
int m_rescaleModel;
//////////
// Which texture type (linear, spheric)
virtual void applyProperties(void);
virtual void rescaleMess(bool state);
virtual void textureMess(int state);
glmtexture_t m_textype;
bool m_rebuild;
virtual void smoothMess(float state);
float m_currentH, m_currentW;
gem::Properties m_properties;
private:
//////////
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment