#!/usr/bin/env ruby

require 'fox'
require 'opengl'

include Fox

class GLTestWindow < FXMainWindow

  # Draws a simple box using the given corners
  def drawBox(xmin, ymin, zmin, xmax, ymax, zmax)
    GL.Begin(GL::TRIANGLE_STRIP)
      GL.Normal(0.0, 0.0, -1.0)
      GL.Vertex(xmin, ymin, zmin)
      GL.Vertex(xmin, ymax, zmin)
      GL.Vertex(xmax, ymin, zmin)
      GL.Vertex(xmax, ymax, zmin)
    GL.End()
  
    GL.Begin(GL::TRIANGLE_STRIP)
      GL.Normal(1.0, 0.0, 0.0)
      GL.Vertex(xmax, ymin, zmin)
      GL.Vertex(xmax, ymax, zmin)
      GL.Vertex(xmax, ymin, zmax)
      GL.Vertex(xmax, ymax, zmax)
    GL.End()
  
    GL.Begin(GL::TRIANGLE_STRIP)
      GL.Normal(0.0, 0.0, 1.0)
      GL.Vertex(xmax, ymin, zmax)
      GL.Vertex(xmax, ymax, zmax)
      GL.Vertex(xmin, ymin, zmax)
      GL.Vertex(xmin, ymax, zmax)
    GL.End()
  
    GL.Begin(GL::TRIANGLE_STRIP)
      GL.Normal(-1.0, 0.0, 0.0)
      GL.Vertex(xmin, ymin, zmax)
      GL.Vertex(xmin, ymax, zmax)
      GL.Vertex(xmin, ymin, zmin)
      GL.Vertex(xmin, ymax, zmin)
    GL.End()
  
    GL.Begin(GL::TRIANGLE_STRIP)
      GL.Normal(0.0, 1.0, 0.0)
      GL.Vertex(xmin, ymax, zmin)
      GL.Vertex(xmin, ymax, zmax)
      GL.Vertex(xmax, ymax, zmin)
      GL.Vertex(xmax, ymax, zmax)
    GL.End()
  
    GL.Begin(GL::TRIANGLE_STRIP)
      GL.Normal(0.0, -1.0, 0.0)
      GL.Vertex(xmax, ymin, zmax)
      GL.Vertex(xmax, ymin, zmin)
      GL.Vertex(xmin, ymin, zmax)
      GL.Vertex(xmin, ymin, zmin)
    GL.End()
  end

  # Draw the GL scene
  def drawScene
    lightPosition = [15.0, 10.0, 5.0, 1.0]
    lightAmbient  = [ 0.1,  0.1, 0.1, 1.0]
    lightDiffuse  = [ 0.9,  0.9, 0.9, 1.0]
    redMaterial   = [ 1.0,  0.0, 0.0, 1.0]
    blueMaterial  = [ 0.0,  0.0, 1.0, 1.0]
  
    width = @glcanvas.width.to_f
    height = @glcanvas.height.to_f
    aspect = width/height
  
    # Make context current
    @glcanvas.makeCurrent()
    
    GL.Viewport(0, 0, @glcanvas.width, @glcanvas.height)
  
    GL.ClearColor(1.0, 1.0, 1.0, 1.0)
    GL.Clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT)
    GL.Enable(GL::DEPTH_TEST)
    
    GL.Disable(GL::DITHER)
  
    GL.MatrixMode(GL::PROJECTION)
    GL.LoadIdentity()
    GLU.Perspective(30.0, aspect, 1.0, 100.0)
  
    GL.MatrixMode(GL::MODELVIEW)
    GL.LoadIdentity()
    GLU.LookAt(5.0, 10.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
  
    GL.ShadeModel(GL::SMOOTH)
    GL.Light(GL::LIGHT0, GL::POSITION, lightPosition)
    GL.Light(GL::LIGHT0, GL::AMBIENT, lightAmbient)
    GL.Light(GL::LIGHT0, GL::DIFFUSE, lightDiffuse)
    GL.Enable(GL::LIGHT0)
    GL.Enable(GL::LIGHTING)
  
    GL.Material(GL::FRONT, GL::AMBIENT, blueMaterial)
    GL.Material(GL::FRONT, GL::DIFFUSE, blueMaterial)
  
    GL.PushMatrix()
    drawBox(-1, -1, -1, 1, 1, 1)
  
    GL.Material(GL::FRONT, GL::AMBIENT, redMaterial)
    GL.Material(GL::FRONT, GL::DIFFUSE, redMaterial)
  
    GL.PushMatrix()
    GL.Translated(0.0, 1.75, 0.0)
    drawBox(-0.5, -0.5, -0.5, 0.5, 0.5, 0.5)
    GL.PopMatrix()
  
    GL.PushMatrix()
    GL.Translated(0.0, -1.75, 0.0)
    drawBox(-0.5, -0.5, -0.5, 0.5, 0.5, 0.5)
    GL.PopMatrix()
  
    GL.PushMatrix()
    GL.Rotated(90.0, 1.0, 0.0, 0.0)
    GL.Translated(0.0, 1.75, 0.0)
    drawBox(-0.5,-0.5,-0.5,0.5,0.5,0.5)
    GL.PopMatrix()
  
    GL.PushMatrix()
    GL.Rotated(90.0, -1.0, 0.0, 0.0)
    GL.Translated(0.0,1.75,0.0)
    drawBox(-0.5,-0.5,-0.5,0.5,0.5,0.5)
    GL.PopMatrix()
  
    GL.PushMatrix()
    GL.Rotated(90.0, 0.0, 0.0, 1.0)
    GL.Translated(0.0,1.75,0.0)
    drawBox(-0.5,-0.5,-0.5,0.5,0.5,0.5)
    GL.PopMatrix()
  
    GL.PushMatrix()
    GL.Rotated(90.0, 0.0, 0.0, -1.0)
    GL.Translated(0.0,1.75,0.0)
    drawBox(-0.5,-0.5,-0.5,0.5,0.5,0.5)
    GL.PopMatrix()
  
    GL.PopMatrix()
  
    # Swap if it is double-buffered
    @glcanvas.swapBuffers if @glvisual.doubleBuffered?
    
    # Make context non-current
    @glcanvas.makeNonCurrent
  end

  def initialize(app)
    # Invoke the base class initializer
    super(app, "OpenGL Test Application", nil, nil, DECOR_ALL, 0, 0, 800, 600)

    # Construct the main window elements
    scrollWindow = FXScrollWindow.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y)

    # A visual to draw OpenGL
    @glvisual = FXGLVisual.new(getApp(), VISUAL_DOUBLEBUFFER)

=begin
    # Make a layout manager the first child
    fixedSizeFrame = FXPacker.new(scrollWindow, LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT)
    fixedSizeFrame.width  = 1024
    fixedSizeFrame.height = 1024

    # Drawing glcanvas
    @glcanvas = FXGLCanvas.new(fixedSizeFrame, @glvisual, nil, 0,
      LAYOUT_FILL_X|LAYOUT_FILL_Y)
=end

    # Make a layout manager the first child
    canvasFrame = FXPacker.new(scrollWindow, LAYOUT_FILL_X|LAYOUT_FILL_Y)

    # Drawing glcanvas
    @glcanvas = FXGLCanvas.new(canvasFrame, @glvisual, nil, 0,
      LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 1024, 1024)

=begin
    # Drawing glcanvas
    @glcanvas = FXGLCanvas.new(scrollWindow, @glvisual, nil, 0,
      LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0, 0, 1024, 1024)
=end
      
    # Handle expose events on canvas
    @glcanvas.connect(SEL_PAINT) {
      drawScene
    }

    # Handle resize events on canvas
    @glcanvas.connect(SEL_CONFIGURE) { |sender, sel, ptr|
      if @glcanvas.makeCurrent
        GL.Viewport(0, 0, @glcanvas.width, @glcanvas.height)
        @glcanvas.makeNonCurrent
      end
    }
  end

  # Create and initialize
  def create
    super
    show(PLACEMENT_SCREEN)
  end
end

if __FILE__ == $0
  # Construct the application
  application = FXApp.new("GLTest", "FXRuby")
  
  # Construct the main window
  GLTestWindow.new(application)

  # Create the app's windows
  application.create

  # Run the application
  application.run
end
