00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
00066
00067 return;
00068 }
00069 }
00070
00071 bool use_uniform_transform = false;
00072
00073
00074 ref<Image> detail_img = detailTexture().empty() ? ref<Image>(NULL) : loadImage(detailTexture());
00075
00076
00077 ref<Image> terrain_img = loadImage(terrainTexture());
00078
00079
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
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
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;
00153 ref<ArrayFloat2> dmap_uv = detail_img ? new ArrayFloat2 : NULL;
00154 ref<ArrayFloat2> hmap_uv = new ArrayFloat2;
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);
00164 float v = (float)z/(zsize-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
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(IN_Propagate, 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;
00222 texenv->setMode(TEM_MODULATE);
00223 shaderNode()->setRenderState(IN_Propagate, texenv.get(), 1);
00224 }
00225
00226
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
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
00238 ref<Image> tex_image = terrain_img->subImage(tx, tz, tx_xsize, tx_zsize);
00239 ref<TextureSampler> tex_unit0 = new TextureSampler;
00240 shader_node->setRenderState(IN_Propagate, tex_unit0.get(), 0);
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
00248 if (detail_img)
00249 {
00250 ref<TextureSampler> tex_unit1 = new TextureSampler;
00251 shader_node->setRenderState(IN_Propagate, tex_unit1.get(), 1);
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 (Has_GL_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
00266 ref<Image> hmap_image = heightmap_img->subImage(mx, mz, xsize, zsize);
00267 if (useGLSL())
00268 {
00269 ref<TextureSampler> tex_unit2 = new TextureSampler;
00270 shader_node->setRenderState(IN_Propagate, tex_unit2.get(), 2);
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
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->setLocalAndWorldMatrix((mat4)dmat);
00285
00286 if (!useGLSL())
00287 {
00288 terr_tile = vl::makeGrid( vec3(0,0,0), 1.0f, 1.0f, xsize, zsize);
00289 terr_tile->setTexCoordArray(0, tmap_uv.get());
00290 terr_tile->setTexCoordArray(1, dmap_uv.get());
00291
00292 ref<ArrayFloat3> verts = terr_tile->vertexArray()->as<ArrayFloat3>(); VL_CHECK(verts.get());
00293 for(int z=0; z<zsize; ++z)
00294 {
00295 for(int x=0; x<xsize; ++x)
00296 {
00297 fvec4 sample = hmap_image->sample(x,z) * (float)height();
00298 int index = x + xsize * z;
00299 verts->at(index).y() = sample.r();
00300 }
00301 }
00302 }
00303
00304
00305
00306 ref<Actor> actor = new Actor(terr_tile.get(), terr_fx.get(), (use_uniform_transform && useGLSL())?NULL:transform.get());
00307 mChunks.push_back(actor.get());
00308
00309 if (use_uniform_transform && useGLSL())
00310 {
00311 #if 1
00312 actor->setUniformSet( new UniformSet );
00313 ref<Uniform> uniform_matrix = new Uniform("matrix");
00314 uniform_matrix->setUniform( (fmat4)dmat );
00315 actor->setUniform( uniform_matrix.get() );
00316 #else
00317 ref<Uniform> uniform_matrix = new Uniform("matrix");
00318 uniform_matrix->setUniform( (mat4)dmat );
00319 terr_fx->shader()->setUniform( uniform_matrix.get() );
00320 #endif
00321 }
00322
00323 #if 0 // for debuggin purposes
00324
00325 terr_tile->setColorArray( fvec4(rand()%256/255.0f,rand()%256/255.0f,rand()%256/255.0f) );
00326 #endif
00327 }
00328 }
00329
00330 shaderNode()->updateHierarchy();
00331 tree()->buildKdTree(mChunks);
00332 }