/// <summary> /// Connect all the sections of this road that meet at this node. /// </summary> /// <param name="inRoad"></param> /// <param name="inNode"></param> /// <returns></returns> public bool Connect(Road road, WayPoint.Node node) { this.road = road; this.node = node; // Make a list of all edges hitting this node. This should // probably already be stored on the node. sections.Clear(); foreach (Section section in Road.Sections) { WayPoint.Edge edge = section.Edge; if ((edge.Node0 == node) || (edge.Node1 == node)) { sections.Add(section); section.AddIntersection(this); } } // Sort them by angle sections.Sort(new EdgeCompare(node)); BuildNormal(); BuildSectionStrengths(); return(true); }
/// <summary> /// Scans through the path ensuring that all the nodes in the path are /// connected by edges. If not, it splits this path into multiple paths /// of the same color. Also checks all edges to make sure that they are /// only connected to nodes in this path. If not, they are just deleted. /// </summary> public void EnsureCoherence() { // Delete any edges that reference nodes not in this path. for (int i = Edges.Count - 1; i >= 0; i--) { Edge e = Edges[i]; if (!Nodes.Contains(e.Node0) || !Nodes.Contains(e.Node1)) { RemoveEdge(e); } } if (Nodes.Count == 0) { // Hmm, degenerate path. What to do? Should never get here. throw new Exception("Degenerate waypoint path found."); } // Sweep through all nodes marking them as "not in". Node n = null; for (int i = 0; i < Nodes.Count; i++) { n = Nodes[i]; n.temp = 0; } // Mark first node as in. n = Nodes[0]; n.temp = 1; // Flood fill this out to the other connected nodes. Flood(n); // At this point, any nodes that are not marked are not connected to this path and // should be removed from this path and given their own path. bool newPaths = false; for (int i = Nodes.Count - 1; i > 0; i--) { n = Nodes[i]; if (n.temp != 1) { ///Note that in this loop, no nodes or edges are created or destroyed, ///just moved from one path to another. So no bookkeeping on counts ///is needed. // Remove this node from the current path. Nodes.RemoveAt(i); // Create a new path for the node in the same color and add the node to the path. Path path = new Path(n.Path.color); n.Path = path; path.Nodes.Add(n); // Move any edges that originate from this node to the new path. for (int j = Edges.Count - 1; j >= 0; j--) { Edge e = Edges[j]; if (e.Node0 == n) { Edges.RemoveAt(j); n.Path.Edges.Add(e); } } newPaths = true; } } // Finally, if we removed any nodes and created new paths for // them we may have multiple paths that need to be merged. if (newPaths) { MergePaths(); } // ***ROAD - nuke the road so we'll rebuild it. if (Road != null) { Road.Rebuild(); } } // end of Path EnsureCoherence()
internal void ClearAll() { Road.Clear(); ClearEdges(); ClearNodes(); }
/// <summary> /// Actually render the batch. /// </summary> /// <param name="road"></param> public void RenderBatch(Road road) { GraphicsDevice device = BokuGame.bokuGame.GraphicsDevice; device.Indices = indexBuff; device.SetVertexBuffer(vertBuff); if (wireframe) { device.RasterizerState = UI2D.Shared.RasterStateWireframe; } Vector4 color = DiffuseColor * road.Path.RGBColor; Parameter(EffectParams.DiffuseColor).SetValue(color); Parameter(EffectParams.SpecularColor).SetValue(SpecularColor); Parameter(EffectParams.EmissiveColor).SetValue(EmissiveColor); Parameter(EffectParams.SpecularPower).SetValue(SpecularPower); Parameter(EffectParams.Shininess).SetValue(Shininess); Parameter(EffectParams.UVXfm).SetValue(uvXfm); Parameter(EffectParams.DiffuseTexture0).SetValue(diffuseTex0); Parameter(EffectParams.DiffuseTexture1).SetValue(diffuseTex1); #if !NETFX_CORE Parameter(EffectParams.NormalTexture0).SetValue(normalTex0); Parameter(EffectParams.NormalTexture1).SetValue(normalTex1); #endif Texture2D shadowTexture = InGame.inGame.ShadowCamera.ShadowTexture; // Sometimes after multiple device resets we can get here with // a bad shadow texture. At this point we can just set it to // null rendering a frame without shadows and then everything // will be back to normal next frame. if (shadowTexture != null && (shadowTexture.IsDisposed || shadowTexture.GraphicsDevice.IsDisposed)) { if (!shadowTexture.IsDisposed) { BokuGame.Release(ref shadowTexture); } shadowTexture = null; } Texture2D shadowMask = InGame.inGame.ShadowCamera.ShadowMask; Parameter(EffectParams.ShadowTexture).SetValue(shadowTexture); Parameter(EffectParams.ShadowMask).SetValue(shadowMask); Vector4 offsetScale = InGame.inGame.ShadowCamera.OffsetScale; Parameter(EffectParams.ShadowTextureOffsetScale).SetValue(offsetScale); offsetScale = InGame.inGame.ShadowCamera.MaskOffsetScale; Parameter(EffectParams.ShadowMaskOffsetScale).SetValue(offsetScale); effect.CurrentTechnique.Passes[0].Apply(); device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, NumVertices, 0, NumTriangles); if (wireframe) { device.RasterizerState = RasterizerState.CullCounterClockwise; } }
protected virtual bool NewFan( Road.Intersection isect, Vector2 startRadial, double rads, List <Road.RenderObj> fans) { Road road = isect.Road; int numRadials = (int)Math.Ceiling(rads / road.RadStep); double radStep = rads / numRadials; Vector2 center = isect.Node.Position2d; int vertsPerRadial = VertsPerStep / 2; int numVerts = (numRadials + 1) * vertsPerRadial + 1; RoadVertex[] verts = new RoadVertex[numVerts]; Vector3 terrNormal = Vector3.UnitZ; AABB box = AABB.EmptyBox(); int iVert = 0; for (int iRadial = 0; iRadial <= numRadials; ++iRadial) { double ang = radStep * iRadial; float cos = (float)Math.Cos(ang); float sin = (float)Math.Sin(ang); Vector2 radial = new Vector2(startRadial.X * cos - startRadial.Y * sin, startRadial.X * sin + startRadial.Y * cos); for (int iOut = 0; iOut < vertsPerRadial; ++iOut) { float width = widthTable[iOut]; float height = heightTable[iOut]; float arc = (float)(ang * width); RoadVertex vtx = new RoadVertex(); Vector2 pos = center + width * radial; //float baseHeight = isect.BaseHeight(pos); //height += baseHeight; vtx.pos.X = pos.X; vtx.pos.Y = pos.Y; vtx.pos.Z = height; box.Union(vtx.pos); vtx.norm = VtxNormal(terrNormal, radial, iOut); vtx.uv.X = arc; vtx.uv.Y = distTable[iOut]; vtx.texSelect = TexSelect(iOut); verts[iVert++] = vtx; } } float centerBaseHeight = 0.0f; // isect.BaseHeight(center); float heightAtCenter = centerHeight + centerBaseHeight; RoadVertex last = new RoadVertex(); last.pos.X = center.X; last.pos.Y = center.Y; last.pos.Z = heightAtCenter; box.Union(last.pos); last.norm = terrNormal; last.uv.X = 0.0f; last.uv.Y = 0.0f; last.texSelect = TexSelect(0); int centerIdx = iVert++; verts[centerIdx] = last; Debug.Assert(iVert == numVerts); // First step per radial is a single tri, // then the rest of the steps are quads int quadsPerRadial = vertsPerRadial - 1; int numTris = 0; if (!skipTable[0]) { numTris += numRadials; numTris += numRadials * (quadsPerRadial - numSkips) * 2; } else { numTris += numRadials * (quadsPerRadial - (numSkips - 1)) * 2; } Int16[] indices = new Int16[numTris * 3]; int nextRad = vertsPerRadial; int nextOut = 1; int baseVtx = 0; int idx = 0; for (int iRadial = 0; iRadial < numRadials; ++iRadial) { if (!skipTable[0]) { indices[idx++] = (Int16)(baseVtx); indices[idx++] = (Int16)(centerIdx); indices[idx++] = (Int16)(baseVtx + nextRad); } for (int iOut = 0; iOut < quadsPerRadial; iOut++) { if (!skipTable[iOut + 1]) { indices[idx++] = (Int16)(baseVtx + iOut + nextRad); indices[idx++] = (Int16)(baseVtx + iOut + nextRad + nextOut); indices[idx++] = (Int16)(baseVtx + iOut); indices[idx++] = (Int16)(baseVtx + iOut); indices[idx++] = (Int16)(baseVtx + iOut + nextRad + nextOut); indices[idx++] = (Int16)(baseVtx + iOut + nextOut); } } baseVtx += nextRad; } Debug.Assert(idx == numTris * 3); RoadStdRenderObj ro = null; if ((verts.Length > 0) && (indices.Length > 0)) { 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; ro.Sphere = box.MakeSphere(); fans.Add(ro); return(true); } return(false); }