306 lines
9.9 KiB
C
306 lines
9.9 KiB
C
#include "square.h"
|
|
|
|
// Positionne v à (xx,yy) et calcule z. Met ref_count à 0.
|
|
inline void init_vertex(Vertex* v, int x, int y) {
|
|
v->refCount = 0;
|
|
v->x = x;
|
|
v->y = y;
|
|
v->z = get_z(x,y);
|
|
}
|
|
|
|
// ROTATE4(x,r) == x+r % 4
|
|
#define ROTATE4(x,r) ((x+r) & 3)
|
|
|
|
// L'ordre dans les tableaux est toujours {ne,se,so,no} ou bien {n,e,s,o}.
|
|
typedef enum QTQuadrant { QT_NE = 0, QT_SE = 1, QT_SO = 2, QT_NO = 3 } QTQuadrant;
|
|
typedef enum QTCardinal { QT_N = 0, QT_E = 1, QT_S = 2, QT_O = 3 } QTCardinal;
|
|
|
|
#define ROT_NE (ROTATE4(QT_NE, r))
|
|
#define ROT_SE (ROTATE4(QT_SE, r))
|
|
#define ROT_SO (ROTATE4(QT_SO, r))
|
|
#define ROT_NO (ROTATE4(QT_NO, r))
|
|
|
|
#define ROT_N (ROTATE4(QT_N, r))
|
|
#define ROT_E (ROTATE4(QT_E, r))
|
|
#define ROT_S (ROTATE4(QT_S, r))
|
|
#define ROT_O (ROTATE4(QT_O, r))
|
|
|
|
|
|
static inline void vertex_link_create(Vertex* a, Vertex* b, QTCardinal directionAB) {
|
|
//printf("vertex_link_create %x to %x direction %d (N=%d)\n", (int)a, (int)b, directionAB, QT_N);
|
|
if (a != NULL) a->next[directionAB] = b;
|
|
if (b != NULL) b->next[ROTATE4(directionAB, 2)] = a;
|
|
}
|
|
|
|
static inline void vertex_link_between(Vertex* vnew, Vertex* a, Vertex* b, QTCardinal directionAB) {
|
|
vertex_link_create(a, vnew, directionAB);
|
|
vertex_link_create(vnew, b, directionAB);
|
|
}
|
|
|
|
static inline void vertex_link_remove(Vertex* v) {
|
|
vertex_link_create(v->next[QT_S], v->next[QT_N], QT_N);
|
|
vertex_link_create(v->next[QT_O], v->next[QT_E], QT_E);
|
|
}
|
|
|
|
static inline void qtnode_link_create(QTNode* a, QTNode* b) {
|
|
if (a != NULL) a->nextNode = b;
|
|
if (b != NULL) b->previousNode = a;
|
|
}
|
|
|
|
inline Vertex* use_vertex(Vertex* v) { v->refCount++; return v; }
|
|
inline void unuse_vertex(Vertex* v) {
|
|
// TODO : assert(v->refCount > 0);
|
|
if (--(v->refCount) == 0) {
|
|
// Supprime le vertex des listes de parcours.
|
|
vertex_link_remove(v);
|
|
free(v);
|
|
}
|
|
}
|
|
|
|
void QT_split(QTNode* parent) {
|
|
// Ne pas split un noeud déjà split.
|
|
if (parent->children[QT_NE] != NULL) return;
|
|
|
|
int r;
|
|
QTNode* q[4];
|
|
for (r = 0; r < 4; r++) {
|
|
q[ROT_NE] = malloc(sizeof(QTNode));
|
|
}
|
|
|
|
Vertex* new_vertices[4];
|
|
for (r = 0; r < 4; r++) {
|
|
// réutiliser le vertex existant (parent->top_neighbor->se_child->so ou bien parent->top_neighbor->so_child->se)
|
|
if (parent->neighbors[ROT_N] != NULL && parent->neighbors[ROT_N]->children[ROT_SE] != NULL) {
|
|
new_vertices[ROT_N] = parent->neighbors[ROT_N]->children[ROT_SE]->vertices[ROT_SO];
|
|
} else {
|
|
new_vertices[ROT_N] = (Vertex*)malloc(sizeof(Vertex));
|
|
// Insère le nouveau vertex entre les deux coins de parent.
|
|
vertex_link_between(new_vertices[ROT_N], parent->vertices[ROT_NO], parent->vertices[ROT_NE], ROT_E);
|
|
// place le nouveau vertex après center.
|
|
vertex_link_create(parent->center, new_vertices[ROT_N], ROT_N);
|
|
// Définit x,y,z et ref_count.
|
|
switch (r) { // TODO : Devrait être factorisé.
|
|
case 0: init_vertex(new_vertices[0], parent->center->x, parent->vertices[QT_NE]->y); break;
|
|
case 1: init_vertex(new_vertices[1], parent->vertices[QT_SE]->x, parent->center->y); break;
|
|
case 2: init_vertex(new_vertices[2], parent->center->x, parent->vertices[QT_SO]->y); break;
|
|
case 3: init_vertex(new_vertices[3], parent->vertices[QT_NO]->x, parent->center->y); break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (r = 0; r < 4; r++) { // Dans le corps de la boucle, positions pour le quadrant ne.
|
|
q[ROT_NE]->center = malloc(sizeof(Vertex));
|
|
// Pas besoin d'insérer center dans une des listes : à sa création il ne sera accédé dans aucun parcours de périmètre.
|
|
// Coordonnées du centre de qne = moyenne du center et de parent->vertices[QT_NE].
|
|
init_vertex(q[ROT_NE]->center, (parent->center->x + parent->vertices[ROT_NE]->x) / 2, (parent->center->y + parent->vertices[ROT_NE]->y) / 2);
|
|
use_vertex(q[ROT_NE]->center);
|
|
|
|
q[ROT_NE]->vertices[ROT_NE] = use_vertex(parent->vertices[ROT_NE]);
|
|
q[ROT_NE]->vertices[ROT_SE] = use_vertex(new_vertices[ROT_E]);
|
|
q[ROT_NE]->vertices[ROT_SO] = use_vertex(parent->center);
|
|
q[ROT_NE]->vertices[ROT_NO] = use_vertex(new_vertices[ROT_N]);
|
|
|
|
q[ROT_NE]->children[ROT_NE] = NULL;
|
|
q[ROT_NE]->children[ROT_SE] = NULL;
|
|
q[ROT_NE]->children[ROT_SO] = NULL;
|
|
q[ROT_NE]->children[ROT_NO] = NULL;
|
|
|
|
// Si le voisin du haut de parent a un se_child, c'est le voisin du haut de qne.
|
|
if (parent->neighbors[ROT_N] != NULL) {
|
|
q[ROT_NE]->neighbors[ROT_N] = parent->neighbors[ROT_N]->children[ROT_SE];
|
|
if (parent->neighbors[ROT_N]->children[ROT_SE] != NULL)
|
|
parent->neighbors[ROT_N]->children[ROT_SE]->neighbors[ROT_S] = q[ROT_NE];
|
|
} else {
|
|
q[ROT_NE]->neighbors[ROT_N] = NULL;
|
|
}
|
|
// Si le voisin de droite de parent a un no_child, c'est le voisin de droite de qne.
|
|
if (parent->neighbors[ROT_E] != NULL) {
|
|
q[ROT_NE]->neighbors[ROT_E] = parent->neighbors[ROT_E]->children[ROT_NO];
|
|
if (parent->neighbors[ROT_E]->children[ROT_NO] != NULL)
|
|
parent->neighbors[ROT_E]->children[ROT_NO]->neighbors[ROT_O] = q[ROT_NE];
|
|
} else {
|
|
q[ROT_NE]->neighbors[ROT_E] = NULL;
|
|
}
|
|
q[ROT_NE]->neighbors[ROT_S] = q[ROT_SE];
|
|
q[ROT_NE]->neighbors[ROT_O] = q[ROT_NO];
|
|
|
|
parent->children[ROT_NE] = q[ROT_NE];
|
|
}
|
|
|
|
// remplacer parent par ses quatre enfants dans la liste d'énumération de tous les QTNode feuilles.
|
|
qtnode_link_create(parent->previousNode, q[QT_NO]);
|
|
qtnode_link_create(q[QT_NO], q[QT_NE]);
|
|
qtnode_link_create(q[QT_NE], q[QT_SE]);
|
|
qtnode_link_create(q[QT_SE], q[QT_SO]);
|
|
qtnode_link_create(q[QT_SO], parent->nextNode);
|
|
|
|
// TODO : set minLOD = maxLOD = parent->LOD + 1; // À moins que ça soit le parcours récursif de màj du mesh qui écrive cette information ?
|
|
}
|
|
|
|
void QT_merge(QTNode* parent) {
|
|
// Ne pas merge un noeud sans enfants.
|
|
if (parent->children[QT_NE] == NULL) return;
|
|
|
|
qtnode_link_create(parent->children[QT_NO]->previousNode, parent);
|
|
qtnode_link_create(parent, parent->children[QT_SO]->nextNode);
|
|
|
|
int r;
|
|
for (r = 0; r < 4; r++) {
|
|
// Merge récursif des enfants.
|
|
QT_merge(parent->children[ROT_NE]);
|
|
|
|
// reset à NULL les voisins qui pointaient vers des enfants.
|
|
if (parent->neighbors[ROT_N] != NULL)
|
|
if (parent->neighbors[ROT_N]->children[ROT_SE] != NULL)
|
|
parent->neighbors[ROT_N]->children[ROT_SE]->neighbors[ROT_S] = NULL;
|
|
if (parent->neighbors[ROT_E] != NULL)
|
|
if (parent->neighbors[ROT_E]->children[ROT_NO] != NULL)
|
|
parent->neighbors[ROT_E]->children[ROT_NO]->neighbors[ROT_O] = NULL;
|
|
|
|
unuse_vertex(parent->children[ROT_NE]->center);
|
|
int i;
|
|
for (i = 0; i < 4; i++)
|
|
unuse_vertex(parent->children[ROT_NE]->vertices[i]);
|
|
|
|
free(parent->children[ROT_NE]);
|
|
parent->children[ROT_NE] = NULL;
|
|
}
|
|
}
|
|
|
|
QTNode* QT_baseNode() {
|
|
int i;
|
|
QTNode* q = malloc(sizeof(QTNode));
|
|
Vertex* _v = (Vertex*) malloc(sizeof(Vertex)*5);
|
|
Vertex* v[5]; for (i = 0; i < 5; i++) v[i] = &(_v[i]);
|
|
|
|
vertex_link_create(v[1], v[2], QT_S);
|
|
vertex_link_create(v[2], v[3], QT_O);
|
|
vertex_link_create(v[3], v[4], QT_N);
|
|
vertex_link_create(v[4], v[1], QT_E);
|
|
|
|
init_vertex(v[0], 0, 0);
|
|
init_vertex(v[1], +1024, -1024);
|
|
init_vertex(v[2], +1024, +1024);
|
|
init_vertex(v[3], -1024, +1024);
|
|
init_vertex(v[4], -1024, -1024);
|
|
|
|
q->center = use_vertex(v[0]);
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
q->vertices[i] = use_vertex(v[i+1]);
|
|
q->children[i] = NULL;
|
|
q->neighbors[i] = NULL;
|
|
}
|
|
|
|
qtnode_link_create(q, NULL);
|
|
qtnode_link_create(NULL, q);
|
|
|
|
q->minLOD = 0;
|
|
q->maxLOD = 0;
|
|
|
|
return q;
|
|
}
|
|
|
|
void vertex_print(Vertex* v) {
|
|
v=v;
|
|
//printf("vertex %x(%d,%d,%d) N=%x E=%x S=%x O=%x\n", (unsigned int)v, v->x, v->y, v->z, (int)v->next[QT_N], (int)v->next[QT_E], (int)v->next[QT_S], (int)v->next[QT_O]);
|
|
}
|
|
|
|
void qtnode_print(QTNode* n) {
|
|
//printf("node %x center=", (unsigned int)n);
|
|
vertex_print(n->center);
|
|
}
|
|
|
|
void setNormal(Vertex *center, Vertex *va, Vertex *v) {
|
|
int ax = va->x - center->x;
|
|
int ay = va->y - center->y;
|
|
int az = va->z - center->z;
|
|
int bx = center->x - v->x;
|
|
int by = center->y - v->y;
|
|
int bz = center->z - v->z;
|
|
|
|
float x = (float)((ay * bz) - (az * by));
|
|
float y = (float)((az * bx) - (ax * bz));
|
|
float z = -(float)((ax * by) - (ay * bx));
|
|
float length = sqrt(x*x + y*y + z*z);
|
|
|
|
length = length;
|
|
x = x/length;
|
|
y = y/length;
|
|
z = z/length;
|
|
|
|
/*va = center;
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glColor3ub(255,255,255);
|
|
glBegin(GL_LINES);
|
|
glVertex3f(va->x,va->y,va->z);
|
|
glVertex3f(va->x+500*x,va->y+500*y,va->z+500*z);
|
|
glEnd();
|
|
glEnable(GL_LIGHTING);*/
|
|
glNormal3f(x,y,-z);
|
|
}
|
|
|
|
// first est le QTNode le plus en haut à gauche (NO). Par la suite, on
|
|
// pourra créer un first artificiel qui évitera la descente récursive
|
|
// jusqu'au NO le plus petit.
|
|
void QT_enumerate(QTNode* first) {
|
|
//printf("\nFRAME\n\n");
|
|
while (first->children[QT_NO] != NULL)
|
|
first = first->children[QT_NO];
|
|
|
|
QTNode* n;
|
|
int r;
|
|
int i=0;
|
|
Vertex* v;
|
|
Vertex *center;
|
|
Vertex *va = NULL;
|
|
|
|
for (n = first; n != NULL; n = n->nextNode) {
|
|
qtnode_print(n);
|
|
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
setNormal(n->vertices[QT_NE],n->vertices[QT_SO],n->vertices[QT_SE]);
|
|
// envoyer le vertex central
|
|
center = n->center;
|
|
setNormal(center,n->vertices[ROT_NO],n->vertices[ROT_NO]->next[ROT_E]);
|
|
glVertex3f(center->x,center->y,center->z);
|
|
|
|
// Pour chaque côté
|
|
for (r = 0, i = 0; r < 4; r++) {
|
|
// On parcourt tous les vertices le long du côté.
|
|
for (v = n->vertices[ROT_NO]; v != n->vertices[ROT_NE]; i++, v = v->next[ROT_E]) {
|
|
if(i <= 1){
|
|
va = v;
|
|
//setNormal(center,n->vertices[QT_SO],v);
|
|
}
|
|
else {
|
|
setNormal(center,va,v);
|
|
va = v;
|
|
}
|
|
|
|
glVertex3f(v->x,v->y,v->z);
|
|
// envoyer un vertex du fan :
|
|
//(void)(v);
|
|
}
|
|
}
|
|
|
|
// Nécessaire ssi on fait un TRIANGLE_FAN et qu'on ne peut pas lui dire de fermer la boucle.
|
|
// On renvoie le 1er vertex du bord :
|
|
(void)(n->vertices[QT_NO]);
|
|
setNormal(center,va,n->vertices[QT_NO]);
|
|
glVertex3f(n->vertices[QT_NO]->x,n->vertices[QT_NO]->y,n->vertices[QT_NO]->z);
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
QTNode* QT_example() {
|
|
QTNode* q = QT_baseNode();
|
|
QT_split(q);
|
|
QT_split(q->children[QT_NO]);
|
|
QT_split(q->children[QT_NO]->children[QT_SE]);
|
|
QT_split(q->children[QT_NO]->children[QT_SE]->children[QT_SO]);
|
|
QT_split(q->children[QT_NO]->children[QT_SE]->children[QT_NE]);
|
|
return q;
|
|
}
|