SWORD25: Load and parse vector images

Libart is temporary solution.

svn-id: r53313
This commit is contained in:
Eugene Sandulenko 2010-09-03 21:49:33 +00:00
parent dcf70dc6a6
commit 5f83fd1954
4 changed files with 126 additions and 70 deletions

View File

@ -41,10 +41,13 @@
#include "graphics/colormasks.h"
#include <libart_lgpl/art_vpath_bpath.h>
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();
}
const VectorImageElement &vectorImageElement;
};
Common::Rect CalculateBoundingBox(const VectorImageElement &vectorImageElement) {
#if 0 // TODO
agg::path_storage Path = vectorImageElement.GetPaths();
CBBGetId IdSource(vectorImageElement);
double x0, y0, x1, y1;
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<int>(x1), static_cast<int>(y1), static_cast<int>(x2) + 1, static_cast<int>(y2) + 1);
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;
}
}
}
return Common::Rect(static_cast<int>(x0), static_cast<int>(y0), static_cast<int>(x1) + 1, static_cast<int>(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();
// Store previous curve if any
if (bezNodes) {
bez = storeBez(bez, lineStyle, fillStyle0, fillStyle1, &bezNodes, &bezAllocated);
}
// 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
// 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);
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;
#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 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<VectorImageElement>::iterator it = _elements.begin();
for (; it != _elements.end(); ++it)

View File

@ -43,9 +43,9 @@
#include "sword25/gfx/image/image.h"
#include "common/rect.h"
#if 0
#include "agg_path_storage.h"
#endif
#include <libart_lgpl/art_vpath.h>
#include <libart_lgpl/art_bpath.h>
#include <libart_lgpl/art_misc.h>
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<VectorPathInfo> _pathInfos;
Common::Array<LineStyleType> _lineStyles;
Common::Array<uint32> _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<VectorImageElement> _elements;
Common::Rect _boundingBox;
};

View File

@ -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);

View File

@ -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)