| Paste number 29688: | render-to-texture.lisp |
| Pasted by: | omarkovic |
| 1 year, 11 months ago | |
| None | |
| Paste contents: |
| ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*- ;;; render-to-texture.lisp --- Simple usage of the EXT_framebuffer_object extension (in-package #:cl-glut-examples) (defclass render-to-texture-window (glut:window) ((texture :accessor texture) (framebuffer :accessor framebuffer)) (:default-initargs :width 640 :height 480 :title "render-to-texture.lisp" :mode '(:double :rgb :depth :multisample))) ;;; Do initialization here: ;;; ;;; In order to render to a texture, we need to setup a complete framebuffer, ;;; which consists of color-buffers, a depth-buffer and a stencil-buffer. ;;; In our simple case, we setup a texture as color-buffer and add a 24-bit ;;; depth-buffer so we can render the teapot correctly. We don't attach a ;;; stencil-buffer since it isn't needed in this simple example. (defmethod glut:display-window :before ((w render-to-texture-window)) (let ((framebuffer (first (gl:gen-framebuffers-ext 1))) (depthbuffer (first (gl:gen-renderbuffers-ext 1))) (texture (first (gl:gen-textures 1)))) ;; setup framebuffer (gl:bind-framebuffer-ext :framebuffer-ext framebuffer) ;; setup texture and attach it to the framebuffer (gl:bind-texture :texture-2d texture) (gl:tex-parameter :texture-2d :texture-min-filter :linear-mipmap-linear) (gl:tex-parameter :texture-2d :texture-mag-filter :linear) (gl:tex-image-2d :texture-2d 0 :rgba 512 512 0 :rgba :unsigned-byte (cffi:null-pointer)) (gl:framebuffer-texture-2d-ext :framebuffer-ext :color-attachment0-ext :texture-2d texture 0) ;; setup depth-buffer and attach it to the framebuffer (gl:bind-renderbuffer-ext :renderbuffer-ext depthbuffer) (gl:renderbuffer-storage-ext :renderbuffer-ext :depth-component24 512 512) (gl:framebuffer-renderbuffer-ext :framebuffer-ext :depth-attachment-ext :renderbuffer-ext depthbuffer) ;; validate framebuffer (let ((framebuffer-status (gl:check-framebuffer-status-ext :framebuffer-ext))) (unless (eql framebuffer-status :framebuffer-complete-ext) (error "Framebuffer not complete: ~A." framebuffer-status))) (setf (texture w) texture (framebuffer w) framebuffer)) (gl:enable :depth-test :multisample)) (defmethod glut:display ((window render-to-texture-window)) (gl:load-identity) ;; We render the teapot in the first pass. To do this, we switch to our ;; custom framebuffer, set the viewport to the texture size and render it ;; normally. (gl:bind-framebuffer-ext :framebuffer-ext (framebuffer window)) (gl:viewport 0 0 512 512) (gl:matrix-mode :projection) (gl:load-identity) (glu:perspective 50 1 0.5 20) (gl:matrix-mode :modelview) (draw-teapot) ;; Now that the texture has been updated, we can draw the spinning quad(s) in ;; the second pass. We want to render into the window, so we need to bind to ;; the default framebuffer, which always has the ID 0. (gl:bind-framebuffer-ext :framebuffer-ext 0) (gl:viewport 0 0 (glut:width window) (glut:height window)) (gl:matrix-mode :projection) (gl:load-identity) (glu:perspective 50 (/ (glut:width window) (glut:height window)) 0.5 20) (gl:matrix-mode :modelview) (draw-spinning-quad (texture window)) (glut:swap-buffers)) (defmethod glut:idle ((window render-to-texture-window)) (glut:post-redisplay)) (defmethod glut:reshape ((window render-to-texture-window) width height) (setf (glut:width window) width (glut:height window) height)) (defmethod glut:keyboard ((window render-to-texture-window) key x y) (declare (ignore x y)) (when (eql key #\Esc) (glut:destroy-current-window))) (defun render-to-texture () (glut:display-window (make-instance 'render-to-texture-window))) ;;; FIXME: the rotations are dependent on the frame rate. ;;; I'd need to calculate the frametime, but I'm too lazy right now. (defparameter *teapot-rotation-x* 0.0) (defparameter *teapot-rotation-y* 0.0) (defparameter *teapot-rotation-z* 0.0) (defun draw-teapot () (gl:clear-color 0 0.3 0.5 1.0) (gl:clear :color-buffer-bit :depth-buffer-bit) (gl:disable :blend :texture-2d) (gl:enable :lighting :light0 :depth-test) (gl:color-material :front :ambient-and-diffuse) (gl:light :light0 :position '(0 1 1 0)) (gl:light :light0 :diffuse '(0.2 0.4 0.6 0)) (gl:load-identity) (gl:translate 0 0 -4) (gl:rotate *teapot-rotation-x* 1 0 0) (gl:rotate *teapot-rotation-y* 0 1 0) (gl:rotate *teapot-rotation-z* 0 0 1) (gl:color 1 1 1) (glut:solid-teapot 1.3) (incf *teapot-rotation-x* 0.01) (incf *teapot-rotation-y* 0.05) (incf *teapot-rotation-z* 0.03)) (defparameter *quad-rotation* 0.0) (defun draw-spinning-quad (texture) (gl:clear-color 0 0 0 0) (gl:clear :color-buffer-bit :depth-buffer-bit) (gl:disable :lighting) (gl:enable :blend :texture-2d :depth-test) (gl:blend-func :src-alpha :one) (gl:load-identity) (gl:translate 0 -1 -3) (gl:rotate *quad-rotation* 0 1 0) (gl:bind-texture :texture-2d texture) ;; the teapot texture gets regenerated every frame, so we also need to ;; recalculate the mipmaps every frame since trilinear filtering is enabled. (gl:generate-mipmap-ext :texture-2d) ;; draw textured quad (gl:color 1 1 1) (gl:with-primitives :quads (gl:tex-coord 0 1) (gl:vertex -1 2) (gl:tex-coord 1 1) (gl:vertex 1 2) (gl:tex-coord 1 0) (gl:vertex 1 0) (gl:tex-coord 0 0) (gl:vertex -1 0)) ;; draw fake reflection (gl:with-primitives :quads (gl:color 1 1 1 0.7) (gl:tex-coord 0 0) (gl:vertex -1 0) (gl:tex-coord 1 0) (gl:vertex 1 0) (gl:tex-coord 1 0.5) (gl:color 1 1 1 0) (gl:vertex 1 -1) (gl:tex-coord 0 0.5) (gl:vertex -1 -1)) (incf *quad-rotation* 0.1)) |
This paste has no annotations.