package.path = package.path .. ";./assets/scripts/?.lua"
require "luascape.framework"
require "luascape.fx"
require "luascape.input"
require "luascape.render"
require "luascape.objects"
require "luascape.physics"
require "luascape.bullet"
require "luascape.graphics"
require "settings"
require "tinyandbig"
require "renderer.debugpasses"
require "renderer.orthogonalrenderpass"
require "renderer.shadowrenderpass"
require "renderer.skyboxrenderpass"

function addOutlinePass(renderer, normalRenderTarget, camera)
  local edgePass = renderer.passes:add(QuadRenderPass())
  local shader = edgePass.material
  local normalBuffer = normalRenderTarget:getColorTexture()
  shader.textureState:setTexture(0, normalBuffer)
  shader.textureState:setTexture(1, normalRenderTarget:getDepthTexture())
  shader.shaderProgramState = graphics.createShaderProgramState(
    "edgedetect_vp.cg", nil,
    "edgedetect_fp.cg", { 
      FloatUniform(camera.nearPlane, "cameraNear"),
      FloatUniform(camera.farPlane, "cameraFar"),
      FloatUniform(settings.fog.near - 10, "fadeNear"),
      FloatUniform(settings.fog.near, "fadeFar"),
      VectorUniform(Vector(normalBuffer.pixelBuffer.width, normalBuffer.pixelBuffer.height, 0), "normalBufferSize")
    }
  )
  graphics.applyBlending(edgePass.quad, AlphaBlendState.BLEND_SRC_ALPHA, AlphaBlendState.BLEND_INV_SRC_ALPHA)
  if not settings.retail then
    InputManager.instance().bindings:add(ToggleRenderPassInputBinding(KeyboardState.KEY_F7, edgePass))
  end
end

function addParticlePass(levelRenderPass)
  local particlePass = levelRenderPass.renderer.passes:add(SeparateRenderPass())
  particlePass.name = "particleRenderPass"
  particlePass.scene = Node()
  -- particlePass.scene.cullStrategy = Node.CULL_NEVER_INCLUDING_CHILDREN
  Act.currentAct().updateables:add(particlePass.scene)
  if not settings.retail then
    InputManager.instance().bindings:add(ToggleRenderPassInputBinding(KeyboardState.KEY_F8, particlePass))
  end
  return particlePass
end

function addTypoPass(levelRenderPass)
  local typoPass = levelRenderPass.renderer.passes:add(SeparateRenderPass())
  typoPass.name = "typoRenderPass"
  typoPass.scene = Node()
  Act.currentAct().updateables:add(typoPass.scene)
  return typoPass
end

function addLODRenderPass(levelRenderer)
  local lodRenderPass = LODRenderPass()
  lodRenderPass.nearNode = levelRenderer.scene
  lodRenderPass.farNode = Act.currentAct().primitiveScene
  lodRenderPass.clipDistance = settings.camera.clip
  levelRenderer.scene = Node()
  return lodRenderPass
end

function addPostLayerPass(renderer, normalRenderTarget, camera)
  local postLayerPass = renderer.passes:add(QuadRenderPass())
  postLayerPass.material.textureState:setTexture(0, Texture.loadFromFile(settings.fog.texture))
  postLayerPass.material.textureState:setTexture(1, normalRenderTarget:getDepthTexture())
  graphics.applyBlending(postLayerPass.quad, AlphaBlendState.BLEND_SRC_ALPHA, AlphaBlendState.BLEND_INV_SRC_ALPHA)
  postLayerPass.material.shaderProgramState = graphics.createShaderProgramState(
    "fullscreen_quad_vp.cg", nil,
    "postlayer_fp.cg", {
      FloatUniform(camera.nearPlane, "cameraNear"),
      FloatUniform(camera.farPlane, "cameraFar"),
      FloatUniform(settings.fog.near, "fogNear"),
      FloatUniform(settings.fog.far, "fogFar")
    }
  )
  
  if not settings.retail then
    InputManager.instance().bindings:add(ToggleRenderPassInputBinding(KeyboardState.KEY_F9, postLayerPass))
  end
end

function addVignetteLayerPass(renderer)
  local vignettePass = renderer.passes:add(QuadRenderPass())
  vignettePass.material.textureState:setTexture(0, Texture.loadFromFile("posteffect_layer_vignette.jpg"))
  graphics.applyBlending(vignettePass.quad, AlphaBlendState.BLEND_DST_COLOR, AlphaBlendState.BLEND_ZERO)
end


function addFadeRenderPass(renderer)
  local transitionPass = renderer.passes:add(QuadRenderPass())
  transitionPass.name = "FadeRenderPass"
  local material = AlphaTransitionMaterial()
  material.texture = Texture.loadFromFile("transition.png")
  transitionPass.quad.material = material
end

function addTriggerRenderPass()
  local triggerPass = SeparateRenderPass()
  triggerPass.clearFlags = 0
  triggerPass.scene = Node()
  triggerPass.name = "TriggerPass"
  return triggerPass
end


function initRenderer(levelRenderPass)
  local renderer = Renderer()
  local camera = levelRenderPass.camera
  camera.farPlane = 1000
  camera.nearPlane = 0.1
  levelRenderPass.renderer = renderer
  renderer.passes:clear()

  -- pre-render
  addSkyBoxRenderPass(renderer)
  
  
  local lodRenderPass = addLODRenderPass(levelRenderPass)
  
  createShadowPasses(renderer, lodRenderPass.nearNode)
  local depthNormalShadowPrePass = levelRenderPass.renderer:findFirstRenderPass("depthNormalShadowPrePass")

  renderer.passes:add(lodRenderPass)
  
  -- post-render
  if not settings.perPixelHatch then
    render.createShadowPostPass(renderer)
  end
--  addPostLayerPass(renderer, depthNormalShadowPrePass.renderTarget, levelRenderPass.camera)
  if settings.outlines then
    addOutlinePass(renderer, depthNormalShadowPrePass.renderTarget, levelRenderPass.camera)
  end
  addParticlePass(levelRenderPass)
  addTypoPass(levelRenderPass)
  addOrthogonalRenderPass(levelRenderPass)
  addVignetteLayerPass(renderer)
  addFadeRenderPass(renderer)
  
  -- debug passes
  if not settings.retail then
    addDebugPass(renderer, DepthNormalPrePass(), KeyboardState.KEY_F6).clearFlags = Display.CLEAR_ALL
    addDebugPass(renderer, BulletRenderPass(Act.currentAct().space), KeyboardState.KEY_F3)
    local bpass =  BoundingVolumePass() 
    bpass.drawAABBs = true
    addDebugPass(renderer, bpass, KeyboardState.KEY_F4)
    addDebugPass(renderer, NormalRenderPass(), KeyboardState.KEY_F10)
    addDebugPass(renderer, ProfilerRenderPass(renderer), KeyboardState.KEY_F2)
    addDebugPass(renderer, createShadowDebugPass(levelRenderPass), KeyboardState.KEY_8)
    addDebugPass(renderer, addTriggerRenderPass(), KeyboardState.KEY_F11)
  end
end
