Thread Rating:
  • 1 Vote(s) - 4 Average
  • 1
  • 2
  • 3
  • 4
  • 5
md2 loading test
#1
Here's a quick test of a function for loading md2 (quake 2 models) files.


Attached Files
.zip   md2_loader.zip (Size: 235.07 KB / Downloads: 9)
Reply
#2
Thanks ! I think 3D animation with md2 will look way more lively. By the way, how do I make the character punch and kick ? .... Big Grin

I've known how to punch 
anim = AnimationLoop([198,199,200,201,202,203,204,205,206,207]) 'punch

Big Grin
Reply
#3
Nicely done!! Very cool...
Logic is the beginning of wisdom.
Reply
#4
Here's a better animation example. This is pretty much how I do it in Neon Breath and Robowack 3.

I got a weird runtime error related to the % operator when testing this. Because of it, I relased a new n7 version without posting about it (https://naalaa.com/n7/N7_250906.zip). If you get a runtime error when testing this example, you can download the new n7 version and see if it helps.

Put this code in the same folder as the original example. Basicly, in a game, you would let every object (like enemies) have an "AnimationController" to help you with its animations.

Code:
' http://tfc.duke.free.fr/coding/md2-specs-en.html
' ------------------------------------------------

include "s3d.n7"

'#win32

' Display settings.
constant RES = 480          ' Vertical resolution.
constant SCALE = 1          ' Window scale.
constant FULLSCREEN = 0    ' Fullscreen if 1
constant DISPLAY_FPS = 1    ' Display fps if 1.
constant FOV = 45          ' Vertical field of view in degrees.
constant MOUSE_SENS = 1    ' Mouse sensitivity.

' For delta time.
visible vLastTick = 0

' Some animations. You can look for other animations in the output when the program starts.
visible vPlayerWalkAnim = [40, 41, 42, 43, 44, 45]
visible vPlayerPunchAnim = [198, 199, 200, 201, 202, 203, 204, 205, 206, 207]
visible vPlayerCrouchPunchAnim = [208, 209, 210, 211, 212]
visible vPlayerWaveAnim = [112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122]
visible vSaluteAnim = [84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94]

' Create window.
set window "MD2", RES*screenw()/screenh(), RES, FULLSCREEN, SCALE
set redraw off

' Load md2 model.
info = []
scale = 0.04
model = LoadMD2("assets/doomguy/tris.md2", true, scale, -scale, scale, false, info)
texture = loadimage("assets/doomguy/texture.png")
' Print list of available frames.
for i = 0 to sizeof(info.frames) - 1
    pln i + ": " + info.frames[i]
next

' Create an AnimationController, with some functions that help us manage animations for an object.
anim = AnimationController()
' Start playing the looped walk animation.
anim.Play(vPlayerWalkAnim, 5, true)
' Flag player walking. If player is walking we can press keys to do other stuff.
walking = true

' Init s3d with the window as render target, a field of view of FOV degrees, near clip plane at
' distance 0.1 and far clip plane at 10.
S3D_SetView(primary, rad(FOV), 0.1, 10)

' Rotation angle for the mesh.
rotY = 225
distance = 3
dragging = false
lastMouseX = 0
lastMouseY = 0

' Loop until user presses esc.
while not keydown(KEY_ESCAPE, true)
    ' Get time passed since last frame.
    dt = DeltaTime()

    ' Update mesh animation.
    '  AnimationController.Update returns false if a non-looped animation has finished playing. In
    ' that case, restart the walk animation.
    if not anim.Update(dt)
        anim.Play(vPlayerWalkAnim, 5, true)
        walking = true
    endif
   
    ' Check keys if walking.
    if walking
        if keydown(KEY_1, true)
            ' Start punch animation and unflag walking.
            anim.Play(vPlayerPunchAnim, 10, false)
            walking = false
        elseif keydown(KEY_2, true)
            anim.Play(vPlayerCrouchPunchAnim, 10, false)
            walking = false
        elseif keydown(KEY_3, true)
            anim.Play(vPlayerWaveAnim, 10, false)
            walking = false
        elseif keydown(KEY_4, true)
            anim.Play(vSaluteAnim, 10, false)
            walking = false
        endif
    endif

    ' Rotate and zoom when left mouse button is pressed.
    if mousebutton(0)
        if dragging
            mx = mousex()
            my = mousey()
            rotY = rotY - (mx - lastMouseX)*MOUSE_SENS
            distance = min(max(distance + 0.05*(my - lastMouseY)*MOUSE_SENS, 0.5), 10)
            lastMouseX = mx
            lastMouseY = my
        else
            dragging = true
            lastMouseX = mousex()
            lastMouseY = mousey()           
        endif
    else
        dragging = false
    endif

    ' Dark blueish background.
    set color 16, 16, 32
    cls
   
    ' Clear transformation and depth buffer.
    S3D_Clear()

    ' Translate and rotate.
    S3D_Translate(0, 0.25, distance)
    S3D_RotateY(rad(rotY))
    S3D_Texture(texture)
    'S3D_BlendMesh(model, anim.f0, anim.f1, anim.b)
    anim.Render(model)


    ' Write information and instructions.
    set color 255, 255, 255
    set caret 0, 0
    wln "Rotate and zoom by moving the mouse while holding down left mouse button"
    wln "Press 1 to punch, 2 to crouch punch, 3 to wave and 4 to salute"
    wln
    wln "Press Esc to quit"

    ' Display.
    DisplayFps(dt)
   
    ' Update window.
    redraw
    wait 1
wend

' AnimationLoop
' -------------
' Just a helper.
function AnimationLoop(frames)
    anim = []
    anim.frames = frames
    anim.param = 0
    anim.frame0 = frames[0]
    anim.frame1 = frames[1]
    anim.blend = 0
    anim.Forward = function(k)
        k = k*sizeof(.frames)
        .param = (.param + k)%sizeof(.frames)
        .frame0 = .frames[int(.param)]
        .frame1 = .frames[int((.param) + 1)%sizeof(.frames)]
        .blend = .param%1
    endfunc
    return anim
endfunc


' DeltaTime
' ---------
' Return delta time in seconds since last call.
function DeltaTime()
    t = clock()
    dt = (min(t - vLastTick, 100))/1000
    vLastTick = t
    return dt
endfunc

' DisplayFps
' ----------
' Display number of frames per second in bottom right corner based on delta time in seconds.
function DisplayFps(dt)
    if DISPLAY_FPS
        set caret width(primary) - fwidth(" "), height(primary) - fheight()
        set justification right
        set color 0, 255, 0
        write "FPS: " + str(round(1/dt), 3)
        set justification left
    endif
endfunc

' LoadMdD2
' --------
' Create a mesh, possibly with multiple frames, from MD2 file.
function LoadMD2(filename, swapYZ, scaleX, scaleY, scaleZ, invertFaces, info)
    assert typeof(info) = TYPE_UNSET or typeof(info) = TYPE_TABLE, "LoadMD2: info parameter must be unset or a table"
   
    ' Load all data from file.
    f = openfile(filename, true)
    if not file(f)  return unset
    ident = fread(f, 32, true)
    if ident <> 844121161  return unset
    version = fread(f, 32, true)
    if version <> 8  return unset
    skinWidth = fread(f, 32, true)
    skinHeight = fread(f, 32, true)
    frameSize = fread(f, 32, true)
    numSkins = fread(f, 32, true)
    numVertices = fread(f, 32, true)
    numSt = fread(f, 32, true)
    numTris = fread(f, 32, true)
    numGlCmds = fread(f, 32, true)
    numFrames = fread(f, 32, true)
    offsetSkins = fread(f, 32, true)
    offsetSt = fread(f, 32, true)
    offsetTris = fread(f, 32, true)
    offsetFrames = fread(f, 32, true)
    offsetGlCmds = fread(f, 32, true)
    offsetEnd = fread(f, 32, true)
    uvs = []
    if numSt
        file seek f, offsetSt, SEEK_SET
        for i = 0 to numSt - 1
            uvs[sizeof(uvs)] = [fread(f, 16, true)/skinWidth, fread(f, 16, true)/skinHeight]
        next
    endif
    tris = []
    if numTris
        file seek f, offsetTris, SEEK_SET
        for i = 0 to numTris - 1
            v0 = fread(f, 16, true);  v1 = fread(f, 16, true);  v2 = fread(f, 16, true)
            uv0 = fread(f, 16, true);  uv1 = fread(f, 16, true);  uv2 = fread(f, 16, true)
            if invertFaces  tris[sizeof(tris)] = [v2, v1, v0, uv2, uv1, uv0, unset]
            else  tris[sizeof(tris)] = [v0, v1, v2, uv0, uv1, uv2, unset]
        next
    endif
    frames = []
    if typeof(info)  info.frames = []
    if numFrames
        file seek f, offsetFrames, SEEK_SET
        for i = 0 to numFrames - 1
            frame = []
            frames[sizeof(frames)] = frame
            sx = fread(f, 64, false);  sy = fread(f, 64, false);  sz = fread(f, 64, false)
            tx = fread(f, 64, false);  ty = fread(f, 64, false);  tz = fread(f, 64, false)
            name = ""
            done = false
            for j = 0 to 15
                c = fread(f, 8, true)
                if c = 0  done = true
                if not done  name = name + chr(c)
            next
            if typeof(info)  info.frames[sizeof(info.frames)] = name
            frame.verts = []
            for j = 0 to numVertices - 1
                x = tx + fread(f, 8, false)*sx
                y = ty + fread(f, 8, false)*sy
                z = tz + fread(f, 8, false)*sz
                if swapYZ  frame.verts[sizeof(frame.verts)] = [scaleX*x, scaleY*z, scaleZ*y]
                else  frame.verts[sizeof(frame.verts)] = [scaleX*x, scaleY*y, scaleZ*z]
                tmp = fread(f, 8, false)  ' Not interested in normal index.
            next       
        next
    endif
    free file f
   
    ' Build mesh.
    mesh = S3D_CreateMesh(frames[0].verts, uvs, unset, tris)
    if numFrames > 1
        for i = 1 to numFrames - 1
            S3D_AddMeshFrame(mesh, frames[i].verts)
        next
    endif
   
    return mesh
endfunc

' AnimationController
' -------------------
function AnimationController()
    a = []
    a.f = unset    ' frames
    a.f0 = 0        ' frame 0
    a.f1 = 0        ' frame 1
    a.p = 1        ' param
    a.b = 1        ' blend
    a.spd = 0      ' speed
    a.ospd = 0      ' old speed
    a.l = false    ' looped
    a.s = 0        ' state
   
    ' Play
    ' ----
    a.Play = function(frames, spd, looped)
        .f = frames
        '.mf = sizeof(.f) - 1
        if .spd then .ospd = .spd
        else  .ospd = spd
        .spd = spd
        .l = looped
        if .b < 1
            .s = 2 ' finish blend
        else
            .f0 = .f1
            .f1 = .f[0]
            .b = 0
            .s = 3 ' blend old frame to first frame
        endif     
    endfunc
   
    ' SetSpeed
    ' --------
    a.SetSpeed = function(spd)
        .spd = spd
    endfunc
   
    ' Update
    ' ------
    a.Update = function(dt)
        if .s = 2 ' finish blend
            .b = .b + 2*.ospd*dt
            if .b >= 1
                .f0 = .f1
                .f1 = .f[0]
                .b = 0
                .s = 3 
            endif
        elseif .s = 3 ' blend old frame to first frame
            .b = .b + 2*.spd*dt
            if .b >= 1
                .f0 = .f[0]
                .f1 = .f[0]
                .p = 0
                .b = 0
                .s = 1
            endif 
        elseif .s = 1 ' animate
            if .l  ' looped.
                .p = (.p + .spd*dt)%sizeof(.f)
                .f0 = .f[int(.p)]
                .f1 = .f[int((.p) + 1)%sizeof(.f)]
                .b = .p%1
            else
                .p = .p + .spd*dt
                if .p >= sizeof(.f) - 1 ' done.
                    .s = 0
                    .b = 1
                    .f0 = .f[sizeof(.f) - 1]
                    .f1 = .f[sizeof(.f) - 1]
                else
                    .b = .p%1
                    ' crash on f1 line when low fps
                    .f0 = .f[int(.p)]
                    .f1 = .f[int(.p) + 1]
                endif
            endif
        endif
        return .s <> 0
    endfunc
   
    ' Render
    ' ------
    a.Render = function(mesh)
        S3D_BlendMesh(mesh, .f0, .f1, .b)
    endfunc
   
    return a
endfunc
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)