

SideScroller = {}
SideScroller.description = ""

function SideScroller.start()
	SideScroller.walkSpeed = 3.0

	SideScroller.position = vec3(0.0, 0.0, 0.0)
	SideScroller.grounded = false

	SideScroller.collisionRadius = 1.0
	SideScroller.cameraDistance = 5.0
	SideScroller.cameraHeight = 2.0
	SideScroller.fov = degToRad(60.0)
	SideScroller.lastTime = getTime()

	local pageId = 1
	local levelModels = loadLevel("le1.lvl", pageId)
	SideScroller.levelMeshes = modelFilter(levelModels, MODEL_FILTER_MESH)
	SideScroller.floorModels = modelFilter(levelModels, MODEL_FILTER_DATA, "flo")
	SideScroller.wallModels = modelFilter(levelModels, MODEL_FILTER_DATA, "wal")

	SideScroller.charRoot = loadModel("sprite.gltf", pageId)[1]
	SideScroller.charMesh = modelFilter({SideScroller.charRoot}, MODEL_FILTER_MESH)[1]

	SideScroller.characterWalkSpeed = 10.0
	SideScroller.animTimer = 0.0
	SideScroller.animFrame = 0
end

function SideScroller.update()
	local currentTime = getTime()
	local dt = currentTime - SideScroller.lastTime
	SideScroller.lastTime = currentTime

	-- movement
	local moveDir = vec3(0.0, 0.0, 0.0)
	if getKeyDown(KEY_W) then
		moveDir = moveDir + vec3(0.0, 0.0, -1.0)
	end
	if getKeyDown(KEY_S) then
		moveDir = moveDir + vec3(0.0, 0.0, 1.0)
	end
	if getKeyDown(KEY_D) then
		moveDir = moveDir + vec3(1.0, 0.0, 0.0)
	end
	if getKeyDown(KEY_A) then
		moveDir = moveDir + vec3(-1.0, 0.0, 0.0)
	end

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

	newPosition.y = 0.8

	-- wall collision
	local wallCollisionRadius = SideScroller.collisionRadius * 0.5
	for i = 1, #SideScroller.wallModels do
		local hit = sphereCast(newPosition, wallCollisionRadius, SideScroller.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

	-- floor collision (vertical ray down to detect platform geometry)
	local rayOrigin = vec3(newPosition.x, 1.0, newPosition.z)
	local rayDir = vec3(0.0, -1.0, 0.0)
	local onPlatform = false
	for i = 1, #SideScroller.floorModels do
		local hit = rayCast(rayOrigin, rayDir, SideScroller.floorModels[i])
		if hit.hitDistance >= 0.0 then
			onPlatform = true
			break
		end
	end

	if onPlatform then
		SideScroller.position = newPosition
	end

	-- character transform
	local charMat = mat4()
	charMat.position = SideScroller.position
	charMat.rotation = eulerRot(0.0, 0.0, 0.0)
	charMat.scale = vec3(0.7, 0.7, 0.7)
	setModelMatrix(SideScroller.charRoot, charMat)

	-- update camera to look at character
	local cameraPos = SideScroller.position + vec3(0.0, SideScroller.cameraHeight, SideScroller.cameraDistance)
	local lookDir = vec3Normalize(cameraPos - SideScroller.position)
	local cameraMat = mat4LookAt(cameraPos, lookDir, vec3(0.0, 1.0, 0.0))
	setCamera(cameraMat, SideScroller.fov)

	-- animate character sprite
	if vec3Length(moveDir) > 0.0 then
		moveDir = vec3Normalize(moveDir)
		
		SideScroller.animTimer = SideScroller.animTimer + dt
		if SideScroller.animTimer >= 1.0 / SideScroller.characterWalkSpeed then
			SideScroller.animTimer = 0.0
			if SideScroller.animFrame == 1 then
				SideScroller.animFrame = 2
			else
				SideScroller.animFrame = 1
			end

			meshUVAnimFrame(SideScroller.charMesh, SideScroller.animFrame)
		end
	else
		if SideScroller.animFrame ~= 0 then
			SideScroller.animFrame = 0
			SideScroller.animTimer = 0.0
			
			meshUVAnimFrame(SideScroller.charMesh, 0)
		end
	end

	-- render
	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, #SideScroller.levelMeshes do
		PolyUtil.meshLight(SideScroller.levelMeshes[i], lightDir, lightColor, ambientColor)
		drawMesh(SideScroller.levelMeshes[i])
	end
	PolyUtil.endLighting()

	-- the character is drawn unlit, so it stays outside the lighting region
	drawMesh(SideScroller.charMesh)
end
