public bool TryAdd(LotFacadeWall wall) { var effectiveLength = wall.Length; if (Walls.Count > 0) { effectiveLength += GAP; //we need space behind us } if (effectiveLength > Space) { return(false); //try the next bin } else { //space after us is not necessary when we hit the edge, so this gap is added after the space check. effectiveLength += GAP; Space -= effectiveLength; if (Space < 0) { Space = 0; } wall.EffectiveLength = effectiveLength; Walls.Add(wall); return(true); } }
private int AddToBin(LotFacadeWall wall) { int i = 0; while (true) { if (i >= WallBins.Count) { WallBins.Add(new LotFacadeWallBin()); } if (WallBins[i].TryAdd(wall)) { return(i); } i++; } }
public void GenerateWalls(GraphicsDevice gd, WorldRC world, Blueprint bp, bool justTexture) { //generate wall geometry and texture. if (!justTexture) { foreach (var room in bp.Rooms) { //add walls for each outside room. if (room.Base == room.RoomID && room.IsOutside) { var walls = new List <Vector2[]>(room.WallLines); walls.AddRange(room.FenceLines); foreach (var wall in walls) { var facadeWall = new LotFacadeWall(wall, room); AddToBin(facadeWall); } } } } //ok, allocate the texture for the wall. var tex = new RenderTarget2D(gd, MAX_WALL_WIDTH * WALL_WIDTH, CeilToFour(Math.Max(1, WallBins.Count * (WALL_HEIGHT + GAP * 2) - GAP * 2)), false, SurfaceFormat.Color, DepthFormat.Depth24); gd.SetRenderTarget(tex); gd.DepthStencilState = DepthStencilState.Default; gd.Clear(Color.TransparentBlack); //ace, let's draw each wall var oldLevel = world.State.Level; world.State.SilentLevel = bp.Stories; world.State.ZeroWallOffset = true; var cuts = bp.Cutaway; bp.Cutaway = new bool[cuts.Length]; bp.WCRC?.Generate(gd, world.State, false); int wallCount = 0; int bini = 0; foreach (var bin in WallBins) { var yPos = bini * (WALL_HEIGHT + GAP * 2); var xPos = 0; foreach (var wall in bin.Walls) { wallCount++; //get a camera for this wall first //create a look at matrix for the wall. first find a camera point at one side of the wall, //then create an orthographic projection with the size of the wall in mind. var ctr = (wall.Points[0] + wall.Points[1]) / (2 * 16); var rNorm = wall.Points[1] - wall.Points[0]; rNorm = new Vector2(rNorm.Y, -rNorm.X); rNorm.Normalize(); //which side is "outside"? //check one side. assume the other is outside if we fail var testPos = (ctr + rNorm * 0.6f).ToPoint(); if (testPos.X >= 0 && testPos.X < bp.Width && testPos.Y >= 0 && testPos.Y < bp.Height) { var room = bp.RoomMap[wall.Room.Floor][testPos.X + testPos.Y * bp.Width]; if (!bp.Rooms[bp.Rooms[(ushort)room].Base].IsOutside) { rNorm *= -1; } } var height = (wall.Room.Floor + 0.5f) * 2.95f * 3 + bp.InterpAltitude(new Vector3(ctr, 0)) * 3f + 0.2f; var camp = (ctr + rNorm) * 3; var objp = ctr * 3; var lookat = Matrix.CreateLookAt(new Vector3(camp.X, height, camp.Y), new Vector3(objp.X, height, objp.Y), Vector3.Up); var ortho = Matrix.CreateOrthographic(3 * wall.PhysicalLength, 2.90f * 3, 0, 6); //rescale our camera matrix to render to the correct part of the render target. Apply scissor test for that area. var rect = new Rectangle(xPos + (wall.EffectiveLength - (wall.Length + GAP)), yPos, wall.Length, WALL_HEIGHT); gd.RasterizerState = Scissor; gd.ScissorRectangle = rect; var trans = Matrix.CreateScale((rect.Width / ((float)tex.Width)), (rect.Height / ((float)tex.Height)), 1) * Matrix.CreateTranslation((-(rect.X * -2 - wall.Length) / (float)tex.Width) - 1f, (-(rect.Y * 2 + WALL_HEIGHT - 2) / (float)tex.Height) + 1f, 0); var frustrum = new BoundingFrustum(lookat * ortho); ortho = ortho * trans; //draw the walls and objects for this wall segment. this is a little slow right now. var effect = WorldContent.RCObject; gd.BlendState = BlendState.NonPremultiplied; var vp = lookat * ortho; effect.Parameters["ViewProjection"].SetValue(vp); bp.WCRC?.Draw(gd, world.State); effect.CurrentTechnique = effect.Techniques["Draw"]; var objs = bp.Objects.Where(x => x.Level >= wall.Room.Floor - 5 && frustrum.Intersects(((ObjectComponentRC)x).GetBounds())) .OrderBy(x => ((ObjectComponentRC)x).SortDepth(vp)); foreach (var obj in objs) { obj.Draw(gd, world.State); } xPos += wall.EffectiveLength; } bini++; } gd.RasterizerState = RasterizerState.CullNone; bp.Cutaway = cuts; bp.WCRC?.Generate(gd, world.State, false); world.State.ZeroWallOffset = false; world.State.SilentLevel = oldLevel; //generate wall geometry var data = new Color[tex.Width * tex.Height]; tex.GetData(data); var verts = new VertexPositionTexture[wallCount * 4]; var indices = new int[wallCount * 6]; bini = 0; var verti = 0; var indi = 0; foreach (var bin in WallBins) { var xInt = 0; var yInt = bini * (WALL_HEIGHT + GAP * 2); var yPos = bini * (WALL_HEIGHT + GAP * 2) / (float)tex.Height; var xPos = 0f; var div = WALL_HEIGHT / (float)tex.Height; foreach (var wall in bin.Walls) { var rect = new Rectangle(xInt + (wall.EffectiveLength - (wall.Length + GAP)), yInt, wall.Length, WALL_HEIGHT); BleedRect(data, rect, tex.Width, tex.Height); if (!justTexture) { var ctr = (wall.Points[0] + wall.Points[1]) / (2 * 16); var off = (wall.EffectiveLength - (wall.Length + GAP)) / (float)tex.Width; var height1 = ((wall.Room.Floor) * 2.95f + bp.InterpAltitude(new Vector3(ctr, 0))); var height2 = height1 + 2.95f; var pt1 = wall.Points[0] / 16f; var pt2 = wall.Points[1] / 16f; verts[verti++] = new VertexPositionTexture(new Vector3(pt1.X, height2, pt1.Y), new Vector2(xPos + off, yPos)); verts[verti++] = new VertexPositionTexture(new Vector3(pt2.X, height2, pt2.Y), new Vector2(xPos + off + wall.Length / (float)tex.Width, yPos)); verts[verti++] = new VertexPositionTexture(new Vector3(pt2.X, height1, pt2.Y), new Vector2(xPos + off + wall.Length / (float)tex.Width, (yPos + div))); verts[verti++] = new VertexPositionTexture(new Vector3(pt1.X, height1, pt1.Y), new Vector2(xPos + off, (yPos + div))); indices[indi++] = verti - 2; indices[indi++] = verti - 3; indices[indi++] = verti - 4; indices[indi++] = verti - 4; indices[indi++] = verti - 1; indices[indi++] = verti - 2; xInt += wall.EffectiveLength; xPos += wall.EffectiveLength / (float)tex.Width; } } bini++; } //using (var fs = new FileStream(@"C:\Users\Rhys\Desktop\walls.png", FileMode.Create, FileAccess.Write)) // tex.SaveAsPng(fs, tex.Width, tex.Height); tex.SetData(data); if (!justTexture) { WallTarget = tex; WallVerts = verts; WallIndices = indices; } }