#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; }