' Gambas module file

'tutorial based on tutorial from NeHe Productions site at http://nehe.gamedev.net/
'visit the page for more info on OpenGL
'
'This tutorial shows how to build 3D world using textured block and defining the building in world.txt file
'To get continuous movement we use timer() and keypress() - keyrelease() functions.
'No collision implemented yet.

' Gambas module file
Const world_x_size As Integer = 16
Const world_y_size As Integer = 16
Const piover180 As Float = 0.0174532925
Private screen As New Window(True) As "Screen"
Private xrot As Float    'X Rotation( NEW )
Private yrot As Float    'Y Rotation( NEW )
Private xspeed As Float  'x rotation speed
Private yspeed As Float  'y rotation speed
' [GB2:ARRD] Private texture As Integer[3]       'storage FOR one texture
Private texture As New Integer[3]       'storage FOR one texture
Private LightAmbient As Float[]
Private LightDiffuse As Float[]
Private LightPosition As Float[]
Private filter As Integer = 0
Private light As Integer = 0
Private blend As Integer = 0
Private walkbias As Float = 0.0
Private walkbiasangle As Float = 0.0
Private lookupdown As Float = 0.0
Private heading As Float
Private xpos As Float
Private zpos As Float
Private mypos_x As Float = 0
Private mypos_z As Float = 20
Private camx As Float = 0.0
Private camy As Float = 0.0
Private camz As Float = 0.0
Private therotate As Float
Private z As Float = - world_x_size - 20.0      'depth into the screen.
Private lp As Integer = 0
Private objlists As Integer
' [GB2:ARRD] Private world As Integer[world_x_size, world_y_size]   'world size 8x8 cube places
Private world As New Integer[world_x_size, world_y_size]   'world size 8x8 cube places
Private up_pressed As Boolean
Private down_pressed As Boolean
Private left_pressed As Boolean
Private right_pressed As Boolean
Private hTimer As New Timer As "Timer1"
Private CTime As Float

Public Sub Main()

  Dim i, j As Integer

  For i = 0 To world_x_size - 1
    For j = 0 To world_y_size - 1
      world[i, j] = 0
    Next
  Next
  
  With screen
    .Width = 800
    .Height = 600
    .Title = MMain.Title
    .Show()
  End With
  
  CTime = Timer()
  hTimer.Delay = 100
  hTimer.Enabled = True

End

Public Sub Screen_Open()
  
  LightAmbient = [0.5, 0.5, 0.5, 1.0]
  LightDiffuse = [1.0, 1.0, 1.0, 1.0]
  LightPosition = [0.0, 0.0, 2.0, 1.0]
  
  Gl.ClearDepth(100.0)                'Enables Clearing Of The Depth Buffer
  gl.ClearColor(0.0, 0.0, 0.0, 0.0)   'This Will Clear The Background Color To Black
  gl.DepthFunc(gl.LESS)            'The Type Of Depth Test To Do
  gl.Enable(gl.DEPTH_TEST)         'Enables Depth Testing
  gl.ShadeModel(gl.SMOOTH)         'Enables Smooth Color Shading
  init()
  
End

Public Sub Screen_resize()

  Gl.Viewport(0, 0, Screen.Width, Screen.Height)
  
  Gl.MatrixMode(Gl.PROJECTION)
  Gl.LoadIdentity()                     'Reset The Projection Matrix
  glu.Perspective(45.0, screen.Width / screen.Height, 0.1, 100.0)   'Calculate The Aspect Ratio Of The Window
  Gl.MatrixMode(Gl.MODELVIEW)
  
End

Public Sub load_world()

  Dim world_file As File
  Dim brick As String
  Dim wall As String
  Dim i, j, k As Integer
  
  world_file = Open "world.txt" For Read
  For i = 0 To world_x_size - 2
    Read #world_file, wall, world_x_size + 1
    For j = 1 To world_y_size
      brick = Mid$(wall, j, 1)
      If brick = "#" Then world[i, j - 1] = 1
    Next
  Next
  Read #world_file, wall, world_x_size
  For j = 1 To world_y_size
    brick = Mid$(wall, j, 1)
    If brick = "#" Then world[world_x_size - 1, j - 1] = 1
  Next
  world_file.Close

End

Public Sub load_texture()

  Dim wall As Image
  Dim floor1 As Image
  Dim ceiling As Image
  Dim egs As Boolean
  
  gl.Enable(gl.TEXTURE_2D)                     ' Enable Texture Mapping
  texture = Gl.GenTextures(3)
  wall = Image.Load("wall.jpeg")
  Gl.BindTexture(Gl.TEXTURE_2D, texture[0])
  Gl.TexImage2D(wall)
  Glu.Build2DMipmaps(wall)
  
  floor1 = Image.Load("floor.png")
  Gl.BindTexture(Gl.TEXTURE_2D, texture[1])
  Gl.TexImage2D(Floor1)
  Glu.Build2DMipmaps(Floor1)
  
  ceiling = Image.Load("ceiling.png")
  Gl.BindTexture(Gl.TEXTURE_2D, texture[2])
  Gl.TexImage2D(ceiling)
  Glu.Build2DMipmaps(ceiling)
  
  Gl.TexParameteri(Gl.TEXTURE_2D, Gl.TEXTURE_MIN_FILTER, Gl.LINEAR_MIPMAP_NEAREST)
  Gl.TexParameteri(Gl.TEXTURE_2D, Gl.TEXTURE_MAG_FILTER, Gl.LINEAR)
  
End

Public Sub init()

  load_world()
  load_texture()
  gl.Enable(gl.TEXTURE_2D)                     ' Enable Texture Mapping( NEW )
  gl.ShadeModel(gl.SMOOTH)                     ' Enable Smooth Shading
  gl.ClearColor(0.0, 0.0, 0.0, 0.0)               ' Black Background
  gl.ClearDepth(2.0)                              ' Depth Buffer Setup
  gl.Enable(gl.DEPTH_TEST)                     ' Enables Depth Testing
  gl.DepthFunc(gl.LESS)                      ' The Type OF Depth Testing TO DO
  gl.MatrixMode(gl.PROJECTION)
  gl.LoadIdentity()                     'Reset The Projection Matrix
  glu.Perspective(45.0, screen.Width / screen.Height, 0.1, 100.0)   'Calculate The Aspect Ratio Of The Window
  gl.MatrixMode(gl.MODELVIEW)
  gl.Lightfv(gl.LIGHT1, gl.AMBIENT, LightAmbient) ' add lighting.(ambient)
  gl.Lightfv(gl.LIGHT1, gl.DIFFUSE, LightDiffuse) ' add lighting.(diffuse).
  gl.Lightfv(gl.LIGHT1, gl.POSITION, LightPosition) ' set light position.
  gl.Enable(gl.LIGHT1)
  objlists = Gl.GenLists(3)
  
  Gl.NewList(objlists, Gl.COMPILE)
  
  gl.BindTexture(gl.TEXTURE_2D, texture[0])         ' SELECT Our Texture
  Gl.Begin(Gl.QUADS)
  gl.Normal3f(0.0, 0.0, 1.0)       'front face
  Gl.TexCoordf(0.0, 1.0)
  Gl.Vertexf(-1.0, 0.0, 1.0)
  Gl.TexCoordf(1.0, 1.0)
  Gl.Vertexf(1.0, 0.0, 1.0)
  Gl.TexCoordf(1.0, 0.0)
  Gl.Vertexf(1.0, 4.0, 1.0)
  Gl.TexCoordf(0.0, 0.0)
  Gl.Vertexf(-1.0, 4.0, 1.0)
  gl.Normal3f(0.0, 0.0, -1.0)      'back face
  Gl.TexCoordf(1.0, 1.0)
  Gl.Vertexf(-1.0, 0.0, -1.0)
  Gl.TexCoordf(1.0, 0.0)
  Gl.Vertexf(-1.0, 4.0, -1.0)
  Gl.TexCoordf(0.0, 0.0)
  Gl.Vertexf(1.0, 4.0, -1.0)
  Gl.TexCoordf(0.0, 1.0)
  Gl.Vertexf(1.0, 0.0, -1.0)
  gl.Normal3f(0.0, 1.0, 0.0)       ' top face - no need for texture
  Gl.Vertexf(-1.0, 4.0, -1.0)
  Gl.Vertexf(-1.0, 4.0, 1.0)
  Gl.Vertexf(1.0, 4.0, 1.0)
  Gl.Vertexf(1.0, 4.0, -1.0)
  gl.Normal3f(0.0, 0.0, 0.0)      'bottom face - no textutre
  Gl.Vertexf(-1.0, 0.0, -1.0)
  Gl.Vertexf(1.0, 0.0, -1.0)
  Gl.Vertexf(1.0, 0.0, 1.0)
  Gl.Vertexf(-1.0, 0.0, 1.0)
  gl.Normal3f(1.0, 0.0, 0.0)       'right face
  Gl.TexCoordf(1.0, 1.0)
  Gl.Vertexf(1.0, 0.0, -1.0)
  Gl.TexCoordf(1.0, 0.0)
  Gl.Vertexf(1.0, 4.0, -1.0)
  Gl.TexCoordf(0.0, 0.0)
  Gl.Vertexf(1.0, 4.0, 1.0)
  Gl.TexCoordf(0.0, 1.0)
  Gl.Vertexf(1.0, 0.0, 1.0)
  gl.Normal3f(-1.0, 0.0, 0.0)      'left face
  Gl.TexCoordf(0.0, 1.0)
  Gl.Vertexf(-1.0, 0.0, -1.0)
  Gl.TexCoordf(1.0, 1.0)
  Gl.Vertexf(-1.0, 0.0, 1.0)
  Gl.TexCoordf(1.0, 0.0)
  Gl.Vertexf(-1.0, 4.0, 1.0)
  Gl.TexCoordf(0.0, 0.0)
  Gl.Vertexf(-1.0, 4.0, -1.0)
  Gl.End()
  
  gl.EndList()
  
  Gl.NewList(objlists + 1, Gl.COMPILE)
  
  gl.BindTexture(gl.TEXTURE_2D, texture[1])         ' SELECT Our Texture
  gl.Begin(gl.QUADS)
  Gl.TexCoordf(0.0, 1.0)
  gl.Vertex3f(-1, 0, world_y_size * 2 - 1)
  Gl.TexCoordf(1.0, 1.0)
  gl.Vertex3f(world_x_size * 2 - 1, 0, world_y_size * 2 - 1)
  Gl.TexCoordf(1.0, 0.0)
  gl.Vertex3f(world_x_size * 2 - 1, 0, 1)
  Gl.TexCoordf(0.0, 0.0)
  gl.Vertex3f(-1, 0, 1)
  gl.End()
  
  Gl.EndList()
  
  Gl.NewList(objlists + 2, Gl.COMPILE)
  
  gl.BindTexture(gl.TEXTURE_2D, texture[2])         ' SELECT Our Texture
  gl.Begin(gl.QUADS)
  Gl.TexCoordf(0.0, 0.0)
  gl.Vertex3f(-1, 4, 1)
  Gl.TexCoordf(0.0, 1.0)
  gl.Vertex3f(world_x_size * 2 - 1, 4, 1)
  Gl.TexCoordf(1.0, 1.0)
  gl.Vertex3f(world_x_size * 2 - 1, 4, world_y_size * 2 - 1)
  Gl.TexCoordf(1.0, 0.0)
  gl.Vertex3f(-1, 4, world_y_size * 2 - 1)
  gl.End()
  
  Gl.EndList()
  
End

Public Sub Screen_draw()

  Dim i, j, k As Integer
  Dim x_m, y_m, z_m, u_m, v_m As Float
  Dim xtrans, ztrans, ytrans As Float
  Dim sceneroty As Float
  
  xtrans = - xpos
  ztrans = - zpos
  ytrans = - walkbias - 0.25
  sceneroty = 360.0 - yrot
  
  gl.LoadIdentity()
  gl.Clear(gl.COLOR_BUFFER_BIT Or gl.DEPTH_BUFFER_BIT)         ' Clear Screen AND Depth Buffer
  
  For i = 0 To world_x_size - 1
    For j = 0 To world_y_size - 1
      k = 0
      k = world[i, j]
      gl.LoadIdentity()
      gl.Rotatef(camy, 0, 1, 0)
      gl.Rotatef(camz, 1, 0, 0)
      gl.Rotatef(lookupdown, 1.0, 0, 0)
      gl.Rotatef(sceneroty, 0, 1.0, 0)
      gl.Translatef(xtrans, ytrans, z + ztrans)
      
      gl.Translatef(j * 2, -2.5, i * 2)
      If k = 1 Then Gl.CallList(objlists)
    Next
  Next
  
  gl.LoadIdentity()
  gl.Rotatef(camy, 0, 1, 0)
  gl.Rotatef(camz, 1, 0, 0)
  gl.Rotatef(lookupdown, 1.0, 0, 0)
  gl.Rotatef(sceneroty, 0, 1.0, 0)
  gl.Translatef(xtrans, ytrans - 2.5, z + ztrans)
  gl.CallList(objlists + 1)
  
  gl.LoadIdentity()
  gl.Rotatef(camy, 0, 1, 0)
  gl.Rotatef(camz, 1, 0, 0)
  gl.Rotatef(lookupdown, 1.0, 0, 0)
  gl.Rotatef(sceneroty, 0, 1.0, 0)
  
  gl.Translatef(xtrans, ytrans - 2.5, z + ztrans)
  gl.CallList(objlists + 2)

End

Public Sub screen_KeyRelease()
  
  up_pressed = False
  down_pressed = False
  left_pressed = False
  right_pressed = False
  
End

Public Sub Screen_keyPress()
  
  If (key.code = key.F1) Then screen.Fullscreen = Not screen.Fullscreen
  If (key.Code = key.Esc) Then Screen.Close()
  If (key.text = "l" Or key.Text = "L") Then
    If lp = 0 Then gl.Enable(gl.LIGHTing)
    If lp = 1 Then gl.Disable(gl.LIGHTing)
    lp = 1 - lp
  Endif
  If (key.code = key.PageUp) Then
    z -= 0.2
    mypos_z = +0.2
    lookupdown -= 0.2
  Endif
  
  If (key.code = key.Pagedown) Then
    z += 0.2
    mypos_z -= 0.2
    lookupdown += 1.0
  Endif
  If (key.code = key.UP) Then up_pressed = True
  If (key.code = key.DOWN) Then down_pressed = True
  If (key.code = key.LEFT) Then left_pressed = True
  If (key.code = key.RIGHT) Then right_pressed = True
  
End

Public Sub Timer1_Timer()

  If up_pressed = True Then
    'IF (world[Round(mypos_x + 0.2), Round(mypos_z + 0.2)] = 0) THEN 
    xpos -= Sin(yrot * piover180) '* 0.5
    'mypos_x += Sin(yrot * piover180) * 0.5 
    zpos -= Cos(yrot * piover180) '* 0.5
    'mypos_z += Cos(yrot * piover180) * 0.5
    If (walkbiasangle >= 359.0) Then
      walkbiasangle = 0.0
    Else
      walkbiasangle += 10
    Endif
    walkbias = Sin(walkbiasangle * piover180) / 20.0
    'ENDIF
  Endif
  
  If down_pressed = True Then
    'IF (world[Round(mypos_x + 0.2), Round(mypos_z + 0.2)] = 0) THEN 
    xpos += Sin(yrot * piover180) '* 0.5
    ' mypos_x -= Sin(yrot * piover180) * 0.5
    zpos += Cos(yrot * piover180) '* 0.5
    'mypos_z -= Cos(yrot * piover180) * 0.5
    If (walkbiasangle <= 1.0) Then
      walkbiasangle = 359.0
    Else
      walkbiasangle -= 10
    Endif
    walkbias = Sin(walkbiasangle * piover180) / 20.0
    'ENDIF   
  Endif
  
  If left_pressed = True Then yrot += 3.5
  If right_pressed = True Then yrot -= 3.5
  
End

'PUBLIC SUB Screen_MouseMove()

'camy += Mouse.Relativex
'camz += Mouse.RelativeY

' END
