# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# D:/VL/BuildSystem/VL_DISTRO/Visualization_Library_SDK/src/vlGraphics/Terrain.cpp

Go to the documentation of this file.

    00001 /**************************************************************************************/
    00002 /*                                                                                    */
    00003 /*  Visualization Library                                                             */
    00004 /*  http://www.visualizationlibrary.com                                               */
    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/Terrain.hpp>
    00033 #include <vlGraphics/Actor.hpp>
    00034 #include <vlGraphics/Effect.hpp>
    00035 #include <vlGraphics/Geometry.hpp>
    00036 #include <vlGraphics/GLSL.hpp>
    00037 #include <vlGraphics/GeometryPrimitives.hpp>
    00038 #include <vlCore/Log.hpp>
    00039 #include <vlCore/Say.hpp>
    00040
    00041 using namespace vl;
    00042
    00043 void Terrain::init()
    00044 {
    00045   mChunks.clear();
    00046
    00047   if (mWidth <= 0 || mHeight <= 0 || mDepth <= 0 || mDetailRepetitionCount <= 0)
    00048   {
    00049     Log::error(
    00050         Say("Terrain initialization failed: invalid parameters.\n"
    00051              "width = %n\n"
    00052              "hieght = %n\n"
    00053              "depth = %n\n"
    00054              "detail repetition = %n\n")
    00055         << mWidth << mHeight << mDepth << mDetailRepetitionCount
    00056       );
    00057     return;
    00058   }
    00059
    00060   if (useGLSL())
    00061   {
    00062     if(fragmentShader().empty() || vertexShader().empty())
    00063     {
    00064       Log::error("vertex shader or fragment shader not defined.\n");
    00065       /*mFragmentShader = "/glsl/terrain.fs";
    00066       mVertexShader   = "/glsl/terrain.vs";*/
    00067       return;
    00068     }
    00069   }
    00070
    00071   bool use_uniform_transform = false; // experimental only
    00072
    00073   // Log::print("Loading detail texture... ");
    00074   ref<Image> detail_img = detailTexture().empty() ? ref<Image>(NULL) : loadImage(detailTexture());
    00075
    00076   // Log::print("Loading terrain texture... ");
    00077   ref<Image> terrain_img = loadImage(terrainTexture());
    00078
    00079   // Log::print("Loading heightmap... ");
    00080   ref<Image> heightmap_img = loadImage(heightmapTexture());
    00081
    00082   if ( (!detail_img && !detailTexture().empty()) || !terrain_img || !heightmap_img)
    00083   {
    00084     Log::error("Terrain initialization failed.\n");
    00085     return;
    00086   }
    00087
    00088   double dx = width() / heightmap_img->width();
    00089   double dz = depth() / heightmap_img->height();
    00090
    00091   int x_subdivision = -1;
    00092   for(int ch=1; ch<1024; ++ch)
    00093   {
    00094     for(int ts=128; ts<=1024*8; ts*=2)
    00095     {
    00096       // printf("[%d][%d]x = %d\n", ch, ts, ch*ts-ch+1);
    00097       if (ch*ts-ch+1 == heightmap_img->width())
    00098       {
    00099         x_subdivision = ch;
    00100         break;
    00101       }
    00102     }
    00103   }
    00104
    00105   int y_subdivision = -1;
    00106   for(int ch=1; ch<1024; ++ch)
    00107   {
    00108     for(int ts=128; ts<=1024*8; ts*=2)
    00109     {
    00110       // printf("[%d][%d]y = %d\n", ch, ts, ch*ts-ch+1);
    00111       if (ch*ts-ch+1 == heightmap_img->height())
    00112       {
    00113         y_subdivision = ch;
    00114         break;
    00115       }
    00116     }
    00117   }
    00118
    00119   if ( x_subdivision == -1 )
    00120   {
    00121     Log::error("texture width must be of the type: cn*ts-cn+1 where cn=chunk-number, ts=texture-chunk-size\n");
    00122     return;
    00123   }
    00124   if ( y_subdivision == -1 )
    00125   {
    00126     Log::error("texture height must be of the type: cn*ts-cn+1 where cn=chunk-number, ts=texture-chunk-size\n");
    00127     return;
    00128   }
    00129
    00130   int xsize  =   (heightmap_img->width()  -1 + x_subdivision)/x_subdivision;
    00131   int zsize  =   (heightmap_img->height() -1 + y_subdivision)/y_subdivision;
    00132   int tx_xsize = (terrain_img->width()    -1 + x_subdivision)/x_subdivision;
    00133   int tx_zsize = (terrain_img->height()   -1 + y_subdivision)/y_subdivision;
    00134
    00135   float dtu  = float(1.0 / tx_xsize / 2.0);
    00136   float dtv  = float(1.0 / tx_zsize / 2.0);
    00137   float dtu2 = 1.0f - dtu;
    00138   float dtv2 = 1.0f - dtv;
    00139   float du   = float(1.0 / xsize / 2.0);
    00140   float dv   = float(1.0 / zsize / 2.0);
    00141   float du2  = 1.0f - du;
    00142   float dv2  = 1.0f - dv;
    00143
    00144   float detail_du   = detail_img ? float(1.0 / detail_img->width()  / 2.0) : 0;
    00145   float detail_dv   = detail_img ? float(1.0 / detail_img->height() / 2.0) : 0;
    00146   float detail_du2  = mDetailRepetitionCount - detail_du;
    00147   float detail_dv2  = mDetailRepetitionCount - detail_dv;
    00148
    00149   ref<Geometry> terr_tile;
    00150   ref<GLSLProgram> glsl;
    00151
    00152   ref<ArrayFloat2> tmap_uv = new ArrayFloat2; // texture map
    00153   ref<ArrayFloat2> dmap_uv = detail_img ? new ArrayFloat2 : NULL; // detail texture map
    00154   ref<ArrayFloat2> hmap_uv = new ArrayFloat2; // height map
    00155   tmap_uv->resize( xsize * zsize );
    00156   if(detail_img)
    00157     dmap_uv->resize( xsize * zsize );
    00158   hmap_uv->resize( xsize * zsize );
    00159   for(int z=0; z<zsize; ++z)
    00160   {
    00161     for(int x=0; x<xsize; ++x)
    00162     {
    00163       float u = (float)x/(xsize-1); // 0 .. 1
    00164       float v = (float)z/(zsize-1); // 0 .. 1
    00165       tmap_uv->at(x + z*xsize).s() = (1.0f-u) * dtu + u * dtu2;
    00166       tmap_uv->at(x + z*xsize).t() = (1.0f-v) * dtv + v * dtv2;
    00167       if (detail_img)
    00168       {
    00169         dmap_uv->at(x + z*xsize).s() = (1.0f-u) * detail_du + u * detail_du2;
    00170         dmap_uv->at(x + z*xsize).t() = (1.0f-v) * detail_dv + v * detail_dv2;
    00171       }
    00172       hmap_uv->at(x + z*xsize).s() = (1.0f-u) * du + u * du2;
    00173       hmap_uv->at(x + z*xsize).t() = (1.0f-v) * dv + v * dv2;
    00174     }
    00175   }
    00176
    00177   if (useGLSL())
    00178   {
    00179     terr_tile = vl::makeGrid( vec3(0,0,0), 1.0f, 1.0f, xsize, zsize);
    00180     terr_tile->setTexCoordArray(0, tmap_uv.get());
    00181     terr_tile->setTexCoordArray(1, dmap_uv.get());
    00182     terr_tile->setTexCoordArray(2, hmap_uv.get());
    00183
    00184     glsl = new GLSLProgram;
    00185     ref<Uniform> Height = new vl::Uniform("Height");
    00186     Height->setUniformF((float)height());
    00187     glsl->setUniform( Height.get() );
    00188     glsl->attachShader( new GLSLFragmentShader( String::loadText(fragmentShader()) ) );
    00189     if (use_uniform_transform)
    00190       glsl->attachShader( new GLSLVertexShader( String::loadText("/glsl/terrain_ut.vs") ) );
    00191     else
    00192       glsl->attachShader( new GLSLVertexShader( String::loadText(vertexShader()) ) );
    00193
    00194     // setup GLSL program 'static' uniforms
    00195     ref<Uniform> terrain_tex   = new Uniform("terrain_tex");
    00196     ref<Uniform> detail_tex    = new Uniform("detail_tex");
    00197     ref<Uniform> heightmap_tex = new Uniform("heightmap_tex");
    00198     terrain_tex  ->setUniformI(0);
    00199     detail_tex   ->setUniformI(1);
    00200     heightmap_tex->setUniformI(2);
    00201     glsl->setUniform(terrain_tex.get());
    00202     if (!detailTexture().empty())
    00203       glsl->setUniform(detail_tex.get());
    00204     glsl->setUniform(heightmap_tex.get());
    00205
    00206     AABB aabb;
    00207     aabb.setMinCorner((Real)-0.5, 0, (Real)-0.5);
    00208     aabb.setMaxCorner((Real)+0.5, (Real)height(), (Real)+0.5);
    00209     terr_tile->setBoundingBox( aabb );
    00210     terr_tile->setBoundingSphere(aabb);
    00211     terr_tile->setBoundsDirty(false);
    00212
    00213     shaderNode()->setRenderState(glsl.get());
    00214   }
    00215
    00216   shaderNode()->setEnable(EN_CULL_FACE, true);
    00217   shaderNode()->setEnable(EN_DEPTH_TEST,true);
    00218
    00219   if (!useGLSL())
    00220   {
    00221     ref<TexEnv> texenv = new TexEnv(1);
    00222     texenv->setMode(TEM_MODULATE);
    00223     shaderNode()->setRenderState(texenv.get());
    00224   }
    00225
    00226   // generate chunks
    00227   for(int mz=0, tz=0; mz<heightmap_img->height()-1; mz+=zsize-1, tz+=tx_zsize-1)
    00228   {
    00229     for(int mx=0, tx=0; mx<heightmap_img->width()-1; mx+=xsize-1, tx+=tx_xsize-1)
    00230     {
    00231       // effect settings for this tile
    00232       ref<Effect> terr_fx = new Effect;
    00233       ref<ShaderNode> shader_node = new ShaderNode;
    00234       shaderNode()->addChild(shader_node.get());
    00235       shader_node->setShader(terr_fx->shader());
    00236
    00237       // terrain texture
    00238       ref<Image> tex_image = terrain_img->subImage(tx, tz, tx_xsize, tx_zsize);
    00239       ref<TextureUnit> tex_unit0 = new TextureUnit(0);
    00240       shader_node->setRenderState(tex_unit0.get());
    00241       tex_unit0->setTexture(new Texture(tex_image.get(), terrainTextureFormat(), false));
    00242       tex_unit0->texture()->getTexParameter()->setMagFilter(TPF_LINEAR);
    00243       tex_unit0->texture()->getTexParameter()->setMinFilter(TPF_LINEAR);
    00244       tex_unit0->texture()->getTexParameter()->setWrapS(TPW_REPEAT);
    00245       tex_unit0->texture()->getTexParameter()->setWrapT(TPW_REPEAT);
    00246
    00247       // detail texture
    00248       if (detail_img)
    00249       {
    00250         ref<TextureUnit> tex_unit1 = new TextureUnit(1);
    00251         shader_node->setRenderState(tex_unit1.get());
    00252         tex_unit1->setTexture(new Texture(detail_img.get(), detailTextureFormat(), true));
    00253         tex_unit1->texture()->getTexParameter()->setMagFilter(TPF_LINEAR);
    00254         tex_unit1->texture()->getTexParameter()->setMinFilter(TPF_LINEAR_MIPMAP_LINEAR);
    00255         tex_unit1->texture()->getTexParameter()->setWrapS(TPW_REPEAT);
    00256         tex_unit1->texture()->getTexParameter()->setWrapT(TPW_REPEAT);
    00257         if (GLEW_EXT_texture_filter_anisotropic)
    00258         {
    00259           float max = 1.0f;
    00260           glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max);
    00261           tex_unit1->texture()->getTexParameter()->setAnisotropy(max);
    00262         }
    00263       }
    00264
    00265       // heightmap texture
    00266       ref<Image> hmap_image = heightmap_img->subImage(mx, mz, xsize, zsize);
    00267       if (useGLSL())
    00268       {
    00269         ref<TextureUnit> tex_unit2 = new TextureUnit(2);
    00270         shader_node->setRenderState(tex_unit2.get());
    00271         tex_unit2->setTexture(new Texture(hmap_image.get(), heightmapTextureFormat(), false));
    00272         tex_unit2->texture()->getTexParameter()->setMagFilter(TPF_NEAREST);
    00273         tex_unit2->texture()->getTexParameter()->setMinFilter(TPF_NEAREST);
    00274         tex_unit2->texture()->getTexParameter()->setWrapS(TPW_REPEAT);
    00275         tex_unit2->texture()->getTexParameter()->setWrapT(TPW_REPEAT);
    00276       }
    00277
    00278       // compute tile transform
    00279       dmat4 dmat;
    00280       dmat.scale((xsize-1)*dx, 1.0, (zsize-1)*dz);
    00281       dmat.translate(mx*dx + (xsize-1)*dx*0.5 - width()/2.0, 0, mz*dz + (zsize-1)*dz*0.5 - depth()/2.0);
    00282       dmat.translate((dvec3)mOrigin);
    00283       ref<Transform> transform = new Transform;
    00284       transform->setLocalMatrix((mat4)dmat);
    00285       transform->computeWorldMatrix(NULL);
    00286
    00287       if (!useGLSL())
    00288       {
    00289         terr_tile = vl::makeGrid( vec3(0,0,0), 1.0f, 1.0f, xsize, zsize);
    00290         terr_tile->setTexCoordArray(0, tmap_uv.get());
    00291         terr_tile->setTexCoordArray(1, dmap_uv.get());
    00292
    00293         ref<ArrayFloat3> verts = dynamic_cast<ArrayFloat3*>(terr_tile->vertexArray());
    00294         for(int z=0; z<zsize; ++z)
    00295         {
    00296           for(int x=0; x<xsize; ++x)
    00297           {
    00298             fvec4 sample = hmap_image->sample(x,z) * (float)height();
    00299             int index = x + xsize * z;
    00300             verts->at(index).y() = sample.r();
    00301           }
    00302         }
    00303       }
    00304
    00305       // collect the terrain chunks to be inserted later in the ActorKdTree
    00306
    00307       ref<Actor> actor = new Actor(terr_tile.get(), terr_fx.get(), (use_uniform_transform && useGLSL())?NULL:transform.get());
    00308       mChunks.push_back(actor.get());
    00309
    00310       if (use_uniform_transform && useGLSL())
    00311       {
    00312         #if 1
    00313           actor->setUniformSet( new UniformSet );
    00314           ref<Uniform> uniform_matrix = new Uniform("matrix");
    00315           uniform_matrix->setUniform( (fmat4)dmat );
    00316           actor->setUniform( uniform_matrix.get() );
    00317         #else
    00318           ref<Uniform> uniform_matrix = new Uniform("matrix");
    00319           uniform_matrix->setUniform( (mat4)dmat );
    00320           terr_fx->shader()->setUniform( uniform_matrix.get() );
    00321         #endif
    00322       }
    00323
    00324       #if 0 // for debuggin purposes
    00325         // terr_fx->shader()->gocMaterial()->setColorMaterialEnabled(true);
    00326         terr_tile->setColorArray( fvec4(rand()%256/255.0f,rand()%256/255.0f,rand()%256/255.0f) );
    00327       #endif
    00328     }
    00329   }
    00330
    00331   shaderNode()->updateHierarchy();
    00332   tree()->buildKdTree(mChunks);
    00333 }

Visualization Library v2011.05.1142 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 26 2011 22:51:25.
Permission is granted to use this page to write and publish articles regarding Visualization Library.