public void Calculate() { // texture orientation Real radangle = MathUtil.BinaryAngleToRadian((ushort)TextureAngle); Real texorientx = (Real)System.Math.Cos(radangle); Real texorienty = (Real)System.Math.Sin(radangle); Real texorientz = 0; TextureOrientation = new V3(texorientx, texorienty, texorientz); // generate other endpoints from plane normal, texture origin, and texture // orientation which determine the orientation of the texture's u v space // in the 3d world's x, y, z space // plane normal V3 planeNormal = new V3(A, B, C); // first point // calculate z of texture origin from x, y, and plane equation Real z = (-A * X0 - B * Y0 - D) / C; P0 = new V3(X0, Y0, z); // cross normal with texture orientation to get vector perpendicular to texture // orientation and normal = v axis direction V3 v2 = planeNormal.CrossProduct(TextureOrientation); v2.ScaleToLength(GeometryConstants.FINENESS); // cross normal with v axis direction vector to get vector perpendicular to v axis // and normal = u axis direction vector V3 v1 = v2.CrossProduct(planeNormal); v1.ScaleToLength(GeometryConstants.FINENESS); // add vectors to origin to get endpoints P1 = P0 + v1; P2 = P0 + v2; }
/// <summary> /// Returns ready to display render information for a sidepart of this wall. /// Note: Z component is the height. /// </summary> /// <param name="PartType">Which part (upper, middle, lower)</param> /// <param name="IsLeftSide">Left or Right side</param> /// <param name="TexWidth">Texture width</param> /// <param name="TexHeight">Texture height</param> /// <param name="TexShrink">Texture shrink</param> /// <param name="Scale">Additional scale for vertices</param> /// <returns></returns> public RenderInfo GetRenderInfo(WallPartType PartType, bool IsLeftSide, int TexWidth, int TexHeight, int TexShrink, Real Scale = 1.0f) { RenderInfo RI = new RenderInfo(); bool drawTopDown = true; RooSideDefFlags flags; int xoffset = 0; int yoffset = 0; // fill vars based on left or right side if (!IsLeftSide) { RI.P0.X = X1; RI.P3.X = X2; RI.P1.X = X1; RI.P2.X = X2; RI.P0.Y = Y1; RI.P3.Y = Y2; RI.P1.Y = Y1; RI.P2.Y = Y2; flags = RightSide.Flags; xoffset = RightXOffset; yoffset = RightYOffset; switch (PartType) { case WallPartType.Upper: RI.P0.Z = Z3; RI.P3.Z = ZZ3; RI.P1.Z = Z2; RI.P2.Z = ZZ2; drawTopDown = !RightSide.Flags.IsAboveBottomUp; break; case WallPartType.Middle: RI.P0.Z = Z2; RI.P3.Z = ZZ2; RI.P1.Z = Z1; RI.P2.Z = ZZ1; drawTopDown = RightSide.Flags.IsNormalTopDown; break; case WallPartType.Lower: RI.P0.Z = Z1; RI.P3.Z = ZZ1; RI.P1.Z = Z0; RI.P2.Z = ZZ0; drawTopDown = RightSide.Flags.IsBelowTopDown; break; } } else { RI.P0.X = X2; RI.P3.X = X1; RI.P1.X = X2; RI.P2.X = X1; RI.P0.Y = Y2; RI.P3.Y = Y1; RI.P1.Y = Y2; RI.P2.Y = Y1; flags = LeftSide.Flags; xoffset = LeftXOffset; yoffset = LeftYOffset; switch (PartType) { case WallPartType.Upper: RI.P0.Z = ZZ3; RI.P3.Z = Z3; RI.P1.Z = ZZ2; RI.P2.Z = Z2; drawTopDown = !LeftSide.Flags.IsAboveBottomUp; break; case WallPartType.Middle: RI.P0.Z = ZZ2; RI.P3.Z = Z2; RI.P1.Z = ZZ1; RI.P2.Z = Z1; drawTopDown = LeftSide.Flags.IsNormalTopDown; break; case WallPartType.Lower: RI.P0.Z = ZZ1; RI.P3.Z = Z1; RI.P1.Z = ZZ0; RI.P2.Z = Z0; drawTopDown = LeftSide.Flags.IsBelowTopDown; break; } } // scales Real invWidth = 1.0f / (Real)TexWidth; Real invHeight = 1.0f / (Real)TexHeight; Real invWidthFudge = 1.0f / (Real)(TexWidth << 4); Real invHeightFudge = 1.0f / (Real)(TexHeight << 4); // Start with UV calculation, see d3drender.c --- Real u1 = (Real)xoffset * (Real)TexShrink * invHeight; Real u2 = u1 + ((Real)ClientLength * (Real)TexShrink * invHeight); // set U RI.UV0.X = u1; RI.UV1.X = u1; RI.UV3.X = u2; RI.UV2.X = u2; // calculate V int bottom, top; if (!drawTopDown) { if (RI.P1.Z == RI.P2.Z) { bottom = (int)RI.P1.Z; } else { bottom = (int)MathUtil.Min(RI.P1.Z, RI.P2.Z); bottom = bottom & ~(GeometryConstants.FINENESS - 1); } if (RI.P0.Z == RI.P3.Z) { top = (int)RI.P0.Z; } else { top = (int)MathUtil.Max(RI.P0.Z, RI.P3.Z); top = (top + GeometryConstants.FINENESS - 1) & ~(GeometryConstants.FINENESS - 1); } if (RI.P1.Z == RI.P2.Z) { RI.UV1.Y = 1.0f - ((Real)yoffset * (Real)TexShrink * invWidth); RI.UV2.Y = 1.0f - ((Real)yoffset * (Real)TexShrink * invWidth); } else { RI.UV1.Y = 1.0f - ((Real)yoffset * (Real)TexShrink * invWidth); RI.UV2.Y = 1.0f - ((Real)yoffset * (Real)TexShrink * invWidth); RI.UV1.Y -= ((Real)RI.P1.Y - bottom) * (Real)TexShrink * invWidthFudge; RI.UV2.Y -= ((Real)RI.P2.Y - bottom) * (Real)TexShrink * invWidthFudge; } RI.UV0.Y = RI.UV1.Y - ((Real)(RI.P0.Z - RI.P1.Z) * (Real)TexShrink * invWidthFudge); RI.UV3.Y = RI.UV2.Y - ((Real)(RI.P3.Z - RI.P2.Z) * (Real)TexShrink * invWidthFudge); } // else, need to place tex origin at top left else { if (RI.P0.Z == RI.P3.Z) { top = (int)RI.P0.Z; } else { top = (int)MathUtil.Max(RI.P0.Z, RI.P3.Z); top = (top + GeometryConstants.FINENESS - 1) & ~(GeometryConstants.FINENESS - 1); } if (RI.P1.Z == RI.P2.Z) { bottom = (int)RI.P1.Z; } else { bottom = (int)MathUtil.Min(RI.P1.Z, RI.P2.Z); bottom = bottom & ~(GeometryConstants.FINENESS - 1); } if (RI.P0.Z == RI.P3.Z) { RI.UV0.Y = 0.0f; RI.UV3.Y = 0.0f; } else { RI.UV0.Y = ((Real)top - RI.P0.Z) * (Real)TexShrink * invWidthFudge; RI.UV3.Y = ((Real)top - RI.P3.Z) * (Real)TexShrink * invWidthFudge; } RI.UV0.Y -= ((Real)(yoffset * TexShrink) * invWidth); RI.UV3.Y -= ((Real)(yoffset * TexShrink) * invWidth); RI.UV1.Y = RI.UV0.Y + ((RI.P0.Z - RI.P1.Z) * (Real)TexShrink * invWidthFudge); RI.UV2.Y = RI.UV3.Y + ((RI.P3.Z - RI.P2.Z) * (Real)TexShrink * invWidthFudge); } // backwards if (flags.IsBackwards) { Real temp; temp = RI.UV3.X; RI.UV3.X = RI.UV0.X; RI.UV0.X = temp; temp = RI.UV2.X; RI.UV2.X = RI.UV1.X; RI.UV1.X = temp; } // no vtile // seems to apply only to middle parts, at least for bottom it creates strange holes if (flags.IsNoVTile && PartType == WallPartType.Middle) { if (RI.UV0.Y < 0.0f) { Real tex, wall, ratio, temp; tex = RI.UV1.Y - RI.UV0.Y; if (tex == 0) { tex = 1.0f; } temp = -RI.UV0.Y; ratio = temp / tex; wall = RI.P0.Z - RI.P1.Z; temp = wall * ratio; RI.P0.Z -= temp; RI.UV0.Y = 0.0f; } if (RI.UV3.Y < 0.0f) { Real tex, wall, ratio, temp; tex = RI.UV2.Y - RI.UV3.Y; if (tex == 0) { tex = 1.0f; } temp = -RI.UV3.Y; ratio = temp / tex; wall = RI.P3.Z - RI.P2.Z; temp = wall * ratio; RI.P3.Z -= temp; RI.UV3.Y = 0.0f; } RI.P1.Z -= 16.0f; RI.P2.Z -= 16.0f; } RI.UV0.Y += 1.0f / TexWidth; RI.UV3.Y += 1.0f / TexWidth; RI.UV1.Y -= 1.0f / TexWidth; RI.UV2.Y -= 1.0f / TexWidth; // scale by user scale RI.P0 *= Scale; RI.P3 *= Scale; RI.P1 *= Scale; RI.P2 *= Scale; // calculate the normal V3 P0P1 = (RI.P1 - RI.P0); V3 P0P2 = (RI.P2 - RI.P0); RI.Normal = P0P1.CrossProduct(P0P2); RI.Normal.Normalize(); RI.Normal = -RI.Normal; return(RI); }