00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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;
00128 }
00129
00130
00131 Math::Segment2d testLine(Math::Vector2d(point.x, point.y), Math::Vector2d(-100, -100));
00132
00133
00134 Math::Vector2d prevPoint = Math::Vector2d(polygon.back().x, polygon.back().y);
00135
00136
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
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
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;
00208 }
00209
00210 if (_noName) {
00211 return;
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;
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 }
00323 }