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

resources/image.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/stark/resources/image.h"
00024 
00025 #include "common/debug.h"
00026 #include "image/png.h"
00027 
00028 #include "engines/stark/debug.h"
00029 #include "engines/stark/formats/xrc.h"
00030 #include "engines/stark/services/archiveloader.h"
00031 #include "engines/stark/services/settings.h"
00032 #include "engines/stark/services/services.h"
00033 #include "engines/stark/visual/effects/bubbles.h"
00034 #include "engines/stark/visual/effects/fireflies.h"
00035 #include "engines/stark/visual/effects/fish.h"
00036 #include "engines/stark/visual/image.h"
00037 #include "engines/stark/visual/text.h"
00038 
00039 #include "math/line2d.h"
00040 #include "math/vector2d.h"
00041 
00042 namespace Stark {
00043 namespace Resources {
00044 
00045 Object *Image::construct(Object *parent, byte subType, uint16 index, const Common::String &name) {
00046     switch (subType) {
00047     case kImageSub2:
00048     case kImageSub3:
00049         return new ImageStill(parent, subType, index, name);
00050     case kImageSub4:
00051         return new ImageText(parent, subType, index, name);
00052     default:
00053         error("Unknown image subtype %d", subType);
00054     }
00055 }
00056 
00057 Image::~Image() {
00058     delete _visual;
00059 }
00060 
00061 Image::Image(Object *parent, byte subType, uint16 index, const Common::String &name) :
00062         Object(parent, subType, index, name),
00063         _transparent(false),
00064         _transparentColor(0),
00065         _field_44_ADF(0),
00066         _field_48_ADF(30),
00067         _visual(nullptr) {
00068     _type = TYPE;
00069 }
00070 
00071 void Image::readData(Formats::XRCReadStream *stream) {
00072     _filename = stream->readString();
00073     _hotspot = stream->readPoint();
00074     _transparent = stream->readBool();
00075     _transparentColor = stream->readUint32LE();
00076 
00077     uint32 polygonCount = stream->readUint32LE();
00078     for (uint32 i = 0; i < polygonCount; i++) {
00079         Polygon polygon;
00080 
00081         uint32 pointCount = stream->readUint32LE();
00082         for (uint32 j = 0; j < pointCount; j++) {
00083             polygon.push_back(stream->readPoint());
00084         }
00085 
00086         _polygons.push_back(polygon);
00087     }
00088 
00089     _archiveName = stream->getArchiveName();
00090 }
00091 
00092 Visual *Image::getVisual() {
00093     initVisual();
00094     return _visual;
00095 }
00096 
00097 void Image::printData() {
00098     debug("filename: %s", _filename.c_str());
00099     debug("hotspot: x %d, y %d", _hotspot.x, _hotspot.y);
00100     debug("transparent: %d", _transparent);
00101     debug("transparentColor: %d", _transparentColor);
00102     debug("field_44: %d", _field_44_ADF);
00103     debug("field_48: %d", _field_48_ADF);
00104 
00105     for (uint32 i = 0; i < _polygons.size(); i++) {
00106         Common::String description;
00107         for (uint32 j = 0; j < _polygons[i].size(); j++) {
00108             description += Common::String::format("(x %d, y %d) ", _polygons[i][j].x, _polygons[i][j].y);
00109         }
00110         debug("polygon %d: %s", i, description.c_str());
00111     }
00112 }
00113 
00114 int Image::indexForPoint(const Common::Point &point) const {
00115     int index = -1;
00116     for (uint32 i = 0; i < _polygons.size(); i++) {
00117         if (isPointInPolygon(_polygons[i], point)) {
00118             index = i;
00119         }
00120     }
00121 
00122     return index;
00123 }
00124 
00125 bool Image::isPointInPolygon(const Polygon &polygon, const Common::Point &point) const {
00126     if (polygon.size() <= 1) {
00127         return false; // Empty polygon
00128     }
00129 
00130     // A ray cast from the point
00131     Math::Segment2d testLine(Math::Vector2d(point.x, point.y), Math::Vector2d(-100, -100));
00132 
00133     // Special case the line created between the last point and the first
00134     Math::Vector2d prevPoint = Math::Vector2d(polygon.back().x, polygon.back().y);
00135 
00136     // Count the intersections of the ray with the polygon's edges
00137     int intersectCount = 0;
00138     for (uint32 j = 0; j < polygon.size(); j++) {
00139         Math::Vector2d curPoint = Math::Vector2d(polygon[j].x, polygon[j].y);
00140 
00141         if (Math::Segment2d(prevPoint, curPoint).intersectsSegment(testLine, nullptr)) {
00142             intersectCount++;
00143         }
00144 
00145         prevPoint = curPoint;
00146     }
00147 
00148     // If the ray crosses the polygon an odd number of times, the point is inside the polygon
00149     return intersectCount % 2 != 0;
00150 }
00151 
00152 Common::Point Image::getHotspotPosition(uint index) const {
00153     if (index >= _polygons.size()) {
00154         return Common::Point(-1, -1);
00155     }
00156 
00157     Polygon polygon = _polygons[index];
00158 
00159     // Return the top-middle point as the hotspot
00160     int right = polygon[0].x, top = polygon[0].y;
00161 
00162     for (uint i = 1; i < polygon.size(); ++i) {
00163         right += polygon[i].x;
00164         if (polygon[i].y < top) {
00165             top = polygon[i].y;
00166         }
00167     }
00168 
00169     right /= polygon.size();
00170     
00171     if (top < 0) {
00172         top = 0;
00173     }
00174 
00175     return Common::Point(right, top);
00176 }
00177 
00178 ImageStill::~ImageStill() {
00179 }
00180 
00181 ImageStill::ImageStill(Object *parent, byte subType, uint16 index, const Common::String &name) :
00182         Image(parent, subType, index, name),
00183         _noName(false) {
00184 }
00185 
00186 void ImageStill::readData(Formats::XRCReadStream *stream) {
00187     Image::readData(stream);
00188 
00189     if (stream->isDataLeft()) {
00190         _field_44_ADF = stream->readUint32LE();
00191         _field_44_ADF /= 33;
00192     }
00193 
00194     if (stream->isDataLeft()) {
00195         _field_48_ADF = stream->readUint32LE();
00196     }
00197 
00198     _noName = _filename == "noname" || _filename == "noname.xmg";
00199 }
00200 
00201 void ImageStill::onPostRead() {
00202     initVisual();
00203 }
00204 
00205 void ImageStill::initVisual() {
00206     if (_visual) {
00207         return; // The visual is already there
00208     }
00209 
00210     if (_noName) {
00211         return; // No file to load
00212     }
00213 
00214     Common::ReadStream *xmgStream = StarkArchiveLoader->getFile(_filename, _archiveName);
00215 
00216     VisualImageXMG *visual = new VisualImageXMG(StarkGfx);
00217 
00218     if (StarkSettings->isAssetsModEnabled() && loadPNGOverride(visual)) {
00219         visual->readOriginalSize(xmgStream);
00220     } else {
00221         visual->load(xmgStream);
00222     }
00223 
00224     visual->setHotSpot(_hotspot);
00225 
00226     _visual = visual;
00227 
00228     delete xmgStream;
00229 }
00230 
00231 bool ImageStill::loadPNGOverride(VisualImageXMG *visual) const {
00232     if (!_filename.hasSuffixIgnoreCase(".xmg")) {
00233         return false;
00234     }
00235 
00236     Common::String pngFilename = Common::String(_filename.c_str(), _filename.size() - 4) + ".png";
00237     Common::String pngFilePath = StarkArchiveLoader->getExternalFilePath(pngFilename, _archiveName);
00238 
00239     debugC(kDebugModding, "Attempting to load %s", pngFilePath.c_str());
00240 
00241     Common::SeekableReadStream *pngStream = SearchMan.createReadStreamForMember(pngFilePath);
00242     if (!pngStream) {
00243         return false;
00244     }
00245 
00246     if (!visual->loadPNG(pngStream)) {
00247         warning("Failed to load %s. It is not a valid PNG file.", pngFilePath.c_str());
00248         delete pngStream;
00249         return false;
00250     }
00251 
00252     debugC(kDebugModding, "Loaded %s", pngFilePath.c_str());
00253 
00254     delete pngStream;
00255     return true;
00256 }
00257 
00258 void ImageStill::printData() {
00259     Image::printData();
00260 }
00261 
00262 ImageText::ImageText(Object *parent, byte subType, uint16 index, const Common::String &name) :
00263         Image(parent, subType, index, name),
00264         _color(Color(0, 0, 0)),
00265         _font(0) {
00266 }
00267 
00268 ImageText::~ImageText() {
00269 }
00270 
00271 void ImageText::readData(Formats::XRCReadStream *stream) {
00272     Image::readData(stream);
00273 
00274     _size = stream->readPoint();
00275     _text = stream->readString();
00276     _color.r = stream->readByte();
00277     _color.g = stream->readByte();
00278     _color.b = stream->readByte();
00279     _color.a = stream->readByte() | 0xFF;
00280     _font = stream->readUint32LE();
00281 }
00282 
00283 void ImageText::initVisual() {
00284     if (_visual) {
00285         return; // The visual is already there
00286     }
00287 
00288     if (_text.hasPrefix("GFX_Bubbles")) {
00289         VisualEffectBubbles *bubbles = new VisualEffectBubbles(StarkGfx, _size);
00290         bubbles->setParams(_text);
00291         _visual = bubbles;
00292     } else if (_text.hasPrefix("GFX_FireFlies")) {
00293         VisualEffectFireFlies *fireFlies = new VisualEffectFireFlies(StarkGfx, _size);
00294         fireFlies->setParams(_text);
00295         _visual = fireFlies;
00296     } else if (_text.hasPrefix("GFX_Fish")) {
00297         VisualEffectFish *fish = new VisualEffectFish(StarkGfx, _size);
00298         fish->setParams(_text);
00299         _visual = fish;
00300     } else if (_text.hasPrefix("GFX_")) {
00301         error("Unknown effect '%s'", _text.c_str());
00302     } else {
00303         VisualText *text = new VisualText(StarkGfx);
00304         text->setText(_text);
00305         text->setColor(_color);
00306         text->setTargetWidth(_size.x);
00307         text->setTargetHeight(_size.y);
00308         text->setFont(FontProvider::kCustomFont, _font);
00309         _visual = text;
00310     }
00311 }
00312 
00313 void ImageText::printData() {
00314     Image::printData();
00315 
00316     debug("size: x %d, y %d", _size.x, _size.y);
00317     debug("text: %s", _text.c_str());
00318     debug("color: (%d, %d, %d, %d)", _color.r, _color.g, _color.b, _color.a);
00319     debug("font: %d", _font);
00320 }
00321 
00322 } // End of namespace Resources
00323 } // End of namespace Stark


Generated on Sat Mar 23 2019 05:01:42 for ResidualVM by doxygen 1.7.1
curved edge   curved edge