예제 #1
0
		public static Rectangle GetBounds(GameObject obj, ShpFile shp, DrawProperties props) {
			shp.Initialize();
			int frameIndex = DecideFrameIndex(props.FrameDecider(obj), shp.NumImages);
			var offset = new Point(-shp.Width / 2, -shp.Height / 2);
			Size size = new Size(0, 0);
			var img = shp.GetImage(frameIndex);
			if (img != null) {
				offset.Offset(img.X, img.Y);
				size = new Size(img.Width, img.Height);
			}
			return new Rectangle(offset, size);
		}
예제 #2
0
        unsafe public static void DrawAlpha(GameObject obj, ShpFile shp, DrawProperties props, DrawingSurface ds)
        {
            shp.Initialize();

            // Change originally implemented by Starkku: Ares supports multiframe AlphaImages, based on frame count
            // the direction the unit it facing.
            int frameIndex = props.FrameDecider(obj);

            var img     = shp.GetImage(frameIndex);
            var imgData = img.GetImageData();
            var c_px    = (uint)(img.Width * img.Height);

            if (c_px <= 0 || img.Width < 0 || img.Height < 0 || frameIndex > shp.NumImages)
            {
                return;
            }

            Point offset = props.GetOffset(obj);

            offset.X += obj.Tile.Dx * Drawable.TileWidth / 2;
            offset.Y += (obj.Tile.Dy - obj.Tile.Z) * Drawable.TileHeight / 2;
            Logger.Trace("Drawing AlphaImage SHP file {0} (frame {1}) at ({2},{3})", shp.FileName, frameIndex, offset.X, offset.Y);

            int   stride = ds.BitmapData.Stride;
            var   w_low  = (byte *)ds.BitmapData.Scan0;
            byte *w_high = (byte *)ds.BitmapData.Scan0 + stride * ds.BitmapData.Height;

            int dx        = offset.X + Drawable.TileWidth / 2 - shp.Width / 2 + img.X,
                dy        = offset.Y - shp.Height / 2 + img.Y;
            byte *w       = (byte *)ds.BitmapData.Scan0 + dx * 3 + stride * dy;
            short zOffset = (short)((obj.Tile.Rx + obj.Tile.Ry) * Drawable.TileHeight / 2 - shp.Height / 2 + img.Y);
            int   rIdx    = 0;

            for (int y = 0; y < img.Height; y++)
            {
                for (int x = 0; x < img.Width; x++)
                {
                    if (imgData[rIdx] != 0 && w_low <= w && w < w_high)
                    {
                        float mult = imgData[rIdx] / 127.0f;
                        *(w + 0) = limit(mult, *(w + 0));
                        *(w + 1) = limit(mult, *(w + 1));
                        *(w + 2) = limit(mult, *(w + 2));
                    }
                    // Up to the next pixel
                    rIdx++;
                    w += 3;
                }
                w += stride - 3 * img.Width;                    // ... and if we're no more on the same row,
                // adjust the writing pointer accordingy
            }
        }
예제 #3
0
        public Rectangle GetBounds(GameObject obj, ShpFile shp, DrawProperties props)
        {
            shp.Initialize();
            int  frameIndex = DecideFrameIndex(props.FrameDecider(obj), shp.NumImages);
            var  offset     = new Point(-shp.Width / 2, -shp.Height / 2);
            Size size       = new Size(0, 0);
            var  img        = shp.GetImage(frameIndex);

            if (img != null)
            {
                offset.Offset(img.X, img.Y);
                size = new Size(img.Width, img.Height);
            }
            return(new Rectangle(offset, size));
        }
예제 #4
0
		private unsafe void BlitVoxelToSurface(DrawingSurface ds, DrawingSurface vxl_ds, GameObject obj, DrawProperties props) {
			Point d = new Point(obj.Tile.Dx * TileWidth / 2, (obj.Tile.Dy - obj.Tile.Z) * TileHeight / 2);
			d.Offset(props.GetOffset(obj));
			d.Offset(-vxl_ds.BitmapData.Width / 2, -vxl_ds.BitmapData.Height / 2);

			// rows inverted!
			var w_low = (byte*)ds.BitmapData.Scan0;
			byte* w_high = w_low + ds.BitmapData.Stride * ds.BitmapData.Height;
			var zBuffer = ds.GetZBuffer();
			var shadowBufVxl = vxl_ds.GetShadows();
			var shadowBuf = ds.GetShadows();
			// int rowsTouched = 0;

			// short firstRowTouched = short.MaxValue;
			for (int y = 0; y < vxl_ds.Height; y++) {
				byte* src_row = (byte*)vxl_ds.BitmapData.Scan0 + vxl_ds.BitmapData.Stride * (vxl_ds.Height - y - 1);
				byte* dst_row = ((byte*)ds.BitmapData.Scan0 + (d.Y + y) * ds.BitmapData.Stride + d.X * 3);
				int zIdx = (d.Y + y) * ds.Width + d.X;
				if (dst_row < w_low || dst_row >= w_high) continue;

				for (int x = 0; x < vxl_ds.Width; x++) {
					// only non-transparent pixels
					if (*(src_row + x * 4 + 3) > 0) {
						*(dst_row + x * 3) = *(src_row + x * 4);
						*(dst_row + x * 3 + 1) = *(src_row + x * 4 + 1);
						*(dst_row + x * 3 + 2) = *(src_row + x * 4 + 2);

						// if (y < firstRowTouched)
						// 	firstRowTouched = (short)y;

						short zBufVal = (short)((obj.Tile.Rx + obj.Tile.Ry + obj.Tile.Z) * TileHeight / 2);
						if (zBufVal >= zBuffer[zIdx])
							zBuffer[zIdx] = zBufVal;
					}
					// or shadows
					else if (shadowBufVxl[x + y * vxl_ds.Height]) {
						int shadIdx = (d.Y + y) * ds.Width + d.X + x;
						if (!shadowBuf[shadIdx]) {
							*(dst_row + x * 3) /= 2;
							*(dst_row + x * 3 + 1) /= 2;
							*(dst_row + x * 3 + 2) /= 2;
							shadowBuf[shadIdx] = true;
						}
					}
					zIdx++;
				}
			}
		}
예제 #5
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 frameTransl = Matrix4.CreateTranslation(section.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);
        }
예제 #6
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);

#if DEBUG
            /*
             * GL.PushMatrix();
             * GL.LineWidth(4);
             * GL.Color3(Color.Red);
             * GL.Begin(BeginMode.Lines);
             * GL.Vertex3(-100, 0, 0);
             * GL.Vertex3(100, 0, 0);
             * GL.End();
             * GL.Color3(Color.Green);
             * GL.Begin(BeginMode.Lines);
             * GL.Vertex3(0, -100, 0);
             * GL.Vertex3(0, 100, 0);
             * GL.End();
             * GL.Color3(Color.White);
             * GL.Begin(BeginMode.Lines);
             * GL.Vertex3(0, 0, -100);
             * GL.Vertex3(0, 0, 100);
             * GL.End();
             * GL.PopMatrix();*/
#endif

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

            GL.Translate(0, 0, 10);
            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.CreateRotationY(MathHelper.DegreesToRadians(180)) * world;             // this is how the game places voxels flat on the world
            world = Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(objectRotation)) * world;  // object facing
            world = Matrix4.Scale(0.028f, 0.028f, 0.028f) * world;

            // art.ini TurretOffset value positions some voxel parts over our x-axis
            world = Matrix4.CreateTranslation(0.18f * props.TurretVoxelOffset, 0, 0) * world;
            GL.MultMatrix(ref world);

            // direction of light vector given by pitch & yaw
            float pitch = MathHelper.DegreesToRadians(210);
            float yaw   = MathHelper.DegreesToRadians(120);

            // helps to find good pitch/yaw

            /*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 < 360; i += 30) {
             *      for (int j = 0; j < 360; j += 30) {
             *              GL.Color3(colors[i / 30]);
             *              var shadowTransform2 =
             *                      Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(210))
             * Matrix4.CreateRotationY(MathHelper.DegreesToRadians(120));
             *              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);

            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);

                // undo world transformations on light direction
                var lightDirection = ExtractRotationVector(ToOpenGL(Matrix4.Invert(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);

                            /* 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);
        }
예제 #7
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 = Matrix4.Identity;
            int     tiltPitch = 0, tiltYaw = 0;

            if (obj.Tile.Drawable != null)
            {
                var img  = (obj.Tile.Drawable as TileDrawable).GetTileImage(obj.Tile);
                int ramp = img?.RampType ?? 0;
                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 v = @object * world * frame * shadowTransform;

                var lightDirection = (v.Determinant != 0.0) ? ExtractRotationVector(ToOpenGL(Matrix4.Invert(v))) : Vector3.Zero;

                // 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);
        }
예제 #8
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;
		}
예제 #9
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;
		}
예제 #10
0
        public unsafe void Draw(ShpFile shp, GameObject obj, Drawable dr, DrawProperties props, DrawingSurface ds, int transLucency = 0)
        {
            shp.Initialize();
            Palette p          = props.PaletteOverride ?? obj.Palette;
            int     frameIndex = props.FrameDecider(obj);

            if (obj.Drawable.IsActualWall)
            {
                frameIndex = ((StructureObject)obj).WallBuildingFrame;
            }
            frameIndex = DecideFrameIndex(frameIndex, shp.NumImages);
            if (frameIndex >= shp.Images.Count)
            {
                return;
            }

            var img     = shp.GetImage(frameIndex);
            var imgData = img.GetImageData();

            if (imgData == null || img.Width * img.Height != imgData.Length)
            {
                return;
            }

            Point offset = props.GetOffset(obj);

            offset.X += obj.Tile.Dx * _config.TileWidth / 2 - shp.Width / 2 + img.X;
            offset.Y += (obj.Tile.Dy - obj.Tile.Z) * _config.TileHeight / 2 - shp.Height / 2 + img.Y;
            Logger.Trace("Drawing SHP file {0} (Frame {1}) at ({2},{3})", shp.FileName, frameIndex, offset.X, offset.Y);

            int stride       = ds.BitmapData.Stride;
            var heightBuffer = ds.GetHeightBuffer();
            var zBuffer      = ds.GetZBuffer();

            var   w_low  = (byte *)ds.BitmapData.Scan0;
            byte *w_high = (byte *)ds.BitmapData.Scan0 + stride * ds.BitmapData.Height;
            byte *w      = (byte *)ds.BitmapData.Scan0 + offset.X * 3 + stride * offset.Y;

            // clip to 25-50-75-100
            transLucency = (transLucency / 25) * 25;
            float a = transLucency / 100f;
            float b = 1 - a;

            int   rIdx    = 0;                              // image pixel index
            int   zIdx    = offset.X + offset.Y * ds.Width; // z-buffer pixel index
            short hBufVal = (short)(obj.Tile.Z * _config.TileHeight / 2);
            short zOffset = (short)((obj.BottomTile.Rx + obj.BottomTile.Ry) * _config.TileHeight / 2 + props.ZAdjust);

            if (!dr.Flat)
            {
                hBufVal += shp.Height;
            }

            for (int y = 0; y < img.Height; y++)
            {
                if (offset.Y + y < 0)
                {
                    w    += stride;
                    rIdx += img.Width;
                    zIdx += ds.Width;
                    continue;                     // out of bounds
                }

                for (int x = 0; x < img.Width; x++)
                {
                    byte paletteValue = imgData[rIdx];

                    short zshapeOffset = obj is StructureObject ? (GetBuildingZ(x, y, shp, img, obj)) : (short)0;

                    if (paletteValue != 0)
                    {
                        short zBufVal = zOffset;
                        if (dr.Flat)
                        {
                            zBufVal += (short)(y - img.Height);
                        }
                        else if (dr.IsBuildingPart)
                        {
                            // nonflat building
                            zBufVal += zshapeOffset;
                        }
                        else
                        {
                            zBufVal += img.Height;
                        }

                        if (w_low <= w && w < w_high /*&& zBufVal >= zBuffer[zIdx]*/)
                        {
                            if (transLucency != 0)
                            {
                                *(w + 0) = (byte)(a * *(w + 0) + b * p.Colors[paletteValue].B);
                                *(w + 1) = (byte)(a * *(w + 1) + b * p.Colors[paletteValue].G);
                                *(w + 2) = (byte)(a * *(w + 2) + b * p.Colors[paletteValue].R);
                            }
                            else
                            {
                                *(w + 0) = p.Colors[paletteValue].B;
                                *(w + 1) = p.Colors[paletteValue].G;
                                *(w + 2) = p.Colors[paletteValue].R;

                                //var pal = Theater.Active.GetPalettes().UnitPalette.Colors;
                                //*(w + 0) = pal[zshapeOffset].R;
                                //*(w + 1) = pal[zshapeOffset].G;
                                //*(w + 2) = pal[zshapeOffset].B;
                            }
                            zBuffer[zIdx]      = zBufVal;
                            heightBuffer[zIdx] = hBufVal;
                        }
                    }
                    //else {
                    //	*(w + 0) = 0;
                    //	*(w + 1) = 0;
                    //	*(w + 2) = 255;
                    //}

                    // Up to the next pixel
                    rIdx++;
                    zIdx++;
                    w += 3;
                }
                w    += stride - 3 * img.Width;
                zIdx += ds.Width - img.Width;
            }
        }
예제 #11
0
        public unsafe void DrawShadow(GameObject obj, ShpFile shp, DrawProperties props, DrawingSurface ds)
        {
            shp.Initialize();
            int frameIndex = props.FrameDecider(obj);

            if (obj.Drawable.IsActualWall)
            {
                frameIndex = ((StructureObject)obj).WallBuildingFrame;
            }
            frameIndex  = DecideFrameIndex(frameIndex, shp.NumImages);
            frameIndex += shp.Images.Count / 2;             // latter half are shadow Images
            if (frameIndex >= shp.Images.Count)
            {
                return;
            }

            var img     = shp.GetImage(frameIndex);
            var imgData = img.GetImageData();

            if (imgData == null || img.Width * img.Height != imgData.Length)
            {
                return;
            }

            Point offset = props.GetShadowOffset(obj);

            offset.X += obj.Tile.Dx * _config.TileWidth / 2 - shp.Width / 2 + img.X;
            offset.Y += (obj.Tile.Dy - obj.Tile.Z) * _config.TileHeight / 2 - shp.Height / 2 + img.Y;
            Logger.Trace("Drawing SHP shadow {0} (frame {1}) at ({2},{3})", shp.FileName, frameIndex, offset.X, offset.Y);

            int stride       = ds.BitmapData.Stride;
            var shadows      = ds.GetShadows();
            var zBuffer      = ds.GetZBuffer();
            var heightBuffer = ds.GetHeightBuffer();

            var   w_low  = (byte *)ds.BitmapData.Scan0;
            byte *w_high = (byte *)ds.BitmapData.Scan0 + stride * ds.BitmapData.Height;

            byte *w          = (byte *)ds.BitmapData.Scan0 + offset.X * 3 + stride * offset.Y;
            int   zIdx       = offset.X + offset.Y * ds.Width;
            int   rIdx       = 0;
            short zOffset    = (short)((obj.Tile.Rx + obj.Tile.Ry) * _config.TileHeight / 2 - shp.Height / 2 + img.Y);
            int   castHeight = obj.Tile.Z * _config.TileHeight / 2;

            if (obj.Drawable != null && !obj.Drawable.Flat)
            {
                castHeight += shp.Height;
                castHeight += obj.Drawable.TileElevation * _config.TileHeight / 2;
            }

            for (int y = 0; y < img.Height; y++)
            {
                if (offset.Y + y < 0)
                {
                    w    += stride;
                    rIdx += img.Width;
                    zIdx += ds.Width;
                    continue;                     // out of bounds
                }

                short zBufVal = zOffset;
                if (obj.Drawable.Flat)
                {
                    zBufVal += (short)y;
                }
                else
                {
                    zBufVal += img.Height;
                }

                for (int x = 0; x < img.Width; x++)
                {
                    if (0 <= offset.X + x && offset.X + x < ds.Width && 0 <= y + offset.Y && y + offset.Y < ds.Height &&
                        imgData[rIdx] != 0 && !shadows[zIdx] &&
                        // zBufVal >= zBuffer[zIdx] &&
                        castHeight >= heightBuffer[zIdx])
                    {
                        *(w + 0)     /= 2;
                        *(w + 1)     /= 2;
                        *(w + 2)     /= 2;
                        shadows[zIdx] = true;
                    }
                    // Up to the next pixel
                    rIdx++;
                    zIdx++;
                    w += 3;
                }
                w    += stride - 3 * img.Width;                 // ... and if we're no more on the same row,
                zIdx += ds.Width - img.Width;
                // adjust the writing pointer accordingy
            }
        }
예제 #12
0
        private static byte GetBuildingZ(int x, int y, ShpFile shp, ShpFile.ShpImage img, GameObject obj, DrawProperties props)
        {
            if (BuildingZ == null)
            {
                BuildingZ = VFS.Open <ShpFile>("buildngz.shp");
                BuildingZ.Initialize();
            }

            var zImg = BuildingZ.GetImage(0);

            byte[] zData = zImg.GetImageData();

            // center x
            x += zImg.Width / 2;
            x += obj.Drawable.Foundation.Width * Drawable.TileHeight / 2;

            // align y
            y += zImg.Height - shp.Height;
            // y += props.ZAdjust;

            return(zData[y * zImg.Width + x]);
        }
예제 #13
0
		unsafe public static void Draw(ShpFile shp, GameObject obj, Drawable dr, DrawProperties props, DrawingSurface ds, int transLucency = 0) {
			shp.Initialize();

			int frameIndex = props.FrameDecider(obj);
			Palette p = props.PaletteOverride ?? obj.Palette;

			frameIndex = DecideFrameIndex(frameIndex, shp.NumImages);
			if (frameIndex >= shp.Images.Count)
				return;

			var img = shp.GetImage(frameIndex);
			var imgData = img.GetImageData();
			if (imgData == null || img.Width * img.Height != imgData.Length)
				return;

			Point offset = props.GetOffset(obj);
			offset.X += obj.Tile.Dx * Drawable.TileWidth / 2 - shp.Width / 2 + img.X;
			offset.Y += (obj.Tile.Dy - obj.Tile.Z) * Drawable.TileHeight / 2 - shp.Height / 2 + img.Y;
			Logger.Trace("Drawing SHP file {0} (Frame {1}) at ({2},{3})", shp.FileName, frameIndex, offset.X, offset.Y);

			int stride = ds.BitmapData.Stride;
			var heightBuffer = ds.GetHeightBuffer();
			var zBuffer = ds.GetZBuffer();

			var w_low = (byte*)ds.BitmapData.Scan0;
			byte* w_high = (byte*)ds.BitmapData.Scan0 + stride * ds.BitmapData.Height;
			byte* w = (byte*)ds.BitmapData.Scan0 + offset.X * 3 + stride * offset.Y;

			// clip to 25-50-75-100
			transLucency = (transLucency / 25) * 25;
			float a = transLucency / 100f;
			float b = 1 - a;

			int rIdx = 0; // image pixel index
			int zIdx = offset.X + offset.Y * ds.Width; // z-buffer pixel index
			short hBufVal = (short)(obj.Tile.Z * Drawable.TileHeight / 2);
			short zOffset = (short)((obj.BottomTile.Rx + obj.BottomTile.Ry) * Drawable.TileHeight / 2);

			if (!dr.Flat)
				hBufVal += shp.Height;

			for (int y = 0; y < img.Height; y++) {
				if (offset.Y + y < 0) {
					w += stride;
					rIdx += img.Width;
					zIdx += ds.Width;
					continue; // out of bounds
				}

				for (int x = 0; x < img.Width; x++) {
					byte paletteValue = imgData[rIdx];

					short zshapeOffset = obj is StructureObject ? (GetBuildingZ(x, y, shp, img, obj)) : (short)0;
					
					if (paletteValue != 0) {
						short zBufVal = zOffset;
						if (dr.Flat)
							zBufVal += (short)(y - img.Height);
						else if (dr.IsBuildingPart) {
							// nonflat building
							zBufVal += zshapeOffset;
						}
						else
							zBufVal += img.Height;

						if (w_low <= w && w < w_high  /*&& zBufVal >= zBuffer[zIdx]*/) {
							if (transLucency != 0) {
								*(w + 0) = (byte)(a * *(w + 0) + b * p.Colors[paletteValue].B);
								*(w + 1) = (byte)(a * *(w + 1) + b * p.Colors[paletteValue].G);
								*(w + 2) = (byte)(a * *(w + 2) + b * p.Colors[paletteValue].R);
							}
							else {
								*(w + 0) = p.Colors[paletteValue].B;
								*(w + 1) = p.Colors[paletteValue].G;
								*(w + 2) = p.Colors[paletteValue].R;

								//var pal = Theater.Active.GetPalettes().UnitPalette.Colors;
								//*(w + 0) = pal[zshapeOffset].R;
								//*(w + 1) = pal[zshapeOffset].G;
								//*(w + 2) = pal[zshapeOffset].B;
							}
							zBuffer[zIdx] = zBufVal;
							heightBuffer[zIdx] = hBufVal;
						}
					}
					//else {
					//	*(w + 0) = 0;
					//	*(w + 1) = 0;
					//	*(w + 2) = 255;
					//}

					// Up to the next pixel
					rIdx++;
					zIdx++;
					w += 3;
				}
				w += stride - 3 * img.Width;
				zIdx += ds.Width - img.Width;
			}
		}
예제 #14
0
		unsafe public static void DrawAlpha(GameObject obj, ShpFile shp, DrawProperties props, DrawingSurface ds) {
			shp.Initialize();

			// Change originally implemented by Starkku: Ares supports multiframe AlphaImages, based on frame count 
			// the direction the unit it facing.
			int frameIndex = props.FrameDecider(obj);

			var img = shp.GetImage(frameIndex);
			var imgData = img.GetImageData();
			var c_px = (uint)(img.Width * img.Height);
			if (c_px <= 0 || img.Width < 0 || img.Height < 0 || frameIndex > shp.NumImages)
				return;

			Point offset = props.GetOffset(obj);
			offset.X += obj.Tile.Dx * Drawable.TileWidth / 2;
			offset.Y += (obj.Tile.Dy - obj.Tile.Z) * Drawable.TileHeight / 2;
			Logger.Trace("Drawing AlphaImage SHP file {0} (frame {1}) at ({2},{3})", shp.FileName, frameIndex, offset.X, offset.Y);

			int stride = ds.BitmapData.Stride;
			var w_low = (byte*)ds.BitmapData.Scan0;
			byte* w_high = (byte*)ds.BitmapData.Scan0 + stride * ds.BitmapData.Height;

			int dx = offset.X + Drawable.TileWidth / 2 - shp.Width / 2 + img.X,
				dy = offset.Y - shp.Height / 2 + img.Y;
			byte* w = (byte*)ds.BitmapData.Scan0 + dx * 3 + stride * dy;
			short zOffset = (short)((obj.Tile.Rx + obj.Tile.Ry) * Drawable.TileHeight / 2 - shp.Height / 2 + img.Y);
			int rIdx = 0;

			for (int y = 0; y < img.Height; y++) {
				for (int x = 0; x < img.Width; x++) {
					if (imgData[rIdx] != 0 && w_low <= w && w < w_high) {
						float mult = imgData[rIdx] / 127.0f;
						*(w + 0) = limit(mult, *(w + 0));
						*(w + 1) = limit(mult, *(w + 1));
						*(w + 2) = limit(mult, *(w + 2));
					}
					// Up to the next pixel
					rIdx++;
					w += 3;
				}
				w += stride - 3 * img.Width;	// ... and if we're no more on the same row,
				// adjust the writing pointer accordingy
			}
		}
예제 #15
0
		unsafe public static void DrawShadow(GameObject obj, ShpFile shp, DrawProperties props, DrawingSurface ds) {
			int frameIndex = props.FrameDecider(obj);
			frameIndex = DecideFrameIndex(frameIndex, shp.NumImages);
			frameIndex += shp.Images.Count / 2; // latter half are shadow Images
			if (frameIndex >= shp.Images.Count)
				return;

			var img = shp.GetImage(frameIndex);
			var imgData = img.GetImageData();
			if (imgData == null || img.Width * img.Height != imgData.Length)
				return;

			Point offset = props.GetShadowOffset(obj);
			offset.X += obj.Tile.Dx * Drawable.TileWidth / 2 - shp.Width / 2 + img.X;
			offset.Y += (obj.Tile.Dy - obj.Tile.Z) * Drawable.TileHeight / 2 - shp.Height / 2 + img.Y;
			Logger.Trace("Drawing SHP shadow {0} (frame {1}) at ({2},{3})", shp.FileName, frameIndex, offset.X, offset.Y);

			int stride = ds.BitmapData.Stride;
			var shadows = ds.GetShadows();
			var zBuffer = ds.GetZBuffer();
			var heightBuffer = ds.GetHeightBuffer();

			var w_low = (byte*)ds.BitmapData.Scan0;
			byte* w_high = (byte*)ds.BitmapData.Scan0 + stride * ds.BitmapData.Height;

			byte* w = (byte*)ds.BitmapData.Scan0 + offset.X * 3 + stride * offset.Y;
			int zIdx = offset.X + offset.Y * ds.Width;
			int rIdx = 0;
			short zOffset = (short)((obj.Tile.Rx + obj.Tile.Ry) * Drawable.TileHeight / 2 - shp.Height / 2 + img.Y);
			int castHeight = obj.Tile.Z * Drawable.TileHeight / 2;
			if (obj.Drawable != null && !obj.Drawable.Flat) {
				castHeight += shp.Height;
				castHeight += obj.Drawable.TileElevation * Drawable.TileHeight / 2;
			}

			for (int y = 0; y < img.Height; y++) {
				if (offset.Y + y < 0) {
					w += stride;
					rIdx += img.Width;
					zIdx += ds.Width;
					continue; // out of bounds
				}

				short zBufVal = zOffset;
				if (obj.Drawable.Flat)
					zBufVal += (short)y;
				else
					zBufVal += img.Height;

				for (int x = 0; x < img.Width; x++) {
					if (w_low <= w && w < w_high && imgData[rIdx] != 0 && !shadows[zIdx] 
						//&& zBufVal >= zBuffer[zIdx] 
						&& castHeight >= heightBuffer[zIdx]
						) {
						*(w + 0) /= 2;
						*(w + 1) /= 2;
						*(w + 2) /= 2;
						shadows[zIdx] = true;
					}
					// Up to the next pixel
					rIdx++;
					zIdx++;
					w += 3;
				}
				w += stride - 3 * img.Width;	// ... and if we're no more on the same row,
				zIdx += ds.Width - img.Width;
				// adjust the writing pointer accordingy
			}
		}
예제 #16
0
		private AnimDrawable LoadExtraImage(string extraImage, DrawProperties inheritProps) {
			string animSection = Art.ReadString(extraImage);
			if (animSection == "") return null;

			IniFile.IniSection extraRules = OwnerCollection.Rules.GetOrCreateSection(animSection);
			IniFile.IniSection extraArt = OwnerCollection.Art.GetOrCreateSection(animSection);
			var anim = new AnimDrawable(extraRules, extraArt);
			anim.OwnerCollection = OwnerCollection;
			anim.LoadFromRules();

			anim.NewTheater = this.NewTheater;

			if (extraArt.HasKey("YSortAdjust") || Art.HasKey(extraImage + "YSort") ||
				extraArt.HasKey("ZAdjust") || Art.HasKey(extraImage + "ZAdjust"))
				anim.Props.SortIndex = extraArt.ReadInt("YSortAdjust", Art.ReadInt(extraImage + "YSort"))
					- extraArt.ReadInt("ZAdjust", Art.ReadInt(extraImage + "ZAdjust"));
			else
				anim.Props.SortIndex = inheritProps.SortIndex;
			if (Art.HasKey(extraImage + "X") || Art.HasKey(extraImage + "Y"))
				anim.Props.Offset = this.Props.Offset + new Size(Art.ReadInt(extraImage + "X"), Art.ReadInt(extraImage + "Y"));
			else
				anim.Props.Offset = inheritProps.Offset;
			anim.Props.ZAdjust = Art.ReadInt(extraImage + "ZAdjust");
			anim.IsBuildingPart = true;

			anim.Shp = VFS.Open<ShpFile>(anim.GetFilename());
			return anim;
		}