/* textureBlender - Used for blending textures together for the terrain *////////////////////////////////////////////////////////////////////#include <Base.h>#include "textureBlender.h"#include "Terrain.h"// Static Initialization//////////////////////////////////////////////////ShaderRef textureBlender::m_blendShader; //loadAssets - Loads all the external assets needed for this classvoid textureBlender::loadAssets(){ //Load our blending shader m_blendShader = G3D::Shader::fromFiles("shaders/terrainblend.vert", "shaders/terrainblend.frag"); assert(m_blendShader->ok(), "Terrain texture blending shader failed to load."); }// Con/De-struction//////////////////////////////////////////////////textureBlender::textureBlender(){}textureBlender::~textureBlender(){}// Texture functions////////////////////////////////////////////////////blend - Blends the given textures together using the specified alpha mapsTextureRef textureBlender::blend(RenderDevice *rd, TextureRef oldSurface){ //Allocate a new texture to render to, if we don't have an old one to use TextureRef renderSurface; if (oldSurface.isNull()) renderSurface = Texture::createEmpty(TEXTURE_SIZE, TEXTURE_SIZE, "terrainTexture", TextureFormat::RGBA8, Texture::TILE, Texture::NO_INTERPOLATION, Texture::DIM_2D); else renderSurface = oldSurface; //Setup a framebuffer FramebufferRef fb = Framebuffer::create("terrainTexturer"); fb->set(Framebuffer::COLOR_ATTACHMENT0, renderSurface); //Set the rendering device up for rendering to our framebuffer/texture rd->pushState(); rd->push2D(fb); //First, clear the scene rd->setColorClearValue(Color3(0, 1, 0)); rd->clear(); //Render the opacity map stuff for(s32 i=0; i < m_sources.size(); i += 4) { //Break if there's nothing to draw if (m_sources[i + 0].source.isNull() && m_sources[i + 1].source.isNull() && m_sources[i + 2].source.isNull() && m_sources[i + 3].source.isNull() ) break; bool source2 = (m_sources.size() > i + 1); bool source3 = (m_sources.size() > i + 2); bool source4 = (m_sources.size() > i + 3); //Load up the blending shader rd->setShader(m_blendShader); //Maybe move this call outside? faster? m_blendShader->args.set("opacityMap", m_opacity[i / 4]); m_blendShader->args.set("source0", m_sources[i + 0].source); //Replace textures that don't exist with the first texture to keep glsl happy. //The opacity map should ignore them regardless. m_blendShader->args.set("source1", m_sources[i + (source2 ? 1:0)].source); m_blendShader->args.set("source2", m_sources[i + (source3 ? 2:0)].source); m_blendShader->args.set("source3", m_sources[i + (source4 ? 3:0)].source); //Render the texture Draw::rect2D(Rect2D::xywh(0,0,TEXTURE_SIZE,TEXTURE_SIZE), rd, Color3::white()); break; } //Reset the render mode rd->setPixelProgram(NULL); rd->pop2D(); rd->popState(); fb->set(Framebuffer::COLOR_ATTACHMENT0, NULL); // Return the surface debugAssertGLOk(); return renderSurface;}//addTexture - Adds a texture to be blended using the specified alpha mapvoid textureBlender::addTexture(u32 materialIdx, TextureRef tex, u8 *alphas){ //Make a new sourcetexture and jam it into the array SourceTexture s; s.alpha = alphas; s.source = tex; //Resize the array if necessary if (m_sources.size() <= (s32)materialIdx) m_sources.resize(materialIdx + 1); m_sources[materialIdx] = s;}//updateOpacity - Merges all the alpha maps into a single texturevoid textureBlender::updateOpacity(u32 alphamapsize){ //Ready the opacity texture array u32 alphamapsizesq = (alphamapsize*alphamapsize); m_opacity.clear(); m_opacity.resize((m_sources.size() / 4) + 1); //4 Textures for each opacity map //Build new maps for(s32 rangeStart=0; rangeStart < m_sources.size(); rangeStart +=4) { //If we have a null on source #rangeStart, we are done. if (!m_sources[rangeStart + 0].alpha) break; bool source2 = (m_sources.size() > rangeStart + 1); bool source3 = (m_sources.size() > rangeStart + 2); bool source4 = (m_sources.size() > rangeStart + 3); //Ready an image GImage tempMap(alphamapsize, alphamapsize, 4); u8 *tmpBits = tempMap.byte(); ZeroMemory(tmpBits, sizeof(u32) * alphamapsizesq); // Copy everything relevant into the texture... for(u32 x=0; x < alphamapsizesq; ++x) { //Always assume that the first alpha exists, but don't rely on the others tmpBits[0] = m_sources[rangeStart + 0].alpha[x]; if (source2) tmpBits[1] = m_sources[rangeStart + 1].alpha[x]; if (source3) tmpBits[2] = m_sources[rangeStart + 2].alpha[x]; if (source4) tmpBits[3] = m_sources[rangeStart + 3].alpha[x]; // Move to next chunk of data... tmpBits += 4; } // Make a texture and store it... m_opacity[rangeStart / 4] = Texture::fromGImage("terrainAlphaMap", tempMap); //NOTE: Does having a constant name for all alpha textures mean that // it'll just always default for the first one commited? }}