Пример #1
0
            public void ReadBodySpans(VxlFile f)
            {
                // need to have position at start of bodies
                f.Seek(StartingSpanOffset, SeekOrigin.Current);
                Spans = new SectionSpan[SizeX, SizeY];

                for (byte y = 0; y < SizeY; ++y)
                {
                    for (byte x = 0; x < SizeX; ++x)
                    {
                        var s = new SectionSpan();
                        s.StartIndex = f.ReadInt32();
                        s.Height     = SizeZ;
                        s.X          = x;
                        s.Y          = y;
                        Spans[x, y]  = s;
                    }
                }
                for (byte y = 0; y < SizeY; ++y)
                {
                    for (byte x = 0; x < SizeX; ++x)
                    {
                        Spans[x, y].EndIndex = f.ReadInt32();
                    }
                }

                for (byte y = 0; y < SizeY; ++y)
                {
                    for (byte x = 0; x < SizeX; ++x)
                    {
                        Spans[x, y].Read(f);
                    }
                }
            }
Пример #2
0
 public bool ReadHeader(VxlFile f)
 {
     Name       = f.ReadCString(16);
     LimbNumber = f.ReadUInt32();
     unknown1   = f.ReadUInt32();
     unknown2   = f.ReadUInt32();
     return(true);
 }
Пример #3
0
 public void Read(VxlFile f)
 {
     for (var i = 0; i < 3; ++i)
     {
         V[i].X = f.ReadFloat();
         V[i].Y = f.ReadFloat();
         V[i].Z = f.ReadFloat();
         V[i].W = f.ReadFloat();
     }
 }
Пример #4
0
			// public Palette Palette; // not actually used

			public bool Read(VxlFile f) {
				FileName = f.ReadCString(16);
				PaletteCount = f.ReadUInt32();
				HeaderCount = f.ReadUInt32();
				TailerCount = f.ReadUInt32();
				Debug.Assert(HeaderCount == TailerCount);
				BodySize = f.ReadUInt32();
				PaletteRemapStart = f.ReadByte();
				PaletteRemapEnd = f.ReadByte();
				var pal = f.Read(768);
				// Palette = new Palette(pal, "voxel palette");
				return true;
			}
Пример #5
0
            // public Palette Palette; // not actually used

            public bool Read(VxlFile f)
            {
                FileName     = f.ReadCString(16);
                PaletteCount = f.ReadUInt32();
                HeaderCount  = f.ReadUInt32();
                TailerCount  = f.ReadUInt32();
                Debug.Assert(HeaderCount == TailerCount);
                BodySize          = f.ReadUInt32();
                PaletteRemapStart = f.ReadByte();
                PaletteRemapEnd   = f.ReadByte();
                var pal = f.Read(768);

                // Palette = new Palette(pal, "voxel palette");
                return(true);
            }
Пример #6
0
            public bool ReadTailer(VxlFile f)
            {
                StartingSpanOffset = f.ReadUInt32();
                EndingSpanOffset   = f.ReadUInt32();
                DataSpanOffset     = f.ReadUInt32();
                HVAMultiplier      = f.ReadFloat();
                TM.Read(f);
                MinBounds.X = f.ReadFloat();
                MinBounds.Y = f.ReadFloat();
                MinBounds.Z = f.ReadFloat();
                MaxBounds.X = f.ReadFloat();
                MaxBounds.Y = f.ReadFloat();
                MaxBounds.Z = f.ReadFloat();

                SizeX       = f.ReadByte();
                SizeY       = f.ReadByte();
                SizeZ       = f.ReadByte();
                NormalsMode = f.ReadByte();

                return(true);
            }
Пример #7
0
		public static Rectangle GetBounds(GameObject obj, VxlFile vxl, HvaFile hva, DrawProperties props) {
			vxl.Initialize();
			hva.Initialize();

			float direction = (obj is OwnableObject) ? (obj as OwnableObject).Direction : 0;
			float objectRotation = 45f - direction / 256f * 360f; // convert game rotation to world degrees

			var world = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(60));
			world = Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(objectRotation)) * world; // object facing
			world = Matrix4.Scale(0.25f, 0.25f, 0.25f) * world;

			// art.ini TurretOffset value positions some voxel parts over our x-axis
			world = Matrix4.CreateTranslation(0.18f * props.TurretVoxelOffset, 0, 0) * world;
			var camera = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(30), 1f, 1, 100);
			world = world * camera;

			Rectangle ret = Rectangle.Empty;
			foreach (var section in vxl.Sections) {
				var frameRot = hva.LoadGLMatrix(section.Index);
				frameRot.M41 *= section.HVAMultiplier * section.ScaleX;
				frameRot.M42 *= section.HVAMultiplier * section.ScaleY;
				frameRot.M43 *= section.HVAMultiplier * section.ScaleZ;

				var minbounds = new Vector3(section.MinBounds);
				if (props.HasShadow)
					minbounds.Z = -100;

				var frameTransl = Matrix4.CreateTranslation(minbounds);
				var frame = frameTransl * frameRot * world;

				// floor rect of the bounding box
				Vector3 floorTopLeft = new Vector3(0, 0, 0);
				Vector3 floorTopRight = new Vector3(section.SpanX, 0, 0);
				Vector3 floorBottomRight = new Vector3(section.SpanX, section.SpanY, 0);
				Vector3 floorBottomLeft = new Vector3(0, section.SpanY, 0);

				// ceil rect of the bounding box
				Vector3 ceilTopLeft = new Vector3(0, 0, section.SpanZ);
				Vector3 ceilTopRight = new Vector3(section.SpanX, 0, section.SpanZ);
				Vector3 ceilBottomRight = new Vector3(section.SpanX, section.SpanY, section.SpanZ);
				Vector3 ceilBottomLeft = new Vector3(0, section.SpanY, section.SpanZ);

				// apply transformations
				floorTopLeft = Vector3.Transform(floorTopLeft, frame);
				floorTopRight = Vector3.Transform(floorTopRight, frame);
				floorBottomRight = Vector3.Transform(floorBottomRight, frame);
				floorBottomLeft = Vector3.Transform(floorBottomLeft, frame);

				ceilTopLeft = Vector3.Transform(ceilTopLeft, frame);
				ceilTopRight = Vector3.Transform(ceilTopRight, frame);
				ceilBottomRight = Vector3.Transform(ceilBottomRight, frame);
				ceilBottomLeft = Vector3.Transform(ceilBottomLeft, frame);

				int FminX = (int)Math.Floor(Math.Min(Math.Min(Math.Min(floorTopLeft.X, floorTopRight.X), floorBottomRight.X), floorBottomLeft.X));
				int FmaxX = (int)Math.Ceiling(Math.Max(Math.Max(Math.Max(floorTopLeft.X, floorTopRight.X), floorBottomRight.X), floorBottomLeft.X));
				int FminY = (int)Math.Floor(Math.Min(Math.Min(Math.Min(floorTopLeft.Y, floorTopRight.Y), floorBottomRight.Y), floorBottomLeft.Y));
				int FmaxY = (int)Math.Ceiling(Math.Max(Math.Max(Math.Max(floorTopLeft.Y, floorTopRight.Y), floorBottomRight.Y), floorBottomLeft.Y));

				int TminX = (int)Math.Floor(Math.Min(Math.Min(Math.Min(ceilTopLeft.X, ceilTopRight.X), ceilBottomRight.X), ceilBottomLeft.X));
				int TmaxX = (int)Math.Ceiling(Math.Max(Math.Max(Math.Max(ceilTopLeft.X, ceilTopRight.X), ceilBottomRight.X), ceilBottomLeft.X));
				int TminY = (int)Math.Floor(Math.Min(Math.Min(Math.Min(ceilTopLeft.Y, ceilTopRight.Y), ceilBottomRight.Y), ceilBottomLeft.Y));
				int TmaxY = (int)Math.Ceiling(Math.Max(Math.Max(Math.Max(ceilTopLeft.Y, ceilTopRight.Y), ceilBottomRight.Y), ceilBottomLeft.Y));

				int minX = Math.Min(FminX, TminX);
				int maxX = Math.Max(FmaxX, TmaxX);
				int minY = Math.Min(FminY, TminY);
				int maxY = Math.Max(FmaxY, TmaxY);

				ret = Rectangle.Union(ret, Rectangle.FromLTRB(minX, minY, maxX, maxY));
			}

			// return new Rectangle(-ret.Width / 2, -ret.Height / 2, ret.Width, ret.Height);
			return ret;
		}
Пример #8
0
		public DrawingSurface Render(VxlFile vxl, HvaFile hva, GameObject obj, DrawProperties props) {
			if (!_isInit) Initialize();
			if (!_canRender) {
				Logger.Warn("Not rendering {0} because no OpenGL context could be obtained", vxl.FileName);
				return null;
			}

			Logger.Debug("Rendering voxel {0}", vxl.FileName);
			vxl.Initialize();
			hva.Initialize();

			GL.Viewport(0, 0, _surface.BitmapData.Width, _surface.BitmapData.Height);
			GL.Clear(ClearBufferMask.DepthBufferBit | ClearBufferMask.ColorBufferBit);

			// RA2 uses dimetric projection with camera elevated 30° off the ground
			GL.MatrixMode(MatrixMode.Projection);
			var persp = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(30), _surface.BitmapData.Width / (float)_surface.BitmapData.Height, 1, _surface.BitmapData.Height);
			GL.LoadMatrix(ref persp);

			GL.MatrixMode(MatrixMode.Modelview);
			GL.LoadIdentity();

			var lookat = Matrix4.LookAt(0, 0, -10, 0, 0, 0, 0, 1, 0);
			GL.MultMatrix(ref lookat);
			
			var trans = Matrix4.CreateTranslation(0, 0, 10);
			GL.MultMatrix(ref trans);

			// align and zoom
			var world = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(60));
			world = Matrix4.CreateRotationY(MathHelper.DegreesToRadians(180)) * world;
			world = Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(-45)) * world; 
			world = Matrix4.Scale(0.028f, 0.028f, 0.028f) * world;
			GL.MultMatrix(ref world);

			// DrawAxes();
			
			// determine tilt vectors
			Matrix4 tilt;
			int tiltPitch, tiltYaw;
			if (true) {
				int ramp = (obj.Tile.Drawable as TileDrawable).GetTileImage(obj.Tile).RampType;
				if (ramp == 0 || ramp >= 17) {
					tiltPitch = tiltYaw = 0;
				}
				else if (ramp <= 4) {
					// screen-diagonal facings (perpendicular to axes)
					tiltPitch = 25;
					tiltYaw = -90 * ramp;
				}
				else {
					// world-diagonal facings (perpendicular to screen)
					tiltPitch = 25;
					tiltYaw = 225 - 90 * ((ramp - 1) % 4);
				}
				tilt = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(tiltPitch));
				tilt *= Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(tiltYaw));

				/*// show tilt direction
				GL.Color3(Color.Black);
				GL.Begin(BeginMode.Lines);
				GL.Vertex3(Vector3.Zero);
				var tiltVec = Vector3.UnitZ;
				tiltVec = Vector3.Transform(tiltVec, tilt);
				tiltVec = Vector3.Multiply(tiltVec, 1000f);
				GL.Vertex3(tiltVec);
				GL.End();*/
			}

			/*// draw slope normals
			GL.LineWidth(2);
			var colors = new[] { Color.Red, Color.Green, Color.Blue, Color.Yellow, Color.Orange, Color.Black, Color.Purple, Color.SlateBlue, Color.DimGray, Color.White, Color.Teal, Color.Tan };
			for (int i = 0; i < 8; i++) {
				GL.Color3(colors[i]);

				const float roll = 25f;
				float syaw = 45f * i;
				var slopeNormal = Vector3.UnitZ;
				slopeNormal = Vector3.Transform(slopeNormal, Matrix4.CreateRotationX(MathHelper.DegreesToRadians(roll)));
				slopeNormal = Vector3.Transform(slopeNormal, Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(syaw)));
				GL.Begin(BeginMode.Lines);
				GL.Vertex3(0, 0, 0);
				GL.Vertex3(Vector3.Multiply(slopeNormal, 1000f));
				GL.End();
			}*/


			// object rotation around Z
			float direction = (obj is OwnableObject) ? (obj as OwnableObject).Direction : 0;
			float objectRotation = 90 - direction / 256f * 360f - tiltYaw; // convert game rotation to world degrees
			Matrix4 @object = Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(objectRotation)) * tilt; // object facing
			// art.ini TurretOffset value positions some voxel parts over our x-axis
			@object = Matrix4.CreateTranslation(0.18f * props.TurretVoxelOffset, 0, 0) * @object;
			GL.MultMatrix(ref @object);

			// DrawAxes();
			
			float pitch = MathHelper.DegreesToRadians(210);
			float yaw = MathHelper.DegreesToRadians(120);
			/*// helps to find good pitch/yaw
			// direction of light vector given by pitch & yaw
			for (int i = 0; i < 360; i += 30) {
				for (int j = 0; j < 360; j += 30) {
					GL.Color3(colors[i / 30]);
					var shadowTransform2 =
						Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(i))
						* Matrix4.CreateRotationY(MathHelper.DegreesToRadians(j));
					GL.LineWidth(2);
					GL.Begin(BeginMode.Lines);
					GL.Vertex3(0, 0, 0);
					GL.Vertex3(Vector3.Multiply(ExtractRotationVector(ToOpenGL(Matrix4.Invert(world * shadowTransform2))), 100f));
					GL.End();
				}
			}*/

			var shadowTransform = Matrix4.CreateRotationZ(pitch) * Matrix4.CreateRotationY(yaw);
			// clear shadowbuf
			var shadBuf = _surface.GetShadows();
			Array.Clear(shadBuf, 0, shadBuf.Length);
			
			foreach (var section in vxl.Sections) {
				GL.PushMatrix();

				var frameRot = hva.LoadGLMatrix(section.Index);
				frameRot.M41 *= section.HVAMultiplier * section.ScaleX;
				frameRot.M42 *= section.HVAMultiplier * section.ScaleY;
				frameRot.M43 *= section.HVAMultiplier * section.ScaleZ;

				var frameTransl = Matrix4.CreateTranslation(section.MinBounds);
				var frame = frameTransl * frameRot;
				GL.MultMatrix(ref frame);

				var shadowScale = Matrix4.Scale(0.5f);
				//var shadowTilt = null;
				var shadowToScreen = frameTransl * shadowScale * frameRot * (@object * world) * trans * lookat;

				// undo world transformations on light direction
				var lightDirection = ExtractRotationVector(ToOpenGL(Matrix4.Invert((@object * world) * frame * shadowTransform)));

				// draw line in direction light comes from
				/*GL.Color3(Color.Red);
				GL.LineWidth(4f);
				GL.Begin(BeginMode.Lines);
				GL.Vertex3(0, 0, 0);
				GL.Vertex3(Vector3.Multiply(lightDirection, 100f));
				GL.End();*/

				GL.Begin(BeginMode.Quads);
				for (uint x = 0; x != section.SizeX; x++) {
					for (uint y = 0; y != section.SizeY; y++) {
						foreach (VxlFile.Voxel vx in section.Spans[x, y].Voxels) {
							Color color = obj.Palette.Colors[vx.ColorIndex];
							Vector3 normal = section.GetNormal(vx.NormalIndex);
							// shader function taken from https://github.com/OpenRA/OpenRA/blob/bleed/cg/vxl.fx
							// thanks to pchote for a LOT of help getting it right
							Vector3 colorMult = Vector3.Add(Ambient, Diffuse * Math.Max(Vector3.Dot(normal, lightDirection), 0f));
							GL.Color3(
								(byte)Math.Min(255, color.R * colorMult.X),
								(byte)Math.Min(255, color.G * colorMult.Y),
								(byte)Math.Min(255, color.B * colorMult.Z));

							Vector3 vxlPos = Vector3.Multiply(new Vector3(x, y, vx.Z), section.Scale);
							RenderVoxel(vxlPos);

							var shadpos = new Vector3(x, y, 0);
							var screenPos = Vector3.Transform(shadpos, shadowToScreen);
							screenPos = Vector3.Transform(screenPos, persp);
							screenPos.X /= screenPos.Z;
							screenPos.Y /= screenPos.Z;
							screenPos.X = (screenPos.X + 1) * _surface.Width / 2;
							screenPos.Y = (screenPos.Y + 1) * _surface.Height / 2;
							
							if (0 <= screenPos.X && screenPos.X < _surface.Width && 0 <= screenPos.Y && screenPos.Y < _surface.Height)
								shadBuf[(int)screenPos.X + (_surface.Height - 1 - (int)screenPos.Y) * _surface.Width] = true;

							/* draw line in normal direction
							if (r.Next(100) == 4) {
								float m = Math.Max(Vector3.Dot(normal, lightDirection), 0f);
								GL.Color3(m, m, m);
								GL.LineWidth(1);
								GL.Begin(BeginMode.Lines);
								GL.Vertex3(new Vector3(x, y, vx.Z));
								GL.Vertex3(new Vector3(x, y, vx.Z) + Vector3.Multiply(normal, 100f));
								GL.End();
							}*/

						}
					}
				}
				GL.End();
				GL.PopMatrix();
			}

			// read pixels back to surface
			GL.ReadPixels(0, 0, _surface.BitmapData.Width, _surface.BitmapData.Height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, _surface.BitmapData.Scan0);
			return _surface;
		}
Пример #9
0
			public bool ReadTailer(VxlFile f) {
				StartingSpanOffset = f.ReadUInt32();
				EndingSpanOffset = f.ReadUInt32();
				DataSpanOffset = f.ReadUInt32();
				HVAMultiplier = f.ReadFloat();
				TM.Read(f);
				MinBounds.X = f.ReadFloat();
				MinBounds.Y = f.ReadFloat();
				MinBounds.Z = f.ReadFloat();
				MaxBounds.X = f.ReadFloat();
				MaxBounds.Y = f.ReadFloat();
				MaxBounds.Z = f.ReadFloat();

				SizeX = f.ReadByte();
				SizeY = f.ReadByte();
				SizeZ = f.ReadByte();
				NormalsMode = f.ReadByte();

				return true;
			}
Пример #10
0
			public void ReadBodySpans(VxlFile f) {
				// need to have position at start of bodies
				f.Seek(StartingSpanOffset, SeekOrigin.Current);
				Spans = new SectionSpan[SizeX, SizeY];

				for (byte y = 0; y < SizeY; ++y) {
					for (byte x = 0; x < SizeX; ++x) {
						var s = new SectionSpan();
						s.StartIndex = f.ReadInt32();
						s.Height = SizeZ;
						s.X = x;
						s.Y = y;
						Spans[x, y] = s;
					}
				}
				for (byte y = 0; y < SizeY; ++y)
					for (byte x = 0; x < SizeX; ++x)
						Spans[x, y].EndIndex = f.ReadInt32();

				for (byte y = 0; y < SizeY; ++y) {
					for (byte x = 0; x < SizeX; ++x) {
						Spans[x, y].Read(f);
					}
				}
			}
Пример #11
0
			public bool ReadHeader(VxlFile f) {
				Name = f.ReadCString(16);
				LimbNumber = f.ReadUInt32();
				unknown1 = f.ReadUInt32();
				unknown2 = f.ReadUInt32();
				return true;
			}
Пример #12
0
			public void Read(VxlFile f) {
				for (var i = 0; i < 3; ++i) {
					V[i].X = f.ReadFloat();
					V[i].Y = f.ReadFloat();
					V[i].Z = f.ReadFloat();
					V[i].W = f.ReadFloat();
				}
			}
Пример #13
0
		public VoxelDrawable(VxlFile vxl, HvaFile hva) {
			Vxl = vxl;
			Hva = hva;
		}