;;; Implementation of smooth pixelart scaling. ;;; This is basically the equivalent of CSS `image-rendering: pixelated` ;; native render resolution (defvar *render-width* 384) (defvar *render-height* 256) ;; window resolution (defvar *window-width* 1200) (defvar *window-height* 800) (defvar *render-tex* (gl:gen-texture)) (defvar *render-fb* (gl:gen-framebuffer)) (defvar *upscale-tex* (gl:gen-texture)) (defvar *upscale-fb* (gl:gen-framebuffer)) (defvar *upscale-width*) (defvar *upscale-height*) (defmacro with-bind-texture ((target texture) &body body) `(progn (gl:bind-texture ,target ,texture) ,@body (gl:bind-texture ,target 0))) (defmacro with-bind-framebuffer ((target framebuffer) &body body) `(progn (gl:bind-framebuffer ,target ,framebuffer) ,@body (gl:bind-framebuffer ,target 0))) (defun init-textures () "Initialize textures. Call this whenever the window or render resolution changes." ;; generate the render texture (with-bind-texture (:texture-2d *render-tex*) (gl:tex-image-2d :texture-2d 0 :rgba *render-width* *render-height* 0 :rgba :unsigned-byte (cffi:null-pointer)) (gl:tex-parameter :texture-2d :texture-wrap-s :clamp-to-edge) (gl:tex-parameter :texture-2d :texture-wrap-t :clamp-to-edge) (gl:tex-parameter :texture-2d :texture-min-filter :nearest) (gl:tex-parameter :texture-2d :texture-mag-filter :nearest)) (with-bind-framebuffer (:framebuffer *render-fb*) (gl:framebuffer-texture-2d :framebuffer :color-attachment0 :texture-2d *render-tex* 0)) ;; generate the upscale texture, which is scaled to an integer multiple of the render size (setf *upscale-width* (* (ceiling *window-width* *render-width*) *render-width*) *upscale-height* (* (ceiling *window-height* *render-height*) *render-height*)) (with-bind-texture (:texture-2d *upscale-tex*) (gl:tex-image-2d :texture-2d 0 :rgba *upscale-width* *upscale-height* 0 :rgba :unsigned-byte (cffi:null-pointer)) (gl:tex-parameter :texture-2d :texture-wrap-s :clamp-to-edge) (gl:tex-parameter :texture-2d :texture-wrap-t :clamp-to-edge) (gl:tex-parameter :texture-2d :texture-min-filter :linear) (gl:tex-parameter :texture-2d :texture-mag-filter :linear)) (with-bind-framebuffer (:framebuffer *upscale-fb*) (gl:framebuffer-texture-2d :framebuffer :color-attachment0 :texture-2d *upscale-tex* 0))) (defun before-render () (gl:bind-framebuffer :framebuffer *render-fb*) (gl:viewport 0 0 *render-width* *render-height*)) (defun after-render () ;; upscale with nearest-neighbour (gl:bind-framebuffer :framebuffer *upscale-fb*) (gl:viewport 0 0 *upscale-width* *upscale-height*) (gl:disable :depth-test) (gl:enable :texture-2d) (gl:bind-texture :texture-2d *render-tex*) (draw-full-screen-quad) ;; downscale with linear, render to window (gl:bind-framebuffer :framebuffer 0) (gl:viewport 0 0 *window-width* *window-height*) (gl:bind-texture :texture-2d *upscale-tex*) (draw-full-screen-quad) (gl:bind-texture :texture-2d 0)) (defun draw-full-screen-quad () "Draw a quad from (-1,-1) to (1,1). Essentially draw a texture stretched across the entire viewport." (not-implemented))