MicroShaderExample = {}

function MicroShaderExample.start()
	setMouseLocked(true)

	MicroShaderExample.walkSpeed = 3.0
	MicroShaderExample.mouseSensitivity = 0.3

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

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

	MicroShaderExample.fogColor = vec4(120, 132, 171, 255)
	MicroShaderExample.fogNear = 1.0
	MicroShaderExample.fogFar = 5.0

	local pageId = 1
	MicroShaderExample.models = loadLevel("le1.lvl", pageId)

	MicroShaderExample.meshes = modelFilter(MicroShaderExample.models, MODEL_FILTER_MESH)

	MicroShaderExample.shader = allocMicroShader()
	local compileResult = compileMicroShader(MicroShaderExample.shader, [[
		uniform float fog;
		uniform float fogNear;
		uniform float fogFar;
		uniform vec4 fogColor;
		uniform float time;

		varying float varFogFactor;

		void microVertex(){
			float speed = 5.0;

			float amplitude = 0.1;
			float wobble = sin(vertexPosition.y + time * speed) * amplitude;
			outVertexPosition = vec3(vertexPosition.x + wobble, vertexPosition.y, vertexPosition.z);

			vec3 worldPos = (modelMat * vec4(outVertexPosition, 1.0)).xyz;
			float viewDepth = abs((viewMat * vec4(worldPos, 1.0)).z);
			float rawFogFactor = (fogFar > 0.0) ? clamp((fogFar - viewDepth) / (fogFar - fogNear), 0.0, 1.0) : 1.0;
			varFogFactor = mix(1.0, rawFogFactor, fog);
		}

		void microPixel(){
			outPixelColor.rgb = mix(fogColor.rgb / 255.0, outPixelColor.rgb, varFogFactor);
		}
	]])

	if compileResult ~= "" then
		print("error while compiling microShader!", compileResult)
	end
end

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

	local mousePos = getMousePosition()

	local dx = mousePos.x - MicroShaderExample.lastMousePos.x
	local dy = MicroShaderExample.lastMousePos.y - mousePos.y
	MicroShaderExample.lastMousePos = mousePos

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

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

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

	MicroShaderExample.position = newPosition

	cameraMat.position = MicroShaderExample.position
	setCamera(cameraMat, MicroShaderExample.fov)

	clearScreen(MicroShaderExample.fogColor)

	setActiveMicroShader(MicroShaderExample.shader)

	for i = 1, #MicroShaderExample.meshes do
		setMeshMicroShader(MicroShaderExample.meshes[i], "time", currentTime, MICROSHADER_UNIFORM)
		setMeshMicroShader(MicroShaderExample.meshes[i], "fog", 1.0, MICROSHADER_UNIFORM)
		setMeshMicroShader(MicroShaderExample.meshes[i], "fogNear", MicroShaderExample.fogNear, MICROSHADER_UNIFORM)
		setMeshMicroShader(MicroShaderExample.meshes[i], "fogFar", MicroShaderExample.fogFar, MICROSHADER_UNIFORM)
		setMeshMicroShader(MicroShaderExample.meshes[i], "fogColor", MicroShaderExample.fogColor, MICROSHADER_UNIFORM)
		
		drawMesh(MicroShaderExample.meshes[i])
	end

	setActiveMicroShader(nil) -- set to nil to restore the standard mesh shader
end
