Episode 25: 3D Points and Lines (Part 2)
author |
Steve Losh <steve@stevelosh.com> |
date |
Sun, 15 May 2016 19:08:06 +0000 |
parents |
c716dc6a9a47 |
children |
f5e42ff3a78c |
(in-package #:coding-math.3d.demo)
;;;; Config
(setf *bypass-cache* t)
(defparameter *width* 600)
(defparameter *height* 400)
(defparameter *center-x* (/ *width* 2))
(defparameter *center-y* (/ *height* 2))
;;;; Utils
(defmacro with-centered-coords (&body body)
`(in-context
(translate *center-x* *center-y*)
,@body))
(defmacro with-setup (&body body)
`(with-fps
(background (gray 1))
(with-centered-coords
,@body)))
;;;; Draw
(defun draw-point (screen size)
(circle (vec-x screen) (vec-y screen) size))
;;;; Structs
(defstruct (point (:constructor make-point (world &optional screen)))
world screen)
;;;; Sketch
(defun project (points focal-length)
(map nil
(lambda (p)
(with-vecs ((screen (point-screen p))
(world (point-world p)))
(let ((scale (/ focal-length (+ focal-length world.z))))
(setf screen.x (* scale world.x)
screen.y (* scale world.y)))))
points))
(defun translate-model (points x y z)
(map nil (lambda (p)
(with-vec (p (point-world p))
(incf p.x x)
(incf p.y y)
(incf p.z z)))
points))
(defsketch demo
((width *width*) (height *height*) (y-axis :down) (title "Coding Math")
(mouse (cons 0 0))
;; variables
(fl 300.0)
(r 200.0)
(points
(make-array 8
:initial-contents
(list
(make-point (vec (- r) (- r) 1000.0) (zero-vec))
(make-point (vec r (- r) 1000.0) (zero-vec))
(make-point (vec r (- r) 500.0) (zero-vec))
(make-point (vec (- r) (- r) 500.0) (zero-vec))
(make-point (vec (- r) r 1000.0) (zero-vec))
(make-point (vec r r 1000.0) (zero-vec))
(make-point (vec r r 500.0) (zero-vec))
(make-point (vec (- r) r 500.0) (zero-vec)))))
(dirty t)
;; pens
(simple-pen (make-pen :fill (gray 0.1)))
(line-pen (make-pen :stroke (gray 0.1) :weight 1))
)
(with-setup
(flet
((draw-line (&rest vertices)
(loop :for (a b) ; lame way to close the loop...
:in (n-grams 2 (append vertices (list (car vertices))))
:do (with-vecs ((a (point-screen (aref points a)))
(b (point-screen (aref points b))))
(line a.x a.y b.x b.y)))))
(when dirty
(setf dirty nil)
(project points fl))
(with-pen simple-pen
; (loop :for p :across points
; :do (draw-point (point-screen p) 5))
nil)
(with-pen line-pen
(draw-line 0 1 2 3)
(draw-line 0 3 7 4)
(draw-line 1 2 6 5)
(draw-line 6 5 4 7)
nil
))
;;
))
;;;; Mouse
(defun mousemove (instance x y)
(with-slots (mouse) instance
(setf (car mouse) x)
(setf (cdr mouse) y)
;;
;;
)
)
(defun mousedown-left (instance x y)
(declare (ignorable instance x y))
)
(defun mousedown-right (instance x y)
(declare (ignorable instance x y))
)
(defun mouseup-left (instance x y)
(declare (ignorable instance x y))
)
(defun mouseup-right (instance x y)
(declare (ignorable instance x y))
)
(defmethod kit.sdl2:mousemotion-event ((window demo) ts b x y xrel yrel)
(declare (ignore ts b xrel yrel))
(mousemove window x y))
(defmethod kit.sdl2:mousebutton-event ((window demo) state ts button x y)
(declare (ignore ts))
(funcall (case state
(:mousebuttondown
(case button
(1 #'mousedown-left)
(3 #'mousedown-right)))
(:mousebuttonup
(case button
(1 #'mouseup-left)
(3 #'mouseup-right))))
window x y))
;;;; Keyboard
(defun keydown (instance scancode)
(declare (ignorable instance))
(setf (slot-value instance 'dirty) t)
(scancode-case scancode
(:scancode-space (sketch::prepare instance))
;;
(:scancode-left (translate-model (slot-value instance 'points) -15 0 0))
(:scancode-right (translate-model (slot-value instance 'points) 15 0 0))
(:scancode-up (translate-model (slot-value instance 'points) 0 -15 0))
(:scancode-down (translate-model (slot-value instance 'points) 0 15 0))
(:scancode-s (translate-model (slot-value instance 'points) 0 0 -15))
(:scancode-w (translate-model (slot-value instance 'points) 0 0 15))
;;
))
(defun keyup (instance scancode)
(declare (ignorable instance))
(scancode-case scancode
(:scancode-space
nil)))
(defmethod kit.sdl2:keyboard-event ((instance demo) state timestamp repeatp keysym)
(declare (ignore timestamp repeatp))
(cond
((eql state :keyup) (keyup instance (sdl2:scancode-value keysym)))
((eql state :keydown) (keydown instance (sdl2:scancode-value keysym)))
(t nil)))
;;;; Run
; (defparameter *demo* (make-instance 'demo))