1 using System.Linq;
2 using OpenBveApi.Colors;
3 using OpenBveApi.Math;
4 using OpenBveApi.Textures;
5 using OpenBveApi.World;
6 using OpenTK.Graphics.OpenGL;
7 using Vector2 = OpenBveApi.Math.Vector2;
8 
9 namespace LibRender2.Primitives
10 {
11 	/// <summary>A Cube of nomimal 1.0 size</summary>
12 	public class Cube
13 	{
14 		private readonly BaseRenderer renderer;
15 		private readonly VertexArrayObject defaultVAO;
16 
17 		/// <summary>Creates a new cube</summary>
Cube(BaseRenderer renderer)18 		public Cube(BaseRenderer renderer) : this(renderer, Color128.White)
19 		{
20 		}
21 
22 		/// <summary>Creates a new colored cube</summary>
Cube(BaseRenderer renderer, Color128 color)23 		public Cube(BaseRenderer renderer, Color128 color)
24 		{
25 			this.renderer = renderer;
26 
27 			LibRenderVertex[] vertexData =
28 			{
29 				// back
30 				new LibRenderVertex
31 				{
32 					Position = new Vector3f(1.0f, 1.0f, 1.0f),
33 					UV = Vector2f.Null,
34 					Color = color
35 				},
36 				new LibRenderVertex
37 				{
38 					Position = new Vector3f(-1.0f, 1.0f, 1.0f),
39 					UV = Vector2f.Right,
40 					Color = color
41 				},
42 				new LibRenderVertex
43 				{
44 					Position = new Vector3f(-1.0f, -1.0f, 1.0f),
45 					UV = Vector2f.One,
46 					Color = color
47 				},
48 				new LibRenderVertex
49 				{
50 					Position = new Vector3f(1.0f, -1.0f, 1.0f),
51 					UV = Vector2f.Down,
52 					Color = color
53 				},
54 
55 				// right
56 				new LibRenderVertex
57 				{
58 					Position = new Vector3f(1.0f, 1.0f, 1.0f),
59 					UV = Vector2f.Right,
60 					Color = color
61 				},
62 				new LibRenderVertex
63 				{
64 					Position = new Vector3f(1.0f, -1.0f, 1.0f),
65 					UV = Vector2f.One,
66 					Color = color
67 				},
68 				new LibRenderVertex
69 				{
70 					Position = new Vector3f(1.0f, -1.0f, -1.0f),
71 					UV = Vector2f.Down,
72 					Color = color
73 				},
74 				new LibRenderVertex
75 				{
76 					Position = new Vector3f(1.0f, 1.0f, -1.0f),
77 					UV = Vector2f.Null,
78 					Color = color
79 				},
80 
81 				// top
82 				new LibRenderVertex
83 				{
84 					Position = new Vector3f(1.0f, 1.0f, 1.0f),
85 					UV = Vector2f.Right,
86 					Color = color
87 				},
88 				new LibRenderVertex
89 				{
90 					Position = new Vector3f(1.0f, 1.0f, -1.0f),
91 					UV = Vector2f.One,
92 					Color = color
93 				},
94 				new LibRenderVertex
95 				{
96 					Position = new Vector3f(-1.0f, 1.0f, -1.0f),
97 					UV = Vector2f.Down,
98 					Color = color
99 				},
100 				new LibRenderVertex
101 				{
102 					Position = new Vector3f(-1.0f, 1.0f, 1.0f),
103 					UV = Vector2f.Null,
104 					Color = color
105 				},
106 
107 				// front
108 				new LibRenderVertex
109 				{
110 					Position = new Vector3f(-1.0f, -1.0f, -1.0f),
111 					UV = Vector2f.Down,
112 					Color = color
113 				},
114 				new LibRenderVertex
115 				{
116 					Position = new Vector3f(-1.0f, 1.0f, -1.0f),
117 					UV = Vector2f.Null,
118 					Color = color
119 				},
120 				new LibRenderVertex
121 				{
122 					Position = new Vector3f(1.0f, 1.0f, -1.0f),
123 					UV = Vector2f.Right,
124 					Color = color
125 				},
126 				new LibRenderVertex
127 				{
128 					Position = new Vector3f(1.0f, -1.0f, -1.0f),
129 					UV = Vector2f.One,
130 					Color = color
131 				},
132 
133 				// left
134 				new LibRenderVertex
135 				{
136 					Position = new Vector3f(-1.0f, -1.0f, -1.0f),
137 					UV = Vector2f.One,
138 					Color = color
139 				},
140 				new LibRenderVertex
141 				{
142 					Position = new Vector3f(-1.0f, -1.0f, 1.0f),
143 					UV = Vector2f.Down,
144 					Color = color
145 				},
146 				new LibRenderVertex
147 				{
148 					Position = new Vector3f(-1.0f, 1.0f, 1.0f),
149 					UV = Vector2f.Null,
150 					Color = color
151 				},
152 				new LibRenderVertex
153 				{
154 					Position = new Vector3f(-1.0f, 1.0f, -1.0f),
155 					UV = Vector2f.Right,
156 					Color = color
157 				},
158 
159 				// bottom
160 				new LibRenderVertex
161 				{
162 					Position = new Vector3f(-1.0f, -1.0f, -1.0f),
163 					UV = Vector2f.Null,
164 					Color = color
165 				},
166 				new LibRenderVertex
167 				{
168 					Position = new Vector3f(1.0f, -1.0f, -1.0f),
169 					UV = Vector2f.Right,
170 					Color = color
171 				},
172 				new LibRenderVertex
173 				{
174 					Position = new Vector3f(1.0f, -1.0f, 1.0f),
175 					UV = Vector2f.One,
176 					Color = color
177 				},
178 				new LibRenderVertex
179 				{
180 					Position = new Vector3f(-1.0f, -1.0f, 1.0f),
181 					UV = Vector2f.Down,
182 					Color = color
183 				}
184 			};
185 
186 			if (!renderer.ForceLegacyOpenGL)
187 			{
188 				defaultVAO = new VertexArrayObject();
189 				defaultVAO.Bind();
190 				defaultVAO.SetVBO(new VertexBufferObject(vertexData, BufferUsageHint.StaticDraw));
191 				defaultVAO.SetIBO(new IndexBufferObjectUS(Enumerable.Range(0, vertexData.Length).Select(x => (ushort)x).ToArray(), BufferUsageHint.StaticDraw));
192 				defaultVAO.SetAttributes(renderer.DefaultShader.VertexLayout);
193 				defaultVAO.UnBind();
194 			}
195 		}
196 
197 		/// <summary>Draws a 3D cube</summary>
198 		/// <param name="Position">The position in world-space</param>
199 		/// <param name="Direction">The direction vector</param>
200 		/// <param name="Up">The up vector</param>
201 		/// <param name="Side">The side vector</param>
202 		/// <param name="Size">The size of the cube in M</param>
203 		/// <param name="Camera">The camera position</param>
204 		/// <param name="TextureIndex">The texture to apply</param>
Draw(Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, double Size, Vector3 Camera, Texture TextureIndex)205 		public void Draw(Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, double Size, Vector3 Camera, Texture TextureIndex)
206 		{
207 			if (renderer.AvailableNewRenderer)
208 			{
209 				Draw(Position, Direction, Up, Side, new Vector3(Size, Size, Size), Camera, TextureIndex);
210 			}
211 			else
212 			{
213 				DrawImmediate(Position, Direction, Up, Side, new Vector3(Size, Size, Size), Camera, TextureIndex);
214 			}
215 		}
216 
217 		/// <summary>Draws a 3D cube</summary>
218 		/// <param name="Position">The position in world-space</param>
219 		/// <param name="Direction">The direction vector</param>
220 		/// <param name="Up">The up vector</param>
221 		/// <param name="Side">The side vector</param>
222 		/// <param name="Size">A 3D vector describing the size of the cube</param>
223 		/// <param name="Camera">The camera position</param>
224 		/// <param name="TextureIndex">The texture to apply</param>
Draw(Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, Vector3 Size, Vector3 Camera, Texture TextureIndex)225 		public void Draw(Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, Vector3 Size, Vector3 Camera, Texture TextureIndex)
226 		{
227 			if (renderer.AvailableNewRenderer)
228 			{
229 				DrawRetained(defaultVAO, Position, Direction, Up, Side, Size, Camera, TextureIndex);
230 			}
231 			else
232 			{
233 				DrawImmediate(Position, Direction, Up, Side, Size, Camera, TextureIndex);
234 			}
235 		}
236 
237 		/// <summary>Draws a 3D cube</summary>
238 		/// <param name="VAO"></param>
239 		/// <param name="Position">The position in world-space</param>
240 		/// <param name="Direction">The direction vector</param>
241 		/// <param name="Up">The up vector</param>
242 		/// <param name="Side">The side vector</param>
243 		/// <param name="Size">A 3D vector describing the size of the cube</param>
244 		/// <param name="Camera">The camera position</param>
245 		/// <param name="TextureIndex">The texture to apply</param>
DrawRetained(VertexArrayObject VAO, Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, Vector3 Size, Vector3 Camera, Texture TextureIndex)246 		private void DrawRetained(VertexArrayObject VAO, Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, Vector3 Size, Vector3 Camera, Texture TextureIndex)
247 		{
248 			renderer.DefaultShader.Activate();
249 			renderer.ResetShader(renderer.DefaultShader);
250 			// matrix
251 			renderer.DefaultShader.SetCurrentProjectionMatrix(renderer.CurrentProjectionMatrix);
252 			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);
253 
254 			// texture
255 			if (TextureIndex != null && renderer.currentHost.LoadTexture(ref TextureIndex, OpenGlTextureWrapMode.ClampClamp))
256 			{
257 				GL.Enable(EnableCap.Texture2D);
258 				GL.BindTexture(TextureTarget.Texture2D, TextureIndex.OpenGlTextures[(int)OpenGlTextureWrapMode.ClampClamp].Name);
259 			}
260 			else
261 			{
262 				GL.Disable(EnableCap.Texture2D);
263 			}
264 
265 			// render polygon
266 			VAO.Bind();
267 			VAO.Draw(PrimitiveType.Quads);
268 			GL.Disable(EnableCap.Texture2D);
269 		}
270 
271 		/// <summary>Draws a 3D cube in immediate mode</summary>
272 		/// <param name="Position">The position in world-space</param>
273 		/// <param name="Direction">The direction vector</param>
274 		/// <param name="Up">The up vector</param>
275 		/// <param name="Side">The side vector</param>
276 		/// <param name="Size">A 3D vector describing the size of the cube</param>
277 		/// <param name="Camera">The camera position</param>
278 		/// <param name="TextureIndex">The texture to apply</param>
DrawImmediate(Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, Vector3 Size, Vector3 Camera, Texture TextureIndex)279 		private void DrawImmediate(Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, Vector3 Size, Vector3 Camera, Texture TextureIndex)
280 		{
281 			renderer.LastBoundTexture = null;
282 			GL.MatrixMode(MatrixMode.Projection);
283 			GL.PushMatrix();
284 			GL.LoadIdentity();
285 			OpenTK.Matrix4d perspective = OpenTK.Matrix4d.Perspective(renderer.Camera.VerticalViewingAngle, -renderer.Screen.AspectRatio, 0.2, 1000.0);
286 			GL.MultMatrix(ref perspective);
287 			double dx = renderer.Camera.AbsoluteDirection.X;
288 			double dy = renderer.Camera.AbsoluteDirection.Y;
289 			double dz = renderer.Camera.AbsoluteDirection.Z;
290 			double ux = renderer.Camera.AbsoluteUp.X;
291 			double uy = renderer.Camera.AbsoluteUp.Y;
292 			double uz = renderer.Camera.AbsoluteUp.Z;
293 			OpenTK.Matrix4d lookat = OpenTK.Matrix4d.LookAt(0.0, 0.0, 0.0, dx, dy, dz, ux, uy, uz);
294 			GL.MatrixMode(MatrixMode.Modelview);
295 			GL.PushMatrix();
296 			GL.LoadMatrix(ref lookat);
297 			Vector3[] v = new Vector3[8];
298 			v[0] = new Vector3(Size.X, Size.Y, -Size.Z);
299 			v[1] = new Vector3(Size.X, -Size.Y, -Size.Z);
300 			v[2] = new Vector3(-Size.X, -Size.Y, -Size.Z);
301 			v[3] = new Vector3(-Size.X, Size.Y, -Size.Z);
302 			v[4] = new Vector3(Size.X, Size.Y, Size.Z);
303 			v[5] = new Vector3(Size.X, -Size.Y, Size.Z);
304 			v[6] = new Vector3(-Size.X, -Size.Y, Size.Z);
305 			v[7] = new Vector3(-Size.X, Size.Y, Size.Z);
306 			for (int i = 0; i < 8; i++)
307 			{
308 				v[i].Rotate(Direction, Up, Side);
309 				v[i] += Position - Camera;
310 			}
311 			int[][] Faces = new int[6][];
312 			Faces[0] = new[] { 0, 1, 2, 3 };
313 			Faces[1] = new[] { 0, 4, 5, 1 };
314 			Faces[2] = new[] { 0, 3, 7, 4 };
315 			Faces[3] = new[] { 6, 5, 4, 7 };
316 			Faces[4] = new[] { 6, 7, 3, 2 };
317 			Faces[5] = new[] { 6, 2, 1, 5 };
318 			if (TextureIndex == null || !renderer.currentHost.LoadTexture(ref TextureIndex, OpenGlTextureWrapMode.ClampClamp))
319 			{
320 				GL.Disable(EnableCap.Texture2D);
321 				for (int i = 0; i < 6; i++)
322 				{
323 					GL.Begin(PrimitiveType.Quads);
324 					for (int j = 0; j < 4; j++)
325 					{
326 						GL.Vertex3(v[Faces[i][j]].X, v[Faces[i][j]].Y, v[Faces[i][j]].Z);
327 					}
328 					GL.End();
329 				}
330 				GL.PopMatrix();
331 
332 				GL.MatrixMode(MatrixMode.Projection);
333 				GL.PopMatrix();
334 				return;
335 			}
336 			GL.Enable(EnableCap.Texture2D);
337 			GL.BindTexture(TextureTarget.Texture2D, TextureIndex.OpenGlTextures[(int)OpenGlTextureWrapMode.ClampClamp].Name);
338 			Vector2[][] t = new Vector2[6][];
339 			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) };
340 			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) };
341 			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) };
342 			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) };
343 			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) };
344 			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) };
345 			for (int i = 0; i < 6; i++)
346 			{
347 				GL.Begin(PrimitiveType.Quads);
348 				GL.Color3(1.0, 1.0, 1.0);
349 				for (int j = 0; j < 4; j++)
350 				{
351 					GL.TexCoord2(t[i][j].X, t[i][j].Y);
352 					GL.Vertex3(v[Faces[i][j]].X, v[Faces[i][j]].Y, v[Faces[i][j]].Z);
353 				}
354 				GL.End();
355 			}
356 			GL.PopMatrix();
357 
358 			GL.MatrixMode(MatrixMode.Projection);
359 			GL.PopMatrix();
360 		}
361 	}
362 }
363