summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Thompson <dthompson2@worcester.edu>2018-01-05 15:56:26 -0500
committerDavid Thompson <dthompson2@worcester.edu>2018-01-05 15:56:26 -0500
commitcf1b09a12f39767c1cdf2b9cee81c396dc8b52cd (patch)
tree88187c4ac8e2c2f9e1473e455939a204e9ae7753
parent41681454c4a1b0a12605f512a52f8fc46afefff1 (diff)
render: sprite: Allow passing custom transformation matrices.
* chickadee/render/sprite.scm (draw-sprite-unbatched, draw-sprite-batched): Replace 'scale' and 'rotation' arguments with a 'matrix' argument. (sprite-batch-add!): Ditto. Also, correctly transform sprite vertices. This was previously not handling rotations properly. (%default-offset): New variable. (draw-sprite, draw-nine-patch): Change default values for 'rotation' and 'scale'. Add 'matrix' and 'offset' arguments. * chickadee/render/font.scm (%default-offset): New variable. (draw-text): Change default values for 'rotation' and 'scale'. Add 'offset' and 'matrix' arguments.
-rw-r--r--chickadee/render/font.scm11
-rw-r--r--chickadee/render/sprite.scm298
2 files changed, 180 insertions, 129 deletions
diff --git a/chickadee/render/font.scm b/chickadee/render/font.scm
index 31670ad..bac5056 100644
--- a/chickadee/render/font.scm
+++ b/chickadee/render/font.scm
@@ -295,10 +295,17 @@ extension must be either .xml or .fnt."
(define (font-ref font char)
(hashv-ref (font-chars font) char))
+(define %default-offset (vec2 0.0 0.0))
+
(define draw-text
(let ((cursor (vec2 0.0 0.0))
(char-pos (vec2 0.0 0.0)))
- (lambda* (font text position #:key scale rotation (blend-mode 'alpha))
+ (lambda* (font text position #:key
+ (rotation 0)
+ (scale 1.0)
+ matrix
+ (offset %default-offset)
+ (blend-mode 'alpha))
"Draw the string TEXT with the first character starting at
POSITION using FONT."
;; TODO: Respect kerning.
@@ -310,8 +317,10 @@ POSITION using FONT."
(set-vec2-y! char-pos (+ (vec2-y cursor) (vec2-y offset)))
(draw-sprite (font-char-texture-region char)
char-pos
+ #:offset offset
#:scale scale
#:rotation rotation
+ #:matrix matrix
#:blend-mode blend-mode)
;; Move forward to where the next character needs to be drawn.
(set-vec2-x! cursor
diff --git a/chickadee/render/sprite.scm b/chickadee/render/sprite.scm
index b07a969..38b1594 100644
--- a/chickadee/render/sprite.scm
+++ b/chickadee/render/sprite.scm
@@ -80,15 +80,13 @@ void main (void) {
#:attributes
`((0 . ,(force position-buffer))
(1 . ,(force texcoord-buffer))))))
- (tmp-matrix (make-null-matrix4))
- (mvp (make-null-matrix4))
- (position (vec2 0 0)))
- (lambda (texture region scale rotation blend-mode shader texture-region)
+ (mvp (make-null-matrix4)))
+ (lambda (texture region world-matrix blend-mode shader texture-region)
(with-mapped-typed-buffer (force position-buffer)
- (let* ((x1 0)
- (y1 0)
- (x2 (rect-width region))
- (y2 (rect-height region))
+ (let* ((x1 (rect-x region))
+ (y1 (rect-y region))
+ (x2 (+ x1 (rect-width region)))
+ (y2 (+ y1 (rect-height region)))
(bv (typed-buffer-data (force position-buffer))))
(f32vector-set! bv 0 x1)
(f32vector-set! bv 1 y1)
@@ -112,21 +110,15 @@ void main (void) {
(f32vector-set! bv 5 t2)
(f32vector-set! bv 6 s1)
(f32vector-set! bv 7 t2)))
- (matrix4-identity! mvp)
- (when rotation
- (matrix4-rotate-z! tmp-matrix rotation)
- (matrix4-mult! mvp mvp tmp-matrix))
- (when scale
- (matrix4-scale! tmp-matrix scale)
- (matrix4-mult! mvp mvp tmp-matrix))
- (set-vec2-x! position (rect-x region))
- (set-vec2-y! position (rect-y region))
- (matrix4-translate! tmp-matrix position)
- (matrix4-mult! mvp mvp tmp-matrix)
- (matrix4-mult! mvp mvp (current-projection))
(with-blend-mode blend-mode
(with-texture 0 texture
- (gpu-apply shader (force vertex-array) #:mvp mvp))))))
+ (gpu-apply shader (force vertex-array)
+ #:mvp (if world-matrix
+ (begin
+ (matrix4-mult! mvp world-matrix
+ (current-projection))
+ mvp)
+ (current-projection))))))))
;;;
@@ -223,17 +215,16 @@ void main (void) {
(sprite-batch-reset! batch)))))
(define sprite-batch-add!
- (let ((tmp-matrix (make-null-matrix4))
- (matrix (make-null-matrix4))
- (position (vec2 0.0 0.0))
- (world1 (vec2 0.0 0.0))
+ (let ((world1 (vec2 0.0 0.0))
(world2 (vec2 0.0 0.0))
+ (world3 (vec2 0.0 0.0))
+ (world4 (vec2 0.0 0.0))
(offset-bv (make-u32vector 1)))
(define (set-offset offset)
(u32vector-set! offset-bv 0 offset))
(define (offset)
(u32vector-ref offset-bv 0))
- (lambda (batch texture region scale rotation blend-mode
+ (lambda (batch texture region world-matrix blend-mode
shader texture-region)
;; Expand the buffers when necessary.
(when (sprite-batch-full? batch)
@@ -251,93 +242,74 @@ void main (void) {
(let* ((indices (typed-buffer-data (sprite-batch-index-buffer batch)))
(vertices (typed-buffer-data (sprite-batch-position-buffer batch)))
(texcoords (typed-buffer-data (sprite-batch-texture-buffer batch)))
- (rx (rect-x region))
- (ry (rect-y region))
- (local-x1 0.0)
- (local-y1 0.0)
- (local-x2 (rect-width region))
- (local-y2 (rect-height region))
+ (local-x1 (rect-x region))
+ (local-y1 (rect-y region))
+ (local-x2 (+ local-x1 (rect-width region)))
+ (local-y2 (+ local-y1 (rect-height region)))
(s1 (rect-left texture-region))
(t1 (rect-bottom texture-region))
(s2 (rect-right texture-region))
(t2 (rect-top texture-region)))
- (if (or rotation scale)
- (begin
- (matrix4-identity! matrix)
- (when rotation
- (matrix4-rotate-z! tmp-matrix rotation)
- (matrix4-mult! matrix matrix tmp-matrix))
- (when scale
- (matrix4-scale! tmp-matrix scale)
- (matrix4-mult! matrix matrix tmp-matrix))
- (set-vec2-x! position rx)
- (set-vec2-y! position ry)
- (matrix4-translate! tmp-matrix position)
- (matrix4-mult! matrix matrix tmp-matrix)
- (set-vec2-x! world1 local-x1)
- (set-vec2-y! world1 local-y1)
- (set-vec2-x! world2 local-x2)
- (set-vec2-y! world2 local-y2)
- (transform! matrix world1)
- (transform! matrix world2))
- (begin
- (set-vec2-x! world1 (+ local-x1 rx))
- (set-vec2-y! world1 (+ local-y1 ry))
- (set-vec2-x! world2 (+ local-x2 rx))
- (set-vec2-y! world2 (+ local-y2 ry))))
- (let ((world-x1 (vec2-x world1))
- (world-y1 (vec2-y world1))
- (world-x2 (vec2-x world2))
- (world-y2 (vec2-y world2)))
- ;; Add indices.
- (set-offset (* size 4))
- (let ((index-vertex-offset (offset)))
- (set-offset (* size 6))
- (u32vector-set! indices (offset) index-vertex-offset)
- (u32vector-set! indices (+ (offset) 1) (+ index-vertex-offset 3))
- (u32vector-set! indices (+ (offset) 2) (+ index-vertex-offset 2))
- (u32vector-set! indices (+ (offset) 3) index-vertex-offset)
- (u32vector-set! indices (+ (offset) 4) (+ index-vertex-offset 2))
- (u32vector-set! indices (+ (offset) 5) (+ index-vertex-offset 1)))
- ;; Add vertices.
- (set-offset (* size 8)) ;; 4 vertices, 2 floats per vertex
- ;; Bottom-left
- (f32vector-set! vertices (offset) world-x1)
- (f32vector-set! vertices (+ (offset) 1) world-y1)
- ;; Bottom-right
- (f32vector-set! vertices (+ (offset) 2) world-x2)
- (f32vector-set! vertices (+ (offset) 3) world-y1)
- ;; Top-right
- (f32vector-set! vertices (+ (offset) 4) world-x2)
- (f32vector-set! vertices (+ (offset) 5) world-y2)
- ;; Top-left
- (f32vector-set! vertices (+ (offset) 6) world-x1)
- (f32vector-set! vertices (+ (offset) 7) world-y2)
- ;; Add texture coordinates.
- (set-offset (* size 8))
- ;; Bottom-left
- (f32vector-set! texcoords (offset) s1)
- (f32vector-set! texcoords (+ (offset) 1) t1)
- ;; Bottom-right
- (f32vector-set! texcoords (+ (offset) 2) s2)
- (f32vector-set! texcoords (+ (offset) 3) t1)
- ;; Top-right
- (f32vector-set! texcoords (+ (offset) 4) s2)
- (f32vector-set! texcoords (+ (offset) 5) t2)
- ;; Top-left
- (f32vector-set! texcoords (+ (offset) 6) s1)
- (f32vector-set! texcoords (+ (offset) 7) t2)
- (set-sprite-batch-size! batch (1+ size))))))))
+ (set-vec2-x! world1 local-x1)
+ (set-vec2-y! world1 local-y1)
+ (set-vec2-x! world2 local-x2)
+ (set-vec2-y! world2 local-y1)
+ (set-vec2-x! world3 local-x2)
+ (set-vec2-y! world3 local-y2)
+ (set-vec2-x! world4 local-x1)
+ (set-vec2-y! world4 local-y2)
+ (when world-matrix
+ (transform! world-matrix world1)
+ (transform! world-matrix world2)
+ (transform! world-matrix world3)
+ (transform! world-matrix world4))
+ ;; Add indices.
+ (set-offset (* size 4))
+ (let ((index-vertex-offset (offset)))
+ (set-offset (* size 6))
+ (u32vector-set! indices (offset) index-vertex-offset)
+ (u32vector-set! indices (+ (offset) 1) (+ index-vertex-offset 3))
+ (u32vector-set! indices (+ (offset) 2) (+ index-vertex-offset 2))
+ (u32vector-set! indices (+ (offset) 3) index-vertex-offset)
+ (u32vector-set! indices (+ (offset) 4) (+ index-vertex-offset 2))
+ (u32vector-set! indices (+ (offset) 5) (+ index-vertex-offset 1)))
+ ;; Add vertices.
+ (set-offset (* size 8)) ;; 4 vertices, 2 floats per vertex
+ ;; Bottom-left
+ (f32vector-set! vertices (offset) (vec2-x world1))
+ (f32vector-set! vertices (+ (offset) 1) (vec2-y world1))
+ ;; Bottom-right
+ (f32vector-set! vertices (+ (offset) 2) (vec2-x world2))
+ (f32vector-set! vertices (+ (offset) 3) (vec2-y world2))
+ ;; Top-right
+ (f32vector-set! vertices (+ (offset) 4) (vec2-x world3))
+ (f32vector-set! vertices (+ (offset) 5) (vec2-y world3))
+ ;; Top-left
+ (f32vector-set! vertices (+ (offset) 6) (vec2-x world4))
+ (f32vector-set! vertices (+ (offset) 7) (vec2-y world4))
+ ;; Add texture coordinates.
+ (set-offset (* size 8))
+ ;; Bottom-left
+ (f32vector-set! texcoords (offset) s1)
+ (f32vector-set! texcoords (+ (offset) 1) t1)
+ ;; Bottom-right
+ (f32vector-set! texcoords (+ (offset) 2) s2)
+ (f32vector-set! texcoords (+ (offset) 3) t1)
+ ;; Top-right
+ (f32vector-set! texcoords (+ (offset) 4) s2)
+ (f32vector-set! texcoords (+ (offset) 5) t2)
+ ;; Top-left
+ (f32vector-set! texcoords (+ (offset) 6) s1)
+ (f32vector-set! texcoords (+ (offset) 7) t2)
+ (set-sprite-batch-size! batch (1+ size)))))))
(define *batch?* #f)
(define %batch (delay (make-sprite-batch 256)))
-(define (draw-sprite-batched texture region
- scale rotation blend-mode shader
+(define (draw-sprite-batched texture region world-matrix blend-mode shader
texture-region)
- (sprite-batch-add! (force %batch) texture region
- scale rotation blend-mode shader
- texture-region))
+ (sprite-batch-add! (force %batch) texture region world-matrix blend-mode
+ shader texture-region))
(define-syntax-rule (with-batched-sprites body ...)
"Use batched rendering for all draw-sprite calls within BODY."
@@ -361,22 +333,40 @@ void main (void) {
(@@ (chickadee render texture) texture-region-gl-rect))
(define %default-texcoords (make-rect 0.0 0.0 1.0 1.0))
+(define %default-offset (vec2 0.0 0.0))
(define draw-sprite
- (let ((rect (make-rect 0.0 0.0 0.0 0.0)))
- (lambda* (texture region #:key
- scale rotation (blend-mode 'alpha)
- (texcoords
- (if (texture-region? texture)
- (texture-region-gl-rect texture)
- %default-texcoords))
- (shader (force default-shader)))
+ (let ((rect (make-rect 0.0 0.0 0.0 0.0))
+ (tmp-matrix (make-null-matrix4))
+ (%matrix (make-null-matrix4)))
+ (lambda* (texture
+ region
+ #:key
+ (scale 1.0)
+ (rotation 0)
+ matrix
+ (offset %default-offset)
+ (blend-mode 'alpha)
+ (texcoords
+ (if (texture-region? texture)
+ (texture-region-gl-rect texture)
+ %default-texcoords))
+ (shader (force default-shader)))
"Draw TEXTURE over the area defined by the rect REGION. Instead
of a rect, REGION may be a vec2 representing the position of the
sprite, in which case the width and height of the sprite corresponds
to the size of the texture. TEXTURE may be a texture or a texture
-region. ROTATION specifies by how many radians the sprite will be
-rotated. SCALE specifies the scaling factor. By default, alpha
+region.
+
+ROTATION specifies the angle to rotate the sprite, in radians. SCALE
+specifies the scaling factor. No scaling or rotation is applied by
+default. Alternatively, MATRIX may be specified, in which case
+ROTATION and SCALE are ignored and the given transformation matrix is
+used instead. All transformations are applied relative to the lower
+left corner of the sprite by default. This can be changed by
+specifying an OFFSET vector.
+
+By default, alpha
blending is used but can be changed by setting BLEND-MODE. Finally,
advanced users may pass SHADER to change the way the sprite is
rendered entirely."
@@ -386,20 +376,66 @@ rendered entirely."
(texture (if (texture-region? texture)
(texture-region-texture texture)
texture))
- (region (if (rect? region)
- region
- (begin
- (rect-move-vec2! rect region)
- (set-rect-width! rect (f32vector-ref size 0))
- (set-rect-height! rect (f32vector-ref size 1))
- rect))))
+ (matrix (cond
+ (matrix matrix) ; user-specified matrix
+ ((or rotation scale) ; compute matrix on-the-fly
+ (matrix4-identity! %matrix)
+ (unless (zero? rotation)
+ (matrix4-rotate-z! tmp-matrix rotation)
+ (matrix4-mult! %matrix %matrix tmp-matrix))
+ (unless (= scale 1.0)
+ (matrix4-scale! tmp-matrix scale)
+ (matrix4-mult! %matrix %matrix tmp-matrix))
+ (matrix4-translate! tmp-matrix region)
+ (matrix4-mult! %matrix %matrix tmp-matrix)
+ %matrix)
+ ;; No transformation needed, in which case we
+ ;; use no matrix at all in order to save cycles
+ ;; and not waste time multiplying against the
+ ;; identity matrix.
+ (else #f))))
+ (cond
+ ((and (rect? region)
+ (not matrix)
+ (zero? rotation) ; no rotation
+ (= scale 1.0)) ; no scale
+ ;; We won't be using a transformation matrix.
+ ;; Just apply the offset.
+ (set-rect-x! rect (- (rect-x region) (vec2-x offset)))
+ (set-rect-y! rect (- (rect-y region) (vec2-y offset)))
+ (set-rect-width! rect (rect-width region))
+ (set-rect-height! rect (rect-height region)))
+ ((rect? region)
+ ;; We will be using a transformation matrix, so
+ ;; ignore the region's X and Y coordinates as
+ ;; those will be accounted for in the
+ ;; translation matrix.
+ (set-rect-x! rect (- (vec2-x offset)))
+ (set-rect-y! rect (- (vec2-y offset)))
+ (set-rect-width! rect (rect-width region))
+ (set-rect-height! rect (rect-height region)))
+ ((and (not matrix)
+ (zero? rotation)
+ (= scale 1.0))
+ ;; No region specified and no transformation
+ ;; matrix. Use texture width/height for the
+ ;; dimensions of the region.
+ (set-rect-x! rect (- (vec2-x region) (vec2-x offset)))
+ (set-rect-y! rect (- (vec2-y region) (vec2-y offset)))
+ (set-rect-width! rect (f32vector-ref size 0))
+ (set-rect-height! rect (f32vector-ref size 1)))
+ (else
+ ;; No region specified but we will be using a
+ ;; transformation matrix.
+ (set-rect-x! rect (- (vec2-x offset)))
+ (set-rect-y! rect (- (vec2-y offset)))
+ (set-rect-width! rect (f32vector-ref size 0))
+ (set-rect-height! rect (f32vector-ref size 1))))
(if *batch?*
- (draw-sprite-batched texture region
- scale rotation blend-mode shader
- texcoords)
- (draw-sprite-unbatched texture region
- scale rotation blend-mode shader
- texcoords))))))
+ (draw-sprite-batched texture rect matrix blend-mode
+ shader texcoords)
+ (draw-sprite-unbatched texture rect matrix blend-mode
+ shader texcoords))))))
;;;
@@ -412,7 +448,11 @@ rendered entirely."
(lambda* (texture region #:key (margin 0)
(top-margin margin) (bottom-margin margin)
(left-margin margin) (right-margin margin)
- scale rotation (blend-mode 'alpha)
+ (offset %default-offset)
+ (rotation 0)
+ (scale 1.0)
+ matrix
+ (blend-mode 'alpha)
(shader (force default-shader)))
"Draw a \"nine patch\" sprite. A nine patch sprite renders
TEXTURE as a WIDTH x HEIGHT rectangle whose stretchable areas are
@@ -463,8 +503,10 @@ LEFT-MARGIN, and RIGHT-MARGIN arguments may be used."
(set-rect-height! trect (- t2 t1))
(draw-sprite texture rect
#:texcoords trect
+ #:offset offset
#:scale scale
#:rotation rotation
+ #:matrix matrix
#:blend-mode blend-mode
#:shader shader))
(with-batched-sprites