1183 lines
28 KiB
C++
1183 lines
28 KiB
C++
#ifdef USE_SVG
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include "triangulate.h"
|
|
|
|
|
|
|
|
/** déclarations : **/
|
|
extern char CamcamCCM[];
|
|
tsVertex* vertices = NULL;
|
|
int nvertices = 0;
|
|
|
|
|
|
/** déclarations externes : **/
|
|
|
|
//chemin du répertoire image à générer pour les textures du MAD
|
|
extern char svgTexturesDir[512];
|
|
//id de l'objet SVG courant
|
|
extern char svgObjectID[260];
|
|
//nouveaux points à créer
|
|
extern char** textureFilenames;
|
|
//nouveaux points à créer
|
|
extern std::vector<PointF> pointsList;
|
|
//noeud SVG courant
|
|
extern TiXmlElement* cNode;
|
|
//liste des textures SVG du document SVG
|
|
extern SvgTexture* svgTextures;
|
|
//nombre de textures SVG du document SVG
|
|
extern int numberOfSvgTextures;
|
|
//limites de la forme SVG courante
|
|
extern float svgxmin, svgymin, svgxmax, svgymax, svgz;
|
|
//centre de l'objet SVG en cours
|
|
extern PointF objectCenter;
|
|
//nombre de points composant l'objet SVG
|
|
extern int svgNbPoints;
|
|
//nombre d'allocations mémoire
|
|
extern int nbAlloc;
|
|
//tableau des tailles des zones mémoire allouées
|
|
extern unsigned int* allocSizes;
|
|
//tableau des pointeurs vers les zones mémoire allouées
|
|
extern void** allocStack;
|
|
//bounding box du monde SVG à créer
|
|
extern float svgWorld_Xmin, svgWorld_Ymin, svgWorld_Xmax, svgWorld_Ymax;
|
|
|
|
|
|
/** définition des fonctions : **/
|
|
|
|
|
|
/** triangulation de la forme SVG courante en utilisant les coordonnées des points de son contour **/
|
|
void triangulatePath(MAD_Simple3DVertex* madPointsList, MAD_GeometricObjectElement* madTrianglesList)
|
|
{
|
|
//retournement des coordonnées des vertices en Y en gardant l'ordre trigonométrique des vertices
|
|
{
|
|
float swp;
|
|
int n = pointsList.size();
|
|
for(int i=0; i<=(n-1)/2; i++)
|
|
{
|
|
//pour les Y
|
|
pointsList.at(i).y = -pointsList.at(i).y;
|
|
if(i!=(n-1)/2 || (n+1)%2)
|
|
{
|
|
pointsList.at(n-1-i).y = -pointsList.at(n-1-i).y;
|
|
swp = pointsList.at(i).y;
|
|
pointsList.at(i).y = pointsList.at(n-1-i).y;
|
|
pointsList.at(n-1-i).y = swp;
|
|
}
|
|
//pour les X
|
|
swp = pointsList.at(i).x;
|
|
pointsList.at(i).x = pointsList.at(n-1-i).x;
|
|
pointsList.at(n-1-i).x = swp;
|
|
}
|
|
//retournement en Y des coordonnées du dégradé
|
|
char fillValue[256] = "";
|
|
SvgFillType fillType = svgFillType(cNode->Attribute("fill"));
|
|
|
|
if(fillType!=FILL_EMPTY)
|
|
strcpy(fillValue, cNode->Attribute("fill"));
|
|
|
|
if(fillType==FILL_URL)
|
|
{
|
|
//récupération de l'ID de la texture
|
|
memmove(fillValue, fillValue+strlen("url(#"), strlen(fillValue)-strlen("url(#")-1);
|
|
*(fillValue+strlen(fillValue)-strlen("url(#")-1) = 0;
|
|
|
|
//récupération des caractéristiques de la texture
|
|
for(int i=0; i<numberOfSvgTextures; i++)
|
|
{
|
|
if(strcmp(svgTextures[i].name, fillValue)==0)
|
|
{
|
|
if(svgTextures[i].type== LINEAR_GRADIENT)
|
|
{
|
|
svgTextures[i].y1 = -svgTextures[i].y1;
|
|
svgTextures[i].y2 = -svgTextures[i].y2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//passage des vertices au trianguleur
|
|
read_vertices(madPointsList);
|
|
|
|
//récupération des frontières et points significatifs de l'objet
|
|
scale_data();
|
|
|
|
//mémorisation du nombre de points de l'objet
|
|
svgNbPoints = pointsList.size();
|
|
|
|
//triangulation de l'objet
|
|
triangulate(madTrianglesList);
|
|
}
|
|
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
AREA_POLY2 returns the area of a polygon.
|
|
|
|
Parameters:
|
|
|
|
Output, int AREA_POLY2, the area of the polygon.
|
|
*/
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
READ_VERTICES reads the polygon vertice from standard input.
|
|
|
|
Discussion:
|
|
|
|
After reading the vertices, the function links them into a circular
|
|
list with MAKE_NULL_VERTEX. There is no need for the # of vertices
|
|
to be the first line: the function looks for EOF instead.
|
|
*/
|
|
void read_vertices(MAD_Simple3DVertex* madPointsList)
|
|
{
|
|
tsVertex* v;
|
|
vertices = NULL;
|
|
nvertices = 0;
|
|
float x;
|
|
float y;
|
|
|
|
int vnum = 0;
|
|
for(int i=0; i<svgNbPoints; i++)
|
|
{
|
|
//récupération des coordonnées du point à rajouter
|
|
x = pointsList.at(i).x;
|
|
y = pointsList.at(i).y;
|
|
|
|
//remplissage de la structure Mad
|
|
madPointsList[i].Point.x = x;
|
|
madPointsList[i].Point.y = y;
|
|
madPointsList[i].Point.z = svgz;
|
|
|
|
//remplissage de la structure tsVertex
|
|
v = make_null_vertex();
|
|
v->v[0] = x;
|
|
v->v[1] = y;
|
|
v->vnum = vnum++;
|
|
}
|
|
nvertices = vnum;
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
SCALE_DATA determines the scale for the polygonal data.
|
|
|
|
Parameters:
|
|
|
|
Output, int *XMIN, *XMAX, *YMIN, *YMAX, the minimum and maximum
|
|
0 and 1 values of the coordinates of the vertices of the polygon.
|
|
*/
|
|
void scale_data()
|
|
{
|
|
tsVertex* v;
|
|
|
|
//Compute bounding box for Encapsulated PostScript.
|
|
v = vertices;
|
|
svgxmin = v->v[0];
|
|
svgxmax = v->v[0];
|
|
svgymin = v->v[1];
|
|
svgymax = v->v[1];
|
|
|
|
do
|
|
{
|
|
if(v->v[0] > svgxmax) svgxmax = v->v[0];
|
|
|
|
else if(v->v[0] < svgxmin) svgxmin = v->v[0];
|
|
|
|
if(v->v[1] > svgymax) svgymax = v->v[1];
|
|
|
|
else if(v->v[1] < svgymin) svgymin = v->v[1];
|
|
|
|
v = v->next;
|
|
} while (v != vertices);
|
|
|
|
//calcul des coordonnées du point de pivot
|
|
objectCenter = PointF((svgxmax+svgxmin)/2, (svgymax+svgymin)/2);
|
|
|
|
//mise à jour de la bounding box du monde SVG à créer
|
|
if(svgxmin<svgWorld_Xmin) svgWorld_Xmin = svgxmin;
|
|
if(svgymin<svgWorld_Ymin) svgWorld_Ymin = svgymin;
|
|
if(svgxmax>svgWorld_Xmax) svgWorld_Xmax = svgxmax;
|
|
if(svgymax>svgWorld_Ymax) svgWorld_Ymax = svgymax;
|
|
}
|
|
|
|
/*
|
|
Index a face in the Mad Meshes List
|
|
*/
|
|
void indexFace(MAD_GeometricObjectElement* madTrianglesList, tsVertex* v1, tsVertex* v2, tsVertex* v3, int trgInd)
|
|
{
|
|
madTrianglesList->Faces[trgInd].Index[2] = v3->vnum;
|
|
madTrianglesList->Faces[trgInd].Index[1] = v2->vnum;
|
|
madTrianglesList->Faces[trgInd].Index[0] = v1->vnum;
|
|
madTrianglesList->Faces[trgInd].UVIndex[2] = v3->vnum;
|
|
madTrianglesList->Faces[trgInd].UVIndex[1] = v2->vnum;
|
|
madTrianglesList->Faces[trgInd].UVIndex[0] = v1->vnum;
|
|
madTrianglesList->Faces[trgInd].SmoothingGroup = MAD_NULL_INDEX; //TO TRY
|
|
madTrianglesList->Faces[trgInd].MAXflags = 0; //7 = all //TO CHECK : effect under MAX and Camcam
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
TRIANGULATE prints N-3 diagonals which triangulate the polygon.
|
|
|
|
Parameters:
|
|
|
|
Input, int XMIN, XMAX, YMIN, YMAX, the minimum and maximum
|
|
0 and 1 values of the coordinates of the vertices of the polygon.
|
|
*/
|
|
void triangulate(MAD_GeometricObjectElement* madTrianglesList)
|
|
{
|
|
//initialisations
|
|
tsVertex* v0, *v1, *v2, *v3, *v4; /* five consecutive vertices */
|
|
int n = nvertices; /* number of vertices; shrinks to 3. */
|
|
int trgInd = 0;
|
|
|
|
//remplissage des triangles de la structure Mad
|
|
madTrianglesList->MaterialID = 0;
|
|
madTrianglesList->NumberOfTriangles = nvertices-2;
|
|
madTrianglesList->Faces = (MAD_Face*)malloc2(madTrianglesList->NumberOfTriangles*sizeof(MAD_Face));
|
|
memset(madTrianglesList->Faces, 0, madTrianglesList->NumberOfTriangles*sizeof(MAD_Face));
|
|
madTrianglesList->NumberOfUsedIndex = svgNbPoints;
|
|
madTrianglesList->UsedIndex = (unsigned long*)malloc2(svgNbPoints*sizeof(unsigned long));
|
|
for(int i=0; i<svgNbPoints; i++) madTrianglesList->UsedIndex[i] = i;
|
|
madTrianglesList->OneUVPerVertexPerElementBase = 0;
|
|
|
|
//triangulation
|
|
ear_init();
|
|
//each step of outer loop removes one ear.
|
|
while(n > 3)
|
|
{
|
|
//inner loop searches for an ear.
|
|
v2 = vertices;
|
|
do
|
|
{
|
|
if(v2->ear)
|
|
{
|
|
//ear found. Fill variables.
|
|
v3 = v2->next;
|
|
v4 = v3->next;
|
|
v1 = v2->prev;
|
|
v0 = v1->prev;
|
|
|
|
//(v1,v3) is a diagonal
|
|
//ajout du triangle (v1, v2, v3) à la structure MAD
|
|
indexFace(madTrianglesList, v1, v2, v3, trgInd);
|
|
trgInd++;
|
|
|
|
//update earity of diagonal endpoints.
|
|
v1->ear = diagonal(v0, v3);
|
|
v3->ear = diagonal(v1, v4);
|
|
|
|
//cut off the ear v2.
|
|
v1->next = v3;
|
|
v3->prev = v1;
|
|
vertices = v3;
|
|
|
|
//in case the head was v2.
|
|
n--;
|
|
break;
|
|
}
|
|
|
|
//End if ear found
|
|
v2 = v2->next;
|
|
} while(v2 != vertices);
|
|
}
|
|
|
|
//ajout du dernier triangle (v1, v2, v3) à la structure MAD
|
|
v2 = v3->next; v3 = v2->next; v1 = v2->prev;
|
|
indexFace(madTrianglesList, v1, v2, v3, trgInd);
|
|
trgInd++;
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
Calculates the UV coords for texturing the vertices created
|
|
|
|
Parameters:
|
|
|
|
Input, int XMIN, XMAX, YMIN, YMAX, the minimum and maximum
|
|
0 and 1 values of the coordinates of the vertices of the polygon.
|
|
*/
|
|
void createUVCoords(MAD_Vertex* madUVList)
|
|
{
|
|
bool isImage = svgTextures[numberOfSvgTextures-1].type == PNG_IMAGE
|
|
|| svgTextures[numberOfSvgTextures-1].type == JPEG_IMAGE;
|
|
|
|
//on doit assigner les UV pour une image (<-> rectangle)
|
|
if(isImage)
|
|
{
|
|
//remplissage des uv des vertices
|
|
madUVList[0].x = 1;
|
|
madUVList[0].y = 1;
|
|
madUVList[0].z = 1;
|
|
|
|
madUVList[1].x = 1;
|
|
madUVList[1].y = 0;
|
|
madUVList[1].z = 1;
|
|
|
|
madUVList[2].x = 0;
|
|
madUVList[2].y = 0;
|
|
madUVList[2].z = 1;
|
|
|
|
madUVList[3].x = 0;
|
|
madUVList[3].y = 1;
|
|
madUVList[3].z = 1;
|
|
|
|
//retournement verticale de la texture d'une image pour MAX
|
|
if(TheScene->GetIniValue(CamcamCCM, "svgFlipTexturesFor3DSMAX"))
|
|
{
|
|
MAD_Vertex tmp = madUVList[0];
|
|
madUVList[0] = madUVList[1];
|
|
madUVList[1] = tmp;
|
|
|
|
tmp = madUVList[3];
|
|
madUVList[3] = madUVList[2];
|
|
madUVList[2] = tmp;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
char fillValue[256] = "0";
|
|
|
|
SvgFillType fillType = svgFillType(cNode->Attribute("fill"));
|
|
|
|
//lecture de la valeur de la donnée de remplissage de la forme
|
|
if(fillType!=FILL_EMPTY)
|
|
strcpy(fillValue, cNode->Attribute("fill"));
|
|
|
|
//cas de la texture unicolor
|
|
if(fillType==FILL_COLOR)
|
|
{
|
|
//récupération de la couleur de remplissage
|
|
int fillColor = (int)atoh(fillValue+1);
|
|
|
|
//remplissage des uv des vertices
|
|
for(int i=0; i<svgNbPoints; i++)
|
|
{
|
|
madUVList[i].x = 0;
|
|
madUVList[i].y = 0;
|
|
madUVList[i].z = 1;
|
|
}
|
|
}
|
|
//cas de la texture multicolor
|
|
if(fillType==FILL_URL)
|
|
{
|
|
//récupération de l'ID de la texture
|
|
memmove(fillValue, fillValue+strlen("url(#"), strlen(fillValue)-strlen("url(#")-1);
|
|
*(fillValue+strlen(fillValue)-strlen("url(#")-1) = 0;
|
|
|
|
//récupération des caractéristiques de la texture
|
|
for(int i=0; i<numberOfSvgTextures; i++)
|
|
{
|
|
if(strcmp(svgTextures[i].name, fillValue)==0)
|
|
{
|
|
//TO FINISH:
|
|
switch(svgTextures[i].type)
|
|
{
|
|
case LINEAR_GRADIENT :
|
|
{
|
|
//calcul de l'équation de la droite directrice du dégradé
|
|
float x1 = (float)svgTextures[i].x1;
|
|
float y1 = (float)svgTextures[i].y1;
|
|
float x2 = (float)svgTextures[i].x2;
|
|
float y2 = (float)svgTextures[i].y2;
|
|
|
|
//calcul des paramètres de la droite directrice (P1,P2) du dégradé
|
|
float c = 0; float d = 0;
|
|
if(x1!=x2)
|
|
{
|
|
c = (y1-y2)/(x1-x2);
|
|
d = y1 - c*x1;
|
|
}
|
|
|
|
//norme au carré du vecteur P1P2
|
|
float nc12 = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
|
|
|
|
//remplissage des uv des vertices
|
|
for(int i=0; i<svgNbPoints; i++)
|
|
{
|
|
//position du vertex courant (M) de la forme SVG (en coordonnées flottantes absolues)
|
|
float xm = pointsList.at(i).x;
|
|
float ym = pointsList.at(i).y;
|
|
|
|
//projeté P de M sur la droite (P1,P2)
|
|
float xp = x1;
|
|
float yp = ym;
|
|
if(x1!=x2)
|
|
{
|
|
xp = (c*ym + xm - c*d)/(c*c+1);
|
|
yp = c*xp + d;
|
|
}
|
|
|
|
//produit scalaire des vecteurs P1P et P1P2
|
|
float s1p12 = (xp-x1)*(x2-x1) + (yp-y1)*(y2-y1);
|
|
|
|
//place de P sur la droite P1P2
|
|
float prop = 0;
|
|
if(s1p12!=0 && nc12!=0) prop = s1p12/nc12;
|
|
|
|
//pour le mode de dégradé "PAD"
|
|
if(prop<0) prop = 0.001;
|
|
if(prop>1) prop = 0.999;
|
|
|
|
//affectation des uv pour le vertex M
|
|
madUVList[i].x = prop;
|
|
madUVList[i].y = 0;
|
|
madUVList[i].z = 1;
|
|
}
|
|
} break;
|
|
|
|
//TO FINISH:
|
|
case RADIAL_GRADIENT :
|
|
{
|
|
|
|
if(svgTextures[i].cx==1e-30) svgTextures[i].cx = objectCenter.x; //TO CHANGE to 50%
|
|
if(svgTextures[i].cy==1e-30) svgTextures[i].cy = objectCenter.y; //TO CHANGE to 50%
|
|
if(svgTextures[i].r==1e-30) svgTextures[i].r = 0; //TO CHANGE to 50%
|
|
if(svgTextures[i].fx==1e-30) svgTextures[i].fx = svgTextures[i].cx;
|
|
if(svgTextures[i].fy==1e-30) svgTextures[i].fy = svgTextures[i].cy;
|
|
|
|
//calcul de l'équation de la droite directrice du dégradé
|
|
float x1 = (float)svgTextures[i].cx;
|
|
float y1 = (float)svgTextures[i].cy;
|
|
float x2 = (float)svgTextures[i].fx;
|
|
float y2 = (float)svgTextures[i].fy;
|
|
|
|
//calcul des paramètres de la droite directrice (P1,P2) du dégradé
|
|
float c = 0; float d = 0;
|
|
if(x1!=x2)
|
|
{
|
|
c = (y1-y2)/(x1-x2);
|
|
d = y1 - c*x1;
|
|
}
|
|
|
|
//norme au carré du vecteur P1P2
|
|
float nc12 = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
|
|
|
|
//remplissage des uv des vertices
|
|
for(int i=0; i<svgNbPoints; i++)
|
|
{
|
|
//position du vertex courant (M) de la forme SVG (en coordonnées flottantes absolues)
|
|
float xm = pointsList.at(i).x;
|
|
float ym = pointsList.at(i).y;
|
|
|
|
//projeté P de M sur la droite (P1,P2)
|
|
float xp = x1;
|
|
float yp = ym;
|
|
if(x1!=x2)
|
|
{
|
|
xp = (c*ym + xm - c*d)/(c*c+1);
|
|
yp = c*xp + d;
|
|
}
|
|
|
|
//produit scalaire des vecteurs P1P et P1P2
|
|
float s1p12 = (xp-x1)*(x2-x1) + (yp-y1)*(y2-y1);
|
|
|
|
//place de P sur la droite P1P2
|
|
float prop = 1.0f - 1.0/OFFSET_PRECISION;
|
|
if(s1p12!=0 && nc12!=0)
|
|
prop = s1p12/nc12;
|
|
|
|
//pour le mode de dégradé "PAD"
|
|
if(prop<0) prop = 0;
|
|
if(prop>1) prop = 1;
|
|
|
|
//affectation des uv pour le vertex M
|
|
madUVList[i].x = prop;
|
|
madUVList[i].y = 0;
|
|
madUVList[i].z = 1;
|
|
}
|
|
} break;
|
|
|
|
case PNG_IMAGE :
|
|
{
|
|
|
|
} break;
|
|
}
|
|
//sortie de la boucle
|
|
i = numberOfSvgTextures;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
création de la texture "path" correspondant à l'image SVG courante
|
|
*/
|
|
void createImageTexture(char *textureFilename)
|
|
{
|
|
//création du nom du fichier image temporaire PNG ou JPEG
|
|
char path[260] = "";
|
|
if(svgTextures[numberOfSvgTextures-1].type == PNG_IMAGE) sprintf(path, "%s\\%s - texture.png", svgTexturesDir, svgObjectID);
|
|
else sprintf(path, "%s\\%s - texture.jpeg", svgTexturesDir, svgObjectID);
|
|
|
|
//récupération des données images en base 64 dans le node SVG courant
|
|
char* data = svgTextures[numberOfSvgTextures-1].data;
|
|
data = strstr(data, ",") + 1;
|
|
//décodage des données image de base 64 vers ascii
|
|
char* cleanedData = getCleanedString(data);
|
|
char* decodedData = (char*)malloc2(1+strlen(data));
|
|
int dataLength = decodeB64(cleanedData, decodedData);
|
|
free2(cleanedData);
|
|
free2(svgTextures[numberOfSvgTextures-1].data);
|
|
svgTextures[numberOfSvgTextures-1].data = decodedData;
|
|
|
|
//écriture du fichier temporaire
|
|
FILE* outFile = CC_fopen(path, "wb");
|
|
fwrite(decodedData, 1, dataLength, outFile);
|
|
CC_fclose(outFile);
|
|
|
|
//***** à supprimer dès que camcam supportera les fichiers PNG comme texture *****
|
|
//vérification de la présence de "nconvert.exe" dans le répertoire "/SVG"
|
|
char myShareDirPath[] = "\\\\mtp-mauboussin\\Share";
|
|
extern HWND hWnd;
|
|
char Text[2048];
|
|
sprintf(Text,"NCONVERT.EXE is missing in the \"/SVG\" folder of the application and is necessary to convert SVG files to MAD files. \nYou should find it in the folder \"%s\".", myShareDirPath);
|
|
while(lengthOfFile("SVG\\nconvert.exe")==-1)
|
|
{
|
|
int userAnswer = MessageBox(GetDesktopWindow(),Text,"Camcam message",MB_RETRYCANCEL|MB_SYSTEMMODAL);
|
|
if(userAnswer == IDCANCEL)
|
|
{
|
|
char svgTexturesDir[] = "SVG\\TMP";
|
|
CleanDirectory(svgTexturesDir);
|
|
RemoveDirectory(svgTexturesDir);
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
//écriture de la texture TGA
|
|
remove(textureFilename);
|
|
char convertLine[200] = "";
|
|
sprintf(convertLine, "\"SVG\\nconvert.exe\" -out tga -o \"%s\" \"%s\"", textureFilename, path);
|
|
WinExec(convertLine, SW_HIDE);
|
|
|
|
//TO IMPROVE:
|
|
FILE* filetmp;
|
|
while(!(filetmp = CC_fopen(textureFilename, "r")))
|
|
Sleep(10);
|
|
CC_fclose(filetmp);
|
|
|
|
//suppression du fichier temporaire
|
|
remove(path);
|
|
//*/
|
|
}
|
|
|
|
void createShapeTexture(char *path)
|
|
{
|
|
//définition de la MAP de texture
|
|
MAP * sourceMap = (MAP*)malloc2(sizeof(MAP));
|
|
|
|
//récupération du type de remplissage de la forme
|
|
SvgFillType fillType = svgFillType(cNode->Attribute("fill"));
|
|
|
|
//cas de la texture unicolor : FILL_EMPTY or FILL_NONE or FILL_COLOR
|
|
if(fillType!=FILL_URL)
|
|
{
|
|
//récupération de la couleur de remplissage
|
|
int fillColor = 0;
|
|
if(fillType==FILL_COLOR)
|
|
{
|
|
//lecture de la valeur de la donnée de remplissage de la forme
|
|
char fillValue[256] = "";
|
|
strcpy(fillValue, cNode->Attribute("fill"));
|
|
//transformation en entier de la couleur en hexadécimal
|
|
fillColor = (int)atoh(fillValue+1);
|
|
}
|
|
|
|
//création de la MAP de texture
|
|
sourceMap->SX = sourceMap->SY = sourceMap->PITCH = 8;
|
|
sourceMap->BASE = (s32*)malloc2(sourceMap->SX*sourceMap->SY*sizeof(s32));
|
|
|
|
//remplissage de la MAP de texture
|
|
int color = 255<<24 | fillColor;
|
|
if(fillType==FILL_NONE) color = 0;
|
|
for(int pixel=0; pixel<sourceMap->SX*sourceMap->SY; pixel++)
|
|
*(sourceMap->BASE+pixel) = color;
|
|
}
|
|
//cas de la texture multicolor
|
|
else
|
|
{
|
|
//lecture de la valeur de la donnée de remplissage de la forme
|
|
char fillValue[256] = "";
|
|
strcpy(fillValue, cNode->Attribute("fill"));
|
|
|
|
//récupération de l'ID de la texture
|
|
memmove(fillValue, fillValue+strlen("url(#"), strlen(fillValue)-strlen("url(#")-1);
|
|
*(fillValue+strlen(fillValue)-strlen("url(#")-1) = 0;
|
|
|
|
//récupération des caractéristiques de la texture
|
|
for(int i=0; i<numberOfSvgTextures; i++)
|
|
{
|
|
if(strcmp(svgTextures[i].name, fillValue)==0)
|
|
{
|
|
//TO FINISH:
|
|
switch(svgTextures[i].type)
|
|
{
|
|
case LINEAR_GRADIENT :
|
|
{
|
|
//création de la MAP de texture
|
|
sourceMap->SY = 8;
|
|
sourceMap->SX = sourceMap->PITCH = OFFSET_PRECISION;
|
|
sourceMap->BASE = (s32*)malloc2(sourceMap->SX*sourceMap->SY*sizeof(s32));
|
|
|
|
//remplissage de la MAP de texture
|
|
int indOffset = 0;
|
|
for(int px=0; px<sourceMap->SX; px++)
|
|
{
|
|
float offsetInf = (float)(svgTextures[i].stopColors[indOffset])/OFFSET_PRECISION;
|
|
float offsetSup = (float)(svgTextures[i].stopColors[indOffset+2])/OFFSET_PRECISION;
|
|
float x = ((float)px/OFFSET_PRECISION);
|
|
float prop = (float)(x-offsetInf)/(float)(offsetSup-offsetInf);
|
|
|
|
int colorInf = svgTextures[i].stopColors[indOffset+1];
|
|
int colorSup = svgTextures[i].stopColors[indOffset+3];
|
|
int red = prop*(float)(getR(colorSup)-getR(colorInf))+getR(colorInf);
|
|
int green = prop*(float)(getV(colorSup)-getV(colorInf))+getV(colorInf);
|
|
int blue = prop*(float)(getB(colorSup)-getB(colorInf))+getB(colorInf);
|
|
|
|
int color = makeRGB(red, green, blue);
|
|
for(int py=0; py<sourceMap->SY; py++)
|
|
{
|
|
*(sourceMap->BASE+px+py*sourceMap->PITCH) = 255<<24 | color;
|
|
}
|
|
if(x > offsetSup)
|
|
indOffset+=2;
|
|
}
|
|
} break;
|
|
|
|
case RADIAL_GRADIENT : //TO FINISH:
|
|
break;
|
|
}
|
|
//sortie de la boucle
|
|
i = numberOfSvgTextures;
|
|
}
|
|
}
|
|
}
|
|
|
|
//remplissage de la structure TGA
|
|
MyTGAHeader header;
|
|
memset(&header, 0, sizeof(header));
|
|
header.uc_ImageTypeCode = 2;
|
|
header.uw_Width = sourceMap->SX;
|
|
header.uw_Height = sourceMap->SY;
|
|
header.uc_BPP = 32;
|
|
header.ucDescriptorByte = 0x8;
|
|
|
|
//écriture du fichier TGA
|
|
FILE* f = CC_fopen(path, "wb");
|
|
if(f)
|
|
{
|
|
fwrite(&header, sizeof(header), 1, f);
|
|
fwrite(sourceMap->BASE, sizeof(char), sourceMap->SX * sourceMap->SY * 4, f);
|
|
CC_fclose(f);
|
|
}
|
|
|
|
//libération des ressources utilisées
|
|
free2(sourceMap->BASE);
|
|
free2(sourceMap);
|
|
}
|
|
|
|
/************************************************************************************/
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
DIAGONAL returns TRUE iff (A,B) is a proper internal diagonal of the polygon.
|
|
|
|
Parameters:
|
|
|
|
Input, tsVertex* A, B, two vertices of the polygon.
|
|
|
|
Output, bool DIAGONAL, is TRUE if the line connecting A and B is a
|
|
proper internal diagonal of the polygon.
|
|
*/
|
|
bool diagonal ( tsVertex* a, tsVertex* b )
|
|
{
|
|
return in_cone ( a, b ) && in_cone ( b, a ) && diagonalie ( a, b );
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
MAKE_NULL_VERTEX makes a vertex.
|
|
|
|
Parameters:
|
|
|
|
Output, tsVertex* MAKE_NULL_VERTEX, the new vertex.
|
|
*/
|
|
tsVertex* make_null_vertex ( void )
|
|
{
|
|
tsVertex* v;
|
|
|
|
v = ( tsVertex * ) malloc2 ( sizeof ( tsVertex ) );
|
|
|
|
if(vertices)
|
|
{
|
|
v->next = vertices;
|
|
v->prev = vertices->prev;
|
|
vertices->prev = v;
|
|
v->prev->next = v;
|
|
}
|
|
else
|
|
{
|
|
vertices = v;
|
|
vertices->next = v;
|
|
vertices->prev = v;
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
EAR_INIT initializes the data structures, and calls Triangulate2 to clip ears.
|
|
|
|
Local Parameters:
|
|
|
|
Local, tsVertex* V0, V1, V2, three consecutive vertices of the polygon.
|
|
*/
|
|
void ear_init ( void )
|
|
{
|
|
tsVertex* v0;
|
|
tsVertex* v1;
|
|
tsVertex* v2;
|
|
/*
|
|
Initialize v1->ear for all vertices.
|
|
*/
|
|
v1 = vertices;
|
|
do
|
|
{
|
|
v2 = v1->next;
|
|
v0 = v1->prev;
|
|
v1->ear = diagonal ( v0, v2 );
|
|
v1 = v1->next;
|
|
} while ( v1 != vertices );
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
DIAGONALIE returns TRUE iff (A,B) is a proper diagonal of a polygon.
|
|
|
|
Discussion:
|
|
|
|
(A,B) may be an internal or external diagonal of the polygon, ignoring edges
|
|
incident to A and B.
|
|
|
|
Parameters:
|
|
|
|
Input, tsVertex* A, B, two vertices of the polygon.
|
|
|
|
Output, bool DIAGONALIE, is TRUE if the line connecting A and B is a
|
|
proper diagonal of the polygon.
|
|
*/
|
|
|
|
bool diagonalie ( tsVertex* a, tsVertex* b )
|
|
{
|
|
tsVertex* c;
|
|
tsVertex* c1;
|
|
/*
|
|
For each edge (C,C1) of P.
|
|
*/
|
|
c = vertices;
|
|
do
|
|
{
|
|
c1 = c->next;
|
|
/*
|
|
Skip edges incident to A or B.
|
|
*/
|
|
if ( ( c != a ) && ( c1 != a ) && ( c != b ) && ( c1 != b ) &&
|
|
intersect( a->v, b->v, c->v, c1->v ) )
|
|
{
|
|
return false;
|
|
}
|
|
c = c->next;
|
|
} while ( c != vertices );
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
IN_CONE returns TRUE iff the diagonal (A,B) is strictly internal.
|
|
|
|
Discussion:
|
|
|
|
More correctly, the diagonal (A,B) must be strictly internal to the
|
|
polygon in the neighborhood of the A endpoint.
|
|
|
|
Parameters:
|
|
|
|
Input, tsVertex* A, B, two vertices of the polygon.
|
|
|
|
Output, bool IN_CONE, is TRUE if the line connecting A and B is
|
|
strictly internal to the polygon in the neighborhood of A.
|
|
|
|
Local Parameters:
|
|
|
|
Local, tsVertex* A0, A1, are the vertices before and after A.
|
|
*/
|
|
bool in_cone ( tsVertex* a, tsVertex* b )
|
|
{
|
|
tsVertex* a0;
|
|
tsVertex* a1;
|
|
|
|
a1 = a->next;
|
|
a0 = a->prev;
|
|
/*
|
|
If A is a convex vertex ...
|
|
*/
|
|
if ( left_on ( a->v, a1->v, a0->v ) )
|
|
{
|
|
return left ( a->v, b->v, a0->v )
|
|
&& left ( b->v, a->v, a1->v );
|
|
}
|
|
/*
|
|
Else A is reflex vertex:
|
|
*/
|
|
else
|
|
{
|
|
return !( left_on ( a->v, b->v, a1->v )
|
|
&& left_on ( b->v, a->v, a0->v ) );
|
|
}
|
|
}
|
|
|
|
float area_poly2 ( void )
|
|
{
|
|
tsVertex* a;
|
|
tsVertex* p;
|
|
float sum = 0;
|
|
|
|
p = vertices; /* Fixed. */
|
|
a = p->next; /* Moving. */
|
|
|
|
do
|
|
{
|
|
sum = sum + area2 ( p->v, a->v, a->next->v );
|
|
a = a->next;
|
|
} while ( a->next != vertices );
|
|
|
|
return sum;
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
AREA_SIGN returns the sign of the area defined by three points.
|
|
|
|
Parameters:
|
|
|
|
Input, tPointi A, B, C, three points that define a triangle.
|
|
|
|
Output, int AREA_SIGN, the sign of the area of the triangle.
|
|
*/
|
|
int area_sign ( tPointi a, tPointi b, tPointi c )
|
|
{
|
|
float area;
|
|
|
|
area = ( b[0] - a[0] ) * ( c[1] - a[1] ) - ( c[0] - a[0] ) * ( b[1] - a[1] );
|
|
/*
|
|
The area should be an integer.
|
|
*/
|
|
if ( area > 0 )
|
|
{
|
|
return 1;
|
|
}
|
|
else if ( area < 0 )
|
|
{
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
AREA2 returns twice the signed area of a triangle.
|
|
|
|
Discussion:
|
|
|
|
The area is positive if points A, B, and C are oriented counter clockwise,
|
|
negative if clockwise, and zero if the points are collinear.
|
|
|
|
Parameters:
|
|
|
|
Input, tPointi A, B, C, three points that define a triangle.
|
|
|
|
Output, int AREA2, twice the signed area of the triangle.
|
|
*/
|
|
float area2 ( tPointi a, tPointi b, tPointi c )
|
|
{
|
|
return (( b[0] - a[0] ) * ( c[1] - a[1] ) - ( c[0] - a[0] ) * ( b[1] - a[1] ));
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
BETWEEN returns TRUE iff point C lies on the closed segement AB.
|
|
|
|
Discussion:
|
|
|
|
The function first checks that C is collinear with A and B.
|
|
|
|
Parameters:
|
|
|
|
Input, tPointi A, B, C, three points to be tested.
|
|
|
|
Output, bool BETWEEN is TRUE if point C lies on the closed
|
|
segment between A and B.
|
|
*/
|
|
bool between ( tPointi a, tPointi b, tPointi c )
|
|
{
|
|
if ( ! collinear ( a, b, c ) )
|
|
{
|
|
return false;
|
|
}
|
|
/*
|
|
If AB not vertical, check betweenness on x; else on y.
|
|
*/
|
|
if ( a[0] != b[0] )
|
|
{
|
|
return ( (a[0] <= c[0] ) && ( c[0] <= b[0] ) ) ||
|
|
( (a[0] >= c[0] ) && ( c[0] >= b[0] ) );
|
|
}
|
|
else
|
|
{
|
|
return ( ( a[1] <= c[1] ) && ( c[1] <= b[1] ) ) ||
|
|
( ( a[1] >= c[1] ) && ( c[1] >= b[1] ) );
|
|
}
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
COLLINEAR is TRUE if the points A, B and C are collinear.
|
|
|
|
Parameters:
|
|
|
|
Input, tPointi A, B, C, three points to be tested.
|
|
|
|
Output, bool COLLINEAR, is TRUE if the points are collinear.
|
|
*/
|
|
bool collinear ( tPointi a, tPointi b, tPointi c )
|
|
{
|
|
return ( area_sign ( a, b, c ) == 0 );
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
INTERSECT returns TRUE iff segments AB and CD intersect.
|
|
|
|
Discussion:
|
|
|
|
The intersection may be proper or improper.
|
|
|
|
Parameters:
|
|
|
|
Input, tPointi A, B, C, D, points that define the segments.
|
|
|
|
Output, bool INTERSECT, is TRUE if segments AB and CD intersect.
|
|
*/
|
|
bool intersect ( tPointi a, tPointi b, tPointi c, tPointi d )
|
|
{
|
|
if ( intersect_prop ( a, b, c, d ) )
|
|
{
|
|
return true;
|
|
}
|
|
else if ( between ( a, b, c )
|
|
|| between ( a, b, d )
|
|
|| between ( c, d, a )
|
|
|| between ( c, d, b ) )
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
INTERSECT_PROP returns true if and only if AB properly intersects CD.
|
|
|
|
Discussion:
|
|
|
|
AB and CD must share a point interior to both segments. The properness of
|
|
the intersection is ensured by using strict leftness.
|
|
|
|
Parameters:
|
|
|
|
Input, tPointi A, B, C, D, points that define segments AB and CD.
|
|
|
|
Output, bool INTERSECT_PROP, is TRUE if AB properly intersects CD.
|
|
*/
|
|
bool intersect_prop ( tPointi a, tPointi b, tPointi c, tPointi d )
|
|
{
|
|
/*
|
|
Eliminate improper cases.
|
|
*/
|
|
if ( collinear ( a, b, c ) ||
|
|
collinear ( a, b, d ) ||
|
|
collinear ( c, d, a ) ||
|
|
collinear ( c, d, b ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return
|
|
xor ( left ( a, b, c ), left ( a, b, d ) )
|
|
&& xor ( left ( c, d, a ), left ( c, d, b ) );
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
LEFT is TRUE if C is on the left side of the line from A to B.
|
|
|
|
Discussion:
|
|
|
|
More correctly, the function returns true if and only if C is strictly
|
|
to the left of the directed line through A to B.
|
|
|
|
Parameters:
|
|
|
|
Input, tPointi A, B, C, three points to be tested.
|
|
|
|
Output, bool LEFT, is TRUE if C is strictly to the left of the directed
|
|
line from A to B.
|
|
*/
|
|
bool left ( tPointi a, tPointi b, tPointi c )
|
|
{
|
|
return ( area_sign ( a, b, c ) > 0 );
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
LEFT_ON is TRUE if C is to the left side, or on, the line from A to B.
|
|
|
|
Parameters:
|
|
|
|
Input, tPointi A, B, C, three points to be tested.
|
|
|
|
Output, bool LEFT_ON, is TRUE if C is strictly to the left of, or on,
|
|
the directed line from A to B.
|
|
*/
|
|
bool left_on ( tPointi a, tPointi b, tPointi c )
|
|
{
|
|
return ( area_sign ( a, b, c ) >= 0 );
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
PRINT_POLY prints the polygon data.
|
|
*/
|
|
void print_poly ( void )
|
|
{
|
|
tsVertex* v;
|
|
|
|
printf ( "%%\n" );
|
|
printf ( "%%Polygon circular list:\n" );
|
|
printf ( "%%\n" );
|
|
|
|
v = vertices;
|
|
do
|
|
{
|
|
printf( "%% vnum=%5d: ear=%d\n", v->vnum, v->ear );
|
|
v = v->next;
|
|
} while ( v != vertices );
|
|
|
|
printf ( "%%\n" );
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
Purpose:
|
|
|
|
PRINT_VERTICES prints the vertices.
|
|
|
|
Discussion:
|
|
|
|
This function uses the VNUM indices corresponding to the order in which
|
|
the vertices were input. The output is in PostScript format.
|
|
|
|
Parameters:
|
|
|
|
Input, int XMIN, XMAX, YMIN, YMAX, the minimum and maximum
|
|
0 and 1 values of the coordinates of the vertices of the polygon.
|
|
|
|
Input, int SCALE, an appropriate scaling for the data.
|
|
*/
|
|
void print_vertices ( float xmin, float xmax, float ymin, float ymax, int scale )
|
|
{
|
|
/* Pointers to vertices, edges, faces. */
|
|
tsVertex* v;
|
|
int x;
|
|
int y;
|
|
/*
|
|
PostScript header
|
|
*/
|
|
printf ( "%%!PS\n" );
|
|
printf ( "%%%%Creator: triangulate.c (Joseph O'Rourke)\n" );
|
|
printf ( "%%%%BoundingBox: %d %d %d %d\n",
|
|
0, 0, 72 + scale * ( xmax - xmin ), 72 + scale * ( ymax - ymin ) );
|
|
printf ( "%%%%EndComments\n" );
|
|
printf ( "1 1 setlinewidth\n" );
|
|
/*
|
|
Output vertex information as a PostScript comment.
|
|
*/
|
|
printf ( "\n" );
|
|
printf ( "%% number of vertices = %d\n", nvertices );
|
|
|
|
v = vertices;
|
|
do
|
|
{
|
|
printf ( "%% vnum=%5d:\tx=%5d\ty=%5d\n", v->vnum, v->v[0], v->v[1] );
|
|
v = v->next;
|
|
} while ( v != vertices );
|
|
/*
|
|
Draw the polygon.
|
|
*/
|
|
printf ( "\n%%Polygon:\n" );
|
|
printf ( "newpath\n" );
|
|
v = vertices;
|
|
x = 36 + scale * ( v->v[0] - xmin );
|
|
y = 36 + scale * ( v->v[1] - ymin );
|
|
printf ( "%d\t%d\tmoveto\n", x, y );
|
|
v = v->next;
|
|
do
|
|
{
|
|
x = 36 + scale * ( v->v[0] - xmin );
|
|
y = 36 + scale * ( v->v[1] - ymin );
|
|
printf ( "%d\t%d\tlineto\n", x, y );
|
|
v = v->next;
|
|
} while ( v != vertices );
|
|
|
|
printf ( "closepath stroke\n" );
|
|
}
|
|
|
|
bool xor ( bool x, bool y )
|
|
{
|
|
return ( !x ^ !y );
|
|
}
|
|
#endif //USE_SVG
|