;; pick the right procedure based on the size of the variable ;; vector sizes expand to 2, 3 or 4 dimensions. ;; (pp (expand '(vector-length-dispatch variable f32vector +/type/for/variable))) (define-syntax vector-length-dispatch (er-macro-transformer (lambda (x r t) (let* ((variable (cadr x)) (vtype (caddr x)) (form (cadddr x)) (precision-prefix (case vtype ((f32vector) "") ((f64vector) 'd) ((s32vector) 'i) ((u32vector) 'u) ((u8vector) 'b))) (vector-type? (string->symbol (conc vtype "?"))) (vector-length (string->symbol (conc vtype "-length")))) `(begin (,(r 'case) (,vector-length ,variable) ((2) ,(rewrite form variable (conc precision-prefix "vec2"))) ((3) ,(rewrite form variable (conc precision-prefix "vec3"))) ((4) ,(rewrite form variable (conc precision-prefix "vec4"))))))))) ;; *** vector constructors (begin-template `((P vec dvec ivec uvec bvec) (R ,glmtype->schemetype)) ;; f32vector s32vector etc (define (P2 x y) (R x y)) (define (P3 x y z) (R x y z)) (define (P4 x y z w) (R x y z w))) (begin-template `((D 2 3 4)) (define (make-vecD fill) (make-f32vector D fill)) (define (make-dvecD fill) (make-f64vector D fill)) (define (make-ivecD fill) (make-s32vector D fill)) (define (make-uvecD fill) (make-u32vector D fill)) (define (make-bvecD fill) (make-u8vector D fill))) ;; OBS: we won't be able to distinguish between vec4 and mat2 for example (begin-template `((D 2 3 4)) (define ( vecD? vec) (and (f32vector? vec) (= (f32vector-length vec) D))) (define (dvecD? vec) (and (f64vector? vec) (= (f64vector-length vec) D))) (define (ivecD? vec) (and (s32vector? vec) (= (s32vector-length vec) D))) (define (uvecD? vec) (and (u32vector? vec) (= (u32vector-length vec) D))) (define (bvecD? vec) (and (u8vector? vec) (= (u8vector-length vec) D)))) ;;; vector operations (begin-template `((T vec2 vec3 vec4 dvec2 dvec3 dvec4 uvec2 uvec3 uvec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 ) (R ,value-type)) ;; unary operators (define length/T (glm R "return(" "glm::length(" T "));")) ;; infix operators (begin-template `((OP + - * /) ) (define OP/T/T! (glm void T "=" T "OP" T)) (define (OP/T/T operand1 operand2) (with-destination (make-T #f) OP/T/T! operand1 operand2))) ;; vector unary operators (begin-template `((OP abs ceil floor fract round roundEven sign sin cos tan sinh cosh tanh asin acos atan asinh acosh atanh degrees radians exp exp2 inversesqrt log log2 sqrt normalize )) (define OP/T! (glm void T "=" "glm::OP(" T ")")) (define (OP/T vec) (with-destination (make-T #f) OP/T! vec))) ;; prefix binary operators, primitive return type (begin-template `((OP "dot" "distance")) (define OP/T (glm R "return(" "glm::" "OP" "(" T "," T "));")))) (define (length/vec v) (cond-template `((VECTOR f32vector f64vector s32vector u32vector u8vector)) ((VECTOR? v) ((vector-length-dispatch v VECTOR length/v) v)) (error "unknown vector-type" v))) (begin-template `(( dot distance)) (define ( v1 v2) (cond-template `((VECTOR f32vector f64vector s32vector u32vector u8vector)) ((VECTOR? v2) (if (VECTOR? v2) (if (= (VECTOR-length v1) (VECTOR-length v2)) ((vector-length-dispatch v1 VECTOR /v1) v1 v2) (error "vector length mismatch" v1 v2)) (error "operand two must be vector" v2))) (error "unknown vector-type" v1)))) ;; vector-scalar infix operators (excludes bvec types) (begin-template `((T vec2 vec3 vec4 dvec2 dvec3 dvec4 uvec2 uvec3 uvec4 ivec2 ivec3 ivec4 ) (R ,value-type)) ;; infix operators (begin-template `((OP + - * /) ) (define OP/T/scalar! (glm void T "=" T "OP" R)) (define (OP/T/scalar vec scalar) (with-destination (make-T #f) OP/T/scalar! vec scalar)))) ;; cross is only defined for vec3 (begin-template `((T vec3 dvec3 ivec3 uvec3 bvec3)) (define cross/T! (glm void T "=" "glm::cross(" T "," T ")")) (define (cross/T veca vecb) (with-destination (make-T #f) cross/T! veca vecb))) ;; vector-vector or vector-scalar (begin-template `(( * / + -)) (define (/vec/scalar/delegate vec scalar) (cond ((f32vector? vec) (vector-length-dispatch vec f32vector /vec/scalar)) ((f64vector? vec) (vector-length-dispatch vec f64vector /vec/scalar)) ((s32vector? vec) (vector-length-dispatch vec s32vector /vec/scalar)) ((u32vector? vec) (vector-length-dispatch vec u32vector /vec/scalar)))) (define (v/delegate v1 v2) (if (number? v2) (/vec/scalar/delegate v1 v2) (cond-template `((VECTOR f32vector f64vector s32vector u32vector)) ((VECTOR? v1) (if (VECTOR? v2) (if (= (VECTOR-length v1) (VECTOR-length v2)) (vector-length-dispatch v1 VECTOR /v1/v1) (error "vector dimension mismatch" v1 v2)) (if (number? v2) (vector-length-dispatch v1 VECTOR /v1/scalar) (error "invalid operand types" v1 v2)))) (error "unknown vector type" v1)))) (define (v v1 v2) ((v/delegate v1 v2) v1 v2))) ;; this should do what we want, ;; but let's keep an eye on this guy: (define v= equal?)