zoukankan      html  css  js  c++  java
  • MAC 下用 Common Lisp 调试 OpenGL 程序

    MAC 下用 Common Lisp 调试 OpenGL 程序

    环境搭建

    • 运行环境: OSX 10.11.3 EI Capitan
    • Common Lisp: SBCL

    使用 SBCL, 首先要安装这几个库 quicklisp, cl-opengl, cl-glu, lispbuilder-sdl. 先安装好 quicklisp, 再用它来安装其他库.

    安装过程如下.

    安装 quicklisp

    先安装 quicklisp

    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) 发现原来已经安装过了, 那就选择使用已经安装好的.

    * (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:

    * (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 之后, 剩下的就是用它来安装其他几个库, 具体来说就是这几条命令:

    (ql:quickload 'cl-opengl)
    (ql:quickload 'cl-glu)
    (ql:quickload 'lispbuilder-sdl)
    

    安装 cl-opengl

    接下来就可以用 quicklispql:quickload 命令加载需要的库了, 先加载 cl-opengl

    * (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

    再加载 cl-glu

    * (ql:quickload 'cl-glu)
    To load "cl-glu":
      Load 1 ASDF system:
        cl-glu
    ; Loading "cl-glu"
    [package cl-glu].....
    (CL-GLU)
    * 
    

    安装 lispbuilder-sdl

    接下来加载 lispbuilder-sdl, 结果一开始出错, 报错信息如下:

    * (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 就可以了.

    另外开一个终端窗口, 编译 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 图

    这里有一段只用 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))))))
    

    运行截图如下:

    3D

    这是一个非常好的开始, 以后就可以在这个基础上用 Common Lisp 来调试 OpenGL 程序了.

    参考

    Using OpenGL with Common Lisp
    Common Lisp 3D/2D Graphics Engine for OpenGL
    Common Lisp library for creative coding

  • 相关阅读:
    2018-8-10-win10-uwp-按下等待按钮
    2018-8-10-win10-uwp-按下等待按钮
    2019-6-23-win10-uwp-应用放到桌面
    2019-6-23-win10-uwp-应用放到桌面
    PHP mysqli_get_client_info() 函数
    PHP mysqli_get_charset() 函数
    PHP mysqli_free_result() 函数
    PHP mysqli_field_tell() 函数
    PHP mysqli_field_seek() 函数
    约束、视图、序列、伪列和索引
  • 原文地址:https://www.cnblogs.com/freeblues/p/5697204.html
Copyright © 2011-2022 走看看