private void CreateWater(WarpRenderer renderer, bool threeD)
        {
            float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;

            warp_Material waterColormaterial;

            if (!threeD)
            {
                if (m_scene.RegionInfo.RegionSizeX >= m_scene.RegionInfo.RegionSizeY)
                {
                    renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeX / 2);
                }
                else
                {
                    renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeY / 2);
                }

                renderer.Scene.sceneobject("Water").setPos((m_scene.RegionInfo.RegionSizeX / 2) - 0.5f, waterHeight,
                                                           (m_scene.RegionInfo.RegionSizeY / 2) - 0.5f);
                waterColormaterial = new warp_Material(ConvertColor(WATER_COLOR));
                waterColormaterial.setTransparency((byte)((1f - WATER_COLOR.A) * 255f) * 2);
            }
            else
            {
                if (m_scene.RegionInfo.RegionSizeX >= m_scene.RegionInfo.RegionSizeY)
                {
                    renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeX / 2);
                }
                else
                {
                    renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeY / 2);
                }

                renderer.Scene.sceneobject("Water").setPos(
                    (m_scene.RegionInfo.RegionSizeX / 2) - 0.5f,
                    -0.5f,
                    waterHeight + 5.1f
                    );

                waterColormaterial = new warp_Material(ConvertColor(OPAQUE_WATER_COLOR));
                waterColormaterial.setTransparency(48);
            }

            waterColormaterial.setReflectivity(0);
            renderer.Scene.addMaterial("WaterColor", waterColormaterial);
            renderer.SetObjectMaterial("Water", "WaterColor");
        }
        string GetOrCreateMaterial(WarpRenderer renderer, Color4 color)
        {
            string name = color.ToString();

            warp_Material material = renderer.Scene.material(name);

            if (material != null)
            {
                return(name);
            }

            renderer.AddMaterial(name, ConvertColor(color));
            if (color.A < 1f)
            {
                renderer.Scene.material(name).setTransparency((byte)((1f - color.A) * 255f));
            }
            return(name);
        }
        public string GetOrCreateMaterial(WarpRenderer renderer, Color4 faceColor, UUID textureID)
        {
            string materialName = "Color-" + faceColor + "-Texture-" + textureID;

            if (renderer.Scene.material(materialName) == null)
            {
                MainConsole.Instance.DebugFormat("[WarpTile generator]: Creating material {0}", materialName);
                renderer.AddMaterial(materialName, ConvertColor(faceColor));
                if (faceColor.A < 1f)
                {
                    renderer.Scene.material(materialName).setTransparency((byte)((1f - faceColor.A) * 255f));
                }
                warp_Texture texture = GetTexture(textureID);
                if (texture != null)
                {
                    renderer.Scene.material(materialName).setTexture(texture);
                }
            }

            return(materialName);
        }
        public string GetOrCreateMaterial (WarpRenderer renderer, Color4 faceColor, UUID textureID)
        {
            string materialName = "Color-" + faceColor + "-Texture-" + textureID;

            if (renderer.Scene.material (materialName) == null) {
                MainConsole.Instance.DebugFormat ("Creating material {0}", materialName);
                renderer.AddMaterial (materialName, ConvertColor (faceColor));
                if (faceColor.A < 1f) {
                    renderer.Scene.material (materialName).setTransparency ((byte)((1f - faceColor.A) * 255f));
                }
                warp_Texture texture = GetTexture (textureID);
                if (texture != null)
                    renderer.Scene.material (materialName).setTexture (texture);
            }

            return materialName;
        }
        string GetOrCreateMaterial (WarpRenderer renderer, Color4 color)
        {
            string name = color.ToString ();

            warp_Material material = renderer.Scene.material (name);
            if (material != null)
                return name;

            renderer.AddMaterial (name, ConvertColor (color));
            if (color.A < 1f)
                renderer.Scene.material (name).setTransparency ((byte)((1f - color.A) * 255f));
            return name;
        }
        void CreatePrim (WarpRenderer renderer, ISceneChildEntity prim)
        {
            try {

                if ((PCode)prim.Shape.PCode != PCode.Prim)
                    return;
                if (prim.Scale.LengthSquared () < MIN_PRIM_SIZE * MIN_PRIM_SIZE)
                    return;

                Primitive omvPrim = prim.Shape.ToOmvPrimitive (prim.OffsetPosition, prim.GetRotationOffset ());
                FacetedMesh renderMesh = null;

                // Are we dealing with a sculptie or mesh?
                if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero) {
                    // Try fetching the asset
                    byte [] sculptAsset = m_scene.AssetService.GetData (omvPrim.Sculpt.SculptTexture.ToString ());
                    if (sculptAsset != null) {
                        // Is it a mesh?
                        if (omvPrim.Sculpt.Type == SculptType.Mesh) {
                            AssetMesh meshAsset = new AssetMesh (omvPrim.Sculpt.SculptTexture, sculptAsset);
                            FacetedMesh.TryDecodeFromAsset (omvPrim, meshAsset, DetailLevel.Highest, out renderMesh);
                            meshAsset = null;
                        } else // It's sculptie
                          {
                            Image sculpt = m_imgDecoder.DecodeToImage (sculptAsset);
                            if (sculpt != null) {
                                renderMesh = m_primMesher.GenerateFacetedSculptMesh (omvPrim, (Bitmap)sculpt,
                                                                                    DetailLevel.Medium);
                                sculpt.Dispose ();
                            }
                        }
                        sculptAsset = null;
                    } else {
                        // missing sculpt data... replace with something
                        renderMesh = m_primMesher.GenerateFacetedMesh (omvPrim, DetailLevel.Medium);
                    }

                } else // Prim
                  {
                    renderMesh = m_primMesher.GenerateFacetedMesh (omvPrim, DetailLevel.Medium);
                }

                if (renderMesh == null)
                    return;

                warp_Vector primPos = ConvertVector (prim.GetWorldPosition ());
                warp_Quaternion primRot = ConvertQuaternion (prim.GetRotationOffset ());

                warp_Matrix m = warp_Matrix.quaternionMatrix (primRot);

                if (prim.ParentID != 0) {
                    ISceneEntity group = m_scene.GetGroupByPrim (prim.LocalId);
                    if (group != null)
                        m.transform (warp_Matrix.quaternionMatrix (ConvertQuaternion (group.RootChild.GetRotationOffset ())));
                }

                warp_Vector primScale = ConvertVector (prim.Scale);

                string primID = prim.UUID.ToString ();

                // Create the prim faces
                for (int i = 0; i < renderMesh.Faces.Count; i++) {
                    Face renderFace = renderMesh.Faces [i];
                    string meshName = primID + "-Face-" + i;

                    warp_Object faceObj = new warp_Object (renderFace.Vertices.Count, renderFace.Indices.Count / 3);

                    foreach (Vertex v in renderFace.Vertices) {
                        warp_Vector pos = ConvertVector (v.Position);
                        warp_Vector norm = ConvertVector (v.Normal);

                        if (prim.Shape.SculptTexture == UUID.Zero)
                            norm = norm.reverse ();
                        warp_Vertex vert = new warp_Vertex (pos, norm, v.TexCoord.X, v.TexCoord.Y);

                        faceObj.addVertex (vert);
                    }

                    for (int j = 0; j < renderFace.Indices.Count;) {
                        faceObj.addTriangle (
                            renderFace.Indices [j++],
                            renderFace.Indices [j++],
                            renderFace.Indices [j++]);
                    }

                    Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace ((uint)i);
                    string materialName;
                    Color4 faceColor = GetFaceColor (teFace);

                    if (m_texturePrims && (prim.Scale.LengthSquared () > m_texturePrimSize)) {
                        materialName = GetOrCreateMaterial (renderer, faceColor, teFace.TextureID);
                    } else {
                        materialName = GetOrCreateMaterial (renderer, faceColor);
                    }

                    faceObj.transform (m);
                    faceObj.setPos (primPos);
                    faceObj.scaleSelf (primScale.x, primScale.y, primScale.z);

                    renderer.Scene.addObject (meshName, faceObj);

                    renderer.SetObjectMaterial (meshName, materialName);

                    faceObj = null;
                }
                renderMesh.Faces.Clear ();
                renderMesh = null;
            } catch (Exception ex) {
                MainConsole.Instance.Warn ("[Warp3D]: Exception creating prim, " + ex);
            }
        }
        warp_Object CreateTerrain (WarpRenderer renderer, bool textureTerrain)
        {
            ITerrainChannel terrain = m_scene.RequestModuleInterface<ITerrainChannel> ();

            float diffX = 1.0f; //(float) m_scene.RegionInfo.RegionSizeX/(float) Constants.RegionSize;
            float diffY = 1.0f; //(float) m_scene.RegionInfo.RegionSizeY/(float) Constants.RegionSize;
            int newRsX = m_scene.RegionInfo.RegionSizeX / (int)diffX;
            int newRsY = m_scene.RegionInfo.RegionSizeY / (int)diffY;

            warp_Object obj = new warp_Object (newRsX * newRsY, ((newRsX - 1) * (newRsY - 1) * 2));

            for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diffY) {
                for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diffX) {
                    float t_height = terrain [(int)x, (int)y];
                    float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;

                    //clamp to eliminate artifacts
                    t_height = Utils.Clamp (t_height, waterHeight - 0.5f, waterHeight + 0.5f);
                    if (t_height < 0.0f) t_height = 0.0f;

                    warp_Vector pos = ConvertVector (x / diffX, y / diffY, t_height);
                    obj.addVertex (
                        new warp_Vertex (pos,
                                        x / m_scene.RegionInfo.RegionSizeX,
                                        (m_scene.RegionInfo.RegionSizeY - y) / (m_scene.RegionInfo.RegionSizeY)));
                }
            }

            const float normal_map_reduction = 2.0f; //2.0f-2.5f is the sweet spot

            for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diffY) {
                for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diffX) {
                    float newX = x / diffX;
                    float newY = y / diffY;

                    if (newX < newRsX - 1 && newY < newRsY - 1) {
                        int v = (int)(newY * newRsX + newX);

                        // Normal
                        Vector3 v1 = new Vector3 (newX, newY, (terrain [(int)x, (int)y]) / normal_map_reduction);
                        Vector3 v2 = new Vector3 (newX + 1, newY,
                                                 (terrain [(int)x + 1, (int)y]) / normal_map_reduction);
                        Vector3 v3 = new Vector3 (newX, newY + 1,
                                                 (terrain [(int)x, (int)(y + 1)]) / normal_map_reduction);
                        warp_Vector norm = ConvertVector (SurfaceNormal (v1, v2, v3));
                        norm = norm.reverse ();
                        obj.vertex (v).n = norm;

                        // Triangle 1
                        obj.addTriangle (
                            v,
                            v + 1,
                            v + newRsX);

                        // Triangle 2
                        obj.addTriangle (
                            v + newRsX + 1,
                            v + newRsX,
                            v + 1);
                    }
                }
            }

            renderer.Scene.addObject ("Terrain", obj);
            renderer.Scene.sceneobject ("Terrain").setPos (0.0f, 0.0f, 0.0f);

            UUID [] textureIDs = new UUID [4];
            float [] startHeights = new float [4];
            float [] heightRanges = new float [4];

            RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings;

            textureIDs [0] = regionInfo.TerrainTexture1;
            textureIDs [1] = regionInfo.TerrainTexture2;
            textureIDs [2] = regionInfo.TerrainTexture3;
            textureIDs [3] = regionInfo.TerrainTexture4;

            startHeights [0] = (float)regionInfo.Elevation1SW;
            startHeights [1] = (float)regionInfo.Elevation1NW;
            startHeights [2] = (float)regionInfo.Elevation1SE;
            startHeights [3] = (float)regionInfo.Elevation1NE;

            heightRanges [0] = (float)regionInfo.Elevation2SW;
            heightRanges [1] = (float)regionInfo.Elevation2NW;
            heightRanges [2] = (float)regionInfo.Elevation2SE;
            heightRanges [3] = (float)regionInfo.Elevation2NE;

            uint globalX, globalY;
            Utils.LongToUInts (m_scene.RegionInfo.RegionHandle, out globalX, out globalY);

            Bitmap image = TerrainSplat.Splat (terrain, textureIDs, startHeights, heightRanges,
                                              new Vector3d (globalX, globalY, 0.0), m_scene.AssetService, textureTerrain);
            warp_Texture texture = new warp_Texture (image);
            warp_Material material = new warp_Material (texture);
            material.setReflectivity (0); // reduces tile seams a bit thanks lkalif
            renderer.Scene.addMaterial ("TerrainColor", material);
            renderer.SetObjectMaterial ("Terrain", "TerrainColor");

            image.Dispose ();

            return obj;
        }
        void CreateWater (WarpRenderer renderer, bool threeD)
        {
            float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
            int maxSize = m_scene.RegionInfo.RegionSizeX;
            if (m_scene.RegionInfo.RegionSizeY >= maxSize)
                maxSize = m_scene.RegionInfo.RegionSizeY;

            warp_Material waterColormaterial;
            if (!threeD) {
                // 20160210 -greythane-
                // it appears that the default plan object is rotated 45 degrees
                // work-a-round until verified or otherwise in the Warp3D library
                renderer.AddPlane ("Water", maxSize);
                renderer.Scene.sceneobject ("Water").setPos (0, waterHeight, 0);

                /* reference    if(m_scene.RegionInfo.RegionSizeX >= m_scene.RegionInfo.RegionSizeY)
                                    renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeX/2);
                                else
                                    renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeY/2);

                                renderer.Scene.sceneobject ("Water").setPos (
                                    (m_scene.RegionInfo.RegionSizeX / 2) - 0.5f,
                                    waterHeight,
                                    (m_scene.RegionInfo.RegionSizeY / 2) - 0.5f);


                */
                waterColormaterial = new warp_Material (ConvertColor (WATER_COLOR));
                //  waterColormaterial.setTransparency ((byte)((1f - WATER_COLOR.A) * 255f) * 2);
                waterColormaterial.setTransparency ((byte)((1f - WATER_COLOR.A) * 255f));
            } else {
                renderer.AddPlane ("Water", maxSize / 2);

                /* for reference
                                if(m_scene.RegionInfo.RegionSizeX >= m_scene.RegionInfo.RegionSizeY)
                                    renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeX/2);
                                else
                                    renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeY/2);
                */
                renderer.Scene.sceneobject ("Water").setPos (
                    (m_scene.RegionInfo.RegionSizeX / 2f) - 0.5f,
                    -0.5f,
                    waterHeight + 5.1f
                    );

                waterColormaterial = new warp_Material (ConvertColor (OPAQUE_WATER_COLOR));
                waterColormaterial.setTransparency (48);
                //waterColormaterial.opaque = true;
            }

            waterColormaterial.setReflectivity (0);
            renderer.Scene.addMaterial ("WaterColor", waterColormaterial);
            renderer.SetObjectMaterial ("Water", "WaterColor");
        }
        public Bitmap TerrainBitmap (Viewport viewport, bool threeD)
        {
            // AntiAliasing
            int width = viewport.Width * 2;
            int height = viewport.Height * 2;

            WarpRenderer renderer = new WarpRenderer ();
            if (!renderer.CreateScene (width, height)) {
                MainConsole.Instance.Error ("[Warp3D]: Unable to create the required scene! Maybe lack of RAM?");
                return new Bitmap (Constants.RegionSize, Constants.RegionSize, PixelFormat.Format24bppRgb);
            }
            renderer.Scene.autoCalcNormals = false;
            if (threeD)
                renderer.SetBackgroundColor (SKYCOLOR);

            #region Camera

            warp_Vector pos = ConvertVector (viewport.Position);
            pos.z -= 0.001f; // Works around an issue with the Warp3D camera
            warp_Vector lookat = warp_Vector.add (ConvertVector (viewport.Position), ConvertVector (viewport.LookDirection));

            renderer.Scene.defaultCamera.setPos (pos);
            renderer.Scene.defaultCamera.lookAt (lookat);

            if (viewport.Orthographic) {
                renderer.Scene.defaultCamera.isOrthographic = true;
                if (viewport.OrthoWindowWidth <= viewport.OrthoWindowHeight) {
                    renderer.Scene.defaultCamera.orthoViewWidth = viewport.OrthoWindowWidth;
                    renderer.Scene.defaultCamera.orthoViewHeight = viewport.OrthoWindowWidth;
                } else {
                    renderer.Scene.defaultCamera.orthoViewWidth = viewport.OrthoWindowHeight;
                    renderer.Scene.defaultCamera.orthoViewHeight = viewport.OrthoWindowHeight;
                }
            } else {
                viewport.Orthographic = false;
                float fov = viewport.FieldOfView;
                renderer.Scene.defaultCamera.setFov (fov);
            }

            #endregion Camera

            renderer.Scene.addLight ("Light1", new warp_Light (new warp_Vector (1.0f, 0.5f, 1f), 0xffffff, 0, 320, 40));
            renderer.Scene.addLight ("Light2", new warp_Light (new warp_Vector (-1f, -1f, 1f), 0xffffff, 0, 100, 40));


            try {
                CreateWater (renderer, threeD);
                CreateTerrain (renderer, m_textureTerrain);

                if (m_drawPrimVolume && m_primMesher != null) {
                    foreach (ISceneChildEntity part in m_scene.Entities.GetEntities ().SelectMany (ent => ent.ChildrenEntities ()))
                        CreatePrim (renderer, part);
                }

            } catch (Exception ex) {
                MainConsole.Instance.Warn ("[Warp3D]: Exception in the map generation, " + ex);
            }

            renderer.Render ();
            Bitmap bitmap = renderer.Scene.getImage ();

            // AntiAliasing
            using (Bitmap origBitmap = bitmap)
                bitmap = ImageUtils.ResizeImage (origBitmap, viewport.Width, viewport.Height);


            // Clean up
            SaveCache ();
            foreach (var o in renderer.Scene.objectData.Values) {
                warp_Object obj = (warp_Object)o;
                obj.vertexData = null;
                obj.triangleData = null;
            }

            renderer.Scene.removeAllObjects ();
            renderer.Reset ();
            m_colors.Clear ();

            //Force GC to try to clean this mess up
            GC.Collect ();

            return bitmap;
        }
        void CreateWater(WarpRenderer renderer, bool threeD)
        {
            float waterHeight = (float) m_scene.RegionInfo.RegionSettings.WaterHeight;

            warp_Material waterColormaterial;
            if (!threeD)
            {
                if(m_scene.RegionInfo.RegionSizeX >= m_scene.RegionInfo.RegionSizeY)
                    renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeX/2);
                else
                    renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeY/2);

                renderer.Scene.sceneobject ("Water").setPos ((m_scene.RegionInfo.RegionSizeX / 2) - 0.5f, waterHeight,
                    (m_scene.RegionInfo.RegionSizeY / 2) - 0.5f);
                               waterColormaterial = new warp_Material (ConvertColor (WATER_COLOR));
                waterColormaterial.setTransparency ((byte)((1f - WATER_COLOR.A) * 255f) * 2);
            } else
            {
                if(m_scene.RegionInfo.RegionSizeX >= m_scene.RegionInfo.RegionSizeY)
                    renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeX/2);
                else
                    renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeY/2);

                renderer.Scene.sceneobject ("Water").setPos (
                    (m_scene.RegionInfo.RegionSizeX / 2) -0.5f,
                    - 0.5f,
                    waterHeight+5.1f
                    );

                waterColormaterial = new warp_Material(ConvertColor(OPAQUE_WATER_COLOR));
                waterColormaterial.setTransparency (48);
                //waterColormaterial.opaque = true;
            }

            waterColormaterial.setReflectivity(0);
            renderer.Scene.addMaterial("WaterColor", waterColormaterial);
            renderer.SetObjectMaterial("Water", "WaterColor");
        }
        void CreatePrim(WarpRenderer renderer, ISceneChildEntity prim, bool texturePrims)
        {
            try {
                if ((PCode)prim.Shape.PCode != PCode.Prim)
                {
                    return;
                }
                if (prim.Scale.LengthSquared() < MIN_PRIM_SIZE * MIN_PRIM_SIZE)
                {
                    return;
                }

                Primitive   omvPrim    = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.GetRotationOffset());
                FacetedMesh renderMesh = null;

                // Are we dealing with a sculptie or mesh?
                if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero)
                {
                    // Try fetching the asset
                    byte [] sculptAsset = m_scene.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString());
                    if (sculptAsset != null)
                    {
                        // Is it a mesh?
                        if (omvPrim.Sculpt.Type == SculptType.Mesh)
                        {
                            AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset);
                            FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out renderMesh);
                            meshAsset = null;
                        }
                        else   // It's sculptie
                        {
                            Image sculpt = m_imgDecoder.DecodeToImage(sculptAsset);
                            if (sculpt != null)
                            {
                                renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt,
                                                                                    DetailLevel.Medium);
                                sculpt.Dispose();
                            }
                        }
                        sculptAsset = null;
                    }
                    else
                    {
                        // missing sculpt data... replace with something
                        renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium);
                    }
                }
                else   // Prim
                {
                    renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium);
                }

                if (renderMesh == null)
                {
                    return;
                }

                warp_Vector     primPos = ConvertVector(prim.GetWorldPosition());
                warp_Quaternion primRot = ConvertQuaternion(prim.GetRotationOffset());

                warp_Matrix m = warp_Matrix.quaternionMatrix(primRot);

                if (prim.ParentID != 0)
                {
                    ISceneEntity group = m_scene.GetGroupByPrim(prim.LocalId);
                    if (group != null)
                    {
                        m.transform(warp_Matrix.quaternionMatrix(ConvertQuaternion(group.RootChild.GetRotationOffset())));
                    }
                }

                warp_Vector primScale = ConvertVector(prim.Scale);

                string primID = prim.UUID.ToString();

                // Create the prim faces
                for (int i = 0; i < renderMesh.Faces.Count; i++)
                {
                    Face   renderFace = renderMesh.Faces [i];
                    string meshName   = primID + "-Face-" + i;

                    warp_Object faceObj = new warp_Object(renderFace.Vertices.Count, renderFace.Indices.Count / 3);

                    foreach (Vertex v in renderFace.Vertices)
                    {
                        warp_Vector pos  = ConvertVector(v.Position);
                        warp_Vector norm = ConvertVector(v.Normal);

                        if (prim.Shape.SculptTexture == UUID.Zero)
                        {
                            norm = norm.reverse();
                        }
                        warp_Vertex vert = new warp_Vertex(pos, norm, v.TexCoord.X, v.TexCoord.Y);

                        faceObj.addVertex(vert);
                    }

                    for (int j = 0; j < renderFace.Indices.Count;)
                    {
                        faceObj.addTriangle(
                            renderFace.Indices [j++],
                            renderFace.Indices [j++],
                            renderFace.Indices [j++]);
                    }

                    Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i);
                    string materialName;
                    Color4 faceColor = GetFaceColor(teFace);

                    if (texturePrims && (prim.Scale.LengthSquared() > m_texturePrimSize))
                    {
                        materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID);
                    }
                    else
                    {
                        materialName = GetOrCreateMaterial(renderer, faceColor);
                    }

                    faceObj.transform(m);
                    faceObj.setPos(primPos);
                    faceObj.scaleSelf(primScale.x, primScale.y, primScale.z);

                    renderer.Scene.addObject(meshName, faceObj);

                    renderer.SetObjectMaterial(meshName, materialName);

                    faceObj = null;
                }
                renderMesh.Faces.Clear();
                renderMesh = null;
            } catch (Exception ex) {
                MainConsole.Instance.Warn("[WarpTile generator]: Exception creating prim, " + ex);
            }
        }
        warp_Object CreateTerrain(WarpRenderer renderer, bool textureTerrain)
        {
            ITerrainChannel terrain = m_scene.RequestModuleInterface <ITerrainChannel> ();

            float diffX  = 1.0f; //(float) m_scene.RegionInfo.RegionSizeX/(float) Constants.RegionSize;
            float diffY  = 1.0f; //(float) m_scene.RegionInfo.RegionSizeY/(float) Constants.RegionSize;
            int   newRsX = m_scene.RegionInfo.RegionSizeX / (int)diffX;
            int   newRsY = m_scene.RegionInfo.RegionSizeY / (int)diffY;

            warp_Object obj = new warp_Object(newRsX * newRsY, ((newRsX - 1) * (newRsY - 1) * 2));

            for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diffY)
            {
                for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diffX)
                {
                    float t_height    = terrain [(int)x, (int)y];
                    float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;

                    //clamp to eliminate artifacts
                    t_height = Utils.Clamp(t_height, waterHeight - 0.5f, waterHeight + 0.5f);
                    if (t_height < 0.0f)
                    {
                        t_height = 0.0f;
                    }

                    warp_Vector pos = ConvertVector(x / diffX, y / diffY, t_height);
                    obj.addVertex(
                        new warp_Vertex(pos,
                                        x / m_scene.RegionInfo.RegionSizeX,
                                        (m_scene.RegionInfo.RegionSizeY - y) / (m_scene.RegionInfo.RegionSizeY)));
                }
            }

            const float normal_map_reduction = 2.0f; //2.0f-2.5f is the sweet spot

            for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diffY)
            {
                for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diffX)
                {
                    float newX = x / diffX;
                    float newY = y / diffY;

                    if (newX < newRsX - 1 && newY < newRsY - 1)
                    {
                        int v = (int)(newY * newRsX + newX);

                        // Normal
                        Vector3 v1 = new Vector3(newX, newY, (terrain [(int)x, (int)y]) / normal_map_reduction);
                        Vector3 v2 = new Vector3(newX + 1, newY,
                                                 (terrain [(int)x + 1, (int)y]) / normal_map_reduction);
                        Vector3 v3 = new Vector3(newX, newY + 1,
                                                 (terrain [(int)x, (int)(y + 1)]) / normal_map_reduction);
                        warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3));
                        norm            = norm.reverse();
                        obj.vertex(v).n = norm;

                        // Triangle 1
                        obj.addTriangle(
                            v,
                            v + 1,
                            v + newRsX);

                        // Triangle 2
                        obj.addTriangle(
                            v + newRsX + 1,
                            v + newRsX,
                            v + 1);
                    }
                }
            }

            renderer.Scene.addObject("Terrain", obj);
            renderer.Scene.sceneobject("Terrain").setPos(0.0f, 0.0f, 0.0f);

            UUID []  textureIDs   = new UUID [4];
            float [] startHeights = new float [4];
            float [] heightRanges = new float [4];

            RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings;

            textureIDs [0] = regionInfo.TerrainTexture1;
            textureIDs [1] = regionInfo.TerrainTexture2;
            textureIDs [2] = regionInfo.TerrainTexture3;
            textureIDs [3] = regionInfo.TerrainTexture4;

            startHeights [0] = (float)regionInfo.Elevation1SW;
            startHeights [1] = (float)regionInfo.Elevation1NW;
            startHeights [2] = (float)regionInfo.Elevation1SE;
            startHeights [3] = (float)regionInfo.Elevation1NE;

            heightRanges [0] = (float)regionInfo.Elevation2SW;
            heightRanges [1] = (float)regionInfo.Elevation2NW;
            heightRanges [2] = (float)regionInfo.Elevation2SE;
            heightRanges [3] = (float)regionInfo.Elevation2NE;

            uint globalX, globalY;

            Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out globalX, out globalY);

            Bitmap image = TerrainSplat.Splat(terrain, textureIDs, startHeights, heightRanges,
                                              new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain);
            warp_Texture  texture  = new warp_Texture(image);
            warp_Material material = new warp_Material(texture);

            material.setReflectivity(0);  // reduces tile seams a bit thanks lkalif
            renderer.Scene.addMaterial("TerrainColor", material);
            renderer.SetObjectMaterial("Terrain", "TerrainColor");

            image.Dispose();

            return(obj);
        }
        void CreateWater(WarpRenderer renderer, bool threeD)
        {
            float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
            int   maxSize     = m_scene.RegionInfo.RegionSizeX;

            if (m_scene.RegionInfo.RegionSizeY >= maxSize)
            {
                maxSize = m_scene.RegionInfo.RegionSizeY;
            }

            warp_Material waterColormaterial;

            if (!threeD)
            {
                // 20160210 -greythane-
                // it appears that the default plan object is rotated 45 degrees
                // work-a-round until verified or otherwise in the Warp3D library
                renderer.AddPlane("Water", maxSize);
                renderer.Scene.sceneobject("Water").setPos(0, waterHeight, 0);

                /* reference    if(m_scene.RegionInfo.RegionSizeX >= m_scene.RegionInfo.RegionSizeY)
                 *                  renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeX/2);
                 *              else
                 *                  renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeY/2);
                 *
                 *              renderer.Scene.sceneobject ("Water").setPos (
                 *                  (m_scene.RegionInfo.RegionSizeX / 2) - 0.5f,
                 *                  waterHeight,
                 *                  (m_scene.RegionInfo.RegionSizeY / 2) - 0.5f);
                 *
                 *
                 */
                waterColormaterial = new warp_Material(ConvertColor(WATER_COLOR));
                //  waterColormaterial.setTransparency ((byte)((1f - WATER_COLOR.A) * 255f) * 2);
                waterColormaterial.setTransparency((byte)((1f - WATER_COLOR.A) * 255f));
            }
            else
            {
                renderer.AddPlane("Water", maxSize / 2);

                /* for reference
                 *              if(m_scene.RegionInfo.RegionSizeX >= m_scene.RegionInfo.RegionSizeY)
                 *                  renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeX/2);
                 *              else
                 *                  renderer.AddPlane ("Water", m_scene.RegionInfo.RegionSizeY/2);
                 */
                renderer.Scene.sceneobject("Water").setPos(
                    (m_scene.RegionInfo.RegionSizeX / 2f) - 0.5f,
                    -0.5f,
                    waterHeight + 5.1f
                    );

                waterColormaterial = new warp_Material(ConvertColor(OPAQUE_WATER_COLOR));
                waterColormaterial.setTransparency(48);
                //waterColormaterial.opaque = true;
            }

            waterColormaterial.setReflectivity(0);
            renderer.Scene.addMaterial("WaterColor", waterColormaterial);
            renderer.SetObjectMaterial("Water", "WaterColor");
        }
        public Bitmap TerrainBitmap(Viewport viewport, bool threeD, bool useTextures)
        {
            // AntiAliasing
            int width      = viewport.Width * 2;
            int height     = viewport.Height * 2;
            var texTerrain = m_textureTerrain & useTextures;
            var texPrims   = m_texturePrims & useTextures;

            WarpRenderer renderer = new WarpRenderer();

            if (!renderer.CreateScene(width, height))
            {
                MainConsole.Instance.Error("[WarpTile generator]: Unable to create the required scene! Maybe lack of RAM?");
                return(new Bitmap(Constants.RegionSize, Constants.RegionSize, PixelFormat.Format24bppRgb));
            }
            renderer.Scene.autoCalcNormals = false;
            if (threeD)
            {
                renderer.SetBackgroundColor(SKYCOLOR);
            }

            #region Camera

            warp_Vector pos = ConvertVector(viewport.Position);
            pos.z -= 0.001f; // Works around an issue with the Warp3D camera
            warp_Vector lookat = warp_Vector.add(ConvertVector(viewport.Position), ConvertVector(viewport.LookDirection));

            renderer.Scene.defaultCamera.setPos(pos);
            renderer.Scene.defaultCamera.lookAt(lookat);

            if (viewport.Orthographic)
            {
                renderer.Scene.defaultCamera.isOrthographic = true;
                if (viewport.OrthoWindowWidth <= viewport.OrthoWindowHeight)
                {
                    renderer.Scene.defaultCamera.orthoViewWidth  = viewport.OrthoWindowWidth;
                    renderer.Scene.defaultCamera.orthoViewHeight = viewport.OrthoWindowWidth;
                }
                else
                {
                    renderer.Scene.defaultCamera.orthoViewWidth  = viewport.OrthoWindowHeight;
                    renderer.Scene.defaultCamera.orthoViewHeight = viewport.OrthoWindowHeight;
                }
            }
            else
            {
                viewport.Orthographic = false;
                float fov = viewport.FieldOfView;
                renderer.Scene.defaultCamera.setFov(fov);
            }

            #endregion Camera

            renderer.Scene.addLight("Light1", new warp_Light(new warp_Vector(1.0f, 0.5f, 1f), 0xffffff, 0, 320, 40));
            renderer.Scene.addLight("Light2", new warp_Light(new warp_Vector(-1f, -1f, 1f), 0xffffff, 0, 100, 40));


            try {
                CreateWater(renderer, threeD);
                CreateTerrain(renderer, texTerrain);

                if (m_drawPrimVolume && m_primMesher != null)
                {
                    foreach (ISceneChildEntity part in m_scene.Entities.GetEntities().SelectMany(ent => ent.ChildrenEntities()))
                    {
                        CreatePrim(renderer, part, texPrims);
                    }
                }
            } catch (Exception ex) {
                MainConsole.Instance.Warn("[WarpTile generator]: Exception in the map generation, " + ex);
            }

            renderer.Render();
            Bitmap bitmap = renderer.Scene.getImage();

            // AntiAliasing
            using (Bitmap origBitmap = bitmap)
                bitmap = ImageUtils.ResizeImage(origBitmap, viewport.Width, viewport.Height);


            // Clean up
            SaveCache();
            foreach (var o in renderer.Scene.objectData.Values)
            {
                warp_Object obj = (warp_Object)o;
                obj.vertexData   = null;
                obj.triangleData = null;
            }

            renderer.Scene.removeAllObjects();
            renderer.Reset();
            m_colors.Clear();

            //Force GC to try to clean this mess up
            GC.Collect();

            return(bitmap);
        }