Example #1
0
        //mxd. Normals calculation algorithm taken from OpenGl wiki
        private void CalculateNormals()
        {
            if (triangles == 0)
            {
                return;
            }

            BoundingBoxSizes bbs = new BoundingBoxSizes(vertices[0]);

            for (int i = 0; i < triangles; i++)
            {
                int         startindex = i * 3;
                WorldVertex p1         = vertices[startindex];
                WorldVertex p2         = vertices[startindex + 1];
                WorldVertex p3         = vertices[startindex + 2];

                Vector3f U = new Vector3f(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z);
                Vector3f V = new Vector3f(p3.x - p1.x, p3.y - p1.y, p3.z - p1.z);

                p1.nx = p2.nx = p3.nx = -(U.Y * V.Z - U.Z * V.Y);
                p1.ny = p2.ny = p3.ny = -(U.Z * V.X - U.X * V.Z);
                p1.nz = p2.nz = p3.nz = -(U.X * V.Y - U.Y * V.X);

                vertices[startindex]     = p1;
                vertices[startindex + 1] = p2;
                vertices[startindex + 2] = p3;

                BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, p1);
                BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, p2);
                BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, p3);
            }

            boundingBox = BoundingBoxTools.CalculateBoundingPlane(bbs);
        }
Example #2
0
        public static void UpdateBoundingBoxSizes(ref BoundingBoxSizes bbs, WorldVertex v)
        {
            if (v.x < bbs.MinX)
            {
                bbs.MinX = (int)v.x;
            }
            else if (v.x > bbs.MaxX)
            {
                bbs.MaxX = (int)v.x;
            }

            if (v.z < bbs.MinZ)
            {
                bbs.MinZ = (int)v.z;
            }
            else if (v.z > bbs.MaxZ)
            {
                bbs.MaxZ = (int)v.z;
            }

            if (v.y < bbs.MinY)
            {
                bbs.MinY = (int)v.y;
            }
            else if (v.y > bbs.MaxY)
            {
                bbs.MaxY = (int)v.y;
            }
        }
Example #3
0
        // Returns index of added vert
        private static int AddVertex(WorldVertex v, List <WorldVertex> verts, List <int> indices, Dictionary <long, int> hashes)
        {
            long hash;

            unchecked             // Overflow is fine, just wrap
            {
                hash = 2166136261;
                hash = (hash * 16777619) ^ v.x.GetHashCode();
                hash = (hash * 16777619) ^ v.y.GetHashCode();
                hash = (hash * 16777619) ^ v.z.GetHashCode();
                hash = (hash * 16777619) ^ v.u.GetHashCode();
                hash = (hash * 16777619) ^ v.v.GetHashCode();
            }

            if (hashes.ContainsKey(hash))
            {
                indices.Add(hashes[hash]);
                return(hashes[hash]);
            }
            else
            {
                verts.Add(v);
                hashes.Add(hash, verts.Count - 1);
                indices.Add(verts.Count - 1);
                return(verts.Count - 1);
            }
        }
Example #4
0
 public void WriteWorldVertex(WorldVertex v)
 {
     _stream.WriteFloat3(v.Position.XYZ);
     _stream.WriteFloat2(v.Texcoord);
     _stream.WriteFloat3(v.Normal);
     _stream.WriteFloat3(v.Tangent.XYZ);
     _stream.WriteFloat3(v.Binormal);
 }
Example #5
0
        // Shameless GZDoom rip-off
        private static void AddFace(List <WorldVertex> verts, List <int> indices, Dictionary <long, int> hashes, Vector3D v1, Vector3D v2, Vector3D v3, Vector3D v4, Vector3D pivot, int colorIndex)
        {
            float pu0 = (colorIndex % 16) / 16f;
            float pu1 = pu0 + 0.001f;
            float pv0 = (colorIndex / 16) / 16f;
            float pv1 = pv0 + 0.001f;

            WorldVertex wv1 = new WorldVertex
            {
                x = v1.x - pivot.x,
                y = -v1.y + pivot.y,
                z = -v1.z + pivot.z,
                c = -1,
                u = pu0,
                v = pv0
            };
            int i1 = AddVertex(wv1, verts, indices, hashes);

            WorldVertex wv2 = new WorldVertex
            {
                x = v2.x - pivot.x,
                y = -v2.y + pivot.y,
                z = -v2.z + pivot.z,
                c = -1,
                u = pu1,
                v = pv1
            };

            AddVertex(wv2, verts, indices, hashes);

            WorldVertex wv4 = new WorldVertex
            {
                x = v4.x - pivot.x,
                y = -v4.y + pivot.y,
                z = -v4.z + pivot.z,
                c = -1,
                u = pu0,
                v = pv0
            };
            int i4 = AddVertex(wv4, verts, indices, hashes);

            WorldVertex wv3 = new WorldVertex
            {
                x = v3.x - pivot.x,
                y = -v3.y + pivot.y,
                z = -v3.z + pivot.z,
                c = -1,
                u = pu1,
                v = pv1
            };

            AddVertex(wv3, verts, indices, hashes);

            indices.Add(i1);
            indices.Add(i4);
        }
Example #6
0
 // This swaps triangles so that the plane faces the other way
 protected static void SwapTriangleVertices(WorldVertex[] verts)
 {
     // Swap some vertices to flip all triangles
     for (int i = 0; i < verts.Length; i += 3)
     {
         // Swap
         WorldVertex v = verts[i];
         verts[i]     = verts[i + 1];
         verts[i + 1] = v;
     }
 }
Example #7
0
        // This builds the geometry. Returns false when no geometry created.
        public override bool Setup()
        {
            WorldVertex[] verts;
            Sector        s = base.Sector.Sector;
            int           brightness;

            // Load floor texture
            base.Texture = General.Map.Data.GetFlatImage(s.LongFloorTexture);
            if (base.Texture == null)
            {
                brightness           = mode.CalculateBrightness(256);
                base.Texture         = General.Map.Data.MissingTexture3D;
                setuponloadedtexture = s.LongFloorTexture;
            }
            else
            {
                brightness = mode.CalculateBrightness(s.Brightness);
                if (!base.Texture.IsImageLoaded)
                {
                    setuponloadedtexture = s.LongFloorTexture;
                }
            }

            // Make vertices
            verts = new WorldVertex[s.Triangles.Vertices.Count];
            for (int i = 0; i < s.Triangles.Vertices.Count; i++)
            {
                // Use sector brightness for color shading
                verts[i].c = brightness;

                // Grid aligned texture coordinates
                if (base.Texture.IsImageLoaded)
                {
                    verts[i].u = s.Triangles.Vertices[i].x / base.Texture.ScaledWidth;
                    verts[i].v = -s.Triangles.Vertices[i].y / base.Texture.ScaledHeight;
                }
                else
                {
                    verts[i].u = s.Triangles.Vertices[i].x / 64;
                    verts[i].v = -s.Triangles.Vertices[i].y / 64;
                }

                // Vertex coordinates
                verts[i].x = s.Triangles.Vertices[i].x;
                verts[i].y = s.Triangles.Vertices[i].y;
                verts[i].z = (float)s.FloorHeight;
            }

            // Apply vertices
            base.SetVertices(verts);
            return(verts.Length > 0);
        }
        // This builds the geometry. Returns false when no geometry created.
        public override bool Setup()
        {
            Sector s = base.Sector.Sector;

            // Load ceiling image
            Texture = General.Map.Data.GetImageData(s.CeilingTileIndex);
            if (Texture is UnknownImage)
            {
                // Use missing texture
                //Texture = General.Map.Data.MissingTexture3D;
                setuponloadedtexture = -1;
            }
            else if (!Texture.IsImageLoaded)
            {
                setuponloadedtexture = s.CeilingTileIndex;
            }

            // Make vertices
            WorldVertex[] verts = new WorldVertex[s.FloorVertices.Length];

            if (s.CeilingSloped)
            {
                for (int i = 0; i < s.CeilingVertices.Length; i++)
                {
                    var v = s.CeilingVertices[i];
                    verts[i] = new WorldVertex(v, s.CeilingPlane.GetZ(v.x, v.y));
                }
            }
            else
            {
                for (int i = 0; i < s.CeilingVertices.Length; i++)
                {
                    verts[i] = new WorldVertex(s.CeilingVertices[i], s.CeilingHeight);
                }
            }

            // The sector triangulation created clockwise triangles that
            // are right up for the floor. For the ceiling we must flip the triangles upside down.
            for (int i = 0; i < verts.Length; i += 3)
            {
                // Swap some vertices to flip the triangle
                WorldVertex v = verts[i];
                verts[i]     = verts[i + 1];
                verts[i + 1] = v;
            }

            // Apply vertices
            base.SetVertices(verts);
            return(verts.Length > 0);
        }
Example #9
0
        // This builds the geometry. Returns false when no geometry created.
        public override bool Setup()
        {
            Sector s = base.Sector.Sector;

            // Load floor image
            Texture = General.Map.Data.GetImageData(s.FloorTileIndex);
            if (Texture is UnknownImage)
            {
                // Use missing texture
                //Texture = General.Map.Data.MissingTexture3D;
                setuponloadedtexture = -1;
            }
            else if (!Texture.IsImageLoaded)
            {
                setuponloadedtexture = s.FloorTileIndex;
            }

            // Make vertices
            WorldVertex[] verts = new WorldVertex[s.FloorVertices.Length];

            if (s.FloorSloped)
            {
                for (int i = 0; i < s.FloorVertices.Length; i++)
                {
                    var v = s.FloorVertices[i];
                    verts[i] = new WorldVertex(v, s.FloorPlane.GetZ(v.x, v.y));
                }
            }
            else
            {
                for (int i = 0; i < s.FloorVertices.Length; i++)
                {
                    verts[i] = new WorldVertex(s.FloorVertices[i], s.FloorHeight);
                }
            }

            // Apply vertices
            base.SetVertices(verts);
            return(verts.Length > 0);
        }
Example #10
0
        public bool Setup(Effect3DFloor extrafloor)
        {
            Vector2D vl, vr;
            Sidedef  sourceside = extrafloor.Linedef.Front;

            this.extrafloor = extrafloor;

            int  lightvalue    = Sidedef.Fields.GetValue("light", 0);
            bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false);

            Vector2D tscale = new Vector2D(sourceside.Fields.GetValue("scalex_mid", 1.0f),
                                           sourceside.Fields.GetValue("scaley_mid", 1.0f));
            Vector2D toffset1 = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f),
                                             Sidedef.Fields.GetValue("offsety_mid", 0.0f));
            Vector2D toffset2 = new Vector2D(sourceside.Fields.GetValue("offsetx_mid", 0.0f),
                                             sourceside.Fields.GetValue("offsety_mid", 0.0f));

            // Left and right vertices for this sidedef
            if (Sidedef.IsFront)
            {
                vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
                vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
            }
            else
            {
                vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
                vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
            }

            // Load sector data
            SectorData sd = mode.GetSectorData(Sidedef.Sector);

            // Texture given?
            if ((sourceside.MiddleTexture.Length > 0) && (sourceside.MiddleTexture[0] != '-'))
            {
                // Load texture
                base.Texture = General.Map.Data.GetTextureImage(sourceside.LongMiddleTexture);
                if (base.Texture == null)
                {
                    base.Texture         = General.Map.Data.MissingTexture3D;
                    setuponloadedtexture = sourceside.LongMiddleTexture;
                }
                else
                {
                    if (!base.Texture.IsImageLoaded)
                    {
                        setuponloadedtexture = sourceside.LongMiddleTexture;
                    }
                }
            }
            else
            {
                // Use missing texture
                base.Texture         = General.Map.Data.MissingTexture3D;
                setuponloadedtexture = 0;
            }

            // Get texture scaled size
            Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);

            tsz = tsz / tscale;

            // Get texture offsets
            Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);

            tof = tof + toffset1 + toffset2;
            tof = tof / tscale;
            if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
            {
                tof = tof * base.Texture.Scale;
            }

            // For Vavoom type 3D floors the ceiling is lower than floor and they are reversed.
            // We choose here.
            float sourcetopheight    = extrafloor.VavoomType ? sourceside.Sector.FloorHeight : sourceside.Sector.CeilHeight;
            float sourcebottomheight = extrafloor.VavoomType ? sourceside.Sector.CeilHeight : sourceside.Sector.FloorHeight;

            // Determine texture coordinates plane as they would be in normal circumstances.
            // We can then use this plane to find any texture coordinate we need.
            // The logic here is the same as in the original VisualMiddleSingle (except that
            // the values are stored in a TexturePlane)
            // NOTE: I use a small bias for the floor height, because if the difference in
            // height is 0 then the TexturePlane doesn't work!
            TexturePlane tp        = new TexturePlane();
            float        floorbias = (sourcetopheight == sourcebottomheight) ? 1.0f : 0.0f;

            tp.trb.x = tp.tlt.x + Sidedef.Line.Length;
            tp.trb.y = tp.tlt.y + (sourcetopheight - sourcebottomheight) + floorbias;

            // Apply texture offset
            tp.tlt += tof;
            tp.trb += tof;

            // Transform pixel coordinates to texture coordinates
            tp.tlt /= tsz;
            tp.trb /= tsz;

            // Left top and right bottom of the geometry that
            tp.vlt = new Vector3D(vl.x, vl.y, sourcetopheight);
            tp.vrb = new Vector3D(vr.x, vr.y, sourcebottomheight + floorbias);

            // Make the right-top coordinates
            tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
            tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);

            // Get ceiling and floor heights
            float fl = sd.Floor.plane.GetZ(vl);
            float fr = sd.Floor.plane.GetZ(vr);
            float cl = sd.Ceiling.plane.GetZ(vl);
            float cr = sd.Ceiling.plane.GetZ(vr);

            // Anything to see?
            if (((cl - fl) > 0.01f) || ((cr - fr) > 0.01f))
            {
                // Keep top and bottom planes for intersection testing
                top    = extrafloor.Floor.plane;
                bottom = extrafloor.Ceiling.plane;

                // Create initial polygon, which is just a quad between floor and ceiling
                WallPolygon poly = new WallPolygon();
                poly.Add(new Vector3D(vl.x, vl.y, fl));
                poly.Add(new Vector3D(vl.x, vl.y, cl));
                poly.Add(new Vector3D(vr.x, vr.y, cr));
                poly.Add(new Vector3D(vr.x, vr.y, fr));

                // Determine initial color
                int        lightlevel     = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
                PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
                PixelColor wallcolor      = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
                poly.color = wallcolor.WithAlpha(255).ToInt();

                // Cut off the part above the 3D floor and below the 3D ceiling
                CropPoly(ref poly, extrafloor.Floor.plane, false);
                CropPoly(ref poly, extrafloor.Ceiling.plane, false);

                // Cut out pieces that overlap 3D floors in this sector
                List <WallPolygon> polygons = new List <WallPolygon>(1);
                polygons.Add(poly);
                foreach (Effect3DFloor ef in sd.ExtraFloors)
                {
                    // Same 3D floor and other floors that are not translucent will clip my walls
                    if ((ef.Alpha == 255) || (ef.Linedef.Front.Sector == extrafloor.Linedef.Front.Sector))
                    {
                        int num = polygons.Count;
                        for (int pi = 0; pi < num; pi++)
                        {
                            // Split by floor plane of 3D floor
                            WallPolygon p  = polygons[pi];
                            WallPolygon np = SplitPoly(ref p, ef.Ceiling.plane, true);

                            if (np.Count > 0)
                            {
                                // Split part below floor by the ceiling plane of 3D floor
                                // and keep only the part below the ceiling (front)
                                SplitPoly(ref np, ef.Floor.plane, true);

                                if (p.Count == 0)
                                {
                                    polygons[pi] = np;
                                }
                                else
                                {
                                    polygons[pi] = p;
                                    polygons.Add(np);
                                }
                            }
                            else
                            {
                                polygons[pi] = p;
                            }
                        }
                    }
                }

                // Process the polygon and create vertices
                List <WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);
                if (verts.Count > 0)
                {
                    if (extrafloor.Alpha < 255)
                    {
                        // Apply alpha to vertices
                        byte alpha = (byte)General.Clamp(extrafloor.Alpha, 0, 255);
                        if (alpha < 255)
                        {
                            for (int i = 0; i < verts.Count; i++)
                            {
                                WorldVertex v = verts[i];
                                PixelColor  c = PixelColor.FromInt(v.c);
                                v.c      = c.WithAlpha(alpha).ToInt();
                                verts[i] = v;
                            }
                        }

                        this.RenderPass = RenderPass.Alpha;
                    }
                    else
                    {
                        this.RenderPass = RenderPass.Mask;
                    }

                    base.SetVertices(verts);
                    return(true);
                }
            }

            return(false);
        }
Example #11
0
        // This builds the geometry. Returns false when no geometry created.
        public override bool Setup(SectorLevel level, Effect3DFloor extrafloor)
        {
            WorldVertex[] verts;
            Sector        s = level.sector;
            Vector2D      texscale;

            base.Setup(level, extrafloor);

            // Fetch ZDoom fields
            float    rotate = Angle2D.DegToRad(s.Fields.GetValue("rotationceiling", 0.0f));
            Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningceiling", 0.0f),
                                           s.Fields.GetValue("ypanningceiling", 0.0f));
            Vector2D scale = new Vector2D(s.Fields.GetValue("xscaleceiling", 1.0f),
                                          s.Fields.GetValue("yscaleceiling", 1.0f));

            // Load floor texture
            base.Texture = General.Map.Data.GetFlatImage(s.LongCeilTexture);
            if (base.Texture == null)
            {
                base.Texture         = General.Map.Data.MissingTexture3D;
                setuponloadedtexture = s.LongCeilTexture;
            }
            else
            {
                if (!base.Texture.IsImageLoaded)
                {
                    setuponloadedtexture = s.LongCeilTexture;
                }
            }

            // Determine texture scale
            if (base.Texture.IsImageLoaded)
            {
                texscale = new Vector2D(1.0f / base.Texture.ScaledWidth, 1.0f / base.Texture.ScaledHeight);
            }
            else
            {
                texscale = new Vector2D(1.0f / 64.0f, 1.0f / 64.0f);
            }

            // Make vertices
            ReadOnlyCollection <Vector2D> triverts = base.Sector.Sector.Triangles.Vertices;

            verts = new WorldVertex[triverts.Count];
            for (int i = 0; i < triverts.Count; i++)
            {
                // Color shading
                PixelColor c = PixelColor.FromInt(level.color);
                verts[i].c = c.WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt();

                // Vertex coordinates
                verts[i].x = triverts[i].x;
                verts[i].y = triverts[i].y;
                verts[i].z = level.plane.GetZ(triverts[i]);                 //(float)s.CeilHeight;

                // Texture coordinates
                Vector2D pos = triverts[i];
                pos        = pos.GetRotated(rotate);
                pos.y      = -pos.y;
                pos        = (pos + offset) * scale * texscale;
                verts[i].u = pos.x;
                verts[i].v = pos.y;
            }

            // The sector triangulation created clockwise triangles that
            // are right up for the floor. For the ceiling we must flip
            // the triangles upside down.
            if ((extrafloor == null) || extrafloor.VavoomType)
            {
                SwapTriangleVertices(verts);
            }

            // Determine render pass
            if (extrafloor != null)
            {
                if (level.alpha < 255)
                {
                    this.RenderPass = RenderPass.Alpha;
                }
                else
                {
                    this.RenderPass = RenderPass.Mask;
                }
            }
            else
            {
                this.RenderPass = RenderPass.Solid;
            }

            // Apply vertices
            base.SetVertices(verts);
            return(verts.Length > 0);
        }
Example #12
0
 public void WriteWorldVertex(WorldVertex v)
 {
     _stream.WriteFloat4(v.Position);
     _stream.WriteFloat2(v.Texcoord);
     _stream.WriteUByte4N(v.Tangent);
 }
        public bool Setup(Effect3DFloor extrafloor)
        {
            Sidedef sourceside = extrafloor.Linedef.Front;

            this.extrafloor = extrafloor;

            //mxd. Extrafloor may've become invalid during undo/redo...
            if (sourceside == null)
            {
                base.SetVertices(null);
                return(false);
            }

            Vector2D vl, vr;

            //mxd. lightfog flag support
            int  lightvalue;
            bool lightabsolute;

            GetLightValue(out lightvalue, out lightabsolute);

            Vector2D tscale = new Vector2D(sourceside.Fields.GetValue("scalex_mid", 1.0f),
                                           sourceside.Fields.GetValue("scaley_mid", 1.0f));
            Vector2D tscaleAbs = new Vector2D(Math.Abs(tscale.x), Math.Abs(tscale.y));
            Vector2D toffset1  = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f),
                                              Sidedef.Fields.GetValue("offsety_mid", 0.0f));
            Vector2D toffset2 = new Vector2D(sourceside.Fields.GetValue("offsetx_mid", 0.0f),
                                             sourceside.Fields.GetValue("offsety_mid", 0.0f));

            // Left and right vertices for this sidedef
            if (Sidedef.IsFront)
            {
                vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
                vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
            }
            else
            {
                vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
                vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
            }

            // Load sector data
            SectorData sd = mode.GetSectorData(Sidedef.Sector);

            //mxd. which texture we must use?
            long texturelong = 0;

            if ((sourceside.Line.Args[2] & (int)Effect3DFloor.Flags.UseUpperTexture) != 0)
            {
                if (Sidedef.LongHighTexture != MapSet.EmptyLongName)
                {
                    texturelong = Sidedef.LongHighTexture;
                }
            }
            else if ((sourceside.Line.Args[2] & (int)Effect3DFloor.Flags.UseLowerTexture) != 0)
            {
                if (Sidedef.LongLowTexture != MapSet.EmptyLongName)
                {
                    texturelong = Sidedef.LongLowTexture;
                }
            }
            else if (sourceside.LongMiddleTexture != MapSet.EmptyLongName)
            {
                texturelong = sourceside.LongMiddleTexture;
            }

            // Texture given?
            if (texturelong != 0)
            {
                // Load texture
                base.Texture = General.Map.Data.GetTextureImage(texturelong);
                if (base.Texture == null || base.Texture is UnknownImage)
                {
                    base.Texture         = General.Map.Data.UnknownTexture3D;
                    setuponloadedtexture = texturelong;
                }
                else if (!base.Texture.IsImageLoaded)
                {
                    setuponloadedtexture = texturelong;
                }
            }
            else
            {
                // Use missing texture
                base.Texture         = General.Map.Data.MissingTexture3D;
                setuponloadedtexture = 0;
            }

            // Get texture scaled size
            Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);

            tsz = tsz / tscale;

            // Get texture offsets
            Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY) + new Vector2D(sourceside.OffsetX, sourceside.OffsetY);

            tof = tof + toffset1 + toffset2;
            tof = tof / tscaleAbs;
            if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
            {
                tof = tof * base.Texture.Scale;
            }

            // For Vavoom type 3D floors the ceiling is lower than floor and they are reversed.
            // We choose here.
            float sourcetopheight    = extrafloor.VavoomType ? sourceside.Sector.FloorHeight : sourceside.Sector.CeilHeight;
            float sourcebottomheight = extrafloor.VavoomType ? sourceside.Sector.CeilHeight : sourceside.Sector.FloorHeight;

            // Determine texture coordinates plane as they would be in normal circumstances.
            // We can then use this plane to find any texture coordinate we need.
            // The logic here is the same as in the original VisualMiddleSingle (except that
            // the values are stored in a TexturePlane)
            // NOTE: I use a small bias for the floor height, because if the difference in
            // height is 0 then the TexturePlane doesn't work!
            TexturePlane tp        = new TexturePlane();
            float        floorbias = (sourcetopheight == sourcebottomheight) ? 1.0f : 0.0f;

            tp.trb.x = tp.tlt.x + (float)Math.Round(Sidedef.Line.Length);             //mxd. (G)ZDoom snaps texture coordinates to integral linedef length
            tp.trb.y = tp.tlt.y + (sourcetopheight - sourcebottomheight) + floorbias;

            // Apply texture offset
            tp.tlt += tof;
            tp.trb += tof;

            // Transform pixel coordinates to texture coordinates
            tp.tlt /= tsz;
            tp.trb /= tsz;

            // Left top and right bottom of the geometry that
            tp.vlt = new Vector3D(vl.x, vl.y, sourcetopheight);
            tp.vrb = new Vector3D(vr.x, vr.y, sourcebottomheight + floorbias);

            // Make the right-top coordinates
            tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
            tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);

            //mxd. Get ceiling and floor heights. Use our and neighbour sector's data
            SectorData sdo = mode.GetSectorData(Sidedef.Other.Sector);

            float flo = sdo.Floor.plane.GetZ(vl);
            float fro = sdo.Floor.plane.GetZ(vr);
            float clo = sdo.Ceiling.plane.GetZ(vl);
            float cro = sdo.Ceiling.plane.GetZ(vr);

            float fle = sd.Floor.plane.GetZ(vl);
            float fre = sd.Floor.plane.GetZ(vr);
            float cle = sd.Ceiling.plane.GetZ(vl);
            float cre = sd.Ceiling.plane.GetZ(vr);

            float fl = flo > fle ? flo : fle;
            float fr = fro > fre ? fro : fre;
            float cl = clo < cle ? clo : cle;
            float cr = cro < cre ? cro : cre;

            // Anything to see?
            if (((cl - fl) > 0.01f) || ((cr - fr) > 0.01f))
            {
                // Keep top and bottom planes for intersection testing
                top    = extrafloor.Floor.plane;
                bottom = extrafloor.Ceiling.plane;

                // Create initial polygon, which is just a quad between floor and ceiling
                WallPolygon poly = new WallPolygon();
                poly.Add(new Vector3D(vl.x, vl.y, fl));
                poly.Add(new Vector3D(vl.x, vl.y, cl));
                poly.Add(new Vector3D(vr.x, vr.y, cr));
                poly.Add(new Vector3D(vr.x, vr.y, fr));

                // Determine initial color
                int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;

                //mxd. This calculates light with doom-style wall shading
                PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
                PixelColor wallcolor      = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
                fogfactor  = CalculateFogFactor(lightlevel);
                poly.color = wallcolor.WithAlpha(255).ToInt();

                // Cut off the part above the 3D floor and below the 3D ceiling
                CropPoly(ref poly, extrafloor.Floor.plane, false);
                CropPoly(ref poly, extrafloor.Ceiling.plane, false);

                // Cut out pieces that overlap 3D floors in this sector
                List <WallPolygon> polygons = new List <WallPolygon> {
                    poly
                };
                bool translucent = (extrafloor.RenderAdditive || extrafloor.Alpha < 255);
                foreach (Effect3DFloor ef in sd.ExtraFloors)
                {
                    //mxd. Our poly should be clipped when our ond other extrafloors are both solid or both translucent,
                    // or when only our extrafloor is translucent.
                    // Our poly should not be clipped when our extrafloor is translucent and the other one isn't and both have renderinside setting.
                    bool othertranslucent = (ef.RenderAdditive || ef.Alpha < 255);
                    if (translucent && !othertranslucent && !ef.ClipSidedefs)
                    {
                        continue;
                    }
                    if (ef.ClipSidedefs == extrafloor.ClipSidedefs || ef.ClipSidedefs)
                    {
                        //TODO: find out why ef can be not updated at this point
                        //TODO: [this crashed on me once when performing auto-align on myriad of textures on BoA C1M0]
                        if (ef.Floor == null || ef.Ceiling == null)
                        {
                            ef.Update();
                        }

                        int num = polygons.Count;
                        for (int pi = 0; pi < num; pi++)
                        {
                            // Split by floor plane of 3D floor
                            WallPolygon p  = polygons[pi];
                            WallPolygon np = SplitPoly(ref p, ef.Ceiling.plane, true);

                            if (np.Count > 0)
                            {
                                // Split part below floor by the ceiling plane of 3D floor
                                // and keep only the part below the ceiling (front)
                                SplitPoly(ref np, ef.Floor.plane, true);

                                if (p.Count == 0)
                                {
                                    polygons[pi] = np;
                                }
                                else
                                {
                                    polygons[pi] = p;
                                    polygons.Add(np);
                                }
                            }
                            else
                            {
                                polygons[pi] = p;
                            }
                        }
                    }
                }

                // Process the polygon and create vertices
                if (polygons.Count > 0)
                {
                    List <WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);
                    if (verts.Count > 2)
                    {
                        if (extrafloor.Sloped3dFloor)
                        {
                            this.RenderPass = RenderPass.Mask;                                                   //mxd
                        }
                        else if (extrafloor.RenderAdditive)
                        {
                            this.RenderPass = RenderPass.Additive;                                                         //mxd
                        }
                        else if ((extrafloor.Alpha < 255) || Texture.IsTranslucent)
                        {
                            this.RenderPass = RenderPass.Alpha;                                                                                 // [ZZ] translucent texture should trigger Alpha pass
                        }
                        else
                        {
                            this.RenderPass = RenderPass.Mask;
                        }

                        if (extrafloor.Alpha < 255)
                        {
                            // Apply alpha to vertices
                            byte alpha = (byte)General.Clamp(extrafloor.Alpha, 0, 255);
                            if (alpha < 255)
                            {
                                for (int i = 0; i < verts.Count; i++)
                                {
                                    WorldVertex v = verts[i];
                                    v.c      = PixelColor.FromInt(v.c).WithAlpha(alpha).ToInt();
                                    verts[i] = v;
                                }
                            }
                        }

                        base.SetVertices(verts);
                        return(true);
                    }
                }
            }

            base.SetVertices(null);             //mxd
            return(false);
        }
Example #14
0
        //mxd
        public bool Setup(SectorLevel level, Effect3DFloor extrafloor, bool innerside)
        {
            Sector   s = level.sector;
            Vector2D texscale;

            this.innerside = innerside;             //mxd

            base.Setup(level, extrafloor);

            // Fetch ZDoom fields
            float    rotate = Angle2D.DegToRad(s.Fields.GetValue("rotationceiling", 0.0f));
            Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningceiling", 0.0f),
                                           s.Fields.GetValue("ypanningceiling", 0.0f));
            Vector2D scale = new Vector2D(s.Fields.GetValue("xscaleceiling", 1.0f),
                                          s.Fields.GetValue("yscaleceiling", 1.0f));

            //Load ceiling texture
            if (s.LongCeilTexture != MapSet.EmptyLongName)
            {
                base.Texture = General.Map.Data.GetFlatImage(s.LongCeilTexture);
                if (base.Texture == null || base.Texture is UnknownImage)
                {
                    base.Texture         = General.Map.Data.UnknownTexture3D;
                    setuponloadedtexture = s.LongCeilTexture;
                }
                else if (!base.Texture.IsImageLoaded)
                {
                    setuponloadedtexture = s.LongCeilTexture;
                }
            }
            else
            {
                // Use missing texture
                base.Texture         = General.Map.Data.MissingTexture3D;
                setuponloadedtexture = 0;
            }

            // Determine texture scale
            if (base.Texture.IsImageLoaded)
            {
                texscale = new Vector2D(1.0f / base.Texture.ScaledWidth, 1.0f / base.Texture.ScaledHeight);
            }
            else
            {
                texscale = new Vector2D(1.0f / 64.0f, 1.0f / 64.0f);
            }

            // Determine brightness
            byte alpha = (byte)General.Clamp(level.alpha, 0, 255);
            int  color = PixelColor.FromInt(level.color).WithAlpha(alpha).ToInt();
            int  targetbrightness;

            if (extrafloor != null && !extrafloor.VavoomType && !level.disablelighting)
            {
                //mxd. Top extrafloor level should calculate fogdensity from the brightness of the level above it
                if (!innerside)
                {
                    targetbrightness = 0;
                    SectorData sd = mode.GetSectorData(this.Sector.Sector);
                    for (int i = 0; i < sd.LightLevels.Count - 1; i++)
                    {
                        if (sd.LightLevels[i] == level)
                        {
                            targetbrightness = sd.LightLevels[i + 1].brightnessbelow;
                            break;
                        }
                    }
                }
                //mxd. Inner extrafloor ceilings must be colored using control sector's color and brightness
                else
                {
                    targetbrightness = level.brightnessbelow;
                    SectorData sd = mode.GetSectorData(this.Sector.Sector);
                    for (int i = 0; i < sd.LightLevels.Count; i++)
                    {
                        if (sd.LightLevels[i] == level)
                        {
                            if (i > 0)
                            {
                                color = PixelColor.FromInt(sd.LightLevels[i - 1].color).WithAlpha(alpha).ToInt();
                            }
                            break;
                        }
                    }
                }
            }
            else
            {
                targetbrightness = level.brightnessbelow;
            }

            //mxd. Determine fog density
            fogfactor = CalculateFogFactor(targetbrightness);

            // Make vertices
            ReadOnlyCollection <Vector2D> triverts = Sector.Sector.Triangles.Vertices;

            WorldVertex[] verts = new WorldVertex[triverts.Count];
            for (int i = 0; i < triverts.Count; i++)
            {
                // Color shading
                verts[i].c = color;                 //mxd

                // Vertex coordinates
                verts[i].x = triverts[i].x;
                verts[i].y = triverts[i].y;
                verts[i].z = level.plane.GetZ(triverts[i]);

                // Texture coordinates
                Vector2D pos = triverts[i];
                pos        = pos.GetRotated(rotate);
                pos.y      = -pos.y;
                pos        = (pos + offset) * scale * texscale;
                verts[i].u = pos.x;
                verts[i].v = pos.y;
            }

            // The sector triangulation created clockwise triangles that
            // are right up for the floor. For the ceiling we must flip
            // the triangles upside down.
            if (extrafloor == null || extrafloor.VavoomType || innerside)
            {
                SwapTriangleVertices(verts);
            }

            // Determine render pass
            if (extrafloor != null)
            {
                if (extrafloor.Sloped3dFloor)                //mxd
                {
                    this.RenderPass = RenderPass.Mask;
                }
                else if (extrafloor.RenderAdditive)                //mxd
                {
                    this.RenderPass = RenderPass.Additive;
                }
                else if (level.alpha < 255)
                {
                    this.RenderPass = RenderPass.Alpha;
                }
                else
                {
                    this.RenderPass = RenderPass.Mask;
                }
            }
            else
            {
                this.RenderPass = RenderPass.Solid;
            }

            //mxd. Update sky render flag
            bool isrenderedassky = renderassky;

            renderassky = (level.sector.CeilTexture == General.Map.Config.SkyFlatName);
            if (isrenderedassky != renderassky && Sector.Sides != null)
            {
                // Upper sidedef geometry may need updating...
                foreach (Sidedef side in level.sector.Sidedefs)
                {
                    VisualSidedefParts parts = Sector.GetSidedefParts(side);

                    // Upper side can exist in either our, or the neightbouring sector, right?
                    if (parts.upper != null && parts.upper.Triangles > 0)
                    {
                        parts.upper.UpdateSkyRenderFlag();
                    }
                    else if (side.Other != null && side.Other.Sector != null && side.Other.Sector.CeilTexture == General.Map.Config.SkyFlatName)
                    {
                        // Update upper side of the neightbouring sector
                        BaseVisualSector other = (BaseVisualSector)mode.GetVisualSector(side.Other.Sector);
                        if (other != null && other.Sides != null)
                        {
                            parts = other.GetSidedefParts(side.Other);
                            if (parts.upper != null && parts.upper.Triangles > 0)
                            {
                                parts.upper.UpdateSkyRenderFlag();
                            }
                        }
                    }
                }
            }

            // Apply vertices
            base.SetVertices(verts);
            return(verts.Length > 0);
        }
Example #15
0
        // This builds the thing geometry. Returns false when nothing was created.
        public bool Setup()
        {
            // Find the sector in which the thing resides
            Thing.DetermineSector(mode.BlockMap);

            //mxd. If the thing is inside a sector, apply DECORATE/UDMF alpha/renderstyle overrides
            byte alpha = 255;

            if (Thing.Sector != null)
            {
                string renderstyle = info.RenderStyle.ToLowerInvariant();
                alpha = info.AlphaByte;

                if (General.Map.UDMF)
                {
                    if (Thing.IsFlagSet("translucent"))
                    {
                        renderstyle = "translucent";
                        alpha       = 64;
                    }
                    else if (Thing.IsFlagSet("invisible"))
                    {
                        renderstyle = "none";
                        alpha       = 0;
                    }
                    else if (Thing.Fields.ContainsKey("renderstyle"))
                    {
                        renderstyle = Thing.Fields.GetValue("renderstyle", renderstyle).ToLowerInvariant();
                    }

                    if ((renderstyle == "add" || renderstyle == "translucent" || renderstyle == "subtract" || renderstyle == "translucentstencil") &&
                        Thing.Fields.ContainsKey("alpha"))
                    {
                        alpha = (byte)(General.Clamp(Thing.Fields.GetValue("alpha", info.Alpha), 0.0, 1.0) * 255.0);
                    }
                    else if (renderstyle == "soultrans")
                    {
                        // Lost Soul trasparency is controlled by a CVAR (see https://zdoom.org/wiki/CVARs:Display#transsouls), let's use the default 0.75 here
                        alpha = 192;
                    }
                    else if (renderstyle == "shadow")
                    {
                        alpha        = 76;                  // about 0.3
                        stencilColor = PixelColor.FromInt(PixelColor.INT_BLACK);
                    }

                    if (renderstyle.EndsWith("stencil"))
                    {
                        stencilColor   = PixelColor.FromInt(UniFields.GetInteger(Thing.Fields, "fillcolor", 0));
                        stencilColor.a = 255; // 0xFF alpha means nothing was read. 0x00 alpha means there was a valid fillcolor.
                    }
                    else if (renderstyle != "shadow")
                    {
                        stencilColor.a = 0;
                    }
                }
                else if (General.Map.HEXEN)
                {
                    if (Thing.IsFlagSet("2048"))
                    {
                        renderstyle = "translucent";
                        alpha       = 64;
                    }
                    else if (Thing.IsFlagSet("4096"))
                    {
                        renderstyle = "none";
                        alpha       = 0;
                    }
                }

                // Set appropriate RenderPass
                switch (renderstyle)
                {
                case "translucent":
                case "subtract":
                case "soultrans":
                case "translucentstencil":
                case "shadow":
                    RenderPass = RenderPass.Alpha;
                    break;

                case "add":
                case "addstencil":
                    RenderPass = RenderPass.Additive;
                    break;

                case "none":
                    RenderPass = RenderPass.Mask;
                    alpha      = 0;
                    break;

                // Many render styles are not supported yet...
                default:
                    RenderPass = RenderPass.Mask;
                    alpha      = 255;
                    break;
                }
            }

            int sectorcolor = new PixelColor(alpha, 255, 255, 255).ToInt();

            fogfactor = 0f;             //mxd

            //mxd. Check thing size
            float thingradius = Thing.Size;         // Thing.Size has ThingRadius arg override applied

            thingheight = Thing.Height;             // Thing.Height has ThingHeight arg override applied

            if (thingradius < 0.1f || thingheight < 0.1f)
            {
                thingradius = FIXED_RADIUS;
                thingheight = FIXED_RADIUS;
                sizeless    = true;
            }
            else
            {
                sizeless = false;
            }

            if (Thing.Sector != null)
            {
                SectorData sd    = mode.GetSectorData(Thing.Sector);
                Plane      floor = sd.Floor.plane;            //mxd

                if (!info.Bright)
                {
                    Vector3D    thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position));
                    SectorLevel level    = sd.GetLevelAboveOrAt(thingpos);

                    //mxd. Let's use point on floor plane instead of Thing.Sector.FloorHeight;
                    if (nointeraction && level == null && sd.LightLevels.Count > 0)
                    {
                        level = sd.LightLevels[sd.LightLevels.Count - 1];
                    }

                    //mxd. Use the light level of the highest surface when a thing is above highest sector level.
                    if (level != null)
                    {
                        // TECH: In GZDoom, ceiling glow doesn't affect thing brightness
                        // Use sector brightness for color shading
                        int brightness = level.brightnessbelow;

                        //mxd. Apply lightfloor value
                        // According to Graf, this is incorrect behaviour...
                        // TECH: In (G)ZDoom, this is ignored when ceiling texture is sky or a thing is below a 3D floor
                        // It's probably more involved than this, but for now let's do it only when there are no 3d floors in Thing.Sector...

                        /*if(General.Map.UDMF && sd.LightLevels.Count == 2 && Thing.Sector.CeilTexture != General.Map.Config.SkyFlatName)
                         * {
                         *      if(sd.Sector.Fields.GetValue("lightfloorabsolute", false))
                         *              brightness = UniFields.GetInteger(sd.Sector.Fields, "lightfloor");
                         *      else
                         *              brightness += UniFields.GetInteger(sd.Sector.Fields, "lightfloor");
                         * }*/

                        // Level is glowing
                        if (level.affectedbyglow && level.type == SectorLevelType.Floor)
                        {
                            // Extrafloor glow doesn't affect thing brightness
                            if (level.sector == Thing.Sector)
                            {
                                double planez = level.plane.GetZ(thingpos);

                                // Get glow brightness
                                int         glowbrightness = sd.FloorGlow.Brightness / 2;
                                SectorLevel nexthigher     = sd.GetLevelAbove(new Vector3D(thingpos, planez));

                                // Interpolate thing brightness between glow and regular ones
                                if (nexthigher != null)
                                {
                                    double higherz = nexthigher.plane.GetZ(thingpos);
                                    double delta   = General.Clamp(1.0f - (thingpos.z - planez) / (higherz - planez), 0f, 1f);
                                    brightness = (int)((glowbrightness + level.sector.Brightness / 2) * delta + nexthigher.sector.Brightness * (1.0f - delta));
                                }
                            }
                        }
                        // Level below this one is glowing. Only possible for floor glow(?)
                        else if (level.type == SectorLevelType.Glow)
                        {
                            // Interpolate thing brightness between glow and regular ones
                            if (sd.Floor != null && sd.FloorGlow != null)
                            {
                                // Get glow brightness
                                double glowz  = level.plane.GetZ(thingpos);
                                double floorz = floor.GetZ(thingpos);
                                double delta  = General.Clamp((thingpos.z - floorz) / (glowz - floorz), 0f, 1f);

                                brightness = (int)((sd.FloorGlow.Brightness / 2 + sd.Floor.sector.Brightness / 2) * (1.0f - delta) + sd.Floor.sector.Brightness * delta);
                            }
                        }

                        PixelColor areabrightness = PixelColor.FromInt(mode.CalculateBrightness(brightness));
                        PixelColor areacolor      = PixelColor.Modulate(level.colorbelow, areabrightness);

                        // [ZZ] if sector is using Doom64 lighting, apply thing color here.
                        sectorcolor = PixelColor.Modulate(sd.ColorSprites, areacolor).WithAlpha(alpha).ToInt();

                        //mxd. Calculate fogfactor
                        fogfactor = VisualGeometry.CalculateFogFactor(level.sector, brightness);
                    }
                }
                //TECH: even Bright Thing frames are affected by custom fade...
                else
                {
                    Vector3D    thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position));
                    SectorLevel level    = sd.GetLevelAboveOrAt(thingpos);

                    if (level != null && level.sector.FogMode > SectorFogMode.CLASSIC)
                    {
                        //mxd. Calculate fogfactor
                        fogfactor = VisualGeometry.CalculateFogFactor(level.sector, level.brightnessbelow);
                    }
                }
            }

            //mxd. Create verts for all sprite angles
            WorldVertex[][] allverts   = new WorldVertex[info.SpriteFrame.Length][];
            Vector2D[]      alloffsets = new Vector2D[info.SpriteFrame.Length];
            base.textures = new ImageData[info.SpriteFrame.Length];
            isloaded      = true;

            for (int i = 0; i < sprites.Length; i++)
            {
                Vector2D offsets = new Vector2D();

                // Check if the texture is loaded
                ImageData sprite = sprites[i];
                if (!sprite.IsImageLoaded && !sprite.LoadFailed)
                {
                    sprite.LoadImageNow();
                }
                if (sprite.IsImageLoaded)
                {
                    base.textures[i] = sprite;

                    // Determine sprite size and offset
                    float        radius    = sprite.ScaledWidth * 0.5f;
                    float        height    = sprite.ScaledHeight;
                    ISpriteImage spriteimg = sprite as ISpriteImage;
                    if (spriteimg != null)
                    {
                        offsets.x = radius - spriteimg.OffsetX;
                        offsets.y = spriteimg.OffsetY - height;
                    }

                    // Scale by thing type/actor scale
                    // We do this after the offset x/y determination above, because that is entirely in sprite pixels space
                    radius    *= info.SpriteScale.Width;
                    height    *= info.SpriteScale.Height;
                    offsets.x *= info.SpriteScale.Width;
                    offsets.y *= info.SpriteScale.Height;

                    // Make vertices
                    WorldVertex[] verts = new WorldVertex[6];

                    //mxd. Sprite mirroring
                    float ul = (info.SpriteFrame[i].Mirror ? 1f : 0f);
                    float ur = (info.SpriteFrame[i].Mirror ? 0f : 1f);

                    if (sizeless)                    //mxd
                    {
                        float hh = height / 2;
                        verts[0] = new WorldVertex((float)(-radius + offsets.x), 0.0f, (float)(offsets.y - hh), sectorcolor, ul, 1.0f);
                        verts[1] = new WorldVertex((float)(-radius + offsets.x), 0.0f, (float)(hh + offsets.y), sectorcolor, ul, 0.0f);
                        verts[2] = new WorldVertex((float)(+radius + offsets.x), 0.0f, (float)(hh + offsets.y), sectorcolor, ur, 0.0f);
                        verts[3] = verts[0];
                        verts[4] = verts[2];
                        verts[5] = new WorldVertex((float)(+radius + offsets.x), 0.0f, (float)(offsets.y - hh), sectorcolor, ur, 1.0f);
                    }
                    else
                    {
                        verts[0] = new WorldVertex((float)(-radius + offsets.x), 0.0f, (float)offsets.y, sectorcolor, ul, 1.0f);
                        verts[1] = new WorldVertex((float)(-radius + offsets.x), 0.0f, (float)(height + offsets.y), sectorcolor, ul, 0.0f);
                        verts[2] = new WorldVertex((float)(+radius + offsets.x), 0.0f, (float)(height + offsets.y), sectorcolor, ur, 0.0f);
                        verts[3] = verts[0];
                        verts[4] = verts[2];
                        verts[5] = new WorldVertex((float)(+radius + offsets.x), 0.0f, (float)offsets.y, sectorcolor, ur, 1.0f);
                    }
                    allverts[i] = verts;
                }
                else
                {
                    isloaded         = false;
                    base.textures[i] = sprite;

                    // Determine sprite size
                    float radius = Math.Min(thingradius, thingheight / 2f);
                    float height = Math.Min(thingradius * 2f, thingheight);

                    //mxd. Determine sprite offsets
                    offsets.x = radius;
                    offsets.y = height / 2;

                    // Make vertices
                    WorldVertex[] verts = new WorldVertex[6];
                    verts[0]    = new WorldVertex(-radius, 0.0f, 0.0f, sectorcolor, 0.0f, 1.0f);
                    verts[1]    = new WorldVertex(-radius, 0.0f, height, sectorcolor, 0.0f, 0.0f);
                    verts[2]    = new WorldVertex(+radius, 0.0f, height, sectorcolor, 1.0f, 0.0f);
                    verts[3]    = verts[0];
                    verts[4]    = verts[2];
                    verts[5]    = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor, 1.0f, 1.0f);
                    allverts[i] = verts;
                }

                //mxd. Store offsets
                alloffsets[i] = offsets;
            }

            //mxd
            SetVertices(allverts, alloffsets /*, floor, ceiling*/);

            // Determine position
            Vector3D pos = Thing.Position;

            if (Thing.Type == 9501)
            {
                if (Thing.Sector != null)                //mxd
                {
                    // This is a special thing that needs special positioning
                    SectorData sd = mode.GetSectorData(Thing.Sector);
                    pos.z = sd.Ceiling.sector.CeilHeight + Thing.Position.z;
                }
            }
            else if (Thing.Type == 9500)
            {
                if (Thing.Sector != null)                //mxd
                {
                    // This is a special thing that needs special positioning
                    SectorData sd = mode.GetSectorData(Thing.Sector);
                    pos.z = sd.Floor.sector.FloorHeight + Thing.Position.z;
                }
            }
            else if (info.AbsoluteZ)
            {
                // Absolute Z position
                pos.z = Thing.Position.z;
            }
            else if (info.Hangs)
            {
                // Hang from ceiling
                if (Thing.Sector != null)
                {
                    SectorData sd   = mode.GetSectorData(Thing.Sector);
                    double     maxz = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height;
                    pos.z = maxz;

                    if (Thing.Position.z > 0 || nointeraction)
                    {
                        pos.z -= Thing.Position.z;
                    }

                    // Check if below floor
                    if (!nointeraction)
                    {
                        double minz = sd.Floor.plane.GetZ(Thing.Position);
                        if (pos.z < minz)
                        {
                            pos.z = Math.Min(minz, maxz);
                        }
                    }
                }
            }
            else
            {
                // Stand on floor
                if (Thing.Sector != null)
                {
                    SectorData sd   = mode.GetSectorData(Thing.Sector);
                    double     minz = sd.Floor.plane.GetZ(Thing.Position);
                    pos.z = minz;

                    if (Thing.Position.z > 0 || nointeraction)
                    {
                        pos.z += Thing.Position.z;
                    }

                    // Check if above ceiling
                    if (!nointeraction)
                    {
                        double maxz = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height;
                        if (pos.z > maxz)
                        {
                            pos.z = Math.Max(minz, maxz);
                        }
                    }
                }
            }

            // Apply settings
            SetPosition(pos);
            SetCageColor(Thing.Color);

            // Keep info for object picking
            cageradius2 = thingradius * Angle2D.SQRT2;
            cageradius2 = cageradius2 * cageradius2;
            pos2d       = pos;

            if (sizeless)            //mxd
            {
                boxp1 = new Vector3D(pos.x - thingradius, pos.y - thingradius, pos.z - thingradius / 2);
                boxp2 = new Vector3D(pos.x + thingradius, pos.y + thingradius, pos.z + thingradius / 2);
            }
            else
            {
                boxp1 = new Vector3D(pos.x - thingradius, pos.y - thingradius, pos.z);
                boxp2 = new Vector3D(pos.x + thingradius, pos.y + thingradius, pos.z + thingheight);
            }

            // Done
            changed = false;
            return(true);
        }
Example #16
0
        // This builds the geometry. Returns false when no geometry created.
        public override bool Setup()
        {
            WorldVertex[] verts;
            WorldVertex   v;
            Sector        s = base.Sector.Sector;
            int           brightness;

            // Load floor texture
            base.Texture = General.Map.Data.GetFlatImage(s.LongCeilTexture);
            if (base.Texture == null)
            {
                brightness = mode.CalculateBrightness(256);

                base.Texture         = General.Map.Data.MissingTexture3D;
                setuponloadedtexture = s.LongCeilTexture;
            }
            else
            {
                brightness = mode.CalculateBrightness(s.Brightness);
                if (!base.Texture.IsImageLoaded)
                {
                    setuponloadedtexture = s.LongCeilTexture;
                }
            }

            // Make vertices
            verts = new WorldVertex[s.Triangles.Vertices.Count];
            for (int i = 0; i < s.Triangles.Vertices.Count; i++)
            {
                // Use sector brightness for color shading
                verts[i].c = brightness;

                // Grid aligned texture coordinates
                if (base.Texture.IsImageLoaded)
                {
                    verts[i].u = s.Triangles.Vertices[i].x / base.Texture.ScaledWidth;
                    verts[i].v = -s.Triangles.Vertices[i].y / base.Texture.ScaledHeight;
                }
                else
                {
                    verts[i].u = s.Triangles.Vertices[i].x / 64;
                    verts[i].v = -s.Triangles.Vertices[i].y / 64;
                }

                // Vertex coordinates
                verts[i].x = s.Triangles.Vertices[i].x;
                verts[i].y = s.Triangles.Vertices[i].y;
                verts[i].z = (float)s.CeilHeight;
            }

            // The sector triangulation created clockwise triangles that
            // are right up for the floor. For the ceiling we must flip
            // the triangles upside down.
            // Swap some vertices to flip all triangles
            for (int i = 0; i < verts.Length; i += 3)
            {
                // Swap
                v            = verts[i];
                verts[i]     = verts[i + 1];
                verts[i + 1] = v;
            }

            // Apply vertices
            base.SetVertices(verts);
            return(verts.Length > 0);
        }
Example #17
0
        // This builds the geometry. Returns false when no geometry created.
        public override bool Setup()
        {
            // Left and right vertices for this wall
            Vector2D vl, vr;

            if (Sidedef.IsFront)
            {
                vl = new Vector2D(Sidedef.Line.Start.Position);
                vr = new Vector2D(Sidedef.Line.End.Position);
            }
            else
            {
                vl = new Vector2D(Sidedef.Line.End.Position);
                vr = new Vector2D(Sidedef.Line.Start.Position);
            }

            // Keep top and bottom planes for intersection testing
            top    = Sidedef.Sector.CeilingPlane;
            bottom = Sidedef.Sector.FloorPlane;

            // Get ceiling and floor heights
            float cl = top.GetZ(vl);
            float cr = top.GetZ(vr);
            float fl = bottom.GetZ(vl);
            float fr = bottom.GetZ(vr);

            // Anything to see?
            if (cl - fl > 0.01f || cr - fr > 0.01f)
            {
                int brightness = MapElement.CalculateBrightness(Sidedef.Shade);

                // Texture given?
                Texture = General.Map.Data.GetImageData(Sidedef.TileIndex);
                if (Texture is UnknownImage)
                {
                    // Use missing texture
                    //Texture = General.Map.Data.MissingTexture3D;
                    setuponloadedimage = -1;
                }
                else if (!Texture.IsImageLoaded)
                {
                    setuponloadedimage = Sidedef.TileIndex;
                }

                WorldVertex[] verts = new WorldVertex[6];
                verts[0] = new WorldVertex(vl.x, vl.y, fl, brightness, 0, 0);
                verts[1] = new WorldVertex(vl.x, vl.y, cl, brightness, 0, 0);
                verts[2] = new WorldVertex(vr.x, vr.y, cr, brightness, 0, 0);
                verts[3] = verts[0];
                verts[4] = verts[2];
                verts[5] = new WorldVertex(vr.x, vr.y, fr, brightness, 0, 0);

                //mxd. Set UV coords the Build way...
                int   xref             = (!Sidedef.ImageFlipX ? 1 : 0);
                int   xrefinv          = 1 - xref;
                int   yref             = (Sidedef.AlignImageToBottom ? Sidedef.Sector.FloorHeight : Sidedef.Sector.CeilingHeight);
                float ypancoef         = CalculateOffsetV(Sidedef.OffsetY, Texture, !Sidedef.AlignImageToBottom);
                float scaledtexrepeaty = ((Texture.Height * 128f) / Sidedef.RepeatY);

                for (int i = 0; i < 6; i++)
                {
                    float dist = ((i == 2 || i == 4 || i == 5) ? xref : xrefinv);

                    verts[i].u = ((dist * 8.0f * Sidedef.RepeatX) + Sidedef.OffsetX) / Texture.Width;
                    // w->wall.buffer[i].v = (-(float)(yref + (w->wall.buffer[i].y * 16)) / ((tilesiz[curpicnum].y * 2048.0f) / (float)(wal->yrepeat))) + ypancoef;
                    verts[i].v = ((yref + (-verts[i].z)) / scaledtexrepeaty) - ypancoef;
                    if (Sidedef.ImageFlipY)
                    {
                        verts[i].v *= -1;
                    }
                }

                // Apply vertices
                SetVertices(verts);
                return(true);
            }

            // No geometry for invisible wall
            SetVertices(new WorldVertex[0]);
            return(false);
        }
        // This sets the vertices for the thing sprite
        protected void SetVertices(WorldVertex[][] verts, Vector2D[] offsets /*, Plane floor, Plane ceiling*/)
        {
            // Copy vertices
            vertices  = new WorldVertex[verts.Length][];
            triangles = new int[verts.Length];

            //mxd
            for (int i = 0; i < verts.Length; i++)
            {
                vertices[i] = new WorldVertex[verts[i].Length];
                verts[i].CopyTo(vertices[i], 0);
                triangles[i] = vertices[i].Length / 3;
            }

            updategeo = true;

            //mxd. Do some special GZDoom rendering shenanigans...
            for (int c = 0; c < vertices.Length; c++)
            {
                if (triangles[c] < 2)
                {
                    continue;
                }

                Matrix transform, rotation;
                float  centerx, centerz;

                // ROLLCENTER flag support
                if (info.RollSprite && info.RollCenter && thing.Roll != 0)
                {
                    // Rotate around sprite center
                    centerx = offsets[c].x;
                    centerz = vertices[c][1].z * 0.5f - offsets[c].y;
                }
                else
                {
                    // Sprite center is already where it needs to be
                    centerx = 0f;
                    centerz = 0f;
                }

                switch (thing.RenderMode)
                {
                // Don't do anything
                case ThingRenderMode.MODEL: break;

                case ThingRenderMode.VOXEL: break;

                // Actor becomes a flat sprite which can be tilted with the use of the Pitch actor property.
                case ThingRenderMode.FLATSPRITE:
                    transform = Matrix.Scaling(thing.ScaleX, thing.ScaleX, thing.ScaleY);

                    // Apply roll?
                    if (thing.Roll != 0)
                    {
                        if (info.RollCenter)
                        {
                            rotation   = Matrix.RotationY(-thing.RollRad);
                            transform *= Matrix.Translation(-centerx, -centerx, -centerz) * rotation * Matrix.Translation(centerx, centerx, centerz);
                        }
                        else
                        {
                            // Sprite center is already where it needs to be
                            transform *= Matrix.RotationY(-thing.RollRad);
                        }
                    }

                    // Apply pitch
                    transform *= Matrix.RotationX(thing.PitchRad + Angle2D.PIHALF);

                    // Apply angle
                    transform *= Matrix.RotationZ(thing.Angle);

                    // Apply transform
                    float zoffset = ((thing.Pitch == 0f && thing.Position.z == 0f) ? 0.1f : 0f);                             // Slight offset to avoid z-fighting...
                    for (int i = 0; i < vertices[c].Length; i++)
                    {
                        Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), transform);
                        vertices[c][i].x = transformed.X;
                        vertices[c][i].y = transformed.Y;
                        vertices[c][i].z = transformed.Z + zoffset;
                    }
                    break;

                // Similar to FLATSPRITE but is not affected by pitch.
                case ThingRenderMode.WALLSPRITE:
                    transform = Matrix.Scaling(thing.ScaleX, thing.ScaleX, thing.ScaleY);

                    // Apply roll?
                    if (thing.Roll != 0)
                    {
                        rotation = Matrix.RotationY(-thing.RollRad) * Matrix.RotationZ(thing.Angle);
                        if (info.RollCenter)
                        {
                            transform *= Matrix.Translation(-centerx, -centerx, -centerz) * rotation * Matrix.Translation(centerx, centerx, centerz);
                        }
                        else
                        {
                            transform *= rotation;                                     // Sprite center is already where it needs to be
                        }
                    }
                    else
                    {
                        transform *= Matrix.RotationZ(thing.Angle);
                    }

                    // Apply transform
                    for (int i = 0; i < vertices[c].Length; i++)
                    {
                        Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), transform);
                        vertices[c][i].x = transformed.X;
                        vertices[c][i].y = transformed.Y;
                        vertices[c][i].z = transformed.Z;
                    }
                    break;

                    #region Some old GLOOME FLOOR_SPRITE/CEILING_SPRITE support code

                    /*case Thing.SpriteRenderMode.FLOOR_SPRITE:
                     *      Matrix floorrotation = Matrix.RotationZ(info.RollSprite ? Thing.RollRad : 0f)
                     * Matrix.RotationY(Thing.Angle)
                     * Matrix.RotationX(Angle2D.PIHALF);
                     *
                     *      m = Matrix.Translation(0f, 0f, -localcenterz) * floorrotation * Matrix.Translation(0f, 0f, localcenterz);
                     *
                     *      for(int i = 0; i < vertices[c].Length; i++)
                     *      {
                     *              Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), m);
                     *              vertices[c][i].x = transformed.X;
                     *              vertices[c][i].y = transformed.Y;
                     *              vertices[c][i].z = transformed.Z;
                     *      }
                     *
                     *      // TODO: this won't work on things with AbsoluteZ flag
                     *      // TODO: +ROLLSPRITE implies +STICKTOPLANE?
                     *      if(info.StickToPlane || info.RollSprite)
                     *      {
                     *              // Calculate vertical offset
                     *              float floorz = floor.GetZ(Thing.Position);
                     *              float ceilz = ceiling.GetZ(Thing.Position);
                     *
                     *              if(!float.IsNaN(floorz) && !float.IsNaN(ceilz))
                     *              {
                     *                      float voffset;
                     *                      if(info.Hangs)
                     *                      {
                     *                              float thingz = ceilz - Thing.Position.z + Thing.Height;
                     *                              voffset = 0.01f - floorz - General.Clamp(thingz, 0, ceilz - floorz);
                     *                      }
                     *                      else
                     *                      {
                     *                              voffset = 0.01f - floorz - General.Clamp(Thing.Position.z, 0, ceilz - floorz);
                     *                      }
                     *
                     *                      // Apply it
                     *                      for(int i = 0; i < vertices[c].Length; i++)
                     *                              vertices[c][i].z = floor.GetZ(vertices[c][i].x + Thing.Position.x, vertices[c][i].y + Thing.Position.y) + voffset;
                     *              }
                     *      }
                     *      break;
                     *
                     * case Thing.SpriteRenderMode.CEILING_SPRITE:
                     *      Matrix ceilrotation = Matrix.RotationZ(info.RollSprite ? Thing.RollRad : 0f)
                     * Matrix.RotationY(Thing.Angle)
                     * Matrix.RotationX(Angle2D.PIHALF);
                     *
                     *      m = Matrix.Translation(0f, 0f, -localcenterz) * ceilrotation * Matrix.Translation(0f, 0f, localcenterz);
                     *
                     *      for(int i = 0; i < vertices[c].Length; i++)
                     *      {
                     *              Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), m);
                     *              vertices[c][i].x = transformed.X;
                     *              vertices[c][i].y = transformed.Y;
                     *              vertices[c][i].z = transformed.Z;
                     *      }
                     *
                     *      // TODO: this won't work on things with AbsoluteZ flag
                     *      // TODO: +ROLLSPRITE implies +STICKTOPLANE?
                     *      if(info.StickToPlane || info.RollSprite)
                     *      {
                     *              // Calculate vertical offset
                     *              float floorz = floor.GetZ(Thing.Position);
                     *              float ceilz = ceiling.GetZ(Thing.Position);
                     *
                     *              if(!float.IsNaN(floorz) && !float.IsNaN(ceilz))
                     *              {
                     *                      float voffset;
                     *                      if(info.Hangs)
                     *                      {
                     *                              float thingz = ceilz - Math.Max(0, Thing.Position.z) - Thing.Height;
                     *                              voffset = -0.01f - General.Clamp(thingz, 0, ceilz - floorz);
                     *                      }
                     *                      else
                     *                      {
                     *                              voffset = -0.01f - floorz - General.Clamp(Thing.Position.z, 0, ceilz - floorz);
                     *                      }
                     *
                     *                      // Apply it
                     *                      for(int i = 0; i < vertices[c].Length; i++)
                     *                              vertices[c][i].z = ceiling.GetZ(vertices[c][i].x + Thing.Position.x, vertices[c][i].y + Thing.Position.y) + voffset;
                     *              }
                     *      }
                     *      break;*/
                    #endregion

                case ThingRenderMode.NORMAL:
                    transform = Matrix.Scaling(thing.ScaleX, thing.ScaleX, thing.ScaleY);

                    // Apply roll?
                    if (info.RollSprite && thing.Roll != 0)
                    {
                        rotation = Matrix.RotationY(-thing.RollRad);
                        if (info.RollCenter)
                        {
                            transform *= Matrix.Translation(-centerx, -centerx, -centerz) * rotation * Matrix.Translation(centerx, centerx, centerz);
                        }
                        else
                        {
                            transform *= rotation;                                     // Sprite center is already where it needs to be
                        }
                    }

                    // Apply transform
                    for (int i = 0; i < vertices[c].Length; i++)
                    {
                        Vector4 transformed = Vector3.Transform(new Vector3(vertices[c][i].x, vertices[c][i].y, vertices[c][i].z), transform);
                        vertices[c][i].x = transformed.X;
                        vertices[c][i].y = transformed.Y;
                        vertices[c][i].z = transformed.Z;
                    }
                    break;

                default: throw new NotImplementedException("Unknown ThingRenderMode");
                }
            }
        }
        // This builds the thing geometry. Returns false when nothing was created.
        public bool Setup()
        {
            // Find the sector in which the thing resides
            Thing.DetermineSector(mode.BlockMap);

            //mxd. If the thing is inside a sector, apply DECORATE/UDMF alpha/renderstyle overrides
            byte alpha = 255;

            if (Thing.Sector != null)
            {
                string renderstyle = info.RenderStyle;
                alpha = info.AlphaByte;

                if (General.Map.UDMF)
                {
                    if (Thing.IsFlagSet("translucent"))
                    {
                        renderstyle = "translucent";
                        alpha       = 64;
                    }
                    else if (Thing.IsFlagSet("invisible"))
                    {
                        renderstyle = "none";
                        alpha       = 0;
                    }
                    else if (Thing.Fields.ContainsKey("renderstyle"))
                    {
                        renderstyle = Thing.Fields.GetValue("renderstyle", renderstyle);
                    }

                    if ((renderstyle == "add" || renderstyle == "translucent" || renderstyle == "subtract" || renderstyle == "stencil") &&
                        Thing.Fields.ContainsKey("alpha"))
                    {
                        alpha = (byte)(General.Clamp(Thing.Fields.GetValue("alpha", info.Alpha), 0f, 1f) * 255);
                    }
                }
                else if (General.Map.HEXEN)
                {
                    if (Thing.IsFlagSet("2048"))
                    {
                        renderstyle = "translucent";
                        alpha       = 64;
                    }
                    else if (Thing.IsFlagSet("4096"))
                    {
                        renderstyle = "none";
                        alpha       = 0;
                    }
                }

                // Set appropriate RenderPass
                switch (renderstyle)
                {
                case "translucent":
                case "subtract":
                case "stencil":
                    RenderPass = RenderPass.Alpha;
                    break;

                case "add":
                    RenderPass = RenderPass.Additive;
                    break;

                case "none":
                    RenderPass = RenderPass.Mask;
                    alpha      = 0;
                    break;

                // Many render styles are not supported yet...
                default:
                    RenderPass = RenderPass.Mask;
                    alpha      = 255;
                    break;
                }
            }

            // Don't bother when alpha is unchanged, unless Additive RenderStyle is used
            if (RenderPass != RenderPass.Additive && alpha == 255)
            {
                RenderPass = RenderPass.Mask;
            }

            int sectorcolor = new PixelColor(alpha, 255, 255, 255).ToInt();

            fogfactor = 0f;             //mxd

            //mxd. Check thing size
            float thingradius = Thing.Size;         // Thing.Size has ThingRadius arg override applied

            thingheight = Thing.Height;             // Thing.Height has ThingHeight arg override applied

            if (thingradius < 0.1f || thingheight < 0.1f)
            {
                thingradius = FIXED_RADIUS;
                thingheight = FIXED_RADIUS;
                sizeless    = true;
            }
            else
            {
                sizeless = false;
            }

            Plane floor   = new Plane();           //mxd
            Plane ceiling = new Plane();           //mxd

            if (Thing.Sector != null)
            {
                SectorData sd = mode.GetSectorData(Thing.Sector);
                floor   = sd.Floor.plane;               //mxd
                ceiling = sd.Ceiling.plane;             //mxd

                if (!info.Bright)
                {
                    Vector3D    thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position));
                    SectorLevel level    = sd.GetLevelAboveOrAt(thingpos);

                    //mxd. Let's use point on floor plane instead of Thing.Sector.FloorHeight;
                    if (nointeraction && level == null && sd.LightLevels.Count > 0)
                    {
                        level = sd.LightLevels[sd.LightLevels.Count - 1];
                    }

                    //mxd. Use the light level of the highest surface when a thing is above highest sector level.
                    if (level != null)
                    {
                        // TECH: In GZDoom, ceiling glow doesn't affect thing brightness
                        // Use sector brightness for color shading
                        int brightness = level.brightnessbelow;

                        // Level is glowing
                        if (level.affectedbyglow && level.type == SectorLevelType.Floor)
                        {
                            // Extrafloor glow doesn't affect thing brightness
                            if (level.sector == Thing.Sector)
                            {
                                float planez = level.plane.GetZ(thingpos);

                                // Get glow brightness
                                int         glowbrightness = sd.FloorGlow.Brightness / 2;
                                SectorLevel nexthigher     = sd.GetLevelAbove(new Vector3D(thingpos, planez));

                                // Interpolate thing brightness between glow and regular ones
                                if (nexthigher != null)
                                {
                                    float higherz = nexthigher.plane.GetZ(thingpos);
                                    float delta   = General.Clamp(1.0f - (thingpos.z - planez) / (higherz - planez), 0f, 1f);
                                    brightness = (int)((glowbrightness + level.sector.Brightness / 2) * delta + nexthigher.sector.Brightness * (1.0f - delta));
                                }
                            }
                        }
                        // Level below this one is glowing. Only possible for floor glow(?)
                        else if (level.type == SectorLevelType.Glow)
                        {
                            // Interpolate thing brightness between glow and regular ones
                            if (sd.Floor != null && sd.FloorGlow != null)
                            {
                                // Get glow brightness
                                float glowz  = level.plane.GetZ(thingpos);
                                float floorz = floor.GetZ(thingpos);
                                float delta  = General.Clamp((thingpos.z - floorz) / (glowz - floorz), 0f, 1f);

                                brightness = (int)((sd.FloorGlow.Brightness / 2 + sd.Floor.sector.Brightness / 2) * (1.0f - delta) + sd.Floor.sector.Brightness * delta);
                            }
                        }

                        PixelColor areabrightness = PixelColor.FromInt(mode.CalculateBrightness(brightness));
                        PixelColor areacolor      = PixelColor.Modulate(level.colorbelow, areabrightness);
                        sectorcolor = areacolor.WithAlpha(alpha).ToInt();

                        //mxd. Calculate fogfactor
                        fogfactor = VisualGeometry.CalculateFogFactor(level.sector.FogMode, brightness);
                    }
                }
                //TECH: even Bright Thing frames are affected by custom fade...
                else
                {
                    Vector3D    thingpos = new Vector3D(Thing.Position.x, Thing.Position.y, Thing.Position.z + sd.Floor.plane.GetZ(Thing.Position));
                    SectorLevel level    = sd.GetLevelAboveOrAt(thingpos);

                    if (level != null && level.sector.FogMode > SectorFogMode.CLASSIC)
                    {
                        //mxd. Calculate fogfactor
                        fogfactor = VisualGeometry.CalculateFogFactor(level.sector.FogMode, level.brightnessbelow);
                    }
                }
            }

            //mxd. Create verts for all sprite angles
            WorldVertex[][] allverts   = new WorldVertex[info.SpriteFrame.Length][];
            Vector2D[]      alloffsets = new Vector2D[info.SpriteFrame.Length];
            base.textures = new ImageData[info.SpriteFrame.Length];
            isloaded      = true;

            for (int i = 0; i < sprites.Length; i++)
            {
                Vector2D offsets = new Vector2D();

                // Check if the texture is loaded
                ImageData sprite = sprites[i];
                sprite.LoadImage();
                if (sprite.IsImageLoaded)
                {
                    base.textures[i] = sprite;

                    // Determine sprite size and offset
                    float        radius    = sprite.ScaledWidth * 0.5f;
                    float        height    = sprite.ScaledHeight;
                    ISpriteImage spriteimg = sprite as ISpriteImage;
                    if (spriteimg != null)
                    {
                        offsets.x = radius - spriteimg.OffsetX;
                        offsets.y = spriteimg.OffsetY - height;
                    }

                    // Scale by thing type/actor scale
                    // We do this after the offset x/y determination above, because that is entirely in sprite pixels space
                    radius    *= info.SpriteScale.Width;
                    height    *= info.SpriteScale.Height;
                    offsets.x *= info.SpriteScale.Width;
                    offsets.y *= info.SpriteScale.Height;

                    // Make vertices
                    WorldVertex[] verts = new WorldVertex[6];

                    //mxd. Sprite mirroring
                    float ul = (info.SpriteFrame[i].Mirror ? 1f : 0f);
                    float ur = (info.SpriteFrame[i].Mirror ? 0f : 1f);

                    if (sizeless)                    //mxd
                    {
                        float hh = height / 2;
                        verts[0] = new WorldVertex(-radius + offsets.x, 0.0f, offsets.y - hh, sectorcolor, ul, 1.0f);
                        verts[1] = new WorldVertex(-radius + offsets.x, 0.0f, hh + offsets.y, sectorcolor, ul, 0.0f);
                        verts[2] = new WorldVertex(+radius + offsets.x, 0.0f, hh + offsets.y, sectorcolor, ur, 0.0f);
                        verts[3] = verts[0];
                        verts[4] = verts[2];
                        verts[5] = new WorldVertex(+radius + offsets.x, 0.0f, offsets.y - hh, sectorcolor, ur, 1.0f);
                    }
                    else
                    {
                        verts[0] = new WorldVertex(-radius + offsets.x, 0.0f, offsets.y, sectorcolor, ul, 1.0f);
                        verts[1] = new WorldVertex(-radius + offsets.x, 0.0f, height + offsets.y, sectorcolor, ul, 0.0f);
                        verts[2] = new WorldVertex(+radius + offsets.x, 0.0f, height + offsets.y, sectorcolor, ur, 0.0f);
                        verts[3] = verts[0];
                        verts[4] = verts[2];
                        verts[5] = new WorldVertex(+radius + offsets.x, 0.0f, offsets.y, sectorcolor, ur, 1.0f);
                    }
                    allverts[i] = verts;
                }
                else
                {
                    isloaded         = false;
                    base.textures[i] = General.Map.Data.Hourglass3D;

                    // Determine sprite size
                    float radius = Math.Min(thingradius, thingheight / 2f);
                    float height = Math.Min(thingradius * 2f, thingheight);

                    //mxd. Determine sprite offsets
                    offsets.x = radius;
                    offsets.y = height / 2;

                    // Make vertices
                    WorldVertex[] verts = new WorldVertex[6];
                    verts[0]    = new WorldVertex(-radius, 0.0f, 0.0f, sectorcolor, 0.0f, 1.0f);
                    verts[1]    = new WorldVertex(-radius, 0.0f, height, sectorcolor, 0.0f, 0.0f);
                    verts[2]    = new WorldVertex(+radius, 0.0f, height, sectorcolor, 1.0f, 0.0f);
                    verts[3]    = verts[0];
                    verts[4]    = verts[2];
                    verts[5]    = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor, 1.0f, 1.0f);
                    allverts[i] = verts;
                }

                //mxd. Store offsets
                alloffsets[i] = offsets;
            }

            //mxd
            SetVertices(allverts, alloffsets /*, floor, ceiling*/);

            // Determine position
            Vector3D pos = Thing.Position;

            if (Thing.Type == 9501)
            {
                if (Thing.Sector != null)                //mxd
                {
                    // This is a special thing that needs special positioning
                    SectorData sd = mode.GetSectorData(Thing.Sector);
                    pos.z = sd.Ceiling.sector.CeilHeight + Thing.Position.z;
                }
            }
            else if (Thing.Type == 9500)
            {
                if (Thing.Sector != null)                //mxd
                {
                    // This is a special thing that needs special positioning
                    SectorData sd = mode.GetSectorData(Thing.Sector);
                    pos.z = sd.Floor.sector.FloorHeight + Thing.Position.z;
                }
            }
            else if (info.AbsoluteZ)
            {
                // Absolute Z position
                pos.z = Thing.Position.z;
            }
            else if (info.Hangs)
            {
                // Hang from ceiling
                if (Thing.Sector != null)
                {
                    SectorData sd   = mode.GetSectorData(Thing.Sector);
                    float      maxz = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height;
                    pos.z = maxz;

                    if (Thing.Position.z > 0 || nointeraction)
                    {
                        pos.z -= Thing.Position.z;
                    }

                    // Check if below floor
                    if (!nointeraction)
                    {
                        float minz = sd.Floor.plane.GetZ(Thing.Position);
                        if (pos.z < minz)
                        {
                            pos.z = Math.Min(minz, maxz);
                        }
                    }
                }
            }
            else
            {
                // Stand on floor
                if (Thing.Sector != null)
                {
                    SectorData sd   = mode.GetSectorData(Thing.Sector);
                    float      minz = sd.Floor.plane.GetZ(Thing.Position);
                    pos.z = minz;

                    if (Thing.Position.z > 0 || nointeraction)
                    {
                        pos.z += Thing.Position.z;
                    }

                    // Check if above ceiling
                    if (!nointeraction)
                    {
                        float maxz = sd.Ceiling.plane.GetZ(Thing.Position) - info.Height;
                        if (pos.z > maxz)
                        {
                            pos.z = Math.Max(minz, maxz);
                        }
                    }
                }
            }

            // Apply settings
            SetPosition(pos);
            SetCageColor(Thing.Color);

            // Keep info for object picking
            cageradius2 = thingradius * Angle2D.SQRT2;
            cageradius2 = cageradius2 * cageradius2;
            pos2d       = pos;

            if (sizeless)            //mxd
            {
                boxp1 = new Vector3D(pos.x - thingradius, pos.y - thingradius, pos.z - thingradius / 2);
                boxp2 = new Vector3D(pos.x + thingradius, pos.y + thingradius, pos.z + thingradius / 2);
            }
            else
            {
                boxp1 = new Vector3D(pos.x - thingradius, pos.y - thingradius, pos.z);
                boxp2 = new Vector3D(pos.x + thingradius, pos.y + thingradius, pos.z + thingheight);
            }

            // Done
            changed = false;
            return(true);
        }
Example #20
0
        // This builds the geometry. Returns false when no geometry created.
        public override bool Setup()
        {
            Vector2D vl, vr;

            int  lightvalue    = Sidedef.Fields.GetValue("light", 0);
            bool lightabsolute = Sidedef.Fields.GetValue("lightabsolute", false);

            Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_mid", 1.0f),
                                           Sidedef.Fields.GetValue("scaley_mid", 1.0f));
            Vector2D toffset = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f),
                                            Sidedef.Fields.GetValue("offsety_mid", 0.0f));

            // Texture given?
            if ((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-'))
            {
                // Left and right vertices for this sidedef
                if (Sidedef.IsFront)
                {
                    vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
                    vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
                }
                else
                {
                    vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
                    vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
                }

                // Load sector data
                SectorData sd  = mode.GetSectorData(Sidedef.Sector);
                SectorData osd = mode.GetSectorData(Sidedef.Other.Sector);
                if (!osd.Updated)
                {
                    osd.Update();
                }

                // Texture given?
                if ((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-'))
                {
                    // Load texture
                    base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture);
                    if (base.Texture == null)
                    {
                        base.Texture         = General.Map.Data.MissingTexture3D;
                        setuponloadedtexture = Sidedef.LongMiddleTexture;
                    }
                    else
                    {
                        if (!base.Texture.IsImageLoaded)
                        {
                            setuponloadedtexture = Sidedef.LongMiddleTexture;
                        }
                    }
                }
                else
                {
                    // Use missing texture
                    base.Texture         = General.Map.Data.MissingTexture3D;
                    setuponloadedtexture = 0;
                }

                // Get texture scaled size
                Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);
                tsz = tsz / tscale;

                // Get texture offsets
                Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
                tof = tof + toffset;
                tof = tof / tscale;
                if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
                {
                    tof = tof * base.Texture.Scale;
                }

                // Determine texture coordinates plane as they would be in normal circumstances.
                // We can then use this plane to find any texture coordinate we need.
                // The logic here is the same as in the original VisualMiddleSingle (except that
                // the values are stored in a TexturePlane)
                // NOTE: I use a small bias for the floor height, because if the difference in
                // height is 0 then the TexturePlane doesn't work!
                TexturePlane tp        = new TexturePlane();
                float        floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f;
                float        geotop    = (float)Math.Min(Sidedef.Sector.CeilHeight, Sidedef.Other.Sector.CeilHeight);
                float        geobottom = (float)Math.Max(Sidedef.Sector.FloorHeight, Sidedef.Other.Sector.FloorHeight);
                if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
                {
                    // When lower unpegged is set, the middle texture is bound to the bottom
                    tp.tlt.y = tsz.y - (float)(geotop - geobottom);
                }
                tp.trb.x = tp.tlt.x + Sidedef.Line.Length;
                tp.trb.y = tp.tlt.y + ((float)Sidedef.Sector.CeilHeight - ((float)Sidedef.Sector.FloorHeight + floorbias));

                // Apply texture offset
                tp.tlt += tof;
                tp.trb += tof;

                // Transform pixel coordinates to texture coordinates
                tp.tlt /= tsz;
                tp.trb /= tsz;

                // Left top and right bottom of the geometry that
                tp.vlt = new Vector3D(vl.x, vl.y, (float)Sidedef.Sector.CeilHeight);
                tp.vrb = new Vector3D(vr.x, vr.y, (float)Sidedef.Sector.FloorHeight + floorbias);

                // Make the right-top coordinates
                tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
                tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);

                // Keep top and bottom planes for intersection testing
                top    = sd.Ceiling.plane;
                bottom = sd.Floor.plane;

                // Create initial polygon, which is just a quad between floor and ceiling
                WallPolygon poly = new WallPolygon();
                poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl)));
                poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl)));
                poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr)));
                poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr)));

                // Determine initial color
                int        lightlevel     = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;
                PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel));
                PixelColor wallcolor      = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);
                poly.color = wallcolor.WithAlpha(255).ToInt();

                // Cut off the part below the other floor and above the other ceiling
                CropPoly(ref poly, osd.Ceiling.plane, true);
                CropPoly(ref poly, osd.Floor.plane, true);

                // Determine if we should repeat the middle texture
                if (Sidedef.Fields.ContainsKey("wrapmidtex"))
                {
                    repeatmidtex = Sidedef.Fields.GetValue("wrapmidtex", false);
                }
                else
                {
                    repeatmidtex = Sidedef.Line.IsFlagSet("wrapmidtex");
                }

                if (!repeatmidtex)
                {
                    // First determine the visible portion of the texture
                    float textop, texbottom;

                    // Determine top portion height
                    if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
                    {
                        textop = geobottom + tof.y + tsz.y;
                    }
                    else
                    {
                        textop = geotop + tof.y;
                    }

                    // Calculate bottom portion height
                    texbottom = textop - tsz.y;

                    // Create crop planes (we also need these for intersection testing)
                    topclipplane    = new Plane(new Vector3D(0, 0, -1), textop);
                    bottomclipplane = new Plane(new Vector3D(0, 0, 1), -texbottom);

                    // Crop polygon by these heights
                    CropPoly(ref poly, topclipplane, true);
                    CropPoly(ref poly, bottomclipplane, true);
                }

                if (poly.Count > 2)
                {
                    // Keep top and bottom planes for intersection testing
                    top    = osd.Ceiling.plane;
                    bottom = osd.Floor.plane;

                    // Process the polygon and create vertices
                    List <WorldVertex> verts = CreatePolygonVertices(poly, tp, sd, lightvalue, lightabsolute);
                    if (verts.Count > 0)
                    {
                        // Apply alpha to vertices
                        byte alpha = SetLinedefRenderstyle(true);
                        if (alpha < 255)
                        {
                            for (int i = 0; i < verts.Count; i++)
                            {
                                WorldVertex v = verts[i];
                                PixelColor  c = PixelColor.FromInt(v.c);
                                v.c      = c.WithAlpha(alpha).ToInt();
                                verts[i] = v;
                            }
                        }

                        base.SetVertices(verts);
                        return(true);
                    }
                }
            }

            return(false);
        }
Example #21
0
        private static MD3LoadResult ReadMD2Model(ref BoundingBoxSizes bbs, Stream s, Device device, int frame, string framename)
        {
            long          start  = s.Position;
            MD3LoadResult result = new MD3LoadResult();

            using (var br = new BinaryReader(s, Encoding.ASCII))
            {
                string magic = ReadString(br, 4);
                if (magic != "IDP2")                //magic number: "IDP2"
                {
                    result.Errors = "unknown header: expected \"IDP2\", but got \"" + magic + "\"";
                    return(result);
                }

                int modelVersion = br.ReadInt32();
                if (modelVersion != 8)                //MD2 version. Must be equal to 8
                {
                    result.Errors = "expected MD3 version 15, but got " + modelVersion;
                    return(result);
                }

                int texWidth  = br.ReadInt32();
                int texHeight = br.ReadInt32();
                int framesize = br.ReadInt32();  // Size of one frame in bytes
                s.Position += 4;                 //Number of textures
                int num_verts = br.ReadInt32();  //Number of vertices
                int num_uv    = br.ReadInt32();  //The number of UV coordinates in the model
                int num_tris  = br.ReadInt32();  //Number of triangles
                s.Position += 4;                 //Number of OpenGL commands
                int num_frames = br.ReadInt32(); //Total number of frames

                // Sanity checks
                if (frame < 0 || frame >= num_frames)
                {
                    result.Errors = "frame " + frame + " is outside of model's frame range [0.." + (num_frames - 1) + "]";
                    return(result);
                }

                s.Position += 4;                    //Offset to skin names (each skin name is an unsigned char[64] and are null terminated)
                int ofs_uv        = br.ReadInt32(); //Offset to s-t texture coordinates
                int ofs_tris      = br.ReadInt32(); //Offset to triangles
                int ofs_animFrame = br.ReadInt32(); //An offset to the first animation frame

                List <int>         polyIndecesList = new List <int>();
                List <int>         uvIndecesList   = new List <int>();
                List <Vector2>     uvCoordsList    = new List <Vector2>();
                List <WorldVertex> vertList        = new List <WorldVertex>();

                // Polygons
                s.Position = ofs_tris + start;

                for (int i = 0; i < num_tris; i++)
                {
                    polyIndecesList.Add(br.ReadUInt16());
                    polyIndecesList.Add(br.ReadUInt16());
                    polyIndecesList.Add(br.ReadUInt16());

                    uvIndecesList.Add(br.ReadUInt16());
                    uvIndecesList.Add(br.ReadUInt16());
                    uvIndecesList.Add(br.ReadUInt16());
                }

                // UV coords
                s.Position = ofs_uv + start;

                for (int i = 0; i < num_uv; i++)
                {
                    uvCoordsList.Add(new Vector2((float)br.ReadInt16() / texWidth, (float)br.ReadInt16() / texHeight));
                }

                // Frames
                // Find correct frame
                if (!string.IsNullOrEmpty(framename))
                {
                    // Skip frames untill frame name matches
                    bool framefound = false;
                    for (int i = 0; i < num_frames; i++)
                    {
                        s.Position  = ofs_animFrame + start + i * framesize;
                        s.Position += 24;                         // Skip scale and translate
                        string curframename = ReadString(br, 16).ToLowerInvariant();

                        if (curframename == framename)
                        {
                            // Step back so scale and translate can be read
                            s.Position -= 40;
                            framefound  = true;
                            break;
                        }
                    }

                    // No dice? Bail out!
                    if (!framefound)
                    {
                        result.Errors = "unable to find frame \"" + framename + "\"!";
                        return(result);
                    }
                }
                else
                {
                    // If we have frame number, we can go directly to target frame
                    s.Position = ofs_animFrame + start + frame * framesize;
                }

                Vector3 scale     = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                Vector3 translate = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());

                s.Position += 16;                 // Skip frame name

                // Prepare to fix rotation angle
                float angleOfsetCos = (float)Math.Cos(-Angle2D.PIHALF);
                float angleOfsetSin = (float)Math.Sin(-Angle2D.PIHALF);

                //verts
                for (int i = 0; i < num_verts; i++)
                {
                    WorldVertex v = new WorldVertex();

                    v.x = (br.ReadByte() * scale.X + translate.X);
                    v.y = (br.ReadByte() * scale.Y + translate.Y);
                    v.z = (br.ReadByte() * scale.Z + translate.Z);

                    // Fix rotation angle
                    float rx = angleOfsetCos * v.x - angleOfsetSin * v.y;
                    float ry = angleOfsetSin * v.x + angleOfsetCos * v.y;
                    v.y = ry;
                    v.x = rx;

                    vertList.Add(v);
                    s.Position += 1;                     //vertex normal
                }

                for (int i = 0; i < polyIndecesList.Count; i++)
                {
                    WorldVertex v = vertList[polyIndecesList[i]];

                    //bounding box
                    BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, new WorldVertex(v.y, v.x, v.z));

                    //uv
                    float tu = uvCoordsList[uvIndecesList[i]].X;
                    float tv = uvCoordsList[uvIndecesList[i]].Y;

                    //uv-coordinates already set?
                    if (v.c == -1 && (v.u != tu || v.v != tv))
                    {
                        //add a new vertex
                        vertList.Add(new WorldVertex(v.x, v.y, v.z, -1, tu, tv));
                        polyIndecesList[i] = vertList.Count - 1;
                    }
                    else
                    {
                        v.u = tu;
                        v.v = tv;
                        v.c = -1;                         //set color to white

                        //return to proper place
                        vertList[polyIndecesList[i]] = v;
                    }
                }

                //mesh
                Mesh mesh = new Mesh(device, polyIndecesList.Count / 3, vertList.Count, MeshFlags.Use32Bit | MeshFlags.IndexBufferManaged | MeshFlags.VertexBufferManaged, vertexElements);

                using (DataStream stream = mesh.LockVertexBuffer(LockFlags.None))
                {
                    stream.WriteRange(vertList.ToArray());
                }
                mesh.UnlockVertexBuffer();

                using (DataStream stream = mesh.LockIndexBuffer(LockFlags.None))
                {
                    stream.WriteRange(polyIndecesList.ToArray());
                }
                mesh.UnlockIndexBuffer();

                mesh.OptimizeInPlace(MeshOptimizeFlags.AttributeSort);

                //store in result
                result.Meshes.Add(mesh);
                result.Skins.Add("");                 //no skin support for MD2
            }

            return(result);
        }
Example #22
0
        private static string ReadSurface(ref BoundingBoxSizes bbs, ref string skin, BinaryReader br, List <int> polyIndecesList, List <WorldVertex> vertList, int frame)
        {
            int  vertexOffset = vertList.Count;
            long start        = br.BaseStream.Position;

            string magic = ReadString(br, 4);

            if (magic != "IDP3")
            {
                return("error while reading surface. Unknown header: expected \"IDP3\", but got \"" + magic + "\"");
            }

            string name         = ReadString(br, 64);
            int    flags        = br.ReadInt32();
            int    numFrames    = br.ReadInt32();   //Number of animation frames. This should match NUM_FRAMES in the MD3 header.
            int    numShaders   = br.ReadInt32();   //Number of Shader objects defined in this Surface, with a limit of MD3_MAX_SHADERS. Current value of MD3_MAX_SHADERS is 256.
            int    numVerts     = br.ReadInt32();   //Number of Vertex objects defined in this Surface, up to MD3_MAX_VERTS. Current value of MD3_MAX_VERTS is 4096.
            int    numTriangles = br.ReadInt32();   //Number of Triangle objects defined in this Surface, maximum of MD3_MAX_TRIANGLES. Current value of MD3_MAX_TRIANGLES is 8192.
            int    ofsTriangles = br.ReadInt32();   //Relative offset from SURFACE_START where the list of Triangle objects starts.
            int    ofsShaders   = br.ReadInt32();
            int    ofsST        = br.ReadInt32();   //Relative offset from SURFACE_START where the list of ST objects (s-t texture coordinates) starts.
            int    ofsNormal    = br.ReadInt32();   //Relative offset from SURFACE_START where the list of Vertex objects (X-Y-Z-N vertices) starts.
            int    ofsEnd       = br.ReadInt32();   //Relative offset from SURFACE_START to where the Surface object ends.

            // Sanity check
            if (frame < 0 || frame >= numFrames)
            {
                return("frame " + frame + " is outside of model's frame range [0.." + (numFrames - 1) + "]");
            }

            // Polygons
            if (start + ofsTriangles != br.BaseStream.Position)
            {
                br.BaseStream.Position = start + ofsTriangles;
            }

            for (int i = 0; i < numTriangles * 3; i++)
            {
                polyIndecesList.Add(vertexOffset + br.ReadInt32());
            }

            // Shaders
            if (start + ofsShaders != br.BaseStream.Position)
            {
                br.BaseStream.Position = start + ofsShaders;
            }

            skin = ReadString(br, 64);             //we are interested only in the first one

            // Vertices
            if (start + ofsST != br.BaseStream.Position)
            {
                br.BaseStream.Position = start + ofsST;
            }

            for (int i = 0; i < numVerts; i++)
            {
                WorldVertex v = new WorldVertex();
                v.c = -1;                 //white
                v.u = br.ReadSingle();
                v.v = br.ReadSingle();

                vertList.Add(v);
            }

            // Positions and normals
            long vertoffset = start + ofsNormal + numVerts * 8 * frame;             // The length of Vertex struct is 8 bytes

            if (br.BaseStream.Position != vertoffset)
            {
                br.BaseStream.Position = vertoffset;
            }

            for (int i = vertexOffset; i < vertexOffset + numVerts; i++)
            {
                WorldVertex v = vertList[i];

                //read vertex
                v.y = -(float)br.ReadInt16() / 64;
                v.x = (float)br.ReadInt16() / 64;
                v.z = (float)br.ReadInt16() / 64;

                //bounding box
                BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, v);

                var lat = br.ReadByte() * (2 * Math.PI) / 255.0;
                var lng = br.ReadByte() * (2 * Math.PI) / 255.0;

                v.nx = (float)(Math.Sin(lng) * Math.Sin(lat));
                v.ny = -(float)(Math.Cos(lng) * Math.Sin(lat));
                v.nz = (float)(Math.Cos(lat));

                vertList[i] = v;
            }

            if (start + ofsEnd != br.BaseStream.Position)
            {
                br.BaseStream.Position = start + ofsEnd;
            }
            return("");
        }
Example #23
0
        // This builds the geometry. Returns false when no geometry created.
        public override bool Setup()
        {
            WorldVertex[] verts;

            //int brightness = mode.CalculateBrightness(Sidedef.Sector.Brightness);
            int c1;
            int c2;

            if (!Sidedef.Line.IsFlagSet("8388608"))
            {
                c1 = Sidedef.Sector.ThingColor.GetColor();
                c2 = Sidedef.Sector.ThingColor.GetColor();
            }
            else
            {
                c1 = Sidedef.Sector.TopColor.GetColor();
                c2 = Sidedef.Sector.LowerColor.GetColor();
            }

            // Calculate size of this wall part
            float geotop    = (float)Math.Min(Sidedef.Sector.CeilHeight, Sidedef.Other.Sector.CeilHeight);
            float geobottom = (float)Math.Max(Sidedef.Sector.FloorHeight, Sidedef.Other.Sector.FloorHeight);
            float geoheight = geotop - geobottom;

            if (geoheight > 0.001f)
            {
                // Texture given?
                if ((Sidedef.MiddleTexture.Length > 0) && (Sidedef.MiddleTexture[0] != '-'))
                {
                    Vector2D t1 = new Vector2D();
                    Vector2D t2 = new Vector2D();
                    float    textop, texbottom;
                    float    cliptop    = 0.0f;
                    float    clipbottom = 0.0f;

                    // Load texture
                    base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture);
                    if (base.Texture == null)
                    {
                        base.Texture         = General.Map.Data.MissingTexture3D;
                        setuponloadedtexture = Sidedef.LongMiddleTexture;
                    }
                    else
                    {
                        if (!base.Texture.IsImageLoaded)
                        {
                            setuponloadedtexture = Sidedef.LongMiddleTexture;
                        }
                    }

                    // Get texture scaled size
                    Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);

                    // villsa
                    if (General.Map.FormatInterface.InDoom64Mode)
                    {
                        textop = geotop;
                    }
                    else
                    {
                        // Because the middle texture on a double sided line does not repeat vertically,
                        // we first determine the visible portion of the texture
                        if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
                        {
                            textop = geobottom + tsz.y;
                        }
                        else
                        {
                            textop = geotop;
                        }

                        // Apply texture offset
                        textop += Sidedef.OffsetY;
                    }

                    // villsa
                    if (General.Map.FormatInterface.InDoom64Mode)
                    {
                        texbottom = geobottom;
                    }
                    else
                    {
                        // Calculate texture portion bottom
                        texbottom = textop - tsz.y;
                    }

                    // Clip texture portion by geometry
                    if (geotop < textop)
                    {
                        cliptop = textop - geotop; textop = geotop;
                    }
                    if (geobottom > texbottom)
                    {
                        clipbottom = geobottom - texbottom; texbottom = geobottom;
                    }

                    // Check if anything is still visible
                    if ((textop - texbottom) > 0.001f)
                    {
                        // Determine texture coordinatess

                        // villsa
                        if (General.Map.FormatInterface.InDoom64Mode)
                        {
                            t1.y = geobottom + Sidedef.OffsetY - geotop;
                            t2.y = geotop + Sidedef.OffsetY - geotop;
                        }
                        else
                        {
                            t1.y = cliptop;
                            t2.y = tsz.y - clipbottom;
                        }
                        t1.x = Sidedef.OffsetX;
                        t2.x = t1.x + Sidedef.Line.Length;

                        // Transform pixel coordinates to texture coordinates
                        t1 /= tsz;
                        t2 /= tsz;

                        // Get world coordinates for geometry
                        Vector2D v1, v2;
                        if (Sidedef.IsFront)
                        {
                            v1 = Sidedef.Line.Start.Position;
                            v2 = Sidedef.Line.End.Position;
                        }
                        else
                        {
                            v1 = Sidedef.Line.End.Position;
                            v2 = Sidedef.Line.Start.Position;
                        }

                        // Make vertices
                        verts    = new WorldVertex[6];
                        verts[0] = new WorldVertex(v1.x, v1.y, texbottom, c2, t1.x, t2.y);
                        verts[1] = new WorldVertex(v1.x, v1.y, textop, c1, t1.x, t1.y);
                        verts[2] = new WorldVertex(v2.x, v2.y, textop, c1, t2.x, t1.y);
                        verts[3] = verts[0];
                        verts[4] = verts[2];
                        verts[5] = new WorldVertex(v2.x, v2.y, texbottom, c2, t2.x, t2.y);

                        // Keep properties
                        base.top    = textop;
                        base.bottom = texbottom;

                        // Apply vertices
                        base.SetVertices(verts);
                        return(true);
                    }
                }
            }

            // No geometry for invisible wall
            base.top    = geotop;
            base.bottom = geotop;               // bottom same as top so that it has a height of 0 (otherwise it will still be picked up by object picking)
            verts       = new WorldVertex[0];
            base.SetVertices(verts);
            return(false);
        }
Example #24
0
        // This builds the thing geometry. Returns false when nothing was created.
        public virtual bool Setup()
        {
            // Must have a width and height!
            float radius, height;

            // Find the sector in which the thing resides
            Thing.DetermineSector(mode.BlockMap);

            if (sprite != null)
            {
                //mxd. Transparency and brightness
                int brightness;
                if (Thing.SemiTransparent)
                {
                    brightness      = MapElement.CalculateBrightness(Thing.Shade, (byte)(Thing.Transparent ? 85 : 170));
                    this.RenderPass = RenderPass.Alpha;
                }
                else
                {
                    brightness      = MapElement.CalculateBrightness(Thing.Shade);
                    this.RenderPass = RenderPass.Mask;
                }

                // Check if the texture is loaded
                sprite.LoadImage();
                isloaded = sprite.IsImageLoaded;

                if (isloaded)
                {
                    base.Texture = sprite;

                    // Determine sprite size and offsets
                    bool flooraligned = Thing.FlatAligned;
                    bool wallaligned  = Thing.WallAligned;
                    bool truecentered = Thing.TrueCentered;

                    float xratio = Thing.RepeatX * ((flooraligned && truecentered) ? 0.2f : 0.25f);
                    float yratio = Thing.RepeatY * 0.25f;

                    int xsize = (int)(sprite.Width * xratio);
                    int ysize = (int)(sprite.Height * yratio);

                    int tilexoff = Thing.OffsetX + sprite.OffsetX;
                    int tileyoff = Thing.OffsetY + sprite.OffsetY;

                    int xoff = (int)(tilexoff * xratio);
                    int yoff = (int)(tileyoff * yratio);

                    if (truecentered && !flooraligned)
                    {
                        yoff -= ysize / 2;                                                   // Seems that centeryoff shenanigans in polymer_updatesprite.cpp do exactly the same thing...
                    }
                    bool xflip = Thing.FlipX;
                    bool yflip = Thing.FlipY;

                    // Initially set flipu and flipv.
                    bool flipu = (xflip ^ flooraligned);
                    bool flipv = (yflip && !flooraligned);

                    if (flipu)
                    {
                        xoff = -xoff;
                    }
                    if (yflip && (flooraligned || wallaligned))
                    {
                        yoff = -yoff;
                    }

                    radius = xsize * 0.5f;
                    height = ysize;

                    // Make vertices
                    WorldVertex[] verts = new WorldVertex[6];
                    verts[0] = new WorldVertex(-radius + xoff, 0.0f, yoff, brightness, 0.0f, 1.0f);
                    verts[1] = new WorldVertex(-radius + xoff, 0.0f, height + yoff, brightness, 0.0f, 0.0f);
                    verts[2] = new WorldVertex(radius + xoff, 0.0f, height + yoff, brightness, 1.0f, 0.0f);
                    verts[3] = verts[0];
                    verts[4] = verts[2];
                    verts[5] = new WorldVertex(radius + xoff, 0.0f, yoff, brightness, 1.0f, 1.0f);

                    // Update UVs if needed
                    if (flipu || flipv)
                    {
                        for (int i = 0; i < 6; i++)
                        {
                            if (flipu)
                            {
                                verts[i].u = (verts[i].u - 1.0f) * -1.0f;
                            }
                            if (flipv)
                            {
                                verts[i].v = (verts[i].v - 1.0f) * -1.0f;
                            }
                        }
                    }

                    SetVertices(verts);
                }
                else
                {
                    base.Texture = General.Map.Data.Hourglass3D;

                    // Determine sprite size
                    radius = Math.Min(Texture.Width / 2f, Texture.Height / 2f);
                    height = Math.Min(Texture.Width, Texture.Height);

                    // Make vertices
                    WorldVertex[] verts = new WorldVertex[6];
                    verts[0] = new WorldVertex(-radius, 0.0f, 0.0f, brightness, 0.0f, 1.0f);
                    verts[1] = new WorldVertex(-radius, 0.0f, height, brightness, 0.0f, 0.0f);
                    verts[2] = new WorldVertex(+radius, 0.0f, height, brightness, 1.0f, 0.0f);
                    verts[3] = verts[0];
                    verts[4] = verts[2];
                    verts[5] = new WorldVertex(+radius, 0.0f, 0.0f, brightness, 1.0f, 1.0f);
                    SetVertices(verts);
                }
            }
            else
            {
                // Use some default values...
                radius = MINIMUM_RADIUS;
                height = MINIMUM_HEIGHT;

                SetVertices(new WorldVertex[0]);
            }

            // Determine position
            Vector3D pos = Thing.Position;

            if (Thing.Sector != null)
            {
                pos.z = Thing.Sector.FloorPlane.GetZ(Thing.Position.x, Thing.Position.y);
            }
            if (Thing.Position.z > 0)
            {
                pos.z += Thing.Position.z;
            }

            // Check if above ceiling
            if ((Thing.Sector != null) && ((pos.z + height) > Thing.Sector.CeilingHeight))
            {
                // Put thing against ceiling
                pos.z = Thing.Sector.CeilingHeight - height;
            }

            // Apply settings
            SetPosition(pos);
            SetCageSize(Math.Max(radius, MINIMUM_RADIUS), Math.Max(height, MINIMUM_HEIGHT));
            SetCageColor(Thing.Color);

            // Keep info for object picking
            cageradius2 = radius * Angle2D.SQRT2;
            cageradius2 = cageradius2 * cageradius2;
            pos2d       = pos;
            boxp1       = new Vector3D(pos.x - radius, pos.y - radius, pos.z);
            boxp2       = new Vector3D(pos.x + radius, pos.y + radius, pos.z + height);

            // Done
            changed = false;
            return(true);
        }
        // This builds the geometry. Returns false when no geometry created.
        public override bool Setup()
        {
            //mxd
            if (Sidedef.LongMiddleTexture == MapSet.EmptyLongName)
            {
                base.SetVertices(null);
                return(false);
            }

            Vector2D vl, vr;

            //mxd. lightfog flag support
            int  lightvalue;
            bool lightabsolute;

            GetLightValue(out lightvalue, out lightabsolute);

            Vector2D tscale = new Vector2D(Sidedef.Fields.GetValue("scalex_mid", 1.0f),
                                           Sidedef.Fields.GetValue("scaley_mid", 1.0f));
            Vector2D tscaleAbs = new Vector2D(Math.Abs(tscale.x), Math.Abs(tscale.y));
            Vector2D toffset   = new Vector2D(Sidedef.Fields.GetValue("offsetx_mid", 0.0f),
                                              Sidedef.Fields.GetValue("offsety_mid", 0.0f));

            // Left and right vertices for this sidedef
            if (Sidedef.IsFront)
            {
                vl = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
                vr = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
            }
            else
            {
                vl = new Vector2D(Sidedef.Line.End.Position.x, Sidedef.Line.End.Position.y);
                vr = new Vector2D(Sidedef.Line.Start.Position.x, Sidedef.Line.Start.Position.y);
            }

            // Load sector data
            SectorData sd  = mode.GetSectorData(Sidedef.Sector);
            SectorData osd = mode.GetSectorData(Sidedef.Other.Sector);

            if (!osd.Updated)
            {
                osd.Update();
            }

            // Load texture
            if (Sidedef.LongMiddleTexture != MapSet.EmptyLongName)
            {
                base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongMiddleTexture);
                if (base.Texture == null || base.Texture is UnknownImage)
                {
                    base.Texture         = General.Map.Data.UnknownTexture3D;
                    setuponloadedtexture = Sidedef.LongMiddleTexture;
                }
                else if (!base.Texture.IsImageLoaded)
                {
                    setuponloadedtexture = Sidedef.LongMiddleTexture;
                }
            }
            else
            {
                // Use missing texture
                base.Texture         = General.Map.Data.MissingTexture3D;
                setuponloadedtexture = 0;
            }

            // Get texture scaled size
            Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);

            tsz = tsz / tscale;

            // Get texture offsets
            Vector2D tof = new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);

            tof = tof + toffset;
            tof = tof / tscaleAbs;
            if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
            {
                tof = tof * base.Texture.Scale;
            }

            // Determine texture coordinates plane as they would be in normal circumstances.
            // We can then use this plane to find any texture coordinate we need.
            // The logic here is the same as in the original VisualMiddleSingle (except that
            // the values are stored in a TexturePlane)
            // NOTE: I use a small bias for the floor height, because if the difference in
            // height is 0 then the TexturePlane doesn't work!
            TexturePlane tp        = new TexturePlane();
            float        floorbias = (Sidedef.Sector.CeilHeight == Sidedef.Sector.FloorHeight) ? 1.0f : 0.0f;
            float        geotop    = Math.Min(Sidedef.Sector.CeilHeight, Sidedef.Other.Sector.CeilHeight);
            float        geobottom = Math.Max(Sidedef.Sector.FloorHeight, Sidedef.Other.Sector.FloorHeight);
            float        zoffset   = Sidedef.Sector.CeilHeight - Sidedef.Other.Sector.CeilHeight;    //mxd

            // When lower unpegged is set, the middle texture is bound to the bottom
            if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
            {
                tp.tlt.y = tsz.y - (geotop - geobottom);
            }

            if (zoffset > 0)
            {
                tp.tlt.y -= zoffset;                                      //mxd
            }
            tp.trb.x = tp.tlt.x + (float)Math.Round(Sidedef.Line.Length); //mxd. (G)ZDoom snaps texture coordinates to integral linedef length
            tp.trb.y = tp.tlt.y + (Sidedef.Sector.CeilHeight - (Sidedef.Sector.FloorHeight + floorbias));

            // Apply texture offset
            tp.tlt += tof;
            tp.trb += tof;

            // Transform pixel coordinates to texture coordinates
            tp.tlt /= tsz;
            tp.trb /= tsz;

            // Left top and right bottom of the geometry that
            tp.vlt = new Vector3D(vl.x, vl.y, Sidedef.Sector.CeilHeight);
            tp.vrb = new Vector3D(vr.x, vr.y, Sidedef.Sector.FloorHeight + floorbias);

            // Make the right-top coordinates
            tp.trt = new Vector2D(tp.trb.x, tp.tlt.y);
            tp.vrt = new Vector3D(tp.vrb.x, tp.vrb.y, tp.vlt.z);

            // Keep top and bottom planes for intersection testing
            top    = sd.Ceiling.plane;
            bottom = sd.Floor.plane;

            // Create initial polygon, which is just a quad between floor and ceiling
            WallPolygon poly = new WallPolygon();

            poly.Add(new Vector3D(vl.x, vl.y, sd.Floor.plane.GetZ(vl)));
            poly.Add(new Vector3D(vl.x, vl.y, sd.Ceiling.plane.GetZ(vl)));
            poly.Add(new Vector3D(vr.x, vr.y, sd.Ceiling.plane.GetZ(vr)));
            poly.Add(new Vector3D(vr.x, vr.y, sd.Floor.plane.GetZ(vr)));

            // Determine initial color
            int lightlevel = lightabsolute ? lightvalue : sd.Ceiling.brightnessbelow + lightvalue;

            //mxd. This calculates light with doom-style wall shading
            PixelColor wallbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightlevel, Sidedef));
            PixelColor wallcolor      = PixelColor.Modulate(sd.Ceiling.colorbelow, wallbrightness);

            fogfactor  = CalculateFogFactor(lightlevel);
            poly.color = wallcolor.WithAlpha(255).ToInt();

            // Cut off the part below the other floor and above the other ceiling
            CropPoly(ref poly, osd.Ceiling.plane, true);
            CropPoly(ref poly, osd.Floor.plane, true);

            // Determine if we should repeat the middle texture
            repeatmidtex = Sidedef.IsFlagSet("wrapmidtex") || Sidedef.Line.IsFlagSet("wrapmidtex");             //mxd
            if (!repeatmidtex)
            {
                // First determine the visible portion of the texture
                float textop;

                // Determine top portion height
                if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
                {
                    textop = geobottom + tof.y + Math.Abs(tsz.y);
                }
                else
                {
                    textop = geotop + tof.y;
                }

                // Calculate bottom portion height
                float texbottom = textop - Math.Abs(tsz.y);

                // Create crop planes (we also need these for intersection testing)
                topclipplane    = new Plane(new Vector3D(0, 0, -1), textop);
                bottomclipplane = new Plane(new Vector3D(0, 0, 1), -texbottom);

                // Crop polygon by these heights
                CropPoly(ref poly, topclipplane, true);
                CropPoly(ref poly, bottomclipplane, true);
            }

            //mxd. In(G)ZDoom, middle sidedef parts are not clipped by extrafloors of any type...
            List <WallPolygon> polygons = new List <WallPolygon> {
                poly
            };

            //ClipExtraFloors(polygons, sd.ExtraFloors, true); //mxd
            //ClipExtraFloors(polygons, osd.ExtraFloors, true); //mxd

            //if(polygons.Count > 0)
            //{
            // Keep top and bottom planes for intersection testing
            top    = osd.Ceiling.plane;
            bottom = osd.Floor.plane;

            // Process the polygon and create vertices
            List <WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute);

            if (verts.Count > 2)
            {
                // Apply alpha to vertices
                byte alpha = SetLinedefRenderstyle(true);
                if (alpha < 255)
                {
                    for (int i = 0; i < verts.Count; i++)
                    {
                        WorldVertex v = verts[i];
                        v.c      = PixelColor.FromInt(v.c).WithAlpha(alpha).ToInt();
                        verts[i] = v;
                    }
                }

                base.SetVertices(verts);
                return(true);
            }
            //}

            base.SetVertices(null);             //mxd
            return(false);
        }
Example #26
0
        // This builds the thing geometry. Returns false when nothing was created.
        public virtual bool Setup()
        {
            PixelColor sectorcolor = new PixelColor(255, 255, 255, 255);

            // Must have a width and height!
            if ((info.Radius < 0.1f) || (info.Height < 0.1f))
            {
                return(false);
            }

            // Find the sector in which the thing resides
            Thing.DetermineSector(mode.BlockMap);

            if (sprite != null)
            {
                if (Thing.Sector != null)
                {
                    // Use sector brightness for color shading
                    byte brightness = (byte)General.Clamp(Thing.Sector.Brightness, 0, 255);
                    sectorcolor = new PixelColor(255, brightness, brightness, brightness);
                }

                // Check if the texture is loaded
                sprite.LoadImage();
                isloaded = sprite.IsImageLoaded;
                if (isloaded)
                {
                    float offsetx = 0.0f;
                    float offsety = 0.0f;

                    base.Texture = sprite;

                    // Determine sprite size and offset
                    float radius = sprite.ScaledWidth * 0.5f;
                    float height = sprite.ScaledHeight;
                    if (sprite is SpriteImage)
                    {
                        offsetx = (sprite as SpriteImage).OffsetX - radius;
                        offsety = (sprite as SpriteImage).OffsetY - height;
                    }

                    // Scale by thing type/actor scale
                    // We do this after the offset x/y determination above, because that is entirely in sprite pixels space
                    radius  *= info.SpriteScale.Width;
                    height  *= info.SpriteScale.Height;
                    offsetx *= info.SpriteScale.Width;
                    offsety *= info.SpriteScale.Height;

                    // Make vertices
                    WorldVertex[] verts = new WorldVertex[6];
                    verts[0] = new WorldVertex(-radius + offsetx, 0.0f, 0.0f + offsety, sectorcolor.ToInt(), 0.0f, 1.0f);
                    verts[1] = new WorldVertex(-radius + offsetx, 0.0f, height + offsety, sectorcolor.ToInt(), 0.0f, 0.0f);
                    verts[2] = new WorldVertex(+radius + offsetx, 0.0f, height + offsety, sectorcolor.ToInt(), 1.0f, 0.0f);
                    verts[3] = verts[0];
                    verts[4] = verts[2];
                    verts[5] = new WorldVertex(+radius + offsetx, 0.0f, 0.0f + offsety, sectorcolor.ToInt(), 1.0f, 1.0f);
                    SetVertices(verts);
                }
                else
                {
                    base.Texture = General.Map.Data.Hourglass3D;

                    // Determine sprite size
                    float radius = Math.Min(info.Radius, info.Height / 2f);
                    float height = Math.Min(info.Radius * 2f, info.Height);

                    // Make vertices
                    WorldVertex[] verts = new WorldVertex[6];
                    verts[0] = new WorldVertex(-radius, 0.0f, 0.0f, sectorcolor.ToInt(), 0.0f, 1.0f);
                    verts[1] = new WorldVertex(-radius, 0.0f, height, sectorcolor.ToInt(), 0.0f, 0.0f);
                    verts[2] = new WorldVertex(+radius, 0.0f, height, sectorcolor.ToInt(), 1.0f, 0.0f);
                    verts[3] = verts[0];
                    verts[4] = verts[2];
                    verts[5] = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor.ToInt(), 1.0f, 1.0f);
                    SetVertices(verts);
                }
            }

            // Determine position
            Vector3D pos = Thing.Position;

            if (info.AbsoluteZ)
            {
                // Absolute Z position
                pos.z = Thing.Position.z;
            }
            else if (info.Hangs)
            {
                // Hang from ceiling
                if (Thing.Sector != null)
                {
                    pos.z = Thing.Sector.CeilHeight - info.Height;
                }
                if (Thing.Position.z > 0)
                {
                    pos.z -= Thing.Position.z;
                }

                // Check if below floor
                if ((Thing.Sector != null) && (pos.z < Thing.Sector.FloorHeight))
                {
                    // Put thing on the floor
                    pos.z = Thing.Sector.FloorHeight;
                }
            }
            else
            {
                // Stand on floor
                if (Thing.Sector != null)
                {
                    pos.z = Thing.Sector.FloorHeight;
                }
                if (Thing.Position.z > 0)
                {
                    pos.z += Thing.Position.z;
                }

                // Check if above ceiling
                if ((Thing.Sector != null) && ((pos.z + info.Height) > Thing.Sector.CeilHeight))
                {
                    // Put thing against ceiling
                    pos.z = Thing.Sector.CeilHeight - info.Height;
                }
            }

            // Apply settings
            SetPosition(pos);
            SetCageSize(info.Radius, info.Height);
            SetCageColor(Thing.Color);

            // Keep info for object picking
            cageradius2 = info.Radius * Angle2D.SQRT2;
            cageradius2 = cageradius2 * cageradius2;
            pos2d       = pos;
            boxp1       = new Vector3D(pos.x - info.Radius, pos.y - info.Radius, pos.z);
            boxp2       = new Vector3D(pos.x + info.Radius, pos.y + info.Radius, pos.z + info.Height);

            // Done
            changed = false;
            return(true);
        }
Example #27
0
        //mxd
        public bool Setup(SectorLevel level, Effect3DFloor extrafloor, bool innerside)
        {
            Sector   s = level.sector;
            Vector2D texscale;

            this.innerside = innerside;

            base.Setup(level, extrafloor);

            // Fetch ZDoom fields
            float    rotate = Angle2D.DegToRad(s.Fields.GetValue("rotationfloor", 0.0f));
            Vector2D offset = new Vector2D(s.Fields.GetValue("xpanningfloor", 0.0f),
                                           s.Fields.GetValue("ypanningfloor", 0.0f));
            Vector2D scale = new Vector2D(s.Fields.GetValue("xscalefloor", 1.0f),
                                          s.Fields.GetValue("yscalefloor", 1.0f));

            //Load floor texture
            if (s.LongFloorTexture != MapSet.EmptyLongName)
            {
                base.Texture = General.Map.Data.GetFlatImage(s.LongFloorTexture);
                if (base.Texture == null || base.Texture is UnknownImage)
                {
                    base.Texture         = General.Map.Data.UnknownTexture3D;
                    setuponloadedtexture = s.LongFloorTexture;
                }
                else if (!base.Texture.IsImageLoaded)
                {
                    setuponloadedtexture = s.LongFloorTexture;
                }
            }
            else
            {
                // Use missing texture
                base.Texture         = General.Map.Data.MissingTexture3D;
                setuponloadedtexture = 0;
            }

            // Determine texture scale
            if (base.Texture.IsImageLoaded)
            {
                texscale = new Vector2D(1.0f / base.Texture.ScaledWidth, 1.0f / base.Texture.ScaledHeight);
            }
            else
            {
                texscale = new Vector2D(1.0f / 64.0f, 1.0f / 64.0f);
            }

            // Determine brightness
            int color = PixelColor.FromInt(level.color).WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt();

            //mxd. Top extrafloor level should calculate fogdensity
            //from the brightness of the level above it
            int targetbrightness;

            if (extrafloor != null && extrafloor.VavoomType && !level.disablelighting)
            {
                targetbrightness = 0;
                SectorData sd = mode.GetSectorData(this.Sector.Sector);
                for (int i = 0; i < sd.LightLevels.Count - 1; i++)
                {
                    if (sd.LightLevels[i] == level)
                    {
                        targetbrightness = sd.LightLevels[i + 1].brightnessbelow;
                        break;
                    }
                }
            }
            else
            {
                targetbrightness = level.brightnessbelow;
            }

            //mxd. Determine fog density
            fogfactor = CalculateFogFactor(targetbrightness);

            // Make vertices
            ReadOnlyCollection <Vector2D> triverts = Sector.Sector.Triangles.Vertices;

            WorldVertex[] verts = new WorldVertex[triverts.Count];
            for (int i = 0; i < triverts.Count; i++)
            {
                // Color shading
                verts[i].c = color;                 //mxd

                // Vertex coordinates
                verts[i].x = triverts[i].x;
                verts[i].y = triverts[i].y;
                verts[i].z = level.plane.GetZ(triverts[i]);

                // Texture coordinates
                Vector2D pos = triverts[i];
                pos        = pos.GetRotated(rotate);
                pos.y      = -pos.y;
                pos        = (pos + offset) * scale * texscale;
                verts[i].u = pos.x;
                verts[i].v = pos.y;
            }

            // The sector triangulation created clockwise triangles that
            // are right up for the floor. For the ceiling we must flip
            // the triangles upside down.
            if ((extrafloor != null) && !extrafloor.VavoomType && !innerside)
            {
                SwapTriangleVertices(verts);
            }

            // Determine render pass
            if (extrafloor != null)
            {
                if (extrafloor.Sloped3dFloor)                //mxd
                {
                    this.RenderPass = RenderPass.Mask;
                }
                else if (extrafloor.RenderAdditive)                //mxd
                {
                    this.RenderPass = RenderPass.Additive;
                }
                else if (level.alpha < 255)
                {
                    this.RenderPass = RenderPass.Alpha;
                }
                else
                {
                    this.RenderPass = RenderPass.Mask;
                }
            }
            else
            {
                this.RenderPass = RenderPass.Solid;
            }

            //mxd. Update sky render flag
            UpdateSkyRenderFlag();

            // Apply vertices
            base.SetVertices(verts);
            return(verts.Length > 0);
        }
Example #28
0
        // This builds the thing geometry. Returns false when nothing was created.
        public virtual bool Setup()
        {
            int sectorcolor = 0;

            // Must have a width and height!
            if ((info.Radius < 0.1f) || (info.Height < 0.1f))
            {
                return(false);
            }

            // Find the sector in which the thing resides
            Thing.DetermineSector(mode.BlockMap);

            if (sprite != null)
            {
                if (Thing.Sector != null)
                {
                    // Use sector brightness for color shading
                    //byte brightness = (byte)General.Clamp(Thing.Sector.Brightness, 0, 255);
                    //sectorcolor = new PixelColor(255, brightness, brightness, brightness);

                    // villsa 9/11/11 (builder64) cameras/triggers are rendered full bright
                    if (Thing.Type == 0 || Thing.Type == 89)
                    {
                        sectorcolor = -1;
                    }
                    else
                    {
                        sectorcolor = Thing.Sector.ThingColor.GetColor();
                    }
                }

                // villsa 9/11/11 (builder64) render camera/trigger icon
                if (Thing.Type == 0 || Thing.Type == 89)
                {
                    if (Thing.Type == 89)
                    {
                        base.Texture = General.Map.Data.ThingTrigger;
                    }
                    else
                    {
                        base.Texture = General.Map.Data.ThingCamera;
                    }

                    // Determine sprite size
                    float radius = Math.Min(info.Radius, info.Height / 2f);
                    float height = Math.Min(info.Radius * 2f, info.Height);

                    // Make vertices
                    WorldVertex[] verts = new WorldVertex[6];
                    verts[0] = new WorldVertex(-radius, 0.0f, 0.0f, sectorcolor, 0.0f, 1.0f);
                    verts[1] = new WorldVertex(-radius, 0.0f, height, sectorcolor, 0.0f, 0.0f);
                    verts[2] = new WorldVertex(+radius, 0.0f, height, sectorcolor, 1.0f, 0.0f);
                    verts[3] = verts[0];
                    verts[4] = verts[2];
                    verts[5] = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor, 1.0f, 1.0f);
                    SetVertices(verts);
                }
                else
                {
                    // Check if the texture is loaded
                    sprite.LoadImage();
                    isloaded = sprite.IsImageLoaded;
                    if (isloaded)
                    {
                        float offsetx = 0.0f;
                        float offsety = 0.0f;

                        base.Texture = sprite;

                        // Determine sprite size and offset
                        float radius = sprite.ScaledWidth * 0.5f;
                        float height = sprite.ScaledHeight;
                        if (sprite is SpriteImage)
                        {
                            offsetx = (sprite as SpriteImage).OffsetX - radius;
                            offsety = (sprite as SpriteImage).OffsetY - height;
                        }

                        // Make vertices
                        WorldVertex[] verts = new WorldVertex[6];
                        verts[0] = new WorldVertex(-radius + offsetx, 0.0f, 0.0f + offsety, sectorcolor, 0.0f, 1.0f);
                        verts[1] = new WorldVertex(-radius + offsetx, 0.0f, height + offsety, sectorcolor, 0.0f, 0.0f);
                        verts[2] = new WorldVertex(+radius + offsetx, 0.0f, height + offsety, sectorcolor, 1.0f, 0.0f);
                        verts[3] = verts[0];
                        verts[4] = verts[2];
                        verts[5] = new WorldVertex(+radius + offsetx, 0.0f, 0.0f + offsety, sectorcolor, 1.0f, 1.0f);
                        SetVertices(verts);
                    }
                    else
                    {
                        base.Texture = General.Map.Data.Hourglass3D;

                        // Determine sprite size
                        float radius = Math.Min(info.Radius, info.Height / 2f);
                        float height = Math.Min(info.Radius * 2f, info.Height);

                        // Make vertices
                        WorldVertex[] verts = new WorldVertex[6];
                        verts[0] = new WorldVertex(-radius, 0.0f, 0.0f, sectorcolor, 0.0f, 1.0f);
                        verts[1] = new WorldVertex(-radius, 0.0f, height, sectorcolor, 0.0f, 0.0f);
                        verts[2] = new WorldVertex(+radius, 0.0f, height, sectorcolor, 1.0f, 0.0f);
                        verts[3] = verts[0];
                        verts[4] = verts[2];
                        verts[5] = new WorldVertex(+radius, 0.0f, 0.0f, sectorcolor, 1.0f, 1.0f);
                        SetVertices(verts);
                    }
                }
            }

            // Determine position
            Vector3D pos = Thing.Position;

            if (info.AbsoluteZ)
            {
                // Absolute Z position
                pos.z = Thing.Position.z;
            }
            else if (info.Hangs)
            {
                // Hang from ceiling
                if (Thing.Sector != null)
                {
                    pos.z = Thing.Sector.CeilHeight - info.Height;
                }
                if (Thing.Position.z > 0)
                {
                    pos.z -= Thing.Position.z;
                }

                // Check if below floor
                if ((Thing.Sector != null) && (pos.z < Thing.Sector.FloorHeight))
                {
                    // Put thing on the floor
                    pos.z = Thing.Sector.FloorHeight;
                }
            }
            else
            {
                // Stand on floor
                if (Thing.Sector != null)
                {
                    pos.z = Thing.Sector.FloorHeight;
                }
                if (Thing.Position.z > 0)
                {
                    pos.z += Thing.Position.z;
                }

                // Check if above ceiling
                if ((Thing.Sector != null) && ((pos.z + info.Height) > Thing.Sector.CeilHeight))
                {
                    // Put thing against ceiling
                    pos.z = Thing.Sector.CeilHeight - info.Height;
                }
            }

            // Apply settings
            SetPosition(pos);
            SetCageSize(info.Radius, info.Height);
            SetCageColor(Thing.Color);

            // Keep info for object picking
            cageradius2 = info.Radius * Angle2D.SQRT2;
            cageradius2 = cageradius2 * cageradius2;
            pos2d       = pos;
            boxp1       = new Vector3D(pos.x - info.Radius, pos.y - info.Radius, pos.z);
            boxp2       = new Vector3D(pos.x + info.Radius, pos.y + info.Radius, pos.z + info.Height);

            // Done
            changed = false;
            return(true);
        }
        // This updates the visual thing
        public virtual void Update()
        {
            // Do we need to update the geometry buffer?
            if (updategeo)
            {
                //mxd. Trash geometry buffers
                if (geobuffers != null)
                {
                    foreach (VertexBuffer geobuffer in geobuffers)
                    {
                        geobuffer.Dispose();
                    }
                }

                // Any vertics?
                if (vertices.Length > 0)
                {
                    geobuffers = new VertexBuffer[vertices.Length];
                    for (int i = 0; i < vertices.Length; i++)
                    {
                        // Make a new buffer
                        geobuffers[i] = new VertexBuffer(General.Map.Graphics.Device, WorldVertex.Stride * vertices[i].Length,
                                                         Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default);

                        // Fill the buffer
                        DataStream bufferstream = geobuffers[i].Lock(0, WorldVertex.Stride * vertices[i].Length, LockFlags.Discard);
                        bufferstream.WriteRange(vertices[i]);
                        geobuffers[i].Unlock();
                        bufferstream.Dispose();
                    }
                }

                //mxd. Check if thing is light
                CheckLightState();

                // Done
                updategeo = false;
            }

            //mxd. Need to update thing cage?
            if (updatecage)
            {
                // Trash cage buffer
                if (cagebuffer != null)
                {
                    cagebuffer.Dispose();
                }
                cagebuffer = null;

                // Make a new cage
                List <WorldVertex> cageverts;
                if (sizeless)
                {
                    WorldVertex v0 = new WorldVertex(-thing.Size + position_v3.X, -thing.Size + position_v3.Y, position_v3.Z);
                    WorldVertex v1 = new WorldVertex(thing.Size + position_v3.X, thing.Size + position_v3.Y, position_v3.Z);
                    WorldVertex v2 = new WorldVertex(thing.Size + position_v3.X, -thing.Size + position_v3.Y, position_v3.Z);
                    WorldVertex v3 = new WorldVertex(-thing.Size + position_v3.X, thing.Size + position_v3.Y, position_v3.Z);
                    WorldVertex v4 = new WorldVertex(position_v3.X, position_v3.Y, thing.Size + position_v3.Z);
                    WorldVertex v5 = new WorldVertex(position_v3.X, position_v3.Y, -thing.Size + position_v3.Z);

                    cageverts = new List <WorldVertex>(new[] { v0, v1, v2, v3, v4, v5 });
                }
                else
                {
                    float top    = position_v3.Z + thing.Height;
                    float bottom = position_v3.Z;

                    WorldVertex v0 = new WorldVertex(-thing.Size + position_v3.X, -thing.Size + position_v3.Y, bottom);
                    WorldVertex v1 = new WorldVertex(-thing.Size + position_v3.X, thing.Size + position_v3.Y, bottom);
                    WorldVertex v2 = new WorldVertex(thing.Size + position_v3.X, thing.Size + position_v3.Y, bottom);
                    WorldVertex v3 = new WorldVertex(thing.Size + position_v3.X, -thing.Size + position_v3.Y, bottom);

                    WorldVertex v4 = new WorldVertex(-thing.Size + position_v3.X, -thing.Size + position_v3.Y, top);
                    WorldVertex v5 = new WorldVertex(-thing.Size + position_v3.X, thing.Size + position_v3.Y, top);
                    WorldVertex v6 = new WorldVertex(thing.Size + position_v3.X, thing.Size + position_v3.Y, top);
                    WorldVertex v7 = new WorldVertex(thing.Size + position_v3.X, -thing.Size + position_v3.Y, top);

                    cageverts = new List <WorldVertex>(new[] { v0, v1,
                                                               v1, v2,
                                                               v2, v3,
                                                               v3, v0,
                                                               v4, v5,
                                                               v5, v6,
                                                               v6, v7,
                                                               v7, v4,
                                                               v0, v4,
                                                               v1, v5,
                                                               v2, v6,
                                                               v3, v7 });
                }

                // Make new arrow
                if (Thing.IsDirectional)
                {
                    Matrix transform = Matrix.Scaling(thing.Size, thing.Size, thing.Size)
                                       * (Matrix.RotationY(-Thing.RollRad) * Matrix.RotationX(-Thing.PitchRad) * Matrix.RotationZ(Thing.Angle))
                                       * (sizeless ? position : position * Matrix.Translation(0.0f, 0.0f, thingheight / 2f));

                    WorldVertex a0 = new WorldVertex(Vector3D.Transform(0.0f, 0.0f, 0.0f, transform));                     //start
                    WorldVertex a1 = new WorldVertex(Vector3D.Transform(0.0f, -1.5f, 0.0f, transform));                    //end
                    WorldVertex a2 = new WorldVertex(Vector3D.Transform(0.2f, -1.1f, 0.2f, transform));
                    WorldVertex a3 = new WorldVertex(Vector3D.Transform(-0.2f, -1.1f, 0.2f, transform));
                    WorldVertex a4 = new WorldVertex(Vector3D.Transform(0.2f, -1.1f, -0.2f, transform));
                    WorldVertex a5 = new WorldVertex(Vector3D.Transform(-0.2f, -1.1f, -0.2f, transform));

                    cageverts.AddRange(new[] { a0, a1,
                                               a1, a2,
                                               a1, a3,
                                               a1, a4,
                                               a1, a5 });
                }

                // Create buffer
                WorldVertex[] cv = cageverts.ToArray();
                cagelength = cv.Length / 2;
                cagebuffer = new VertexBuffer(General.Map.Graphics.Device, WorldVertex.Stride * cv.Length, Usage.WriteOnly | Usage.Dynamic, VertexFormat.None, Pool.Default);
                cagebuffer.Lock(0, WorldVertex.Stride * cv.Length, LockFlags.None).WriteRange(cv);
                cagebuffer.Unlock();

                // Done
                updatecage = false;
            }
        }
Example #30
0
        // This builds the geometry. Returns false when no geometry created.
        public override bool Setup()
        {
            int brightness = mode.CalculateBrightness(Sidedef.Sector.Brightness);

            // Calculate size of this wall part
            float geotop    = (float)Sidedef.Other.Sector.FloorHeight;
            float geobottom = (float)Sidedef.Sector.FloorHeight;
            float geoheight = geotop - geobottom;

            if (geoheight > 0.001f)
            {
                Vector2D t1 = new Vector2D();
                Vector2D t2 = new Vector2D();

                // Texture given?
                if ((Sidedef.LowTexture.Length > 0) && (Sidedef.LowTexture[0] != '-'))
                {
                    // Load texture
                    base.Texture = General.Map.Data.GetTextureImage(Sidedef.LongLowTexture);
                    if (base.Texture == null)
                    {
                        base.Texture         = General.Map.Data.MissingTexture3D;
                        setuponloadedtexture = Sidedef.LongLowTexture;
                    }
                    else
                    {
                        if (!base.Texture.IsImageLoaded)
                        {
                            setuponloadedtexture = Sidedef.LongLowTexture;
                        }
                    }
                }
                else
                {
                    // Use missing texture
                    base.Texture         = General.Map.Data.MissingTexture3D;
                    setuponloadedtexture = 0;
                }

                // Get texture scaled size
                Vector2D tsz = new Vector2D(base.Texture.ScaledWidth, base.Texture.ScaledHeight);

                // Determine texture coordinates
                // See http://doom.wikia.com/wiki/Texture_alignment
                // We just use pixels for coordinates for now
                if (Sidedef.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
                {
                    // When lower unpegged is set, the lower texture is bound to the bottom
                    t1.y = (float)Sidedef.Sector.CeilHeight - geotop;
                }
                t2.x = t1.x + Sidedef.Line.Length;
                t2.y = t1.y + geoheight;

                // Apply texture offset
                if (General.Map.Config.ScaledTextureOffsets && !base.Texture.WorldPanning)
                {
                    t1 += new Vector2D(Sidedef.OffsetX * base.Texture.Scale.x, Sidedef.OffsetY * base.Texture.Scale.y);
                    t2 += new Vector2D(Sidedef.OffsetX * base.Texture.Scale.x, Sidedef.OffsetY * base.Texture.Scale.y);
                }
                else
                {
                    t1 += new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
                    t2 += new Vector2D(Sidedef.OffsetX, Sidedef.OffsetY);
                }

                // Transform pixel coordinates to texture coordinates
                t1 /= tsz;
                t2 /= tsz;

                // Get world coordinates for geometry
                Vector2D v1, v2;
                if (Sidedef.IsFront)
                {
                    v1 = Sidedef.Line.Start.Position;
                    v2 = Sidedef.Line.End.Position;
                }
                else
                {
                    v1 = Sidedef.Line.End.Position;
                    v2 = Sidedef.Line.Start.Position;
                }

                // Make vertices
                WorldVertex[] verts = new WorldVertex[6];
                verts[0] = new WorldVertex(v1.x, v1.y, geobottom, brightness, t1.x, t2.y);
                verts[1] = new WorldVertex(v1.x, v1.y, geotop, brightness, t1.x, t1.y);
                verts[2] = new WorldVertex(v2.x, v2.y, geotop, brightness, t2.x, t1.y);
                verts[3] = verts[0];
                verts[4] = verts[2];
                verts[5] = new WorldVertex(v2.x, v2.y, geobottom, brightness, t2.x, t2.y);

                // Keep properties
                base.top    = geotop;
                base.bottom = geobottom;

                // Apply vertices
                base.SetVertices(verts);
                return(true);
            }
            else
            {
                // No geometry for invisible wall
                base.top    = geotop;
                base.bottom = geobottom;
                WorldVertex[] verts = new WorldVertex[0];
                base.SetVertices(verts);
                return(false);
            }
        }