Logo
  • Main Page
  • Related Pages
  • Modules
  • Classes
  • Files

mms3dpolygonmesh.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2007 Stefan Schwarzer, Jens Schneider,             *
00003  *                           Matthias Hardt, Guido Madaus                  *
00004  *                                                                         *
00005  *   Copyright (C) 2007-2008 BerLinux Solutions GbR                        *
00006  *                           Stefan Schwarzer & Guido Madaus               *
00007  *                                                                         *
00008  *   Copyright (C) 2009-2013 BerLinux Solutions GmbH                       *
00009  *                                                                         *
00010  *   Authors:                                                              *
00011  *      Stefan Schwarzer   <stefan.schwarzer@diskohq.org>,                 *
00012  *      Matthias Hardt     <matthias.hardt@diskohq.org>,                   *
00013  *      Jens Schneider     <jens.schneider@diskohq.org>,                   *
00014  *      Guido Madaus       <guido.madaus@diskohq.org>,                     *
00015  *      Patrick Helterhoff <patrick.helterhoff@diskohq.org>,               *
00016  *      René Bählkow       <rene.baehlkow@diskohq.org>                     *
00017  *                                                                         *
00018  *   This library is free software; you can redistribute it and/or         *
00019  *   modify it under the terms of the GNU Lesser General Public            *
00020  *   License version 2.1 as published by the Free Software Foundation.     *
00021  *                                                                         *
00022  *   This library is distributed in the hope that it will be useful,       *
00023  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00024  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00025  *   Lesser General Public License for more details.                       *
00026  *                                                                         *
00027  *   You should have received a copy of the GNU Lesser General Public      *
00028  *   License along with this library; if not, write to the                 *
00029  *   Free Software Foundation, Inc.,                                       *
00030  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
00031  **************************************************************************/
00032 
00033 #include "mmsgui/3d/mms3dpolygonmesh.h"
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <math.h>
00037 
00038 
00039 MMS3DPolygonMesh::MMS3DPolygonMesh() {
00040 
00041     // reset number of items to zero
00042     this->pm_items_cnt = 0;
00043 
00044     // init vertex and index array
00045     this->varrays_cnt = 0;
00046     this->varrays[varrays_cnt] = NULL;
00047     this->iarrays_cnt = 0;
00048     this->iarrays[iarrays_cnt] = NULL;
00049 }
00050 
00051 void MMS3DPolygonMesh::genRectangle(float width, float height,
00052                     MMS_VERTEX_ARRAY    *vertices,
00053                     MMS_VERTEX_ARRAY    *normals,
00054                     MMS_VERTEX_ARRAY    *texcoords,
00055                     MMS_INDEX_ARRAY     *indices) {
00056 
00057     // allocate memory for buffers
00058     initVertexArray(vertices,   2, 4);
00059     initVertexArray(normals,    3, 4);
00060     initVertexArray(texcoords,  2, 4);
00061 
00062     // we do NOT need an index array data buffer, because all elements are in correctly sequence
00063     initIndexArray(indices, MMS_INDEX_ARRAY_TYPE_TRIANGLE_STRIP);
00064 
00065     // vertices
00066     MMS_VA_SET_VERTEX_2v(vertices, 0, -width/2, -height/2);
00067     MMS_VA_SET_VERTEX_2v(vertices, 1, width/2,  -height/2);
00068     MMS_VA_SET_VERTEX_2v(vertices, 2, -width/2, height/2);
00069     MMS_VA_SET_VERTEX_2v(vertices, 3, width/2,  height/2);
00070 
00071     // normals
00072     MMS_VA_SET_VERTEX_3v(normals, 0, 0, 0, 1);
00073     MMS_VA_SET_VERTEX_3v(normals, 1, 0, 0, 1);
00074     MMS_VA_SET_VERTEX_3v(normals, 2, 0, 0, 1);
00075     MMS_VA_SET_VERTEX_3v(normals, 3, 0, 0, 1);
00076 
00077     // texcoords
00078     MMS_VA_SET_VERTEX_2v(texcoords, 0, 0, 0);
00079     MMS_VA_SET_VERTEX_2v(texcoords, 1, 1, 0);
00080     MMS_VA_SET_VERTEX_2v(texcoords, 2, 0, 1);
00081     MMS_VA_SET_VERTEX_2v(texcoords, 3, 1, 1);
00082 }
00083 
00084 void MMS3DPolygonMesh::genSphere(int numSlices, float radius,
00085                 MMS_VERTEX_ARRAY    *vertices,
00086                 MMS_VERTEX_ARRAY    *normals,
00087                 MMS_VERTEX_ARRAY    *texcoords,
00088                 MMS_INDEX_ARRAY     *indices) {
00089     int i;
00090     int j;
00091     int numParallels = numSlices / 2;
00092     float angleStep = (2.0f * MMS_PI) / ((float) numSlices);
00093 
00094     // allocate memory for buffers
00095     initVertexArray(vertices,   3, (numParallels + 1) * (numSlices + 1));
00096     initVertexArray(normals,    3, (numParallels + 1) * (numSlices + 1));
00097     initVertexArray(texcoords,  2, (numParallels + 1) * (numSlices + 1));
00098     initIndexArray(indices, MMS_INDEX_ARRAY_TYPE_TRIANGLES, numParallels * numSlices * 6);
00099 
00100     for ( i = 0; i < numParallels + 1; i++ ) {
00101         for ( j = 0; j < numSlices + 1; j++ ) {
00102             int v = ( i * (numSlices + 1) + j );
00103 
00104             // vertices
00105             MMS_VA_SET_VERTEX_3v(vertices, v,
00106                                  radius * sinf ( angleStep * (float)i ) * sinf ( angleStep * (float)j ),
00107                                  radius * cosf ( angleStep * (float)i ),
00108                                  radius * sinf ( angleStep * (float)i ) * cosf ( angleStep * (float)j ));
00109 
00110             // normals
00111             if (vertices) {
00112                 float *vdata = (float *)vertices->data;
00113                 MMS_VA_SET_VERTEX_3v(normals, v,
00114                                      vdata[v * vertices->eSize + 0] / radius,
00115                                      vdata[v * vertices->eSize + 1] / radius,
00116                                      vdata[v * vertices->eSize + 2] / radius);
00117             }
00118 
00119             // texcoords
00120             MMS_VA_SET_VERTEX_2v(texcoords, v,
00121                                  (float) j / (float) numSlices,
00122                                  ( 1.0f - (float) i ) / (float) (numParallels - 1 ));
00123         }
00124     }
00125 
00126     // generate the indices
00127     if (indices) {
00128         unsigned int *idata = (unsigned int *)indices->data;
00129         for ( i = 0; i < numParallels ; i++) {
00130             for ( j = 0; j < numSlices; j++) {
00131                 *idata++ = i * ( numSlices + 1 ) + j;
00132                 *idata++ = ( i + 1 ) * ( numSlices + 1 ) + j;
00133                 *idata++ = ( i + 1 ) * ( numSlices + 1 ) + ( j + 1 );
00134                 *idata++ = i * ( numSlices + 1 ) + j;
00135                 *idata++ = ( i + 1 ) * ( numSlices + 1 ) + ( j + 1 );
00136                 *idata++ = i * ( numSlices + 1 ) + ( j + 1 );
00137             }
00138         }
00139     }
00140 }
00141 
00142 void MMS3DPolygonMesh::genTorus(int numwraps, int numperwrap, float majorradius, float minorradius,
00143                 MMS_VERTEX_ARRAY    *vertices,
00144                 MMS_VERTEX_ARRAY    *normals,
00145                 MMS_VERTEX_ARRAY    *texcoords,
00146                 MMS_INDEX_ARRAY     *indices) {
00147 
00148 
00149     // we use triangle strip, so same number of elements for all buffers
00150     int eNum = (numwraps * numperwrap + 1) * 2;
00151 
00152     // allocate memory for buffers
00153     initVertexArray(vertices,   3, eNum);
00154     initVertexArray(normals,    3, eNum);
00155     initVertexArray(texcoords,  2, eNum);
00156 
00157     // we do NOT need an index array data buffer, because all elements are in correctly sequence
00158     initIndexArray(indices, MMS_INDEX_ARRAY_TYPE_TRIANGLE_STRIP);
00159 
00160     // init buffer index
00161     int index = 0;
00162 
00163     // calculate it
00164     float PI2 = 2.0f * MMS_PI;
00165     bool final = false;
00166     while (1) {
00167         for (int i = 0; i < numwraps; i++) {
00168             for (int j = 0; j < numperwrap; j++) {
00169 
00170                 float wrapFrac = (j % numperwrap) / (float)numperwrap;
00171                 float phi = PI2*wrapFrac;
00172                 float sinphi = sin(phi);
00173                 float cosphi = cos(phi);
00174                 float y = minorradius * sinphi;
00175                 float r = majorradius + minorradius * cosphi;
00176 
00177                 for (int k = i; k <= i + 1; k++) {
00178 
00179                     float theta = PI2 * (k % numwraps+wrapFrac) / (float)numwraps;
00180                     float sintheta = sin(theta);
00181                     float costheta = cos(theta);
00182                     float x = sintheta * r;
00183                     float z = costheta * r;
00184 
00185                     // normals
00186                     MMS_VA_SET_VERTEX_3v(normals, index,
00187                                          sintheta * cosphi,
00188                                          sinphi,
00189                                          costheta * cosphi);
00190 
00191                     // vertices
00192                     MMS_VA_SET_VERTEX_3v(vertices, index, x, y, z);
00193 
00194                     index++;
00195                 }
00196 
00197                 if (final) break;
00198             }
00199             if (final) break;
00200         }
00201         if (final) break;
00202         final = true;
00203     }
00204 }
00205 
00206 void MMS3DPolygonMesh::genCylinder(int numSlices, float height, float radius,
00207                     MMS_VERTEX_ARRAY    *vertices,
00208                     MMS_VERTEX_ARRAY    *normals,
00209                     MMS_VERTEX_ARRAY    *texcoords,
00210                     MMS_INDEX_ARRAY     *indices) {
00211 
00212 
00213     // we use triangle strip, so same number of elements for all buffers
00214     int eNum = (numSlices + 1) * 2;
00215 
00216     // allocate memory for buffers
00217     initVertexArray(vertices,   3, eNum);
00218     initVertexArray(normals,    3, eNum);
00219     initVertexArray(texcoords,  2, eNum);
00220 
00221     // we do NOT need an index array data buffer, because all elements are in correctly sequence
00222     initIndexArray(indices, MMS_INDEX_ARRAY_TYPE_TRIANGLE_STRIP);
00223 
00224     // init buffer index
00225     int index = 0;
00226 
00227     // calculate it
00228     float angleStep = 2.0f * MMS_PI / ((float) numSlices);
00229     float z0 = 0.5 * height;
00230     float z1 = z0 - height;
00231 
00232     for (int j = 0; j <= numSlices; j++) {
00233         float a = j * angleStep;
00234         float x = radius * cos(a);
00235         float y = radius * sin(a);
00236 
00237         // normals
00238         MMS_VA_SET_VERTEX_3v(normals, index,    x / radius, y / radius, 0);
00239         MMS_VA_SET_VERTEX_3v(normals, index+1,  x / radius, y / radius, 0);
00240 
00241         // vertices
00242         MMS_VA_SET_VERTEX_3v(vertices, index,   x, y, z0);
00243         MMS_VA_SET_VERTEX_3v(vertices, index+1, x, y, z1);
00244 
00245         // texcoords
00246         MMS_VA_SET_VERTEX_2v(texcoords, index,      j / (float) numSlices, 0);
00247         MMS_VA_SET_VERTEX_2v(texcoords, index+1,    j / (float) numSlices, 1);
00248 
00249         index+=2;
00250     }
00251 }
00252 
00253 int MMS3DPolygonMesh::findPMItem(MMS3DPM_TYPE type, MMS3DPM_MESHID identifier, int *vertices, int *normals, int *texcoords, int *indices) {
00254     for (int i = 0; i < this->pm_items_cnt; i++) {
00255         MMS3DPM_ITEM *item = &this->pm_items[i];
00256 
00257         if (item->type != type)
00258                 continue;
00259         if (memcmp(item->identifier, identifier, 8 * sizeof(float)))
00260                 continue;
00261         if (vertices && item->vertices < 0)
00262                 continue;
00263         if (normals && item->normals < 0)
00264                 continue;
00265         if (texcoords && item->texcoords < 0)
00266                 continue;
00267         if (indices && item->indices < 0)
00268                 continue;
00269 
00270         // successfully found, return buffer indices
00271         if (vertices) *vertices  = item->vertices;
00272         if (normals)  *normals   = item->normals;
00273         if (texcoords)*texcoords = item->texcoords;
00274         if (indices)  *indices   = item->indices;
00275 
00276         return i;
00277     }
00278 
00279     return -1;
00280 }
00281 
00282 int MMS3DPolygonMesh::newPMItem(MMS3DPM_TYPE type, MMS3DPM_MESHID identifier, int *vertices, int *normals, int *texcoords, int *indices) {
00283     if (this->pm_items_cnt >= MMS3DPM_ITEM_MAX) {
00284         // no more space
00285         return -1;
00286     }
00287 
00288     // get new item
00289     MMS3DPM_ITEM *item = &this->pm_items[this->pm_items_cnt];
00290     this->pm_items_cnt++;
00291     item->type = type;
00292     memcpy(item->identifier, identifier, 8 * sizeof(float));
00293 
00294     // get new indices for the new item
00295     if (vertices) {
00296         item->vertices = *vertices = this->varrays_cnt;
00297         this->varrays[item->vertices] = &this->vabuf[this->varrays_cnt];
00298         this->varrays_cnt++;
00299         this->varrays[this->varrays_cnt] = NULL;
00300     }
00301     else {
00302         item->vertices = -1;
00303     }
00304     if (normals) {
00305         item->normals = *normals = this->varrays_cnt;
00306         this->varrays[item->normals] = &this->vabuf[this->varrays_cnt];
00307         this->varrays_cnt++;
00308         this->varrays[this->varrays_cnt] = NULL;
00309     }
00310     else {
00311         item->normals = -1;
00312     }
00313     if (texcoords) {
00314         item->texcoords = *texcoords = varrays_cnt;
00315         varrays[item->texcoords] = &this->vabuf[this->varrays_cnt];
00316         varrays_cnt++;
00317         varrays[varrays_cnt] = NULL;
00318     }
00319     else {
00320         item->texcoords = -1;
00321     }
00322     if (indices) {
00323         item->indices = *indices = this->iarrays_cnt;
00324         this->iarrays[item->indices] = &this->iabuf[this->iarrays_cnt];
00325         this->iarrays_cnt++;
00326         this->iarrays[this->iarrays_cnt] = NULL;
00327     }
00328     else {
00329         item->indices = -1;
00330     }
00331 
00332     switch (type) {
00333     case MMS3DPM_TYPE_RECTANGLE:
00334         genRectangle(identifier[0], identifier[1],
00335                     (vertices) ? this->varrays[*vertices] : NULL,
00336                     (normals)  ? this->varrays[*normals]  : NULL,
00337                     (texcoords)? this->varrays[*texcoords]: NULL,
00338                     (indices)  ? this->iarrays[*indices]  : NULL);
00339         break;
00340     case MMS3DPM_TYPE_SPHERE:
00341         genSphere(identifier[0], identifier[1],
00342                     (vertices) ? this->varrays[*vertices] : NULL,
00343                     (normals)  ? this->varrays[*normals]  : NULL,
00344                     (texcoords)? this->varrays[*texcoords]: NULL,
00345                     (indices)  ? this->iarrays[*indices]  : NULL);
00346         break;
00347     case MMS3DPM_TYPE_TORUS:
00348         genTorus(identifier[0], identifier[1], identifier[2], identifier[3],
00349                     (vertices) ? this->varrays[*vertices] : NULL,
00350                     (normals)  ? this->varrays[*normals]  : NULL,
00351                     (texcoords)? this->varrays[*texcoords]: NULL,
00352                     (indices)  ? this->iarrays[*indices]  : NULL);
00353         break;
00354     case MMS3DPM_TYPE_CYLINDER:
00355         genCylinder(identifier[0], identifier[1], identifier[2],
00356                     (vertices) ? this->varrays[*vertices] : NULL,
00357                     (normals)  ? this->varrays[*normals]  : NULL,
00358                     (texcoords)? this->varrays[*texcoords]: NULL,
00359                     (indices)  ? this->iarrays[*indices]  : NULL);
00360         break;
00361     case MMS3DPM_TYPE_PRIMITIVES:
00362         break;
00363     }
00364 
00365     return this->pm_items_cnt - 1;
00366 }
00367 
00368 int MMS3DPolygonMesh::newPMItem(MMS3DPM_TYPE type, MMS3DPM_MESHID identifier,
00369                                 MMS_VERTEX_ARRAY *vertices, MMS_VERTEX_ARRAY *normals,
00370                                 MMS_VERTEX_ARRAY *texcoords, MMS_INDEX_ARRAY *indices) {
00371     if (this->pm_items_cnt >= MMS3DPM_ITEM_MAX) {
00372         // no more space
00373         return -1;
00374     }
00375 
00376     // get new item
00377     MMS3DPM_ITEM *item = &this->pm_items[this->pm_items_cnt];
00378     this->pm_items_cnt++;
00379     item->type = type;
00380     memcpy(item->identifier, identifier, 8 * sizeof(float));
00381 
00382     // get new indices for the new item
00383     if (vertices) {
00384         item->vertices = this->varrays_cnt;
00385         this->varrays[item->vertices] = &this->vabuf[this->varrays_cnt];
00386         this->varrays_cnt++;
00387         this->varrays[this->varrays_cnt] = NULL;
00388     }
00389     else {
00390         item->vertices = -1;
00391     }
00392     if (normals) {
00393         item->normals = this->varrays_cnt;
00394         this->varrays[item->normals] = &this->vabuf[this->varrays_cnt];
00395         this->varrays_cnt++;
00396         this->varrays[this->varrays_cnt] = NULL;
00397     }
00398     else {
00399         item->normals = -1;
00400     }
00401     if (texcoords) {
00402         item->texcoords = varrays_cnt;
00403         varrays[item->texcoords] = &this->vabuf[this->varrays_cnt];
00404         varrays_cnt++;
00405         varrays[varrays_cnt] = NULL;
00406     }
00407     else {
00408         item->texcoords = -1;
00409     }
00410     if (indices) {
00411         item->indices = this->iarrays_cnt;
00412         this->iarrays[item->indices] = &this->iabuf[this->iarrays_cnt];
00413         this->iarrays_cnt++;
00414         this->iarrays[this->iarrays_cnt] = NULL;
00415     }
00416     else {
00417         item->indices = -1;
00418     }
00419 
00420     // copy buffers
00421     if (item->vertices >= 0) {
00422         if (initVertexArray(this->varrays[item->vertices], vertices->eSize, vertices->eNum, vertices->dtype))
00423             memcpy(this->varrays[item->vertices]->data, vertices->data, getVertexArraySize(vertices));
00424     }
00425     if (item->normals >= 0) {
00426         if (initVertexArray(this->varrays[item->normals], normals->eSize, normals->eNum, normals->dtype))
00427             memcpy(this->varrays[item->normals]->data, normals->data, getVertexArraySize(normals));
00428     }
00429     if (item->texcoords >= 0) {
00430         if (initVertexArray(this->varrays[item->texcoords], texcoords->eSize, texcoords->eNum, texcoords->dtype))
00431             memcpy(this->varrays[item->texcoords]->data, texcoords->data, getVertexArraySize(texcoords));
00432     }
00433     if (item->indices >= 0) {
00434         if (initIndexArray(this->iarrays[item->indices], indices->type, indices->eNum))
00435             memcpy(this->iarrays[item->indices]->data, indices->data, getIndexArraySize(indices));
00436     }
00437 
00438     return this->pm_items_cnt - 1;
00439 }
00440 
00441 void MMS3DPolygonMesh::getArrays(MMS_VERTEX_ARRAY ***varrays, MMS_INDEX_ARRAY ***iarrays) {
00442     *varrays = this->varrays;
00443     *iarrays = this->iarrays;
00444 }
00445 
00446 bool MMS3DPolygonMesh::setPrimitives(string id, MMS_VERTEX_ARRAY *vertices, MMS_VERTEX_ARRAY *normals,
00447                                      MMS_VERTEX_ARRAY *texcoords, MMS_INDEX_ARRAY *indices) {
00448     MMS3DPM_MESHID identifier;
00449     memset(&identifier[0], 0, sizeof(identifier));
00450     int len = id.size();
00451     if (len >= sizeof(identifier))
00452         len = sizeof(identifier) - 1;
00453     memcpy(&identifier[0], id.c_str(), len);
00454 
00455     if (findPMItem(MMS3DPM_TYPE_PRIMITIVES, identifier, NULL, NULL, NULL, NULL) < 0) {
00456         // primitives mesh does not exist, generate it
00457         return (newPMItem(MMS3DPM_TYPE_PRIMITIVES, identifier, vertices, normals, texcoords, indices) >= 0);
00458     }
00459 
00460     // duplicate key
00461     return false;
00462 }
00463 
00464 bool MMS3DPolygonMesh::getPrimitives(string id, int *vertices, int *normals, int *texcoords, int *indices) {
00465     MMS3DPM_MESHID identifier;
00466     memset(&identifier[0], 0, sizeof(identifier));
00467     int len = id.size();
00468     if (len >= sizeof(identifier))
00469         len = sizeof(identifier) - 1;
00470     memcpy(&identifier[0], id.c_str(), len);
00471 
00472     return (findPMItem(MMS3DPM_TYPE_PRIMITIVES, identifier, vertices, normals, texcoords, indices) >= 0);
00473 }
00474 
00475 bool MMS3DPolygonMesh::genRectangle(float width, float height, int *vertices, int *normals, int *texcoords, int *indices) {
00476     MMS3DPM_MESHID identifier = {width, height, 0, 0, 0, 0, 0, 0};
00477     if (findPMItem(MMS3DPM_TYPE_RECTANGLE, identifier, vertices, normals, texcoords, indices) < 0) {
00478         // rectangle mesh does not exist, generate it
00479         return (newPMItem(MMS3DPM_TYPE_RECTANGLE, identifier, vertices, normals, texcoords, indices) >= 0);
00480     }
00481     return true;
00482 }
00483 
00484 bool MMS3DPolygonMesh::genSphere(int numSlices, float radius, int *vertices, int *normals, int *texcoords, int *indices) {
00485     MMS3DPM_MESHID identifier = {numSlices, radius, 0, 0, 0, 0, 0, 0};
00486     if (findPMItem(MMS3DPM_TYPE_SPHERE, identifier, vertices, normals, texcoords, indices) < 0) {
00487         // sphere mesh does not exist, generate it
00488         return (newPMItem(MMS3DPM_TYPE_SPHERE, identifier, vertices, normals, texcoords, indices) >= 0);
00489     }
00490     return true;
00491 }
00492 
00493 bool MMS3DPolygonMesh::genTorus(int numwraps, int numperwrap, float majorradius, float minorradius,
00494                                 int *vertices, int *normals, int *texcoords, int *indices) {
00495     MMS3DPM_MESHID identifier = {numwraps, numperwrap, majorradius, minorradius, 0, 0, 0, 0};
00496     if (findPMItem(MMS3DPM_TYPE_TORUS, identifier, vertices, normals, texcoords, indices) < 0) {
00497         // torus mesh does not exist, generate it
00498         return (newPMItem(MMS3DPM_TYPE_TORUS, identifier, vertices, normals, texcoords, indices) >= 0);
00499     }
00500     return true;
00501 }
00502 
00503 bool MMS3DPolygonMesh::genCylinder(int numSlices, float height, float radius,
00504                                    int *vertices, int *normals, int *texcoords, int *indices) {
00505     MMS3DPM_MESHID identifier = {numSlices, height, radius, 0, 0, 0, 0, 0};
00506     if (findPMItem(MMS3DPM_TYPE_CYLINDER, identifier, vertices, normals, texcoords, indices) < 0) {
00507         // cylinder mesh does not exist, generate it
00508         return (newPMItem(MMS3DPM_TYPE_CYLINDER, identifier, vertices, normals, texcoords, indices) >= 0);
00509     }
00510     return true;
00511 }
00512 
00513 
00514 

Generated by doxygen