tahoma2d/toonz/sources/common/tvrender/tflash.cpp

2807 lines
87 KiB
C++
Raw Normal View History

2016-03-19 06:57:51 +13:00
#include "tflash.h"
//#include "tstroke.h"
#include "tcurves.h"
#include "tregion.h"
#include "tstrokeprop.h"
#include "tregionprop.h"
#include "tpalette.h"
#include "tvectorimage.h"
#include "tmachine.h"
#include "trasterimage.h"
#include "tsimplecolorstyles.h"
#include "tcolorfunctions.h"
#include "F3SDK.h"
#include "FFixed.h"
#include "tsop.h"
#include "tropcm.h"
#include "tsweepboundary.h"
#include "tiio_jpg_util.h"
#include "zlib.h"
//#include "trop.h"
#include "ttoonzimage.h"
#include "tconvert.h"
#include "timage_io.h"
#include "tsystem.h"
#include <stack>
#include <fstream>
#if !defined(TNZ_LITTLE_ENDIAN)
TNZ_LITTLE_ENDIAN undefined !!
#endif
int Tw = 0;
bool areTwEqual(double x, double y)
{
assert(Tw != 0);
return (int)(Tw * x) == (int)(Tw * y);
}
bool areTwEqual(TPointD p0, TPointD p1)
{
assert(Tw != 0);
return areTwEqual(p0.x, p1.x) && areTwEqual(p0.y, p1.y);
}
//-------------------------------------------------------------------
const wstring TFlash::ConstantLines = L"Low: Constant Thickness";
const wstring TFlash::MixedLines = L"Medium: Mixed Thickness";
const wstring TFlash::VariableLines = L"High: Variable Thickness";
Tiio::SwfWriterProperties::SwfWriterProperties()
: m_lineQuality("Curve Quality"), m_isCompressed("File Compression", true), m_autoplay("Autoplay", true), m_looping("Looping", true), m_jpgQuality("Jpg Quality", 0, 100, 90), m_url("URL", wstring()), m_preloader("Insert Preloader", false)
{
m_lineQuality.addValue(TFlash::MixedLines);
m_lineQuality.addValue(TFlash::ConstantLines);
m_lineQuality.addValue(TFlash::VariableLines);
bind(m_lineQuality);
bind(m_isCompressed);
bind(m_autoplay);
bind(m_looping);
bind(m_jpgQuality);
bind(m_url);
bind(m_preloader);
TEnumProperty::Range range = m_lineQuality.getRange();
}
//-------------------------------------------------------------------
enum PolyType { None,
Centerline,
Solid,
Texture,
LinearGradient,
RadialGradient };
class PolyStyle
{
public:
PolyType m_type;
TPixel32 m_color1; //only if type!=Texture
TPixel32 m_color2; //only if type==LinearGradient || type==RadialGradient
double m_smooth; //only if type==RadialGradient
double m_thickness; //only if type==Centerline
TAffine m_matrix; //only if type==Texture
TRaster32P m_texture; //only if type==Texture
//bool m_isRegion; //only if type!=Centerline
//bool m_isHole; //only if type!=Centerline && m_isRegion==true
PolyStyle() : m_type(None), m_color1(), m_color2(), m_smooth(0), m_thickness(0), m_matrix(), m_texture() /*, m_isRegion(false), m_isHole(false)*/ {}
bool operator==(const PolyStyle &p) const;
bool operator<(const PolyStyle &p) const;
};
class FlashPolyline
{
public:
UINT m_depth;
bool m_skip;
bool m_toBeDeleted;
bool m_isPoint;
vector<TQuadratic *> m_quads;
PolyStyle m_fillStyle1;
PolyStyle m_fillStyle2;
PolyStyle m_lineStyle;
//PolyStyle m_bgStyle;
FlashPolyline() : m_depth(0), m_skip(false), m_toBeDeleted(false), m_isPoint(false), m_fillStyle1(), m_fillStyle2(), m_lineStyle() {}
bool operator<(const FlashPolyline &p) const { return m_depth < p.m_depth; }
};
class biPoint
{
public:
TPointD p0, p1;
biPoint(TPointD _p0, TPointD _p1) : p0(_p0), p1(_p1) {}
biPoint() {}
bool operator<(const biPoint &b) const
{
biPoint aux;
aux.p0.x = areTwEqual(p0.x, b.p0.x) ? p0.x : b.p0.x;
aux.p0.y = areTwEqual(p0.y, b.p0.y) ? p0.y : b.p0.y;
aux.p1.x = areTwEqual(p1.x, b.p1.x) ? p1.x : b.p1.x;
aux.p1.y = areTwEqual(p1.y, b.p1.y) ? p1.y : b.p1.y;
return (p0.x == aux.p0.x) ? ((p0.y == aux.p0.y) ? ((p1.x == aux.p1.x) ? (p1.y < aux.p1.y) : (p1.x < aux.p1.x)) : (p0.y < aux.p0.y)) : p0.x < aux.p0.x;
}
void revert() { tswap(p0, p1); }
};
class wChunk
{
public:
double w0, w1;
wChunk(double _w0, double _w1) : w0(_w0), w1(_w1) {}
bool operator<(const wChunk &b) const { return (w1 < b.w0); }
};
//-------------------------------------------------------------------
const int c_soundRate = 5512; // 5512; //11025
const int c_soundBps = 16;
const bool c_soundIsSigned = false;
const int c_soundChannelNum = 1;
const int c_soundCompression = 3; //per compatibilita' con MAC!!!
//-------------------------------------------------------------------
class FlashImageData
{
public:
FlashImageData(TAffine aff, TImageP img, const TColorFunction *cf, bool isMask, bool isMasked)
: m_aff(aff), m_img(img), m_cf(cf), m_isMask(isMask), m_isMasked(isMasked)
{
assert(!isMask || !isMasked);
}
TAffine m_aff;
const TColorFunction *m_cf;
bool m_isMask, m_isMasked;
TImageP m_img;
};
class FlashColorStyle
{
public:
TPixel m_color;
double m_thickness;
U32 m_id;
FlashColorStyle(TPixel color, double thickness, U32 id)
: m_color(color), m_thickness(thickness), m_id(id) {}
};
class TFlash::Imp
{
public:
//double m_totMem;
bool m_supportAlpha;
int m_tw;
UCHAR m_version;
SCOORD m_sCoord1;
bool m_loaderAdded;
TAffine m_globalScale;
//typedef triple FlashImageData;
typedef vector<FlashImageData> FrameData;
FObjCollection m_tags;
FDTSprite *m_currSprite;
int m_currDepth;
int m_frameRate;
int m_currFrameIndex;
int m_lx, m_ly;
//ouble cameradpix, cameradpiy, inchFactor;
const TPalette *m_currPalette;
int m_soundRate;
Tiio::SwfWriterProperties m_properties;
bool m_maskEnabled;
bool m_isMask;
bool m_keepImages;
std::list<FlashPolyline> m_polylinesArray;
//std::set<Polyline> m_currentEdgeArray;
TPixel32 m_lineColor;
double m_thickness;
PolyStyle m_polyData;
//vector<PolyStyle> m_currentBgStyle;
int m_regionDepth;
int m_strokeCount;
/*TPixel32 m_fillColor;
TAffine m_fillMatrix;
TRaster32P m_texture;
GradientType m_gradientType;
TPixel32 m_gradientColor1, m_gradientColor2;*/
//std::ofstream m_of;
TAffine m_affine;
vector<TAffine> m_matrixStack;
map<const TImage *, USHORT> m_imagesMap;
map<const TImage *, double> m_imagesScaleMap;
map<TEdge, FlashPolyline *> m_edgeMap;
map<const void *, USHORT> m_texturesMap;
map<biPoint, FlashPolyline *> m_autocloseMap;
map<const TStroke *, std::set<wChunk>> m_strokeMap;
vector<TStroke *> m_outlines;
TPixel m_currStrokeColor;
//std::set<TPixel> m_outlineColors;
FrameData *m_frameData;
FrameData *m_oldFrameData;
//bool m_notClipped;
vector<TSoundTrackP> m_sound;
int m_soundSize;
vector<UCHAR *> m_soundBuffer;
int m_soundOffset;
TVectorImageP m_currMask;
vector<vector<UCHAR> *> m_toBeDeleted;
vector<TQuadratic *> m_quadsToBeDeleted;
vector<TStroke *> m_strokesToBeDeleted;
void drawPolygon(const vector<TQuadratic *> &poly, bool isOutline);
int setFill(FDTDefineShape3 *shape);
inline FMatrix *affine2Matrix(const TAffine &aff);
void drawHangedObjects();
void setStyles(const list<FlashPolyline> &polylines,
vector<U32> &lineStyleID, vector<U32> &fillStyle1ID, vector<U32> &fillStyle2ID,
FDTDefineShape3 *polygon);
U32 findStyle(const PolyStyle &p, std::map<PolyStyle, U32> &idMap, FDTDefineShape3 *polygon);
void addEdge(const TEdge &e, TPointD &p0, TPointD &p1);
void addNewEdge(const TEdge &e);
//void closeRegion(int numEdges);
void drawHangedOutlines();
void addAutoclose(biPoint &bp, int edgeIndex);
inline TPoint toTwips(const TPointD &p) { return TPoint((int)(m_tw * p.x), (int)(m_tw * (-p.y))); }
~Imp()
{
clearPointerContainer(m_toBeDeleted);
clearPointerContainer(m_quadsToBeDeleted);
clearPointerContainer(m_strokesToBeDeleted);
if (m_oldFrameData)
delete m_oldFrameData;
while (!m_soundBuffer.empty()) {
delete[] * m_soundBuffer.rbegin();
m_soundBuffer.pop_back();
}
}
//===================================================================
/*
l'inizializzazione di m_currDepth e' 3 poiche' si riservanola depth 1
per la clipcamera e la depth 2 per l'eventuale bottone (non visibile)
del play non automatico
*/
Imp(int lx, int ly, int frameCount, int frameRate, TPropertyGroup *properties, bool keepImages)
: m_version(4), m_tags(), m_currSprite(0), m_currDepth(3), m_frameRate(frameRate), m_currFrameIndex(-1), m_lx(lx), m_ly(ly), m_currPalette(0), m_maskEnabled(false), m_isMask(false), m_polylinesArray(), m_lineColor(TPixel32::Black), m_thickness(0), m_polyData(), m_regionDepth(0), m_strokeCount(0), m_affine(), m_matrixStack(), m_imagesMap(), m_imagesScaleMap(), m_edgeMap(), m_texturesMap(), m_autocloseMap(), m_strokeMap(), m_outlines(), m_currStrokeColor(0, 0, 0, 0), m_frameData(0), m_oldFrameData(0)
//, m_notClipped(true)
,
m_sound(), m_soundSize(0), m_soundBuffer(), m_currMask(), m_toBeDeleted(), m_quadsToBeDeleted(), m_strokesToBeDeleted(), m_soundOffset(0), m_loaderAdded(false), m_globalScale(), m_keepImages(keepImages), m_supportAlpha(true), m_soundRate(c_soundRate)
//, m_totMem(0)
//, m_of("c:\\temp\\boh.txt")
{
m_tags.AddFObj(new FCTFrameLabel(new FString("DigitalVideoRm")));
if (properties)
m_properties.setProperties(properties);
//m_currentBgStyle.push_back(PolyStyle());
m_tw = 16384 / tmax(m_lx, m_ly);
if (m_tw > 20)
m_tw = 20;
Tw = m_tw;
m_sCoord1 = m_tw;
//addCameraClip();
if (!m_properties.m_autoplay.getValue() && !m_properties.m_preloader.getValue())
addPause();
}
void drawSubregions(TFlash *tf, const TRegion *r, const TPalette *palette);
void doDrawPolygon(list<FlashPolyline> &polylines, int clippedShapes = 0);
int drawSegments(const vector<TSegment> segmentArray, bool isGradientColor);
int drawquads(const vector<TQuadratic> quadsArray);
int drawRectangle(const TRectD &rect);
int drawPolyline(vector<TPointD> &poly);
int drawEllipse(const TPointD &center, double radiusX, double radiusY);
void drawDot(const TPointD &center, double radius);
void buildRegion(TFlash *tf, const TVectorImageP &vi, int regionIndex);
void buildStroke(TFlash *tf, const TVectorImageP &vi, int strokeIndex);
//void addCameraClip(int index);
void writeFrame(TFlash *tf, bool isLast, int frameCountLoader, bool lastScene);
U16 getTexture(const PolyStyle &p, int &lx, int &ly);
void addSoundToFrame(bool isLast);
void addActionStop();
void addLoader();
void addSkipLoader(int jumpToFrame);
void addPause();
void beginMask();
void endMask();
void addUrlLink(string url);
USHORT buildImage(const TImageP vi, TFlash *tf, double &scaleFactor, bool isMask);
USHORT buildVectorImage(const TVectorImageP &img, TFlash *tf, double &scaleFactor, bool isMask);
USHORT buildRasterImage(const TImageP rimg, TFlash *tf);
bool drawOutline(TStroke *s, bool separeDifferentColors = true);
inline void addEdgeStraightToShape(FDTDefineShape3 *shape, int x, int y);
inline void addEdgeStraightToShape(FDTDefineShape3 *shape, const TPoint &p);
};
//===================================================================
void TFlash::setSoundRate(int soundrate)
{
m_imp->m_soundRate = soundrate;
}
//===================================================================
void TFlash::enableAlphaChannelForRaster(bool supportAlpha)
{
m_imp->m_supportAlpha = supportAlpha;
}
//===================================================================
namespace
{
inline void addShape(FDTDefineShape3 *polygon, bool newStyle, bool lStyle,
bool fillStyle1, bool fillStyle0, bool move, int x, int y,
int style0, int style1, int lineStyle)
{
polygon->AddShapeRec(new FShapeRecChange(newStyle, lStyle, fillStyle1, fillStyle0, move,
x, y, style0, style1, lineStyle, 0, 0));
}
inline void addShape(FDTDefineShape3 *polygon, bool newStyle, bool lStyle,
bool fillStyle1, bool fillStyle0, bool move, TPoint *p,
int style0, int style1, int lineStyle)
{
polygon->AddShapeRec(new FShapeRecChange(newStyle, lStyle, fillStyle1, fillStyle0, move,
p ? p->x : 0, p ? p->y : 0, style0, style1, lineStyle, 0, 0));
}
}
//===================================================================
inline void TFlash::Imp::addEdgeStraightToShape(FDTDefineShape3 *shape, int x, int y)
{
if (x == 0 && y == 0)
return;
//m_of<< "ADD STRAIGHT LINE: "<<x<<", "<<y<<std::endl;
if (abs(x) > 65535 || abs(y) > 65535) //flash non sa scrivere segmenti piu' lunghi di cosi', spezzo
{
shape->AddShapeRec(new FShapeRecEdgeStraight((x + 1) / 2, (y + 1) / 2));
shape->AddShapeRec(new FShapeRecEdgeStraight(x / 2, y / 2));
} else
shape->AddShapeRec(new FShapeRecEdgeStraight(x, y));
}
inline void TFlash::Imp::addEdgeStraightToShape(FDTDefineShape3 *shape, const TPoint &p)
{
addEdgeStraightToShape(shape, p.x, p.y);
}
//-------------------------------------------------------------------
double computeAverageThickness(const TStroke *s)
{
int count = s->getControlPointCount();
double resThick = 0;
int i;
for (i = 0; i < s->getControlPointCount(); i++) {
double thick = s->getControlPoint(i).thick;
if (i >= 2 && i < s->getControlPointCount() - 2)
resThick += thick;
}
if (count < 6)
return s->getControlPoint(count / 2 + 1).thick;
return resThick / (s->getControlPointCount() - 4);
}
//-------------------------------------------------------------------
inline FMatrix *TFlash::Imp::affine2Matrix(const TAffine &aff)
{
if (aff != TAffine()) {
bool hasA11OrA22, hasA12OrA21;
hasA11OrA22 = hasA12OrA21 = (aff.a12 != 0 || aff.a21 != 0);
if (!hasA12OrA21)
hasA11OrA22 = !areAlmostEqual(aff.det(), 1.0, 1e-3);
return new FMatrix(hasA11OrA22, FloatToFixed(aff.a11), FloatToFixed(aff.a22),
hasA12OrA21, FloatToFixed(-aff.a21), FloatToFixed(-aff.a12),
(TINT32)tround(aff.a13 * m_tw), -(TINT32)tround(aff.a23 * m_tw));
} else
return 0;
}
//-------------------------------------------------------------------
int TFlash::Imp::drawSegments(const vector<TSegment> segmentArray, bool isGradientColor)
{
int i;
assert(m_currSprite);
if (segmentArray.empty())
return 0;
TPointD firstPoint = segmentArray[0].getP0();
FDTDefineShape3 *polygon = new FDTDefineShape3();
U32 lineStyleID1, lineStyleID2, lineStyleID4;
lineStyleID1 = polygon->AddLineStyle((int)m_thickness * m_tw, new FColor(m_lineColor.r, m_lineColor.g, m_lineColor.b, m_lineColor.m));
if (isGradientColor) {
lineStyleID2 = polygon->AddLineStyle((int)m_thickness * m_tw, new FColor(m_lineColor.r, m_lineColor.g, m_lineColor.b, int(0.50 * (m_lineColor.m))));
//U32 lineStyleID3 = polygon->AddLineStyle(m_tw, new FColor(m_color.r, m_color.g, m_color.b, int(0.25*(m_color.m))));
lineStyleID4 = polygon->AddLineStyle((int)m_thickness * m_tw, new FColor(m_lineColor.r, m_lineColor.g, m_lineColor.b, int(0.125 * (m_lineColor.m))));
}
polygon->FinishStyleArrays();
TRectD box;
box.x0 = firstPoint.x;
box.x1 = firstPoint.x;
box.y0 = firstPoint.y;
box.y1 = firstPoint.y;
for (i = 0; i < (int)segmentArray.size(); i++) {
box += segmentArray[i].getBBox();
TPoint p0 = convert(segmentArray[i].getP0());
TPoint dp = convert(segmentArray[i].getP1()) - p0;
TPoint p((int)(m_tw * p0.x), (int)(-m_tw * p0.y));
addShape(polygon, false, isGradientColor || (i == 0), false, false, true, &p, 0,
0, (isGradientColor || (i == 0)) ? lineStyleID1 : 0);
if (isGradientColor)
addEdgeStraightToShape(polygon, 5 * dp.x, -5 * dp.y);
else {
addEdgeStraightToShape(polygon, (int)(m_tw * dp.x), (int)(m_tw * -dp.y));
continue;
}
addShape(polygon, false, true, false, false, false, 0, 0, 0, lineStyleID2);
addEdgeStraightToShape(polygon, 5 * dp.x, -5 * dp.y);
addShape(polygon, false, true, false, false, false, 0, 0, 0, lineStyleID4);
addEdgeStraightToShape(polygon, 5 * dp.x, -5 * dp.y);
}
polygon->AddShapeRec(new FShapeRecEnd());
polygon->setBounds(new FRect((int)(m_tw * box.x0), -(int)(m_tw * box.y0), (int)(m_tw * box.x1), -(int)(m_tw * box.y1)));
m_tags.AddFObj(polygon);
FCTPlaceObject2 *placePolygon = new FCTPlaceObject2(false, // ~ _hasClipDepth
false, true, false,
m_currDepth++, polygon->ID(), affine2Matrix(m_affine), 0, 0, 0, 0 /**/);
m_currSprite->AddFObj(placePolygon);
return polygon->ID();
}
//-------------------------------------------------------------------
int TFlash::Imp::drawquads(const vector<TQuadratic> quadsArray)
{
int i;
assert(m_currSprite);
if (quadsArray.empty())
return 0;
TPointD firstPoint = quadsArray[0].getP0();
TRectD box;
box.x0 = firstPoint.x;
box.x1 = firstPoint.x;
box.y0 = firstPoint.y;
box.y1 = firstPoint.y;
for (i = 0; i < (int)quadsArray.size(); i++)
box += quadsArray[i].getBBox();
FDTDefineShape3 *polygon = new FDTDefineShape3(new FRect((int)(m_tw * box.x0), -(int)(m_tw * box.y0), (int)(m_tw * box.x1), -(int)(m_tw * box.y1)));
U32 lineStyleID;
lineStyleID = polygon->AddLineStyle(m_tw, new FColor(m_lineColor.r, m_lineColor.g, m_lineColor.b, m_lineColor.m));
polygon->FinishStyleArrays();
for (i = 0; i < (int)quadsArray.size(); i++) {
TPoint p0 = toTwips(quadsArray[i].getP0());
addShape(polygon, false, i == 0, false, false, true, &p0, 0, 0, (i == 0) ? lineStyleID : 0);
TPoint dp1 = convert((quadsArray[i].getP1() - quadsArray[i].getP0()));
TPoint dp2 = convert((quadsArray[i].getP2() - quadsArray[i].getP1()));
if ((dp1 == TPoint())) {
if (dp2 == TPoint())
continue;
addEdgeStraightToShape(polygon, (int)(m_tw * dp2.x), (int)(m_tw * -dp2.y));
} else if ((dp2 == TPoint()))
addEdgeStraightToShape(polygon, (int)(m_tw * dp1.x), (int)(m_tw * -dp1.y));
else
polygon->AddShapeRec(new FShapeRecEdgeCurved((int)(m_tw * dp1.x), (int)(m_tw * -dp1.y), (int)(m_tw * dp2.x), (int)(m_tw * -dp2.y)));
}
polygon->AddShapeRec(new FShapeRecEnd());
m_tags.AddFObj(polygon);
FCTPlaceObject2 *placePolygon = new FCTPlaceObject2(false, // ~ _hasClipDepth
false, true, false,
m_currDepth++, polygon->ID(), affine2Matrix(m_affine), 0, 0, 0, 0 /**/);
m_currSprite->AddFObj(placePolygon);
return polygon->ID();
}
//-------------------------------------------------------------------
void putquads(const TStroke *s, double w0, double w1, vector<TQuadratic *> &quads)
{
int chunkIndex0, chunkIndex1, i;
double dummy;
bool ret;
ret = s->getChunkAndT(w0, chunkIndex0, dummy);
assert(!ret);
ret = s->getChunkAndT(w1, chunkIndex1, dummy);
assert(!ret);
assert(chunkIndex0 <= chunkIndex1);
for (i = chunkIndex0; i <= chunkIndex1; i++)
quads.push_back((TQuadratic *)s->getChunk(i));
}
//-------------------------------------------------------------------
void computeOutlineBoundary(vector<TStroke *> &outlines, list<FlashPolyline> &polylinesArray, const TPixel &color)
{
UINT size = polylinesArray.size();
vector<vector<TQuadratic *>> quads;
computeSweepBoundary(outlines, quads);
outlines.clear();
std::list<FlashPolyline>::iterator it = polylinesArray.begin();
std::advance(it, size);
for (int i = 0; i < (int)quads.size(); i++) {
vector<TQuadratic *> &q = quads[i];
polylinesArray.push_back(FlashPolyline());
polylinesArray.back().m_quads = quads[i];
polylinesArray.back().m_toBeDeleted = true;
polylinesArray.back().m_fillStyle1.m_type = Solid;
polylinesArray.back().m_fillStyle1.m_color1 = color;
}
}
//-------------------------------------------------------------------
void TFlash::Imp::drawHangedObjects()
{
//int i=0;
if (!m_outlines.empty())
computeOutlineBoundary(m_outlines, m_polylinesArray, m_currStrokeColor);
m_currStrokeColor = TPixel::Transparent;
//m_outlineColors.clear();
if (!m_polylinesArray.empty()) {
doDrawPolygon(m_polylinesArray, false);
std::list<FlashPolyline>::iterator it;
for (it = m_polylinesArray.begin(); it != m_polylinesArray.end(); ++it)
if (it->m_toBeDeleted)
clearPointerContainer(it->m_quads);
m_polylinesArray.clear();
m_edgeMap.clear();
m_autocloseMap.clear();
m_strokeMap.clear();
}
clearPointerContainer(m_strokesToBeDeleted);
}
//-------------------------------------------------------------------
int TFlash::Imp::drawPolyline(vector<TPointD> &poly)
{
TRect box(1000, 1000, -1000, -1000);
int i;
FDTDefineShape3 *polyLine = new FDTDefineShape3();
U16 id = polyLine->ID();
U32 fillID = setFill(polyLine);
U32 lineStyleID = 0;
if (m_thickness > 0)
lineStyleID = polyLine->AddLineStyle((int)(m_thickness * m_tw), new FColor(m_lineColor.r, m_lineColor.g, m_lineColor.b, m_lineColor.m));
polyLine->FinishStyleArrays();
TPointD currP = TPointD(m_tw * poly[0].x, -m_tw * poly[0].y);
TPoint oldIntCurrP, intCurrP = convert(currP);
addShape(polyLine, false, lineStyleID != 0, false, fillID != 0, true,
&intCurrP, fillID, 0, lineStyleID);
poly.push_back(poly.front()); //con le approssimazioni,le poly chiuse potrebbero non esserlo
for (i = 0; i < (int)poly.size() - 1; i++) {
currP += TPointD(m_tw * (+poly[i + 1].x - poly[i].x), m_tw * (-poly[i + 1].y + poly[i].y));
oldIntCurrP = intCurrP;
intCurrP = convert(currP);
if (intCurrP != oldIntCurrP)
addEdgeStraightToShape(polyLine, intCurrP.x - oldIntCurrP.x, intCurrP.y - oldIntCurrP.y);
if (intCurrP.x > box.x1)
box.x1 = intCurrP.x;
if (intCurrP.x < box.x0)
box.x0 = intCurrP.x;
if (intCurrP.y > box.y1)
box.y1 = intCurrP.y;
if (intCurrP.y < box.y0)
box.y0 = intCurrP.y;
}
poly.pop_back(); //ritolgo, per non alterare il vettore in ingresso alla funzione
polyLine->AddShapeRec(new FShapeRecEnd());
polyLine->setBounds(new FRect(box.x0, box.y0, box.x1, box.y1));
m_tags.AddFObj(polyLine);
FCTPlaceObject2 *placePoly = new FCTPlaceObject2(false, false, true, false,
m_currDepth++, id, affine2Matrix(m_affine), 0, 0, 0, 0);
m_currSprite->AddFObj(placePoly);
return id;
}
//-------------------------------------------------------------------
int TFlash::Imp::drawRectangle(const TRectD &rect)
{
TRect box = convert(TRectD(rect.x0 * m_tw, rect.y0 * m_tw, rect.x1 * m_tw, rect.y1 * m_tw));
FDTDefineShape3 *rectangle = new FDTDefineShape3(new FRect(box.x0, box.y0, box.x1, box.y1));
U16 id = rectangle->ID();
U32 fillID = setFill(rectangle);
U32 lineStyleID = 0;
if (m_thickness > 0)
lineStyleID = rectangle->AddLineStyle((int)(m_thickness * m_tw), new FColor(m_lineColor.r, m_lineColor.g, m_lineColor.b, m_lineColor.m));
rectangle->FinishStyleArrays();
addShape(rectangle, false, true, false, fillID != 0, true,
box.x0, -box.y0, fillID, 0, lineStyleID);
addEdgeStraightToShape(rectangle, box.x1 - box.x0, 0);
addEdgeStraightToShape(rectangle, 0, -box.y1 + box.y0);
addEdgeStraightToShape(rectangle, -box.x1 + box.x0, 0);
addEdgeStraightToShape(rectangle, 0, box.y1 - box.y0);
rectangle->AddShapeRec(new FShapeRecEnd());
m_tags.AddFObj(rectangle);
FCTPlaceObject2 *placeRectangle = new FCTPlaceObject2(false, false, true, false,
m_currDepth++, id, affine2Matrix(m_affine), 0, 0, 0, 0);
m_currSprite->AddFObj(placeRectangle);
return id;
}
//-------------------------------------------------------------------
//-------------------------------------------------------------------
U16 TFlash::Imp::getTexture(const PolyStyle &p, int &lx, int &ly)
{
assert(p.m_type == Texture);
assert(p.m_texture->getPixelSize() == 4);
lx = p.m_texture->getLx(), ly = p.m_texture->getLy();
std::map<const void *, USHORT>::iterator it = m_texturesMap.find(p.m_texture.getPointer());
if (it != m_texturesMap.end())
return (*it).second;
assert(p.m_texture->getWrap() == lx);
std::vector<UCHAR> *buffer = new std::vector<UCHAR>();
m_toBeDeleted.push_back(buffer);
Tiio::createJpg(*buffer, p.m_texture, m_properties.m_jpgQuality.getValue());
FDTDefineBitsJPEG2 *bitmap = new FDTDefineBitsJPEG2((UCHAR *)&(*buffer)[0], buffer->size());
m_tags.AddFObj(bitmap);
m_texturesMap[p.m_texture.getPointer()] = bitmap->ID();
//delete bufout;
return bitmap->ID();
}
//-------------------------------------------------------------------
void TFlash::Imp::drawDot(const TPointD &center, double radius)
{
FlashPolyline quads;
quads.m_lineStyle.m_type = Centerline;
quads.m_lineStyle.m_thickness = radius * 1.5;
quads.m_lineStyle.m_color1 = (m_polyData.m_color1 == TPixel::Transparent) ? m_lineColor : m_polyData.m_color1;
//quads.m_lineStyle.m_isRegion = false;
//quads.m_lineStyle.m_isHole = false;
int x = (int)((m_tw * center.x) + 0.5);
x += 3;
TPointD aux = TPointD((double)x / m_tw, center.y);
quads.m_quads.push_back((TQuadratic *)new TQuadratic(center, 0.5 * (center + aux), aux));
m_polylinesArray.push_back(quads);
}
//-------------------------------------------------------------------
int TFlash::Imp::drawEllipse(const TPointD &center, double radiusX, double radiusY)
{
int xmin = (int)(m_tw * (center.x - radiusX)); // x coordinate of the upper left corner of the bounding rectangle
int ymin = (int)(m_tw * (-center.y - radiusY)); // y coordinate of the upper left corner of the bounding rectangle
int xmax = (int)(m_tw * (center.x + radiusX)); // x coordinate of the bottom right corner of the bounding rectangle
int ymax = (int)(m_tw * (-center.y + radiusY)); // y coordinate of the bottom right corner of the bounding rectangle
int dx = xmax - xmin; // dx is width diameter
int dy = ymax - ymin; // dy is height diameter
// connect a serie of curves to draw the circle
int c1dx = (int)(0.1465 * dx);
int c1dy = (int)(0.1465 * dy);
int c2dx = (int)(0.2070 * dx);
int c2dy = (int)(0.2070 * dy);
if (c1dx == 0 || c1dy == 0 || c2dx == 0 || c2dy == 0)
return 0;
FDTDefineShape3 *ellipse = new FDTDefineShape3(new FRect(xmin, ymin, xmax, ymax));
U16 ellipseID = ellipse->ID();
U32 fillID = setFill(ellipse);
U32 lineStyleID = 0;
if (m_thickness > 0)
lineStyleID = ellipse->AddLineStyle((int)(2 * m_thickness * m_tw),
new FColor(m_lineColor.r, m_lineColor.g, m_lineColor.b, m_lineColor.m));
ellipse->FinishStyleArrays();
addShape(ellipse, false, lineStyleID > 0, false, fillID != 0, true,
xmax, -(int)(m_tw * center.y), fillID, 0, lineStyleID);
ellipse->AddShapeRec(new FShapeRecEdgeCurved(0, -c2dy, -c1dx, -c1dy));
ellipse->AddShapeRec(new FShapeRecEdgeCurved(-c1dx, -c1dy, -c2dx, 0));
ellipse->AddShapeRec(new FShapeRecEdgeCurved(-c2dx, 0, -c1dx, c1dy));
ellipse->AddShapeRec(new FShapeRecEdgeCurved(-c1dx, c1dy, 0, c2dy));
ellipse->AddShapeRec(new FShapeRecEdgeCurved(0, c2dy, c1dx, c1dy));
ellipse->AddShapeRec(new FShapeRecEdgeCurved(c1dx, c1dy, c2dx, 0));
ellipse->AddShapeRec(new FShapeRecEdgeCurved(c2dx, 0, c1dx, -c1dy));
ellipse->AddShapeRec(new FShapeRecEdgeCurved(c1dx, -c1dy, 0, -c2dy));
//TPoint dp1 = convert(m_tw*(outPolyline[0]->getP0()-outPolyline.back()->getP2()));
ellipse->AddShapeRec(new FShapeRecEnd());
m_tags.AddFObj(ellipse);
FCTPlaceObject2 *placePolygon = new FCTPlaceObject2(false, // ~ _hasClipDepth
false, true, false,
m_currDepth++, ellipseID, affine2Matrix(m_affine), 0, 0, 0, 0 /**/);
m_currSprite->AddFObj(placePolygon);
return ellipseID;
}
//-------------------------------------------------------------------
int TFlash::Imp::setFill(FDTDefineShape3 *shape)
{
if (m_polyData.m_type == Texture) {
int lx, ly;
U16 texId = getTexture(m_polyData, lx, ly);
FMatrix *app = affine2Matrix(m_polyData.m_matrix * TScale(2048.0 / lx, 2048.0 / ly));
return shape->AddFillStyle(new FFillStyleBitmap(true, texId, app));
} else if (m_polyData.m_type == LinearGradient || m_polyData.m_type == RadialGradient) {
FGradient *grad = new FGradient();
FGradRecord *gradRec1 = new FGradRecord(0, new FColor(m_polyData.m_color1.r, m_polyData.m_color1.g, m_polyData.m_color1.b, m_polyData.m_color1.m));
FGradRecord *gradRec2 = new FGradRecord(255, new FColor(m_polyData.m_color2.r, m_polyData.m_color2.g, m_polyData.m_color2.b, m_polyData.m_color2.m));
grad->Add(gradRec1);
grad->Add(gradRec2);
return shape->AddFillStyle(new FFillStyleGradient(m_polyData.m_type == LinearGradient, affine2Matrix(m_polyData.m_matrix * TScale(10.0)), grad));
} else if (m_polyData.m_type == Solid) {
FColor *color1 = new FColor(m_polyData.m_color1.r, m_polyData.m_color1.g, m_polyData.m_color1.b, m_polyData.m_color1.m);
return shape->AddSolidFillStyle(color1);
}
return 0;
}
//-------------------------------------------------------------------
bool PolyStyle::operator==(const PolyStyle &p) const
{
if (m_type != p.m_type)
return false;
switch (m_type) {
case Centerline:
return m_thickness == p.m_thickness && m_color1 == p.m_color1;
CASE Solid : return m_color1 == p.m_color1;
CASE Texture : return m_matrix == p.m_matrix && m_texture.getPointer() == p.m_texture.getPointer();
CASE LinearGradient : __OR RadialGradient : return m_color1 == p.m_color1 && m_color2 == p.m_color2 && m_matrix == p.m_matrix && m_smooth == p.m_smooth;
DEFAULT:
assert(false);
return false;
}
}
//-------------------------------------------------------------------
bool affineMinorThen(const TAffine &m0, const TAffine &m1)
{
if (m0.a11 == m1.a11) {
if (m0.a12 == m1.a12) {
if (m0.a13 == m1.a13) {
if (m0.a21 == m1.a21) {
if (m0.a22 == m1.a22)
return m0.a23 < m1.a23;
else
return m0.a22 < m1.a22;
} else
return m0.a21 < m1.a21;
} else
return m0.a13 < m1.a13;
} else
return m0.a12 < m1.a12;
} else
return m0.a11 < m1.a11;
}
//-------------------------------------------------------------------
bool PolyStyle::operator<(const PolyStyle &p) const
{
if (m_type == p.m_type)
switch (m_type) {
case Centerline:
return (m_thickness == p.m_thickness) ? m_color1 < p.m_color1 : m_thickness < p.m_thickness;
CASE Solid : return m_color1 < p.m_color1;
CASE Texture : return m_texture.getPointer() < p.m_texture.getPointer(); //ignoro la matrice!!!!
CASE LinearGradient : __OR RadialGradient : return (m_smooth == p.m_smooth) ? ((m_color1 == p.m_color1) ? ((m_color2 == p.m_color2) ? affineMinorThen(m_matrix, p.m_matrix) : m_color2 < p.m_color2) : m_color1 < p.m_color1) : m_smooth < p.m_smooth;
DEFAULT:
assert(false);
return false;
}
else
return m_type < p.m_type;
}
//-------------------------------------------------------------------
U32 TFlash::Imp::findStyle(const PolyStyle &p, std::map<PolyStyle, U32> &idMap,
FDTDefineShape3 *polygon)
{
U32 styleID = 0;
std::map<PolyStyle, U32>::iterator it;
it = idMap.find(p);
if (it != idMap.end())
return (*it).second;
else {
switch (p.m_type) {
case Centerline: {
FColor *color = new FColor(p.m_color1.r, p.m_color1.g,
p.m_color1.b, p.m_color1.m);
int thickness = (int)(2 * p.m_thickness * m_tw);
if (p.m_thickness > 0 && thickness == 0)
thickness = 1;
styleID = polygon->AddLineStyle(thickness, color);
}
CASE Solid:
{
if (p.m_color1.m == 0)
styleID = 0;
else {
FColor *color = new FColor(p.m_color1.r, p.m_color1.g,
p.m_color1.b, p.m_color1.m);
styleID = polygon->AddSolidFillStyle(color);
}
}
CASE Texture:
{
try {
int lx, ly;
U16 texId = getTexture(p, lx, ly);
FMatrix *app = affine2Matrix(p.m_matrix * TScale(2048.0 / lx, 2048.0 / ly));
styleID = polygon->AddFillStyle(new FFillStyleBitmap(true, texId, app));
} catch (TException &) {
FColor *color = new FColor(0, 0, 0, 255);
styleID = polygon->AddSolidFillStyle(color);
}
}
CASE RadialGradient:
{
FGradient *grad = new FGradient();
//FGradRecord *gradRec1 = new FGradRecord(0, new FColor(p.m_color1.r, p.m_color1.g, p.m_color1.b, p.m_color1.m));
//FGradRecord *gradRec2 = new FGradRecord(255, new FColor(p.m_color2.r, p.m_color2.g, p.m_color2.b, p.m_color2.m));
int fac = (int)(127.0 - 0.56 * p.m_smooth);
assert(fac >= 0 && fac < 128);
FGradRecord *gradRec1 = new FGradRecord(fac, new FColor(p.m_color1.r, p.m_color1.g, p.m_color1.b, p.m_color1.m));
FGradRecord *gradRec2 = new FGradRecord(255 - fac, new FColor(p.m_color2.r, p.m_color2.g, p.m_color2.b, p.m_color2.m));
grad->Add(gradRec1);
grad->Add(gradRec2);
styleID = polygon->AddFillStyle(new FFillStyleGradient(false, affine2Matrix(p.m_matrix * TScale(15.0)), grad));
}
CASE LinearGradient:
{
FGradient *grad = new FGradient();
FGradRecord *gradRec1 = new FGradRecord(0, new FColor(p.m_color1.r, p.m_color1.g, p.m_color1.b, p.m_color1.m));
FGradRecord *gradRec2 = new FGradRecord(255, new FColor(p.m_color2.r, p.m_color2.g, p.m_color2.b, p.m_color2.m));
grad->Add(gradRec1);
grad->Add(gradRec2);
styleID = polygon->AddFillStyle(new FFillStyleGradient(true, affine2Matrix(p.m_matrix * TScale(10.0)), grad));
}
DEFAULT:
assert(false);
}
idMap[p] = styleID;
return styleID;
}
}
//-------------------------------------------------------------------
void TFlash::Imp::setStyles(const list<FlashPolyline> &polylines,
vector<U32> &lineStyleID, vector<U32> &fillStyle1ID, vector<U32> &fillStyle2ID, FDTDefineShape3 *polygon)
{
int i;
std::list<FlashPolyline>::const_iterator it, itOld;
std::map<PolyStyle, U32> idMap;
for (i = 0, it = polylines.begin(); it != polylines.end(); ++i, itOld = it, ++it) {
if (it->m_lineStyle.m_type == None)
lineStyleID[i] = 0;
else if (i > 0 && it->m_lineStyle == itOld->m_lineStyle)
lineStyleID[i] = lineStyleID[i - 1];
else
lineStyleID[i] = findStyle(it->m_lineStyle, idMap, polygon);
if (it->m_fillStyle1.m_type == None)
fillStyle1ID[i] = 0;
else if (i > 0 && it->m_fillStyle1 == itOld->m_fillStyle1)
fillStyle1ID[i] = fillStyle1ID[i - 1];
else
fillStyle1ID[i] = findStyle(it->m_fillStyle1, idMap, polygon);
if (it->m_fillStyle2.m_type == None)
fillStyle2ID[i] = 0;
else if (i > 0 && it->m_fillStyle2 == itOld->m_fillStyle2)
fillStyle2ID[i] = fillStyle2ID[i - 1];
else
fillStyle2ID[i] = findStyle(it->m_fillStyle2, idMap, polygon);
}
}
//-------------------------------------------------------------------
TPoint drawPoint(const TQuadratic *poly, FDTDefineShape3 *polygon, double radius, TRect &box)
{
TPointD center = poly->getP0();
int xmin = (int)(Tw * (center.x - radius)); // x coordinate of the upper left corner of the bounding rectangle
int ymin = (int)(Tw * (-center.y - radius)); // y coordinate of the upper left corner of the bounding rectangle
int xmax = (int)(Tw * (center.x + radius)); // x coordinate of the bottom right corner of the bounding rectangle
int ymax = (int)(Tw * (-center.y + radius)); // y coordinate of the bottom right corner of the bounding rectangle
int dx = xmax - xmin; // dx is width diameter
int dy = ymax - ymin; // dy is height diameter
// connect a serie of curves to draw the circle
int c1dx = (int)(0.1465 * dx);
int c1dy = (int)(0.1465 * dy);
int c2dx = (int)(0.2070 * dx);
int c2dy = (int)(0.2070 * dy);
if (c1dx == 0 || c1dy == 0 || c2dx == 0 || c2dy == 0)
return TPoint();
if (xmax > box.x1)
box.x1 = xmax;
if (xmin < box.x0)
box.x0 = xmin;
if (ymax > box.y1)
box.y1 = ymax;
if (ymin < box.y0)
box.y0 = ymin;
//polygon->AddShapeRec(new FShapeRecEdgeCurved(dp1.x, -dp1.y, dp2.x, -dp2.y));
//
addShape(polygon, false, true, false, false, true,
xmax, (int)(Tw * -center.y), 0, 0, 0);
polygon->AddShapeRec(new FShapeRecEdgeCurved(0, -c2dy, -c1dx, -c1dy));
polygon->AddShapeRec(new FShapeRecEdgeCurved(-c1dx, -c1dy, -c2dx, 0));
polygon->AddShapeRec(new FShapeRecEdgeCurved(-c2dx, 0, -c1dx, c1dy));
polygon->AddShapeRec(new FShapeRecEdgeCurved(-c1dx, c1dy, 0, c2dy));
polygon->AddShapeRec(new FShapeRecEdgeCurved(0, c2dy, c1dx, c1dy));
polygon->AddShapeRec(new FShapeRecEdgeCurved(c1dx, c1dy, c2dx, 0));
polygon->AddShapeRec(new FShapeRecEdgeCurved(c2dx, 0, c1dx, -c1dy));
polygon->AddShapeRec(new FShapeRecEdgeCurved(c1dx, -c1dy, 0, -c2dy));
return TPoint(xmax, (int)(Tw * -center.y));
}
//-------------------------------------------------------------------
inline void updateBBox(TRect &box, const TPoint &p)
{
if (p.x > box.x1)
box.x1 = p.x;
if (p.x < box.x0)
box.x0 = p.x;
if (p.y > box.y1)
box.y1 = p.y;
if (p.y < box.y0)
box.y0 = p.y;
}
void TFlash::Imp::doDrawPolygon(list<FlashPolyline> &polylines, int clippedShapes)
{
assert(m_currSprite);
assert(!polylines.empty());
FDTDefineShape3 *polygon = new FDTDefineShape3();
U16 polygonID = polygon->ID();
//U32 fillID = 0;
/*
if (isOutline || isRegion)
fillID = ((clippedShapes>0)?polygon->AddSolidFillStyle( new FColor(0, 0, 0)):setFill(polygon));
*/
std::map<double, std::map<TPixel32, U32>> idMap;
vector<U32> fillStyle1ID(polylines.size());
vector<U32> fillStyle2ID(polylines.size());
vector<U32> lineStyleID(polylines.size());
int i, j;
setStyles(polylines, lineStyleID, fillStyle1ID, fillStyle2ID, polygon);
polygon->FinishStyleArrays();
std::list<FlashPolyline>::iterator itOld, it = polylines.begin(), it_e = polylines.end();
for (i = 0; it != it_e; ++i, ++it) //le maschere non vengono bene con regioni con fill2 opaco e fill1 trasparente. le giro
if (fillStyle2ID[i] != 0 && fillStyle1ID[i] == 0) {
fillStyle1ID[i] = fillStyle2ID[i];
fillStyle2ID[i] = 0;
vector<TQuadratic *> &v = (*it).m_quads;
std::reverse(v.begin(), v.end());
for (j = 0; j < (int)v.size(); j++) {
v[j] = new TQuadratic(v[j]->getP2(), v[j]->getP1(), v[j]->getP0());
m_quadsToBeDeleted.push_back(v[j]);
}
}
TPoint lastPoint, firstPoint = toTwips(polylines.front().m_quads[0]->getP0());
TPoint currP = TPoint(firstPoint.x, firstPoint.y);
TRect box;
box.x0 = firstPoint.x;
box.x1 = firstPoint.x;
box.y0 = firstPoint.y;
box.y1 = firstPoint.y;
//const PolyStyle& p = polylines.front().m_fillStyle1;
//assert(firstPoint.x!=0 && firstPoint.y!=0);
U32 currLineStyle = 0, currFillStyle1 = 0, currFillStyle2 = 0;
//if (lineStyleID[0]!=0 && (isOutline||p.m_isRegion))
currLineStyle = lineStyleID[0];
//if (fillStyle1ID[0]!=0 && (isOutline||p.m_isRegion))
currFillStyle1 = fillStyle1ID[0];
//if (fillStyle2ID[0]!=0 && p.m_isRegion)
currFillStyle2 = fillStyle2ID[0];
//m_of << "DRAW POLYGON da (" << firstPoint.x<< ", "<<firstPoint.y<<")"<<std::endl;
addShape(polygon, false, lineStyleID[0] != 0, true, true, true,
&firstPoint, currFillStyle1, currFillStyle2, currLineStyle);
//vengono aggiunti gli edges al polygon, compresi i buchi. Attenzione: i buchi sono aggiunti
//nel verso opposto di percorrenza, se no non funzionerebbe quando il polygon funge da mask!
for (it = polylines.begin(), j = 0; it != it_e; ++j, itOld = it, ++it) {
if (it->m_skip) //m_of << " SKIPPOOOOO! " <<std::endl;
continue;
const vector<TQuadratic *> &poly = it->m_quads;
firstPoint = toTwips(poly[0]->getP0());
lastPoint = toTwips(poly.back()->getP2());
/* m_of << " POLYLINE # da ( "
<<firstPoint.x
<<", "
<<firstPoint.y
<<") a ("
<<lastPoint.x
<<", "
<<lastPoint.y
<<")"
<<std::endl;*/
if (j > 0) {
//faccio una move se il salto e' sensato...evito di mettere inutili addShapeRec nell'swf per renderlo piu' piccolo...
bool isMove = (currP != firstPoint);
//bool isMove = (currP.x-firstPoint.x)<-20 || (currP.x-firstPoint.x)>20||(currP.y-firstPoint.y)<-20||(currP.y-firstPoint.y)>20;
currP = firstPoint;
updateBBox(box, currP);
bool isLineStyle = (lineStyleID[j] != currLineStyle);
if (isLineStyle)
currLineStyle = lineStyleID[j];
bool isFillStyle1 = (fillStyle1ID[j] != currFillStyle1); //se sto passando da una regione a una linea, devo mettere a zero lo stile di fill!
if (isFillStyle1)
currFillStyle1 = fillStyle1ID[j];
bool isFillStyle2 = (fillStyle2ID[j] != currFillStyle2); //se sto passando da una regione a una linea, devo mettere a zero lo stile di fill!
if (isFillStyle2)
currFillStyle2 = fillStyle2ID[j];
assert(firstPoint.x != 0 || firstPoint.y != 0);
if (isMove || isLineStyle || isFillStyle1 || isFillStyle2)
addShape(polygon, false, isLineStyle, isFillStyle2, isFillStyle1, isMove, &firstPoint,
currFillStyle1, currFillStyle2, currLineStyle);
}
for (i = 0; i < (int)poly.size(); i++) {
if (i > 0) {
TPoint dp = toTwips(poly[i]->getP0()) - toTwips(poly[i - 1]->getP2());
if (dp.x != 0 || dp.y != 0) {
addEdgeStraightToShape(polygon, dp);
currP.x += dp.x;
currP.y += dp.y;
}
}
if (!it->m_isPoint) {
TPoint dp1 = toTwips(poly[i]->getP1()) - toTwips(poly[i]->getP0());
TPoint dp2 = toTwips(poly[i]->getP2()) - toTwips(poly[i]->getP1());
if (dp1 == dp2)
addEdgeStraightToShape(polygon, dp1 + dp2);
else if (dp1 == TPoint(0, 0))
addEdgeStraightToShape(polygon, dp2);
else if (dp2 == TPoint(0, 0))
addEdgeStraightToShape(polygon, dp1);
else
polygon->AddShapeRec(new FShapeRecEdgeCurved(dp1.x, dp1.y, dp2.x, dp2.y));
currP.x += dp1.x + dp2.x;
currP.y += dp1.y + dp2.y;
//m_of<<"CURRPOINT: ("<<currP.x<<", "<<currP.y<<")"<<std::endl;
} else //e' un punto isolato! bisogna disegnarlo
{
currP = drawPoint(poly[0], polygon, it->m_lineStyle.m_thickness, box);
currLineStyle = 0;
}
updateBBox(box, currP);
}
if (poly.size() != 1 && currP != lastPoint) {
addEdgeStraightToShape(polygon, lastPoint - currP);
currP.x += lastPoint.x - currP.x;
currP.y += lastPoint.y - currP.y;
//m_of<<"AGGIUNTO RACCORDO!CURRPOINT: ("<<currP.x<<", "<<currP.y<<")"<<std::endl;
}
}
polygon->AddShapeRec(new FShapeRecEnd());
box = box.enlarge((int)(m_thickness * m_tw) + 1000);
polygon->setBounds(new FRect(box.x0, box.y0, box.x1, box.y1));
m_tags.AddFObj(polygon);
//m_of<< "aggiungo poly " <<polygon->ID()<< " a depth "<<m_currDepth<<endl;
FCTPlaceObject2 *placePolygon = new FCTPlaceObject2(clippedShapes > 0, // ~ _hasClipDepth
false, true, false,
m_currDepth, polygonID,
affine2Matrix(m_affine), 0, 0, 0,
(clippedShapes > 0) ? m_currDepth + clippedShapes : 0 /**/);
m_currDepth++;
m_currSprite->AddFObj(placePolygon);
}
//-------------------------------------------------------------------
#ifdef LEVO
void TFlash::Imp::addCameraClip(int index)
{
m_notClipped = false;
FRect *clipRectBounds = new FRect(0, 0, m_lx * m_tw, m_ly * m_tw); //coordinate values are in TWIPS
FDTDefineShape3 *clipRectangle = new FDTDefineShape3(clipRectBounds);
FColor black = FColor(0, 0, 0);
U32 blackfillID = clipRectangle->AddSolidFillStyle(new FColor(black));
clipRectangle->FinishStyleArrays();
addShape(clipRectangle, false, true, true, false, true, 0, 0, blackfillID, 0);
addEdgeStraightToShape(clipRectangle, 0, m_ly * m_tw);
addEdgeStraightToShape(clipRectangle, m_lx * m_tw, 0);
addEdgeStraightToShape(clipRectangle, 0, -m_ly * m_tw);
addEdgeStraightToShape(clipRectangle, -m_lx * m_tw, 0);
clipRectangle->AddShapeRec(new FShapeRecEnd());
// la depth e' 1 perche' riservata per la camera
m_tags.InsertFObj(index, new FCTPlaceObject2(true, false, true, false, 1,
clipRectangle->ID(), 0, 0, 0, 0, (U16)60000 /**/));
m_tags.InsertFObj(index, clipRectangle);
}
#endif
//-------------------------------------------------------------------
void computeQuadChain(const TEdge &e,
vector<TQuadratic *> &quadArray, vector<TQuadratic *> &toBeDeleted)
{
int chunk_b, chunk_e, chunk = -1;
double t_b, t_e, w0, w1;
TThickQuadratic *q_b = 0, *q_e = 0;
TThickQuadratic dummy;
bool reversed = false;
if (e.m_w0 > e.m_w1) {
reversed = true;
w0 = e.m_w1;
w1 = e.m_w0;
} else {
w0 = e.m_w0;
w1 = e.m_w1;
}
if (w0 == 0.0)
chunk_b = 0;
else {
if (e.m_s->getChunkAndT(w0, chunk, t_b))
assert(false);
q_b = new TThickQuadratic();
toBeDeleted.push_back(q_b);
e.m_s->getChunk(chunk)->split(t_b, dummy, *q_b);
chunk_b = chunk + 1;
}
if (w1 == 1.0)
chunk_e = e.m_s->getChunkCount() - 1;
else {
if (e.m_s->getChunkAndT(w1, chunk_e, t_e))
assert(false);
q_e = new TThickQuadratic();
toBeDeleted.push_back(q_e);
if (chunk_e == chunk) {
if (q_b) {
t_e = q_b->getT(e.m_s->getChunk(chunk)->getPoint(t_e));
q_b->split(t_e, *q_e, dummy);
} else
e.m_s->getChunk(0)->split(t_e, *q_e, dummy);
if (!reversed)
quadArray.push_back(q_e);
else {
quadArray.push_back(new TQuadratic(q_e->getP2(), q_e->getP1(), q_e->getP0()));
toBeDeleted.push_back(quadArray.back());
}
return;
}
e.m_s->getChunk(chunk_e)->split(t_e, *q_e, dummy);
chunk_e--;
}
int i;
assert(chunk_e >= chunk_b - 1);
if (reversed) {
if (q_e) {
q_e->reverse();
quadArray.push_back(q_e);
}
for (i = chunk_e; i >= chunk_b; i--) {
const TThickQuadratic *qAux = e.m_s->getChunk(i);
quadArray.push_back(new TQuadratic(qAux->getP2(), qAux->getP1(), qAux->getP0()));
toBeDeleted.push_back(quadArray.back());
}
if (q_b) {
q_b->reverse();
quadArray.push_back(q_b);
}
} else {
if (q_b)
quadArray.push_back(q_b);
for (i = chunk_b; i <= chunk_e; i++)
quadArray.push_back((TQuadratic *)e.m_s->getChunk(i));
if (q_e)
quadArray.push_back(q_e);
}
}
//-------------------------------------------------------------------
namespace
{
inline bool isOuterEdge(const FlashPolyline &p)
{
bool isTrasp1 = p.m_fillStyle1.m_type == None || (p.m_fillStyle1.m_type == Solid && p.m_fillStyle1.m_color1.m == 0);
bool isTrasp2 = p.m_fillStyle2.m_type == None || (p.m_fillStyle2.m_type == Solid && p.m_fillStyle2.m_color1.m == 0);
return (isTrasp1 ^ isTrasp2);
}
}
//-------------------------------------------------------------------
void TFlash::Imp::addAutoclose(biPoint &bp, int edgeIndex)
{
std::map<biPoint, FlashPolyline *>::iterator it = m_autocloseMap.end();
bp.revert();
it = m_autocloseMap.find(bp);
bp.revert();
if (it != m_autocloseMap.end())
(*it).second->m_fillStyle2 = m_polyData;
else if ((it = m_autocloseMap.find(bp)) != m_autocloseMap.end())
(*it).second->m_fillStyle1 = m_polyData;
else {
FlashPolyline quadArray1;
quadArray1.m_depth = m_regionDepth * m_strokeCount + edgeIndex + 1;
quadArray1.m_fillStyle1 = m_polyData;
quadArray1.m_quads.push_back(new TQuadratic(bp.p0, .5 * (bp.p0 + bp.p1), bp.p1));
m_quadsToBeDeleted.push_back(quadArray1.m_quads.back());
m_polylinesArray.push_back(quadArray1);
m_autocloseMap[bp] = &m_polylinesArray.back();
}
if (m_isMask && it != m_autocloseMap.end())
(*it).second->m_skip = !isOuterEdge(*(*it).second);
}
//-------------------------------------------------------------------
void TFlash::Imp::addNewEdge(const TEdge &e)
{
m_polylinesArray.push_back(FlashPolyline());
FlashPolyline &quadArray = m_polylinesArray.back();
m_edgeMap[e] = &m_polylinesArray.back();
computeQuadChain(e, quadArray.m_quads, m_quadsToBeDeleted);
quadArray.m_fillStyle1 = m_polyData;
quadArray.m_depth = m_regionDepth * m_strokeCount + e.m_index + 1;
if (e.m_s->getAverageThickness() > 0) {
assert(m_currPalette);
TStrokeProp *prop = e.m_s->getProp();
/////questo codice stava dentro tstroke::getprop/////////
TColorStyle *style = m_currPalette->getStyle(e.m_s->getStyle());
if (!style->isStrokeStyle() || style->isEnabled() == false)
prop = 0;
else {
if (!prop || style != prop->getColorStyle()) {
e.m_s->setProp(style->makeStrokeProp(e.m_s));
prop = e.m_s->getProp();
}
}
///////////
if (prop) {
OutlineStrokeProp *aux = dynamic_cast<OutlineStrokeProp *>(prop);
if (aux) {
const TSolidColorStyle *st = dynamic_cast<const TSolidColorStyle *>(aux->getColorStyle());
if (st) {
quadArray.m_lineStyle.m_color1 = st->getMainColor();
quadArray.m_lineStyle.m_type = Centerline;
quadArray.m_lineStyle.m_thickness = e.m_s->getAverageThickness();
}
}
}
//quadArray.m_lineStyle.m_color1 = e.m_s->getStyle();
}
if (quadArray.m_fillStyle1.m_type == None) {
//assert(clippedShapes>0);
quadArray.m_fillStyle1.m_type = Solid;
quadArray.m_fillStyle1.m_color1 = TPixel::Black;
}
}
//-------------------------------------------------------------------
void TFlash::Imp::addEdge(const TEdge &e, TPointD &pBegin, TPointD &pEnd)
{
TPointD auxP = pEnd;
TEdge aux = e;
tswap(aux.m_w0, aux.m_w1);
std::map<TEdge, FlashPolyline *>::iterator it;
//PolyStyle style = m_polyData;
std::stack<PolyStyle> auxs;
if ((it = m_edgeMap.find(aux)) != m_edgeMap.end()) {
(*it).second->m_fillStyle2 = m_polyData;
pBegin = (*it).second->m_quads.back()->getP2();
pEnd = (*it).second->m_quads.front()->getP0();
} else if ((it = m_edgeMap.find(e)) != m_edgeMap.end()) {
(*it).second->m_fillStyle1 = m_polyData;
pBegin = (*it).second->m_quads.front()->getP0();
pEnd = (*it).second->m_quads.back()->getP2();
} else {
addNewEdge(e);
pBegin = m_polylinesArray.back().m_quads[0]->getP0();
pEnd = m_polylinesArray.back().m_quads.back()->getP2();
}
if (m_isMask && it != m_edgeMap.end()) //per fare le maschere, non metto gli edge che hanno entrambe le sponde non trasparenti
(*it).second->m_skip = !isOuterEdge(*(*it).second);
if (!areTwEqual(auxP, pBegin)) {
biPoint tmp(auxP, pBegin);
addAutoclose(tmp, e.m_index);
}
if (m_properties.m_lineQuality.getValue() == ConstantLines) {
std::map<const TStroke *, std::set<wChunk>>::iterator it;
it = m_strokeMap.find(e.m_s);
if (it != m_strokeMap.end()) {
std::set<wChunk>::iterator it1;
wChunk wc(tmin(e.m_w0, e.m_w1), tmax(e.m_w0, e.m_w1));
it1 = it->second.find(wc);
if (it1 == it->second.end())
it->second.insert(wc);
} else {
std::set<wChunk> chunkSet;
chunkSet.insert(wChunk(tmin(e.m_w0, e.m_w1), tmax(e.m_w0, e.m_w1)));
m_strokeMap[e.m_s] = chunkSet;
}
}
}
//-------------------------------------------------------------------
void TFlash::Imp::drawSubregions(TFlash *tf, const TRegion *r, const TPalette *palette)
{
int i;
//m_currentBgStyle.push_back(m_polyData);
m_regionDepth++;
for (i = 0; i < (int)r->getSubregionCount(); i++) {
TRegion *region = r->getSubregion(i);
TRegionProp *prop = region->getProp(/*palette*/);
////prima questo codice stava dentro tregion::getprop////
int styleId = region->getStyle();
//if (styleId)
{
TColorStyle *style = palette->getStyle(styleId);
if (!style->isRegionStyle() || style->isEnabled() == false)
prop = 0;
else if (!prop || style != prop->getColorStyle()) {
region->setProp(style->makeRegionProp(region));
prop = region->getProp();
}
////////
if (prop)
prop->draw(*tf);
//m_currentBgStyle.push_back(m_polyData);
drawSubregions(tf, region, palette);
//m_currentBgStyle.pop_back();
}
}
m_regionDepth--;
//m_currentBgStyle.pop_back();
}
//-------------------------------------------------------------------
bool comparevector(const FlashPolyline &p1, const FlashPolyline &p2)
{
return p2.m_depth > p1.m_depth;
}
//-------------------------------------------------------------------
void TFlash::Imp::buildRegion(TFlash *tf, const TVectorImageP &vi, int regionIndex)
{
TRegion *region = vi->getRegion(regionIndex);
TRectD rect = region->getBBox();
double lx = rect.x1 - rect.x0;
double ly = rect.y1 - rect.y0;
if (lx < 0.5 || ly < 0.5)
return;
TRegionProp *prop = region->getProp();
int styleId = region->getStyle();
TColorStyle *style = vi->getPalette()->getStyle(styleId);
if (!style->isRegionStyle() || style->isEnabled() == false)
prop = 0;
else if (!prop || style != prop->getColorStyle()) {
region->setProp(style->makeRegionProp(region));
prop = region->getProp();
}
tf->setThickness(0);
if (prop)
prop->draw(*tf);
drawSubregions(tf, region, m_currPalette);
}
//-------------------------------------------------------------------
void TFlash::Imp::buildStroke(TFlash *tf, const TVectorImageP &vi, int strokeIndex)
{
TStroke *stroke = vi->getStroke(strokeIndex);
if (stroke->getBBox().isEmpty())
return;
TStrokeProp *prop = stroke->getProp();
/////questo codice stava dentro tstroke::getprop/////////
TColorStyle *style = vi->getPalette()->getStyle(stroke->getStyle() /*m_imp->m_styleId*/);
if (!style->isStrokeStyle() || style->isEnabled() == false)
prop = 0;
else if (!prop || style != prop->getColorStyle()) {
stroke->setProp(style->makeStrokeProp(stroke));
prop = stroke->getProp();
}
if (prop)
prop->draw(*tf);
}
//-------------------------------------------------------------------
USHORT TFlash::Imp::buildVectorImage(const TVectorImageP &_vi, TFlash *tf, double &scaleFactor, bool isMask)
{
USHORT id;
int i;
const TPalette *oldPalette;
assert(m_regionDepth == 0);
m_strokeCount = _vi->getStrokeCount();
std::vector<int> strokes;
for (i = 0; i < m_strokeCount; i++)
strokes.push_back(i);
_vi->enableMinimizeEdges(false);
_vi->notifyChangedStrokes(strokes, vector<TStroke *>());
_vi->enableMinimizeEdges(true);
TRectD box = _vi->getBBox();
int dim = tmax(convert(box).getLx(), convert(box).getLy());
TVectorImageP vi;
if (dim * m_tw > 32767.0) {
scaleFactor = dim * m_tw / 32767.0;
vi = _vi->clone();
vi->transform(TScale(1.0 / scaleFactor), true);
} else
vi = _vi;
oldPalette = m_currPalette;
m_currPalette = vi->getPalette();
bool newSprite = false;
if (m_currSprite == 0) //non e' un image pattern!!!
{
m_currSprite = new FDTSprite();
m_currDepth = 1;
newSprite = true;
}
/*assert(m_currSprite==0);
m_currSprite = new FDTSprite();
m_currDepth = 1;*/
tf->setThickness(0);
m_isMask = isMask;
if (!isMask)
for (i = 0; i < (int)vi->getStrokeCount(); i++)
vi->getStroke(i)->setAverageThickness((m_properties.m_lineQuality.getValue() == ConstantLines) ? computeAverageThickness(vi->getStroke(i)) : 0);
UINT strokeIndex = 0;
int parentDepth = 0;
while (strokeIndex < vi->getStrokeCount()) // ogni ciclo di while fa un gruppo
{
FDTSprite *parentSprite = 0;
int currStrokeIndex = strokeIndex;
if (vi->isStrokeGrouped(currStrokeIndex) != 0) {
parentSprite = m_currSprite;
parentDepth = m_currDepth;
m_currSprite = new FDTSprite();
m_currDepth = 0;
}
for (UINT regionIndex = 0; regionIndex < vi->getRegionCount(); regionIndex++)
if (vi->sameGroupStrokeAndRegion(currStrokeIndex, regionIndex))
buildRegion(tf, vi, regionIndex);
if (m_properties.m_lineQuality.getValue() != ConstantLines)
tf->drawHangedObjects();
//else
m_polylinesArray.sort(comparevector);
while (strokeIndex < vi->getStrokeCount() && vi->sameGroup(strokeIndex, currStrokeIndex)) {
if (!isMask)
buildStroke(tf, vi, strokeIndex);
strokeIndex++;
}
if (isMask && vi->getRegionCount() == 0) //pezza:se non ci sono regioni, la maschera
//deve mostrare il nulla; per fare cio', metto
//un poligono posticcio(non mascherante, puro stroke
//centerline) nella sprite, altrimenti
//invece di non vedersi nulla si vede l'
//immagine mascherata completa..
{
FlashPolyline quads;
TQuadratic qaux(TPointD(0, 0), TPointD(10, 10), TPointD(20, 20));
quads.m_quads.push_back(&qaux);
m_polylinesArray.push_back(quads);
}
tf->drawHangedObjects();
if (parentSprite) {
m_tags.AddFObj(m_currSprite);
parentSprite->AddFObj(new FCTPlaceObject2(false, // hasClipDepth
false, // hasRatio,
true, // hasCharId,
false, // hasMove,
parentDepth++, //depth
m_currSprite->ID(), //id
affine2Matrix(TAffine()), //matrix
0, 0, 0, 0));
m_currSprite = parentSprite;
m_currDepth = parentDepth;
parentSprite = 0;
}
}
id = m_currSprite->ID();
if (newSprite) {
m_currSprite->AddFObj(new FCTShowFrame());
m_tags.AddFObj(m_currSprite);
m_currSprite = 0;
}
m_currPalette = oldPalette;
return id;
}
//-------------------------------------------------------------------
USHORT TFlash::Imp::buildRasterImage(const TImageP img, TFlash *tf)
{
if (m_currSprite) //e' un custom style
{
std::map<const TImage *, USHORT>::iterator it;
if (m_keepImages && (it = m_imagesMap.find(img.getPointer())) != m_imagesMap.end()) {
m_currSprite->AddFObj(new FCTPlaceObject2(false, // hasClipDepth
false, // hasRatio,
true, // hasCharId,
false, //i!=0, // hasMove,
m_currDepth++, it->second, affine2Matrix(m_affine),
0, 0, 0, 0));
return 0;
}
}
TToonzImageP tim = (TToonzImageP)img;
TRasterImageP rim = (TRasterImageP)img;
TRasterP ri;
if (tim) {
TRaster32P raux(tim->getSize());
TRop::convert(raux, tim->getRaster(), img->getPalette(), TRect(0, 0, tim->getSize().lx - 1, tim->getSize().ly - 1), false, true);
ri = raux;
} else if (!((TRaster32P)rim->getRaster())) {
TRaster32P raux(rim->getRaster()->getSize());
TRop::convert(raux, rim->getRaster());
ri = raux;
} else
ri = rim->getRaster();
//TImageWriter::save(TFilePath("C:\\temp\\flame.tif"), ri);
int lx = ri->getLx(), ly = ri->getLy(), wrap = ri->getWrap();
/*
double dpix=72.,dpiy=72.;
if (rim)
rim->getDpi(dpix,dpiy);
else
tim->getDpi(dpix,dpiy);
if (dpix==0 && dpiy==0)
{
dpix=cameradpix;
dpiy=cameradpiy;
}
*/
//const double factor = Stage::inch;
//double unit = 100;
//int realLx = lx;//(int)(cameradpix * lx / dpix);
//int realLy = ly;//(int)(cameradpiy * ly / dpiy);
std::vector<UCHAR> *buffer = new std::vector<UCHAR>();
//TRaster32P newRaster= TRop::copyAndSwapRBChannels(ri);
//#ifdef TNZ_MACHINE_CHANNEL_ORDER_MRGB
//TRaster32P newRaster= TRop::copyAndSwapRBChannels(ri);
//Tiio::createJpg(*buffer, newRaster, m_properties.m_jpgQuality.getValue());
//#else
Tiio::createJpg(*buffer, ri, m_properties.m_jpgQuality.getValue());
m_toBeDeleted.push_back(buffer);
//#endif
int bitmapId;
if (m_supportAlpha) {
std::vector<UCHAR> alphachannel(lx * ly);
ri->lock();
TPixel *auxin, *bufin = (TPixel *)ri->getRawData();
int i, j, count = 0;
for (i = 0; i < ly; i++) {
auxin = bufin + (ly - i - 1) * wrap;
for (j = 0; j < lx; j++, auxin++)
alphachannel[count++] = auxin->m;
}
ri->unlock();
U32 zippedAlphaSizeOut = (U32)(2 * ((alphachannel.size() * 1.1) + 12));
std::vector<UCHAR> *zippedAlphaChannel = new std::vector<UCHAR>(zippedAlphaSizeOut);
compress(&(*zippedAlphaChannel)[0], (uLongf *)&zippedAlphaSizeOut, (const UCHAR *)&alphachannel[0], alphachannel.size());
zippedAlphaChannel->resize(zippedAlphaSizeOut);
m_toBeDeleted.push_back(zippedAlphaChannel);
FDTDefineBitsJPEG3 *bitmap = new FDTDefineBitsJPEG3((U8 *)&(*buffer)[0], buffer->size(), &(*zippedAlphaChannel)[0], zippedAlphaSizeOut);
m_tags.AddFObj(bitmap);
bitmapId = bitmap->ID();
} else {
FDTDefineBitsJPEG2 *bitmap = new FDTDefineBitsJPEG2((U8 *)&(*buffer)[0], buffer->size());
m_tags.AddFObj(bitmap);
bitmapId = bitmap->ID();
}
//
//m_totMem += (buffer->size()/*+zippedAlphaChannel->size()*/)/1024.0;
FRect *rectBounds = new FRect(-lx * m_sCoord1 / 2, -ly * m_sCoord1 / 2, lx * m_sCoord1 / 2, ly * m_sCoord1 / 2);
FDTDefineShape3 *rectangle = new FDTDefineShape3(rectBounds);
FMatrix *matrix1 = new FMatrix(true, m_tw * Fixed1, m_tw * Fixed1, false, 0, 0, -(lx / 2) * m_sCoord1, -(ly / 2) * m_sCoord1);
FFillStyle *fill1 = new FFillStyleBitmap(false, bitmapId, matrix1);
U32 fillStyle1_ID = rectangle->AddFillStyle(fill1);
rectangle->FinishStyleArrays();
addShape(rectangle, false, false, true, false, true, (lx / 2) * m_sCoord1, (ly / 2) * m_sCoord1, 0,
fillStyle1_ID, 0);
addEdgeStraightToShape(rectangle, -lx * m_sCoord1, 0);
addEdgeStraightToShape(rectangle, 0, -ly * m_sCoord1);
addEdgeStraightToShape(rectangle, lx * m_sCoord1, 0);
addEdgeStraightToShape(rectangle, 0, ly * m_sCoord1);
rectangle->AddShapeRec(new FShapeRecEnd());
m_tags.AddFObj(rectangle);
if (m_currSprite) {
//e' un custom style
m_imagesMap[img.getPointer()] = rectangle->ID();
m_currSprite->AddFObj(new FCTPlaceObject2(false, // hasClipDepth
false, // hasRatio,
true, // hasCharId,
false, //i!=0, // hasMove,
m_currDepth++, rectangle->ID(), affine2Matrix(m_affine),
0, 0, 0, 0));
}
return rectangle->ID();
//delete bufout;
}
//-------------------------------------------------------------------
USHORT TFlash::Imp::buildImage(const TImageP img, TFlash *tf, double &scaleFactor, bool isMask)
{
scaleFactor = 1.0;
if (img->getType() == TImage::VECTOR)
return buildVectorImage((TVectorImageP)img, tf, scaleFactor, isMask);
else
return buildRasterImage(img, tf);
}
//-------------------------------------------------------------------
void TFlash::Imp::addSoundToFrame(bool isLast)
{
if (!m_sound.empty()) {
TSoundTrackP sound = *m_sound.begin();
if ((int)m_sound.size() == m_soundSize) {
bool is16Bit = (sound->getBitPerSample() == 16);
bool isStereo = (sound->getChannelCount() == 2);
UCHAR rate;
switch (sound->getSampleRate() / 5000) {
case 1: // 5k
rate = 0;
break;
case 2: // 11k
rate = 1;
break;
case 4: // 22k
rate = 2;
break;
case 8: // 44k
rate = 3;
break;
default:
rate = 0;
}
UCHAR format = 4 * (rate) + is16Bit * 2 + isStereo;
FDTSoundStreamHead2 *head = new FDTSoundStreamHead2(
format, c_soundCompression, rate, is16Bit, isStereo, (USHORT)sound->getSampleCount());
m_tags.AddFObj(head);
}
int bytes = sound->getSampleCount() * sound->getSampleSize();
U8 *aux = new U8[bytes];
#if TNZ_LITTLE_ENDIAN
memcpy(aux, sound->getRawData(), bytes);
#else //su mac, gli short vanno girati!!
int ii;
assert(c_soundBps == 16);
const U8 *buf = sound->getRawData();
for (ii = 0; ii < (bytes & (~0x1)); ii += 2)
aux[ii] = buf[ii + 1], aux[ii + 1] = buf[ii];
#endif
m_tags.AddFObj(new FDTSoundStreamBlock(bytes, aux));
m_soundBuffer.push_back(aux);
m_sound.erase(m_sound.begin());
if (isLast)
m_sound.erase(m_sound.begin(), m_sound.end());
}
}
//-------------------------------------------------------------------
void TFlash::setGlobalScale(const TAffine &aff)
{
m_imp->m_globalScale = aff;
}
//-------------------------------------------------------------------
void TFlash::Imp::writeFrame(TFlash *tf, bool isLast, int frameCountLoader, bool lastScene)
{
if (!m_frameData)
return;
int oldSize = m_oldFrameData ? (int)m_oldFrameData->size() : -1;
int depth;
//bool firstTime = true;
static bool loaderAdded = false;
bool insiderLoader = (frameCountLoader == 1);
int currTagIndex = m_tags.GetFObjCount() - 1;
//bool putCameraClip = false;
//aggiungo l'istruzione per evitare preloader se e' gia
//caricato
if (m_currFrameIndex == 1) {
if (m_properties.m_preloader.getValue() && frameCountLoader >= 1)
addSkipLoader(frameCountLoader + 1);
if (m_properties.m_url.getValue().length() > 0)
addUrlLink(toString(m_properties.m_url.getValue()));
}
if (m_currFrameIndex > m_soundOffset)
addSoundToFrame(isLast);
double scaleFactor;
std::map<const TImage *, USHORT>::iterator it;
bool lastOneIsNotMasked = true;
TImageP currMask = 0;
int currMaskDepth;
bool animatedPalette = false;
for (depth = 0; depth < tmax((int)m_frameData->size(), oldSize); depth++) {
FCXFormWAlpha *form = 0;
if (depth < (int)m_frameData->size()) {
TImageP img = (*m_frameData)[depth].m_img;
if ((*m_frameData)[depth].m_isMask) {
currMask = img;
currMaskDepth = depth;
lastOneIsNotMasked = true;
continue;
} else if ((*m_frameData)[depth].m_isMasked && lastOneIsNotMasked) {
//assert(currMask);
lastOneIsNotMasked = false;
int numMasked = 1;
while (depth + numMasked < (int)m_frameData->size() && (*m_frameData)[depth + numMasked].m_isMasked)
numMasked++;
if (m_oldFrameData && currMaskDepth < (int)m_oldFrameData->size())
m_tags.AddFObj(new FCTRemoveObject2(currMaskDepth + 3));
if (currMaskDepth < (int)m_frameData->size() && currMask) //&&
//(currMask->getType()!=TImage::VECTOR || ((TVectorImage*)currMask)->getRegionCount()>0))
{
UINT id = buildImage(currMask, tf, scaleFactor, true);
assert(scaleFactor >= 1.0);
TAffine aff = TTranslation(0.5 * m_lx, -0.5 * m_ly) * m_globalScale * TScale(scaleFactor);
m_tags.AddFObj(new FCTPlaceObject2(true, // hasClipDepth
false, // hasRatio,
true, // hasCharId,
false, //i!=0, // hasMove,
currMaskDepth + 3, id, affine2Matrix(aff),
0, 0, 0, currMaskDepth + 3 + numMasked));
}
} else if (!(*m_frameData)[depth].m_isMasked)
lastOneIsNotMasked = true;
TVectorImageP vimg = (TVectorImageP)img;
if (vimg) {
assert(vimg->getPalette());
animatedPalette = vimg->getPalette()->isAnimated();
}
}
if (m_oldFrameData && depth < (int)m_oldFrameData->size() && depth < (int)m_frameData->size() &&
(*m_frameData)[depth].m_img.getPointer() == (*m_oldFrameData)[depth].m_img.getPointer() && !animatedPalette) {
TImageP img = (*m_frameData)[depth].m_img;
const TColorFunction *ct = (*m_frameData)[depth].m_cf;
TColorFunction::Parameters p;
if (ct && ct->getParameters(p))
form = new FCXFormWAlpha(1, 1, (TINT32)(p.m_mR * 256), (TINT32)(p.m_mG * 256), (TINT32)(p.m_mB * 256), (TINT32)(p.m_mM * 256),
(TINT32)(p.m_cR), (TINT32)(p.m_cG), (TINT32)(p.m_cB), (TINT32)(p.m_cM));
if ((*m_frameData)[depth].m_aff != (*m_oldFrameData)[depth].m_aff) {
std::map<const TImage *, double>::iterator it1;
it1 = m_imagesScaleMap.find(img.getPointer());
assert(it1 != m_imagesScaleMap.end());
scaleFactor = (*it1).second;
TAffine aff = TTranslation(0.5 * m_lx, -0.5 * m_ly) * m_globalScale * (*m_frameData)[depth].m_aff * TScale(scaleFactor);
/*if (m_notClipped && !putCameraClip)
{
TRectD box = aff*img->getBBox();
if (box.x0<0 || -box.y1<0 || box.x1>m_lx || -box.y0>m_ly)
putCameraClip = true;
}*/
m_tags.AddFObj(new FCTPlaceObject2(false, // hasClipDepth
false, // hasRatio,
false, // hasCharId,
true, //i!=0, // hasMove,
depth + 3, 0, affine2Matrix(aff),
form, 0, 0, 0));
}
} else {
if (m_oldFrameData && depth < (int)m_oldFrameData->size())
m_tags.AddFObj(new FCTRemoveObject2(depth + 3));
if (depth < (int)m_frameData->size()) {
TImageP img = (*m_frameData)[depth].m_img;
const TColorFunction *cf = (*m_frameData)[depth].m_cf;
TColorFunction::Parameters p;
if (cf && cf->getParameters(p))
form = new FCXFormWAlpha(1, 1, (TINT32)(p.m_mR * 256), (TINT32)(p.m_mG * 256), (TINT32)(p.m_mB * 256), (TINT32)(p.m_mM * 256),
(TINT32)(p.m_cR), (TINT32)(p.m_cG), (TINT32)(p.m_cB), (TINT32)(p.m_cM));
it = m_keepImages ? m_imagesMap.find(img.getPointer()) : m_imagesMap.end();
USHORT id;
if (it == m_imagesMap.end()) {
id = buildImage(img, tf, scaleFactor, false);
if (!animatedPalette) {
m_imagesMap[img.getPointer()] = id;
m_imagesScaleMap[img.getPointer()] = scaleFactor;
}
} else {
id = (*it).second;
std::map<const TImage *, double>::iterator it1;
it1 = m_imagesScaleMap.find(img.getPointer());
assert(it1 != m_imagesScaleMap.end());
scaleFactor = (*it1).second;
}
assert(scaleFactor >= 1.0);
TAffine aff = TTranslation(0.5 * m_lx, -0.5 * m_ly) * m_globalScale * (*m_frameData)[depth].m_aff * TScale(scaleFactor);
/*if (m_notClipped && !putCameraClip)
{
TRectD box = img->getBBox();
box = aff*box;
if (box.x0<0 || -box.y1<0 || box.x1>m_lx || -box.y0>m_ly)
putCameraClip = true;
}*/
/*Commento al seguente if:
questa cosa e' davvero FOLLE. C'era un baco per cui se facevi rewind
nel flash player mentre era in play restavano appese alcune immagini.
Dopo indagini e confronti con gli swf generati da flash mx, ho scoperto che , quando si fa place di una sprite
ad una certa depth, sostituendo un'altra sprite alla stessa depth, mx mette hasRatio=true con un valore
di ratio pari a 0x8!!!! Non capisco, ma lo faccio anch'io e funziona, don't ask me why. Vincenzo. */
int ratioVal = 0;
if (m_oldFrameData && (int)m_oldFrameData->size() > depth && ((*m_oldFrameData)[depth].m_img))
ratioVal = 0x8;
m_tags.AddFObj(new FCTPlaceObject2(false, // hasClipDepth
ratioVal > 0, // hasRatio,
true, // hasCharId,
false, //i!=0, // hasMove,
depth + 3, id, affine2Matrix(aff),
form, ratioVal, 0, 0));
}
}
}
//inserisce lo stop sull'ultimo frame
if (isLast && lastScene && !m_properties.m_looping.getValue()) {
addActionStop();
//loaderAdded = false;
}
m_tags.AddFObj(new FCTShowFrame());
//if (putCameraClip)
//addCameraClip(currTagIndex);
//ho una sola scena => loader interno I frame oppure
//ci sono piu' scene => la I fa da loader
if (m_properties.m_preloader.getValue() && !m_loaderAdded && (insiderLoader || (isLast && frameCountLoader > 1))) {
for (depth = 0; depth < (int)m_frameData->size(); depth++)
m_tags.AddFObj(new FCTRemoveObject2(depth + 3));
if (m_oldFrameData)
delete m_oldFrameData;
m_oldFrameData = m_frameData;
m_frameData = 0;
addLoader();
m_tags.AddFObj(new FCTShowFrame());
m_currFrameIndex++;
//inserisce lo stop al primo frame che segue il loader
if (!m_properties.m_autoplay.getValue() && loaderAdded && m_currFrameIndex == frameCountLoader + 1)
addPause();
//m_properties.m_preloader = false;
m_loaderAdded = true;
}
//else if (!m_properties.m_autoplay.getValue())
// addPauseAtStart();
if (m_frameData && isLast && m_currFrameIndex != 1)
for (depth = 0; depth < (int)m_frameData->size(); depth++)
m_tags.AddFObj(new FCTRemoveObject2(depth + 3));
}
//-------------------------------------------------------------------
void TFlash::Imp::addActionStop()
{
//construct an empty CTDoAction tag object
FCTDoAction *doAction = new FCTDoAction();
//add the stop action to the CTDoAction tag object
doAction->AddAction(new FActionStop());
//add the CTDoAction object to allTags
m_tags.AddFObj(doAction);
}
//-------------------------------------------------------------------
void TFlash::Imp::addLoader()
{
string target = "";
//construct an empty CTDoAction tag object
FCTDoAction *doAction = new FCTDoAction();
doAction->AddAction(new FActionGotoFrame((U16)0));
doAction->AddAction(new FActionPlay());
//add the CTDoAction object to allTags
m_tags.AddFObj(doAction);
}
//-------------------------------------------------------------------
void TFlash::Imp::addSkipLoader(int jumpToFrame)
{
string target = "";
//construct an empty CTDoAction tag object
FCTDoAction *doAction = new FCTDoAction();
//controlla se il file e' stato tutto caricato
doAction->AddAction(new FActionPush(new FString((U8 *)target.c_str())));
doAction->AddAction(new FActionPush(7, FLOAT(12)));
doAction->AddAction(new FActionGetProperty());
doAction->AddAction(new FActionPush(new FString((U8 *)target.c_str())));
doAction->AddAction(new FActionPush(7, FLOAT(5)));
doAction->AddAction(new FActionGetProperty());
doAction->AddAction(new FActionEquals2());
doAction->AddAction(new FActionNot());
doAction->AddAction(new FActionIf(5 + 1));
doAction->AddAction(new FActionGotoFrame((U16)jumpToFrame));
doAction->AddAction(new FActionPlay());
//add the CTDoAction object to allTags
m_tags.AddFObj(doAction);
}
//-------------------------------------------------------------------
void TFlash::Imp::addPause()
{
addActionStop();
FRect *clipRectBounds = new FRect(0, 0, m_lx * m_tw, m_ly * m_tw); //coordinate values are in TWIPS
FDTDefineShape3 *clipRectangle = new FDTDefineShape3(clipRectBounds);
FColor black = FColor(0, 0, 0);
U32 blackfillID = clipRectangle->AddSolidFillStyle(new FColor(black));
clipRectangle->FinishStyleArrays();
addShape(clipRectangle, false, true, true, false, true, 0, 0, blackfillID, 0);
addEdgeStraightToShape(clipRectangle, 0, m_ly * m_tw);
addEdgeStraightToShape(clipRectangle, m_lx * m_tw, 0);
addEdgeStraightToShape(clipRectangle, 0, -m_ly * m_tw);
addEdgeStraightToShape(clipRectangle, -m_lx * m_tw, 0);
clipRectangle->AddShapeRec(new FShapeRecEnd());
m_tags.AddFObj(clipRectangle);
FDTDefineButton2 *theButton = new FDTDefineButton2(0); //flag is 0 to indicate a push button
FMatrix *mx = new FMatrix();
FCXFormWAlpha *cxf = new FCXFormWAlpha(false, false, 0, 0, 0, 0, 0, 0, 0, 0);
FButtonRecord2 *bRec = new FButtonRecord2(true, false, false, false, clipRectangle->ID(), 1, mx, cxf);
theButton->AddButtonRecord(bRec);
//the button action
FActionCondition *ac = new FActionCondition();
ac->AddCondition(OverDownToOverUp);
ac->AddActionRecord(new FActionPlay());
theButton->AddActionCondition(ac);
m_tags.AddFObj(theButton);
FMatrix *matrix = new FMatrix();
// la depth e' 2 perche' riservata per il bottone
FCTPlaceObject2 *placeButton = new FCTPlaceObject2(false, // ~ _hasClipDepth
true, true, false,
2, theButton->ID(), matrix, 0, 0, 0, 0);
m_tags.AddFObj(placeButton);
}
//-------------------------------------------------------------------
void TFlash::Imp::addUrlLink(const string _url)
{
//addActionStop();
string url;
if (url.find("http") == -1)
url = "http://" + _url;
else
url = _url;
FRect *clipRectBounds = new FRect(0, 0, m_lx * m_tw, m_ly * m_tw); //coordinate values are in TWIPS
FDTDefineShape3 *clipRectangle = new FDTDefineShape3(clipRectBounds);
FColor black = FColor(0, 0, 0, 0);
U32 blackfillID = clipRectangle->AddSolidFillStyle(new FColor(black));
clipRectangle->FinishStyleArrays();
addShape(clipRectangle, false, true, true, false, true, 0, 0, blackfillID, 0);
addEdgeStraightToShape(clipRectangle, 0, m_ly * m_tw);
addEdgeStraightToShape(clipRectangle, m_lx * m_tw, 0);
addEdgeStraightToShape(clipRectangle, 0, -m_ly * m_tw);
addEdgeStraightToShape(clipRectangle, -m_lx * m_tw, 0);
clipRectangle->AddShapeRec(new FShapeRecEnd());
m_tags.AddFObj(clipRectangle);
FDTDefineButton2 *theButton = new FDTDefineButton2(0); //flag is 0 to indicate a push button
FMatrix *mx = new FMatrix();
FCXFormWAlpha *cxf = new FCXFormWAlpha(false, false, 0, 0, 0, 0, 0, 0, 0, 0);
FButtonRecord2 *bRec = new FButtonRecord2(true, false, false, false, clipRectangle->ID(), 1, mx, cxf);
theButton->AddButtonRecord(bRec);
//the button action
FActionCondition *ac = new FActionCondition();
ac->AddCondition(OverDownToOverUp);
ac->AddActionRecord(new FActionGetURL(new FString(url.c_str()), new FString("")));
theButton->AddActionCondition(ac);
m_tags.AddFObj(theButton);
FMatrix *matrix = new FMatrix();
// la depth e' 2 perche' riservata per il bottone
FCTPlaceObject2 *placeButton = new FCTPlaceObject2(false, // ~ _hasClipDepth
true, true, false,
2, theButton->ID(), matrix, 0, 0, 0, 0);
m_tags.AddFObj(placeButton);
}
//-------------------------------------------------------------------
void TFlash::Imp::beginMask()
{
//m_currMask = TVectorImageP();
m_currMask = new TVectorImage();
m_currMask->setPalette(new TPalette());
}
//-------------------------------------------------------------------
void TFlash::Imp::endMask()
{
m_frameData->push_back(FlashImageData(TAffine(), m_currMask, 0, true, false));
m_currMask = TVectorImageP();
}
//-------------------------------------------------------------------
bool TFlash::Imp::drawOutline(TStroke *s, bool separeDifferentColors)
{
if (m_polyData.m_color1 != m_currStrokeColor) {
//bool inserted = m_outlineColors.insert(m_polyData.m_color1).second;
if (!m_outlines.empty()) {
computeOutlineBoundary(m_outlines, m_polylinesArray, m_currStrokeColor);
}
if (!m_polylinesArray.empty() && (separeDifferentColors /* || !inserted*/)) //non posso accorpare strokes di colore diverso....flash macromedia non le importa bene! lo stronzo.
drawHangedObjects();
m_currStrokeColor = m_polyData.m_color1;
}
m_outlines.push_back(s);
return true;
}
//===================================================================
TFlash::TFlash(int lx, int ly, int frameCount, int frameRate, TPropertyGroup *properties, bool keepImages)
: m_imp(new Imp(lx, ly, frameCount, frameRate, properties, keepImages))
{
}
//-------------------------------------------------------------------
TFlash::~TFlash()
{
delete m_imp;
}
//-------------------------------------------------------------------
void TFlash::setBackgroundColor(const TPixel32 &bgColor)
{
FCTSetBackgroundColor *background =
new FCTSetBackgroundColor(new FColor(bgColor.r, bgColor.g, bgColor.b));
m_imp->m_tags.AddFObj(background);
}
//-------------------------------------------------------------------
void TFlash::setThickness(double thickness)
{
m_imp->m_thickness = thickness;
}
//-------------------------------------------------------------------
void TFlash::setFillColor(const TPixel32 &color)
{
m_imp->m_polyData.m_color1 = color;
m_imp->m_polyData.m_type = Solid;
}
//-------------------------------------------------------------------
void TFlash::setLineColor(const TPixel32 &color)
{
m_imp->m_lineColor = color;
}
//-------------------------------------------------------------------
void TFlash::setTexture(const TRaster32P &texture)
{
m_imp->m_polyData.m_type = Texture;
m_imp->m_polyData.m_texture = texture;
}
//-------------------------------------------------------------------
void TFlash::setGradientFill(bool isLinear, const TPixel &color1, const TPixel &color2, double smooth)
{
m_imp->m_polyData.m_type = (isLinear) ? LinearGradient : RadialGradient;
m_imp->m_polyData.m_color1 = color1;
m_imp->m_polyData.m_color2 = color2;
m_imp->m_polyData.m_smooth = smooth;
}
//-------------------------------------------------------------------
void TFlash::setFillStyleMatrix(const TAffine &aff)
{
m_imp->m_polyData.m_matrix = aff;
}
//-------------------------------------------------------------------
void TFlash::drawSegments(const vector<TSegment> segmentArray, bool isGradientColor)
{
m_imp->drawSegments(segmentArray, isGradientColor);
}
//-------------------------------------------------------------------
void TFlash::drawquads(const vector<TQuadratic> quadArray)
{
m_imp->drawquads(quadArray);
}
//-------------------------------------------------------------------
void TFlash::cleanCachedImages()
{
m_imp->m_imagesMap.clear();
m_imp->m_imagesScaleMap.clear();
m_imp->m_texturesMap.clear();
}
//===================================================================
void TFlash::drawCenterline(const TStroke *s, bool drawAll)
{
//vector<TQuadratic*> quads;
int i;
double thickness;
if (m_imp->m_thickness > 0)
thickness = m_imp->m_thickness;
else if (m_imp->m_properties.m_lineQuality.getValue() != ConstantLines)
thickness = computeAverageThickness(s);
else
thickness = s->getAverageThickness();
if (m_imp->m_lineColor.m == 0 || thickness == 0)
return;
if (m_imp->m_properties.m_lineQuality.getValue() != ConstantLines && m_imp->m_lineColor != m_imp->m_currStrokeColor) {
drawHangedObjects();
//m_imp->m_outlineColors.insert(m_imp->m_lineColor).second;
m_imp->m_currStrokeColor = m_imp->m_lineColor;
}
FlashPolyline quads;
if (s->getChunkCount() == 1 &&
norm2(m_imp->toTwips(s->getChunk(0)->getP2()) - m_imp->toTwips(s->getChunk(0)->getP0())) <= 4 //metto lo stile di fill: i punti si disegnano come cerchi
&& thickness > 0) {
quads.m_isPoint = true;
quads.m_fillStyle1.m_type = Solid;
quads.m_fillStyle1.m_color1 = m_imp->m_lineColor;
}
quads.m_lineStyle.m_type = Centerline;
quads.m_lineStyle.m_thickness = thickness;
quads.m_lineStyle.m_color1 = m_imp->m_lineColor;
//quads.m_lineStyle.m_isRegion = false;
//quads.m_lineStyle.m_isHole = false;
std::map<const TStroke *, std::set<wChunk>>::iterator it = m_imp->m_strokeMap.end();
if (!drawAll)
it = m_imp->m_strokeMap.find(s);
if (it == m_imp->m_strokeMap.end()) {
for (i = 0; i < s->getChunkCount(); i++)
quads.m_quads.push_back((TQuadratic *)s->getChunk(i));
m_imp->m_polylinesArray.push_back(quads);
} else {
std::set<wChunk>::iterator it1;
double oldW1 = 0;
for (it1 = it->second.begin(); it1 != it->second.end(); it1++) {
if (it1->w0 > oldW1) {
putquads(s, oldW1, it1->w0, quads.m_quads);
m_imp->m_polylinesArray.push_back(quads);
quads.m_quads.clear();
}
oldW1 = it1->w1;
}
if (oldW1 < 1.0) {
putquads(s, oldW1, 1.0, quads.m_quads);
m_imp->m_polylinesArray.push_back(quads);
quads.m_quads.clear();
}
}
}
void TFlash::drawHangedObjects()
{
m_imp->drawHangedObjects();
}
//-------------------------------------------------------------------
int TFlash::drawRectangle(const TRectD &rect)
{
m_imp->drawHangedObjects();
vector<TPointD> v;
v.push_back(rect.getP00());
v.push_back(rect.getP01());
v.push_back(rect.getP11());
v.push_back(rect.getP10());
return m_imp->drawPolyline(v);
}
//-------------------------------------------------------------------
int TFlash::drawPolyline(vector<TPointD> &poly)
{
m_imp->drawHangedObjects();
return m_imp->drawPolyline(poly);
}
//-------------------------------------------------------------------
void TFlash::drawPolygon(vector<vector<TQuadratic *>> &quads, int clippedShapes)
{
m_imp->drawHangedObjects();
//std::list<Polyline>::iterator it = polylines.begin(), it_e = polylines.end();
list<FlashPolyline> polylines;
for (int i = 0; i < (int)quads.size(); i++) {
polylines.push_back(FlashPolyline());
polylines.back().m_quads = quads[i];
polylines.back().m_fillStyle1 = m_imp->m_polyData;
}
m_imp->doDrawPolygon(polylines, clippedShapes);
}
//-------------------------------------------------------------------
void TFlash::drawDot(const TPointD &center, double radius)
{
m_imp->drawDot(center, radius);
}
//-------------------------------------------------------------------
int TFlash::drawEllipse(const TPointD &center, double radiusX, double radiusY)
{
m_imp->drawHangedObjects();
return m_imp->drawEllipse(center, radiusX, radiusY);
}
//-------------------------------------------------------------------
void TFlash::pushMatrix()
{
m_imp->m_matrixStack.push_back(m_imp->m_affine);
}
//-------------------------------------------------------------------
void TFlash::popMatrix()
{
assert(!m_imp->m_matrixStack.empty());
m_imp->m_affine = m_imp->m_matrixStack.back();
m_imp->m_matrixStack.pop_back();
}
//-------------------------------------------------------------------
void TFlash::multMatrix(const TAffine &aff)
{
m_imp->m_affine *= aff;
}
//-------------------------------------------------------------------
void TFlash::putSound(TSoundTrackP st, int offset)
{
m_imp->m_soundSize = 0;
m_imp->m_sound.clear();
TSoundTrackP st1 = st;
if (st1->getBitPerSample() != c_soundBps ||
st1->isSampleSigned() != c_soundIsSigned ||
st1->getChannelCount() != c_soundChannelNum)
st1 = TSop::convert(st, TSoundTrackFormat(m_imp->m_soundRate, c_soundBps, c_soundChannelNum, c_soundIsSigned));
else if (st1->getSampleRate() != (UINT)m_imp->m_soundRate)
st1 = TSop::resample(st1, m_imp->m_soundRate);
int frameCount = st1->getSampleCount() / (st1->getSampleRate() / m_imp->m_frameRate);
if (!frameCount)
return;
int averagePerFrame = st1->getSampleCount() / frameCount;
int sampleCount = st1->getSampleCount();
TINT32 firstSample = 0;
m_imp->m_soundOffset = offset;
while (sampleCount > 0) {
sampleCount -= averagePerFrame;
if (sampleCount >= 0) {
TSoundTrackP snd = st1->extract(firstSample, firstSample + averagePerFrame - 1);
m_imp->m_sound.push_back(snd);
firstSample += averagePerFrame;
} else {
//deversamente dalla documentazione anche x il raw data deve essere
//sempre lo stesso il numero di campioni per ogni blocco aggiunto
//allo streaming audio
TSoundTrackP snd = st1->extract(firstSample, st1->getSampleCount() - 1);
snd = TSop::insertBlank(snd, snd->getSampleCount(), abs(sampleCount));
m_imp->m_sound.push_back(snd);
}
}
m_imp->m_soundSize = m_imp->m_sound.size();
}
//-------------------------------------------------------------------
void TFlash::writeMovie(FILE *fp)
{
//m_imp->writeFrame(this, true);
//if (m_imp->m_putCameraClip)
// m_imp->addCameraClip();
if (m_imp->m_properties.m_isCompressed.getValue())
m_imp->m_tags.CreateCompressedMovie(fp,
FRect(0, 0, m_imp->m_lx * m_imp->m_tw,
m_imp->m_ly * m_imp->m_tw),
m_imp->m_frameRate);
else
m_imp->m_tags.CreateMovie(fp,
FRect(0, 0, m_imp->m_lx * m_imp->m_tw,
m_imp->m_ly * m_imp->m_tw),
m_imp->m_frameRate,
m_imp->m_version);
}
//-------------------------------------------------------------------
void TFlash::drawRegion(const TRegion &r, int clippedShapes)
{
int i;
vector<FlashPolyline> polylines;
TPointD firstPoint, lastPoint;
if (clippedShapes > 0 || m_imp->m_isMask) {
if (clippedShapes > 0)
m_imp->drawHangedObjects();
//setFillColor(TPixel::Black);
}
TPointD pBegin, pEnd, pBeginRegion;
pEnd = r.getEdge(r.getEdgeCount() - 1)->m_s->getPoint(r.getEdge(r.getEdgeCount() - 1)->m_w1);
for (i = 0; i < (int)r.getEdgeCount(); i++)
m_imp->addEdge(*r.getEdge(i), pBegin, pEnd);
//m_imp->closeRegion(r.getEdgeCount());
m_imp->m_regionDepth++;
for (i = 0; i < (int)r.getSubregionCount(); i++) {
TRegion &rr = *r.getSubregion(i);
pEnd = rr.getEdge(0)->m_s->getPoint(rr.getEdge(0)->m_w0);
for (int j = rr.getEdgeCount() - 1; j >= 0; j--) {
TEdge *e = rr.getEdge(j);
tswap(e->m_w0, e->m_w1);
m_imp->addEdge(*e, pBegin, pEnd);
tswap(e->m_w0, e->m_w1);
}
}
m_imp->m_regionDepth--;
if (clippedShapes > 0) {
m_imp->doDrawPolygon(m_imp->m_polylinesArray, clippedShapes);
//clearPointerContainer(m_imp->m_polylinesArray);
m_imp->m_polylinesArray.clear();
m_imp->m_edgeMap.clear();
m_imp->m_strokeMap.clear();
m_imp->m_autocloseMap.clear();
}
}
//-------------------------------------------------------------------
USHORT TFlash::buildImage(const TImageP img, bool isMask)
{
double scalefactor;
return m_imp->buildImage(img, this, scalefactor, isMask);
assert(scalefactor == 1.0);
}
void TFlash::beginFrame(int frameIndex)
{
m_imp->m_frameData = new TFlash::Imp::FrameData;
m_imp->m_currFrameIndex = frameIndex;
assert(m_imp->m_matrixStack.empty());
m_imp->m_affine = TAffine();
}
//-------------------------------------------------------------------
int TFlash::endFrame(bool isLast, int frameCountLoader, bool lastScene)
{
m_imp->writeFrame(this, isLast, frameCountLoader, lastScene);
if (m_imp->m_oldFrameData)
delete m_imp->m_oldFrameData;
m_imp->m_oldFrameData = m_imp->m_frameData;
m_imp->m_frameData = 0;
//QString msg = "mem: " + QString::number(m_imp->m_totMem/1024.0)+"\n";
//TSystem::outputDebug(msg.toStdString());
return m_imp->m_currFrameIndex;
}
//-------------------------------------------------------------------
//void TFlash::addPauseAtStart()
//{
// m_imp->addPauseAtStart();
//}
//-------------------------------------------------------------------
void TFlash::enableMask()
{
m_imp->m_maskEnabled = true;
}
//-------------------------------------------------------------------
void TFlash::disableMask()
{
m_imp->m_maskEnabled = false;
}
//-------------------------------------------------------------------
void TFlash::beginMask()
{
m_imp->beginMask();
}
//-------------------------------------------------------------------
void TFlash::endMask()
{
m_imp->endMask();
}
//-------------------------------------------------------------------
void TFlash::draw(const TImageP img, const TColorFunction *cf)
{
//std::map<const TVectorImage *, USHORT>::iterator it;
if (m_imp->m_currMask) {
if (img->getType() == TImage::VECTOR)
m_imp->m_currMask->mergeImage((TVectorImageP)img, m_imp->m_affine);
} else if (img)
m_imp->m_frameData->push_back(FlashImageData(m_imp->m_affine, img, cf ? cf->clone() : 0, false, m_imp->m_maskEnabled));
}
//-------------------------------------------------------------------
wstring TFlash::getLineQuality()
{
return m_imp->m_properties.m_lineQuality.getValue();
}
//-------------------------------------------------------------------
bool TFlash::drawOutline(TStroke *s)
{
assert(m_imp->m_polyData.m_type == Solid);
m_imp->drawHangedObjects();
TThickPoint p0 = s->getThickPoint(0.0), p1 = s->getThickPoint(1.0);
if (tdistance(p0, p1) < (p0.thick + p1.thick)) //pezza infame!nelle curve che si autochiudono, lo sweepboundary fa casini.
//le splitto in due pezzi, e per poter metterli nello steso poligono
//senza vedere le sovrapposizioni cambio leggermente il colore al secondo....eh eh eh
{
TStroke *s0 = new TStroke(), *s1 = new TStroke();
s->split(0.5, *s0, *s1);
m_imp->drawOutline(s0, true);
int aux = m_imp->m_polyData.m_color1.b;
m_imp->m_polyData.m_color1.b = (m_imp->m_polyData.m_color1.b == 255) ? 254 : m_imp->m_polyData.m_color1.b + 1;
//m_imp->drawHangedObjects();
m_imp->drawOutline(s1, false);
m_imp->m_polyData.m_color1.b = aux;
//m_imp->drawHangedObjects();
m_imp->m_strokesToBeDeleted.push_back(s0);
m_imp->m_strokesToBeDeleted.push_back(s1);
return true;
}
return m_imp->drawOutline(s, true);
}
//-------------------------------------------------------------