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;
		}
	}
示例#3
0
	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;
	}