Turok: Dinosaur Hunter Forums!

Turok Games => Turok Dinosaur Hunter => Turok Dinosaur Hunter Modding/Mapping => Topic started by: Duke64 on April 14, 2017, 01:10:14 AM

Title: Kaiser's Model/Animation Format (Technical Documentation)
Post by: Duke64 on April 14, 2017, 01:10:14 AM
This was shared and written by Samuel Villarreal (Kaiser):

Source: http://steamcommunity.com/app/405820/discussions/1/135514376585626037/

Kaiser's Gist Link ) https://gist.githubusercontent.com/svkaiser/0d64663480f46a0ec1e0b20ea8f02907/raw/3fd73db97af55fe6dc204c8047ea6d01db477f77/gistfile1.txt

//
// Turok EX Model and Animation Format Specifications
//
// Samuel 'Kaiser' Villarreal (svkaiser---at---gmail.com)
// Revised: 04/13/17
//

//-----------------------------------------------------------------------------
//
// What is this document for?
//
//-----------------------------------------------------------------------------

This technical document is targeted towards users with programming expirence as
well as expirence with 3D modeling tools and writing plugins for them.

//-----------------------------------------------------------------------------
//
// Model Format
//
//-----------------------------------------------------------------------------

Model files (.BIN) are simple binary files that are read in a linear fashion.
The information below details the data, byte count and additional notes.


name                bytes           notes   
---------------------------------------------------------
version             4 (int)         always 1
bounding box min    12 (3 floats)   always 0 for non-animating models
bounding box max    12 (3 floats)   always 0 for non-animating models
node count          4 (int)         always 1 for non-animating models


for (node count) loop:
-----------------------
child count         4 (int)         number of child node indexes for recursion
variant count       4 (int)         variant count should be the same for all nodes
object count        4 (int)         total number of unique models for this node (bare hands, hand w/Axe, etc)


for (child count) loop:
-----------------------
child index         2 (int16)       index to the next child node
exit (child count) loop

for (variant table count) loop:
-----------------------
variation index     2 (int16)       see below for more information about variants
exit (variant table count) loop

for (object count) count loop:
-----------------------
surface count       4 (int)

for (surface count) loop:
-----------------------
material file       string          (zero terminated)
triangle count      4 (int)         stored as nTriangles / 3. multiply by 3 when reading from model file

for (triangle count) loop:
-----------------------
indice index        2 (int16)
exit (triangle count) loop

vertex count        4 (int)

for (vertex count) loop:
-----------------------
xyz                 12 (3 floats)
uv coords           8 (2 floats)    when read in TurokEX, the y coordinate is always read as 1.0f - UV.y   
normals             12 (3 floats)
exit (vertex count) loop

exit nSurface loop

exit (object count) loop

exit nNode loop


Each node can have several alternative models which variant indexes can define which ones to show based on the actor's
variant ID setting in the level. The variant table contains a list of indexes to that object to display based on the
actor's variation ID. Example, if the table contains values of 2, 1, 3, 0, 4 and the actor has a variation ID set to 2
then it will lookup the entry at that index, which will be 3. This will dictate which object model to display for that node.

Surfaces are geometry with a unique material thats issued as a single draw call.

It is not required to compute the bounding box information for static models (leave all zeros).


//-----------------------------------------------------------------------------
//
// Animation Format
//
//-----------------------------------------------------------------------------

Animation files (.BIN) are simple binary files that are read in a linear fashion.
The information below details the data, byte count and additional notes.

name                        bytes           notes   
---------------------------------------------------------
version                     4 (int)         always 1
anim block count            4 (int)

for nAnimBlock count loop
-----------------------
anim ID                     4 (int)         each anim ID has a special purpose and is used for special behaviors
frame count                 4 (int)
num node indexes            4 (int)
num nodes                   4 (int)
num translations            4 (int)
num rotations               4 (int)
num keyframe actions        4 (int)

marker                      4 (int)

if (marker == 1) then read:
blend length                2 (int16)
loop frame                  2 (int16)
end if

Node index count should match the node count of the model using this animation

for node indexes loop
-----------------------
translation index           2 (int16)
rotation index              2 (int16)
end node indexes loop

The following is just a table for the 'binding' pose or default pose

for num nodes loop
-----------------------
initial translation         12 (3 floats)
initial rotation            16 (4 floats)
end num nodes loop

Create a float array based on frame count. This is used to physically rotate the actor playing this animation.

for num frames loop
-----------------------
yaw offsets                 4 (float)
end num frames loop

Create a translation table for every nTranslation. Each table should contain (vector3 * nFrames). This
table will be referenced by the node index table

for nTranslation loop
-----------------------
for nFrame count loop
-----------------------
translation                 12 (3 floats)

end nFrame count loop
end nTranslation loop

Create a rotation table for every nRotation. Each table should contain (vector4 * nFrames). This
table will be referenced by the node index table

for nRotation loop
-----------------------
for nFrame count loop
-----------------------
rotation                    16 (quaternion (4 floats))

end nFrame count loop
end nRotation loop

for nKeyFrame action loop
-----------------------
eventType                   4 (int)
frame                       4 (int)         which frame this event occurs on
args                        16 (4 floats)

end nKeyFrame action loop

end nAnimBlock count loop


//-----------------------------------------------------------------------------
//
// Keyframe Event Types
// Any other types the engine will consider them scripted/user defined
//
//-----------------------------------------------------------------------------

55  - Play footstep sound
232 - Disable blocking sector (args: 0 - unused, 1 - x offset, 2 - y offset, 3 - z offset)
233 - Enable blocking sector (args: 0 - unused, 1 - x offset, 2 - y offset, 3 - z offset)
248 - Play sound (args: 0 - SoundID, 1 - x offset, 2 - y offset, 3 - z offset)
407 - Removes actor
900 - Spawn particle (args: 0 - Particle ID, 1 - x offset, 2 - y offset, 3 - z offset)

Note: All xyz offsets are based on local model space, not world space


//-----------------------------------------------------------------------------
//
// Animation Type IDs
// The following is taken from the animation.txt script file
//
//-----------------------------------------------------------------------------

enum turokAnimations
{
    // ai movement/turning
    anim_aiStanding                     = 0,
    anim_aiWalking,
    anim_aiRunning,
    anim_aiTurn_L_Stand,
    anim_aiTurn_R_Stand,
    anim_aiTurn_B_Stand                 = 6,
    anim_aiTurn_L_Walk,
    anim_aiTurn_R_Walk,
    anim_aiTurn_B_Walk,
    anim_aiTurn_L_Run,
    anim_aiTurn_R_Run,
    anim_aiTurn_B_Run,
   
    anim_aiLostSight,
    anim_aiReach,
   
    anim_aiDodgeRight                   = 15,
    anim_aiDodgeLeft,
    anim_aiDodgeCrouch,
   
    // ai melee
    anim_aiMelee1                       = 18,
    anim_aiMelee2,
    anim_aiMelee3,
    anim_aiMelee4,
    anim_aiMelee5,
    anim_aiMelee6,
    anim_aiMelee7                       = 25,
    anim_aiMelee8,
    anim_aiMelee9,
    anim_aiMelee10                      = 54,
    anim_aiMelee11,
    anim_aiMelee12,
    anim_aiMelee13,
    anim_aiMelee14,
   
    anim_stun1                          = 28,
    anim_stun2,
   
    // ai death knockback
    anim_aiDeathKnockback1              = 30,
    anim_aiDeathKnockback2,
    anim_aiDeathKnockback3,
    anim_aiDeathKnockback4,
   
    // ai death
    anim_aiDeathStand                   = 34,
    anim_aiDeathViolent,
    anim_aiDeathRunning                 = 37,
   
    anim_trexRoar,
   
    anim_activate                       = 200,
   
    // ai specific
    anim_aiPurlinSpawnDrop              = 205,
   
    // swimming
    anim_aiSwim1                        = 2500,
    anim_aiSwim2,
    anim_aiSwim3,
    anim_aiSwim4,
    anim_aiSwim5,
    anim_aiSwim6,
    anim_aiSwim7,
    anim_aiSwim8,
    anim_aiSwim9,
    anim_aiSwim10,
    anim_aiSwim11,
   
    // doors
    anim_doorIdle                       = 2600,
    anim_doorOpen,
    anim_doorClose,
   
    // traps
    anim_trapIdle,
    anim_trapActivate,
   
    // mantis statue
    anim_mantisStatueIdle,
    anim_mantisStatueTrigger,
   
    // lifts
    anim_liftRaise,
    anim_liftLower,
   
    // timer
    anim_timerIdle,
    anim_timerStart,
   
    anim_mantisWallIdle,
    anim_mantisWallCollapseOutward,
    anim_mantisWallCollapseInward,
   
    // laser wall
    anim_laserWallStart                 = 2623,
    anim_laserWallGo                    = 2624,
    anim_laserWallStop                  = 2625,
   
    // destructibles
    anim_destructibleIdle               = 2626,
    anim_destructibleDeath,
   
    // mantis key
    anim_mantisKeyIdle                  = 2637,
    anim_mantisKeyLower,
    anim_mantisKeyRaise,
   
    // ai grunt
    anim_aiGruntStandAlt                = 129,
    anim_aiGruntWalkAlt,
    anim_aiGruntRunAlt,
    anim_aiGruntTurn_L_StandAlt,
    anim_aiGruntTurn_R_StandAlt,
    anim_aiGruntTurn_B_StandAlt,
    anim_aiGruntTurn_L_WalkAlt,
    anim_aiGruntTurn_R_WalkAlt,
    anim_aiGruntTurn_B_WalkAlt,
    anim_aiGruntTurn_L_RunAlt,
    anim_aiGruntTurn_R_RunAlt,
    anim_aiGruntTurn_B_RunAlt,
   
    anim_aiAltMelee1                    = 2700,
    anim_aiAltMelee2,
    anim_aiAltMelee3,
    anim_aiAltMelee4,
    anim_aiAltMelee5,
    anim_aiAltMelee6,
    anim_aiAltMelee7,
    anim_aiAltMelee8,
    anim_aiAltMelee9,
    anim_aiAltMelee10,
    anim_aiAltMelee11,
    anim_aiAltMelee12,
    anim_aiAltMelee13,
    anim_aiAltMelee14,
   
    anim_aiGruntDeathStandAlt           = 143,
    anim_aiGruntDeathViolentAlt,
    anim_aiGruntDeathRunningAlt,
   
    // ai range attack
    anim_aiRangeAttack1                 = 24,
    anim_aiRangeAttack2                 = 59,
    anim_aiRangeAttack3                 = 121,
    anim_aiRangeAttack4,
    anim_aiRangeAttack5,
    anim_aiRangeAttack6,
    anim_aiRangeAttack7                 = 141,
    anim_aiRangeAttack8,
    anim_aiRangeAttack9                 = 150,
    anim_aiRangeAttack10,
   
    // ai teleport
    anim_aiTeleportIn                   = 2550,
    anim_aiTeleportOut,
   
    // mantis animations
    anim_mantisCeilingIdle              = 62,
    anim_mantisGroundIdle,
    anim_mantisWallRightIdle,
    anim_mantisWallLeftIdle,
    anim_mantisLostSight,
    anim_mantisCeilingStandTurnLeft,
    anim_mantisCeilingStandTurnRight,
    anim_mantisGroundStandTurnRight,
    anim_mantisGroundStandTurnLeft,
    anim_mantisWake,
    anim_mantisDeath,
    anim_mantisSlowAttack,
    anim_mantisPain,
    anim_mantisCeilingForward,
    anim_mantisGroundForward,
    anim_mantisCeilingToGround,
    anim_mantisGroundToAir,
    anim_mantisAirLoop,
    anim_mantisAirToGround,
    anim_mantisGroundToCeiling          = 82,
    anim_mantisGroundToRightWall,
    anim_mantisGroundToLeftWall         = 87,
    anim_mantisRightWallToCeiling       = 91,
    anim_mantisRightWallToGround,
    anim_mantisRightWallToAir,
    anim_mantisRightWallToAirLoop,
    anim_mantisAirToLeftWall,
    anim_mantisLeftWallToCeiling        = 97,
    anim_mantisLeftWallToGround,
    anim_mantisLeftWallToAir,
    anim_mantisLeftWallToAirLoop,
    anim_mantisAirToRightWall,
    anim_mantisAttackGround1            = 103,
    anim_mantisAttackCeiling1,
    anim_mantisAttackCeiling2,
    anim_mantisAttackGround2,
    anim_mantisAttackRightWall1,
    anim_mantisAttackRightWall2,
    anim_mantisAttackLeftWall1,
    anim_mantisAttackLeftWall2,
    anim_mantisAttackGroundMelee,
    anim_mantisChargeForward            = 114,
    anim_mantisDamageBack,
    anim_mantisDamageRight,
    anim_mantisDamageLeft,
    anim_mantisInvokeCeiling,
    anim_mantisInvokeRightWall,
    anim_mantisInvokeLeftWall,
   
    // player weapons
    anim_weaponIdle                     = 39,
    anim_weaponWalk,
    anim_weaponRun,
    anim_weaponAttack1,
    anim_weaponAttack2,
    anim_weaponAttack3,
    anim_weaponFire,
    anim_weaponFireCharged,
    anim_weaponSwapIn,
    anim_weaponSwapOut,
    anim_weaponFireLoop,
    anim_weaponAttackUnderwater         = 250,
    anim_weaponIdleUnderwater,
    anim_weaponFireBowNoAmmo            = 2000,
   
    anim_turokIsNom                     = 201,
    anim_campaingerRage                 = 202,
    anim_event03                        = 203,
    anim_event04                        = 204,
    anim_event05                        = 205,
    anim_event06                        = 206,
    anim_event07                        = 207,
    anim_event08                        = 208,
    anim_event09                        = 209,
    anim_event10                        = 210,
    anim_trexGulp                       = 230,
   
    // event animations
    anim_special_event01                = 2801,
    anim_special_event02                = 2802,
    anim_special_event03                = 2803,
    anim_special_event04                = 2804,
    anim_campaingerCrumble              = 2805,
    anim_longHunterTaunt                = 2808,
    anim_player_acquire_key             = 2810,
    anim_player_jump                    = 2815,
    anim_player_panic                   = 2816,
    anim_player_idle                    = 2817,
    anim_player_exit                    = 2818,
    anim_player_run                     = 2819,
    anim_player_surface                 = 2820,
   
    anim_aiWounded                      = 2900,
    anim_aiTurn_L_Wound,
    anim_aiTurn_R_Wound,
    anim_aiTurn_B_Wound
}
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: Smoke39 on April 20, 2017, 10:05:43 PM
I wrote some kinda pseudocode to help me wrap my head around how all the pieces fit together.  If anyone's interested, you can find it in my notes (https://www.dropbox.com/sh/fbro1hq1v0h5634/AAD8lTTQbP86goQhYZIdIyKpa?dl=0) (also linked from my modding guide).
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: Snake Plissken on April 25, 2017, 06:01:07 AM
i have taken this as a chance to learn python. i belive since it all continues to line up as  i study and continue to learn and put to, that- making a blender add-on or plugin is the way to go and .obj format is pretty straight forward, i found a tamplete that will import the .obj model and has features to allow for the user to customly define further header information from within a interface in blender and its quite articulate and indepth about it. but it seems operators need to be ajusted, the tamplete needs to be conformed to the latest version of blender, and i wish to edit the plugin to add and restrict the custom header features to acompany kex's model format that is pretty much the binary with a few custom bytes in this "header" that define params specific to thew model in the engine and engine runing the model. its a tuff road however and i prob wasnt the one to pick it up but hell i had to start sometime and... oh yeah no better time then with this here and now. its slow however, and just in case someone else is alive on this earth who can do it with such a quickness since there a pro and thus pull it off before i can; just in case of this i made a post on the blender forums under some request thread, as a back up plan, since we need this quick. i have no other goals at the momment in life other then pulling of some things i inivisioned and pulling them off in kex, and the support the creation of such a thing would lead to would enable it, there for i have nothing better to do, then try to see to its construction. btw smoke your a smart guy and your understanding of the code sheds light through the point of view it was written. perhaps if your intrested, i can show you my tamplete becuse, this work is straight forward and i know you could accomplish it, no worrys however we are all bizzy guys and gals so i can understand and hope others do when they sense me away for some time off the radar when really im working towards this 24/7 in that: all i do i see to my abilitys to do what im planing in kex ( through pulling this off to ) and when i get burnt out i run a video game, then back and forth. hang in there you guys will have the crazyest epic stuff happening in kex before you know it, or a bit after when you would of liked to have known of such a thing
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: Smoke39 on May 12, 2017, 05:03:32 PM
Code: [Select]
kevin@Linoox ~/Games/[extra]/Turok $ ./a.out
materials/mat_dyn_pistol/surf_663_0000A

Loaded the first person pistol model and successfully printed out the first material as a quick test to see if it even remotely worked.  It may not look like much, but shut up it's the first time I've written C++ in years and I'm excited that it seems to be working. O:<

edit: Okay, here, I did something actually useful now.  Finally fixed the backward faces in the offhand knife/grenade in Turok+.
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: Smoke39 on May 15, 2017, 04:31:32 AM
Got a T2 model converted to T1, animations and all.
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: DoomMarine23 on May 15, 2017, 06:07:03 PM
My god, that is fucking incredible.
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: Duke64 on May 16, 2017, 12:45:06 AM
Really nice Smoke damn can't wait to shoot it!
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: Smoke39 on May 16, 2017, 05:05:24 AM
It's progressing well, but I'm not sure how I should integrate it into the game.  Upgrade for the shotgun (would require yet another keybind for single/double shot toggle), replace the auto shotgun (lose the auto shotgun), or just as a third shotgun (weapon list is already long, weapon order issues).
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: DoomMarine23 on May 16, 2017, 09:40:08 AM
I'm not entirely sure. I think replacing the auto shotgun is the weakest idea because the auto shotgun has its own feel and game-play niche. Having it as a third weapon is interesting but it really fulfills the same game-play niche as the shotgun except just better.

So, I think it might just work best as an upgrade for the regular shotgun if possible. I'm aware it would require a keybind toggle, though it makes me wonder. I assume "Firemode" is used for both ammo and fire-types, perhaps now would be the best time to separate them?

But honestly, failing all of this? I think just making it upgrade the shotgun and having it only consume 1 shot despite shooting more, would be the best compromise. I don't think players will care all that much, I don't think any of us really cared in Turok 2 that it was double barrel and only used 1 shell.

Either way, its a really cool proof of concept and I'm just excited that you got animations working which I'd like to ask how you did it, if possible? Animation support has been halting my more complex ideas.
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: Jay Doomed on May 16, 2017, 12:14:02 PM
Hey Smoke any reason why some mods are not compatible with each other?  I use your mod and Level mods but every time i start the game via Editor Mode a box always pops out.

Most mods use the same script files. The game only reads one of them so combining two mods causes issues. The game doesn't read two of the same scripts.

For example Duke64's maps use main.txt but so does Brutal Turok. So launching both will cause a tangle. They will either not function correctly or they will crash..
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: Smoke39 on May 16, 2017, 01:54:16 PM
But honestly, failing all of this? I think just making it upgrade the shotgun and having it only consume 1 shot despite shooting more, would be the best compromise. I don't think players will care all that much, I don't think any of us really cared in Turok 2 that it was double barrel and only used 1 shell.

Either way, its a really cool proof of concept and I'm just excited that you got animations working which I'd like to ask how you did it, if possible? Animation support has been halting my more complex ideas.

Using only 1 shell is a cosmetic issue in T2.  In T1, it's a balance issue -- the difference in ammo efficiency between the double shotgun and auto shotgun would be pretty big if it only used 1 ammo.

Animations are just converted from T2's format to T1's.  They're mostly the same, so it wasn't that hard.  Converting from other formats, like obj or something, will require more research.

Hey Smoke any reason why some mods are not compatible with each other?  I use your mod and Level mods but every time i start the game via Editor Mode a box always pops out.

Like Jay said, if two mods try to override the same file, they'll conflict with each other.  I think Duke's maps only include main.txt to make "new game" start his map.  If you subscribe to Turok+ after the map (to make it take precedence in the load order), and load the map manually, it might work.

I advocated for reorganizing main.txt in the base game to reduce the chance of maps and mods conflicting over it, but never got a response.  We could do it ourselves, but it'd require everyone agreeing to the standard, and would be an additional hoop for players to jump through.  And there'd still be other files that could be in conflict (e.g., the defs files).  Kex just isn't very modular when it comes to its file structure, so it's kinda inherently prone to conflicts.
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: Mon-Ark on May 16, 2017, 03:25:35 PM
Adding a third shotgun really sounds like alot fo balancing issues. Maybe if you could choose between 2 characters, some of their weapons were different between eachother, or somehting like that.

Personally I feel a few of the original weapons could have some new functions. Dual miniguns maybe?
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: raul on May 31, 2017, 03:51:18 AM
Smoke39, how did you about importing the shotgun with animations into the game? This code kaiser posted is very confusing to me, because im not exactly what language even is or how to go about doing anything with it. Thanks!
Title: Re: Kaiser's Model/Animation Format (Technical Documentation)
Post by: Smoke39 on May 31, 2017, 04:32:41 AM
Kaiser's notes aren't code, they're just specifications of the file formats.  If you missed my earlier post about it, I wrote my own C-style pseudo-code that represents the data in the same structure as the files, with some additional comments on how all the parts fit together.  You can find my notes at the bottom of my guide, which is linked in my sig.

Just read each variable in order.  When you get to an array, read each element in sequence.