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

set.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 "common/foreach.h"
00024 
00025 #include "engines/grim/debug.h"
00026 #include "engines/grim/set.h"
00027 #include "engines/grim/textsplit.h"
00028 #include "engines/grim/colormap.h"
00029 #include "engines/grim/grim.h"
00030 #include "engines/grim/savegame.h"
00031 #include "engines/grim/resource.h"
00032 #include "engines/grim/bitmap.h"
00033 #include "engines/grim/gfx_base.h"
00034 
00035 #include "engines/grim/sound.h"
00036 #include "engines/grim/emi/sound/emisound.h"
00037 
00038 #include "math/frustum.h"
00039 
00040 namespace Grim {
00041 
00042 Set::Set(const Common::String &sceneName, Common::SeekableReadStream *data) :
00043         _locked(false), _name(sceneName), _enableLights(false) {
00044 
00045     char header[7];
00046     data->read(header, 7);
00047     data->seek(0, SEEK_SET);
00048     if (memcmp(header, "section", 7) == 0) {
00049         TextSplitter ts(_name, data);
00050         loadText(ts);
00051     } else {
00052         loadBinary(data);
00053     }
00054     setupOverworldLights();
00055 }
00056 
00057 Set::Set() :
00058         _cmaps(nullptr), _locked(false), _enableLights(false), _numSetups(0),
00059         _numLights(0), _numSectors(0), _numObjectStates(0), _minVolume(0),
00060         _maxVolume(0), _numCmaps(0), _numShadows(0), _currSetup(nullptr),
00061         _setups(nullptr), _lights(nullptr), _sectors(nullptr), _shadows(nullptr) {
00062 
00063     setupOverworldLights();
00064 }
00065 
00066 Set::~Set() {
00067     if (_cmaps || g_grim->getGameType() == GType_MONKEY4) {
00068         delete[] _cmaps;
00069         for (int i = 0; i < _numSetups; ++i) {
00070             delete _setups[i]._bkgndBm;
00071             delete _setups[i]._bkgndZBm;
00072         }
00073         delete[] _setups;
00074         turnOffLights();
00075         delete[] _lights;
00076         for (int i = 0; i < _numSectors; ++i) {
00077             delete _sectors[i];
00078         }
00079         delete[] _sectors;
00080         while (!_states.empty()) {
00081             ObjectState *s = _states.front();
00082             _states.pop_front();
00083             delete s;
00084         }
00085         delete[] _shadows;
00086     }
00087     foreach (Light *l, _overworldLightsList) {
00088         delete l;
00089     }
00090 }
00091 
00092 void Set::setupOverworldLights() {
00093     Light *l;
00094 
00095     l = new Light();
00096     l->_name = "Overworld Light 1";
00097     l->_enabled = true;
00098     l->_type = Light::Ambient;
00099     l->_pos = Math::Vector3d(0, 0, 0);
00100     l->_dir = Math::Vector3d(0, 0, 0);
00101     l->_color = Color(255, 255, 255);
00102     l->setIntensity(0.5f);
00103     _overworldLightsList.push_back(l);
00104 
00105     l = new Light();
00106     l->_name = "Overworld Light 2";
00107     l->_enabled = true;
00108     l->_type = Light::Direct;
00109     l->_pos = Math::Vector3d(0, 0, 0);
00110     l->_dir = Math::Vector3d(0, 0, -1);
00111     l->_color = Color(255, 255, 255);
00112     l->setIntensity(0.6f);
00113     _overworldLightsList.push_back(l);
00114 }
00115 
00116 void Set::loadText(TextSplitter &ts) {
00117     char tempBuf[256];
00118 
00119     ts.expectString("section: colormaps");
00120     ts.scanString(" numcolormaps %d", 1, &_numCmaps);
00121     _cmaps = new ObjectPtr<CMap>[_numCmaps];
00122     char cmap_name[256];
00123     for (int i = 0; i < _numCmaps; i++) {
00124         ts.scanString(" colormap %256s", 1, cmap_name);
00125         _cmaps[i] = g_resourceloader->getColormap(cmap_name);
00126     }
00127 
00128     if (ts.checkString("section: objectstates") || ts.checkString("sections: object_states")) {
00129         ts.nextLine();
00130         ts.scanString(" tot_objects %d", 1, &_numObjectStates);
00131         char object_name[256];
00132         for (int l = 0; l < _numObjectStates; l++) {
00133             ts.scanString(" object %256s", 1, object_name);
00134         }
00135     } else {
00136         _numObjectStates = 0;
00137     }
00138 
00139     ts.expectString("section: setups");
00140     ts.scanString(" numsetups %d", 1, &_numSetups);
00141     _setups = new Setup[_numSetups];
00142     for (int i = 0; i < _numSetups; i++)
00143         _setups[i].load(this, i, ts);
00144     _currSetup = _setups;
00145 
00146     _numShadows = 0;
00147     _numSectors = -1;
00148     _numLights = -1;
00149     _lights = nullptr;
00150     _sectors = nullptr;
00151     _shadows = nullptr;
00152 
00153     _minVolume = 0;
00154     _maxVolume = 0;
00155 
00156     // Lights are optional
00157     if (ts.isEof())
00158         return;
00159 
00160     ts.expectString("section: lights");
00161     ts.scanString(" numlights %d", 1, &_numLights);
00162     _lights = new Light[_numLights];
00163     for (int i = 0; i < _numLights; i++) {
00164         _lights[i].load(ts);
00165         _lights[i]._id = i;
00166         _lightsList.push_back(&_lights[i]);
00167     }
00168 
00169     // Calculate the number of sectors
00170     ts.expectString("section: sectors");
00171     if (ts.isEof()) // Sectors are optional, but section: doesn't seem to be
00172         return;
00173 
00174     int sectorStart = ts.getLineNumber();
00175     _numSectors = 0;
00176     // Find the number of sectors (while the sectors usually
00177     // count down from the highest number there are a few
00178     // cases where they count up, see hh.set for example)
00179     while (!ts.isEof()) {
00180         ts.scanString(" %s", 1, tempBuf);
00181         if (!scumm_stricmp(tempBuf, "sector"))
00182             _numSectors++;
00183     }
00184     // Allocate and fill an array of sector info
00185     _sectors = new Sector*[_numSectors];
00186     ts.setLineNumber(sectorStart);
00187     for (int i = 0; i < _numSectors; i++) {
00188         // Use the ids as index for the sector in the array.
00189         // This way when looping they are checked from the id 0 sto the last,
00190         // which seems important for sets with overlapping camera sectors, like ga.set.
00191         Sector *s = new Sector();
00192         s->load(ts);
00193         _sectors[s->getSectorId()] = s;
00194     }
00195 }
00196 
00197 void Set::loadBinary(Common::SeekableReadStream *data) {
00198     // yes, an array of size 0
00199     _cmaps = nullptr;//new CMapPtr[0];
00200     _numCmaps = 0;
00201     _numObjectStates = 0;
00202 
00203 
00204     _numSetups = data->readUint32LE();
00205     _setups = new Setup[_numSetups];
00206     for (int i = 0; i < _numSetups; i++)
00207         _setups[i].loadBinary(data);
00208     _currSetup = _setups;
00209 
00210     _numSectors = 0;
00211     _numLights = 0;
00212     _lights = nullptr;
00213     _sectors = nullptr;
00214     _shadows = nullptr;
00215 
00216     _minVolume = 0;
00217     _maxVolume = 0;
00218 
00219     // the rest may or may not be optional. Might be a good idea to check if there is no more data.
00220 
00221     _numLights = data->readUint32LE();
00222     _lights = new Light[_numLights];
00223     for (int i = 0; i < _numLights; i++) {
00224         _lights[i].loadBinary(data);
00225         _lights[i]._id = i;
00226         _lightsList.push_back(&_lights[i]);
00227     }
00228 
00229     _numSectors = data->readUint32LE();
00230     // Allocate and fill an array of sector info
00231     _sectors = new Sector*[_numSectors];
00232     for (int i = 0; i < _numSectors; i++) {
00233         _sectors[i] = new Sector();
00234         _sectors[i]->loadBinary(data);
00235     }
00236 
00237     _numShadows = data->readUint32LE();
00238     _shadows = new SetShadow[_numShadows];
00239 
00240     for (int i = 0; i < _numShadows; ++i) {
00241         _shadows[i].loadBinary(data, this);
00242     }
00243 
00244     // Enable lights by default
00245     _enableLights = true;
00246 }
00247 
00248 void Set::saveState(SaveGame *savedState) const {
00249     savedState->writeString(_name);
00250     if (g_grim->getGameType() == GType_GRIM) {
00251         savedState->writeLESint32(_numCmaps);
00252         for (int i = 0; i < _numCmaps; ++i) {
00253             savedState->writeString(_cmaps[i]->getFilename());
00254         }
00255     }
00256     savedState->writeLEUint32((uint32)(_currSetup - _setups)); // current setup id
00257     savedState->writeBool(_locked);
00258     savedState->writeBool(_enableLights);
00259     savedState->writeLESint32(_minVolume);
00260     savedState->writeLESint32(_maxVolume);
00261 
00262     savedState->writeLEUint32(_states.size());
00263     for (StateList::const_iterator i = _states.begin(); i != _states.end(); ++i) {
00264         savedState->writeLESint32((*i)->getId());
00265     }
00266 
00267     //Setups
00268     savedState->writeLESint32(_numSetups);
00269     for (int i = 0; i < _numSetups; ++i) {
00270         _setups[i].saveState(savedState);
00271     }
00272 
00273     //Sectors
00274     savedState->writeLESint32(_numSectors);
00275     for (int i = 0; i < _numSectors; ++i) {
00276         _sectors[i]->saveState(savedState);
00277     }
00278 
00279     //Lights
00280     savedState->writeLESint32(_numLights);
00281     for (int i = 0; i < _numLights; ++i) {
00282         _lights[i].saveState(savedState);
00283     }
00284 
00285     //Shadows
00286     savedState->writeLESint32(_numShadows);
00287     for (int i = 0; i < _numShadows; ++i) {
00288         _shadows[i].saveState(savedState);
00289     }
00290 }
00291 
00292 bool Set::restoreState(SaveGame *savedState) {
00293     _name = savedState->readString();
00294     if (g_grim->getGameType() == GType_GRIM) {
00295         _numCmaps = savedState->readLESint32();
00296         _cmaps = new CMapPtr[_numCmaps];
00297         for (int i = 0; i < _numCmaps; ++i) {
00298             Common::String str = savedState->readString();
00299             _cmaps[i] = g_resourceloader->getColormap(str);
00300         }
00301     }
00302 
00303     int32 currSetupId = savedState->readLEUint32();
00304     _locked           = savedState->readBool();
00305     _enableLights     = savedState->readBool();
00306     _minVolume        = savedState->readLESint32();
00307     _maxVolume        = savedState->readLESint32();
00308 
00309     _numObjectStates = savedState->readLESint32();
00310     _states.clear();
00311     for (int i = 0; i < _numObjectStates; ++i) {
00312         int32 id = savedState->readLESint32();
00313         ObjectState *o = ObjectState::getPool().getObject(id);
00314         _states.push_back(o);
00315     }
00316 
00317     //Setups
00318     _numSetups = savedState->readLESint32();
00319     _setups = new Setup[_numSetups];
00320     _currSetup = _setups + currSetupId;
00321     for (int i = 0; i < _numSetups; ++i) {
00322         _setups[i].restoreState(savedState);
00323     }
00324 
00325     //Sectors
00326     _numSectors = savedState->readLESint32();
00327     if (_numSectors > 0) {
00328         _sectors = new Sector*[_numSectors];
00329         for (int i = 0; i < _numSectors; ++i) {
00330             _sectors[i] = new Sector();
00331             _sectors[i]->restoreState(savedState);
00332         }
00333     } else {
00334         _sectors = nullptr;
00335     }
00336 
00337     _numLights = savedState->readLESint32();
00338     _lights = new Light[_numLights];
00339     for (int i = 0; i < _numLights; i++) {
00340         _lights[i].restoreState(savedState);
00341         _lights[i]._id = i;
00342         _lightsList.push_back(&_lights[i]);
00343     }
00344 
00345     if (savedState->saveMinorVersion() >= 19) {
00346         _numShadows = savedState->readLESint32();
00347         _shadows = new SetShadow[_numShadows];
00348         for (int i = 0; i < _numShadows; ++i) {
00349             _shadows[i].restoreState(savedState);
00350         }
00351     }
00352 
00353     return true;
00354 }
00355 
00356 void Set::Setup::load(Set *set, int id, TextSplitter &ts) {
00357     char buf[256];
00358 
00359     ts.scanString(" setup %256s", 1, buf);
00360     _name = buf;
00361 
00362     ts.scanString(" background %256s", 1, buf);
00363     _bkgndBm = loadBackground(buf);
00364 
00365     // ZBuffer is optional
00366     _bkgndZBm = nullptr;
00367     if (ts.checkString("zbuffer")) {
00368         ts.scanString(" zbuffer %256s", 1, buf);
00369         // Don't even try to load if it's the "none" bitmap
00370         if (strcmp(buf, "<none>.lbm") != 0) {
00371             _bkgndZBm = Bitmap::create(buf);
00372             Debug::debug(Debug::Bitmaps | Debug::Sets,
00373                          "Loading scene z-buffer bitmap: %s\n", buf);
00374         }
00375     }
00376 
00377     ts.scanString(" position %f %f %f", 3, &_pos.x(), &_pos.y(), &_pos.z());
00378     ts.scanString(" interest %f %f %f", 3, &_interest.x(), &_interest.y(), &_interest.z());
00379     ts.scanString(" roll %f", 1, &_roll);
00380     ts.scanString(" fov %f", 1, &_fov);
00381     ts.scanString(" nclip %f", 1, &_nclip);
00382     ts.scanString(" fclip %f", 1, &_fclip);
00383     for (;;) {
00384         char name[256], zname[256];
00385         char bitmap[256], zbitmap[256];
00386         zbitmap[0] = '\0';
00387         if (ts.checkString("object_art"))
00388             ts.scanString(" object_art %256s %256s", 2, name, bitmap);
00389         else
00390             break;
00391         if (ts.checkString("object_z"))
00392             ts.scanString(" object_z %256s %256s", 2, zname, zbitmap);
00393 
00394         if (zbitmap[0] == '\0' || strcmp(name, zname) == 0) {
00395             set->addObjectState(id, ObjectState::OBJSTATE_BACKGROUND, bitmap, zbitmap, true);
00396         }
00397     }
00398 }
00399 
00400 void Set::Setup::loadBinary(Common::SeekableReadStream *data) {
00401     char name[128];
00402     data->read(name, 128);
00403     _name = Common::String(name);
00404 
00405     // Skip an unknown number (this is the stringlength of the following string)
00406     int fNameLen = 0;
00407     fNameLen = data->readUint32LE();
00408 
00409     char *fileName = new char[fNameLen];
00410     data->read(fileName, fNameLen);
00411 
00412     _bkgndZBm = nullptr;
00413     _bkgndBm = loadBackground(fileName);
00414 
00415     _pos.readFromStream(data);
00416 
00417     Math::Quaternion q;
00418     q.readFromStream(data);
00419     q.toMatrix(_rot);
00420 
00421     _fov   = data->readFloatLE();
00422     _nclip = data->readFloatLE();
00423     _fclip = data->readFloatLE();
00424 
00425     delete[] fileName;
00426 }
00427 
00428 void Set::Setup::saveState(SaveGame *savedState) const {
00429     //name
00430     savedState->writeString(_name);
00431 
00432     //bkgndBm
00433     if (_bkgndBm) {
00434         savedState->writeLESint32(_bkgndBm->getId());
00435     } else {
00436         savedState->writeLESint32(0);
00437     }
00438 
00439     //bkgndZBm
00440     if (_bkgndZBm) {
00441         savedState->writeLESint32(_bkgndZBm->getId());
00442     } else {
00443         savedState->writeLESint32(0);
00444     }
00445 
00446     savedState->writeVector3d(_pos);
00447     if (g_grim->getGameType() == GType_MONKEY4) {
00448         // Get the rotation matrix as a quaternion and write it out
00449         Math::Quaternion q(_rot);
00450         savedState->writeFloat(q.x());
00451         savedState->writeFloat(q.y());
00452         savedState->writeFloat(q.z());
00453         savedState->writeFloat(q.w());
00454     } else {
00455         savedState->writeVector3d(_interest);
00456         savedState->writeFloat(_roll);
00457     }
00458     savedState->writeFloat(_fov);
00459     savedState->writeFloat(_nclip);
00460     savedState->writeFloat(_fclip);
00461 }
00462 
00463 bool Set::Setup::restoreState(SaveGame *savedState) {
00464     _name = savedState->readString();
00465 
00466     _bkgndBm = Bitmap::getPool().getObject(savedState->readLESint32());
00467     _bkgndZBm = Bitmap::getPool().getObject(savedState->readLESint32());
00468 
00469     _pos      = savedState->readVector3d();
00470     if (g_grim->getGameType() == GType_MONKEY4) {
00471         float x = savedState->readFloat();
00472         float y = savedState->readFloat();
00473         float z = savedState->readFloat();
00474         float w = savedState->readFloat();
00475         Math::Quaternion q(x, y, z, w);
00476         _rot = q.toMatrix();
00477     } else {
00478         _interest = savedState->readVector3d();
00479         _roll     = savedState->readFloat();
00480     }
00481     _fov      = savedState->readFloat();
00482     _nclip    = savedState->readFloat();
00483     _fclip    = savedState->readFloat();
00484 
00485     return true;
00486 }
00487 
00488 Light::Light() : _falloffNear(0.0f), _falloffFar(0.0f), _enabled(false), _id(0) {
00489     setIntensity(0.0f);
00490     setUmbra(0.0f);
00491     setPenumbra(0.0f);
00492 }
00493 
00494 void Set::Setup::getRotation(float *x, float *y, float *z) {
00495     Math::Angle aX, aY, aZ;
00496     if (g_grim->getGameType() == GType_MONKEY4)
00497         _rot.getEuler(&aX, &aY, &aZ, Math::EO_ZYX);
00498     else
00499         _rot.getEuler(&aX, &aY, &aZ, Math::EO_ZXY);
00500 
00501     if (x != nullptr)
00502         *x = aX.getDegrees();
00503     if (y != nullptr)
00504         *y = aY.getDegrees();
00505     if (z != nullptr)
00506         *z = aZ.getDegrees();
00507 }
00508 
00509 void Set::Setup::setPitch(Math::Angle pitch) {
00510     Math::Angle oldYaw, oldRoll;
00511     if (g_grim->getGameType() == GType_MONKEY4) {
00512         _rot.getEuler(&oldRoll, &oldYaw, nullptr, Math::EO_ZYX);
00513         _rot.buildFromEuler(oldRoll, oldYaw, pitch, Math::EO_ZYX);
00514     } else {
00515         _rot.getEuler(&oldYaw, nullptr, &oldRoll, Math::EO_ZXY);
00516         _rot.buildFromEuler(oldYaw, pitch, oldRoll, Math::EO_ZXY);
00517     }
00518 }
00519 
00520 void Set::Setup::setYaw(Math::Angle yaw) {
00521     Math::Angle oldPitch, oldRoll;
00522     if (g_grim->getGameType() == GType_MONKEY4) {
00523         _rot.getEuler(&oldRoll, nullptr, &oldPitch, Math::EO_ZYX);
00524         _rot.buildFromEuler(oldRoll, yaw, oldPitch, Math::EO_ZYX);
00525     } else {
00526         _rot.getEuler(nullptr, &oldPitch, &oldRoll, Math::EO_ZXY);
00527         _rot.buildFromEuler(yaw, oldPitch, oldRoll, Math::EO_ZXY);
00528     }
00529 }
00530 
00531 void Set::Setup::setRoll(Math::Angle roll) {
00532     Math::Angle oldPitch, oldYaw;
00533     if (g_grim->getGameType() == GType_MONKEY4) {
00534         _rot.getEuler(nullptr, &oldYaw, &oldPitch, Math::EO_ZYX);
00535         _rot.buildFromEuler(roll, oldYaw, oldPitch, Math::EO_ZYX);
00536     } else {
00537         _rot.getEuler(&oldYaw, &oldPitch, nullptr, Math::EO_ZXY);
00538         _rot.buildFromEuler(oldYaw, oldPitch, roll, Math::EO_ZXY);
00539     }
00540 }
00541 
00542 void Light::setUmbra(float angle) {
00543     _umbraangle = angle;
00544     _cosumbraangle = cosf(angle * M_PI / 180.0f);
00545 }
00546 
00547 void Light::setPenumbra(float angle) {
00548     _penumbraangle = angle;
00549     _cospenumbraangle = cosf(angle * M_PI / 180.0f);
00550 }
00551 
00552 void Light::setIntensity(float intensity) {
00553     _intensity = intensity;
00554     if (g_grim->getGameType() == GType_MONKEY4) {
00555         _scaledintensity = intensity / 255;
00556     } else {
00557         _scaledintensity = intensity / 15;
00558     }
00559 }
00560 
00561 void Light::load(TextSplitter &ts) {
00562     char buf[256];
00563     float tmp;
00564 
00565     // Light names can be null, but ts doesn't seem flexible enough to allow this
00566     if (strlen(ts.getCurrentLine()) > strlen(" light"))
00567         ts.scanString(" light %256s", 1, buf);
00568     else {
00569         ts.nextLine();
00570         strcpy(buf, "");
00571     }
00572     _name = buf;
00573 
00574     ts.scanString(" type %256s", 1, buf);
00575     Common::String type = buf;
00576     if (type == "spot") {
00577         _type = Spot;
00578     } else if (type == "omni") {
00579         _type = Omni;
00580     } else if (type == "direct") {
00581         _type = Direct;
00582     } else {
00583         error("Light::load() Unknown type of light: %s", buf);
00584     }
00585 
00586     ts.scanString(" position %f %f %f", 3, &_pos.x(), &_pos.y(), &_pos.z());
00587     ts.scanString(" direction %f %f %f", 3, &_dir.x(), &_dir.y(), &_dir.z());
00588     ts.scanString(" intensity %f", 1, &tmp);
00589     setIntensity(tmp);
00590     ts.scanString(" umbraangle %f", 1, &tmp);
00591     setUmbra(tmp);
00592     ts.scanString(" penumbraangle %f", 1, &tmp);
00593     setPenumbra(tmp);
00594 
00595     int r, g, b;
00596     ts.scanString(" color %d %d %d", 3, &r, &g, &b);
00597     _color.getRed() = r;
00598     _color.getGreen() = g;
00599     _color.getBlue() = b;
00600 
00601     _enabled = true;
00602 }
00603 
00604 void Light::loadBinary(Common::SeekableReadStream *data) {
00605     char name[32];
00606     data->read(name, 32);
00607     _name = name;
00608 
00609     _pos.readFromStream(data);
00610 
00611     Math::Quaternion quat;
00612     quat.readFromStream(data);
00613 
00614     _dir.set(0, 0, -1);
00615     Math::Matrix4 rot = quat.toMatrix();
00616     rot.transform(&_dir, false);
00617 
00618     // This relies on the order of the LightType enum.
00619     _type = (LightType)data->readSint32LE();
00620 
00621     setIntensity(data->readFloatLE());
00622 
00623     int j = data->readSint32LE();
00624     // This always seems to be 0
00625     if (j != 0) {
00626         warning("Light::loadBinary j != 0");
00627     }
00628 
00629     _color.getRed() = data->readSint32LE();
00630     _color.getGreen() = data->readSint32LE();
00631     _color.getBlue() = data->readSint32LE();
00632 
00633     _falloffNear = data->readFloatLE();
00634     _falloffFar = data->readFloatLE();
00635     setUmbra(data->readFloatLE());
00636     setPenumbra(data->readFloatLE());
00637 
00638     _enabled = true;
00639 }
00640 
00641 void Light::saveState(SaveGame *savedState) const {
00642     //name
00643     savedState->writeString(_name);
00644     savedState->writeBool(_enabled);
00645 
00646     //type
00647     savedState->writeLEUint32(_type);
00648 
00649     savedState->writeVector3d(_pos);
00650     savedState->writeVector3d(_dir);
00651 
00652     savedState->writeColor(_color);
00653 
00654     savedState->writeFloat(_intensity);
00655     savedState->writeFloat(_umbraangle);
00656     savedState->writeFloat(_penumbraangle);
00657 
00658     savedState->writeFloat(_falloffNear);
00659     savedState->writeFloat(_falloffFar);
00660 }
00661 
00662 bool Light::restoreState(SaveGame *savedState) {
00663     _name = savedState->readString();
00664     _enabled = savedState->readBool();
00665     if (savedState->saveMinorVersion() > 7) {
00666         if (savedState->saveMinorVersion() >= 12) {
00667             _type = (LightType)savedState->readLEUint32();
00668         } else {
00669             int type = savedState->readLEUint32();
00670             if (type == 1) {
00671                 _type = Spot;
00672             } else if (type == 2) {
00673                 _type = Direct;
00674             } else if (type == 3) {
00675                 _type = Omni;
00676             } else if (type == 4) {
00677                 _type = Ambient;
00678             }
00679         }
00680     } else {
00681         Common::String type = savedState->readString();
00682         if (type == "spot") {
00683             _type = Spot;
00684         } else if (type == "omni") {
00685             _type = Omni;
00686         } else if (type == "direct") {
00687             _type = Direct;
00688         }
00689     }
00690 
00691     _pos           = savedState->readVector3d();
00692     _dir           = savedState->readVector3d();
00693 
00694     _color         = savedState->readColor();
00695 
00696     setIntensity(    savedState->readFloat());
00697     setUmbra(        savedState->readFloat());
00698     setPenumbra(     savedState->readFloat());
00699 
00700     if (savedState->saveMinorVersion() >= 20) {
00701         _falloffNear = savedState->readFloat();
00702         _falloffFar = savedState->readFloat();
00703     }
00704 
00705     return true;
00706 }
00707 
00708 SetShadow::SetShadow() : _numSectors(0) {
00709 }
00710 
00711 void SetShadow::loadBinary(Common::SeekableReadStream *data, Set *set) {
00712     uint32 nameLen = data->readUint32LE();
00713     char *name = new char[nameLen];
00714     data->read(name, nameLen);
00715     _name = Common::String(name);
00716 
00717     int lightNameLen = data->readSint32LE();
00718     char *lightName = new char[lightNameLen];
00719     data->read(lightName, lightNameLen);
00720 
00721     _shadowPoint.readFromStream(data);
00722 
00723     if (lightNameLen > 0) {
00724         for (Common::List<Light *>::const_iterator it = set->getLights(false).begin(); it != set->getLights(false).end(); ++it) {
00725             if ((*it)->_name.equals(lightName)) {
00726                 _shadowPoint = (*it)->_pos;
00727                 break;
00728             }
00729         }
00730     }
00731 
00732     int numSectors = data->readSint32LE();
00733     for (int i = 0; i < numSectors; ++i) {
00734         uint32 sectorNameLen = data->readUint32LE();
00735         char *sectorName = new char[sectorNameLen];
00736         data->read(sectorName, sectorNameLen);
00737         _sectorNames.push_back(sectorName);
00738         delete[] sectorName;
00739     }
00740 
00741     data->skip(4); // Unknown
00742     _color._vals[0] = (byte)data->readSint32LE();
00743     _color._vals[1] = (byte)data->readSint32LE();
00744     _color._vals[2] = (byte)data->readSint32LE();
00745     delete[] lightName;
00746     delete[] name;
00747 }
00748 
00749 void SetShadow::saveState(SaveGame *savedState) const {
00750     savedState->writeString(_name);
00751     savedState->writeVector3d(_shadowPoint);
00752     savedState->writeLESint32(_numSectors);
00753     savedState->writeLEUint32(_sectorNames.size());
00754     for (Common::List<Common::String>::const_iterator it = _sectorNames.begin(); it != _sectorNames.end(); ++it) {
00755         savedState->writeString(*it);
00756     }
00757     savedState->writeColor(_color);
00758 }
00759 
00760 void SetShadow::restoreState(SaveGame *savedState) {
00761     _name = savedState->readString();
00762     _shadowPoint = savedState->readVector3d();
00763     _numSectors = savedState->readLESint32();
00764     uint numSectors = savedState->readLEUint32();
00765     for (uint i = 0; i < numSectors; ++i) {
00766         _sectorNames.push_back(savedState->readString());
00767     }
00768     _color = savedState->readColor();
00769 }
00770 
00771 void Set::Setup::setupCamera() const {
00772     // Ignore nclip_ and fclip_ for now in Grim.  This fixes:
00773     // (a) Nothing was being displayed in the Land of the Living
00774     // diner because lr.set set nclip to 0.
00775     // (b) The zbuffers for setups with different nclip or
00776     // fclip values.  If it turns out that the clipping planes
00777     // are important at some point, we'll need to modify the
00778     // zbuffer transformation in bitmap.cpp to take nclip_ and
00779     // fclip_ into account.
00780     if (g_grim->getGameType() == GType_GRIM) {
00781         g_driver->setupCameraFrustum(_fov, 0.01f, 3276.8f);
00782         g_driver->positionCamera(_pos, _interest, _roll);
00783     } else {
00784         g_driver->setupCameraFrustum(_fov, _nclip, _fclip);
00785         g_driver->positionCamera(_pos, _rot);
00786     }
00787 }
00788 
00789 class Sorter {
00790 public:
00791     Sorter(const Math::Vector3d &pos) {
00792         _pos = pos;
00793     }
00794 
00795     bool operator()(Light *l1, Light *l2) const {
00796         float d1 = (l1->_pos - _pos).getSquareMagnitude();
00797         float d2 = (l2->_pos - _pos).getSquareMagnitude();
00798         if (d1 == d2) {
00799             return l1->_id < l2->_id;
00800         }
00801 
00802         return d1 < d2;
00803     }
00804 
00805     Math::Vector3d _pos;
00806 };
00807 
00808 void Set::setupLights(const Math::Vector3d &pos, bool inOverworld) {
00809     if (g_grim->getGameType() == GType_MONKEY4 && !g_driver->supportsShaders()) {
00810         // If shaders are not available, we do lighting in software for EMI.
00811         g_driver->disableLights();
00812         return;
00813     }
00814 
00815     if (!_enableLights) {
00816         g_driver->disableLights();
00817         return;
00818     }
00819 
00820     // Sort the ligths from the nearest to the farthest to the pos.
00821     Sorter sorter(pos);
00822     Common::List<Light *>* lightsList = inOverworld ? &_overworldLightsList : &_lightsList;
00823     Common::sort(lightsList->begin(), lightsList->end(), sorter);
00824 
00825     int count = 0;
00826     foreach (Light *l, *lightsList) {
00827         if (l->_enabled) {
00828             g_driver->setupLight(l, count);
00829             ++count;
00830         }
00831     }
00832 }
00833 
00834 void Set::turnOffLights() {
00835     _enableLights = false;
00836     int count = 0;
00837     for (int i = 0; i < _numLights; i++) {
00838         Light *l = &_lights[i];
00839         if (l->_enabled) {
00840             g_driver->turnOffLight(count);
00841             ++count;
00842         }
00843     }
00844 }
00845 
00846 void Set::setSetup(int num) {
00847     // Looks like num is zero-based so >= should work to find values
00848     // that are out of the range of valid setups
00849 
00850     // Quite weird, but this is what the original does when the setup id is above
00851     // the upper bound.
00852     if (num >= _numSetups)
00853         num %= _numSetups;
00854 
00855     if (num < 0) {
00856         error("Failed to change scene setup, value out of range");
00857         return;
00858     }
00859     _currSetup = _setups + num;
00860     g_grim->flagRefreshShadowMask(true);
00861     if (g_emiSound) {
00862         g_emiSound->updateSoundPositions();
00863     }
00864 }
00865 
00866 Bitmap::Ptr Set::loadBackground(const char *fileName) {
00867     Bitmap::Ptr bg = Bitmap::create(fileName);
00868     if (!bg) {
00869         Debug::warning(Debug::Bitmaps | Debug::Sets,
00870                        "Unable to load scene bitmap: %s, loading dfltroom instead", fileName);
00871         if (g_grim->getGameType() == GType_MONKEY4) {
00872             bg = Bitmap::create("dfltroom.til");
00873         } else {
00874             bg = Bitmap::create("dfltroom.bm");
00875         }
00876         if (!bg) {
00877             Debug::error(Debug::Bitmaps | Debug::Sets, "Unable to load dfltroom");
00878         }
00879     } else {
00880         Debug::debug(Debug::Bitmaps | Debug::Sets,
00881                      "Loaded scene bitmap: %s", fileName);
00882     }
00883     return bg;
00884 }
00885 
00886 void Set::drawBackground() const {
00887     if (_currSetup->_bkgndZBm) // Some screens have no zbuffer mask (eg, Alley)
00888         _currSetup->_bkgndZBm->draw();
00889 
00890     if (!_currSetup->_bkgndBm) {
00891         // This should fail softly, for some reason jumping to the signpost (sg) will load
00892         // the scene in such a way that the background isn't immediately available
00893         warning("Background hasn't loaded yet for setup %s in %s!", _currSetup->_name.c_str(), _name.c_str());
00894     } else {
00895         _currSetup->_bkgndBm->draw();
00896     }
00897 }
00898 
00899 void Set::drawBitmaps(ObjectState::Position stage) {
00900     for (StateList::iterator i = _states.reverse_begin(); i != _states.end(); --i) {
00901         if ((*i)->getPos() == stage && _currSetup == _setups + (*i)->getSetupID())
00902             (*i)->draw();
00903     }
00904 }
00905 
00906 void Set::setupCamera() {
00907     _currSetup->setupCamera();
00908     _frustum.setup(g_driver->getProjection() * g_driver->getModelView());
00909 }
00910 
00911 Sector *Set::findPointSector(const Math::Vector3d &p, Sector::SectorType type) {
00912     for (int i = 0; i < _numSectors; i++) {
00913         Sector *sector = _sectors[i];
00914         if (sector && (sector->getType() & type) && sector->isVisible() && sector->isPointInSector(p))
00915             return sector;
00916     }
00917     return nullptr;
00918 }
00919 
00920 int Set::findSectorSortOrder(const Math::Vector3d &p, Sector::SectorType type) {
00921     int setup = getSetup();
00922     int sortOrder = 0;
00923     float minDist = 0.01f;
00924 
00925     for (int i = 0; i < _numSectors; i++) {
00926         Sector *sector = _sectors[i];
00927         if (!sector || (sector->getType() & type) == 0 || !sector->isVisible() || setup >= sector->getNumSortplanes())
00928             continue;
00929 
00930         Math::Vector3d closestPt = sector->getClosestPoint(p);
00931         float thisDist = (closestPt - p).getMagnitude();
00932         if (thisDist < minDist) {
00933             minDist = thisDist;
00934             sortOrder = sector->getSortplane(setup);
00935         }
00936     }
00937     return sortOrder;
00938 }
00939 
00940 void Set::findClosestSector(const Math::Vector3d &p, Sector **sect, Math::Vector3d *closestPoint) {
00941     Sector *resultSect = nullptr;
00942     Math::Vector3d resultPt = p;
00943     float minDist = 0.0;
00944 
00945     for (int i = 0; i < _numSectors; i++) {
00946         Sector *sector = _sectors[i];
00947         if ((sector->getType() & Sector::WalkType) == 0 || !sector->isVisible())
00948             continue;
00949         Math::Vector3d closestPt = sector->getClosestPoint(p);
00950         float thisDist = (closestPt - p).getMagnitude();
00951         if (!resultSect || thisDist < minDist) {
00952             resultSect = sector;
00953             resultPt = closestPt;
00954             minDist = thisDist;
00955         }
00956     }
00957 
00958     if (sect)
00959         *sect = resultSect;
00960 
00961     if (closestPoint)
00962         *closestPoint = resultPt;
00963 }
00964 
00965 void Set::shrinkBoxes(float radius) {
00966     for (int i = 0; i < _numSectors; i++) {
00967         Sector *sector = _sectors[i];
00968         sector->shrink(radius);
00969     }
00970 }
00971 
00972 void Set::unshrinkBoxes() {
00973     for (int i = 0; i < _numSectors; i++) {
00974         Sector *sector = _sectors[i];
00975         sector->unshrink();
00976     }
00977 }
00978 
00979 void Set::setLightIntensity(const char *light, float intensity) {
00980     for (int i = 0; i < _numLights; ++i) {
00981         Light &l = _lights[i];
00982         if (l._name == light) {
00983             l.setIntensity(intensity);
00984             return;
00985         }
00986     }
00987 }
00988 
00989 void Set::setLightIntensity(int light, float intensity) {
00990     Light &l = _lights[light];
00991     l.setIntensity(intensity);
00992 }
00993 
00994 void Set::setLightEnabled(const char *light, bool enabled) {
00995     for (int i = 0; i < _numLights; ++i) {
00996         Light &l = _lights[i];
00997         if (l._name == light) {
00998             l._enabled = enabled;
00999             return;
01000         }
01001     }
01002 }
01003 
01004 void Set::setLightEnabled(int light, bool enabled) {
01005     Light &l = _lights[light];
01006     l._enabled = enabled;
01007 }
01008 
01009 void Set::setLightPosition(const char *light, const Math::Vector3d &pos) {
01010     for (int i = 0; i < _numLights; ++i) {
01011         Light &l = _lights[i];
01012         if (l._name == light) {
01013             l._pos = pos;
01014             return;
01015         }
01016     }
01017 }
01018 
01019 void Set::setLightPosition(int light, const Math::Vector3d &pos) {
01020     Light &l = _lights[light];
01021     l._pos = pos;
01022 }
01023 
01024 void Set::setSoundPosition(const char *soundName, const Math::Vector3d &pos) {
01025     setSoundPosition(soundName, pos, _minVolume, _maxVolume);
01026 }
01027 
01028 void Set::setSoundPosition(const char *soundName, const Math::Vector3d &pos, int minVol, int maxVol) {
01029     int newBalance, newVolume;
01030     calculateSoundPosition(pos, minVol, maxVol, newVolume, newBalance);
01031     g_sound->setVolume(soundName, newVolume);
01032     g_sound->setPan(soundName, newBalance);
01033 }
01034 
01035 void Set::calculateSoundPosition(const Math::Vector3d &pos, int minVol, int maxVol, int &volume, int &balance) {
01036     // TODO: The volume and pan needs to be updated when the setup changes.
01037     // Note: This is only used in Grim. See SoundTrack::updatePosition for the corresponding implementation in EMI.
01038 
01039     /* distance calculation */
01040     Math::Vector3d cameraPos = _currSetup->_pos;
01041     Math::Vector3d vector = pos - cameraPos;
01042     float distance = vector.getMagnitude();
01043     float diffVolume = maxVol - minVol;
01044     //This 8.f is a guess, so it may need some adjusting
01045     int newVolume = (int)(8.f * diffVolume / distance);
01046     newVolume += minVol;
01047     if (newVolume > _maxVolume)
01048         newVolume = _maxVolume;
01049     volume = newVolume;
01050     float angle;
01051 
01052     Math::Vector3d cameraVector = _currSetup->_interest - _currSetup->_pos;
01053     Math::Vector3d up(0, 0, 1);
01054     Math::Vector3d right;
01055     cameraVector.normalize();
01056     float roll = -_currSetup->_roll * LOCAL_PI / 180.f;
01057     float cosr = cos(roll);
01058     // Rotate the up vector by roll.
01059     up = up * cosr + Math::Vector3d::crossProduct(cameraVector, up) * sin(roll) +
01060             cameraVector * Math::Vector3d::dotProduct(cameraVector, up) * (1 - cosr);
01061     right = Math::Vector3d::crossProduct(cameraVector, up);
01062     right.normalize();
01063     angle = atan2(Math::Vector3d::dotProduct(vector, right),
01064                         Math::Vector3d::dotProduct(vector, cameraVector));
01065 
01066     float pan = sin(angle);
01067     balance = (int)((pan + 1.f) / 2.f * 127.f + 0.5f);
01068 }
01069 
01070 Sector *Set::getSectorBase(int id) {
01071     if ((_numSectors >= 0) && (id < _numSectors))
01072         return _sectors[id];
01073     else
01074         return nullptr;
01075 }
01076 
01077 Sector *Set::getSectorByName(const Common::String &name) {
01078     for (int i = 0; i < _numSectors; i++) {
01079         Sector *sector = _sectors[i];
01080         if (sector->getName() == name) {
01081             return sector;
01082         }
01083     }
01084     return nullptr;
01085 }
01086 
01087 Sector *Set::getSectorBySubstring(const Common::String &str) {
01088     for (int i = 0; i < _numSectors; i++) {
01089         Sector *sector = _sectors[i];
01090         if (strstr(sector->getName().c_str(), str.c_str())) {
01091             return sector;
01092         }
01093     }
01094     return nullptr;
01095 }
01096 
01097 Sector *Set::getSectorBySubstring(const Common::String &str, const Math::Vector3d &pos) {
01098     for (int i = 0; i < _numSectors; i++) {
01099         Sector *sector = _sectors[i];
01100         if (strstr(sector->getName().c_str(), str.c_str()) && sector->isPointInSector(pos)) {
01101             return sector;
01102         }
01103     }
01104     return nullptr;
01105 }
01106 
01107 void Set::setSoundParameters(int minVolume, int maxVolume) {
01108     _minVolume = minVolume;
01109     _maxVolume = maxVolume;
01110 }
01111 
01112 void Set::getSoundParameters(int *minVolume, int *maxVolume) {
01113     *minVolume = _minVolume;
01114     *maxVolume = _maxVolume;
01115 }
01116 
01117 void Set::addObjectState(const ObjectState::Ptr &s) {
01118     _states.push_front(s);
01119 }
01120 
01121 ObjectState *Set::addObjectState(int setupID, ObjectState::Position pos, const char *bitmap, const char *zbitmap, bool transparency) {
01122     ObjectState *state = findState(bitmap);
01123 
01124     if (state) {
01125         return state;
01126     }
01127 
01128     state = new ObjectState(setupID, pos, bitmap, zbitmap, transparency);
01129     addObjectState(state);
01130 
01131     return state;
01132 }
01133 
01134 ObjectState *Set::findState(const Common::String &filename) {
01135     // Check the different state objects for the bitmap
01136     for (StateList::iterator i = _states.begin(); i != _states.end(); ++i) {
01137         const Common::String &file = (*i)->getBitmapFilename();
01138 
01139         if (file == filename)
01140             return *i;
01141         if (file.compareToIgnoreCase(filename) == 0) {
01142             Debug::warning(Debug::Sets, "State object request '%s' matches object '%s' but is the wrong case", filename.c_str(), file.c_str());
01143             return *i;
01144         }
01145     }
01146     return nullptr;
01147 }
01148 
01149 void Set::moveObjectStateToFront(const ObjectState::Ptr &s) {
01150     _states.remove(s);
01151     _states.push_front(s);
01152     // Make the state invisible. This hides the deadbolt when brennis closes the switcher door
01153     // in the server room (tu), and therefore fixes https://github.com/residualvm/residualvm/issues/24
01154     s->setActiveImage(0);
01155 }
01156 
01157 void Set::moveObjectStateToBack(const ObjectState::Ptr &s) {
01158     _states.remove(s);
01159     _states.push_back(s);
01160 }
01161 
01162 SetShadow *Set::getShadow(int i) {
01163     return &_shadows[i];
01164 }
01165 
01166 SetShadow *Set::getShadowByName(const Common::String &name) {
01167     for (int i = 0; i < _numShadows; ++i) {
01168         SetShadow *shadow = &_shadows[i];
01169         if (shadow->_name.equalsIgnoreCase(name))
01170             return shadow;
01171     }
01172     return nullptr;
01173 }
01174 
01175 } // end of namespace Grim


Generated on Sat Dec 7 2019 05:00:34 for ResidualVM by doxygen 1.7.1
curved edge   curved edge