From 5f83fd19540c3072f50edff0acddf1cb6a072b78 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Fri, 3 Sep 2010 21:49:33 +0000 Subject: SWORD25: Load and parse vector images Libart is temporary solution. svn-id: r53313 --- engines/sword25/gfx/image/vectorimage.cpp | 165 ++++++++++++++++++++---------- engines/sword25/gfx/image/vectorimage.h | 30 +++--- engines/sword25/gfx/opengl/openglgfx.cpp | 2 + engines/sword25/module.mk | 3 +- 4 files changed, 128 insertions(+), 72 deletions(-) (limited to 'engines/sword25') diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp index 35da539597..45e81b6f71 100644 --- a/engines/sword25/gfx/image/vectorimage.cpp +++ b/engines/sword25/gfx/image/vectorimage.cpp @@ -41,10 +41,13 @@ #include "graphics/colormasks.h" +#include + namespace Sword25 { #define BS_LOG_PREFIX "VECTORIMAGE" +#define BEZSMOOTHNESS 0.5 // ----------------------------------------------------------------------------- // SWF Datentypen @@ -197,27 +200,29 @@ uint32 flashColorToAGGRGBA8(uint flashColor) { // Berechnet die Bounding-Box eines BS_VectorImageElement // ----------------------------------------------------------------------------- -struct CBBGetId { - CBBGetId(const VectorImageElement &vectorImageElement_) : vectorImageElement(vectorImageElement_) {} - unsigned operator [](unsigned i) const { - return vectorImageElement.getPathInfo(i).getId(); +Common::Rect CalculateBoundingBox(const VectorImageElement &vectorImageElement) { + double x0, y0, x1, y1; + + for (int j = vectorImageElement.getPathCount() - 1; j >= 0; j--) { + ArtVpath *vec = vectorImageElement.getPathInfo(j).getVec(); + + if (vec[0].code == ART_END) { + continue; + } else { + x0 = x1 = vec[0].x; + y0 = y1 = vec[0].y; + for (int i = 1; vec[i].code != ART_END; i++) { + if (vec[i].x < x0) x0 = vec[i].x; + if (vec[i].x > x1) x1 = vec[i].x; + if (vec[i].y < y0) y0 = vec[i].y; + if (vec[i].y > y1) y1 = vec[i].y; + } + } } - const VectorImageElement &vectorImageElement; -}; -Common::Rect CalculateBoundingBox(const VectorImageElement &vectorImageElement) { -#if 0 // TODO - agg::path_storage Path = vectorImageElement.GetPaths(); - CBBGetId IdSource(vectorImageElement); - - double x1, x2, y1, y2; - agg::bounding_rect(Path, IdSource, 0, vectorImageElement.GetPathCount(), &x1, &y1, &x2, &y2); -#else - double x1, x2, y1, y2; - x1 = x2 = y1 = y2 = 0; -#endif - return Common::Rect(static_cast(x1), static_cast(y1), static_cast(x2) + 1, static_cast(y2) + 1); + return Common::Rect(static_cast(x0), static_cast(y0), static_cast(x1) + 1, static_cast(y1) + 1); } + } @@ -302,7 +307,38 @@ VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success) { BS_ASSERT(false); } -// ----------------------------------------------------------------------------- +VectorImage::~VectorImage() { + for (int j = _elements.size() - 1; j >= 0; j--) + for (int i = _elements[j].getPathCount() - 1; i >= 0; i--) + if (_elements[j].getPathInfo(i).getVec()) + art_free(_elements[j].getPathInfo(i).getVec()); +} + + +ArtBpath *ensureBezStorage(ArtBpath *bez, int nodes, int *allocated) { + if (*allocated <= nodes) { + (*allocated) += 20; + + return art_renew(bez, ArtBpath, *allocated); + } + + return bez; +} + +ArtBpath *VectorImage::storeBez(ArtBpath *bez, int lineStyle, int fillStyle0, int fillStyle1, int *bezNodes, int *bezAllocated) { + (*bezNodes)++; + + bez = ensureBezStorage(bez, *bezNodes, bezAllocated); + bez[*bezNodes].code = ART_END; + + ArtVpath *vec = art_bez_path_to_vec(bez, BEZSMOOTHNESS); + + _elements.back()._pathInfos.push_back(VectorPathInfo(vec, lineStyle, fillStyle0, fillStyle1)); + + return bez; +} + +#define SWF_SCALE_FACTOR (1/20.0) bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) { /*uint32 shapeID = */bs.getUInt16(); @@ -326,6 +362,12 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) { // Shaperecord parsen // ------------------ + double curX = 0; + double curY = 0; + int bezNodes = 0; + int bezAllocated = 10; + ArtBpath *bez = art_new(ArtBpath, bezAllocated); + bool endOfShapeDiscovered = false; while (!endOfShapeDiscovered) { uint32 typeFlag = bs.getBits(1); @@ -344,12 +386,10 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) { endOfShapeDiscovered = true; // Parameter dekodieren } else { - int32 moveDeltaX = 0; - int32 moveDeltaY = 0; if (stateMoveTo) { uint32 moveToBits = bs.getBits(5); - moveDeltaX = bs.getSignedBits(moveToBits); - moveDeltaY = bs.getSignedBits(moveToBits); + curX = bs.getSignedBits(moveToBits) * SWF_SCALE_FACTOR; + curY = bs.getSignedBits(moveToBits) * SWF_SCALE_FACTOR; } if (stateFillStyle0) { @@ -383,21 +423,17 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) { // Ein neuen Pfad erzeugen, es sei denn, es wurden nur neue Styles definiert if (stateLineStyle || stateFillStyle0 || stateFillStyle1 || stateMoveTo) { - // Letzte Zeichenposition merken, beim Aufruf von start_new_path() wird die Zeichenpostionen auf 0, 0 zurückgesetzt -#if 0 // TODO - double lastX = _elements.back()._paths.last_x(); - double lastY = _elements.back()._paths.last_y(); - - // Neue Pfadinformation erzeugen - _elements.back()._pathInfos.push_back(VectorPathInfo(_elements.back()._paths.start_new_path(), lineStyle, fillStyle0, fillStyle1)); - - // Falls eine Bewegung definiert wurde, wird die Zeichenpositionen an die entsprechende Position gesetzt. - // Ansonsten wird die Zeichenposition auf die letzte Zeichenposition gesetzt. - if (stateMoveTo) - _elements.back()._paths.move_to(moveDeltaX, moveDeltaY); - else - _elements.back()._paths.move_to(lastX, lastY); -#endif + // Store previous curve if any + if (bezNodes) { + bez = storeBez(bez, lineStyle, fillStyle0, fillStyle1, &bezNodes, &bezAllocated); + } + + // Start new curve + bez = ensureBezStorage(bez, 1, &bezAllocated); + bez[0].code = ART_MOVETO_OPEN; + bez[0].x3 = curX; + bez[0].y3 = curY; + bezNodes = 0; } } } else { @@ -407,18 +443,30 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) { // Curved edge if (edgeFlag == 0) { - /* int32 controlDeltaX = */bs.getSignedBits(numBits); - /* int32 controlDeltaY = */bs.getSignedBits(numBits); - /* int32 anchorDeltaX = */bs.getSignedBits(numBits); - /* int32 anchorDeltaY = */bs.getSignedBits(numBits); - -#if 0 // TODO - double controlX = _elements.back()._paths.last_x() + controlDeltaX; - double controlY = _elements.back()._paths.last_y() + controlDeltaY; - double anchorX = controlX + AnchorDeltaX; - double anchorY = controlY + AnchorDeltaY; - _elements.back()._paths.curve3(controlX, controlY, anchorX, anchorY); -#endif + double controlDeltaX = bs.getSignedBits(numBits) * SWF_SCALE_FACTOR; + double controlDeltaY = bs.getSignedBits(numBits) * SWF_SCALE_FACTOR; + double anchorDeltaX = bs.getSignedBits(numBits) * SWF_SCALE_FACTOR; + double anchorDeltaY = bs.getSignedBits(numBits) * SWF_SCALE_FACTOR; + + double newX = curX + controlDeltaX; + double newY = curY + controlDeltaY; + double anchorX = curX + anchorDeltaX; + double anchorY = curY + anchorDeltaY; + +#define WEIGHT (2.0/3.0) + + bezNodes++; + bez = ensureBezStorage(bez, bezNodes, &bezAllocated); + bez[bezNodes].code = ART_CURVETO; + bez[bezNodes].x1 = WEIGHT * anchorX + (1 - WEIGHT) * curX; + bez[bezNodes].y1 = WEIGHT * anchorY + (1 - WEIGHT) * curY; + bez[bezNodes].x2 = WEIGHT * anchorX + (1 - WEIGHT) * newX; + bez[bezNodes].y2 = WEIGHT * anchorY + (1 - WEIGHT) * newY; + bez[bezNodes].x3 = newX; + bez[bezNodes].y3 = newY; + + curX = newX; + curY = newY; } else { // Staight edge int32 deltaX = 0; @@ -436,13 +484,24 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) { deltaX = bs.getSignedBits(numBits); } -#if 0 // TODO - _elements.back()._paths.line_rel(deltaX, deltaY); -#endif + curX += deltaX * SWF_SCALE_FACTOR; + curY += deltaY * SWF_SCALE_FACTOR; + + bezNodes++; + bez = ensureBezStorage(bez, bezNodes, &bezAllocated); + bez[bezNodes].code = ART_LINETO; + bez[bezNodes].x3 = curX; + bez[bezNodes].y3 = curY; } } } + // Store last curve + if (bezNodes) + bez = storeBez(bez, lineStyle, fillStyle0, fillStyle1, &bezNodes, &bezAllocated); + + art_free(bez); + // Bounding-Boxes der einzelnen Elemente berechnen Common::Array::iterator it = _elements.begin(); for (; it != _elements.end(); ++it) diff --git a/engines/sword25/gfx/image/vectorimage.h b/engines/sword25/gfx/image/vectorimage.h index 7f14da907c..e5688078ee 100644 --- a/engines/sword25/gfx/image/vectorimage.h +++ b/engines/sword25/gfx/image/vectorimage.h @@ -43,9 +43,9 @@ #include "sword25/gfx/image/image.h" #include "common/rect.h" -#if 0 -#include "agg_path_storage.h" -#endif +#include +#include +#include namespace Sword25 { @@ -60,15 +60,16 @@ class VectorImage; class VectorPathInfo { public: - VectorPathInfo(uint id, uint lineStyle, uint fillStyle0, uint fillStyle1) : - _id(id), _lineStyle(lineStyle), _fillStyle0(fillStyle0), _fillStyle1(fillStyle1) {} + VectorPathInfo(ArtVpath *vec, uint lineStyle, uint fillStyle0, uint fillStyle1) : + _vec(vec), _lineStyle(lineStyle), _fillStyle0(fillStyle0), _fillStyle1(fillStyle1) {} VectorPathInfo() { - _id = _lineStyle = _fillStyle0 = _fillStyle1 = 0; + _lineStyle = _fillStyle0 = _fillStyle1 = 0; + _vec = 0; } - uint getId() const { - return _id; + ArtVpath *getVec() const { + return _vec; } uint getLineStyle() const { return _lineStyle; @@ -81,7 +82,7 @@ public: } private: - uint _id; + ArtVpath *_vec; uint _lineStyle; uint _fillStyle0; uint _fillStyle1; @@ -95,12 +96,6 @@ private: class VectorImageElement { friend class VectorImage; public: -#if 0 // TODO - const agg::path_storage &getPaths() const { - return _paths; - } -#endif - uint getPathCount() const { return _pathInfos.size(); } @@ -144,9 +139,6 @@ private: uint32 color; }; -#if 0 // TODO - agg::path_storage _paths; -#endif Common::Array _pathInfos; Common::Array _lineStyles; Common::Array _fillStyles; @@ -163,6 +155,7 @@ private: class VectorImage : public Image { public: VectorImage(const byte *pFileData, uint fileSize, bool &success); + ~VectorImage(); uint getElementCount() const { return _elements.size(); @@ -223,6 +216,7 @@ private: bool parseDefineShape(uint shapeType, SWFBitStream &bs); bool parseStyles(uint shapeType, SWFBitStream &bs, uint &numFillBits, uint &numLineBits); + ArtBpath *storeBez(ArtBpath *bez, int lineStyle, int fillStyle0, int fillStyle1, int *bezNodes, int *bezAllocated); Common::Array _elements; Common::Rect _boundingBox; }; diff --git a/engines/sword25/gfx/opengl/openglgfx.cpp b/engines/sword25/gfx/opengl/openglgfx.cpp index 0401a99e4d..77fc416c77 100644 --- a/engines/sword25/gfx/opengl/openglgfx.cpp +++ b/engines/sword25/gfx/opengl/openglgfx.cpp @@ -326,6 +326,8 @@ Resource *OpenGLGfx::LoadResource(const Common::String &FileName) { // Vectorgraphik laden if (FileName.hasSuffix(SWF_EXTENSION)) { + debug(2, "VectorImage: %s", FileName.c_str()); + // Pointer auf Package-Manager holen PackageManager *pPackage = Kernel::GetInstance()->GetPackage(); BS_ASSERT(pPackage); diff --git a/engines/sword25/module.mk b/engines/sword25/module.mk index 0abeb5e01a..40be7fad24 100644 --- a/engines/sword25/module.mk +++ b/engines/sword25/module.mk @@ -110,7 +110,8 @@ MODULE_OBJS := \ $(QUIET)$(MKDIR) $(*D)/$(DEPDIR) $(QUIET_CXX)gcc $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o -LIBS += -lpng -ltheoradec +LIBS += -lpng -ltheoradec -lart_lgpl_2 +CXXFLAGS += -I/usr/include/libart-2.0 # This module can be built as a plugin ifeq ($(ENABLE_SWORD25), DYNAMIC_PLUGIN) -- cgit v1.2.3