AlphaImage* AlphaImage::CreateMipmap () { if (w == 1 && h == 1) return 0; int nw = w/2; int nh = h/2; if (!nw) { nw = 1; } if (!nh) { nh = 1; } AlphaImage *mipmap = SAFE_NEW AlphaImage; mipmap->Alloc (nw,nh); // Scale X&Y if (w > 1 && h > 1) { for (int y=0;y<nh;y++) for (int x=0;x<nw;x++) mipmap->at (x,y) = (at(x*2,y*2) + at(x*2+1,y*2) + at(x*2, y*2+1) + at(x*2+1,y*2+1)) * 0.25f; } else if (w == 1 && h > 1) { // Scale Y only for (int y=0;y<nh;y++) for (int x=0;x<nw;x++) mipmap->at (x,y) = (at(x,y*2) + at(x, y*2+1)) * 0.5f; } else { // if (w > 1 && h == 1) { for (int y=0;y<nh;y++) // Scale X only for (int x=0;x<nw;x++) mipmap->at (x,y) = (at(x*2,y) + at(x*2+1, y)) * 0.5f; } return mipmap; }
void TerrainTexture::Load (const TdfParser *tdf, Heightmap *heightmap, TQuad *quadtree, const vector<QuadMap*>& qmaps, Config *cfg, ILoadCallback *cb, LightingInfo *li) { string basepath="MAP\\TERRAIN\\"; if (cb) cb->PrintMsg (" parsing texture stages..."); if (!GLEW_ARB_multitexture) throw std::runtime_error ("No multitexture avaiable"); if (!GLEW_ARB_texture_env_combine) throw std::runtime_error ("Texture env combine extension not avaiable"); heightmapW = heightmap->w; tdfParser = tdf; shaderDef.Parse(*tdf, cfg->useBumpMaps); shaderDef.useShadowMapping = cfg->useShadowMaps; optimizeEpsilon = atof(tdf->SGetValueDef ("0.04", basepath + "LayerOptimizeConst").c_str()); if (optimizeEpsilon < 0.0f) optimizeEpsilon = 0.0f; // Load textures map<string, BaseTexture*> nametbl; if (cb) cb->PrintMsg (" loading textures and blendmaps..."); bool hasBumpmaps = false; for (int a=0;a<shaderDef.stages.size();a++) { ShaderDef::Stage* st = &shaderDef.stages [a]; // Already loaded? if (nametbl.find (st->sourceName) == nametbl.end()) nametbl[st->sourceName] = LoadImageSource(st->sourceName, basepath, heightmap, cb, cfg); st->source = nametbl[st->sourceName]; std::string bm; if (tdf->SGetValue (bm, basepath + st->sourceName + "\\Bumpmap")) hasBumpmaps = true; } if (cfg->useBumpMaps && hasBumpmaps) { for (int a=0;a<shaderDef.normalMapStages.size();a++) { ShaderDef::Stage* st = &shaderDef.normalMapStages [a]; string name = st->sourceName; if (st->operation != ShaderDef::Alpha) name += "_BM"; // make it unique, this whole naming thing is very hackish though.. // Already loaded? if (nametbl.find (name) == nametbl.end()) { // load a bumpmap unless it's an alpha operation st->source = LoadImageSource(st->sourceName, basepath, heightmap, cb, cfg, st->operation != ShaderDef::Alpha); if (!st->source) { if (!flatBumpmap) { flatBumpmap = TiledTexture::CreateFlatBumpmap(); textures.push_back (flatBumpmap); } st->source = flatBumpmap; } st->sourceName = st->source->name; nametbl[st->sourceName] = st->source; } st->source = nametbl[st->sourceName]; } } else cfg->useBumpMaps = false; // Generate blendmap mipmaps deque<AlphaImage*>* bmMipmaps = SAFE_NEW deque<AlphaImage*>[blendMaps.size()]; GenerateInfo gi; gi.bmMipmaps = bmMipmaps; if (cb) { cb->PrintMsg (" generating blendmap mipmaps..."); } for (int a=0;a<blendMaps.size();a++) { Blendmap *bm = blendMaps[a]; AlphaImage *cur = bm->image; bm->image = 0; do { bmMipmaps[a].push_front (cur); cur = cur->CreateMipmap (); } while (cur); for (int c=0;c<bmMipmaps[a].size();c++) if (bmMipmaps[a][c]->w == QUAD_W) { gi.testlod.push_back (c); break; } } if (cb) cb->PrintMsg (" loading blendmaps into OpenGL..."); // Convert to textures for (int a=0;a<blendMaps.size();a++) { AlphaImage *bm = bmMipmaps[a].back(); // Save image if (blendMaps[a]->generatorInfo) { char fn[32]; SNPRINTF (fn,32, "blendmap%d.jpg", a); remove(fn); bm->Save (fn); } // Upload glGenTextures (1, &blendMaps[a]->id); glBindTexture (GL_TEXTURE_2D, blendMaps[a]->id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); if (cfg->anisotropicFiltering > 0.0f) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, cfg->anisotropicFiltering); deque<AlphaImage*>& mipmaps = bmMipmaps[a]; for (int d=0;d<mipmaps.size();d++) { AlphaImage *lod = mipmaps[mipmaps.size()-d-1]; glTexImage2D (GL_TEXTURE_2D, d, GL_ALPHA, lod->w, lod->h, 0, GL_ALPHA, GL_FLOAT, lod->data); } blendMaps[a]->image = 0; } // Create texture application object if (!cfg->forceFallbackTexturing && GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects && GLEW_ARB_shading_language_100) { shaderHandler = SAFE_NEW GLSLShaderHandler; } else { // texture_env_combine as fallback shaderHandler = SAFE_NEW TexEnvSetupHandler; } // Calculate shadows if (cfg->useStaticShadow) { if (cb) cb->PrintMsg(" calculating lightmap"); lightmap = SAFE_NEW Lightmap(heightmap, 2, 1,li); } // see how lighting should be implemented, based on config and avaiable textures InstantiateShaders(cfg, cb); if (cb) { cb->PrintMsg (" initializing terrain node shaders..."); } CreateTexProg (quadtree, &gi); shaderHandler->EndBuild(); // count passes maxPasses = 0; for (map<uint, RenderSetupCollection*>::iterator mi=gi.nodesetup.begin();mi!=gi.nodesetup.end();++mi) { for (int i = 0; i < mi->second->renderSetup.size(); i++) { RenderSetup *rs = mi->second->renderSetup[i]; if (rs->passes.size () > maxPasses) { maxPasses = rs->passes.size(); } } texNodeSetup.push_back (mi->second); } if (cb) cb->PrintMsg (" deleting temporary blendmap data..."); // Free blendmap mipmap images for (int a=0;a<blendMaps.size();a++) { for (deque<AlphaImage*>::iterator i=bmMipmaps[a].begin();i!=bmMipmaps[a].end();++i) { delete *i; } } delete[] bmMipmaps; if (cfg->useShadowMaps) { shadowMapParams = SAFE_NEW ShadowMapParams; } }
void Blendmap::Generate(Heightmap* rootHm, int lodLevel, float hmScale, float hmOffset) { const Heightmap* heightmap = rootHm->GetLevel(-lodLevel); // Allocate the blendmap image AlphaImage* bm = new AlphaImage; bm->Alloc(heightmap->w-1, heightmap->h-1); // texture dimensions have to be power-of-two Blendmap::GeneratorInfo* gi = generatorInfo; // Calculate blend factors using the function parameters and heightmap input: for (int y=0;y<bm->h;y++) { for (int x=0;x<bm->w;x++) { const float h = (heightmap->atSynced(x, y) - hmOffset) / hmScale; float factor=1.0f; if(h < gi->minHeight - gi->minHeightFuzzy) { bm->at(x,y) = 0.0f; continue; } else if (gi->minHeightFuzzy > 0.0f && h < gi->minHeight + gi->minHeightFuzzy) factor = (h - (gi->minHeight - gi->minHeightFuzzy)) / (2.0f * gi->minHeightFuzzy); if(h > gi->maxHeight + gi->maxHeightFuzzy) { bm->at (x,y) = 0.0f; continue; } else if (gi->maxHeightFuzzy > 0.0f && h > gi->maxHeight - gi->maxHeightFuzzy) factor *= ((gi->maxHeight + gi->maxHeightFuzzy) - h) / (2.0f * gi->maxHeightFuzzy); float norm_y = 0.0f; if (heightmap->normalData) { const uchar* cnorm = heightmap->GetNormal(x, y); norm_y = cnorm[1] / 255.0f * 2.0f - 1.0f; if (norm_y > 1.0f) norm_y = 1.0f; } else { Vector3 tangent, binormal; CalculateTangents(heightmap, x,y,tangent,binormal); Vector3 normal = tangent.cross(binormal); normal.ANormalize(); norm_y = normal.y; } // flatness=dotproduct of surface normal with up vector float slope = 1.0f - fabs(norm_y); if (slope < gi->minSlope - gi->minSlopeFuzzy) { bm->at(x,y) = 0.0f; continue; } else if (gi->minSlopeFuzzy > 0.0f && slope < gi->minSlope + gi->minSlopeFuzzy) factor *= (h - (gi->minSlope - gi->minSlopeFuzzy)) / ( 2.0f * gi->minSlopeFuzzy); if (slope > gi->maxSlope + gi->maxSlopeFuzzy) { bm->at(x,y) = 0.0f; continue; } else if (gi->maxSlopeFuzzy > 0.0f && slope > gi->maxSlope - gi->maxSlopeFuzzy) factor *= ((gi->maxSlope + gi->maxSlopeFuzzy) - h) / (2.0f * gi->maxSlopeFuzzy); factor *= gi->coverage; factor *= (rand() < gi->noise * RAND_MAX) ? 0.0f : 1.0f; bm->at(x,y) = factor; } } BlendmapFilter(bm); image = bm; }