

Fps = {}

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

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

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

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

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

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

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

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

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

	local cameraMat = mat4()
	cameraMat.rotation = eulerRot(Fps.pitch, 0.0, 0.0) * eulerRot(0.0, Fps.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 = Fps.position + moveDir * Fps.walkSpeed * dt

	-- handle collisions
	local wallCollisionRadius = Fps.collisionRadius * 0.5
	for i = 1, #Fps.wallModels do
		local hit = sphereCast(newPosition, wallCollisionRadius, Fps.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, #Fps.floorModels do
		local hit = sphereCast(newPosition, Fps.collisionRadius, Fps.floorModels[i])
		if hit.hitDistance >= 0.0 then
			onPlatform = true
			break
		end
	end

	if onPlatform then
		Fps.position = newPosition
	end

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

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

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

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