multimodel.cpp 10 KB
Newer Older
1 2 3 4 5 6 7 8 9
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
//    Copyright (c) 1997-1999 Mark Danks.
zmoelnig's avatar
zmoelnig committed
10
//    Copyright (c) Günther Geiger.
zmoelnig's avatar
zmoelnig committed
11
//    Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
12 13 14 15 16
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#include "multimodel.h"
17
#include "Gem/State.h"
18 19
#include <stdio.h>

20
CPPEXTERN_NEW_WITH_FOUR_ARGS(multimodel, t_symbol *, A_DEFSYM, t_floatarg, A_DEFFLOAT, t_floatarg, A_DEFFLOAT, t_floatarg, A_DEFFLOAT);
21

IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
22
multimodel::multiModelCache *multimodel::s_modelCache = NULL;
23 24 25 26 27 28 29 30 31 32

/////////////////////////////////////////////////////////
//
// multimodel
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
multimodel :: multimodel(t_symbol *filename, t_floatarg baseModel,
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
33
                         t_floatarg topModel, t_floatarg skipRate)
34 35
  : m_loadedCache(NULL),
    m_numModels(0), m_curModel(-1),
36
    m_rescaleModel(1),
37
    m_textype(GLM_TEX_DEFAULT),
38
    m_rebuild(true),
zmoelnig's avatar
zmoelnig committed
39
    m_currentH(1.f), m_currentW(1.f)
40 41 42 43
{
  inlet_new(this->x_obj, &this->x_obj->ob_pd, &s_float, gensym("mdl_num"));

  // make sure that there are some characters
44
  if (filename->s_name[0]) {
zmoelnig's avatar
zmoelnig committed
45 46 47 48 49 50
    int skipRatei=static_cast<int>(skipRate);
    int topModeli=static_cast<int>(topModel);
    int baseModeli=static_cast<int>(baseModel);
    if (skipRatei == 0) {
      if (topModeli == 0)
        openMess(filename, 0, baseModeli, 1);
51
      else
zmoelnig's avatar
zmoelnig committed
52
        openMess(filename, baseModeli, topModeli, 1);
53
    }
zmoelnig's avatar
zmoelnig committed
54
    else openMess(filename, baseModeli, topModeli, skipRatei);
55 56 57
  }
}

IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
58
////////////////////////////////////////////////////////
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
// Destructor
//
/////////////////////////////////////////////////////////
multimodel :: ~multimodel()
{
  cleanMultimodel();
}

/////////////////////////////////////////////////////////
// cleanMultimodel
//
/////////////////////////////////////////////////////////
void multimodel :: cleanMultimodel()
{
  if (m_numModels) {
    // decrement the reference count
    m_loadedCache->refCount--;
76

77 78 79 80
    // If the refCount == 0, then destroy the cache
    if (m_loadedCache->refCount == 0) {
      // find the cache
      multiModelCache *ptr = s_modelCache;
81

82 83
      // if the loaded cache is the first cache in the list
      if (m_loadedCache == s_modelCache) {
84 85
        s_modelCache = m_loadedCache->next;
        delete m_loadedCache;
86 87
      }
      else {
88 89 90 91 92 93
        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;
        }
94 95
      }
    }
96

97 98 99 100 101 102 103 104 105 106 107 108
    m_loadedCache = NULL;
    m_numModels = 0;
  }
}

/////////////////////////////////////////////////////////
// openMess
//
/////////////////////////////////////////////////////////
void multimodel :: openMess(t_symbol *filename, int baseModel, int topModel, int skipRate)
{
  cleanMultimodel();
109

110
  if (!topModel) {
111
    error("requires an int for number of models");
112 113 114
    return;
  }
  if (baseModel > topModel) {
115
    error("top range less than base model");
116 117 118 119 120 121 122 123 124
    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 &&
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
125 126 127
        topModel == cache->topModel &&
        skipRate == cache->skipRate &&
        !strcmp(filename->s_name, cache->modelName)) found = 1;
128 129
    else cache = cache->next;
  }
130

131 132 133 134 135 136
  // yep, we have it
  if (found) {
    m_loadedCache = cache;
    m_loadedCache->refCount++;
    m_curModel = 0;
    m_numModels = m_loadedCache->numModels;
137
    post("loaded models: %s from %d to %d skipping %d",
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
138
         filename->s_name, baseModel, topModel, skipRate);
139 140 141 142
    return;
  }

  // nope, so create the new cache
143
  // find the * in the filename
144 145
  char preName[256];
  char postName[256];
146

147 148 149 150 151 152
  int i = 0;
  char *strPtr = filename->s_name;
  while (strPtr[i] && strPtr[i] != '*') {
    preName[i] = strPtr[i];
    i++;
  }
153

154
  if (!strPtr[i]) {
155
    error("unable to find * in file name");
156 157 158
    return;
  }

159
  preName[i] = '\0';
160
  strcpy(postName, &(strPtr[i+1]));
161

162 163 164 165 166 167 168 169 170 171 172 173 174 175
  // 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 realNum = baseModel;
  char bufName[MAXPDSTRING];
zmoelnig's avatar
zmoelnig committed
176
  canvas_makefilename(const_cast<t_canvas*>(getCanvas()), preName, bufName, MAXPDSTRING);
177 178 179 180

  for (i = 0; i < m_numModels; i++, realNum += skipRate) {
    char newName[256];
    sprintf(newName, "%s%d%s", bufName, realNum, postName);
181

182 183 184 185 186 187 188 189 190 191 192 193 194
    // 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);
195

196 197 198 199 200
    // generate normals if this
    // object doesn't have them.
    //
    glmFacetNormals (m_model);
    glmVertexNormals(m_model, 90); /* SMOOTH */
201

202
    glmTexture(m_model, m_textype, 1, 1);
203 204 205 206 207 208 209 210 211
    newCache->realmodels[i]=m_model;
  }
  m_curModel = 0;

  m_loadedCache = newCache;
  newCache->refCount++;

  // insert the cache at the end of the linked list
  multiModelCache *ptr = s_modelCache;
212

213 214 215 216 217 218
  if (!ptr) s_modelCache = newCache;
  else {
    while(ptr->next) ptr = ptr->next;
    ptr->next = newCache;
  }

219
  post("loaded models: %s %s from %d to %d skipping %d",
220
       bufName, postName, baseModel, topModel, skipRate);
221
  setModified();
222 223 224 225 226 227 228 229 230 231 232 233 234
}
/////////////////////////////////////////////////////////
// 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){
235
    glmTexture(m_loadedCache->realmodels[i], m_textype, m_currentW, m_currentH);
236
    m_loadedCache->models[i]=glmList( m_loadedCache->realmodels[i], GLM_SMOOTH | GLM_TEXTURE);
237

238 239 240 241
    i++;
  }
}

242 243 244 245 246 247 248
/////////////////////////////////////////////////////////
// materialMess
//
/////////////////////////////////////////////////////////
void multimodel :: textureMess(int state)
{
  switch(state) {
249 250
  case 0:
    m_textype=GLM_TEX_LINEAR;
251
    break;
252 253
  case 1:
    m_textype=GLM_TEX_SPHEREMAP;
254 255
    break;
  case 2:
256
    m_textype=GLM_TEX_UV;
257 258
    break;
  default:
259
    m_textype=GLM_TEX_DEFAULT;
260 261 262 263 264
  }
  m_rebuild=true;
}


265 266 267
void multimodel :: startRendering()
{
  // build a display list
268 269
  //  buildList();
  m_rebuild=true;
270 271 272 273 274
}
/////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
275
void multimodel :: render(GemState *state)
276 277
{
  if (!m_numModels || !m_loadedCache) return;
278
  if (state && (m_currentW != state->texCoordX(2) || m_currentH != state->texCoordY(2)))
279 280
    {
      m_rebuild=true;
281
    }
282
  if(m_rebuild) {
283 284
    m_currentW = state->texCoordX(2);
    m_currentH = state->texCoordY(2);
285 286
    buildList();
    m_rebuild=false;
287 288 289 290
  }
  if (!m_loadedCache->models[m_curModel])return;


291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
  glCallList(m_loadedCache->models[m_curModel]);
}

/////////////////////////////////////////////////////////
// rescaleMess
//
/////////////////////////////////////////////////////////
void multimodel :: rescaleMess(int state)
{
  m_rescaleModel = state;
}

/////////////////////////////////////////////////////////
// changeModel
//
/////////////////////////////////////////////////////////
void multimodel :: changeModel(int modelNum)
{
  if (modelNum >= m_numModels)
    {
311
      error("selection number too high: %d (max num is %d)", modelNum, m_numModels-1);
312 313 314 315
      return;
    }
  else if (modelNum < 0)
    {
316
      error("selection number must be > 0");
317 318 319
      return;
    }
  m_curModel = modelNum;
320
  //  setModified();
321 322 323 324 325 326 327 328
}

/////////////////////////////////////////////////////////
// static member function
//
/////////////////////////////////////////////////////////
void multimodel :: obj_setupCallback(t_class *classPtr)
{
zmoelnig's avatar
zmoelnig committed
329
  class_addmethod(classPtr, reinterpret_cast<t_method>(&multimodel::openMessCallback),
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
330
                  gensym("open"), A_SYMBOL, A_FLOAT, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
zmoelnig's avatar
zmoelnig committed
331
  class_addmethod(classPtr, reinterpret_cast<t_method>(&multimodel::changeModelCallback),
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
332
                  gensym("mdl_num"), A_FLOAT, A_NULL);
zmoelnig's avatar
zmoelnig committed
333
  class_addmethod(classPtr, reinterpret_cast<t_method>(&multimodel::rescaleMessCallback),
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
334
                  gensym("rescale"), A_FLOAT, A_NULL);
zmoelnig's avatar
zmoelnig committed
335
  class_addmethod(classPtr, reinterpret_cast<t_method>(&multimodel::textureMessCallback),
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
336
                  gensym("texture"), A_FLOAT, A_NULL);
337 338
}
void multimodel :: openMessCallback(void *data, t_symbol *filename, t_floatarg baseModel,
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
339
                                    t_floatarg topModel, t_floatarg skipRate)
340
{
zmoelnig's avatar
zmoelnig committed
341 342 343 344 345
  int skipRatei=static_cast<int>(skipRate);
  int topModeli=static_cast<int>(topModel);
  int baseModeli=static_cast<int>(baseModel);

  if (skipRatei == 0)
346
    {
zmoelnig's avatar
zmoelnig committed
347
      if (topModeli == 0)
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
348
        GetMyClass(data)->openMess(filename, 0, topModeli, 0);
349
      else
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
350
        GetMyClass(data)->openMess(filename, baseModeli, topModeli, 0);
351 352
    }
  else
zmoelnig's avatar
zmoelnig committed
353
    GetMyClass(data)->openMess(filename, baseModeli, topModeli, skipRatei);
354 355 356
}
void multimodel :: changeModelCallback(void *data, t_floatarg modelNum)
{
zmoelnig's avatar
zmoelnig committed
357
  GetMyClass(data)->changeModel(static_cast<int>(modelNum));
358 359 360
}
void multimodel :: rescaleMessCallback(void *data, t_floatarg state)
{
zmoelnig's avatar
zmoelnig committed
361
  GetMyClass(data)->rescaleMess(static_cast<int>(state));
362
}
363 364
void multimodel :: textureMessCallback(void *data, t_floatarg state)
{
zmoelnig's avatar
zmoelnig committed
365
  GetMyClass(data)->textureMess(static_cast<int>(state));
366
}