

SideScrollerExample = {}
SideScrollerExample.description = ""

function SideScrollerExample.start()
	SideScrollerExample.walkSpeed = 3.0

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

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

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

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

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

function SideScrollerExample.update()
	local currentTime = getTime()
	local dt = currentTime - SideScrollerExample.lastTime
	SideScrollerExample.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 = SideScrollerExample.position + moveDir * SideScrollerExample.walkSpeed * dt

	newPosition.y = 0.8

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

	if onPlatform then
		SideScrollerExample.position = newPosition
	end

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

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

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

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

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

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