////////////////////////// Terrain.cpp//CompileZone - Compiles a zone into a renderable formvoid Terrain::CompileZone(zone &z, u32 zoneidx){ //Calculate zone offset u32 zone_ofs_x = (zoneidx % ZONE_GRID) * m_zonearea; u32 zone_ofs_y = (zoneidx / ZONE_GRID) * m_zonearea; //Allocate a block of memory for the verticies, normals and texture coordinates if (!z.verts) z.verts = (Vector3*)malloc(sizeof(Vector3) * m_zonesizesq); if (!z.normals) z.normals = (Vector3*)malloc(sizeof(Vector3) * m_zonesizesq); if (!z.texcoords) z.texcoords = (Vector2*)malloc(sizeof(Vector2) * m_zonesizesq); //Create the verticies based on our cell data for (u32 y = 0; y < m_zonesize; ++y) { for (u32 x = 0; x < m_zonesize; ++x) { //Convert into a vertex u32 ofs = x + (y * m_zonesize); z.verts[ofs].x = (zone_ofs_x + x); z.verts[ofs].y = z.cells[x + (y * m_zonesize)].height; z.verts[ofs].z = (zone_ofs_y + y); //Bring over the normal data z.normals[ofs] = z.cells[x + (y * m_zonesize)].normal; //Set the texture coordinates z.texcoords[ofs].x = (f32(x) / (m_zonesize - 1)); z.texcoords[ofs].y = (f32(y) / (m_zonesize - 1)); } } //If we don't have initialized vertex arrays yet, then if (!z.var_vertex) { //create them and shove in all the vertex data z.var_vertex = new VAR(z.verts, m_zonesizesq, m_vaarea); z.var_normal = new VAR(z.normals, m_zonesizesq, m_vaarea); z.var_tex = new VAR(z.texcoords, m_zonesizesq, m_vaarea); } else { //Are they valid? if (!z.var_vertex->valid() || !z.var_normal->valid() || !z.var_tex->valid()) { //Delete and create new arrays delete z.var_vertex; delete z.var_tex; delete z.var_normal; z.var_vertex = new VAR(z.verts, m_zonesizesq, m_vaarea); z.var_normal = new VAR(z.normals, m_zonesizesq, m_vaarea); z.var_tex = new VAR(z.texcoords, m_zonesizesq, m_vaarea); } else { //Otherwise, update the existing ones z.var_vertex->update(z.verts, m_zonesizesq); z.var_normal->update(z.normals, m_zonesizesq); z.var_tex->update(z.texcoords, m_zonesizesq); } } // Construct the zone texture ///////////////////////////////////////////// textureBlender tB; Array<u8> alphaMaps[LAYER_COUNT]; //add all our source layer textures for (u32 i=0; i < LAYER_COUNT; ++i) { //Construct the alphamap alphaMaps[i].resize(m_zonesizesq); u8 *mapPtr = alphaMaps[i].getCArray(); //Convert the celldata into an alphamap for (s32 y=0; y < s32(m_zonesize); ++y) for (s32 x=0; x < s32(m_zonesize); ++x) mapPtr[x + (y * m_zonesize)] = z.cells[x + (y * m_zonesize)].layeralphas[i]; tB.addTexture(i, m_layers[i], mapPtr); } //Blend everything to form a texture tB.updateOpacity(m_zonesize); z.zonetex = tB.blend(rd, z.zonetex);}//////////////////////////// textureBlender.cpp//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; Texture::Settings settings = Texture::Settings::defaults(); settings.wrapMode = WrapMode::CLAMP; settings.interpolateMode = Texture::BILINEAR_NO_MIPMAP; if (oldSurface.isNull()) renderSurface = Texture::createEmpty( "terrainTexture", TEXTURE_SIZE, TEXTURE_SIZE, TextureFormat::RGBA8(), Texture::DIM_2D, settings); else renderSurface = oldSurface; rd->pushState(); //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->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(); fb->set(Framebuffer::COLOR_ATTACHMENT0, NULL); rd->popState(); // 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, tmpBits += 4) { //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]; } //Adjust our settings Texture::Settings settings = Texture::Settings::defaults(); settings.wrapMode = WrapMode::CLAMP; //Make a texture and store it... m_opacity[rangeStart / 4] = Texture::fromGImage("terrainAlphaMap", tempMap, TextureFormat::AUTO(), Texture::DIM_2D, settings ); }}