/* -*- c++ -*-
    Copyright (C) 2003 <ryu@gpul.org>

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

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
/*
 *
 * Copyright (C) 2004 Mekensleep
 *
 *	Mekensleep
 *	24 rue vieille du temple
 *	75004 Paris
 *       licensing@mekensleep.com
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * Authors:
 *  Cedric PINSON <cpinson@freesheep.org>
 *  Loic Dachary <loic@gnu.org>
 *
 */
#ifndef __OSGCAL__MODEL_H__
#define __OSGCAL__MODEL_H__

#include <osg/Geode>

#include <cal3d/cal3d.h>

#include <osgCal/CoreModel>
#include <osgCal/Export>

namespace osgCal {

/** @class osgCal::Model
 * @brief Adapter that allows having a model in the scenegraph.
 *
 * This class is an osg::Node so you can add it to your scenegraph. Moreover
 * it handles automatically updating the cal3d model associated, and the
 * generation of drawables binded to submeshes of the model.
 *
 * Note that this node installs an UpdateCallback so don't overwrite it...
 */

class OSGCAL_EXPORT Model: public osg::Geode {
public:
  typedef CoreModel::Textures2D Textures2D;
  typedef std::vector<osg::ref_ptr<osg::Drawable> > Drawables;
  typedef std::map<int,Drawables> CoreMeshId2Drawables;

  META_Object(osgCal, Model);

  Model();
  Model(const Model&, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);

protected:
  virtual ~Model();
public:

  bool create(void);
  void update(void);

  CoreModel *getCoreModel() { return _coreModel.get(); }
  void setCoreModel(CoreModel* coreModel) { _coreModel = coreModel; }
  DynamicCalCoreModel *getCalCoreModel(void) { return _coreModel->getCalCoreModel(); }
  CalModel *getCalModel(void) { return &_calModel; }

  Textures2D* getTextures2D(const std::string& materialName);
  Textures2D* getTextures2D(int coreMaterialId);
  Drawables* getDrawables(const std::string& materialName);
  Drawables* getDrawables(int coreMaterialId);
  bool hasDrawables(int coreMeshId);

  bool setPrivateTextures(const std::vector<std::string>& privateTextures);
  bool setMeshes(const DynamicCalCoreModel::Name2Filename& name2filename);
  bool setInvisibleMeshes(const std::vector<std::string>& meshes) { return setMeshesVector(meshes, _invisibleMeshes); }
  bool setCollisionMeshes(const std::vector<std::string>& meshes) { return setMeshesVector(meshes, _collisionMeshes); }
  bool setUseVertexProgram(bool useVertexProgram);
  bool getUseVertexProgram(void) { return _useVertexProgram; }

private:
  bool createSoftware(void);
  bool createSubMeshSoftware(int meshId, int coreMeshId);
  bool createHardware(void);
  bool setupMaterial(osg::Drawable* drawable, CalSubmesh* calSubmesh);

  bool setMeshesVector(const std::vector<std::string>& meshes, std::vector<int>& vector);
  bool isPrivateTexture(int coreMaterialId) { return find(_privateTextures, coreMaterialId); }
  bool isInvisibleMesh(int coreMeshId) { return find(_invisibleMeshes, coreMeshId); }
  bool isCollisionMesh(int coreMeshId) { return find(_collisionMeshes, coreMeshId); }
  bool find(const std::vector<int>& vector, int item);

  CalHardwareModel mHardwareModel;
  bool _useVertexProgram;
  unsigned int mVbo[6];

  osg::ref_ptr<CoreModel> _coreModel;
  std::vector<int> _privateTextures;
  std::vector<int> _meshes;
  std::vector<int> _invisibleMeshes;
  std::vector<int> _collisionMeshes;
  CoreMeshId2Drawables _coreMeshId2Drawables;
  CoreModel::CoreMaterialId2Textures2D _coreMaterialId2PrivateTextures;
  // Cannot be a base class of Model because rtti disabled in cal3d
  CalModel _calModel;
};

}; // namespace osgCal

#endif
