using System.Linq;
using OpenBveApi.Colors;
using OpenBveApi.Math;
using OpenBveApi.Textures;
using OpenBveApi.World;
using OpenTK.Graphics.OpenGL;
using Vector2 = OpenBveApi.Math.Vector2;
namespace LibRender2.Primitives
{
/// A Cube of nomimal 1.0 size
public class Cube
{
private readonly BaseRenderer renderer;
private readonly VertexArrayObject defaultVAO;
/// Creates a new cube
public Cube(BaseRenderer renderer) : this(renderer, Color128.White)
{
}
/// Creates a new colored cube
public Cube(BaseRenderer renderer, Color128 color)
{
this.renderer = renderer;
LibRenderVertex[] vertexData =
{
// back
new LibRenderVertex
{
Position = new Vector3f(1.0f, 1.0f, 1.0f),
UV = Vector2f.Null,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(-1.0f, 1.0f, 1.0f),
UV = Vector2f.Right,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(-1.0f, -1.0f, 1.0f),
UV = Vector2f.One,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(1.0f, -1.0f, 1.0f),
UV = Vector2f.Down,
Color = color
},
// right
new LibRenderVertex
{
Position = new Vector3f(1.0f, 1.0f, 1.0f),
UV = Vector2f.Right,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(1.0f, -1.0f, 1.0f),
UV = Vector2f.One,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(1.0f, -1.0f, -1.0f),
UV = Vector2f.Down,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(1.0f, 1.0f, -1.0f),
UV = Vector2f.Null,
Color = color
},
// top
new LibRenderVertex
{
Position = new Vector3f(1.0f, 1.0f, 1.0f),
UV = Vector2f.Right,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(1.0f, 1.0f, -1.0f),
UV = Vector2f.One,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(-1.0f, 1.0f, -1.0f),
UV = Vector2f.Down,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(-1.0f, 1.0f, 1.0f),
UV = Vector2f.Null,
Color = color
},
// front
new LibRenderVertex
{
Position = new Vector3f(-1.0f, -1.0f, -1.0f),
UV = Vector2f.Down,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(-1.0f, 1.0f, -1.0f),
UV = Vector2f.Null,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(1.0f, 1.0f, -1.0f),
UV = Vector2f.Right,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(1.0f, -1.0f, -1.0f),
UV = Vector2f.One,
Color = color
},
// left
new LibRenderVertex
{
Position = new Vector3f(-1.0f, -1.0f, -1.0f),
UV = Vector2f.One,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(-1.0f, -1.0f, 1.0f),
UV = Vector2f.Down,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(-1.0f, 1.0f, 1.0f),
UV = Vector2f.Null,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(-1.0f, 1.0f, -1.0f),
UV = Vector2f.Right,
Color = color
},
// bottom
new LibRenderVertex
{
Position = new Vector3f(-1.0f, -1.0f, -1.0f),
UV = Vector2f.Null,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(1.0f, -1.0f, -1.0f),
UV = Vector2f.Right,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(1.0f, -1.0f, 1.0f),
UV = Vector2f.One,
Color = color
},
new LibRenderVertex
{
Position = new Vector3f(-1.0f, -1.0f, 1.0f),
UV = Vector2f.Down,
Color = color
}
};
if (!renderer.ForceLegacyOpenGL)
{
defaultVAO = new VertexArrayObject();
defaultVAO.Bind();
defaultVAO.SetVBO(new VertexBufferObject(vertexData, BufferUsageHint.StaticDraw));
defaultVAO.SetIBO(new IndexBufferObjectUS(Enumerable.Range(0, vertexData.Length).Select(x => (ushort)x).ToArray(), BufferUsageHint.StaticDraw));
defaultVAO.SetAttributes(renderer.DefaultShader.VertexLayout);
defaultVAO.UnBind();
}
}
/// Draws a 3D cube
/// The position in world-space
/// The direction vector
/// The up vector
/// The side vector
/// The size of the cube in M
/// The camera position
/// The texture to apply
public void Draw(Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, double Size, Vector3 Camera, Texture TextureIndex)
{
if (renderer.AvailableNewRenderer)
{
Draw(Position, Direction, Up, Side, new Vector3(Size, Size, Size), Camera, TextureIndex);
}
else
{
DrawImmediate(Position, Direction, Up, Side, new Vector3(Size, Size, Size), Camera, TextureIndex);
}
}
/// Draws a 3D cube
/// The position in world-space
/// The direction vector
/// The up vector
/// The side vector
/// A 3D vector describing the size of the cube
/// The camera position
/// The texture to apply
public void Draw(Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, Vector3 Size, Vector3 Camera, Texture TextureIndex)
{
if (renderer.AvailableNewRenderer)
{
DrawRetained(defaultVAO, Position, Direction, Up, Side, Size, Camera, TextureIndex);
}
else
{
DrawImmediate(Position, Direction, Up, Side, Size, Camera, TextureIndex);
}
}
/// Draws a 3D cube
///
/// The position in world-space
/// The direction vector
/// The up vector
/// The side vector
/// A 3D vector describing the size of the cube
/// The camera position
/// The texture to apply
private void DrawRetained(VertexArrayObject VAO, Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, Vector3 Size, Vector3 Camera, Texture TextureIndex)
{
renderer.DefaultShader.Activate();
renderer.ResetShader(renderer.DefaultShader);
// matrix
renderer.DefaultShader.SetCurrentProjectionMatrix(renderer.CurrentProjectionMatrix);
renderer.DefaultShader.SetCurrentModelViewMatrix(Matrix4D.Scale(Size) * (Matrix4D)new Transformation(Direction, Up, Side) * Matrix4D.CreateTranslation(Position.X - Camera.X, Position.Y - Camera.Y, -Position.Z + Camera.Z) * renderer.CurrentViewMatrix);
// texture
if (TextureIndex != null && renderer.currentHost.LoadTexture(ref TextureIndex, OpenGlTextureWrapMode.ClampClamp))
{
GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, TextureIndex.OpenGlTextures[(int)OpenGlTextureWrapMode.ClampClamp].Name);
}
else
{
GL.Disable(EnableCap.Texture2D);
}
// render polygon
VAO.Bind();
VAO.Draw(PrimitiveType.Quads);
GL.Disable(EnableCap.Texture2D);
}
/// Draws a 3D cube in immediate mode
/// The position in world-space
/// The direction vector
/// The up vector
/// The side vector
/// A 3D vector describing the size of the cube
/// The camera position
/// The texture to apply
private void DrawImmediate(Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, Vector3 Size, Vector3 Camera, Texture TextureIndex)
{
renderer.LastBoundTexture = null;
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
OpenTK.Matrix4d perspective = OpenTK.Matrix4d.Perspective(renderer.Camera.VerticalViewingAngle, -renderer.Screen.AspectRatio, 0.2, 1000.0);
GL.MultMatrix(ref perspective);
double dx = renderer.Camera.AbsoluteDirection.X;
double dy = renderer.Camera.AbsoluteDirection.Y;
double dz = renderer.Camera.AbsoluteDirection.Z;
double ux = renderer.Camera.AbsoluteUp.X;
double uy = renderer.Camera.AbsoluteUp.Y;
double uz = renderer.Camera.AbsoluteUp.Z;
OpenTK.Matrix4d lookat = OpenTK.Matrix4d.LookAt(0.0, 0.0, 0.0, dx, dy, dz, ux, uy, uz);
GL.MatrixMode(MatrixMode.Modelview);
GL.PushMatrix();
GL.LoadMatrix(ref lookat);
Vector3[] v = new Vector3[8];
v[0] = new Vector3(Size.X, Size.Y, -Size.Z);
v[1] = new Vector3(Size.X, -Size.Y, -Size.Z);
v[2] = new Vector3(-Size.X, -Size.Y, -Size.Z);
v[3] = new Vector3(-Size.X, Size.Y, -Size.Z);
v[4] = new Vector3(Size.X, Size.Y, Size.Z);
v[5] = new Vector3(Size.X, -Size.Y, Size.Z);
v[6] = new Vector3(-Size.X, -Size.Y, Size.Z);
v[7] = new Vector3(-Size.X, Size.Y, Size.Z);
for (int i = 0; i < 8; i++)
{
v[i].Rotate(Direction, Up, Side);
v[i] += Position - Camera;
}
int[][] Faces = new int[6][];
Faces[0] = new[] { 0, 1, 2, 3 };
Faces[1] = new[] { 0, 4, 5, 1 };
Faces[2] = new[] { 0, 3, 7, 4 };
Faces[3] = new[] { 6, 5, 4, 7 };
Faces[4] = new[] { 6, 7, 3, 2 };
Faces[5] = new[] { 6, 2, 1, 5 };
if (TextureIndex == null || !renderer.currentHost.LoadTexture(ref TextureIndex, OpenGlTextureWrapMode.ClampClamp))
{
GL.Disable(EnableCap.Texture2D);
for (int i = 0; i < 6; i++)
{
GL.Begin(PrimitiveType.Quads);
for (int j = 0; j < 4; j++)
{
GL.Vertex3(v[Faces[i][j]].X, v[Faces[i][j]].Y, v[Faces[i][j]].Z);
}
GL.End();
}
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
return;
}
GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, TextureIndex.OpenGlTextures[(int)OpenGlTextureWrapMode.ClampClamp].Name);
Vector2[][] t = new Vector2[6][];
t[0] = new[] { new Vector2(1.0, 0.0), new Vector2(1.0, 1.0), new Vector2(0.0, 1.0), new Vector2(0.0, 0.0) };
t[1] = new[] { new Vector2(0.0, 0.0), new Vector2(1.0, 0.0), new Vector2(1.0, 1.0), new Vector2(0.0, 1.0) };
t[2] = new[] { new Vector2(1.0, 1.0), new Vector2(0.0, 1.0), new Vector2(0.0, 0.0), new Vector2(1.0, 0.0) };
t[3] = new[] { new Vector2(1.0, 1.0), new Vector2(0.0, 1.0), new Vector2(0.0, 0.0), new Vector2(1.0, 0.0) };
t[4] = new[] { new Vector2(0.0, 1.0), new Vector2(0.0, 0.0), new Vector2(1.0, 0.0), new Vector2(1.0, 1.0) };
t[5] = new[] { new Vector2(0.0, 1.0), new Vector2(0.0, 0.0), new Vector2(1.0, 0.0), new Vector2(1.0, 1.0) };
for (int i = 0; i < 6; i++)
{
GL.Begin(PrimitiveType.Quads);
GL.Color3(1.0, 1.0, 1.0);
for (int j = 0; j < 4; j++)
{
GL.TexCoord2(t[i][j].X, t[i][j].Y);
GL.Vertex3(v[Faces[i][j]].X, v[Faces[i][j]].Y, v[Faces[i][j]].Z);
}
GL.End();
}
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
}
}
}