Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://visualizationlibrary.org */ 00005 /* */ 00006 /* Copyright (c) 2005-2010, Michele Bosi */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without modification, */ 00010 /* are permitted provided that the following conditions are met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, this */ 00013 /* list of conditions and the following disclaimer. */ 00014 /* */ 00015 /* - Redistributions in binary form must reproduce the above copyright notice, this */ 00016 /* list of conditions and the following disclaimer in the documentation and/or */ 00017 /* other materials provided with the distribution. */ 00018 /* */ 00019 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */ 00020 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ 00021 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ 00022 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */ 00023 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ 00024 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ 00025 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ 00026 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ 00027 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */ 00028 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 00029 /* */ 00030 /**************************************************************************************/ 00031 00032 #include <vlGraphics/Extrusion.hpp> 00033 #include <vlGraphics/Tessellator.hpp> 00034 #include <vlCore/glsl_math.hpp> 00035 00036 using namespace vl; 00037 00038 ref<Geometry> Extrusion::extrude() 00039 { 00040 if (silhouette().empty()) 00041 { 00042 Log::error("Extrusion::extrude(): no silhouette defined.\n"); 00043 return NULL; 00044 } 00045 if (positionPath().empty()) 00046 { 00047 Log::error("Extrusion::extrude() needs at least a non empty positionPath().\n"); 00048 return NULL; 00049 } 00050 if (!scalingPath().empty() && scalingPath().size() != positionPath().size()-2) 00051 { 00052 Log::error("Extrusion::extrude(): scalingPath() must have the same number of control points as positionPath().\n"); 00053 return NULL; 00054 } 00055 if (!rotationPath().empty() && rotationPath().size() != positionPath().size()-2) 00056 { 00057 Log::error("Extrusion::extrude(): rotationPath() must have the same number of control points as positionPath().\n"); 00058 return NULL; 00059 } 00060 if (!colorPath().empty() && colorPath().size() != positionPath().size()-2) 00061 { 00062 Log::error("Extrusion::extrude(): colorPath() must have the same number of control points as positionPath().\n"); 00063 return NULL; 00064 } 00065 00066 ref<Geometry> geom = new Geometry; 00067 00068 size_t segments = positionPath().size()-2; 00069 00070 std::vector<fvec3> verts; 00071 verts.resize( silhouette().size() * segments ); 00072 00073 vl::fmat4 m = fmat4::getRotation(fvec3(0,1,0),positionPath()[1]-positionPath()[0]); 00074 00075 // initialize silhouette on the x/z plane 00076 std::vector<vl::fvec3> projected_sil; 00077 projected_sil.resize(silhouette().size()); 00078 for(unsigned i=0; i<silhouette().size(); ++i) 00079 { 00080 projected_sil[i] = m * vl::fvec3(silhouette()[i].x(),0,silhouette()[i].y()) + positionPath()[0]; 00081 } 00082 00083 // initialize plane normals from 1 to n-1 (end points are excluded) 00084 std::vector<fvec3> plane_normals; 00085 plane_normals.resize(positionPath().size()); 00086 for(unsigned i=1; i<plane_normals.size()-1; ++i) 00087 { 00088 fvec3 p0 = positionPath()[i-1] - positionPath()[i]; 00089 fvec3 p1 = positionPath()[i+1] - positionPath()[i]; 00090 p0.normalize(); 00091 p1.normalize(); 00092 plane_normals[i] = (p1-p0).normalize(); 00093 } 00094 00095 for(unsigned i=1; i<positionPath().size()-1; ++i) 00096 { 00097 for(int j=0; j<(int)silhouette().size(); ++j) 00098 { 00099 fvec3 V = (positionPath()[i] - positionPath()[i-1]).normalize(); 00100 const fvec3& P = projected_sil[j]; 00101 const fvec3& orig = positionPath()[i]; 00102 const fvec3& N = plane_normals [i]; 00103 float d = dot(N,orig); 00104 float t = dot(V,N) ? (d-dot(P,N))/dot(V,N) : 0 /*error*/; 00105 // project current projected_sil on next plane along p0->p1 vector 00106 verts.at(j+silhouette().size()*(i-1)) = projected_sil[j] = P + V*t; 00107 } 00108 } 00109 00110 // rotation 00111 if(!rotationPath().empty()) 00112 { 00113 for(unsigned i=1; i<positionPath().size()-1; ++i) 00114 { 00115 fvec3 r = (positionPath()[i+1] - positionPath()[i]).normalize(); 00116 fmat4 mat = vl::fmat4::getRotation(rotationPath()[i-1],r); 00117 fvec3 c; 00118 for(int j=0; j<(int)silhouette().size(); ++j) 00119 c += verts.at(j+silhouette().size()*(i-1)); 00120 c /= (float)silhouette().size(); 00121 for(int j=0; j<(int)silhouette().size(); ++j) 00122 verts.at(j+silhouette().size()*(i-1)) = (mat*(verts.at(j+silhouette().size()*(i-1))-c))+c; 00123 } 00124 } 00125 00126 // scaling 00127 if(!scalingPath().empty()) 00128 { 00129 for(unsigned i=1; i<positionPath().size()-1; ++i) 00130 { 00131 float s = scalingPath()[i-1]; 00132 fvec3 c; 00133 for(int j=0; j<(int)silhouette().size(); ++j) 00134 c += verts.at(j+silhouette().size()*(i-1)); 00135 c /= (float)silhouette().size(); 00136 for(int j=0; j<(int)silhouette().size(); ++j) 00137 verts.at(j+silhouette().size()*(i-1)) = (s*(verts.at(j+silhouette().size()*(i-1))-c))+c; 00138 } 00139 } 00140 00141 int prof_count = silhouetteMode() == SilhouetteClosed ? (int)silhouette().size() : (int)silhouette().size()-1; 00142 ref<DrawElementsUInt> de = new DrawElementsUInt(PT_QUADS); 00143 geom->drawCalls()->push_back(de.get()); 00144 de->indexBuffer()->resize(4 * prof_count * (segments-1)); 00145 for(size_t iseg=0; iseg<segments-1; ++iseg) 00146 { 00147 for(int iquad=0; iquad<prof_count; ++iquad) 00148 { 00149 de->indexBuffer()->at(iquad*4+iseg*4*prof_count + 3) = (iseg + 0) * (GLuint)silhouette().size() + iquad; 00150 de->indexBuffer()->at(iquad*4+iseg*4*prof_count + 2) = (iseg + 0) * (GLuint)silhouette().size() + (iquad+1)%silhouette().size(); 00151 de->indexBuffer()->at(iquad*4+iseg*4*prof_count + 1) = (iseg + 1) * (GLuint)silhouette().size() + (iquad+1)%silhouette().size(); 00152 de->indexBuffer()->at(iquad*4+iseg*4*prof_count + 0) = (iseg + 1) * (GLuint)silhouette().size() + iquad; 00153 } 00154 } 00155 00156 // bottom/top caps 00157 00158 size_t tess_bottom_count = 0; 00159 size_t tess_top_count = 0; 00160 00161 if(fillBottom()) 00162 { 00163 size_t start = verts.size(); 00164 Tessellator tessellator; 00165 tessellator.contours().push_back((int)silhouette().size()); 00166 for(unsigned i=0; i<silhouette().size(); ++i) 00167 tessellator.contourVerts().push_back((dvec3)verts[i]); 00168 tessellator.setWindingRule(vl::TW_TESS_WINDING_NONZERO); 00169 tessellator.tessellate(); 00170 for(unsigned i=0; i<tessellator.tessellatedTris().size(); ++i) 00171 verts.push_back(tessellator.tessellatedTris()[i]); 00172 if (tessellator.tessellatedTris().size()) 00173 geom->drawCalls()->push_back( new DrawArrays(PT_TRIANGLES, start, tessellator.tessellatedTris().size()) ); 00174 tess_bottom_count = tessellator.tessellatedTris().size(); 00175 } 00176 if(fillTop()) 00177 { 00178 size_t start = verts.size(); 00179 Tessellator tessellator; 00180 tessellator.contours().push_back(silhouette().size()); 00181 for(unsigned i=0; i<silhouette().size(); ++i) 00182 tessellator.contourVerts().push_back((dvec3)verts[verts.size()-i-1-tess_bottom_count]); 00183 tessellator.setWindingRule(vl::TW_TESS_WINDING_NONZERO); 00184 tessellator.tessellate(); 00185 for(unsigned i=0; i<tessellator.tessellatedTris().size(); ++i) 00186 verts.push_back(tessellator.tessellatedTris()[i]); 00187 if (tessellator.tessellatedTris().size()) 00188 geom->drawCalls()->push_back( new DrawArrays(PT_TRIANGLES, start, tessellator.tessellatedTris().size()) ); 00189 tess_top_count = tessellator.tessellatedTris().size(); 00190 } 00191 00192 ref<ArrayFloat3> vert_array = new ArrayFloat3; 00193 geom->setVertexArray( vert_array.get() ); 00194 vert_array->initFrom(verts); 00195 00196 if (!colorPath().empty()) 00197 { 00198 ref<ArrayFloat4> col_array = new ArrayFloat4; 00199 geom->setColorArray(col_array.get()); 00200 col_array->resize(geom->vertexArray()->size()); 00201 int offs = 0; 00202 for(size_t iseg=0; iseg<segments; ++iseg) 00203 { 00204 for(unsigned j=0; j<silhouette().size(); ++j, ++offs) 00205 col_array->at(offs) = colorPath()[iseg]; 00206 } 00207 if (fillBottom()) 00208 { 00209 for(unsigned j=0; j<tess_bottom_count; ++j, ++offs) 00210 col_array->at(offs) = colorPath()[0]; 00211 } 00212 if (fillTop()) 00213 { 00214 for(unsigned j=0; j<tess_top_count; ++j, ++offs) 00215 col_array->at(offs) = colorPath().back(); 00216 } 00217 } 00218 00219 if (!smooth()) 00220 geom->convertDrawCallToDrawArrays(); 00221 00222 geom->computeNormals(); 00223 00224 return geom; 00225 }