' ---------------------------------------------------
' Wavefront OBJ Importer v.1 (02.10.01)
'                               (C) Odyseja|DDD 2001
' by Bartek Dabkowski          http://ddd.odyseja.pl
' bartekd@odyseja.pl              kontakt@odyseja.pl
' ---------------------------------------------------
'
'   Description:
'     This little scripty parses Wavefront OBJ files
'     and builds corresponding geometry.
'
'   Features:
'     Imports polygon meshes
'     Currently ignores all other data (ex. UV)
'       and can mess up when some non-standard
'       indexing is used in the OBJ
'
' ---------------------------------------------------


Option Explicit

SetLocale(1033)

'---------------
'Global variables:

dim g_VERTEX_COUNTER, g_FACE_COUNTER, g_UV_COUNTER

'geometry data counters
g_VERTEX_COUNTER = 0
g_FACE_COUNTER = 0
g_UV_COUNTER = 0

'vertex and face counters
dim g_VC, g_FC
g_VC = 0
g_FC = 0

'geometry tag
dim g_TAG
g_TAG = ""

'---------------
'Launch!

wavefront_import

'---------------
' Procedure:
'   wavefront_import
'
' Description:
'   Main script routine

sub wavefront_import
  dim filename
  dim vertex_array(), face_array(), uv_array()

  filename = "C:\filename.obj"
  filename = inputbox ( "OBJ filename", "Wavefront OBJ Import", filename )
  filename = trim(filename)

  if parse_objfile(filename, vertex_array, face_array, uv_array) = False then
    logmessage "Bad OBJ file : "&filename, 2
    exit sub
  end if
  
  logmessage "Done"
  
end sub

'---------------
' Procedure:
'   build_polymesh
'
' Description:
'   Creates a polygon mesh using vertex and face data arrays

sub build_polymesh(in_vtxarray, in_farray)
  dim root, obj

  if Len(g_TAG) = 0 then g_TAG = "OBJImport"

  logmessage "Building polygon mesh: "& g_TAG &" ["& g_FC &" polygons]"
  
  set root = application.activeproject.activescene.root
  set obj = root.AddPolygonMesh( in_vtxarray, in_farray, g_TAG )  

end sub


'---------------
' Procedure:
'   parse_objfile
'
' Description:
'   Reads OBJ file line by line updating vertex, face, (soon) uv data structures

function parse_objfile(in_fname, out_v, out_f, out_uv)
  const ForReading = 1, ForWriting = 2, ForAppending = 8
  dim fso, objfile
  
  dim obj_line
  dim line_arr, face_arr
  
  set fso = CreateObject("Scripting.FileSystemObject")
  
  set objfile = fso.OpenTextFile(in_fname, ForReading)
  
  dim line_count
  line_count = 0
  
  do until objfile.AtEndOfStream
    obj_line = objfile.ReadLine
    obj_line = Trim(obj_line)
    if NOT Left(obj_line, 1) = "#" AND Len(obj_line) > 0 then
      line_arr = split(obj_line)
      Select Case line_arr(0)
        Case "v"
          if NOT parse_vertex(line_arr, out_v) then
            parse_objfile = False
            exit function
          end if
        Case "f"
          if NOT parse_face(line_arr, out_f) then
            parse_objfile = False
            exit function
          end if
        Case "g"
          g_TAG = line_arr(1)
          if g_FACE_COUNTER <> 0 then
            build_polymesh out_v, out_f
          end if
          g_FACE_COUNTER = 0
          g_UV_COUNTER = 0
          g_FC = 0
        Case Else
          'do nothing        
      End Select
    end if    
    line_count = line_count + 1
    if line_count MOD 1000 = 0 then
      logmessage "read: " & line_count & " lines"
    end if
  loop

  objfile.Close

  build_polymesh out_v, out_f

  parse_objfile = True
end function


'---------------
' Procedure:
'   parse_vertex
'
' Description:
'   reads each vertex data line, into vertex data array

function parse_vertex(in_vtxarray, out_vtxarray)
  redim preserve out_vtxarray(g_VERTEX_COUNTER + 3)

  out_vtxarray(g_VERTEX_COUNTER) = in_vtxarray(1)
  out_vtxarray(g_VERTEX_COUNTER + 1) = in_vtxarray(2)
  out_vtxarray(g_VERTEX_COUNTER + 2) = in_vtxarray(3)

  g_VERTEX_COUNTER = g_VERTEX_COUNTER + 3
  g_VC = g_VC + 1

  parse_vertex = True
end function

'---------------
' Procedure:
'   parse_face
'
' Description:
'   reads each face data line (currently UV data is ommitted),
'   into polygon data array, prepared for AddPolygonMesh method

function parse_face(in_farray, out_farray)
  dim i, c
  dim tridata

  c = ubound(in_farray)

  g_FACE_COUNTER = g_FACE_COUNTER + c + 1

  redim preserve out_farray(g_FACE_COUNTER)

  out_farray(g_FACE_COUNTER - c - 1) = c
  
  for i = 0 to c-1
    if NOT InStr(1,in_farray(i+1),"/") = 0 then
      tridata = split(in_farray(i+1), "/")
      out_farray(g_FACE_COUNTER - c + i) = tridata(0)-1
    else
      out_farray(g_FACE_COUNTER - c + i) = in_farray(i+1)-1
    end if
  next

  g_FC = g_FC + 1

  parse_face = True
end function


