ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

material.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/endian.h"
00024 #include "image/tga.h"
00025 #include "graphics/surface.h"
00026 
00027 #include "engines/grim/grim.h"
00028 #include "engines/grim/debug.h"
00029 #include "engines/grim/material.h"
00030 #include "engines/grim/gfx_base.h"
00031 #include "engines/grim/colormap.h"
00032 #include "engines/grim/resource.h"
00033 #include "engines/grim/textsplit.h"
00034 
00035 namespace Grim {
00036 
00037 Common::List<MaterialData *> *MaterialData::_materials = nullptr;
00038 
00039 MaterialData::MaterialData(const Common::String &filename, Common::SeekableReadStream *data, CMap *cmap) :
00040         _fname(filename), _cmap(cmap), _refCount(1), _textures(nullptr) {
00041 
00042     if (g_grim->getGameType() == GType_MONKEY4) {
00043         initEMI(data);
00044     } else {
00045         initGrim(data);
00046     }
00047 }
00048 
00049 void MaterialData::initGrim(Common::SeekableReadStream *data) {
00050     uint32 tag = data->readUint32BE();
00051     if (tag != MKTAG('M','A','T',' '))
00052         error("Invalid header for texture %s. Expected 'MAT ', got '%c%c%c%c'", _fname.c_str(),
00053                          (tag >> 24) & 0xFF, (tag >> 16) & 0xFF, (tag >> 8) & 0xFF, tag & 0xFF);
00054 
00055     data->seek(12, SEEK_SET);
00056     _numImages = data->readUint32LE();
00057     _textures = new Texture*[_numImages];
00058     /* Discovered by diffing orange.mat with pink.mat and blue.mat .
00059      * Actual meaning unknown, so I prefer to use it as an enum-ish
00060      * at the moment, to detect unexpected values.
00061      */
00062     data->seek(0x4c, SEEK_SET);
00063     uint32 offset = data->readUint32LE();
00064     if (offset == 0x8)
00065         offset = 16;
00066     else if (offset != 0)
00067         error("Unknown offset: %d", offset);
00068 
00069     data->seek(60 + _numImages * 40 + offset, SEEK_SET);
00070     for (int i = 0; i < _numImages; ++i) {
00071         Texture *t = _textures[i] = new Texture();
00072         t->_width = data->readUint32LE();
00073         t->_height = data->readUint32LE();
00074         t->_hasAlpha = data->readUint32LE();
00075         t->_texture = nullptr;
00076         t->_colorFormat = BM_RGBA;
00077         t->_data = nullptr;
00078         if (t->_width == 0 || t->_height == 0) {
00079             Debug::warning(Debug::Materials, "skip load texture: bad texture size (%dx%d) for texture %d of material %s",
00080                            t->_width, t->_height, i, _fname.c_str());
00081             break;
00082         }
00083         t->_data = new uint8[t->_width * t->_height];
00084         data->seek(12, SEEK_CUR);
00085         data->read(t->_data, t->_width * t->_height);
00086     }
00087 }
00088 
00089 void loadTGA(Common::SeekableReadStream *data, Texture *t) {
00090     Image::TGADecoder *tgaDecoder = new Image::TGADecoder();
00091     tgaDecoder->loadStream(*data);
00092     const Graphics::Surface *tgaSurface = tgaDecoder->getSurface();
00093 
00094     t->_width = tgaSurface->w;
00095     t->_height = tgaSurface->h;
00096     t->_texture = nullptr;
00097 
00098     int bpp = tgaSurface->format.bytesPerPixel;
00099     if (bpp == 4) {
00100         t->_colorFormat = BM_BGRA;
00101         t->_bpp = 4;
00102         t->_hasAlpha = true;
00103     } else {
00104         t->_colorFormat = BM_BGR888;
00105         t->_bpp = 3;
00106         t->_hasAlpha = false;
00107     }
00108 
00109     assert(bpp == 3 || bpp == 4); // Assure we have 24/32 bpp
00110 
00111     // Allocate room for the texture.
00112     t->_data = new uint8[t->_width * t->_height * (bpp)];
00113 
00114     // Copy the texture data, as the decoder owns the current copy.
00115     memcpy(t->_data, tgaSurface->getPixels(), t->_width * t->_height * (bpp));
00116 
00117     delete tgaDecoder;
00118 }
00119 
00120 void MaterialData::initEMI(Common::SeekableReadStream *data) {
00121 
00122     if (_fname.hasSuffix(".sur")) {  // This expects that we want all the materials in the sur-file
00123         Common::Array<Common::String> texFileNames;
00124         char readFileName[64];
00125         TextSplitter *ts = new TextSplitter(_fname, data);
00126         ts->setLineNumber(2); // Skip copyright-line
00127         ts->expectString("version\t1.0");
00128         if (ts->checkString("name:"))
00129             ts->scanString("name:%s", 1, readFileName);
00130 
00131         while (!ts->checkString("END_OF_SECTION")) {
00132             ts->scanString("tex:%s", 1, readFileName);
00133             Common::String mFileName(readFileName);
00134             texFileNames.push_back(ResourceLoader::fixFilename(mFileName, false));
00135         }
00136         _textures = new Texture*[texFileNames.size()];
00137         for (uint i = 0; i < texFileNames.size(); i++) {
00138             Common::String name = texFileNames[i];
00139             if (name.hasPrefix("specialty")) {
00140                 _textures[i] = g_driver->getSpecialtyTexturePtr(name);
00141             } else {
00142                 _textures[i] = new Texture();
00143                 Common::SeekableReadStream *texData = g_resourceloader->openNewStreamFile(texFileNames[i].c_str(), true);
00144                 if (!texData) {
00145                     warning("Couldn't find tex-file: %s", texFileNames[i].c_str());
00146                     _textures[i]->_width = 0;
00147                     _textures[i]->_height = 0;
00148                     _textures[i]->_texture = new int(1); // HACK to avoid initializing.
00149                     _textures[i]->_data = nullptr;
00150                     continue;
00151                 }
00152                 loadTGA(texData, _textures[i]);
00153                 delete texData;
00154             }
00155         }
00156         _numImages = texFileNames.size();
00157         delete ts;
00158         return;
00159     } else if (_fname.hasSuffix(".tga")) {
00160         _numImages = 1;
00161         _textures = new Texture*[1];
00162         _textures[0] = new Texture();
00163         loadTGA(data, _textures[0]);
00164         return;
00165     } else if (_fname.hasPrefix("specialty")) {
00166         _numImages = 1;
00167         _textures = new Texture*[1];
00168         _textures[0] = g_driver->getSpecialtyTexturePtr(_fname);
00169     } else {
00170         warning("Unknown material-format: %s", _fname.c_str());
00171     }
00172 }
00173 
00174 MaterialData::~MaterialData() {
00175     _materials->remove(this);
00176     if (_materials->empty()) {
00177         delete _materials;
00178         _materials = nullptr;
00179     }
00180 
00181     for (int i = 0; i < _numImages; ++i) {
00182         Texture *t = _textures[i];
00183         if (!t) continue;
00184         if (t->_isShared) continue; // don't delete specialty textures
00185         if (t->_width && t->_height && t->_texture)
00186             g_driver->destroyTexture(t);
00187         delete[] t->_data;
00188         delete t;
00189     }
00190     delete[] _textures;
00191 }
00192 
00193 MaterialData *MaterialData::getMaterialData(const Common::String &filename, Common::SeekableReadStream *data, CMap *cmap) {
00194     if (!_materials) {
00195         _materials = new Common::List<MaterialData *>();
00196     }
00197 
00198     for (Common::List<MaterialData *>::iterator i = _materials->begin(); i != _materials->end(); ++i) {
00199         MaterialData *m = *i;
00200         if (m->_fname == filename && g_grim->getGameType() == GType_MONKEY4) {
00201             ++m->_refCount;
00202             return m;
00203         }
00204         if (m->_fname == filename && m->_cmap->getFilename() == cmap->getFilename()) {
00205             ++m->_refCount;
00206             return m;
00207         }
00208     }
00209 
00210     MaterialData *m = new MaterialData(filename, data, cmap);
00211     _materials->push_back(m);
00212     return m;
00213 }
00214 
00215 Material::Material(const Common::String &filename, Common::SeekableReadStream *data, CMap *cmap, bool clamp) :
00216         Object(), _currImage(0) {
00217     _data = MaterialData::getMaterialData(filename, data, cmap);
00218     _clampTexture = clamp;
00219 }
00220 
00221 Material::Material() :
00222         Object(), _currImage(0), _data(nullptr), _clampTexture(false) {
00223 }
00224 
00225 void Material::reload(CMap *cmap) {
00226     Common::String fname = _data->_fname;
00227     --_data->_refCount;
00228     if (_data->_refCount < 1) {
00229         delete _data;
00230     }
00231 
00232     Material *m = g_resourceloader->loadMaterial(fname, cmap, _clampTexture);
00233     // Steal the data from the new material and discard it.
00234     _data = m->_data;
00235     ++_data->_refCount;
00236     delete m;
00237 }
00238 
00239 void Material::select() const {
00240     Texture *t = _data->_textures[_currImage];
00241     if (t && t->_width && t->_height) {
00242         if (!t->_texture) {
00243             g_driver->createTexture(t, (uint8 *)t->_data, _data->_cmap, _clampTexture);
00244             delete[] t->_data;
00245             t->_data = nullptr;
00246         }
00247         g_driver->selectTexture(t);
00248     } else {
00249         warning("Can't select material: %s", getFilename().c_str());
00250     }
00251 }
00252 
00253 Material::~Material() {
00254     if (_data) {
00255         --_data->_refCount;
00256         if (_data->_refCount < 1) {
00257             delete _data;
00258         }
00259     }
00260 }
00261 
00262 void Material::setActiveTexture(int n) {
00263     _currImage = n;
00264 }
00265 
00266 int Material::getNumTextures() const {
00267     return _data->_numImages;
00268 }
00269 
00270 int Material::getActiveTexture() const {
00271     return _currImage;
00272 }
00273 
00274 const Common::String &Material::getFilename() const {
00275     return _data->_fname;
00276 }
00277 
00278 MaterialData *Material::getData() const {
00279     return _data;
00280 }
00281 
00282 } // end of namespace Grim


Generated on Sat Mar 16 2019 05:01:45 for ResidualVM by doxygen 1.7.1
curved edge   curved edge