Results 1 to 6 of 6

Thread: Milkshape MS3D Animation

  1. #1
    Join Date
    Apr 2012
    Düsseldorf im Rheinland

    Cool Milkshape MS3D Animation

    Hope you like the Delphi / OpenGL oldschool examples!

    [ Milkshape Animation Collision [TRSI].zip updated ] fixed Bounding Box behavior (onto ground/jump)

    Feel free to post improvements, ports to other compiler and platforms or a comment about this subject !

    !! Thank you, Deathshadow, to invest life-time to make suggestions for the published source.
    Attached Files Attached Files
    Last edited by Micronix-TRSI; 14-09-2012 at 07:45 AM.

  2. #2
    PGDCE Developer Carver413's Avatar
    Join Date
    Jun 2010
    It would be nice if it work with the Lazarus.

  3. #3
    Well, you got my attention with having a milkscape import -- I've done some stuff in Milkshape and 3ds Max, mostly amateur hour mods for the game Freespace.... being able to use the stuff I make there in pascal? Loving the idea.

    I'm going through your codebase now... I'm a bit out of touch with Delphi; Not even sure what the difference between CLASS and OBJECT is other than I HATE the syntax -- seems needlessly vague, almost like it came from C or something -- also having a dog of a time with the oddball formatting... but still, I'm getting the gist of it.

    The swapRGB routine could use a bit of speedups, though the operating on a 24 bit image is gonna suck any way you do it. I'd give serious thought to promoting it to 32 bit anyways, since that's what openGL wants... do the work for it instead of it trying to deal with it on the fly or playing texture loader games. At 32 bit you could just call BSWAP and then ROL EAX,8.

    Though a more robust BMP loader is definitely in order there anyhow.

    in your ms3d handler I end up with a few odd questions -- TStaticModelGL and tAnimatedModelGL are perfectly good objects, why are you then using procedural programming for things like LoadAnimation? If anything, shouldn't that be the constructor for said object? You could also make the stream part of the object, reducing the overhead of passing so much on the stack further speeding up load times.

    Wondering why you're brute-forcing parsing the path, instead of using extractFilePath -- delphi does have that, right? Where you have:
      REPEAT Dec ( j ) UNTIL ( aPath [ j ] = '/' ) OR ( aPath [ j ] = '\' ) OR ( j <= 0 );
      Path := Copy ( aPath, 0, j - 1 );
    I'd probably have:
    Of course that you've got path as a global... could cause confusion; why I'd probably put all that on TAnimatedModelGL as a constructor.

    I'm also wondering why you're spending so much time selectively reading from the stream thus:
          aStream.Read ( AnimFPS, SizeOf ( AnimFPS ) );
          aStream.Position := aStream.Position + SizeOf ( Single ); //Skip CurrentTime
          aStream.Read ( TotalFrames, SizeOf ( TotalFrames ) );
          MaxTime := round ( TotalFrames * 1000 / AnimFPS );
          aStream.Read ( numJoints, SizeOf ( NumJoints ) );
    I'd probably have all those in a record like 'animHeader' so that I could just do them in one read.

    Using a few more WITH could probably help out too... take this:
    FOR c2 := 0 TO ms3dJoint.nRotKeyframes - 1 DO
    		Joints [ c ].RotationKeyframes [ c2 ].JointIndex := c;
    		Joints [ c ].RotationKeyframes [ c2 ].Time			 := ms3dKeyframe.Time * 1000;
    		Joints [ c ].RotationKeyframes [ c2 ].Parameter	 := ms3dKeyframe.Parameter
    I'd clean that into:
    for c2:=0 to ms3dJoint.nRotKeyFrames-1 do
    	with joints[c].rotationKeyFrames[c2] do begin
    		JointIndex := c;
    		Time       := ms3dKeyframe.Time*1000;
    		Parameter  := ms3dKeyframe.Parameter;
    Actually, not true, I'd probably use a setter there. Sure, it adds the overhead of a CALL, but it would be a lot cleaner/simpler to implement.

    I'm seeing some things that could REALLY be sped up -- like ms3d_materiel and tModelMateriel sharing the exact same format for six values, I'd make those a sub-record and do a single copy on them, instead of manually indexing each and every one of them.

    I mean this:
    					Materials [ c ].Ambient			 := ms3dmaterial.Ambient;
    					Materials [ c ].Diffuse			 := ms3dmaterial.Diffuse;
    					Materials [ c ].Specular		 := ms3dmaterial.Specular;
    					Materials [ c ].Emissive		 := ms3dmaterial.Emissive;
    					Materials [ c ].Shininess		 := ms3dmaterial.Shininess;
    					Materials [ c ].Transparency := ms3dmaterial.Transparency;
    is pretty painful, when you could just do

    copy(materiels[c].properties,,sizeof(tMateri alProperties));

    Oddly, you do that with the loadHeader procedure...

    I'd also suggest that for the OpenGL side, you actually use GLFloat -- which is NOT always a Single precision number... it is only guaranteed to be at LEAST 32 bit.

    When/if I have time, I'm gonna see if I can port this to FPC... note I'm saying FPC, not lazarus -- I've got this weird mental block, I can hand compile Z80 machine language, but I can't learn visual programming. I could JUST grasp how to use OWL; along comes the VCL and Delphi, and I'm completely lost to the point I'm better off calling the GDI and Win API directly.

    Should actually move over fairly easy if I toss the windows specific handler and use the SDL/OpenGL bindings that come with FPC.

    -- edit --

    Just looked at .render -- I'd consider using variable procedures for if the object has joints or not. One less if. I'd also suggest building those as real openGL groups, instead of manually mapping every triangle on every pass... NOT that I'm one to talk since my 3d engine does that, but mine is using arctan to build the projection and final rotations since it's meant for 'circlevision' -- so I'm basically using OpenGL as a glorified version of GLIDE.

    Still, pre-rendering as complete objects each frame of an object's animation would REALLY speed things up. I might even consider doing such a thing at load time, so that during gameplay the no longer neccessary frame info isn't sucking down memory.
    Last edited by deathshadow; 11-06-2012 at 09:11 AM.
    The accessibility of a website from time to time must be refreshed with the blood of designers and owners. It is its natural manure

  4. #4
    Thanks for sharing!

    BTW, I did make a Milkshape 3d exporter plugin for the DeleD 3d modelling program...

    The source code for that plugin and others can be found here:


  5. #5
    Co-Founder / PGD Elder WILL's Avatar
    Join Date
    Apr 2003
    Blog Entries
    Can we get some demo video posts perhaps? Just to see how this is supposed to look on screen.
    Jason McMillen
    Pascal Game Development

  6. #6
    Here's screenshot attached. The ninja is moving a little in place, sort of idle animation. Sword is moving along with the hand, unsure if it's separate object. Camera is seemingly picking random points around and moving there, centered on point under the character.

    I would have liked to convert it to nxPascal but it would seem to be a little complicated process. Alot of internal things would need to be done first. For instance this us using milkshape binary format, whereas i use ascii, with no support for animation and bones yet. Are the camera paths actually in model file too or just randomized? I was pondering if i should focus more on other format support like 3DS. Also this code seemed a little hard to read, a bit like directly converted from C++ or so, leaving the formatting like that. Very procedural, and ms3d-unit itself contains rendering too.
    Attached Images Attached Images

Tags for this Thread


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
Comodo SSL