rem This is a most simple example of how to use multi-pass shading with the Ziggurat engine.
rem We will use two different pixel shaders to draw the same spinning cube; the first will
rem render it red and the other dark green. We will then blend together the result of both
rem of these passes to draw an orange cube to the screen.
rem                                                             - Joel Sjöqvist, 2015-09-09

rem Initialize the Ziggurat engine.
rem We don't need any DX11-specific features for this example so we'll run in DX10-compatible mode.
dx11 init 1600, 900, false, "DX11 Example: multi-pass shading", DXVERSION_10_0

rem Create minimalistic vertex layout needed by our shaders. We could just use the default one
rem if we made the vs_in struct in our HLSL code correspond to it, but since we need neither 
rem vertex colours nor texture coordinates or normals this is (perhaps ever so slightly but still)
rem more efficient.
vl = dx11 create vertex layout()
dx11 add vertex layout element vl, "POSITION", DXGI_FORMAT_R32G32B32_FLOAT  ` 3x32-bit floats
dx11 finalize vertex layout vl

rem Load shaders
vsMain  = dx11 load vertex shader("Multipass.hlsl", "MainVS", "vs_4_0")
psRed   = dx11 load pixel shader("Multipass.hlsl", "RedPS", "ps_4_0")
psGreen = dx11 load pixel shader("Multipass.hlsl", "GreenPS", "ps_4_0")

rem Next we create our shader techniques. We'll use two here; one per shading "pass", but you can
rem use an arbitrary number when doing multi-pass shading.
rem It should be noted that the shader techniques used as passes can have completely different 
rem shaders and states associated with them; these two share the same vertex shader just for
rem the sake of simplicity.
techRed     = dx11 create shader technique(vl, vsMain, psRed)
techGreen   = dx11 create shader technique(vl, vsMain, psGreen)

rem We need to create a depth-stencil state that disables writing to the z-buffer (depth map)
rem for the red rendering technique. If we do not do this, the object will be drawn using the 
rem red technique first and then again using the green technique, however at this time, all 
rem pixels drawn by the green technique will have the same z-(depth-) value as the previously
rem rendered red pixels and as such the green ones will be considered occluded by the red ones 
rem and clipped by the GPU. To prevent this we draw the red mesh without filling out the z-buffer; 
rem the green pass will fill out this once done so that our multi-pass rendered cube will properly 
rem overlap any other geometry drawn behind it though.
dss = dx11 create depth stencil state()
dx11 set depth write mask dss, D3D11_DEPTH_WRITE_MASK_DISABLED

rem We also need to create a blend state to tell the second pass how it will blend together its 
rem output (from the green shader technique) with what is already on the render target (originating 
rem from the red shader technique that was used in the previous pass).
bs = dx11 create blend state(1)
dx11 enable blend state alpha coverage bs,  false
dx11 enable blending bs,                    true
dx11 set source blend bs,                   D3D11_BLEND_ONE                 ` Multiply source (currently rendered) with one
dx11 set destination blend bs,              D3D11_BLEND_ONE                 ` Multiply destination (previously rendered) with one
dx11 set blend operation bs,                D3D11_BLEND_OP_ADD              ` Add source + dest (write 1 * source + 1 * dest)
dx11 set source blend alpha bs,             D3D11_BLEND_ONE                 ` Multiply source alpha with one
dx11 set destination blend alpha bs,        D3D11_BLEND_ZERO                ` Multiply destination alpha with zero
dx11 set blend operation alpha bs,          D3D11_BLEND_OP_ADD              ` Add source + dest => write only source alpha
dx11 set blend state colour write mask bs,  D3D11_COLOR_WRITE_ENABLE_ALL    ` Enable writing to all colour channels

rem Associate our depth-stencil state with the red (first pass) technique...
dx11 set depth stencil state techRed, dss
rem ... and the blend state with the green (second pass) technique.
dx11 set blend state techGreen, bs

rem Create our cube object and associate both our shader technique passes to it
cube = dx11 create object cube(10.0, vl)
dx11 set object shader technique cube, techRed,   0 ` First pass
dx11 set object shader technique cube, techGreen, 1 ` Second pass

rem Obtain main camera reference and position it so that it is looking at the cube
rem (the default position for an object unless manually moved is (0, 0, 0))
cam = dx11 get main camera()
dx11 set camera position cam, 0, 0, -30


rem Setup high resolution timing variables to maintain smooth and consistent movement over
rem varying frame rates
currentTick as double integer = dx11 get high resolution tick()
lastTick    as double integer

rem Main loop
while not dx11 quit()
    rem Update time factor
    lastTick    = currentTick
    currentTick = dx11 get high resolution tick()
    rem This function will return the delta time between the two high resolution tick values expressed in seconds.
    rem As such we can use it as a factor to multiply with all movement and get the result that whatever we multiply with this factor 
    rem will be the movement per second.
    timeFactor# = dx11 get high resolution delta time(lastTick, currentTick)
    
    rem Rotate the cube around its Y-axis by 180 degrees per second
    dx11 apply object angle cube, 0.0, 180.0 * timeFactor#, 0.0
    
    rem Print the current frame rate to the screen
    dx11 draw text 0, 0, "FPS: " + str$(dx11 get screen fps())
    
    rem Render camera(s) and update engine internals
    dx11 sync
endwhile

end
