Moteur 3d hardcoder (fenetre sdl)

Description

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 !

Codes Sources

A voir également

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.