trim spaces and use 4 space instead of 2

This commit is contained in:
Mylloon 2021-12-22 02:17:16 +01:00
parent db59cc2a85
commit 0b62517c35
Signed by: Anri
GPG key ID: A82D63DFF8D1317F
6 changed files with 894 additions and 893 deletions

View file

@ -1,10 +1,10 @@
/*!\file geometry.h
/*!\file geometry.h
*
* \brief quelques surfaces basiques sous forme polygonale : un plan
* (quad), un cube et une sphere.
*
* \author Farès BELHADJ, amsi@up8.edu
* \date November, 2021.
* \date November, 2021.
*/
#include "rasterize.h"
#include <assert.h>
@ -17,141 +17,141 @@
* quadrilatère "debout" et à la profondeur 0. Il fait la hauteur et
* la largeur du cube unitaire (-1 à 1).*/
surface_t * mk_quad(void) {
static const float
data[] = {
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f,
1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, -1.0f
};
static const int order[] = { 0, 1, 2, 2, 1, 3 };
surface_t * s;
/* on met du jaune partout */
const vec4 color0 = { 1.0f, 1.0f, 0.0f, 1.0f };
triangle_t t[2];
int i, j, k, o;
for(i = 0, o = 0; i < 2; ++i)
for(j = 0; j < 3; ++j, ++o) {
k = order[o] * 8;
t[i].v[j].position = *(vec4 *)&(data[k]);
t[i].v[j].position.w = 1.0f;
t[i].v[j].normal = *(vec3 *)&(data[k + 3]);
t[i].v[j].texCoord = *(vec2 *)&(data[k + 6]);
t[i].v[j].color0 = color0;
}
s = new_surface(t, 2, 1, 1);
snormals(s);
return s;
static const float
data[] = {
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f,
1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, -1.0f
};
static const int order[] = { 0, 1, 2, 2, 1, 3 };
surface_t * s;
/* on met du jaune partout */
const vec4 color0 = { 1.0f, 1.0f, 0.0f, 1.0f };
triangle_t t[2];
int i, j, k, o;
for(i = 0, o = 0; i < 2; ++i)
for(j = 0; j < 3; ++j, ++o) {
k = order[o] * 8;
t[i].v[j].position = *(vec4 *)&(data[k]);
t[i].v[j].position.w = 1.0f;
t[i].v[j].normal = *(vec3 *)&(data[k + 3]);
t[i].v[j].texCoord = *(vec2 *)&(data[k + 6]);
t[i].v[j].color0 = color0;
}
s = new_surface(t, 2, 1, 1);
snormals(s);
return s;
}
/*!\brief fabrique et renvoie une surface représentant un
* cube unitaire (de -1 à 1).*/
surface_t * mk_cube(void) {
const float
data[] = {
/* front */
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
/* back */
1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
/* right */
1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
/* left */
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
/* top */
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
/* bottom */
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f
};
const int order[] = { 0, 1, 2, 2, 1, 3 };
surface_t * s;
/* on met du vert-clair partout */
const vec4 color0 = { 0.5f, 1.0f, 0.0f, 1.0f };
triangle_t t[12];
int i, j, k, o;
for(i = 0, o = 0; i < 12; ++i)
for(j = 0; j < 3; ++j, ++o) {
k = 8 * (order[o % 6] + 4 * (i / 2));
t[i].v[j].position = *(vec4 *)&(data[k]);
t[i].v[j].position.w = 1.0f;
t[i].v[j].normal = *(vec3 *)&(data[k + 3]);
t[i].v[j].texCoord = *(vec2 *)&(data[k + 6]);
t[i].v[j].color0 = color0;
}
s = new_surface(t, 12, 1, 1);
snormals(s);
return s;
const float
data[] = {
/* front */
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
/* back */
1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
/* right */
1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
/* left */
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
/* top */
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
/* bottom */
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f
};
const int order[] = { 0, 1, 2, 2, 1, 3 };
surface_t * s;
/* on met du vert-clair partout */
const vec4 color0 = { 0.5f, 1.0f, 0.0f, 1.0f };
triangle_t t[12];
int i, j, k, o;
for(i = 0, o = 0; i < 12; ++i)
for(j = 0; j < 3; ++j, ++o) {
k = 8 * (order[o % 6] + 4 * (i / 2));
t[i].v[j].position = *(vec4 *)&(data[k]);
t[i].v[j].position.w = 1.0f;
t[i].v[j].normal = *(vec3 *)&(data[k + 3]);
t[i].v[j].texCoord = *(vec2 *)&(data[k + 6]);
t[i].v[j].color0 = color0;
}
s = new_surface(t, 12, 1, 1);
snormals(s);
return s;
}
/*!\brief fabrique et renvoie une surface représentant une sphère
* centrée en zéro et de rayon 1. Elle est découpée en \a longitudes
* longitudes et \a latitudes latitudes. */
surface_t * mk_sphere(int longitudes, int latitudes) {
triangle_t * t;
vertex_t * data;
double phi, theta, r, y;
double c2MPI_Long = 2.0 * M_PI / longitudes;
double cMPI_Lat = M_PI / latitudes;
/* on met du vert-clair partout */
const vec4 color0 = { 0.5f, 1.0f, 0.0f, 1.0f };
int z, nz, x, nx, zw, nzw, k, n = 2 * longitudes * latitudes;
assert(n);
data = malloc((longitudes + 1) * (latitudes + 1) * sizeof *data);
assert(data);
t = malloc(n * sizeof *t);
assert(t);
for(z = 0, k = 0; z <= latitudes; ++z) {
theta = -M_PI_2 + z * cMPI_Lat;
y = sin(theta);
r = cos(theta);
for(x = 0; x <= longitudes; ++x, ++k) {
phi = x * c2MPI_Long;
data[k].position.x = r * cos(phi);
data[k].position.y = y;
data[k].position.z = r * sin(phi);
data[k].position.w = 1.0f;
data[k].texCoord.x = phi / (2.0 * M_PI);
data[k].texCoord.y = (theta + M_PI_2) / M_PI;
data[k].color0 = color0;
/* gcc 7.5 et plus abusent : data[k].normal = *(vec3 *)&(data[k].position); */
data[k].normal.x = data[k].position.x;
data[k].normal.y = data[k].position.y;
data[k].normal.z = data[k].position.z;
triangle_t * t;
vertex_t * data;
double phi, theta, r, y;
double c2MPI_Long = 2.0 * M_PI / longitudes;
double cMPI_Lat = M_PI / latitudes;
/* on met du vert-clair partout */
const vec4 color0 = { 0.5f, 1.0f, 0.0f, 1.0f };
int z, nz, x, nx, zw, nzw, k, n = 2 * longitudes * latitudes;
assert(n);
data = malloc((longitudes + 1) * (latitudes + 1) * sizeof *data);
assert(data);
t = malloc(n * sizeof *t);
assert(t);
for(z = 0, k = 0; z <= latitudes; ++z) {
theta = -M_PI_2 + z * cMPI_Lat;
y = sin(theta);
r = cos(theta);
for(x = 0; x <= longitudes; ++x, ++k) {
phi = x * c2MPI_Long;
data[k].position.x = r * cos(phi);
data[k].position.y = y;
data[k].position.z = r * sin(phi);
data[k].position.w = 1.0f;
data[k].texCoord.x = phi / (2.0 * M_PI);
data[k].texCoord.y = (theta + M_PI_2) / M_PI;
data[k].color0 = color0;
/* gcc 7.5 et plus abusent : data[k].normal = *(vec3 *)&(data[k].position); */
data[k].normal.x = data[k].position.x;
data[k].normal.y = data[k].position.y;
data[k].normal.z = data[k].position.z;
}
}
}
for(z = 0, k = 0; z < latitudes; ++z) {
nz = z + 1;
zw = z * (longitudes + 1);
nzw = nz * (longitudes + 1);
for(x = 0; x < longitudes; ++x) {
nx = x + 1;
t[k].v[0] = data[zw + x];
t[k].v[1] = data[nzw + x];
t[k].v[2] = data[zw + nx];
tnormal(&t[k]);++k;
t[k].v[0] = data[zw + nx];
t[k].v[1] = data[nzw + x];
t[k].v[2] = data[nzw + nx];
tnormal(&t[k]);++k;
for(z = 0, k = 0; z < latitudes; ++z) {
nz = z + 1;
zw = z * (longitudes + 1);
nzw = nz * (longitudes + 1);
for(x = 0; x < longitudes; ++x) {
nx = x + 1;
t[k].v[0] = data[zw + x];
t[k].v[1] = data[nzw + x];
t[k].v[2] = data[zw + nx];
tnormal(&t[k]);++k;
t[k].v[0] = data[zw + nx];
t[k].v[1] = data[nzw + x];
t[k].v[2] = data[nzw + nx];
tnormal(&t[k]);++k;
}
}
}
free(data);
return new_surface(t, n, 0, 1);
free(data);
return new_surface(t, n, 0, 1);
}

View file

@ -3,7 +3,7 @@
* principalement que du cas du triangle.
*
* CE CODE A EU COMME POINT DE DÉPART CE QUI A É FAIT
* EN COURS, IL EST COMPLÉTÉ PAR L'ENSEIGNANT POUR ÊTRE
* EN COURS, IL EST COMPLÉTÉ PAR L'ENSEIGNANT POUR ÊTRE
* FONCTIONNEL MAIS IL DES CHOSES À AMÉLIORER.
*
* \author Farès BELHADJ, amsi@up8.edu
@ -33,7 +33,7 @@ static inline GLubyte red(GLuint c);
static inline GLubyte green(GLuint c);
static inline GLubyte blue(GLuint c);
static inline GLubyte alpha(GLuint c);
static void pquit(void);
static void pquit(void);
/*!\brief la texture courante à utiliser en cas de mapping de texture */
static GLuint * _tex = NULL;
@ -53,71 +53,72 @@ static int _perpective_correction = 0;
/*!\brief transforme et rastérise l'ensemble des triangles de la
* surface. */
void transform_n_rasterize(surface_t * s, float * model_view_matrix, float * projection_matrix) {
int i;
/* la première fois allouer le depth buffer */
if(_depth == NULL) {
_depth = calloc(gl4dpGetWidth() * gl4dpGetHeight(), sizeof *_depth);
assert(_depth);
atexit(pquit);
}
/* si projection_matrix[15] est à 1, c'est une projection orthogonale, pas
* besoin de correction de perspective */
_perpective_correction = projection_matrix[15] == 1.0f ? 0 : 1;
/* le viewport est fixe ; \todo peut devenir paramétrable ... */
float viewport[] = { 0.0f, 0.0f, (float)gl4dpGetWidth(), (float)gl4dpGetHeight() };
stransform(s, model_view_matrix, projection_matrix, viewport);
/* mettre en place la texture qui sera utilisée pour mapper la surface */
if(s->options & SO_USE_TEXTURE)
set_texture(s->tex_id);
for(i = 0; i < s->n; ++i) {
/* si le triangle est déclaré CULL (par exemple en backface), le rejeter */
if(s->t[i].state & PS_CULL ) continue;
/* on rejette aussi les triangles complètement out */
if(s->t[i].state & PS_TOTALLY_OUT) continue;
/* "hack" pas terrible permettant de rejeter les triangles
* partiellement out dont au moins un sommet est TOO_FAR (trop
* éloigné). Voir le fichier transformations.c pour voir comment
* améliorer ce traitement. */
if( s->t[i].state & PS_PARTIALLY_OUT &&
( (s->t[i].v[0].state & PS_TOO_FAR) ||
(s->t[i].v[1].state & PS_TOO_FAR) ||
(s->t[i].v[2].state & PS_TOO_FAR) ) )
continue;
fill_triangle(s, &(s->t[i]));
}
int i;
/* la première fois allouer le depth buffer */
if(_depth == NULL) {
_depth = calloc(gl4dpGetWidth() * gl4dpGetHeight(), sizeof *_depth);
assert(_depth);
atexit(pquit);
}
/* si projection_matrix[15] est à 1, c'est une projection orthogonale, pas
* besoin de correction de perspective */
_perpective_correction = projection_matrix[15] == 1.0f ? 0 : 1;
/* le viewport est fixe ; \todo peut devenir paramétrable ... */
float viewport[] = { 0.0f, 0.0f, (float)gl4dpGetWidth(), (float)gl4dpGetHeight() };
stransform(s, model_view_matrix, projection_matrix, viewport);
/* mettre en place la texture qui sera utilisée pour mapper la surface */
if(s->options & SO_USE_TEXTURE)
set_texture(s->tex_id);
for(i = 0; i < s->n; ++i) {
/* si le triangle est déclaré CULL (par exemple en backface), le rejeter */
if(s->t[i].state & PS_CULL ) continue;
/* on rejette aussi les triangles complètement out */
if(s->t[i].state & PS_TOTALLY_OUT) continue;
/* "hack" pas terrible permettant de rejeter les triangles
* partiellement out dont au moins un sommet est TOO_FAR (trop
* éloigné). Voir le fichier transformations.c pour voir comment
* améliorer ce traitement. */
if( s->t[i].state & PS_PARTIALLY_OUT &&
( (s->t[i].v[0].state & PS_TOO_FAR) ||
(s->t[i].v[1].state & PS_TOO_FAR) ||
(s->t[i].v[2].state & PS_TOO_FAR) )
)
continue;
fill_triangle(s, &(s->t[i]));
}
}
/*!\brief effacer le buffer de profondeur (à chaque frame) pour
* réaliser le z-test */
void clear_depth_map(void) {
if(_depth) {
memset(_depth, 0, gl4dpGetWidth() * gl4dpGetHeight() * sizeof *_depth);
}
if(_depth) {
memset(_depth, 0, gl4dpGetWidth() * gl4dpGetHeight() * sizeof *_depth);
}
}
/*!\brief met en place une texture pour être mappée sur la surface en cours */
void set_texture(GLuint screen) {
GLuint old_id = gl4dpGetTextureId(); /* au cas où */
gl4dpSetScreen(screen);
_tex = gl4dpGetPixels();
_texW = gl4dpGetWidth();
_texH = gl4dpGetHeight();
if(old_id)
gl4dpSetScreen(old_id);
GLuint old_id = gl4dpGetTextureId(); /* au cas où */
gl4dpSetScreen(screen);
_tex = gl4dpGetPixels();
_texW = gl4dpGetWidth();
_texH = gl4dpGetHeight();
if(old_id)
gl4dpSetScreen(old_id);
}
/*!\brief met à jour la fonction d'interpolation et de coloriage
* (shadingfunc) de la surface en fonction de ses options */
void updatesfuncs(surface_t * s) {
int t;
if(s->options & SO_USE_TEXTURE) {
s->interpolatefunc = (t = s->options & SO_COLOR_MATERIAL) ? metainterpolate_all : metainterpolate_only_tex;
s->shadingfunc = (s->options & SO_USE_COLOR) ? (t ? shading_all_CM : shading_all) : shading_only_tex;
} else {
s->interpolatefunc = (t = s->options & SO_COLOR_MATERIAL) ? metainterpolate_only_color : metainterpolate_none;
s->shadingfunc = (s->options & SO_USE_COLOR) ? (t ? shading_only_color_CM : shading_only_color) : shading_none;;
}
int t;
if(s->options & SO_USE_TEXTURE) {
s->interpolatefunc = (t = s->options & SO_COLOR_MATERIAL) ? metainterpolate_all : metainterpolate_only_tex;
s->shadingfunc = (s->options & SO_USE_COLOR) ? (t ? shading_all_CM : shading_all) : shading_only_tex;
} else {
s->interpolatefunc = (t = s->options & SO_COLOR_MATERIAL) ? metainterpolate_only_color : metainterpolate_none;
s->shadingfunc = (s->options & SO_USE_COLOR) ? (t ? shading_only_color_CM : shading_only_color) : shading_none;;
}
}
/*!\brief fonction principale de ce fichier, elle dessine un triangle
@ -125,331 +126,331 @@ void updatesfuncs(surface_t * s) {
* (interpolations bilinaires des attributs du sommet).
*/
inline void fill_triangle(surface_t * s, triangle_t * t) {
vertex_t * aG = NULL, * aD = NULL;
int bas, median, haut, n, signe, i, h = gl4dpGetHeight();
if(t->v[0].y < t->v[1].y) {
if(t->v[0].y < t->v[2].y) {
bas = 0;
if(t->v[1].y < t->v[2].y) {
median = 1;
haut = 2;
} else {
median = 2;
haut = 1;
}
} else {
bas = 2;
median = 0;
haut = 1;
vertex_t * aG = NULL, * aD = NULL;
int bas, median, haut, n, signe, i, h = gl4dpGetHeight();
if(t->v[0].y < t->v[1].y) {
if(t->v[0].y < t->v[2].y) {
bas = 0;
if(t->v[1].y < t->v[2].y) {
median = 1;
haut = 2;
} else {
median = 2;
haut = 1;
}
} else {
bas = 2;
median = 0;
haut = 1;
}
} else { /* p0 au dessus de p1 */
if(t->v[1].y < t->v[2].y) {
bas = 1;
if(t->v[0].y < t->v[2].y) {
median = 0;
haut = 2;
} else {
median = 2;
haut = 0;
}
} else {
bas = 2;
median = 1;
haut = 0;
}
}
} else { /* p0 au dessus de p1 */
if(t->v[1].y < t->v[2].y) {
bas = 1;
if(t->v[0].y < t->v[2].y) {
median = 0;
haut = 2;
} else {
median = 2;
haut = 0;
}
n = t->v[haut].y - t->v[bas].y + 1;
aG = malloc(n * sizeof *aG);
assert(aG);
aD = malloc(n * sizeof *aD);
assert(aD);
/* est-ce que Pm est à gauche (+) ou à droite (-) de la droite (Pb->Ph) ? */
/* idée TODO?, un produit vectoriel pourrait s'avérer mieux */
if(t->v[haut].x == t->v[bas].x || t->v[haut].y == t->v[bas].y) {
/* eq de la droite x = t->v[haut].x; ou y = t->v[haut].y; */
signe = (t->v[median].x > t->v[haut].x) ? -1 : 1;
} else {
bas = 2;
median = 1;
haut = 0;
/* eq ax + y + c = 0 */
float a, c, x;
a = (t->v[haut].y - t->v[bas].y) / (float)(t->v[bas].x - t->v[haut].x);
c = -a * t->v[haut].x - t->v[haut].y;
/* on trouve le x sur la droite au même y que le median et on compare */
x = -(c + t->v[median].y) / a;
signe = (t->v[median].x >= x) ? -1 : 1;
}
}
n = t->v[haut].y - t->v[bas].y + 1;
aG = malloc(n * sizeof *aG);
assert(aG);
aD = malloc(n * sizeof *aD);
assert(aD);
/* est-ce que Pm est à gauche (+) ou à droite (-) de la droite (Pb->Ph) ? */
/* idée TODO?, un produit vectoriel pourrait s'avérer mieux */
if(t->v[haut].x == t->v[bas].x || t->v[haut].y == t->v[bas].y) {
/* eq de la droite x = t->v[haut].x; ou y = t->v[haut].y; */
signe = (t->v[median].x > t->v[haut].x) ? -1 : 1;
} else {
/* eq ax + y + c = 0 */
float a, c, x;
a = (t->v[haut].y - t->v[bas].y) / (float)(t->v[bas].x - t->v[haut].x);
c = -a * t->v[haut].x - t->v[haut].y;
/* on trouve le x sur la droite au même y que le median et on compare */
x = -(c + t->v[median].y) / a;
signe = (t->v[median].x >= x) ? -1 : 1;
}
if(signe < 0) { /* aG reçoit Ph->Pb, et aD reçoit Ph->Pm puis Pm vers Pb */
abscisses(s, &(t->v[haut]), &(t->v[bas]), aG, 1);
abscisses(s, &(t->v[haut]), &(t->v[median]), aD, 1);
abscisses(s, &(t->v[median]), &(t->v[bas]), &aD[t->v[haut].y - t->v[median].y], 0);
} else { /* aG reçoit Ph->Pm puis Pm vers Pb, et aD reçoit Ph->Pb */
abscisses(s, &(t->v[haut]), &(t->v[bas]), aD, 1);
abscisses(s, &(t->v[haut]), &(t->v[median]), aG, 1);
abscisses(s, &(t->v[median]), &(t->v[bas]), &aG[t->v[haut].y - t->v[median].y], 0);
}
for(i = 0; i < n; ++i) {
if( aG[i].y >= 0 && aG[i].y < h &&
( (aG[i].z >= 0 && aG[i].z <= 1) || (aD[i].z >= 0 && aD[i].z <= 1) ) )
horizontal_line(s, &aG[i], &aD[i]);
}
free(aG);
free(aD);
if(signe < 0) { /* aG reçoit Ph->Pb, et aD reçoit Ph->Pm puis Pm vers Pb */
abscisses(s, &(t->v[haut]), &(t->v[bas]), aG, 1);
abscisses(s, &(t->v[haut]), &(t->v[median]), aD, 1);
abscisses(s, &(t->v[median]), &(t->v[bas]), &aD[t->v[haut].y - t->v[median].y], 0);
} else { /* aG reçoit Ph->Pm puis Pm vers Pb, et aD reçoit Ph->Pb */
abscisses(s, &(t->v[haut]), &(t->v[bas]), aD, 1);
abscisses(s, &(t->v[haut]), &(t->v[median]), aG, 1);
abscisses(s, &(t->v[median]), &(t->v[bas]), &aG[t->v[haut].y - t->v[median].y], 0);
}
for(i = 0; i < n; ++i) {
if( aG[i].y >= 0 && aG[i].y < h &&
( (aG[i].z >= 0 && aG[i].z <= 1) || (aD[i].z >= 0 && aD[i].z <= 1) ) )
horizontal_line(s, &aG[i], &aD[i]);
}
free(aG);
free(aD);
}
/*!\brief utilise Br'65 pour determiner les abscisses des segments du
* triangle à remplir (par \a horizontal_line).
*/
inline void abscisses(surface_t * s, vertex_t * p0, vertex_t * p1, vertex_t * absc, int replace) {
int u = p1->x - p0->x, v = p1->y - p0->y, pasX = u < 0 ? -1 : 1, pasY = v < 0 ? -1 : 1;
float dmax = sqrtf(u * u + v * v), p;
u = abs(u); v = abs(v);
if(u > v) { // 1er octan
if(replace) {
int objX = (u + 1) * pasX;
int delta = u - 2 * v, incH = -2 * v, incO = 2 * u - 2 * v;
for (int x = 0, y = 0, k = 0; x != objX; x += pasX) {
absc[k].x = x + p0->x;
absc[k].y = y + p0->y;
p = sqrtf(x * x + y * y) / dmax;
s->interpolatefunc(&absc[k], p0, p1, 1.0f - p, p);
if(delta < 0) {
++k;
y += pasY;
delta += incO;
} else
delta += incH;
}
} else {
int objX = (u + 1) * pasX;
int delta = u - 2 * v, incH = -2 * v, incO = 2 * u - 2 * v;
for (int x = 0, y = 0, k = 0, done = 0; x != objX; x += pasX) {
if(!done) {
absc[k].x = x + p0->x;
absc[k].y = y + p0->y;
p = sqrtf(x * x + y * y) / dmax;
s->interpolatefunc(&absc[k], p0, p1, 1.0f - p, p);
done = 1;
}
if(delta < 0) {
++k;
done = 0;
y += pasY;
delta += incO;
} else
delta += incH;
}
int u = p1->x - p0->x, v = p1->y - p0->y, pasX = u < 0 ? -1 : 1, pasY = v < 0 ? -1 : 1;
float dmax = sqrtf(u * u + v * v), p;
u = abs(u); v = abs(v);
if(u > v) { // 1er octan
if(replace) {
int objX = (u + 1) * pasX;
int delta = u - 2 * v, incH = -2 * v, incO = 2 * u - 2 * v;
for (int x = 0, y = 0, k = 0; x != objX; x += pasX) {
absc[k].x = x + p0->x;
absc[k].y = y + p0->y;
p = sqrtf(x * x + y * y) / dmax;
s->interpolatefunc(&absc[k], p0, p1, 1.0f - p, p);
if(delta < 0) {
++k;
y += pasY;
delta += incO;
} else
delta += incH;
}
} else {
int objX = (u + 1) * pasX;
int delta = u - 2 * v, incH = -2 * v, incO = 2 * u - 2 * v;
for (int x = 0, y = 0, k = 0, done = 0; x != objX; x += pasX) {
if(!done) {
absc[k].x = x + p0->x;
absc[k].y = y + p0->y;
p = sqrtf(x * x + y * y) / dmax;
s->interpolatefunc(&absc[k], p0, p1, 1.0f - p, p);
done = 1;
}
if(delta < 0) {
++k;
done = 0;
y += pasY;
delta += incO;
} else
delta += incH;
}
}
} else { // 2eme octan
int objY = (v + 1) * pasY;
int delta = v - 2 * u, incH = -2 * u, incO = 2 * v - 2 * u;
for (int x = 0, y = 0, k = 0; y != objY; y += pasY) {
absc[k].x = x + p0->x;
absc[k].y = y + p0->y;
p = sqrtf(x * x + y * y) / dmax;
s->interpolatefunc(&absc[k], p0, p1, 1.0f - p, p);
++k;
if(delta < 0) {
x += pasX;
delta += incO;
} else
delta += incH;
}
}
} else { // 2eme octan
int objY = (v + 1) * pasY;
int delta = v - 2 * u, incH = -2 * u, incO = 2 * v - 2 * u;
for (int x = 0, y = 0, k = 0; y != objY; y += pasY) {
absc[k].x = x + p0->x;
absc[k].y = y + p0->y;
p = sqrtf(x * x + y * y) / dmax;
s->interpolatefunc(&absc[k], p0, p1, 1.0f - p, p);
++k;
if(delta < 0) {
x += pasX;
delta += incO;
} else
delta += incH;
}
}
}
/*!\brief remplissage par droite horizontale entre deux abscisses */
inline void horizontal_line(surface_t * s, vertex_t * vG, vertex_t * vD) {
int w = gl4dpGetWidth(), x, yw = vG->y * w;
GLuint * image = gl4dpGetPixels();
float dmax = vD->x - vG->x, p, deltap;
vertex_t v;
/* il reste d'autres optims possibles */
for(x = vG->x, p = 0.0f, deltap = 1.0f / dmax; x <= vD->x; ++x, p += deltap)
if(x >= 0 && x < w) {
s->interpolatefunc(&v, vG, vD, 1.0f - p, p);
if(v.z < 0 || v.z > 1 || v.z < _depth[yw + x]) { continue; }
s->shadingfunc(s, &image[yw + x], &v);
_depth[yw + x] = v.z;
}
int w = gl4dpGetWidth(), x, yw = vG->y * w;
GLuint * image = gl4dpGetPixels();
float dmax = vD->x - vG->x, p, deltap;
vertex_t v;
/* il reste d'autres optims possibles */
for(x = vG->x, p = 0.0f, deltap = 1.0f / dmax; x <= vD->x; ++x, p += deltap)
if(x >= 0 && x < w) {
s->interpolatefunc(&v, vG, vD, 1.0f - p, p);
if(v.z < 0 || v.z > 1 || v.z < _depth[yw + x]) { continue; }
s->shadingfunc(s, &image[yw + x], &v);
_depth[yw + x] = v.z;
}
}
/*!\brief aucune couleur n'est inscrite */
inline void shading_none(surface_t * s, GLuint * pcolor, vertex_t * v) {
//vide pour l'instant, à prévoir le z-buffer
//vide pour l'instant, à prévoir le z-buffer
}
/*!\brief la couleur du pixel est tirée uniquement de la texture */
inline void shading_only_tex(surface_t * s, GLuint * pcolor, vertex_t * v) {
int xt, yt, ct;
GLubyte r, g, b, a;
xt = (int)(v->texCoord.x * (_texW - EPSILON));
if(xt < 0) {
xt = xt % (-_texW);
while(xt < 0) xt += _texW;
} else
xt = xt % _texW;
yt = (int)(v->texCoord.y * (_texH - EPSILON));
if(yt < 0) {
yt = yt % (-_texH);
while(yt < 0) yt += _texH;
} else
yt = yt % _texH;
ct = yt * _texW + xt;
*pcolor = _tex[yt * _texW + xt];
r = (GLubyte)( red(_tex[ct]) * v->li);
g = (GLubyte)(green(_tex[ct]) * v->li);
b = (GLubyte)( blue(_tex[ct]) * v->li);
a = (GLubyte) alpha(_tex[ct]);
*pcolor = rgba(r, g, b, a);
int xt, yt, ct;
GLubyte r, g, b, a;
xt = (int)(v->texCoord.x * (_texW - EPSILON));
if(xt < 0) {
xt = xt % (-_texW);
while(xt < 0) xt += _texW;
} else
xt = xt % _texW;
yt = (int)(v->texCoord.y * (_texH - EPSILON));
if(yt < 0) {
yt = yt % (-_texH);
while(yt < 0) yt += _texH;
} else
yt = yt % _texH;
ct = yt * _texW + xt;
*pcolor = _tex[yt * _texW + xt];
r = (GLubyte)( red(_tex[ct]) * v->li);
g = (GLubyte)(green(_tex[ct]) * v->li);
b = (GLubyte)( blue(_tex[ct]) * v->li);
a = (GLubyte) alpha(_tex[ct]);
*pcolor = rgba(r, g, b, a);
}
/*!\brief la couleur du pixel est tirée de la couleur interpolée */
inline void shading_only_color_CM(surface_t * s, GLuint * pcolor, vertex_t * v) {
GLubyte r, g, b, a;
r = (GLubyte)(v->li * v->icolor.x * (255 + EPSILON));
g = (GLubyte)(v->li * v->icolor.y * (255 + EPSILON));
b = (GLubyte)(v->li * v->icolor.z * (255 + EPSILON));
a = (GLubyte)(v->icolor.w * (255 + EPSILON));
*pcolor = rgba(r, g, b, a);
GLubyte r, g, b, a;
r = (GLubyte)(v->li * v->icolor.x * (255 + EPSILON));
g = (GLubyte)(v->li * v->icolor.y * (255 + EPSILON));
b = (GLubyte)(v->li * v->icolor.z * (255 + EPSILON));
a = (GLubyte)(v->icolor.w * (255 + EPSILON));
*pcolor = rgba(r, g, b, a);
}
/*!\brief la couleur du pixel est tirée de la couleur diffuse de la
* surface */
inline void shading_only_color(surface_t * s, GLuint * pcolor, vertex_t * v) {
GLubyte r, g, b, a;
r = (GLubyte)(v->li * s->dcolor.x * (255 + EPSILON));
g = (GLubyte)(v->li * s->dcolor.y * (255 + EPSILON));
b = (GLubyte)(v->li * s->dcolor.z * (255 + EPSILON));
a = (GLubyte)(s->dcolor.w * (255 + EPSILON));
*pcolor = rgba(r, g, b, a);
GLubyte r, g, b, a;
r = (GLubyte)(v->li * s->dcolor.x * (255 + EPSILON));
g = (GLubyte)(v->li * s->dcolor.y * (255 + EPSILON));
b = (GLubyte)(v->li * s->dcolor.z * (255 + EPSILON));
a = (GLubyte)(s->dcolor.w * (255 + EPSILON));
*pcolor = rgba(r, g, b, a);
}
/*!\brief la couleur du pixel est le produit de la couleur interpolée
* et de la texture */
inline void shading_all_CM(surface_t * s, GLuint * pcolor, vertex_t * v) {
GLubyte r, g, b, a;
int xt, yt, ct;
xt = (int)(v->texCoord.x * (_texW - EPSILON));
if(xt < 0) {
xt = xt % (-_texW);
while(xt < 0) xt += _texW;
} else
xt = xt % _texW;
yt = (int)(v->texCoord.y * (_texH - EPSILON));
if(yt < 0) {
yt = yt % (-_texH);
while(yt < 0) yt += _texH;
} else
yt = yt % _texH;
ct = yt * _texW + xt;
r = (GLubyte)(( red(_tex[ct]) + EPSILON) * v->li * v->icolor.x);
g = (GLubyte)((green(_tex[ct]) + EPSILON) * v->li * v->icolor.y);
b = (GLubyte)(( blue(_tex[ct]) + EPSILON) * v->li * v->icolor.z);
a = (GLubyte)((alpha(_tex[ct]) + EPSILON) * v->icolor.w);
*pcolor = rgba(r, g, b, a);
GLubyte r, g, b, a;
int xt, yt, ct;
xt = (int)(v->texCoord.x * (_texW - EPSILON));
if(xt < 0) {
xt = xt % (-_texW);
while(xt < 0) xt += _texW;
} else
xt = xt % _texW;
yt = (int)(v->texCoord.y * (_texH - EPSILON));
if(yt < 0) {
yt = yt % (-_texH);
while(yt < 0) yt += _texH;
} else
yt = yt % _texH;
ct = yt * _texW + xt;
r = (GLubyte)(( red(_tex[ct]) + EPSILON) * v->li * v->icolor.x);
g = (GLubyte)((green(_tex[ct]) + EPSILON) * v->li * v->icolor.y);
b = (GLubyte)(( blue(_tex[ct]) + EPSILON) * v->li * v->icolor.z);
a = (GLubyte)((alpha(_tex[ct]) + EPSILON) * v->icolor.w);
*pcolor = rgba(r, g, b, a);
}
/*!\brief la couleur du pixel est le produit de la couleur diffuse
* de la surface et de la texture */
inline void shading_all(surface_t * s, GLuint * pcolor, vertex_t * v) {
GLubyte r, g, b, a;
int xt, yt, ct;
xt = (int)(v->texCoord.x * (_texW - EPSILON));
if(xt < 0) {
xt = xt % (-_texW);
while(xt < 0) xt += _texW;
} else
xt = xt % _texW;
yt = (int)(v->texCoord.y * (_texH - EPSILON));
if(yt < 0) {
yt = yt % (-_texH);
while(yt < 0) yt += _texH;
} else
yt = yt % _texH;
ct = yt * _texW + xt;
r = (GLubyte)(( red(_tex[ct]) + EPSILON) * v->li * s->dcolor.x);
g = (GLubyte)((green(_tex[ct]) + EPSILON) * v->li * s->dcolor.y);
b = (GLubyte)(( blue(_tex[ct]) + EPSILON) * v->li * s->dcolor.z);
a = (GLubyte)((alpha(_tex[ct]) + EPSILON) * s->dcolor.w);
*pcolor = rgba(r, g, b, a);
GLubyte r, g, b, a;
int xt, yt, ct;
xt = (int)(v->texCoord.x * (_texW - EPSILON));
if(xt < 0) {
xt = xt % (-_texW);
while(xt < 0) xt += _texW;
} else
xt = xt % _texW;
yt = (int)(v->texCoord.y * (_texH - EPSILON));
if(yt < 0) {
yt = yt % (-_texH);
while(yt < 0) yt += _texH;
} else
yt = yt % _texH;
ct = yt * _texW + xt;
r = (GLubyte)(( red(_tex[ct]) + EPSILON) * v->li * s->dcolor.x);
g = (GLubyte)((green(_tex[ct]) + EPSILON) * v->li * s->dcolor.y);
b = (GLubyte)(( blue(_tex[ct]) + EPSILON) * v->li * s->dcolor.z);
a = (GLubyte)((alpha(_tex[ct]) + EPSILON) * s->dcolor.w);
*pcolor = rgba(r, g, b, a);
}
/*!\brief interpolation de plusieurs floattants (entre \a s et \a e)
* de la structure vertex_t en utilisant \a a et \a b, les
* facteurs \a fa et \a fb, le tout dans \a r
* facteurs \a fa et \a fb, le tout dans \a r
* \todo un pointeur de fonction pour éviter un test s'il faut
* un _perpective_correction != 0 ??? */
inline void interpolate(vertex_t * r, vertex_t * a, vertex_t * b, float fa, float fb, int s, int e) {
int i;
float * pr = (float *)&(r->texCoord);
float * pa = (float *)&(a->texCoord);
float * pb = (float *)&(b->texCoord);
/* Correction de l'interpolation par rapport à la perspective, le z
* joue un rôle dans les distances, il est nécessaire de le
* réintégrer en modifiant les facteurs de proportion.
* lien utile : https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes
*/
if(_perpective_correction) {
float z = 1.0f / (fa / a->zmod + fb / b->zmod);
if(e == 8) { /* attention il faut que cet indice colle avec la position de la proriété z à partir de l'adresse texCoord */
pr[e] = fa * pa[e] + fb * pb[e];
e = 7;
int i;
float * pr = (float *)&(r->texCoord);
float * pa = (float *)&(a->texCoord);
float * pb = (float *)&(b->texCoord);
/* Correction de l'interpolation par rapport à la perspective, le z
* joue un rôle dans les distances, il est nécessaire de le
* réintégrer en modifiant les facteurs de proportion.
* lien utile : https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes
*/
if(_perpective_correction) {
float z = 1.0f / (fa / a->zmod + fb / b->zmod);
if(e == 8) { /* attention il faut que cet indice colle avec la position de la proriété z à partir de l'adresse texCoord */
pr[e] = fa * pa[e] + fb * pb[e];
e = 7;
}
fa = z * fa / a->zmod; fb = z * fb / b->zmod;
}
fa = z * fa / a->zmod; fb = z * fb / b->zmod;
}
for(i = s; i <= e; ++i)
pr[i] = fa * pa[i] + fb * pb[i];
for(i = s; i <= e; ++i)
pr[i] = fa * pa[i] + fb * pb[i];
}
/*!\brief meta-fonction pour appeler \a interpolate, demande
* uniquement l'interpolation des z */
inline void metainterpolate_none(vertex_t * r, vertex_t * a, vertex_t * b, float fa, float fb) {
interpolate(r, a, b, fa, fb, 6, 8);
interpolate(r, a, b, fa, fb, 6, 8);
}
/*!\brief meta-fonction pour appeler \a interpolate, demande
* uniquement l'interpolation des coord. de texture et les z */
inline void metainterpolate_only_tex(vertex_t * r, vertex_t * a, vertex_t * b, float fa, float fb) {
interpolate(r, a, b, fa, fb, 0, 1);
interpolate(r, a, b, fa, fb, 6, 8);
interpolate(r, a, b, fa, fb, 0, 1);
interpolate(r, a, b, fa, fb, 6, 8);
}
/*!\brief meta-fonction pour appeler \a interpolate, demande
* uniquement l'interpolation des couleurs et les z */
inline void metainterpolate_only_color(vertex_t * r, vertex_t * a, vertex_t * b, float fa, float fb) {
interpolate(r, a, b, fa, fb, 2, 8);
interpolate(r, a, b, fa, fb, 2, 8);
}
/*!\brief meta-fonction pour appeler \a interpolate, demande
* l'interpolation de l'ensemble des attributs */
inline void metainterpolate_all(vertex_t * r, vertex_t * a, vertex_t * b, float fa, float fb) {
interpolate(r, a, b, fa, fb, 0, 8);
interpolate(r, a, b, fa, fb, 0, 8);
}
GLuint rgba(GLubyte r, GLubyte g, GLubyte b, GLubyte a) {
return RGBA(r, g, b, a);
return RGBA(r, g, b, a);
}
GLubyte red(GLuint c) {
return RED(c);
return RED(c);
}
GLubyte green(GLuint c) {
return GREEN(c);
return GREEN(c);
}
GLubyte blue(GLuint c) {
return BLUE(c);
return BLUE(c);
}
GLubyte alpha(GLuint c) {
return ALPHA(c);
return ALPHA(c);
}
/*!\brief au moment de quitter le programme désallouer la mémoire
* utilisée pour _depth */
void pquit(void) {
if(_depth) {
free(_depth);
_depth = NULL;
}
if(_depth) {
free(_depth);
_depth = NULL;
}
}

View file

@ -1,10 +1,10 @@
/*!\file rasterize.h
/*!\file rasterize.h
*
* \brief structures de données et protos de fonctions externes pour
* réaliser un moteur de rendu DIY par rastérisation.
*
* \author Farès BELHADJ, amsi@up8.edu
* \date November 17, 2021.
* \date November 17, 2021.
*/
#ifndef RASTERIZE_H_SEEN
@ -19,72 +19,72 @@
# ifdef __cplusplus
extern "C" {
# endif
typedef enum pstate_t pstate_t;
typedef enum soptions_t soptions_t;
typedef struct vec4 vec4;
typedef struct vec3 vec3;
typedef struct vec2 vec2;
typedef struct vertex_t vertex_t;
typedef struct triangle_t triangle_t;
typedef struct surface_t surface_t;
/*!\brief états pour les sommets ou les triangles */
enum pstate_t {
PS_NONE = 0,
PS_TOTALLY_OUT = 1,
PS_PARTIALLY_OUT = 2,
PS_CULL = 4, /* si en BACKFACE et que
SO_CULL_BACKFACES est actif */
PS_TOO_FAR = 8,
PS_OUT_LEFT = 16,
PS_OUT_RIGHT = 32,
PS_OUT_BOTTOM = 64,
PS_OUT_TOP = 128,
PS_OUT_NEAR = 256,
PS_OUT_FAR = 512
};
typedef enum pstate_t pstate_t;
typedef enum soptions_t soptions_t;
typedef struct vec4 vec4;
typedef struct vec3 vec3;
typedef struct vec2 vec2;
typedef struct vertex_t vertex_t;
typedef struct triangle_t triangle_t;
typedef struct surface_t surface_t;
/*!\brief options pour les surfaces */
enum soptions_t {
SO_NONE = 0, /* la surface n'a pas de rendu
"couleur" */
SO_USE_TEXTURE = 1, /* utiliser la texture pour
colorer (multiplication si
SO_USE_COLOR est actif) */
SO_USE_COLOR = 2, /* utiliser la couleur de la
surface ou des sommets pour
colorer (multiplication si
SO_USE_TEXTURE est actif) */
SO_COLOR_MATERIAL = 4, /* utiliser la couleur aux
sommets si actif
(nécessite aussi
l'activation de
SO_USE_COLOR) */
SO_CULL_BACKFACES = 8, /* active le fait de cacher
les faces arrières */
SO_USE_LIGHTING = 16, /* active le calcul d'ombre
propre (Gouraud sur
diffus) */
SO_DEFAULT = SO_CULL_BACKFACES | SO_USE_COLOR /* comportement
par
défaut */
};
/*!\brief états pour les sommets ou les triangles */
enum pstate_t {
PS_NONE = 0,
PS_TOTALLY_OUT = 1,
PS_PARTIALLY_OUT = 2,
PS_CULL = 4, /* si en BACKFACE et que
SO_CULL_BACKFACES est actif */
PS_TOO_FAR = 8,
PS_OUT_LEFT = 16,
PS_OUT_RIGHT = 32,
PS_OUT_BOTTOM = 64,
PS_OUT_TOP = 128,
PS_OUT_NEAR = 256,
PS_OUT_FAR = 512
};
struct vec4 {
/*!\brief options pour les surfaces */
enum soptions_t {
SO_NONE = 0, /* la surface n'a pas de rendu
"couleur" */
SO_USE_TEXTURE = 1, /* utiliser la texture pour
colorer (multiplication si
SO_USE_COLOR est actif) */
SO_USE_COLOR = 2, /* utiliser la couleur de la
surface ou des sommets pour
colorer (multiplication si
SO_USE_TEXTURE est actif) */
SO_COLOR_MATERIAL = 4, /* utiliser la couleur aux
sommets si actif
(nécessite aussi
l'activation de
SO_USE_COLOR) */
SO_CULL_BACKFACES = 8, /* active le fait de cacher
les faces arrières */
SO_USE_LIGHTING = 16, /* active le calcul d'ombre
propre (Gouraud sur
diffus) */
SO_DEFAULT = SO_CULL_BACKFACES | SO_USE_COLOR /* comportement
par
défaut */
};
struct vec4 {
float x /* r */, y/* g */, z /* b */, w /* a */;
};
};
struct vec2 {
float x /* s */, y /* t */;
};
struct vec2 {
float x /* s */, y /* t */;
};
struct vec3 {
struct vec3 {
float x /* r */, y/* g */, z/* b */;
};
};
/*!\brief le sommet et l'ensemble de ses attributs */
struct vertex_t {
/*!\brief le sommet et l'ensemble de ses attributs */
struct vertex_t {
vec4 position;
vec4 color0;
/* début des données à partir desquelles on peut interpoler en masse */
@ -92,68 +92,68 @@ extern "C" {
vec4 icolor; /* couleur à interpoler */
float li; /* intensité de lumière (lambertien) */
float zmod; /* z après modelview, sert à corriger
l'interpolation par rapport à une projection en
perspective */
l'interpolation par rapport à une projection en
perspective */
float z; /* ce z représente la depth */
/* fin des données à partir desquelles on peut interpoler */
vec3 normal; /* interpolez les normales si vous implémentez Phong */
int x, y;
enum pstate_t state;
};
};
/*!\brief le triangle */
struct triangle_t {
/*!\brief le triangle */
struct triangle_t {
vertex_t v[3];
vec3 normal;
vec3 normal;
enum pstate_t state;
};
};
/*!\brief la surface englobe plusieurs triangles et des options
* telles que le type de rendu, la couleur diffuse ou la texture.
*/
struct surface_t {
/*!\brief la surface englobe plusieurs triangles et des options
* telles que le type de rendu, la couleur diffuse ou la texture.
*/
struct surface_t {
int n;
triangle_t * t;
GLuint tex_id;
vec4 dcolor; /* couleur diffuse, ajoutez une couleur ambiante et
spéculaire si vous souhaitez compléter le
modèle */
spéculaire si vous souhaitez compléter le
modèle */
soptions_t options; /* paramétrage du rendu de la surface */
void (*interpolatefunc)(vertex_t *, vertex_t *, vertex_t *, float, float);
void (*shadingfunc)(surface_t *, GLuint *, vertex_t *);
};
/* dans rasterize.c */
extern void transform_n_rasterize(surface_t * s, float * model_view_matrix, float * projection_matrix);
extern void clear_depth_map(void);
extern void set_texture(GLuint screen);
extern void updatesfuncs(surface_t * s);
};
/* dans vtranform.c */
extern vertex_t vtransform(surface_t * s, vertex_t v, float * model_view_matrix, float * ti_model_view_matrix, float * projection_matrix, float * viewport);
extern void stransform(surface_t * s, float * model_view_matrix, float * projection_matrix, float * viewport);
extern void mult_matrix(float * res, float * m);
extern void translate(float * m, float tx, float ty, float tz);
extern void rotate(float * m, float angle, float x, float y, float z);
extern void scale(float * m, float sx, float sy, float sz);
extern void lookAt(float * m, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ);
/* dans surface.c */
extern void tnormal(triangle_t * t);
extern void snormals(surface_t * s);
extern void tnormals2vertices(surface_t * s);
extern void set_texture_id(surface_t * s, GLuint tex_id);
extern void set_diffuse_color(surface_t * s, vec4 dcolor);
extern void enable_surface_option(surface_t * s, soptions_t option);
extern void disable_surface_option(surface_t * s, soptions_t option);
extern surface_t * new_surface(triangle_t * t, int n, int duplicateTriangles, int hasNormals);
extern void free_surface(surface_t * s);
extern GLuint get_texture_from_BMP(const char * filename);
/* dans rasterize.c */
extern void transform_n_rasterize(surface_t * s, float * model_view_matrix, float * projection_matrix);
extern void clear_depth_map(void);
extern void set_texture(GLuint screen);
extern void updatesfuncs(surface_t * s);
/* dans geometry.c */
extern surface_t * mk_quad(void);
extern surface_t * mk_cube(void);
extern surface_t * mk_sphere(int longitudes, int latitudes);
/* dans vtranform.c */
extern vertex_t vtransform(surface_t * s, vertex_t v, float * model_view_matrix, float * ti_model_view_matrix, float * projection_matrix, float * viewport);
extern void stransform(surface_t * s, float * model_view_matrix, float * projection_matrix, float * viewport);
extern void mult_matrix(float * res, float * m);
extern void translate(float * m, float tx, float ty, float tz);
extern void rotate(float * m, float angle, float x, float y, float z);
extern void scale(float * m, float sx, float sy, float sz);
extern void lookAt(float * m, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ);
/* dans surface.c */
extern void tnormal(triangle_t * t);
extern void snormals(surface_t * s);
extern void tnormals2vertices(surface_t * s);
extern void set_texture_id(surface_t * s, GLuint tex_id);
extern void set_diffuse_color(surface_t * s, vec4 dcolor);
extern void enable_surface_option(surface_t * s, soptions_t option);
extern void disable_surface_option(surface_t * s, soptions_t option);
extern surface_t * new_surface(triangle_t * t, int n, int duplicateTriangles, int hasNormals);
extern void free_surface(surface_t * s);
extern GLuint get_texture_from_BMP(const char * filename);
/* dans geometry.c */
extern surface_t * mk_quad(void);
extern surface_t * mk_cube(void);
extern surface_t * mk_sphere(int longitudes, int latitudes);
# ifdef __cplusplus
}
# endif

122
surface.c
View file

@ -13,14 +13,14 @@
/*!\brief calcule le vecteur normal à un triangle */
void tnormal(triangle_t * t) {
vec3 u = {
t->v[1].position.x - t->v[0].position.x,
t->v[1].position.y - t->v[0].position.y,
t->v[1].position.z - t->v[0].position.z
t->v[1].position.x - t->v[0].position.x,
t->v[1].position.y - t->v[0].position.y,
t->v[1].position.z - t->v[0].position.z
};
vec3 v = {
t->v[2].position.x - t->v[0].position.x,
t->v[2].position.y - t->v[0].position.y,
t->v[2].position.z - t->v[0].position.z
t->v[2].position.x - t->v[0].position.x,
t->v[2].position.y - t->v[0].position.y,
t->v[2].position.z - t->v[0].position.z
};
MVEC3CROSS((float *)&(t->normal), (float *)&u, (float *)&v);
MVEC3NORMALIZE((float *)&(t->normal));
@ -28,40 +28,40 @@ void tnormal(triangle_t * t) {
/*!\brief calcule les vecteurs normaux aux triangles de la surface */
void snormals(surface_t * s) {
int i;
for(i = 0; i < s->n; ++i)
tnormal(&(s->t[i]));
int i;
for(i = 0; i < s->n; ++i)
tnormal(&(s->t[i]));
}
/*!\brief affecte les normales aux triangles de la surface à ses vertices */
void tnormals2vertices(surface_t * s) {
int i;
for(i = 0; i < s->n; ++i)
s->t[i].v[0].normal = s->t[i].v[1].normal = s->t[i].v[2].normal = s->t[i].normal;
int i;
for(i = 0; i < s->n; ++i)
s->t[i].v[0].normal = s->t[i].v[1].normal = s->t[i].v[2].normal = s->t[i].normal;
}
/*!\brief affecte l'identifiant de texture de la surface */
void set_texture_id(surface_t * s, GLuint tex_id) {
s->tex_id = tex_id;
s->tex_id = tex_id;
}
/*!\brief affecte la couleur diffuse de la surface */
void set_diffuse_color(surface_t * s, vec4 dcolor) {
s->dcolor = dcolor;
s->dcolor = dcolor;
}
/*!\brief active une option de la surface */
void enable_surface_option(surface_t * s, soptions_t option) {
if(!(s->options & option))
s->options |= option;
updatesfuncs(s);
if(!(s->options & option))
s->options |= option;
updatesfuncs(s);
}
/*!\brief désactive une option de la surface */
void disable_surface_option(surface_t * s, soptions_t option) {
if(s->options & option)
s->options ^= option;
updatesfuncs(s);
if(s->options & option)
s->options ^= option;
updatesfuncs(s);
}
/*!\brief créé et renvoie une surface (allouée) à partir de \a n
@ -74,53 +74,53 @@ void disable_surface_option(surface_t * s, soptions_t option) {
* faux (0) elle force le calcul des normales par triangle et les
* affecte aux sommets. */
surface_t * new_surface(triangle_t * t, int n, int duplicate_triangles, int has_normals) {
const vec4 dcolor = { 0.42f, 0.1f, 0.1f, 1.0f };
surface_t * s = malloc(1 * sizeof *s);
assert(s);
s->n = n;
if(duplicate_triangles) {
s->t = malloc(s->n * sizeof *(s->t));
assert(s->t);
memcpy(s->t, t, s->n * sizeof *(s->t));
} else
s->t = t;
set_diffuse_color(s, dcolor);
s->options = SO_DEFAULT;
s->tex_id = 0;
updatesfuncs(s);
if(!has_normals) {
snormals(s);
tnormals2vertices(s);
}
return s;
const vec4 dcolor = { 0.42f, 0.1f, 0.1f, 1.0f };
surface_t * s = malloc(1 * sizeof *s);
assert(s);
s->n = n;
if(duplicate_triangles) {
s->t = malloc(s->n * sizeof *(s->t));
assert(s->t);
memcpy(s->t, t, s->n * sizeof *(s->t));
} else
s->t = t;
set_diffuse_color(s, dcolor);
s->options = SO_DEFAULT;
s->tex_id = 0;
updatesfuncs(s);
if(!has_normals) {
snormals(s);
tnormals2vertices(s);
}
return s;
}
/*!\brief libère la mémoire utilisée par la surface */
void free_surface(surface_t * s) {
free(s->t);
free(s);
free(s->t);
free(s);
}
/*!\brief charge et fabrique un identifiant pour une texture issue
* d'un fichier BMP */
GLuint get_texture_from_BMP(const char * filename) {
GLuint id, old_id;
/* chargement d'une image dans une surface SDL */
SDL_Surface * s = SDL_LoadBMP(filename);
assert(s);
old_id = gl4dpGetTextureId(); /* au cas où */
/* création d'un screen GL4Dummies aux dimensions de la texture */
id = gl4dpInitScreenWithDimensions(s->w, s->h);
/* copie de la surface SDL vers le screen en cours */
{
GLuint * p = gl4dpGetPixels();
SDL_Surface * d = SDL_CreateRGBSurface(0, s->w, s->h, 32, R_MASK, G_MASK, B_MASK, A_MASK);
SDL_BlitSurface(s, NULL, d, NULL);
memcpy(p, d->pixels, d->w * d->h * sizeof *p);
SDL_FreeSurface(d);
}
/* libération de la surface SDL */
SDL_FreeSurface(s);
if(old_id)
gl4dpSetScreen(old_id);
return id;
GLuint id, old_id;
/* chargement d'une image dans une surface SDL */
SDL_Surface * s = SDL_LoadBMP(filename);
assert(s);
old_id = gl4dpGetTextureId(); /* au cas où */
/* création d'un screen GL4Dummies aux dimensions de la texture */
id = gl4dpInitScreenWithDimensions(s->w, s->h);
/* copie de la surface SDL vers le screen en cours */
{
GLuint * p = gl4dpGetPixels();
SDL_Surface * d = SDL_CreateRGBSurface(0, s->w, s->h, 32, R_MASK, G_MASK, B_MASK, A_MASK);
SDL_BlitSurface(s, NULL, d, NULL);
memcpy(p, d->pixels, d->w * d->h * sizeof *p);
SDL_FreeSurface(d);
}
/* libération de la surface SDL */
SDL_FreeSurface(s);
if(old_id)
gl4dpSetScreen(old_id);
return id;
}

View file

@ -20,59 +20,59 @@ static inline void clip2_unit_cube(triangle_t * t);
matrice de model-view \a model_view_matrix et de projection \a projection_matrix. \a
ti_model_view_matrix est la transposée de l'inverse de la matrice \a model_view_matrix.*/
vertex_t vtransform(surface_t * s, vertex_t v, float * model_view_matrix, float * ti_model_view_matrix, float * projection_matrix, float * viewport) {
float dist = 1.0f;
vec4 r1, r2;
v.state = PS_NONE;
MMAT4XVEC4((float *)&r1, model_view_matrix, (float *)&(v.position));
MMAT4XVEC4((float *)&r2, projection_matrix, (float *)&r1);
r2.x /= r2.w;
r2.y /= r2.w;
r2.z /= r2.w;
r2.w = 1.0f;
/* dist doit être à 1 ci-après */
if(r2.x < -dist) v.state |= PS_OUT_LEFT;
if(r2.x > dist) v.state |= PS_OUT_RIGHT;
if(r2.y < -dist) v.state |= PS_OUT_BOTTOM;
if(r2.y > dist) v.state |= PS_OUT_TOP;
if(r2.z < -dist) v.state |= PS_OUT_NEAR;
if(r2.z > dist) v.state |= PS_OUT_FAR;
/* "hack" pas terrible permettant d'éviter les gros triangles
partiellement hors-champ. Modifier dist pour jouer sur la taille
(une fois projetés) des triangles qu'on laisse passer (plus c'est
gros plus c'est lent avec les gros triangles). La "vraie"
solution est obtenue en calculant l'intersection exacte entre le
triangle et le cube unitaire ; attention, ceci produit
potentiellement une nouvelle liste de triangles à chaque frame,
et les attributs des sommets doivent être recalculés. */
dist = 10.0f;
if(r2.x < -dist || r2.x > dist || r2.y < -dist || r2.y > dist || r2.z < -dist || r2.z > dist) {
v.state |= PS_TOO_FAR;
float dist = 1.0f;
vec4 r1, r2;
v.state = PS_NONE;
MMAT4XVEC4((float *)&r1, model_view_matrix, (float *)&(v.position));
MMAT4XVEC4((float *)&r2, projection_matrix, (float *)&r1);
r2.x /= r2.w;
r2.y /= r2.w;
r2.z /= r2.w;
r2.w = 1.0f;
/* dist doit être à 1 ci-après */
if(r2.x < -dist) v.state |= PS_OUT_LEFT;
if(r2.x > dist) v.state |= PS_OUT_RIGHT;
if(r2.y < -dist) v.state |= PS_OUT_BOTTOM;
if(r2.y > dist) v.state |= PS_OUT_TOP;
if(r2.z < -dist) v.state |= PS_OUT_NEAR;
if(r2.z > dist) v.state |= PS_OUT_FAR;
/* "hack" pas terrible permettant d'éviter les gros triangles
partiellement hors-champ. Modifier dist pour jouer sur la taille
(une fois projetés) des triangles qu'on laisse passer (plus c'est
gros plus c'est lent avec les gros triangles). La "vraie"
solution est obtenue en calculant l'intersection exacte entre le
triangle et le cube unitaire ; attention, ceci produit
potentiellement une nouvelle liste de triangles à chaque frame,
et les attributs des sommets doivent être recalculés. */
dist = 10.0f;
if(r2.x < -dist || r2.x > dist || r2.y < -dist || r2.y > dist || r2.z < -dist || r2.z > dist) {
v.state |= PS_TOO_FAR;
return v;
}
/* Gouraud */
if(s->options & SO_USE_LIGHTING) {
/* la lumière est positionnelle et fixe dans la scène. \todo dans
scene.c la rendre modifiable, voire aussi pouvoir la placer par
rapport aux objets (elle subirait la matrice modèle). */
const vec4 lp[1] = { {0.0f, 0.0f, 1.0f} };
vec4 ld = {lp[0].x - r1.x, lp[0].y - r1.y, lp[0].z - r1.z, lp[0].w - r1.w};
float n[4] = {v.normal.x, v.normal.y, v.normal.z, 0.0f}, res[4];
MMAT4XVEC4(res, ti_model_view_matrix, n);
MVEC3NORMALIZE(res);
MVEC3NORMALIZE((float *)&ld);
v.li = MVEC3DOT(res, (float *)&ld);
v.li = MIN(MAX(0.0f, v.li), 1.0f);
} else
v.li = 1.0f;
v.icolor = v.color0;
/* Mapping du cube unitaire vers l'écran */
v.x = viewport[0] + ((r2.x + 1.0f) * 0.5f) * (viewport[2] - EPSILON);
v.y = viewport[1] + ((r2.y + 1.0f) * 0.5f) * (viewport[3] - EPSILON);
v.z = pow((-r2.z + 1.0f) * 0.5f, 0.5);
/* sinon pour near = 0.1f et far = 10.0f on peut rendre non linéaire la depth avec */
/* v.z = 1.0f - (1.0f / r2.z - 1.0f / 0.1f) / (1.0f / 10.0f - 1.0f / 0.1f); */
v.zmod = r1.z;
return v;
}
/* Gouraud */
if(s->options & SO_USE_LIGHTING) {
/* la lumière est positionnelle et fixe dans la scène. \todo dans
scene.c la rendre modifiable, voire aussi pouvoir la placer par
rapport aux objets (elle subirait la matrice modèle). */
const vec4 lp[1] = { {0.0f, 0.0f, 1.0f} };
vec4 ld = {lp[0].x - r1.x, lp[0].y - r1.y, lp[0].z - r1.z, lp[0].w - r1.w};
float n[4] = {v.normal.x, v.normal.y, v.normal.z, 0.0f}, res[4];
MMAT4XVEC4(res, ti_model_view_matrix, n);
MVEC3NORMALIZE(res);
MVEC3NORMALIZE((float *)&ld);
v.li = MVEC3DOT(res, (float *)&ld);
v.li = MIN(MAX(0.0f, v.li), 1.0f);
} else
v.li = 1.0f;
v.icolor = v.color0;
/* Mapping du cube unitaire vers l'écran */
v.x = viewport[0] + ((r2.x + 1.0f) * 0.5f) * (viewport[2] - EPSILON);
v.y = viewport[1] + ((r2.y + 1.0f) * 0.5f) * (viewport[3] - EPSILON);
v.z = pow((-r2.z + 1.0f) * 0.5f, 0.5);
/* sinon pour near = 0.1f et far = 10.0f on peut rendre non linéaire la depth avec */
/* v.z = 1.0f - (1.0f / r2.z - 1.0f / 0.1f) / (1.0f / 10.0f - 1.0f / 0.1f); */
v.zmod = r1.z;
return v;
}
/*!\brief projette le triangle \a t à l'écran (\a W x \a H) selon la
@ -82,132 +82,132 @@ vertex_t vtransform(surface_t * s, vertex_t v, float * model_view_matrix, float
* surface. Elle utilise aussi \a clip2_unit_cube pour connaître l'état
* du triangle par rapport au cube unitaire.
*
* \see vtransform
* \see vtransform
* \see clip2_unit_cube
*/
void stransform(surface_t * s, float * model_view_matrix, float * projection_matrix, float * viewport) {
int i, j;
float ti_model_view_matrix[16];
triangle_t vcull;
/* calcul de la transposée de l'inverse de la matrice model-view
pour la transformation des normales et le calcul du lambertien
utilisé par le shading Gouraud dans vtransform. */
memcpy(ti_model_view_matrix, model_view_matrix, sizeof ti_model_view_matrix);
MMAT4INVERSE(ti_model_view_matrix);
MMAT4TRANSPOSE(ti_model_view_matrix);
for(i = 0; i < s->n; ++i) {
s->t[i].state = PS_NONE;
for(j = 0; j < 3; ++j) {
s->t[i].v[j] = vtransform(s, s->t[i].v[j], model_view_matrix, ti_model_view_matrix, projection_matrix, viewport);
if(s->options & SO_CULL_BACKFACES) {
vcull.v[j].position.x = s->t[i].v[j].x;
vcull.v[j].position.y = s->t[i].v[j].y;
vcull.v[j].position.z = 0.0f;
}
int i, j;
float ti_model_view_matrix[16];
triangle_t vcull;
/* calcul de la transposée de l'inverse de la matrice model-view
pour la transformation des normales et le calcul du lambertien
utilisé par le shading Gouraud dans vtransform. */
memcpy(ti_model_view_matrix, model_view_matrix, sizeof ti_model_view_matrix);
MMAT4INVERSE(ti_model_view_matrix);
MMAT4TRANSPOSE(ti_model_view_matrix);
for(i = 0; i < s->n; ++i) {
s->t[i].state = PS_NONE;
for(j = 0; j < 3; ++j) {
s->t[i].v[j] = vtransform(s, s->t[i].v[j], model_view_matrix, ti_model_view_matrix, projection_matrix, viewport);
if(s->options & SO_CULL_BACKFACES) {
vcull.v[j].position.x = s->t[i].v[j].x;
vcull.v[j].position.y = s->t[i].v[j].y;
vcull.v[j].position.z = 0.0f;
}
}
if(s->options & SO_CULL_BACKFACES) {
tnormal(&vcull);
if(vcull.normal.z <= 0.0f) {
s->t[i].state |= PS_CULL;
continue;
}
}
clip2_unit_cube(&(s->t[i]));
}
if(s->options & SO_CULL_BACKFACES) {
tnormal(&vcull);
if(vcull.normal.z <= 0.0f) {
s->t[i].state |= PS_CULL;
continue;
}
}
clip2_unit_cube(&(s->t[i]));
}
}
/*!\brief multiplie deux matrices : \a res = \a res x \a m */
void mult_matrix(float * res, float * m) {
/* res = res x m */
float cpy[16];
memcpy(cpy, res, sizeof cpy);
MMAT4XMAT4(res, cpy, m);
/* res = res x m */
float cpy[16];
memcpy(cpy, res, sizeof cpy);
MMAT4XMAT4(res, cpy, m);
}
/*!\brief ajoute (multiplication droite) une translation à la matrice
* \a m */
void translate(float * m, float tx, float ty, float tz) {
float mat[] = { 1.0f, 0.0f, 0.0f, tx,
0.0f, 1.0f, 0.0f, ty,
0.0f, 0.0f, 1.0f, tz,
0.0f, 0.0f, 0.0f, 1.0f };
mult_matrix(m, mat);
float mat[] = { 1.0f, 0.0f, 0.0f, tx,
0.0f, 1.0f, 0.0f, ty,
0.0f, 0.0f, 1.0f, tz,
0.0f, 0.0f, 0.0f, 1.0f };
mult_matrix(m, mat);
}
/*!\brief ajoute (multiplication droite) une rotation à la matrice \a
* m */
void rotate(float * m, float angle, float x, float y, float z) {
float n = sqrtf(x * x + y * y + z * z);
if ( n > 0.0f ) {
float a, s, c, cc, x2, y2, z2, xy, yz, zx, xs, ys, zs;
float mat[] = { 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
s = sinf ( a = (angle * (float)M_PI / 180.0f) );
cc = 1.0f - (c = cosf ( a ));
x /= n; y /= n; z /= n;
x2 = x * x; y2 = y * y; z2 = z * z;
xy = x * y; yz = y * z; zx = z * x;
xs = x * s; ys = y * s; zs = z * s;
mat[0] = (cc * x2) + c;
mat[1] = (cc * xy) - zs;
mat[2] = (cc * zx) + ys;
/* mat[3] = 0.0f; */
mat[4] = (cc * xy) + zs;
mat[5] = (cc * y2) + c;
mat[6] = (cc * yz) - xs;
/* mat[7] = 0.0f; */
mat[8] = (cc * zx) - ys;
mat[9] = (cc * yz) + xs;
mat[10] = (cc * z2) + c;
/* mat[11] = 0.0f; */
/* mat[12] = 0.0f; mat[= 0.0f; mat[14] = 0.0f; mat[15] = 1.0f; */
mult_matrix(m, mat);
}
float n = sqrtf(x * x + y * y + z * z);
if ( n > 0.0f ) {
float a, s, c, cc, x2, y2, z2, xy, yz, zx, xs, ys, zs;
float mat[] = { 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
s = sinf ( a = (angle * (float)M_PI / 180.0f) );
cc = 1.0f - (c = cosf ( a ));
x /= n; y /= n; z /= n;
x2 = x * x; y2 = y * y; z2 = z * z;
xy = x * y; yz = y * z; zx = z * x;
xs = x * s; ys = y * s; zs = z * s;
mat[0] = (cc * x2) + c;
mat[1] = (cc * xy) - zs;
mat[2] = (cc * zx) + ys;
/* mat[3] = 0.0f; */
mat[4] = (cc * xy) + zs;
mat[5] = (cc * y2) + c;
mat[6] = (cc * yz) - xs;
/* mat[7] = 0.0f; */
mat[8] = (cc * zx) - ys;
mat[9] = (cc * yz) + xs;
mat[10] = (cc * z2) + c;
/* mat[11] = 0.0f; */
/* mat[12] = 0.0f; mat[= 0.0f; mat[14] = 0.0f; mat[15] = 1.0f; */
mult_matrix(m, mat);
}
}
/*!\brief ajoute (multiplication droite) un scale à la matrice \a m */
void scale(float * m, float sx, float sy, float sz) {
float mat[] = { sx , 0.0f, 0.0f, 0.0f,
0.0f, sy, 0.0f, 0.0f,
0.0f, 0.0f, sz, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
mult_matrix(m, mat);
float mat[] = { sx , 0.0f, 0.0f, 0.0f,
0.0f, sy, 0.0f, 0.0f,
0.0f, 0.0f, sz, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
mult_matrix(m, mat);
}
/*!\brief simule une free camera, voir la doc de gluLookAt */
void lookAt(float * m, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ) {
float forward[3], side[3], up[3];
float mat[] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
forward[0] = centerX - eyeX;
forward[1] = centerY - eyeY;
forward[2] = centerZ - eyeZ;
up[0] = upX;
up[1] = upY;
up[2] = upZ;
MVEC3NORMALIZE(forward);
/* side = forward x up */
MVEC3CROSS(side, forward, up);
MVEC3NORMALIZE(side);
/* up = side x forward */
MVEC3CROSS(up, side, forward);
mat[0] = side[0];
mat[1] = side[1];
mat[2] = side[2];
mat[4] = up[0];
mat[5] = up[1];
mat[6] = up[2];
mat[8] = -forward[0];
mat[9] = -forward[1];
mat[10] = -forward[2];
mult_matrix(m, mat);
translate(m, -eyeX, -eyeY, -eyeZ);
float forward[3], side[3], up[3];
float mat[] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
forward[0] = centerX - eyeX;
forward[1] = centerY - eyeY;
forward[2] = centerZ - eyeZ;
up[0] = upX;
up[1] = upY;
up[2] = upZ;
MVEC3NORMALIZE(forward);
/* side = forward x up */
MVEC3CROSS(side, forward, up);
MVEC3NORMALIZE(side);
/* up = side x forward */
MVEC3CROSS(up, side, forward);
mat[0] = side[0];
mat[1] = side[1];
mat[2] = side[2];
mat[4] = up[0];
mat[5] = up[1];
mat[6] = up[2];
mat[8] = -forward[0];
mat[9] = -forward[1];
mat[10] = -forward[2];
mult_matrix(m, mat);
translate(m, -eyeX, -eyeY, -eyeZ);
}
/*!\brief intersection triangle-cube unitaire, à compléter (voir le
@ -215,18 +215,18 @@ void lookAt(float * m, float eyeX, float eyeY, float eyeZ, float centerX, float
void clip2_unit_cube(triangle_t * t) {
int i, oleft = 0, oright = 0, obottom = 0, otop = 0, onear = 0, ofar = 0;
for (i = 0; i < 3; ++i) {
if(t->v[i].state & PS_OUT_LEFT) ++oleft;
if(t->v[i].state & PS_OUT_RIGHT) ++oright;
if(t->v[i].state & PS_OUT_BOTTOM) ++obottom;
if(t->v[i].state & PS_OUT_TOP) ++otop;
if(t->v[i].state & PS_OUT_NEAR) ++onear;
if(t->v[i].state & PS_OUT_FAR) ++ofar;
if(t->v[i].state & PS_OUT_LEFT) ++oleft;
if(t->v[i].state & PS_OUT_RIGHT) ++oright;
if(t->v[i].state & PS_OUT_BOTTOM) ++obottom;
if(t->v[i].state & PS_OUT_TOP) ++otop;
if(t->v[i].state & PS_OUT_NEAR) ++onear;
if(t->v[i].state & PS_OUT_FAR) ++ofar;
}
if(!(oleft | oright | obottom | otop | onear | ofar))
return;
return;
if(oleft == 3 || oright == 3 || obottom == 3 || otop == 3 || onear == 3 || ofar == 3) {
t->state |= PS_TOTALLY_OUT;
return;
t->state |= PS_TOTALLY_OUT;
return;
}
t->state |= PS_PARTIALLY_OUT;
/* le cas PARTIALLY_OUT n'est pas réellement géré. Il serait

302
window.c
View file

@ -1,4 +1,4 @@
/*!\file window.c
/*!\file window.c
* \brief Utilisation du raster DIY comme pipeline de rendu 3D. Cet
* exemple montre les géométries disponibles et quelques
* transformations dessus.
@ -42,172 +42,172 @@ static float _ycam = 3.0f;
/*!\brief paramètre l'application et lance la boucle infinie. */
int main(int argc, char ** argv) {
/* tentative de création d'une fenêtre pour GL4Dummies */
if(!gl4duwCreateWindow(argc, argv, /* args du programme */
"The DIY Rasterizer", /* titre */
10, 10, 800, 600, /* x, y, largeur, heuteur */
GL4DW_SHOWN) /* état visible */) {
/* ici si échec de la création souvent lié à un problème d'absence
* de contexte graphique ou d'impossibilité d'ouverture d'un
* contexte OpenGL (au moins 3.2) */
return 1;
}
init();
/* mettre en place la fonction d'interception clavier */
gl4duwKeyDownFunc(key);
/* mettre en place la fonction de display */
gl4duwDisplayFunc(draw);
/* boucle infinie pour éviter que le programme ne s'arrête et ferme
* la fenêtre immédiatement */
gl4duwMainLoop();
return 0;
/* tentative de création d'une fenêtre pour GL4Dummies */
if(!gl4duwCreateWindow(argc, argv, /* args du programme */
"The DIY Rasterizer", /* titre */
10, 10, 800, 600, /* x, y, largeur, heuteur */
GL4DW_SHOWN) /* état visible */) {
/* ici si échec de la création souvent lié à un problème d'absence
* de contexte graphique ou d'impossibilité d'ouverture d'un
* contexte OpenGL (au moins 3.2) */
return 1;
}
init();
/* mettre en place la fonction d'interception clavier */
gl4duwKeyDownFunc(key);
/* mettre en place la fonction de display */
gl4duwDisplayFunc(draw);
/* boucle infinie pour éviter que le programme ne s'arrête et ferme
* la fenêtre immédiatement */
gl4duwMainLoop();
return 0;
}
/*!\brief init de nos données, spécialement les trois surfaces
* utilisées dans ce code */
void init(void) {
GLuint id;
vec4 r = {1, 0, 0, 1}, g = {0, 1, 0, 1}, b = {0, 0, 1, 1};
/* création d'un screen GL4Dummies (texture dans laquelle nous
* pouvons dessiner) aux dimensions de la fenêtre. IMPORTANT de
* créer le screen avant d'utiliser les fonctions liées au
* textures */
gl4dpInitScreen();
/* Pour forcer la désactivation de la synchronisation verticale */
SDL_GL_SetSwapInterval(0);
/* on créé nos trois type de surfaces */
_quad = mk_quad(); /* ça fait 2 triangles */
_cube = mk_cube(); /* ça fait 2x6 triangles */
_sphere = mk_sphere(12, 12); /* ça fait 12x12x2 trianles ! */
/* on change les couleurs de surfaces */
_quad->dcolor = r; _cube->dcolor = b; _sphere->dcolor = g;
/* on leur rajoute à toutes la même texture */
id = get_texture_from_BMP("images/tex.bmp");
set_texture_id( _quad, id);
set_texture_id( _cube, id);
set_texture_id(_sphere, id);
/* si _use_tex != 0, on active l'utilisation de la texture pour les
* trois */
if(_use_tex) {
enable_surface_option( _quad, SO_USE_TEXTURE);
enable_surface_option( _cube, SO_USE_TEXTURE);
enable_surface_option(_sphere, SO_USE_TEXTURE);
}
/* si _use_lighting != 0, on active l'ombrage */
if(_use_lighting) {
enable_surface_option( _quad, SO_USE_LIGHTING);
enable_surface_option( _cube, SO_USE_LIGHTING);
enable_surface_option(_sphere, SO_USE_LIGHTING);
}
/* on désactive le back cull face pour le quadrilatère, ainsi on
* peut voir son arrière quand le lighting est inactif */
disable_surface_option(_quad, SO_CULL_BACKFACES);
/* mettre en place la fonction à appeler en cas de sortie */
atexit(sortie);
GLuint id;
vec4 r = {1, 0, 0, 1}, g = {0, 1, 0, 1}, b = {0, 0, 1, 1};
/* création d'un screen GL4Dummies (texture dans laquelle nous
* pouvons dessiner) aux dimensions de la fenêtre. IMPORTANT de
* créer le screen avant d'utiliser les fonctions liées au
* textures */
gl4dpInitScreen();
/* Pour forcer la désactivation de la synchronisation verticale */
SDL_GL_SetSwapInterval(0);
/* on créé nos trois type de surfaces */
_quad = mk_quad(); /* ça fait 2 triangles */
_cube = mk_cube(); /* ça fait 2x6 triangles */
_sphere = mk_sphere(12, 12); /* ça fait 12x12x2 trianles ! */
/* on change les couleurs de surfaces */
_quad->dcolor = r; _cube->dcolor = b; _sphere->dcolor = g;
/* on leur rajoute à toutes la même texture */
id = get_texture_from_BMP("images/tex.bmp");
set_texture_id( _quad, id);
set_texture_id( _cube, id);
set_texture_id(_sphere, id);
/* si _use_tex != 0, on active l'utilisation de la texture pour les
* trois */
if(_use_tex) {
enable_surface_option( _quad, SO_USE_TEXTURE);
enable_surface_option( _cube, SO_USE_TEXTURE);
enable_surface_option(_sphere, SO_USE_TEXTURE);
}
/* si _use_lighting != 0, on active l'ombrage */
if(_use_lighting) {
enable_surface_option( _quad, SO_USE_LIGHTING);
enable_surface_option( _cube, SO_USE_LIGHTING);
enable_surface_option(_sphere, SO_USE_LIGHTING);
}
/* on désactive le back cull face pour le quadrilatère, ainsi on
* peut voir son arrière quand le lighting est inactif */
disable_surface_option(_quad, SO_CULL_BACKFACES);
/* mettre en place la fonction à appeler en cas de sortie */
atexit(sortie);
}
/*!\brief la fonction appelée à chaque display. */
void draw(void) {
static float a = 0.0f;
float model_view_matrix[16], projection_matrix[16], nmv[16];
/* effacer l'écran et le buffer de profondeur */
gl4dpClearScreen();
clear_depth_map();
/* des macros facilitant le travail avec des matrices et des
* vecteurs se trouvent dans la bibliothèque GL4Dummies, dans le
* fichier gl4dm.h */
/* charger un frustum dans projection_matrix */
MFRUSTUM(projection_matrix, -0.05f, 0.05f, -0.05f, 0.05f, 0.1f, 1000.0f);
/* charger la matrice identité dans model-view */
MIDENTITY(model_view_matrix);
/* on place la caméra en arrière-haut, elle regarde le centre de la scène */
lookAt(model_view_matrix, 0, _ycam, 10, 0, 0, 0, 0, 1, 0);
/* le quadrilatère est mis à gauche et tourne autour de son axe x */
memcpy(nmv, model_view_matrix, sizeof nmv); /* copie model_view_matrix dans nmv */
translate(nmv, -3.0f, 0.0f, 0.0f);
rotate(nmv, a, 1.0f, 0.0f, 0.0f);
transform_n_rasterize(_quad, nmv, projection_matrix);
/* le cube est mis à droite et tourne autour de son axe z */
memcpy(nmv, model_view_matrix, sizeof nmv); /* copie model_view_matrix dans nmv */
translate(nmv, 3.0f, 0.0f, 0.0f);
rotate(nmv, a, 0.0f, 0.0f, 1.0f);
transform_n_rasterize(_cube, nmv, projection_matrix);
/* la sphère est laissée au centre et tourne autour de son axe y */
memcpy(nmv, model_view_matrix, sizeof nmv); /* copie model_view_matrix dans nmv */
rotate(nmv, a, 0.0f, 1.0f, 0.0f);
transform_n_rasterize(_sphere, nmv, projection_matrix);
/* déclarer qu'on a changé des pixels du screen (en bas niveau) */
gl4dpScreenHasChanged();
/* fonction permettant de raffraîchir l'ensemble de la fenêtre*/
gl4dpUpdateScreen(NULL);
a += 0.1f;
static float a = 0.0f;
float model_view_matrix[16], projection_matrix[16], nmv[16];
/* effacer l'écran et le buffer de profondeur */
gl4dpClearScreen();
clear_depth_map();
/* des macros facilitant le travail avec des matrices et des
* vecteurs se trouvent dans la bibliothèque GL4Dummies, dans le
* fichier gl4dm.h */
/* charger un frustum dans projection_matrix */
MFRUSTUM(projection_matrix, -0.05f, 0.05f, -0.05f, 0.05f, 0.1f, 1000.0f);
/* charger la matrice identité dans model-view */
MIDENTITY(model_view_matrix);
/* on place la caméra en arrière-haut, elle regarde le centre de la scène */
lookAt(model_view_matrix, 0, _ycam, 10, 0, 0, 0, 0, 1, 0);
/* le quadrilatère est mis à gauche et tourne autour de son axe x */
memcpy(nmv, model_view_matrix, sizeof nmv); /* copie model_view_matrix dans nmv */
translate(nmv, -3.0f, 0.0f, 0.0f);
rotate(nmv, a, 1.0f, 0.0f, 0.0f);
transform_n_rasterize(_quad, nmv, projection_matrix);
/* le cube est mis à droite et tourne autour de son axe z */
memcpy(nmv, model_view_matrix, sizeof nmv); /* copie model_view_matrix dans nmv */
translate(nmv, 3.0f, 0.0f, 0.0f);
rotate(nmv, a, 0.0f, 0.0f, 1.0f);
transform_n_rasterize(_cube, nmv, projection_matrix);
/* la sphère est laissée au centre et tourne autour de son axe y */
memcpy(nmv, model_view_matrix, sizeof nmv); /* copie model_view_matrix dans nmv */
rotate(nmv, a, 0.0f, 1.0f, 0.0f);
transform_n_rasterize(_sphere, nmv, projection_matrix);
/* déclarer qu'on a changé des pixels du screen (en bas niveau) */
gl4dpScreenHasChanged();
/* fonction permettant de raffraîchir l'ensemble de la fenêtre*/
gl4dpUpdateScreen(NULL);
a += 0.1f;
}
/*!\brief intercepte l'événement clavier pour modifier les options. */
void key(int keycode) {
switch(keycode) {
case GL4DK_UP:
_ycam += 0.05f;
break;
case GL4DK_DOWN:
_ycam -= 0.05f;
break;
case GL4DK_t: /* 't' la texture */
_use_tex = !_use_tex;
if(_use_tex) {
enable_surface_option( _quad, SO_USE_TEXTURE);
enable_surface_option( _cube, SO_USE_TEXTURE);
enable_surface_option(_sphere, SO_USE_TEXTURE);
} else {
disable_surface_option( _quad, SO_USE_TEXTURE);
disable_surface_option( _cube, SO_USE_TEXTURE);
disable_surface_option(_sphere, SO_USE_TEXTURE);
switch(keycode) {
case GL4DK_UP:
_ycam += 0.05f;
break;
case GL4DK_DOWN:
_ycam -= 0.05f;
break;
case GL4DK_t: /* 't' la texture */
_use_tex = !_use_tex;
if(_use_tex) {
enable_surface_option( _quad, SO_USE_TEXTURE);
enable_surface_option( _cube, SO_USE_TEXTURE);
enable_surface_option(_sphere, SO_USE_TEXTURE);
} else {
disable_surface_option( _quad, SO_USE_TEXTURE);
disable_surface_option( _cube, SO_USE_TEXTURE);
disable_surface_option(_sphere, SO_USE_TEXTURE);
}
break;
case GL4DK_c: /* 'c' utiliser la couleur */
_use_color = !_use_color;
if(_use_color) {
enable_surface_option( _quad, SO_USE_COLOR);
enable_surface_option( _cube, SO_USE_COLOR);
enable_surface_option(_sphere, SO_USE_COLOR);
} else {
disable_surface_option( _quad, SO_USE_COLOR);
disable_surface_option( _cube, SO_USE_COLOR);
disable_surface_option(_sphere, SO_USE_COLOR);
}
break;
case GL4DK_l: /* 'l' utiliser l'ombrage par la méthode Gouraud */
_use_lighting = !_use_lighting;
if(_use_lighting) {
enable_surface_option( _quad, SO_USE_LIGHTING);
enable_surface_option( _cube, SO_USE_LIGHTING);
enable_surface_option(_sphere, SO_USE_LIGHTING);
} else {
disable_surface_option( _quad, SO_USE_LIGHTING);
disable_surface_option( _cube, SO_USE_LIGHTING);
disable_surface_option(_sphere, SO_USE_LIGHTING);
}
break;
default: break;
}
break;
case GL4DK_c: /* 'c' utiliser la couleur */
_use_color = !_use_color;
if(_use_color) {
enable_surface_option( _quad, SO_USE_COLOR);
enable_surface_option( _cube, SO_USE_COLOR);
enable_surface_option(_sphere, SO_USE_COLOR);
} else {
disable_surface_option( _quad, SO_USE_COLOR);
disable_surface_option( _cube, SO_USE_COLOR);
disable_surface_option(_sphere, SO_USE_COLOR);
}
break;
case GL4DK_l: /* 'l' utiliser l'ombrage par la méthode Gouraud */
_use_lighting = !_use_lighting;
if(_use_lighting) {
enable_surface_option( _quad, SO_USE_LIGHTING);
enable_surface_option( _cube, SO_USE_LIGHTING);
enable_surface_option(_sphere, SO_USE_LIGHTING);
} else {
disable_surface_option( _quad, SO_USE_LIGHTING);
disable_surface_option( _cube, SO_USE_LIGHTING);
disable_surface_option(_sphere, SO_USE_LIGHTING);
}
break;
default: break;
}
}
/*!\brief à appeler à la sortie du programme. */
void sortie(void) {
/* on libère nos trois surfaces */
if(_quad) {
free_surface(_quad);
_quad = NULL;
}
if(_cube) {
free_surface(_cube);
_cube = NULL;
}
if(_sphere) {
free_surface(_sphere);
_sphere = NULL;
}
/* libère tous les objets produits par GL4Dummies, ici
* principalement les screen */
gl4duClean(GL4DU_ALL);
/* on libère nos trois surfaces */
if(_quad) {
free_surface(_quad);
_quad = NULL;
}
if(_cube) {
free_surface(_cube);
_cube = NULL;
}
if(_sphere) {
free_surface(_sphere);
_sphere = NULL;
}
/* libère tous les objets produits par GL4Dummies, ici
* principalement les screen */
gl4duClean(GL4DU_ALL);
}