使用 SBCL
, 首先要安裝這幾個庫 quicklisp
, cl-opengl
, cl-glu
, lispbuilder-sdl
. 先安裝好 quicklisp
, 再用它來安裝其餘庫.git
安裝過程以下.github
先安裝 quicklisp
macos
Air:~ admin$ cd code-staff/ Air:code-staff admin$ mkdir sbcl Air:code-staff admin$ cd sbcl Air:sbcl admin$ curl -O https://beta.quicklisp.org/quicklisp.lisp % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 57144 100 57144 0 0 12184 0 0:00:04 0:00:04 --:--:-- 12545 Air:sbcl admin$ ls quicklisp.lisp Air:sbcl admin$ sbcl --load quicklisp.lisp This is SBCL 1.0.55, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information. ==== quicklisp quickstart 2015-01-28 loaded ==== To continue with installation, evaluate: (quicklisp-quickstart:install) For installation options, evaluate: (quicklisp-quickstart:help)
執行 (quicklisp-quickstart:install)
發現原來已經安裝過了, 那就選擇使用已經安裝好的.api
* (quicklisp-quickstart:install) debugger invoked on a SIMPLE-ERROR in thread #<THREAD "initial thread" RUNNING {10029A91C3}>: Quicklisp has already been installed. Load #P"/Users/admin/quicklisp/setup.lisp" instead. Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL. restarts (invokable by number or by possibly-abbreviated name): 0: [LOAD-SETUP] Load #P"/Users/admin/quicklisp/setup.lisp" 1: [ABORT ] Exit debugger, returning to top level. (QUICKLISP-QUICKSTART:INSTALL :PATH NIL :PROXY NIL :CLIENT-URL NIL :CLIENT-VERSION NIL :DIST-URL NIL :DIST-VERSION NIL) 0] 0 T
而後執行 (ql:add-to-init-file)
加載到 SBCL
的初始化文件中, 這樣每次啓動 SBCL
就會自動加載 quicklisp
:app
* (ql:add-to-init-file) I will append the following lines to #P"/Users/admin/.sbclrc": ;;; The following lines added by ql:add-to-init-file: #-quicklisp (let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp" (user-homedir-pathname)))) (when (probe-file quicklisp-init) (load quicklisp-init))) Press Enter to continue. #P"/Users/admin/.sbclrc" *
安裝好 quicklisp
以後, 剩下的就是用它來安裝其餘幾個庫, 具體來講就是這幾條命令:dom
(ql:quickload 'cl-opengl) (ql:quickload 'cl-glu) (ql:quickload 'lispbuilder-sdl)
接下來就能夠用 quicklisp
的 ql:quickload
命令加載須要的庫了, 先加載 cl-opengl
curl
* (ql:quickload 'cl-opengl) To load "cl-opengl": Load 2 ASDF systems: alexandria cffi Install 1 Quicklisp release: cl-opengl ; Fetching #<URL "http://beta.quicklisp.org/archive/cl-opengl/2013-03-12/cl-opengl-20130312-git.tgz"> ; 356.91KB ================================================== 365,475 bytes in 1.52 seconds (235.43KB/sec) ; Loading "cl-opengl" .................................................. [package cl-opengl-bindings]...................... .................................................. .................................................. [package cl-opengl]............................... ........ (CL-OPENGL) *
再加載 cl-glu
ide
* (ql:quickload 'cl-glu) To load "cl-glu": Load 1 ASDF system: cl-glu ; Loading "cl-glu" [package cl-glu]..... (CL-GLU) *
接下來加載 lispbuilder-sdl
, 結果一開始出錯, 報錯信息以下:svn
* (ql:quickload 'lispbuilder-sdl) To load "lispbuilder-sdl": Load 1 ASDF system: lispbuilder-sdl ; Loading "lispbuilder-sdl" debugger invoked on a LOAD-FOREIGN-LIBRARY-ERROR in thread #<THREAD "initial thread" RUNNING {10029A91C3}>: Unable to load any of the alternatives: ((:FRAMEWORK "cocoahelper") (:DEFAULT "cocoahelper")) Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL. restarts (invokable by number or by possibly-abbreviated name): 0: [RETRY ] Try loading the foreign library again. 1: [USE-VALUE ] Use another library instead. 2: [TRY-RECOMPILING] Recompile cocoahelper and try loading it again 3: [RETRY ] Retry loading FASL for #<CL-SOURCE-FILE "cocoahelper" "cocoahelper" "cocoahelper">. 4: [ACCEPT ] Continue, treating loading FASL for #<CL-SOURCE-FILE "cocoahelper" "cocoahelper" "cocoahelper"> as having been successful. 5: [ABORT ] Give up on "lispbuilder-sdl" 6: Exit debugger, returning to top level. (CFFI::FL-ERROR "Unable to load any of the alternatives:~% ~S" ((:FRAMEWORK "cocoahelper") (:DEFAULT "cocoahelper"))) 0]
仔細閱讀這篇文檔Using OpenGL with Common Lisp, 發現做者提到了這一點, 也說了解決辦法, 就是進入對應的 cocoahelper
目錄, 手動編譯/安裝, 實際上只要進到這個目錄 /Users/admin/quicklisp/dists/quicklisp/software/lispbuilder-20130312-svn/lispbuilder-sdl/cocoahelper
, 而後執行命令 make
就能夠了.oop
另外開一個終端窗口, 編譯 cocoahelper
庫, 在個人機器上操做記錄以下:
Air:cocoahelper admin$ pwd /Users/admin/quicklisp/dists/quicklisp/software/lispbuilder-20130312-svn/lispbuilder-sdl/cocoahelper Air:cocoahelper admin$ make gcc -fPIC -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_THREAD_SAFE -c cocoahelper.m -o cocoahelper.o cocoahelper.m:90:52: warning: passing 'char [1024]' to parameter of type 'UInt8 *' (aka 'unsigned char *') converts between pointers to integer types with different sign [-Wpointer-sign] if (CFURLGetFileSystemRepresentation(url2, true, parentdir, MAXPATHLEN)) { ^~~~~~~~~ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/CoreFoundation.framework/Headers/CFURL.h:113:91: note: passing argument to parameter 'buffer' here Boolean CFURLGetFileSystemRepresentation(CFURLRef url, Boolean resolveAgainstBase, UInt8 *buffer, CFIndex maxBufLen); ^ cocoahelper.m:163:12: warning: instance method '-setAppleMenu:' not found (return type defaults to 'id') [-Wobjc-method-access] [NSApp setAppleMenu:appleMenu]; ^~~~~~~~~~~~ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSApplication.h:110:12: note: receiver is instance of class declared here @interface NSApplication : NSResponder <NSUserInterfaceValidations, NSAccessibilityElement, NSAccessibility> ^ cocoahelper.m:292:31: warning: incompatible pointer to integer conversion passing 'void *' to parameter of type 'int' [-Wint-conversion] CustomApplicationMain (0, NULL); ^~~~ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/7.3.0/include/stddef.h:105:16: note: expanded from macro 'NULL' # define NULL ((void*)0) ^~~~~~~~~~ cocoahelper.m:293:5: warning: 'GetCurrentProcess' is deprecated: first deprecated in OS X 10.9 [-Wdeprecated-declarations] GetCurrentProcess(&processSerialNum); ^ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/ApplicationServices.framework/Frameworks/HIServices.framework/Headers/Processes.h:415:1: note: 'GetCurrentProcess' has been explicitly marked deprecated here MacGetCurrentProcess(ProcessSerialNumber * PSN) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9; ^ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/ApplicationServices.framework/Frameworks/HIServices.framework/Headers/Processes.h:412:34: note: expanded from macro 'MacGetCurrentProcess' #define MacGetCurrentProcess GetCurrentProcess ^ cocoahelper.m:294:5: warning: implicit declaration of function 'CPSEnableForegroundOperation' is invalid in C99 [-Wimplicit-function-declaration] CPSEnableForegroundOperation (&processSerialNum); ^ cocoahelper.m:295:5: warning: 'SetFrontProcess' is deprecated: first deprecated in OS X 10.9 [-Wdeprecated-declarations] SetFrontProcess(&processSerialNum); ^ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/ApplicationServices.framework/Frameworks/HIServices.framework/Headers/Processes.h:603:1: note: 'SetFrontProcess' has been explicitly marked deprecated here SetFrontProcess(const ProcessSerialNumber * PSN) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_9; ^ 6 warnings generated. gcc -dynamiclib -L/usr/local/lib -lSDLmain -lSDL -Wl,-framework,Cocoa -o cocoahelper.dylib cocoahelper.o Air:cocoahelper admin$
回到剛纔加載 lispbuilder-sdl
的窗口, 選擇 0
, 這樣:
0] 0 [package lispbuilder-sdl-cffi].................... .................................................. [package lispbuilder-sdl-base].................... [package trivial-garbage]......................... [package lispbuilder-sdl]......................... .................................................. .............. (LISPBUILDER-SDL) *
不太放心, 再從新來一次, 直接顯示成功:
* (ql:quickload 'lispbuilder-sdl) To load "lispbuilder-sdl": Load 1 ASDF system: lispbuilder-sdl ; Loading "lispbuilder-sdl" (LISPBUILDER-SDL) *
這裏有一段只用 cl-glut
庫繪製的 manderlbrot
集的代碼, 以下:
(ql:quickload "cl-glut") (defparameter *width* 500) (defparameter *height* 500) (defparameter *magnification* 100.0) (defun get-latice-points (width height reduction) (apply #'append (loop for x from (* -1 (/ width 2)) below (1+ (/ width 2)) collect (loop for y from (* -1 (/ height 2)) below (1+ (/ height 2)) collect (complex (/ x reduction) (/ y reduction)))))) (defun calc-mandelbrot (c) (labels ((f (z c n) (cond ((= n 27) `(,c -1)) ((< 2 (abs z)) `(,c ,n)) (t (f (+ c (expt z 2)) c (1+ n)))))) (f 0 c 0))) (defun get-mandelbrot () (mapcar #'calc-mandelbrot (get-latice-points *width* *height* *magnification*))) (defun set-mandelbrot-vertexes (latice-points) (mapcar #'(lambda (x) (let ((latice-point (car x)) (n (cadr x))) (cond ((= n -1) (%gl:color-3f 0 0 0)) (t (%gl:color-3f (* n 0.2) 0 0))) (gl:vertex (* *magnification* (realpart latice-point)) (* *magnification* (imagpart latice-point)) 0))) latice-points)) (defclass my-window (glut:window) () (:default-initargs :title "mandelbrot" :width *width* :height *height* :mode '(:single :rgb :depth))) (defmethod glut:display-window :before ((w my-window)) (gl:clear-color 1 1 1 0) (gl:matrix-mode :projection) (gl:load-identity) (gl:ortho 0 *width* *height* 0 -1 1)) (defmethod glut:display ((window my-window)) (gl:clear :color-buffer-bit) (%gl:color-3f 0 0 0) (gl:push-matrix) (gl:translate (/ *width* 2) (/ *height* 2) 0) (gl:begin :points) (set-mandelbrot-vertexes *mandelbrot*) (gl:end) (gl:pop-matrix) (gl:flush)) (defparameter *mandelbrot* (get-mandelbrot)) (defun draw-mandelbrot () (glut:display-window (make-instance 'my-window)))
加載命令:
sbcl --load mandelbrot.lisp
而後執行:
* (draw-mandelbrot)
運行截圖:
具體就是繪製一個立方體, 代碼以下:
(require 'cl-opengl) (require 'cl-glu) (require 'lispbuilder-sdl) (defconstant +window-width+ 600) (defconstant +window-height+ 600) (defconstant +cube-vertices+ #(#(0 0 0) #(0 1 0) #(1 1 0) #(1 0 0) #(0 0 1) #(0 1 1) #(1 1 1) #(1 0 1))) (defconstant +cube-faces+ '((#(4 7 6 5) #(0 0 1)) (#(5 6 2 1) #(0 1 0)) (#(1 2 3 0) #(0 0 -1)) (#(0 3 7 4) #(0 -1 0)) (#(4 5 1 0) #(-1 0 0)) (#(3 2 6 7) #(1 0 0)))) (defun draw-figure (verts faces) (labels ((set-normal (n) (gl:normal (aref n 0) (aref n 1) (aref n 2))) (set-vertex (index) (let ((v (aref verts index))) (gl:vertex (aref v 0) (aref v 1) (aref v 2)))) (draw-face (vertex-indices normal) (set-normal normal) (gl:begin :quads) (map 'nil #'set-vertex vertex-indices) (gl:end))) (map 'nil #'(lambda (x) (draw-face (first x) (second x))) faces))) (defun draw-frame (rotx roty rotz) (gl:matrix-mode :modelview) (gl:push-matrix) (gl:translate 0.5 0.5 0.5) (gl:rotate rotx 1 0 0) (gl:rotate roty 0 1 0) (gl:rotate rotz 0 0 1) (gl:translate -0.5 -0.5 -0.5) (draw-figure +cube-vertices+ +cube-faces+) (gl:pop-matrix)) (defun start () (let ((rotx 0) (roty 0) (rotz 0)) (sdl:with-init () (sdl:window +window-width+ +window-height+ :opengl t :opengl-attributes '((:sdl-gl-depth-size 16) (:sdl-gl-doublebuffer 1))) (setf (sdl:frame-rate) 10) (gl:viewport 0 0 +window-width+ +window-height+) (gl:matrix-mode :projection) (gl:load-identity) (glu:perspective 50 (/ +window-height+ +window-width+) 1.0 10.0) (glu:look-at -2 2 4 0.5 0.5 0.5 0 1 0) (gl:matrix-mode :modelview) (gl:load-identity) (gl:clear-color 0 0 0 0) (gl:shade-model :flat) (gl:cull-face :back) (gl:polygon-mode :front :fill) (gl:draw-buffer :back) (gl:material :front :ambient-and-diffuse #(0.7 0.7 0.7 0.4)) (gl:light :light0 :position #(0 0 1 0)) (gl:light :light0 :diffuse #(1 0 0 0)) (gl:light :light1 :position #(-1 2 -0.5 0)) (gl:light :light1 :diffuse #(0 1 0 0)) (gl:enable :cull-face :depth-test :lighting :light0 :light1) (gl:clear :color-buffer :depth-buffer) (draw-frame rotx roty rotz) (sdl:update-display) (sdl:with-events () (:quit-event () t) (:video-expose-event () (sdl:update-display)) (:idle (setq rotx (mod (+ rotx 2.5) 360.0)) (setq roty (mod (+ roty 0.7) 360.0)) (setq rotz (mod (+ rotz 4.4) 360.0)) (gl:clear :color-buffer :depth-buffer) (draw-frame rotx roty rotz) (sdl:update-display))))))
運行截圖以下:
這是一個很是好的開始, 之後就能夠在這個基礎上用 Common Lisp
來調試 OpenGL
程序了.
Using OpenGL with Common Lisp
Common Lisp 3D/2D Graphics Engine for OpenGL
Common Lisp library for creative coding