;;;; Tutorial 01: Hello OpenGL from - https://learnopengl.com/Getting-started/Hello-Triangle
;;;; Original C source: https://learnopengl.com/code_viewer_gh.php?code=src/1.getting_started/2.2.hello_triangle_indexed/hello_triangle_indexed.cpp
;;;; Usage; Recommend using quicklisp and create an ASD file that loads this.
;;;; Dependencies: #:CL-opengl #:bt-semaphore #:Lispbuilder-sdl
(defpackage #:hello-rectangle
(:use #:cl)
(:export :main))
(in-package #:hello-rectangle)
(defparameter *fps* 60)
(defparameter *Width* 640)
(defparameter *height* 480)
(defparameter *vertex-shader-source* "
#version 330 core
layout (location = 0) in vec3 position;
void main(){
gl_Position = vec4(position.x, position.y, position.z, 1.0);
}")
(defparameter *fragment-shader-source* "
#version 330 core
out vec4 color;
void main(){
color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}")
(defparameter *verticies-data* #( 0.5 0.5 0.0 ; Top Right
0.5 -0.5 0.0 ; Bottom Right
-0.5 -0.5 0.0 ; Bottom Left
-0.5 0.5 0.0)); Top Left
(defparameter *indices-data* #(0 1 3 ; First Triangle
1 2 3)) ; Second Triangle
(defparameter *verticies* nil)
(defparameter *indices* nil)
(defparameter *VBO* nil)
(defparameter *VAO* nil)
(defparameter *EBO* nil)
(defparameter *shader-program* nil)
(defun check-shader-error (shader)
"Check for shader compilation errors"
(let ((success (cffi:foreign-alloc :int :initial-element 0)))
(unwind-protect
(progn
(%gl:get-shader-iv shader :compile-status success)
(unless (= (cffi:mem-aref success :int) 1)
(error "OpenGL Shader Error:~%~a~%" (gl:get-shader-info-log shader)))
(cffi:foreign-free success)))))
(defun check-program-error (program)
"Check for linking errors"
(let ((success (cffi:foreign-alloc :int :initial-element 0)))
(unwind-protect
(progn
(%gl:get-program-iv program :link-status success)
(unless (= (cffi:mem-aref success :int) 1)
(error "OpenGL Program Error:~%~a~%" (gl:get-program-info-log program))))
(cffi:foreign-free success))))
(defun setup-program (vertex-Shader Fragment-Shader)
"link and attach the shader programs"
(let ((program (gl:create-program)))
(gl:attach-shader program vertex-shader)
(gl:attach-shader program fragment-shader)
(gl:link-program program)
(check-program-error program)
(setf *shader-program* program)))
(defun setup-shaders ()
"Build and compile the actual shaders"
(let ((vertex-shader (gl:create-shader :vertex-shader))
(fragment-shader (gl:create-shader :fragment-shader)))
;; Vertex shader
(gl:shader-source vertex-shader *vertex-shader-source*)
(gl:compile-shader vertex-shader)
(check-shader-error vertex-shader)
;; Fragment shader
(gl:shader-source fragment-shader *fragment-shader-source*)
(gl:compile-shader fragment-shader)
(check-shader-error fragment-shader)
(setup-program vertex-shader fragment-shader)
(gl:delete-shader vertex-shader)
(gl:delete-shader fragment-shader)))
(defun setup-vertex-attributes ()
"Set up vertex data (and buffer(s)) and configure vertex attributes"
(setf *VBO* (gl:gen-buffer))
(setf *vao* (gl:gen-vertex-array))
(setf *EBO* (gl:gen-buffer))
;; Convert CL arrays into an C arrays
(setf *verticies*
(loop :with gl-array = (gl:alloc-gl-array :float (length *verticies-data*))
:for i :below (length *verticies-data*)
:do (setf (gl:glaref gl-array i) (aref *verticies-data* i))
:finally (return gl-array))
*indices*
(loop :with gl-array = (gl:alloc-gl-array :unsigned-int (length *indices-data*))
:for i :below (length *indices-data*)
:do (setf (gl:glaref gl-array i) (aref *indices-data* i))
:finally (return gl-array)))
(gl:bind-vertex-array *vao*)
(gl:bind-buffer :array-buffer *vbo*)
(gl:buffer-data :array-buffer :static-draw *verticies*)
(gl:bind-buffer :element-array-buffer *ebo*)
(gl:buffer-data :element-array-buffer :static-draw *indices*)
(gl:vertex-attrib-pointer 0 3 :float nil (* 3 (cffi:foreign-type-size :float)) 0)
(gl:enable-vertex-attrib-array 0)
(gl:bind-buffer :array-buffer 0)
(gl:bind-vertex-array 0))
(defun init-openGL ()
"Gets openGL ready"
(gl:clear-color .2 .3 .3 1.0)
;;(gl:polygon-mode :front-and-back :line)
(setup-shaders)
(setup-vertex-attributes)
)
(defun rendering ()
"Displays the actual rectangle"
(gl:clear :color-buffer-bit)
(gl:use-program *shader-program*)
(gl:bind-vertex-array *vao*)
(%gl:draw-elements :triangles 6 :unsigned-int 0)
(gl:bind-vertex-array 0)
(sdl:update-display))
(defun freeing-memory ()
"Clear allocated memory"
(gl:free-gl-array *verticies*)
(gl:free-gl-array *indices*)
(gl:delete-vertex-arrays '(*vao*))
(gl:delete-buffers '(*vbo* *ebo* ))
(gl:delete-program *shader-program*))
(defun main (&aux (title "Hello Rectangle"))
(bt:make-thread
(lambda ()
(sdl:with-init ()
(unwind-protect ; ensures proper error handling in-case of crash
(sdl:window *width* *height* :title-caption title :flags '(sdl:sdl-opengl)) ; Window creation with opengl rendering
(setf (sdl:frame-rate) *fps*)
(sdl:enable-key-repeat 100 1)
(setf cl-opengl-bindings:*gl-get-proc-address* #'sdl-cffi::sdl-gl-get-proc-address) ; overwrite SDL's rendering with CL-opengl's.
(init-openGL)
(sdl:with-events ()
(:quit-event () t)
(:idle ()
(rendering)))
(freeing-memory)))) ;; Freeing the memory after program terminates
:name title))