rem *************************************************************************************************
rem * NOTE                                                                                          *
rem *  This is an example from the first release of the Ziggurat plugin.                            *
rem * New functions and default resources have since been added to make the process                 *
rem * of creating simple things like a spinning cube less ardous. This example is still             *
rem * included because it describes some concepts in detail that you will probably want to          *
rem * use when setting out to create more elaborate scenes where you want to have greater control   *
rem * yourself. See the «Spinning Cube (Simple)» example project for a less verbose way of          *
rem * achieving the same results as this program does by depending on default resources.            *
rem *************************************************************************************************
rem In this simple example program we'll create a cube and have it rotate continously around        *
rem its Y axis at 180 degrees per second.

rem Ensure that DX11Constants.dba is included
INCLUDEGUARD DX11_CONSTANTS

rem First we need to set up the DX11 engine.
rem This is done using the DX11 INIT function, which takes a width and height parameter for 
rem the render window to create, a flag denoting whether to run in fullscreen, a caption 
rem for the render window and optionally a custom window style you want to use for the 
rem created window. Since the DX11 plugin creates and maintains its own window you will 
rem probably want to set the screen type to "hidden" so as to not display the standard 
rem DBPro window on startup.
rem Also take note that the width and height provided to the DX11 INIT function must 
rem correspond to a valid 32-bit display mode on your system.
rem Let's create a 800x600px windowed display for now.
rem Let's also set the feature mode to DXVERSION_10_0; this will allow our program
rem to run on older DX10 hardware (provided the system has the DX11 runtime installed).
rem As long as no DX11 specific functions are used and a maximum shader level of 4 is 
rem maintained (shader level 5 is DX11 exclusive) this will work.
dx11 init 800, 600, 0, "DX11 Example: Spinning Cube", DXVERSION_10_0


rem The next thing we need is a cube object. There is a function for creating a simple 
rem 3D cube, but before we can do that we need to set up a vertex layout.
rem Vertex layouts work like the Flexible Vertex Formats (FVF) used in DirectX 9, but 
rem are more arbitrary to what they can contain.
rem We will create a simple layout containing a POSITION and a TEXCOORD semantic. Take 
rem note that the vertex layout corresponds directly to what is sent as input to your
rem vertex shaders.
vertLayout = dx11 create vertex layout()
rem We use DXGI_FORMAT_R32G32B32_FLOAT here since a position needs three 32-bit float values (x, y, z).
rem The semantic ("POSITION") is what the vertex shader will use to refer to this per-vertex element.
dx11 add vertex layout element vertLayout, "POSITION", DXGI_FORMAT_R32G32B32_FLOAT
rem We don't really make any use of vertex colours here, however it is vital that this semantic be included
rem when using the default vertex shader since that one expects a COLOR member for the vertex input data.
dx11 add vertex layout element vertLayout, "COLOR", DXGI_FORMAT_B8G8R8A8_UNORM
rem Likewise we use DXGI_FORMAT_R32G32_FLOAT here since a UV coordinate uses two 32-bit float values
dx11 add vertex layout element vertLayout, "TEXCOORD", DXGI_FORMAT_R32G32_FLOAT
rem That's it for the vertex layout. Now that we have added all our needed elements to it, we need to 
rem finalize it to create the internal buffers used to represent it.
dx11 finalize vertex layout vertLayout

rem Now that we have a finalized vertex layout we can create our cube
cube = dx11 create object cube(10.0, vertLayout)

rem In order to render the cube, it needs a shader technique.
rem Since the effects framework from earlier versions of DirectX has been deprecated we have to 
rem create individual "techniques" in code by mixing different shaders and states. This has the 
rem advantage that a technique can be changed in realtime however.
rem The current version of the DX11 plugin only supports vertex and pixel shaders*. We need to 
rem provide one of each when creating a shader technique, and the vertex shader must have a
rem vertex input structure that maps to the vertex layout used by the geometry that will be
rem using said shader. We can write our own shaders, as will be appropriate most all of the time, 
rem but there are a default vertex and pixel shader included with the plugin that works for just 
rem getting geometry drawn to the screen. We will use those here for the sake of simplicity.
rem     (*) This was true for version 0.1, the latest version at the time of writing (0.4) 
rem         supports all shader types (vertex, hull, domain, geometry, pixel and compute shaders).
vShader = dx11 get default vertex shader()
pShader = dx11 get default pixel shader()
shaderTechnique = dx11 create shader technique(vertLayout, vShader, pShader)
rem If you want specific rendering options you can also associate blend states (mainly used 
rem to instruct the GPU how to blend pixels together based on transparency), rasterizer states 
rem (used to set things like backface culling and wireframe rendering) and sampler states (that
rem describe how to sample each of the up to 16 different textures an object can have).
rem The default ones will do for this application though so we won't explicitly create and set those.

rem Set our cube object to use our newly created shader technique
dx11 set object shader technique cube, shaderTechnique

rem The default shaders expect the rendered objects to have a texture. The DX11 CREATE OBJECT CUBE 
rem function automatically sets appropriate texture coordinates for the cube's vertices, but we have 
rem to also give it a texture in order to render properly*.
rem We just create a small, single-colour texture here but you can of course load and apply any texture
rem you desire.
rem     (*) This was true in version 0.1, all more recent versions will apply a default, white texture
rem         to newly created objects which will be used unless you set another one.
rem Let's make a standard 32-bit teal-coloured texture and generate a set of mip maps for it automatically:
texture = dx11 create image(16, 16, DXGI_FORMAT_B8G8R8A8_UNORM, true, 0.0, 0.75, 0.5, 1.0)

rem Now we set this texture to our cube object. Each object can have up to 16 different textures at any one time.
dx11 set object texture cube, texture

rem Position the cube at an appropriate position
dx11 set object position cube, 0, 0, 0

rem Set the main (screen) camera to look at the cube
mainCam = dx11 get main camera()
dx11 set camera position mainCam, 0, 0, -20
dx11 set camera lookat mainCam, 0, 0, 0


rem We need to use bitmap fonts to display any text on the screen.
rem There is a default 12x12 pixel font included with the DX11 plugin, but you can also load your own if you prefer.
font = dx11 get default font()

rem Using a font, we can draw to so called "labels" - these are pieces of text that can be drawn to the screen and
rem and can have their text or position changed.
rem Let's create one for displaying the frame rate of our application in the upper left corner of the window.
fpsLabel = dx11 create label(font, "FPS", 0, 0)


rem Alright, that's enough set up. The main loop follows.
rem Note that there is no "sync rate" in the DX11 engine; it will run as fast as possible (a vertical sync mode may come 
rem in a future release). As such we need to keep track of how much time has elapsed since the last frame in order to 
rem have smooth movements.
rem The built-in high resolution timer returns a double integer tick, so we need to explicitly declare a double integer 
rem variable to store its returned value.
currentTick as double integer
lastTick    as double integer
currentTick =  dx11 get high resolution tick()

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 it's Y axis, 180 degrees per second.
    rem The "apply xxx" functions are merely for convenience; they will add the given values to the current one.
    rem As such the below is identical to calling 
    rem DX11 SET OBJECT ANGLE cube, 0.0, DX11 WRAP(DX11 GET OBJECT ANGLE Y(cube) + (180.0 * timeFactor#), 0.0, 360.0), 0.0.
    rem When applying an angle, the angle is automatically wrapped if the resulting angle after application end up outside the 
    rem [0..360] degree range.
    dx11 apply object angle cube, 0.0, 180.0 * timeFactor#, 0.0
    
    rem Update the fps label's text to properly reflect the current frame rate (note however that the value returned by DX11 GET SCREEN FPS
    rem is only updated once per second).
    dx11 set label text fpsLabel, "FPS: " + str$(dx11 get screen fps())
    
    rem DX11 SYNC will render all cameras specified in the sync mask.
    rem You can render one or all of your cameras manually using DX11 RENDER CAMERA, but DX11 SYNC performs 
    rem various other per-frame updates and thus needs to be called once per frame still. If you take manual control over all 
    rem camera rendering, you can just set the sync mask to 0 - in this case, no rendering will be done by DX11 SYNC.
    dx11 sync
endwhile

rem You can perform any cleanup that you need to do from here.
rem The DX11 engine will be automatically shut down and cleaned up when the plugin is unloaded, which happens when you call
rem END / your program code ends just like usual.
end
