#include "fbgfx.bi"

#ifdef __FB_JS__
  extern "C"
    function  fb_hGetWindowHandle() as any ptr : return 0 : end function
    function fb_hGetDisplayHandle() as any ptr : return 0 : end function
  end extern
#endif

'#define UseGL

var iGfxFlags = fb.GFX_HIGH_PRIORITY or fb.GFX_SHAPED_WINDOW
dim as long DeskWid=any,DeskHei=any : screeninfo DeskWid,DeskHei

#ifdef UseGL
  screencontrol fb.SET_GL_2D_MODE , fb.OGL_2D_MANUAL_SYNC 'OGL_2D_AUTO_SYNC '
  iGfxFlags xor = (fb.GFX_OPENGL or fb.GFX_SHAPED_WINDOW)    
#endif
#ifdef __FB_JS__
  DeskHei = (DeskHei*11)\12
#endif

screenres DeskHei, DeskHei, 8,2,iGfxFlags
#if defined(UseGL) or defined(__FB_JS__)    
    palette 0,0,0,0
#else
    palette 0,255,0,255 
#endif
window screen(-2,-2)-(2,2) 

' Bayer 8x8 matrix for dithering
dim shared as integer bayer8(63) = { _
     0, 48, 12, 60,  3, 51, 15, 63, 32, 16, 44, 28, 35, 19, 47, 31, _
     8, 56,  4, 52, 11, 59,  7, 55, 40, 24, 36, 20, 43, 27, 39, 23, _
     2, 50, 14, 62,  1, 49, 13, 61, 34, 18, 46, 30, 33, 17, 45, 29, _
    10, 58,  6, 54,  9, 57,  5, 53, 42, 26, 38, 22, 41, 25, 37, 21 }
dim as string sPattern = space(64)

' Vertices of the cube
dim as double v(7, 2) = { _
    {-1, -1, -1}, {1, -1, -1}, {1, 1, -1}, {-1, 1, -1}, _
    {-1, -1,  1}, {1, -1,  1}, {1, 1,  1}, {-1, 1,  1} }

' Winding order (Counter-Clockwise for front faces)
dim as integer f(5, 3) = { _
    {0, 1, 2, 3}, {7, 6, 5, 4}, {3, 2, 6, 7}, {0, 4, 5, 1}, {2, 1, 5, 6}, {0, 3, 7, 4} }

dim as integer baseCols(5, 2) = { _
    {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0}, {255, 0, 255}, {0, 255, 255} }

dim as double dStart = timer
dim as double angleX, angleY, rx(7), ry(7), rz(7), px(7), py(7)
dim as long iPage

screenset iPage,iPage xor 1

do  
    'screenlock
    
    cls
    var dNow = timer
    angleX = (dNow-dStart)*.5
    angleY = angleX*0.77
    
    ' Rotate Vertices
    for i as integer = 0 to 7
        dim as double x = v(i,0), y = v(i,1), z = v(i,2)
        dim as double tx = x * cos(angleY) + z * sin(angleY)
        dim as double tz = -x * sin(angleY) + z * cos(angleY)
        rx(i) = tx : rz(i) = y * sin(angleX) + tz * cos(angleX)
        ry(i) = y * cos(angleX) - tz * sin(angleX)
        dim as double factor = 32 / (32 + rz(i))
        px(i) = rx(i) * factor : py(i) = ry(i) * factor
    next i

    ' Z-Sort faces
    dim as integer faceOrder(5) = {0, 1, 2, 3, 4, 5}
    for i as integer = 0 to 4
        for j as integer = i + 1 to 5
            if (rz(f(faceOrder(i),0))+rz(f(faceOrder(i),1))+rz(f(faceOrder(i),2))+rz(f(faceOrder(i),3))) < _
               (rz(f(faceOrder(j),0))+rz(f(faceOrder(j),1))+rz(f(faceOrder(j),2))+rz(f(faceOrder(j),3))) then
                swap faceOrder(i), faceOrder(j)
            end if
        next j
    next i

    ' Render
    for i as integer = 0 to 5
        dim as integer idx = faceOrder(i)
        dim as integer i0 = f(idx,0), i1 = f(idx,1), i2 = f(idx,2)
        
        ' Normal Calculation
        dim as double ux = rx(i1)-rx(i0), uy = ry(i1)-ry(i0), uz = rz(i1)-rz(i0)
        dim as double vx = rx(i2)-rx(i0), vy = ry(i2)-ry(i0), vz = rz(i2)-rz(i0)
        dim as double nx = uy*vz - uz*vy, ny = uz*vx - ux*vz, nz = ux*vy - uy*vx
        
        ' Culling: only draw if normal points towards camera
        if nz > 0 then
            'dim as double intensity = (nz / sqr(nx*nx + ny*ny + nz*nz)) * 0.8 + 0.2
            'palette idx + 1, baseCols(idx,0)*intensity, baseCols(idx,1)*intensity, baseCols(idx,2)*intensity
            dim as double intensity = (nz / sqr(nx*nx + ny*ny + nz*nz))
            dim as integer threshold = int(intensity * 64+.5)
            for N as long = 0 to 63
                sPattern[N] = iif(bayer8(N) < threshold, idx + 9, 16)
            next N
            
            dim as single x1 = px(f(idx,0)), y1 = py(f(idx,0))
            dim as single x2 = px(f(idx,1)), y1b = py(f(idx,1))
            dim as single x3 = px(f(idx,2)), y2 = py(f(idx,2))
            dim as single x4 = px(f(idx,3)), y3 = py(f(idx,3))
            
            ' Draw edges (as border)
            line (x1, y1)-(x2, y1b), 255
            line -(x3, y2), 255
            line -(x4, y3), 255
            line -(x1, y1), 255
            
            ' Paint fill
            if threshold > 3 then
              paint ((x1+x2+x3+x4)/4, (y1+y1b+y2+y3)/4), sPattern, 255            
            end if
            
            line (x1, y1)-(x2, y1b), idx + 1
            line -(x3, y2), idx + 1
            line -(x4, y3), idx + 1
            line -(x1, y1), idx + 1
        end if
    next i
    
    'if point(-2,-2) then continue do    
    iPage xor= 1 : screenset iPage,iPage xor 1
    #ifdef UseGL
        flip
    #endif
    'screensync
    
loop until multikey(1)
