Пример #1
0
        private void addPolygon(ref BSPNode root, BSPFaceRef face, Polygon transformed)
        {
            if(root == null) root = new BSPNode();

            if(root.PolygonsFront.Count == 0)
            {
                // We though root.Front == null && root.Back == null
                root.Plane = transformed.Plane;
                root.PolygonsFront = new List<BSPFaceRef> { face };
                return;
            }

            var positive = 0;
            var negative = 0;
            var inPlane = 0;

            foreach(var v in transformed.Vertices)
            {
                var dist = root.Plane.Distance(v.Position);
                if (dist > SPLIT_EPSILON)
                    positive++;
                else if (dist < -SPLIT_EPSILON)
                    negative++;
                else
                    inPlane++;
            }

            if(positive > 0 && negative == 0) // SPLIT_FRONT
            {
                addPolygon(ref root.Front, face, transformed);
            }
            else if(positive == 0 && negative > 0) // SPLIT_BACK
            {
                addPolygon(ref root.Back, face, transformed);
            }
            else // SPLIT_IN_PLANE
            {
                if(transformed.Plane.Normal.Dot(root.Plane.Normal) > 0.9)
                {
                    root.PolygonsFront.Add(face);
                }
                else
                {
                    root.PolygonsBack.Add(face);
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Assign animated texture to a polygon.
        /// </summary>
        public static bool Res_Poly_SetAnimTexture(Polygon polygon, uint texIndex, World world)
        {
            polygon.AnimID = 0; // Reset to 0 by default

            for (var i = 0; i < world.AnimSequences.Count; i++)
            {
                for (var j = 0; j < world.AnimSequences[i].Frames.Count; j++)
                {
                    if(world.AnimSequences[i].FrameList[j] == texIndex)
                    {
                        // If we have found assigned texture ID in animation texture lists,
                        // we assign corresponding animation sequence to this polygon,
                        // additionally specifying frame offset.
                        polygon.AnimID = (ushort)(i + 1); // Animation sequence ID.
                        polygon.FrameOffset = (ushort)j; // Animation frame offset.
                        return true;
                    }
                }
            }

            return false; // No such TexInfo found in animation textures lists.
        }
Пример #3
0
 public static void tr_setupTexturedFace(Mesh trMesh, BaseMesh mesh, ushort[] vertexIndices, Polygon p)
 {
     if (trMesh.Lights.Length == trMesh.Vertices.Length)
     {
         for (var i = 0; i < p.Vertices.Count; i++)
         {
             p.Vertices[i].Color[0] = 1.0f - trMesh.Lights[vertexIndices[i]] / 8192.0f;
             p.Vertices[i].Color[1] = 1.0f - trMesh.Lights[vertexIndices[i]] / 8192.0f;
             p.Vertices[i].Color[2] = 1.0f - trMesh.Lights[vertexIndices[i]] / 8192.0f;
             p.Vertices[i].Color[3] = 1.0f;
         }
     }
     else
     {
         foreach (var v in p.Vertices)
         {
             v.Color = new float[] {1, 1, 1, 1};
         }
     }
 }
Пример #4
0
        public static void tr_setupColoredFace(Mesh trMesh, Level tr, BaseMesh mesh, ushort[] vertexIndices, int color,
            Polygon p)
        {
            var tmp = trMesh.Lights.Length == trMesh.Vertices.Length;
            for (var i = 0; i < p.Vertices.Count; i++)
            {
                p.Vertices[i].Color[0] = tr.Palette.Colour[color].R / 255.0f;
                p.Vertices[i].Color[1] = tr.Palette.Colour[color].G / 255.0f;
                p.Vertices[i].Color[2] = tr.Palette.Colour[color].B / 255.0f;
                if(tmp)
                {
                    p.Vertices[i].Color[0] = p.Vertices[i].Color[0] * 1.0f - trMesh.Lights[vertexIndices[i]] / 8192.0f;
                    p.Vertices[i].Color[1] = p.Vertices[i].Color[1] * 1.0f - trMesh.Lights[vertexIndices[i]] / 8192.0f;
                    p.Vertices[i].Color[2] = p.Vertices[i].Color[2] * 1.0f - trMesh.Lights[vertexIndices[i]] / 8192.0f;
                }
                p.Vertices[i].Color[3] = 1.0f;

                p.Vertices[i].TexCoord[0] = (i & 2) == 2 ? 1.0f : 0.0f;
                p.Vertices[i].TexCoord[1] = i >= 2 ? 1.0f : 0.0f;
            }
            mesh.UsesVertexColors = true;
        }
Пример #5
0
        public static void tr_accumulateNormals(Mesh trMesh, BaseMesh mesh, int numCorners, ushort[] vertexIndices, Polygon p)
        {
            p.Vertices.Resize(numCorners, () => new Vertex());

            for (var i = 0; i < numCorners; i++)
            {
                p.Vertices[i].Position = trMesh.Vertices[vertexIndices[i]].ToVector3();
            }
            p.FindNormal();

            for (var i = 0; i < numCorners; i++)
            {
                mesh.Vertices[vertexIndices[i]].Normal += p.Plane.Normal;
            }
        }
Пример #6
0
 public static void tr_copyNormals(Polygon polygon, BaseMesh mesh, ushort[] mesh_vertex_indices)
 {
     for (var i = 0; i < polygon.Vertices.Count; i++)
     {
         polygon.Vertices[i].Normal = mesh.Vertices[mesh_vertex_indices[i]].Normal;
     }
 }
Пример #7
0
        public static void tr_setupRoomVertices(World world, Level tr, Loader.Room tr_room, BaseMesh mesh,
            int numCorners, ushort[] vertices, ushort masked_texture, Polygon p)
        {
            p.Vertices.Resize(numCorners, () => new Vertex());

            for (var i = 0; i < numCorners; i++)
            {
                p.Vertices[i].Position = tr_room.Vertices[vertices[i]].Vertex.ToVector3();
            }
            p.FindNormal();

            for (var i = 0; i < numCorners; i++)
            {
                mesh.Vertices[vertices[i]].Normal += p.Plane.Normal;
                p.Vertices[i].Normal = p.Plane.Normal;
                p.Vertices[i].Color = TR_color_to_arr(tr_room.Vertices[vertices[i]].Color);
            }

            var tex = tr.ObjectTextures[masked_texture];
            SetAnimTexture(p, masked_texture, world);
            p.BlendMode = tex.TransparencyFlags;

            world.TextureAtlas.GetCoordinates(masked_texture, false, p);
        }
Пример #8
0
        public void AddNewPolygonList(List<TransparentPolygonReference> p, Transform transform, Frustum frustum, Camera cam)
        {
            foreach (var pp in p)
            {
                var transformed = new Polygon();
                transformed.Vertices.Resize(pp.Polygon.Vertices.Count, () => new Vertex());
                transformed.Transform(pp.Polygon, transform);
                transformed.DoubleSide = pp.Polygon.DoubleSide;

                if(frustum.IsPolyVisible(transformed, cam))
                {
                    addPolygon(ref _root, new BSPFaceRef(transform, pp), transformed);
                }
            }
        }
Пример #9
0
        public static void TR_GenMesh(World world, int mesh_index, BaseMesh mesh, Level tr)
        {
            var texMask = world.EngineVersion == Loader.Engine.TR4 ? TextureIndexMaskTr4 : TextureIndexMask;

            /* TR WAD FORMAT DOCUMENTATION!
             * tr4_face[3,4]_t:
             * flipped texture & 0x8000 (1 bit  ) - horizontal flipping.
             * shape texture   & 0x7000 (3 bits ) - texture sample shape.
             * index texture   & $0FFF  (12 bits) - texture sample index.
             *
             * if bit [15] is set, as in ( texture and $8000 ), it indicates that the texture
             * sample must be flipped horizontally prior to be used.
             * Bits [14..12] as in ( texture and $7000 ), are used to store the texture
             * shape, given by: ( texture and $7000 ) shr 12.
             * The valid values are: 0, 2, 4, 6, 7, as assigned to a square starting from
             * the top-left corner and going clockwise: 0, 2, 4, 6 represent the positions
             * of the square angle of the triangles, 7 represents a quad.
             */

            var trMesh = tr.Meshes[mesh_index];
            mesh.ID = (uint)mesh_index;
            mesh.Center.X = trMesh.Centre.X;
            mesh.Center.Y = trMesh.Centre.Z;
            mesh.Center.Z = trMesh.Centre.Y;
            mesh.Radius = trMesh.CollisionSize;
            mesh.TexturePageCount = world.TextureAtlas.NumAtlasPages + 1;

            mesh.Vertices.Resize(trMesh.Vertices.Length, () => new Vertex());
            for (var i = 0; i < mesh.Vertices.Count; i++)
            {
                mesh.Vertices[i].Position = trMesh.Vertices[i].ToVector3();
                mesh.Vertices[i].Normal = Vector3.Zero; // paranoid
            }
            
            mesh.FindBB();

            mesh.Polygons.Clear();

            // textured triangles
            foreach (var face3 in trMesh.TexturedTriangles)
            {
                var p = new Polygon();

                var tex = tr.ObjectTextures[face3.Texture & texMask];

                p.DoubleSide = face3.Texture >> 15 != 0; // CORRECT, BUT WRONG IN TR3-5

                SetAnimTexture(p, (uint)face3.Texture & texMask, world);

                p.BlendMode = face3.Lighting.HasFlagUns(0x01) ? BlendingMode.Multiply : tex.TransparencyFlags;

                tr_accumulateNormals(trMesh, mesh, 3, face3.Vertices, p);
                tr_setupTexturedFace(trMesh, mesh, face3.Vertices, p);

                world.TextureAtlas.GetCoordinates((uint) face3.Texture & texMask, false, p);

                mesh.Polygons.Add(p);
            }

            // coloured triangles
            foreach (var face3 in trMesh.ColouredTriangles)
            {
                var p = new Polygon();

                var col = face3.Texture & 0xff;
                p.TexIndex = (ushort)world.TextureAtlas.NumAtlasPages;
                p.BlendMode = BlendingMode.Opaque;
                p.AnimID = 0;

                tr_accumulateNormals(trMesh, mesh, 3, face3.Vertices, p);
                tr_setupColoredFace(trMesh, tr, mesh, face3.Vertices, col, p);

                mesh.Polygons.Add(p);
            }

            // textured rectangles
            foreach (var face4 in trMesh.TexturedRectangles)
            {
                var p = new Polygon();

                var tex = tr.ObjectTextures[face4.Texture & texMask];

                p.DoubleSide = face4.Texture >> 15 != 0; // CORRECT, BUT WRONG IN TR3-5

                SetAnimTexture(p, (uint)face4.Texture & texMask, world);

                p.BlendMode = face4.Lighting.HasFlagUns(0x01) ? BlendingMode.Multiply : tex.TransparencyFlags;

                tr_accumulateNormals(trMesh, mesh, 4, face4.Vertices, p);
                tr_setupTexturedFace(trMesh, mesh, face4.Vertices, p);

                world.TextureAtlas.GetCoordinates((uint)face4.Texture & texMask, false, p);

                mesh.Polygons.Add(p);
            }

            // coloured rectangles
            foreach (var face4 in trMesh.ColouredRectangles)
            {
                var p = new Polygon();

                var col = face4.Texture & 0xff;
                p.TexIndex = (ushort)world.TextureAtlas.NumAtlasPages;
                p.BlendMode = BlendingMode.Opaque;
                p.AnimID = 0;

                tr_accumulateNormals(trMesh, mesh, 4, face4.Vertices, p);
                tr_setupColoredFace(trMesh, tr, mesh, face4.Vertices, col, p);

                mesh.Polygons.Add(p);
            }

            // let us normalise normals %)
            foreach (var v in mesh.Vertices)
            {
                v.Normal = v.Normal.SafeNormalize();
            }

            // triangles
            var j = 0;
            for (var i = 0; i < trMesh.TexturedTriangles.Length; i++, j++)
            {
                tr_copyNormals(mesh.Polygons[j], mesh, trMesh.TexturedTriangles[i].Vertices);
            }

            for (var i = 0; i < trMesh.ColouredTriangles.Length; i++, j++)
            {
                tr_copyNormals(mesh.Polygons[j], mesh, trMesh.ColouredTriangles[i].Vertices);
            }

            // triangles
            for (var i = 0; i < trMesh.TexturedRectangles.Length; i++, j++)
            {
                tr_copyNormals(mesh.Polygons[j], mesh, trMesh.TexturedRectangles[i].Vertices);
            }

            for (var i = 0; i < trMesh.ColouredRectangles.Length; i++, j++)
            {
                tr_copyNormals(mesh.Polygons[j], mesh, trMesh.ColouredRectangles[i].Vertices);
            }

            mesh.Vertices.Clear();
            mesh.GenFaces();
            mesh.PolySortInMesh();
        }
Пример #10
0
        public void Split(Plane n, ref Polygon front, ref Polygon back)
        {
            front.Plane = Plane;
            front.AnimID = AnimID;
            front.FrameOffset = FrameOffset;
            front.DoubleSide = DoubleSide;
            front.TexIndex = TexIndex;
            front.BlendMode = BlendMode;

            back.Plane = Plane;
            back.AnimID = AnimID;
            back.FrameOffset = FrameOffset;
            back.DoubleSide = DoubleSide;
            back.TexIndex = TexIndex;
            back.BlendMode = BlendMode;

            var prev_v = Vertices.Last();
            var dist0 = n.Distance(prev_v.Position);
            foreach (var curr_v in Vertices)
            {
                var dist1 = n.Distance(curr_v.Position);

                if(Math.Abs(dist1) > SPLIT_EPSILON)
                {
                    if ((dist1 > SPLIT_EPSILON && dist0 < -SPLIT_EPSILON)
                        || (dist1 < -SPLIT_EPSILON && dist0 > SPLIT_EPSILON))
                    {
                        var dir = curr_v.Position - prev_v.Position;
                        float t;
                        var tv = new Vertex
                        {
                            Position = n.RayIntersect(prev_v.Position, dir, out t),
                            Normal = prev_v.Normal.Lerp(curr_v.Normal, t).Normalized(),
                            Color = new[]
                            {
                                prev_v.Color[0] + t * (curr_v.Color[0] - prev_v.Color[0]),
                                prev_v.Color[1] + t * (curr_v.Color[1] - prev_v.Color[1]),
                                prev_v.Color[2] + t * (curr_v.Color[2] - prev_v.Color[2]),
                                prev_v.Color[3] + t * (curr_v.Color[3] - prev_v.Color[3])
                            },
                            TexCoord = new[]
                            {
                                prev_v.TexCoord[0] + t * (curr_v.TexCoord[0] - prev_v.TexCoord[0]),
                                prev_v.TexCoord[1] + t * (curr_v.TexCoord[1] - prev_v.TexCoord[1])
                            }
                        };

                        front.Vertices.Add(tv);
                        back.Vertices.Add(tv);
                    }

                    if (dist1 > SPLIT_EPSILON)
                        front.Vertices.Add(curr_v);
                    else
                        back.Vertices.Add(curr_v);
                }
                else
                {
                    front.Vertices.Add(curr_v);
                    back.Vertices.Add(curr_v);
                }

                prev_v = curr_v;
                dist0 = dist1;
            }
        }
Пример #11
0
        public bool IntersectPolygon(Polygon p2)
        {
            if(SplitClassify(p2.Plane) != PolygonSplit.InBoth || p2.SplitClassify(Plane) != PolygonSplit.InBoth)
            {
                return false; // Quick check
            }

            var resultBuf = new List<Vector3>();

            // Intersection of polygon p1 and plane p2
            var prev_v = Vertices.Last();
            var dist0 = p2.Plane.Distance(prev_v.Position);
            foreach (var curr_v in Vertices)
            {
                var dist1 = p2.Plane.Distance(curr_v.Position);
                if ((dist1 > SPLIT_EPSILON && dist0 < -SPLIT_EPSILON)
                    || (dist1 < -SPLIT_EPSILON && dist0 > SPLIT_EPSILON))
                {
                    resultBuf.Add(p2.Plane.RayIntersect(prev_v.Position, curr_v.Position - prev_v.Position));
                }
                else
                {
                    resultBuf.Add(curr_v.Position);
                }

                if (resultBuf.Count >= 2) break;

                dist0 = dist1;
                prev_v = curr_v;
            }

            // Splitting p2 by p1 split plane
            prev_v = Vertices.Last();
            dist0 = p2.Plane.Distance(prev_v.Position);
            foreach (var curr_v in Vertices)
            {
                var dist1 = p2.Plane.Distance(curr_v.Position);
                if ((dist1 > SPLIT_EPSILON && dist0 < -SPLIT_EPSILON)
                    || (dist1 < -SPLIT_EPSILON && dist0 > SPLIT_EPSILON))
                {
                    resultBuf.Add(p2.Plane.RayIntersect(prev_v.Position, curr_v.Position - prev_v.Position));
                }
                else
                {
                    resultBuf.Add(curr_v.Position);
                }

                if (resultBuf.Count >= 4) break;

                dist0 = dist1;
                prev_v = curr_v;
            }

            var dir = Plane.Normal.Cross(p2.Plane.Normal); // vector of two planes intersection line
            var t = Math.Abs(dir.X);
            dist0 = Math.Abs(dir.Y);
            var dist1_ = Math.Abs(dir.Z);
            var dist2 = 0.0f;
            var pn = PLANE_X;
            if(t < dist0)
            {
                t = dist0;
                pn = PLANE_Y;
            }
            if(t < dist1_)
            {
                pn = PLANE_Z;
            }

            switch(pn)
            {
                case PLANE_X:
                    dist0 = (resultBuf[1][0] - resultBuf[0][0]) / dir[0];
                    dist1_ = (resultBuf[2][0] - resultBuf[0][0]) / dir[0];
                    dist2 = (resultBuf[3][0] - resultBuf[0][0]) / dir[0];
                    break;

                case PLANE_Y:
                    dist0 = (resultBuf[1][1] - resultBuf[0][1]) / dir[1];
                    dist1_ = (resultBuf[2][1] - resultBuf[0][1]) / dir[1];
                    dist2 = (resultBuf[3][1] - resultBuf[0][1]) / dir[1];
                    break;

                case PLANE_Z:
                    dist0 = (resultBuf[1][2] - resultBuf[0][2]) / dir[2];
                    dist1_ = (resultBuf[2][2] - resultBuf[0][2]) / dir[2];
                    dist2 = (resultBuf[3][2] - resultBuf[0][2]) / dir[2];
                    break;
            }

            if(dist0 > 0)
            {
                return !((dist1_ < 0 && dist2 < 0) || (dist1_ > dist0 && dist2 > dist0));
            }

            return !((dist1_ < dist0 && dist2 < dist0) || (dist1_ > 0 && dist2 > 0));
        }
Пример #12
0
        public void Transform(Polygon src, Transform tr)
        {
            Vertices.Resize(src.Vertices.Count, () => new Vertex());

            Plane.Normal = tr.Basis.MultiplyByVector(src.Plane.Normal);
            for (var i = 0; i < src.Vertices.Count; i++)
            {
                Vertices[i].Position = tr * src.Vertices[i].Position;
                Vertices[i].Normal = tr.Basis.MultiplyByVector(src.Vertices[i].Normal);
            }
            Plane.MoveTo(Vertices[0].Position);
        }
Пример #13
0
 public void VTransform(Polygon src, Transform tr)
 {
     Plane.Normal = tr.Basis.MultiplyByVector(src.Plane.Normal);
     for (var i = 0; i < src.Vertices.Count; i++)
     {
         Vertices[i].Position = tr * src.Vertices[i].Position;
     }
     Plane.MoveTo(Vertices[0].Position);
 }
Пример #14
0
 public void Move(Polygon src, Vector3 move)
 {
     for (var i = 0; i < src.Vertices.Count; i++)
     {
         Vertices[i].Position = src.Vertices[i].Position + move;
     }
     Plane = src.Plane;
     Plane.MoveTo(Vertices[0].Position);
 }
Пример #15
0
 public Polygon(Polygon rhs)
 {
     Vertices = rhs.Vertices;
     TexIndex = rhs.TexIndex;
     AnimID = rhs.AnimID;
     FrameOffset = rhs.FrameOffset;
     BlendMode = rhs.BlendMode;
     DoubleSide = rhs.DoubleSide;
     Plane = rhs.Plane;
 }
Пример #16
0
        public bool IsAABBVisible(Vector3 bbMin, Vector3 bbMax, Camera cam)
        {
            var poly = new Polygon();
            poly.Vertices = new List<Vertex>(4);
            var ins = true;

            // X AXIS

            if(cam.Position.X < bbMin.X)
            {
                poly.Plane.Normal.X = -1.0f;
                poly.Plane.Dot = -bbMin.X;

                poly.Vertices[0].Position[0] = bbMin[0];
                poly.Vertices[0].Position[1] = bbMax[1];
                poly.Vertices[0].Position[2] = bbMax[2];

                poly.Vertices[1].Position[0] = bbMin[0];
                poly.Vertices[1].Position[1] = bbMin[1];
                poly.Vertices[1].Position[2] = bbMax[2];

                poly.Vertices[2].Position[0] = bbMin[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMin[2];

                poly.Vertices[3].Position[0] = bbMin[0];
                poly.Vertices[3].Position[1] = bbMax[1];
                poly.Vertices[3].Position[2] = bbMin[2];

                if(IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }
            else if(cam.Position.X > bbMax.X)
            {
                poly.Plane.Normal.X = 1.0f;
                poly.Plane.Dot = bbMax.X;

                poly.Vertices[0].Position[0] = bbMax[0];
                poly.Vertices[0].Position[1] = bbMax[1];
                poly.Vertices[0].Position[2] = bbMax[2];

                poly.Vertices[1].Position[0] = bbMax[0];
                poly.Vertices[1].Position[1] = bbMin[1];
                poly.Vertices[1].Position[2] = bbMax[2];

                poly.Vertices[2].Position[0] = bbMax[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMin[2];

                poly.Vertices[3].Position[0] = bbMax[0];
                poly.Vertices[3].Position[1] = bbMax[1];
                poly.Vertices[3].Position[2] = bbMin[2];

                if (IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }

            // Y AXIS

            poly.Plane.Normal.X = 0;
            poly.Plane.Normal.Z = 0;

            if (cam.Position.Y < bbMin.Y)
            {
                poly.Plane.Normal.Y = -1.0f;
                poly.Plane.Dot = -bbMin.Y;

                poly.Vertices[0].Position[0] = bbMax[0];
                poly.Vertices[0].Position[1] = bbMin[1];
                poly.Vertices[0].Position[2] = bbMax[2];

                poly.Vertices[1].Position[0] = bbMin[0];
                poly.Vertices[1].Position[1] = bbMin[1];
                poly.Vertices[1].Position[2] = bbMax[2];

                poly.Vertices[2].Position[0] = bbMin[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMin[2];

                poly.Vertices[3].Position[0] = bbMax[0];
                poly.Vertices[3].Position[1] = bbMin[1];
                poly.Vertices[3].Position[2] = bbMin[2];

                if (IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }
            else if (cam.Position.Y > bbMax.Y)
            {
                poly.Plane.Normal.Y = 1.0f;
                poly.Plane.Dot = -bbMax.Y;

                poly.Vertices[0].Position[0] = bbMax[0];
                poly.Vertices[0].Position[1] = bbMax[1];
                poly.Vertices[0].Position[2] = bbMax[2];

                poly.Vertices[1].Position[0] = bbMax[0];
                poly.Vertices[1].Position[1] = bbMin[1];
                poly.Vertices[1].Position[2] = bbMax[2];

                poly.Vertices[2].Position[0] = bbMax[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMin[2];

                poly.Vertices[3].Position[0] = bbMax[0];
                poly.Vertices[3].Position[1] = bbMax[1];
                poly.Vertices[3].Position[2] = bbMin[2];

                if (IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }

            // Z AXIS

            poly.Plane.Normal.X = 0;
            poly.Plane.Normal.Y = 0;

            if (cam.Position.Z < bbMin.Z)
            {
                poly.Plane.Normal.Z = -1.0f;
                poly.Plane.Dot = -bbMin.Z;

                poly.Vertices[0].Position[0] = bbMax[0];
                poly.Vertices[0].Position[1] = bbMax[1];
                poly.Vertices[0].Position[2] = bbMin[2];

                poly.Vertices[1].Position[0] = bbMin[0];
                poly.Vertices[1].Position[1] = bbMax[1];
                poly.Vertices[1].Position[2] = bbMin[2];

                poly.Vertices[2].Position[0] = bbMin[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMin[2];

                poly.Vertices[3].Position[0] = bbMax[0];
                poly.Vertices[3].Position[1] = bbMin[1];
                poly.Vertices[3].Position[2] = bbMin[2];

                if (IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }
            else if (cam.Position.Z > bbMax.Z)
            {
                poly.Plane.Normal.Z = 1.0f;
                poly.Plane.Dot = -bbMax.Z;

                poly.Vertices[0].Position[0] = bbMax[0];
                poly.Vertices[0].Position[1] = bbMax[1];
                poly.Vertices[0].Position[2] = bbMax[2];

                poly.Vertices[1].Position[0] = bbMin[0];
                poly.Vertices[1].Position[1] = bbMax[1];
                poly.Vertices[1].Position[2] = bbMax[2];

                poly.Vertices[2].Position[0] = bbMin[0];
                poly.Vertices[2].Position[1] = bbMin[1];
                poly.Vertices[2].Position[2] = bbMax[2];

                poly.Vertices[3].Position[0] = bbMax[0];
                poly.Vertices[3].Position[1] = bbMin[1];
                poly.Vertices[3].Position[2] = bbMax[2];

                if (IsPolyVisible(poly, cam))
                {
                    return true;
                }
                ins = false;
            }

            return ins;
        }
Пример #17
0
        /// <summary>
        /// Check polygon visibility through the portal.
        /// </summary>
        public bool IsPolyVisible(Polygon p, Camera cam)
        {
            if (!p.DoubleSide && p.Plane.Distance(cam.Position) < 0)
                return false;

            // Direction from the camera position to an arbitrary vertex frustum
            StaticFuncs.Assert(Vertices.Any());
            var dir = Vertices[0] - cam.Position;
            var lambda = 0.0f;

            // Polygon fits whole frustum (shouldn't happen, but we check anyway)
            if(p.RayIntersect(dir, cam.Position, ref lambda))
            {
                return true;
            }

            // Generate queue order
            var nextPlaneIdx = 0;
            // 3 neighboring clipping planes
            var currentPlane = Planes.Last();
            var prevPlane = Planes[Planes.Count - 2];
            // in case no intersection
            var ins = true;
            // iterate through all the planes of this frustum
            for (var i = 0; i < Vertices.Count; i++)
            {
                var nextPlane = Planes[nextPlaneIdx];

                // Queue vertices for testing
                var prevVertex = p.Vertices.Last();
                // signed distance from the current point to the previous plane
                var dist0 = currentPlane.Distance(prevVertex.Position);
                var outs = true;
                // iterate through all the vertices of the polygon
                foreach (var currentVertex in p.Vertices)
                {
                    var dist1 = currentPlane.Distance(currentVertex.Position);
                    // the split point in the plane
                    if(Math.Abs(dist0) < SPLIT_EPSILON)
                    {
                        if(prevPlane.Distance(prevVertex.Position) > -SPLIT_EPSILON
                            && nextPlane.Distance(prevVertex.Position) > -SPLIT_EPSILON
                            && Normal.Distance(prevVertex.Position) > -SPLIT_EPSILON)
                        {
                            // Frustum-vertex intersection test is passed
                            return true;
                        }
                    }

                    // vertices from different sides of the plane (or on it)
                    if(dist0 * dist1 < 0 && Math.Abs(dist1) >= SPLIT_EPSILON)
                    {
                        // vector connecting vertices
                        dir = currentVertex.Position - prevVertex.Position;
                        // We are looking for the point of intersection
                        var T = currentPlane.RayIntersect(prevVertex.Position, dir);
                        if(prevPlane.Distance(T) > -SPLIT_EPSILON && nextPlane.Distance(T) > -SPLIT_EPSILON)
                        {
                            // Frustum-ray intersection test is passed
                            return true;
                        }
                    }

                    // point is outside
                    if(dist1 < -SPLIT_EPSILON)
                    {
                        ins = false;
                    }
                    else
                    {
                        outs = false;
                    }

                    // We moved all the vertices of the polygon
                    prevVertex = currentVertex;
                    // We moved all distances
                    dist0 = dist1;
                    // finished with all polygon vertices
                }

                if(outs)
                {
                    // all points are outside of the current plane - definitely exit
                    return false;
                }
                // We moved all the clipping planes
                prevPlane = currentPlane;
                currentPlane = nextPlane;
                nextPlaneIdx++;
                // finished with all planes of this frustum
            }
            if(ins)
            {
                // all the vertices are inside - test is passed
                return true;
            }

            return false;
        }
Пример #18
0
        /**   Animated textures loading.
          *   Natively, animated textures stored as a stream of bitu16s, which
          *   is then parsed on the fly. What we do is parse this stream to the
          *   proper structures to be used later within renderer.
          */
        public static unsafe void TR_GenAnimTextures(World world, Level tr)
        {
            var p0 = new Polygon();
            var p = new Polygon();

            p0.Vertices.Resize(3, () => new Vertex());
            p.Vertices.Resize(3, () => new Vertex());

            fixed(ushort* tmp = tr.AnimatedTextures)
            {
                var pointer = tmp;
                var numUvrotates = tr.AnimatedTexturesUVCount;

                var numSequences = *pointer++; // First word in a stream is sequence count.

                world.AnimSequences.Resize(numSequences, () => new AnimSeq());

                for(var i = 0; i < numSequences; i++)
                {
                    var seq = world.AnimSequences[i];

                    seq.Frames.Resize(*pointer++ + 1, () => new TexFrame());
                    seq.FrameList.Resize(seq.Frames.Count);

                    // Fill up new sequence with frame list
                    seq.AnimType = TR_ANIMTEXTURE.Forward;
                    seq.FrameLock = false; // by default anim is playing
                    seq.UVRotate = false; // by default uvrotate
                    seq.ReverseDirection = false; // Needed for proper reverse-type start-up.
                    seq.FrameRate = 0.05f; // Should be passed as 1 / FPS.
                    seq.FrameTime = 0.0f; // Reset frame time to initial state.
                    seq.CurrentFrame = 0; // Reset current frame to zero.

                    for(var j = 0; j < seq.Frames.Count; j++)
                    {
                        seq.FrameList[j] = *pointer++; // Add one frame.
                    }

                    // UVRotate textures case.
                    // In TR4-5, it is possible to define special UVRotate animation mode.
                    // It is specified by num_uvrotates variable. If sequence belongs to
                    // UVRotate range, each frame will be divided in half and continously
                    // scrolled from one part to another by shifting UV coordinates.
                    // In OpenTomb, we can have BOTH UVRotate and classic frames mode
                    // applied to the same sequence, but there we specify compatibility
                    // method for TR4-5.

                    var uvrotateScript = 0;
                    var tmp1 = EngineLua["UVRotate"];
                    if(tmp1 != null)
                    {
                        uvrotateScript = (int) tmp1;
                    }

                    if(i < numUvrotates)
                    {
                        seq.FrameLock = false; // by default anim is playing

                        seq.UVRotate = true;
                        // Get texture height and divide it in half.
                        // This way, we get a reference value which is used to identify
                        // if scrolling is completed or not.
                        seq.Frames.Resize(8, () => new TexFrame());
                        seq.UVRotateMax = world.TextureAtlas.GetTextureHeight(seq.FrameList[0]) / 2f;
                        seq.UVRotateSpeed = seq.UVRotateMax / seq.Frames.Count;
                        seq.FrameList.Resize(8);

                        if(uvrotateScript > 0)
                        {
                            seq.AnimType = TR_ANIMTEXTURE.Forward;
                        }
                        else if(uvrotateScript < 0)
                        {
                            seq.AnimType = TR_ANIMTEXTURE.Backward;
                        }

                        EngineWorld.TextureAtlas.GetCoordinates(seq.FrameList[0], false, p, 0, true);
                        for(var j = 0; j < seq.Frames.Count; j++)
                        {
                            EngineWorld.TextureAtlas.GetCoordinates(seq.FrameList[0], false, p, (int)(j * seq.UVRotateSpeed), true);
                            seq.Frames[j].TextureIndex = p.TexIndex;

                            var A0 = new[]
                            {
                                p0.Vertices[1].TexCoord[0] - p0.Vertices[0].TexCoord[0], // TODO: p0 hasn't been modified??
                                p0.Vertices[1].TexCoord[1] - p0.Vertices[0].TexCoord[1]
                            };
                            var B0 = new[]
                            {
                                p0.Vertices[2].TexCoord[0] - p0.Vertices[0].TexCoord[0],
                                p0.Vertices[2].TexCoord[1] - p0.Vertices[0].TexCoord[1]
                            };

                            var A = new[]
                            {
                                p.Vertices[1].TexCoord[0] - p.Vertices[0].TexCoord[0],
                                p.Vertices[1].TexCoord[1] - p.Vertices[0].TexCoord[1]
                            };
                            var B = new[]
                            {
                                p.Vertices[2].TexCoord[0] - p.Vertices[0].TexCoord[0],
                                p.Vertices[2].TexCoord[1] - p.Vertices[0].TexCoord[1]
                            };

                            var d = A0[0] * B0[1] - A0[1] * B0[0];
                            seq.Frames[j].Mat[0 + 0 * 2] = (A[0] * B0[1] - A0[1] * B[0]) / d;
                            seq.Frames[j].Mat[1 + 0 * 2] = -(A[1] * B0[1] - A0[1] * B[1]) / d;
                            seq.Frames[j].Mat[0 + 1 * 2] = -(A0[0] * B[0] - A[0] * B0[0]) / d;
                            seq.Frames[j].Mat[1 + 1 * 2] = (A0[0] * B[1] - A[1] * B0[0]) / d;

                            seq.Frames[j].Move[0] = p.Vertices[0].TexCoord[0] -
                                                    (p0.Vertices[0].TexCoord[0] * seq.Frames[j].Mat[0 + 0 * 2] +
                                                     p0.Vertices[0].TexCoord[1] * seq.Frames[j].Mat[0 + 1 * 2]);
                            seq.Frames[j].Move[1] = p.Vertices[0].TexCoord[1] -
                                                    (p0.Vertices[0].TexCoord[0] * seq.Frames[j].Mat[1 + 0 * 2] +
                                                     p0.Vertices[0].TexCoord[1] * seq.Frames[j].Mat[1 + 1 * 2]);
                        }
                    }
                    else
                    {
                        EngineWorld.TextureAtlas.GetCoordinates(seq.FrameList[0], false, p0);
                        for (var j = 0; j < seq.Frames.Count; j++)
                        {
                            EngineWorld.TextureAtlas.GetCoordinates(seq.FrameList[j], false, p);
                            seq.Frames[j].TextureIndex = p.TexIndex;

                            var A0 = new[]
                            {
                                p0.Vertices[1].TexCoord[0] - p0.Vertices[0].TexCoord[0],
                                p0.Vertices[1].TexCoord[1] - p0.Vertices[0].TexCoord[1]
                            };
                            var B0 = new[]
                            {
                                p0.Vertices[2].TexCoord[0] - p0.Vertices[0].TexCoord[0],
                                p0.Vertices[2].TexCoord[1] - p0.Vertices[0].TexCoord[1]
                            };

                            var A = new[]
                            {
                                p.Vertices[1].TexCoord[0] - p.Vertices[0].TexCoord[0],
                                p.Vertices[1].TexCoord[1] - p.Vertices[0].TexCoord[1]
                            };
                            var B = new[]
                            {
                                p.Vertices[2].TexCoord[0] - p.Vertices[0].TexCoord[0],
                                p.Vertices[2].TexCoord[1] - p.Vertices[0].TexCoord[1]
                            };

                            var d = A0[0] * B0[1] - A0[1] * B0[0];
                            seq.Frames[j].Mat[0 + 0 * 2] = (A[0] * B0[1] - A0[1] * B[0]) / d;
                            seq.Frames[j].Mat[1 + 0 * 2] = -(A[1] * B0[1] - A0[1] * B[1]) / d;
                            seq.Frames[j].Mat[0 + 1 * 2] = -(A0[0] * B[0] - A[0] * B0[0]) / d;
                            seq.Frames[j].Mat[1 + 1 * 2] = (A0[0] * B[1] - A[1] * B0[0]) / d;

                            seq.Frames[j].Move[0] = p.Vertices[0].TexCoord[0] -
                                                    (p0.Vertices[0].TexCoord[0] * seq.Frames[j].Mat[0 + 0 * 2] +
                                                     p0.Vertices[0].TexCoord[1] * seq.Frames[j].Mat[0 + 1 * 2]);
                            seq.Frames[j].Move[1] = p.Vertices[0].TexCoord[1] -
                                                    (p0.Vertices[0].TexCoord[0] * seq.Frames[j].Mat[1 + 0 * 2] +
                                                     p0.Vertices[0].TexCoord[1] * seq.Frames[j].Mat[1 + 1 * 2]);
                        }
                    }
                }
            }
        }