From d89629e400a570122a57cc0cb7243ad40cc0a954 Mon Sep 17 00:00:00 2001 From: David Thompson Date: Thu, 19 Jan 2017 09:30:02 -0500 Subject: render: Add framebuffers. --- Makefile.am | 1 + chickadee/render.scm | 14 +++++ chickadee/render/framebuffer.scm | 125 +++++++++++++++++++++++++++++++++++++++ chickadee/render/gl.scm | 22 +++---- 4 files changed, 152 insertions(+), 10 deletions(-) create mode 100644 chickadee/render/framebuffer.scm diff --git a/Makefile.am b/Makefile.am index fa84dd6..c9a563e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,6 +54,7 @@ SOURCES = \ chickadee/render/shader.scm \ chickadee/render/vertex-buffer.scm \ chickadee/render/viewport.scm \ + chickadee/render/framebuffer.scm \ chickadee/render/shapes.scm \ chickadee/render/sprite.scm \ chickadee/render.scm \ diff --git a/chickadee/render.scm b/chickadee/render.scm index efb5004..9588a95 100644 --- a/chickadee/render.scm +++ b/chickadee/render.scm @@ -26,16 +26,19 @@ #:use-module (chickadee math matrix) #:use-module (chickadee render gpu) #:use-module (chickadee render blend) + #:use-module (chickadee render framebuffer) #:use-module (chickadee render shader) #:use-module (chickadee render texture) #:use-module (chickadee render vertex-buffer) #:use-module (chickadee render viewport) #:export (current-viewport + current-framebuffer current-blend-mode current-depth-test current-texture current-projection with-viewport + with-framebuffer with-blend-mode with-depth-test with-texture @@ -44,6 +47,7 @@ gpu-apply*)) (define *current-viewport* null-viewport) +(define *current-framebuffer* null-framebuffer) (define *current-blend-mode* 'replace) (define *current-depth-test* #f) (define *current-texture* null-texture) @@ -52,6 +56,9 @@ (define (current-viewport) *current-viewport*) +(define (current-framebuffer) + *current-framebuffer*) + (define (current-blend-mode) *current-blend-mode*) @@ -74,6 +81,9 @@ (define-syntax-rule (with-viewport viewport body ...) (with (*current-viewport* viewport) body ...)) +(define-syntax-rule (with-framebuffer framebuffer body ...) + (with (*current-framebuffer* framebuffer) body ...)) + (define-syntax-rule (with-blend-mode blend-mode body ...) (with (*current-blend-mode* blend-mode) body ...)) @@ -133,6 +143,10 @@ (define-syntax-rule (gpu-apply* shader vertex-array count . uniforms) (begin + ;; It's important that the framebuffer is set before setting the + ;; viewport because applying a new viewport will clear the current + ;; framebuffer. + (gpu-state-set! *framebuffer-state* (current-framebuffer)) (gpu-state-set! *viewport-state* (current-viewport)) (gpu-state-set! *blend-mode-state* (current-blend-mode)) (gpu-state-set! *depth-test-state* (current-depth-test)) diff --git a/chickadee/render/framebuffer.scm b/chickadee/render/framebuffer.scm new file mode 100644 index 0000000..39e4bfa --- /dev/null +++ b/chickadee/render/framebuffer.scm @@ -0,0 +1,125 @@ +;;; Chickadee Game Toolkit +;;; Copyright © 2017 David Thompson +;;; +;;; Chickadee is free software: you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published +;;; by the Free Software Foundation, either version 3 of the License, +;;; or (at your option) any later version. +;;; +;;; Chickadee is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;; General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with this program. If not, see +;;; . + +;;; Commentary: +;; +;; Render to texture. +;; +;;; Code: + +(define-module (chickadee render framebuffer) + #:use-module (oop goops) + #:use-module (ice-9 match) + #:use-module (srfi srfi-9) + #:use-module (system foreign) + #:use-module (gl) + #:use-module (gl enums) + #:use-module (chickadee render gl) + #:use-module (chickadee render gpu) + #:use-module ((chickadee render texture) #:select (make-texture null-texture)) + #:export (make-framebuffer + framebuffer? + framebuffer-texture + null-framebuffer + apply-framebuffer + *framebuffer-state*)) + +(define (generate-framebuffer) + "Generate a new OpenGL framebuffer object." + (let ((bv (u32vector 1))) + (gl-gen-framebuffers 1 (bytevector->pointer bv)) + (u32vector-ref bv 0))) + +(define (generate-renderbuffer) + "Generate a new OpenGL renderbuffer object." + (let ((bv (u32vector 1))) + (gl-gen-renderbuffers 1 (bytevector->pointer bv)) + (u32vector-ref bv 0))) + +(define-record-type + (%make-framebuffer id renderbuffer-id texture) + framebuffer? + (id framebuffer-id) + (renderbuffer-id framebuffer-renderbuffer-id) + (texture framebuffer-texture)) + +(define null-framebuffer + (%make-framebuffer 0 0 null-texture)) + +(define <> (class-of null-framebuffer)) + +(define (free-framebuffer framebuffer) + (gl-delete-renderbuffers 1 + (bytevector->pointer + (u32vector + (framebuffer-renderbuffer-id framebuffer)))) + (gl-delete-framebuffers 1 + (bytevector->pointer + (u32vector + (framebuffer-id framebuffer))))) + +(define-method (gpu-finalize (framebuffer <>)) + (free-framebuffer framebuffer)) + +(define (apply-framebuffer framebuffer) + (gl-bind-framebuffer (version-3-0 framebuffer) + (framebuffer-id framebuffer))) + +(define *framebuffer-state* + (make-gpu-state apply-framebuffer null-framebuffer)) + +(define make-framebuffer + (let ((draw-buffers (u32vector (version-3-0 color-attachment0)))) + (lambda* (width height #:key (min-filter 'linear) (mag-filter 'linear) + (wrap-s 'repeat) (wrap-t 'repeat)) + "Create a new framebuffer that renders to a texture with +dimensions WIDTH x HEIGHT." + (let* ((framebuffer-id (generate-framebuffer)) + (renderbuffer-id (generate-renderbuffer)) + (texture (make-texture #f width height + #:min-filter min-filter + #:mag-filter mag-filter + #:wrap-s wrap-s + #:wrap-t wrap-t)) + (framebuffer (%make-framebuffer framebuffer-id + renderbuffer-id + texture))) + (gpu-state-set! *framebuffer-state* framebuffer) + ;; Setup depth buffer. + (gl-bind-renderbuffer (version-3-0 renderbuffer) + renderbuffer-id) + (gl-renderbuffer-storage (version-3-0 renderbuffer) + (pixel-format depth-component) + width + height) + (gl-framebuffer-renderbuffer (version-3-0 framebuffer) + (arb-framebuffer-object depth-attachment) + (version-3-0 renderbuffer) + renderbuffer-id) + ;; Setup framebuffer. + (gl-framebuffer-texture-2d (version-3-0 framebuffer) + (version-3-0 color-attachment0) + (texture-target texture-2d) + ((@@ (chickadee render texture) texture-id) + texture) + 0) + (gl-draw-buffers 1 (bytevector->pointer draw-buffers)) + ;; Check for errors. + (unless (= (gl-check-framebuffer-status (version-3-0 framebuffer)) + (version-3-0 framebuffer-complete)) + (error "Framebuffer cannot be created")) + framebuffer)))) diff --git a/chickadee/render/gl.scm b/chickadee/render/gl.scm index 005194b..bbe3c44 100644 --- a/chickadee/render/gl.scm +++ b/chickadee/render/gl.scm @@ -220,16 +220,18 @@ object.") -> void) "Attach a renderbuffer object to a framebuffer object.") -(export glGenFramebuffers - glDeleteFramebuffers - glBindFramebuffer - glFramebufferTexture2D - glCheckFramebufferStatus - glGenRenderbuffers - glDeleteRenderbuffers - glBindRenderbuffer - glRenderbufferStorage - glFramebufferRenderbuffer) +(export (glGenFramebuffers . gl-gen-framebuffers) + (glDeleteFramebuffers . gl-delete-framebuffers) + (glBindFramebuffer . gl-bind-framebuffer) + (glFramebufferTexture2D . gl-framebuffer-texture-2d) + (glCheckFramebufferStatus . gl-check-framebuffer-status) + (glGenRenderbuffers . gl-gen-renderbuffers) + (glDeleteRenderbuffers . gl-delete-renderbuffers) + (glBindRenderbuffer . gl-bind-renderbuffer) + (glRenderbufferStorage . gl-renderbuffer-storage) + (glFramebufferRenderbuffer . gl-framebuffer-renderbuffer)) + +(re-export (%glDrawBuffers . gl-draw-buffers)) ;;; -- cgit v1.2.3