{-# 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.