/* * This is a very simple demonstration of how to provide procedural textures to Demeter. * This sample texture factory simply creates texels based on the terrain elevation at each texel. * Colors become more yellow at higher elevations and more blue at lower elevations. * For more interesting procedural texture algorithms and ideas, see the Open Mountains website * (openmountains.sourceforge.net) for some good ideas and some good links. */ #include "SampleTextureFactory.h" using namespace Demeter; using namespace std; const float texelsPerMeter = 1.0f; const float texelSpacing = 1.0f / texelsPerMeter; const float textureSize = 256.0f; SampleTextureFactory::SampleTextureFactory(Terrain * pTerrain) { m_pTerrain = pTerrain; } SampleTextureFactory::~SampleTextureFactory() { } Texture *SampleTextureFactory::GetTexture(int index, float originX, float originY, float width, float height) { // The Demeter terrain calls this method when a texture has become visible and needs to be rendered. // Your implementation of TextureFactory must return a valid OpenGL texture, generated by whatever // means you like. Notice that a map of textures is kept as a cache so that subsequent requests for this // texture will be nearly instantaneous. You don't have to do this (e.g. for extremely large terrains // it wouldn't be practical), but you need some kind of strategy to keep your texture requests fast since // they happen at runtime. float texelSpacing = width / textureSize; Texture *pTexture = m_Textures[index]; if (pTexture == NULL) { cout << "SAMPLETEXTUREFACTORY: width = " << width << " height = " << height << endl; cout << "SAMPLETEXTUREFACTORY: texelSpacing = " << texelSpacing << endl; cout << "SAMPLETEXTUREFACTORY: texture size = " << (int)((textureSize + 1.0f) * (textureSize + 1.0f)) * 4 << " bytes" << endl; // Allocate an extra row and column to protect from float precision error. Uint8 *pImage = new Uint8[(int)((textureSize + 1.0f) * (textureSize + 1.0f)) * 3]; int imageIndex = 0; for (float y = originY; y < originY + height; y += texelSpacing) { for (float x = originX; x < originX + width; x += texelSpacing, imageIndex += 3) { float elev = m_pTerrain->GetElevation(x, y); Uint8 red = (Uint8) (255.0f * elev / m_pTerrain->GetMaxElevation()); Uint8 green = (Uint8) (255.0f * elev / m_pTerrain->GetMaxElevation()); Uint8 blue = (Uint8) 255 - (Uint8) (255.0f * elev / m_pTerrain->GetMaxElevation()); pImage[imageIndex] = red; pImage[imageIndex + 1] = green; pImage[imageIndex + 2] = blue; } } pTexture = new Texture(pImage, (int)textureSize, (int)textureSize, (int)textureSize, 0, true, false, false); m_Textures[index] = pTexture; delete[]pImage; } return pTexture; } void SampleTextureFactory::UnloadTexture(int index) { // Called by the Demeter terrain when a texture is no longer visible. // We could unload the texture here, set it to a lower priority for OpenGL, etc. // m_Textures[index]->UnloadTexture(); // Keep the texture for now ... }