# Generating Sims-style walls

Here's some code I wrote about 5 years ago and was looking over recently. The goal was to generate walls with textures on them. If there are intersections in the walls, the textures on the inside are slightly compressed and textures on the outside will be slightly expanded so that patterns tile correctly and there can be special patterns for corners that line up. Here's an example of it in use:

Here's the monstrosity that implements the core algorithm of generating it. It creates quads of 4 points and sends them to the QuadGeometry class, which builds the actual vertex/index buffers. It also generates the tops and edges of walls (as you can see from the TODOs I never finished this part).

using System.Collections.Generic;
using masques.map;
using masques.util;
using SharpDX;

namespace masques.graphics
{
public static class WallGeometry
{
private static Vector3 vec3(float x, float y, float z) { return new Vector3(x, y, z); }

private static int lookLeftAndRight(MapWalls walls, int x, int y, int z)
{
int c = 0;
if(x > 0 && walls.X.exists(x - 1, y, z)) c += 1;
if(x < walls.width && walls.X.exists(x, y, z)) c += 2;
return c;
}

private static int lookUpAndDown(MapWalls walls, int x, int y, int z)
{
int c = 0;
if(y > 0 && walls.Y.exists(x, y - 1, z)) c += 1;
if(y < walls.height && walls.Y.exists(x, y, z)) c += 2;
return c;
}

private static void adjustCorners(ref float a, ref float b, int corners, float adjustment, bool pushOut)
{
if(corners == 1)      { a -= adjustment; if(pushOut) b += adjustment; }
else if(corners == 2) { b -= adjustment; if(pushOut) a += adjustment; }
else if(corners == 3) { a -= adjustment; b -= adjustment; }
}

// TODO edge and top materials not always the defaults
// TODO don't put top on wall if wall/tile is above
public static void build(MapWalls walls, QuadGeometry geo) { build(walls, geo, 0, 0, 0, walls.width, walls.height, walls.layers, MapWalls.EDGE_SIZE, 1, true); }
public static void build(MapWalls walls, QuadGeometry geo, int x0, int y0, int z0, int x1, int y1, int z1, float edgeSize, float wallHeight, bool includeBorders)
{
if(x1 <= x0 || y1 <= y0) return;
int w = walls.width, h = walls.height;
const ushort edgeMat = 1;
const ushort topMat = 1;

/***********************************************************************************************
*                                           X WALLS                                           *
***********************************************************************************************/

int y0x = includeBorders ? y0 : y0 + 1;
int y1x = includeBorders ? y1 + 1 : y1;
foreach(KeyValuePair<IntPoint, WallSegment> kvp in walls.X)
{
int x = kvp.Key.x;
int y = kvp.Key.y;
int z = kvp.Key.z;
if(x < x0 || x >= x1 || y < y0x || y >= y1x || z < z0 || z >= z1)
continue;

WallSegment segment = kvp.Value;
float px1 = x, px1a = px1, px1b = px1;
float px2 = x + 1, px2a = px2, px2b = px2;
float py = y;
float py1 = py - edgeSize;
float py2 = py + edgeSize;
float pz = z;

int corners1 = lookUpAndDown(walls, x, y, z);
int corners2 = lookUpAndDown(walls, x + 1, y, z);
bool isWallStart = x == 0 || !walls.X.exists(x - 1, y, z);
bool isWallEnd = x == w - 1 || !walls.X.exists(x + 1, y, z);
adjustCorners(ref px1a, ref px1b, corners1, -edgeSize, isWallStart);
adjustCorners(ref px2a, ref px2b, corners2, +edgeSize, isWallEnd);
float tx1a = px1a, tx1b = px1b, tx2a = px2a, tx2b = px2b;

// if we're the beginning of a wall...
if(isWallStart)
{
// If there are no Y intersections here, add an edge
if(corners1 == 0) geo.add(vec3(px1a, py2, pz), vec3(px1a, py1, pz), vec3(px1a, py2, pz + wallHeight), vec3(px1a, py1, pz + wallHeight), 0, 1, 0, 1, edgeMat);
}
else if(corners1 != 3)
{
tx1a = px1;
tx1b = px1;
}

// if we're at the end of a wall...
if(isWallEnd)
{
// If there are no Y intersections here, add an edge
if(corners2 == 0) geo.add(vec3(px2a, py1, pz), vec3(px2a, py2, pz), vec3(px2a, py1, pz + wallHeight), vec3(px2a, py2, pz + wallHeight), 0, 1, 0, 1, edgeMat);
}
else if(corners2 != 3)
{
tx2a = px2;
tx2b = px2;
}

// top
if(!walls.X.exists(x, y, z + 1))
{
geo.add(vec3(tx2b, py2, pz + wallHeight), vec3(tx1b, py2, pz + wallHeight), vec3(tx2a, py1, pz + wallHeight), vec3(tx1a, py1, pz + wallHeight), 0, 1, 0, 1, topMat);
}

// faces
geo.add(vec3(px1a, py1, pz),  vec3(px2a, py1, pz),  vec3(px1a, py1, pz + wallHeight), vec3(px2a, py1, pz + wallHeight), x + 1, x, z, z + 1, segment.back);
geo.add(vec3(px2b, py2, pz),  vec3(px1b, py2, pz),  vec3(px2b, py2, pz + wallHeight), vec3(px1b, py2, pz + wallHeight), w - x, w - x - 1, z, z + 1, segment.front);
}

/***********************************************************************************************
*                                           Y WALLS                                           *
***********************************************************************************************/

int x0y = includeBorders ? x0 : x0 + 1;
int x1y = includeBorders ? x1 + 1 : x1;
foreach(KeyValuePair<IntPoint, WallSegment> kvp in walls.Y)
{
int x = kvp.Key.x;
int y = kvp.Key.y;
int z = kvp.Key.z;
if(x < x0y || x >= x1y || y < y0 || y >= y1 || z < z0 || z >= z1)
continue;

WallSegment segment = kvp.Value;
float px = x;
float px1 = px - edgeSize;
float px2 = px + edgeSize;
float py1 = y, py1a = py1, py1b = py1;
float py2 = py1 + 1, py2a = py2, py2b = py2;
float pz = z;

int corners1 = lookLeftAndRight(walls, x, y, z);
int corners2 = lookLeftAndRight(walls, x, y + 1, z);
bool isWallStart = y == 0 || !walls.Y.exists(x, y - 1, z);
bool isWallEnd = y == h - 1 || !walls.Y.exists(x, y + 1, z);
adjustCorners(ref py1a, ref py1b, corners1, -edgeSize, isWallStart);
adjustCorners(ref py2a, ref py2b, corners2, +edgeSize, isWallEnd);
float ty1a = py1a, ty1b = py1b, ty2a = py2a, ty2b = py2b;

// if we're the beginning of a wall...
if(isWallStart)
{
// If there are no X intersections here, add an edge
if(corners1 == 0) geo.add(vec3(px1, py1a, pz), vec3(px2, py1a, pz), vec3(px1, py1a, pz + wallHeight), vec3(px2, py1a, pz + wallHeight), 0, 1, 0, 1, edgeMat);
}
else
{
ty1a = py1;
ty1b = py1;
}

// if we're at the end of a wall...
if(isWallEnd)
{
// If there are no X intersections here, add an edge
if(corners2 == 0) geo.add(vec3(px2, py2a, pz), vec3(px1, py2a, pz), vec3(px2, py2a, pz + wallHeight), vec3(px1, py2a, pz + wallHeight), 0, 1, 0, 1, edgeMat);
}
else
{
ty2a = py2;
ty2b = py2;
}

// top
if(!walls.Y.exists(x, y, z + 1))
{
geo.add(vec3(px2, ty2b, pz + wallHeight), vec3(px1, ty2a, pz + wallHeight), vec3(px2, ty1b, pz + wallHeight), vec3(px1, ty1a, pz + wallHeight), 0, 1, 0, 1, topMat);
}

// wall faces
geo.add(vec3(px1, py2a, pz),  vec3(px1, py1a, pz),  vec3(px1, py2a, pz + wallHeight), vec3(px1, py1a, pz + wallHeight), h - y, h - y - 1, z, z + 1, segment.back);
geo.add(vec3(px2, py1b, pz),  vec3(px2, py2b, pz),  vec3(px2, py1b, pz + wallHeight), vec3(px2, py2b, pz + wallHeight), y + 1, y, z, z + 1, segment.front);
}
}
}
}


I was thinking about converting it to Unity, which uses Y-up instead of Z-up since this is a pretty efficient/easy way to throw together simple buildings, but before I do that it might make sense to clean it up a bit. In particular, I'm looking if there's a good way to combine the totally duplicated X walls and Y walls parts. It might be possible to tackle those a different way (such as generating always in X then swapping the coordinates for Y walls), though it's not straightforward how that would be done.

Any suggestions, or is this unsalvageable?