rem Ensure that DX11Constants.dba is included
INCLUDEGUARD DX11_CONSTANTS

rem Initialize the DX11 plugin; since we don't have any DX11-specific features here we might as well set the
rem feature level to DXVERSION_10_0 in order to support older hardware
dx11 init 1600, 900, false, "DX11 Animation Demo", DXVERSION_10_0

rem We will be leaving out lots of resources here and thus make the engine use its default resources for 
rem things like vertex layouts, fonts, shaders and so on. If you are interested in how you can set these manually 
rem in order to achieve greater control over the looks and feel of your program the "Spinning Cube (original)" example
rem uses and explains these concepts thouroghly.

rem Create a label for outputting various information to the screen
lbl = dx11 create label("Placeholder", 0, 0)

rem Load the 3d object we're going to animate.
rem This is a FPSC model that contains a *lot* of animations (about 2500 frames); quite a few of these are combinations 
rem such as "strafe sideways while aiming". Since the aiming animation only really affects the upper part of the body and 
rem the walking the lower, such animations can be combined by playing different animations on different limbs ("joints" / "bones").
rem We will see this done later as we combine the walking, running and aiming animations.
obj = dx11 load object("media\tommy.x")

rem Position the main camera to look at the object
dx11 set camera position dx11 get main camera(), 0.0, 40.0, -100.0


rem The animations are imported along with the object they belong to and can be accessed like so:
fullAnim = dx11 get animation from object(obj, 0)
rem Usually all animation frames will be melded together into one single animation by the modelling software when the object is exported.
rem This is the case with the Tommy model we're using here. We can split this "master animation" into subanimations to make character animation
rem more intuitive by separating sequences such as "idle", "run", "walk" and so on.
rem The name set when creating an animation like this doesn't really have any use other than being associated with the animation.
rem As such you can pretty much set it to whatever. In a future release it may be used to identify the animations, should a larger collection
rem of them be created. The main point to realize about them is that unlike Enhanced Animations, these "sub animations" are created purely in
rem memory and no file will be written to disk; the animation name is thus not a file name.
animWalk    = dx11 extract animation(fullAnim, 236, 259, "Walk")
animRun     = dx11 extract animation(fullAnim, 300, 317, "Run")
animAim     = dx11 extract animation(fullAnim, 573, 597, "Aim")

rem The intended frame rate of animations are parsed during importing if such are found; if not they will get a default frame rate of 30 FPS.
rem A lot of models (for example those that come as demo media with DBPro) tend to be exported with the frame rate set to 1 without this being
rem the intended frame rate; if this is the case it will NOT be set to 30 by the engine since it cannot know if the 1 FPS frame rate is actually
rem intended or not.
rem Of course we may also set the frame rate ourselves using DX11 SET ANIMATION FRAMES PER SECOND.
rem This model has a default frame rate of 24 FPS set in its file which will do fine here.

rem Find the parent joint (limb) for the separate bottom and top animations...
jointUpper  = dx11 get object limb(obj, "Bip01_Spine2")
jointLower  = dx11 get object limb(obj, "Bip01")

rem ... And set the walk animation to play on the lower part and the aim animation for the upper part.
rem Take note that jointLower is actually a parent limb to jointUpper's parent. As such we must set the lower animation first or else it 
rem would overwrite the animations set to the upper part since those are also children of the lower part's root limb.
rem As we only have two animations here we could as well have set the lower animation to the entire object and then replaced the upper joints
rem with the aiming animation but this hopefully shows the general approach better.
dx11 set object animation obj, animWalk, true, 100, jointLower  ` This will apply the animation to the specified limb and all its child limbs
dx11 set object animation obj, animAim, true, 100, jointUpper
rem Store the current animation for the lower part of the object's body so that we may toggle between the walking and running animations
lowerAnim = animWalk

rem This function will play the object's overall animation, that is any partial animations may be set to any limb(s); this will start playing all of them
dx11 play object animation obj, true

rem Main loop
while dx11 quit() = false
    rem Toggle the animation on the lower part of the model's body between walking and running by pressing the space key
    if dx11 is key hit(DIK_SPACE)
        rem Determine the new animation
        if lowerAnim = animWalk
            lowerAnim = animRun
        else
            lowerAnim = animWalk
        endif
        
        rem As previously mentioned we cannot change the animation directly of the jointLower limb since its place in the limb hierarchy would then 
        rem cause it to overwrite the limbs animated by the upper animation. You could set the new lower animation and then reset the upper but that
        rem would restart the upper animation which isn't desirable. We can however set the animation of a certain limb but not touch its children; 
        rem this requires a few more function calls but it gets the job done. Whether you have to do this or not of course depends on how your limb 
        rem hierarchy looks (you can inspect it by using the DX11 GET OBJECT ROOT LIMB and DX11 GET LIMB CHILD functions).
        rem For this particular model we will need to set the animation for the below limbs:
        dx11 set object animation obj, lowerAnim, true, 1000, dx11 get object limb(obj, "Bip01"), true
        dx11 set object animation obj, lowerAnim, true, 1000, dx11 get object limb(obj, "Bip01_Pelvis"), true
        dx11 set object animation obj, lowerAnim, true, 1000, dx11 get object limb(obj, "Bip01_Spine"), true
        dx11 set object animation obj, lowerAnim, true, 1000, dx11 get object limb(obj, "Bip01_Spine1"), true
        rem The below limbs are not parents to any of the limbs involved in the upper body animation so we can save a few function calls and set
        rem the lower animation to all of their child limbs as well
        dx11 set object animation obj, lowerAnim, true, 1000, dx11 get object limb(obj, "Bip01_L_Thigh")
        dx11 set object animation obj, lowerAnim, true, 1000, dx11 get object limb(obj, "Bip01_R_Thigh")
        rem That should be it.
        rem Take note of the fourth and sixth parameters used above; the fourth allow us to get a smoother transition between two animations by 
        rem interpolating between the new and the old ones for as many milliseconds as are specified. 0 may be specified for an immediate switch to the new animation. 
        rem The sixth parameter is what allows us to optionally not set the animation to any children of the targeted limb.
        rem Specify «true» to not set the children and «false» (or just leave this argument out) to indeed set it to all child limbs (and their child
        rem limbs in turn and so on); this is the default behaviour of the function as seen above.
        rem For the best results when transitioning between different walk cycles (such as the walk / run animations used here) you probably want to synchronize
        rem the previous and next animations such that if the walk animation currently has its left leg in the air, you don't want to start the run animation with
        rem its right leg in the air instead. The interpolation between the animations do smooth this transition out but it still doesn't look right.
        rem To keep this demo program simple we are not doing that here, but it can be done by using the DX11 SET ANIMATION FRAME function to set the new
        rem animation to change to to a frame that corresponds to the current frame of the previous animation (which can be retrieved using DX11 GET ANIMATION FRAME).
    endif
    
    rem Output the current frame rate as well as some simple instructions to the screen
    dx11 set label text lbl, "FPS: " + str$(dx11 get screen fps()) + chr$(10) + "Press [space] to toggle between walking / running lower animation"
    
    rem Update internals of the engine, render the main camera etc.
    dx11 sync
endwhile

rem Ensure we terminate the application before running down into the function declarations in the DX11Constants.dba include file
end
