OSGQuadTreeTerrain.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *               Copyright (C) 2000-2002 by the OpenSG Forum                 *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038 
00039 /* Stefan Roettgers Quadtree Tesselation Algorithm
00040     http://wwwvis.informatik.uni-stuttgart.de/~roettger/data/Papers/TERRAIN.PDF
00041    This code is based on a Java3D Implementation by Martin Barbisch, 
00042    University Stuttgart
00043    http://wwwvis.informatik.uni-stuttgart.de/javatevi/
00044  */
00045 
00046 //---------------------------------------------------------------------------
00047 //  Includes
00048 //---------------------------------------------------------------------------
00049 
00050 #include <cstdlib>
00051 #include <cstdio>
00052 #include <sstream>
00053 
00054 #include <OSGConfig.h>
00055 
00056 #include "OSGQuadTreeTerrain.h"
00057 #include "OSGImage.h"
00058 #include "OSGRenderAction.h"
00059 #include "OSGMaterial.h"
00060 #include <OSGChunkMaterial.h>
00061 #include <OSGTextureObjChunk.h>
00062 #include <OSGTextureEnvChunk.h>
00063 #include <OSGSHLParameterChunk.h>
00064 #include "OSGTypedGeoIntegralProperty.h"
00065 
00066 OSG_USING_NAMESPACE
00067 
00068 // min global res., the higher the more vertices
00069 static const Real32 MinGlobalRes  = 10.0f; 
00070 static const UInt32 
00071     NW = 0, 
00072     W = 1, 
00073     SW = 2, 
00074     S = 3, 
00075     SE = 4, 
00076     E = 5, 
00077     NE = 6, 
00078     N = 7, 
00079     C = 8;
00080 
00081 // switch to fill Geometry with TRIANGLE_FANS instead of TRIANGLES
00082 //#define WITH_TRIANGLE_FANS
00083 
00084 // switch to share a single SHLChunk with several SHLParameterChunks
00085 //#define WITH_SINGLE_SHLCHUNK
00086 
00087 // Documentation for this class is emited in the
00088 // OSGQuadTreeTerrainBase.cpp file.
00089 // To modify it, please change the .fcd file (OSGQuadTreeTerrain.fcd) and
00090 // regenerate the base file.
00091 
00092 /***************************************************************************\
00093  *                           Class variables                               *
00094 \***************************************************************************/
00095 
00096 /***************************************************************************\
00097  *                           Class methods                                 *
00098 \***************************************************************************/
00099 
00100 void QuadTreeTerrain::initMethod(InitPhase ePhase)
00101 {
00102     Inherited::initMethod(ePhase);
00103 
00104     if(ePhase == TypeObject::SystemPost)
00105     {
00106         RenderAction::registerEnterDefault(
00107             getClassType(), 
00108             reinterpret_cast<Action::Callback>(&QuadTreeTerrain::renderEnter));
00109     }
00110 }
00111 
00112 
00113 /***************************************************************************\
00114  *                           Instance methods                              *
00115 \***************************************************************************/
00116 
00117 /*-------------------------------------------------------------------------*\
00118  -  private                                                                 -
00119 \*-------------------------------------------------------------------------*/
00120 
00121 /*----------------------- constructors & destructors ----------------------*/
00122 
00123 QuadTreeTerrain::QuadTreeTerrain(void) :
00124     Inherited()
00125 {
00126 }
00127 
00128 QuadTreeTerrain::QuadTreeTerrain(const QuadTreeTerrain &source) :
00129     Inherited(source)
00130 {
00131 }
00132 
00133 QuadTreeTerrain::~QuadTreeTerrain(void)
00134 {
00135 }
00136 
00137 Real32 QuadTreeTerrain::getHeightDataScaled (UInt32 i) const
00138 {
00139    switch(getHeightData()->getDataType()) 
00140    {
00141        default:
00142        case Image::OSG_INVALID_IMAGEDATATYPE:
00143        case Image::OSG_UINT8_IMAGEDATA:
00144 
00145            return 
00146                ((UInt8*) getHeightData()->getData())[i] /
00147                Real32(TypeTraits<UInt8>::getMax());
00148 
00149        case Image::OSG_UINT16_IMAGEDATA:
00150 
00151            return 
00152                ((UInt16*)getHeightData()->getData())[i] /
00153                Real32(TypeTraits<UInt16>::getMax());
00154 
00155        case Image::OSG_UINT32_IMAGEDATA:
00156            return 
00157                ((UInt32*)getHeightData()->getData())[i] /
00158                Real32(TypeTraits<UInt32>::getMax());
00159 
00160        case Image::OSG_FLOAT16_IMAGEDATA:
00161            return ((Real16*)getHeightData()->getData())[i];
00162 
00163        case Image::OSG_FLOAT32_IMAGEDATA:
00164            return ((Real32*)getHeightData()->getData())[i];
00165    };
00166 }
00167 
00168 void QuadTreeTerrain::getVertex(UInt32 i, Pnt3f &point) const
00169 {
00170     GeoPnt3fPropertyPtr pos = 
00171         dynamic_cast<GeoPnt3fPropertyPtr>(getHeightVertices());
00172 
00173    point.setValue(pos->getField()[i]);
00174 }
00175 const Pnt3f &QuadTreeTerrain::getVertex(UInt32 i) const
00176 {
00177    GeoPnt3fPropertyPtr pos = 
00178        dynamic_cast<GeoPnt3fPropertyPtr>(getHeightVertices());
00179 
00180    return pos->getField()[i];
00181 }
00182 UInt32 QuadTreeTerrain::getNumVertices(void) const
00183 {
00184    GeoPnt3fPropertyPtr pos = 
00185        dynamic_cast<GeoPnt3fPropertyPtr>(getHeightVertices());
00186 
00187    return pos->getField().size();
00188 }
00189 
00190 // GLSL programs
00191 
00192 // vertex shader program for bump mapping in surface local coordinates
00193 static std::string _vp_program =
00194 "const vec3   planenormal   = vec3 (0.0, 0.0, 1.0);\n"
00195 "const vec3   planebinormal = vec3 (0.0, 1.0, 0.0);\n"
00196 "const vec3   planetangent  = vec3 (1.0, 0.0, 0.0);\n"
00197 "varying vec3 lightDir;    // interpolated surface local coordinate light direction\n"
00198 "varying vec3 viewDir;     // interpolated surface local coordinate view direction\n"
00199 
00200 "void main(void)\n"
00201 "{\n"
00202 "    // Do standard vertex stuff\n"
00203 
00204 "    gl_Position    = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
00205 "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
00206 
00207 "    // Compute the binormal\n"
00208 "    vec3 n = normalize(gl_NormalMatrix * planenormal);\n"
00209 "    vec3 t = normalize(gl_NormalMatrix * planetangent);\n"
00210 "    vec3 b = cross(n, t);\n"
00211 
00212 "    // Transform light position into surface local coordinates\n"
00213 "    vec3 LightPosition = gl_LightSource[0].position.xyz;\n"
00214 
00215 "    vec3 v;\n"
00216 "    v.x = dot(LightPosition, t);\n"
00217 "    v.y = dot(LightPosition, b);\n"
00218 "    v.z = dot(LightPosition, n);\n"
00219 
00220 "    lightDir = normalize(v);\n"
00221 
00222 "    vec3 pos = vec3 (gl_ModelViewMatrix * gl_Vertex);\n"
00223 "    v.x = dot(pos, t);\n"
00224 "    v.y = dot(pos, b);\n"
00225 "    v.z = dot(pos, n);\n"
00226 
00227 "    viewDir = normalize(v);\n"
00228 "\n"
00229 "}\n";
00230 
00231 // fragment shader program for bump mapping in surface local coordinates
00232 static std::string _fp_program =
00233 "uniform sampler2D texSampler;\n"
00234 "uniform sampler2D nmapSampler;\n"
00235 "uniform float offsetS;\n"
00236 "uniform float offsetT;\n"
00237 "uniform float scaleS;\n"
00238 "uniform float scaleT;\n"
00239 "uniform float specularExponent;\n"
00240 "uniform float diffuseFactor;\n"
00241 "uniform float specularFactor;\n"
00242 "uniform vec3  basecolor;\n"
00243 "varying vec3 lightDir;       // interpolated surface local coordinate light direction\n"
00244 "varying vec3 viewDir;        // interpolated surface local coordinate view direction\n"
00245 
00246 "void main (void)\n"
00247 "{\n"
00248 "    vec3 norm;\n"
00249 "    vec3 r;\n"
00250 "    vec3 color;\n"
00251 "    vec3 texcolor;\n"
00252 "    float intensity;\n"
00253 "    float spec;\n"
00254 "    float d;\n"
00255 "    // Fetch normal from normal map\n"
00256 "    vec2 nmapST = vec2 (gl_TexCoord[0])*vec2(scaleS, scaleT) + vec2(offsetS, offsetT);\n"
00257 "    norm = vec3(texture2D(nmapSampler, nmapST));\n"
00258 "    norm = (norm - 0.5) * 2.0;\n"
00259 "    // Compute diffuse reflection\n"
00260 "    d = dot(lightDir, norm);\n"
00261 "    intensity = max(d, 0.0) * diffuseFactor;\n"
00262 "    // Compute specular reflection\n"
00263 "    d = 2.0 * d;\n"
00264 "    r = d * norm;\n"
00265 "    r = lightDir - r;\n"
00266 "    spec = pow(max(dot(r, viewDir), 0.0), specularExponent) * specularFactor;\n"
00267 "    intensity += min (spec, 1.0);\n"
00268 "    // mix texture color and lighting color\n"
00269 "    texcolor = vec3(texture2D(texSampler, vec2 (gl_TexCoord[0])));\n"
00270 "    color = clamp(texcolor * basecolor * intensity, 0.0, 1.0);\n"
00271 "    // Write out final fragment color\n"
00272 "    gl_FragColor = vec4 (color, 1.0);\n"
00273 "\n"
00274 "}\n";
00275 
00276 // SHLChunk initialized in QuadTreeTerrain::changed
00277 static SHLChunkPtr s_shlChunk;
00278 
00279 SHLChunkPtr QuadTreeTerrain::createSHLChunk () const
00280 {
00281    SHLChunkPtr shl = SHLChunk::create();
00282 
00283    shl->setVertexProgram  (_vp_program);
00284    shl->setFragmentProgram(_fp_program);
00285 
00286    // CF without the following addRefCP, 
00287    // it crashes on changing SHLParameterChunks in Terrain::addMaterialChunks
00288 
00289    addRef(shl);
00290 
00291    return shl;
00292 }
00293 
00294 
00295 // ARB vertex and fragment programs
00296 // generated out of GLSL programs by 
00297 // cgc -oglsl -strict -profile arbvp1 vertex.glsl   -o perpixel.avp
00298 // cgc -oglsl -strict -profile arbfp1 fragment.glsl -o perpixel.afp
00299 
00300 // CF does not work currently!
00301 
00302 static std::string _avp_program =
00303 "!!ARBvp1.0\n"
00304 "PARAM mv[4]    = { state.matrix.modelview };\n"
00305 "PARAM mvp[4]   = { state.matrix.mvp };\n"
00306 "PARAM mvinv[4] = { state.matrix.modelview.invtrans };\n"
00307 "PARAM light0   = state.light[0].position;\n"
00308 "TEMP R0;\n"
00309 "TEMP R1;\n"
00310 "TEMP R2;\n"
00311 "TEMP R3;\n"
00312 "TEMP R4;\n"
00313 "TEMP R5;\n"
00314 "MOV result.texcoord[0], vertex.texcoord[0];\n"
00315 "MUL R0, vertex.position.y, mvp[1];\n"
00316 "//MUL R3.xyz, vertex.position.y, mv[1];\n"
00317 "//MOV R2.xyz, mvinv[0];\n"
00318 "//MOV R1.xyz, mvinv[2];\n"
00319 "//DP3 R1.w, mvinv[2], R1;\n"
00320 "//DP3 R2.x, mvinv[0], R2;\n"
00321 "//MAD R1.xyz, vertex.position.x, mv[0], R3;\n"
00322 "MAD R0, vertex.position.x, mvp[0], R0;\n"
00323 "MAD R0, vertex.position.z, mvp[2], R0;\n"
00324 "//MAD R1.xyz, vertex.position.z, mv[2], R1;\n"
00325 "//RSQ R2.x, R2.x;\n"
00326 "//MAD R4.xyz, vertex.position.w, mv[3], R1;\n"
00327 "//RSQ R1.x, R1.w;\n"
00328 "//MUL R2.xyz, R2.x, mvinv[0];\n"
00329 "//MUL R1.xyz, R1.x, mvinv[2];\n"
00330 "//DP3 R5.z, R4, R1;\n"
00331 "//DP3 R5.x, R4, R2;\n"
00332 "//DP3 R1.w, R1, light0;\n"
00333 "//MUL R3.xyz, R1.zxyw, R2.yzxw;\n"
00334 "//MAD R3.xyz, R1.yzxw, R2.zxyw, -R3;\n"
00335 "//DP3 R1.x, R2, light0;\n"
00336 "//DP3 R1.y, R3, light0;\n"
00337 "//DP3 R5.y, R4, R3;\n"
00338 "//DP3 R1.z, R1.xyww, R1.xyww;\n"
00339 "//DP3 R2.x, R5, R5;\n"
00340 "//RSQ R1.z, R1.z;\n"
00341 "MAD result.position, vertex.position.w, mvp[3], R0;\n"
00342 "//RSQ R0.x, R2.x;\n"
00343 "//MUL result.texcoord[1].xyz, R1.z, R1.xyww;\n"
00344 "//MUL result.texcoord[2].xyz, R0.x, R5;\n"
00345 "END\n"
00346 "# 31 instructions, 6 R-regs\n";
00347 
00348 VertexProgramChunkPtr QuadTreeTerrain::createVPChunk () const
00349 {
00350    std::istringstream vpcode(_avp_program.c_str());
00351 
00352    VertexProgramChunkPtr vp = VertexProgramChunk::create();
00353    vp->read(vpcode);
00354 
00355    // parameter come here
00356 
00357    addRef(vp);
00358 
00359    return vp;
00360 }
00361 
00362 static std::string _afp_program =
00363 "!!ARBfp1.0\n"
00364 "PARAM c[9] = { program.local[0..4], { 0.5, 2, 0, 1 }, program.local[6..8] };\n"
00365 "TEMP R0;\n"
00366 "TEMP R1;\n"
00367 "MOV R0.w, c[4].x;\n"
00368 "MOV R0.z, c[3].x;\n"
00369 "MOV R0.x, c[1];\n"
00370 "MOV R0.y, c[2].x;\n"
00371 "MAD R0.xy, fragment.texcoord[0], R0, R0.zwzw;\n"
00372 "TEX R0.xyz, R0, texture[1], 2D;\n"
00373 "ADD R0.xyz, R0, -c[5].x;\n"
00374 "MUL R1.xyz, R0, c[5].y;\n"
00375 "DP3 R0.x, fragment.texcoord[1], R1;\n"
00376 "MUL R1.xyz, R0.x, R1;\n"
00377 "MAD R1.xyz, -R1, c[5].y, fragment.texcoord[1];\n"
00378 "DP3 R0.y, R1, fragment.texcoord[2];\n"
00379 "MAX R0.y, R0, c[5].z;\n"
00380 "POW R0.y, R0.y, c[7].x;\n"
00381 "MUL R0.y, R0, c[8].x;\n"
00382 "MIN R1.x, R0.y, c[5].w;\n"
00383 "MAX R0.w, R0.x, c[5].z;\n"
00384 "TEX R0.xyz, fragment.texcoord[0], texture[0], 2D;\n"
00385 "MAD R0.w, R0, c[6].x, R1.x;\n"
00386 "MUL R0.xyz, R0, c[0];\n"
00387 "MUL_SAT result.color.xyz, R0, R0.w;\n"
00388 "MOV result.color.w, c[5];\n"
00389 "MOV result.color, c[5];\n"
00390 "END\n"
00391 "# 22 instructions, 2 R-regs\n";
00392 
00393 FragmentProgramChunkPtr QuadTreeTerrain::createFPChunk () const
00394 {
00395    std::istringstream fpcode(_afp_program.c_str());
00396 
00397    FragmentProgramChunkPtr fp = FragmentProgramChunk::create();
00398 
00399    fp->read(fpcode);
00400    // parameter come here
00401    fp->addParameter("offsetS", 
00402                     3, 
00403                     Vec4f(1.0f/getTexSpacing(), 
00404                           1.0f/getTexSpacing(), 
00405                           1.0f/getTexSpacing(), 
00406                           1.0f/getTexSpacing()));
00407    
00408    fp->addParameter("scaleS",  1, 
00409                     Vec4f(-getOriginTexX()/getTexSpacing(),  
00410                           -getOriginTexX()/getTexSpacing(), 
00411                           -getOriginTexX()/getTexSpacing(), 
00412                           -getOriginTexX()/getTexSpacing()));
00413 
00414    if(getTexYSpacing() != 1.0f) 
00415    {
00416        fp->addParameter("offsetT", 
00417                         4, 
00418                         Vec4f(-getOriginTexY()/getTexYSpacing(), 
00419                               -getOriginTexY()/getTexYSpacing(), 
00420                               -getOriginTexY()/getTexYSpacing(), 
00421                               -getOriginTexY()/getTexYSpacing()));
00422 
00423        fp->addParameter("scaleT",  
00424                         2, 
00425                         Vec4f(1.0f/getTexYSpacing(), 
00426                               1.0f/getTexYSpacing(), 
00427                               1.0f/getTexYSpacing(), 
00428                               1.0f/getTexYSpacing()));
00429    } 
00430    else 
00431    {
00432        fp->addParameter("offsetT", 
00433                         4, Vec4f(-getOriginTexY()/getTexSpacing(), 
00434                                  -getOriginTexY()/getTexSpacing(), 
00435                                  -getOriginTexY()/getTexSpacing(), 
00436                                  -getOriginTexY()/getTexSpacing()));
00437 
00438        fp->addParameter("scaleT",  
00439                         2, 
00440                         Vec4f(1.0f/getTexSpacing(), 
00441                               1.0f/getTexSpacing(), 
00442                               1.0f/getTexSpacing(), 
00443                               1.0f/getTexSpacing()));
00444    }
00445 
00446    fp->addParameter("diffuseFactor",    6, Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
00447    fp->addParameter("specularExponent", 7, Vec4f(6.0f, 6.0f, 6.0f, 6.0f));
00448    fp->addParameter("specularFactor",   8, Vec4f(0.2f, 0.2f, 0.2f, 0.2f));
00449    fp->addParameter("basecolor",        0, Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
00450 
00451    addRef(fp);
00452 
00453    return fp;
00454 }
00455 
00456 void QuadTreeTerrain::addMaterialChunks(void) const
00457 {
00458 #if 1
00459 #ifndef WITH_SINGLE_SHLCHUNK
00460 
00461    SHLParameterChunkPtr shlp = SHLParameterChunk::create();
00462 
00463    shlp->setSHLChunk(s_shlChunk);
00464    shlp->setUniformParameter("texSampler",  0);
00465    shlp->setUniformParameter("nmapSampler", 1);
00466    // the following spares a second set of texture coordinates
00467    shlp->setUniformParameter("offsetS",    -getOriginTexX()/getTexSpacing());
00468    shlp->setUniformParameter("scaleS",     1.0f/getTexSpacing());
00469 
00470    if(getTexYSpacing() != 1.0f) 
00471    {
00472        shlp->setUniformParameter("offsetT", -getOriginTexY()/getTexYSpacing());
00473        shlp->setUniformParameter("scaleT",   1.0f/getTexYSpacing());
00474    } 
00475    else
00476    {
00477        shlp->setUniformParameter("offsetT", -getOriginTexY()/getTexSpacing());
00478        shlp->setUniformParameter("scaleT",   1.0f/getTexSpacing());
00479    }
00480 
00481    shlp->setUniformParameter("diffuseFactor",    1.0f);
00482    shlp->setUniformParameter("specularFactor",   0.2f);
00483    shlp->setUniformParameter("specularExponent", 6.0f);
00484    shlp->setUniformParameter("basecolor",        Vec3f(1.0, 1.0, 1.0));
00485 
00486 #else
00487 
00488    SHLChunkPtr shl = SHLChunk::create();
00489 
00490    shl->setVertexProgram  (_vp_program);
00491    shl->setFragmentProgram(_fp_program);
00492    shl->setUniformParameter("texSampler",  0);
00493    shl->setUniformParameter("nmapSampler", 1);
00494    // the following spares a second set of texture coordinates
00495 
00496    shl->setUniformParameter("offsetS",    -getOriginTexX()/getTexSpacing());
00497    shl->setUniformParameter("scaleS",     1.0f/getTexSpacing());
00498 
00499    if(getTexYSpacing() != 1.0f) 
00500    {
00501        shl->setUniformParameter("offsetT", -getOriginTexY()/getTexYSpacing());
00502       shl->setUniformParameter("scaleT",    1.0f/getTexYSpacing());
00503    } 
00504    else 
00505    {
00506        shl->setUniformParameter("offsetT", -getOriginTexY()/getTexSpacing());
00507        shl->setUniformParameter("scaleT",   1.0f/getTexSpacing());
00508    }
00509 
00510    shl->setUniformParameter("diffuseFactor",    1.0f);
00511    shl->setUniformParameter("specularFactor",   0.2f);
00512    shl->setUniformParameter("specularExponent", 6.0f);
00513    shl->setUniformParameter("basecolor",        Vec3f(1.0, 1.0, 1.0));
00514 
00515 #endif
00516 
00517 #else
00518    VertexProgramChunkPtr   vp = createVPChunk();
00519    FragmentProgramChunkPtr fp = createFPChunk();
00520 #endif
00521 
00522    ImagePtr           normal_map_img = createNormalMap();
00523    TextureObjChunkPtr tex_normal_map = TextureObjChunk::create();
00524 
00525    tex_normal_map->setImage(normal_map_img);
00526    tex_normal_map->setMinFilter(GL_LINEAR);
00527    tex_normal_map->setMagFilter(GL_LINEAR);
00528    tex_normal_map->setWrapS(GL_CLAMP);
00529    tex_normal_map->setWrapT(GL_CLAMP);
00530    //tex_normal_map->setEnvMode(GL_MODULATE);
00531 
00532    ChunkMaterialPtr mat = dynamic_cast<ChunkMaterialPtr>(getMaterial());
00533 
00534 #if 1
00535 
00536 #ifndef WITH_SINGLE_SHLCHUNK
00537    StateChunkPtr oldSHL  = mat->find(SHLChunk::getClassType());
00538 
00539    if(oldSHL == NullFC) 
00540    {
00541        mat->addChunk(s_shlChunk);
00542    }
00543 
00544    StateChunkPtr oldSHLP = mat->find(SHLParameterChunk::getClassType());
00545 
00546    if(oldSHLP != NullFC) 
00547    {
00548        mat->subChunk(oldSHLP);
00549    }
00550 
00551    mat->addChunk(shlp);
00552 #else
00553    StateChunkPtr oldSHL  = mat->find(SHLChunk::getClassType());
00554 
00555    if(oldSHL != NullFC) 
00556    {
00557        mat->subChunk(oldSHL);
00558    }
00559 
00560    mat->addChunk(shl);
00561 #endif
00562 
00563 #else
00564    StateChunkPtr oldVP  = mat->find(VertexProgramChunk::getClassType());
00565    
00566    if(oldVP != NullFC) 
00567    {
00568        mat->subChunk(oldVP);
00569    }
00570 
00571    mat->addChunk(vp);
00572 
00573    StateChunkPtr oldFP  = mat->find(FragmentProgramChunk::getClassType());
00574    if(oldFP != NullFC) 
00575    {
00576        mat->subChunk(oldFP);
00577    }
00578 
00579    mat->addChunk(fp);
00580 #endif
00581 
00582    StateChunkPtr oldTEX  = mat->find(TextureObjChunk::getClassType(), 1);
00583 
00584    if(oldTEX != NullFC) 
00585    {
00586        mat->subChunk(oldTEX);
00587    }
00588 
00589    mat->addChunk(tex_normal_map, 1);
00590 }
00591 
00592 ImagePtr QuadTreeTerrain::createNormalMap () const
00593 {
00594    ImagePtr out = Image::create();
00595 
00596    out->set(Image::OSG_RGB_PF, getWidth()-1, getWidth()-1, 1, 
00597             1, 1, 0.0f, NULL, Image::OSG_UINT8_IMAGEDATA);
00598 
00599    UInt8* outData = (UInt8*) out->editData();
00600 
00601    GeoPnt3fPropertyPtr pos = dynamic_cast<GeoPnt3fPropertyPtr>(getPositions());
00602 
00603    const Real32  maxData = 0.5f*TypeTraits<UInt8>::getMax();
00604 
00605    UInt32 vnum, inum;
00606 
00607    vnum = inum = 0;
00608 
00609    for(UInt32 z = 0; z < getWidth(); z++) 
00610    {
00611        for (UInt32 x = 0; x < getWidth(); x++, vnum++) 
00612        {
00613            Vec3f tanx, tany, norm;
00614 
00615            if(x == 0 || z == 0) 
00616            {
00617                continue;
00618            }
00619 
00620            //if (x > 0) {
00621            tanx = pos->getValue(vnum)          - pos->getValue(vnum-1);
00622            //} else {
00623            //tanx = pos->getValue(vnum+1)        - pos->getValue(vnum);     
00624            //}
00625            //if (z > 0) {
00626            tany = pos->getValue(vnum) - pos->getValue(vnum-getWidth());
00627            //} else {
00628            //tany = pos->getValue(vnum+getWidth()) - pos->getValue(vnum);
00629            //}
00630            
00631            norm.setValue(tany.cross(tanx)); norm.normalize();
00632            outData[inum]   = UInt8(maxData*(norm[0]+1.0f));
00633            outData[inum+1] = UInt8(maxData*(norm[1]+1.0f));
00634            outData[inum+2] = UInt8(maxData*(norm[2]+1.0f));
00635            inum += 3;
00636        }
00637    }
00638    return out;
00639 }
00640 
00641 
00642 void QuadTreeTerrain::calcD2ErrorMatrix() 
00643 {  
00644     //--- call recursive function for setting initial D2-Values ---
00645     calcD2ErrorMatrixRec(getWidth() / 2, getWidth() / 2, getWidth(), 1);
00646     
00647     //--- ensure max level difference of 1 ------------------------
00648     propagateD2Errors();
00649 }
00650 
00651 void QuadTreeTerrain::calcD2ErrorMatrixRec(Int32 centerX, 
00652                                            Int32 centerZ, 
00653                                            Int32 width, 
00654                                            Int32 level) 
00655 {
00656     if(level <= getLevel()) 
00657     {
00658         Int32 w2 = width / 2;
00659         Int32 w4 = width / 4;
00660         //--- current value ---------------------------------------------------
00661         
00662         Int32 nodeIndex = centerZ * getWidth() + centerX;
00663         
00664         if(level == getLevel()-getBorderDetail() && 
00665            ( centerX <= w2               || 
00666             (getWidth()-centerX) <= w2+1 || 
00667              centerZ <= w2               || 
00668             (getWidth()-centerZ) <= w2+1  )       ) 
00669         {
00670             
00671             editHeightError(nodeIndex) = 
00672                 (getBoundMax()[1]-getBoundMin()[1]) / 
00673                 ((Real32) width * getVertexSpacing());
00674         } 
00675         else if(level > getLevel()-getBorderDetail() && 
00676                 ( centerX <= w2               || 
00677                  (getWidth()-centerX) <= w2+1 || 
00678                   centerZ <= w2               || 
00679                  (getWidth()-centerZ) <= w2+1  )       ) 
00680         { 
00681             editHeightError(nodeIndex) = 0.0f;
00682         } 
00683         else 
00684         {
00685             editHeightError(nodeIndex) = calcD2Value(centerX, centerZ, width);
00686         }
00687         //--- descend tree ------------------------------------------------
00688         
00689         // nw child
00690         calcD2ErrorMatrixRec(centerX - w4, centerZ + w4, w2, level + 1);  
00691         // ne child
00692         calcD2ErrorMatrixRec(centerX + w4, centerZ + w4, w2, level + 1);  
00693         // se child
00694         calcD2ErrorMatrixRec(centerX + w4, centerZ - w4, w2, level + 1);  
00695         // sw child
00696         calcD2ErrorMatrixRec(centerX - w4, centerZ - w4, w2, level + 1);  
00697     }
00698 }
00699 
00700 Real32 QuadTreeTerrain::calcD2Value (Int32 centerX, 
00701                                      Int32 centerZ, 
00702                                      Int32 width) 
00703 {
00704     //--- init needed vars -----------------------------------------------
00705     Int32 rx = width / 2;                       // radius offset in x direction
00706     Int32 rz = rx * getWidth();                 // radius offset in z direction
00707   
00708     Int32 c  = centerZ * getWidth() + centerX;  // center vertex
00709     Int32 n  = c - rz;                          // northern vertex
00710     Int32 w  = c - rx;                          // western
00711     Int32 s  = c + rz;                          // southern
00712     Int32 e  = c + rx;                          // eastern
00713     Int32 nw = n - rx;                          // ...
00714     Int32 sw = s - rx;
00715     Int32 se = s + rx;
00716     Int32 ne = n + rx;
00717   
00718     // shortcut
00719     const GeoPnt3fProperty::StoredFieldType &v = 
00720         dynamic_cast<GeoPnt3fPropertyPtr>(getHeightVertices())->getField(); 
00721     
00722     //--- north, east, south, west errors -------------------------------------
00723     Real32 nErr = osgAbs( v[n][1] -  (v[nw][1] + v[ne][1]) / 2.0f);
00724     Real32 eErr = osgAbs( v[e][1] -  (v[ne][1] + v[se][1]) / 2.0f);
00725     Real32 sErr = osgAbs( v[s][1] -  (v[se][1] + v[sw][1]) / 2.0f);
00726     Real32 wErr = osgAbs( v[w][1] -  (v[sw][1] + v[nw][1]) / 2.0f);
00727     
00728     
00729     //--- 1. and 2. diagonal error --------------------------------------------
00730     
00731     Real32 d1Err = osgAbs( v[c][1] -  (v[nw][1] + v[se][1]) / 2.0f);
00732     Real32 d2Err = osgAbs( v[c][1] -  (v[ne][1] + v[sw][1]) / 2.0f);
00733     
00734     //--- determine max of the 6 errors ---------------------------------------
00735     
00736     Real32 maxErr = osgMax(osgMax(nErr, eErr),
00737                            osgMax(osgMax(sErr, wErr), osgMax(d1Err, d2Err)));
00738     
00739     return (maxErr / ((Real32) width * getVertexSpacing()));
00740 }
00741 
00742 
00743 
00744 void QuadTreeTerrain::propagateD2Errors() 
00745 {
00746     const Real32 D2K = MinGlobalRes / (2.0f * (MinGlobalRes - 1.0f));
00747     
00748     // find the highest level
00749     //--- init vars -----------------------------------------------------------
00750 
00751     Int32 steps = getWidth() / 2;
00752     Int32 width = 2;
00753     
00754     Int32 centerX, centerZ;
00755     
00756     Int32 w2;
00757     Int32 p1, p2, p3;                 // indices of parents
00758     Int32 
00759         p1x = 0, p1z = 0, 
00760         p2x = 0, p2z = 0, 
00761         p3x = 0, p3z = 0;
00762     
00763     MFReal32 &em = editHeightError(); // shortcut
00764     
00765 
00766     //--- iterate through all levels ------------------------------------------
00767     while(steps > 1) 
00768     {
00769         w2 = width / 2;
00770         centerX = w2;
00771         
00772         for(Int32 i = 0; i < steps; i++) 
00773         {
00774             centerZ = w2;
00775             for(Int32 j = 0; j < steps; j++) 
00776             {
00777                 //--- determine parents' indices ------------------------
00778                 switch ((centerX/width)%2 + 2*((centerZ/width)%2)) 
00779                 {
00780                     case 0: 
00781                         p1x = centerX+w2;
00782                         p1z = centerZ+w2;
00783                         p2x = centerX-width-w2;
00784                         p2z = centerZ+w2;
00785                         p3x = centerX+w2;
00786                         p3z = centerZ-width-w2;
00787                         break;
00788                     case 1: 
00789                         p1x = centerX-w2;
00790                         p1z = centerZ+w2;
00791                         p2x = centerX-w2;
00792                         p2z = centerZ-width-w2;
00793                         p3x = centerX+width+w2;
00794                         p3z = centerZ+w2;
00795                         break;
00796                     case 2: 
00797                         p1x = centerX+w2;
00798                         p1z = centerZ-w2;
00799                         p2x = centerX+w2;
00800                         p2z = centerZ+width+w2;
00801                         p3x = centerX-width-w2;
00802                         p3z = centerZ-w2;
00803                         break;
00804                     case 3: 
00805                         p1x = centerX-w2;
00806                         p1z = centerZ-w2;
00807                         p2x = centerX+width+w2;
00808                         p2z = centerZ-w2;
00809                         p3x = centerX-w2;
00810                         p3z = centerZ+width+w2;
00811                         break;
00812                 }
00813                 
00814                 //--- propagate to 3 parents -----------------------------
00815 
00816                 Real32 d2K_EMthis = D2K * em[centerZ * getWidth() + centerX];
00817                 
00818                 //--- to real father -------------------------------------
00819 
00820                 p1     = p1z * getWidth() + p1x;
00821                 em[p1] = osgMax(em[p1], d2K_EMthis);
00822                 
00823                 //--- other 2 "parents" ----------------------------------
00824 
00825                 if(p2x >= 0         &&  
00826                    p2x < getWidth() && 
00827                    p2z >= 0         &&  
00828                    p2z < getWidth()    ) 
00829                 {
00830                     p2     = p2z * getWidth() + p2x;
00831                     em[p2] = osgMax(em[p2], d2K_EMthis);
00832                 }
00833 
00834                 if(p3x >= 0          &&  
00835                    p3x < getWidth()  && 
00836                    p3z >= 0          &&  
00837                    p3z < getWidth()    ) 
00838                 {
00839                     p3     = p3z * getWidth() + p3x;
00840                     em[p3] = osgMax(em[p3], d2K_EMthis);
00841                 }
00842                 
00843                 centerZ += width;                  // advance zPos
00844             }
00845             centerX += width;                          // advance xPos
00846         }
00847         width *= 2;  
00848         steps /= 2;
00849     }
00850 }
00851 
00852 Real32 QuadTreeTerrain::calcSubDiv(Int32 nodeIndex, Int32 width) 
00853 {
00854    //--- calculate the eye distance to each node, using L1-Norm --------------
00855 
00856    const Pnt3f& v = getVertex(nodeIndex);
00857 
00858    Real32 eyeDist = 
00859        osgAbs(v[0] - getEyePoint()[0]) +
00860        osgAbs(getEyeHeight()) +
00861        osgAbs(v[2] - getEyePoint()[2]);
00862    
00863    //--- calc subdiv value ---------------------------------------------------
00864    return 
00865        eyeDist / ((width * getVertexSpacing()) * MinGlobalRes *
00866                   osgMax(getDetail() * getHeightError(nodeIndex), 1.0f));
00867 }
00868 
00869 void QuadTreeTerrain::triangulateMeshRec(const FrustumVolume &frustum, 
00870                                                Int32          c, 
00871                                                Int32          width, 
00872                                                Int32          level) 
00873 {
00874     if(level > getLevel()) 
00875     {  
00876         return;  
00877     }
00878 
00879     //--- check view frustum -------------------------------------------------      
00880 #if 1
00881     if(level <= getLevel() - 2) 
00882     {
00883         Pnt3f point;
00884         getVertex(c, point);
00885         
00886         SphereVolume current(point,
00887                              (0.5f*width) * getVertexSpacing() * 15.0f);
00888         
00889         if(!OSG::intersect(frustum, current))  
00890         {
00891             return;  
00892         }
00893     }
00894 #endif
00895 
00896     //--- go on ---------------------------------------------------------------
00897 
00898     Real32 subDiv = calcSubDiv(c, width);
00899     
00900     Int32   w2     = width / 2;
00901     Int32   w4     = width / 4;
00902     Int32   r      = w4 * getWidth();
00903 
00904     Int32   nw     = c - r - w4;
00905     Int32   ne     = c - r + w4;
00906     Int32   sw     = c + r - w4;
00907     Int32   se     = c + r + w4;
00908     
00909     if(subDiv >= 1.0f) 
00910     { //--- NOT to be drawn --------------------
00911         deleteNode(c, width);
00912         return;
00913     } 
00914     else 
00915     { //--- leaf or parent? ---------------------
00916         editHeightQuad(c) = calcBlend(subDiv);
00917         
00918         triangulateMeshRec(frustum, nw, w2, level+1);
00919         triangulateMeshRec(frustum, ne, w2, level+1);
00920         triangulateMeshRec(frustum, sw, w2, level+1);
00921         triangulateMeshRec(frustum, se, w2, level+1);
00922         
00923         return;
00924     }
00925 }
00926 
00927 //=== Render Terrain-Mesh ===================================================
00928 bool QuadTreeTerrain::renderMeshRec(const FrustumVolume &frustum, 
00929                                           Int32          x, 
00930                                           Int32          z, 
00931                                           Int32          width, 
00932                                           Int32          level, 
00933                                           Int32          dirToFather,
00934                                           Real32         rhNW, 
00935                                           Real32         rhNE, 
00936                                           Real32         rhSW, 
00937                                           Real32         rhSE       ) 
00938 {
00939    // returns true if caller has to draw this corner
00940     Int32 c = z * getWidth() + x;              // center
00941     
00942     if(getHeightQuad(c) == TypeTraits<Real32>::getMax()) 
00943     { // stop recursion
00944         return true;  
00945     }  
00946     
00947     Int32 w2 = width / 2;
00948     Int32 w4 = width / 4;
00949     
00950     
00951     //--- check view frustum --------------------------------------------------
00952 
00953 #if 1
00954     if(level <= getLevel()-2) 
00955     {  
00956         Pnt3f point;
00957         getVertex(c, point);
00958         
00959         SphereVolume current;
00960         current.setCenter(point);
00961         current.setRadius((Real32) w2 * (Real32) getVertexSpacing() * 5.0f);
00962         
00963         if(!OSG::intersect(frustum, current)) 
00964         {  
00965             return false;  
00966         }
00967     }
00968 #endif
00969     
00970     //--- init necessary vars -------------------------------------------------
00971 
00972     Int32 rx = width / 2;             // radius offset in x direction
00973     Int32 rz = rx * getWidth();            // radius offset in z direction
00974     
00975     Int32 n  = c - rz;                // northern vertex
00976     Int32 w  = c - rx;                // western
00977     Int32 s  = c + rz;                // southern
00978     Int32 e  = c + rx;                // eastern
00979     Int32 nw = n - rx;
00980     Int32 sw = s - rx;
00981     Int32 se = s + rx;
00982     Int32 ne = n + rx;
00983     
00984     //--- get all 9 heights ---------------------------------------------------
00985 
00986     Real32 blend = getHeightQuad(c);
00987     
00988     Real32 hC  = getHeight(c, 
00989                            width, 
00990                            dirToFather, 
00991                            C, 
00992                            blend, 
00993                            rhNW, 
00994                            rhNE, 
00995                            rhSW, 
00996                            rhSE);
00997 
00998     Real32 hN  = getHeight(n, 
00999                            width, 
01000                            dirToFather, 
01001                            N, 
01002                            blend, 
01003                            rhNW, 
01004                            rhNE, 
01005                            rhSW, 
01006                            rhSE);
01007 
01008     Real32 hS  = getHeight(s, 
01009                            width, 
01010                            dirToFather, 
01011                            S, 
01012                            blend, 
01013                            rhNW, 
01014                            rhNE, 
01015                            rhSW, 
01016                            rhSE);
01017 
01018     Real32 hW  = getHeight(w, 
01019                            width, 
01020                            dirToFather, 
01021                            W, 
01022                            blend, 
01023                            rhNW, 
01024                            rhNE, 
01025                            rhSW, 
01026                            rhSE);
01027     Real32 hE  = getHeight(e, 
01028                            width, 
01029                            dirToFather, 
01030                            E, 
01031                            blend, 
01032                            rhNW, 
01033                            rhNE, 
01034                            rhSW, 
01035                            rhSE);
01036     
01037     //--- check if node has children ------------------------------------------
01038 
01039     bool corners[] = { true, true, true, true, true, true, true, true };
01040     bool isLeaf  = false;
01041     
01042     if(level < getLevel()) 
01043     {
01044         corners[NW] = renderMeshRec(frustum, 
01045                                     x-w4, 
01046                                     z-w4, 
01047                                     w2, 
01048                                     level+1, 
01049                                     SE, 
01050                                     rhNW, 
01051                                     hN,   
01052                                     hW,   
01053                                     hC );
01054 
01055         corners[NE] = renderMeshRec(frustum, 
01056                                     x+w4, 
01057                                     z-w4, 
01058                                     w2, 
01059                                     level+1, 
01060                                     SW, 
01061                                     hN,   
01062                                     rhNE, 
01063                                     hC,   
01064                                     hE );
01065         
01066         corners[SW] = renderMeshRec(frustum, 
01067                                     x-w4, 
01068                                     z+w4, 
01069                                     w2, 
01070                                     level+1, 
01071                                     NE, 
01072                                     hW,   
01073                                     hC,   
01074                                     rhSW, 
01075                                     hS );
01076 
01077         corners[SE] = renderMeshRec(frustum, 
01078                                     x+w4, 
01079                                     z+w4, 
01080                                     w2, 
01081                                     level+1, 
01082                                     NW, 
01083                                     hC,   
01084                                     hE,   
01085                                     hS,   
01086                                     rhSE);
01087     } 
01088     else
01089     {
01090         isLeaf = true;
01091     }
01092     
01093     if(corners[NW] || corners[SW] || corners[SE] || corners[NE]) 
01094     {
0109