PureBasic
;
; OpenGL Демонстрация Гаджетов
;
; (c) Fantaisie Software
;
; Объяснение оси:
;
;             +
;             y
;
;             |
;             |
;  +          |
;  x ---------\
;              \
;               \
;                \ 
;                  z+
;
; Таким образом, поворот по оси y будет принимать ось y как центр. С OpenGL мы можем указать
; положительное и отрицательное значение. Положительные значения всегда в том же смысле,
; что и ось (как описано на schmatic, со знаками "+").
;

Global RollAxisX.f
Global RollAxisY.f
Global RollAxisZ.f

Global RotateSpeedX.f = 1.0
Global RotateSpeedY.f
Global RotateSpeedZ.f = 1.0

Global ZoomFactor.f = 1.0 ; Расстояние до камеры. Отрицательное значение = зум назад

Procedure DrawCube(Gadget)
  SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
  
  glPushMatrix_()                  ; Сохранить исходные координаты матрицы
  glMatrixMode_(#GL_MODELVIEW)

  glTranslatef_(0, 0, ZoomFactor)  ;  Немного подвинем его вперед

  glRotatef_ (RollAxisX, 1.0, 0, 0) ; Вращаем вокруг оси X
  glRotatef_ (RollAxisY, 0, 1.0, 0) ; Вращаем вокруг оси Y
  glRotatef_ (RollAxisZ, 0, 0, 1.0) ; Вращаем вокруг оси Z
 
  RollAxisX + RotateSpeedX 
  RollAxisY + RotateSpeedY 
  RollAxisZ + RotateSpeedZ 

  ; Очистим фрейм-буфер И буфер глубины.

  glClear_ (#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)

  ; Нарисуем грани куба.
  
  ; Нарисуем цветные грани.

  glDisable_(#GL_LIGHTING)
  glBegin_  (#GL_QUADS)
  
  ; Построим грань, состоящую из 4 вершин!
  ; GlBegin () определяет, как рассматриваются вершины. Здесь группа 
  ; из 4-х вершин (GL_QUADS) образует прямоугольную поверхность.

  ; Теперь цвет: это r, v, b, но с плавающими значениями, которые могут 
  ; изменяться от 0.0 до 1.0 (0 - это нуль, а 1.0 - полная интенсивность) 
  
  glNormal3f_ (0,0,1.0)
  glColor3f_  (0,0,1.0)
  glVertex3f_ (0.5,0.5,0.5)   
  glColor3f_  (0,1.0,1.0)         
  glVertex3f_ (-0.5,0.5,0.5)
  glColor3f_  (1.0,1.0,1.0)
  glVertex3f_ (-0.5,-0.5,0.5)
  glColor3f_  (0,0,0)
  glVertex3f_ (0.5,-0.5,0.5) 

  ; Другая грань такая же, как и предыдущая, 
  ; кроме цвета с красивым сине-белым градиентом

  glNormal3f_ (0,0,-1.0)
  glColor3f_  (0,0,1.0)
  glVertex3f_ (-0.5,-0.5,-0.5)
  glColor3f_  (0,0,1.0)
  glVertex3f_ (-0.5,0.5,-0.5)
  glColor3f_  (1.0,1.0,1.0)
  glVertex3f_ (0.5,0.5,-0.5)
  glColor3f_  (1.0,1.0,1.0)
  glVertex3f_ (0.5,-0.5,-0.5)
  
  glEnd_()
  
  ; Рисуем затененные грани.

  glEnable_(#GL_LIGHTING)
  glEnable_(#GL_LIGHT0)
  glBegin_ (#GL_QUADS)

  glNormal3f_ (   0, 1.0,   0)
  glVertex3f_ ( 0.5, 0.5, 0.5)
  glVertex3f_ ( 0.5, 0.5,-0.5)
  glVertex3f_ (-0.5, 0.5,-0.5)
  glVertex3f_ (-0.5, 0.5, 0.5)

  glNormal3f_ (0,-1.0,0)
  glVertex3f_ (-0.5,-0.5,-0.5)
  glVertex3f_ (0.5,-0.5,-0.5)
  glVertex3f_ (0.5,-0.5,0.5)
  glVertex3f_ (-0.5,-0.5,0.5)

  glNormal3f_ (1.0,0,0)
  glVertex3f_ (0.5,0.5,0.5)
  glVertex3f_ (0.5,-0.5,0.5)
  glVertex3f_ (0.5,-0.5,-0.5)
  glVertex3f_ (0.5,0.5,-0.5)

  glNormal3f_ (-1.0,   0,   0)
  glVertex3f_ (-0.5,-0.5,-0.5)
  glVertex3f_ (-0.5,-0.5, 0.5)
  glVertex3f_ (-0.5, 0.5, 0.5)
  glVertex3f_ (-0.5, 0.5,-0.5)

  glEnd_()

  glPopMatrix_()
  glFinish_()

  SetGadgetAttribute(Gadget, #PB_OpenGL_FlipBuffers, #True)
EndProcedure


Procedure SetupGL()
    
  glMatrixMode_(#GL_PROJECTION)
  gluPerspective_(30.0, 200/200, 1.0, 10.0) 
  
  ; Позиция просмотра.
  glMatrixMode_(#GL_MODELVIEW)
  
  glTranslatef_(0, 0, -5.0)
  
  glEnable_(#GL_DEPTH_TEST)   ; Включено, это замедляет рендеринг. Это чтобы быть уверенным,
                              ; чем переданные объекты внутри Z-буфера.
  
  glEnable_(#GL_CULL_FACE)    ; Это увеличит скорость рендеринга, так как вся задняя поверхность 
                              ; будет игнорироваться. Это работает только с CLOSED-объектами, такими как куб
                              ; Одиночные плоскости поверхностей будут видимыми только с одной стороны.
    
  glShadeModel_(#GL_SMOOTH)
EndProcedure


Procedure HandleError (Result, Text$)
  If Result = 0
    MessageRequester("Ошибка", Text$, 0)
    End
  EndIf
EndProcedure

OpenWindow(0, 0, 0, 530, 320, "OpenGL Gadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

OpenGLGadget(0, 10, 10, 200, 200)
SetupGL()

OpenGLGadget(1, 220, 10, 300, 300)
SetupGL()

AddWindowTimer(0, 1, 16) ; Около 60 кадров в секунду

Repeat
  Event = WaitWindowEvent()
  
  Select Event
    Case #PB_Event_Timer
      If EventTimer() = 1
        DrawCube(0)
        DrawCube(1)
      EndIf
  EndSelect
  
Until Event = #PB_Event_CloseWindow