// // RenderController.swift // ShedCalc // // Created by Jacky Jack on 28/07/2026. // import SwiftUI import RealityKit let BEAM_2x4_WIDTH: Float = 0.02 let BEAM_2x4_LENGTH: Float = 0.04 struct BeamData { let id: String let position: SIMD3 let height: Float let rotation: SIMD3 } class RenderController { func createScene(dimensions: SIMD3, rotation: SIMD2) -> Entity { let scene = Entity() scene.name = "scene" let box = createBox(dimensions: [1,1,1]) scene.addChild(box) let beam0 = createBeam2x4(position: [1,1,0], height: 2.4, rotate: [90,0,0], id: "beam0") scene.addChild(beam0) //let beam1 = createBeam2x4(position: [1,0,0], height: 2.4, rotate: [0,0,0], id: "beam1") //scene.addChild(beam1) //let beam2 = createBeam2x4(position: [1,1,0], height: 2.4, rotate: [0,0,90], id: "beam2") //Z-around beam //scene.addChild(beam2) //let beam3 = createBeam2x4(position: [1,1,0], height: 2.4, rotate: [0,90,0], id: "beam3") //scene.addChild(beam3) let ground = createGround() scene.addChild(ground) return scene } func createLights() -> (DirectionalLight, PointLight) { let directional = DirectionalLight() directional.light.intensity = 2000 directional.look(at: .zero, from: [2, 4, 3], relativeTo: nil) let point = PointLight() point.light.intensity = 5000 point.position = [-2, 2, -2] return (directional, point) } func createCamera() -> PerspectiveCamera { let camera = PerspectiveCamera() camera.camera.fieldOfViewInDegrees = 60 camera.position = [0,1,5] camera.look(at: .zero, from: camera.position, relativeTo: nil) return camera } // MARK: - Gesture Handling func handleDragGesture( _ value: DragGesture.Value, lastDrag: CGSize, currentRotation: SIMD2 ) -> (rotation: SIMD2, drag: CGSize) { let dx = Float(value.translation.width - lastDrag.width) * 0.01 let dy = Float(value.translation.height - lastDrag.height) * 0.01 let newRotation = SIMD2( currentRotation.x + dy, currentRotation.y + dx ) return (rotation: newRotation, drag: value.translation) } // MARK: - Private Helpers private func createBox(dimensions: SIMD3) -> ModelEntity { let box = ModelEntity( mesh: .generateBox(size: dimensions, cornerRadius: 0.02), materials: [SimpleMaterial(color: .yellow, isMetallic: false)] ) box.position = [0,0,0] box.name = "box" return box } private func createBeam2x4(position: SIMD3, height: Float, rotate: SIMD3, id: String) -> ModelEntity { let box = ModelEntity( mesh: .generateBox(size: SIMD3(BEAM_2x4_WIDTH,BEAM_2x4_LENGTH,height), cornerRadius: 0.02), materials: [SimpleMaterial(color: .yellow, isMetallic: false)] ) //box.look(at: position, from: lookFrom, relativeTo: nil) //box.setOrientation(.init(eulerAngles: lookFrom), relativeTo: nil) box.position = position // Create individual axis rotations let pitch = simd_quatf(angle: Float.pi*rotate.x/180.0, axis: [1, 0, 0]) // X-axis let yaw = simd_quatf(angle: Float.pi*rotate.y/180.0, axis: [0, 1, 0]) // Y-axis let roll = simd_quatf(angle: Float.pi*rotate.z/180.0, axis: [0, 0, 1]) // Z-axis // Combine rotations (order matters: usually yaw * pitch * roll) box.transform.rotation = yaw * pitch * roll box.name = "beam-\(id)" return box } func generateShedWall(position: SIMD3, height: Float, widthNum: Int, lengthNum: Int, spaceBeem: Float) -> [BeamData] { var beams: [BeamData] = [] var id: Int = 0 //Wall 0 for i in 0...widthNum { let x0 = Float(i)*spaceBeem beams.append(BeamData(id: "beam\(id)", position: [x0,position.y, position.z], height: height, rotation: [90,0,0])) id += 1 } //Wall 1 //Wall 2 //Wall 3 return beams } func createBeams(_ beams: [BeamData]) -> [ModelEntity] { return beams.map { beam in createBeam2x4(position: beam.position, height: beam.height, rotate: beam.rotation, id: beam.id) } } private func createGround() -> ModelEntity { let ground = ModelEntity( mesh: .generatePlane(width: 10, depth: 10), materials: [UnlitMaterial(color: .green)] ) ground.position.y = -0.5 return ground } }