

FpsExample = {}

function FpsExample.start()
	setMouseLocked(true)
	
	-- define our fps game data
	FpsExample.walkSpeed = 3.0
	FpsExample.mouseSensitivity = 0.3

	FpsExample.position = vec3(0.0, 1.0, 0.0)
	FpsExample.yaw = 0.0
	FpsExample.pitch = 0.0

	FpsExample.collisionRadius = 1.0
	FpsExample.fov = degToRad(60.0)
	FpsExample.lastTime = getTime()
	FpsExample.lastMousePos = getMousePosition()

	-- load level and cache the data we frequently need from update
	local pageId = 1
	FpsExample.models = loadLevel("le1.lvl", pageId)

	FpsExample.meshes = modelFilter(FpsExample.models, MODEL_FILTER_MESH)
	FpsExample.floorModels = modelFilter(FpsExample.models, MODEL_FILTER_DATA, "flo")
	FpsExample.wallModels = modelFilter(FpsExample.models, MODEL_FILTER_DATA, "wal")
end

function FpsExample.update()
	-- simulate movement with WASD + mouse
	local currentTime = getTime()
	local dt = currentTime - FpsExample.lastTime
	FpsExample.lastTime = currentTime

	local mousePos = getMousePosition()
	
	local dx = mousePos.x - FpsExample.lastMousePos.x
	local dy = FpsExample.lastMousePos.y - mousePos.y
	FpsExample.lastMousePos = mousePos

	FpsExample.yaw = FpsExample.yaw - dx * FpsExample.mouseSensitivity
	FpsExample.pitch = FpsExample.pitch + dy * FpsExample.mouseSensitivity

	if FpsExample.pitch > 89.0 then FpsExample.pitch = 89.0 end
	if FpsExample.pitch < -89.0 then FpsExample.pitch = -89.0 end

	local cameraMat = mat4()
	cameraMat.rotation = eulerRot(FpsExample.pitch, 0.0, 0.0) * eulerRot(0.0, FpsExample.yaw, 0.0)

	local forward = cameraMat.forwardAxis
	local right = cameraMat.rightAxis

	local moveDir = vec3(0.0, 0.0, 0.0)

	if getKeyDown(KEY_W) then
		moveDir = moveDir - vec3(forward.x, 0.0, forward.z)
	end
	if getKeyDown(KEY_S) then
		moveDir = moveDir + vec3(forward.x, 0.0, forward.z)
	end
	if getKeyDown(KEY_D) then
		moveDir = moveDir + vec3(right.x, 0.0, right.z)
	end
	if getKeyDown(KEY_A) then
		moveDir = moveDir - vec3(right.x, 0.0, right.z)
	end

	if vec3Length(moveDir) > 0.0 then
		moveDir = vec3Normalize(moveDir)
	end

	local newPosition = FpsExample.position + moveDir * FpsExample.walkSpeed * dt

	-- handle collisions
	local wallCollisionRadius = FpsExample.collisionRadius * 0.5
	for i = 1, #FpsExample.wallModels do
		local hit = sphereCast(newPosition, wallCollisionRadius, FpsExample.wallModels[i])
		if hit.hitDistance >= 0.0 then
			local pushDir = newPosition - hit.hitPoint
			pushDir.y = 0.0
			local pushLen = vec3Length(pushDir)
			if pushLen > 0.001 then
				pushDir = pushDir * (1.0 / pushLen)
				local penetration = wallCollisionRadius - pushLen
				newPosition = newPosition + pushDir * penetration
			end
		end
	end

	local onPlatform = false
	for i = 1, #FpsExample.floorModels do
		local hit = sphereCast(newPosition, FpsExample.collisionRadius, FpsExample.floorModels[i])
		if hit.hitDistance >= 0.0 then
			onPlatform = true
			break
		end
	end

	if onPlatform then
		FpsExample.position = newPosition
	end

	-- move the player
	cameraMat.position = FpsExample.position
	setCamera(cameraMat, FpsExample.fov)

	-- render the world
	local lightDir = vec3Normalize(vec3(0.5, 1.0, 0.7))
	local lightColor = vec4(255.0, 255.0, 255.0, 255.0)
	local ambientColor = vec4(100.0, 100.0, 100.0, 255.0)

	PolyUtil.beginLighting()
	for i = 1, #FpsExample.meshes do
		PolyUtil.meshLight(FpsExample.meshes[i], lightDir, lightColor, ambientColor)

		drawMesh(FpsExample.meshes[i])
	end
	PolyUtil.endLighting()
end
