defint a-z
randomize timer

'this includes all our declarations for the non Tree related routines
#include once "syn3d.bi"

declare sub drawTree ()
declare sub generateTree ()

DIM SHARED pnt(4,7) as single, pntf(4, 2) as single

CONST MAX_NODES = 13, MAX_BRANCHES = 13, MAX_LEAVES = 10, MAX_SEGS = 3

type pointType
    x   as single
    y   as single
    z   as single
end type

TYPE nodeType
  x AS SINGLE
  y AS SINGLE
  z AS SINGLE
  globalNode    as integer
  plane(MAX_SEGS - 1) as pointType
  connected as integer
END TYPE

TYPE nodeAngleType
  x AS SINGLE
  y AS SINGLE
  z AS SINGLE
end type

TYPE branchType
  nNodes  AS INTEGER
  nodes(MAX_NODES) as nodeType
  nodeAngle(MAX_NODES) as nodeAngleType
  root  as nodeType
END TYPE

type leafType
    x   as single
    y   as single
    z   as single
    size    as single
end type

DIM SHARED branches(MAX_BRANCHES) AS branchType, leaves(MAX_LEAVES) AS leafType, nBranches
DIM SHARED rotSpd!, scaleSpd!, leafscale!

DIM SHARED barkTex as gluint, leafTex as gluint
DIM SHARED barkTex2 as gluint

init

load_texture "bark.png", barkTex
load_textureAlpha "leaves.png", leafTex

generateTree
main

sub generateTree ()
    
    sag! = 20
    growth! = 0
    scale! = .5
    leafscale! = 4
    
    twistyness = 30
    nleaves = 0
    nBranches = MAX_BRANCHES
    totalNodes = MAX_NODES
    baseBranches = 1
    
    trunkLength = 4
    twigLength = 1.5
    branchLengthInter! = (twigLength - trunkLength) / totalNodes
    
    
    trunkWidth = 1.4
    twigWidth = 0
    branchWidthInter! = (twigWidth - trunkWidth) / totalNodes
    
    for branch = 0 to nBranches - 1
        for i = 0 to totalNodes - 1
            branches(branch).nodes(i).globalNode = 0
            branches(branch).nodeAngle(i).x = 0
            branches(branch).nodeAngle(i).y = 0
            branches(branch).nodeAngle(i).z = 0
            branches(branch).nodes(i).x = 0
            branches(branch).nodes(i).y = 0
            branches(branch).nodes(i).z = 0
        next
        do
            parentBranch = int(rnd * branch)
            if baseBranches > 0 then parentBranch = -1
            parentNode = -1
            if parentBranch > -1 then
                parentNode = int(rnd * branches(parentBranch).nNodes)
                branches(branch).root.x = branches(parentBranch).nodes(parentNode).x
                branches(branch).root.y = branches(parentBranch).nodes(parentNode).y
                branches(branch).root.z = branches(parentBranch).nodes(parentNode).z
                branches(branch).nodeAngle(0).x = branches(parentBranch).nodeAngle(parentNode).x
                branches(branch).nodeAngle(0).y = branches(parentBranch).nodeAngle(parentNode).y + rnd * 180 - 90
                branches(branch).nodeAngle(0).z = branches(parentBranch).nodeAngle(parentNode).z
                globalNode = branches(parentBranch).nodes(parentNode).globalNode
            else
                branches(branch).root.x = 0
                branches(branch).root.y = 0
                branches(branch).root.z = 0
                branches(branch).nodeAngle(0).x = 0
                branches(branch).nodeAngle(0).y = rnd * 360
                branches(branch).nodeAngle(0).z = 0
                globalNode = 0
                baseBranches = baseBranches - 1
            end if
            nNodes = totalNodes - globalNode
            branches(branch).nNodes = nNodes
            
            if nNodes > 0 and parentNode <> 0 then exit do
        loop
        
        ox! = branches(branch).root.x
        oy! = branches(branch).root.y
        oz! = branches(branch).root.z
        for node = 0 to nNodes - 1
            globalNode = globalNode + 1
            rx! = branches(branch).nodeAngle(node).x + rnd * twistyness - twistyness / 2
            ry! = branches(branch).nodeAngle(node).y + rnd * twistyness - twistyness / 2
            rz! = branches(branch).nodeAngle(node).z + rnd * twistyness - twistyness / 2
            rz! = rz! + rnd * sag! * rz! / 90 + sag! / 5
            rz! = rz! - rnd * growth! * rz! / 90 - growth! / 5
            rotpnt 0, (trunkLength + globalNode * branchLengthInter!) * scale!, 0, 0, 0, rz!, nx!, ny!, nz!
            rotpnt nx!, ny!, nz!, rx!, 0, 0, nx!, ny!, nz!
            rotpnt nx!, ny!, nz!, 0, ry!, 0, nx!, ny!, nz!
            branches(branch).nodes(node).x = ox! + nx!
            branches(branch).nodes(node).y = oy! + ny!
            branches(branch).nodes(node).z = oz! + nz!
            branches(branch).nodeAngle(node+1).x = rx!
            branches(branch).nodeAngle(node+1).y = ry!
            branches(branch).nodeAngle(node+1).z = rz!
            branches(branch).nodes(node).globalNode = globalNode
            branches(branch).nodes(node).connected = branches(branch).nodes(node).connected + 1
            ox! = branches(branch).nodes(node).x
            oy! = branches(branch).nodes(node).y
            oz! = branches(branch).nodes(node).z
            
            for p = 0 to MAX_SEGS - 1
                rotpnt 0, 0, (trunkWidth * cos(3.14159 / 2 * globalNode / totalNodes)) * scale!, 0, p * 360/MAX_SEGS, 0, nx!, ny!, nz!
                rotpnt nx!, ny!, nz!, 0, 0, rz!, nx!, ny!, nz!
                rotpnt nx!, ny!, nz!, rx!, 0, 0, nx!, ny!, nz!
                rotpnt nx!, ny!, nz!, 0, ry!, 0, nx!, ny!, nz!
            
                branches(branch).nodes(node).plane(p).x = ox! + nx!
                branches(branch).nodes(node).plane(p).y = oy! + ny!
                branches(branch).nodes(node).plane(p).z = oz! + nz!
            next
            
        next
    next    
    
    
    for leaf = 0 to MAX_LEAVES
        try = 0
        do
            try = try + 1
            if try = 100 then exit do
            branch = int(rnd * nBranches)
            node = int(rnd * branches(branch).nNodes)
            globalNode = branches(branch).nodes(node).globalNode
            pass = 0
            if globalNode > MAX_NODES / 2 and globalNode < MAX_NODES - 1 then pass = 1
            for i = 0 to leaf - 1
                ff = 0
                if leaves(i).x = branches(branch).nodes(node).x then ff = ff + 1
                if leaves(i).y = branches(branch).nodes(node).y then ff = ff + 1
                if leaves(i).z = branches(branch).nodes(node).z then ff = ff + 1
                if ff = 3 then pass = 0
            next
            if pass = 1 then exit do
            
        loop
        
        leaves(leaf).x = branches(branch).nodes(node).x
        leaves(leaf).y = branches(branch).nodes(node).y
        leaves(leaf).z = branches(branch).nodes(node).z
        leaves(leaf).size = branches(branch).nodes(node).connected
        if leaves(leaf).size > 2 then leaves(leaf).size = 2
    next

end sub

sub init ()
    
    SDL_FLAGS = SDL_HWSURFACE OR SDL_OPENGL OR SDL_GL_DOUBLEBUFFER
    'SDL_FLAGS = SDL_FLAGS OR SDL_FULLSCREEN
    
    if SDL_Init(SDL_INIT_EVERYTHING) <> 0 THEN end 1
    
    selectRes
    
    video = SDL_SetVideoMode (SCR_WIDTH, SCR_HEIGHT, SCR_BITS, SDL_FLAGS)
    if video = 0 then
        SDL_Quit
        end 1
    end if
    
    
    SDL_WM_SetCaption "display", ""
    
    glViewport 0, 0, SCR_WIDTH, SCR_HEIGHT
    glMatrixMode GL_PROJECTION
    glLoadIdentity
    
    FOVy = 40
    aspect! = SCR_WIDTH / SCR_HEIGHT
    znear! = .1
    zfar! = 1000
    
    gluPerspective FOVy, aspect!, znear!, zfar!
    glMatrixMode GL_MODELVIEW
    glLoadIdentity
    
    
    glShadeModel GL_SMOOTH
    glClearColor .5, .5, .5, 1
    glClearDepth 1.0
    glEnable GL_DEPTH_TEST
    glDepthFunc GL_LEQUAL
    glEnable GL_COLOR_MATERIAL
    glHint GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST
    
    lightAmbient(0) = .2
    lightAmbient(1) = .2
    lightAmbient(2) = .2
    lightAmbient(3) = 1
    
    lightDiffuse(0) = 1
    lightDiffuse(1) = 1
    lightDiffuse(2) = .9
    lightDiffuse(3) = 1
    
    lightSpecular(0) = lightDiffuse(0)
    lightSpecular(1) = lightDiffuse(1)
    lightSpecular(2) = lightDiffuse(2)
    lightSpecular(3) = 1
        
    lightEmission(0) = 0
    lightEmission(1) = 0
    lightEmission(2) = 0
    lightEmission(3) = 1
    
    glEnable GL_LIGHTING
    glLightModelfv GL_LIGHT_MODEL_AMBIENT, @lightAmbient(0)
    glShadeModel GL_SMOOTH
    
    lightPosition(0) = 0
    lightPosition(1) = 20
    lightPosition(2) = 0
    
    glLightfv GL_LIGHT1, GL_AMBIENT, @lightAmbient(0)
    glLightfv GL_LIGHT1, GL_DIFFUSE, @lightDiffuse(0)
    glLightfv GL_LIGHT1, GL_SPECULAR, @lightSpecular(0)
    glLightfv GL_LIGHT1, GL_POSITION, @lightPosition(0)
    
    glEnable GL_LIGHT1
    glEnable GL_COLOR_MATERIAL    
    glColorMaterial GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE
    
    glMaterialfv GL_FRONT_AND_BACK, GL_SPECULAR, @lightSpecular(0)
    glMaterialfv GL_FRONT_AND_BACK, GL_EMISSION, @lightEmission(0)
    glMaterialf GL_FRONT_AND_BACK, GL_SHININESS, 75
    
    lightAmbient(0) = 0
    lightAmbient(1) = 0
    lightAmbient(2) = 0
    lightAmbient(3) = 1
    
    lightDiffuse(0) = 1 / 2
    lightDiffuse(1) = 1 / 2
    lightDiffuse(2) = .9 / 2
    lightDiffuse(3) = 1
    
    lightSpecular(0) = lightDiffuse(0)
    lightSpecular(1) = lightDiffuse(1)
    lightSpecular(2) = lightDiffuse(2)
    lightSpecular(3) = 1
    
    glLightfv GL_LIGHT2, GL_AMBIENT, @lightAmbient(0)
    glLightfv GL_LIGHT2, GL_DIFFUSE, @lightDiffuse(0)
    glLightfv GL_LIGHT2, GL_SPECULAR, @lightSpecular(0)
    
        
    glEnable GL_LIGHT1
    glEnable GL_LIGHTING
    
    glCullFace GL_BACK
    glEnable GL_CULL_FACE
    glEnable GL_TEXTURE_2D
    
    glHint GL_LINE_SMOOTH_HINT, GL_NICEST
    if linesmoothing then glEnable GL_LINE_SMOOTH
    'glLineWidth 2
    
    'glBlendFunc GL_SRC_ALPHA, GL_ONE
    glBlendFunc GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA
    glAlphaFunc GL_GREATER, .5
    glEnable GL_BLEND
    glEnable GL_ALPHA_TEST
    
    glEnable GL_RESCALE_NORMAL
    
    
    yheight = 5
    
    xres = SCR_WIDTH
    yres = SCR_HEIGHT
    xcen = xres / 2
    ycen = yres / 2
    
    xzratio! = xres / 1.6
    yzratio! = yres / 1.6
    
    camx = 0
    camy = 0
    'camz = 15
    
    rad = 3.141592 / 180
    zback = 50
    
    rotSpd! = .05
    scaleSpd! = .01
    
    camrx = 20
    
    glLoadIdentity
    
end sub



sub main ()

    fpsr = 1
    waitticks = ticks + 1000
    do
        
        checkinputs        
        drawview
        
        SDL_GL_SwapBuffers
        SDL_PumpEvents
        
        tickspassed = ticks
        ticks = SDL_GetTicks
        
        tickspassed = ticks - tickspassed
        fpsr = (fpsr + tickspassed / 20) / 2
    
        fp = fp + 1
        if ticks > nextticks then
            nextticks = ticks + 1000
            fps = fp
            fp = 0
        end if

        locate 1,1:print fps
        
        
        'body.yangle = body.yangle + 1
        'if body.yangle >= 360 then body.yangle = body.yangle - 360
        
    loop
    
end sub

sub checkinputs ()
    
    keys = SDL_GetKeyState(null)
    if keys[SDLK_ESCAPE] then deinit
    
    while SDL_PollEvent(@event)
        if event.type = SDL_EXIT then deInit
    wend
    
    if keys[SDLK_LEFT] then camry -= rotSpd!
    if keys[SDLK_RIGHT] then camry += rotSpd!

    if keys[SDLK_DOWN] then camrx += rotSpd!
    if keys[SDLK_UP] then camrx -= rotSpd!
    
    if keys[SDLK_KP_PLUS] then zback -= scaleSpd!
    if keys[SDLK_KP_MINUS] then zback += scaleSpd!
    
    if keys[SDLK_RETURN] and waitTicks < ticks then
        generateTree
        waitTicks = ticks + 150
    end if

end sub


sub drawTree ()
    
    glBindTexture GL_TEXTURE_2D, barkTex
    
    glColor3f 1, 1, 1
    for pass = 0 to 1
        if pass = 0 then glBegin GL_TRIANGLES
        if pass = 1 then glBegin GL_QUADS
            
        for branch = 0 to nBranches - 1
            nNodes = branches(branch).nNodes
            for node = 0 to nNodes - 1
                for p = 0 to MAX_SEGS - 1
                    n = p + 1
                    if n = MAX_SEGS then n = 0
                    pntf(0,0) = branches(branch).nodes(node).plane(n).x
                    pntf(0,1) = branches(branch).nodes(node).plane(n).y
                    pntf(0,2) = branches(branch).nodes(node).plane(n).z
                    n = p
                    pntf(3,0) = branches(branch).nodes(node).plane(n).x
                    pntf(3,1) = branches(branch).nodes(node).plane(n).y
                    pntf(3,2) = branches(branch).nodes(node).plane(n).z
                    
                    nn = node - 1
                    if nn > -1 then
                        n = p + 1 
                        if n = MAX_SEGS then n = 0
                        pntf(1,0) = branches(branch).nodes(nn).plane(n).x
                        pntf(1,1) = branches(branch).nodes(nn).plane(n).y
                        pntf(1,2) = branches(branch).nodes(nn).plane(n).z
                        n = p
                        pntf(2,0) = branches(branch).nodes(nn).plane(n).x
                        pntf(2,1) = branches(branch).nodes(nn).plane(n).y
                        pntf(2,2) = branches(branch).nodes(nn).plane(n).z
                        refs = 4
                    else
                        pntf(1,0) = branches(branch).root.x
                        pntf(1,1) = branches(branch).root.y
                        pntf(1,2) = branches(branch).root.z
                        refs = 3
                    end if
                    
                    cross2 pntf(0, 0), pntf(0, 1), pntf(0, 2), pntf(1, 0), pntf(1, 1), pntf(1, 2), pntf(3, 0), pntf(3, 1), pntf(3, 2), nx!, ny!, nz!
                    glNormal3f nx!, ny!, nz!
                    
                    if refs = 3 and pass = 0 then
                        'triangle
                        glTexCoord2f 0, 0
                        glVertex3f pntf(0,0), pntf(0,1), pntf(0,2)
                        glTexCoord2f .5, 1
                        glVertex3f pntf(1,0), pntf(1,1), pntf(1,2)
                        glTexCoord2f 1, 0
                        glVertex3f pntf(3,0), pntf(3,1), pntf(3,2)
                    elseif refs = 4 and pass = 1 then
                        'quad
                        glTexCoord2f 0, 0
                        glVertex3f pntf(0,0), pntf(0, 1), pntf(0,2)
                        glTexCoord2f 0, 1
                        glVertex3f pntf(1,0), pntf(1, 1), pntf(1,2)
                        glTexCoord2f 1, 1
                        glVertex3f pntf(2,0), pntf(2, 1), pntf(2,2)
                        glTexCoord2f 1, 0
                        glVertex3f pntf(3,0), pntf(3, 1), pntf(3,2)
                        
                    end if
                next
            next
        next
        
        glEnd
    next
    
    
    'draw the leaf planes:
    pnt(0,0) = .5
    pnt(0,1) = -.5
    pnt(1,0) = .5
    pnt(1,1) = .5
    pnt(2,0) = -.5
    pnt(2,1) = .5
    pnt(3,0) = -.5
    pnt(3,1) = -.5
    
    glDisable GL_LIGHTING
    glBindTexture GL_TEXTURE_2D, leafTex
    glColor4f 1, 1, 1, .8
    for leaf = 0 to MAX_LEAVES
        glPushMatrix
        glTranslatef leaves(leaf).x, leaves(leaf).y, leaves(leaf).z
        glRotatef camrz, 0, 0, -1
        glRotatef camry, 0, 1, 0
        glRotatef camrx, -1, 0, 0
    
        
        for p = 0 to 3
            pntf(p, 0) = pnt(p,0) * leaves(leaf).size * leafscale!
            pntf(p, 1) = pnt(p,1) * leaves(leaf).size * leafscale!
            pntf(p, 2) = 0
        next
        
        glBegin GL_QUADS
            glTexCoord2f 0, 0
            glVertex3f pntf(0,0), pntf(0, 1), pntf(0,2)
            glTexCoord2f 0, 1
            glVertex3f pntf(1,0), pntf(1, 1), pntf(1,2)
            glTexCoord2f 1, 1
            glVertex3f pntf(2,0), pntf(2, 1), pntf(2,2)
            glTexCoord2f 1, 0
            glVertex3f pntf(3,0), pntf(3, 1), pntf(3,2)
        glEnd
        glPopMatrix
        
    next
    glEnable GL_LIGHTING
    
end sub

sub drawview ()
    
    dim dataset as objectinfo ptr
    
    glPolygonMode GL_FRONT_AND_BACK, GL_FILL
    
    glClear  GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT
    
    glLoadIdentity
    
    glTranslatef 0, -yheight, -zback
    
    glRotatef camrx, 1, 0, 0
    glRotatef camry, 0, -1, 0
    glRotatef camrz, 0, 0, 1
    
    glLightfv GL_LIGHT1, GL_POSITION, @lightPosition(0)
    
    glTranslatef -camx, -camy, -camz
    
    glPushMatrix
    
    'draw something
    drawTree
    
    glDisable GL_LIGHTING
    glDisable GL_TEXTURE_2D
    glBegin GL_POINTS
        glColor3f 1, 1, 1
        for x = -10 to 10
            for z = -10 to 10
                glVertex3f x, 0, z
            next
        next
    glEnd
    
    glEnable GL_LIGHTING
    glEnable GL_TEXTURE_2D
    
    glPopMatrix
    
    glFlush
    
    
end sub


