From 8fff42deda80974665fd401ed5e29f8aa0794370 Mon Sep 17 00:00:00 2001 From: Christophe Geuzaine <cgeuzaine@ulg.ac.be> Date: Tue, 22 Aug 2006 15:34:34 +0000 Subject: [PATCH] reimplemented VertexArrays with std::vector (it's a bit faster) --- Common/VertexArray.cpp | 232 ++++++++++++++++++----------------------- Common/VertexArray.h | 29 ++++-- Graphics/Mesh.cpp | 20 ++-- Graphics/Post.cpp | 26 ++--- 4 files changed, 150 insertions(+), 157 deletions(-) diff --git a/Common/VertexArray.cpp b/Common/VertexArray.cpp index 2b610dcd87..8b874065cf 100644 --- a/Common/VertexArray.cpp +++ b/Common/VertexArray.cpp @@ -1,4 +1,4 @@ -// $Id: VertexArray.cpp,v 1.13 2006-08-22 01:58:32 geuzaine Exp $ +// $Id: VertexArray.cpp,v 1.14 2006-08-22 15:34:34 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -19,7 +19,7 @@ // // Please report all bugs and problems to <gmsh@geuz.org>. -#include "Gmsh.h" +#include <algorithm> #include "VertexArray.h" #include "Context.h" #include "Numeric.h" @@ -27,166 +27,142 @@ extern Context_T CTX; VertexArray::VertexArray(int numNodesPerElement, int numElements) + : fill(0), _type(numNodesPerElement) { - type = numNodesPerElement; - if(type < 1 || type > 4){ - Msg(GERROR, "Vertex arrays not done for %d-node element", type); - type = 3; - } - fill = 0; - if(!numElements) - numElements = 1; - int nb = numElements * numNodesPerElement; - vertices = List_Create(nb * 3, 3000, sizeof(float)); - normals = List_Create(nb * 3, 3000, sizeof(char)); - colors = List_Create(nb * 4, 4000, sizeof(unsigned char)); -} - -VertexArray::~VertexArray() -{ - List_Delete(vertices); - List_Delete(normals); - List_Delete(colors); -} - -int VertexArray::n() -{ - return List_Nbr(vertices) / 3; -} - -template<class T> -inline void List_Add_3(List_T * liste, T *data1, T *data2, T *data3) -{ - liste->n += 3; - List_Realloc(liste, liste->n); - liste->isorder = 0; - T* dest1 = (T*)&liste->array[(liste->n - 3) * liste->size]; - T* dest2 = (T*)&liste->array[(liste->n - 2) * liste->size]; - T* dest3 = (T*)&liste->array[(liste->n - 1) * liste->size]; - *dest1 = *data1; - *dest2 = *data2; - *dest3 = *data3; -} - -template<class T> -inline void List_Add_4(List_T * liste, T *data1, T *data2, T *data3, T *data4) -{ - liste->n += 4; - List_Realloc(liste, liste->n); - liste->isorder = 0; - T* dest1 = (T*)&liste->array[(liste->n - 4) * liste->size]; - T* dest2 = (T*)&liste->array[(liste->n - 3) * liste->size]; - T* dest3 = (T*)&liste->array[(liste->n - 2) * liste->size]; - T* dest4 = (T*)&liste->array[(liste->n - 1) * liste->size]; - *dest1 = *data1; - *dest2 = *data2; - *dest3 = *data3; - *dest4 = *data4; + int nb = (numElements ? numElements : 1) * numNodesPerElement; + _vertices.reserve(nb * 3); + _normals.reserve(nb * 3); + _colors.reserve(nb *4); } void VertexArray::add(float x, float y, float z, float n0, float n1, float n2, unsigned int col) { - List_Add_3(vertices, &x, &y, &z); + _vertices.push_back(x); + _vertices.push_back(y); + _vertices.push_back(z); + // Warning: storing the normals as bytes WILL hurt rendering + // performance... but it reduces significantly the memory footprint. char c0 = float2char(n0); char c1 = float2char(n1); char c2 = float2char(n2); - List_Add_3(normals, &c0, &c1, &c2); + _normals.push_back(c0); + _normals.push_back(c1); + _normals.push_back(c2); unsigned char r = CTX.UNPACK_RED(col); unsigned char g = CTX.UNPACK_GREEN(col); unsigned char b = CTX.UNPACK_BLUE(col); unsigned char a = CTX.UNPACK_ALPHA(col); - List_Add_4(colors, &r, &g, &b, &a); + _colors.push_back(r); + _colors.push_back(g); + _colors.push_back(b); + _colors.push_back(a); } void VertexArray::add(float x, float y, float z, unsigned int col) { - List_Add_3(vertices, &x, &y, &z); + _vertices.push_back(x); + _vertices.push_back(y); + _vertices.push_back(z); unsigned char r = CTX.UNPACK_RED(col); unsigned char g = CTX.UNPACK_GREEN(col); unsigned char b = CTX.UNPACK_BLUE(col); unsigned char a = CTX.UNPACK_ALPHA(col); - List_Add_4(colors, &r, &g, &b, &a); + _colors.push_back(r); + _colors.push_back(g); + _colors.push_back(b); + _colors.push_back(a); } -static double theeye[3]; -int compareTriEye(const void *a, const void *b) -{ - float *q = (float*)a; - float *w = (float*)b; - double d, dq, dw, cgq[3] = { 0., 0., 0. }, cgw[3] = { 0., 0., 0.}; - for(int i = 0; i < 3; i++) { - cgq[0] += q[3*i]; - cgq[1] += q[3*i + 1]; - cgq[2] += q[3*i + 2]; - cgw[0] += w[3*i]; - cgw[1] += w[3*i + 1]; - cgw[2] += w[3*i + 2]; +class AlphaElement { +public: + AlphaElement(float *vp, char *np, unsigned char *cp) : v(vp), n(np), c(cp) {} + float *v; + char *n; + unsigned char *c; +}; + +class AlphaElementLessThan { + public: + static int numVertices; + static double eye[3]; + bool operator()(const AlphaElement &e1, const AlphaElement &e2) const + { + double cg1[3] = { 0., 0., 0. }, cg2[3] = { 0., 0., 0.}; + for(int i = 0; i < numVertices; i++) { + cg1[0] += e1.v[3 * i]; + cg1[1] += e1.v[3 * i + 1]; + cg1[2] += e1.v[3 * i + 2]; + cg2[0] += e2.v[3 * i]; + cg2[1] += e2.v[3 * i + 1]; + cg2[2] += e2.v[3 * i + 2]; + } + double d1, d2; + prosca(eye, cg1, &d1); + prosca(eye, cg2, &d2); + if(d1 < d2) + return true; + return false; } - prosca(theeye, cgq, &dq); - prosca(theeye, cgw, &dw); - d = dq - dw; - if(d > 0) - return 1; - if(d < 0) - return -1; - return 0; -} +}; + +int AlphaElementLessThan::numVertices = 0; +double AlphaElementLessThan::eye[3] = {0., 0., 0.}; void VertexArray::sort(double eye[3]) { - // sort assumes that the all the arrays are filled - if(!List_Nbr(vertices) || !List_Nbr(normals) || !List_Nbr(colors)) - return; - - if(type != 3){ - Msg(GERROR, "VertexArray sort only implemented for triangles"); - return; - } - - theeye[0] = eye[0]; - theeye[1] = eye[1]; - theeye[2] = eye[2]; - - int num = n() / 3; - int nb = List_Nbr(vertices) + List_Nbr(normals) + List_Nbr(colors); - float *tmp = new float[nb]; + // This simplementation is pretty bad: it copies the whole data + // twice. We should think about a more efficient way to sort the + // three arrays in place. + + AlphaElementLessThan::numVertices = getType(); + AlphaElementLessThan::eye[0] = eye[0]; + AlphaElementLessThan::eye[1] = eye[1]; + AlphaElementLessThan::eye[2] = eye[2]; + + int n = getNumVertices() / getType(); + + std::vector<AlphaElement> elements; + elements.reserve(n); + if(_normals.size()) + for(int i = 0; i < n; i++) + elements.push_back(AlphaElement(&_vertices[3 * getType() * i], + &_normals[3 * getType() * i], + &_colors[4 * getType() * i])); + else + for(int i = 0; i < n; i++) + elements.push_back(AlphaElement(&_vertices[3 * getType() * i], + 0, + &_colors[4 * getType() * i])); - int iv = 0, in = 0, ic = 0, k = 0; - for(int i = 0; i < num; i++){ - for(int j = 0; j < 9; j++) - List_Read(vertices, iv++, &tmp[k++]); - for(int j = 0; j < 9; j++) - List_Read(normals, in++, &tmp[k++]); - for(int j = 0; j < 12; j++){ - unsigned char c; - List_Read(colors, ic++, &c); - tmp[k++] = c; + std::sort(elements.begin(), elements.end(), AlphaElementLessThan()); + + std::vector<float> sortedVertices; + std::vector<char> sortedNormals; + std::vector<unsigned char> sortedColors; + sortedVertices.reserve(_vertices.size()); + sortedNormals.reserve(_normals.size()); + sortedColors.reserve(_colors.size()); + + for(int i = 0; i < n; i++){ + for(int j = 0; j < getType(); j++){ + for(int k = 0; k < 3; k++){ + sortedVertices.push_back(elements[i].v[3 * j + k]); + if(elements[i].v) + sortedNormals.push_back(elements[i].n[3 * j + k]); + } + for(int k = 0; k < 4; k++){ + sortedColors.push_back(elements[i].c[4 * j + k]); + } } } - List_Reset(vertices); - List_Reset(normals); - List_Reset(colors); - - qsort(tmp, num, (9+9+12)*sizeof(float), compareTriEye); - - k = 0; - for(int i = 0; i < num; i++){ - for(int j = 0; j < 9; j++) - List_Add(vertices, &tmp[k++]); - for(int j = 0; j < 9; j++) - List_Add(normals, &tmp[k++]); - for(int j = 0; j < 12; j++){ - unsigned char c = (unsigned char)tmp[k++]; - List_Add(colors, &c); - } - } - - delete [] tmp; + _vertices = sortedVertices; + _normals = sortedNormals; + _colors = sortedColors; } diff --git a/Common/VertexArray.h b/Common/VertexArray.h index f53b030fab..01f5034889 100644 --- a/Common/VertexArray.h +++ b/Common/VertexArray.h @@ -20,21 +20,34 @@ // // Please report all bugs and problems to <gmsh@geuz.org>. -#include "List.h" +#include "vector" class VertexArray{ public: - int type, fill; - List_T *vertices, *normals, *colors; + int fill; // this must/will be removed + private: + int _type; + std::vector<float> _vertices; + std::vector<char> _normals; + std::vector<unsigned char> _colors; + public: VertexArray(int numNodesPerElement, int numElements); - ~VertexArray(); - // return the number of nodes in the array - int n(); - // add a node in the array + ~VertexArray(){} + // returns the number of nodes in the array + int getNumVertices() { return _vertices.size() / 3; } + // returns the type of the array + int getType() { return _type; } + // returns a pointer to the raw vertex array + float *getVertexArray(){ return &_vertices[0]; } + // returns a pointer to the raw normal array + char *getNormalArray(){ return &_normals[0]; } + // returns a pointer to the raw color array + unsigned char *getColorArray(){ return &_colors[0]; } + // adds a vertex in the arrays void add(float x, float y, float z, float n0, float n1, float n2, unsigned int col); void add(float x, float y, float z, unsigned int col); - // sort the elements back to fron wrt the eye position + // sorts the elements back to front wrt the eye position void sort(double eye[3]); }; diff --git a/Graphics/Mesh.cpp b/Graphics/Mesh.cpp index b24ef9b33b..01c53442cc 100644 --- a/Graphics/Mesh.cpp +++ b/Graphics/Mesh.cpp @@ -1,4 +1,4 @@ -// $Id: Mesh.cpp,v 1.182 2006-08-22 01:58:34 geuzaine Exp $ +// $Id: Mesh.cpp,v 1.183 2006-08-22 15:34:34 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -435,9 +435,9 @@ static void drawArrays(GEntity *e, VertexArray *va, GLint type, bool useNormalAr { if(!va) return; - glVertexPointer(3, GL_FLOAT, 0, va->vertices->array); - glNormalPointer(GL_BYTE, 0, va->normals->array); - glColorPointer(4, GL_UNSIGNED_BYTE, 0, va->colors->array); + glVertexPointer(3, GL_FLOAT, 0, va->getVertexArray()); + glNormalPointer(GL_BYTE, 0, va->getNormalArray()); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, va->getColorArray()); glEnableClientState(GL_VERTEX_ARRAY); @@ -462,13 +462,13 @@ static void drawArrays(GEntity *e, VertexArray *va, GLint type, bool useNormalAr glColor4ubv((GLubyte *) & color); } - if(va->type > 2 && !drawOutline && CTX.polygon_offset) + if(va->getType() > 2 && !drawOutline && CTX.polygon_offset) glEnable(GL_POLYGON_OFFSET_FILL); if(drawOutline) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glDrawArrays(type, 0, va->n()); + glDrawArrays(type, 0, va->getNumVertices()); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisable(GL_POLYGON_OFFSET_FILL); @@ -591,7 +591,9 @@ class initMeshGFace { // Further optimizations are possible when useEdges is true: // 1) store the unique vertices in the vertex array and use - // glDrawElements() instead of glDrawArrays(). + // glDrawElements() instead of glDrawArrays(). Question: + // which normal do you choose for each vertex, and so how + // can you achieve accurate "flat shading" rendering? // 2) use tc to stripe the triangles and draw strips instead of // individual triangles @@ -624,7 +626,7 @@ class drawMeshGFace { MRep *m = f->meshRep; if(CTX.mesh.surfaces_edges){ - if(m->va_lines && m->va_lines->n()){ + if(m->va_lines && m->va_lines->getNumVertices()){ drawArrays(f, m->va_lines, GL_LINES, CTX.mesh.light && CTX.mesh.light_lines, CTX.mesh.surfaces_faces, CTX.color.mesh.line); } @@ -732,7 +734,7 @@ class drawMeshGRegion { MRep *m = r->meshRep; if(CTX.mesh.volumes_edges){ - if(m->va_lines && m->va_lines->n()){ + if(m->va_lines && m->va_lines->getNumVertices()){ drawArrays(r, m->va_lines, GL_LINES, CTX.mesh.light && CTX.mesh.light_lines, CTX.mesh.volumes_faces, CTX.color.mesh.line); } diff --git a/Graphics/Post.cpp b/Graphics/Post.cpp index 13c9be08ff..4c7d65b553 100644 --- a/Graphics/Post.cpp +++ b/Graphics/Post.cpp @@ -1,4 +1,4 @@ -// $Id: Post.cpp,v 1.111 2006-08-18 21:11:43 geuzaine Exp $ +// $Id: Post.cpp,v 1.112 2006-08-22 15:34:34 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -749,25 +749,27 @@ void Draw_Post(void) pass_1: if(v->TriVertexArray && v->TriVertexArray->fill){ - Msg(DEBUG, "View[%d]; %d tris in vertex array", v->Index, v->TriVertexArray->n()/3); + Msg(DEBUG, "View[%d]; %d tris in vertex array", + v->Index, v->TriVertexArray->getNumVertices()/3); v->TriVertexArray->fill = 0; } if(v->LinVertexArray && v->LinVertexArray->fill){ - Msg(DEBUG, "View[%d]; %d segs in vertex array", v->Index, v->LinVertexArray->n()/2); + Msg(DEBUG, "View[%d]; %d segs in vertex array", + v->Index, v->LinVertexArray->getNumVertices()/2); v->LinVertexArray->fill = 0; } } - if(v->TriVertexArray && v->TriVertexArray->n()){ + if(v->TriVertexArray && v->TriVertexArray->getNumVertices()){ if(CTX.alpha && ColorTable_IsAlpha(&v->CT) && !v->FakeTransparency && (changedEye() || v->Changed)){ Msg(DEBUG, "Sorting View[%d] for transparency (WITH vertex array)", v->Index); v->TriVertexArray->sort(storedEye); } - glVertexPointer(3, GL_FLOAT, 0, v->TriVertexArray->vertices->array); - glNormalPointer(GL_BYTE, 0, v->TriVertexArray->normals->array); - glColorPointer(4, GL_UNSIGNED_BYTE, 0, v->TriVertexArray->colors->array); + glVertexPointer(3, GL_FLOAT, 0, v->TriVertexArray->getVertexArray()); + glNormalPointer(GL_BYTE, 0, v->TriVertexArray->getNormalArray()); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, v->TriVertexArray->getColorArray()); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); @@ -778,7 +780,7 @@ void Draw_Post(void) else glDisableClientState(GL_NORMAL_ARRAY); if(CTX.polygon_offset) glEnable(GL_POLYGON_OFFSET_FILL); - glDrawArrays(GL_TRIANGLES, 0, v->TriVertexArray->n()); + glDrawArrays(GL_TRIANGLES, 0, v->TriVertexArray->getNumVertices()); glDisable(GL_POLYGON_OFFSET_FILL); glDisable(GL_LIGHTING); @@ -787,12 +789,12 @@ void Draw_Post(void) glDisableClientState(GL_COLOR_ARRAY); } - if(v->LinVertexArray && v->LinVertexArray->n()){ - glVertexPointer(3, GL_FLOAT, 0, v->LinVertexArray->vertices->array); - glColorPointer(4, GL_UNSIGNED_BYTE, 0, v->LinVertexArray->colors->array); + if(v->LinVertexArray && v->LinVertexArray->getNumVertices()){ + glVertexPointer(3, GL_FLOAT, 0, v->LinVertexArray->getVertexArray()); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, v->LinVertexArray->getColorArray()); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); - glDrawArrays(GL_LINES, 0, v->LinVertexArray->n()); + glDrawArrays(GL_LINES, 0, v->LinVertexArray->getNumVertices()); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } -- GitLab