using flecs.script
const PI = 3.1415926
struct Position(x: f32, y: f32, z: f32)
struct Rotation(x: f32, y: f32, z: f32)
struct Box(x: f32, y: f32, z: f32)
struct Rgb(r: u8, g: u8, b: u8)
const stone: Rgb = {236, 224, 200}
const stoneDark: Rgb = {212, 196, 168}
const trim: Rgb = {250, 246, 236}
const zinc: Rgb = {104, 116, 130}
const iron: Rgb = {44, 48, 54}
const glass: Rgb = {138, 178, 196}
const wood: Rgb = {74, 52, 40}
const brass: Rgb = {222, 184, 96}
const asphalt: Rgb = {72, 72, 78}
const paint: Rgb = {232, 232, 226}
const pavement: Rgb = {188, 182, 170}
const granite: Rgb = {132, 130, 128}
const awningRed: Rgb = {186, 62, 58}
const awningGreen: Rgb = {58, 110, 86}
interface {
template Road {
prop size: f32 = 3
prop width: f32 = 1
}
template Intersection {
prop width: f32 = 1
}
template Facade {
prop width: f32 = 4
prop height: f32 = 2
prop depth: f32 = 0.25
}
template Building {
prop width: f32 = 3
prop floors: i32 = 3
prop ground_facade: template interface.Facade
prop floor_facade: template interface.Facade
prop roof_facade: template interface.Facade
}
template Block {
prop x: i32 = 1
prop z: i32 = 1
prop size: i32 = 1
prop building: template interface.Building
}
}
template SquareLayout {
prop object: template
prop size = 1.0
const offset = size / 2
for i in 0..4 {
const angle = i * PI / 2
{
object
Position: {offset * math.cos(angle), 0, -offset * math.sin(angle)}
Rotation: {y: angle}
}
}
}
template SideWalk {
prop width = 1
prop length = 8
prop height = 0.12
const curb = 0.12
const slabHeight = height - 0.03
{
Position: {-curb / 2, slabHeight / 2, (width - curb) / 2}
Box: {width - curb, slabHeight, length - width - curb}
Rgb: pavement
}
{
Position: {(width - curb) / 2, height / 2, curb / 2}
Box: {curb, height, length - curb}
Rgb: granite
}
}
template Road : interface.Road {
Box: {width, 0.1, size}
Rgb: asphalt
const stripes: i32 = width / 0.5
for end in 0..2 {
for i in 0..stripes {
{
Position: {-width / 2 + (i + 0.5) * width / stripes, 0.01, (end * 2 - 1) * (size / 2 - 0.55)}
Box: {0.22, 0.1, 0.7}
Rgb: paint
}
}
}
}
template Intersection : interface.Intersection {
Box: {width, 0.1, width}
Rgb: asphalt
}
template Block : interface.Block {
prop sidewalkSize = 1
SquareLayout(SideWalk(sidewalkSize, size), size - sidewalkSize)
building(width: size - sidewalkSize * 2) { }
}
template Building : interface.Building {
const groundHeight = 1.8
const floorHeight = 1.4
const roofHeight = 1.2
SquareLayout(ground_facade(width, groundHeight), width - ground_facade.depth)
for i in 1..floors {
SquareLayout(floor_facade(width, floorHeight), width - floor_facade.depth) {
Position: {y: groundHeight + (i - 1) * floorHeight}
}
}
roof_facade(width, roofHeight) {
Position: {y: groundHeight + (floors - 1) * floorHeight}
}
}
template Window {
prop width = 0.6
prop height = 1.0
prop wall = 0.25
const x = wall / 2
{
Position: {x + 0.015, height / 2}
Box: {0.03, height + 0.12, width + 0.12}
Rgb: trim
}
{
Position: {x + 0.035, height / 2}
Box: {0.03, height, width}
Rgb: glass
}
{
Position: {x + 0.055, height / 2}
Box: {0.02, height - 0.04, 0.04}
Rgb: trim
}
{
Position: {x + 0.06, 0.01}
Box: {0.12, 0.06, width + 0.2}
Rgb: stoneDark
}
{
Position: {x + 0.1, 0.17}
Box: {0.02, 0.3, width + 0.16}
Rgb: iron
}
}
template GroundFacade : interface.Facade {
const bays: i32 = width / 1.5
const spacing = width / bays
const x = depth / 2
{
Position: {0, height / 2, depth / 2}
Box: {depth, height, width - depth}
Rgb: stoneDark
}
{
Position: {x + 0.09, height - 0.05, 0.09}
Box: {0.18, 0.1, width + 0.18}
Rgb: trim
}
{
Position: {x + 0.16, height + 0.14, 0.01}
Box: {0.02, 0.32, width + 0.32}
Rgb: iron
}
{
Position: {x + 0.16, height + 0.3, 0.02}
Box: {0.04, 0.03, width + 0.32}
Rgb: iron
}
for i in 0..bays {
const z = -width / 2 + spacing * (i + 0.5)
if i == bays / 2 {
{
Position: {x + 0.015, 0.65, z}
Box: {0.03, 1.3, 0.84}
Rgb: trim
}
{
Position: {x + 0.04, 0.6, z}
Box: {0.04, 1.2, 0.7}
Rgb: wood
}
{
Position: {x + 0.07, 0.6, z + 0.25}
Box: {0.03, 0.06, 0.06}
Rgb: brass
}
} else {
{
Position: {x + 0.015, 0.75, z}
Box: {0.03, 1.1, spacing - 0.4}
Rgb: wood
}
{
Position: {x + 0.035, 0.75, z}
Box: {0.03, 1.0, spacing - 0.5}
Rgb: glass
}
}
{
Position: {x + 0.2, 1.42, z}
Rotation: {z: -0.4}
Box: {0.5, 0.03, spacing - 0.3}
if i % 2 == 0 {
Rgb: awningRed
} else {
Rgb: awningGreen
}
}
}
}
template FloorFacade : interface.Facade {
const bays: i32 = width / 1.5
const spacing = width / bays
{
Position: {0, height / 2, depth / 2}
Box: {depth, height, width - depth}
Rgb: stone
}
{
Position: {(depth + 0.1) / 2, 0, 0.05}
Box: {0.1, 0.06, width + 0.1}
Rgb: trim
}
for i in 0..bays {
Window(0.6, height - 0.5, depth) {
Position: {0, 0.25, -width / 2 + spacing * (i + 0.5)}
}
}
}
template DormerRow {
prop width = 4.0
const bays: i32 = width / 1.5
const spacing = width / bays
for i in 0..bays {
const z = -width / 2 + spacing * (i + 0.5)
{
Position: {-0.1, 0.42, z}
Box: {0.5, 0.55, 0.5}
Rgb: stone
}
{
Position: {-0.1, 0.71, z}
Box: {0.6, 0.08, 0.6}
Rgb: zinc
}
{
Position: {0.165, 0.42, z}
Box: {0.03, 0.4, 0.36}
Rgb: trim
}
{
Position: {0.185, 0.42, z}
Box: {0.03, 0.3, 0.26}
Rgb: glass
}
}
}
template RoofFacade : interface.Facade {
const steps = 4
const stepHeight = height * 0.6 / steps
const inset = 0.14
const base = width + 0.3
{
Position: {y: 0.06}
Box: {width + 0.4, 0.12, width + 0.4}
Rgb: trim
}
for i in 0..steps {
{
Position: {y: 0.12 + stepHeight * (i + 0.5)}
Box: {base - inset * 2 * i, stepHeight, base - inset * 2 * i}
Rgb: zinc
}
}
SquareLayout(DormerRow(width), base) {
Position: {y: 0.12}
}
}
template City {
prop width = 3
prop depth = 3
prop block : template interface.Block
prop road : template interface.Road
prop intersection : template interface.Intersection
prop cellSize = 7
prop roadWidth = 2
const gridSize = cellSize + roadWidth
{
Position: {x: -(gridSize * (width - 1)) / 2, z: -(gridSize * (depth - 1)) / 2}
for x in 0..width {
for z in 0..depth {
const gp: Position = {gridSize * x, 0, gridSize * z}
block(x, z, cellSize) {
Position: gp
}
if x < width - 1 {
road(cellSize, roadWidth) {
Position: {gp.x + gridSize / 2, 0, gp.z}
}
}
if z < depth - 1 {
road(cellSize, roadWidth) {
Position: {gp.x, 0, gp.z + gridSize / 2}
Rotation: {y: PI / 2}
}
}
if x < width - 1 && z < depth - 1 {
intersection(roadWidth) {
Position: {gp.x + gridSize / 2, 0, gp.z + gridSize / 2}
}
}
}
}
}
}
City(3, 3,
block: Block(
sidewalkSize: 1,
building: Building(
floors: 4,
ground_facade: GroundFacade,
floor_facade: FloorFacade,
roof_facade: RoofFacade)),
road: Road,
intersection: Intersection)