From cabd0d583fd275689b4ec928234952e145a586df Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Mon, 18 Jul 2011 22:16:40 +0200 Subject: [PATCH] GRIM: Make Material implicitly shared. Cleaned up Model a lot. --- engines/grim/costume.cpp | 4 +- engines/grim/gfx_base.h | 5 ++- engines/grim/gfx_opengl.cpp | 10 ++--- engines/grim/gfx_opengl.h | 4 +- engines/grim/gfx_tinygl.cpp | 10 ++--- engines/grim/gfx_tinygl.h | 4 +- engines/grim/material.cpp | 78 ++++++++++++++++++++++++++++++------- engines/grim/material.h | 33 ++++++++++------ engines/grim/model.cpp | 36 ++++++----------- engines/grim/model.h | 2 +- engines/grim/resource.cpp | 19 --------- engines/grim/resource.h | 3 -- 12 files changed, 117 insertions(+), 91 deletions(-) diff --git a/engines/grim/costume.cpp b/engines/grim/costume.cpp index 9e93820008b..2f7117790e8 100644 --- a/engines/grim/costume.cpp +++ b/engines/grim/costume.cpp @@ -635,7 +635,7 @@ public: ~MaterialComponent() { } private: - MaterialPtr _mat; + Material *_mat; Common::String _filename; int _num; }; @@ -986,7 +986,7 @@ void MaterialComponent::init() { Model *model = p->getModel(); for (int i = 0; i < model->_numMaterials; ++i) { if (_filename.compareToIgnoreCase(model->_materials[i]->getFilename()) == 0) { - _mat = model->_materials[i].object(); + _mat = model->_materials[i]; return; } } diff --git a/engines/grim/gfx_base.h b/engines/grim/gfx_base.h index 86ff49e4b56..6280dd18b96 100644 --- a/engines/grim/gfx_base.h +++ b/engines/grim/gfx_base.h @@ -31,6 +31,7 @@ namespace Grim { struct Shadow; class SaveGame; class BitmapData; +class MaterialData; class PrimitiveObject; class Font; class TextObject; @@ -78,9 +79,9 @@ public: virtual void disableLights() = 0; virtual void setupLight(Scene::Light *light, int lightId) = 0; - virtual void createMaterial(Material *material, const char *data, const CMap *cmap) = 0; + virtual void createMaterial(MaterialData *material, const char *data, const CMap *cmap) = 0; virtual void selectMaterial(const Material *material) = 0; - virtual void destroyMaterial(Material *material) = 0; + virtual void destroyMaterial(MaterialData *material) = 0; virtual void createBitmap(BitmapData *bitmap) = 0; virtual void drawBitmap(const Bitmap *bitmap) = 0; diff --git a/engines/grim/gfx_opengl.cpp b/engines/grim/gfx_opengl.cpp index 26c39857c17..c6850c84283 100644 --- a/engines/grim/gfx_opengl.cpp +++ b/engines/grim/gfx_opengl.cpp @@ -958,7 +958,7 @@ void GfxOpenGL::drawTextObject(TextObject *text) { void GfxOpenGL::destroyTextObject(TextObject *text) { } -void GfxOpenGL::createMaterial(Material *material, const char *data, const CMap *cmap) { +void GfxOpenGL::createMaterial(MaterialData *material, const char *data, const CMap *cmap) { material->_textures = new GLuint[material->_numImages]; glGenTextures(material->_numImages, (GLuint *)material->_textures); char *texdata = new char[material->_width * material->_height * 4]; @@ -991,14 +991,14 @@ void GfxOpenGL::createMaterial(Material *material, const char *data, const CMap } void GfxOpenGL::selectMaterial(const Material *material) { - GLuint *textures = (GLuint *)material->_textures; - glBindTexture(GL_TEXTURE_2D, textures[material->_currImage]); + GLuint *textures = (GLuint *)material->getData()->_textures; + glBindTexture(GL_TEXTURE_2D, textures[material->getCurrentImage()]); glMatrixMode(GL_TEXTURE); glLoadIdentity(); - glScalef(1.0f / material->_width, 1.0f / material->_height, 1); + glScalef(1.0f / material->getData()->_width, 1.0f / material->getData()->_height, 1); } -void GfxOpenGL::destroyMaterial(Material *material) { +void GfxOpenGL::destroyMaterial(MaterialData *material) { GLuint *textures = (GLuint *)material->_textures; if (textures) { glDeleteTextures(material->_numImages, textures); diff --git a/engines/grim/gfx_opengl.h b/engines/grim/gfx_opengl.h index 81e2af85f07..1bd2768afd7 100644 --- a/engines/grim/gfx_opengl.h +++ b/engines/grim/gfx_opengl.h @@ -79,9 +79,9 @@ public: void disableLights(); void setupLight(Scene::Light *light, int lightId); - void createMaterial(Material *material, const char *data, const CMap *cmap); + void createMaterial(MaterialData *material, const char *data, const CMap *cmap); void selectMaterial(const Material *material); - void destroyMaterial(Material *material); + void destroyMaterial(MaterialData *material); void createBitmap(BitmapData *bitmap); void drawBitmap(const Bitmap *bitmap); diff --git a/engines/grim/gfx_tinygl.cpp b/engines/grim/gfx_tinygl.cpp index 50a0320d682..c6b79f07bf8 100644 --- a/engines/grim/gfx_tinygl.cpp +++ b/engines/grim/gfx_tinygl.cpp @@ -801,7 +801,7 @@ void GfxTinyGL::destroyTextObject(TextObject *text) { } } -void GfxTinyGL::createMaterial(Material *material, const char *data, const CMap *cmap) { +void GfxTinyGL::createMaterial(MaterialData *material, const char *data, const CMap *cmap) { material->_textures = new TGLuint[material->_numImages]; tglGenTextures(material->_numImages, (TGLuint *)material->_textures); char *texdata = new char[material->_width * material->_height * 4]; @@ -833,17 +833,17 @@ void GfxTinyGL::createMaterial(Material *material, const char *data, const CMap } void GfxTinyGL::selectMaterial(const Material *material) { - TGLuint *textures = (TGLuint *)material->_textures; - tglBindTexture(TGL_TEXTURE_2D, textures[material->_currImage]); + TGLuint *textures = (TGLuint *)material->getData()->_textures; + tglBindTexture(TGL_TEXTURE_2D, textures[material->getCurrentImage()]); tglPushMatrix(); tglMatrixMode(TGL_TEXTURE); tglLoadIdentity(); - tglScalef(1.0f / material->_width, 1.0f / material->_height, 1); + tglScalef(1.0f / material->getData()->_width, 1.0f / material->getData()->_height, 1); tglMatrixMode(TGL_MODELVIEW); tglPopMatrix(); } -void GfxTinyGL::destroyMaterial(Material *material) { +void GfxTinyGL::destroyMaterial(MaterialData *material) { tglDeleteTextures(material->_numImages, (TGLuint *)material->_textures); delete[] (TGLuint *)material->_textures; } diff --git a/engines/grim/gfx_tinygl.h b/engines/grim/gfx_tinygl.h index e799f2589df..0100f0e51da 100644 --- a/engines/grim/gfx_tinygl.h +++ b/engines/grim/gfx_tinygl.h @@ -70,9 +70,9 @@ public: void disableLights(); void setupLight(Scene::Light *light, int lightId); - void createMaterial(Material *material, const char *data, const CMap *cmap); + void createMaterial(MaterialData *material, const char *data, const CMap *cmap); void selectMaterial(const Material *material); - void destroyMaterial(Material *material); + void destroyMaterial(MaterialData *material); void createBitmap(BitmapData *bitmap); void drawBitmap(const Bitmap *bitmap); diff --git a/engines/grim/material.cpp b/engines/grim/material.cpp index 9cceffa9578..a56bf9b3748 100644 --- a/engines/grim/material.cpp +++ b/engines/grim/material.cpp @@ -25,26 +25,28 @@ #include "engines/grim/grim.h" #include "engines/grim/material.h" #include "engines/grim/gfx_base.h" -#include "engines/grim/resource.h" +#include "engines/grim/colormap.h" namespace Grim { -Material::Material(const Common::String &filename, const char *data, int len, CMap *cmap) : - Object(), _fname(filename), _cmap(cmap) { +Common::List *MaterialData::_materials = NULL; + +MaterialData::MaterialData(const Common::String &filename, const char *data, int len, CMap *cmap) : + _fname(filename), _cmap(cmap), _refCount(1) { + if (len < 4 || memcmp(data, "MAT ", 4) != 0) error("invalid magic loading texture"); _numImages = READ_LE_UINT32(data + 12); - _currImage = 0; /* Discovered by diffing orange.mat with pink.mat and blue.mat . * Actual meaning unknown, so I prefer to use it as an enum-ish * at the moment, to detect unexpected values. */ uint32 offset = READ_LE_UINT32(data + 0x4c); if (offset == 0x8) - data += 16; + data += 16; else if (offset != 0) - error("Unknown offset: %d", offset); + error("Unknown offset: %d", offset); _width = READ_LE_UINT32(data + 60 + _numImages * 40); _height = READ_LE_UINT32(data + 64 + _numImages * 40); @@ -59,18 +61,66 @@ Material::Material(const Common::String &filename, const char *data, int len, CM g_driver->createMaterial(this, data, cmap); } +MaterialData::~MaterialData() { + _materials->remove(this); + if (_materials->empty()) { + delete _materials; + _materials = NULL; + } + + if (_width && _height) + g_driver->destroyMaterial(this); +} + +MaterialData *MaterialData::getMaterialData(const Common::String &filename, const char *data, int len, CMap *cmap) { + if (!_materials) { + _materials = new Common::List(); + } + + for (Common::List::iterator i = _materials->begin(); i != _materials->end(); ++i) { + MaterialData *m = *i; + if (m->_fname == filename && *m->_cmap == *cmap) { + ++m->_refCount; + return m; + } + } + + MaterialData *m = new MaterialData(filename, data, len, cmap); + _materials->push_back(m); + return m; +} + +Material::Material(const Common::String &filename, const char *data, int len, CMap *cmap) : + Object(), _currImage(0) { + _data = MaterialData::getMaterialData(filename, data, len, cmap); +} + void Material::select() const { - if (_width == 0 || _height == 0) - return; - g_driver->selectMaterial(this); + if (_data->_width && _data->_height) + g_driver->selectMaterial(this); } Material::~Material() { - if (g_resourceloader) - g_resourceloader->uncacheMaterial(this); - if (_width == 0 || _height == 0) - return; - g_driver->destroyMaterial(this); + --_data->_refCount; + if (_data->_refCount < 1) { + delete _data; + } +} + +int Material::getNumImages() const { + return _data->_numImages; +} + +int Material::getCurrentImage() const { + return _currImage; +} + +const Common::String &Material::getFilename() const { + return _data->_fname; +} + +MaterialData *Material::getData() const { + return _data; } } // end of namespace Grim diff --git a/engines/grim/material.h b/engines/grim/material.h index 1ea70fadc26..c335e816114 100644 --- a/engines/grim/material.h +++ b/engines/grim/material.h @@ -27,11 +27,24 @@ namespace Grim { -class CMAp; +class MaterialData { +public: + MaterialData(const Common::String &filename, const char *data, int len, CMap *cmap); + ~MaterialData(); + + static MaterialData *getMaterialData(const Common::String &filename, const char *data, int len, CMap *cmap); + static Common::List *_materials; + + Common::String _fname; + const ObjectPtr _cmap; + int _numImages; + int _width, _height; + void *_textures; + int _refCount; +}; class Material : public Object { public: - Material() { _width = 0; } // Load a texture from the given data. Material(const Common::String &filename, const char *data, int len, CMap *cmap); @@ -41,18 +54,16 @@ public: // Set which image in an animated texture to use void setNumber(int n) { _currImage = n; } - int getNumImages() const { return _numImages; } - int getCurrentImage() const { return _currImage; } - const Common::String &getFilename() { return _fname; } + int getNumImages() const; + int getCurrentImage() const; + const Common::String &getFilename() const; + MaterialData *getData() const; ~Material(); - Common::String _fname; - - const ObjectPtr _cmap; - int _numImages, _currImage; - int _width, _height; - void *_textures; +private: + MaterialData *_data; + int _currImage; }; } // end of namespace Grim diff --git a/engines/grim/model.cpp b/engines/grim/model.cpp index 0be30eef880..ba3f018c285 100644 --- a/engines/grim/model.cpp +++ b/engines/grim/model.cpp @@ -60,15 +60,11 @@ Model::Model(const Common::String &filename, const char *data, int len, CMap *cm void Model::reload(CMap *cmap) { // Load the new colormap for (int i = 0; i < _numMaterials; i++) { - _materials[i] = g_resourceloader->getMaterial(_materialNames[i], cmap); - } - Material **materials = new Material*[_numMaterials]; - for (int j = 0; j < _numMaterials; ++j) { - materials[j] = _materials[j]; + delete _materials[i]; + _materials[i] = g_resourceloader->loadMaterial(_materialNames[i], cmap); } for (int i = 0; i < _numGeosets; i++) - _geosets[i].changeMaterials(materials); - delete[] materials; + _geosets[i].changeMaterials(_materials); } void Model::loadEMI(Common::MemoryReadStream &ms) { @@ -83,7 +79,7 @@ void Model::loadEMI(Common::MemoryReadStream &ms) { ms.seek(48, SEEK_CUR); _numMaterials = ms.readUint32LE(); - _materials = new MaterialPtr[_numMaterials]; + _materials = new Material*[_numMaterials]; _materialNames = new char[_numMaterials][32]; for (int i = 0; i < _numMaterials; i++) { nameLength = ms.readUint32LE(); @@ -94,7 +90,7 @@ void Model::loadEMI(Common::MemoryReadStream &ms) { if (memcmp(_materialNames[i], "specialty", 9) == 0) { _materials[i] = 0; } else { - _materials[i] = g_resourceloader->getMaterial(_materialNames[i], 0); + _materials[i] = g_resourceloader->loadMaterial(_materialNames[i], 0); } ms.seek(4, SEEK_CUR); } @@ -106,24 +102,19 @@ void Model::loadEMI(Common::MemoryReadStream &ms) { void Model::loadBinary(const char *&data, CMap *cmap) { _numMaterials = READ_LE_UINT32(data + 4); data += 8; - _materials = new MaterialPtr[_numMaterials]; + _materials = new Material*[_numMaterials]; _materialNames = new char[_numMaterials][32]; for (int i = 0; i < _numMaterials; i++) { strcpy(_materialNames[i], data); - _materials[i] = g_resourceloader->getMaterial(_materialNames[i], cmap); + _materials[i] = g_resourceloader->loadMaterial(_materialNames[i], cmap); data += 32; } data += 32; // skip name _numGeosets = READ_LE_UINT32(data + 4); data += 8; _geosets = new Geoset[_numGeosets]; - Material **materials = new Material*[_numMaterials]; - for (int j = 0; j < _numMaterials; ++j) { - materials[j] = _materials[j]; - } for (int i = 0; i < _numGeosets; i++) - _geosets[i].loadBinary(data, materials); - delete[] materials; + _geosets[i].loadBinary(data, _materials); _numHierNodes = READ_LE_UINT32(data + 4); data += 8; _rootHierNode = new HierNode[_numHierNodes]; @@ -334,14 +325,14 @@ void Model::loadText(TextSplitter *ts, CMap *cmap) { ts->scanString("3do %d.%d", 2, &major, &minor); ts->expectString("section: modelresource"); ts->scanString("materials %d", 1, &_numMaterials); - _materials = new MaterialPtr[_numMaterials]; + _materials = new Material*[_numMaterials]; _materialNames = new char[_numMaterials][32]; for (int i = 0; i < _numMaterials; i++) { char materialName[32]; int num; ts->scanString("%d: %32s", 2, &num, materialName); - _materials[num] = g_resourceloader->getMaterial(materialName, cmap); + _materials[num] = g_resourceloader->loadMaterial(materialName, cmap); strcpy(_materialNames[num], materialName); } @@ -350,16 +341,11 @@ void Model::loadText(TextSplitter *ts, CMap *cmap) { ts->scanString("insert offset %f %f %f", 3, &_insertOffset.x(), &_insertOffset.y(), &_insertOffset.z()); ts->scanString("geosets %d", 1, &_numGeosets); _geosets = new Geoset[_numGeosets]; - Material **materials = new Material*[_numMaterials]; - for (int j = 0; j < _numMaterials; ++j) { - materials[j] = _materials[j]; - } for (int i = 0; i < _numGeosets; i++) { int num; ts->scanString("geoset %d", 1, &num); - _geosets[num].loadText(ts, materials); + _geosets[num].loadText(ts, _materials); } - delete[] materials; ts->expectString("section: hierarchydef"); ts->scanString("hierarchy nodes %d", 1, &_numHierNodes); diff --git a/engines/grim/model.h b/engines/grim/model.h index 259def6d04d..0e890b91be8 100644 --- a/engines/grim/model.h +++ b/engines/grim/model.h @@ -148,7 +148,7 @@ public: int _numMaterials; char (*_materialNames)[32]; - ObjectPtr *_materials; + Material **_materials; Graphics::Vector3d _insertOffset; int _numGeosets; Geoset *_geosets; diff --git a/engines/grim/resource.cpp b/engines/grim/resource.cpp index eb9b879f7f0..7b831bde432 100644 --- a/engines/grim/resource.cpp +++ b/engines/grim/resource.cpp @@ -101,7 +101,6 @@ ResourceLoader::~ResourceLoader() { delete r.resPtr; } clearList(_labs); - clearList(_materials); clearList(_models); clearList(_colormaps); clearList(_keyframeAnims); @@ -341,7 +340,6 @@ Material *ResourceLoader::loadMaterial(const Common::String &filename, CMap *c) } Material *result = new Material(fname, b->getData(), b->getLen(), c); - _materials.push_back(result); return result; } @@ -382,10 +380,6 @@ void ResourceLoader::uncache(const char *filename) { } } -void ResourceLoader::uncacheMaterial(Material *mat) { - _materials.remove(mat); -} - void ResourceLoader::uncacheModel(Model *m) { _models.remove(m); } @@ -406,19 +400,6 @@ void ResourceLoader::uncacheLipSync(LipSync *s) { _lipsyncs.remove(s); } -MaterialPtr ResourceLoader::getMaterial(const char *fname, CMap *c) { - Common::String filename = fname; - filename.toLowercase(); - for (Common::List::const_iterator i = _materials.begin(); i != _materials.end(); ++i) { - Material *m = *i; - if (filename.equals(m->_fname) && *m->_cmap == *c) { - return m; - } - } - - return loadMaterial(fname, c); -} - ModelPtr ResourceLoader::getModel(const Common::String &fname, CMap *c) { Common::String filename = fname; filename.toLowercase(); diff --git a/engines/grim/resource.h b/engines/grim/resource.h index 16d927e43aa..903fddb33c2 100644 --- a/engines/grim/resource.h +++ b/engines/grim/resource.h @@ -73,13 +73,11 @@ public: bool getFileExists(const Common::String &filename) const; int getFileLength(const char *filename) const; - MaterialPtr getMaterial(const char *filename, CMap *c); ModelPtr getModel(const Common::String &fname, CMap *c); CMapPtr getColormap(const Common::String &fname); KeyframeAnimPtr getKeyframe(const Common::String &fname); FontPtr getFont(const Common::String &fname); LipSyncPtr getLipSync(const Common::String &fname); - void uncacheMaterial(Material *m); void uncacheModel(Model *m); void uncacheColormap(CMap *c); void uncacheKeyframe(KeyframeAnim *kf); @@ -105,7 +103,6 @@ private: bool _cacheDirty; int32 _cacheMemorySize; - Common::List _materials; Common::List _models; Common::List _colormaps; Common::List _keyframeAnims;