init dump
276
Sources/Test/CavesOfJolk.swift
Normal file
@ -0,0 +1,276 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
497
Sources/Test/Collision.swift
Normal file
@ -0,0 +1,497 @@
|
||||
import Foundation
|
||||
import JolkEngine
|
||||
|
||||
|
||||
class Collision
|
||||
{
|
||||
struct Edge { let p: Vec2f, n: Vec2f, w: Float }
|
||||
|
||||
enum Edge3D
|
||||
{
|
||||
case triangle(n: Vec3f, p: Vec3f, v: (Vec3f, Vec3f, Vec3f))
|
||||
case aabbFloor(n: Vec3f, p: Vec3f, w: Float, d: Float)
|
||||
case quad(p: (Vec3f, Vec3f, Vec3f, Vec3f), w: Winding)
|
||||
}
|
||||
var edge3d = [Edge3D]()
|
||||
|
||||
/*
|
||||
0,-2 1,-2
|
||||
*--*
|
||||
| |
|
||||
0,-1 * * 1,-1
|
||||
| |
|
||||
*--*
|
||||
0, 0 1, 0
|
||||
*/
|
||||
|
||||
|
||||
init()
|
||||
{
|
||||
assert(Self.isRectangle([
|
||||
Vec3f(0.0, 0.0, 0.0),
|
||||
Vec3f(0.0, 0.0, -1.0),
|
||||
Vec3f(1.0, 0.0, -1.0),
|
||||
Vec3f(1.0, 0.0, 0.0),
|
||||
]))
|
||||
|
||||
|
||||
// CW
|
||||
assert(Self.isRectangle([
|
||||
Vec3f(0.0, 0.0, 0.0),
|
||||
Vec3f(0.0, 0.0, -1.0),
|
||||
Vec3f(0.0, 0.0, -2.0),
|
||||
Vec3f(1.0, 0.0, -2.0),
|
||||
Vec3f(1.0, 0.0, -1.0),
|
||||
Vec3f(1.0, 0.0, 0.0),
|
||||
]))
|
||||
assert(Self.isRectangle([
|
||||
Vec3f(0.0, 0.0, -1.0),
|
||||
Vec3f(0.0, 0.0, -2.0),
|
||||
Vec3f(1.0, 0.0, -2.0),
|
||||
Vec3f(1.0, 0.0, -1.0),
|
||||
Vec3f(1.0, 0.0, 0.0),
|
||||
Vec3f(0.0, 0.0, 0.0),
|
||||
]))
|
||||
assert(Self.isRectangle([
|
||||
Vec3f(0.0, 0.0, -2.0),
|
||||
Vec3f(1.0, 0.0, -2.0),
|
||||
Vec3f(1.0, 0.0, -1.0),
|
||||
Vec3f(1.0, 0.0, 0.0),
|
||||
Vec3f(0.0, 0.0, 0.0),
|
||||
Vec3f(0.0, 0.0, -1.0),
|
||||
]))
|
||||
assert(Self.isRectangle([
|
||||
Vec3f(1.0, 0.0, -2.0),
|
||||
Vec3f(1.0, 0.0, -1.0),
|
||||
Vec3f(1.0, 0.0, 0.0),
|
||||
Vec3f(0.0, 0.0, 0.0),
|
||||
Vec3f(0.0, 0.0, -1.0),
|
||||
Vec3f(0.0, 0.0, -2.0),
|
||||
]))
|
||||
assert(Self.isRectangle([
|
||||
Vec3f(1.0, 0.0, -1.0),
|
||||
Vec3f(1.0, 0.0, 0.0),
|
||||
Vec3f(0.0, 0.0, 0.0),
|
||||
Vec3f(0.0, 0.0, -1.0),
|
||||
Vec3f(0.0, 0.0, -2.0),
|
||||
Vec3f(1.0, 0.0, -2.0),
|
||||
]))
|
||||
assert(Self.isRectangle([
|
||||
Vec3f(1.0, 0.0, 0.0),
|
||||
Vec3f(0.0, 0.0, 0.0),
|
||||
Vec3f(0.0, 0.0, -1.0),
|
||||
Vec3f(0.0, 0.0, -2.0),
|
||||
Vec3f(1.0, 0.0, -2.0),
|
||||
Vec3f(1.0, 0.0, -1.0),
|
||||
]))
|
||||
|
||||
// CCW
|
||||
assert(Self.isRectangle([
|
||||
Vec3f( 0.0, 0.0, 0.0),
|
||||
Vec3f( 0.0, 0.0, -1.0),
|
||||
Vec3f( 0.0, 0.0, -2.0),
|
||||
Vec3f(-1.0, 0.0, -2.0),
|
||||
Vec3f(-1.0, 0.0, -1.0),
|
||||
Vec3f(-1.0, 0.0, 0.0),
|
||||
]))
|
||||
assert(Self.isRectangle([
|
||||
Vec3f( 0.0, 0.0, -1.0),
|
||||
Vec3f( 0.0, 0.0, -2.0),
|
||||
Vec3f(-1.0, 0.0, -2.0),
|
||||
Vec3f(-1.0, 0.0, -1.0),
|
||||
Vec3f(-1.0, 0.0, 0.0),
|
||||
Vec3f( 0.0, 0.0, 0.0),
|
||||
]))
|
||||
assert(Self.isRectangle([
|
||||
Vec3f( 0.0, 0.0, -2.0),
|
||||
Vec3f(-1.0, 0.0, -2.0),
|
||||
Vec3f(-1.0, 0.0, -1.0),
|
||||
Vec3f(-1.0, 0.0, 0.0),
|
||||
Vec3f( 0.0, 0.0, 0.0),
|
||||
Vec3f( 0.0, 0.0, -1.0),
|
||||
]))
|
||||
assert(Self.isRectangle([
|
||||
Vec3f(-1.0, 0.0, -2.0),
|
||||
Vec3f(-1.0, 0.0, -1.0),
|
||||
Vec3f(-1.0, 0.0, 0.0),
|
||||
Vec3f( 0.0, 0.0, 0.0),
|
||||
Vec3f( 0.0, 0.0, -1.0),
|
||||
Vec3f( 0.0, 0.0, -2.0),
|
||||
]))
|
||||
assert(Self.isRectangle([
|
||||
Vec3f(-1.0, 0.0, -1.0),
|
||||
Vec3f(-1.0, 0.0, 0.0),
|
||||
Vec3f( 0.0, 0.0, 0.0),
|
||||
Vec3f( 0.0, 0.0, -1.0),
|
||||
Vec3f( 0.0, 0.0, -2.0),
|
||||
Vec3f(-1.0, 0.0, -2.0),
|
||||
]))
|
||||
assert(Self.isRectangle([
|
||||
Vec3f(-1.0, 0.0, 0.0),
|
||||
Vec3f( 0.0, 0.0, 0.0),
|
||||
Vec3f( 0.0, 0.0, -1.0),
|
||||
Vec3f( 0.0, 0.0, -2.0),
|
||||
Vec3f(-1.0, 0.0, -2.0),
|
||||
Vec3f(-1.0, 0.0, -1.0),
|
||||
]))
|
||||
}
|
||||
|
||||
private static let epsilon: Float = 0.00001 //.ulpOfOne
|
||||
|
||||
private static func isSimpleQuad(_ p: (Vec3f, Vec3f, Vec3f, Vec3f)) -> Bool
|
||||
{
|
||||
if abs(p.0.y - p.1.y) <= epsilon { return abs(p.2.y - p.3.y) <= epsilon }
|
||||
if abs(p.1.y - p.2.y) <= epsilon { return abs(p.3.y - p.0.y) <= epsilon }
|
||||
return false
|
||||
}
|
||||
|
||||
private static func isRectangle(_ p: (Vec3f, Vec3f, Vec3f, Vec3f)) -> Bool
|
||||
{
|
||||
if abs(p.0.x - p.1.x) <= epsilon &&
|
||||
abs(p.1.z - p.2.z) <= epsilon &&
|
||||
abs(p.2.x - p.3.x) <= epsilon &&
|
||||
abs(p.3.z - p.0.z) <= epsilon { return true }
|
||||
if abs(p.0.z - p.1.z) <= epsilon &&
|
||||
abs(p.1.x - p.2.x) <= epsilon &&
|
||||
abs(p.2.z - p.3.z) <= epsilon &&
|
||||
abs(p.3.x - p.0.x) <= epsilon { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
private static func isRectangle(_ positions: [Vec3f]) -> Bool
|
||||
{
|
||||
var winding: Winding = .none
|
||||
var xdir: Float = 0.0, zdir: Float = 0.0
|
||||
let first = positions[0]
|
||||
var previous = first
|
||||
for p in positions[1...]
|
||||
{
|
||||
let (xdelta, zdelta) = (p.x - previous.x, p.z - previous.z)
|
||||
let (xzero, zzero) = (abs(xdelta) <= epsilon, abs(zdelta) <= epsilon)
|
||||
if !xzero && zzero
|
||||
{
|
||||
if xdir != 0.0 && xdelta.sign != xdir.sign { return false }
|
||||
if zdir != 0.0
|
||||
{
|
||||
switch winding
|
||||
{
|
||||
case .none: winding = xdelta.sign == zdir.sign ? .ccw : .cw
|
||||
case .cw: if xdelta.sign == zdir.sign { return false }
|
||||
case .ccw: if xdelta.sign != zdir.sign { return false }
|
||||
}
|
||||
}
|
||||
(xdir, zdir) = (xdelta, 0.0)
|
||||
}
|
||||
else if xzero && !zzero
|
||||
{
|
||||
if zdir != 0.0 && zdelta.sign != zdir.sign { return false }
|
||||
if xdir != 0.0
|
||||
{
|
||||
switch winding
|
||||
{
|
||||
case .none: winding = zdelta.sign == xdir.sign ? .cw : .ccw
|
||||
case .cw: if zdelta.sign != xdir.sign { return false }
|
||||
case .ccw: if zdelta.sign == xdir.sign { return false }
|
||||
}
|
||||
}
|
||||
(xdir, zdir) = (0.0, zdelta)
|
||||
}
|
||||
else if !xzero && !zzero { return false }
|
||||
previous = p
|
||||
}
|
||||
return abs(first.x - previous.x) <= epsilon || abs(first.z - previous.z) <= epsilon
|
||||
}
|
||||
|
||||
private static func getQuadWinding(_ p: (Vec3f, Vec3f, Vec3f, Vec3f)) -> Winding
|
||||
{
|
||||
var area: Float = 0.0
|
||||
area += (p.1.x - p.0.x) * ((p.0.z + p.1.z) * 0.5)
|
||||
area += (p.2.x - p.1.x) * ((p.1.z + p.2.z) * 0.5)
|
||||
area += (p.3.x - p.2.x) * ((p.2.z + p.3.z) * 0.5)
|
||||
area += (p.0.x - p.3.x) * ((p.3.z + p.0.z) * 0.5)
|
||||
return area.sign == .plus ? .ccw : .cw // z is towards us
|
||||
}
|
||||
|
||||
static func quadSpaceFromCartesian(quad: (Vec3f, Vec3f, Vec3f, Vec3f), position: Vec3f) -> Vec2f
|
||||
{
|
||||
let p = (
|
||||
Vec2d(Double(quad.0.x), Double(quad.0.z)),
|
||||
Vec2d(Double(quad.1.x), Double(quad.1.z)),
|
||||
Vec2d(Double(quad.2.x), Double(quad.2.z)),
|
||||
Vec2d(Double(quad.3.x), Double(quad.3.z)))
|
||||
|
||||
let xz = Vec2d(Double(position.x), Double(position.z))
|
||||
|
||||
/*
|
||||
let old = {
|
||||
let a = xz.x - p.0.x
|
||||
let b = p.1.x - p.0.x
|
||||
let c = p.3.x - p.0.x
|
||||
let d = p.0.x - p.1.x + p.2.x - p.3.x
|
||||
let f = xz.y - p.0.y
|
||||
let g = p.1.y - p.0.y
|
||||
let h = p.3.y - p.0.y
|
||||
let j = p.0.y - p.1.y + p.2.y - p.3.y
|
||||
let v2 = -c * j - (-d * h)
|
||||
let v1 = a * j - c * g - (d * f - b * h)
|
||||
let v0 = a * g - b * f
|
||||
let vq = (-v1 + sqrt(v1 * v1 - 4.0 * v2 * v0)) / (2.0 * v2)
|
||||
let uq = (a - c * vq) / (b + d * vq)
|
||||
return Vec2f(Float(uq), Float(vq))
|
||||
}
|
||||
*/
|
||||
|
||||
let a = xz - p.0
|
||||
let b = p.1 - p.0
|
||||
let c = p.3 - p.0
|
||||
let d = p.0 - p.1 + p.2 - p.3
|
||||
let v0 = a.cross(b), v2 = c.cross(-d)
|
||||
let v1 = a.x * d.y - b.y * c.x - (a.y * d.x - b.x * c.y)
|
||||
let vq = (-v1 + sqrt(v1 * v1 - 4.0 * v2 * v0)) / (2.0 * v2)
|
||||
let uq = (a.x - c.x * vq) / (b.x + d.x * vq)
|
||||
return Vec2f(Float(uq), Float(vq))
|
||||
//let oldUv = old()
|
||||
//if !oldUv.x.isNaN || !uv.x.isNaN { assert (oldUv.x == uv.x) }
|
||||
//if !oldUv.y.isNaN || !uv.y.isNaN { assert (oldUv.y == uv.y) }
|
||||
//return uv
|
||||
}
|
||||
|
||||
enum Winding { case none, cw, ccw }
|
||||
|
||||
func build(obj: ObjModel, collision: ObjModel.Object)
|
||||
{
|
||||
for face in collision.faces
|
||||
{
|
||||
switch face
|
||||
{
|
||||
case .triangle(let v1, let v2, let v3):
|
||||
let p = (obj.positions[v1.p], obj.positions[v2.p], obj.positions[v3.p])
|
||||
let n = (obj.normals[v1.n] + obj.normals[v2.n] + obj.normals[v3.n]).normalised
|
||||
if abs(n.y) < 0.25 { continue }
|
||||
edge3d.append(.triangle(n: n, p: (p.0 + p.1 + p.2) / 3.0, v: p))
|
||||
case .quad(let v1, let v2, let v3, let v4):
|
||||
let p = (obj.positions[v1.p], obj.positions[v2.p], obj.positions[v3.p], obj.positions[v4.p])
|
||||
let n = (obj.normals[v1.n] + obj.normals[v2.n] + obj.normals[v3.n] + obj.normals[v4.n]).normalised
|
||||
if Self.isSimpleQuad(p) && Self.isRectangle(p)
|
||||
{
|
||||
if abs(n.y) < 0.25 { continue }
|
||||
let left = min(p.0.x, p.1.x, p.2.x, p.3.x)
|
||||
let right = max(p.0.x, p.1.x, p.2.x, p.3.x)
|
||||
let back = min(p.0.z, p.1.z, p.2.z, p.3.z)
|
||||
let forward = max(p.0.z, p.1.z, p.2.z, p.3.z)
|
||||
edge3d.append(.aabbFloor(n: n,
|
||||
p: (p.0 + p.1 + p.2 + p.3) / 4.0,
|
||||
w: (right - left) / 2.0,
|
||||
d: (forward - back) / 2.0))
|
||||
}
|
||||
else
|
||||
{
|
||||
if abs(n.y) < 0.25 { continue }
|
||||
edge3d.append(.quad(p: p, w: Self.getQuadWinding(p)))
|
||||
/*
|
||||
edge3d.append(.triangle(n: n, p: (p.0 + p.1 + p.2) / 3.0, v: (p.0, p.1, p.2)))
|
||||
edge3d.append(.triangle(n: n, p: (p.2 + p.3 + p.0) / 3.0, v: (p.2, p.3, p.0)))
|
||||
*/
|
||||
}
|
||||
case .ngon(let v):
|
||||
let p = v.map { obj.positions[$0.p] }
|
||||
let n = v.reduce(.zero) { $0 + obj.normals[$1.n] }.normalised
|
||||
if abs(n.y) < 0.25 { continue }
|
||||
if Self.isRectangle(p)
|
||||
{
|
||||
let left = p.map { $0.x }.min()!, right = p.map { $0.x }.max()!
|
||||
let bottom = p.map { $0.y }.min()!, top = p.map { $0.y }.max()!
|
||||
let back = p.map { $0.z }.min()!, forward = p.map { $0.z }.max()!
|
||||
let position = Vec3f(left + right, bottom + top, back + forward) / 2.0
|
||||
edge3d.append(.aabbFloor(n: n, p: position,
|
||||
w: (right - left) / 2.0,
|
||||
d: (forward - back) / 2.0))
|
||||
}
|
||||
else
|
||||
{
|
||||
let p0 = p[0]
|
||||
for i in 1..<(v.count-1)
|
||||
{
|
||||
let p1 = p[i], p2 = p[i + 1]
|
||||
edge3d.append(.triangle(n: n, p: (p0 + p1 + p2) / 3.0, v: (p0, p1, p2)))
|
||||
}
|
||||
}
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func draw(_ render: Renderer, position: Vec3f)
|
||||
{
|
||||
var lines = [Line](
|
||||
repeating: .init(from: .init(), to: .init(), colour: .zero),
|
||||
count: edge3d.count * 6)
|
||||
var i: Int = 0
|
||||
for edge in edge3d
|
||||
{
|
||||
var o: Vec3f = .zero, n: Vec3f = .zero
|
||||
switch edge
|
||||
{
|
||||
case .triangle(let trin, let trip, let triv):
|
||||
o = trip
|
||||
n = trin
|
||||
|
||||
let v0 = triv.1 - triv.0;
|
||||
let v1 = triv.2 - triv.0;
|
||||
let v2 = position - triv.0;
|
||||
let iden = 1.0 / (v0.x * v1.z - v1.x * v0.z);
|
||||
let v = (v2.x * v1.z - v1.x * v2.z) * iden;
|
||||
let w = (v0.x * v2.z - v2.x * v0.z) * iden;
|
||||
let colour = if v >= 0.0 && w >= 0.0 && v + w <= 1.0
|
||||
{ XnaColour.Red } else { XnaColour.GreenYellow }
|
||||
//let p = triv
|
||||
//let det = (p.1.x - p.0.x) * (p.2.z - p.0.z) - (p.1.z - p.0.z) * (p.2.x - p.0.x)
|
||||
//let colour: Colour = if
|
||||
// det * (p.1.x - p.0.x) * (position.z - p.0.z) - (p.1.z - p.0.z) * (position.x - p.0.x) >= 0,
|
||||
// det * (p.2.x - p.1.x) * (position.z - p.1.z) - (p.2.z - p.1.z) * (position.x - p.1.x) >= 0,
|
||||
// det * (p.0.x - p.2.x) * (position.z - p.2.z) - (p.0.z - p.2.z) * (position.x - p.2.x) >= 0
|
||||
/*
|
||||
let side = { (v1: Vec3f, v2: Vec3f, p: Vec3f) in
|
||||
(v2.z - v1.z) * (p.x - v1.x) + (v2.x + v1.x) * (position.z - v1.z) }
|
||||
let colour = if
|
||||
side(triv.0, triv.1, position) >= 0,
|
||||
side(triv.1, triv.2, position) >= 0,
|
||||
side(triv.2, triv.0, position) >= 0
|
||||
*/
|
||||
|
||||
lines[i + 0] = Line(from: triv.0, to: triv.1, colour: colour)
|
||||
lines[i + 1] = Line(from: triv.1, to: triv.2, colour: colour)
|
||||
lines[i + 2] = Line(from: triv.2, to: triv.0, colour: colour)
|
||||
i += 3
|
||||
case .aabbFloor(let floorn, let floorp, let floorw, let floord):
|
||||
o = floorp
|
||||
n = floorn
|
||||
|
||||
let n2 = Vec2f(n.x, n.z) / n.y
|
||||
let z0 = Vec2f(-floorw, floord).dot(n2)
|
||||
let z1 = Vec2f(-floorw, -floord).dot(n2)
|
||||
let z2 = Vec2f( floorw, -floord).dot(n2)
|
||||
let z3 = Vec2f( floorw, floord).dot(n2)
|
||||
|
||||
let c0 = floorp + Vec3f( floorw, z0, -floord)
|
||||
let c1 = floorp + Vec3f( floorw, z1, floord)
|
||||
let c2 = floorp + Vec3f(-floorw, z2, floord)
|
||||
let c3 = floorp + Vec3f(-floorw, z3, -floord)
|
||||
|
||||
lines[i + 0] = Line(from: c0, to: c1, colour: XnaColour.GreenYellow)
|
||||
lines[i + 1] = Line(from: c1, to: c2, colour: XnaColour.GreenYellow)
|
||||
lines[i + 2] = Line(from: c2, to: c3, colour: XnaColour.GreenYellow)
|
||||
lines[i + 3] = Line(from: c3, to: c0, colour: XnaColour.GreenYellow)
|
||||
i += 4
|
||||
case .quad(let verts, let winding):
|
||||
/*
|
||||
let p = (
|
||||
verts.0 + (verts.1 - verts.0) * position.x,
|
||||
verts.3 + (verts.2 - verts.3) * position.x,
|
||||
verts.0 + (verts.3 - verts.0) * position.z,
|
||||
verts.1 + (verts.2 - verts.1) * position.z)
|
||||
|
||||
let xdiff = Vec2f(p.0.x - p.1.x, p.2.x - p.3.x)
|
||||
let ydiff = Vec2f(p.0.z - p.1.z, p.2.z - p.3.z)
|
||||
let div = xdiff.cross(ydiff)
|
||||
guard div != 0.0 else { break }
|
||||
|
||||
let d = Vec2f(
|
||||
Vec2f(p.0.x, p.0.z).cross(Vec2f(p.1.x, p.1.z)),
|
||||
Vec2f(p.2.x, p.2.z).cross(Vec2f(p.3.x, p.3.z)))
|
||||
let pos = Vec2f(d.cross(xdiff), d.cross(ydiff)) / div
|
||||
|
||||
o = Vec3f(pos.x, 0.0, pos.y)
|
||||
n = .up
|
||||
*/
|
||||
|
||||
//n = winding == .ccw ? .up : .down
|
||||
o = verts.0.lerp(verts.3, 0.5).lerp(
|
||||
verts.2.lerp(verts.1, 0.5), 0.5)
|
||||
|
||||
/*
|
||||
let xy = Vec2d(Double(position.x), Double(position.z))
|
||||
let a = xy.x - p.0.x
|
||||
let b = p.1.x - p.0.x
|
||||
let c = p.3.x - p.0.x
|
||||
let d = p.0.x - p.1.x + p.2.x - p.3.x
|
||||
let f = xy.y - p.0.y
|
||||
let g = p.1.y - p.0.y
|
||||
let h = p.3.y - p.0.y
|
||||
let j = p.0.y - p.1.y + p.2.y - p.3.y
|
||||
let v2 = -c * j - (-d * h)
|
||||
let v1 = a * j - c * g - (d * f - b * h)
|
||||
let v0 = a * g - b * f
|
||||
let vq = (-v1 + sqrt(v1 * v1 - 4.0 * v2 * v0)) / (2.0 * v2)
|
||||
let uq = (a - c * vq) / (b + d * vq)
|
||||
let uv = Vec2d(uq, vq)
|
||||
*/
|
||||
|
||||
var colour = XnaColour.GreenYellow
|
||||
|
||||
/*
|
||||
p1 p2
|
||||
*------*
|
||||
| |
|
||||
| |
|
||||
*------*
|
||||
p0 p3
|
||||
*/
|
||||
|
||||
let p = winding == .ccw ? (verts.3, verts.2, verts.1, verts.0) : (verts.0, verts.1, verts.2, verts.3)
|
||||
let vn = (
|
||||
(verts.1 - verts.0).cross(verts.3 - verts.0),
|
||||
(verts.2 - verts.1).cross(verts.0 - verts.1),
|
||||
(verts.3 - verts.2).cross(verts.1 - verts.2),
|
||||
(verts.0 - verts.3).cross(verts.2 - verts.3)
|
||||
)
|
||||
n = (vn.0 + vn.1 + vn.2 + vn.3).normalised
|
||||
|
||||
let uv = Self.quadSpaceFromCartesian(quad: p, position: position)
|
||||
if uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0
|
||||
//if uv.x >= -1.0 && uv.x <= 1.0 && uv.y >= -1.0 && uv.y <= 1.0
|
||||
{
|
||||
var pp = p.0
|
||||
pp += (p.1 - p.0) * uv.x
|
||||
pp += (p.3 - p.0) * uv.y
|
||||
pp += (p.0 - p.1 + p.2 - p.3) * uv.x * uv.y
|
||||
lines[i] = Line(from: o, to: pp, colour: XnaColour.Aquamarine)
|
||||
i += 1
|
||||
colour = XnaColour.BurlyWood
|
||||
o = pp
|
||||
n = vn.0.lerp(vn.3, uv.x).lerp(
|
||||
vn.2.lerp(vn.1, uv.x), winding == .cw ? uv.y : 1.0 - uv.y).normalised
|
||||
}
|
||||
|
||||
lines[i + 0] = Line(from: verts.0, to: verts.1, colour: colour)
|
||||
lines[i + 1] = Line(from: verts.1, to: verts.2, colour: colour)
|
||||
lines[i + 2] = Line(from: verts.2, to: verts.3, colour: colour)
|
||||
lines[i + 3] = Line(from: verts.3, to: verts.0, colour: colour)
|
||||
i += 4
|
||||
}
|
||||
let p = position
|
||||
let a = p.dot(n) - o.dot(n)
|
||||
let pissy = p - n * a
|
||||
|
||||
//let d = colin.position - edge.p
|
||||
//let pissy = edge.p + d.cross(edge.n)
|
||||
|
||||
/*
|
||||
if a > -1.0 && a <= 0.0
|
||||
{
|
||||
lines[i + 0] = Line(from: o, to: o + n * max(0, a), colour: XnaColour.Magenta)
|
||||
lines[i + 1] = Line(from: pissy + .up, to: o, colour: XnaColour.Red)
|
||||
i += 2
|
||||
}
|
||||
*/
|
||||
lines[i + 0] = Line(from: o, to: o + n * 0.2, colour: XnaColour.Magenta)
|
||||
i += 1
|
||||
//lines[i + 4] = Line(from: pissy + Vec3f(-1, 0, 0) * 0.1, to: pissy + Vec3f(1, 0, 0) * 0.1, colour: XnaColour.Red)
|
||||
//lines[i + 5] = Line(from: pissy + Vec3f( 0,-1, 0) * 0.1, to: pissy + Vec3f(0, 1, 0) * 0.1, colour: XnaColour.Red)
|
||||
//lines[i + 6] = Line(from: pissy + Vec3f( 0, 0,-1) * 0.1, to: pissy + Vec3f(0, 0, 1) * 0.1, colour: XnaColour.Red)
|
||||
|
||||
}
|
||||
render.drawGizmos(lines: lines)
|
||||
}
|
||||
}
|
9
Sources/Test/Objects/Actor.swift
Normal file
@ -0,0 +1,9 @@
|
||||
import JolkEngine
|
||||
|
||||
protocol Actor
|
||||
{
|
||||
func update(deltaTime: Float, world: Collision)
|
||||
|
||||
var position: Vec3f { get }
|
||||
var transform: Mat4f { get }
|
||||
}
|
276
Sources/Test/Objects/Colin.swift
Normal file
@ -0,0 +1,276 @@
|
||||
import SDL2
|
||||
import simd
|
||||
import OpenGL.GL
|
||||
import JolkEngine
|
||||
|
||||
|
||||
class Colin: Actor
|
||||
{
|
||||
var position: Vec3f { _pos }
|
||||
|
||||
var transform: Mat4f
|
||||
{
|
||||
//.rotate(yaw: angle.x, pitch: angle.y, roll: sin(time)) *
|
||||
//.scale(Vec3f(1.0 + 0.25 * cos(time), 1.0 + 0.25 * sin(time), 1.0)) *
|
||||
.rotate(yawPitch: angle) * .translate(-position - Vec3f(0, 1, 0))
|
||||
}
|
||||
|
||||
var angle: Vec2f { return Vec2f(ofsAngle.x + _angle, ofsAngle.y) }
|
||||
var fov: Float { return _fov }
|
||||
|
||||
private var time: Float = 0.0
|
||||
//private var jumpVel: Float = 0.0
|
||||
private var velocity: Vec3f = .zero
|
||||
private var _pos: Vec3f = .zero
|
||||
private var _pos2D: Vec2f { get { Vec2f(_pos.x, _pos.z) } set(new) { _pos.x = new.x; _pos.z = new.y } }
|
||||
private var _angle: Float = 0.0
|
||||
private var ofsAngle: Vec2f = .zero
|
||||
private var _fov: Float = 60.0
|
||||
|
||||
private var nutted = false
|
||||
private var colinMode = false
|
||||
private var backPressed = false
|
||||
|
||||
private let colinWidth: Float = 0.2
|
||||
|
||||
private func move2D(new: Vec2f, edges: [Collision.Edge])
|
||||
{
|
||||
let velocity = new - _pos2D
|
||||
var lastPos = _pos2D
|
||||
_pos2D = new
|
||||
|
||||
var collided = -1
|
||||
jolk: while (collided != 0)
|
||||
{
|
||||
let scabidabadoo = 10
|
||||
for edge in edges
|
||||
{
|
||||
let diff = _pos2D - lastPos
|
||||
if simd_dot(edge.n, diff) > 0 && simd_dot(edge.n, velocity) > 0 { continue }
|
||||
|
||||
let deltaPos = _pos2D - edge.p
|
||||
let something = deltaPos.cross(edge.n)
|
||||
if abs(something) * 2.0 < edge.w
|
||||
{
|
||||
let dot = simd_dot(edge.n, deltaPos)
|
||||
if dot > 0 && dot < colinWidth
|
||||
{
|
||||
lastPos = _pos2D
|
||||
_pos2D += edge.n * (colinWidth - dot)
|
||||
if collided < 0 { collided = scabidabadoo };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
let vec = (deltaPos - Vec2f(edge.n.y, -edge.n.x) * Float(signOf: something, magnitudeOf: edge.w * 0.5))
|
||||
let distance2 = vec.len2
|
||||
let epsilon: Float = 0.001
|
||||
if distance2 < (colinWidth - epsilon) * (colinWidth - epsilon)
|
||||
{
|
||||
let distance = distance2.squareRoot()
|
||||
lastPos = _pos2D
|
||||
_pos2D += (vec / distance) * (colinWidth - epsilon - distance)
|
||||
if collided < 0 { collided = scabidabadoo };
|
||||
}
|
||||
}
|
||||
}
|
||||
collided -= 1;
|
||||
if collided <= 0 { break jolk }
|
||||
}
|
||||
}
|
||||
|
||||
private func response3D(plainPos o: Vec3f, plainNorm n: Vec3f)
|
||||
{
|
||||
let height: Float = 1.12
|
||||
//let diff = _pos - lastPos
|
||||
|
||||
//let p = n.y > 1.0 ? _pos : (_pos + 2.0)
|
||||
let ofs: Vec3f = n.y.sign == .plus ? .zero : .up * height
|
||||
//let p = if n.y.sign == .plus { _pos } else { _pos + 1.0 }
|
||||
let p = _pos + ofs
|
||||
let a = p.dot(n) - o.dot(n)
|
||||
|
||||
if a > height * -0.5 && a < 0.0
|
||||
{
|
||||
_pos -= n * a
|
||||
velocity -= velocity.project(n)
|
||||
}
|
||||
}
|
||||
|
||||
private func move3D(_ deltaTime: Float, world: Collision)
|
||||
{
|
||||
var lastPos = _pos
|
||||
_pos += velocity * deltaTime
|
||||
|
||||
for edge in world.edge3d
|
||||
{
|
||||
switch edge
|
||||
{
|
||||
case .aabbFloor(let normal, let origin, let width, let depth):
|
||||
//let left = min(edge.v0.x, edge.v1.x, edge.v2.x)
|
||||
//let right = max(edge.v0.x, edge.v1.x, edge.v2.x)
|
||||
//let back = min(edge.v0.z, edge.v1.z, edge.v2.z)
|
||||
//let forward = max(edge.v0.z, edge.v1.z, edge.v2.z)
|
||||
|
||||
let left = origin.x - width, right = origin.x + width
|
||||
let back = origin.z - depth, forward = origin.z + depth
|
||||
|
||||
if _pos.x < left || _pos.x > right { continue }
|
||||
if _pos.z < back || _pos.z > forward { continue }
|
||||
|
||||
response3D(plainPos: origin, plainNorm: normal)
|
||||
|
||||
case .triangle(let normal, let origin, let verts):
|
||||
let p = (verts.1 - verts.0, verts.2 - verts.0, _pos - verts.0)
|
||||
let invDenom = 1.0 / (p.0.x * p.1.z - p.1.x * p.0.z);
|
||||
let v = invDenom * (p.2.x * p.1.z - p.1.x * p.2.z);
|
||||
let w = invDenom * (p.0.x * p.2.z - p.2.x * p.0.z);
|
||||
let x = 1.0 - v - w
|
||||
//guard v >= 0.0 && w >= 0.0 && v + w <= 1.0 else { break }
|
||||
guard v >= 0.0 && w >= 0.0 && 0 <= x && x <= 1.0 else { break }
|
||||
response3D(plainPos: origin, plainNorm: normal)
|
||||
|
||||
case .quad(let verts, let winding):
|
||||
let vn = (
|
||||
(verts.1 - verts.0).cross(verts.3 - verts.0),
|
||||
(verts.2 - verts.1).cross(verts.0 - verts.1),
|
||||
(verts.3 - verts.2).cross(verts.1 - verts.2),
|
||||
(verts.0 - verts.3).cross(verts.2 - verts.3)
|
||||
)
|
||||
|
||||
let uv = Collision.quadSpaceFromCartesian(quad:
|
||||
winding == .ccw ? (verts.3, verts.2, verts.1, verts.0) : (verts.0, verts.1, verts.2, verts.3)
|
||||
, position: _pos)
|
||||
if uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0
|
||||
{
|
||||
//var pp = p.0
|
||||
//pp += (p.1 - p.0) * uv.x
|
||||
//pp += (p.3 - p.0) * uv.y
|
||||
//pp += (p.0 - p.1 + p.2 - p.3) * uv.x * uv.y
|
||||
let p = verts.0.lerp(verts.1, uv.x).lerp(
|
||||
verts.3.lerp(verts.2, uv.x), winding == .cw ? uv.y : 1.0 - uv.y)
|
||||
let n = vn.0.lerp(vn.3, uv.x).lerp(
|
||||
vn.2.lerp(vn.1, uv.x), winding == .cw ? uv.y : 1.0 - uv.y).normalised
|
||||
|
||||
response3D(plainPos: Vec3f(_pos.x, p.y, _pos.z), plainNorm: n)
|
||||
}
|
||||
/*
|
||||
let p = (
|
||||
verts.0 + (verts.1 - verts.0) * _pos.x,
|
||||
verts.3 + (verts.2 - verts.3) * _pos.x,
|
||||
verts.0 + (verts.3 - verts.0) * _pos.z,
|
||||
verts.1 + (verts.2 - verts.1) * _pos.z)
|
||||
|
||||
let xdiff = Vec2f(p.0.x - p.1.x, p.2.x - p.3.x)
|
||||
let ydiff = Vec2f(p.0.z - p.1.z, p.2.z - p.3.z)
|
||||
let div = xdiff.cross(ydiff)
|
||||
guard div != 0.0 else { break }
|
||||
|
||||
let d = Vec2f(
|
||||
Vec2f(p.0.x, p.0.z).cross(Vec2f(p.1.x, p.1.z)),
|
||||
Vec2f(p.2.x, p.2.z).cross(Vec2f(p.3.x, p.3.z)))
|
||||
let pos = Vec2f(d.cross(xdiff), d.cross(ydiff)) / div
|
||||
*/
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func update(deltaTime: Float, world: Collision)
|
||||
{
|
||||
time += deltaTime
|
||||
|
||||
let axisRescale = 1.0 / Float(INT16_MAX)
|
||||
let getAxis = { (axis: SDL_GameControllerAxis) in
|
||||
Float(SDL_GameControllerGetAxis(sdlPad, axis)) * axisRescale }
|
||||
let getButton = { (btn: SDL_GameControllerButton) in
|
||||
SDL_GameControllerGetButton(sdlPad, btn) == SDL_PRESSED }
|
||||
|
||||
let stick = Vec2f(
|
||||
getAxis(SDL_CONTROLLER_AXIS_LEFTX),
|
||||
getAxis(SDL_CONTROLLER_AXIS_LEFTY))
|
||||
.cardinalDeadzone(min: 0.1, max: 1)
|
||||
|
||||
let turnSpeed = Float.pi * 2 * 0.1
|
||||
if Input.instance.keyDown(.left)
|
||||
{
|
||||
_angle -= turnSpeed * deltaTime
|
||||
}
|
||||
if Input.instance.keyDown(.right)
|
||||
{
|
||||
_angle += turnSpeed * deltaTime
|
||||
}
|
||||
if stick != .zero
|
||||
{
|
||||
_angle += stick.x * 2.0 * turnSpeed * deltaTime
|
||||
}
|
||||
|
||||
var moveVec: Vec2f = .zero
|
||||
|
||||
let speed: Float = 2
|
||||
let forward = Vec2f(sin(self._angle), -cos(self._angle))
|
||||
if Input.instance.keyDown(.up)
|
||||
{
|
||||
moveVec += forward * speed
|
||||
}
|
||||
if Input.instance.keyDown(.down)
|
||||
{
|
||||
moveVec -= forward * speed
|
||||
}
|
||||
if stick != .zero
|
||||
{
|
||||
moveVec -= forward * stick.y * speed
|
||||
}
|
||||
|
||||
if Input.instance.keyDown(.c)
|
||||
{
|
||||
colinMode = !colinMode
|
||||
}
|
||||
|
||||
let lookCone = Float.pi / 2.0
|
||||
let dst = Vec2f(
|
||||
getAxis(SDL_CONTROLLER_AXIS_RIGHTX),
|
||||
getAxis(SDL_CONTROLLER_AXIS_RIGHTY))
|
||||
.radialDeadzone(min: 0.1, max: 1) * lookCone
|
||||
ofsAngle = ofsAngle.lerp(dst, 16 * deltaTime)
|
||||
|
||||
let targetFov = Float.lerp(60, 20, getAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT))
|
||||
_fov = Float.lerp(_fov, targetFov, 20 * deltaTime)
|
||||
|
||||
let right = Vec2f(cos(self._angle), sin(self._angle))
|
||||
if getButton(SDL_CONTROLLER_BUTTON_LEFTSHOULDER)
|
||||
{
|
||||
moveVec -= right * speed
|
||||
}
|
||||
if getButton(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)
|
||||
{
|
||||
moveVec += right * speed
|
||||
}
|
||||
|
||||
let back = getButton(SDL_CONTROLLER_BUTTON_BACK)
|
||||
if !backPressed && back { colinMode = !colinMode }
|
||||
backPressed = back
|
||||
|
||||
if getButton(SDL_CONTROLLER_BUTTON_A) || Input.instance.keyDown(.n)
|
||||
{
|
||||
// play nut.wav
|
||||
nutted = true
|
||||
}
|
||||
else { nutted = false }
|
||||
|
||||
//move2D(new: _pos2D + velocity, edges: edges)
|
||||
|
||||
if Input.instance.keyDown(.z) || getButton(SDL_CONTROLLER_BUTTON_B) { velocity.y = 2.0 }
|
||||
//_pos.y += jumpVel * deltaTime
|
||||
//if _pos.y > 0.0 { jumpVel -= 5.4 * deltaTime }
|
||||
velocity.y -= 5.4 * deltaTime
|
||||
velocity.x = moveVec.x
|
||||
velocity.z = moveVec.y
|
||||
move3D(deltaTime, world: world)
|
||||
//else if _pos.y < 0.0
|
||||
//{
|
||||
// jumpVel = max(jumpVel, 0.0)
|
||||
// _pos.y = 0.0
|
||||
//}
|
||||
}
|
||||
}
|
33
Sources/Test/Objects/JolkCube.swift
Normal file
@ -0,0 +1,33 @@
|
||||
import Foundation
|
||||
import simd
|
||||
import JolkEngine
|
||||
|
||||
|
||||
class JolkCube: Actor
|
||||
{
|
||||
private var _pos: Vec3f
|
||||
private var theta: Float = 0.0
|
||||
|
||||
init(position: Vec3f)
|
||||
{
|
||||
_pos = position
|
||||
}
|
||||
|
||||
var position: Vec3f { _pos }
|
||||
|
||||
func update(deltaTime: Float, world: Collision)
|
||||
{
|
||||
theta += 15 * deltaTime
|
||||
_pos.y = 1 + sin(theta * 0.25) * 0.25
|
||||
}
|
||||
|
||||
var transform: Mat4f
|
||||
{
|
||||
.translate(_pos) *
|
||||
.rotate(x: theta * 0.25) *
|
||||
.rotate(y: Float.rad(fromDeg: theta)) *
|
||||
// .rotate(axis: .X, angle: theta * 0.25) *
|
||||
// .rotate(axis: .Y, angle: Float.rad(fromDeg: theta)) *
|
||||
.scale(scalar: 0.25)
|
||||
}
|
||||
}
|
33
Sources/Test/Resources/Models/World.mtl
Normal file
@ -0,0 +1,33 @@
|
||||
# Blender 3.6.2 MTL File: 'World.blend'
|
||||
# www.blender.org
|
||||
|
||||
newmtl Cobblestone
|
||||
Ns 437.449280
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.450000
|
||||
d 1.000000
|
||||
illum 1
|
||||
map_Kd cobblestone.png
|
||||
map_Ks cobblestone_specular.png
|
||||
map_Bump -bm 1.000000 cobblestone_normal.png
|
||||
|
||||
newmtl Material
|
||||
Ns 167.965591
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.089179 0.800000 0.000000
|
||||
Ks 0.483607 0.483607 0.483607
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.450000
|
||||
d 1.000000
|
||||
illum 2
|
||||
|
||||
newmtl MetalWall
|
||||
Ns 55.588612
|
||||
Ka 0.390244 0.390244 0.390244
|
||||
Ks 0.573171 0.573171 0.573171
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 9.650000
|
||||
d 1.000000
|
||||
illum 3
|
||||
map_Kd metalwall1.jpg
|
13583
Sources/Test/Resources/Models/World.obj
Normal file
BIN
Sources/Test/Resources/Models/suzanne.g3db
Normal file
BIN
Sources/Test/Resources/Models/toybox.g3db
Normal file
BIN
Sources/Test/Resources/Textures/cobblestone.png
Normal file
After Width: | Height: | Size: 3.3 MiB |
BIN
Sources/Test/Resources/Textures/cobblestone_bump.png
Normal file
After Width: | Height: | Size: 197 KiB |
BIN
Sources/Test/Resources/Textures/cobblestone_normal.png
Normal file
After Width: | Height: | Size: 265 KiB |
BIN
Sources/Test/Resources/Textures/cobblestone_specular.png
Normal file
After Width: | Height: | Size: 235 KiB |
BIN
Sources/Test/Resources/Textures/colin.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
Sources/Test/Resources/Textures/jolkmeup.jpg
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
Sources/Test/Resources/Textures/metalwall1.jpg
Normal file
After Width: | Height: | Size: 102 KiB |
BIN
Sources/Test/Resources/Textures/suzanne_diffuse.png
Normal file
After Width: | Height: | Size: 656 KiB |
BIN
Sources/Test/Resources/Textures/suzanne_normal.png
Normal file
After Width: | Height: | Size: 881 KiB |
BIN
Sources/Test/Resources/Textures/toybox_albedo.png
Normal file
After Width: | Height: | Size: 1.6 MiB |
BIN
Sources/Test/Resources/Textures/toybox_displace.png
Normal file
After Width: | Height: | Size: 145 KiB |
BIN
Sources/Test/Resources/Textures/toybox_normal.png
Normal file
After Width: | Height: | Size: 231 KiB |
BIN
Sources/Test/World.blend
Normal file
148
Sources/Test/XnaColour.swift
Normal file
@ -0,0 +1,148 @@
|
||||
import JolkEngine
|
||||
|
||||
|
||||
public struct XnaColour
|
||||
{
|
||||
public static let Transparent = Colour.zero
|
||||
public static let AliceBlue = Colour(fromRgb24: 0xF0F8FF)
|
||||
public static let AntiqueWhite = Colour(fromRgb24: 0xFAEBD7)
|
||||
public static let Aqua = Colour(fromRgb24: 0x00FFFF)
|
||||
public static let Aquamarine = Colour(fromRgb24: 0x7FFFD4)
|
||||
public static let Azure = Colour(fromRgb24: 0xF0FFFF)
|
||||
public static let Beige = Colour(fromRgb24: 0xF5F5DC)
|
||||
public static let Bisque = Colour(fromRgb24: 0xFFE4C4)
|
||||
public static let Black = Colour.black
|
||||
public static let BlanchedAlmond = Colour(fromRgb24: 0xFFEBCD)
|
||||
public static let Blue = Colour(fromRgb24: 0x0000FF)
|
||||
public static let BlueViolet = Colour(fromRgb24: 0x8A2BE2)
|
||||
public static let Brown = Colour(fromRgb24: 0xA52A2A)
|
||||
public static let BurlyWood = Colour(fromRgb24: 0xDEB887)
|
||||
public static let CadetBlue = Colour(fromRgb24: 0x5F9EA0)
|
||||
public static let Chartreuse = Colour(fromRgb24: 0x7FFF00)
|
||||
public static let Chocolate = Colour(fromRgb24: 0xD2691E)
|
||||
public static let Coral = Colour(fromRgb24: 0xFF7F50)
|
||||
public static let CornflowerBlue = Colour(fromRgb24: 0x6495ED)
|
||||
public static let Cornsilk = Colour(fromRgb24: 0xFFF8DC)
|
||||
public static let Crimson = Colour(fromRgb24: 0xDC143C)
|
||||
public static let Cyan = Colour(fromRgb24: 0x00FFFF)
|
||||
public static let DarkBlue = Colour(fromRgb24: 0x00008B)
|
||||
public static let DarkCyan = Colour(fromRgb24: 0x008B8B)
|
||||
public static let DarkGoldenrod = Colour(fromRgb24: 0xB8860B)
|
||||
public static let DarkGray = Colour(fromRgb24: 0xA9A9A9)
|
||||
public static let DarkGreen = Colour(fromRgb24: 0x006400)
|
||||
public static let DarkKhaki = Colour(fromRgb24: 0xBDB76B)
|
||||
public static let DarkMagenta = Colour(fromRgb24: 0x8B008B)
|
||||
public static let DarkOliveGreen = Colour(fromRgb24: 0x556B2F)
|
||||
public static let DarkOrange = Colour(fromRgb24: 0xFF8C00)
|
||||
public static let DarkOrchid = Colour(fromRgb24: 0x9932CC)
|
||||
public static let DarkRed = Colour(fromRgb24: 0x8B0000)
|
||||
public static let DarkSalmon = Colour(fromRgb24: 0xE9967A)
|
||||
public static let DarkSeaGreen = Colour(fromRgb24: 0x8FBC8B)
|
||||
public static let DarkSlateBlue = Colour(fromRgb24: 0x483D8B)
|
||||
public static let DarkSlateGray = Colour(fromRgb24: 0x2F4F4F)
|
||||
public static let DarkTurquoise = Colour(fromRgb24: 0x00CED1)
|
||||
public static let DarkViolet = Colour(fromRgb24: 0x9400D3)
|
||||
public static let DeepPink = Colour(fromRgb24: 0xFF1493)
|
||||
public static let DeepSkyBlue = Colour(fromRgb24: 0x00BFFF)
|
||||
public static let DimGray = Colour(fromRgb24: 0x696969)
|
||||
public static let DodgerBlue = Colour(fromRgb24: 0x1E90FF)
|
||||
public static let Firebrick = Colour(fromRgb24: 0xB22222)
|
||||
public static let FloralWhite = Colour(fromRgb24: 0xFFFAF0)
|
||||
public static let ForestGreen = Colour(fromRgb24: 0x228B22)
|
||||
public static let Fuchsia = Colour(fromRgb24: 0xFF00FF)
|
||||
public static let Gainsboro = Colour(fromRgb24: 0xDCDCDC)
|
||||
public static let GhostWhite = Colour(fromRgb24: 0xF8F8FF)
|
||||
public static let Gold = Colour(fromRgb24: 0xFFD700)
|
||||
public static let Goldenrod = Colour(fromRgb24: 0xDAA520)
|
||||
public static let Gray = Colour(fromRgb24: 0x808080)
|
||||
public static let Green = Colour(fromRgb24: 0x008000)
|
||||
public static let GreenYellow = Colour(fromRgb24: 0xADFF2F)
|
||||
public static let Honeydew = Colour(fromRgb24: 0xF0FFF0)
|
||||
public static let HotPink = Colour(fromRgb24: 0xFF69B4)
|
||||
public static let IndianRed = Colour(fromRgb24: 0xCD5C5C)
|
||||
public static let Indigo = Colour(fromRgb24: 0x4B0082)
|
||||
public static let Ivory = Colour(fromRgb24: 0xFFFFF0)
|
||||
public static let Khaki = Colour(fromRgb24: 0xF0E68C)
|
||||
public static let Lavender = Colour(fromRgb24: 0xE6E6FA)
|
||||
public static let LavenderBlush = Colour(fromRgb24: 0xFFF0F5)
|
||||
public static let LawnGreen = Colour(fromRgb24: 0x7CFC00)
|
||||
public static let LemonChiffon = Colour(fromRgb24: 0xFFFACD)
|
||||
public static let LightBlue = Colour(fromRgb24: 0xADD8E6)
|
||||
public static let LightCoral = Colour(fromRgb24: 0xF08080)
|
||||
public static let LightCyan = Colour(fromRgb24: 0xE0FFFF)
|
||||
public static let LightGoldenrodYellow = Colour(fromRgb24: 0xFAFAD2)
|
||||
public static let LightGray = Colour(fromRgb24: 0xD3D3D3)
|
||||
public static let LightGreen = Colour(fromRgb24: 0x90EE90)
|
||||
public static let LightPink = Colour(fromRgb24: 0xFFB6C1)
|
||||
public static let LightSalmon = Colour(fromRgb24: 0xFFA07A)
|
||||
public static let LightSeaGreen = Colour(fromRgb24: 0x20B2AA)
|
||||
public static let LightSkyBlue = Colour(fromRgb24: 0x87CEFA)
|
||||
public static let LightSlateGray = Colour(fromRgb24: 0x778899)
|
||||
public static let LightSteelBlue = Colour(fromRgb24: 0xB0C4DE)
|
||||
public static let LightYellow = Colour(fromRgb24: 0xFFFFE0)
|
||||
public static let Lime = Colour(fromRgb24: 0x00FF00)
|
||||
public static let LimeGreen = Colour(fromRgb24: 0x32CD32)
|
||||
public static let Linen = Colour(fromRgb24: 0xFAF0E6)
|
||||
public static let Magenta = Colour(fromRgb24: 0xFF00FF)
|
||||
public static let Maroon = Colour(fromRgb24: 0x800000)
|
||||
public static let MediumAquamarine = Colour(fromRgb24: 0x66CDAA)
|
||||
public static let MediumBlue = Colour(fromRgb24: 0x0000CD)
|
||||
public static let MediumOrchid = Colour(fromRgb24: 0xBA55D3)
|
||||
public static let MediumPurple = Colour(fromRgb24: 0x9370DB)
|
||||
public static let MediumSeaGreen = Colour(fromRgb24: 0x3CB371)
|
||||
public static let MediumSlateBlue = Colour(fromRgb24: 0x7B68EE)
|
||||
public static let MediumSpringGreen = Colour(fromRgb24: 0x00FA9A)
|
||||
public static let MediumTurquoise = Colour(fromRgb24: 0x48D1CC)
|
||||
public static let MediumVioletRed = Colour(fromRgb24: 0xC71585)
|
||||
public static let MidnightBlue = Colour(fromRgb24: 0x191970)
|
||||
public static let MintCream = Colour(fromRgb24: 0xF5FFFA)
|
||||
public static let MistyRose = Colour(fromRgb24: 0xFFE4E1)
|
||||
public static let Moccasin = Colour(fromRgb24: 0xFFE4B5)
|
||||
public static let MonoGameOrange = Colour(fromRgb24: 0xE73C00)
|
||||
public static let NavajoWhite = Colour(fromRgb24: 0xFFDEAD)
|
||||
public static let Navy = Colour(fromRgb24: 0x000080)
|
||||
public static let OldLace = Colour(fromRgb24: 0xFDF5E6)
|
||||
public static let Olive = Colour(fromRgb24: 0x808000)
|
||||
public static let OliveDrab = Colour(fromRgb24: 0x6B8E23)
|
||||
public static let Orange = Colour(fromRgb24: 0xFFA500)
|
||||
public static let OrangeRed = Colour(fromRgb24: 0xFF4500)
|
||||
public static let Orchid = Colour(fromRgb24: 0xDA70D6)
|
||||
public static let PaleGoldenrod = Colour(fromRgb24: 0xEEE8AA)
|
||||
public static let PaleGreen = Colour(fromRgb24: 0x98FB98)
|
||||
public static let PaleTurquoise = Colour(fromRgb24: 0xAFEEEE)
|
||||
public static let PaleVioletRed = Colour(fromRgb24: 0xDB7093)
|
||||
public static let PapayaWhip = Colour(fromRgb24: 0xFFEFD5)
|
||||
public static let PeachPuff = Colour(fromRgb24: 0xFFDAB9)
|
||||
public static let Peru = Colour(fromRgb24: 0xCD853F)
|
||||
public static let Pink = Colour(fromRgb24: 0xFFC0CB)
|
||||
public static let Plum = Colour(fromRgb24: 0xDDA0DD)
|
||||
public static let PowderBlue = Colour(fromRgb24: 0xB0E0E6)
|
||||
public static let Purple = Colour(fromRgb24: 0x800080)
|
||||
public static let Red = Colour(fromRgb24: 0xFF0000)
|
||||
public static let RosyBrown = Colour(fromRgb24: 0xBC8F8F)
|
||||
public static let RoyalBlue = Colour(fromRgb24: 0x4169E1)
|
||||
public static let SaddleBrown = Colour(fromRgb24: 0x8B4513)
|
||||
public static let Salmon = Colour(fromRgb24: 0xFA8072)
|
||||
public static let SandyBrown = Colour(fromRgb24: 0xF4A460)
|
||||
public static let SeaGreen = Colour(fromRgb24: 0x2E8B57)
|
||||
public static let SeaShell = Colour(fromRgb24: 0xFFF5EE)
|
||||
public static let Sienna = Colour(fromRgb24: 0xA0522D)
|
||||
public static let Silver = Colour(fromRgb24: 0xC0C0C0)
|
||||
public static let SkyBlue = Colour(fromRgb24: 0x87CEEB)
|
||||
public static let SlateBlue = Colour(fromRgb24: 0x6A5ACD)
|
||||
public static let SlateGray = Colour(fromRgb24: 0x708090)
|
||||
public static let Snow = Colour(fromRgb24: 0xFFFAFA)
|
||||
public static let SpringGreen = Colour(fromRgb24: 0x00FF7F)
|
||||
public static let SteelBlue = Colour(fromRgb24: 0x4682B4)
|
||||
public static let Tan = Colour(fromRgb24: 0xD2B48C)
|
||||
public static let Teal = Colour(fromRgb24: 0x008080)
|
||||
public static let Thistle = Colour(fromRgb24: 0xD8BFD8)
|
||||
public static let Tomato = Colour(fromRgb24: 0xFF6347)
|
||||
public static let Turquoise = Colour(fromRgb24: 0x40E0D0)
|
||||
public static let Violet = Colour(fromRgb24: 0xEE82EE)
|
||||
public static let Wheat = Colour(fromRgb24: 0xF5DEB3)
|
||||
public static let White = Colour.white
|
||||
public static let WhiteSmoke = Colour(fromRgb24: 0xF5F5F5)
|
||||
public static let Yellow = Colour(fromRgb24: 0xFFFF00)
|
||||
public static let YellowGreen = Colour(fromRgb24: 0x9ACD32)
|
||||
}
|