{-# OPTIONS_GHC -Wno-unused-imports #-}

-- |
-- [Previous Chapter: Basics]("Mischief.Render.Tutorial.Basics")
--
-- [Next Chapter: Materials]("Mischief.Render.Tutorial.Materials")
--
-- [Main Page]("Mischief.Render")
module Mischief.Render.Tutorial.Shaders
  ( -- * 2.2. Shaders
    -- $intro

    -- * The Shmonad
    -- $monad

    -- * Types
    -- $types

    -- * Operations
    -- $operations

    -- * Functions
    -- $functions

    -- * [Next Chapter: Materials]("Mischief.Render.Tutorial.Materials")
  )
where

import Mischief.Animation
import Mischief.ECS
import Mischief.Materials
import Mischief.Materials.Fullscreen qualified as Full
import Mischief.Materials.Sprite qualified as Sprite
import Mischief.Math
import Mischief.Render
import Prelude ()
import Prelude qualified

-- $intro
-- This chapter will teach you about writing custom shaders in the @Shader@ monad.

-- $monad
-- The shader monad is a state monad in which you build custom shader code which will then be parsed into actual code.
-- When writing shaders, it is recommended to do the following imports:
--
-- @
-- import "Prelude"()
-- import "Mischief.Materials"
-- @
--
-- Prelude needs to be hidden, as shader code uses its own definition of primitive types and operations. See for instance,
-- @'Prelude.Float'@ vs @'Float'@ and @'Prelude.+'@ vs. @'+'@.

-- $types
-- When working with shaders, there are 3 __primitive types__:
--
-- * 'Int'
-- * 'Uint'
-- * 'Float'
--
-- Each can be built with a literal. For instance, this is a shader that returns 5:
--
-- @
-- five :: 'Shader' a 'Int'
-- five = 'pure' 5
-- @
--
-- There are __vecs__ of between 2 and 4 elements. Each size having its own constructor: 'vec2', 'vec3', 'vec4'.
--
-- @
-- foo :: 'Vec3' 'Float'
-- foo = 'vec3' 3.4 0.1 (-5)
-- @
--
-- There are also __arrays__, which can be of vecs or primitives.
--
-- @
-- bar :: 'Array' ('Vec2' 'Uint')
-- bar = 'array' ['vec2' 5 0, 'vec2' 1 4, 'vec2' 10 3]
-- @
--
-- Arrays can be indexed into using '!!':
--
-- @
-- let x = bar '!!' 2
-- @
--
-- Finally, there are matrices:
--
-- @
-- baz :: 'Mat' 2 3
-- baz = 'mat' ('vec3' 5 0 4, 'vec3' 1 1 1)
-- @
--
-- You can cast between different primitive types, or between vecs of the same size, using @'cast'@.

-- $operations
-- Algebric operators are defined using a convention inspired by "Linear".
--
-- Two elements of the same type can be multiplied using @*@.
--
-- @
-- let a :: 'Float' = 2 '*' 3
-- @
--
-- A scalar (left) can be multiplied with a vector (right) using @*^@, and vice versa for @^*@.
--
-- @
-- let a :: 'Vec2' 'Float' = 2 '*^' 'vec2' 5 2
-- @
--
-- A matrix (left) can be multiplied with a vector (right) using @!*^@, or with a scalar (right) using @!*@. Vice versa
-- for @^*!@ and @*!@.
--
-- The same goes for other operators, such as @/@, @+@, @-@, @%@.

-- $functions
-- Shader functions are defined according to the [wgpu standard](https://www.w3.org/TR/WGSL/] in "Mischief.Shader.Functions".
--
-- If a function you need isn't yet defined by Mischief, you can bind it yourself using @unsafeCall@. For instance, assuming
-- @atan2@ wasn't defined, you could call it like this:
--
-- @
-- let x :: 'Vec2' 'Float' = 'vec2' 5 2
-- let y :: 'Vec2' 'Float' = 'vec2' 1 2
-- let z :: 'Vec2' 'Float' = 'unsafeCall' \"atan2\" ['Param' x, 'Param' y]
-- @
--
-- But be careful! This removes all typechecking. If you call a function with the wrong parameters it will
-- panic.