Skip to content

Instantly share code, notes, and snippets.

@GOFAI
Created October 16, 2017 06:18
Show Gist options
  • Save GOFAI/e77a06de8124ddd82facc6f8f19499ce to your computer and use it in GitHub Desktop.
Save GOFAI/e77a06de8124ddd82facc6f8f19499ce to your computer and use it in GitHub Desktop.
Example of OpenGL 4.1 in Cocoa in Clozure Common Lisp using ObjC Bridge
(defpackage :color-triangle-demo)
(in-package :color-triangle-demo)
(require 'cl-opengl)
(require 'cl-glu)
;;; needed to run at full resolution in Retina display
(objc:defmethod (#/setWantsBestResolutionOpenGLSurface: :void)
((self ns:ns-object) (value :<BOOL>)))
;;; borrowed from CCL opengl demo
(defun new-pixel-format (&rest attributes)
;; take a list of opengl pixel format attributes (enums and other
;; small ints), make an array (character array?), and create and
;; return an NSOpenGLPixelFormat
(let* ((attribute-size (ccl::foreign-size #>NSOpenGLPixelFormatAttribute :bytes))
(nattributes (length attributes)))
(ccl::%stack-block ((objc-attributes (* attribute-size (1+ nattributes))))
(loop for i from 0 to nattributes
for attribute in attributes do
(setf (ccl:paref objc-attributes (:* #>NSOpenGLPixelFormatAttribute) i)
attribute) ; <- autocoerced?
finally (setf
(ccl:paref objc-attributes
(:* #>NSOpenGLPixelFormatAttribute) nattributes) 0))
(make-instance ns:ns-opengl-pixel-format :with-attributes objc-attributes))))
(defclass color-triangle-view (ns:ns-opengl-view)
((vbuff :accessor vertex-buffer)
(cbuff :accessor color-buffer)
(vs :accessor vertex-shader)
(fs :accessor fragment-shader)
(va :accessor vertex-array)
(program :accessor program))
(:metaclass ns:+ns-object))
(defvar *triangle-vertex-program*
"#version 410
layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec3 vertex_colour;
out vec3 color;
void main() {
color = vertex_colour;
gl_Position = vec4(vertex_position, 1.0);
}")
(defvar *triangle-fragment-program*
"#version 410
in vec3 color;
out vec4 frag_colour;
void main() {
frag_colour = vec4 (color, 1.0);
}")
(defun make-color-triangle-view ()
(let ((view (make-instance 'color-triangle-view)))
(#/setPixelFormat: view (new-pixel-format #$NSOpenGLPFAOpenGLProfile
#$NSOpenGLProfileVersion3_2Core
#$NSOpenGLPFADoubleBuffer
#$NSOpenGLPFAColorSize 32
#$NSOpenGLPFADepthSize 8))
(#/setWantsBestResolutionOpenGLSurface: view 1) ; Retina display
(#/autorelease view)))
(objc:defmethod (#/prepareOpenGL :void) ((self color-triangle-view))
(ccl:rlet ((swap-int #>GLint 1))
(#/setValues:forParameter: (#/openGLContext self) swap-int #$NSOpenGLCPSwapInterval))
(let ((buffers (gl:gen-buffers 2)))
(setf (vertex-buffer self) (elt buffers 0)
(color-buffer self) (elt buffers 1)))
(gl:bind-buffer :array-buffer (vertex-buffer self))
(let ((arr (gl:alloc-gl-array :float 9))
(vals #(0.0 0.5 0.0 0.5 -0.5 0.0 -0.5 -0.5 0.0)))
(dotimes (i (length vals))
(setf (gl:glaref arr i) (aref vals i)))
(gl:buffer-data :array-buffer :static-draw arr)
(gl:free-gl-array arr))
(gl:bind-buffer :array-buffer (color-buffer self))
(let ((arr (gl:alloc-gl-array :float 9))
(vals #(1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0)))
(dotimes (i (length vals))
(setf (gl:glaref arr i) (aref vals i)))
(gl:buffer-data :array-buffer :static-draw arr)
(gl:free-gl-array arr))
(setf (vertex-array self) (gl:gen-vertex-array))
(gl:bind-vertex-array (vertex-array self))
(gl:bind-buffer :array-buffer (vertex-buffer self))
(gl:vertex-attrib-pointer 0 3 :float nil 0 (cffi:null-pointer))
(gl:bind-buffer :array-buffer (color-buffer self))
(gl:vertex-attrib-pointer 1 3 :float nil 0 (cffi:null-pointer))
(gl:enable-vertex-attrib-array 0)
(gl:enable-vertex-attrib-array 1)
(let ((vs (gl:create-shader :vertex-shader))
(fs (gl:create-shader :fragment-shader)))
(setf (vertex-shader self) vs)
(setf (fragment-shader self) fs)
(gl:shader-source vs *triangle-vertex-program*)
(gl:compile-shader vs)
(gl:shader-source fs *triangle-fragment-program*)
(gl:compile-shader fs)
(setf (program self) (gl:create-program))
(gl:attach-shader (program self) vs)
(gl:attach-shader (program self) fs))
(gl:link-program (program self)))
(objc:defmethod (#/drawRect: :void) ((self color-triangle-view) (rect #>NSRect))
(declare (ignorable rect))
(#/makeCurrentContext (#/openGLContext self))
(gl:clear :color-buffer-bit :depth-buffer-bit)
(gl:use-program (program self))
(gl:bind-vertex-array (vertex-array self))
(gl:draw-arrays :triangles 0 3)
(#/flushBuffer (#/openGLContext self)))
(defclass color-triangle-window (ns:ns-window)
()
(:metaclass ns:+ns-object))
(objc:defmethod (#/close :void) ((self color-triangle-window))
(let ((w (#/contentView self)))
(when (slot-boundp w 'vs)
(gl:delete-shader (vertex-shader w)))
(when (slot-boundp w 'fs)
(gl:delete-shader (fragment-shader w)))
(when (slot-boundp w 'program)
(gl:delete-program (program w)))
(when (slot-boundp w 'vbuff)
(gl:delete-buffers (list (vertex-buffer w) (color-buffer w))))
(when (slot-boundp w 'va)
(gl:delete-vertex-arrays (list (vertex-array w)))))
(call-next-method))
(defun triangle-demo ()
(objc:with-autorelease-pool
(let* ((w (gui::execute-in-gui
#'(lambda () (gui::new-cocoa-window :class (find-class 'color-triangle-window)
:title "OpenGL 4.1 Color Triangle Window"
:height 480
:width 640
:expandable t))))
(v (make-color-triangle-view)))
(#/setContentView: w v)
(list w v))))
@GOFAI
Copy link
Author

GOFAI commented Oct 16, 2017

Tested on OS X 10.10.5, MacBook Pro (Retina, 13-inch, Mid 2014). Make sure cl-opengl is loaded first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment