示例#1
0
        public void LoadModel(List<string> tileList)
        {
            foreach(var tile in tileList)
            {
                if (!cache.terrain.ContainsKey(tile))
                {
                    ADTLoader.LoadADT(tile, cache, adtShaderProgram);
                }

                ActiveCamera.Pos = new Vector3(cache.terrain[tile].startPos.Position.X, cache.terrain[tile].startPos.Position.Y, cache.terrain[tile].startPos.Position.Z);
                ActiveCamera.Pos.Y -= 533.33333f / 2;
                ActiveCamera.Pos.X += 533.33333f / 2;
                ActiveCamera.Pos.Z += 50f;
                modelType = "adt";

                ready = true;
            }

            adtList = tileList;
        }
        public void LoadModel(LoadType type, uint fileDataId)
        {
            switch (type)
            {
            case LoadType.M2:
                M2Loader.Load(fileDataId, new Vector3(0, 0, 1), new Quaternion(0, -90, 0, 0), Vector3.one);
                break;

            case LoadType.ADT:
                ADTLoader.Load(fileDataId, 39, 38);
                ADTLoader.Load(fileDataId, 39, 39);
                ADTLoader.Load(fileDataId, 39, 40);

                ADTLoader.Load(fileDataId, 40, 38);
                ADTLoader.Load(fileDataId, 40, 39);
                ADTLoader.Load(fileDataId, 40, 40);

                ADTLoader.Load(fileDataId, 41, 38);
                ADTLoader.Load(fileDataId, 41, 39);
                ADTLoader.Load(fileDataId, 41, 40);
                break;
            }
        }
示例#3
0
        public void Generate(string filename, string outName, CacheStorage cache, int bakeShaderProgram)
        {
            float TileSize    = 1600.0f / 3.0f;   //533.333
            float ChunkSize   = TileSize / 16.0f; //33.333
            float UnitSize    = ChunkSize / 8.0f; //4.166666
            float MapMidPoint = 32.0f / ChunkSize;

            var bakeSize   = 4096;
            var splitFiles = false;

            ConfigurationManager.RefreshSection("appSettings");

            var size = ConfigurationManager.AppSettings["bakeQuality"];

            if (size == "low")
            {
                bakeSize = 4096;
            }
            else if (size == "medium")
            {
                bakeSize = 8192;
            }
            else if (size == "high")
            {
                bakeSize   = 1024;
                splitFiles = true;
            }

            if (!Directory.Exists(Path.GetDirectoryName(outName)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(outName));
            }

            GL.ClearColor(Color.Black);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            GL.UseProgram(bakeShaderProgram);

            if (!cache.terrain.ContainsKey(filename))
            {
                ADTLoader.LoadADT(filename, cache, bakeShaderProgram);
            }

            var firstPos = cache.terrain[filename].startPos.Position;
            var projectionMatrixLocation = GL.GetUniformLocation(bakeShaderProgram, "projection_matrix");
            var modelviewMatrixLocation  = GL.GetUniformLocation(bakeShaderProgram, "modelview_matrix");
            var firstPosLocation         = GL.GetUniformLocation(bakeShaderProgram, "firstPos");
            var heightScaleLoc           = GL.GetUniformLocation(bakeShaderProgram, "pc_heightScale");
            var heightOffsetLoc          = GL.GetUniformLocation(bakeShaderProgram, "pc_heightOffset");

            if (splitFiles)
            {
                GL.BindVertexArray(cache.terrain[filename].vao);

                for (int i = 0; i < cache.terrain[filename].renderBatches.Length; i++)
                {
                    if (File.Exists(outName.Replace(".png", "_" + i + ".png")))
                    {
                        continue;
                    }

                    var x = i / 16;
                    var y = i % 16;

                    var frameBuffer = GL.GenFramebuffer();
                    GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBuffer);

                    var bakedTexture = GL.GenTexture();
                    GL.BindTexture(TextureTarget.Texture2D, bakedTexture);

                    GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, bakeSize, bakeSize, 0, PixelFormat.Rgb, PixelType.UnsignedByte, new IntPtr(0));
                    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
                    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);

                    GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, bakedTexture, 0);

                    GL.DrawBuffers(1, new DrawBuffersEnum[] { DrawBuffersEnum.ColorAttachment0 });

                    if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete)
                    {
                        var fbError = GL.GetError().ToString();
                        Console.WriteLine(fbError);
                    }

                    var projectionMatrix = Matrix4.CreateOrthographic(ChunkSize, ChunkSize, -1500f, 1500f);
                    GL.UniformMatrix4(projectionMatrixLocation, false, ref projectionMatrix);

                    var eye    = new Vector3(-ChunkSize / 2, (-ChunkSize / 2), 400f);
                    var target = new Vector3(-ChunkSize / 2, (-ChunkSize / 2), 399.9999f);

                    Matrix4 modelViewMatrix = Matrix4.LookAt(eye, target, new Vector3(0f, 1f, 0f));
                    GL.UniformMatrix4(modelviewMatrixLocation, false, ref modelViewMatrix);

                    var chunkPos = firstPos;
                    chunkPos.X -= ChunkSize * x;
                    chunkPos.Y -= ChunkSize * y;

                    GL.Uniform3(firstPosLocation, ref chunkPos);

                    GL.Viewport(0, 0, bakeSize, bakeSize);

                    GL.Uniform4(heightScaleLoc, cache.terrain[filename].renderBatches[i].heightScales);

                    GL.Uniform4(heightOffsetLoc, cache.terrain[filename].renderBatches[i].heightOffsets);

                    for (int j = 0; j < cache.terrain[filename].renderBatches[i].materialID.Length; j++)
                    {
                        var textureLoc = GL.GetUniformLocation(bakeShaderProgram, "pt_layer" + j);
                        GL.Uniform1(textureLoc, j);

                        var scaleLoc = GL.GetUniformLocation(bakeShaderProgram, "layer" + j + "scale");
                        GL.Uniform1(scaleLoc, cache.terrain[filename].renderBatches[i].scales[j]);

                        GL.ActiveTexture(TextureUnit.Texture0 + j);
                        GL.BindTexture(TextureTarget.Texture2D, (int)cache.terrain[filename].renderBatches[i].materialID[j]);
                    }

                    for (int j = 1; j < cache.terrain[filename].renderBatches[i].alphaMaterialID.Length; j++)
                    {
                        var textureLoc = GL.GetUniformLocation(bakeShaderProgram, "pt_blend" + j);
                        GL.Uniform1(textureLoc, 3 + j);

                        GL.ActiveTexture(TextureUnit.Texture3 + j);
                        GL.BindTexture(TextureTarget.Texture2D, cache.terrain[filename].renderBatches[i].alphaMaterialID[j]);
                    }

                    for (int j = 0; j < cache.terrain[filename].renderBatches[i].heightMaterialIDs.Length; j++)
                    {
                        var textureLoc = GL.GetUniformLocation(bakeShaderProgram, "pt_height" + j);
                        GL.Uniform1(textureLoc, 7 + j);

                        GL.ActiveTexture(TextureUnit.Texture7 + j);
                        GL.BindTexture(TextureTarget.Texture2D, cache.terrain[filename].renderBatches[i].heightMaterialIDs[j]);
                    }

                    GL.DrawElements(PrimitiveType.Triangles, (int)cache.terrain[filename].renderBatches[i].numFaces, DrawElementsType.UnsignedInt, (int)cache.terrain[filename].renderBatches[i].firstFace * 4);

                    for (int j = 0; j < 11; j++)
                    {
                        GL.ActiveTexture(TextureUnit.Texture0 + j);
                        GL.BindTexture(TextureTarget.Texture2D, 0);
                    }

                    var error = GL.GetError().ToString();
                    if (error != "NoError")
                    {
                        Console.WriteLine(error);
                    }

                    Bitmap bmp = new Bitmap(bakeSize, bakeSize);
                    System.Drawing.Imaging.BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                    GL.ReadPixels(0, 0, bakeSize, bakeSize, PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
                    bmp.UnlockBits(data);

                    bmp.RotateFlip(RotateFlipType.Rotate270FlipX);
                    bmp.Save(outName.Replace(".png", "_" + i + ".png"), System.Drawing.Imaging.ImageFormat.Png);

                    bmp.Dispose();

                    GL.DeleteFramebuffer(frameBuffer);
                }

                GL.UseProgram(0);
            }
            else
            {
                if (File.Exists(outName))
                {
                    return;
                }

                var frameBuffer = GL.GenFramebuffer();
                GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBuffer);

                var bakedTexture = GL.GenTexture();
                GL.BindTexture(TextureTarget.Texture2D, bakedTexture);

                GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, bakeSize, bakeSize, 0, PixelFormat.Rgb, PixelType.UnsignedByte, new IntPtr(0));
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);

                GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, bakedTexture, 0);

                GL.DrawBuffers(1, new DrawBuffersEnum[] { DrawBuffersEnum.ColorAttachment0 });

                if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete)
                {
                    var error = GL.GetError().ToString();
                    Console.WriteLine(error);
                }

                var projectionMatrix = Matrix4.CreateOrthographic(TileSize, TileSize, -1500f, 1500f);
                GL.UniformMatrix4(projectionMatrixLocation, false, ref projectionMatrix);

                var     eye             = new Vector3(-TileSize / 2, -TileSize / 2, 400f);
                var     target          = new Vector3(-TileSize / 2, -TileSize / 2, 399.9999f);
                Matrix4 modelViewMatrix = Matrix4.LookAt(eye, target, new Vector3(0f, 1f, 0f));
                GL.UniformMatrix4(modelviewMatrixLocation, false, ref modelViewMatrix);

                GL.Uniform3(firstPosLocation, ref firstPos);

                GL.Viewport(0, 0, bakeSize, bakeSize);

                GL.BindVertexArray(cache.terrain[filename].vao);

                for (int i = 0; i < cache.terrain[filename].renderBatches.Length; i++)
                {
                    GL.Uniform4(heightScaleLoc, cache.terrain[filename].renderBatches[i].heightScales);
                    GL.Uniform4(heightOffsetLoc, cache.terrain[filename].renderBatches[i].heightOffsets);

                    for (int j = 0; j < cache.terrain[filename].renderBatches[i].materialID.Length; j++)
                    {
                        var textureLoc = GL.GetUniformLocation(bakeShaderProgram, "pt_layer" + j);
                        GL.Uniform1(textureLoc, j);

                        var scaleLoc = GL.GetUniformLocation(bakeShaderProgram, "layer" + j + "scale");
                        GL.Uniform1(scaleLoc, cache.terrain[filename].renderBatches[i].scales[j]);

                        GL.ActiveTexture(TextureUnit.Texture0 + j);
                        GL.BindTexture(TextureTarget.Texture2D, (int)cache.terrain[filename].renderBatches[i].materialID[j]);
                    }

                    for (int j = 1; j < cache.terrain[filename].renderBatches[i].alphaMaterialID.Length; j++)
                    {
                        var textureLoc = GL.GetUniformLocation(bakeShaderProgram, "pt_blend" + j);
                        GL.Uniform1(textureLoc, 3 + j);

                        GL.ActiveTexture(TextureUnit.Texture3 + j);
                        GL.BindTexture(TextureTarget.Texture2D, cache.terrain[filename].renderBatches[i].alphaMaterialID[j]);
                    }

                    for (int j = 0; j < cache.terrain[filename].renderBatches[i].heightMaterialIDs.Length; j++)
                    {
                        var textureLoc = GL.GetUniformLocation(bakeShaderProgram, "pt_height" + j);
                        GL.Uniform1(textureLoc, 7 + j);

                        GL.ActiveTexture(TextureUnit.Texture7 + j);
                        GL.BindTexture(TextureTarget.Texture2D, cache.terrain[filename].renderBatches[i].heightMaterialIDs[j]);
                    }

                    GL.DrawElements(PrimitiveType.Triangles, (int)cache.terrain[filename].renderBatches[i].numFaces, DrawElementsType.UnsignedInt, (int)cache.terrain[filename].renderBatches[i].firstFace * 4);

                    for (int j = 0; j < 11; j++)
                    {
                        GL.ActiveTexture(TextureUnit.Texture0 + j);
                        GL.BindTexture(TextureTarget.Texture2D, 0);
                    }

                    var error = GL.GetError().ToString();
                    if (error != "NoError")
                    {
                        Console.WriteLine(error);
                    }
                }

                Bitmap bmp = new Bitmap(bakeSize, bakeSize);
                System.Drawing.Imaging.BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                GL.ReadPixels(0, 0, bakeSize, bakeSize, PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
                bmp.UnlockBits(data);

                bmp.RotateFlip(RotateFlipType.Rotate270FlipX);
                bmp.Save(outName, System.Drawing.Imaging.ImageFormat.Png);

                bmp.Dispose();

                GL.DeleteFramebuffer(frameBuffer);
                GL.UseProgram(0);
            }
        }
示例#4
0
        public void Generate(MapTile mapTile, string outName, int bakeShaderProgram, bool loadModels = false)
        {
            var TileSize    = 1600.0f / 3.0f;   //533.333
            var ChunkSize   = TileSize / 16.0f; //33.333
            var UnitSize    = ChunkSize / 8.0f; //4.166666
            var MapMidPoint = 32.0f / ChunkSize;

            var bakeSize   = 4096;
            var splitFiles = false;

            ConfigurationManager.RefreshSection("appSettings");
            switch (ConfigurationManager.AppSettings["bakeQuality"])
            {
            case "minimap": bakeSize = 256; break;

            case "low": bakeSize = 4096; break;

            case "medium": bakeSize = 8192; break;

            case "high":
                bakeSize   = 1024;
                splitFiles = true;
                break;
            }

            Directory.CreateDirectory(Path.GetDirectoryName(outName));

            Terrain terrain = ADTLoader.LoadADT(mapTile, bakeShaderProgram, loadModels);

            GL.ClearColor(Color.Black);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            GL.UseProgram(bakeShaderProgram);

            // Look up uniforms beforehand instead of during drawing
            var firstPos = terrain.startPos.Position;
            var projectionMatrixLocation = GL.GetUniformLocation(bakeShaderProgram, "projection_matrix");
            var modelviewMatrixLocation  = GL.GetUniformLocation(bakeShaderProgram, "modelview_matrix");
            var firstPosLocation         = GL.GetUniformLocation(bakeShaderProgram, "firstPos");
            var doodadOffsLocation       = GL.GetUniformLocation(bakeShaderProgram, "doodadOffs");
            var heightScaleLoc           = GL.GetUniformLocation(bakeShaderProgram, "pc_heightScale");
            var heightOffsetLoc          = GL.GetUniformLocation(bakeShaderProgram, "pc_heightOffset");

            var layerLocs  = new int[4];
            var scaleLocs  = new int[4];
            var heightLocs = new int[4];
            var blendLocs  = new int[4];

            for (var i = 0; i < 4; i++)
            {
                layerLocs[i]  = GL.GetUniformLocation(bakeShaderProgram, "pt_layer" + i);
                scaleLocs[i]  = GL.GetUniformLocation(bakeShaderProgram, "layer" + i + "scale");
                heightLocs[i] = GL.GetUniformLocation(bakeShaderProgram, "pt_height" + i);

                // There are only 3 blend samplers
                if (i > 0)
                {
                    blendLocs[i] = GL.GetUniformLocation(bakeShaderProgram, "pt_blend" + i);
                }
            }

            if (splitFiles)
            {
                GL.BindVertexArray(terrain.vao);

                for (var i = 0; i < terrain.renderBatches.Length; i++)
                {
                    var x = i / 16;
                    var y = i % 16;

                    var frameBuffer = GL.GenFramebuffer();
                    GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBuffer);

                    var bakedTexture = GL.GenTexture();
                    GL.BindTexture(TextureTarget.Texture2D, bakedTexture);

                    GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, bakeSize, bakeSize, 0, PixelFormat.Rgb, PixelType.UnsignedByte, new IntPtr(0));
                    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
                    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);

                    GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, bakedTexture, 0);

                    GL.DrawBuffers(1, new DrawBuffersEnum[] { DrawBuffersEnum.ColorAttachment0 });

                    if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete)
                    {
                        var fberror = GL.GetError().ToString();
                        Logger.WriteLine("Frame buffer initialization error: " + fberror);
                    }

                    var projectionMatrix = Matrix4.CreateOrthographic(ChunkSize, ChunkSize, -1500f, 1500f);
                    GL.UniformMatrix4(projectionMatrixLocation, false, ref projectionMatrix);

                    var eye    = new Vector3(-ChunkSize / 2, (-ChunkSize / 2), 400f);
                    var target = new Vector3(-ChunkSize / 2, (-ChunkSize / 2), 399.9999f);

                    var modelViewMatrix = Matrix4.LookAt(eye, target, new Vector3(0f, 1f, 0f));
                    GL.UniformMatrix4(modelviewMatrixLocation, false, ref modelViewMatrix);

                    var chunkPos = firstPos;
                    chunkPos.X -= ChunkSize * x;
                    chunkPos.Y -= ChunkSize * y;

                    GL.Uniform3(firstPosLocation, ref chunkPos);
                    GL.Viewport(0, 0, bakeSize, bakeSize);
                    GL.Uniform4(heightScaleLoc, terrain.renderBatches[i].heightScales);
                    GL.Uniform4(heightOffsetLoc, terrain.renderBatches[i].heightOffsets);

                    for (var j = 0; j < terrain.renderBatches[i].materialID.Length; j++)
                    {
                        GL.Uniform1(layerLocs[j], j);
                        GL.Uniform1(scaleLocs[j], terrain.renderBatches[i].scales[j]);

                        GL.ActiveTexture(TextureUnit.Texture0 + j);
                        GL.BindTexture(TextureTarget.Texture2D, (int)terrain.renderBatches[i].materialID[j]);
                    }

                    for (var j = 1; j < terrain.renderBatches[i].alphaMaterialID.Length; j++)
                    {
                        GL.Uniform1(blendLocs[j], 3 + j);

                        GL.ActiveTexture(TextureUnit.Texture3 + j);
                        GL.BindTexture(TextureTarget.Texture2D, terrain.renderBatches[i].alphaMaterialID[j]);
                    }

                    for (var j = 0; j < terrain.renderBatches[i].heightMaterialIDs.Length; j++)
                    {
                        GL.Uniform1(heightLocs[j], 7 + j);

                        GL.ActiveTexture(TextureUnit.Texture7 + j);
                        GL.BindTexture(TextureTarget.Texture2D, terrain.renderBatches[i].heightMaterialIDs[j]);
                    }

                    GL.DrawElements(PrimitiveType.Triangles, (int)terrain.renderBatches[i].numFaces, DrawElementsType.UnsignedInt, (int)terrain.renderBatches[i].firstFace * 4);

                    for (var j = 0; j < 11; j++)
                    {
                        GL.ActiveTexture(TextureUnit.Texture0 + j);
                        GL.BindTexture(TextureTarget.Texture2D, 0);
                    }

                    var error = GL.GetError().ToString();
                    if (error != "NoError")
                    {
                        Logger.WriteLine("Drawing error: " + error);
                    }

                    var bmp  = new Bitmap(bakeSize, bakeSize, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                    var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                    GL.ReadPixels(0, 0, bakeSize, bakeSize, PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
                    bmp.UnlockBits(data);

                    bmp.RotateFlip(RotateFlipType.Rotate270FlipX);
                    bmp.Save(outName.Replace(".png", "_" + i + ".png"), System.Drawing.Imaging.ImageFormat.Png);

                    bmp.Dispose();

                    GL.DeleteTexture(bakedTexture);
                    GL.DeleteFramebuffer(frameBuffer);
                }

                GL.UseProgram(0);
            }
            else
            {
                var frameBuffer = GL.GenFramebuffer();
                GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBuffer);

                var bakedTexture = GL.GenTexture();
                GL.BindTexture(TextureTarget.Texture2D, bakedTexture);

                GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, bakeSize, bakeSize, 0, PixelFormat.Rgb, PixelType.UnsignedByte, new IntPtr(0));
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);

                GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, bakedTexture, 0);

                GL.DrawBuffers(1, new DrawBuffersEnum[] { DrawBuffersEnum.ColorAttachment0 });

                if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete)
                {
                    var fberror = GL.GetError().ToString();
                    Logger.WriteLine("Frame buffer initialization error: " + fberror);
                }

                var projectionMatrix = Matrix4.CreateOrthographic(TileSize, TileSize, -1500f, 1500f);
                GL.UniformMatrix4(projectionMatrixLocation, false, ref projectionMatrix);

                var eye             = new Vector3(-TileSize / 2, -TileSize / 2, 400f);
                var target          = new Vector3(-TileSize / 2, -TileSize / 2, 399.9999f);
                var modelViewMatrix = Matrix4.LookAt(eye, target, new Vector3(0f, 1f, 0f));
                GL.UniformMatrix4(modelviewMatrixLocation, false, ref modelViewMatrix);

                GL.Uniform3(firstPosLocation, ref firstPos);

                GL.Viewport(0, 0, bakeSize, bakeSize);

                GL.BindVertexArray(terrain.vao);

                for (var i = 0; i < terrain.renderBatches.Length; i++)
                {
                    GL.Uniform4(heightScaleLoc, terrain.renderBatches[i].heightScales);
                    GL.Uniform4(heightOffsetLoc, terrain.renderBatches[i].heightOffsets);

                    for (var j = 0; j < terrain.renderBatches[i].materialID.Length; j++)
                    {
                        GL.Uniform1(layerLocs[j], j);
                        GL.Uniform1(scaleLocs[j], terrain.renderBatches[i].scales[j]);

                        GL.ActiveTexture(TextureUnit.Texture0 + j);
                        GL.BindTexture(TextureTarget.Texture2D, (int)terrain.renderBatches[i].materialID[j]);
                    }

                    for (var j = 1; j < terrain.renderBatches[i].alphaMaterialID.Length; j++)
                    {
                        GL.Uniform1(blendLocs[j], 3 + j);

                        GL.ActiveTexture(TextureUnit.Texture3 + j);
                        GL.BindTexture(TextureTarget.Texture2D, terrain.renderBatches[i].alphaMaterialID[j]);
                    }

                    for (var j = 0; j < terrain.renderBatches[i].heightMaterialIDs.Length; j++)
                    {
                        GL.Uniform1(heightLocs[j], 7 + j);

                        GL.ActiveTexture(TextureUnit.Texture7 + j);
                        GL.BindTexture(TextureTarget.Texture2D, terrain.renderBatches[i].heightMaterialIDs[j]);
                    }

                    GL.DrawElements(PrimitiveType.Triangles, (int)terrain.renderBatches[i].numFaces, DrawElementsType.UnsignedInt, (int)terrain.renderBatches[i].firstFace * 4);

                    for (var j = 0; j < 11; j++)
                    {
                        GL.ActiveTexture(TextureUnit.Texture0 + j);
                        GL.BindTexture(TextureTarget.Texture2D, 0);
                    }
                }

                var error = GL.GetError().ToString();
                if (error != "NoError")
                {
                    Logger.WriteLine("Drawing error: " + error);
                }

                try
                {
                    using (var bmp = new Bitmap(bakeSize, bakeSize))
                    {
                        var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
                        GL.ReadPixels(0, 0, bakeSize, bakeSize, PixelFormat.Bgr, PixelType.UnsignedByte, data.Scan0);
                        bmp.UnlockBits(data);

                        bmp.RotateFlip(RotateFlipType.Rotate270FlipX);
                        bmp.Save(outName, System.Drawing.Imaging.ImageFormat.Png);

                        bmp.Dispose();
                    }
                }
                catch (Exception e)
                {
                    Logger.WriteLine("An error occured while baking minimap image " + Path.GetFileNameWithoutExtension(outName) + ": " + e.StackTrace);
                }
                finally
                {
                    GL.DeleteTexture(bakedTexture);
                    GL.DeleteFramebuffer(frameBuffer);
                    GL.UseProgram(0);
                }
            }

            // Clean-up.
            foreach (var batch in terrain.renderBatches)
            {
                GL.DeleteTextures(batch.alphaMaterialID.Length, batch.alphaMaterialID);
            }

            GC.Collect();
        }