using System; using System.Drawing; using ClassicalSharp.GraphicsAPI; using OpenTK; namespace ClassicalSharp.Renderers { /// Same as NormalEnvRenderer, but breaks sky and clouds into 128 sized blocks. public class LegacyEnvRenderer : EnvRenderer { public LegacyEnvRenderer( Game window ) { Window = window; Map = Window.Map; } int cloudTexture = -1, cloudsVbo = -1, cloudsVertices = 0; int skyOffset = 10, skyVbo = -1, skyVertices = 6; public float CloudsSpeed = 1f; public override void Render( double deltaTime ) { if( skyVbo != -1 ) { Vector3 pos = Window.LocalPlayer.EyePosition; if( pos.Y < Map.Height + skyOffset ) { Graphics.DrawVbPos3fCol4b( DrawMode.Triangles, skyVbo, skyVertices ); } } if( cloudsVbo != -1 ) { RenderClouds( deltaTime ); } ResetFog(); } public void SetSkyOffset( int offset ) { skyOffset = offset; ResetSky(); } protected override void CloudsColourChanged() { ResetClouds(); } protected override void FogColourChanged() { ResetFog(); } protected override void SkyColourChanged() { ResetSky(); } public override void OnNewMap( object sender, EventArgs e ) { Graphics.Fog = false; Graphics.DeleteVb( skyVbo ); Graphics.DeleteVb( cloudsVbo ); skyVbo = -1; cloudsVbo = -1; } public override void OnNewMapLoaded( object sender, EventArgs e ) { Graphics.Fog = true; ResetFog(); ResetSky(); ResetClouds(); } public override void Init() { base.Init(); Graphics.Fog = true; ResetFog(); ResetSky(); ResetClouds(); cloudTexture = Graphics.LoadTexture( "clouds.png" ); Window.ViewDistanceChanged += delegate { ResetFog(); ResetSky(); ResetClouds(); }; } public override void Dispose() { base.Dispose(); Graphics.DeleteVb( skyVbo ); Graphics.DeleteVb( cloudsVbo ); Graphics.DeleteTexture( cloudTexture ); } void RenderClouds( double delta ) { double time = Window.accumulator; float offset = (float)( time / 2048f * 0.6f * CloudsSpeed ); Graphics.SetMatrixMode( MatrixType.Texture ); Matrix4 matrix = Matrix4.CreateTranslation( offset, 0, 0 ); Graphics.LoadMatrix( ref matrix ); Graphics.SetMatrixMode( MatrixType.Modelview ); Graphics.AlphaTest = true; Graphics.Texturing = true; Graphics.Bind2DTexture( cloudTexture ); Graphics.DrawVbPos3fTex2fCol4b( DrawMode.Triangles, cloudsVbo, cloudsVertices ); Graphics.AlphaTest = false; Graphics.Texturing = false; Graphics.SetMatrixMode( MatrixType.Texture ); Graphics.LoadIdentityMatrix(); Graphics.SetMatrixMode( MatrixType.Modelview ); } void ResetClouds() { Graphics.DeleteVb( cloudsVbo ); if( Map.IsNotLoaded ) return; int extent = Window.ViewDistance; int x1 = 0 - extent, x2 = Map.Width + extent; int y = Map.Height + 2; int z1 = 0 - extent, z2 = Map.Length + extent; FastColour cloudsCol = Map.CloudsCol; cloudsVertices = CountVertices( x2 - x1, z2 - z1 ); VertexPos3fTex2fCol4b[] vertices = new VertexPos3fTex2fCol4b[cloudsVertices]; DrawCloudsYPlane( x1, z1, x2, z2, y, cloudsCol, vertices ); cloudsVbo = Graphics.InitVb( vertices, DrawMode.Triangles, VertexFormat.VertexPos3fTex2fCol4b ); } void ResetSky() { Graphics.DeleteVb( skyVbo ); if( Map.IsNotLoaded ) return; int extent = Window.ViewDistance; int x1 = 0 - extent, x2 = Map.Width + extent; int y = Map.Height + skyOffset; int z1 = 0 - extent, z2 = Map.Length + extent; FastColour skyCol = Map.SkyCol; skyVertices = CountVertices( x2 - x1, z2 - z1 ); VertexPos3fCol4b[] vertices = new VertexPos3fCol4b[skyVertices]; DrawSkyYPlane( x1, z1, x2, z2, y, skyCol, vertices ); skyVbo = Graphics.InitVb( vertices, DrawMode.Triangles, VertexFormat.VertexPos3fCol4b ); } int CountVertices( int axis1Len, int axis2Len ) { int cellsAxis1 = axis1Len / 128 + ( axis1Len % 128 != 0 ? 1 : 0 ); int cellsAxis2 = axis2Len / 128 + ( axis2Len % 128 != 0 ? 1 : 0 ); return cellsAxis1 * cellsAxis2 * 6; } void DrawSkyYPlane( int x1, int z1, int x2, int z2, int y, FastColour col, VertexPos3fCol4b[] vertices ) { int width = x2 - x1, endX = x2; int length = z2 - z1, endZ = z2, startZ = z1; int index = 0; for( ; x1 < endX; x1 += 128 ) { x2 = x1 + 128; if( x2 > endX ) x2 = endX; z1 = startZ; for( ; z1 < endZ; z1 += 128 ) { z2 = z1 + 128; if( z2 > endZ ) z2 = endZ; vertices[index++] = new VertexPos3fCol4b( x1, y, z1, col ); vertices[index++] = new VertexPos3fCol4b( x1, y, z2, col ); vertices[index++] = new VertexPos3fCol4b( x2, y, z2, col ); vertices[index++] = new VertexPos3fCol4b( x2, y, z2, col ); vertices[index++] = new VertexPos3fCol4b( x2, y, z1, col ); vertices[index++] = new VertexPos3fCol4b( x1, y, z1, col ); } } } void DrawCloudsYPlane( int x1, int z1, int x2, int z2, int y, FastColour col, VertexPos3fTex2fCol4b[] vertices ) { int width = x2 - x1, endX = x2; int length = z2 - z1, endZ = z2, startZ = z1; int index = 0; for( ; x1 < endX; x1 += 128 ) { x2 = x1 + 128; if( x2 > endX ) x2 = endX; z1 = startZ; for( ; z1 < endZ; z1 += 128 ) { z2 = z1 + 128; if( z2 > endZ ) z2 = endZ; vertices[index++] = new VertexPos3fTex2fCol4b( x1, y, z1, x1 / 2048f, z1 / 2048f, col ); vertices[index++] = new VertexPos3fTex2fCol4b( x1, y, z2, x1 / 2048f, z2 / 2048f, col ); vertices[index++] = new VertexPos3fTex2fCol4b( x2, y, z2, x2 / 2048f, z2 / 2048f, col ); vertices[index++] = new VertexPos3fTex2fCol4b( x2, y, z2, x2 / 2048f, z2 / 2048f, col ); vertices[index++] = new VertexPos3fTex2fCol4b( x2, y, z1, x2 / 2048f, z1 / 2048f, col ); vertices[index++] = new VertexPos3fTex2fCol4b( x1, y, z1, x1 / 2048f, z1 / 2048f, col ); } } } double blendFactor( int x ) { //return -0.05 + 0.22 * Math.Log( Math.Pow( x, 0.25 ) ); double blend = -0.13 + 0.28 * Math.Log( Math.Pow( x, 0.25 ) ); if( blend < 0 ) blend = 0; return blend; } public override void EnableAmbientLighting() { Block headBlock = Window.LocalPlayer.BlockAtHead; if( headBlock == Block.Water || headBlock == Block.StillWater ) { Graphics.AmbientLighting = true; Graphics.SetAmbientColour( new FastColour( 102, 102, 230 ) ); } else if( headBlock == Block.Lava || headBlock == Block.StillLava ) { Graphics.AmbientLighting = true; Graphics.SetAmbientColour( new FastColour( 102, 77, 77 ) ); } else { // don't turn on unnecessary ambient colour of 255,255,255 } } public override void DisableAmbientLighting() { Graphics.AmbientLighting = false; } void ResetFog() { if( Map.IsNotLoaded ) return; FastColour fogCol = Map.FogCol; FastColour skyCol = Map.SkyCol; FastColour adjFogCol = fogCol; Block headBlock = Window.LocalPlayer.BlockAtHead; if( headBlock == Block.Water || headBlock == Block.StillWater ) { Graphics.SetFogMode( Fog.Exp ); Graphics.SetFogDensity( 0.1f ); adjFogCol = new FastColour( 5, 5, 51 ); } else if( headBlock == Block.Lava || headBlock == Block.StillLava ) { Graphics.SetFogMode( Fog.Exp ); Graphics.SetFogDensity( 2f ); adjFogCol = new FastColour( 153, 25, 0 ); } else { // Blend fog and sky together float blend = (float)blendFactor( Window.ViewDistance ); adjFogCol.R = (byte)( Utils.Lerp( fogCol.R / 255f, skyCol.R / 255f, blend ) * 255 ); adjFogCol.G = (byte)( Utils.Lerp( fogCol.G / 255f, skyCol.G / 255f, blend ) * 255 ); adjFogCol.B = (byte)( Utils.Lerp( fogCol.B / 255f, skyCol.B / 255f, blend ) * 255 ); Graphics.SetFogMode( Fog.Linear ); Graphics.SetFogStart( 0 ); Graphics.SetFogEnd( Window.ViewDistance ); } Graphics.ClearColour( adjFogCol ); Graphics.SetFogColour( adjFogCol ); } } }