se moteur, qui n'utilise aucunne fonction 3D toute faite, a pour but (ludique) la comprention du fonctionnement de la 3D : rotation d'objet (trigo), effet de persepective (pythagore), l'eclairage (vecteurs et normal), les loadeur de map (fichier ascii .ase vers memoire) ...
le source est portable =)
il n'est pas tres documenter car se serai trop long et sa restera comme sa
Source / Exemple :
/*****************************************************************************/
/* */
/* fichier : moteur.c version : V2.1 */
/* projet : moteur date : 24/05/2005 */
/* par : aerith */
/* */
/* mini moteur 3D */
/* */
/*****************************************************************************/
#include "moteur.h"
SDL_Surface *pScreen;
char *gettok(const char *pData, int iPos, char *pCar)
{
static char Data[NBCARLINE];
char * Token;
int i;
strcpy(Data, pData);
for(Token = strtok(Data, pCar), i = 0; Token && (i < iPos); ++i, Token = strtok(0, pCar));
return Token;
}
void Load(char *pFichier, mesh *pMesh)
{
FILE *Fichier;
char Data[NBCARLINE];
Fichier = fopen(pFichier, "r");
if(!Fichier)
{
perror("erreur map non trouver\n");
exit(1);
}
while(!feof(Fichier))
{
if(fgets(Data, NBCARLINE, Fichier))
{
if(strcmp(gettok(Data, 0, ":* \t\n\""), "MESH_NUMVERTEX") == 0)
{
pMesh->NumVertex = atoi(gettok(Data, 1, ":* \t\n\""));
pMesh->Vertex = malloc(sizeof(vertex) * (pMesh->NumVertex + 1));
}
if(strcmp(gettok(Data, 0, ":* \t\n\""), "MESH_NUMFACES") == 0)
{
pMesh->NumFace = atoi(gettok(Data, 1, ":* \t\n\""));
pMesh->Faces = malloc(sizeof(face) * (pMesh->NumFace + 1));
}
if (strcmp(gettok(Data, 0, ":* \t\n"), "MESH_VERTEX") == 0)
{
pMesh->Vertex[atoi(gettok(Data, 1, ":* \t\n"))].v3D.x = (float)atof(gettok(Data, 2, ":* \t\n"));
pMesh->Vertex[atoi(gettok(Data, 1, ":* \t\n"))].v3D.y = (float)atof(gettok(Data, 3, ":* \t\n"));
pMesh->Vertex[atoi(gettok(Data, 1, ":* \t\n"))].v3D.z = (float)atof(gettok(Data, 4, ":* \t\n"));
}
if (strcmp(gettok(Data, 0, ":* \t\n"), "MESH_FACE") == 0)
{
pMesh->Faces[atoi(gettok(Data, 1, ":* \t\n"))].a = atoi(gettok(Data, 3, ":* \t\n"));
pMesh->Faces[atoi(gettok(Data, 1, ":* \t\n"))].b = atoi(gettok(Data, 5, ":* \t\n"));
pMesh->Faces[atoi(gettok(Data, 1, ":* \t\n"))].c = atoi(gettok(Data, 7, ":* \t\n"));
}
if (strcmp(gettok(Data, 0, ":* \t\n"), "MESH_FACENORMAL") == 0)
{
pMesh->Faces[atoi(gettok(Data, 1, ":* \t\n"))].normal.x = (float)atof(gettok(Data, 2, ":* \t\n"));
pMesh->Faces[atoi(gettok(Data, 1, ":* \t\n"))].normal.y = (float)atof(gettok(Data, 3, ":* \t\n"));
pMesh->Faces[atoi(gettok(Data, 1, ":* \t\n"))].normal.z = (float)atof(gettok(Data, 4, ":* \t\n"));
}
}
}
fclose(Fichier);
}
void Init(char *pFichier, option *pOption)
{
FILE *Fichier;
char Data[NBCARLINE];
pOption->Zoom = 10;
pOption->Cliping = 50;
pOption->Camera.x = 0;
pOption->Camera.y = 0;
pOption->Camera.z = 100;
pOption->Rotate.a = 0;
pOption->Rotate.x = 0;
pOption->Rotate.y = 0;
pOption->Rotate.z = 0;
pOption->Light = 1;
pOption->Lcolor.i = 100;
pOption->Lcolor.r = 255;
pOption->Lcolor.g = 255;
pOption->Lcolor.b = 255;
pOption->Render = 1;
pOption->Allface = 0;
pOption->WindowX = 320;
pOption->WindowY = 240;
pOption->Color = 16;
strcpy(pOption->Title, "m3d");
pOption->Triface = 1;
Fichier = fopen(pFichier, "r");
if(!Fichier)
{
perror("erreur fichier init inexistant\n");
exit(2);
}
while(!feof(Fichier))
{
if(fgets(Data, NBCARLINE, Fichier) != NULL)
{
if(!(Data[0] == '\\' && Data[1] == '\\') && Data[0] != '\n')
{
if(strcmp(gettok(Data, 0, "=: \t\n\""), "zoom") == 0)
pOption->Zoom = (float)atof(gettok(Data, 1, "=: \t\n\""));
if(strcmp(gettok(Data, 0, "=: \t\n\""), "cliping") == 0)
pOption->Cliping = (float)atof(gettok(Data, 1, "=: \t\n\""));
if(strcmp(gettok(Data, 0, "=: \t\n\""), "camera") == 0)
{
pOption->Camera.x = (float)atof(gettok(Data, 1, "=: \t\n\""));
pOption->Camera.y = (float)atof(gettok(Data, 2, "=: \t\n\""));
pOption->Camera.z = (float)atof(gettok(Data, 3, "=: \t\n\""));
}
if(strcmp(gettok(Data, 0, "=: \t\n\""), "rotate") == 0)
{
pOption->Rotate.a = (float)atof(gettok(Data, 1, "=: \t\n\""));
pOption->Rotate.x = (float)atof(gettok(Data, 2, "=: \t\n\""));
pOption->Rotate.y = (float)atof(gettok(Data, 3, "=: \t\n\""));
pOption->Rotate.z = (float)atof(gettok(Data, 4, "=: \t\n\""));
}
if(strcmp(gettok(Data, 0, "=: \t\n\""), "light") == 0)
pOption->Light = atoi(gettok(Data, 1, "=: \t\n\""));
if(strcmp(gettok(Data, 0, "=: \t\n\""), "lcolor") == 0)
{
pOption->Lcolor.i = atoi(gettok(Data, 1, "=: \t\n\""));
pOption->Lcolor.r = atoi(gettok(Data, 2, "=: \t\n\""));
pOption->Lcolor.g = atoi(gettok(Data, 3, "=: \t\n\""));
pOption->Lcolor.b = atoi(gettok(Data, 4, "=: \t\n\""));
}
if(strcmp(gettok(Data, 0, "=: \t\n\""), "render") == 0)
pOption->Render = atoi(gettok(Data, 1, "=: \t\n\""));
if(strcmp(gettok(Data, 0, "=: \t\n\""), "allface") == 0)
pOption->Allface = atoi(gettok(Data, 1, "=: \t\n\""));
if(strcmp(gettok(Data, 0, "=: \t\n\""), "window") == 0)
{
pOption->WindowX = atoi(gettok(Data, 1, "=: \t\n\""));
pOption->WindowY = atoi(gettok(Data, 2, "=: \t\n\""));
pOption->Color = atoi(gettok(Data, 3, "=: \t\n\""));
}
if(strcmp(gettok(Data, 0, "=: \t\n\""), "title") == 0)
strcpy(pOption->Title, gettok(Data, 1, "=: \t\n\""));
if(strcmp(gettok(Data, 0, "=: \t\n\""), "triface") == 0)
pOption->Triface = atoi(gettok(Data, 1, "=: \t\n\""));
}
}
}
fclose(Fichier);
if(SDL_Init(SDL_INIT_VIDEO) < 0)
{
perror("erreur init SDL\n");
exit(3);
}
atexit(SDL_Quit);
pScreen = SDL_SetVideoMode(pOption->WindowX, pOption->WindowY,
pOption->Color, SDL_SWSURFACE | SDL_DOUBLEBUF);
if(!pScreen)
{
perror("erreur creation screen\n");
exit(4);
}
SDL_WM_SetCaption(pOption->Title, NULL);
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
}
void Point(vecteur p1, int r, int g, int b)
{
Uint16 *Pointer;
if((p1.x > 0) && (p1.x < (float)pScreen->w) && (p1.y > 0) && (p1.y < (float)pScreen->h))
{
Pointer = (Uint16*)pScreen->pixels + ((pScreen->pitch / 2 * (int)p1.y) + (int)p1.x);
- Pointer = SDL_MapRGB(pScreen->format, (Uint8)r, (Uint8)g, (Uint8)b);
}
}
void Line(vecteur p1, vecteur p2, int r, int g, int b)
{
vecteur p;
float d;
if(abs((int)(p1.x - p2.x)) > abs((int)(p1.y - p2.y)))
{
if(p1.x > p2.x)
{
p = p1;
p1 = p2;
p2 = p;
}
d = (p1.y - p2.y) / (p1.x - p2.x);
for(; p1.x <= p2.x; p1.x++, p1.y += d)
Point(p1, r, g, b);
}
else
{
if(p1.y > p2.y)
{
p = p1;
p1 = p2;
p2 = p;
}
d = (p1.x - p2.x) / (p1.y - p2.y);
for(; p1.y <= p2.y; p1.x += d, p1.y++)
Point(p1, r, g, b);
}
}
void Triangle(vecteur p1, vecteur p2, vecteur p3, int r, int g, int b)
{
vecteur p;
float d;
if(abs((int)(p2.x - p3.x)) > abs((int)(p2.y - p3.y)))
{
if(p2.x > p3.x)
{
p = p2;
p2 = p3;
p3 = p;
}
d = (p2.y - p3.y) / (p2.x - p3.x);
for(; p2.x <= p3.x; p2.x++, p2.y += d)
Line(p1, p2, r, g, b);
}
else
{
if(p2.y > p3.y)
{
p = p2;
p2 = p3;
p3 = p;
}
d = (p2.x - p3.x) / (p2.y - p3.y);
for(;p2.y <= p3.y; p2.x += d, p2.y++)
Line(p1, p2, r, g, b);
}
}
void Render(mesh *pMesh, option *pOption)
{
float cosT = (float)cos(pOption->Rotate.a);
float sinT = (float)sin(pOption->Rotate.a);
float cosT1 = 1 - cosT;
float cosT2 = 1 + cosT;
float xs = pOption->Rotate.x * sinT;
float ys = pOption->Rotate.y * sinT;
float zs = pOption->Rotate.z * sinT;
float ex1 = cosT + cosT1 * (pOption->Rotate.x * pOption->Rotate.x);
float ex2 = cosT1 * pOption->Rotate.x * pOption->Rotate.y - zs;
float ex3 = cosT1 * pOption->Rotate.x * pOption->Rotate.z + ys;
float ey1 = cosT2 * pOption->Rotate.x * pOption->Rotate.y + zs;
float ey2 = cosT + cosT1 * (pOption->Rotate.y * pOption->Rotate.y);
float ey3 = cosT1 * pOption->Rotate.y * pOption->Rotate.z - xs;
float ez1 = cosT2 * pOption->Rotate.x * pOption->Rotate.z - ys;
float ez2 = cosT1 * pOption->Rotate.y * pOption->Rotate.z + xs;
float ez3 = cosT + cosT1 * (pOption->Rotate.z * pOption->Rotate.z);
int i, j, n;
float m, o;
vecteur vt;
face ft;
clock_t start;
static int Fpsc = 0;
static int Fpsa = 0;
int Fps = 0;
Uint32 Color;
light couleur;
char Titre[256];
start = clock();
couleur.r = 255;
couleur.g = 255;
couleur.b = 255;
for(i = 0; i < pMesh->NumVertex; i++)
{
pMesh->Vertex[i].v3D.x = ex1 * pMesh->Vertex[i].v3D.x + ex2 * pMesh->Vertex[i].v3D.y + ex3 * pMesh->Vertex[i].v3D.z;
pMesh->Vertex[i].v3D.y = ey1 * pMesh->Vertex[i].v3D.x + ey2 * pMesh->Vertex[i].v3D.y + ey3 * pMesh->Vertex[i].v3D.z;
pMesh->Vertex[i].v3D.z = ez1 * pMesh->Vertex[i].v3D.x + ez2 * pMesh->Vertex[i].v3D.y + ez3 * pMesh->Vertex[i].v3D.z;
pMesh->Vertex[i].v2D.x = (pMesh->Vertex[i].v3D.x + pOption->Camera.x) * pOption->Zoom / ((pMesh->Vertex[i].v3D.z + pOption->Camera.z) / pOption->Cliping) + (pOption->WindowX / 2);
pMesh->Vertex[i].v2D.y = (pMesh->Vertex[i].v3D.y + pOption->Camera.y) * pOption->Zoom / ((pMesh->Vertex[i].v3D.z + pOption->Camera.z) / pOption->Cliping) + (pOption->WindowY / 2);
}
for(i = 0; i < pMesh->NumFace; i++)
{
pMesh->Faces[i].normal.x = ex1 * pMesh->Faces[i].normal.x + ex2 * pMesh->Faces[i].normal.y + ex3 * pMesh->Faces[i].normal.z;
pMesh->Faces[i].normal.y = ey1 * pMesh->Faces[i].normal.x + ey2 * pMesh->Faces[i].normal.y + ey3 * pMesh->Faces[i].normal.z;
pMesh->Faces[i].normal.z = ez1 * pMesh->Faces[i].normal.x + ez2 * pMesh->Faces[i].normal.y + ez3 * pMesh->Faces[i].normal.z;
pMesh->Faces[i].centre.x = (pMesh->Vertex[pMesh->Faces[i].a].v3D.x + pMesh->Vertex[pMesh->Faces[i].b].v3D.x + pMesh->Vertex[pMesh->Faces[i].c].v3D.x) / 3;
pMesh->Faces[i].centre.y = (pMesh->Vertex[pMesh->Faces[i].a].v3D.y + pMesh->Vertex[pMesh->Faces[i].b].v3D.y + pMesh->Vertex[pMesh->Faces[i].c].v3D.y) / 3;
pMesh->Faces[i].centre.z = (pMesh->Vertex[pMesh->Faces[i].a].v3D.z + pMesh->Vertex[pMesh->Faces[i].b].v3D.z + pMesh->Vertex[pMesh->Faces[i].c].v3D.z) / 3;
vt.x = abs((int)(pOption->Camera.x - pMesh->Faces[i].centre.x));
vt.y = abs((int)(pOption->Camera.y - pMesh->Faces[i].centre.y));
vt.z = abs((int)(pOption->Camera.z - pMesh->Faces[i].centre.z));
pMesh->Faces[i].dist = (int)sqrt((vt.x * vt.x) + (vt.y * vt.y) + (vt.z * vt.z));
}
if(pOption->Triface)
{
for(i = 0; i < (pMesh->NumFace - 1); i++)
{
for(j = i + 1; j < pMesh->NumFace; j++)
{
if(pMesh->Faces[i].dist > pMesh->Faces[j].dist)
{
memcpy((void *)&ft, (void *)&pMesh->Faces[i], sizeof(face));
memcpy((void *)&pMesh->Faces[i], (void *)&pMesh->Faces[j], sizeof(face));
memcpy((void *)&pMesh->Faces[j], (void *)&ft, sizeof(face));
}
}
}
}
Color = SDL_MapRGB(pScreen->format, 0, 0, 0);
SDL_FillRect(pScreen, NULL, Color);
if(SDL_MUSTLOCK(pScreen))
if(SDL_LockSurface(pScreen) < 0)
return;
vt.x = (int)(pOption->Camera.x * pOption->Camera.x);
vt.y = (int)(pOption->Camera.y * pOption->Camera.y);
vt.z = (int)(pOption->Camera.z * pOption->Camera.z);
n = sqrt(vt.x + vt.y + vt.z);
for(i = 0; i < pMesh->NumFace; i++)
{
vt.x = (pOption->Camera.x / n) + pMesh->Faces[i].normal.x;
vt.y = (pOption->Camera.y / n) + pMesh->Faces[i].normal.y;
vt.z = (pOption->Camera.z / n) + pMesh->Faces[i].normal.z;
m = sqrt((vt.x * vt.x) + (vt.y * vt.y) + (vt.z * vt.z));
if(pOption->Light)
{
o = ((float)pOption->Lcolor.i / (float)pMesh->Faces[i].dist) / m;
couleur.r = (int)(pOption->Lcolor.r * o);
couleur.g = (int)(pOption->Lcolor.g * o);
couleur.b = (int)(pOption->Lcolor.b * o);
if(couleur.r > 255)
couleur.r = 255;
else if(couleur.r < 0)
couleur.r = 0;
if(couleur.g > 255)
couleur.g = 255;
else if(couleur.g < 0)
couleur.g = 0;
if(couleur.b > 255)
couleur.b = 255;
else if(couleur.b < 0)
couleur.b = 0;
}
if((pMesh->Faces[i].normal.z <= 0) || pOption->Allface)
{
if(!pOption->Render)
{
Triangle(pMesh->Vertex[pMesh->Faces[i].a].v2D,
pMesh->Vertex[pMesh->Faces[i].b].v2D,
pMesh->Vertex[pMesh->Faces[i].c].v2D,
couleur.r, couleur.g, couleur.b);
}
else
{
if(pOption->Render == 2)
{
Point(pMesh->Vertex[pMesh->Faces[i].a].v2D,
couleur.r, couleur.g, couleur.b);
}
else
{
Line(pMesh->Vertex[pMesh->Faces[i].a].v2D,
pMesh->Vertex[pMesh->Faces[i].b].v2D,
couleur.r, couleur.g, couleur.b);
Line(pMesh->Vertex[pMesh->Faces[i].b].v2D,
pMesh->Vertex[pMesh->Faces[i].c].v2D,
couleur.r, couleur.g, couleur.b);
Line(pMesh->Vertex[pMesh->Faces[i].c].v2D,
pMesh->Vertex[pMesh->Faces[i].a].v2D,
couleur.r, couleur.g, couleur.b);
}
}
}
}
if(SDL_MUSTLOCK(pScreen))
SDL_UnlockSurface(pScreen);
SDL_Flip(pScreen);
Fps = CLOCKS_PER_SEC / (clock() - start + 1);
Fpsc++;
Fpsa += Fps;
if(Fpsc > Fps)
{
Fpsc = 1;
Fpsa = Fps;
sprintf(Titre, "%s - fps : %i", pOption->Title, Fpsa / Fpsc);
SDL_WM_SetCaption(Titre, NULL);
}
}
Conclusion :
y a un .c de test en plus
lisez le readme :p
oui je sais y a mieu que SDL, mais je ne veux pas de truc tout fait !
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.