static protected bool FindBend(Road.Section first, Road.Section second, WayPoint.Node nodeC, out WayPoint.Node node0, out WayPoint.Node node1) { node0 = null; node1 = null; if (first.Edge.Node0 == nodeC) { node0 = first.Edge.Node1; } else if (first.Edge.Node1 == nodeC) { node0 = first.Edge.Node0; } if (second.Edge.Node0 == nodeC) { node1 = second.Edge.Node1; } else if (second.Edge.Node1 == nodeC) { node1 = second.Edge.Node0; } return((node0 != null) && (node1 != null)); }
/// <summary> /// Spread flora over intersection of road. /// </summary> /// <param name="node"></param> /// <param name="first"></param> /// <param name="second"></param> /// <returns></returns> public override bool NewFan( Road.Intersection isect, Road.Section first, Road.Section second, List <Road.RenderObj> fans) { FBXModel model = EndModel; if (model != null) { RoadFBXRenderObj ro = new RoadFBXRenderObj(); ro.Model = model; ro.Animator = EndAnim; Matrix localToWorld = Matrix.Identity; Vector3 position = isect.Node.Position; position.Z = Terrain.GetTerrainHeightFlat(position) + isect.Node.Height; localToWorld.Translation = position; RandomizeAngle(ref localToWorld); ro.LocalToWorld = localToWorld; fans.Add(ro); return(true); } return(false); }
public void Finish(Road.Section section) { AABB box = AABB.EmptyBox(); bool stretchUp = section.Road.Generator.StretchUp; int cnt = Verts.Length; for (int i = 0; i < cnt; ++i) { if (stretchUp) { float minHeight = section.Road.Generator.MinHeight; float maxHeight = section.Road.Generator.MaxHeight; float t = (Verts[i].pos.Z - minHeight) / (maxHeight - minHeight); float baseHeight = section.BaseHeight(Verts[i].pos); float terrHeight = Terrain.GetTerrainHeightFlat(Verts[i].pos); Verts[i].pos.Z = terrHeight + t * (Verts[i].pos.Z + baseHeight - terrHeight); } else { if (Verts[i].pos.Z >= 0.0f) { Verts[i].pos.Z += section.BaseHeight(Verts[i].pos); } else { Verts[i].pos.Z = Terrain.GetTerrainHeightFlat(Verts[i].pos); } } box.Union(Verts[i].pos); } sphere = box.MakeSphere(); }
/// <summary> /// Create new intersection fan. /// </summary> /// <param name="node"></param> /// <param name="first"></param> /// <param name="second"></param> /// <returns></returns> public override bool NewFan( Road.Intersection isect, Road.Section first, Road.Section second, List <Road.RenderObj> fans) { return(NewFan(isect, new Vector2(1.0f, 0.0f), MathHelper.TwoPi, fans)); }
/// <summary> /// Create a new post. /// </summary> /// <param name="node"></param> /// <param name="first"></param> /// <param name="second"></param> /// <returns></returns> public override bool NewFan( Road.Intersection isect, Road.Section first, Road.Section second, List <Road.RenderObj> fans) { return(posts.NewFan(isect, first, second, fans)); }
public void Finish(Road.Section section) { AABB box = AABB.EmptyBox(); foreach (Road.RenderObj renderObj in renderObjs) { renderObj.Finish(section); box.Union(renderObj.Sphere); } sphere = box.MakeSphere(); }
/// <summary> /// Put down a tree at the intersection. /// </summary> public override bool NewFan( Road.Intersection isect, Road.Section first, Road.Section second, List <Road.RenderObj> fans) { FBXModel model = EndModel; if (model != null) { RoadMultiRenderObj multiRo = new RoadMultiRenderObj(); Vector2 center = isect.Node.Position2d; float area = width * width * (float)Math.PI; int count = (int)Math.Ceiling(area * density); for (int i = 0; i < count; ++i) { double rndAng = BokuGame.bokuGame.rnd.NextDouble() * Math.PI * 2.0; float rndOut = (float)(BokuGame.bokuGame.rnd.NextDouble() * 2.0 - 1.0); float cos = (float)Math.Cos(rndAng); float sin = (float)Math.Sin(rndAng); Vector2 rndPos = center; rndPos.X += cos * rndOut; rndPos.Y += sin * rndOut; float height = Terrain.GetTerrainHeightFlat(rndPos); Matrix localToWorld = Matrix.CreateTranslation(rndPos.X, rndPos.Y, height); RoadFBXRenderObj ro = new RoadFBXRenderObj(); ro.Model = model; ro.Animator = EndAnim; ro.LocalToWorld = localToWorld; multiRo.RenderObjList.Add(ro); } fans.Add(multiRo); return(count > 0); } return(false); }
/// <summary> /// Trim all geometry for two sections by the bisecting plane (if appropriate) /// </summary> /// <param name="plane"></param> public virtual bool Trim(Road.Section first, Road.Section second) { RoadStdRenderObj roFirst = first.RenderObj as RoadStdRenderObj; RoadStdRenderObj roSecond = second.RenderObj as RoadStdRenderObj; if ((roFirst == null) || (roSecond == null)) { return(false); } WayPoint.Node node0 = null; WayPoint.Node node1 = null; WayPoint.Node nodeC = null; if (!FindBend(first, second, out nodeC, out node0, out node1)) { return(false); } Vector2 edge0 = Vector2.Normalize(node0.Position2d - nodeC.Position2d); Vector2 edge1 = Vector2.Normalize(node1.Position2d - nodeC.Position2d); float dot = Vector2.Dot(edge0, edge1); { float cross = edge0.X * edge1.Y - edge0.Y * edge1.X; double rads = Math.Atan2(cross, dot); if (rads > 0.0) { Vector2 bisect = dot > -0.999f ? Vector2.Normalize(edge0 + edge1) : new Vector2(-edge0.Y, edge0.X); Vector3 norm = new Vector3(-bisect.Y, bisect.X, 0.0f); float dist = Vector3.Dot(norm, nodeC.Position); Vector4 plane = new Vector4(norm, dist); TrimToPlane(-plane, roFirst); TrimToPlane(plane, roSecond); return(true); } } return(false); }
/// <summary> /// Generate a fan to fill out an intersection. /// </summary> /// <param name="nodeC"></param> /// <param name="first"></param> /// <param name="second"></param> /// <returns></returns> public override bool NewFan( Road.Intersection isect, Road.Section first, Road.Section second, List <Road.RenderObj> fans) { if ((first == null) || (second == null)) { return(NewFan(isect, new Vector2(1.0f, 0.0f), Math.PI * 2.0, fans)); } WayPoint.Node nodeC = isect.Node; WayPoint.Node node0; WayPoint.Node node1; if (!FindBend(first, second, nodeC, out node0, out node1)) { return(false); } Vector2 center = nodeC.Position2d; Vector2 firstEdge = Vector2.Normalize(node0.Position2d - center); Vector2 startRadial = new Vector2(-firstEdge.Y, firstEdge.X); double rads0 = first.EdgeAngle(nodeC) + Math.PI * 0.5; if (rads0 < 0.0) { rads0 += Math.PI * 2.0; } double rads1 = second.EdgeAngle(nodeC) - Math.PI * 0.5; if (rads1 < 0.0) { rads1 += Math.PI * 2.0; } double rads = rads1 - rads0; if (rads < 0.0) { rads += Math.PI * 2.0; } return(NewFan(isect, startRadial, rads, fans)); }
/// <summary> /// Spread flora over new section of road. /// </summary> /// <param name="section"></param> public override void NewSection(Road.Section section) { RoadMultiRenderObj multiRo = null; FBXModel model = Model; if (model != null) { multiRo = new RoadMultiRenderObj(); Vector2 start = section.Edge.Node0.Position2d; Vector2 end = section.Edge.Node1.Position2d; Vector2 axis = end - start; Vector2 norm = new Vector2(-axis.Y, axis.X); norm = Vector2.Normalize(norm) * width; float area = axis.Length() * width * 2.0f; int count = (int)Math.Ceiling(area * density); for (int i = 0; i < count; ++i) { float rndTo = (float)BokuGame.bokuGame.rnd.NextDouble(); float rndOut = (float)(BokuGame.bokuGame.rnd.NextDouble() * 2.0 - 1.0); Vector2 rndPos = start + rndTo * axis + rndOut * norm; float height = Terrain.GetTerrainHeightFlat(rndPos); height += section.Edge.Node0.Height + rndTo * (section.Edge.Node1.Height - section.Edge.Node0.Height); Matrix localToWorld = Matrix.CreateTranslation(rndPos.X, rndPos.Y, height); RandomizeAngle(ref localToWorld); RoadFBXRenderObj ro = new RoadFBXRenderObj(); ro.Model = model; ro.LocalToWorld = localToWorld; ro.Animator = Anim; multiRo.RenderObjList.Add(ro); } } section.RenderObj = multiRo; }
/// <summary> /// Find the node shared by two sections and the unshared nodes /// </summary> /// <param name="first">First section</param> /// <param name="second">Second section</param> /// <param name="node0">Unshared node from first</param> /// <param name="node1">Unshared node from second</param> /// <param name="nodeC">Shared node</param> /// <returns>Return true if they do share a node</returns> static protected bool FindBend(Road.Section first, Road.Section second, out WayPoint.Node nodeC, out WayPoint.Node node0, out WayPoint.Node node1) { // Find the common and end nodes if (first.Edge.Node0 == second.Edge.Node0) { nodeC = first.Edge.Node0; node0 = first.Edge.Node1; node1 = second.Edge.Node1; } else if (first.Edge.Node0 == second.Edge.Node1) { nodeC = first.Edge.Node0; node0 = first.Edge.Node1; node1 = second.Edge.Node0; } else if (first.Edge.Node1 == second.Edge.Node0) { nodeC = first.Edge.Node1; node0 = first.Edge.Node0; node1 = second.Edge.Node1; } else if (first.Edge.Node1 == second.Edge.Node1) { nodeC = first.Edge.Node1; node0 = first.Edge.Node0; node1 = second.Edge.Node0; } else { node0 = null; node1 = null; nodeC = null; // Might assert, since these two edges don't share a node. // But not asserting lets this be used to check whether // two sections share a node. return(false); } return(true); }
/// <summary> /// Generate a castle as an intersection. /// </summary> /// <param name="node"></param> /// <param name="first"></param> /// <param name="second"></param> /// <returns></returns> public override bool NewFan( Road.Intersection isect, Road.Section first, Road.Section second, List <Road.RenderObj> fans) { bool didBase = base.NewFan(isect, first, second, fans); WayPoint.Node node = isect.Node; /* * centerheight * 4.4 * height * 4.3, 2.0, 2.3, 2.3, -1.0 * width * 0.05, 0.2, 0.2, 0.3, 0.3 * */ RoadFBXRenderObj ro = null; FBXModel model = ActorManager.GetActor("Castle").Model; if (model != null) { ro = new RoadFBXRenderObj(); ro.Model = model; Matrix localToWorld = Matrix.Identity; Vector3 position = node.Position; localToWorld.Translation = position; ro.LocalToWorld = localToWorld; fans.Add(ro); return(true); } return(didBase); }
/// <summary> /// Generate a new section. /// </summary> /// <param name="section"></param> public override void NewSection(Road.Section section) { section.RenderObj = null; RoadVertex[] verts = GenVerts(section); Int16[] indices = GenIndices(section); if ((verts.Length > 0) && (indices.Length > 0)) { RoadStdRenderObj ro = new RoadStdRenderObj(); ro.Verts = verts; ro.Indices = indices; ro.DiffuseTex0 = diffTex0; ro.DiffuseTex1 = diffTex1; ro.NormalTex0 = normTex0; ro.NormalTex1 = normTex1; ro.UVXfm = uvXfm; ro.Shininess = Shininess; section.RenderObj = ro; } }
/// <summary> /// Generate the vertex data for a (straight) section of road. /// </summary> /// <param name="section"></param> /// <returns></returns> protected RoadVertex[] GenVerts(Road.Section section) { Vector2 p0 = section.Edge.Node0.Position2d; Vector2 p1 = section.Edge.Node1.Position2d; Vector2 axis = p1 - p0; float len = axis.Length(); axis /= len; Vector2 norm = new Vector2(-axis.Y, axis.X); float step = Road.Step; numSteps = Math.Max(1, (int)Math.Ceiling(len / step)); step = len / (float)numSteps; int vertsPerHalfStep = VertsPerStep / 2; int baseVertex = 0; RoadVertex[] verts = new RoadVertex[(numSteps + 1) * VertsPerStep]; for (int iStep = 0; iStep <= numSteps; ++iStep) { Vector2 posCen = p0 + axis * step * iStep; Vector3 terrNormal = Vector3.UnitZ; // line it up with direction of travel by subtracting out component // along norm. //vtxNormal.X -= vtxNormal.X * norm.X; //vtxNormal.Y -= vtxNormal.Y * norm.Y; //vtxNormal.Normalize(); // Negative side for (int iVert = vertsPerHalfStep - 1; iVert >= 0; --iVert) { float width = widthTable[iVert]; float height = heightTable[iVert]; Vector2 pos = new Vector2( posCen.X - norm.X * width, posCen.Y - norm.Y * width); //float baseHeight = section.BaseHeight(pos); //height += baseHeight; verts[baseVertex].pos.X = pos.X; verts[baseVertex].pos.Y = pos.Y; verts[baseVertex].pos.Z = height; verts[baseVertex].norm = VtxNormal(terrNormal, -norm, iVert); verts[baseVertex].uv.X = step * iStep; verts[baseVertex].uv.Y = distTable[iVert]; verts[baseVertex].texSelect = TexSelect(iVert); ++baseVertex; } // Center float centerBaseHeight = 0.0f; // section.BaseHeight(posCen); float heightAtCenter = centerHeight + centerBaseHeight; verts[baseVertex].pos.X = posCen.X; verts[baseVertex].pos.Y = posCen.Y; verts[baseVertex].pos.Z = heightAtCenter; verts[baseVertex].norm = terrNormal; verts[baseVertex].uv.X = step * iStep; verts[baseVertex].uv.Y = 0.0f; verts[baseVertex].texSelect = TexSelect(0); ++baseVertex; // Positive side for (int iVert = 0; iVert < vertsPerHalfStep; ++iVert) { float width = widthTable[iVert]; float height = heightTable[iVert]; Vector2 pos = new Vector2( posCen.X + norm.X * width, posCen.Y + norm.Y * width); //float baseHeight = section.BaseHeight(pos); //height += baseHeight; verts[baseVertex].pos.X = pos.X; verts[baseVertex].pos.Y = pos.Y; verts[baseVertex].pos.Z = height; verts[baseVertex].norm = VtxNormal(terrNormal, norm, iVert); verts[baseVertex].uv.X = step * iStep; verts[baseVertex].uv.Y = distTable[iVert]; verts[baseVertex].texSelect = TexSelect(iVert); ++baseVertex; } } return(verts); }
/// <summary> /// No trimming /// </summary> /// <param name="first"></param> /// <param name="second"></param> /// <returns></returns> public override bool Trim(Road.Section first, Road.Section second) { return(false); }
/// <summary> /// Sections are rails. /// </summary> /// <param name="section"></param> public override void NewSection(Road.Section section) { rails.NewSection(section); }
/// <summary> /// Generate connectivity for a straight section of road. /// </summary> /// <param name="section"></param> /// <returns></returns> protected Int16[] GenIndices(Road.Section section) { int vertRowBase = 0; int nextRow = VertsPerStep; // 3 per row int nextCol = 1; // the next one over int quadsPerStep = VertsPerStep - 1; int quadsPerSide = quadsPerStep / 2; int numTris = numSteps * (quadsPerStep - numSkips * 2) * 2; Int16[] indices = new Int16[numTris * 3]; int idx = 0; for (int iStep = 0; iStep < numSteps; ++iStep) { if ((iStep & 1) != 0) { for (int iQuad = 0; iQuad < quadsPerStep; iQuad += 2) { int vertBase = vertRowBase + iQuad; if (!SkipQuad(iQuad, quadsPerSide)) { indices[idx++] = ((Int16)vertBase); indices[idx++] = ((Int16)(vertBase + nextCol)); indices[idx++] = ((Int16)(vertBase + nextRow)); indices[idx++] = ((Int16)(vertBase + nextRow)); indices[idx++] = ((Int16)(vertBase + nextCol)); indices[idx++] = ((Int16)(vertBase + nextRow + nextCol)); } ++vertBase; if (!SkipQuad(iQuad + 1, quadsPerSide)) { indices[idx++] = ((Int16)(vertBase + nextCol)); indices[idx++] = ((Int16)(vertBase + nextCol + nextRow)); indices[idx++] = ((Int16)(vertBase)); indices[idx++] = ((Int16)(vertBase)); indices[idx++] = ((Int16)(vertBase + nextCol + nextRow)); indices[idx++] = ((Int16)(vertBase + nextRow)); } } } else { for (int iQuad = 0; iQuad < quadsPerStep; iQuad += 2) { int vertBase = vertRowBase + iQuad; if (!SkipQuad(iQuad, quadsPerSide)) { indices[idx++] = ((Int16)(vertBase + nextCol)); indices[idx++] = ((Int16)(vertBase + nextCol + nextRow)); indices[idx++] = ((Int16)(vertBase)); indices[idx++] = ((Int16)(vertBase)); indices[idx++] = ((Int16)(vertBase + nextCol + nextRow)); indices[idx++] = ((Int16)(vertBase + nextRow)); } ++vertBase; if (!SkipQuad(iQuad + 1, quadsPerSide)) { indices[idx++] = ((Int16)vertBase); indices[idx++] = ((Int16)(vertBase + nextCol)); indices[idx++] = ((Int16)(vertBase + nextRow)); indices[idx++] = ((Int16)(vertBase + nextRow)); indices[idx++] = ((Int16)(vertBase + nextCol)); indices[idx++] = ((Int16)(vertBase + nextRow + nextCol)); } } } vertRowBase += VertsPerStep; } return(indices); }
/// <summary> /// Generate a straight section /// </summary> /// <param name="section">the section to hold the output</param> public abstract void NewSection(Road.Section section);
/// <summary> /// Generate a new fan filling the sector defined by p0, p1, and pC as the center. /// Assumes |p0 - pC| == |p1 - pC| == radius == roadwidth/2, and that the fan goes from /// p0 to p1 counterclockwise. /// </summary> /// <param name="node">the shared node at the intersection</param> /// <param name="first">edge of start of the arc</param> /// <param name="second">edge of end of the arc</param> public abstract bool NewFan( Road.Intersection isect, Road.Section first, Road.Section second, List <Road.RenderObj> fans);
public void Finish(Road.Section section) { }