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

node.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 AUTHORS
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 "engines/myst3/database.h"
00024 #include "engines/myst3/effects.h"
00025 #include "engines/myst3/node.h"
00026 #include "engines/myst3/myst3.h"
00027 #include "engines/myst3/state.h"
00028 #include "engines/myst3/subtitles.h"
00029 
00030 #include "common/config-manager.h"
00031 #include "common/debug.h"
00032 #include "common/rect.h"
00033 
00034 namespace Myst3 {
00035 
00036 void Face::setTextureFromJPEG(const ResourceDescription *jpegDesc) {
00037     _bitmap = Myst3Engine::decodeJpeg(jpegDesc);
00038     _texture = _vm->_gfx->createTexture(_bitmap);
00039 
00040     // Set the whole texture as dirty
00041     addTextureDirtyRect(Common::Rect(_bitmap->w, _bitmap->h));
00042 }
00043 
00044 Face::Face(Myst3Engine *vm) :
00045         _vm(vm),
00046         _textureDirty(true),
00047         _texture(0),
00048         _bitmap(0),
00049         _finalBitmap(0) {
00050 }
00051 
00052 void Face::addTextureDirtyRect(const Common::Rect &rect) {
00053     if (!_textureDirty) {
00054         _textureDirtyRect = rect;
00055     } else {
00056         _textureDirtyRect.extend(rect);
00057     }
00058 
00059     _textureDirty = true;
00060 }
00061 
00062 void Face::uploadTexture() {
00063     if (_textureDirty) {
00064         if (_finalBitmap)
00065             _texture->updatePartial(_finalBitmap, _textureDirtyRect);
00066         else
00067             _texture->updatePartial(_bitmap, _textureDirtyRect);
00068 
00069         _textureDirty = false;
00070     }
00071 }
00072 
00073 Face::~Face() {
00074     _bitmap->free();
00075     delete _bitmap;
00076     _bitmap = 0;
00077 
00078     if (_finalBitmap) {
00079         _finalBitmap->free();
00080         delete _finalBitmap;
00081     }
00082 
00083     if (_texture) {
00084         _vm->_gfx->freeTexture(_texture);
00085     }
00086 }
00087 
00088 Node::Node(Myst3Engine *vm, uint16 id) :
00089         _vm(vm),
00090         _id(id),
00091         _subtitles(nullptr) {
00092     for (uint i = 0; i < ARRAYSIZE(_faces); i++)
00093         _faces[i] = nullptr;
00094 }
00095 
00096 void Node::initEffects() {
00097     resetEffects();
00098 
00099     if (_vm->_state->getViewType() == kMenu) {
00100         // The node init script does not clear the magnet effect state.
00101         // Here we ignore effects on menu nodes so we don't try to
00102         // to load the magnet effect when opening the main menu on Amateria.
00103         return;
00104     }
00105 
00106     if (_vm->_state->getWaterEffects()) {
00107         Effect *effect = WaterEffect::create(_vm, _id);
00108         if (effect) {
00109             _effects.push_back(effect);
00110             _vm->_state->setWaterEffectActive(true);
00111         }
00112     }
00113 
00114     Effect *effect = MagnetEffect::create(_vm, _id);
00115     if (effect) {
00116         _effects.push_back(effect);
00117         _vm->_state->setMagnetEffectActive(true);
00118     }
00119 
00120     effect = LavaEffect::create(_vm, _id);
00121     if (effect) {
00122         _effects.push_back(effect);
00123         _vm->_state->setLavaEffectActive(true);
00124     }
00125 
00126     effect = ShieldEffect::create(_vm, _id);
00127     if (effect) {
00128         _effects.push_back(effect);
00129         _vm->_state->setShieldEffectActive(true);
00130     }
00131 }
00132 
00133 void Node::resetEffects() {
00134     for (uint i = 0; i < _effects.size(); i++) {
00135         delete _effects[i];
00136     }
00137     _effects.clear();
00138 }
00139 
00140 Node::~Node() {
00141     for (uint i = 0; i < _spotItems.size(); i++) {
00142         delete _spotItems[i];
00143     }
00144     _spotItems.clear();
00145 
00146     resetEffects();
00147 
00148     _vm->_state->setWaterEffectActive(false);
00149     _vm->_state->setMagnetEffectActive(false);
00150     _vm->_state->setLavaEffectActive(false);
00151     _vm->_state->setShieldEffectActive(false);
00152 
00153     for (int i = 0; i < 6; i++) {
00154         delete _faces[i];
00155     }
00156 
00157     delete _subtitles;
00158 }
00159 
00160 void Node::loadSpotItem(uint16 id, int16 condition, bool fade) {
00161     SpotItem *spotItem = new SpotItem(_vm);
00162 
00163     spotItem->setCondition(condition);
00164     spotItem->setFade(fade);
00165     spotItem->setFadeVar(abs(condition));
00166 
00167     for (int i = 0; i < 6; i++) {
00168         ResourceDescriptionArray spotItemImages = _vm->listFilesMatching("", id, i + 1, Archive::kLocalizedSpotItem);
00169 
00170         if (spotItemImages.empty())
00171             spotItemImages = _vm->listFilesMatching("", id, i + 1, Archive::kSpotItem);
00172 
00173         for (uint j = 0; j < spotItemImages.size(); j++) {
00174             const ResourceDescription &image = spotItemImages[j];
00175             ResourceDescription::SpotItemData spotItemData = image.getSpotItemData();
00176 
00177             SpotItemFace *spotItemFace = new SpotItemFace(
00178                     _faces[i],
00179                     spotItemData.u,
00180                     spotItemData.v);
00181 
00182             spotItemFace->loadData(&image);
00183 
00184             // SpotItems with an always true conditions cannot be undrawn.
00185             // Draw them now to make sure the "non drawn backups" for other, potentially
00186             // overlapping SpotItems have them drawn.
00187             if (condition == 1) {
00188                 spotItemFace->draw();
00189             }
00190 
00191             spotItem->addFace(spotItemFace);
00192         }
00193     }
00194 
00195     _spotItems.push_back(spotItem);
00196 }
00197 
00198 SpotItemFace *Node::loadMenuSpotItem(int16 condition, const Common::Rect &rect) {
00199     SpotItem *spotItem = new SpotItem(_vm);
00200 
00201     spotItem->setCondition(condition);
00202     spotItem->setFade(false);
00203     spotItem->setFadeVar(abs(condition));
00204 
00205     SpotItemFace *spotItemFace = new SpotItemFace(_faces[0], rect.left, rect.top);
00206     spotItemFace->initBlack(rect.width(), rect.height());
00207 
00208     spotItem->addFace(spotItemFace);
00209 
00210     _spotItems.push_back(spotItem);
00211 
00212     return spotItemFace;
00213 }
00214 
00215 void Node::loadSubtitles(uint32 id) {
00216     _subtitles = Subtitles::create(_vm, id);
00217 }
00218 
00219 bool Node::hasSubtitlesToDraw() {
00220     if (!_subtitles || _vm->_state->getSpotSubtitle() <= 0)
00221         return false;
00222 
00223     if (!_vm->isTextLanguageEnglish() && _vm->_state->getLocationRoom() == kRoomNarayan) {
00224         // The words written on the walls in Narayan are always in English.
00225         // Show the subtitles regardless of the "subtitles" setting if the game language is not English.
00226         return true;
00227     }
00228 
00229     return ConfMan.getBool("subtitles");
00230 }
00231 
00232 void Node::drawOverlay() {
00233     if (hasSubtitlesToDraw()) {
00234         uint subId = _vm->_state->getSpotSubtitle();
00235         _subtitles->setFrame(15 * subId + 1);
00236         _vm->_gfx->renderWindowOverlay(_subtitles);
00237     }
00238 }
00239 
00240 void Node::update() {
00241     // First undraw ...
00242     for (uint i = 0; i < _spotItems.size(); i++) {
00243         _spotItems[i]->updateUndraw();
00244     }
00245 
00246     // ... then redraw
00247     for (uint i = 0; i < _spotItems.size(); i++) {
00248         _spotItems[i]->updateDraw();
00249     }
00250 
00251     bool needsUpdate = false;
00252     for (uint i = 0; i < _effects.size(); i++) {
00253         needsUpdate |= _effects[i]->update();
00254     }
00255 
00256     // Apply the effects for all the faces
00257     for (uint faceId = 0; faceId < 6; faceId++) {
00258         Face *face = _faces[faceId];
00259 
00260         if (face == 0)
00261             continue; // No such face in this node
00262 
00263         if (!isFaceVisible(faceId)) {
00264             continue; // This face is not currently visible
00265         }
00266 
00267         uint effectsForFace = 0;
00268         for (uint i = 0; i < _effects.size(); i++) {
00269             if (_effects[i]->hasFace(faceId))
00270                 effectsForFace++;
00271         }
00272 
00273         if (effectsForFace == 0)
00274             continue;
00275         if (!needsUpdate && !face->isTextureDirty())
00276             continue;
00277 
00278         // Alloc the target surface if necessary
00279         if (!face->_finalBitmap) {
00280             face->_finalBitmap = new Graphics::Surface();
00281         }
00282         face->_finalBitmap->copyFrom(*face->_bitmap);
00283 
00284         if (effectsForFace == 1) {
00285             _effects[0]->applyForFace(faceId, face->_bitmap, face->_finalBitmap);
00286 
00287             face->addTextureDirtyRect(_effects[0]->getUpdateRectForFace(faceId));
00288         } else if (effectsForFace == 2) {
00289             // TODO: Keep the same temp surface to avoid heap fragmentation ?
00290             Graphics::Surface *tmp = new Graphics::Surface();
00291             tmp->copyFrom(*face->_bitmap);
00292 
00293             _effects[0]->applyForFace(faceId, face->_bitmap, tmp);
00294             _effects[1]->applyForFace(faceId, tmp, face->_finalBitmap);
00295 
00296             tmp->free();
00297             delete tmp;
00298 
00299             face->addTextureDirtyRect(_effects[0]->getUpdateRectForFace(faceId));
00300             face->addTextureDirtyRect(_effects[1]->getUpdateRectForFace(faceId));
00301         } else {
00302             error("Unable to render more than 2 effects per faceId (%d)", effectsForFace);
00303         }
00304     }
00305 }
00306 
00307 SpotItem::SpotItem(Myst3Engine *vm) :
00308     _vm(vm) {
00309 }
00310 
00311 SpotItem::~SpotItem() {
00312     for (uint i = 0; i < _faces.size(); i++) {
00313         delete _faces[i];
00314     }
00315 }
00316 
00317 void SpotItem::updateUndraw() {
00318     for (uint i = 0; i < _faces.size(); i++) {
00319         if (!_vm->_state->evaluate(_condition) && _faces[i]->isDrawn()) {
00320             _faces[i]->undraw();
00321         }
00322     }
00323 }
00324 
00325 void SpotItem::updateDraw() {
00326     for (uint i = 0; i < _faces.size(); i++) {
00327         if (_enableFade) {
00328             uint16 newFadeValue = _vm->_state->getVar(_fadeVar);
00329 
00330             if (_faces[i]->getFadeValue() != newFadeValue) {
00331                 _faces[i]->setFadeValue(newFadeValue);
00332                 _faces[i]->setDrawn(false);
00333             }
00334         }
00335 
00336         if (_vm->_state->evaluate(_condition) && !_faces[i]->isDrawn()) {
00337             if (_enableFade)
00338                 _faces[i]->fadeDraw();
00339             else
00340                 _faces[i]->draw();
00341         }
00342     }
00343 }
00344 
00345 SpotItemFace::SpotItemFace(Face *face, uint16 posX, uint16 posY):
00346         _face(face),
00347         _posX(posX),
00348         _posY(posY),
00349         _drawn(false),
00350         _bitmap(0),
00351         _notDrawnBitmap(0),
00352         _fadeValue(0) {
00353 }
00354 
00355 SpotItemFace::~SpotItemFace() {
00356     if (_bitmap) {
00357         _bitmap->free();
00358         delete _bitmap;
00359         _bitmap = 0;
00360     }
00361 
00362     if (_notDrawnBitmap) {
00363         _notDrawnBitmap->free();
00364         delete _notDrawnBitmap;
00365         _notDrawnBitmap = 0;
00366     }
00367 }
00368 
00369 void SpotItemFace::initBlack(uint16 width, uint16 height) {
00370     if (_bitmap) {
00371         _bitmap->free();
00372     }
00373 
00374     _bitmap = new Graphics::Surface();
00375     _bitmap->create(width, height, Texture::getRGBAPixelFormat());
00376 
00377     initNotDrawn(width, height);
00378 
00379     _drawn = false;
00380 }
00381 
00382 void SpotItemFace::loadData(const ResourceDescription *jpegDesc) {
00383     // Convert active SpotItem image to raw data
00384     _bitmap = Myst3Engine::decodeJpeg(jpegDesc);
00385 
00386     initNotDrawn(_bitmap->w, _bitmap->h);
00387 }
00388 
00389 void SpotItemFace::updateData(const Graphics::Surface *surface) {
00390     assert(_bitmap && surface);
00391     assert(surface->format == Texture::getRGBAPixelFormat());
00392 
00393     _bitmap->free();
00394     _bitmap->copyFrom(*surface);
00395 
00396     _drawn = false;
00397 }
00398 
00399 void SpotItemFace::clear() {
00400     memset(_bitmap->getPixels(), 0, _bitmap->pitch * _bitmap->h);
00401 
00402     _drawn = false;
00403 }
00404 
00405 void SpotItemFace::initNotDrawn(uint16 width, uint16 height) {
00406     // Copy not drawn SpotItem image from face
00407     _notDrawnBitmap = new Graphics::Surface();
00408     _notDrawnBitmap->create(width, height, Texture::getRGBAPixelFormat());
00409 
00410     for (uint i = 0; i < height; i++) {
00411         memcpy(_notDrawnBitmap->getBasePtr(0, i),
00412                 _face->_bitmap->getBasePtr(_posX, _posY + i), width * 4);
00413     }
00414 }
00415 
00416 Common::Rect SpotItemFace::getFaceRect() const {
00417     assert(_bitmap);
00418 
00419     Common::Rect r = Common::Rect(_bitmap->w, _bitmap->h);
00420     r.translate(_posX, _posY);
00421     return r;
00422 }
00423 
00424 void SpotItemFace::draw() {
00425     for (uint i = 0; i < _bitmap->h; i++) {
00426         memcpy(_face->_bitmap->getBasePtr(_posX, _posY + i),
00427                 _bitmap->getBasePtr(0, i),
00428                 _bitmap->w * 4);
00429     }
00430 
00431     _drawn = true;
00432     _face->addTextureDirtyRect(getFaceRect());
00433 }
00434 
00435 void SpotItemFace::undraw() {
00436     for (uint i = 0; i < _notDrawnBitmap->h; i++) {
00437         memcpy(_face->_bitmap->getBasePtr(_posX, _posY + i),
00438                 _notDrawnBitmap->getBasePtr(0, i),
00439                 _notDrawnBitmap->w * 4);
00440     }
00441 
00442     _drawn = false;
00443     _face->addTextureDirtyRect(getFaceRect());
00444 }
00445 
00446 void SpotItemFace::fadeDraw() {
00447     uint16 fadeValue = CLIP<uint16>(_fadeValue, 0, 100);
00448 
00449     for (int i = 0; i < _bitmap->h; i++) {
00450         byte *ptrND = (byte *)_notDrawnBitmap->getBasePtr(0, i);
00451         byte *ptrD = (byte *)_bitmap->getBasePtr(0, i);
00452         byte *ptrDest = (byte *)_face->_bitmap->getBasePtr(_posX, _posY + i);
00453 
00454         for (int j = 0; j < _bitmap->w; j++) {
00455             byte rND = *ptrND++;
00456             byte gND = *ptrND++;
00457             byte bND = *ptrND++;
00458             ptrND++; // Alpha
00459             byte rD = *ptrD++;
00460             byte gD = *ptrD++;
00461             byte bD = *ptrD++;
00462             ptrD++; // Alpha
00463 
00464             // TODO: optimize ?
00465             *ptrDest++ = rND * (100 - fadeValue) / 100 + rD * fadeValue / 100;
00466             *ptrDest++ = gND * (100 - fadeValue) / 100 + gD * fadeValue / 100;
00467             *ptrDest++ = bND * (100 - fadeValue) / 100 + bD * fadeValue / 100;
00468             ptrDest++; // Alpha
00469         }
00470     }
00471 
00472     _drawn = true;
00473     _face->addTextureDirtyRect(getFaceRect());
00474 }
00475 
00476 } // end of namespace Myst3


Generated on Sat Sep 19 2020 05:01:30 for ResidualVM by doxygen 1.7.1
curved edge   curved edge