'a lot of this code has been borrowed from rel's opengl tutorials
DEFINT A - Z
randomize timer

const PI = 3.141593
const SCR_WIDTH = 640
const SCR_HEIGHT = 480
const BITSPP = 32

const maxseg = 2000

'option explicit  

'$include: "\sdl\sdl.bi" 
'$include: "\gl\gl.bi"   
'$include: "\gl\glu.bi"  


DECLARE SUB Init_GL_SDL(SDLscreen as SDL_Surface ptr)
Declare Sub SDL_GetEvents(EscapeVal as Integer)
Declare Sub draw_scene()
Declare Sub Draw_Cube()

declare sub genmap ()    
declare sub rotpnt (x1!, y1!, z1!, rotx!, roty!, rotz!, nx!, ny!, nz!)
declare function u! (an!)


	dim vpage as SDL_Surface ptr            
    dim Finished as integer                 
    
    
    dim shared cs(360) as single, sn(360) as single
    dim shared rx!, ry!, rz!, camx!, camy!, camz!
    
    dim shared segangle(maxseg) as single
dim shared segdata(maxseg, 9) as single
    'xyz increment on the z axis, xyz increment on the x axis, xyz increment on the z axis

dim shared fp, fps, fpsr!, tim#

dim shared nearseg, nearsub
dim shared mapscale!, viewdist,radius!

dim shared tilt!, campitch!, lethrottle!, methrottle!, yheight!
dim shared pathvector(6) as single
    'this contains the nxyz values from the draw routine to compare vs camera
    'angle to turn the camera angle to follow perpendicular to track position
    
dim shared event as SDL_Event, keys as Uint8 ptr

const maxpoly = 20
type pointtype
    x   as single
    y   as single
    z   as single
end type

type polytype
    pnt(3)  as pointtype
    col(3)  as single
end type


type tiletype
    npolies as integer
    polies(maxpoly) as polytype
end type


dim shared tileinfo(1) as tiletype

read npolies
tileinfo(0).npolies = npolies
for i = 0 to npolies - 1
    for a = 0 to 2        
        read tileinfo(0).polies(i).pnt(a).x
        read tileinfo(0).polies(i).pnt(a).y
        read tileinfo(0).polies(i).pnt(a).z
    next
    for a = 0 to 2        
        read tileinfo(0).polies(i).col(a)
    next
next

    
    

radius! = 10

mapscale! = 5
viewdist = 80

'yheight! = .1
camy! = yheight!
camz! = -10

tim# = timer + 1

genmap

maxspeed! = 4
nearseg = 0

tilt! = 0



for i = 0 to 360
    cs(i) = cos(3.141592 / 180 * i)
    sn(i) = sin(3.141592 / 180 * i)
next


    genmap
    
    Init_GL_SDL vpage                       

    Finished = 0                            
	do
	    SDL_GetEvents(Finished)             
        draw_scene                          
		SDL_GL_SwapBuffers                  
		SDL_PumpEvents                      
        
        
        
        tilt! = tilt! - 5 * lethrottle!
    if tilt! > 20 then tilt! = 20
    if tilt! < -20 then tilt! = -20
    
    tilt! = tilt! * .9
    
    ry! = u!(ry! + lethrottle! * 3)
    
    rotpnt 0, 0, 1, 0, ry!, 0, nx!, ny!, nz!
    rotpnt nx!, ny!, nz!, campitch!, 0, 0, nx!, ny!, nz!
    
    camx! = camx! + nx! * speed!
    camy! = camy! + ny! * speed!
    camz! = camz! - nz! * speed!
        
    speed! = speed! + methrottle! * .1
    
    if speed! > maxspeed! then speed! = maxspeed!
    
    speed! = speed! * .99
        
    closer = nearseg
    dist! = 500
    for iter = -5 to 5
    
        a = nearseg + iter
        if a < 0 then a = 0
        if a > maxseg then a = maxseg
        
        ax! = camx! - segdata(a, 0) * mapscale!
        ay! = camy! - segdata(a, 1) * mapscale!        
        az! = camz! - segdata(a, 2) * mapscale!
        
        d1! = sqr(ax! * ax! + ay! * ay! + az! * az!)       
        if d1! < dist! then
            dist! = d1!
            closer = a            
        end if
        
        
    next
    
    nearseg = closer
    ax! = camx! - segdata(nearseg, 0) * mapscale!
    ay! = camy! - segdata(nearseg, 1) * mapscale!        
    az! = camz! - segdata(nearseg, 2) * mapscale!
        
    d1! = sqr(ax! * ax! + ay! * ay! + az! * az!)       
            
    closeness! = .9
    maxd! = radius! * closeness! * 2
    if d1! > maxd! then
        bx! = ax! * maxd! / d1! + segdata(nearseg, 0) * mapscale!
        by! = ay! * maxd! / d1! + segdata(nearseg, 1) * mapscale!
        bz! = az! * maxd! / d1! + segdata(nearseg, 2) * mapscale!
        
        camx! = camx! + (bx! - camx!) * closeness!
        camy! = camy! + (by! - camy!) * closeness!
        camz! = camz! + (bz! - camz!) * closeness!
            
    end if    
    
	loop until Finished

	SDL_Quit                                

    end


data 40
data -1, 0, 1
data -1, 0, 0
data 0, 0, 1
data 0.5, 0.5, 0.5

data 0, 0, 0
data 0, 0, 1
data -1, 0, 0
data 1, 1, 1

data -2, 0, 1
data -2, 0, 0
data -1, 0, 1
data 0.5, 0.5, 0.5

data -1, 0, 0
data -1, 0, 1
data -2, 0, 0
data 0.5, 0.5, 0.5

data -3, 0, 1
data -3, 0, 0
data -2, 0, 1
data 0.5, 0.5, 0.5

data -2, 0, 0
data -2, 0, 1
data -3, 0, 0
data 0.5, 0.5, 0.5

data -4, 0, 1
data -4, 0, 0
data -3, 0, 1
data 0.5, 0.5, 0.5

data -3, 0, 0
data -3, 0, 1
data -4, 0, 0
data 0.5, 0.5, 0.5

data -5, 0, 1
data -5, 0, 0
data -4, 0, 1
data 0.5, 0.5, 0.5

data -4, 0, 0
data -4, 0, 1
data -5, 0, 0
data 0.5, 0.5, 0.5

data -6, 0, 1
data -6, 0, 0
data -5, 0, 1
data 0.5, 0.5, 0.5

data -5, 0, 0
data -5, 0, 1
data -6, 0, 0
data 0.5, 0.5, 0.5

data -7, 0, 1
data -7, 0, 0
data -6, 0, 1
data 0.5, 0.5, 0.5

data -6, 0, 0
data -6, 0, 1
data -7, 0, 0
data 0.5, 0.5, 0.5

data -8, 0, 1
data -8, 0, 0
data -7, 0, 1
data 0.5, 0.5, 0.5

data -7, 0, 0
data -7, 0, 1
data -8, 0, 0
data 0.5, 0.5, 0.5

data -9, 0, 1
data -9, 0, 0
data -8, 0, 1
data 0.5, 0.5, 0.5

data -8, 0, 0
data -8, 0, 1
data -9, 0, 0
data 0.5, 0.5, 0.5

data -10, 1, 1
data -10, 1, 0
data -9, 0, 1
data 0.3, 0.3, 0.3

data -9, 0, 0
data -9, 0, 1
data -10, 1, 0
data 0.3, 0.3, 0.3

'--

data 1, 0, 1
data 1, 0, 0
data 0, 0, 1
data 0.5, 0.5, 0.5

data 0, 0, 0
data 0, 0, 1
data 1, 0, 0
data 1, 1, 1

data 2, 0, 1
data 2, 0, 0
data 1, 0, 1
data 0.5, 0.5, 0.5

data 1, 0, 0
data 1, 0, 1
data 2, 0, 0
data 0.5, 0.5, 0.5

data 3, 0, 1
data 3, 0, 0
data 2, 0, 1
data 0.5, 0.5, 0.5

data 2, 0, 0
data 2, 0, 1
data 3, 0, 0
data 0.5, 0.5, 0.5

data 4, 0, 1
data 4, 0, 0
data 3, 0, 1
data 0.5, 0.5, 0.5

data 3, 0, 0
data 3, 0, 1
data 4, 0, 0
data 0.5, 0.5, 0.5

data 5, 0, 1
data 5, 0, 0
data 4, 0, 1
data 0.5, 0.5, 0.5

data 4, 0, 0
data 4, 0, 1
data 5, 0, 0
data 0.5, 0.5, 0.5

data 6, 0, 1
data 6, 0, 0
data 5, 0, 1
data 0.5, 0.5, 0.5

data 5, 0, 0
data 5, 0, 1
data 6, 0, 0
data 0.5, 0.5, 0.5

data 7, 0, 1
data 7, 0, 0
data 6, 0, 1
data 0.5, 0.5, 0.5

data 6, 0, 0
data 6, 0, 1
data 7, 0, 0
data 0.5, 0.5, 0.5

data 8, 0, 1
data 8, 0, 0
data 7, 0, 1
data 0.5, 0.5, 0.5

data 7, 0, 0
data 7, 0, 1
data 8, 0, 0
data 0.5, 0.5, 0.5

data 9, 0, 1
data 9, 0, 0
data 8, 0, 1
data 0.5, 0.5, 0.5

data 8, 0, 0
data 8, 0, 1
data 9, 0, 0
data 0.5, 0.5, 0.5

data 10, 1, 1
data 10, 1, 0
data 9, 0, 1
data 0.3, 0.3, 0.3

data 9, 0, 0
data 9, 0, 1
data 10, 1, 0
data 0.3, 0.3, 0.3






SUB Init_GL_SDL(SDLscreen as SDL_Surface ptr)

    dim Result as unsigned integer      'checker value for SDL initialization
	dim SDL_flags as integer            'Flags for SDL screen

    'OpenGL params for gluerspective
	dim FOVy as double            'Feild of view angle in Y
	dim Aspect as double          'Aspect of screen
	dim znear as double           'z-near clip distance
	dim zfar as double            'z-far clip distance


    'Let's set up our sdl flags variable

    SDL_flags = SDL_HWSURFACE                   'use Hardware surface
    SDL_flags = SDL_flags or SDL_DOUBLEBUF      'doublebuffer to prevent flicker
    SDL_flags = SDL_flags or SDL_OPENGL         'activate OpenGL
    SDL_flags = SDL_flags or SDL_FULLSCREEN     'FullScreen(REM for windowed)

    'Init everything for SDL(video,audio, key, joy, etc)
	result = SDL_Init(SDL_INIT_EVERYTHING)
	if result <> 0 then                     'error?
  		end 1                               'then quit
	end if

    'Set 640*480*32
    'SCR_WIDTH/HEIGHT/BITSPP are CONSTANTS declared at the main module
	SDLscreen = SDL_SetVideoMode(SCR_WIDTH, SCR_HEIGHT, BITSPP, SDL_flags)
	if SDLscreen = 0 then
		SDL_Quit
		end 1
	end if

	SDL_WM_SetCaption "glflattest", ""       'Make caption if windowed

    'Set OpenGL ViewPort to screen dimensions
	glViewport 0, 0, SCR_WIDTH, SCR_HEIGHT

	'Set current Mode to projection(ie: 3d)
	glMatrixMode GL_PROJECTION

    'Load identity matrix to projection matrix
	glLoadIdentity

    'Set gluPerspective params
    FOVy = 80/2                                     '45 deg fovy
    Aspect = SCR_WIDTH / SCR_HEIGHT                 'aspect = x/y
    znear = 1                                       'Near clip
    zfar = 2000                                      'far clip

    'use glu Perspective to set our 3d frustum dimension up
	gluPerspective FOVy, aspect, znear, zfar

    'Modelview mode
    'ie. Matrix that does things to anything we draw
    'as in lines, points, tris, etc.
	glMatrixMode GL_MODELVIEW
	'load identity(clean) matrix to modelview
	glLoadIdentity

	glShadeModel GL_SMOOTH                 'set shading to smooth(try GL_FLAT)
	glClearColor 0.0, 0.0, 0.0, 0.0        'set Clear color to BLACK
	glClearDepth 1.0                       'Set Depth buffer to 1(z-Buffer)
	glEnable GL_DEPTH_TEST                 'Enable Depth Testing so that our z-buffer works

	'compare each incoming pixel z value with the z value present in the depth buffer
	'LEQUAL means than pixel is drawn if the incoming z value is less than
    'or equal to the stored z value
	glDepthFunc GL_LEQUAL

    'have one or more material parameters track the current color
    'Material is your 3d model
	glEnable GL_COLOR_MATERIAL

	'Tell openGL that we want the best possible perspective transform
	glHint GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST

END SUB


'*******************************************************************************************
'Check for events from SDL
'Params: Escapeval is a byref integer that allows us to
'       quit out mainloop and quit the proggie

Sub SDL_GetEvents(EscapeVal as Integer)
  'SDL event is type in the SDL inc directory
  

        'poll events
    SDL_PollEvent ( @event )
    
    keys = SDL_GetKeyState(null)
			
    methrottle! = 0    
    lethrottle! = 0
    
    if keys[SDLK_ESCAPE] then EscapeVal = 1
    
    if keys[SDLK_W] then lethrottle! = lethrottle! - .5
    if keys[SDLK_L] then lethrottle! = lethrottle! - .5
    if keys[SDLK_S] then lethrottle! = lethrottle! + .5
    if keys[SDLK_O] then lethrottle! = lethrottle! + .5
    
    if keys[SDLK_I] then methrottle! = methrottle! + .5
    if keys[SDLK_E] then methrottle! = methrottle! + .5
    if keys[SDLK_D] then methrottle! = methrottle! - .5
    if keys[SDLK_K] then methrottle! = methrottle! - .5
	'if keys[SDLK_LEFT] then movingleft = 1
	'if keys[SDLK_RIGHT] then movingright = 1
    '
    'if k$ = "w" then 
    'if k$ = "l" then lethrottle! = lethrottle! + .5
    'if k$ = "s" then lethrottle! = lethrottle! - .5
    'if k$ = "o" then lethrottle! = lethrottle! - .5
        
    'if k$ = "j" then 
    'if k$ = "f" then 
    
    'if k$ = "u" then 
    'if k$ = "r" then 
    
    'if k$ = "i" then methrottle! = methrottle! + .5
    'if k$ = "e" then methrottle! = methrottle! + .5
    'if k$ = "d" then methrottle! = methrottle! - .5
    'if k$ = "k" then methrottle! = methrottle! - .5
    
End Sub

'*******************************************************************************************
'Draw to our open GL screen

Sub draw_scene()

    static theta as integer     'Rotation degrees
    dim xtrans   as single      'xtranslation
    dim ytrans   as single      'ytranslation
    dim ztrans   as single      'ztranslation
    dim scalefactor as single   'Scaling factor


    'clear the screen
    'GL_COLOR_BUFFER_BIT = to black(remember glClearColor?)
    'GL_DEPTH_BUFFER_BIT set depth buffer to 1 (remember glClearDepth?)
    glClear  GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT

    'Push matrix to the matrix stack so that we start fresh
    glPushMatrix

    'Reset the matrix to identity
    glLoadIdentity

    'Our translation factor
    'Try to change these arguments
    xtrans = 0.0
    ytrans = 0.0
    ztrans = -10
    glTranslatef xtrans, ytrans, ztrans

    'Our scale factor
    Scalefactor = 1.0


    'glScalef scalefactor, scalefactor, scalefactor
    'Scales our modelview matrix 3x in the x, y, z axes
    'try to change its arguments to different values
    glScalef scalefactor, scalefactor, scalefactor


    'glRotatef angle, x, y, z  rotates your model
    'angle = Specifies the angle of rotation, in degrees
    'x, y, z = Specify the x, y, and z coordinates of a vector
    'So to rotate your 3d object theta degrees in the x axis you would write:
    'we will meke use of some other values for x,y ans z coords in later tutes

    glRotatef u!(5 + tiltb! / 10), 1, 0, 0        
    'glRotatef theta, 0, 1, 0        'rotate in the y axis
    'tiltb! = tilt!
    'glRotatef u!(tiltb!), 0, 0, 1

    Draw_Cube

    glPopMatrix
    Theta = theta + 1
    'Force completion of drawing
    glFlush
end sub


'*******************************************************************************************
'Draw's our a normalized cube. Taken andmodified from NeHe's tutorials(Im lazy so what? ;*))
'NEW!!!!!!
Sub Draw_Cube()


    endseg = nearseg + viewdist
    if endseg > maxseg - 1 then endseg = maxseg - 1
    startseg = nearseg - viewdist
    if startseg < 1 then startseg = 1
        
    dim pnts(3, 3) as single
    
    pullx! = 0
    pully! = 0
    pullz! = 0
    
    a! = tilt!
    tiltb! = u!(a!)
            
    for i = endseg to startseg step -1
                        
        if i = nearseg then
            closer = 0
            dist! = 500
        end if
        
        nx! = segdata(i, 0)
        ny! = segdata(i, 1)
        nz! = segdata(i, 2)
        
        x! = nearsub
        
        xl! = nx! * mapscale! - camx!
        yl! = ny! * mapscale! - camy!
        zl! = nz! * mapscale! - camz!
        xl! = xl! + x! * segdata(i, 3) + y! * segdata(i, 6)
        yl! = yl! + x! * segdata(i, 4) + y! * segdata(i, 7)
        zl! = zl! + x! * segdata(i, 5) + y! * segdata(i, 8)
            
        rotpnt xl!, yl!, zl!, rx!, ry!, 0, nx!, ny!, nz!
        'rotpnt nx!, ny!, nz!, 0, 0, tiltb!, nx!, ny!, nz!            
                                                
        if i = nearseg then
            d1! = sqr(xl! * xl! + yl! * yl! + zl! * zl!)       
            if d1! < dist! then
                dist! = d1!
                closer = a          
            end if
                        
            pathvector(4) = ny!
            campitch! = u!(segangle(i))            
        end if
        
            
                
        npolies = tileinfo(0).npolies
        for ply = 0 to npolies - 1            
        
            for pnt = 0 to 2
                iz = i + tileinfo(0).polies(ply).pnt(pnt).z
                
                nx! = segdata(iz, 0)
                ny! = segdata(iz, 1)
                nz! = segdata(iz, 2)            
                
                x! = tileinfo(0).polies(ply).pnt(pnt).x
                y! = tileinfo(0).polies(ply).pnt(pnt).y
                        
                xl! = nx! * mapscale! - camx!
                yl! = ny! * mapscale! - camy! - 1
                zl! = nz! * mapscale! - camz!
                xl! = xl! - x! * segdata(iz, 3) + y! * segdata(iz, 6)
                yl! = yl! - x! * segdata(iz, 4) + y! * segdata(iz, 7)
                zl! = zl! - x! * segdata(iz, 5) + y! * segdata(iz, 8)
            
                rotpnt xl!, yl!, zl!, rx!, ry!, 0, nx!, ny!, nz!
                rotpnt nx!, ny!, nz!, 0, 0, tiltb!, nx!, ny!, nz!                
                
                pnts(pnt, 0) = nx!
                pnts(pnt, 1) = ny!
                pnts(pnt, 2) = nz!
                
            next                
            
            if nz! < 15 - zback then    
                
                r! = cos((i mod 8) / 8 * 3.14159 * 2) * .15 + .85
                
                glBegin GL_TRIANGLES
                    glColor3f   tileinfo(0).polies(ply).col(0) * r!,  tileinfo(0).polies(ply).col(1) * r!,  tileinfo(0).polies(ply).col(2) * r!
                    glVertex3f  pnts(0,0), pnts(0,1),  pnts(0,2)
                    glVertex3f  pnts(1,0), pnts(1,1),  pnts(1,2)
                    glVertex3f  pnts(2,0), pnts(2,1),  pnts(2,2)
                glEnd

                glBegin GL_LINES
                    glColor3f   tileinfo(0).polies(ply).col(0) * .75 * r!,  tileinfo(0).polies(ply).col(1) * .75 * r!,  tileinfo(0).polies(ply).col(2) * .75 * r!
                    glVertex3f  pnts(0,0), pnts(0,1),  pnts(0,2)
                    glVertex3f  pnts(1,0), pnts(1,1),  pnts(1,2)
                    glVertex3f  pnts(1,0), pnts(1,1),  pnts(1,2)
                    glVertex3f  pnts(2,0), pnts(2,1),  pnts(2,2)
                    glVertex3f  pnts(2,0), pnts(2,1),  pnts(2,2)
                    glVertex3f  pnts(0,0), pnts(0,1),  pnts(0,2)
                glEnd
                
            else
                startseg = i
            end if
            
        next
    next
        
    nearsub = closer
    
    if pathvector(4) + yheight! > 0 then camy! = camy! + (pathvector(4) + yheight!)' * .8
        

End Sub


sub genmap ()    
    
    bx! = 0
    by! = 0
    bz! = 0
    
    yawness = 10
    pitchness = 2
    
    yawan! = 180
    pitchan! = 0
    y! = 0
    
    i = 0
    
    do
        
        yaw! = rnd * yawness - yawness / 2
        pitch! = rnd * pitchness - pitchness / 2
        
        if i > maxseg - 3 then yaw! = 0
        if i < 3 then yaw! = 0
        
        if i > maxseg - 3 then pitch! = 0
        if i < 3 then pitch! = 0
        
        l = int(5) * 2
        for a = 0 to l            
            yawan! = u!(yawan! + yaw!)
            opitch! = pitchan!
            pitchan! = u!(pitchan! + pitch!)
            
            if opitch! > 340 and pitchan! <= 340 then pitchan! = opitch!
            if opitch! < 20 and pitchan! >= 20 then pitchan! = opitch!
            'if pitchan! 
            
            'bx! = bx! + .5 * cos(3.14159 / 180 * yawan!)
            'by! = by! + .5 * sin(3.14159 / 180 * yawan!)
            'y! = y! + .5 * sin(3.14159 / 180 * pitchan!)
            
            i = i + 1
            if i > maxseg then exit do
                        
            rotpnt 2, 0, 0, 0, yawan!, 0, nx!, ny!, nz!
            rotpnt nx!, ny!, nz!, pitchan!, 0, 0, nx!, ny!, nz!
            
            segdata(i, 3) = nx!
            segdata(i, 4) = ny!
            segdata(i, 5) = nz!
            
            rotpnt 0, 2, 0, 0, yawan!, 0, nx!, ny!, nz!
            rotpnt nx!, ny!, nz!, pitchan!, 0, 0, nx!, ny!, nz!
            
            segdata(i, 6) = nx!
            segdata(i, 7) = ny!
            segdata(i, 8) = nz!
            
            rotpnt 0, 0, 1, 0, yawan!, 0, nx!, ny!, nz!
            rotpnt nx!, ny!, nz!, pitchan!, 0, 0, nx!, ny!, nz!
            
            
            segdata(i, 0) = bx! + nx!
            segdata(i, 1) = by! + ny!
            segdata(i, 2) = bz! + nz!
            
            bx! = bx! + nx!
            by! = by! + ny!
            bz! = bz! + nz!
            
            
            segangle(i) = -pitchan!
            'segangle(i, 1) = yawan!
                        
            
        next
        
    loop
    
    
end sub


sub rotpnt (x1!, y1!, z1!, rotx!, roty!, rotz!, nx!, ny!, nz!)
    
    rx = rotx!
    ry = roty!
    rz = rotz!
    
    'x
    nx1! = x1!
    ny1! = z1! * sn(rx) + y1! * cs(rx)
    nz1! = z1! * cs(rx) - y1! * sn(rx)

    'y
    nx2! = nx1! * cs(ry) - nz1! * sn(ry)
    ny2! = ny1!
    nz2! = nx1! * sn(ry) + nz1! * cs(ry)
   
    'z
    nx3! = nx2! * cs(rz) - ny2! * sn(rz)
    ny3! = nx2! * sn(rz) + ny2! * cs(rz)
    nz3! = nz2!

    nx! = nx3!
    ny! = ny3!
    nz! = nz3!
    
end sub


function u! (an!)
    
    while an! > 359: an! = an! - 360: wend
    while an! < 0: an! = an! + 360: wend
    
    u! = an!
    
end function