home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2005 December / DPPCPRO1205.ISO / Essentials / Programming / Basic4GL / Setup Basic4GL v2.3.1.exe / $INSTDIR / Programs / LitMD2Viewer.gb < prev    next >
Encoding:
Text File  |  2005-07-29  |  15.9 KB  |  493 lines

  1. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  2. ' Data types
  3.  
  4. struc SMD2_header
  5.     
  6.     ' File information
  7.     dim ident
  8.     dim version
  9.     dim skinwidth                   ' Width of skin texture (pixels)
  10.     dim skinheight                  ' Height of skin texture (pixels)
  11.     dim framesize                   
  12.     
  13.     ' Number of different components
  14.     dim num_skins                   ' Skins
  15.     dim num_xyz                     ' Vertices (x, y, z)
  16.     dim num_st                      ' Texture coordinates (s, t)
  17.     dim num_tris                    ' Triangles
  18.     dim num_glcmds                  ' GL Commands (which we aren't going to use)
  19.     dim num_frames                  ' Frames
  20.     
  21.     ' File offset of different components
  22.     dim ofs_skins                   ' Skins 
  23.     dim ofs_st                      ' Texture coordinates (s,t)
  24.     dim ofs_tris                    ' Triangles
  25.     dim ofs_frames                  ' Frames
  26.     dim ofs_glcmds                  ' GL Commands (which we aren't going to use)
  27.     dim ofs_end                     ' End of file
  28. endstruc
  29.  
  30. struc SMD2_vertex
  31.     dim v#(2)                                   ' Vertex
  32.     dim normal#(2)
  33. endstruc
  34.  
  35. struc SMD2_triangle
  36.     dim index_xyz(2)                            ' Index of triangle vertices
  37.     dim index_st(2)                             ' Index of texture coordinates
  38. endstruc
  39.  
  40. struc SMD2_frame
  41.     dim scale#(2), translate#(2)                ' Scaling and translation
  42.     dim name$                                   ' Display name
  43.     dim SMD2_vertex &verts()                    ' Vertices
  44. endstruc
  45.  
  46. struc SMD2_model
  47.     dim SMD2_header header                      ' Header data
  48.     dim &skins ()                               ' Skin textures
  49.     dim &st# ()()                               ' Texture coordinates (compressed)
  50.     dim SMD2_triangle &tris ()                  ' Triangles
  51.     dim SMD2_frame &frames()                    ' Frames
  52. endstruc
  53.  
  54. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  55. ' Variables
  56.  
  57. ' Pointers for passing parameters into routines
  58. dim SMD2_model &theModel, SMD2_frame &theFrame, SMD2_frame &theFrame2, SMD2_vertex &theVertex
  59. dim SMD2_header &theHeader, theFrameNum, theFrameNum2, theSkin, SMD2_triangle &theTriangle
  60. dim theFileName$, theFileDir$, theFrameFactor#, temp$
  61.  
  62.  
  63. ' Working variables
  64. dim tempStr$, i, i2, i3, tempVec# (2), tempNormal# (2), tempTriangle#(2)(2)
  65. dim theFile
  66.  
  67. goto Start
  68.  
  69. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  70. ' Functions
  71.  
  72. ''''''''''''''''''''''
  73. ' Internal functions
  74. LoadMD2Header:
  75.     
  76.     ' Expects:
  77.     '   &theHeader = points to the destination header data
  78.     '   file       = file handle to read from
  79.     theHeader.ident       = ReadInt (theFile)
  80.     theHeader.version     = ReadInt (theFile)
  81.     theHeader.skinwidth   = ReadInt (theFile)
  82.     theHeader.skinheight  = ReadInt (theFile)
  83.     theHeader.framesize   = ReadInt (theFile)
  84.     theHeader.num_skins   = ReadInt (theFile)
  85.     theHeader.num_xyz     = ReadInt (theFile)
  86.     theHeader.num_st      = ReadInt (theFile)
  87.     theHeader.num_tris    = ReadInt (theFile)
  88.     theHeader.num_glcmds  = ReadInt (theFile)
  89.     theHeader.num_frames  = ReadInt (theFile)
  90.     theHeader.ofs_skins   = ReadInt (theFile)
  91.     theHeader.ofs_st      = ReadInt (theFile)
  92.     theHeader.ofs_tris    = ReadInt (theFile)
  93.     theHeader.ofs_frames  = ReadInt (theFile)
  94.     theHeader.ofs_glcmds  = ReadInt (theFile)
  95.     theHeader.ofs_end     = ReadInt (theFile)
  96.     return
  97.     
  98. LoadMD2Skins:
  99.  
  100.     ' Expects:
  101.     '   &theModel  = points to the destination model
  102.     '   file       = file handle to read from
  103.     
  104.     ' Seek to skin texture names
  105.     Seek (theFile, theModel.header.ofs_skins)
  106.  
  107.     ' Allocate skin texture handles
  108.     alloc theModel.skins, theModel.header.num_skins - 1
  109.     
  110.     ' Load textures
  111.     for i = 0 to theModel.header.num_skins - 1
  112.     
  113.         ' Read texture name
  114.         tempStr$ = ""
  115.         for i2 = 1 to 64                                ' Read name 
  116.         
  117.             temp$ = ReadChar (theFile)
  118.             if temp$ = "/" then temp$ = "\" endif
  119.             tempStr$ = tempStr$ + temp$
  120.         next    
  121.         while Len (tempStr$) > 0 and Right$ (tempStr$, 1) <= " "            ' Trim whitespace from right
  122.             tempStr$ = Left$ (tempStr$, Len (tempStr$) - 1)
  123.         wend
  124.  
  125.         ' Load texture
  126.         theModel.skins (i) = LoadMipmapTexture (theFileDir$ + tempStr$)
  127.         if theModel.skins (i) <= 0 then 
  128.             print "Failed to load texture: " + theFileDir$ + tempStr$
  129.             end
  130.         endif  
  131.     next               
  132.     return
  133.     
  134. LoadMD2ST:
  135.     
  136.     ' Expects:
  137.     '   &theModel  = points to the destination model
  138.     '   file       = file handle to read from
  139.     
  140.     ' Allocate texture coordinates    
  141.     alloc theModel.st#, theModel.header.num_st - 1, 1
  142.     
  143.     ' Seek to texture coordinates
  144.     Seek (theFile, theModel.header.ofs_st)
  145.  
  146.     ' Load texture coordinates
  147.     for i = 0 to theModel.header.num_st - 1
  148.         theModel.st# (i)(0) = ReadWord (theFile)
  149.         theModel.st# (i)(1) = ReadWord (theFile)
  150.     next
  151.     return
  152.     
  153. LoadMD2Tris:
  154.  
  155.     ' Expects:
  156.     '   &theModel  = points to the destination model
  157.     '   file       = file handle to read from
  158.     
  159.     ' Allocate triangles
  160.     alloc theModel.tris, theModel.header.num_tris - 1
  161.     
  162.     ' Seek to triangles
  163.     Seek (theFile, theModel.header.ofs_tris)
  164.     
  165.     ' Load triangles
  166.     for i = 0 to theModel.header.num_tris - 1
  167.         for i2 = 0 to 2
  168.             theModel.tris (i).index_xyz (i2) = ReadWord (theFile)
  169.         next
  170.         for i2 = 0 to 2
  171.             theModel.tris (i).index_st (i2) = ReadWord (theFile)
  172.         next
  173.     next
  174.     return
  175.     
  176. LoadMD2Frames:
  177.  
  178.     ' Expects:
  179.     '   &theModel  = points to the destination model
  180.     '   file       = file handle to read from
  181.  
  182.     ' Allocate frames
  183.     alloc theModel.frames, theModel.header.num_frames - 1
  184.     
  185.     ' Seek to frames
  186.     Seek (theFile, theModel.header.ofs_frames)
  187.     
  188.     ' Load frames
  189.     for i = 0 to theModel.header.num_frames - 1 
  190.         &theFrame = &theModel.frames (i)
  191.         
  192.         for i2 = 0 to 2
  193.             theFrame.scale# (i2) = ReadFloat (theFile)
  194.         next
  195.         for i2 = 0 to 2
  196.             theFrame.translate# (i2) = ReadFloat (theFile)
  197.         next
  198.         tempStr$ = ""
  199.         for i2 = 1 to 16: tempStr$ = tempStr$ + ReadChar (theFile): next   ' Read name             
  200.         while Len (tempStr$) > 0 and Right$ (tempStr$, 1) <= " "        ' Trim whitespace from right
  201.             tempStr$ = Left$ (tempStr$, Len (tempStr$) - 1)
  202.         wend
  203.         theFrame.name$ = tempStr$
  204.         
  205.         ' Allocate vertices
  206.         alloc theFrame.verts, theModel.header.num_xyz
  207.         
  208.         ' Read vertices
  209.         for i2 = 0 to theModel.header.num_xyz - 1
  210.             for i3 = 0 to 2
  211.                 theFrame.verts (i2).v# (i3) = ReadByte (theFile)
  212.             next
  213.             ReadByte (theFile)          ' Throw away normal info from file
  214.         next    
  215.     next
  216.     return
  217.     
  218.  
  219. CalcMD2Normals:
  220.     ' Note: The MD2 file format stores normals as indexed lookups into some normal table.
  221.     ' I cannot find this table, so I will simply recalculate them.
  222.     
  223.     ' Expects:
  224.     '   &theModel  = points to the destination model
  225.     &theHeader = &theModel.header
  226.     
  227.     ' Calculate for all frames
  228.     for i3 = 0 to theHeader.num_frames - 1
  229.         &theFrame  = &theModel.frames (i3)          
  230.         for i = 0 to theHeader.num_tris - 1  
  231.     
  232.             ' Fetch the triangle vertices
  233.             &theTriangle = &theModel.tris (i)
  234.             for i2 = 0 to 2
  235.                 tempTriangle# (i2) = theFrame.verts (theTriangle.index_xyz (i2)).v#
  236.             next
  237.         
  238.             ' Calculate normal as cross product between edges 0-1 and 0-2
  239.             tempNormal# = Normalize (-CrossProduct (tempTriangle# (1) - tempTriangle# (0), tempTriangle# (2) - tempTriangle# (0)))
  240.             
  241.             ' Add new normal to normals at ALL vertices of the triangle.
  242.             ' This will have an averaging effect over vertices that are shared between multiple triangles
  243.             for i2 = 0 to 2
  244.                 theFrame.verts (theTriangle.index_xyz (i2)).normal# = theFrame.verts (theTriangle.index_xyz (i2)).normal# + tempNormal#
  245.             next
  246.         next
  247.             
  248.         ' Normalise all normals
  249.         for i = 0 to theHeader.num_xyz - 1
  250.             theFrame.verts (i).normal# = Normalize (theFrame.verts (i).normal#)
  251.         next
  252.     next
  253.     return
  254.     
  255. ''''''''''''''''''
  256. ' Main functions
  257.  
  258. ' LoadMD2
  259. ' Input:  theFileName$ = file to load
  260. ' Output: theModel     = MD2 model
  261.  
  262. LoadMD2:
  263.  
  264.     ' Open file
  265.     theFile = OpenFileRead (theFileDir$ + theFileName$)
  266.     if FileError() <> "" then 
  267.         printr "Failed to open " + theFileName$
  268.         printr "Reason: " + FileError ()
  269.         end
  270.     endif
  271.     
  272.     ' Allocate model
  273.     alloc theModel
  274.  
  275.     ' Read header
  276.     &theHeader = &theModel.header
  277.     gosub LoadMD2Header
  278.     
  279.     ' Read data
  280.     gosub LoadMD2Skins                      ' Skins
  281.     gosub LoadMD2ST                         ' Texture coordinates (s, t)    
  282.     gosub LoadMD2Tris                       ' Triangles
  283.     gosub LoadMD2Frames                     ' Frames
  284.  
  285.     ' Close file
  286.     CloseFile (theFile)
  287.     
  288.     ' Calculate normals
  289.     gosub CalcMD2Normals
  290.     return
  291.  
  292. DrawMD2:
  293.     
  294.     ' Draw an interpolated MD2 frame
  295.     
  296.     ' Expects:
  297.     '   theModel        = pointer to model
  298.     '   theFrameNum     = index of first frame
  299.     '   theFrameNum2    = index of the second frame
  300.     '   theFrameFactor# = 0 to draw the first frame, 1 to draw the second frame, or a value between 0 and 1
  301.     '   theSkin         = skin to use
  302.   
  303.     &theHeader = &theModel.header
  304.     &theFrame  = &theModel.frames (theFrameNum)
  305.     &theFrame2 = &theModel.frames (theFrameNum2)
  306.  
  307.     ' Bind texture    
  308.     glEnable (GL_TEXTURE_2D)
  309.     glBindTexture (GL_TEXTURE_2D, theModel.skins (theSkin))
  310.     glEnable (GL_CULL_FACE)
  311.     glCullFace (GL_FRONT)
  312.     
  313.     ' Setup texture scaling
  314.     glMatrixMode (GL_TEXTURE)
  315.     glPushMatrix ()
  316.     glScalef (1.0 / theHeader.skinWidth, -1.0 / theHeader.skinHeight, 1)
  317.     glMatrixMode (GL_MODELVIEW)
  318.     
  319.     ' Apply model scaling
  320.     glPushMatrix ()
  321.     glRotatef( -90, 1, 0, 0 )
  322.     glRotatef( -90, 0, 0, 1 )
  323.     tempVec# = theFrame.translate# * (1 - theFrameFactor#) + theFrame2.translate# * theFrameFactor#
  324.     glTranslatef (tempVec# (0), tempVec# (1), tempVec# (2))
  325.     tempVec# = theFrame.scale# * (1 - theFrameFactor#) + theFrame2.scale# * theFrameFactor#
  326.     glScalef     (tempVec# (0), tempVec# (1), tempVec# (2))
  327.     
  328.     ' Render each triangle
  329.     glBegin (GL_TRIANGLES)    
  330.         for i = 0 to theHeader.num_tris - 1
  331.             &theTriangle = &theModel.tris (i)
  332.             for i2 = 0 to 2
  333.                 glNormal3fv (theFrame.verts (theTriangle.index_xyz (i2)).normal# * (1 - theFrameFactor#) + theFrame2.verts (theTriangle.index_xyz (i2)).normal# * theFrameFactor#)
  334.                 glTexCoord2fv (theModel.st# (theTriangle.index_st (i2)))
  335.                 glVertex3fv (theFrame.verts (theTriangle.index_xyz (i2)).v# * (1 - theFrameFactor#) + theFrame2.verts (theTriangle.index_xyz (i2)).v# * theFrameFactor#)
  336.             next
  337.         next
  338.     glEnd ()
  339.     
  340.     ' Restore modelview matrix
  341.     glPopMatrix ()
  342.     
  343.     ' Restore texture matrix
  344.     glMatrixMode (GL_TEXTURE)
  345.     glPopMatrix ()
  346.     glMatrixMode (GL_MODELVIEW)
  347.  
  348.     return
  349.  
  350.  
  351. Start:
  352.  
  353. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  354. '  Test by loading a sample model
  355.  
  356.     dim SMD2_model &model, xang#, yang#, a$, animSpeed#, zoom#, anim$, still, lit
  357.  
  358.     ResizeText (60, 30)    
  359.     
  360.     theFileDir$ = "files\"
  361.     theFileName$ = "cyberdemon.md2"
  362.     gosub LoadMD2
  363.     &model = &theModel
  364.     
  365.     theFrameNum     = 0
  366.     theFrameNum2    = 0
  367.     theFrameFactor# = 0
  368.     theSkin         = 0
  369.     animSpeed#      = 0.05
  370.     zoom#           = 300
  371.     yang#           = 30
  372.     anim$           = "defg"      
  373.     still           = false
  374.     lit             = true
  375.  
  376.     ' Lighting
  377.     glEnable (GL_LIGHTING)
  378.     glEnable (GL_LIGHT0)
  379.     glEnable (GL_COLOR_MATERIAL)
  380.     glEnable (GL_NORMALIZE)
  381.     glClearColor (.2, .2, .2, 1)
  382.     
  383.     gosub Instructions     
  384.  
  385.     ' Draw model
  386.     while true
  387.         glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
  388.         glLoadIdentity ()
  389.         glTranslatef (0, 0, -zoom#)
  390.         glRotatef (yang#, 0, 1, 0)
  391.         glRotatef (xang#, 1, 0, 0)
  392.         glTranslatef (0, -100, 0)
  393.         &theModel   = &model
  394.         gosub DrawMD2        
  395.         DrawText ()
  396.         SwapBuffers ()           
  397.             
  398.         ' User interface
  399.         ' Letter keys choose a frame
  400.         if still then
  401.             a$ = inkey$ ()
  402.             if a$ = chr$(13) then
  403.                 gosub AnimString
  404.                 a$ = ""
  405.             endif
  406.             if a$ <> "" then 
  407.                 if anim$ <> "" then
  408.                     anim$ = ""
  409.                     gosub Instructions
  410.                 endif
  411.             else 
  412.                 if anim$ <> "" then 
  413.                     a$ = left$ (anim$, 1)
  414.                     anim$ = right$ (anim$, len(anim$) - 1) + a$
  415.                 endif
  416.             endif
  417.             if a$ = "?" then 
  418.                 theFrameNum2 = rnd () % model.header.num_frames
  419.                 still = false
  420.             endif
  421.             if a$ >= "a" and a$ <= "z" then
  422.                 theFrameNum2 = asc (a$) - asc ("a")
  423.                 still = false
  424.             endif
  425.             if a$ >= "A" and a$ <= "Z" then
  426.                 theFrameNum2 = asc (a$) - asc ("A") + 26
  427.                 still = false
  428.             endif
  429.             if theFrameNum2 >= model.header.num_frames then
  430.                 theFrameNum2 = model.header.num_frames - 1
  431.                 still = false
  432.             endif            
  433.         endif
  434.         if InScanKey () = VK_F1 then
  435.             lit = not lit
  436.             if lit then glEnable (GL_LIGHTING)
  437.             else        glDisable (GL_LIGHTING)
  438.             endif
  439.             gosub Instructions
  440.         endif
  441.  
  442.         yang# = yang# + mouse_xd () * 100
  443.         xang# = xang# + mouse_yd () * 100
  444.         zoom# = zoom# - mouse_wheel () * 25
  445.  
  446.         while SyncTimer (10)
  447.             
  448.             ' Arrow keys rotate model
  449.             if ScanKeyDown (VK_LEFT)    then yang# = yang# - 1 endif
  450.             if ScanKeyDown (VK_RIGHT)   then yang# = yang# + 1 endif
  451.             if ScanKeyDown (VK_UP)      then xang# = xang# - 1 endif
  452.             if ScanKeyDown (VK_DOWN)    then xang# = xang# + 1 endif
  453.             
  454.             ' Pgup/Pgdn zoom in/out
  455.             if ScanKeyDOWN (VK_PRIOR)   then zoom# = zoom# - 1 endif
  456.             if ScanKeyDOWN (VK_NEXT)    then zoom# = zoom# + 1 endif
  457.             
  458.             ' Animate
  459.             if not still then
  460.                 theFrameFactor# = theFrameFactor# + animSpeed#
  461.                 if theFrameFactor# >= 1 then
  462.                     theFrameFactor# = theFrameFactor# - 1
  463.                     theFrameNum = theFrameNum2
  464.                     still = true
  465.                 endif
  466.             endif
  467.         wend
  468.     wend
  469.     
  470.     end
  471.  
  472. Instructions:
  473.     TextMode (TEXT_OVERLAID)
  474.     cls
  475.     printr "Arrow keys rotate"
  476.     printr "PgUp/PgDn zooms"
  477.     printr "'A' - 'Z' select frame"
  478.     printr "F1 toggles lighting"
  479.     printr "ENTER for new animation string"
  480.     printr
  481.     if lit then printr "Lighting ON" : else printr "Lighting off": endif
  482.     if anim$ <> "" then 
  483.         printr "Animation string = " + anim$
  484.     endif
  485.     return
  486.     
  487. AnimString:
  488.     TextMode (TEXT_SIMPLE)
  489.     cls
  490.     print "Animation string (letters): "
  491.     anim$ = Input$ ()
  492.     gosub Instructions
  493.     return