From 60766a0b335ded2b9cd9ef7feb5b39c0a846cce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Tue, 4 Oct 2011 09:33:23 +0200 Subject: [PATCH 1/3] =?UTF-8?q?D=C3=A9but=20d'impl=C3=A9mentation=20d'une?= =?UTF-8?q?=20repr=C3=A9sentation=20du=20terrain=20par=20un=20QuadTree.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- square.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 square.c diff --git a/square.c b/square.c new file mode 100644 index 0000000..38f4eb8 --- /dev/null +++ b/square.c @@ -0,0 +1,61 @@ +// get_z() +#include "roam.h" + +#define INIT_VERTEX(v,xx,yy) do { (v)->x=(xx); (v)->y=(yy); (v)->z=get_z((xx),(yy)); } while(0); + +// QuadTree Node. +typedef struct QTNode { + Vertex* center; + Vertex* ne; + Vertex* se; + Vertex* so; + Vertex* no; + struct QTNode* ne_child; + struct QTNode* se_child; + struct QTNode* so_child; + struct QTNode* no_child; +} QTNode; + +typedef enum QTQuadrant { + QT_NE, + QT_SE, + QT_SO, + QT_NO, +} QTQuadrant; + +void QT_split(QTNode* parent, QTQuadrant quadrant) { + if (quadrant == QT_NE) { + q = malloc(sizeof(QTNode)); + + q->center = malloc(sizeof(Vertex)); + INIT_VERTEX(q->center, (parent->ne->x + parent->so->x) / 2, (parent->ne->y + parent->so->y) / 2); + + q->ne = parent->ne; + + q->se = malloc(sizeof(Vertex)); // TODO : réutiliser le vertex existant s'il y en a un. + INIT_VERTEX(q->se, parent->ne->x, (parent->ne->y + parent->so->y) / 2); + + q->so = parent->center; + + q->no = malloc(sizeof(Vertex)); // TODO : réutiliser le vertex existant s'il y en a un. + INIT_VERTEX(q->no, (parent->ne->x + parent->so->x) / 2, parent->ne->y); + + parent->ne_child = q; + } +} + +QTNode* QT_example() { + QTNode* q = malloc(sizeof(QTNode)); + Vertex** v = malloc(sizeof(Vertex)*5); + 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 = v[0]; + q->ne = v[1]; + q->se = v[2]; + q->so = v[3]; + q->no = v[4]; + return q; +} From 8b3316b28e3d9129c6cb6552690e48d563653369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Tue, 4 Oct 2011 10:47:02 +0200 Subject: [PATCH 2/3] Split et merge pour les QuadTree. --- square.c | 142 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 107 insertions(+), 35 deletions(-) diff --git a/square.c b/square.c index 38f4eb8..70d071d 100644 --- a/square.c +++ b/square.c @@ -3,48 +3,115 @@ #define INIT_VERTEX(v,xx,yy) do { (v)->x=(xx); (v)->y=(yy); (v)->z=get_z((xx),(yy)); } while(0); +// 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)) + // QuadTree Node. typedef struct QTNode { Vertex* center; - Vertex* ne; - Vertex* se; - Vertex* so; - Vertex* no; - struct QTNode* ne_child; - struct QTNode* se_child; - struct QTNode* so_child; - struct QTNode* no_child; + Vertex* vertices[4]; + struct QTNode* children[4]; + struct QTNode* neighbors[4]; } QTNode; -typedef enum QTQuadrant { - QT_NE, - QT_SE, - QT_SO, - QT_NO, -} QTQuadrant; +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]; + q[0] = malloc(sizeof(QTNode)); + q[1] = malloc(sizeof(QTNode)); + q[2] = malloc(sizeof(QTNode)); + q[3] = malloc(sizeof(QTNode)); -void QT_split(QTNode* parent, QTQuadrant quadrant) { - if (quadrant == QT_NE) { - q = 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] = malloc(sizeof(Vertex)); + switch (r) { // Pourrait être factorisé, mais on y perdrait en clarté ! + case 0: INIT_VERTEX(new_vertices[0], parent->center->x, parent->children[QT_NE]->y); break; + case 1: INIT_VERTEX(new_vertices[1], parent->children[QT_SE]->x, parent->center->y); break; + case 2: INIT_VERTEX(new_vertices[2], parent->center->x, parent->children[QT_SO]->y); break; + case 3: INIT_VERTEX(new_vertices[3], parent->children[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)); + // Coordonnées du centre de qne = moyenne du center et de parent->children[QT_NE]. + INIT_VERTEX(q[ROT_NE]->center, (parent->center->x + parent->children[ROT_NE]->x) / 2, (parent->center->y + parent->children[ROT_NE]->y) / 2); - q->center = malloc(sizeof(Vertex)); - INIT_VERTEX(q->center, (parent->ne->x + parent->so->x) / 2, (parent->ne->y + parent->so->y) / 2); + q[ROT_NE]->children[ROT_NE] = parent->children[ROT_NE]; + q[ROT_NE]->children[ROT_SE] = new_vertices[ROT_E]; + q[ROT_NE]->children[ROT_SO] = parent->center; + q[ROT_NE]->children[ROT_NO] = 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]; - q->ne = parent->ne; - - q->se = malloc(sizeof(Vertex)); // TODO : réutiliser le vertex existant s'il y en a un. - INIT_VERTEX(q->se, parent->ne->x, (parent->ne->y + parent->so->y) / 2); - - q->so = parent->center; - - q->no = malloc(sizeof(Vertex)); // TODO : réutiliser le vertex existant s'il y en a un. - INIT_VERTEX(q->no, (parent->ne->x + parent->so->x) / 2, parent->ne->y); - - parent->ne_child = q; + parent->children[ROT_NE] = q[ROT_NE]; } } -QTNode* QT_example() { +void QT_merge(QTNode* parent) { + // Ne pas merge un noeud sans enfants. + if (parent->children[QT_NE] == NULL) return; + + int r; + for (r = 0; r < 4; r++) { + QT_merge(parent->children[ROT_NE]); + parent->children[ROT_NE] = NULL; + // 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; + } +} + +QTNode QT_baseNode() { QTNode* q = malloc(sizeof(QTNode)); Vertex** v = malloc(sizeof(Vertex)*5); INIT_VERTEX(v[0], 0, 0); @@ -53,9 +120,14 @@ QTNode* QT_example() { INIT_VERTEX(v[3], -1024, -1024); INIT_VERTEX(v[4], -1024, +1024); q->center = v[0]; - q->ne = v[1]; - q->se = v[2]; - q->so = v[3]; - q->no = v[4]; + q->children[QT_NE] = v[1]; + q->children[QT_SE] = v[2]; + q->children[QT_SO] = v[3]; + q->children[QT_NO] = v[4]; + return q; +} + +QTNode* QT_example() { + QTNode* q = QT_baseNode(); return q; } From 965dc0d4ff2767ebab8ae29da8dafa292a8755bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Tue, 4 Oct 2011 11:03:11 +0200 Subject: [PATCH 3/3] Ajout de square.c au makefile et nettoyage des bugs de compilation. --- Makefile | 2 +- roam.h | 33 +++++++++++++++--------------- square.c | 62 ++++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 58 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index c37f784..4ab8962 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ test: all simple-terrain: simple-terrain.c $(CC) $< -o $@ -display: display.o roam.o +display: display.o roam.o square.o $(CC) -lGLEW -lSDL -lGLU $^ -o $@ # Create objects from C source code diff --git a/roam.h b/roam.h index 59e552e..5f35641 100644 --- a/roam.h +++ b/roam.h @@ -3,25 +3,26 @@ #include typedef struct Vertex { - int x; - int y; - int z; - float xNormal; - float yNormal; - float zNormal; - /* Ajouter des champs ici. */ + int x; + int y; + int z; + float xNormal; + float yNormal; + float zNormal; + int refCount; + /* Ajouter des champs ici. */ } Vertex; typedef struct Triangle { - Vertex* vApex; - Vertex* vLeft; - Vertex* vRight; - struct Triangle* tLeftChild; - struct Triangle* tRightChild; - struct Triangle* tBaseNeighbor; - struct Triangle* tLeftNeighbor; - struct Triangle* tRightNeighbor; - struct Triangle* tParent; + Vertex* vApex; + Vertex* vLeft; + Vertex* vRight; + struct Triangle* tLeftChild; + struct Triangle* tRightChild; + struct Triangle* tBaseNeighbor; + struct Triangle* tLeftNeighbor; + struct Triangle* tRightNeighbor; + struct Triangle* tParent; } Triangle; Triangle* initDefaultExample(); diff --git a/square.c b/square.c index 70d071d..372e74a 100644 --- a/square.c +++ b/square.c @@ -1,7 +1,10 @@ // get_z() #include "roam.h" -#define INIT_VERTEX(v,xx,yy) do { (v)->x=(xx); (v)->y=(yy); (v)->z=get_z((xx),(yy)); } while(0); +#define INIT_VERTEX(v,xx,yy) do { (v)->refCount=0; (v)->x=(xx); (v)->y=(yy); (v)->z=get_z((xx),(yy)); } while(0); + +inline Vertex* use_vertex(Vertex* v) { v->refCount++; return v; } +inline void unuse_vertex(Vertex* v) { if (--(v->refCount) == 0) free(v); } // ROTATE4(x,r) == x+r % 4 #define ROTATE4(x,r) ((x+r) & 3) @@ -34,10 +37,9 @@ void QT_split(QTNode* parent) { int r; QTNode* q[4]; - q[0] = malloc(sizeof(QTNode)); - q[1] = malloc(sizeof(QTNode)); - q[2] = malloc(sizeof(QTNode)); - q[3] = malloc(sizeof(QTNode)); + for (r = 0; r < 4; r++) { + q[ROT_NE] = malloc(sizeof(QTNode)); + } Vertex* new_vertices[4]; for (r = 0; r < 4; r++) { @@ -47,23 +49,24 @@ void QT_split(QTNode* parent) { } else { new_vertices[ROT_N] = malloc(sizeof(Vertex)); switch (r) { // Pourrait être factorisé, mais on y perdrait en clarté ! - case 0: INIT_VERTEX(new_vertices[0], parent->center->x, parent->children[QT_NE]->y); break; - case 1: INIT_VERTEX(new_vertices[1], parent->children[QT_SE]->x, parent->center->y); break; - case 2: INIT_VERTEX(new_vertices[2], parent->center->x, parent->children[QT_SO]->y); break; - case 3: INIT_VERTEX(new_vertices[3], parent->children[QT_NO]->x, parent->center->y); break; + 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)); - // Coordonnées du centre de qne = moyenne du center et de parent->children[QT_NE]. - INIT_VERTEX(q[ROT_NE]->center, (parent->center->x + parent->children[ROT_NE]->x) / 2, (parent->center->y + parent->children[ROT_NE]->y) / 2); + // 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]->children[ROT_NE] = parent->children[ROT_NE]; - q[ROT_NE]->children[ROT_SE] = new_vertices[ROT_E]; - q[ROT_NE]->children[ROT_SO] = parent->center; - q[ROT_NE]->children[ROT_NO] = new_vertices[ROT_N]; + 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; @@ -99,8 +102,9 @@ void QT_merge(QTNode* parent) { int r; for (r = 0; r < 4; r++) { + // Merge récursif des enfants. QT_merge(parent->children[ROT_NE]); - parent->children[ROT_NE] = NULL; + // reset à NULL les voisins qui pointaient vers des enfants. if (parent->neighbors[ROT_N] != NULL) if (parent->neighbors[ROT_N]->children[ROT_SE] != NULL) @@ -108,22 +112,36 @@ void QT_merge(QTNode* parent) { 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() { +QTNode* QT_baseNode() { QTNode* q = malloc(sizeof(QTNode)); Vertex** v = malloc(sizeof(Vertex)*5); + 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 = v[0]; - q->children[QT_NE] = v[1]; - q->children[QT_SE] = v[2]; - q->children[QT_SO] = v[3]; - q->children[QT_NO] = v[4]; + + q->center = use_vertex(v[0]); + + int i; + for (i = 0; i < 4; i++) { + q->vertices[i] = use_vertex(v[1]); + q->children[i] = NULL; + q->neighbors[i] = NULL; + } + return q; }