.x Microsoft Direct X XoF loader

Everything related to 3D programming
miso
Enthusiast
Enthusiast
Posts: 712
Joined: Sat Oct 21, 2023 4:06 pm
Location: Hungary

.x Microsoft Direct X XoF loader

Post by miso »

For exporting to ogre mesh:
More description in the header.

Code: Select all

;=====================================
;.x (microsoft direct x XOF) loader.
;Created by miso
;Usage policy 777, do what you please
;No warranties whatsoever.
;
;This is not a parser, but a quick and dirty hack
;to get the mesh data from a xof file. 
;I post this, as it surprisingly performed well with 95% of my .x meshes.
;
;Works with :
;-text format .x
;-single mesh
;
;-if submeshes are presented, only the last one will be loaded
;-animations might be presented, but will be skipped
;This tool is mainly for loading meshes and export it with savemesh() to native ogre
;if you lack an exporter, or have to deal with different exporters winding issues programmatically first.

;NOTE: If you improve this in any way, please consider reposting. Thanks.

;NOTE: After this I started to make a tokenizer that could even extract bone and animation data,
;I finished the tokenizer part, idents, lbrace, rbrace, int, float, string, etc
;but got distracted so I don't know when will I deal with the mesh assembly part.
;It's not advised, but if you need that and got strength to fiddle with it, pm me. Will send you the tokenizer part.
;I also could not managed to use zlib inflate, it will be required for the binary parse.
;(I'm not good with linking/debugging external libraries.)

UseJPEGImageDecoder()
UsePNGImageEncoder()
Structure vertex
  x.f : y.f : z.f : nx.f : ny.f : nz.f : u.f : v.f
EndStructure
  
Structure face
  v.i : a.i : b.i : c.i : d.i
EndStructure
  
;===========================================
;Windowed fullscreen quickstart for 3d
;===========================================
Procedure ministart3d(wTitle.s)
  InitEngine3D():InitSprite():InitKeyboard():InitMouse():UsePNGImageDecoder():UsePNGImageEncoder():UseJPEGImageDecoder():UseJPEGImageEncoder()
  ExamineDesktops()
  OpenWindow(0, 0, 0, DesktopUnscaledX(DesktopWidth(0)), DesktopUnscaledY(DesktopHeight(0)), wTitle, #PB_Window_ScreenCentered|#PB_Window_BorderLess|#PB_Window_Invisible)
  OpenWindowedScreen(WindowID(0), 0, 0, WindowWidth(0) * DesktopResolutionX() , WindowHeight(0) * DesktopResolutionY(), 0, 0, 0, #PB_Screen_WaitSynchronization)
  CreateCamera(0,0,0,100,100)
  CameraBackColor(0,RGB(0,0,0))
  CreateLight(0,RGB(255,255,255),-50,50,0,#PB_Light_Point)
  RenderWorld()
  HideWindow(0,#False)
EndProcedure

  
;===========================================
;Quickly handles flipbuffers, window events, 
;keyboard and mouse, esc And mouse middle 
;quits For short programs/tests
;===========================================
Procedure minicheckevents()
  FlipBuffers()
  While WindowEvent() : Wend
  ClearScreen(RGBA(0,0,0,255)) ;Linux Fix at the moment
  ExamineKeyboard()
  ExamineMouse()
  MouseDeltaX()                ;Linux Fix at the moment
  If KeyboardPushed(#PB_Key_Escape) Or MouseButton(#PB_MouseButton_Middle) : End : EndIf
 EndProcedure
 
 Procedure.s fixstring(s.s)
    Protected temp.s
    temp.s = UCase(s.s)
    temp.s = ReplaceString(temp.s,"MESH ","MESH$")
    temp.s = ReplaceString(temp.s," ","")
    temp.s = ReplaceString(temp.s,Chr(9),"")
    
    ProcedureReturn temp.s
  EndProcedure
  
   Procedure loadx(filename.s)
    Protected fID.i
    Protected sread.s
    Protected vcount.i
    Protected fcount.i
    Protected Dim vertices.vertex(0)
    Protected Dim faces.face(0)
    Protected fval.i

    
    fID =OpenFile(#PB_Any,filename)
    Repeat
      sread = fixstring ( ReadString(fID) )
    
      If Left(sread,5)="MESH$"
        sread = fixstring( ReadString(fid) )
        If sread ="{" : sread = fixstring( ReadString(fid) ) : EndIf
        vcount = Val(StringField(sread,1,";"))
        Debug vcount
        Dim vertices.vertex(vcount-1)
        For i = 0 To vcount-1
          sread = fixstring( ReadString(fid) )
          vertices(i)\x = ValF(StringField(sread,1,";"))
          vertices(i)\y = ValF(StringField(sread,2,";"))
          vertices(i)\z = ValF(StringField(sread,3,";"))
          ;Debug vertices(i)\x
        Next i
        
        sread = fixstring( ReadString(fid) )
        fcount = Val(StringField(sread,1,";"))
        Dim faces.face(fcount)
        Debug fcount
        For i = 0 To fcount-1
          sread = fixstring( ReadString(fid) )
          fval = Val(StringField(sread,1,";"))
          faces(i)\v = fval
          sread = StringField(sread,2,";")
          If fval = 3
            faces(i)\a = Val(StringField(sread,1,","))
            faces(i)\b = Val(StringField(sread,2,","))
            faces(i)\c = Val(StringField(sread,3,","))
          Else
            faces(i)\a = Val(StringField(sread,1,","))
            faces(i)\b = Val(StringField(sread,2,","))
            faces(i)\c = Val(StringField(sread,3,","))
            faces(i)\d = Val(StringField(sread,4,","))
          EndIf
        Next i
      EndIf
      
      If Left(sread,11)="MESHNORMALS"
        ;often buggy, so it will be generated instead
        Repeat
          sread = fixstring( ReadString(fid) )
        Until Left(sread,1)="}"
      EndIf
        
      If Left(sread,8)="MESHTEXT"
        sread = fixstring( ReadString(fid) )
        If sread ="{" : sread = fixstring( ReadString(fid) ) : EndIf

        Debug Val(StringField(sread,1,";"))
        
          
        If vcount = Val(StringField(sread,1,";"))
          Debug "OK==========================="
          For i = 0 To vcount-1
            sread = fixstring( ReadString(fid) )
            vertices(i)\u = ValF(StringField(sread,1,";"))
            vertices(i)\v = ValF(StringField(sread,2,";"))
            Debug "----"
          Next i
        Else
          Debug "NOT OK==========================="
          vcount = Val(StringField(sread,1,";"))
          For i = 0 To vcount-1
            sread = fixstring( ReadString(fid) )
            vertices(i)\u = ValF(StringField(sread,1,";"))
            vertices(i)\v = ValF(StringField(sread,2,";"))
            Debug "----"
          Next i
        EndIf
      EndIf
    Until Eof(fid)
    CloseFile(fid)
    m_id = CreateMesh(#PB_Any,#PB_Mesh_TriangleList)
    
    For i = 0 To vcount-1
      index = i
      MeshVertex(vertices(index)\x,vertices(index)\y,vertices(index)\z,vertices(index)\u,vertices(index)\v,vertices(index)\nx,vertices(index)\ny,vertices(index)\nz,RGB(255,255,255))
      Debug vertices(index)\u
      Debug vertices(index)\v
      
    Next i
    
    For i = 0 To fcount-1
      If faces(i)\v = 3
        MeshFace(faces(i)\a,faces(i)\b,faces(i)\c)
      ElseIf faces(i)\v = 4
        MeshFace(faces(i)\c,faces(i)\b,faces(i)\a)
        MeshFace(faces(i)\a,faces(i)\d,faces(i)\c)
      EndIf
    Next i
    FinishMesh(#True)
    NormalizeMesh(m_id)
    BuildMeshTangents(m_id)
    Debug fcount
    Debug vcount
    ProcedureReturn m_id
  EndProcedure
   
   
ministart3d("Xof Loader")

MoveCamera(0,0,0,-50)
CameraLookAt(0,0,0,0)
Add3DArchive("shaders",#PB_3DArchive_FileSystem)
Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Main", #PB_3DArchive_FileSystem)
Parse3DScripts()


;-model name
knotmesh = loadx("model.x")
LoadTexture(1,"texture.png")
CreateMaterial(2,TextureID(1))


;Some mesh exported with a bad exporter. Uncheck culling to see faulty mesh.
;MaterialCullingMode(2,#PB_Material_NoCulling)
CreateEntity(1,MeshID(knotmesh),MaterialID(2))

speed = 2
  Repeat
    minicheckevents()
    If KeyboardPushed(#PB_Key_W)
      MoveCamera(0,0,0,-speed,#PB_Relative)
    ElseIf KeyboardPushed(#PB_Key_S)
      MoveCamera(0,0,0,speed,#PB_Relative)
    EndIf
    
    If KeyboardPushed(#PB_Key_A)
      RotateCamera(0,0,0.5,0,#PB_Relative)
    ElseIf KeyboardPushed(#PB_Key_D)
      RotateCamera(0,0,-0.5,0,#PB_Relative)
    EndIf

    
    RotateEntity(1,0,0.1,0,#PB_Relative)
    RenderWorld()
ForEver  
  
  
  
  
User avatar
skinkairewalker
Addict
Addict
Posts: 829
Joined: Fri Dec 04, 2015 9:26 pm

Re: .x Microsoft Direct X XoF loader

Post by skinkairewalker »

That's amazing, congratulations!

I was thinking about creating something for .x and .b3x.

I'm going to focus more on .b3d.

THANKS :D
User avatar
minimy
Addict
Addict
Posts: 894
Joined: Mon Jul 08, 2013 8:43 pm
Location: off world

Re: .x Microsoft Direct X XoF loader

Post by minimy »

Wow miso! very nice code, as allways.
Thank you very much for share.
If translation=Error: reply="Sorry, Im Spanish": Endif
threedslider
Enthusiast
Enthusiast
Posts: 610
Joined: Sat Feb 12, 2022 7:15 pm

Re: .x Microsoft Direct X XoF loader

Post by threedslider »

Awesome stuff, thank you for sharing !
miso
Enthusiast
Enthusiast
Posts: 712
Joined: Sat Oct 21, 2023 4:06 pm
Location: Hungary

Re: .x Microsoft Direct X XoF loader

Post by miso »

Thanks friends. I hope there will be some use of it. If you have to change the handedness, switch y and z, then multiply the new z with -1. Might require different triangle order. Not tested.
Post Reply