JD2022-TU1/main/extern/Camcam/LIBS/Mixer/svg/SVG_Manager.cpp

1782 lines
60 KiB
C++

#ifdef USE_SVG
#include "SVG_Manager.h"
extern char CamcamCCM[];
void scaleSvgWorld(MAD_World* svgMad);
void createStroke(MAD_World* svgMad)
void addObjectInMadWorld(MAD_World* svgMad, int parentHierIndex, bool isAGroupNode)
void initSvgMad(MAD_World* svgMad)
void madPath(TiXmlNode* node, MAD_World* svgMad)
bool svg2mad(char* svgFilename, char* destMadFilename)
void browseNode(TiXmlNode* node, MAD_World* svgMad, int parentHierIndex)
SvgFillType svgFillType(const char* fillString)
void cleanPointsList(std::vector<PointF>& pointsList)
void closePath()
void moveTo(float x, float y)
void lineTo(float x, float y)
void cubicTo(PointF c1, PointF c2, PointF e)
void quadTo(PointF c, PointF e)
void pathArc(float rx, float ry, float xAxisRotation, int largeArcFlag,
int sweepFlag, float ex, float ey, float curx, float cury)
float atoh(const char* Decode, bool findFloat)
void CleanDirectory(TCHAR * directoryPath, bool deleteFilesButNotDirectories)
char* getCleanedString(char* string)
void removeAllShit(char* filename)
float getFloat(char* &Decode)
void checkMemIntegrity(void* ptr, int Size)
void* malloc2(u32 Size)
void* realloc2(void* ptr, u32 Size)
void free2(void* ptr)
//nombre d'allocations mémoire
int nbAlloc = 0;
//tableau des tailles des zones mémoire allouées
unsigned int* allocSizes = (unsigned int*)ZeroAlloc(sizeof(unsigned int));
//tableau des pointeurs vers les zones mémoire allouées
void** allocStack = (void**)ZeroAlloc(sizeof(void*));
//nombre de pixels SVG par unité 3DSMax
float PIXELS_PER_UNIT = 30;
//chemin du répertoire image à générer pour les textures du MAD
char svgTexturesDir[512] = "";
//relation entre l'index SVG et son pointeur dans la structure tinyXML
std::vector<TiXmlElement*> svgNodes;
//id de l'objet SVG courant
char svgObjectID[260];
//nouveaux points à créer
char** textureFilenames = (char**)malloc2(sizeof(char*));
//point courant du path SVG
PointF CP(0,0);
//point initial du path SVG
PointF SP(0,0);
//nouveau path SVG à créer
char* startOfPathOut;
char* pathOut;
//longueur du path à créer
long int pathLen;
//nouveaux points à créer
std::vector<PointF> pointsList;
//nombre de points composant l'objet SVG
int svgNbPoints;
//noeud SVG courant
TiXmlElement* cNode;
//liste des textures du document SVG
SvgTexture* svgTextures = (SvgTexture*)malloc2(sizeof(SvgTexture));
//nombre de textures SVG du document SVG
int numberOfSvgTextures = 0;
//limites de la forme SVG courante
float svgxmin, svgymin, svgxmax, svgymax, svgz;
//centre de l'objet SVG en cours
PointF objectCenter;
//liste des objets SVG créés
MAD_GeometricObject** svgObjects = (MAD_GeometricObject**)malloc2(sizeof(MAD_GeometricObject*));
//monde SVG à créer
SvgWorld svgWorld;
//bounding box du monde SVG à créer
float svgWorld_Xmin, svgWorld_Ymin, svgWorld_Xmax, svgWorld_Ymax;
//debug
MAD_Simple3DVertex* saveMadPointsList;
/*****************************************************************************************/
void scaleSvgWorld(MAD_World* svgMad)
{
//récupération des limites du monde
svgWorld_Xmin = svgWorld_Xmin/PIXELS_PER_UNIT;
svgWorld_Xmax = svgWorld_Xmax/PIXELS_PER_UNIT;
svgWorld_Ymin = svgWorld_Ymin/PIXELS_PER_UNIT;
svgWorld_Ymax = svgWorld_Ymax/PIXELS_PER_UNIT;
//placement de la camera "CP"
float width = (svgWorld_Xmax - svgWorld_Xmin);
float height = (svgWorld_Ymax - svgWorld_Ymin);
svgMad->Hierarchie[1].Matrix.Translation.x = width/2;
svgMad->Hierarchie[1].Matrix.Translation.y = -height/2;
svgMad->Hierarchie[1].Matrix.Translation.z = (max(width, height)/2.0)*3.0;
//centrage sur l'origine des pivots des objets
for(int h=2; h<svgMad->NumberOfHierarchieNodes; h++)
{
svgMad->Hierarchie[h].Pivot.x = svgMad->Hierarchie[h].Pivot.x/PIXELS_PER_UNIT;
svgMad->Hierarchie[h].Pivot.y = svgMad->Hierarchie[h].Pivot.y/PIXELS_PER_UNIT;
}
//mise à l'échelle de Camcam et centrage sur l'origine des objets
for(int h=2; h<svgMad->NumberOfHierarchieNodes; h++)
{
int o = svgMad->Hierarchie[h].Object;
if(o != MAD_NULL_INDEX)
{
o--;
for(int n=0; n<svgObjects[o]->NumberOfPoints; n++)
{
svgObjects[o]->OBJ_PointList[n].Point.x = svgObjects[o]->OBJ_PointList[n].Point.x/PIXELS_PER_UNIT
- svgMad->Hierarchie[h].Pivot.x;
svgObjects[o]->OBJ_PointList[n].Point.y = svgObjects[o]->OBJ_PointList[n].Point.y/PIXELS_PER_UNIT
- svgMad->Hierarchie[h].Pivot.y;
}
}
}
//positionnement des matrices globales
for(int h=2; h<svgMad->NumberOfHierarchieNodes; h++)
{
svgMad->Hierarchie[h].Matrix.Translation.x = svgMad->Hierarchie[h].Pivot.x - svgWorld_Xmin;
svgMad->Hierarchie[h].Matrix.Translation.y = svgMad->Hierarchie[h].Pivot.y - svgWorld_Ymax;
svgMad->Hierarchie[h].Matrix.Translation.z = svgMad->Hierarchie[h].Pivot.z;
}
//positionnement des matrices locales
for(int h=2; h<svgMad->NumberOfHierarchieNodes; h++)
{
int p = svgMad->Hierarchie[h].Parent;
svgMad->Hierarchie[h].RelativeMatrix.Translation.x = svgMad->Hierarchie[h].Matrix.Translation.x
- svgMad->Hierarchie[p].Matrix.Translation.x;
svgMad->Hierarchie[h].RelativeMatrix.Translation.y = svgMad->Hierarchie[h].Matrix.Translation.y
- svgMad->Hierarchie[p].Matrix.Translation.y;
svgMad->Hierarchie[h].RelativeMatrix.Translation.z = svgMad->Hierarchie[h].Matrix.Translation.z
- svgMad->Hierarchie[p].Matrix.Translation.z;
}
//remise à zéro des points de pivots
for(int h=2; h<svgMad->NumberOfHierarchieNodes; h++)
{
svgMad->Hierarchie[h].Pivot.x = 0;
svgMad->Hierarchie[h].Pivot.y = 0;
svgMad->Hierarchie[h].Pivot.z = 0;
}
}
void createStroke(MAD_World* svgMad)
{
//initialisations
svgNbPoints = pointsList.size();
std::vector<PointF> innerPointsList;
std::vector<PointF> outerPointsList;
int strokeWidth = 1; if(cNode->Attribute("stroke-width")) strokeWidth = atoi(cNode->Attribute("stroke-width"));
strokeWidth *= 2; //TO IMPROVE
float strokeOpacity = 1.0; if(cNode->Attribute("stroke-opacity")) strokeOpacity = atof(cNode->Attribute("stroke-opacity"));
int deltaSup = strokeWidth - strokeWidth/2;
int deltaInf = strokeWidth/2;
//création des points du contour du path
PointF s0; PointF i0;
for(int i=0; i<svgNbPoints; i++)
{
//récupération des points de deux segments consécutifs
float xa = pointsList.at((i+0)%(svgNbPoints)).x; float ya = pointsList.at((i+0)%(svgNbPoints)).y;
float xb = pointsList.at((i+1)%(svgNbPoints)).x; float yb = pointsList.at((i+1)%(svgNbPoints)).y;
float xc = pointsList.at((i+2)%(svgNbPoints)).x; float yc = pointsList.at((i+2)%(svgNbPoints)).y;
//calcul des pentes de ces deux segments
float d1 = 1e30*signe(yb-ya); if(xa!=xb) d1 = (ya-yb)/(xa-xb);
float d2 = 1e30*signe(yc-yb); if(xb!=xc) d2 = (yb-yc)/(xb-xc);
//calcul des angles correspondants
float alpha1 = atan2(yb-ya, xb-xa);
float alpha2 = atan2(yc-yb, xc-xb);
//calcul des positions des quatres points sur le stroke (un intérieur et un extérieur pour chaque segment)
float xes = deltaSup*sin(alpha1) + xb; float yes = - deltaSup*cos(alpha1) + yb;
float xfs = deltaSup*sin(alpha2) + xb; float yfs = - deltaSup*cos(alpha2) + yb;
float xei = - deltaInf*sin(alpha1) + xb; float yei = deltaInf*cos(alpha1) + yb;
float xfi = - deltaInf*sin(alpha2) + xb; float yfi = deltaInf*cos(alpha2) + yb;
//calcul des ordonnées à l'origine des segments intérieurs et extérieurs du contour
float c3i = yei - d1*xei;
float c4i = yfi - d2*xfi;
float c3s = yes - d1*xes;
float c4s = yfs - d2*xfs;
//calcul des deux points d'intersection des segments intérieurs et extérieurs du contour
float xi = (c4i-c3i)/(d1-d2);
if(xa==xb)
xi = xb - signe(yb-ya)*deltaInf;
if(xb==xc)
xi = xb - signe(yc-yb)*deltaInf;
float yi = d1*xi + c3i;
if(xa==xb)
yi = d2*xi + c4i;
float xs = (c4s-c3s)/(d1-d2);
if(xa==xb)
xs = xb + signe(yb-ya)*deltaSup;
if(xb==xc)
xs = xb + signe(yc-yb)*deltaSup;
float ys = d1*xs + c3s;
if(xa==xb)
ys = d2*xs + c4s;
//ajout de ces deux points intérieur et extérieur au stroke
innerPointsList.push_back(PointF(xi, -yi));
outerPointsList.push_back(PointF(xs, -ys));
//mémorisation des premiers points intérieur et extérieur pour fermer le stroke
if(i==0)
{
i0 = PointF(xi, -yi);
s0 = PointF(xs, -ys);
}
}
//nettoyage des points colinéaires des contours intérieur et extérieur du stroke
cleanPointsList(innerPointsList);
cleanPointsList(outerPointsList);
//suppression des croisements dans le contour intérieur du stroke
PointF i1, i2, A, B;
for(int i=0; false && i<innerPointsList.size(); i++)
{
i1 = innerPointsList.at((i+0)%innerPointsList.size());
i2 = innerPointsList.at((i+1)%innerPointsList.size());
A = pointsList.at((i+1)%pointsList.size());
B = pointsList.at((i+2)%pointsList.size());
if((i1.x-i2.x)*(A.x-B.x) + (i1.y-i2.y)*(A.y-B.y) < 0)
{
PointF IA1(pointsList.at((i+0)%pointsList.size()));
PointF IB1(pointsList.at((i+1)%pointsList.size()));
PointF IA2(pointsList.at((i+1)%pointsList.size()));
PointF IB2(pointsList.at((i+2)%pointsList.size()));
//calcul du point d'intersection de (1) et (2)
//calcul des angles de (1) et (2)
float alpha1 = atan2(IB1.y - IA1.y, IB1.x - IA1.x);
float alpha2 = atan2(IB2.y - IA2.y, IB2.x - IA2.x);
//calcul des pentes de ces deux droites
float d1 = 1e30*signe(IB1.y-IA1.y); if(IB1.x!=IA1.x) d1 = (IA1.y-IB1.y)/(IA1.x-IB1.x);
float d2 = 1e30*signe(IB2.y-IA2.y); if(IB2.x!=IA2.x) d1 = (IA2.y-IB2.y)/(IA2.x-IB2.x);
//calcul des ordonnées à l'origine des segments intérieurs et extérieurs du contour
float c1 = i1.y - d1*i1.x;
float c2 = i2.y - d2*i2.x;
//calcul des deux points d'intersection des segments intérieurs et extérieurs du contour
float xi = (c2-c1)/(d1-d2);
/*
if(xa==xb)
xi = xb - signe(yb-ya)*deltaInf;
if(xb==xc)
xi = xb - signe(yc-yb)*deltaInf;
*/
float yi = d1*xi + c1;
/*
if(xa==xb)
yi = d2*xi + c4i;
*/
//i1 ou i2 devient ce point
innerPointsList.at((i+0)%innerPointsList.size()) = PointF(xi, yi);
}
}
cleanPointsList(innerPointsList);
//+idem dans l'autre sens //cleanage seulement après ???
//association des points du contour
std::vector<PointF> strokePointsList;
//strokePointsList.push_back(i0);
for(int i=0; i<innerPointsList.size(); i++) strokePointsList.push_back(innerPointsList.at(innerPointsList.size()-1-i));
//for(int i=0; i<outerPointsList.size(); i++) strokePointsList.push_back(outerPointsList.at(i));
//strokePointsList.push_back(s0);
//changement des points du path vers ceux de son contour
pointsList = strokePointsList;
svgNbPoints = strokePointsList.size();
//changement des propriétés de remplissage du path dans le node SVG pour devenir ceux du contour
cNode->SetAttribute("opacity", strokeOpacity);
cNode->SetAttribute("fill", cNode->Attribute("stroke"));
//ajout du contour au monde SVG
numberOfSvgTextures++;
addObjectInMadWorld(svgMad);
//inversion des 'z' du stroke et du contenu
///**
int objIndex = svgMad->NumberOfObjects-3;
float newSvgZ = (float)(objIndex+1)/100;
svgMad->Hierarchie[objIndex+1].Pivot.z = newSvgZ;
for(int n=0; n<svgObjects[objIndex]->NumberOfPoints; n++)
{
svgObjects[objIndex]->OBJ_PointList[n].Point.z = newSvgZ;
}
objIndex = svgMad->NumberOfObjects-2;
newSvgZ = (float)(objIndex-1)/100;
svgMad->Hierarchie[objIndex+1].Pivot.z = newSvgZ;
for(int n=0; n<svgObjects[objIndex]->NumberOfPoints; n++)
{
svgObjects[objIndex]->OBJ_PointList[n].Point.z = newSvgZ;
}
//**/
}
void addObjectInMadWorld(MAD_World* svgMad, int parentHierIndex, bool isAGroupNode)
{
bool isAnObject = !isAGroupNode;
//initialisations
int hieIndex = (svgMad->NumberOfHierarchieNodes)++;
int objIndex = MAD_NULL_INDEX;
int matIndex = MAD_NULL_INDEX;
int texIndex = MAD_NULL_INDEX;
if(isAnObject)
{
objIndex = (svgMad->NumberOfObjects)++;
matIndex = (svgMad->NumberOfMaterials)++;
texIndex = (svgMad->NumberOftexture)++;
}
//récupération de l'identifiant de l'objet sous illustrator
char textureFilename[260] = "";
if(cNode->Attribute("id") && cNode->Attribute("id")[0])
sprintf(svgObjectID, "%s\0", cNode->Attribute("id"));
else
sprintf(svgObjectID, "unnamed%d\0", svgMad->NumberOfHierarchieNodes-1);
//restitution des espaces
for(int i=0; i<strlen(svgObjectID); i++)
{
if(svgObjectID[i] == '_')
{
svgObjectID[i] = ' ';
}
}
//restitution des underscores
for(int i=0; i<strlen(svgObjectID)-5; i++)
{
if(strncmp(svgObjectID+i, " x5F ", 5)==0)
{
svgObjectID[i] = '_';
memmove(svgObjectID+i+1, svgObjectID+i+5, strlen(svgObjectID)+1-(i+5));
}
}
//correction de la multiplicité des identifiants
if(svgObjectID[strlen(svgObjectID)-1] == ' ')
{
svgObjectID[strlen(svgObjectID)-1] = ')';
for(int i=strlen(svgObjectID)-1; i>=0; i--)
{
if(svgObjectID[i] == ' ')
{
svgObjectID[i] = '(';
i = -1;
}
}
}
if(isAnObject)
{
//position infinitésimale en z de l'objet pour éviter les problèmes de rendu de superposition
svgz = (float)objIndex/100;
//triangulation des points de l'objet en vertices
MAD_Simple3DVertex* madPointsList = (MAD_Simple3DVertex*)malloc2(svgNbPoints*sizeof(MAD_Simple3DVertex));
MAD_GeometricObjectElement* madTrianglesList = (MAD_GeometricObjectElement*)malloc2(sizeof(MAD_GeometricObjectElement));
triangulatePath(madPointsList, madTrianglesList);
//création des coordonnées de texture
MAD_Vertex* madUVList = (MAD_Vertex*)malloc2(svgNbPoints*sizeof(MAD_Vertex));
createUVCoords(madUVList);
//création du matérial à ajouter
//création du fichier image de la texture
sprintf(textureFilename, "%s\\%s - texture.tga", svgTexturesDir, svgObjectID);
SvgTextureType textureType = svgTextures[numberOfSvgTextures-1].type;
if(textureType == PNG_IMAGE || textureType == JPEG_IMAGE)
createImageTexture(textureFilename);
else
createShapeTexture(textureFilename);
//création de la structure de la texture
MAD_texture* texture = (MAD_texture*)malloc2(sizeof(MAD_texture));
texture->ID.IDType = ID_MAD_Texture;
memset(texture->ID.Name, 0, 256);
sprintf(texture->ID.Name, "%s - texture.tga", svgObjectID);
memset(texture->Texturefile, 0, 260);
char appliPath[260] = "";
GetModuleFileName(NULL, appliPath, 2048);
*(strrchr(appliPath, '\\')+1) = '\0';
sprintf(texture->Texturefile, "%s%s", appliPath, textureFilename);
textureFilenames = (char**)realloc2(textureFilenames, svgMad->NumberOfObjects*sizeof(char*));
textureFilenames[svgMad->NumberOfObjects-1] = (char*)malloc2(261);
strcpy(textureFilenames[svgMad->NumberOfObjects-1], textureFilename);
//affectation de la texture au MadWorld
svgMad->AllTextures = (MAD_texture**)realloc2(svgMad->AllTextures, (svgMad->NumberOftexture)*sizeof(MAD_texture*));
svgMad->AllTextures[texIndex] = texture;
//création du MAD_StandarMaterial
MAD_StandarMaterial* material = (MAD_StandarMaterial*)malloc2(sizeof(MAD_StandarMaterial));
material->Diffuse = -1;
material->Ambient = 0;
material->Specular = 0;
material->SelfIllum = 1.0;
if(cNode->Attribute("opacity") && cNode->Attribute("opacity")[0])
material->Opacity = (float)atof(cNode->Attribute("opacity"));
else material->Opacity = 1.0;
material->MaterialFlag = MAD_MTF_PerspectivCorrection | MAD_MTF_Trans_Alpha; //TO CHECK
material->MadTexture = texIndex;
material->MatRef.MaterialType = ID_MAT_Standard;
memset(material->MatRef.Name, 0, 256);
sprintf(material->MatRef.Name, "%s - material", svgObjectID);
//réallocation de la liste des materiaux du MAD_World
svgMad->AllMaterial = (MAD_MAT_MatID**)realloc2(svgMad->AllMaterial, (svgMad->NumberOfMaterials)*sizeof(MAD_MAT_MatID*));
//affectation du MatID
svgMad->AllMaterial[matIndex] = &material->MatRef;
//création du GeometricObject à ajouter
MAD_GeometricObject* vectorialObject;
vectorialObject = (MAD_GeometricObject*)malloc2(sizeof(MAD_GeometricObject));
vectorialObject->ID.IDType = ID_MAD_GeometricObject_V0;
vectorialObject->ID.SizeOfThisOne = sizeof(MAD_GeometricObject);
memset(vectorialObject->ID.Name, 0, 256);
sprintf(vectorialObject->ID.Name, "%s - mesh", svgObjectID);
vectorialObject->NumberOfPoints = svgNbPoints;
vectorialObject->OBJ_PointList = madPointsList;
if(objIndex==1)
saveMadPointsList = vectorialObject->OBJ_PointList;
vectorialObject->NumberOfUV = svgNbPoints;
vectorialObject->OBJ_UVtextureList = madUVList;
//ajout des éléments
vectorialObject->NumberOfElements = 1;
vectorialObject->Elements = (MAD_GeometricObjectElement**)malloc2((vectorialObject->NumberOfElements)*sizeof(MAD_GeometricObjectElement*));
//ajout des triangles à l'objet
vectorialObject->Elements[0] = madTrianglesList;
vectorialObject->SecondRLIField = 0;
vectorialObject->Colors = 0;
//mémorisation de l'adresse de l'objet
svgObjects = (MAD_GeometricObject**)realloc2(svgObjects, (objIndex)*sizeof(MAD_GeometricObject*));
svgObjects[objIndex-1] = vectorialObject;
//réallocation de la liste des objects du MAD_World
svgMad->AllObjects = (MAD_NodeID**)realloc2(svgMad->AllObjects, (svgMad->NumberOfObjects)*sizeof(MAD_NodeID*));
svgMad->AllObjects[objIndex] = &vectorialObject->ID;
}
//réallocation de la hiérarchie
svgMad->Hierarchie = (MAD_WorldNode*)realloc2(svgMad->Hierarchie, (svgMad->NumberOfHierarchieNodes)*sizeof(MAD_WorldNode));
MAD_WorldNode* hierarchie = svgMad->Hierarchie;
memset(&hierarchie[hieIndex], 0, sizeof(MAD_WorldNode));
//ajout du noeud SVG à la hierarchie
svgNodes.push_back(cNode);
//recherche de la visibilité de l'objet //TO CHECK
int visible = 1;
int indexInHier = 0;
TiXmlElement* node = cNode;
do
{
if(node->Attribute("display") && strcmp(node->Attribute("display"), "none")==0)
visible = -1;
node = node->Parent()->ToElement();
} while(node);
//ajout d'un objet à la hiérarchie
//ID
hierarchie[hieIndex].ID.IDType = ID_MAD_Dummy; //de type "boite vide"
if(isAnObject) hierarchie[hieIndex].ID.IDType = ID_MAD_Shape; //de type "objet"
hierarchie[hieIndex].ID.SizeOfThisOne = 0;
memset(hierarchie[hieIndex].ID.Name, 0, 256);
sprintf(hierarchie[hieIndex].ID.Name, "%s", svgObjectID);
//Matrix
hierarchie[hieIndex].Matrix.ID.IDType = ID_MAD_Matrix;
hierarchie[hieIndex].Matrix.ID.SizeOfThisOne = sizeof(hierarchie[hieIndex].Matrix);
memset(hierarchie[hieIndex].Matrix.ID.Name, 0, 256);
sprintf(hierarchie[hieIndex].Matrix.ID.Name, "%s - GlobalMatrix", svgObjectID);
hierarchie[hieIndex].Matrix.Translation.x = 0;
hierarchie[hieIndex].Matrix.Translation.y = 0;
hierarchie[hieIndex].Matrix.Translation.z = 0;
hierarchie[hieIndex].Matrix.I.x = 1;
hierarchie[hieIndex].Matrix.I.y = 0;
hierarchie[hieIndex].Matrix.I.z = 0;
hierarchie[hieIndex].Matrix.J.x = 0;
hierarchie[hieIndex].Matrix.J.y = visible*1;
hierarchie[hieIndex].Matrix.J.z = 0;
hierarchie[hieIndex].Matrix.K.x = 0;
hierarchie[hieIndex].Matrix.K.y = 0;
hierarchie[hieIndex].Matrix.K.z = visible*1;
//RelativeMatrix
hierarchie[hieIndex].RelativeMatrix.ID.IDType = ID_MAD_Matrix;
hierarchie[hieIndex].RelativeMatrix.ID.SizeOfThisOne = sizeof(hierarchie[hieIndex].RelativeMatrix);
memset(hierarchie[hieIndex].RelativeMatrix.ID.Name, 0, 256);
sprintf(hierarchie[hieIndex].RelativeMatrix.ID.Name, "%s - LocalMatrix", svgObjectID);
hierarchie[hieIndex].RelativeMatrix.Translation.x = 0;
hierarchie[hieIndex].RelativeMatrix.Translation.y = 0;
hierarchie[hieIndex].RelativeMatrix.Translation.z = 0;
hierarchie[hieIndex].RelativeMatrix.I.x = 1;
hierarchie[hieIndex].RelativeMatrix.I.y = 0;
hierarchie[hieIndex].RelativeMatrix.I.z = 0;
hierarchie[hieIndex].RelativeMatrix.J.x = 0;
hierarchie[hieIndex].RelativeMatrix.J.y = visible*1;
hierarchie[hieIndex].RelativeMatrix.J.z = 0;
hierarchie[hieIndex].RelativeMatrix.K.x = 0;
hierarchie[hieIndex].RelativeMatrix.K.y = 0;
hierarchie[hieIndex].RelativeMatrix.K.z = visible*1;
//Pivot
hierarchie[hieIndex].Pivot.x = 0;
hierarchie[hieIndex].Pivot.y = 0;
hierarchie[hieIndex].Pivot.z = 0;
if(isAnObject)
{
hierarchie[hieIndex].Pivot.x = objectCenter.x;
hierarchie[hieIndex].Pivot.y = objectCenter.y;
hierarchie[hieIndex].Pivot.z = svgz;
}
//le reste
hierarchie[hieIndex].WiredColor = 0xff00ff; //blanc sous MAX //TO CHECK (couleur des meshes sous MAX ?)
hierarchie[hieIndex].Object = objIndex;
hierarchie[hieIndex].ObjectWithRadiosity = MAD_NULL_INDEX;
hierarchie[hieIndex].Parent = parentHierIndex;
hierarchie[hieIndex].Target = MAD_NULL_INDEX;
hierarchie[hieIndex].Material = matIndex;
hierarchie[hieIndex].RLIOfObject = 0;
}
void initSvgMad(MAD_World* svgMad)
{
//initialisation de la bounding box du monde SVG à créer
svgWorld_Xmin = 1e30; svgWorld_Ymin = 1e30;
svgWorld_Xmax = -1e30; svgWorld_Ymax = -1e30;
//remplissage du MAD_World
svgMad->MAD_Version = 0xc0de0000;
svgMad->ID.IDType = ID_MAD_World;
svgMad->ID.SizeOfThisOne = sizeof(MAD_World);
strcpy(svgMad->ID.Name, "svgWorld");
svgMad->AmbientColor = 0;
svgMad->NumberOftexture = 0;
svgMad->AllTextures = (MAD_texture**)malloc2(sizeof(MAD_texture*));
svgMad->NumberOfMaterials = 0;
svgMad->AllMaterial = (MAD_MAT_MatID**)malloc2(sizeof(MAD_MAT_MatID*));
svgMad->NumberOfObjects = 1;
svgMad->AllObjects = (MAD_NodeID**)malloc2(sizeof(MAD_NodeID*));
svgMad->NumberOfHierarchieNodes = 2;
svgMad->Hierarchie = (MAD_WorldNode*)malloc2((svgMad->NumberOfHierarchieNodes)*sizeof(MAD_WorldNode));
//création de la hiérarchie pour l'objet "Scene Root"
svgMad->Hierarchie[0].ID.IDType = ID_MAD_UNDEFINED;
svgMad->Hierarchie[0].ID.SizeOfThisOne = 0;
strcpy(svgMad->Hierarchie[0].ID.Name, "Scene Root");
svgMad->Hierarchie[0].Object = MAD_NULL_INDEX;
svgMad->Hierarchie[0].ObjectWithRadiosity = MAD_NULL_INDEX;
svgMad->Hierarchie[0].Parent = MAD_NULL_INDEX;
svgMad->Hierarchie[0].Target = MAD_NULL_INDEX;
svgMad->Hierarchie[0].Material = MAD_NULL_INDEX;
svgMad->Hierarchie[0].RLIOfObject = 0;
//Matrix
svgMad->Hierarchie[0].Matrix.ID.IDType = ID_MAD_Matrix;
svgMad->Hierarchie[0].Matrix.ID.SizeOfThisOne = sizeof(svgMad->Hierarchie[0].Matrix);
memset(svgMad->Hierarchie[0].Matrix.ID.Name, 0, 256);
sprintf(svgMad->Hierarchie[0].Matrix.ID.Name, "Scene Root_GlobalMatrix");
svgMad->Hierarchie[0].Matrix.Translation.x = 0;
svgMad->Hierarchie[0].Matrix.Translation.y = 0;
svgMad->Hierarchie[0].Matrix.Translation.z = 0;
svgMad->Hierarchie[0].Matrix.I.x = 1;
svgMad->Hierarchie[0].Matrix.I.y = 0;
svgMad->Hierarchie[0].Matrix.I.z = 0;
svgMad->Hierarchie[0].Matrix.J.x = 0;
svgMad->Hierarchie[0].Matrix.J.y = 1;
svgMad->Hierarchie[0].Matrix.J.z = 0;
svgMad->Hierarchie[0].Matrix.K.x = 0;
svgMad->Hierarchie[0].Matrix.K.y = 0;
svgMad->Hierarchie[0].Matrix.K.z = 1;
//RelativeMatrix
svgMad->Hierarchie[0].RelativeMatrix.ID.IDType = ID_MAD_Matrix;
svgMad->Hierarchie[0].RelativeMatrix.ID.SizeOfThisOne = sizeof(svgMad->Hierarchie[0].RelativeMatrix);
memset(svgMad->Hierarchie[0].RelativeMatrix.ID.Name, 0, 256);
sprintf(svgMad->Hierarchie[0].RelativeMatrix.ID.Name, "Scene Root_LocalMatrix");
svgMad->Hierarchie[0].RelativeMatrix.Translation.x = 0;
svgMad->Hierarchie[0].RelativeMatrix.Translation.y = 0;
svgMad->Hierarchie[0].RelativeMatrix.Translation.z = 0;
svgMad->Hierarchie[0].RelativeMatrix.I.x = 0;
svgMad->Hierarchie[0].RelativeMatrix.I.y = 1;
svgMad->Hierarchie[0].RelativeMatrix.I.z = 0;
svgMad->Hierarchie[0].RelativeMatrix.J.x = 1;
svgMad->Hierarchie[0].RelativeMatrix.J.y = 0;
svgMad->Hierarchie[0].RelativeMatrix.J.z = 0;
svgMad->Hierarchie[0].RelativeMatrix.K.x = 0;
svgMad->Hierarchie[0].RelativeMatrix.K.y = 0;
svgMad->Hierarchie[0].RelativeMatrix.K.z = 1;
//Pivot
svgMad->Hierarchie[0].Pivot.x = 0;
svgMad->Hierarchie[0].Pivot.y = 0;
svgMad->Hierarchie[0].Pivot.z = 0;
//création de la caméra
MAD_Camera* camera = (MAD_Camera*)malloc2(sizeof(MAD_Camera));
camera->CameraType = MAD_e_PerspCamera;
camera->ID.IDType = ID_MAD_Camera;
strcpy(camera->ID.Name, "CP\0");
camera->ID.SizeOfThisOne = sizeof(MAD_Camera);
camera->PerspInf.Fov = 0.25;
camera->PerspInf.Znear = -100.0f;
camera->PerspInf.Zfar = 1000.0f;
svgMad->AllObjects[0] = &camera->ID;
//création de sa hiérarchie
svgMad->Hierarchie[1].ID.IDType = ID_MAD_Camera;
svgMad->Hierarchie[1].ID.SizeOfThisOne = sizeof(MAD_Camera);
strcpy(svgMad->Hierarchie[1].ID.Name, "CP\0");
svgMad->Hierarchie[1].Object = 0;
svgMad->Hierarchie[1].Parent = MAD_NULL_INDEX;
//Matrix
svgMad->Hierarchie[1].Matrix.ID.IDType = ID_MAD_Matrix;
svgMad->Hierarchie[1].Matrix.ID.SizeOfThisOne = sizeof(svgMad->Hierarchie[1].Matrix);
memset(svgMad->Hierarchie[1].Matrix.ID.Name, 0, 256);
sprintf(svgMad->Hierarchie[1].Matrix.ID.Name, "CP_GlobalMatrix");
svgMad->Hierarchie[1].Matrix.I.x = 1;
svgMad->Hierarchie[1].Matrix.I.y = 0;
svgMad->Hierarchie[1].Matrix.I.z = 0;
svgMad->Hierarchie[1].Matrix.J.x = 0;
svgMad->Hierarchie[1].Matrix.J.y = 1;
svgMad->Hierarchie[1].Matrix.J.z = 0;
svgMad->Hierarchie[1].Matrix.K.x = 0;
svgMad->Hierarchie[1].Matrix.K.y = 0;
svgMad->Hierarchie[1].Matrix.K.z = 1;
}
void madPath(TiXmlNode* node, MAD_World* svgMad)
{
//initialisation des variables globales
{
//longueur du path
pathLen = strlen(node->ToElement()->Attribute("d"))+1;
//allocation du nouveau path
pathOut = (char*)malloc2(pathLen);
startOfPathOut = pathOut;
//initialisation de la liste de points
pointsList.clear();
}
//traitement des fonctions path
char* path = (char*)malloc2(pathLen);
strcpy(path, node->ToElement()->Attribute("d"));
float x0 = 0, y0 = 0; //starting point
float x = 0, y = 0; //toward point
char lastMode = 0;
PointF ctrlPt;
char *str = path;
char *end = str + pathLen;
while (*str != 0 && str != end) {
char pathElem = *str;
str++;
//création de la file des arguments flottants pour les fonctions du path
std::vector<float> arg;
float f = 0;
while((f=getFloat(str))!=0 || *str==',' || *str==' ' || *str=='\n')
{
if(f)
{
if(f==1e-30) arg.push_back(0);
else arg.push_back(f);
}
else str++;
}
if (pathElem == 'z' || pathElem == 'Z')
arg.push_back(0);
while (!arg.empty()) {
float offsetX = x; // correction offsets
float offsetY = y; // for relative commands
CP = PointF(x,y);
SP = PointF(x0,y0);
switch (pathElem) {
case 'm': {
if (arg.size() < 2) {
arg.erase(arg.begin());
break;
}
x = x0 = arg[0] + offsetX;
y = y0 = arg[1] + offsetY;
moveTo(x0, y0);
arg.erase(arg.begin()); arg.erase(arg.begin());
}
break;
case 'M': {
if (arg.size() < 2) {
arg.erase(arg.begin());
break;
}
x = x0 = arg[0];
y = y0 = arg[1];
moveTo(x0, y0);
arg.erase(arg.begin()); arg.erase(arg.begin());
}
break;
case 'z':
case 'Z': {
x = x0;
y = y0;
closePath();
arg.erase(arg.begin());
}
break;
case 'l': {
if (arg.size() < 2) {
arg.erase(arg.begin());
break;
}
x = arg.front() + offsetX;
arg.erase(arg.begin());
y = arg.front() + offsetY;
arg.erase(arg.begin());
lineTo(x, y);
}
break;
case 'L': {
if (arg.size() < 2) {
arg.erase(arg.begin());
break;
}
x = arg.front(); arg.erase(arg.begin());
y = arg.front(); arg.erase(arg.begin());
lineTo(x, y);
}
break;
case 'h': {
x = arg.front() + offsetX; arg.erase(arg.begin());
lineTo(x, y);
}
break;
case 'H': {
x = arg[0];
lineTo(x, y);
arg.erase(arg.begin());
}
break;
case 'v': {
y = arg[0] + offsetY;
lineTo(x, y);
arg.erase(arg.begin());
}
break;
case 'V': {
y = arg[0];
lineTo(x, y);
arg.erase(arg.begin());
}
break;
case 'c': {
if (arg.size() < 6) {
while (arg.size())
arg.erase(arg.begin());
break;
}
PointF c1(arg[0]+offsetX, arg[1]+offsetY);
PointF c2(arg[2]+offsetX, arg[3]+offsetY);
PointF e(arg[4]+offsetX, arg[5]+offsetY);
cubicTo(c1, c2, e);
ctrlPt = c2;
x = e.x;
y = e.y;
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
break;
}
case 'C': {
if (arg.size() < 6) {
while (arg.size())
arg.erase(arg.begin());
break;
}
PointF c1(arg[0], arg[1]);
PointF c2(arg[2], arg[3]);
PointF e(arg[4], arg[5]);
cubicTo(c1, c2, e);
ctrlPt = c2;
x = e.x;
y = e.y;
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
break;
}
case 's': {
if (arg.size() < 4) {
while (arg.size())
arg.erase(arg.begin());
break;
}
PointF c1;
if (lastMode == 'c' || lastMode == 'C' ||
lastMode == 's' || lastMode == 'S')
c1 = PointF(2*x-ctrlPt.x, 2*y-ctrlPt.y);
else
c1 = PointF(x, y);
PointF c2(arg[0]+offsetX, arg[1]+offsetY);
PointF e(arg[2]+offsetX, arg[3]+offsetY);
cubicTo(c1, c2, e);
ctrlPt = c2;
x = e.x;
y = e.y;
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
break;
}
case 'S': {
if (arg.size() < 4) {
while (arg.size())
arg.erase(arg.begin());
break;
}
PointF c1;
if (lastMode == 'c' || lastMode == 'C' ||
lastMode == 's' || lastMode == 'S')
c1 = PointF(2*x-ctrlPt.x, 2*y-ctrlPt.y);
else
c1 = PointF(x, y);
PointF c2(arg[0], arg[1]);
PointF e(arg[2], arg[3]);
cubicTo(c1, c2, e);
ctrlPt = c2;
x = e.x;
y = e.y;
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
break;
}
case 'q': {
if (arg.size() < 4) {
while (arg.size())
arg.erase(arg.begin());
break;
}
PointF c(arg[0]+offsetX, arg[1]+offsetY);
PointF e(arg[2]+offsetX, arg[3]+offsetY);
quadTo(c, e);
ctrlPt = c;
x = e.x;
y = e.y;
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
break;
}
case 'Q': {
if (arg.size() < 4) {
while (arg.size())
arg.erase(arg.begin());
break;
}
PointF c(arg[0], arg[1]);
PointF e(arg[2], arg[3]);
quadTo(c, e);
ctrlPt = c;
x = e.x;
y = e.y;
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
break;
}
case 't': {
if (arg.size() < 2) {
while (arg.size())
arg.erase(arg.begin());
break;
}
PointF e(arg[0]+offsetX, arg[1]+offsetY);
PointF c;
if (lastMode == 'q' || lastMode == 'Q' ||
lastMode == 't' || lastMode == 'T')
c = PointF(2*x-ctrlPt.x, 2*y-ctrlPt.y);
else
c = PointF(x, y);
quadTo(c, e);
ctrlPt = c;
x = e.x;
y = e.y;
arg.erase(arg.begin()); arg.erase(arg.begin());
break;
}
case 'T': {
if (arg.size() < 2) {
while (arg.size())
arg.erase(arg.begin());
break;
}
PointF e(arg[0], arg[1]);
PointF c;
if (lastMode == 'q' || lastMode == 'Q' ||
lastMode == 't' || lastMode == 'T')
c = PointF(2*x-ctrlPt.x, 2*y-ctrlPt.y);
else
c = PointF(x, y);
quadTo(c, e);
ctrlPt = c;
x = e.x;
y = e.y;
arg.erase(arg.begin()); arg.erase(arg.begin());
break;
}
case 'a': {
if (arg.size() < 7) {
while (arg.size())
arg.erase(arg.begin());
break;
}
float rx = arg[0];
float ry = arg[1];
float xAxisRotation = arg[2];
float largeArcFlag = arg[3];
float sweepFlag = arg[4];
float ex = arg[5] + offsetX;
float ey = arg[6] + offsetY;
float curx = x;
float cury = y;
pathArc(rx, ry, xAxisRotation, int(largeArcFlag), int(sweepFlag), ex, ey, curx, cury);
x = ex;
y = ey;
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin());
}
break;
case 'A': {
if (arg.size() < 7) {
while (arg.size())
arg.erase(arg.begin());
break;
}
float rx = arg[0];
float ry = arg[1];
float xAxisRotation = arg[2];
float largeArcFlag = arg[3];
float sweepFlag = arg[4];
float ex = arg[5];
float ey = arg[6];
float curx = x;
float cury = y;
pathArc(rx, ry, xAxisRotation, int(largeArcFlag), int(sweepFlag), ex, ey, curx, cury);
x = ex;
y = ey;
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin()); arg.erase(arg.begin());
arg.erase(arg.begin());
}
break;
}
lastMode = pathElem;
}
}
//suppression des points successifs colinéaires
cleanPointsList(pointsList);
svgNbPoints = pointsList.size();
//réallocation de l'attribut d modifié
node->ToElement()->SetAttribute("d", startOfPathOut);
//ajout de la forme au madWorld
addObjectInMadWorld(svgMad);
//ajout du contour de la forme au madWorld
//TO FINISH:
//if(cNode->Attribute("stroke")) createStroke(svgMad);
//libération de la mémoire
free2(path);
if(startOfPathOut) free2(startOfPathOut);
}
bool svg2mad(char* svgFilename, char* destMadFilename)
{
//récupération du facteur de conversion d'unités entre Illustrator et Camcam
char factorConv[10] = "30";
if(TheScene->GetIniValue(CamcamCCM, "svgPixelsPer3DSMaxUnit"))
TheScene->GetIniValue(CamcamCCM, "svgPixelsPer3DSMaxUnit", factorConv);
PIXELS_PER_UNIT = (float)atof(factorConv);
//précaution sur les fichiers d'entrée et de sortie de la conversion
if(lengthOfFile(svgFilename)==-1 ||
strcmp(strlwr(svgFilename+strlen(svgFilename)-4), ".svg") ||
strcmp(strlwr(destMadFilename+strlen(destMadFilename)-4), ".mad"))
{
return false;
}
//création du répertoire hébergeant les fichiers images des textures
char destFilename[500] = "";
strcpy(destFilename, destMadFilename);
destFilename[strlen(destMadFilename)-4] = 0;
sprintf(svgTexturesDir, "%s - textures", destFilename);
CreateDirectory(svgTexturesDir, NULL);
CleanDirectory(svgTexturesDir);
//travail sur une copie du fichier SVG original pour raison de sécurité
char tmpSvgFilename[] = "Mads\\tmpSvg.txt";
CopyFile(svgFilename, tmpSvgFilename, 0);
//suppression du header XML pour éviter les crashs de la librairie
long int posHead = findText(tmpSvgFilename, 0, "?>");
posHead = findText(tmpSvgFilename, posHead, "<");
long int posSvg = findText(tmpSvgFilename, 0, "<svg");
posSvg = 1 + findText(tmpSvgFilename, posSvg-4, "\n");
char* xmlHeader = (char*)malloc2(posSvg-posHead+10);
getText(tmpSvgFilename, posHead, posSvg, xmlHeader);
deleteText(tmpSvgFilename, posHead, posSvg);
//parcours et conversion des formes vectorielles du document SVG en structure MAD
MAD_World* svgMad = (MAD_World*)malloc2(sizeof(MAD_World));
TiXmlDocument doc(tmpSvgFilename);
bool svgFileLoaded = doc.LoadFile();
if(svgFileLoaded)
{
TiXmlNode* svgNode = doc.FirstChild("svg");
initSvgMad(svgMad);
browseNode(svgNode, svgMad);
scaleSvgWorld(svgMad);
}
//sauvegarde de la structure MAD puis suppression de celle-ci
if(svgFileLoaded)
{
FILE* svgMadFile = CC_fopen(destMadFilename, "w+b");
if(svgMadFile)
{
//sauvegarde du svgMadWorld
MAD_Save(svgMad, svgMadFile, MAD_SaveTextureFiles); //TO GET OPTIONAL
//fermeture du flux
CC_fclose(svgMadFile);
}
}
free2(svgMad);
//sauvegarde du document SVG généré
if(svgFileLoaded && TheScene->GetIniValue(CamcamCCM, "generateSVG"))
{
//création du chemin du fichier SVG de sortie
char* destSvgFilename = (char*)malloc2(strlen(svgFilename)+5);
strncpy(destSvgFilename, svgFilename, strlen(svgFilename)-4);
strcat(destSvgFilename, "_out.svg");
//écriture du node xml <svg> généré dans le fichier de sortie
doc.SaveFile(destSvgFilename);
//correction des problèmes d'écriture de la librairie xml
char tmpChar[50] = "xmlns=\"ns_svg;\" xmlns:xlink=\"ns_xlink;\"";
int pos = findText(destSvgFilename, 0, tmpChar);
if(pos!=-1)
{
deleteText(destSvgFilename, pos, pos+strlen(tmpChar));
insertText(destSvgFilename, pos, "xmlns=\"&ns_svg;\" xmlns:xlink=\"&ns_xlink;\"");
}
insertText(destSvgFilename, posHead, xmlHeader);
//libération des ressources utilisées
free2(destSvgFilename);
}
//libération des ressources utilisées
remove(tmpSvgFilename);
free2(xmlHeader);
//s'il y a eu un problème lors du chargement du document SVG, on renvoie FALSE
if(!svgFileLoaded) return false;
//on quitte l'application si on voulait juste convertir un fichier SVG
if(TheScene->GetIniValue(CamcamCCM, "svg2MadOnly")) exit(0);
//on renvoie TRUE si la conversion s'est passée sans encombre jusqu'au bout
return true;
}
void browseNode(TiXmlNode* node, MAD_World* svgMad, int parentHierIndex)
{
//mémorisation du pointeur vers le noeud SVG courant
cNode = node->ToElement();
//Affichage récursif des sous-balises
TiXmlNode* child = 0;
int hierIndex = svgMad->NumberOfHierarchieNodes;
if(strcmp(node->Value(), "svg") == 0) hierIndex = 0;
//traitement des balises "g"
if(strcmp(node->Value(), "g") == 0)
{
addObjectInMadWorld(svgMad, parentHierIndex, true);
}
//traitement des balises "image"
if(strcmp(node->Value(), "image") == 0)
{
numberOfSvgTextures++;
svgTextures = (SvgTexture*)realloc2(svgTextures, numberOfSvgTextures*sizeof(SvgTexture));
//récupération des données de l'image
svgTextures[numberOfSvgTextures-1].data = (char*)malloc2(1+strlen(node->ToElement()->Attribute("xlink:href")));
char* data = svgTextures[numberOfSvgTextures-1].data;
strcpy(data, node->ToElement()->Attribute("xlink:href"));
sprintf(svgTextures[numberOfSvgTextures-1].name, "imageTexture_%d", svgMad->NumberOfObjects-1);
int imageTypeStartPos = strstr(data, "/") + 1 - data;
int imageTypeEndPos = strstr(data, ";") - data;
if(strncmp(data+imageTypeStartPos, "png", imageTypeEndPos-imageTypeStartPos)==0)
svgTextures[numberOfSvgTextures-1].type = PNG_IMAGE;
else
svgTextures[numberOfSvgTextures-1].type = JPEG_IMAGE;
data = strstr(data, ",") + 1;
//récupération des coordonnées x, y et des proportions de l'image
float& x = svgTextures[numberOfSvgTextures-1].x;
float& y = svgTextures[numberOfSvgTextures-1].y;
float& w = svgTextures[numberOfSvgTextures-1].width;
float& h = svgTextures[numberOfSvgTextures-1].height;
if(node->ToElement()->Attribute("x")) x = (float)atof(node->ToElement()->Attribute("x")); else x = 0;
if(node->ToElement()->Attribute("y")) y = (float)atof(node->ToElement()->Attribute("y")); else y = 0;
w = atoi(node->ToElement()->Attribute("width"));
h = atoi(node->ToElement()->Attribute("height"));
if(node->ToElement()->Attribute("transform"))
{
char* transformation = (char*)malloc2(1000);
strcpy(transformation, node->ToElement()->Attribute("transform"));
if(strncmp("matrix(", transformation, strlen("matrix("))==0)
{
transformation = transformation + strlen("matrix(");
float a = 1.0; float b = 0.0; float c = 0.0; float d = 1.0; float e = 0.0; float f = 1.0;
sscanf(transformation, "%f %f %f %f %f %f", &a, &b, &c, &d, &e, &f);
float lx = x;
float ly = y;
float lw = w;
float lh = h;
x = a*lx+c*ly+e;
y = b*lx+d*ly+f;
w = a*(lw+lx)+c*(lh+ly)+e-x;
h = b*(lw+lx)+d*(lh+ly)+f-y;
}
}
//création des points de la forme
pointsList.clear();
svgNbPoints = 4;
//P0:
PointF P0(x, y+h); pointsList.push_back(P0);
//P1:
PointF P1(x, y); pointsList.push_back(P1);
//P2:
PointF P2(x+w, y); pointsList.push_back(P2);
//P3:
PointF P3(x+w, y+h); pointsList.push_back(P3);
//ajout de la forme au madWorld
addObjectInMadWorld(svgMad, parentHierIndex);
}
//traitement des balises "linearGradient"
if(strcmp(node->Value(), "linearGradient") == 0)
{
numberOfSvgTextures++;
svgTextures = (SvgTexture*)realloc2(svgTextures, numberOfSvgTextures*sizeof(SvgTexture));
strcpy(svgTextures[numberOfSvgTextures-1].name, node->ToElement()->Attribute("id"));
svgTextures[numberOfSvgTextures-1].type = LINEAR_GRADIENT;
float& x1 = svgTextures[numberOfSvgTextures-1].x1;
float& y1 = svgTextures[numberOfSvgTextures-1].y1;
float& x2 = svgTextures[numberOfSvgTextures-1].x2;
float& y2 = svgTextures[numberOfSvgTextures-1].y2;
if(node->ToElement()->Attribute("x1")) x1 = (float)atof(node->ToElement()->Attribute("x1")); else x1 = 0;
if(node->ToElement()->Attribute("y1")) y1 = (float)atof(node->ToElement()->Attribute("y1")); else y1 = 0;
if(node->ToElement()->Attribute("x2")) x2 = (float)atof(node->ToElement()->Attribute("x2")); else x2 = 0;
if(node->ToElement()->Attribute("y2")) y2 = (float)atof(node->ToElement()->Attribute("y2")); else y2 = 0;
if(node->ToElement()->Attribute("gradientTransform"))
{
char* transformation = (char*)malloc2(1000);
strcpy(transformation, node->ToElement()->Attribute("gradientTransform"));
if(strncmp("matrix(", transformation, strlen("matrix("))==0)
{
transformation = transformation + strlen("matrix(");
float a = 1.0; float b = 0.0; float c = 0.0; float d = 1.0; float e = 0.0; float f = 1.0;
sscanf(transformation, "%f %f %f %f %f %f", &a, &b, &c, &d, &e, &f);
float lx1 = x1;
float lx2 = x2;
float ly1 = y1;
float ly2 = y2;
x1 = a*lx1+c*ly1+e;
y1 = b*lx1+d*ly1+f;
x2 = a*lx2+c*ly2+e;
y2 = b*lx2+d*ly2+f;
}
}
TiXmlNode* stopChild = 0;
memset(svgTextures[numberOfSvgTextures-1].stopColors, 0, 2000);
int indOffset = 0;
while(stopChild = node->IterateChildren(stopChild))
{
if(strcmp(stopChild->Value(), "stop") == 0)
{
float offset = (float)(atof(stopChild->ToElement()->Attribute("offset")));
int color = (int)atoh(stopChild->ToElement()->Attribute("style")+strlen("stop-color:#"));
svgTextures[numberOfSvgTextures-1].stopColors[indOffset++] = (int)(OFFSET_PRECISION*offset);
svgTextures[numberOfSvgTextures-1].stopColors[indOffset++] = color;
}
}
}
//traitement des balises "radialGradient"
if(false && strcmp(node->Value(), "radialGradient") == 0)
{
numberOfSvgTextures++;
svgTextures = (SvgTexture*)realloc2(svgTextures, numberOfSvgTextures*sizeof(SvgTexture));
strcpy(svgTextures[numberOfSvgTextures-1].name, node->ToElement()->Attribute("id"));
svgTextures[numberOfSvgTextures-1].type = RADIAL_GRADIENT;
float& cx = svgTextures[numberOfSvgTextures-1].cx;
float& cy = svgTextures[numberOfSvgTextures-1].cy;
float& r = svgTextures[numberOfSvgTextures-1].r;
float& fx = svgTextures[numberOfSvgTextures-1].fx;
float& fy = svgTextures[numberOfSvgTextures-1].fy;
if(node->ToElement()->Attribute("cx")) cx = (float)atof(node->ToElement()->Attribute("cx")); else cx = 1e-30;
if(node->ToElement()->Attribute("cy")) cy = (float)atof(node->ToElement()->Attribute("cy")); else cy = 1e-30;
if(node->ToElement()->Attribute("r")) r = (float)atof(node->ToElement()->Attribute("r")); else r = 1e-30;
if(node->ToElement()->Attribute("fx")) fx = (float)atof(node->ToElement()->Attribute("fx")); else fx = 1e-30;
if(node->ToElement()->Attribute("fy")) fy = (float)atof(node->ToElement()->Attribute("fy")); else fy = 1e-30;
if(node->ToElement()->Attribute("gradientTransform"))
{
char* transformation = (char*)malloc2(1000);
strcpy(transformation, node->ToElement()->Attribute("gradientTransform"));
if(strncmp("matrix(", transformation, strlen("matrix("))==0)
{
transformation = transformation + strlen("matrix(");
float a = 1.0; float b = 0.0; float c = 0.0; float d = 1.0; float e = 0.0; float f = 1.0;
sscanf(transformation, "%f %f %f %f %f %f", &a, &b, &c, &d, &e, &f);
float lcx = cx;
float lcy = cy;
float lfx = fx;
float lfy = fy;
cx = a*lcx+c*lcy+e;
cy = b*lcx+d*lcy+f;
fx = a*lfx+c*lfy+e;
fy = b*lfx+d*lfy+f;
}
}
TiXmlNode* stopChild = 0;
memset(svgTextures[numberOfSvgTextures-1].stopColors, 0, 2000);
int indOffset = 0;
while(stopChild = node->IterateChildren(stopChild))
{
if(strcmp(stopChild->Value(), "stop") == 0)
{
float offset = (float)(atof(stopChild->ToElement()->Attribute("offset")));
int color = (int)atoh(stopChild->ToElement()->Attribute("style")+strlen("stop-color:#"));
svgTextures[numberOfSvgTextures-1].stopColors[indOffset++] = (int)(OFFSET_PRECISION*offset);
svgTextures[numberOfSvgTextures-1].stopColors[indOffset++] = color;
}
}
}
//traitement des balises "rect"
if(strcmp(node->Value(), "rect") == 0)
{
//madRect(node, svgMad);
}
//traitement des balises "path"
if(strcmp(node->Value(), "path") == 0)
{
if(svgFillType(cNode->Attribute("fill"))!=FILL_URL) numberOfSvgTextures++;
madPath(node, svgMad);
}
while(child = node->IterateChildren(child))
{
browseNode(child, svgMad, hierIndex);
}
}
SvgFillType svgFillType(const char* fillString)
{
if(!fillString || !fillString[0]) return FILL_EMPTY;
if(strcmp(fillString, "none")==0) return FILL_NONE;
if(atoh(fillString+1)) return FILL_COLOR;
return FILL_URL;
}
void cleanPointsList(std::vector<PointF>& pointsList)
{
PointF A, B, C;
//suppression des points successifs identiques
int i = 0;
while(i < pointsList.size() && pointsList.size()>=2)
{
A = pointsList.at(i); B = pointsList.at((i+1)%pointsList.size());
//si le point courant et son suivant sont colinéaires
if(A.x==B.x && A.y==B.y)
{
std::vector<PointF>::iterator it = pointsList.begin();
for(int j=0; j!=i; j++) it++;
pointsList.erase(it);
}
else i++;
}
//suppression des points successifs colinéaires
i = 0;
while(i < pointsList.size() && pointsList.size()>=3)
{
A = pointsList.at(i); B = pointsList.at((i+1)%pointsList.size()); C = pointsList.at((i+2)%pointsList.size());
//si le point courant et son suivant sont colinéaires
if((A.x-B.x)*(B.y-C.y) == (A.y-B.y)*(B.x-C.x))
{
std::vector<PointF>::iterator it = pointsList.begin();
for(int j=0; j!=(i+1)%pointsList.size(); j++) it++;
pointsList.erase(it);
}
else i++;
}
}
/*****************************************************************************************/
void closePath()
{
//remplissage du nouveau path
pathLen += 1;
pathOut += sprintf(pathOut, "z");
//remplissage de la liste de points
pointsList.push_back(SP);
}
void moveTo(float x, float y)
{
//remplissage du nouveau path
pathLen += 2 * COORD_DIGIT;
if(startOfPathOut) free2(startOfPathOut);
startOfPathOut = (char*)malloc2(pathLen);
pathOut = startOfPathOut + strlen(startOfPathOut);
pathOut += sprintf(pathOut, "M%.3f %.3f L ", x, y);
//remplissage de la liste de points
pointsList.push_back(PointF(x, y));
}
void lineTo(float x, float y)
{
//remplissage du nouveau path
pathLen += 2 * COORD_DIGIT;
if(startOfPathOut) free2(startOfPathOut);
startOfPathOut = (char*)malloc2(pathLen);
pathOut = startOfPathOut + strlen(startOfPathOut);
pathOut += sprintf(pathOut, "%.3f %.3f ", x, y);
//remplissage de la liste de points
pointsList.push_back(PointF(x, y));
}
void cubicTo(PointF c1, PointF c2, PointF e)
{
//initialisations
PointF A = CP; PointF B = c1; PointF C = c2; PointF D = e;
//calcul du nombre de segments nécessaire pour synthétiser la courbe
float curveLenSup = sqrt(((B-A).x)*((B-A).x)+((B-A).y)*((B-A).y))
+ sqrt(((C-B).x)*((C-B).x)+((C-B).y)*((C-B).y))
+ sqrt(((D-C).x)*((D-C).x)+((D-C).y)*((D-C).y));
float nbSeg = curveLenSup*nbSegPerLen + 1;
//remplissage du nouveau path
pathLen += (nbSeg * 2) * COORD_DIGIT;
if(startOfPathOut) free2(startOfPathOut);
startOfPathOut = (char*)malloc2(pathLen);
pathOut = startOfPathOut + strlen(startOfPathOut);
for(float i=1; i<nbSeg; i++)
{
float t = i/nbSeg;
PointF Ap = A + ((B-A)*t); PointF Bp = B + ((C-B)*t); PointF Cp = C + ((D-C)*t);
PointF As = Ap + ((Bp-Ap)*t); PointF Bs = Bp + ((Cp-Bp)*t);
PointF R = As + ((Bs-As)*t);
pathOut += sprintf(pathOut, "%.3f %.3f ", R.x, R.y);
//remplissage de la liste de points
pointsList.push_back(R);
}
pathOut += sprintf(pathOut, "%.3f %.3f ", e.x, e.y);
//remplissage de la liste de points
pointsList.push_back(e);
}
void quadTo(PointF c, PointF e)
{
}
void pathArc(float rx, float ry, float xAxisRotation, int largeArcFlag,
int sweepFlag, float ex, float ey, float curx, float cury)
{
}
/*****************************************************************************************/
float atoh(const char* Decode, bool findFloat)
{
const char * strOffset = Decode;
if(findFloat)
{
while(*strOffset && !IsHex(*strOffset))
{
strOffset++;
}
}
float RetValue = 0.0f;
bool findHex = false;
while(*strOffset && IsHex(*strOffset))
{
RetValue *= 16.0f;
RetValue += (float)(IsHex(*strOffset)-1);
strOffset++;
findHex = true;
}
if(RetValue==0 && findHex) RetValue = 1e-30;
return RetValue;
}
float atoh(const char* Decode)
{
return atoh(Decode, false);
}
float getFloat(char* &Decode)
{
float RetValue;
float Neg;
Neg = 1.0f;
RetValue = 0.0f;
bool findFloat = false;
if (*Decode == '-')
{
Neg = -1.0f;
Decode++;
findFloat = true;
}
if (*Decode == '+')
{
Decode++;
findFloat = true;
}
while ((*Decode >= '0') && (*Decode <= '9'))
{
RetValue *= 10.0f;
RetValue += (float)(*(Decode++) - '0');
findFloat = true;
}
if (*(Decode) == '.')
{
float Div = 0.1f;
Decode++;
findFloat = true;
while ((*Decode >= '0') && (*Decode <= '9'))
{
RetValue += (float)(*(Decode++) - '0') * Div;
Div /= 10.0f;
}
}
RetValue *= Neg;
if(RetValue==0 && findFloat)
RetValue = 1e-30;
return RetValue;
}
void removeAllShit(char* filename)
{
//allocation des buffers
long fileLen = lengthOfFile(filename);
char* buffer = (char*)malloc2(fileLen+1);
getText(filename, 0, fileLen, buffer);
char* result = (char*)malloc2(fileLen+1);
//copie dans le buffer résultat du buffer source sans les chaines à enlever
char* offset = buffer;
long start = 0;
long dest = 0;
while(*offset!=0)
{
if(strncmp("&#x09;", offset, 6)==0 || strncmp("&#x0A;", offset, 6)==0 || strncmp("&#x0D;", offset, 6)==0)
{
strncpy(result+dest, buffer+start, offset-buffer-start);
dest += offset-buffer-start;
start = offset-buffer+6;
}
offset++;
}
strncpy(result+dest, buffer+start, fileLen-start);
//copie du résultat nettoyé dans le fichier source
FILE* file = CC_fopen(filename,"wb");
fwrite(result, 1, strlen(result), file);
CC_fclose(file);
//libération de la mémoire
free2(result);
free2(buffer);
}
char* getCleanedString(char* string)
{
//création de la chaine de sortie
char* cleanedString = (char*)malloc2(1+strlen(string));
strcpy(cleanedString, string);
//suppression des sauts de lignes et des tabulations
for(int i=0; i<strlen(cleanedString); i++)
{
if(cleanedString[i]=='\t' || cleanedString[i]==10 || cleanedString[i]==13)
{
memmove(cleanedString + i, cleanedString + i + 1, strlen(cleanedString) - i);
i--;
}
}
//renvoi de la chaine nettoyée
return cleanedString;
}
//fonction permettant la suppression du contenu d'un répertoire sans le supprimer
void CleanDirectory(TCHAR * directoryPath, bool deleteFilesButNotDirectories)
{
TCHAR Path[MAX_PATH] ;
_tcscpy(Path, directoryPath) ;
_tcscat(Path, TEXT("\\*")) ;
TCHAR dossier[MAX_PATH] ;
_tcscpy(dossier, directoryPath) ;
_tcscat(dossier, TEXT("\\")) ;
WIN32_FIND_DATA wfd;
HANDLE hfl = FindFirstFile(Path, &wfd); // Recherche du premier fichier du répertoire
if(hfl != INVALID_HANDLE_VALUE)
{
if(strcmp(".", wfd.cFileName)!=0 && strcmp("..", wfd.cFileName)!=0)
{
_tcscat(dossier, wfd.cFileName) ;
if (wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY && !deleteFilesButNotDirectories) // Si il s'agit d'un dossier
{
CleanDirectory(dossier, deleteFilesButNotDirectories) ; // Suppression récursive des dossiers
RemoveDirectory(dossier) ; // Suppression du dossier
}
else
{
DeleteFile(dossier); // Suppression du fichier
}
}
while(FindNextFile(hfl, &wfd)) // Tant qu'il y a de nouveaux fichiers
{
if(strcmp(".", wfd.cFileName)!=0 && strcmp("..", wfd.cFileName)!=0)
{
_tcscpy(dossier, directoryPath) ;
_tcscat(dossier, TEXT("\\")) ;
_tcscat(dossier, wfd.cFileName) ;
if (wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY && !deleteFilesButNotDirectories) // Si il s'agit d'un dossier
{
CleanDirectory(dossier, deleteFilesButNotDirectories) ; // Suppression récursive des dossiers
RemoveDirectory(dossier) ; // Suppression du dossier
}
else
{
DeleteFile(dossier); // Suppression du fichier
}
}
}
FindClose(hfl); // Fermeture du dossier de recherche
}
}
/********************************** Gestion de la mémoire **************************************/
void checkMemIntegrity(void* ptr, int Size)
{
if(ptr!=0)
{
if(strncmp((const char*)ptr, "abcd", 4))
assert(0);
if(strncmp((const char*)ptr+4+Size, "abcd", 4))
assert(0);
}
}
void* malloc2(u32 Size)
{
//vérification de l'intégrité des allocations
for(int i=0; i<nbAlloc; i++)
checkMemIntegrity(allocStack[i], allocSizes[i]);
//allocation de la nouvelle zone mémoire
char* ptr = (char*)CC_malloc(Size+8);
memset(ptr, 0, Size+8);
//ajout des marqueurs à la zone
ptr[0] = 'a'; ptr[1] = 'b'; ptr[2] = 'c'; ptr[3] = 'd';
ptr[Size+4+0] = 'a'; ptr[Size+4+1] = 'b'; ptr[Size+4+2] = 'c'; ptr[Size+4+3] = 'd';
//mise à jour de la liste des allocations
nbAlloc++;
allocSizes = (unsigned int*)CC_realloc(allocSizes, nbAlloc*sizeof(unsigned int));
allocSizes[nbAlloc-1] = Size;
allocStack = (void**)CC_realloc(allocStack, nbAlloc*sizeof(void*));
allocStack[nbAlloc-1] = ptr;
//vérification de l'intégrité des allocations
for(int i=0; i<nbAlloc; i++)
checkMemIntegrity(allocStack[i], allocSizes[i]);
//renvoie du pointeur vers la nouvelle zone mémoire
return ptr+4;
}
void* realloc2(void* ptr, u32 Size)
{
//vérification de l'intégrité des allocations
for(int i=0; i<nbAlloc; i++)
checkMemIntegrity(allocStack[i], allocSizes[i]);
//si le pointeur vers la zone mémoire à réallouer est nul, on quitte de la fonction
if(ptr==0)
return 0;
//sinon, création du pointeur vers la nouvelle zone mémoire
char* newPtr = 0;
//allocation de la nouvelle zone mémoire
newPtr = (char*)CC_malloc(Size+8);
memset(newPtr, 0, Size+8);
//récupération dans la pile d'allocation de la position du pointeur vers la zone mémoire à réallouer
int indexInStack = -1;
for(int i=0; i<nbAlloc; i++)
{
if((char*)allocStack[i]+4==(char*)ptr)
{
indexInStack = i;
i = nbAlloc;
}
}
//si la zone mémoire à réallouer n'avait pas été allouée par la fonction malloc2(), on quitte la fonction
if(indexInStack==-1)
return 0;
//sinon, copie des données utiles de l'ancienne zone mémoire vers la nouvelle
u32 oldSize = allocSizes[indexInStack];
memcpy(newPtr+4, ptr, oldSize);
//ajout des marqueurs à la zone
newPtr[0] = 'a'; newPtr[1] = 'b'; newPtr[2] = 'c'; newPtr[3] = 'd';
newPtr[Size+4+0] = 'a'; newPtr[Size+4+1] = 'b'; newPtr[Size+4+2] = 'c'; newPtr[Size+4+3] = 'd';
//mise à jour de la liste des allocations
allocSizes[indexInStack] = Size;
allocStack[indexInStack] = newPtr;
//vérification de l'intégrité des allocations
for(int i=0; i<nbAlloc; i++)
checkMemIntegrity(allocStack[i], allocSizes[i]);
//renvoie du nouveau pointeur
return newPtr+4;
}
void free2(void* ptr)
{
//vérification de l'intégrité des allocations
for(int i=0; i<nbAlloc; i++)
checkMemIntegrity(allocStack[i], allocSizes[i]);
if(ptr==0)
return;
//récupération dans la pile d'allocation de la position du pointeur vers la zone mémoire à libérer
int indexInStack = -1;
for(int i=0; i<nbAlloc; i++)
{
if((char*)allocStack[i]+4==(char*)ptr)
{
indexInStack = i;
i = nbAlloc;
}
}
//si la zone mémoire à libérer n'avait pas été allouée par la fonction malloc2() ou realloc2(), on quitte la fonction
if(indexInStack==-1)
return;
//suppression de la zone mémoire
free2(allocStack[indexInStack]);
for(int i=indexInStack; i<nbAlloc-1; i++)
{
allocStack[i] = allocStack[i+1];
allocSizes[i] = allocSizes[i+1];
}
nbAlloc--;
allocStack[nbAlloc] = 0;
allocSizes[nbAlloc] = 0;
//vérification de l'intégrité des allocations
for(int i=0; i<nbAlloc; i++)
checkMemIntegrity(allocStack[i], allocSizes[i]);
}
/* liste des balises SVG */
/*
s_utilFactory.insert(QLatin1String("a"), (ParseMethod) parseAnchorNode);
s_utilFactory.insert(QLatin1String("animate"), (ParseMethod) parseAnimateNode);
s_utilFactory.insert(QLatin1String("animateColor"), (ParseMethod) parseAnimateColorNode);
s_utilFactory.insert(QLatin1String("animateMotion"), (ParseMethod) parseAimateMotionNode);
s_utilFactory.insert(QLatin1String("animateTransform"), (ParseMethod) parseAnimateTransformNode);
s_utilFactory.insert(QLatin1String("audio"), (ParseMethod) parseAudioNode);
s_utilFactory.insert(QLatin1String("desc"), (ParseMethod) parseDescNode);
s_utilFactory.insert(QLatin1String("discard"), (ParseMethod) parseDiscardNode);
s_utilFactory.insert(QLatin1String("foreignObject"), (ParseMethod) parseForeignObjectNode);
s_utilFactory.insert(QLatin1String("handler"), (ParseMethod) parseHandlerNode);
s_utilFactory.insert(QLatin1String("hkern"), (ParseMethod) parseHkernNode);
s_utilFactory.insert(QLatin1String("metadata"), (ParseMethod) parseMetadataNode);
s_utilFactory.insert(QLatin1String("mpath"), (ParseMethod) parseMpathNode);
s_utilFactory.insert(QLatin1String("prefetch"), (ParseMethod) parsePrefetchNode);
s_utilFactory.insert(QLatin1String("script"), (ParseMethod) parseScriptNode);
s_utilFactory.insert(QLatin1String("set"), (ParseMethod) parseSetNode);
s_utilFactory.insert(QLatin1String("style"), (ParseMethod) parseStyleNode);
s_utilFactory.insert(QLatin1String("tBreak"), (ParseMethod) parseTbreakNode);
s_utilFactory.insert(QLatin1String("title"), (ParseMethod) parseTitleNode);
s_utilFactory.insert(QLatin1String("tspan"), (ParseMethod) parseTspanNode);
s_groupFactory.insert(QLatin1String("svg"), (FactoryMethod) createSvgNode);
s_groupFactory.insert(QLatin1String("g"), (FactoryMethod) createGNode);
s_groupFactory.insert(QLatin1String("defs"), (FactoryMethod) createDefsNode);
s_groupFactory.insert(QLatin1String("switch"), (FactoryMethod) createSwitchNode);
s_graphicsFactory.insert(QLatin1String("animation"), (FactoryMethod) createAnimationNode);
s_graphicsFactory.insert(QLatin1String("circle"), (FactoryMethod) createCircleNode);
s_graphicsFactory.insert(QLatin1String("ellipse"), (FactoryMethod) createEllipseNode);
s_graphicsFactory.insert(QLatin1String("image"), (FactoryMethod) createImageNode);
s_graphicsFactory.insert(QLatin1String("line"), (FactoryMethod) createLineNode);
s_graphicsFactory.insert(QLatin1String("path"), (FactoryMethod) createPathNode);
s_graphicsFactory.insert(QLatin1String("polygon"), (FactoryMethod) createPolygonNode);
s_graphicsFactory.insert(QLatin1String("polyline"), (FactoryMethod) createPolylineNode);
s_graphicsFactory.insert(QLatin1String("rect"), (FactoryMethod) createRectNode);
s_graphicsFactory.insert(QLatin1String("text"), (FactoryMethod) createTextNode);
s_graphicsFactory.insert(QLatin1String("textArea"), (FactoryMethod) createTextAreaNode);
s_graphicsFactory.insert(QLatin1String("use"), (FactoryMethod) createUseNode);
s_graphicsFactory.insert(QLatin1String("video"), (FactoryMethod) createVideoNode);
s_styleFactory.insert(QLatin1String("linearGradient"), (StyleFactoryMethod) createLinearGradientNode);
s_styleFactory.insert(QLatin1String("radialGradient"), (StyleFactoryMethod) createRadialGradientNode);
s_styleFactory.insert(QLatin1String("font"), (StyleFactoryMethod) createFontNode);
s_styleFactory.insert(QLatin1String("solidColor"), (StyleFactoryMethod) createSolidColorNode);
s_styleUtilFactory.insert(QLatin1String("font-face"), (StyleParseMethod) parseFontFaceNode);
s_styleUtilFactory.insert(QLatin1String("font-face-name"), (StyleParseMethod) parseFontFaceNameNode);
s_styleUtilFactory.insert(QLatin1String("font-face-src"), (StyleParseMethod) parseFontFaceSrcNode);
s_styleUtilFactory.insert(QLatin1String("font-face-uri"), (StyleParseMethod) parseFontFaceUriNode);
s_styleUtilFactory.insert(QLatin1String("glyph"), (StyleParseMethod) parseGlyphNode);
s_styleUtilFactory.insert(QLatin1String("missing-glyph"), (StyleParseMethod) parseMissingGlyphNode);
s_styleUtilFactory.insert(QLatin1String("stop"), (StyleParseMethod) parseStopNode);
*/
#endif //USE_SVG