Created
October 16, 2017 06:18
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Tested on OS X 10.10.5, MacBook Pro (Retina, 13-inch, Mid 2014). Make sure cl-opengl is loaded first.