GRIM: Make Material implicitly shared. Cleaned up Model a lot.

This commit is contained in:
Giulio Camuffo 2011-07-18 22:16:40 +02:00
parent 111d0454fd
commit cabd0d583f
12 changed files with 117 additions and 91 deletions

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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 *> *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<MaterialData *>();
}
for (Common::List<MaterialData *>::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

View File

@ -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<MaterialData *> *_materials;
Common::String _fname;
const ObjectPtr<CMap> _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> _cmap;
int _numImages, _currImage;
int _width, _height;
void *_textures;
private:
MaterialData *_data;
int _currImage;
};
} // end of namespace Grim

View File

@ -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);

View File

@ -148,7 +148,7 @@ public:
int _numMaterials;
char (*_materialNames)[32];
ObjectPtr<Material> *_materials;
Material **_materials;
Graphics::Vector3d _insertOffset;
int _numGeosets;
Geoset *_geosets;

View File

@ -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<Material *>::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();

View File

@ -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<Material *> _materials;
Common::List<Model *> _models;
Common::List<CMap *> _colormaps;
Common::List<KeyframeAnim *> _keyframeAnims;