Code Search for Developers
 
 
  

model.cpp from Boson at Krugle


Show model.cpp syntax highlighted

/*
    This file is part of the Boson game
    Copyright (C) 2005 Rivo Laks (rivolaks@hot.ee)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "model.h"

#include "lod.h"
#include "material.h"
#include "loader.h"
#include "texture.h"
#include "saver.h"
#include "mesh.h"
#include "frame.h"
#include "debug.h"
#include "bmf.h"


Model::Model()
{
  mRadius = 0.0f;

  mVertexArray = 0;
  mVertexArraySize = 0;
  mIndexArray = 0;
  mIndexArraySize = 0;
  mIndexArrayType = 0;
}

bool Model::load(const QString& file)
{
  createBaseLOD();

  Loader* l = Loader::createLoader(this, baseLOD(), file);
  if(!l)
  {
    boError() << k_funcinfo << "could not create a loader for " << file << endl;
    return false;
  }
  bool ret = l->load();
  if(ret)
  {
    ret = checkLoadedModel();
    if(!ret)
    {
      boError() << k_funcinfo << "loader reported success, but model is not valid" << endl;
      // do NOT return (loader must be deleted)
    }
  }

  delete l;
  if(!ret)
  {
    boWarning() << k_funcinfo << "unable to load file " << file << endl;
  }
  return ret;
}

bool Model::checkLoadedModel() const
{
  LOD* lod = baseLOD();
  if(!lod)
  {
    BO_NULL_ERROR(lod);
    return false;
  }
  for(unsigned int i = 0; i < materialCount(); i++)
  {
    if(!material(i))
    {
      boError(100) << k_funcinfo << "NULL material " << i << endl;
      return false;
    }
  }
  for(unsigned int i = 0; i < lod->meshCount(); i++)
  {
    if(!lod->mesh(i))
    {
      boError(100) << k_funcinfo << "NULL mesh" << i << endl;
      return false;
    }
    Mesh* mesh = lod->mesh(i);
    if(!mesh->vertices())
    {
      BO_NULL_ERROR(mesh->vertices());
      return false;
    }
    if(!mesh->faces())
    {
      BO_NULL_ERROR(mesh->faces());
      return false;
    }
    for(unsigned int j = 0; j < mesh->vertexCount(); j++)
    {
      if(!mesh->vertex(j))
      {
        boError(100) << k_funcinfo << "NULL vertex " << j << " in mesh " << i << endl;
        return false;
      }
    }
    for(unsigned int j = 0; j < mesh->faceCount(); j++)
    {
      if(!mesh->face(j))
      {
        boError(100) << k_funcinfo << "NULL face " << j << " in mesh " << i << endl;
        return false;
      }
    }
  }
  for(unsigned int i = 0; i < lod->frameCount(); i++)
  {
    if(!lod->frame(i))
    {
      boError(100) << k_funcinfo << "NULL frame" << i << endl;
      return false;
    }
    Frame* f = lod->frame(i);
    for(unsigned int j = 0; j < f->nodeCount(); j++)
    {
      if(!f->mesh(j))
      {
        boError(100) << k_funcinfo << "NULL mesh " << j << " in frame " << i << endl;
        return false;
      }
      if(!f->matrix(j))
      {
        boError(100) << k_funcinfo << "NULL matrix " << j << " in frame " << i << endl;
        return false;
      }
      if(f->matrix(j)->hasNaN())
      {
        boError(100) << k_funcinfo << "matrix " << j << " in frame " << i << " is invalid: has NaN entry" << endl;
        return false;
      }
    }
  }
  return true;
}

bool Model::save(const QString& file)
{
  Saver s(this, file);
  return s.save();
}

void Model::createBaseLOD()
{
  if(lodCount() > 0)
  {
    boError() << k_funcinfo << "base LOD already created" << endl;
    return;
  }
  LOD* l = new LOD;
  mLODs.append(l);
}

unsigned int Model::addMaterial(Material* m)
{
  mMaterials.append(m);
  return mMaterials.count() - 1;
}

void Model::setMaterials(const QValueVector<Material*>& materials)
{
  mMaterials = materials;
}

void Model::setTextures(const QDict<Texture>& textures)
{
  mTextures = textures;
}

Texture* Model::getTexture(const QString& filename)
{
  if(filename.isEmpty())
  {
    return 0;
  }
  Texture* t = mTextures[filename];
  if(!t)
  {
    t = new Texture(filename);
    mTextures.insert(filename, t);
  }

  return t;
}

void Model::addTexture(Texture* t)
{
  mTextures.insert(t->filename(), t);
}

bool Model::loadTextures()
{
  bool ret = true;
  QDictIterator<Texture> it(mTextures);
  while(it.current())
  {
    ret &= it.current()->load();
    ++it;
  }
  return ret;
}

void Model::prepareForSaving(unsigned int baseframe)
{
  removeEmptyMeshes();
  updateBoundingBox(baseframe);
  updateIds();
  updateRadius(baseframe);
  createArrays();
}

void Model::createArrays()
{
  // Count the number of indices and vertices we need to allocate
  mVertexArraySize = 0;
  mIndexArraySize = 0;
  unsigned int maxIndex = 0;
  for(unsigned int i = 0; i < lodCount(); i++)
  {
    LOD* l = lod(i);
    for(unsigned int j = 0; j < l->meshCount(); j++)
    {
      Mesh* m = l->mesh(j);
      if(m->useIndices())
      {
        mVertexArraySize += m->vertexCount();
        mIndexArraySize += m->faceCount() * 3;
        maxIndex = mVertexArraySize - 1;
      }
      else
      {
        mVertexArraySize += m->faceCount() * 3;
      }
    }
  }

  // Create the arrays
  mVertexArray = new float[mVertexArraySize * (3+3+2)];
  if(maxIndex <= 65535)
  {
    mIndexArrayType = BMF_DATATYPE_UNSIGNED_SHORT;
    mIndexArray = (unsigned char*)new Q_UINT16[mIndexArraySize];
  }
  else
  {
    mIndexArrayType = BMF_DATATYPE_UNSIGNED_INT;
    mIndexArray = (unsigned char*)new Q_UINT32[mIndexArraySize];
  }

  // Copy data into the arrays
  unsigned int vertexoffset = 0;
  unsigned int indexoffset = 0;
  for(unsigned int i = 0; i < lodCount(); i++)
  {
    LOD* l = lod(i);
    for(unsigned int j = 0; j < l->meshCount(); j++)
    {
      l->mesh(j)->createArrays(mVertexArray, mIndexArray, &vertexoffset, &indexoffset, mIndexArrayType);
    }
  }

  boDebug() << k_funcinfo << vertexoffset << " of " << mVertexArraySize << " vertices copied" << endl;
  boDebug() << k_funcinfo << indexoffset << " of " << mIndexArraySize << " indices copied" << endl;
}

void Model::updateIds()
{
  // Textures
  QDictIterator<Texture> it(mTextures);
  for(unsigned int i = 0; it.current(); ++it, i++)
  {
    it.current()->setId(i);
  }

  // Materials
  for(unsigned int i = 0; i < mMaterials.count(); i++)
  {
    mMaterials[i]->setId(i);
  }

  // Stuff in LODs
  for(unsigned int i = 0; i < lodCount(); i++)
  {
    LOD* l = lod(i);
    // Meshes
    for(unsigned int j = 0; j < l->meshCount(); j++)
    {
      Mesh* m = l->mesh(j);
      m->setId(j);
      // Vertices
      for(unsigned int k = 0; k < m->vertexCount(); k++)
      {
        m->vertex(k)->id = k;
      }
    }
    // Frames
    for(unsigned int j = 0; j < l->frameCount(); j++)
    {
      l->frame(j)->setId(j);
    }
  }
}

void Model::calculateFaceNormals()
{
  for(unsigned int i = 0; i < lodCount(); i++)
  {
    LOD* l = lod(i);
    for(unsigned int j = 0; j < l->meshCount(); j++)
    {
      l->mesh(j)->calculateFaceNormals();
    }
  }
}

void Model::calculateVertexNormals()
{
  for(unsigned int i = 0; i < lodCount(); i++)
  {
    LOD* l = lod(i);
    for(unsigned int j = 0; j < l->meshCount(); j++)
    {
      l->mesh(j)->calculateVertexNormals();
    }
  }
}

void Model::smoothAllFaces()
{
  for(unsigned int i = 0; i < lodCount(); i++)
  {
    LOD* l = lod(i);
    for(unsigned int j = 0; j < l->meshCount(); j++)
    {
      l->mesh(j)->smoothAllFaces();
    }
  }
}

void Model::removeEmptyMeshes()
{
  // TODO: maybe this should be moved to some processor?
  for(unsigned int i = 0; i < lodCount(); i++)
  {
    LOD* l = lod(i);

    QValueVector<Mesh*> meshes;
    QValueVector<Mesh*> removedmeshes;
    for(unsigned int j = 0; j < l->meshCount(); j++)
    {
      Mesh* m = l->mesh(j);
      if(m->vertexCount() == 0 || m->faceCount() == 0)
      {
        removedmeshes.append(m);
        continue;
      }
      meshes.append(m);
    }

    if(removedmeshes.isEmpty())
    {
      // Data didn't change
      continue;
    }

    // Some meshes should be removed.
    // Set new mesh list
    l->removeAllMeshesBut(meshes);
  }
}

void Model::updateBoundingBox(unsigned int baseframe)
{
  mMinCoord.set( 1000000000,  1000000000,  1000000000);
  mMaxCoord.set(-1000000000, -1000000000, -1000000000);
  // We only consider the base lod and base frame here.
  Frame* f = baseLOD()->frame(baseframe);
  for(unsigned int i = 0; i < f->nodeCount(); i++)
  {
    Mesh* mesh = f->mesh(i);
    BoMatrix* matrix = f->matrix(i);
    for(unsigned int j = 0; j < mesh->vertexCount(); j++)
    {
      BoVector3Float pos;
      matrix->transform(&pos, &mesh->vertex(j)->pos);
      mMinCoord.setX(QMIN(mMinCoord.x(), pos.x()));
      mMinCoord.setY(QMIN(mMinCoord.y(), pos.y()));
      mMinCoord.setZ(QMIN(mMinCoord.z(), pos.z()));
      mMaxCoord.setX(QMAX(mMaxCoord.x(), pos.x()));
      mMaxCoord.setY(QMAX(mMaxCoord.y(), pos.y()));
      mMaxCoord.setZ(QMAX(mMaxCoord.z(), pos.z()));
    }
  }

  // Update bounding boxes of meshes
  for(unsigned int i = 0; i < lodCount(); i++)
  {
    LOD* l = lod(i);
    for(unsigned int j = 0; j < l->meshCount(); j++)
    {
      l->mesh(j)->updateBoundingBox();
    }
  }
}

void Model::loadingCompleted()
{
  for(unsigned int i = 0; i < lodCount(); i++)
  {
    LOD* l = lod(i);
    for(unsigned int j = 0; j < l->meshCount(); j++)
    {
      l->mesh(j)->loadingCompleted();
    }
  }
}

void Model::createLODs(unsigned int num)
{
  if(lodCount() < 1)
  {
    boError() << k_funcinfo << "need a base LOD first" << endl;
    return;
  }
  updateIds();

  for(unsigned int i = lodCount(); i < num; i++)
  {
    LOD* l = new LOD(baseLOD());
    mLODs.append(l);
  }

  setLodDistances();
}

void Model::setLodDistances(float multiplier)
{
  // Calculate initial distances for lods
  float dist = 0.0f;
  for(unsigned int i = 0; i < lodCount(); i++)
  {
    lod(i)->setDistance(dist * multiplier);
    // dists will be 0, 10, 25, 45, 70, ...
    dist = dist + (10 * (0.5 + i * 0.5));
  }
}

void Model::updateRadius(unsigned int baseframe)
{
  float maxdist = 0.0f;
  // Calculate the radius of the (bounding sphere of the) model.
  // We only consider the base lod and base frame here.
  Frame* f = baseLOD()->frame(baseframe);
  for(unsigned int i = 0; i < f->nodeCount(); i++)
  {
    Mesh* mesh = f->mesh(i);
    BoMatrix* matrix = f->matrix(i);
    for(unsigned int j = 0; j < mesh->vertexCount(); j++)
    {
      BoVector3Float pos;
      matrix->transform(&pos, &mesh->vertex(j)->pos);
      // Calculate distance to the pos from the origin point.
      // Note that the distance is left squared for performace reasons.
      maxdist = QMAX(maxdist, pos.dotProduct());
    }
  }
  mRadius = sqrt(maxdist);
}

/*
 * vim: et sw=2
 */




See more files for this project here

Boson

Boson is an OpenGL real-time strategy game. It is designed to run on Unix (Linux) computers, and is built on top of the KDE, Qt and kdegames libraries.

Project homepage: http://sourceforge.net/projects/boson
Programming language(s): C,C++
License: other

  libgfx/
    gfx/
      arcball.h
      array.h
      baseball.h
      geom3d.h
      geom4d.h
      gfx.h
      gl.h
      glext.h
      gltools.h
      gui.h
      intvec.h
      mat2.h
      mat3.h
      mat4.h
      mfc.h
      quat.h
      raster.h
      script.h
      symmat3.h
      symmat4.h
      trackball.h
      vec2.h
      vec3.h
      vec4.h
      wintools.h
    CMakeLists.txt
    arcball.cxx
    baseball.cxx
    config-libgfx.h.cmake
    geom3d.cxx
    geom4d.cxx
    gltools.cxx
    gui.cxx
    mat2.cxx
    mat3.cxx
    mat4.cxx
    quat.cxx
    raster-jpeg.cxx
    raster-png.cxx
    raster-pnm.cxx
    raster-tiff.cxx
    raster.cxx
    script.cxx
    symmat3.cxx
    symmat4.cxx
    time.cxx
    trackball.cxx
    wintools.cxx
  loaders/
    lib3ds_test/
      README
      lib3ds_test_puma.c
      mob_puma.3ds
    loader-3ds.cpp
    loader-3ds.h
    loader-ac.cpp
    loader-ac.h
    loader-md2.cpp
    loader-md2.h
  mixkit/
    COPYING.txt
    MxAsp.cxx
    MxAsp.h
    MxBlock.h
    MxBlock2.h
    MxBlock3.h
    MxBlockModel.cxx
    MxBlockModel.h
    MxCamera.cxx
    MxCamera.h
    MxCmdParser.cxx
    MxCmdParser.h
    MxDualModel.cxx
    MxDualModel.h
    MxDualSlim.cxx
    MxDualSlim.h
    MxDynBlock.h
    MxEdgeFilter.cxx
    MxEdgeFilter.h
  processors/
  test/
  CMakeLists.txt
  bmf.h
  bo3dtools.cpp
  bo3dtools.h
  debug.h
  frame.cpp
  frame.h
  loader.cpp
  loader.h
  lod.cpp
  lod.h
  main.cpp
  material.cpp
  material.h
  mesh.cpp
  mesh.h
  model.cpp
  model.h
  processor.cpp
  processor.h
  saver.cpp
  saver.h
  texture.cpp
  texture.h