Files
CavesOfSwift/Sources/Test/CavesOfJolk.swift
2024-05-05 17:01:56 +10:00

277 lines
9.0 KiB
Swift

import Foundation
import simd
import JolkEngine
@main struct Program
{
static func main()
{
Application(
application: CavesOfJolk(),
config: ApplicationConfiguration(
resizable: true,
vSync: .on,
windowWidth: 1280,
windowHeight: 720,
bundle: Bundle.module)
).run()
}
}
class CavesOfJolk: ApplicationImplementation
{
private var aspect: Float = 0
private var drawEdges = false
var env = Environment()
var worldMesh = RenderMesh.empty, cube = RenderMesh.empty, suzanne = RenderMesh.empty, toybox = RenderMesh.empty
var texture = Texture2D.empty, jolkTex = Texture2D.empty, suzanneDiffuse = Texture2D.empty
private lazy var world = Collision()
private lazy var colin = Colin()
private lazy var jolkCube = JolkCube(position: .init(0, 1, -4))
private var lightTheta: Float = 0
private var frameCount = 0
private var frameTimer: Float = 1
func create(render: inout Renderer)
{
render.clearColour = XnaColour.CornflowerBlue
env.setFog(
colour: XnaColour.CornflowerBlue,
//mode: .depth, falloff: .range(type: .linear, start: 4, end: 38))
//mode: .depth, falloff: .range(type: .linear, start: 1.25, end: 24.5))
//mode: .distance, falloff: .factor(type: .exp2, density: 0.1))
mode: .depth, falloff: .factor(type: .exp2, density: 0.0222))
env.addAmbientLight(colour: XnaColour.DarkSlateGray.lighten(by: -0.666))
env.addDirectionalLight(
direction: -Vec3f(1, -1, -1).normalised,
colour: XnaColour.BlanchedAlmond
.lighten(by: -0.02)
.mix(with: XnaColour.LightSlateGray, 0.5)
.mix(with: XnaColour.White, 0.125))
env.addPointLight(
position: Vec3f(3, 0.33, -5),
colour: XnaColour.Green.mix(with: XnaColour.Gray, 0.5),
intensity: 2)
env.addPointLight(
position: Vec3f(5.5, 0.33, -6),
colour: XnaColour.Red.mix(with: XnaColour.Gray, 0.5),
intensity: 2)
env.addPointLight(
position: Vec3f(4, 0.33, -7),
colour: XnaColour.Blue.mix(with: XnaColour.Gray, 0.5),
intensity: 2)
}
func loadContent(content: inout ContentManager) throws
{
try loadWorld(&content)
cube = try content.create(mesh: .init(
vertices: [
.init(position: Vec3f(-1, -1, 1), normal: .forward, texCoord: Vec2f(0, 0)),
.init(position: Vec3f( 1, -1, 1), normal: .forward, texCoord: Vec2f(1, 0)),
.init(position: Vec3f(-1, 1, 1), normal: .forward, texCoord: Vec2f(0, 1)),
.init(position: Vec3f( 1, 1, 1), normal: .forward, texCoord: Vec2f(1, 1)),
.init(position: Vec3f( 1, -1, 1), normal: .right, texCoord: Vec2f(0, 0)),
.init(position: Vec3f( 1, -1, -1), normal: .right, texCoord: Vec2f(1, 0)),
.init(position: Vec3f( 1, 1, 1), normal: .right, texCoord: Vec2f(0, 1)),
.init(position: Vec3f( 1, 1, -1), normal: .right, texCoord: Vec2f(1, 1)),
.init(position: Vec3f( 1, -1, -1), normal: .back, texCoord: Vec2f(0, 0)),
.init(position: Vec3f(-1, -1, -1), normal: .back, texCoord: Vec2f(1, 0)),
.init(position: Vec3f( 1, 1, -1), normal: .back, texCoord: Vec2f(0, 1)),
.init(position: Vec3f(-1, 1, -1), normal: .back, texCoord: Vec2f(1, 1)),
.init(position: Vec3f(-1, -1, -1), normal: .left, texCoord: Vec2f(0, 0)),
.init(position: Vec3f(-1, -1, 1), normal: .left, texCoord: Vec2f(1, 0)),
.init(position: Vec3f(-1, 1, -1), normal: .left, texCoord: Vec2f(0, 1)),
.init(position: Vec3f(-1, 1, 1), normal: .left, texCoord: Vec2f(1, 1)),
.init(position: Vec3f(-1, -1, -1), normal: .down, texCoord: Vec2f(0, 0)),
.init(position: Vec3f( 1, -1, -1), normal: .down, texCoord: Vec2f(1, 0)),
.init(position: Vec3f(-1, -1, 1), normal: .down, texCoord: Vec2f(0, 1)),
.init(position: Vec3f( 1, -1, 1), normal: .down, texCoord: Vec2f(1, 1)),
.init(position: Vec3f(-1, 1, 1), normal: .up, texCoord: Vec2f(0, 0)),
.init(position: Vec3f( 1, 1, 1), normal: .up, texCoord: Vec2f(1, 0)),
.init(position: Vec3f(-1, 1, -1), normal: .up, texCoord: Vec2f(0, 1)),
.init(position: Vec3f( 1, 1, -1), normal: .up, texCoord: Vec2f(1, 1))
],
indices: [
0, 1, 2, 2, 1, 3,
4, 5, 6, 6, 5, 7,
8, 9, 10, 10, 9, 11,
12, 13, 14, 14, 13, 15,
16, 17, 18, 18, 17, 19,
20, 21, 22, 22, 21, 23 ]))
suzanne = try content.load("suzanne.g3db")
toybox = try content.load("toybox.g3db")
let linearMipped = Texture2DParameters(
minFilter: .linear, magFilter: .linear,
wrapMode: .repeating,
mipMode: .linear)
let linearClamp = Texture2DParameters(
minFilter: .linear, magFilter: .linear,
wrapMode: .clampEdge)
texture = try content.load("cobblestone.png", params: linearMipped)
jolkTex = try content.load("jolkmeup.jpg", params: linearClamp)
suzanneDiffuse = try content.load("suzanne_diffuse.png", params: linearMipped)
}
func resize(width: Int, height: Int)
{
aspect = Float(width) / Float(height)
print(aspect)
}
func update(deltaTime: Float)
{
colin.update(deltaTime: deltaTime, world: world)
jolkCube.update(deltaTime: deltaTime, world: world)
lightTheta += deltaTime
frameCount += 1
frameTimer -= deltaTime
if frameTimer <= 0
{
print("FPS: \(frameCount)")
frameCount = 0
frameTimer += 1.0
}
}
private func loadWorld(_ content: inout ContentManager) throws
{
//let world: Mesh = try content.load("World.obj")
let obj = try ObjReader.read(url: try content.getResource("World.obj"))
let mesh: Mesh = try ObjLoader.read(model: obj)
worldMesh = try content.create(mesh: mesh)
if let collision = obj.objects["Collision3D"]
{
world.build(obj: obj, collision: collision)
}
}
/*
if let collision = world.subMeshes["Collision"]
{
edges.reserveCapacity(collision.length / 6)
let get2dVertex =
{ i in
let vertex = world.vertices[Int(world.indices[i])]
let position = Vec2f(vertex.position.x, vertex.position.z)
let normal = Vec2f(vertex.normal.x, vertex.normal.z)
return (position, normal)
}
for i in stride(from: collision.start, to: collision.start + collision.length, by: 3)
{
let (v0p, v0n) = get2dVertex(i)
let (v1p, v1n) = get2dVertex(i + 1)
let (v2p, v2n) = get2dVertex(i + 2)
let (p0, p1) = if v0p == v2p || v1p == v2p { (v0p, v1p) }
else if v0p == v1p { (v0p, v2p) }
else { throw NSError() }
let edge = Edge(p: p0.lerp(p1, 0.5), n: (v0n + v1n + v2n).normalised, w: (p0 - p1).len)
if !edges.contains(where: { edge.p == $0.p && edge.w == $0.w })
{
edges.append(edge)
}
}
}
*/
func draw(render: inout Renderer, deltaTime: Float)
{
// Setup camera
render.setProjection(matrix:
.perspective(fovY: Float.rad(fromDeg: colin.fov), aspect: aspect, zNear: 0.1, zFar: 100))
render.setView(matrix: colin.transform)
// Update point lights
var theta = Vec3f(repeating: lightTheta) * Vec3f(0.12, 0.011, 0.056) * 6
var i = env.lights.startIndex
while i != env.lights.endIndex
{
if case .point(let colour, _, _) = env.lights[i]
{
env.lights[i] = .point(
colour: colour,
position: Vec3f(
4 + 6 * cos(theta[0]),
0.33 + 0.33 * sin(theta[1]),
-6 + 3 * sin(theta[0] * 2)),
intensity: 3.1 + 1.53 * cos(theta[2]))
let spacing = 0.5 * Float.pi * (2 / 3.0)
theta += spacing * Vec3f(1, 0.98, 0.5566)
}
i = env.lights.index(after: i)
}
// Draw world
render.setMaterial(Material(
specular: XnaColour.BlanchedAlmond.mix(with: .black, 0.12),
texture: texture.id))
render.draw(mesh: worldMesh, environment: env)
// Draw jolked up shit
render.setMaterial(Material(
specular: XnaColour.Gray,
gloss: 20.0,
texture: jolkTex.id))
render.draw(mesh: cube, model: jolkCube.transform, environment: env)
render.setMaterial(Material(texture: suzanneDiffuse.id))
render.draw(mesh: suzanne, model: .translate(.up + Vec3f(3.0, 0.0, -3.5) * 2.5), environment: env)
render.draw(mesh: toybox,
model: .translate(Vec3f(6.0, 0.667, -3.5) * Vec3f(2.5, 1, 2.5))
* .rotate(y: lightTheta * 0.5) * .scale(scalar: 0.25), environment: env)
if Input.instance.keyPressed(.c) { drawEdges = !drawEdges }
if drawEdges
{
/*
var lines = [Line](
repeating: .init(from: .init(), to: .init(), colour: .zero),
count: edges.count * 3)
var i: Int = 0
for edge in edges
{
let tangent = Vec2f(edge.n.y, -edge.n.x)
let a = edge.p - tangent * edge.w * 0.5
let b = edge.p + tangent * edge.w * 0.5
lines[i] = Line(
from: Vec3f(a.x, 0, a.y),
to: Vec3f(b.x, 0, b.y),
colour: Colour(r: 0.1, g: 0.9, b: 0.1))
lines[i + 1] = Line(
from: Vec3f(edge.p.x, 0, edge.p.y),
to: Vec3f(edge.p.x + edge.n.x * 0.25, 0, edge.p.y + edge.n.y * 0.25),
colour: Colour(r: 0.9, g: 0.1, b: 0.1))
let deltaPos = Vec2f(colin.position.x, colin.position.z) - edge.p
let something = tangent * deltaPos.cross(edge.n)
lines[i + 2] = Line(
from: Vec3f(edge.p.x + something.x, 0.0, edge.p.y + something.y),
to: Vec3f(edge.p.x + something.x + edge.n.x * 0.5, 0.0, edge.p.y + something.y + edge.n.y * 0.5),
colour: XnaColour.Azure)
i += 3
}
render.drawGizmos(lines: lines)
*/
world.draw(render, position: colin.position)
}
}
}