'Option Explicit

#include once "model_module.bi"
#include once "GL/gl.bi" 
#include once "GL/glu.bi"
#include once "gl/glfw.bi"
#include once "gl/glext.bi"


Sub Render_Model( Byval Model As Model3D Ptr, Texture() As Gluint )
    Dim As Integer s, t, p
'    GlEnable GL_BLEND
'    GlBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
    
    For s = 0 To Model->max_surfaces - 1
        'bindtexture here...
        GlEnable GL_TEXTURE_2D
        glBindTexture (GL_TEXTURE_2D, Texture(model->surfaces[s].Texture_ID))
        
        Dim AS RGBAlpha Ambient =(.75,.75,.75,1)
        Dim AS RGBAlpha Diffuse =(.5,.5,.5,1)
        Dim AS RGBAlpha Specular =(.5,.5,.5,1)
        
        'GlColor4Fv( @model->surfaces[s].RGBAlpha.R )
        glMaterialfv GL_FRONT, GL_AMBIENT,   @Ambient.R
        glMaterialfv GL_FRONT, GL_DIFFUSE,   @Diffuse.R
        glMaterialfv GL_FRONT, GL_SPECULAR,  @Specular.R
        glMaterialf  GL_FRONT, GL_SHININESS, 50

        'set surface attributes here.
        'For instance...
        'GlColor4Fv @(entity.model->surfaces[s].RGBAlpha.r)
        Glbegin(GL_TRIANGLES)
        For t = model->surfaces[s].Start_ID To model->surfaces[s].End_ID
            'for flat shading
            'If Shade_Mode = GL_FLAT Then GlNormal3Fv( @Model->triangles[t].Normal.X )
            For p = 1 To 3
                Gltexcoord2fv (@model->triangles[t].texcoord(p).u)
                'for smooth shading...
                'If Shade_Mode = GL_SMOOTH Then 
                glNormal3fv(@model->vnormals[model->triangles[t].point_id(p)].x)
                glVertex3fv(@model->vertices[model->triangles[t].point_id(p)].x)
            Next p
        Next t
        Glend()
    Next s
End Sub



Sub Render_Model_Shadow( Byval Model As Model3D Ptr )
    Dim As Integer s, t, p
    For s = 0 To Model->max_surfaces - 1
        Glbegin(GL_TRIANGLES)
        For t = model->surfaces[s].Start_ID To model->surfaces[s].End_ID
            'for flat shading
            'GlNormal3Fv( @Model->triangles[t].Normal.X )
            For p = 1 To 3
                glNormal3fv(@model->vnormals[model->triangles[t].point_id(p)].x)
                glVertex3fv(@model->vertices[model->triangles[t].point_id(p)].x)
            Next p
        Next t
        Glend()
    Next s
End Sub



Sub LoadMesh( Byref Model As Model3D Ptr, Byval Filename As String, Byval Texture_Offset As Integer, Texture() As Gluint )
    Dim As String FileRec
    Dim As Integer i
    Dim As Uinteger FileID = Freefile
    Dim As Uinteger vertex_counter
    Dim As Uinteger triangle_counter
    Dim As Uinteger uv_counter
    Dim As Uinteger Current_Group
    Dim As Uinteger Reset_Position
    Dim As String   Surf_Name
    Dim As Integer  Surf_Cnt
    Dim As Integer  Found_Start_ID
    Dim As Integer  Add_Face
    
    Dim As String Store_Name(200)
    
    For i = 0 To 200
        Store_Name(i) = ""
    Next
    
    If Model Then 
        Beep
        Print "Model already allocated!!!"
        Exit Sub
    End If
    
    Model = Callocate( Sizeof( Model3D ))
    
    Open Filename For Binary As #FileID
    
    GetSurfaces( FileID, Store_Name() )
    Surf_Name = Store_Name(0)
    Do
        Do
            Line Input #FileID, FileRec
            
            'Allocate our vertices
            If Instr( FileRec, "Vertices:" ) Then
                Model->max_vertices  = Val(Mid$(FileRec, Instr( FileRec, "Vertices:" ) + 10 ))
                Model->vertices      = Callocate( Model->max_vertices * Sizeof( Vector3D ) )
                Model->vNormals      = Callocate( Model->max_vertices * Sizeof( Vector3D ) )
            End If
            
            'Allocate our triangles
            If Instr( FileRec, "Faces:" ) Then
                Model->max_triangles = Val(Mid$(FileRec, Instr( FileRec, "Faces:" ) + 7 ))
                Model->triangles     = Callocate( Model->max_triangles * Sizeof( Triangle3D ) )
            End If
            
            'Allocate our surfaces, or materials as LW calls them
            If Instr( FileRec, "Materials:" ) Then
                Model->max_surfaces  = Val(Mid$(FileRec, Instr( FileRec, "Materials:" ) + 11 ))
                Model->surfaces      = Callocate( Model->max_surfaces * Sizeof( Surface3D ) )
            End If
            
            
            If Instr( FileRec, "#	               Face list" ) Then
                Reset_Position = Seek( FileID )
                
            End If
            
            
            'used later for sorting materials
            'this will allow us to bunch all the triangles that...
            'use the same texture into one block
            'then, we don't have to call glbindtexture nearly as much
            If Mid$( FileRec, 1, 6 ) = "usemtl" Then
                Current_Group = Val( Mid$( FileRec, 7 ) )
                Add_Face = False
                If FileRec = Surf_Name Then 
                    Add_Face = True
                    If Not Found_Start_ID Then
                        Model->Surfaces[Surf_Cnt].Start_ID = Triangle_Counter
                        Found_Start_ID = TRue
                    End If
                    Model->Surfaces[Surf_Cnt].Texture_ID = Current_Group + Texture_Offset
                End If
            End If
            
            
            Select Case Mid$( FileRec, 1, 2 )
            
            Case "v "
                'process a vertex here
                'vertices are loaded straight into an array by themselves.
                Dim As Integer space_counter = 0
                For i = 1 To Len( FileRec )
                    If Mid$(FileRec, i, 1) = " " Then 
                        space_counter+=1
                        Select Case As Const space_counter
                        Case 1
                            'first space  = X
                            Model->vertices[vertex_counter].x = Val(Mid$( FileRec, i+1 ) )
                        Case 2
                            'second space = Y
                            Model->vertices[vertex_counter].y = Val(Mid$( FileRec, i+1 ) )
                        Case 3
                            'third space  = Z
                            Model->vertices[vertex_counter].z = Val(Mid$( FileRec, i+1 ) )
                        End Select
                    End If
                Next
                vertex_counter+=1 'increment the vertex array counter
                
                
            Case "vt"
                If Add_Face Then
                    'process a texture uv here
                    'they are actually listed before the faces that they belong to.
                    'In otherwords, the uvs we are about to load, 
                    'belong to the triangle we will load next.
                    'So, our uv_counter cycles from 1 to 3
                    Dim As Integer space_counter = 0
                    uv_counter  = (uv_counter Mod 3) + 1
                    For i = 1 To Len( FileRec )
                        If Mid$(FileRec, i, 1) = " " Then 
                            space_counter+=1
                            Select Case As Const space_counter
                            Case 1
                                'first space  = U
                                Model->triangles[triangle_counter].texcoord(4-uv_counter).u = Val(Mid$( FileRec, i+1 ) )
                            Case 2
                                'second space = V
                                Model->triangles[triangle_counter].texcoord(4-uv_counter).v = Val(Mid$( FileRec, i+1 ) )
                            End Select
                        End If
                    Next
                End If
            Case "f "
                If Add_Face Then
                    'process a triangle/face here.
                    'Subtract one since this is an index to a pointer array.
                    'Model->triangles[triangle_counter].Group = Current_Group
                    Dim As Integer space_counter = 0
                    For i = 1 To Len( FileRec )
                        If Mid$(FileRec, i, 1) = " " Then 
                            space_counter+=1
                            Model->triangles[triangle_counter].point_id(space_counter) = Val(Mid$( FileRec, i+1 ) )-1
                        End If
                    Next
                    triangle_counter+=1 'increment the triangle index counter
                End If
            End Select
            
            
        Loop While Not Eof(FileID)
        Model->Surfaces[Surf_Cnt].End_ID = Triangle_Counter-1
        Surf_Cnt+=1
        Found_Start_ID = False
        If Surf_Cnt < Model->Max_Surfaces Then
            Seek FileID, Reset_Position
            Surf_Name = Store_Name(Surf_Cnt)
        End If
    Loop While Not Eof(FileID)
    Close #FileID
    
    Calc_Planes( Model )
    Calc_Normals( Model )
    
End Sub


Sub GetSurfaces( Byval FileID As Uinteger, Store_Name() As String )
    Dim As String FileRec
    Dim As Integer i, Surf_Cntr
    
    Do While Not Eof(FileID)
        Line Input #FileID, FileRec
        
        If Mid$( FileRec, 1, 6 ) = "usemtl" Then
            Dim As Integer Skip_Add = False
            
            For i = 0 To Ubound(Store_Name)
                If FileRec = Store_Name(i) Then Skip_Add = True
            Next
            
            If Skip_Add = False Then
                Store_Name(Surf_Cntr) = FileRec
                Surf_Cntr+=1
            End If
        End If
        
    Loop
    Seek FileID, 1
End Sub


Sub Calc_Normals( Byref Model As Model3D Ptr )
    Dim vTriangle(1 To 3) As Vector3D, Normal As Vector3D
    Dim i As Integer, i2 As Integer
    
    For i = 0 To Model->max_triangles -1
        For i2 = 1 To 3     
            vTriangle(i2).X = Model->vertices[Model->triangles[i].point_Id(i2)].X
            vTriangle(i2).Y = Model->vertices[Model->triangles[i].point_Id(i2)].Y
            vTriangle(i2).Z = Model->vertices[Model->triangles[i].point_Id(i2)].Z
        Next
        
        Poly_Normal Vtriangle(), Normal
        Model->triangles[i].Normal.X = Normal.X
        Model->triangles[i].Normal.Y = Normal.Y
        Model->triangles[i].Normal.Z = Normal.Z
        
        For i2 = 1 To 3
             Model->vnormals[Model->triangles[i].point_Id(i2)] + = Normal
            'Model->vnormals[Model->triangles[i].point_Id(i2)].X = Model->vnormals[Model->triangles[i].point_Id(i2)].X + Normal.X
            'Model->vnormals[Model->triangles[i].point_Id(i2)].Y = Model->vnormals[Model->triangles[i].point_Id(i2)].Y + Normal.Y
            'Model->vnormals[Model->triangles[i].point_Id(i2)].Z = Model->vnormals[Model->triangles[i].point_Id(i2)].Z + Normal.Z
        Next
    Next
    
    For i = 0 To Model->max_triangles -1
        For i2 = 1 To 3
            Vector_Normalize Model->vnormals[Model->triangles[i].point_Id(i2)]
        Next
    Next
End Sub


Sub Calc_Planes( Byref Model As Model3D Ptr )
    Dim As Integer i
    Dim v1 As Vector3D, V2 As Vector3D, V3 As Vector3D
    
    
    For i = 0 To Model->max_triangles-1
        V1.X = Model->vertices[Model->triangles[i].point_Id(1)].X
        V1.y = Model->vertices[Model->triangles[i].point_Id(1)].Y
        V1.Z = Model->vertices[Model->triangles[i].point_Id(1)].Z
        
        V2.X = Model->vertices[Model->triangles[i].point_Id(2)].X
        V2.y = Model->vertices[Model->triangles[i].point_Id(2)].Y
        V2.Z = Model->vertices[Model->triangles[i].point_Id(2)].Z
        
        V3.X = Model->vertices[Model->triangles[i].point_Id(3)].X
        V3.y = Model->vertices[Model->triangles[i].point_Id(3)].Y
        V3.Z = Model->vertices[Model->triangles[i].point_Id(3)].Z
        
        Model->triangles[i].Plane.a = v1.y * (v2.z-v3.z) + v2.y * (v3.z-v1.z) + v3.y * (v1.z-v2.z)
        Model->triangles[i].Plane.b = v1.z*(v2.x-v3.x) + v2.z*(v3.x-v1.x) + v3.z*(v1.x-v2.x)
        Model->triangles[i].Plane.c = v1.x*(v2.y-v3.y) + v2.x*(v3.y-v1.y) + v3.x*(v1.y-v2.y)
        Model->triangles[i].Plane.d = -( v1.x*( v2.y*v3.z - v3.y*v2.z ) + v2.x*(v3.y*v1.z - v1.y*v3.z) + v3.x*(v1.y*v2.z - v2.y*v1.z) )
    Next
End Sub


Sub UnloadMesh( Byref Model As Model3D Ptr )
    Model->max_vertices  = 0
    Model->max_triangles = 0
    Model->max_surfaces  = 0
    Deallocate( Model->vertices )
    Deallocate( Model->vNormals )
    Model->vertices = 0
    Deallocate( Model->triangles )
    Model->triangles = 0
    Deallocate( Model->surfaces )
    Model->max_surfaces = 0
    Deallocate( Model )
    Model = 0
End Sub
