mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-10-29 09:35:17 -04:00
226 lines
6.7 KiB
C#
226 lines
6.7 KiB
C#
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
|
|
using System;
|
|
using ClassicalSharp.Events;
|
|
using ClassicalSharp.GraphicsAPI;
|
|
using OpenTK;
|
|
|
|
namespace ClassicalSharp.Renderers {
|
|
|
|
public unsafe class StandardEnvRenderer : EnvRenderer {
|
|
|
|
int cloudsVb = -1, cloudVertices, skyVb = -1, skyVertices;
|
|
internal bool legacy;
|
|
|
|
public override void UseLegacyMode(bool legacy) {
|
|
this.legacy = legacy;
|
|
ContextRecreated();
|
|
}
|
|
|
|
public override void Render(double deltaTime) {
|
|
if (skyVb == -1 || cloudsVb == -1) return;
|
|
if (!game.SkyboxRenderer.ShouldRender)
|
|
RenderMainEnv(deltaTime);
|
|
UpdateFog();
|
|
}
|
|
|
|
void RenderMainEnv(double deltaTime) {
|
|
Vector3 pos = game.CurrentCameraPos;
|
|
float normalY = map.Height + 8;
|
|
float skyY = Math.Max(pos.Y + 8, normalY);
|
|
|
|
gfx.SetBatchFormat(VertexFormat.P3fC4b);
|
|
gfx.BindVb(skyVb);
|
|
if (skyY == normalY) {
|
|
gfx.DrawIndexedVb(DrawMode.Triangles, skyVertices * 6 / 4, 0);
|
|
} else {
|
|
Matrix4 m = Matrix4.Identity;
|
|
m.Row3.Y = skyY - normalY; // Y translation matrix
|
|
|
|
gfx.PushMatrix();
|
|
gfx.MultiplyMatrix(ref m);
|
|
gfx.DrawIndexedVb(DrawMode.Triangles, skyVertices * 6 / 4, 0);
|
|
gfx.PopMatrix();
|
|
}
|
|
RenderClouds(deltaTime);
|
|
}
|
|
|
|
protected override void EnvVariableChanged(object sender, EnvVarEventArgs e) {
|
|
if (e.Var == EnvVar.SkyColour) {
|
|
ResetSky();
|
|
} else if (e.Var == EnvVar.FogColour) {
|
|
UpdateFog();
|
|
} else if (e.Var == EnvVar.CloudsColour) {
|
|
ResetClouds();
|
|
} else if (e.Var == EnvVar.CloudsLevel) {
|
|
ResetSky();
|
|
ResetClouds();
|
|
}
|
|
}
|
|
|
|
public override void Init(Game game) {
|
|
base.Init(game);
|
|
gfx.SetFogStart(0);
|
|
gfx.Fog = true;
|
|
ResetAllEnv(null, null);
|
|
|
|
game.Events.ViewDistanceChanged += ResetAllEnv;
|
|
game.Graphics.ContextLost += ContextLost;
|
|
game.Graphics.ContextRecreated += ContextRecreated;
|
|
game.SetViewDistance(game.UserViewDistance, false);
|
|
}
|
|
|
|
public override void OnNewMap(Game game) {
|
|
gfx.Fog = false;
|
|
gfx.DeleteVb(ref skyVb);
|
|
gfx.DeleteVb(ref cloudsVb);
|
|
}
|
|
|
|
public override void OnNewMapLoaded(Game game) {
|
|
gfx.Fog = true;
|
|
ResetAllEnv(null, null);
|
|
}
|
|
|
|
void ResetAllEnv(object sender, EventArgs e) {
|
|
UpdateFog();
|
|
ContextRecreated();
|
|
}
|
|
|
|
public override void Dispose() {
|
|
base.Dispose();
|
|
ContextLost();
|
|
|
|
game.Events.ViewDistanceChanged -= ResetAllEnv;
|
|
game.Graphics.ContextLost -= ContextLost;
|
|
game.Graphics.ContextRecreated -= ContextRecreated;
|
|
}
|
|
|
|
void RenderClouds(double delta) {
|
|
if (game.World.Env.CloudHeight < -2000) return;
|
|
double time = game.accumulator;
|
|
float offset = (float)(time / 2048f * 0.6f * map.Env.CloudsSpeed);
|
|
gfx.SetMatrixMode(MatrixType.Texture);
|
|
Matrix4 matrix = Matrix4.Identity; matrix.Row3.X = offset; // translate X axis
|
|
gfx.LoadMatrix(ref matrix);
|
|
gfx.SetMatrixMode(MatrixType.Modelview);
|
|
|
|
gfx.AlphaTest = true;
|
|
gfx.Texturing = true;
|
|
gfx.BindTexture(game.CloudsTex);
|
|
gfx.SetBatchFormat(VertexFormat.P3fT2fC4b);
|
|
gfx.BindVb(cloudsVb);
|
|
gfx.DrawIndexedVb_TrisT2fC4b(cloudVertices * 6 / 4, 0);
|
|
gfx.AlphaTest = false;
|
|
gfx.Texturing = false;
|
|
|
|
gfx.SetMatrixMode(MatrixType.Texture);
|
|
gfx.LoadIdentityMatrix();
|
|
gfx.SetMatrixMode(MatrixType.Modelview);
|
|
}
|
|
|
|
void UpdateFog() {
|
|
if (map.IsNotLoaded) return;
|
|
FastColour fogCol = FastColour.White;
|
|
float fogDensity = 0;
|
|
byte block = BlockOn(out fogDensity, out fogCol);
|
|
|
|
if (fogDensity != 0) {
|
|
gfx.SetFogMode(Fog.Exp);
|
|
gfx.SetFogDensity(fogDensity);
|
|
} else {
|
|
gfx.SetFogMode(Fog.Linear);
|
|
gfx.SetFogEnd(game.ViewDistance);
|
|
}
|
|
gfx.ClearColour(fogCol);
|
|
gfx.SetFogColour(fogCol);
|
|
}
|
|
|
|
void ResetClouds() {
|
|
if (map.IsNotLoaded || game.Graphics.LostContext) return;
|
|
gfx.DeleteVb(ref cloudsVb);
|
|
RebuildClouds((int)game.ViewDistance, legacy ? 128 : 65536);
|
|
}
|
|
|
|
void ResetSky() {
|
|
if (map.IsNotLoaded || game.Graphics.LostContext) return;
|
|
gfx.DeleteVb(ref skyVb);
|
|
RebuildSky((int)game.ViewDistance, legacy ? 128 : 65536);
|
|
}
|
|
|
|
void ContextLost() {
|
|
game.Graphics.DeleteVb(ref skyVb);
|
|
game.Graphics.DeleteVb(ref cloudsVb);
|
|
}
|
|
|
|
void ContextRecreated() {
|
|
ResetClouds();
|
|
ResetSky();
|
|
}
|
|
|
|
|
|
void RebuildClouds(int extent, int axisSize) {
|
|
extent = Utils.AdjViewDist(extent);
|
|
int x1 = -extent, x2 = map.Width + extent;
|
|
int z1 = -extent, z2 = map.Length + extent;
|
|
cloudVertices = Utils.CountVertices(x2 - x1, z2 - z1, axisSize);
|
|
|
|
VertexP3fT2fC4b[] vertices = new VertexP3fT2fC4b[cloudVertices];
|
|
DrawCloudsY(x1, z1, x2, z2, map.Env.CloudHeight, axisSize, map.Env.CloudsCol.Pack(), vertices);
|
|
cloudsVb = gfx.CreateVb(vertices, VertexFormat.P3fT2fC4b, cloudVertices);
|
|
}
|
|
|
|
void RebuildSky(int extent, int axisSize) {
|
|
extent = Utils.AdjViewDist(extent);
|
|
int x1 = -extent, x2 = map.Width + extent;
|
|
int z1 = -extent, z2 = map.Length + extent;
|
|
skyVertices = Utils.CountVertices(x2 - x1, z2 - z1, axisSize);
|
|
|
|
VertexP3fC4b[] vertices = new VertexP3fC4b[skyVertices];
|
|
int height = Math.Max(map.Height + 2 + 6, map.Env.CloudHeight + 6);
|
|
|
|
DrawSkyY(x1, z1, x2, z2, height, axisSize, map.Env.SkyCol.Pack(), vertices);
|
|
skyVb = gfx.CreateVb(vertices, VertexFormat.P3fC4b, skyVertices);
|
|
}
|
|
|
|
void DrawSkyY(int x1, int z1, int x2, int z2, int y, int axisSize, int col, VertexP3fC4b[] vertices) {
|
|
int endX = x2, endZ = z2, startZ = z1;
|
|
int i = 0;
|
|
|
|
for (; x1 < endX; x1 += axisSize) {
|
|
x2 = x1 + axisSize;
|
|
if (x2 > endX) x2 = endX;
|
|
z1 = startZ;
|
|
for (; z1 < endZ; z1 += axisSize) {
|
|
z2 = z1 + axisSize;
|
|
if (z2 > endZ) z2 = endZ;
|
|
|
|
vertices[i++] = new VertexP3fC4b(x1, y, z1, col);
|
|
vertices[i++] = new VertexP3fC4b(x1, y, z2, col);
|
|
vertices[i++] = new VertexP3fC4b(x2, y, z2, col);
|
|
vertices[i++] = new VertexP3fC4b(x2, y, z1, col);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawCloudsY(int x1, int z1, int x2, int z2, int y, int axisSize, int col, VertexP3fT2fC4b[] vertices) {
|
|
int endX = x2, endZ = z2, startZ = z1;
|
|
// adjust range so that largest negative uv coordinate is shifted to 0 or above.
|
|
float offset = Utils.CeilDiv(-x1, 2048);
|
|
int i = 0;
|
|
|
|
for (; x1 < endX; x1 += axisSize) {
|
|
x2 = x1 + axisSize;
|
|
if (x2 > endX) x2 = endX;
|
|
z1 = startZ;
|
|
for (; z1 < endZ; z1 += axisSize) {
|
|
z2 = z1 + axisSize;
|
|
if (z2 > endZ) z2 = endZ;
|
|
|
|
vertices[i++] = new VertexP3fT2fC4b(x1, y + 0.1f, z1, x1 / 2048f + offset, z1 / 2048f + offset, col);
|
|
vertices[i++] = new VertexP3fT2fC4b(x1, y + 0.1f, z2, x1 / 2048f + offset, z2 / 2048f + offset, col);
|
|
vertices[i++] = new VertexP3fT2fC4b(x2, y + 0.1f, z2, x2 / 2048f + offset, z2 / 2048f + offset, col);
|
|
vertices[i++] = new VertexP3fT2fC4b(x2, y + 0.1f, z1, x2 / 2048f + offset, z1 / 2048f + offset, col);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |