├── .gitignore ├── CHANGELOG.org ├── LICENSE ├── README.org ├── assets ├── gl │ ├── cubev.png │ ├── earth-1024.jpg │ ├── earth-bump-1024.jpg │ ├── earth-specular-1024.jpg │ └── lancellotti.jpg ├── mesh │ ├── icosphere.svg │ └── suzanne.stl ├── overview.dot ├── overview.svg ├── ptf │ ├── ptf-knot-weave-spectrum.jpg │ ├── ptf-knot-weave.jpg │ ├── ptf-knot-weave2.jpg │ ├── ptf-knot.jpg │ └── ptf-spline.jpg ├── subdiv │ └── sd-compare.svg ├── svg │ ├── hero.svg │ ├── icosphere.svg │ ├── svgdemo01-circles.svg │ ├── svgdemo02-suzanne.svg │ ├── svgdemo03-diffuse.svg │ ├── svgdemo03-lambert.svg │ ├── svgdemo03-phong.svg │ ├── svgdemo04-spiral.svg │ ├── svgdemo05-instancing.svg │ └── svgdemo06-decorators.svg ├── viz │ ├── areaplot-3.svg │ ├── areaplot-polar-3.svg │ ├── bars-3.svg │ ├── bars-interleave-3.svg │ ├── bars-interleave.svg │ ├── bars.svg │ ├── california-detail-gis.png │ ├── commit-history.svg │ ├── contours-2.svg │ ├── contours-3.svg │ ├── contours-4.svg │ ├── contours-log-2.svg │ ├── contours-log-3.svg │ ├── contours-log-4.svg │ ├── contours-log-outline-2.svg │ ├── contours-log-outline-3.svg │ ├── contours-log-outline-4.svg │ ├── contours-log-outline.svg │ ├── contours-log.svg │ ├── contours-log3.svg │ ├── contours-outline-2.svg │ ├── contours-outline-3.svg │ ├── contours-outline-4.svg │ ├── contours-outline.svg │ ├── contours-polar.gif │ ├── contours.svg │ ├── hm-orange-blue.svg │ ├── hm-rainbow2.svg │ ├── hmp-green-magenta.svg │ ├── hmp-yellow-magenta-cyan.svg │ ├── hms-rainbow2.svg │ ├── hmsp-rainbow2.svg │ ├── intervals-2.svg │ ├── intervals-3.svg │ ├── intervals.svg │ ├── lens-focus-2.gif │ ├── lens-focus.gif │ ├── lens-strength-2.gif │ ├── lens-strength-3.gif │ ├── lens-strength-4.gif │ ├── lens-strength.gif │ ├── lineplot-2.svg │ ├── lineplot-3.svg │ ├── lineplot-polar-3.svg │ ├── lineplot-polar.svg │ ├── lineplot.svg │ ├── radarplot-3.svg │ ├── radarplot-minmax.svg │ ├── scatter-3.svg │ ├── scatter-linear-2.svg │ ├── scatter-linear-3.svg │ ├── scatter-linear.svg │ ├── scatter-log-2.svg │ ├── scatter-log-3.svg │ ├── scatter-log.svg │ ├── terrain-12.svg │ ├── terrain-18.svg │ ├── terrain-24.svg │ ├── terrain-6.svg │ ├── timeline-2.svg │ ├── timeline-3.svg │ ├── timeline-separate-3.svg │ └── timeline.svg └── voxel │ ├── svo-d7.jpg │ ├── svo-simplexnoise.jpg │ └── svo-sphere-erosion.jpg ├── benchmarks └── thi │ └── ng │ └── geom │ └── bench │ └── core │ ├── vector.clj │ └── vector.cljs ├── deps.edn ├── examples ├── gl │ ├── colored_cube.cljs │ ├── gears2d.cljs │ ├── gears3d.cljs │ ├── multi_textures.cljs │ ├── picking.cljs │ ├── render_to_texture.cljs │ ├── shaded_cube.cljs │ ├── stl_mesh.cljs │ ├── textured_cube.cljs │ └── torus_knot.cljs ├── jogl │ ├── fullscreen_shader.clj │ ├── fx_pipeline.clj │ ├── stl_mesh.clj │ └── textured_cube.clj ├── repl.clj ├── svg │ ├── circles.clj │ ├── decorators.clj │ ├── instancing.clj │ ├── rings.clj │ ├── spiral.clj │ ├── stl_mesh.clj │ └── subdiv.clj ├── viz │ ├── bars.clj │ ├── contours.clj │ ├── heatmap.clj │ ├── hm-github.clj │ ├── intervals.clj │ ├── lineplot.clj │ ├── radar.clj │ ├── scatter.clj │ ├── terrain.clj │ └── timeline.clj └── voxel │ ├── gyroid.clj │ ├── noise.clj │ └── sphere.clj ├── index.html ├── org ├── bench │ └── core │ │ └── vector.org ├── examples │ ├── all.org │ ├── gl │ │ ├── jogl.org │ │ └── webgl.org │ ├── ptf │ │ └── demos.org │ ├── svg │ │ └── demos.org │ ├── viz │ │ └── demos.org │ └── voxel │ │ └── demos.org └── src │ ├── core │ ├── core.org │ ├── matrix.org │ ├── quaternion.org │ └── vector.org │ ├── gl │ ├── animator.org │ ├── arcball.org │ ├── buffers.org │ ├── camera.org │ ├── constants-jogl.org │ ├── constants-webgl.org │ ├── core.org │ ├── fx-presets.org │ ├── fx.org │ ├── glmesh.org │ ├── jogl-buffers.org │ ├── jogl.org │ ├── shader-presets.org │ ├── shaders.org │ └── utils.org │ ├── mesh │ ├── csg.org │ ├── io.org │ ├── ops.org │ └── subdivision.org │ ├── physics │ └── core.org │ ├── svg │ ├── adapter.org │ ├── core.org │ ├── renderer.org │ └── shaders.org │ ├── types │ ├── aabb.org │ ├── attribs.org │ ├── basicmesh.org │ ├── bezier.org │ ├── circle.org │ ├── cuboid.org │ ├── gmesh.org │ ├── indexedmesh.org │ ├── line.org │ ├── mesh.org │ ├── meshface.org │ ├── path.org │ ├── plane.org │ ├── polygon.org │ ├── polyhedra.org │ ├── ptf.org │ ├── quad.org │ ├── rect.org │ ├── spatialtree.org │ ├── sphere.org │ ├── tetrahedron.org │ ├── triangle.org │ └── types.org │ ├── utils │ ├── delaunay.org │ ├── intersect.org │ ├── subdiv.org │ └── utils.org │ ├── viz │ └── core.org │ └── voxel │ ├── isosurface.org │ └── svo.org ├── out └── .empty ├── project.clj ├── src ├── data_readers.cljc └── thi │ └── ng │ └── geom │ ├── aabb.cljc │ ├── attribs.cljc │ ├── basicmesh.cljc │ ├── bezier.cljc │ ├── circle.cljc │ ├── core.cljc │ ├── cuboid.cljc │ ├── gl │ ├── arcball.cljc │ ├── buffers.cljc │ ├── camera.cljc │ ├── core.cljc │ ├── fx.cljc │ ├── fx │ │ └── bloom.cljc │ ├── glmesh.cljc │ ├── jogl │ │ ├── buffers.clj │ │ ├── constants.clj │ │ └── core.clj │ ├── shaders.cljc │ ├── shaders │ │ ├── basic.cljc │ │ ├── image.cljc │ │ ├── lambert.cljc │ │ ├── phong.cljc │ │ ├── shadow.cljs │ │ ├── spotlight.cljc │ │ └── xray.cljc │ ├── utils.cljs │ └── webgl │ │ ├── animator.cljs │ │ └── constants.cljs │ ├── gmesh.cljc │ ├── indexedmesh.cljc │ ├── line.cljc │ ├── macros │ ├── matrix.clj │ ├── vector.clj │ └── voxel.clj │ ├── matrix.cljc │ ├── mesh │ ├── csg.cljc │ ├── io.cljc │ ├── ops.cljc │ └── subdivision.cljc │ ├── meshface.cljc │ ├── path.cljc │ ├── physics │ └── core.cljc │ ├── plane.cljc │ ├── polygon.cljc │ ├── polyhedra.cljc │ ├── ptf.cljc │ ├── quad.cljc │ ├── quaternion.cljc │ ├── rect.cljc │ ├── spatialtree.cljc │ ├── sphere.cljc │ ├── svg │ ├── adapter.cljc │ ├── core.cljc │ ├── renderer.cljc │ └── shaders.cljc │ ├── tetrahedron.cljc │ ├── triangle.cljc │ ├── types.cljc │ ├── utils.cljc │ ├── utils │ ├── delaunay.cljc │ ├── intersect.cljc │ └── subdiv.cljc │ ├── vector.cljc │ ├── version.cljc │ ├── viz │ └── core.cljc │ └── voxel │ ├── isosurface.cljc │ └── svo.cljc ├── test └── thi │ └── ng │ └── geom │ └── test │ ├── core │ ├── core.cljc │ └── protocols.cljc │ ├── mesh │ └── core.cljc │ ├── physics │ └── core.cljc │ ├── svg │ └── core.cljc │ ├── types │ ├── aabb.cljc │ ├── bezier.cljc │ ├── cuboid.cljc │ ├── line.cljc │ ├── polygon.cljc │ ├── protocols.cljc │ └── utils.cljc │ ├── viz │ └── core.cljc │ └── voxel │ └── core.cljc └── update-changelog.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .lein-deps-sum 2 | .lein-failures 3 | .lein-plugins 4 | .lein-repl-history 5 | .nrepl-port 6 | /.cpcache 7 | /classes 8 | /out 9 | /target 10 | pom.xml 11 | pom.xml.asc 12 | -------------------------------------------------------------------------------- /assets/gl/cubev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/gl/cubev.png -------------------------------------------------------------------------------- /assets/gl/earth-1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/gl/earth-1024.jpg -------------------------------------------------------------------------------- /assets/gl/earth-bump-1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/gl/earth-bump-1024.jpg -------------------------------------------------------------------------------- /assets/gl/earth-specular-1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/gl/earth-specular-1024.jpg -------------------------------------------------------------------------------- /assets/gl/lancellotti.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/gl/lancellotti.jpg -------------------------------------------------------------------------------- /assets/mesh/suzanne.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/mesh/suzanne.stl -------------------------------------------------------------------------------- /assets/ptf/ptf-knot-weave-spectrum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/ptf/ptf-knot-weave-spectrum.jpg -------------------------------------------------------------------------------- /assets/ptf/ptf-knot-weave.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/ptf/ptf-knot-weave.jpg -------------------------------------------------------------------------------- /assets/ptf/ptf-knot-weave2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/ptf/ptf-knot-weave2.jpg -------------------------------------------------------------------------------- /assets/ptf/ptf-knot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/ptf/ptf-knot.jpg -------------------------------------------------------------------------------- /assets/ptf/ptf-spline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/ptf/ptf-spline.jpg -------------------------------------------------------------------------------- /assets/svg/svgdemo01-circles.svg: -------------------------------------------------------------------------------- 1 | 2 | ABCD -------------------------------------------------------------------------------- /assets/svg/svgdemo04-spiral.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /assets/svg/svgdemo06-decorators.svg: -------------------------------------------------------------------------------- 1 | 2 | Jan 2014Feb 2014Mar 2014 -------------------------------------------------------------------------------- /assets/viz/california-detail-gis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/viz/california-detail-gis.png -------------------------------------------------------------------------------- /assets/viz/contours-polar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/viz/contours-polar.gif -------------------------------------------------------------------------------- /assets/viz/intervals-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 0.00100.00200.00300.00 -------------------------------------------------------------------------------- /assets/viz/intervals-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 0.00100.00200.00300.00 -------------------------------------------------------------------------------- /assets/viz/intervals.svg: -------------------------------------------------------------------------------- 1 | 2 | 0.00100.00200.00300.00 -------------------------------------------------------------------------------- /assets/viz/lens-focus-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/viz/lens-focus-2.gif -------------------------------------------------------------------------------- /assets/viz/lens-focus.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/viz/lens-focus.gif -------------------------------------------------------------------------------- /assets/viz/lens-strength-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/viz/lens-strength-2.gif -------------------------------------------------------------------------------- /assets/viz/lens-strength-3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/viz/lens-strength-3.gif -------------------------------------------------------------------------------- /assets/viz/lens-strength-4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/viz/lens-strength-4.gif -------------------------------------------------------------------------------- /assets/viz/lens-strength.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/viz/lens-strength.gif -------------------------------------------------------------------------------- /assets/viz/radarplot-3.svg: -------------------------------------------------------------------------------- 1 | 2 | C1C2C3C4C5C60%50%100% -------------------------------------------------------------------------------- /assets/viz/radarplot-minmax.svg: -------------------------------------------------------------------------------- 1 | 2 | C1C2C3C4C5C60%50%100% -------------------------------------------------------------------------------- /assets/voxel/svo-d7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/voxel/svo-d7.jpg -------------------------------------------------------------------------------- /assets/voxel/svo-simplexnoise.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/voxel/svo-simplexnoise.jpg -------------------------------------------------------------------------------- /assets/voxel/svo-sphere-erosion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/assets/voxel/svo-sphere-erosion.jpg -------------------------------------------------------------------------------- /benchmarks/thi/ng/geom/bench/core/vector.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.bench.core.vector 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.utils :as gu] 5 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 6 | [thi.ng.math.core :as m :refer [*eps* HALF_PI PI]] 7 | [perforate-x.core :refer :all])) 8 | 9 | (def A2 (vec2 1 2)) 10 | (def B2 (vec2 10 20)) 11 | (def C2 (vec2 100 200)) 12 | (def D2 (vec2 1000 2000)) 13 | 14 | (def A3 (vec3 1 2 3)) 15 | (def B3 (vec3 10 20 30)) 16 | (def C3 (vec3 100 200 300)) 17 | (def D3 (vec3 1000 2000 3000)) 18 | 19 | (def N 10.0) 20 | (def M 100.0) 21 | (def O 1000.0) 22 | 23 | (defgoal :vec2-ops "vec2-ops") 24 | 25 | (defcase :vec2-ops :add-v 26 | [] #(m/+ A2 B2)) 27 | 28 | (defcase :vec2-ops :add-vv 29 | [] #(m/+ A2 B2 C2)) 30 | 31 | (defcase :vec2-ops :add-n 32 | [] #(m/+ A2 N)) 33 | 34 | (defcase :vec2-ops :add-nn 35 | [] #(m/+ A2 N M)) 36 | 37 | (defcase :vec2-ops :add-s 38 | [] #(m/+ A2 [N M])) 39 | 40 | (defcase :vec2-ops :scale-v 41 | [] #(m/* A2 B2)) 42 | 43 | (defcase :vec2-ops :scale-n 44 | [] #(m/* A2 N)) 45 | 46 | (defcase :vec2-ops :madd 47 | [] #(m/madd A2 N B2)) 48 | 49 | (defcase :vec2-ops :madd-op2 50 | [] #(m/* (m/+ A2 N) B2)) 51 | 52 | (defcase :vec2-ops :dot 53 | [] #(m/dot A2 B2)) 54 | 55 | (defcase :vec2-ops :normalize 56 | [] #(m/normalize A2)) 57 | 58 | (defcase :vec2-ops :mag 59 | [] #(m/mag A2)) 60 | 61 | (defcase :vec2-ops :mag-squared 62 | [] #(m/mag-squared A2)) 63 | 64 | (defcase :vec2-ops :mix 65 | [] #(m/mix A2 B2 0.5)) 66 | 67 | (defcase :vec2-ops :mix-bi 68 | [] #(m/mix A2 B2 C2 D2 0.5 0.5)) 69 | 70 | (defcase :vec2-ops :rotate 71 | [] #(g/rotate A2 HALF_PI)) 72 | 73 | (defgoal :vec2-ops-mut "vec2-ops-mutable") 74 | 75 | (defcase :vec2-ops-mut :add-v-ctor 76 | [] #(m/+ (vec2 1 2) B2)) 77 | 78 | (defcase :vec2-ops-mut :add-v! 79 | [] #(m/+! (vec2 1 2) B2)) 80 | 81 | (defcase :vec2-ops-mut :madd-v-ctor 82 | [] #(m/madd (vec2 1 2) N B2)) 83 | 84 | (defcase :vec2-ops-mut :madd-v! 85 | [] #(m/madd! (vec2 1 2) N B2)) 86 | 87 | (defgoal :vec3-ops "vec3-ops") 88 | 89 | (defcase :vec3-ops :add-v 90 | [] #(m/+ A3 B3)) 91 | 92 | (defcase :vec3-ops :add-vv 93 | [] #(m/+ A3 B3 C3)) 94 | 95 | (defcase :vec3-ops :add-n 96 | [] #(m/+ A3 N)) 97 | 98 | (defcase :vec3-ops :add-nnn 99 | [] #(m/+ A3 N M O)) 100 | 101 | (defcase :vec3-ops :add-s 102 | [] #(m/+ A3 [N M O])) 103 | 104 | (defcase :vec3-ops :scale-v 105 | [] #(m/* A3 B3)) 106 | 107 | (defcase :vec3-ops :scale-n 108 | [] #(m/* A3 N)) 109 | 110 | (defcase :vec3-ops :madd 111 | [] #(m/madd A3 N B3)) 112 | 113 | (defcase :vec3-ops :madd-op2 114 | [] #(m/* (m/+ A3 N) B3)) 115 | 116 | (defcase :vec3-ops :dot 117 | [] #(m/dot A3 B3)) 118 | 119 | (defcase :vec3-ops :cross 120 | [] #(m/cross A3 B3)) 121 | 122 | (defcase :vec3-ops :ortho-normal 123 | [] #(gu/ortho-normal A3 B3 C3)) 124 | 125 | (defcase :vec3-ops :normalize 126 | [] #(m/normalize A3)) 127 | 128 | (defcase :vec3-ops :mag 129 | [] #(m/mag A3)) 130 | 131 | (defcase :vec3-ops :mag-squared 132 | [] #(m/mag-squared A3)) 133 | 134 | (defcase :vec3-ops :mix 135 | [] #(m/mix A3 B3 0.5)) 136 | 137 | (defcase :vec3-ops :mix-bi 138 | [] #(m/mix A3 B3 C3 D3 0.5 0.5)) 139 | 140 | (defcase :vec3-ops :rotate-x 141 | [] #(g/rotate-x A3 HALF_PI)) 142 | 143 | (defcase :vec3-ops :rotate-axis 144 | [] #(g/rotate-around-axis A3 v/V3Y HALF_PI)) 145 | -------------------------------------------------------------------------------- /benchmarks/thi/ng/geom/bench/core/vector.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.bench.core.vector 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.utils :as gu] 5 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 6 | [thi.ng.math.core :as m :refer [*eps* HALF_PI PI]] 7 | [perforate-x.core :as perf :refer [defgoal defcase]])) 8 | 9 | (def A2 (vec2 1 2)) 10 | (def B2 (vec2 10 20)) 11 | (def C2 (vec2 100 200)) 12 | (def D2 (vec2 1000 2000)) 13 | 14 | (def A3 (vec3 1 2 3)) 15 | (def B3 (vec3 10 20 30)) 16 | (def C3 (vec3 100 200 300)) 17 | (def D3 (vec3 1000 2000 3000)) 18 | 19 | (def N 10.0) 20 | (def M 100.0) 21 | (def O 1000.0) 22 | 23 | (defgoal :vec2-ops "vec2-ops") 24 | 25 | (defcase :vec2-ops :add-v 26 | [] #(m/+ A2 B2)) 27 | 28 | (defcase :vec2-ops :add-vv 29 | [] #(m/+ A2 B2 C2)) 30 | 31 | (defcase :vec2-ops :add-n 32 | [] #(m/+ A2 N)) 33 | 34 | (defcase :vec2-ops :add-nn 35 | [] #(m/+ A2 N M)) 36 | 37 | (defcase :vec2-ops :add-s 38 | [] #(m/+ A2 [N M])) 39 | 40 | (defcase :vec2-ops :scale-v 41 | [] #(m/* A2 B2)) 42 | 43 | (defcase :vec2-ops :scale-n 44 | [] #(m/* A2 N)) 45 | 46 | (defcase :vec2-ops :madd 47 | [] #(m/madd A2 N B2)) 48 | 49 | (defcase :vec2-ops :madd-op2 50 | [] #(m/* (m/+ A2 N) B2)) 51 | 52 | (defcase :vec2-ops :dot 53 | [] #(m/dot A2 B2)) 54 | 55 | (defcase :vec2-ops :normalize 56 | [] #(m/normalize A2)) 57 | 58 | (defcase :vec2-ops :mag 59 | [] #(m/mag A2)) 60 | 61 | (defcase :vec2-ops :mag-squared 62 | [] #(m/mag-squared A2)) 63 | 64 | (defcase :vec2-ops :mix 65 | [] #(m/mix A2 B2 0.5)) 66 | 67 | (defcase :vec2-ops :mix-bi 68 | [] #(m/mix A2 B2 C2 D2 0.5 0.5)) 69 | 70 | (defcase :vec2-ops :rotate 71 | [] #(g/rotate A2 HALF_PI)) 72 | (defgoal :vec2-ops-mut "vec2-ops-mutable") 73 | 74 | (defcase :vec2-ops-mut :add-v-ctor 75 | [] #(m/+ (vec2 1 2) B2)) 76 | 77 | (defcase :vec2-ops-mut :add-v! 78 | [] #(m/+! (vec2 1 2) B2)) 79 | 80 | (defcase :vec2-ops-mut :madd-v-ctor 81 | [] #(m/madd (vec2 1 2) N B2)) 82 | 83 | (defcase :vec2-ops-mut :madd-v! 84 | [] #(m/madd! (vec2 1 2) N B2)) 85 | 86 | (defgoal :vec3-ops "vec3-ops") 87 | 88 | (defcase :vec3-ops :add-v 89 | [] #(m/+ A3 B3)) 90 | 91 | (defcase :vec3-ops :add-vv 92 | [] #(m/+ A3 B3 C3)) 93 | 94 | (defcase :vec3-ops :add-n 95 | [] #(m/+ A3 N)) 96 | 97 | (defcase :vec3-ops :add-nnn 98 | [] #(m/+ A3 N M O)) 99 | 100 | (defcase :vec3-ops :add-s 101 | [] #(m/+ A3 [N M O])) 102 | 103 | (defcase :vec3-ops :scale-v 104 | [] #(m/* A3 B3)) 105 | 106 | (defcase :vec3-ops :scale-n 107 | [] #(m/* A3 N)) 108 | 109 | (defcase :vec3-ops :madd 110 | [] #(m/madd A3 N B3)) 111 | 112 | (defcase :vec3-ops :madd-op2 113 | [] #(m/* (m/+ A3 N) B3)) 114 | 115 | (defcase :vec3-ops :dot 116 | [] #(m/dot A3 B3)) 117 | 118 | (defcase :vec3-ops :cross 119 | [] #(m/cross A3 B3)) 120 | 121 | (defcase :vec3-ops :ortho-normal 122 | [] #(gu/ortho-normal A3 B3 C3)) 123 | 124 | (defcase :vec3-ops :normalize 125 | [] #(m/normalize A3)) 126 | 127 | (defcase :vec3-ops :mag 128 | [] #(m/mag A3)) 129 | 130 | (defcase :vec3-ops :mag-squared 131 | [] #(m/mag-squared A3)) 132 | 133 | (defcase :vec3-ops :mix 134 | [] #(m/mix A3 B3 0.5)) 135 | 136 | (defcase :vec3-ops :mix-bi 137 | [] #(m/mix A3 B3 C3 D3 0.5 0.5)) 138 | 139 | (defcase :vec3-ops :rotate-x 140 | [] #(g/rotate-x A3 HALF_PI)) 141 | 142 | (defcase :vec3-ops :rotate-axis 143 | [] #(g/rotate-around-axis A3 v/V3Y HALF_PI)) 144 | 145 | (perf/run-goals) 146 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src"] 2 | 3 | :deps {org.clojure/clojure {:mvn/version "1.11.1"} 4 | org.clojure/clojurescript {:mvn/version "1.11.121"} 5 | thi.ng/color {:mvn/version "1.5.1"} 6 | thi.ng/dstruct {:mvn/version "0.2.2"} 7 | thi.ng/math {:mvn/version "0.3.2"} 8 | thi.ng/ndarray {:mvn/version "0.3.3"} 9 | thi.ng/shadergraph {:mvn/version "0.3.1"} 10 | thi.ng/strf {:mvn/version "0.2.4"} 11 | thi.ng/typedarrays {:mvn/version "0.1.7"} 12 | thi.ng/xerror {:mvn/version "0.1.0"} 13 | org.jogamp.gluegen/gluegen-rt {:mvn/version "2.3.2"} 14 | org.jogamp.jogl/jogl-all {:mvn/version "2.3.2"} 15 | cljs-log {:mvn/version "0.2.2"} 16 | hiccup {:mvn/version "1.0.5"}}} 17 | -------------------------------------------------------------------------------- /examples/gl/colored_cube.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.gl.colored-cube 2 | (:require-macros 3 | [thi.ng.math.macros :as mm]) 4 | (:require 5 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]] 6 | [thi.ng.color.core :as col] 7 | [thi.ng.typedarrays.core :as arrays] 8 | [thi.ng.geom.gl.core :as gl] 9 | [thi.ng.geom.gl.webgl.constants :as glc] 10 | [thi.ng.geom.gl.webgl.animator :as anim] 11 | [thi.ng.geom.gl.buffers :as buf] 12 | [thi.ng.geom.gl.shaders :as sh] 13 | [thi.ng.geom.gl.utils :as glu] 14 | [thi.ng.geom.gl.glmesh :as glm] 15 | [thi.ng.geom.gl.camera :as cam] 16 | [thi.ng.geom.core :as g] 17 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 18 | [thi.ng.geom.matrix :as mat :refer [M44]] 19 | [thi.ng.geom.aabb :as a] 20 | [thi.ng.geom.attribs :as attr] 21 | [thi.ng.glsl.core :as glsl :include-macros true] 22 | [thi.ng.geom.gl.shaders.basic :as basic])) 23 | 24 | (defn ^:export demo 25 | [] 26 | (let [gl (gl/gl-context "main") 27 | view-rect (gl/get-viewport-rect gl) 28 | model (-> (a/aabb 0.8) 29 | (g/center) 30 | (g/as-mesh 31 | {:mesh (glm/indexed-gl-mesh 12 #{:col}) 32 | :attribs {:col (->> [[1 0 0] [0 1 0] [0 0 1] [0 1 1] [1 0 1] [1 1 0]] 33 | (map col/rgba) 34 | (attr/const-face-attribs))}}) 35 | (gl/as-gl-buffer-spec {}) 36 | (cam/apply (cam/perspective-camera {:aspect view-rect})) 37 | (assoc :shader (sh/make-shader-from-spec gl (basic/make-shader-spec-3d true))) 38 | (gl/make-buffers-in-spec gl glc/static-draw))] 39 | (anim/animate 40 | (fn [t frame] 41 | (doto gl 42 | (gl/set-viewport view-rect) 43 | (gl/clear-color-and-depth-buffer col/WHITE 1) 44 | (gl/enable glc/depth-test) 45 | (gl/draw-with-shader 46 | (assoc-in model [:uniforms :model] (-> M44 (g/rotate-x t) (g/rotate-y (* t 2)))))) 47 | true)))) 48 | -------------------------------------------------------------------------------- /examples/gl/gears2d.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.gl.gears2d 2 | (:require-macros 3 | [thi.ng.math.macros :as mm]) 4 | (:require 5 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]] 6 | [thi.ng.color.core :as col] 7 | [thi.ng.typedarrays.core :as arrays] 8 | [thi.ng.geom.gl.core :as gl] 9 | [thi.ng.geom.gl.webgl.constants :as glc] 10 | [thi.ng.geom.gl.webgl.animator :as anim] 11 | [thi.ng.geom.gl.buffers :as buf] 12 | [thi.ng.geom.gl.shaders :as sh] 13 | [thi.ng.geom.gl.utils :as glu] 14 | [thi.ng.geom.gl.glmesh :as glm] 15 | [thi.ng.geom.gl.camera :as cam] 16 | [thi.ng.geom.core :as g] 17 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 18 | [thi.ng.geom.matrix :as mat :refer [M44]] 19 | [thi.ng.geom.aabb :as a] 20 | [thi.ng.geom.attribs :as attr] 21 | [thi.ng.glsl.core :as glsl :include-macros true] 22 | [thi.ng.geom.gl.shaders.basic :as basic] 23 | [thi.ng.geom.circle :as c] 24 | [thi.ng.geom.polygon :as poly])) 25 | 26 | (defn ^:export demo 27 | [] 28 | (enable-console-print!) 29 | (let [gl (gl/gl-context "main") 30 | view-rect (gl/get-viewport-rect gl) 31 | shader1 (sh/make-shader-from-spec gl (basic/make-shader-spec-2d false)) 32 | shader2 (sh/make-shader-from-spec gl (basic/make-shader-spec-2d true)) 33 | teeth 20 34 | model (-> (poly/cog 0.5 teeth [0.9 1 1 0.9]) 35 | (gl/as-gl-buffer-spec {:normals false :fixed-color [1 0 0 1]}) 36 | (gl/make-buffers-in-spec gl glc/static-draw) 37 | (assoc-in [:uniforms :proj] (gl/ortho view-rect)) 38 | (time))] 39 | (anim/animate 40 | (fn [t frame] 41 | (gl/set-viewport gl view-rect) 42 | (gl/clear-color-and-depth-buffer gl 1 0.98 0.95 1 1) 43 | ;; draw left polygon using color uniform (that's why we need to remove color attrib) 44 | (gl/draw-with-shader 45 | gl (-> model 46 | (assoc :shader shader1) 47 | (update-in [:attribs] dissoc :color) 48 | (update-in [:uniforms] merge 49 | {:model (-> M44 (g/translate (vec3 -0.48 0 0)) (g/rotate t)) 50 | :color [0 1 1 1]}))) 51 | ;; draw right polygon using color attribs 52 | (gl/draw-with-shader 53 | gl (-> model 54 | (assoc :shader shader2) 55 | (assoc-in [:uniforms :model] 56 | (-> M44 (g/translate (vec3 0.48 0 0)) (g/rotate (- (+ t (/ HALF_PI teeth)))))))) 57 | true)))) 58 | -------------------------------------------------------------------------------- /examples/gl/gears3d.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.gl.gears3d 2 | (:require-macros 3 | [thi.ng.math.macros :as mm]) 4 | (:require 5 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]] 6 | [thi.ng.color.core :as col] 7 | [thi.ng.typedarrays.core :as arrays] 8 | [thi.ng.geom.gl.core :as gl] 9 | [thi.ng.geom.gl.webgl.constants :as glc] 10 | [thi.ng.geom.gl.webgl.animator :as anim] 11 | [thi.ng.geom.gl.buffers :as buf] 12 | [thi.ng.geom.gl.shaders :as sh] 13 | [thi.ng.geom.gl.utils :as glu] 14 | [thi.ng.geom.gl.glmesh :as glm] 15 | [thi.ng.geom.gl.camera :as cam] 16 | [thi.ng.geom.core :as g] 17 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 18 | [thi.ng.geom.matrix :as mat :refer [M44]] 19 | [thi.ng.geom.aabb :as a] 20 | [thi.ng.geom.attribs :as attr] 21 | [thi.ng.glsl.core :as glsl :include-macros true] 22 | [thi.ng.geom.gl.shaders.phong :as phong] 23 | [thi.ng.geom.circle :as c] 24 | [thi.ng.geom.polygon :as poly])) 25 | 26 | (defn ^:export demo 27 | [] 28 | (enable-console-print!) 29 | (let [gl (gl/gl-context "main") 30 | view-rect (gl/get-viewport-rect gl) 31 | teeth 20 32 | model (-> (poly/cog 0.5 teeth [0.9 1 1 0.9]) 33 | (g/extrude-shell {:mesh (glm/indexed-gl-mesh 1000 #{:fnorm}) 34 | :depth 0.1 35 | :inset 0.025 36 | :wall 0.015 37 | :bottom? true}) 38 | (gl/as-gl-buffer-spec {}) 39 | (cam/apply (cam/perspective-camera {:aspect view-rect})) 40 | (assoc :shader (sh/make-shader-from-spec gl phong/shader-spec)) 41 | (update :uniforms merge 42 | {:lightPos (vec3 0.1 0 1) 43 | :ambientCol 0x0e1a4c 44 | :diffuseCol 0xff3310 45 | :specularCol 0x99ffff 46 | :shininess 100 47 | :wrap 0 48 | :useBlinnPhong true}) 49 | (gl/make-buffers-in-spec gl glc/static-draw) 50 | (time))] 51 | (anim/animate 52 | (fn [t frame] 53 | (let [rot (g/rotate-y M44 (* t 0.5)) 54 | tx1 (m/* rot (-> M44 55 | (g/translate (vec3 -0.46 0 0)) 56 | (g/rotate-y 0.3) 57 | (g/rotate-z t))) 58 | tx2 (m/* rot (-> M44 59 | (g/translate (vec3 0.46 0 0)) 60 | (g/rotate-y -0.3) 61 | (g/rotate-z (- (+ t (/ HALF_PI teeth))))))] 62 | (doto gl 63 | (gl/set-viewport view-rect) 64 | (gl/clear-color-and-depth-buffer 1 0.98 0.95 1 1) 65 | (gl/draw-with-shader (assoc-in model [:uniforms :model] tx1)) 66 | (gl/draw-with-shader 67 | (-> model 68 | (assoc-in [:uniforms :model] tx2) 69 | (assoc-in [:uniforms :diffuseCol] 0x33ff80)))) 70 | true))))) 71 | -------------------------------------------------------------------------------- /examples/gl/multi_textures.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.gl.multi-textures 2 | (:require-macros 3 | [thi.ng.math.macros :as mm]) 4 | (:require 5 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]] 6 | [thi.ng.color.core :as col] 7 | [thi.ng.typedarrays.core :as arrays] 8 | [thi.ng.geom.gl.core :as gl] 9 | [thi.ng.geom.gl.webgl.constants :as glc] 10 | [thi.ng.geom.gl.webgl.animator :as anim] 11 | [thi.ng.geom.gl.buffers :as buf] 12 | [thi.ng.geom.gl.shaders :as sh] 13 | [thi.ng.geom.gl.utils :as glu] 14 | [thi.ng.geom.gl.glmesh :as glm] 15 | [thi.ng.geom.gl.camera :as cam] 16 | [thi.ng.geom.core :as g] 17 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 18 | [thi.ng.geom.matrix :as mat :refer [M44]] 19 | [thi.ng.geom.aabb :as a] 20 | [thi.ng.geom.attribs :as attr] 21 | [thi.ng.glsl.core :as glsl :include-macros true])) 22 | 23 | (enable-console-print!) 24 | 25 | (def shader-spec 26 | {:vs (glsl/minified 27 | "void main() { 28 | vUV = uv; 29 | gl_Position = proj * view * model * vec4(position, 1.0); 30 | }") 31 | :fs (glsl/minified 32 | "void main() { 33 | gl_FragColor = mix(texture2D(tex1, vUV), texture2D(tex2, vUV), fade); 34 | }") 35 | :uniforms {:model [:mat4 M44] 36 | :view :mat4 37 | :proj :mat4 38 | :tex1 [:sampler2D 0] ;; bound to tex unit #0 39 | :tex2 [:sampler2D 1] ;; bound to tex unit #1 40 | :fade :float} 41 | :attribs {:position :vec3 42 | :uv :vec2} 43 | :varying {:vUV :vec2} 44 | :state {:depth-test true}}) 45 | 46 | (defn ^:export demo 47 | [] 48 | (let [gl (gl/gl-context "main") 49 | view-rect (gl/get-viewport-rect gl) 50 | model (-> (a/aabb 1) 51 | (g/center) 52 | (g/as-mesh 53 | {:mesh (glm/indexed-gl-mesh 12 #{:uv}) 54 | :attribs {:uv (attr/face-attribs (attr/uv-cube-map-v 256 false))}}) 55 | (gl/as-gl-buffer-spec {}) 56 | (cam/apply (cam/perspective-camera {:eye (vec3 0 0 0.5) :fov 60 :aspect view-rect})) 57 | (assoc :shader (sh/make-shader-from-spec gl shader-spec)) 58 | (gl/make-buffers-in-spec gl glc/static-draw)) 59 | tex-ready (volatile! 0) 60 | tex1 (buf/load-texture 61 | gl {:callback (fn [tex img] (vswap! tex-ready inc)) 62 | :src "assets/gl/cubev.png" 63 | :flip false}) 64 | tex2 (buf/load-texture 65 | gl {:callback (fn [tex img] (vswap! tex-ready inc)) 66 | :src "assets/gl/lancellotti.jpg" 67 | :flip false})] 68 | (anim/animate 69 | (fn [t frame] 70 | (when (= @tex-ready 2) 71 | ;; bind both textures 72 | ;; shader will x-fade between them based on :fade uniform value 73 | (gl/bind tex1 0) 74 | (gl/bind tex2 1) 75 | (doto gl 76 | (gl/set-viewport view-rect) 77 | (gl/clear-color-and-depth-buffer col/WHITE 1) 78 | (gl/draw-with-shader 79 | (update model :uniforms merge 80 | {:model (-> M44 (g/rotate-x PI) (g/rotate-y (* t 0.5))) 81 | :fade (+ 0.5 (* 0.5 (Math/sin (* t 2))))})))) 82 | true)))) 83 | -------------------------------------------------------------------------------- /examples/gl/picking.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.gl.picking 2 | (:require-macros 3 | [thi.ng.math.macros :as mm]) 4 | (:require 5 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]] 6 | [thi.ng.color.core :as col] 7 | [thi.ng.typedarrays.core :as arrays] 8 | [thi.ng.geom.gl.core :as gl] 9 | [thi.ng.geom.gl.webgl.constants :as glc] 10 | [thi.ng.geom.gl.webgl.animator :as anim] 11 | [thi.ng.geom.gl.buffers :as buf] 12 | [thi.ng.geom.gl.shaders :as sh] 13 | [thi.ng.geom.gl.utils :as glu] 14 | [thi.ng.geom.gl.glmesh :as glm] 15 | [thi.ng.geom.gl.camera :as cam] 16 | [thi.ng.geom.core :as g] 17 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 18 | [thi.ng.geom.matrix :as mat :refer [M44]] 19 | [thi.ng.geom.aabb :as a] 20 | [thi.ng.geom.attribs :as attr] 21 | [thi.ng.glsl.core :as glsl :include-macros true] 22 | [thi.ng.geom.plane :as pl] 23 | [thi.ng.geom.gl.shaders.phong :as phong])) 24 | 25 | (enable-console-print!) 26 | 27 | (defn raycast 28 | [p eye ground back] 29 | (let [dir (m/- p eye) 30 | i1 (:p (g/intersect-ray ground eye dir)) 31 | i2 (:p (g/intersect-ray back eye dir))] 32 | (if (< (g/dist-squared eye i1) (g/dist-squared eye i2)) i1 i2))) 33 | 34 | (defn ^:export demo 35 | [] 36 | (let [gl (gl/gl-context "main") 37 | view-rect (gl/get-viewport-rect gl) 38 | shader (sh/make-shader-from-spec gl phong/shader-spec) 39 | cam (cam/perspective-camera 40 | {:eye (vec3 1 2 6) 41 | :target (vec3 0 0.6 0) 42 | :aspect view-rect 43 | :far 10}) 44 | size 3 45 | ground-y -0.55 46 | uniforms {:model M44 47 | :shininess 1000 48 | :lightPos (vec3 -1 2 0)} 49 | box (-> (a/aabb 1) 50 | (g/center) 51 | (g/as-mesh {:mesh (glm/indexed-gl-mesh 12 #{:fnorm})}) 52 | (gl/as-gl-buffer-spec {}) 53 | (gl/make-buffers-in-spec gl glc/static-draw) 54 | (assoc :shader shader :uniforms (assoc uniforms :diffuseCol [1 0 1]))) 55 | ground (pl/plane-with-point (vec3 0 ground-y 0) v/V3Y) 56 | back (pl/plane-with-point (vec3 0 0 (* -0.5 size)) v/V3Z) 57 | planes (-> (g/as-mesh back {:mesh (glm/indexed-gl-mesh 4 #{:fnorm}) :size size}) 58 | (g/translate (vec3 0 (+ (* 0.5 size) ground-y) 0)) 59 | (g/into (g/as-mesh ground {:size size})) 60 | (gl/as-gl-buffer-spec {}) 61 | (gl/make-buffers-in-spec gl glc/static-draw) 62 | (assoc :shader shader :uniforms uniforms)) 63 | state (volatile! {:mpos (g/centroid view-rect) :update-ray true}) 64 | update-pos #(vswap! state assoc 65 | :mpos (vec2 (.-clientX %) (.-clientY %)) 66 | :update-ray true)] 67 | (.addEventListener js/window "mousemove" update-pos) 68 | (.addEventListener js/window "touchmove" #(do (.preventDefault %) (update-pos (aget (.-touches %) 0)))) 69 | (anim/animate 70 | (fn [t frame] 71 | (let [cam (cam/set-view cam {:eye #(g/rotate-y % (Math/sin t))}) 72 | isec (if (:update-ray @state) 73 | (let [p (-> (vec3 (:mpos @state) 0) 74 | (mat/unproject-point (m/invert (m/* (:proj cam) (:view cam))) view-rect) 75 | (raycast (:eye cam) ground back))] 76 | (vswap! state assoc :isec p :update-ray false) p) 77 | (:isec @state))] 78 | (doto gl 79 | (gl/set-viewport view-rect) 80 | (gl/clear-color-and-depth-buffer 0.52 0.5 0.5 1 1) 81 | (gl/draw-with-shader (cam/apply planes cam)) 82 | (gl/draw-with-shader 83 | (-> box 84 | (cam/apply cam) 85 | (assoc-in [:uniforms :model] (g/translate M44 isec)))))) 86 | true)) 87 | state)) 88 | -------------------------------------------------------------------------------- /examples/gl/shaded_cube.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.gl.shaded-cube 2 | (:require-macros 3 | [thi.ng.math.macros :as mm]) 4 | (:require 5 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]] 6 | [thi.ng.color.core :as col] 7 | [thi.ng.typedarrays.core :as arrays] 8 | [thi.ng.geom.gl.core :as gl] 9 | [thi.ng.geom.gl.webgl.constants :as glc] 10 | [thi.ng.geom.gl.webgl.animator :as anim] 11 | [thi.ng.geom.gl.buffers :as buf] 12 | [thi.ng.geom.gl.shaders :as sh] 13 | [thi.ng.geom.gl.utils :as glu] 14 | [thi.ng.geom.gl.glmesh :as glm] 15 | [thi.ng.geom.gl.camera :as cam] 16 | [thi.ng.geom.core :as g] 17 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 18 | [thi.ng.geom.matrix :as mat :refer [M44]] 19 | [thi.ng.geom.aabb :as a] 20 | [thi.ng.geom.attribs :as attr] 21 | [thi.ng.glsl.core :as glsl :include-macros true] 22 | [thi.ng.geom.gl.shaders.lambert :as lambert])) 23 | 24 | (defn ^:export demo 25 | [] 26 | (let [gl (gl/gl-context "main") 27 | view-rect (gl/get-viewport-rect gl) 28 | model (-> (a/aabb 0.8) 29 | (g/center) 30 | (g/as-mesh 31 | {:mesh (glm/indexed-gl-mesh 12 #{:col :fnorm}) 32 | :attribs {:col (->> [[1 0 0] [0 1 0] [0 0 1] [0 1 1] [1 0 1] [1 1 0]] 33 | (map col/rgba) 34 | (attr/const-face-attribs))}}) 35 | (gl/as-gl-buffer-spec {}) 36 | (cam/apply (cam/perspective-camera {:aspect view-rect})) 37 | (assoc :shader (sh/make-shader-from-spec gl lambert/shader-spec-attrib)) 38 | (gl/make-buffers-in-spec gl glc/static-draw))] 39 | (anim/animate 40 | (fn [t frame] 41 | (doto gl 42 | (gl/set-viewport view-rect) 43 | (gl/clear-color-and-depth-buffer col/WHITE 1) 44 | (gl/draw-with-shader 45 | (assoc-in model [:uniforms :model] (-> M44 (g/rotate-x t) (g/rotate-y (* t 2)))))) 46 | true)))) 47 | -------------------------------------------------------------------------------- /examples/gl/stl_mesh.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.gl.stl-mesh 2 | (:require-macros 3 | [thi.ng.math.macros :as mm]) 4 | (:require 5 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]] 6 | [thi.ng.color.core :as col] 7 | [thi.ng.typedarrays.core :as arrays] 8 | [thi.ng.geom.gl.core :as gl] 9 | [thi.ng.geom.gl.webgl.constants :as glc] 10 | [thi.ng.geom.gl.webgl.animator :as anim] 11 | [thi.ng.geom.gl.buffers :as buf] 12 | [thi.ng.geom.gl.shaders :as sh] 13 | [thi.ng.geom.gl.utils :as glu] 14 | [thi.ng.geom.gl.glmesh :as glm] 15 | [thi.ng.geom.gl.camera :as cam] 16 | [thi.ng.geom.core :as g] 17 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 18 | [thi.ng.geom.matrix :as mat :refer [M44]] 19 | [thi.ng.geom.aabb :as a] 20 | [thi.ng.geom.attribs :as attr] 21 | [thi.ng.glsl.core :as glsl :include-macros true] 22 | [thi.ng.geom.mesh.io :as mio] 23 | [thi.ng.geom.quaternion :as q] 24 | [thi.ng.geom.gl.arcball :as arc] 25 | [thi.ng.geom.gl.shaders.phong :as phong])) 26 | 27 | (enable-console-print!) 28 | 29 | (def state (atom {})) 30 | 31 | (defn load-binary 32 | [uri onload onerror] 33 | (let [xhr (js/XMLHttpRequest.)] 34 | (set! (.-responseType xhr) "arraybuffer") 35 | (set! (.-onload xhr) 36 | (fn [e] 37 | (if-let [buf (.-response xhr)] 38 | (onload buf) 39 | (when onerror (onerror xhr e))))) 40 | (doto xhr 41 | (.open "GET" uri true) 42 | (.send)))) 43 | 44 | (defn init-model 45 | [gl vrect buf] 46 | (let [model (-> (mio/read-stl (mio/wrapped-input-stream buf) #(glm/gl-mesh % #{:fnorm})) 47 | (gl/as-gl-buffer-spec {}) 48 | (assoc :shader (sh/make-shader-from-spec gl phong/shader-spec)) 49 | (update :uniforms merge 50 | {:proj (mat/perspective 60 vrect 0.1 10) 51 | :view (mat/look-at (v/vec3 0 0 1) (v/vec3) v/V3Y) 52 | :lightPos (vec3 0.1 0 1) 53 | :ambientCol 0x000011 54 | :diffuseCol 0x0033ff 55 | :specularCol 0xffffff 56 | :shininess 100 57 | :wrap 0 58 | :useBlinnPhong true}) 59 | (gl/make-buffers-in-spec gl glc/static-draw) 60 | (time))] 61 | (swap! state assoc :model model))) 62 | 63 | (defn init-arcball 64 | [el vrect] 65 | (swap! state assoc :cam 66 | (-> (arc/arcball {:init (m/normalize (q/quat 0.0 0.707 0.707 0))}) 67 | (arc/resize (g/width vrect) (g/height vrect)))) 68 | (doto el 69 | (.addEventListener 70 | "mousedown" 71 | (fn [e] 72 | (doto state 73 | (swap! assoc :mouse-down true) 74 | (swap! update :cam arc/down (.-clientX e) (.-clientY e))))) 75 | (.addEventListener 76 | "mouseup" 77 | (fn [e] (swap! state assoc :mouse-down false))) 78 | (.addEventListener 79 | "mousemove" 80 | (fn [e] 81 | (when (:mouse-down @state) 82 | (swap! state update :cam arc/drag (.-clientX e) (.-clientY e))))))) 83 | 84 | (defn ^:export demo 85 | [] 86 | (let [gl (gl/gl-context "main") 87 | vrect (gl/get-viewport-rect gl)] 88 | (load-binary 89 | "assets/mesh/suzanne.stl" 90 | (fn [buf] (init-model gl vrect buf)) 91 | (fn [req e] (prn "error loading model"))) 92 | (init-arcball (.getElementById js/document "main") vrect) 93 | (anim/animate 94 | (fn [t frame] 95 | (when-let [model (:model @state)] 96 | (doto gl 97 | (gl/set-viewport vrect) 98 | (gl/clear-color-and-depth-buffer col/WHITE 1) 99 | (gl/draw-with-shader 100 | (assoc-in model [:uniforms :model] (arc/get-view (:cam @state)))))) 101 | true)))) 102 | -------------------------------------------------------------------------------- /examples/gl/textured_cube.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.gl.textured-cube 2 | (:require-macros 3 | [thi.ng.math.macros :as mm]) 4 | (:require 5 | [thi.ng.math.core :as m :refer [PI HALF_PI TWO_PI]] 6 | [thi.ng.color.core :as col] 7 | [thi.ng.typedarrays.core :as arrays] 8 | [thi.ng.geom.gl.core :as gl] 9 | [thi.ng.geom.gl.webgl.constants :as glc] 10 | [thi.ng.geom.gl.webgl.animator :as anim] 11 | [thi.ng.geom.gl.buffers :as buf] 12 | [thi.ng.geom.gl.shaders :as sh] 13 | [thi.ng.geom.gl.utils :as glu] 14 | [thi.ng.geom.gl.glmesh :as glm] 15 | [thi.ng.geom.gl.camera :as cam] 16 | [thi.ng.geom.core :as g] 17 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 18 | [thi.ng.geom.matrix :as mat :refer [M44]] 19 | [thi.ng.geom.aabb :as a] 20 | [thi.ng.geom.attribs :as attr] 21 | [thi.ng.glsl.core :as glsl :include-macros true])) 22 | 23 | (enable-console-print!) 24 | 25 | (def shader-spec 26 | {:vs (glsl/minified 27 | "void main() { 28 | vUV = uv; 29 | gl_Position = proj * view * model * vec4(position, 1.0); 30 | }") 31 | :fs (glsl/minified 32 | "void main() { 33 | gl_FragColor = texture2D(tex, vUV); 34 | }") 35 | :uniforms {:model [:mat4 M44] 36 | :view :mat4 37 | :proj :mat4 38 | :tex :sampler2D} 39 | :attribs {:position :vec3 40 | :uv :vec2} 41 | :varying {:vUV :vec2} 42 | :state {:depth-test true}}) 43 | 44 | (defn ^:export demo 45 | [] 46 | (let [gl (gl/gl-context "main") 47 | view-rect (gl/get-viewport-rect gl) 48 | model (-> (a/aabb 1) 49 | (g/center) 50 | (g/as-mesh 51 | {:mesh (glm/indexed-gl-mesh 12 #{:uv}) 52 | :attribs {:uv (attr/face-attribs (attr/uv-cube-map-v 256 false))}}) 53 | (gl/as-gl-buffer-spec {}) 54 | (cam/apply (cam/perspective-camera {:eye (vec3 0 0 0.5) :fov 90 :aspect view-rect})) 55 | (assoc :shader (sh/make-shader-from-spec gl shader-spec)) 56 | (gl/make-buffers-in-spec gl glc/static-draw)) 57 | tex-ready (volatile! false) 58 | tex (buf/load-texture 59 | gl {:callback (fn [tex img] (vreset! tex-ready true)) 60 | :src "assets/gl/cubev.png" 61 | :flip false})] 62 | (anim/animate 63 | (fn [t frame] 64 | (when @tex-ready 65 | (gl/bind tex 0) 66 | (doto gl 67 | (gl/set-viewport view-rect) 68 | (gl/clear-color-and-depth-buffer col/WHITE 1) 69 | (gl/draw-with-shader 70 | (assoc-in model [:uniforms :model] 71 | (-> M44 (g/rotate-x PI) (g/rotate-y (* t 2))))))) 72 | true)))) 73 | -------------------------------------------------------------------------------- /examples/jogl/stl_mesh.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.jogl.stl-mesh 2 | (:import 3 | [com.jogamp.opengl GL3 GLAutoDrawable] 4 | [com.jogamp.newt.event MouseEvent KeyEvent]) 5 | (:require 6 | [thi.ng.math.core :as m] 7 | [thi.ng.color.core :as col] 8 | [thi.ng.geom.core :as g] 9 | [thi.ng.geom.aabb :as a] 10 | [thi.ng.geom.attribs :as attr] 11 | [thi.ng.geom.vector :as v] 12 | [thi.ng.geom.matrix :as mat] 13 | [thi.ng.geom.quaternion :as q] 14 | [thi.ng.geom.utils :as gu] 15 | [thi.ng.geom.mesh.io :as mio] 16 | [thi.ng.geom.gl.core :as gl] 17 | [thi.ng.geom.gl.arcball :as arc] 18 | [thi.ng.geom.gl.shaders :as sh] 19 | [thi.ng.geom.gl.shaders.phong :as phong] 20 | [thi.ng.geom.gl.glmesh :as glm] 21 | [thi.ng.geom.gl.jogl.core :as jogl] 22 | [thi.ng.geom.gl.jogl.constants :as glc] 23 | [thi.ng.glsl.core :as glsl] 24 | [clojure.java.io :as io])) 25 | 26 | (def app (atom nil)) 27 | 28 | (defn load-mesh 29 | "Loads STL mesh from given path and fits it into centered bounding box." 30 | [path bounds] 31 | (with-open [in (io/input-stream path)] 32 | (->> (mio/read-stl (mio/wrapped-input-stream in) #(glm/gl-mesh % #{:fnorm})) 33 | vector 34 | (gu/fit-all-into-bounds (g/center bounds)) 35 | first))) 36 | 37 | (defn init 38 | [^GLAutoDrawable drawable] 39 | (let [^GL3 gl (.. drawable getGL getGL3) 40 | view-rect (gl/get-viewport-rect gl) 41 | shader (sh/make-shader-from-spec gl (assoc phong/shader-spec :version 330)) 42 | model (-> (load-mesh "assets/mesh/suzanne.stl" (a/aabb 2)) 43 | (gl/as-gl-buffer-spec {}) 44 | (update :uniforms merge 45 | {:lightPos [0 2 2] 46 | :view (mat/look-at (v/vec3 0 0 1) (v/vec3) v/V3Y) 47 | :shininess 50 48 | :wrap 1 49 | :ambientCol [0.0 0.1 0.4 0.0] 50 | :diffuseCol [0.1 0.5 0.6] 51 | :specularCol [0.8 0.3 0.3]}) 52 | (assoc :shader shader) 53 | (gl/make-buffers-in-spec gl glc/static-draw))] 54 | (swap! app assoc 55 | :model model 56 | :wireframe false 57 | :arcball (arc/arcball {:init (m/normalize (q/quat 0.0 0.707 0.707 0))})))) 58 | 59 | (defn display 60 | [^GLAutoDrawable drawable t] 61 | (let [^GL3 gl (.. drawable getGL getGL3) 62 | {:keys [model wireframe arcball]} @app 63 | view (arc/get-view arcball)] 64 | (doto gl 65 | (gl/clear-color-and-depth-buffer col/GRAY 1) 66 | (.glPolygonMode glc/front-and-back (if wireframe glc/line glc/fill)) 67 | (gl/draw-with-shader (assoc-in model [:uniforms :model] view))))) 68 | 69 | (defn resize 70 | [_ x y w h] 71 | (swap! app assoc-in [:model :uniforms :proj] (mat/perspective 45 (/ w h) 0.1 10)) 72 | (swap! app update :arcball arc/resize w h)) 73 | 74 | (defn dispose [_] (jogl/stop-animator (:anim @app))) 75 | 76 | (defn key-pressed 77 | [^KeyEvent e] 78 | (condp = (.getKeyCode e) 79 | KeyEvent/VK_ESCAPE (jogl/destroy-window (:window @app)) 80 | (case (.getKeyChar e) 81 | \w (swap! app update :wireframe not) 82 | nil))) 83 | 84 | (defn mouse-pressed [^MouseEvent e] (swap! app update :arcball arc/down (.getX e) (.getY e))) 85 | 86 | (defn mouse-dragged [^MouseEvent e] (swap! app update :arcball arc/drag (.getX e) (.getY e))) 87 | 88 | (defn wheel-moved [^MouseEvent e deltas] (swap! app update :arcball arc/zoom-delta (nth deltas 1))) 89 | 90 | (defn -main 91 | [& args] 92 | (reset! 93 | app 94 | (jogl/gl-window 95 | {:profile :gl3 96 | :samples 4 97 | :double-buffer true 98 | :fullscreen false 99 | :events {:init init 100 | :display display 101 | :dispose dispose 102 | :resize resize 103 | :keys {:press key-pressed} 104 | :mouse {:press mouse-pressed 105 | :drag mouse-dragged 106 | :wheel wheel-moved}}})) 107 | nil) 108 | 109 | (-main) 110 | -------------------------------------------------------------------------------- /examples/jogl/textured_cube.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.jogl.textured-cube 2 | (:import 3 | [com.jogamp.opengl GL3 GLAutoDrawable] 4 | [com.jogamp.newt.event MouseEvent KeyEvent]) 5 | (:require 6 | [thi.ng.math.core :as m] 7 | [thi.ng.geom.core :as g] 8 | [thi.ng.geom.aabb :as a] 9 | [thi.ng.geom.attribs :as attr] 10 | [thi.ng.geom.vector :as v] 11 | [thi.ng.geom.matrix :as mat] 12 | [thi.ng.geom.gl.core :as gl] 13 | [thi.ng.geom.gl.arcball :as arc] 14 | [thi.ng.geom.gl.buffers :as buf] 15 | [thi.ng.geom.gl.shaders :as sh] 16 | [thi.ng.geom.gl.glmesh :as glm] 17 | [thi.ng.geom.gl.jogl.core :as jogl] 18 | [thi.ng.geom.gl.jogl.constants :as glc] 19 | [clojure.pprint :refer [pprint]] 20 | [clojure.java.io :as io])) 21 | 22 | (def app (atom nil)) 23 | 24 | (def shader 25 | {:vs " 26 | void main() { 27 | vCol = vec4(position.xy * 0.5 + 0.5, fract(time), 1.0); 28 | vUV = uv; 29 | gl_Position = proj * view * model * vec4(position, 1.0); 30 | }" 31 | :fs "out vec4 fragColor; 32 | void main() { 33 | fragColor = vCol * texture(tex, vUV); 34 | }" 35 | :version 330 36 | :attribs {:position :vec3 37 | :uv :vec2} 38 | :varying {:vCol :vec4 39 | :vUV :vec2} 40 | :uniforms {:model [:mat4 mat/M44] 41 | :view :mat4 42 | :proj :mat4 43 | :tex [:sampler2D 0] 44 | :time :float} 45 | :state {:depth-test false 46 | :blend true 47 | :blend-fn [glc/src-alpha glc/one]}}) 48 | 49 | (defn init 50 | [^GLAutoDrawable drawable] 51 | (let [^GL3 gl (.. drawable getGL getGL3) 52 | tex (buf/load-texture gl {:src (io/file "assets/gl/cubev.png")}) 53 | model (-> (a/aabb 1) 54 | (g/center) 55 | (g/as-mesh {:mesh (glm/gl-mesh 12 #{:uv}) 56 | :attribs {:uv (attr/face-attribs (attr/uv-cube-map-v 256 false))}}) 57 | (gl/as-gl-buffer-spec {}) 58 | (assoc :shader (sh/make-shader-from-spec gl shader)) 59 | (assoc-in [:shader :state :tex] tex) 60 | (gl/make-buffers-in-spec gl glc/static-draw))] 61 | (swap! app assoc :model model :arcball (arc/arcball {})))) 62 | 63 | (defn display 64 | [^GLAutoDrawable drawable t] 65 | (let [{:keys [model arcball]} @app 66 | ^GL3 gl (.. drawable getGL getGL3)] 67 | (doto gl 68 | (gl/clear-color-and-depth-buffer 0.3 0.3 0.3 1.0 1.0) 69 | (gl/draw-with-shader 70 | (update model :uniforms assoc 71 | :view (arc/get-view arcball) 72 | :time (* 0.25 t)))))) 73 | 74 | (defn dispose [_] (jogl/stop-animator (:anim @app))) 75 | 76 | (defn resize 77 | [_ x y w h] 78 | (swap! app assoc-in [:model :uniforms :proj] (mat/perspective 45 (/ w h) 0.1 10)) 79 | (swap! app update :arcball arc/resize w h)) 80 | 81 | (defn key-pressed 82 | [^KeyEvent e] 83 | (condp = (.getKeyCode e) 84 | KeyEvent/VK_ESCAPE (jogl/destroy-window (:window @app)) 85 | nil)) 86 | 87 | (defn mouse-pressed [^MouseEvent e] (swap! app update :arcball arc/down (.getX e) (.getY e))) 88 | 89 | (defn mouse-dragged [^MouseEvent e] (swap! app update :arcball arc/drag (.getX e) (.getY e))) 90 | 91 | (defn wheel-moved [^MouseEvent e deltas] (swap! app update :arcball arc/zoom-delta (nth deltas 1))) 92 | 93 | (defn -main 94 | [& args] 95 | (reset! 96 | app 97 | (jogl/gl-window 98 | {:profile :gl3 99 | :samples 4 100 | :double-buffer true 101 | :fullscreen false 102 | :events {:init init 103 | :display display 104 | :resize resize 105 | :keys {:press key-pressed} 106 | :mouse {:press mouse-pressed 107 | :drag mouse-dragged 108 | :wheel wheel-moved}}})) 109 | nil) 110 | 111 | (-main) 112 | -------------------------------------------------------------------------------- /examples/repl.clj: -------------------------------------------------------------------------------- 1 | (defn run-all-in-dir 2 | "Loads (and executes) all .clj files in given directory." 3 | [dir] 4 | (doseq [f (filter #(.endsWith (.getName %) ".clj") (file-seq (java.io.File. dir)))] 5 | (load-file (.getAbsolutePath f)))) 6 | -------------------------------------------------------------------------------- /examples/svg/circles.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.svg.circles 2 | (:require 3 | [thi.ng.math.core :as m] 4 | [thi.ng.geom.core :as g] 5 | [thi.ng.geom.circle :as c] 6 | [thi.ng.geom.svg.core :as svg] 7 | [thi.ng.geom.svg.adapter :as adapt] 8 | [thi.ng.color.core :as col])) 9 | 10 | (defn labeled-dot 11 | [p label] (list (c/circle p 3) (svg/text (m/+ p 10 0) label))) 12 | 13 | ;; This scene defines 2 circles and their intersection points 14 | (def scene 15 | (let [c1 (c/circle 50 150 50) 16 | c2 (c/circle 250 150 50) 17 | c3 (c/circle 150 150 100) 18 | [a b] (g/intersect-shape c1 c3) 19 | [c d] (g/intersect-shape c2 c3)] 20 | (svg/svg 21 | {:width 300 :height 300} 22 | (svg/group 23 | {:fill "yellow"} 24 | ;; these circles inherit all attributes from parent group 25 | c1 c2 26 | ;; we can use metadata to override specific attribs per shape 27 | ;; here we also demonstrate automatic color attrib conversion 28 | (with-meta c3 {:fill (col/rgba 0 1 1 0.25) :stroke (col/hsva 0 1 1)})) 29 | (svg/group 30 | {:fill "#000" 31 | :font-family "Arial, sans-serif" 32 | :font-size 10} 33 | (mapcat labeled-dot [a b c d] ["A" "B" "C" "D"]))))) 34 | 35 | (->> scene 36 | (adapt/all-as-svg) ;; transform all scene elements 37 | (svg/serialize) ;; serialize as SVG XML string 38 | (spit "out/svg-circles.svg")) ;; write to disk 39 | -------------------------------------------------------------------------------- /examples/svg/decorators.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.svg.decorators 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.matrix :refer [M32]] 5 | [thi.ng.geom.line :as l] 6 | [thi.ng.geom.svg.core :as svg] 7 | [thi.ng.geom.svg.adapter :as adapt])) 8 | 9 | (def arrow (svg/arrow-head 15 0.2 false)) 10 | 11 | ;; compose decorators 12 | (def labeler 13 | (svg/comp-decorators 14 | (svg/arrow-head 10 0.25 true {:fill "red"}) 15 | (svg/line-label {:fill "black" :stroke "none"}))) 16 | 17 | (->> (svg/svg 18 | {:width 300 :height 300 :font-family "Arial" :font-size 12} 19 | ;; option 1: use line-strip-decorated 20 | (svg/line-strip-decorated 21 | [[5 0] [5 295] [300 295]] 22 | arrow nil arrow 23 | {:stroke "blue"}) 24 | ;; option 2: attach decorators as metadata 25 | (with-meta 26 | (l/linestrip2 [[10 290] [100 150] [200 200] [290 10]]) 27 | {:stroke "red" 28 | :stroke-dasharray "5 5" 29 | :__segment labeler 30 | :__label ["Jan 2014" "Feb 2014" "Mar 2014"]})) 31 | (adapt/all-as-svg) 32 | (svg/serialize) 33 | (spit "out/svg-decorators.svg")) 34 | -------------------------------------------------------------------------------- /examples/svg/instancing.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.svg.instancing 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.vector :refer [vec2]] 5 | [thi.ng.geom.matrix :refer [M32]] 6 | [thi.ng.geom.svg.core :as svg] 7 | [thi.ng.color.core :as col] 8 | [thi.ng.math.core :as m] 9 | [thi.ng.math.macros :as mm])) 10 | 11 | (defn spiral 12 | [center start end r1 r2 steps] 13 | (map 14 | (fn [r theta] (m/+ (g/as-cartesian (vec2 r theta)) center)) 15 | (range r1 r2 (mm/subdiv r2 r1 steps)) 16 | (range start end (mm/subdiv end start steps)))) 17 | 18 | (def rainbow-gradient (map (fn [h] [h (col/hsva h 1 1)]) (m/norm-range 12))) 19 | 20 | (->> (svg/svg 21 | {:width 600 :height 300} 22 | (svg/defs 23 | (apply svg/radial-gradient "rainbow-rad" {} rainbow-gradient) 24 | (apply svg/linear-gradient "rainbow-lin" {} rainbow-gradient) 25 | (svg/line-strip 26 | (spiral [0 0] 0 (* 6 m/TWO_PI) 0 140 300) 27 | (assoc svg/stroke-round :id "spiral"))) 28 | (svg/instance 29 | "spiral" 30 | {:transform (-> M32 (g/translate (vec2 150 150))) 31 | :stroke "url(#rainbow-rad)" 32 | :stroke-width 10}) 33 | (svg/instance 34 | "spiral" 35 | {:transform (-> M32 (g/translate (vec2 450 150)) (g/rotate m/PI)) 36 | :stroke "url(#rainbow-lin)" 37 | :stroke-width 5})) 38 | (svg/serialize) 39 | (spit "out/svg-instancing.svg")) 40 | -------------------------------------------------------------------------------- /examples/svg/rings.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.svg.rings 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.vector :refer [vec3]] 5 | [thi.ng.geom.matrix :as mat] 6 | [thi.ng.geom.circle :as c] 7 | [thi.ng.geom.polygon :as p] 8 | [thi.ng.geom.gmesh :as gm] 9 | [thi.ng.geom.mesh.subdivision :as sd] 10 | [thi.ng.geom.svg.core :as svg] 11 | [thi.ng.geom.svg.shaders :as shader] 12 | [thi.ng.geom.svg.renderer :as render] 13 | [thi.ng.math.core :as m])) 14 | 15 | (def width 640) 16 | (def height 480) 17 | (def model (g/rotate-y (mat/matrix44) m/SIXTH_PI)) 18 | (def view (apply mat/look-at (mat/look-at-vectors 0 1.75 0.75 0 0 0))) 19 | (def proj (mat/perspective 60 (/ width height) 0.1 10)) 20 | (def mvp (->> model (m/* view) (m/* proj))) 21 | 22 | (def diffuse (shader/normal-rgb (g/rotate-y (mat/matrix44) m/PI))) 23 | (def uniforms {:stroke "white" :stroke-width 0.25}) 24 | 25 | (def shader-diffuse 26 | (shader/shader 27 | {:fill diffuse 28 | :uniforms uniforms 29 | :flags {:solid true}})) 30 | 31 | (def shader-lambert 32 | (shader/shader 33 | {:fill (shader/lambert 34 | {:view view 35 | :light-dir [-1 0 1] 36 | :light-col [1 1 1] 37 | :diffuse diffuse 38 | :ambient 0.1}) 39 | :uniforms uniforms 40 | :flags {:solid true}})) 41 | 42 | (def shader-phong 43 | (shader/shader 44 | {:fill (shader/phong 45 | {:model model 46 | :view view 47 | :light-pos [-1 2 1] 48 | :light-col [1 1 1] 49 | :diffuse diffuse 50 | :ambient [0.05 0.05 0.2] 51 | :specular 0.8 52 | :shininess 8.0}) 53 | :uniforms uniforms 54 | :flags {:solid true}})) 55 | 56 | (defn ring 57 | [res radius depth wall] 58 | (-> (c/circle radius) 59 | (g/as-polygon res) 60 | (g/extrude-shell {:depth depth :wall wall :inset -0.1 :mesh (gm/gmesh)}) 61 | (g/center))) 62 | 63 | (def mesh 64 | (->> [[1 0.25 0.15] [0.75 0.35 0.1] [0.5 0.5 0.05] [0.25 0.75 0.05]] 65 | (map (partial apply ring 40)) 66 | (reduce g/into) 67 | (sd/catmull-clark) 68 | (sd/catmull-clark))) 69 | 70 | ;; 2d text label w/ projected anchor point 71 | (defn label-3d 72 | [p mvp screen [l1 l2]] 73 | (let [p' (mat/project-point p mvp screen) 74 | p2' (mat/project-point (m/+ p 0 0 0.2) mvp screen) 75 | p3' (m/+ p2' 100 0)] 76 | (svg/group 77 | {:fill "black" 78 | :font-family "Arial" 79 | :font-size 12 80 | :text-anchor "end"} 81 | (svg/circle p' 2 nil) 82 | (svg/line-strip [p' p2' p3'] {:stroke "black"}) 83 | (svg/text (m/+ p3' 0 -5) l1 {}) 84 | (svg/text (m/+ p3' 0 12) l2 {:font-weight "bold"})))) 85 | 86 | (defn render-svg 87 | [path mesh mvp shader width height labels] 88 | (let [screen (mat/viewport-matrix width height) 89 | max-z (/ 0.75 2)] 90 | (->> (svg/svg 91 | {:width width :height height} 92 | (render/mesh mesh mvp screen shader) 93 | (label-3d (vec3 0 0 max-z) mvp screen labels)) 94 | (svg/serialize) 95 | (spit path)))) 96 | 97 | (render-svg "out/svg-rings-diffuse.svg" 98 | mesh mvp shader-diffuse width height 99 | ["Shader" "Normal/RGB"]) 100 | (render-svg "out/svg-rings-lambert.svg" 101 | mesh mvp shader-lambert width height 102 | ["Shader" "Lambert"]) 103 | (render-svg "out/svg-rings-phong.svg" 104 | mesh mvp shader-phong width height 105 | ["Shader" "Blinn-Phong"]) 106 | -------------------------------------------------------------------------------- /examples/svg/spiral.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.svg.spiral 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.vector :refer [vec2]] 5 | [thi.ng.geom.svg.core :as svg] 6 | [thi.ng.color.core :as col] 7 | [thi.ng.math.core :as m] 8 | [thi.ng.math.macros :as mm])) 9 | 10 | (defn spiral 11 | [center start end r1 r2 steps] 12 | (map 13 | (fn [r theta] (m/+ (g/as-cartesian (vec2 r theta)) center)) 14 | (range r1 r2 (mm/subdiv r2 r1 steps)) 15 | (range start end (mm/subdiv end start steps)))) 16 | 17 | (def rainbow-gradient (map (fn [h] [h (col/hsva h 1 1)]) (m/norm-range 12))) 18 | 19 | (->> (svg/svg 20 | {:width 300 :height 300} 21 | (svg/defs 22 | (apply svg/radial-gradient "rainbow" {} rainbow-gradient)) 23 | (svg/line-strip 24 | (spiral [150 150] 0 (* 6 m/TWO_PI) 0 140 300) 25 | (assoc svg/stroke-round 26 | :stroke "url(#rainbow)" 27 | :stroke-width 10))) 28 | (svg/serialize) 29 | (spit "out/svg-spiral.svg")) 30 | -------------------------------------------------------------------------------- /examples/svg/stl_mesh.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.svg.stl-mesh 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.matrix :as mat] 5 | [thi.ng.geom.mesh.io :as mio] 6 | [thi.ng.geom.svg.core :as svg] 7 | [thi.ng.geom.svg.shaders :as shader] 8 | [thi.ng.geom.svg.renderer :as render] 9 | [thi.ng.math.core :as m] 10 | [clojure.java.io :as io])) 11 | 12 | (def width 640) 13 | (def height 480) 14 | (def model (-> (mat/matrix44) (g/rotate-x m/HALF_PI) (g/rotate-z m/SIXTH_PI))) 15 | (def view (apply mat/look-at (mat/look-at-vectors 0 0 -2 0 0 0))) 16 | (def proj (mat/perspective 60 (/ width height) 0.1 2)) 17 | (def mvp (->> model (m/* view) (m/* proj))) 18 | (def col-tx (g/rotate-x (mat/matrix44) (- m/HALF_PI))) 19 | 20 | (def shader 21 | (shader/shader 22 | {:fill (shader/phong 23 | {:model model 24 | :view view 25 | :light-pos [0 -2 1] 26 | :light-col [1 1 1] 27 | :diffuse (shader/normal-rgb col-tx) 28 | :ambient [0.1 0.1 0.2] 29 | :specular 1.0 30 | :shininess 6.0}) 31 | :uniforms {:stroke "black" :stroke-width 0.25} 32 | :flags {:solid true}})) 33 | 34 | (def mesh 35 | (with-open [in (io/input-stream "assets/mesh/suzanne.stl")] 36 | (-> in 37 | (mio/wrapped-input-stream) 38 | (mio/read-stl) 39 | (g/center) 40 | (g/scale 0.85)))) 41 | 42 | (defn render-svg 43 | [path mesh mvp width height] 44 | (let [screen (mat/viewport-matrix width height)] 45 | (->> (svg/svg 46 | {:width width :height height} 47 | (render/mesh mesh mvp screen shader)) 48 | (svg/serialize) 49 | (spit path)))) 50 | 51 | (render-svg "out/svg-stl-mesh.svg" mesh mvp width height) 52 | -------------------------------------------------------------------------------- /examples/svg/subdiv.clj: -------------------------------------------------------------------------------- 1 | (require '[thi.ng.geom.core :as g]) 2 | (require '[thi.ng.geom.vector :refer [vec2]]) 3 | (require '[thi.ng.geom.utils.subdiv :as sd]) 4 | (require '[thi.ng.geom.svg.core :as svg]) 5 | (require '[thi.ng.math.core :as m]) 6 | (require '[thi.ng.dstruct.core :as d]) 7 | 8 | (defn demo 9 | [points [id col]] 10 | (for [i (range 1 6)] 11 | (let [off-x (* 120 (dec i)) 12 | pts (->> points 13 | (mapv #(m/+ % off-x 0)) 14 | (d/iterate-n i (partial sd/subdivide-closed (id sd/schemes))))] 15 | (svg/group 16 | {:stroke col} 17 | (svg/polygon pts) 18 | (map #(svg/circle % 1.5) pts))))) 19 | 20 | (def points 21 | (mapv vec2 22 | [[10 10] [60 60] [110 10] [110 60] 23 | [85 80] [110 100] [110 150] [60 100] 24 | [10 150] [10 100] [35 80] [10 60]])) 25 | 26 | (->> [[:chaikin "red"] [:cubic-bezier "blue"]] 27 | (map #(demo points %)) 28 | (apply svg/svg 29 | {:width 600 :height 200 :fill "none" :font-family "Arial" :font-size 12} 30 | (svg/text [300 170] ":chaikin" {:fill "red"}) 31 | (svg/text [300 186] ":cubic-bezier" {:fill "blue"})) 32 | (svg/serialize) 33 | (spit "out/svg-subdiv-curves.svg")) 34 | -------------------------------------------------------------------------------- /examples/viz/bars.clj: -------------------------------------------------------------------------------- 1 | (require '[thi.ng.geom.viz.core :as viz] :reload) 2 | (require '[thi.ng.geom.svg.core :as svg]) 3 | (require '[thi.ng.geom.vector :as v]) 4 | (require '[thi.ng.color.core :as col]) 5 | (require '[thi.ng.math.core :as m :refer [PI TWO_PI]]) 6 | 7 | (defn export-viz 8 | [viz path] (->> viz (svg/svg {:width 600 :height 320}) (svg/serialize) (spit path))) 9 | 10 | (defn bar-spec 11 | [num width] 12 | (fn [idx col] 13 | {:values (map (fn [i] [i (m/random 100)]) (range 2000 2016)) 14 | :attribs {:stroke col 15 | :stroke-width (str (dec width) "px")} 16 | :layout viz/svg-bar-plot 17 | :interleave num 18 | :bar-width width 19 | :offset idx})) 20 | 21 | (def viz-spec 22 | {:x-axis (viz/linear-axis 23 | {:domain [1999 2016] 24 | :range [50 580] 25 | :major 1 26 | :pos 280 27 | :label (viz/default-svg-label int)}) 28 | :y-axis (viz/linear-axis 29 | {:domain [0 100] 30 | :range [280 20] 31 | :major 10 32 | :minor 5 33 | :pos 50 34 | :label-dist 15 35 | :label-style {:text-anchor "end"}}) 36 | :grid {:minor-y true}}) 37 | 38 | (-> viz-spec 39 | (assoc :data [((bar-spec 1 20) 0 "#0af")]) 40 | (viz/svg-plot2d-cartesian) 41 | (export-viz "out/bars.svg")) 42 | 43 | (-> viz-spec 44 | (assoc :data (map-indexed (bar-spec 3 6) ["#0af" "#fa0" "#f0a"])) 45 | (viz/svg-plot2d-cartesian) 46 | (export-viz "out/bars-interleave.svg")) 47 | -------------------------------------------------------------------------------- /examples/viz/contours.clj: -------------------------------------------------------------------------------- 1 | (require '[thi.ng.geom.viz.core :as viz] :reload) 2 | (require '[thi.ng.geom.svg.core :as svg]) 3 | (require '[thi.ng.geom.vector :as v]) 4 | (require '[thi.ng.color.core :as col]) 5 | (require '[thi.ng.math.core :as m :refer [PI TWO_PI]]) 6 | (require '[thi.ng.math.noise :as n]) 7 | 8 | (def viz-spec 9 | {:x-axis (viz/linear-axis 10 | {:domain [0 63] 11 | :range [50 550] 12 | :major 8 13 | :minor 2 14 | :pos 550}) 15 | :y-axis (viz/linear-axis 16 | {:domain [0 63] 17 | :range [550 50] 18 | :major 8 19 | :minor 2 20 | :pos 50 21 | :label-dist 15 22 | :label-style {:text-anchor "end"}}) 23 | :data [{:matrix (->> (for [y (range 64) x (range 64)] (n/noise2 (* x 0.06) (* y 0.06))) 24 | (viz/contour-matrix 64 64)) 25 | :levels (range -1 1 0.05) 26 | :value-domain [-1.0 1.0] 27 | :attribs {:fill "none" :stroke "#0af"} 28 | :layout viz/svg-contour-plot}]}) 29 | 30 | (def viz-spec-log 31 | (merge viz-spec 32 | {:x-axis (viz/log-axis 33 | {:domain [0 64] 34 | :range [50 550] 35 | :base 2 36 | :pos 555}) 37 | :y-axis (viz/log-axis 38 | {:domain [0 64] 39 | :range [550 50] 40 | :base 2 41 | :pos 45 42 | :label-dist 15 43 | :label-style {:text-anchor "end"}})})) 44 | 45 | (def fill-attribs {:fill (col/rgba 0.0 0.66 1.0 0.05) :stroke "#fff"}) 46 | 47 | (defn export-viz 48 | [viz path] (->> viz (svg/svg {:width 600 :height 600}) (svg/serialize) (spit path))) 49 | 50 | (->> {"out/contours-outline.svg" [viz-spec false] 51 | "out/contours.svg" [viz-spec true] 52 | "out/contours-log-outline.svg" [viz-spec-log false] 53 | "out/contours-log.svg" [viz-spec-log true]} 54 | (run! 55 | (fn [[path [spec fill?]]] 56 | (-> (if fill? (assoc-in spec [:data 0 :attribs] fill-attribs) spec) 57 | (viz/svg-plot2d-cartesian) 58 | (export-viz path))))) 59 | -------------------------------------------------------------------------------- /examples/viz/heatmap.clj: -------------------------------------------------------------------------------- 1 | (require '[thi.ng.geom.viz.core :as viz] :reload) 2 | (require '[thi.ng.geom.svg.core :as svg]) 3 | (require '[thi.ng.geom.vector :as v]) 4 | (require '[thi.ng.color.core :as col]) 5 | (require '[thi.ng.math.core :as m :refer [PI TWO_PI]]) 6 | (require '[thi.ng.color.gradients :as grad]) 7 | (require '[thi.ng.geom.core :as g]) 8 | (require '[thi.ng.geom.utils :as gu]) 9 | (require '[thi.ng.math.noise :as n]) 10 | 11 | (def test-matrix 12 | (->> (for [y (range 10) x (range 50)] (n/noise2 (* x 0.1) (* y 0.25))) 13 | (viz/matrix-2d 50 10))) 14 | 15 | (defn heatmap-spec 16 | [id] 17 | {:matrix test-matrix 18 | :value-domain (viz/value-domain-bounds test-matrix) 19 | :palette (->> id grad/cosine-schemes (grad/cosine-gradient 100)) 20 | :palette-scale viz/linear-scale 21 | :layout viz/svg-heatmap}) 22 | 23 | (defn cartesian-viz 24 | [prefix id & [opts]] 25 | (->> {:x-axis (viz/linear-axis 26 | {:domain [0 50] 27 | :range [50 550] 28 | :major 10 29 | :minor 5 30 | :pos 280}) 31 | :y-axis (viz/linear-axis 32 | {:domain [0 10] 33 | :range [280 20] 34 | :major 1 35 | :pos 50 36 | :label-dist 15 37 | :label-style {:text-anchor "end"}}) 38 | :data [(merge (heatmap-spec id) opts)]} 39 | (viz/svg-plot2d-cartesian) 40 | (svg/svg {:width 600 :height 300}) 41 | (svg/serialize) 42 | (spit (str prefix "-" (name id) ".svg")))) 43 | 44 | (cartesian-viz "out/hm" :rainbow2) 45 | (cartesian-viz "out/hm" :orange-blue) 46 | 47 | (defn polar-viz 48 | [prefix id & [opts]] 49 | (->> {:x-axis (viz/linear-axis 50 | {:domain [0 50] 51 | :range [(* 1.1 PI) (* 1.9 PI)] 52 | :major 10 53 | :minor 5 54 | :pos 280}) 55 | :y-axis (viz/linear-axis 56 | {:domain [0 10] 57 | :range [90 280] 58 | :major 5 59 | :pos (* 1.1 PI) 60 | :major-size 10 61 | :label-dist 20}) 62 | :origin (v/vec2 300) 63 | :data [(merge (heatmap-spec id) opts)]} 64 | (viz/svg-plot2d-polar) 65 | (svg/svg {:width 600 :height 320}) 66 | (svg/serialize) 67 | (spit (str prefix "-" (name id) ".svg")))) 68 | 69 | (polar-viz "out/hmp" :yellow-magenta-cyan) 70 | (polar-viz "out/hmp" :green-magenta) 71 | 72 | ;; using custom shape function applied for each matrix cell 73 | ;; (a circle fitting within the 4 points defining a grid cell) 74 | (cartesian-viz "out/hms" :rainbow2 {:shape viz/circle-cell}) 75 | (polar-viz "out/hmsp" :rainbow2 {:shape viz/circle-cell}) 76 | -------------------------------------------------------------------------------- /examples/viz/hm-github.clj: -------------------------------------------------------------------------------- 1 | ;;(require '[tentacles.repos :as repos]) 2 | (require '[thi.ng.ndarray.core :as nd]) 3 | (require '[clojure.string :as str]) 4 | (require '[clojure.java.shell :refer [sh]]) 5 | 6 | (def day (* 24 60 60 1000)) 7 | (def week (* 7 day)) 8 | (def fmt-iso8601 (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ssX")) 9 | (def fmt-month (java.text.SimpleDateFormat. "MMM")) 10 | (def fmt-year (java.text.SimpleDateFormat. "yyyy")) 11 | (def ->epoch #(try (.getTime (.parse fmt-iso8601 %)) (catch Exception e))) 12 | 13 | (defn month-or-year 14 | [from] 15 | #(let [d (java.util.Date. (long (+ from (* % week))))] 16 | (.format (if (zero? (.getMonth d)) fmt-year fmt-month) d))) 17 | 18 | ;; currently disabled to due CLJ 1.8 incompatibility 19 | #_(defn load-commits-gh 20 | [user repo] 21 | (prn (str "loading GH commit history: " user "/" repo)) 22 | (->> (repos/commits user repo {:all-pages true}) 23 | (map #(->epoch (get-in % [:commit :author :date]))) 24 | (filter identity))) 25 | 26 | (defn load-commits-fs 27 | [repo-path] 28 | (->> (sh "git" "log" "--pretty=format:%aI" :dir repo-path) 29 | :out 30 | str/split-lines 31 | (map ->epoch) 32 | (filter identity))) 33 | 34 | (defn commits-per-week-day 35 | [t0 commits] 36 | (->> (for [c commits 37 | :let [t (- c t0) 38 | w (int (/ t week)) 39 | d (int (/ (rem t week) day))]] 40 | [w d]) 41 | (frequencies) 42 | (sort-by first))) 43 | 44 | (defn commits->matrix 45 | [commits] 46 | (let [weeks (inc (- (ffirst (last commits)) (first (ffirst commits)))) 47 | mat (nd/ndarray :int8 (byte-array (* 7 weeks)) [7 weeks])] 48 | (doseq [[[w d] n] commits] (nd/set-at mat d w n)) 49 | mat)) 50 | 51 | (let [commits (load-commits-fs ".") 52 | ;;commits (load-commits-gh "thi-ng" "geom") 53 | [from to] (viz/value-domain-bounds commits) 54 | from (* (long (/ from week)) week) 55 | to (* (inc (long (/ to week))) week) 56 | mat (commits->matrix (commits-per-week-day from commits)) 57 | weeks (last (nd/shape mat)) 58 | max-x (+ 50 (* weeks 10))] 59 | (->> {:x-axis (viz/linear-axis 60 | {:domain [0 weeks] 61 | :range [50 max-x] 62 | :major 4 63 | :minor 1 64 | :pos 85 65 | :label (viz/default-svg-label (month-or-year from))}) 66 | :y-axis (viz/linear-axis 67 | {:domain [0 7] 68 | :range [10 80] 69 | :visible false}) 70 | :data [{:matrix mat 71 | :value-domain [1 (reduce max mat)] 72 | :palette (->> :yellow-red grad/cosine-schemes (grad/cosine-gradient 100)) 73 | :palette-scale viz/linear-scale 74 | :layout viz/svg-heatmap 75 | :shape viz/circle-cell}]} 76 | (viz/svg-plot2d-cartesian) 77 | (svg/svg {:width (+ 70 max-x) :height 120}) 78 | (svg/serialize) 79 | (spit "out/commit-history.svg"))) 80 | -------------------------------------------------------------------------------- /examples/viz/intervals.clj: -------------------------------------------------------------------------------- 1 | (require '[thi.ng.geom.viz.core :as viz] :reload) 2 | (require '[thi.ng.geom.svg.core :as svg]) 3 | (require '[thi.ng.geom.vector :as v]) 4 | (require '[thi.ng.color.core :as col]) 5 | (require '[thi.ng.math.core :as m :refer [PI TWO_PI]]) 6 | 7 | (->> {:x-axis (viz/linear-axis 8 | {:domain [-10 310] 9 | :range [50 550] 10 | :major 100 11 | :minor 50 12 | :pos 150}) 13 | :y-axis (viz/linear-axis 14 | {:domain [0 4] 15 | :range [50 150] 16 | :visible false}) 17 | :data [{:values [[0 100] [10 90] [80 200] [250 300] [150 170] [110 120] 18 | [210 280] [180 280] [160 240] [160 170]] 19 | :attribs {:stroke-width "10px" :stroke-linecap "round" :stroke "#0af"} 20 | :layout viz/svg-stacked-interval-plot}]} 21 | (viz/svg-plot2d-cartesian) 22 | (svg/svg {:width 600 :height 200}) 23 | (svg/serialize) 24 | (spit "out/intervals.svg")) 25 | -------------------------------------------------------------------------------- /examples/viz/lineplot.clj: -------------------------------------------------------------------------------- 1 | (require '[thi.ng.geom.viz.core :as viz] :reload) 2 | (require '[thi.ng.geom.svg.core :as svg]) 3 | (require '[thi.ng.geom.vector :as v]) 4 | (require '[thi.ng.color.core :as col]) 5 | (require '[thi.ng.math.core :as m :refer [PI TWO_PI]]) 6 | 7 | (defn test-equation 8 | [t] (let [x (m/mix* (- PI) PI t)] [x (* (Math/cos (* 0.5 x)) (Math/sin (* x x x)))])) 9 | 10 | (defn export-viz 11 | [viz path] (->> viz (svg/svg {:width 600 :height 320}) (svg/serialize) (spit path))) 12 | 13 | (def viz-spec 14 | {:x-axis (viz/linear-axis 15 | {:domain [(- PI) PI] 16 | :range [50 580] 17 | :major (/ PI 2) 18 | :minor (/ PI 4) 19 | :pos 250}) 20 | :y-axis (viz/linear-axis 21 | {:domain [-1 1] 22 | :range [250 20] 23 | :major 0.2 24 | :minor 0.1 25 | :pos 50 26 | :label-dist 15 27 | :label-style {:text-anchor "end"}}) 28 | :grid {:attribs {:stroke "#caa"} 29 | :minor-y true} 30 | :data [{:values (map test-equation (m/norm-range 200)) 31 | :attribs {:fill "none" :stroke "#0af"} 32 | :layout viz/svg-line-plot}]}) 33 | 34 | (-> viz-spec 35 | (viz/svg-plot2d-cartesian) 36 | (export-viz "out/lineplot.svg")) 37 | 38 | ;; same spec, just update style attribs & layout method 39 | (-> viz-spec 40 | (update-in [:data 0] merge {:attribs {:fill "#0af"} :layout viz/svg-area-plot}) 41 | (viz/svg-plot2d-cartesian) 42 | (export-viz "out/areaplot.svg")) 43 | 44 | (def viz-spec-polar 45 | {:x-axis (viz/linear-axis 46 | {:domain [(- PI) PI] 47 | :range [(* 1.1 PI) (* 1.9 PI)] 48 | :major (/ PI 2) 49 | :minor (/ PI 16) 50 | :pos 280}) 51 | :y-axis (viz/linear-axis 52 | {:domain [-1 1] 53 | :range [60 280] 54 | :major 0.5 55 | :minor 0.25 56 | :pos (* 1.1 PI)}) 57 | :origin (v/vec2 300 310) 58 | :grid {:attribs {:stroke "#caa" :fill "none"} 59 | :minor-x true 60 | :minor-y true} 61 | :data [{:values (map test-equation (m/norm-range 200)) 62 | :attribs {:fill "none" :stroke "#0af"} 63 | :layout viz/svg-line-plot}]}) 64 | 65 | (-> viz-spec-polar (viz/svg-plot2d-polar) (export-viz "out/lineplot-polar.svg")) 66 | 67 | ;; same spec, just update style attribs & layout method 68 | (-> viz-spec-polar 69 | (update-in [:data 0] merge {:attribs {:fill "#0af"} :res 20 :layout viz/svg-area-plot}) 70 | (viz/svg-plot2d-polar) 71 | (export-viz "out/areaplot-polar.svg")) 72 | -------------------------------------------------------------------------------- /examples/viz/radar.clj: -------------------------------------------------------------------------------- 1 | (require '[thi.ng.geom.viz.core :as viz] :reload) 2 | (require '[thi.ng.geom.svg.core :as svg]) 3 | (require '[thi.ng.geom.vector :as v]) 4 | (require '[thi.ng.color.core :as col]) 5 | (require '[thi.ng.math.core :as m :refer [PI TWO_PI]]) 6 | 7 | (def category->domain (zipmap [:C1 :C2 :C3 :C4 :C5 :C6] (range))) 8 | (def domain->category (reduce-kv #(assoc % %3 %2) {} category->domain)) 9 | 10 | (defn random-radar-spec 11 | "Generates radar plot data spec w/ random values for each category in the form: 12 | {:C1 0.8 :C2 0.2 ...}" 13 | [color] 14 | {:values (zipmap (keys category->domain) (repeatedly #(m/random 0.25 1))) 15 | :item-pos (fn [[k v]] [(category->domain k) v]) 16 | :attribs {:fill (col/rgba color)} 17 | :layout viz/svg-radar-plot}) 18 | 19 | (defn random-radar-spec-minmax 20 | "Generates radar plot data spec w/ random value intervals for each category in the form: 21 | {:C1 [0.5 0.8] :C2 [0.12 0.2] ...}" 22 | [color] 23 | {:values (zipmap 24 | (keys category->domain) 25 | (repeatedly #(let [x (m/random 0.5 1)] [(* x (m/random 0.25 0.75)) x]))) 26 | :item-pos-min (fn [[k v]] [(category->domain k) (first v)]) 27 | :item-pos-max (fn [[k v]] [(category->domain k) (peek v)]) 28 | :attribs {:fill (col/rgba color)} 29 | :layout viz/svg-radar-plot-minmax}) 30 | 31 | (def viz-spec 32 | {:x-axis (viz/linear-axis 33 | {:domain [0 5] 34 | :range [0 (* (/ 5 6) TWO_PI)] 35 | :major 1 36 | :label-dist 20 37 | :pos 260 38 | :label (viz/default-svg-label (comp name domain->category))}) 39 | :y-axis (viz/linear-axis 40 | {:domain [0 1.05] 41 | :range [0 260] 42 | :major 0.5 43 | :minor 0.1 44 | :pos (/ PI 2) 45 | :label-style {:text-anchor "start"} 46 | :label (viz/default-svg-label viz/format-percent)}) 47 | :grid {:minor-x true :minor-y true} 48 | :origin (v/vec2 300 300) 49 | :circle true}) 50 | 51 | (->> (assoc viz-spec :data (mapv random-radar-spec [[0 0.66 1 0.33] [1 0.5 0 0.33] [1 0 0.8 0.33]])) 52 | (viz/svg-plot2d-polar) 53 | (svg/svg {:width 600 :height 600}) 54 | (svg/serialize) 55 | (spit "out/radarplot.svg")) 56 | 57 | (->> (assoc viz-spec :data (mapv random-radar-spec-minmax [[0 0.66 1 0.33] [1 0.5 0 0.33] [1 0 0.8 0.33]])) 58 | (viz/svg-plot2d-polar) 59 | (svg/svg {:width 600 :height 600}) 60 | (svg/serialize) 61 | (spit "out/radarplot-minmax.svg")) 62 | -------------------------------------------------------------------------------- /examples/viz/scatter.clj: -------------------------------------------------------------------------------- 1 | (require '[thi.ng.geom.viz.core :as viz] :reload) 2 | (require '[thi.ng.geom.svg.core :as svg]) 3 | (require '[thi.ng.geom.vector :as v]) 4 | (require '[thi.ng.color.core :as col]) 5 | (require '[thi.ng.math.core :as m :refer [PI TWO_PI]]) 6 | 7 | (defn export-viz 8 | [spec path] 9 | (->> spec 10 | (viz/svg-plot2d-cartesian) 11 | (svg/svg {:width 600 :height 600}) 12 | (svg/serialize) 13 | (spit path))) 14 | 15 | (def spec 16 | {:x-axis (viz/log-axis 17 | {:domain [1 201] 18 | :range [50 590] 19 | :pos 550}) 20 | :y-axis (viz/linear-axis 21 | {:domain [0.1 100] 22 | :range [550 20] 23 | :major 10 24 | :minor 5 25 | :pos 50 26 | :label-dist 15 27 | :label-style {:text-anchor "end"}}) 28 | :grid {:attribs {:stroke "#caa"} 29 | :minor-x true 30 | :minor-y true} 31 | :data [{:values (map (juxt identity #(Math/sqrt %)) (range 0 200 2)) 32 | :attribs {:fill "#0af" :stroke "none"} 33 | :layout viz/svg-scatter-plot} 34 | {:values (map (juxt identity #(m/random %)) (range 0 200 2)) 35 | :attribs {:fill "none" :stroke "#f60"} 36 | :shape (viz/svg-triangle-down 6) 37 | :layout viz/svg-scatter-plot}]}) 38 | 39 | (export-viz spec "out/scatter-linear.svg") 40 | 41 | (-> spec 42 | (assoc :y-axis (viz/log-axis 43 | {:domain [0.1 101] 44 | :range [550 20] 45 | :pos 50 46 | :label-dist 15 47 | :label-style {:text-anchor "end"}})) 48 | (export-viz "out/scatter-log.svg")) 49 | -------------------------------------------------------------------------------- /examples/viz/terrain.clj: -------------------------------------------------------------------------------- 1 | (require '[thi.ng.geom.viz.core :as viz] :reload) 2 | (require '[thi.ng.geom.svg.core :as svg]) 3 | (require '[thi.ng.geom.vector :as v]) 4 | (require '[thi.ng.color.core :as col]) 5 | (require '[thi.ng.math.core :as m :refer [PI TWO_PI]]) 6 | (require '[thi.ng.color.gradients :as grad]) 7 | 8 | (defn load-image 9 | [path] 10 | (let [img (javax.imageio.ImageIO/read (java.io.File. path)) 11 | w (.getWidth img) 12 | h (.getHeight img) 13 | rgb (.getRGB img 0 0 w h (int-array (* w h)) 0 w)] 14 | (viz/contour-matrix w h (map #(bit-and % 0xff) rgb)))) 15 | 16 | (def viz-spec 17 | {:x-axis (viz/linear-axis 18 | {:domain [0 79] 19 | :range [50 550] 20 | :major 8 21 | :minor 2 22 | :pos 550}) 23 | :y-axis (viz/linear-axis 24 | {:domain [0 79] 25 | :range [50 550] 26 | :major 8 27 | :minor 2 28 | :pos 50 29 | :label-dist 15 30 | :label-style {:text-anchor "end"}}) 31 | :data [{:matrix (load-image "assets/viz/california-detail-gis.png") 32 | :value-domain [0.0 255.0] 33 | :attribs {:fill "none"} 34 | :palette (->> :orange-blue grad/cosine-schemes (grad/cosine-gradient 100)) 35 | :contour-attribs (fn [col] {:stroke col}) 36 | :layout viz/svg-contour-plot}]}) 37 | 38 | (doseq [res [6 12 18 24]] 39 | (->> (assoc-in viz-spec [:data 0 :levels] (range 0 255 res)) 40 | (viz/svg-plot2d-cartesian) 41 | (svg/svg {:width 600 :height 600}) 42 | (svg/serialize) 43 | (spit (str "out/terrain-" res ".svg")))) 44 | -------------------------------------------------------------------------------- /examples/voxel/gyroid.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.voxel.gyroid 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.vector :refer [vec3]] 5 | [thi.ng.geom.voxel.svo :as svo] 6 | [thi.ng.geom.voxel.isosurface :as iso] 7 | [thi.ng.geom.mesh.io :as mio] 8 | [thi.ng.math.core :as m] 9 | [clojure.java.io :as io])) 10 | 11 | (def res (double 1/8)) 12 | (def wall 0.25) 13 | 14 | (defn gyroid ^double [s t p] 15 | "Evaluates gyroid function at scaled point `p`." 16 | (let [[x y z] (m/* p s)] 17 | (- (m/abs* 18 | (+ (* (Math/cos x) (Math/sin z)) 19 | (* (Math/cos y) (Math/sin x)) 20 | (* (Math/cos z) (Math/sin y)))) 21 | t))) 22 | 23 | (defn voxel-box 24 | ([tree op flt r] 25 | (voxel-box tree op flt r r r)) 26 | ([tree op flt rx ry rz] 27 | (->> (for [x rx y ry, z rz] (vec3 x y z)) 28 | (filter flt) 29 | (svo/apply-voxels op tree)))) 30 | 31 | (time 32 | (def v 33 | (reduce 34 | (fn [tree [op r]] (voxel-box tree op identity r)) 35 | (svo/voxeltree 32 res) 36 | [[svo/set-at (range 10 20 res)] [svo/set-at (range 15 25 res)]]))) 37 | 38 | (time 39 | (def v2 40 | (reduce 41 | (fn [tree [op r]] (voxel-box tree op identity r)) 42 | v [[svo/delete-at (range (+ 10 wall) (- 20 wall) res)] 43 | [svo/delete-at (range (+ 15 wall) (- 25 wall) res)]]))) 44 | 45 | (time 46 | (def v3 47 | (reduce 48 | (fn [tree [op r]] 49 | (voxel-box tree op #(m/in-range? 0.0 10.0 (gyroid 1.0 1.2 %)) r)) 50 | v2 [[svo/set-at (range (+ 10 wall) (- 20 wall) res)] 51 | [svo/set-at (range (+ 15 wall) (- 25 wall) res)]]))) 52 | 53 | (time 54 | (def v4 55 | (reduce 56 | (fn [tree [op rx ry rz]] (voxel-box tree op identity rx ry rz)) 57 | v3 [[svo/delete-at (range 9 26 res) (range 9 26 res) (range 18 26 res)]]))) 58 | 59 | (time 60 | (with-open [o (io/output-stream "out/voxel-gyroid.stl")] 61 | (mio/write-stl 62 | (mio/wrapped-output-stream o) 63 | (g/tessellate (iso/surface-mesh v4 11 0.5))))) 64 | -------------------------------------------------------------------------------- /examples/voxel/noise.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.voxel.noise 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.vector :refer [vec3]] 5 | [thi.ng.geom.voxel.svo :as svo] 6 | [thi.ng.geom.voxel.isosurface :as iso] 7 | [thi.ng.geom.mesh.io :as mio] 8 | [thi.ng.math.core :as m] 9 | [clojure.java.io :as io] 10 | [thi.ng.math.noise :as n])) 11 | 12 | (def res (double 1/4)) 13 | (def n-scale 0.1) 14 | (def iso-val 0.33) 15 | 16 | (def v 17 | (let [r (range 1 31 res)] 18 | (->> (for [x r y r z r 19 | :when (<= iso-val (m/abs* (n/noise3 (* x n-scale) (* y n-scale) (* z n-scale))))] 20 | (vec3 x y z)) 21 | (svo/apply-voxels svo/set-at (svo/voxeltree 32 res))))) 22 | 23 | (time 24 | (with-open [o (io/output-stream "out/voxel-noise.stl")] 25 | (mio/write-stl 26 | (mio/wrapped-output-stream o) 27 | (g/tessellate (iso/surface-mesh v 10 iso-val))))) 28 | -------------------------------------------------------------------------------- /examples/voxel/sphere.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.examples.voxel.sphere 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.vector :refer [vec3]] 5 | [thi.ng.geom.voxel.svo :as svo] 6 | [thi.ng.geom.voxel.isosurface :as iso] 7 | [thi.ng.geom.mesh.io :as mio] 8 | [thi.ng.math.core :as m] 9 | [clojure.java.io :as io])) 10 | 11 | (def res (double 1/4)) 12 | (def num-holes 30) 13 | 14 | (defn voxel-sphere 15 | ([tree op o r res] 16 | (let [rg (range (- r) (+ r res) res)] 17 | (->> (for [x rg y rg, z rg 18 | :let [v (vec3 x y z)] 19 | :when (<= (m/mag v) r)] (m/+ o v)) 20 | (svo/apply-voxels op tree))))) 21 | 22 | (time 23 | (def v 24 | (reduce 25 | (fn [tree [op o r]] (voxel-sphere tree op o r res)) 26 | (svo/voxeltree 32 res) 27 | (concat 28 | [[svo/set-at (vec3 15 15 15) 14]] 29 | (repeatedly 30 | num-holes 31 | #(vector 32 | svo/delete-at 33 | (vec3 (m/random 32) (m/random 32) (m/random 32)) 34 | (m/random 4 8))))))) 35 | 36 | (time 37 | (with-open [o (io/output-stream "out/voxel-sphere.stl")] 38 | (mio/write-stl 39 | (mio/wrapped-output-stream o) 40 | (g/tessellate (iso/surface-mesh v 10 0.5))))) 41 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | thi.ng/geom test 7 | 8 | 9 | 10 |
11 | 14 |
15 | 16 | 17 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /org/examples/all.org: -------------------------------------------------------------------------------- 1 | *This file is archived and only kept for reference - DO NOT edit* 2 | 3 | * thi.ng/geom examples 4 | 5 | This project contains a growing number (currently ~30) examples 6 | demonstrating usage patterns of various modules and core 7 | functionality: 8 | 9 | ** Clojure examples 10 | 11 | - [[./ptf/demos.org][PTF torus knot examples]] 12 | - [[./gl/jogl.org][OpenGL (JOGL) examples]] 13 | - [[./svg/demos.org][SVG examples]] 14 | - [[./viz/demos.org][Visualization examples]] (also SVG) 15 | - [[./voxel/demos.org][Voxel examples]] 16 | 17 | ** Clojurescript examples 18 | 19 | - [[./gl/webgl.org][WebGL examples]] 20 | 21 | ** REPL helpers 22 | 23 | The following helpers are tangled to the file =examples/repl.clj= in 24 | the project's =babel= directory (the build directory). To run all 25 | (Clojure) examples for a given module do this: 26 | 27 | #+BEGIN_SRC 28 | cd geom 29 | ./tangle-all.sh 30 | cd babel 31 | lein repl 32 | 33 | # in the REPL... 34 | 35 | (load-file "examples/repl.clj") 36 | (run-all-in-dir "examples/<>") ;; svg, viz etc. 37 | #+END_SRC 38 | 39 | The =examples/repl.clj= file contains the following function: 40 | 41 | #+BEGIN_SRC clojure :tangle ../babel/examples/repl.clj :mkdirp yes :padline no 42 | (defn run-all-in-dir 43 | "Loads (and executes) all .clj files in given directory." 44 | [dir] 45 | (doseq [f (filter #(.endsWith (.getName %) ".clj") (file-seq (java.io.File. dir)))] 46 | (load-file (.getAbsolutePath f)))) 47 | #+END_SRC 48 | -------------------------------------------------------------------------------- /org/src/gl/animator.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_4_gh: 6 | - [[#thinggeomglanimator][thi.ng.geom.gl.animator]] 7 | - [[#animator][Animator]] 8 | - [[#complete-namespace-definition][Complete namespace definition]] 9 | 10 | * thi.ng.geom.gl.animator 11 | 12 | ** Animator 13 | 14 | #+BEGIN_SRC clojure :noweb-ref animator 15 | (def animframe-provider 16 | (or 17 | (.-requestAnimationFrame js/self) 18 | (.-webkitRequestAnimationFrame js/self) 19 | (.-mozRequestAnimationFrame js/self) 20 | (.-msRequestAnimationFrame js/self) 21 | (.-oRequestAnimationFrame js/self))) 22 | 23 | (defn now 24 | [] 25 | (or 26 | (.now js/performance) 27 | (.webkitNow js/performance) 28 | (.mozNow js/performance) 29 | (.msNow js/performance) 30 | (.oNow js/performance))) 31 | 32 | (defn animate 33 | ([f] 34 | (animate f nil)) 35 | ([f element] 36 | (let [t0 (.getTime (js/Date.)) 37 | fid (volatile! 0) 38 | f' (fn animate* [] 39 | (if (f (* (- (.getTime (js/Date.)) t0) 1e-3) (vswap! fid inc)) 40 | (if element 41 | (animframe-provider animate* element) 42 | (animframe-provider animate*))))] 43 | (f')))) 44 | #+END_SRC 45 | 46 | ** Complete namespace definition 47 | 48 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/gl/webgl/animator.cljs :noweb yes :mkdirp yes :padline no 49 | (ns thi.ng.geom.gl.webgl.animator) 50 | 51 | <> 52 | #+END_SRC 53 | -------------------------------------------------------------------------------- /org/src/gl/arcball.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_3_gh: 6 | - [[#thinggeomglarcball][thi.ng.geom.gl.arcball]] 7 | - [[#overview][Overview]] 8 | - [[#constructor][Constructor]] 9 | - [[#event-handlers--arcball-operations][Event handlers & arcball operations]] 10 | - [[#helpers][Helpers]] 11 | - [[#complete-namespace-definition][Complete namespace definition]] 12 | 13 | * thi.ng.geom.gl.arcball 14 | ** Overview 15 | 16 | Based on "ARCBALL: A User Interface for Specifying Three-Dimensional 17 | Orientation Using a Mouse" by Ken Shoemake 18 | 19 | - http://www.talisman.org/~erlkonig/misc/shoemake92-arcball.pdf 20 | 21 | ** Constructor 22 | 23 | #+BEGIN_SRC clojure :noweb-ref ctor 24 | (defn arcball 25 | [{:keys [init dist min-dist max-dist radius center] :as ab}] 26 | (let [dist (or dist 2.0) 27 | min-dist (or min-dist (/ dist 2.0)) 28 | max-dist (or max-dist (* dist 2.0)) 29 | curr-rot (if init (q/quat init) (q/quat-from-axis-angle V3Y m/PI))] 30 | (-> ab 31 | (merge 32 | {:dist dist 33 | :min-dist min-dist 34 | :max-dist max-dist 35 | :radius (or radius 300.0) 36 | :center (or center (vec2 640 360)) 37 | :curr-rot curr-rot 38 | :click-rot curr-rot}) 39 | update-view))) 40 | #+END_SRC 41 | 42 | ** Event handlers & arcball operations 43 | 44 | #+BEGIN_SRC clojure :noweb-ref ops 45 | (defn down 46 | [ab x y] 47 | (-> ab 48 | (assoc :click-pos (sphere-position ab x y) 49 | :click-rot (:curr-rot ab)) 50 | update-view)) 51 | 52 | (defn drag 53 | [{:keys [click-pos] :as ab} x y] 54 | (when click-pos 55 | (let [drag-pos (sphere-position ab x y) 56 | axis (m/cross click-pos drag-pos) 57 | theta (m/dot click-pos drag-pos) 58 | drag-rot (q/quat axis theta)] 59 | (-> ab 60 | (assoc :curr-rot (m/* drag-rot (:click-rot ab))) 61 | update-view)))) 62 | 63 | (defn up 64 | [ab] (assoc ab :click-pos nil)) 65 | 66 | (defn resize 67 | [ab w h] 68 | (let [ww (/ w 2) 69 | wh (/ h 2)] 70 | (assoc ab 71 | :radius (* (min ww wh) 2) 72 | :center (vec2 ww wh)))) 73 | 74 | (defn zoom-delta 75 | [{:keys [min-dist max-dist] :as ab} delta] 76 | (-> ab 77 | (assoc :dist 78 | (m/clamp 79 | (mm/madd delta (mm/subm max-dist min-dist 1e-3) (get ab :dist)) 80 | min-dist max-dist)) 81 | update-view)) 82 | 83 | (defn zoom-abs 84 | [ab x] (-> ab (assoc :dist (m/clamp x (:min-dist ab) (:max-dist ab))) update-view)) 85 | 86 | (defn update-view 87 | [{:keys [curr-rot] :as ab}] 88 | (let [q (q/quat (:xyz curr-rot) (- (:w curr-rot))) 89 | offset (g/transform-vector q (vec3 0 0 (get ab :dist))) 90 | up (g/transform-vector q V3Y) 91 | eye (m/- offset)] 92 | (assoc ab :view (mat/look-at eye (vec3) up)))) 93 | 94 | (defn get-view 95 | [ab] (or (get ab :view) (get (update-view ab) :view))) 96 | 97 | (defn get-rotation 98 | [ab] (get ab :curr-rot)) 99 | 100 | (defn set-rotation 101 | [ab q] (-> ab (assoc :curr-rot q) update-view)) 102 | 103 | (defn set-zoom-range 104 | [ab min max] (assoc ab :min-dist min :max-dist max :dist (m/clamp (get ab :dist) min max))) 105 | #+END_SRC 106 | 107 | ** Helpers 108 | 109 | #+BEGIN_SRC clojure :noweb-ref helpers 110 | (defn- sphere-position 111 | [{:keys [center radius]} x y] 112 | (let [v (vec3 (mm/subdiv x (v/x center) radius) (mm/subdiv y (v/y center) radius) 0) 113 | m (m/mag-squared v)] 114 | (if (> m 1.0) 115 | (m/normalize v) 116 | (assoc v :z (Math/sqrt (- 1.0 m)))))) 117 | #+END_SRC 118 | 119 | ** Complete namespace definition 120 | 121 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/gl/arcball.cljc :noweb yes :mkdirp yes :padline no 122 | (ns thi.ng.geom.gl.arcball 123 | #?(:cljs 124 | (:require-macros 125 | [thi.ng.math.macros :as mm])) 126 | (:require 127 | [thi.ng.math.core :as m] 128 | [thi.ng.geom.core :as g] 129 | [thi.ng.geom.vector :as v :refer [vec2 vec3 V3Y]] 130 | [thi.ng.geom.matrix :as mat] 131 | [thi.ng.geom.quaternion :as q] 132 | #?(:clj [thi.ng.math.macros :as mm]))) 133 | 134 | (declare update-view) 135 | 136 | <> 137 | 138 | <> 139 | 140 | <> 141 | #+END_SRC 142 | 143 | 144 | -------------------------------------------------------------------------------- /org/src/gl/camera.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_4_gh: 6 | - [[#thinggeomglcamera][thi.ng.geom.gl.camera]] 7 | - [[#perspective-camera][Perspective camera]] 8 | - [[#helpers][Helpers]] 9 | - [[#complete-namespace-definition][Complete namespace definition]] 10 | 11 | * thi.ng.geom.gl.camera 12 | 13 | ** Perspective camera 14 | 15 | | *Key* | *Type* | *Default* | *Description* | 16 | |-----------+---------------+--------------+-----------------------------------------| 17 | | =:eye= | vec3 | nil | Camera position | 18 | | =:target= | vec3 | (vec3 0) | Camera target (center of view) | 19 | | =:up= | vec3 | (vec3 0 1 0) | Camera up axis | 20 | | =:fov= | float | 45 | Vertical FOV in degrees | 21 | | =:aspect= | float or rect | 16:9 | Camera aspect ratio (or view rectangle) | 22 | | =:near= | float | 0.1 | Camera near clipping distance | 23 | | =:far= | float | 100 | Camera far clipping distance | 24 | 25 | #+BEGIN_SRC clojure :noweb-ref cam 26 | (defn set-view 27 | [cam opts] 28 | (let [cam (update-keys cam [:eye :target :up] opts)] 29 | (assoc cam :view (mat/look-at (get cam :eye) (get cam :target) (get cam :up))))) 30 | 31 | (defn set-projection 32 | [cam opts] 33 | (let [cam (update-keys cam [:fov :aspect :near :far] opts)] 34 | (assoc cam :proj (mat/perspective (get cam :fov) (get cam :aspect) (get cam :near) (get cam :far))))) 35 | 36 | (defn perspective-camera 37 | [opts] 38 | (-> (merge 39 | {:eye (vec3 0.0 0.0 2.0) 40 | :target v/V3 41 | :up v/V3Y 42 | :fov 45 43 | :near 0.1 44 | :far 100 45 | :aspect (/ 16.0 9.0)} 46 | opts) 47 | (set-view opts) 48 | (set-projection opts))) 49 | #+END_SRC 50 | 51 | ** Helpers 52 | #+BEGIN_SRC clojure :noweb-ref helpers 53 | (defn apply 54 | "Takes a GL model spec map & camera, injects :view & :proj 55 | uniforms into spec." 56 | [spec cam] 57 | (update spec :uniforms merge {:view (get cam :view) :proj (get cam :proj)})) 58 | 59 | (defn update-keys 60 | "Takes a map m, key seq and map of new vals, replaces keys in m with 61 | new vals. If a value in opts map is a function, applies fn to value 62 | of key in original map." 63 | [m ks opts] 64 | (reduce-kv 65 | (fn [acc k v] (assoc acc k (if (fn? v) (v (m k)) v))) 66 | m (select-keys opts ks))) 67 | #+END_SRC 68 | 69 | ** Complete namespace definition 70 | 71 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/gl/camera.cljc :noweb yes :mkdirp yes :padline no 72 | (ns thi.ng.geom.gl.camera 73 | (:refer-clojure :exclude [apply]) 74 | (:require 75 | [thi.ng.math.core :as m] 76 | [thi.ng.geom.vector :as v :refer [vec3]] 77 | [thi.ng.geom.matrix :as mat])) 78 | 79 | <> 80 | 81 | <> 82 | #+END_SRC 83 | -------------------------------------------------------------------------------- /org/src/gl/fx-presets.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_3_gh: 6 | - [[#fx-pipeline-presets][FX pipeline presets]] 7 | - [[#bloom][Bloom]] 8 | - [[#threshold][Threshold]] 9 | - [[#blur][Blur]] 10 | - [[#composite][Composite]] 11 | - [[#namespace-definition][Namespace definition]] 12 | 13 | * FX pipeline presets 14 | 15 | ** Bloom 16 | *** Threshold 17 | #+BEGIN_SRC glsl :noweb-ref thresh-fs 18 | #if __VERSION__ >= 300 19 | out vec4 fragColor; 20 | void main() { 21 | float c = threshold(texture(tex, vUV).rgb, thresh * 0.5, thresh); 22 | fragColor = vec4(c, c, c, 1.0); 23 | } 24 | #else 25 | void main() { 26 | float c = threshold(texture2D(tex, vUV).rgb, thresh * 0.5, thresh); 27 | gl_FragColor = vec4(c, c, c, 1.0); 28 | } 29 | #endif 30 | #+END_SRC 31 | 32 | *** Blur 33 | #+BEGIN_SRC glsl :noweb-ref blur-fs 34 | #if __VERSION__ >= 300 35 | out vec4 fragColor; 36 | void main() { 37 | fragColor = vec4((horizontal ? blur5H(tex, vUV) : blur5V(tex, vUV)), 1.0); 38 | } 39 | #else 40 | void main() { 41 | gl_FragColor = vec4((horizontal ? blur5H(tex, vUV) : blur5V(tex, vUV)), 1.0); 42 | } 43 | #endif 44 | #+END_SRC 45 | 46 | *** Composite 47 | #+BEGIN_SRC glsl :noweb-ref comp-fs 48 | #if __VERSION__ >= 300 49 | out vec4 fragColor; 50 | void main() { 51 | fragColor = pow(vec4((texture(tex, vUV).rgb * (1.0 - blend) + texture(tex2, vUV).rgb * blend) * exposure, 1.0), vec4(gamma)); 52 | } 53 | #else 54 | void main() { 55 | gl_FragColor = pow(vec4((texture2D(tex, vUV).rgb * (1.0 - blend) + texture2D(tex2, vUV).rgb * blend) * exposure, 1.0), vec4(gamma)); 56 | } 57 | #endif 58 | #+END_SRC 59 | 60 | *** Namespace definition 61 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/gl/fx/bloom.cljc :noweb yes :mkdirp yes :padline no 62 | (ns thi.ng.geom.gl.fx.bloom 63 | (:require 64 | [thi.ng.dstruct.core :as d] 65 | [thi.ng.geom.rect :as r] 66 | [thi.ng.geom.gl.fx :as fx] 67 | [thi.ng.glsl.core :as glsl :include-macros true] 68 | [thi.ng.glsl.color :as col] 69 | [thi.ng.glsl.texture :as tex])) 70 | 71 | (def threshold-shader-spec 72 | (d/merge-deep 73 | fx/shader-spec 74 | {:fs (->> " 75 | <>" 76 | (glsl/glsl-spec-plain [col/threshold]) 77 | (glsl/assemble)) 78 | :uniforms {:thresh [:float 0.8]}})) 79 | 80 | (def blur-shader-spec 81 | (d/merge-deep 82 | fx/shader-spec 83 | {:fs (->> " 84 | <>" 85 | (glsl/glsl-spec-plain [tex/blur5-h tex/blur5-v]) 86 | (glsl/assemble)) 87 | :uniforms {:horizontal :bool}})) 88 | 89 | (def comp-shader-spec 90 | (d/merge-deep 91 | fx/shader-spec 92 | {:fs " 93 | <>" 94 | :uniforms {:tex2 [:sampler2D 1] 95 | :blend [:float 0.35] 96 | :exposure [:float 1.3] 97 | :gamma [:float 1.25]}})) 98 | 99 | (defn make-pipeline-spec 100 | [w h scale version] 101 | {:width w 102 | :height h 103 | :version version 104 | :fbos {:src {:scale 1} 105 | :ping {:scale scale} 106 | :pong {:scale scale}} 107 | :shaders {:threshold threshold-shader-spec 108 | :blur blur-shader-spec 109 | :final comp-shader-spec} 110 | :passes [{:id :threshold 111 | :target :ping 112 | :shader :threshold 113 | :tex :src} 114 | {:id :blur-h 115 | :target :pong 116 | :shader :blur 117 | :tex :ping 118 | :uniforms {:horizontal true}} 119 | {:id :blur-v 120 | :target :ping 121 | :shader :blur 122 | :tex :pong 123 | :uniforms {:horizontal false}} 124 | {:id :final 125 | :shader :final 126 | :tex [:src :ping] 127 | :viewport (r/rect w h)}]}) 128 | #+END_SRC 129 | -------------------------------------------------------------------------------- /org/src/gl/jogl-buffers.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_3_gh: 6 | - [[#thinggeomgljoglbuffers][thi.ng.geom.gl.jogl.buffers]] 7 | - [[#native-buffer-wrappers-for-clojure--jogl][Native buffer wrappers for Clojure / JOGL]] 8 | - [[#todo-refactor-to-avoid-2x-copy-via-array-fill-directly][TODO refactor to avoid 2x copy via array, fill directly]] 9 | - [[#complete-namespace-definition][Complete namespace definition]] 10 | 11 | * thi.ng.geom.gl.jogl.buffers 12 | ** Native buffer wrappers for Clojure / JOGL 13 | *** TODO refactor to avoid 2x copy via array, fill directly 14 | 15 | #+BEGIN_SRC clojure :noweb-ref buffers 16 | (defn ^FloatBuffer float-buffer 17 | [n-or-coll] 18 | (if (number? n-or-coll) 19 | (FloatBuffer/allocate (int n-or-coll)) 20 | (-> n-or-coll float-array FloatBuffer/wrap))) 21 | 22 | (defn ^FloatBuffer float-buffer-direct 23 | [n-or-coll] 24 | (if (number? n-or-coll) 25 | (GLBuffers/newDirectFloatBuffer (int n-or-coll)) 26 | (-> n-or-coll float-array GLBuffers/newDirectFloatBuffer))) 27 | 28 | (defn ^DoubleBuffer double-buffer 29 | [n-or-coll] 30 | (if (number? n-or-coll) 31 | (DoubleBuffer/allocate (int n-or-coll)) 32 | (-> n-or-coll double-array DoubleBuffer/wrap))) 33 | 34 | (defn ^DoubleBuffer double-buffer-direct 35 | [n-or-coll] 36 | (if (number? n-or-coll) 37 | (GLBuffers/newDirectDoubleBuffer (int n-or-coll)) 38 | (-> n-or-coll double-array GLBuffers/newDirectDoubleBuffer))) 39 | 40 | (defn ^ShortBuffer short-buffer 41 | [n-or-coll] 42 | (if (number? n-or-coll) 43 | (ShortBuffer/allocate (int n-or-coll)) 44 | (-> n-or-coll short-array ShortBuffer/wrap))) 45 | 46 | (defn ^ShortBuffer short-buffer-direct 47 | [n-or-coll] 48 | (if (number? n-or-coll) 49 | (GLBuffers/newDirectShortBuffer (int n-or-coll)) 50 | (-> n-or-coll short-array GLBuffers/newDirectShortBuffer))) 51 | 52 | (defn ^IntBuffer int-buffer 53 | [n-or-coll] 54 | (if (number? n-or-coll) 55 | (IntBuffer/allocate (int n-or-coll)) 56 | (-> n-or-coll int-array IntBuffer/wrap))) 57 | 58 | (defn ^IntBuffer int-buffer-direct 59 | [n-or-coll] 60 | (if (number? n-or-coll) 61 | (GLBuffers/newDirectIntBuffer (int n-or-coll)) 62 | (-> n-or-coll int-array GLBuffers/newDirectIntBuffer))) 63 | 64 | (defn copy-float-buffer 65 | [^FloatBuffer dest ^FloatBuffer src did sid len] 66 | (.position dest (int did)) 67 | (loop [len len, did did, sid sid] 68 | (when (pos? len) 69 | (.put dest (.get src (int sid))) 70 | (recur (dec len) (unchecked-inc did) (unchecked-inc sid))))) 71 | 72 | (defn copy-float-buffer-vec2 73 | [^FloatBuffer dest ^FloatBuffer src did sid] 74 | (doto dest 75 | (.position (int did)) 76 | (.put (.get src (int sid))) 77 | (.put (.get src (unchecked-add-int sid 1))))) 78 | 79 | (defn copy-float-buffer-vec3 80 | [^FloatBuffer dest ^FloatBuffer src did sid] 81 | (doto dest 82 | (.position (int did)) 83 | (.put (.get src (int sid))) 84 | (.put (.get src (unchecked-add-int sid 1))) 85 | (.put (.get src (unchecked-add-int sid 2))))) 86 | 87 | (defn copy-float-buffer-vec4 88 | [^FloatBuffer dest ^FloatBuffer src did sid] 89 | (doto dest 90 | (.position (int did)) 91 | (.put (.get src (int sid))) 92 | (.put (.get src (unchecked-add-int sid 1))) 93 | (.put (.get src (unchecked-add-int sid 2))) 94 | (.put (.get src (unchecked-add-int sid 3))))) 95 | #+END_SRC 96 | 97 | ** Complete namespace definition 98 | 99 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/gl/jogl/buffers.clj :noweb yes :mkdirp yes :padline no 100 | (ns thi.ng.geom.gl.jogl.buffers 101 | (:import 102 | [com.jogamp.opengl.util GLBuffers] 103 | [java.nio Buffer DoubleBuffer FloatBuffer ShortBuffer IntBuffer])) 104 | 105 | <> 106 | #+END_SRC 107 | -------------------------------------------------------------------------------- /org/src/gl/utils.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_4_gh: 6 | - [[#thinggeomglutils][thi.ng.geom.gl.utils]] 7 | - [[#dom-element-content-retrieval][DOM element content retrieval]] 8 | - [[#sequence-looping][Sequence looping]] 9 | - [[#complete-namespace-definition][Complete namespace definition]] 10 | 11 | * thi.ng.geom.gl.utils 12 | 13 | ** DOM element content retrieval 14 | 15 | #+BEGIN_SRC clojure :noweb-ref utils 16 | (defn get-script-text 17 | [id] 18 | (if-let [e (.getElementById js/document id)] 19 | (.-text e) 20 | (err/illegal-arg! (str "Unknown DOM element: " id)))) 21 | #+END_SRC 22 | 23 | ** Sequence looping 24 | 25 | #+BEGIN_SRC clojure :noweb-ref utils 26 | (defn loop-kv 27 | "A combination of map & doseq specialized for maps. Takes a function `f` and 28 | a map, calls `f` with each key & value, discards results." 29 | [f xs] 30 | (loop [xs xs] 31 | (if xs 32 | (let [x (first xs)] 33 | (f (first x) (nth x 1)) 34 | (recur (next xs)))))) 35 | #+END_SRC 36 | 37 | ** Complete namespace definition 38 | 39 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/gl/utils.cljs :noweb yes :mkdirp yes :padline no 40 | (ns thi.ng.geom.gl.utils 41 | (:require 42 | [thi.ng.typedarrays.core :as arrays] 43 | [thi.ng.xerror.core :as err]) 44 | (:require-macros 45 | [thi.ng.math.macros :as mm])) 46 | 47 | <> 48 | #+END_SRC 49 | -------------------------------------------------------------------------------- /org/src/svg/adapter.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_4_gh: 6 | - [[#namespace-thinggeomsvgadapter][Namespace: thi.ng.geom.svg.adapter]] 7 | - [[#svg-conversions-for-geomtypes][SVG conversions for geom.types]] 8 | - [[#adapter-implementation][Adapter implementation]] 9 | - [[#reactjs-key-prop-injection][React.js :key prop injection]] 10 | - [[#complete-namespace-svgadapter][Complete namespace: svg.adapter]] 11 | 12 | * Namespace: thi.ng.geom.svg.adapter 13 | ** SVG conversions for geom.types 14 | 15 | The =thi.ng.geom.svg.adapater= namespace provides some simple wrappers 16 | to allow direct use of the shape entities defined in the [[file:~/work/clj/thing/geom/geom-types/src/index.org][geom-types]] 17 | module without having to manually convert them into their SVG 18 | representations. 19 | 20 | The adapaters work by providing implementations of the [[ISVGConvert]] 21 | protocol for all built-in 2D types and a simple helper function to 22 | recursively transform any such types used within an SVG scene. 23 | 24 | Any 3D entities (e.g. meshes) need to be processed via the 25 | [[file:renderer.org][geom.svg.renderer]] namespace. 26 | 27 | *** Adapter implementation 28 | 29 | #+BEGIN_SRC clojure :noweb-ref adapter 30 | (extend-protocol svg/ISVGConvert 31 | 32 | thi.ng.geom.types.Line2 33 | (as-svg 34 | [{p :points} {:keys [__start __end] :as opts}] 35 | (if (or __start __end) 36 | (svg/line-decorated (p 0) (p 1) __start __end opts) 37 | (svg/line (p 0) (p 1) opts))) 38 | 39 | thi.ng.geom.types.Circle2 40 | (as-svg 41 | [_ opts] (svg/circle (get _ :p) (get _ :r) opts)) 42 | 43 | thi.ng.geom.types.LineStrip2 44 | (as-svg 45 | [{:keys [points]} {:keys [__start __segment __end] :as opts}] 46 | (if (or __start __segment __end) 47 | (svg/line-strip-decorated points __start __segment __end opts) 48 | (svg/line-strip points opts))) 49 | 50 | thi.ng.geom.types.Polygon2 51 | (as-svg 52 | [_ opts] (svg/polygon (get _ :points) opts)) 53 | 54 | thi.ng.geom.types.Rect2 55 | (as-svg 56 | [{:keys [p size]} opts] (svg/rect p (size 0) (size 1) opts)) 57 | 58 | thi.ng.geom.types.Triangle2 59 | (as-svg 60 | [_ opts] (svg/polygon (get _ :points) opts))) 61 | 62 | (defn all-as-svg 63 | [form] 64 | (d/postwalk 65 | (fn [x] (if (satisfies? svg/ISVGConvert x) (svg/as-svg x (meta x)) x)) 66 | form)) 67 | #+END_SRC 68 | 69 | *** React.js :key prop injection 70 | 71 | #+BEGIN_SRC clojure :noweb-ref adapter 72 | (defn key-attrib-injector 73 | "To be used with inject-element-attribs, generates an unique :key 74 | attrib for each SVG element w/o :key attrib. Returns updated attribs." 75 | [el attribs] (if (get attribs :key) 76 | attribs 77 | (assoc attribs :key (str (gensym) (hash el))))) 78 | 79 | (defn inject-element-attribs 80 | "Walks SVG DOM tree with thi.ng.dstruct.core/postwalk and applies 81 | given function to each element node. The fn takes 2 args: the 82 | element itself and its attribute map. The fn's return value will be 83 | used as the new attribute map." 84 | ([root] 85 | (inject-element-attribs key-attrib-injector root)) 86 | ([f root] 87 | (d/postwalk 88 | (fn [x] 89 | (if (vector? x) 90 | (let [y (nth x 1)] 91 | (if (or (nil? y) (map? y)) 92 | (assoc x 1 (f x y)) 93 | x)) 94 | x)) 95 | root))) 96 | #+END_SRC 97 | 98 | ** Complete namespace: svg.adapter 99 | 100 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/svg/adapter.cljc :noweb yes :mkdirp yes :padline no 101 | (ns thi.ng.geom.svg.adapter 102 | (:require 103 | [thi.ng.math.core :as m] 104 | [thi.ng.geom.svg.core :as svg] 105 | [thi.ng.geom.core :as g] 106 | [thi.ng.geom.types] 107 | [thi.ng.dstruct.core :as d]) 108 | #?(:clj 109 | (:import 110 | [thi.ng.geom.types Circle2 Line2 LineStrip2 Polygon2 Rect2 Triangle2]))) 111 | 112 | <> 113 | #+END_SRC 114 | -------------------------------------------------------------------------------- /org/src/svg/renderer.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_4_gh: 6 | - [[#namespace-thinggeomsvgrenderer][Namespace: thi.ng.geom.svg.renderer]] 7 | - [[#3d-to-2d-projection][3D to 2D projection]] 8 | - [[#render-functions][Render functions]] 9 | - [[#todo-add-attribute-support-at-least-colors][TODO add attribute support (at least colors)]] 10 | - [[#complete-namespace-definition][Complete namespace definition]] 11 | 12 | * Namespace: thi.ng.geom.svg.renderer 13 | 14 | ** 3D to 2D projection 15 | 16 | #+BEGIN_SRC clojure :noweb-ref projection 17 | (defn project-face 18 | [mvp vtx points] 19 | (mapv #(mat/project-point-z % mvp vtx) points)) 20 | 21 | (defn project-faces 22 | [mvp vtx faces] 23 | (map 24 | (fn [f] 25 | (let [f' (project-face mvp vtx f) 26 | n' (gu/ortho-normal f')] 27 | [f f' n'])) 28 | faces)) 29 | 30 | (defn cull-backfaces 31 | [norm-fn faces] 32 | (filter (fn [f] (neg? (m/dot (norm-fn f) V3Z))) faces)) 33 | 34 | (defn z-map-faces 35 | [faces] 36 | (mapv 37 | (fn [[f f' n']] [(v/z (gu/centroid f')) f f' n']) 38 | faces)) 39 | 40 | (defn z-sort-faces 41 | [z-fn faces] 42 | (reverse (sort-by z-fn faces))) 43 | #+END_SRC 44 | 45 | ** Render functions 46 | *** TODO add attribute support (at least colors) 47 | 48 | #+BEGIN_SRC clojure :noweb-ref render 49 | (defn mesh 50 | [mesh mvp screen shader] 51 | (let [faces (project-faces mvp screen (map #(g/vertices % mesh) (g/faces mesh false))) 52 | faces (->> (if (shader/solid? shader) 53 | (cull-backfaces peek faces) 54 | faces) 55 | (z-map-faces) 56 | (z-sort-faces first))] 57 | (svg/group 58 | (shader/uniforms shader) 59 | (if shader 60 | (map (fn [[z f f']] (svg/polygon f' (shader/shade-facet shader f f' z))) faces) 61 | (map (fn [f] (svg/polygon (f 2) nil)) faces))))) 62 | #+END_SRC 63 | 64 | ** Complete namespace definition 65 | 66 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/svg/renderer.cljc :noweb yes :mkdirp yes :padline no 67 | (ns thi.ng.geom.svg.renderer 68 | (:require 69 | [thi.ng.math.core :as m] 70 | [thi.ng.geom.core :as g] 71 | [thi.ng.geom.svg.core :as svg] 72 | [thi.ng.geom.svg.shaders :as shader] 73 | [thi.ng.geom.utils :as gu] 74 | [thi.ng.geom.vector :as v :refer [vec3 V3Z]] 75 | [thi.ng.geom.matrix :as mat :refer [M44]])) 76 | 77 | <> 78 | 79 | <> 80 | #+END_SRC 81 | -------------------------------------------------------------------------------- /org/src/svg/shaders.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_4_gh: 6 | - [[#namespace-thinggeomsvgshaders][Namespace: thi.ng.geom.svg.shaders]] 7 | - [[#protocols][Protocols]] 8 | - [[#ishader][IShader]] 9 | - [[#shaders][Shaders]] 10 | - [[#complete-namespace-definition][Complete namespace definition]] 11 | 12 | * Namespace: thi.ng.geom.svg.shaders 13 | 14 | ** Protocols 15 | 16 | *** IShader 17 | 18 | #+BEGIN_SRC clojure :noweb-ref protos 19 | (defprotocol IShader 20 | (uniforms [_]) 21 | (solid? [_]) 22 | (shade-facet [_ f f' z])) 23 | #+END_SRC 24 | 25 | ** Shaders 26 | 27 | #+BEGIN_SRC clojure :noweb-ref shader 28 | (defn normal-rgb 29 | ([] (normal-rgb M44)) 30 | ([tx] 31 | (fn [f _ _] 32 | (-> (gu/ortho-normal f) 33 | (g/transform tx) 34 | (m/madd 0.5 0.5))))) 35 | 36 | (defn translucent 37 | [shader alpha] 38 | (fn [f f' z] (conj (vec (shader f f' z)) alpha))) 39 | 40 | (defn shader 41 | [{:keys [fill stroke uniforms flags]}] 42 | (reify 43 | IShader 44 | (shade-facet [_ f f' z] 45 | (cond-> {} 46 | fill (assoc :fill (col/rgba (if (fn? fill) (fill f f' z) fill))) 47 | stroke (assoc :stroke (col/rgba (if (fn? stroke) (stroke f f' z) stroke))))) 48 | (uniforms [_] uniforms) 49 | (solid? [_] (get flags :solid true)))) 50 | 51 | (defn lambert 52 | [{:keys [view light-dir light-col diffuse ambient]}] 53 | (let [light-col (vec3 light-col) 54 | light-dir (m/normalize (vec3 light-dir)) 55 | diffuse (if (fn? diffuse) diffuse (vec3 diffuse)) 56 | ambient (if (fn? ambient) ambient (vec3 ambient)) 57 | nmat (m/transpose (m/invert view))] 58 | (fn [f f' z] 59 | (let [n (g/transform-vector nmat (gu/ortho-normal f)) 60 | lambert (max 0.0 (m/dot n light-dir)) 61 | diffuse (if (fn? diffuse) (diffuse f f' z) diffuse) 62 | ambient (if (fn? ambient) (ambient f f' z) ambient)] 63 | (-> (m/* diffuse light-col) 64 | (m/madd lambert (m/* ambient light-col))))))) 65 | 66 | (defn phong 67 | [{:keys [model view light-pos light-col 68 | diffuse specular ambient shininess]}] 69 | (let [light-col (vec3 light-col) 70 | light-pos (g/transform-vector view (vec3 light-pos)) 71 | diffuse (if (fn? diffuse) diffuse (vec3 diffuse)) 72 | ambient (if (fn? ambient) ambient (vec3 ambient)) 73 | specular (vec3 specular) 74 | mv (m/* view model) 75 | nmat (m/transpose (m/invert view))] 76 | (fn [f f' z] 77 | (let [eye-pos (g/transform-vector mv (gu/centroid f)) 78 | n (m/normalize (g/transform-vector nmat (gu/ortho-normal f))) 79 | l (m/normalize (m/- light-pos eye-pos)) 80 | e (m/normalize (m/- eye-pos)) 81 | lambert (max 0.0 (m/dot n l)) 82 | diffuse (if (fn? diffuse) (diffuse f f' z) diffuse) 83 | ambient (if (fn? ambient) (ambient f f' z) ambient) 84 | spec (max (Math/pow (m/dot (m/normalize (m/+ l e)) n) shininess) 0.0)] 85 | (-> (m/* diffuse light-col) 86 | (m/madd lambert (m/+ (m/* ambient light-col) (m/* specular spec))) 87 | (m/min [1.0 1.0 1.0])))))) 88 | #+END_SRC 89 | 90 | ** Complete namespace definition 91 | 92 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/svg/shaders.cljc :noweb yes :mkdirp yes :padline no 93 | (ns thi.ng.geom.svg.shaders 94 | (:require 95 | [thi.ng.math.core :as m] 96 | [thi.ng.geom.core :as g] 97 | [thi.ng.geom.utils :as gu] 98 | [thi.ng.geom.vector :refer [vec3 V3Z]] 99 | [thi.ng.geom.matrix :as mat :refer [M44]] 100 | [thi.ng.color.core :as col])) 101 | 102 | <> 103 | 104 | <> 105 | #+END_SRC 106 | -------------------------------------------------------------------------------- /org/src/types/meshface.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_4_gh: 6 | - [[#namespace-thinggeommeshface][Namespace: thi.ng.geom.meshface]] 7 | - [[#meshface][MeshFace]] 8 | - [[#indexedmeshface][IndexedMeshFace]] 9 | - [[#helpers][Helpers]] 10 | - [[#complete-namespace-definition][Complete namespace definition]] 11 | 12 | * Namespace: thi.ng.geom.meshface 13 | 14 | ** MeshFace 15 | 16 | #+BEGIN_SRC clojure :noweb-ref plain 17 | (deftype MeshFace 18 | [vertices 19 | #?@(:clj [^:unsynchronized-mutable _hash] 20 | :cljs [^:mutable _hash])] 21 | g/IVertexAccess 22 | (vertices [_ _] vertices) 23 | g/IAttributeAccess 24 | (attribs [_ _] nil) 25 | g/IRawAccess 26 | (raw [_ _] [vertices]) 27 | Object 28 | (toString [_] (str \[ vertices \])) 29 | #?@(:clj 30 | [(hashCode [_] (or _hash (set! _hash (.hashCode vertices)))) 31 | (equals 32 | [_ o] 33 | (and (instance? MeshFace o) 34 | (clojure.lang.Util/equals vertices (.-vertices ^MeshFace o)))) 35 | Comparable 36 | (compareTo [_ o] (compare vertices (.-vertices ^MeshFace o))) 37 | clojure.lang.IHashEq 38 | (hasheq [_] (.hashCode _))] 39 | :cljs 40 | [IHash 41 | (-hash [_] (or _hash (set! _hash (hash vertices)))) 42 | IComparable 43 | (-compare [_ o] (compare vertices (.-vertices ^MeshFace o)))])) 44 | #+END_SRC 45 | 46 | ** IndexedMeshFace 47 | 48 | #+BEGIN_SRC clojure :noweb-ref plain 49 | (deftype IndexedMeshFace 50 | [vertices attribs 51 | #?@(:clj [^:unsynchronized-mutable _hash] 52 | :cljs [^:mutable _hash])] 53 | g/IVertexAccess 54 | (vertices [_ mesh] 55 | (let [idx (-> mesh :vertices :id->v)] 56 | (mapv #(get idx %) vertices))) 57 | g/IAttributeAccess 58 | (attribs [_ mesh] 59 | (let [mattr (get mesh :attribs)] 60 | (reduce-kv 61 | (fn [acc k v] 62 | (let [idx (-> mattr (get k) (get :id->v))] 63 | (assoc acc k (if (sequential? v) (mapv #(get idx %) v) (get idx v))))) 64 | {} attribs))) 65 | (attribs [_ mesh attr] 66 | (let [idx (-> mesh (get :attribs) (get attr) (get :id->v)) 67 | aval (attribs attr)] 68 | (if (sequential? aval) (mapv idx attribs) (idx aval)))) 69 | g/IRawAccess 70 | (raw [_ mesh] 71 | [(g/vertices _ mesh) (g/attribs _ mesh)]) 72 | Object 73 | (toString [_] 74 | (str \[ vertices \space attribs \])) 75 | #?@(:clj 76 | [(hashCode 77 | [_] 78 | (or _hash 79 | (set! _hash 80 | (unchecked-add-int 81 | (unchecked-multiply-int (.hashCode vertices) 31) 82 | (.hashCode attribs))))) 83 | (equals 84 | [_ o] 85 | (and (instance? IndexedMeshFace o) 86 | (clojure.lang.Util/equals vertices (.-vertices ^IndexedMeshFace o)) 87 | (clojure.lang.Util/equals attribs (.-attribs ^IndexedMeshFace o)))) 88 | Comparable 89 | (compareTo 90 | [_ o] 91 | (let [c (compare vertices (.-vertices ^IndexedMeshFace o))] 92 | (if (zero? c) 93 | (compare attribs (.-attribs ^IndexedMeshFace o)) 94 | c))) 95 | clojure.lang.IHashEq 96 | (hasheq [_] (.hashCode _))] 97 | :cljs 98 | [IHash 99 | (-hash 100 | [_] 101 | (or _hash 102 | (set! _hash 103 | (-> (hash vertices) 104 | (imul 31) 105 | (+ (hash attribs)) 106 | (bit-or 0))))) 107 | IComparable 108 | (-compare 109 | [_ o] 110 | (let [c (compare vertices (.-vertices ^IndexedMeshFace o))] 111 | (if (zero? c) 112 | (compare attribs (.-attribs ^IndexedMeshFace o)) 113 | c)))]) 114 | ) 115 | #+END_SRC 116 | 117 | ** Helpers 118 | 119 | #+BEGIN_SRC clojure :noweb-ref helpers 120 | (defn xf-face-verts 121 | [mesh] (map #(first (g/raw % mesh)))) 122 | #+END_SRC 123 | 124 | ** Complete namespace definition 125 | 126 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/meshface.cljc :noweb yes :mkdirp yes :padline no 127 | (ns thi.ng.geom.meshface 128 | (:require 129 | [thi.ng.geom.core :as g] 130 | [thi.ng.geom.vector :as v :refer [vec2 vec3]])) 131 | 132 | <> 133 | 134 | <> 135 | 136 | <> 137 | #+END_SRC 138 | -------------------------------------------------------------------------------- /org/src/utils/delaunay.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_4_gh: 6 | - [[#thinggeomutilsdelaunay][thi.ng.geom.utils.delaunay]] 7 | - [[#implementation][Implementation]] 8 | - [[#complete-namespace-definition][Complete namespace definition]] 9 | 10 | * thi.ng.geom.utils.delaunay 11 | 12 | ** Implementation 13 | 14 | Algorithm fails if *all* points are arranged in a circle. A workaround 15 | is to add additional point(s) in the center. 16 | 17 | - http://astronomy.swin.edu.au/~pbourke/modelling/triangulate/ 18 | 19 | #+BEGIN_SRC clojure :noweb-ref delaunay 20 | (defn- add-unique-edge! 21 | [edges p q] 22 | (let [e [p q]] 23 | (if (edges e) 24 | (disj! edges e) 25 | (let [e2 [q p]] 26 | (if (edges e2) (disj! edges e2) (conj! edges e)))))) 27 | 28 | (defn- compute-edges 29 | [complete tris [px py]] 30 | (persistent! 31 | (reduce 32 | (fn [state t] 33 | (if (complete t) state 34 | (let [x (- px (t 3)) 35 | y (- py (t 4))] 36 | (if (<= (mm/madd x x y y) (t 5)) 37 | (assoc! state 38 | 0 (let [[a b c] t] 39 | (-> (state 0) 40 | (add-unique-edge! a b) 41 | (add-unique-edge! b c) 42 | (add-unique-edge! c a)))) 43 | (assoc! state 44 | 1 (conj! (state 1) t)))))) 45 | (transient [(transient #{}) (transient [])]) 46 | tris))) 47 | 48 | (defn- triangle-spec 49 | [a b c] 50 | (let [[[ox oy] r] (circumcircle-raw a b c)] 51 | [a b c ox oy (* r r) (+ ox r)])) 52 | 53 | (defn- shared-vertex? 54 | [a1 b1 c1 [a2 b2 c2]] 55 | (or (identical? a1 a2) (identical? a1 b2) (identical? a1 c2) 56 | (identical? b1 a2) (identical? b1 b2) (identical? b1 c2) 57 | (identical? c1 a2) (identical? c1 b2) (identical? c1 c2))) 58 | 59 | (defn triangulate 60 | [points] 61 | (let [points (sort-by #(% 0) points) 62 | bmin (reduce m/min points) 63 | bmax (reduce m/max points) 64 | bext (m/- bmax bmin) 65 | dm (max (bext 0) (bext 1)) 66 | d2 (* 2.0 dm) 67 | m (m/mix bmin bmax) 68 | [sa sb sc :as s] (triangle-spec (m/- m d2 dm) (m/+ m 0 d2) (m/+ m d2 (- dm)))] 69 | (loop [points points, tris [s], complete (transient #{})] 70 | (if-let [[px :as p] (first points)] 71 | (let [complete (reduce #(if (< (%2 6) px) (conj! % %2) %) complete tris) 72 | [edges tris] (compute-edges complete tris p) 73 | tris (reduce #(conj! % (triangle-spec (%2 0) (%2 1) p)) tris (persistent! edges))] 74 | (recur (rest points) (persistent! tris) complete)) 75 | (->> tris 76 | (reduce conj! complete) 77 | (persistent!) 78 | (remove #(shared-vertex? sa sb sc %)) 79 | (map (fn [t] [(t 1) (t 0) (t 2)]))))))) 80 | #+END_SRC 81 | 82 | ** Complete namespace definition 83 | 84 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/utils/delaunay.cljc :noweb yes :mkdirp yes :padline no 85 | (ns thi.ng.geom.utils.delaunay 86 | #?(:cljs (:require-macros [thi.ng.math.macros :as mm])) 87 | (:require 88 | [thi.ng.geom.core :as g] 89 | [thi.ng.geom.triangle :refer [circumcircle-raw triangle2]] 90 | [thi.ng.math.core :as m :refer [*eps* delta=]] 91 | #?(:clj [thi.ng.math.macros :as mm])) 92 | #?(:clj 93 | (:import 94 | [thi.ng.geom.types Triangle2]))) 95 | 96 | <> 97 | #+END_SRC 98 | -------------------------------------------------------------------------------- /org/src/utils/subdiv.org: -------------------------------------------------------------------------------- 1 | #+SETUPFILE: ../../meta/setup.org 2 | 3 | *This file is archived and only kept for reference - DO NOT edit* 4 | 5 | * Contents :toc_3_gh: 6 | - [[#namespace-thinggeomutilssubdiv][Namespace: thi.ng.geom.utils.subdiv]] 7 | - [[#iterative-curve-subdivision][Iterative curve subdivision]] 8 | - [[#example--comparison][Example & comparison]] 9 | - [[#implementation][Implementation]] 10 | - [[#complete-namespace-definition][Complete namespace definition]] 11 | 12 | * Namespace: thi.ng.geom.utils.subdiv 13 | ** Iterative curve subdivision 14 | 15 | http://algorithmicbotany.org/papers/subgpu.sig2003.pdf 16 | 17 | *** Example & comparison 18 | 19 | [[../../../assets/subdiv/sd-compare.svg]] 20 | 21 | #+BEGIN_SRC clojure 22 | (require '[thi.ng.geom.core :as g]) 23 | (require '[thi.ng.geom.vector :refer [vec2]]) 24 | (require '[thi.ng.geom.utils.subdiv :as sd]) 25 | (require '[thi.ng.geom.svg.core :as svg]) 26 | (require '[thi.ng.math.core :as m]) 27 | (require '[thi.ng.dstruct.core :as d]) 28 | 29 | (defn demo 30 | [points [id col]] 31 | (->> (range 1 6) 32 | (map 33 | #(let [p (->> points 34 | (mapv #(m/+ % (* (dec %) 120) 0)) 35 | (d/iterate-n % (partial sd/subdivide-closed (id sd/schemes))))] 36 | (svg/group 37 | {:stroke col} 38 | (svg/polygon p) 39 | (map #(svg/circle % 1.5) p)))))) 40 | 41 | (def points 42 | (->> [[10 10] [60 60] [110 10] [110 60] [85 80] [110 100] [110 150] [60 100] [10 150] [10 100] [35 80] [10 60]] 43 | (mapv vec2))) 44 | 45 | (->> [[:chaikin "red"] [:cubic-bezier "blue"]] 46 | (map #(demo points %)) 47 | (apply svg/svg 48 | {:width 600 :height 200 :fill "none" :font-family "Arial" :font-size 12} 49 | (svg/text [300 170] ":chaikin" {:fill "red"}) 50 | (svg/text [300 186] ":cubic-bezier" {:fill "blue"})) 51 | (svg/serialize) 52 | (spit "sd-compare.svg")) 53 | #+END_SRC 54 | 55 | *** Implementation 56 | 57 | #+BEGIN_SRC clojure :noweb-ref subdiv 58 | (defn subdiv-kernel3 59 | [u v [a b c]] 60 | [(->> (m/* c (u 2)) (m/madd b (u 1)) (m/madd a (u 0))) 61 | (->> (m/* c (v 2)) (m/madd b (v 1)) (m/madd a (v 0)))]) 62 | 63 | (defn subdiv-kernel5 64 | [u v [a b c d e]] 65 | [(->> (m/* e (u 4)) (m/madd d (u 3)) (m/madd c (u 2)) (m/madd b (u 1)) (m/madd a (u 0))) 66 | (->> (m/* e (v 4)) (m/madd d (v 3)) (m/madd c (v 2)) (m/madd b (v 1)) (m/madd a (v 0)))]) 67 | 68 | (defn subdivide-closed 69 | ([scheme points] 70 | (subdivide-closed (get scheme :fn) (get scheme :coeff) points)) 71 | ([f [u v] points] 72 | (let [n (count u) 73 | n2 (int (/ n 2))] 74 | (->> (concat (take-last n2 points) points (take n2 points)) 75 | (partition n 1) 76 | (mapcat #(f u v %)))))) 77 | 78 | (def schemes 79 | {:chaikin {:fn subdiv-kernel3 :coeff [[0.25 0.75 0] [0 0.75 0.25]]} 80 | :cubic-bezier {:fn subdiv-kernel3 :coeff [[0.125 0.75 0.125] [0 0.5 0.5]]}}) 81 | #+END_SRC 82 | 83 | 84 | ** Complete namespace definition 85 | 86 | #+BEGIN_SRC clojure :tangle ../../babel/src/thi/ng/geom/utils/subdiv.cljc :noweb yes :mkdirp yes :padline no 87 | (ns thi.ng.geom.utils.subdiv 88 | #?(:cljs 89 | (:require-macros 90 | [thi.ng.math.macros :as mm])) 91 | (:require 92 | [thi.ng.math.core :as m] 93 | [thi.ng.geom.core :as g] 94 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 95 | #?(:clj [thi.ng.math.macros :as mm]))) 96 | 97 | <> 98 | #+END_SRC 99 | -------------------------------------------------------------------------------- /out/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/geom/95022785e23ee0d40294edfb4ef44e66b7cc1208/out/.empty -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject thi.ng/geom "1.0.1" 2 | :description "thi.ng geometry kit - meta project spec including all modules" 3 | :url "https://github.com/thi-ng/geom" 4 | :license {:name "Apache Software License" 5 | :url "http://www.apache.org/licenses/LICENSE-2.0" 6 | :distribution :repo} 7 | :scm {:name "git" 8 | :url "https://github.com/thi-ng/geom"} 9 | 10 | :min-lein-version "2.4.0" 11 | 12 | :dependencies [[org.clojure/clojure "1.11.1"] 13 | [org.clojure/clojurescript "1.11.121"] 14 | [thi.ng/color "1.5.1"] 15 | [thi.ng/dstruct "0.2.2"] 16 | [thi.ng/math "0.3.2"] 17 | [thi.ng/ndarray "0.3.3"] 18 | [thi.ng/shadergraph "0.3.1"] 19 | [thi.ng/strf "0.2.4"] 20 | [thi.ng/typedarrays "0.1.7"] 21 | [thi.ng/xerror "0.1.0"] 22 | [org.jogamp.gluegen/gluegen-rt "2.3.2"] 23 | [org.jogamp.jogl/jogl-all "2.3.2"] 24 | [cljs-log "0.2.2"] 25 | [hiccup "1.0.5"]] 26 | 27 | :perforate {:environments [{:namespaces [thi.ng.geom.bench.core.vector]}]} 28 | 29 | :profiles {:dev {:dependencies [[criterium "0.4.4"] 30 | [org.jogamp.gluegen/gluegen-rt "2.3.2" :classifier "natives-macosx-universal"] 31 | [org.jogamp.jogl/jogl-all "2.3.2" :classifier "natives-macosx-universal"] 32 | [org.jogamp.gluegen/gluegen-rt "2.3.2" :classifier "natives-windows-amd64"] 33 | [org.jogamp.jogl/jogl-all "2.3.2" :classifier "natives-windows-amd64"] 34 | [org.jogamp.gluegen/gluegen-rt "2.3.2" :classifier "natives-linux-amd64"] 35 | [org.jogamp.jogl/jogl-all "2.3.2" :classifier "natives-linux-amd64"] 36 | [com.postspectacular/piksel "0.1.4"]] 37 | :plugins [[lein-cljsbuild "1.1.7"] 38 | [com.cemerick/clojurescript.test "0.3.3"]] 39 | :node-dependencies [[benchmark "1.0.0"]] 40 | :global-vars {*warn-on-reflection* true} 41 | :jvm-opts ^:replace ["-Dclojure.compiler.direct-linking=false"] 42 | :aliases {"bench" ["with-profile" "bench" "do" "clean," "perforate," "cljsbuild" "test"]}} 43 | :bench {:dependencies [[perforate-x "0.1.0"]] 44 | :plugins [[perforate "0.3.4"] 45 | [lein-npm "0.6.2"]] 46 | :cljsbuild 47 | {:builds 48 | [{:id "bench" 49 | :source-paths ["src" "test" "benchmarks"] 50 | :notify-command ["node" "target/cljs/benchmark.js"] 51 | :compiler {:target :nodejs 52 | :output-to "target/cljs/benchmark.js" 53 | :optimizations :simple 54 | :pretty-print true}}] 55 | :test-commands {"unit-tests" ["phantomjs" :runner "target/geom.js"]}}}} 56 | 57 | :cljsbuild {:builds [{:id "simple" 58 | :source-paths ["src" "test" "examples/gl"] 59 | :compiler {:output-to "target/geom.js" 60 | :optimizations :whitespace 61 | :pretty-print true}} 62 | {:source-paths ["src" "examples/gl"] 63 | :id "prod" 64 | :compiler {:output-to "target/geom.js" 65 | :optimizations :advanced 66 | :pretty-print false}}] 67 | :test-commands {"unit-tests" ["phantomjs" :runner "target/geom.js"]}} 68 | 69 | :pom-addition [:developers 70 | [:developer 71 | [:name "Karsten Schmidt"] 72 | [:url "https://thi.ng"] 73 | [:timezone "1"]]]) 74 | -------------------------------------------------------------------------------- /src/data_readers.cljc: -------------------------------------------------------------------------------- 1 | {thi.ng/vec2 thi.ng.geom.vector/vec2 2 | thi.ng/vec3 thi.ng.geom.vector/vec3 3 | thi.ng.geom.types.AABB thi.ng.geom.types/map->AABB 4 | thi.ng.geom.types.BasicMesh thi.ng.geom.types/map->BasicMesh 5 | thi.ng.geom.types.Bezier2 thi.ng.geom.types/map->Bezier2 6 | thi.ng.geom.types.Bezier3 thi.ng.geom.types/map->Bezier3 7 | thi.ng.geom.types.Circle2 thi.ng.geom.types/map->Circle2 8 | thi.ng.geom.types.Cuboid thi.ng.geom.types/map->Cuboid 9 | thi.ng.geom.types.Ellipse2 thi.ng.geom.types/map->Ellipse2 10 | thi.ng.geom.types.GMesh thi.ng.geom.types/map->GMesh 11 | thi.ng.geom.types.Graph thi.ng.geom.types/map->Graph 12 | thi.ng.geom.types.IndexedMesh thi.ng.geom.types/map->IndexedMesh 13 | thi.ng.geom.types.Line2 thi.ng.geom.types/map->Line2 14 | thi.ng.geom.types.Line3 thi.ng.geom.types/map->Line3 15 | thi.ng.geom.types.LineStrip2 thi.ng.geom.types/map->LineStrip2 16 | thi.ng.geom.types.LineStrip3 thi.ng.geom.types/map->LineStrip3 17 | thi.ng.geom.types.Mesh2 thi.ng.geom.types/map->Mesh2 18 | thi.ng.geom.types.Path2 thi.ng.geom.types/map->Path2 19 | thi.ng.geom.types.Plane thi.ng.geom.types/map->Plane 20 | thi.ng.geom.types.Polygon2 thi.ng.geom.types/map->Polygon2 21 | thi.ng.geom.types.Quad3 thi.ng.geom.types/map->Quad3 22 | thi.ng.geom.types.Rect2 thi.ng.geom.types/map->Rect2 23 | thi.ng.geom.types.Sphere thi.ng.geom.types/map->Sphere 24 | thi.ng.geom.types.Tetrahedron thi.ng.geom.types/map->Tetrahedron 25 | thi.ng.geom.types.Triangle2 thi.ng.geom.types/map->Triangle2 26 | thi.ng.geom.types.Triangle3 thi.ng.geom.types/map->Triangle3} 27 | -------------------------------------------------------------------------------- /src/thi/ng/geom/basicmesh.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.basicmesh 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.utils :as gu] 5 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 6 | [thi.ng.geom.matrix :refer [M44]] 7 | [thi.ng.geom.meshface :as mf] 8 | #?(:clj [thi.ng.geom.types] :cljs [thi.ng.geom.types :refer [BasicMesh]]) 9 | [thi.ng.dstruct.core :as d] 10 | [thi.ng.math.core :as m :refer [*eps*]] 11 | [thi.ng.xerror.core :as err] 12 | [clojure.core.reducers :as r]) 13 | #?(:clj (:import [thi.ng.geom.types BasicMesh]))) 14 | 15 | (declare basic-mesh) 16 | 17 | (defn- add-face* 18 | [mesh [fverts]] 19 | (BasicMesh. 20 | (into (get mesh :vertices) fverts) 21 | (conj (get mesh :faces) (thi.ng.geom.meshface.MeshFace. fverts nil)) 22 | (get mesh :fnormals))) 23 | 24 | (defn basic-mesh 25 | "Builds a new 3d mesh data structure and (optionally) populates it with 26 | the given items (a seq of existing meshes and/or faces). Faces are defined 27 | as vectors of their vertices." 28 | [] (BasicMesh. #{} #{} {})) 29 | 30 | (extend-type BasicMesh 31 | 32 | g/IArea 33 | (area 34 | [_] (gu/total-area-3d (mf/xf-face-verts _) (get _ :faces))) 35 | 36 | g/IBounds 37 | (bounds [_] (gu/bounding-box (seq (get _ :vertices)))) 38 | (width [_] (gu/axis-range 0 (get _ :vertices))) 39 | (height [_] (gu/axis-range 1 (get _ :vertices))) 40 | (depth [_] (gu/axis-range 2 (get _ :vertices))) 41 | 42 | g/IBoundingSphere 43 | (bounding-sphere 44 | [_] (gu/bounding-sphere (g/centroid _) (get _ :vertices))) 45 | 46 | g/ICenter 47 | (center 48 | ([_] (g/center _ (vec3))) 49 | ([_ o] (g/translate _ (m/- o (g/centroid _))))) 50 | (centroid 51 | [_] (gu/centroid (seq (get _ :vertices)))) 52 | 53 | g/IFlip 54 | (flip [_] (gu/map-mesh (fn [f] [(vec (rseq f))]) _)) 55 | 56 | g/IVertexAccess 57 | (vertices 58 | [_] (get _ :vertices)) 59 | 60 | g/IEdgeAccess 61 | (edges 62 | [_] 63 | (into 64 | #{} 65 | (comp 66 | (map #(g/vertices % _)) 67 | (mapcat #(d/successive-nth 2 (conj % (first %)))) 68 | (map set)) 69 | (get _ :faces))) 70 | 71 | g/IFaceAccess 72 | (faces 73 | ([_] (get _ :faces)) 74 | ([_ opts] 75 | (if opts 76 | (map #(g/raw % _) (get _ :faces)) 77 | (get _ :faces)))) 78 | (add-face 79 | [_ face] (add-face* _ face)) 80 | (vertex-faces 81 | [_ v] 82 | (sequence 83 | (comp 84 | (map #(g/vertices % _)) 85 | (filter 86 | #(pos? #?(:clj (.indexOf ^clojure.lang.PersistentVector % v) 87 | :cljs (d/index-of % v)))) 88 | (get _ :faces)))) 89 | (remove-face 90 | [_ f] 91 | (err/unsupported!)) ;; TODO implement 92 | 93 | g/INormalAccess 94 | (face-normals 95 | [_ force?] (if (seq (get _ :fnormals)) (get _ :fnormals) (if force? (get (g/compute-face-normals _) :fnormals)))) 96 | (face-normal 97 | [_ f] (get (get _ :fnormals) f)) 98 | (vertex-normals 99 | [_ force?] (if force? (err/unsupported!))) 100 | (vertex-normal 101 | [_ v] (err/unsupported!)) 102 | (compute-face-normals 103 | [_] 104 | (loop [fnorms (transient {}), faces (get _ :faces)] 105 | (if faces 106 | (let [f (first faces)] 107 | (recur (assoc! fnorms f (gu/ortho-normal (g/vertices f _))) (next faces))) 108 | (assoc _ :fnormals (persistent! fnorms))))) 109 | (compute-vertex-normals 110 | [_] (err/unsupported!)) 111 | 112 | g/IGeomContainer 113 | (into 114 | [_ faces] (gu/into-mesh _ add-face* faces)) 115 | 116 | g/IClear 117 | (clear* 118 | [_] (basic-mesh)) 119 | 120 | g/IMeshConvert 121 | (as-mesh 122 | ([_] _) 123 | ([_ opts] (g/into (get opts :mesh) (get _ :faces)))) 124 | 125 | g/ITessellate 126 | (tessellate 127 | ([_] (g/tessellate _ {})) 128 | ([_ opts] (gu/map-mesh (or (get opts :fn) (gu/tessellate-face gu/tessellate-with-first)) _))) 129 | 130 | g/IScale 131 | (scale 132 | [_ s] (gu/transform-mesh _ add-face* #(m/* % s))) 133 | (scale-size 134 | [_ s] 135 | (let [c (g/centroid _)] 136 | (gu/transform-mesh _ add-face* #(m/madd (m/- % c) s c)))) 137 | 138 | g/ITranslate 139 | (translate 140 | [_ t] (gu/transform-mesh _ add-face* #(m/+ % t))) 141 | 142 | g/ITransform 143 | (transform 144 | [_ m] 145 | (gu/transform-mesh _ add-face* m)) 146 | 147 | g/IVolume 148 | (volume 149 | [_] (gu/total-volume (mf/xf-face-verts _) (get _ :faces)))) 150 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/arcball.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.arcball 2 | #?(:cljs 3 | (:require-macros 4 | [thi.ng.math.macros :as mm])) 5 | (:require 6 | [thi.ng.math.core :as m] 7 | [thi.ng.geom.core :as g] 8 | [thi.ng.geom.vector :as v :refer [vec2 vec3 V3Y]] 9 | [thi.ng.geom.matrix :as mat] 10 | [thi.ng.geom.quaternion :as q] 11 | #?(:clj [thi.ng.math.macros :as mm]))) 12 | 13 | (declare update-view) 14 | 15 | ;; Based on "ARCBALL: A User Interface for Specifying 16 | ;; Three-Dimensional Orientation Using a Mouse" by Ken Shoemake 17 | ;; 18 | ;; http://www.talisman.org/~erlkonig/misc/shoemake92-arcball.pdf 19 | 20 | (defn arcball 21 | [{:keys [init dist min-dist max-dist radius center] :as ab}] 22 | (let [dist (or dist 2.0) 23 | min-dist (or min-dist (/ dist 2.0)) 24 | max-dist (or max-dist (* dist 2.0)) 25 | curr-rot (if init (q/quat init) (q/quat-from-axis-angle V3Y m/PI))] 26 | (-> ab 27 | (merge 28 | {:dist dist 29 | :min-dist min-dist 30 | :max-dist max-dist 31 | :radius (or radius 300.0) 32 | :center (or center (vec2 640 360)) 33 | :curr-rot curr-rot 34 | :click-rot curr-rot}) 35 | update-view))) 36 | 37 | ;; Helpers 38 | 39 | (defn- sphere-position 40 | [{:keys [center radius]} x y] 41 | (let [v (vec3 (mm/subdiv x (v/x center) radius) (mm/subdiv y (v/y center) radius) 0) 42 | m (m/mag-squared v)] 43 | (if (> m 1.0) 44 | (m/normalize v) 45 | (assoc v :z (Math/sqrt (- 1.0 m)))))) 46 | 47 | ;; Event handlers & arcball operations 48 | 49 | (defn down 50 | [ab x y] 51 | (-> ab 52 | (assoc :click-pos (sphere-position ab x y) 53 | :click-rot (:curr-rot ab)) 54 | update-view)) 55 | 56 | (defn drag 57 | [{:keys [click-pos] :as ab} x y] 58 | (when click-pos 59 | (let [drag-pos (sphere-position ab x y) 60 | axis (m/cross click-pos drag-pos) 61 | theta (m/dot click-pos drag-pos) 62 | drag-rot (q/quat axis theta)] 63 | (-> ab 64 | (assoc :curr-rot (m/* drag-rot (:click-rot ab))) 65 | update-view)))) 66 | 67 | (defn up 68 | [ab] (assoc ab :click-pos nil)) 69 | 70 | (defn resize 71 | [ab w h] 72 | (let [ww (/ w 2) 73 | wh (/ h 2)] 74 | (assoc ab 75 | :radius (* (min ww wh) 2) 76 | :center (vec2 ww wh)))) 77 | 78 | (defn zoom-delta 79 | [{:keys [min-dist max-dist] :as ab} delta] 80 | (-> ab 81 | (assoc :dist 82 | (m/clamp 83 | (mm/madd delta (mm/subm max-dist min-dist 1e-3) (get ab :dist)) 84 | min-dist max-dist)) 85 | update-view)) 86 | 87 | (defn zoom-abs 88 | [ab x] (-> ab (assoc :dist (m/clamp x (:min-dist ab) (:max-dist ab))) update-view)) 89 | 90 | (defn update-view 91 | [{:keys [curr-rot] :as ab}] 92 | (let [q (q/quat (:xyz curr-rot) (- (:w curr-rot))) 93 | offset (g/transform-vector q (vec3 0 0 (get ab :dist))) 94 | up (g/transform-vector q V3Y) 95 | eye (m/- offset)] 96 | (assoc ab :view (mat/look-at eye (vec3) up)))) 97 | 98 | (defn get-view 99 | [ab] (or (get ab :view) (get (update-view ab) :view))) 100 | 101 | (defn get-rotation 102 | [ab] (get ab :curr-rot)) 103 | 104 | (defn set-rotation 105 | [ab q] (-> ab (assoc :curr-rot q) update-view)) 106 | 107 | (defn set-zoom-range 108 | [ab min max] (assoc ab :min-dist min :max-dist max :dist (m/clamp (get ab :dist) min max))) 109 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/camera.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.camera 2 | (:refer-clojure :exclude [apply]) 3 | (:require 4 | [thi.ng.math.core :as m] 5 | [thi.ng.geom.vector :as v :refer [vec3]] 6 | [thi.ng.geom.matrix :as mat])) 7 | 8 | ;; Perspective camera 9 | ;; 10 | ;; | *Key* | *Type* | *Default* | *Description* | 11 | ;; |-----------+---------------+----------------+-----------------------------------------| 12 | ;; | `:eye` | vec3 | `nil` | Camera position | 13 | ;; | `:target` | vec3 | `(vec3 0)` | Camera target (center of view) | 14 | ;; | `:up` | vec3 | `(vec3 0 1 0)` | Camera up axis | 15 | ;; | `:fov` | float | 45 | Vertical FOV in degrees | 16 | ;; | `:aspect` | float or rect | 16:9 | Camera aspect ratio (or view rectangle) | 17 | ;; | `:near` | float | 0.1 | Camera near clipping distance | 18 | ;; | `:far` | float | 100 | Camera far clipping distance | 19 | 20 | (defn apply 21 | "Takes a GL model spec map & camera, injects :view & :proj 22 | uniforms into spec." 23 | [spec cam] 24 | (update spec :uniforms merge {:view (get cam :view) :proj (get cam :proj)})) 25 | 26 | (defn update-keys 27 | "Takes a map m, key seq and map of new vals, replaces keys in m with 28 | new vals. If a value in opts map is a function, applies fn to value 29 | of key in original map." 30 | [m ks opts] 31 | (reduce-kv 32 | (fn [acc k v] (assoc acc k (if (fn? v) (v (m k)) v))) 33 | m (select-keys opts ks))) 34 | 35 | (defn set-view 36 | [cam opts] 37 | (let [cam (update-keys cam [:eye :target :up] opts)] 38 | (assoc cam :view (mat/look-at (get cam :eye) (get cam :target) (get cam :up))))) 39 | 40 | (defn set-projection 41 | [cam opts] 42 | (let [cam (update-keys cam [:fov :aspect :near :far] opts)] 43 | (assoc cam :proj (mat/perspective (get cam :fov) (get cam :aspect) (get cam :near) (get cam :far))))) 44 | 45 | (defn perspective-camera 46 | [opts] 47 | (-> (merge 48 | {:eye (vec3 0.0 0.0 2.0) 49 | :target v/V3 50 | :up v/V3Y 51 | :fov 45 52 | :near 0.1 53 | :far 100 54 | :aspect (/ 16.0 9.0)} 55 | opts) 56 | (set-view opts) 57 | (set-projection opts))) 58 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/fx/bloom.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.fx.bloom 2 | (:require 3 | [thi.ng.dstruct.core :as d] 4 | [thi.ng.geom.rect :as r] 5 | [thi.ng.geom.gl.fx :as fx] 6 | [thi.ng.glsl.core :as glsl :include-macros true] 7 | [thi.ng.glsl.color :as col] 8 | [thi.ng.glsl.texture :as tex])) 9 | 10 | ;; Bloom filter FX pipeline preset 11 | 12 | ;; Threshold pass 13 | 14 | (def threshold-shader-spec 15 | (d/merge-deep 16 | fx/shader-spec 17 | {:fs (->> " 18 | #if __VERSION__ >= 300 19 | out vec4 fragColor; 20 | void main() { 21 | float c = threshold(texture(tex, vUV).rgb, thresh * 0.5, thresh); 22 | fragColor = vec4(c, c, c, 1.0); 23 | } 24 | #else 25 | void main() { 26 | float c = threshold(texture2D(tex, vUV).rgb, thresh * 0.5, thresh); 27 | gl_FragColor = vec4(c, c, c, 1.0); 28 | } 29 | #endif" 30 | (glsl/glsl-spec-plain [col/threshold]) 31 | (glsl/assemble)) 32 | :uniforms {:thresh [:float 0.8]}})) 33 | 34 | ;; Blur pass 35 | 36 | (def blur-shader-spec 37 | (d/merge-deep 38 | fx/shader-spec 39 | {:fs (->> " 40 | #if __VERSION__ >= 300 41 | out vec4 fragColor; 42 | void main() { 43 | fragColor = vec4((horizontal ? blur5H(tex, vUV) : blur5V(tex, vUV)), 1.0); 44 | } 45 | #else 46 | void main() { 47 | gl_FragColor = vec4((horizontal ? blur5H(tex, vUV) : blur5V(tex, vUV)), 1.0); 48 | } 49 | #endif" 50 | (glsl/glsl-spec-plain [tex/blur5-h tex/blur5-v]) 51 | (glsl/assemble)) 52 | :uniforms {:horizontal :bool}})) 53 | 54 | ;; Composite pass 55 | 56 | (def comp-shader-spec 57 | (d/merge-deep 58 | fx/shader-spec 59 | {:fs " 60 | #if __VERSION__ >= 300 61 | out vec4 fragColor; 62 | void main() { 63 | fragColor = pow(vec4((texture(tex, vUV).rgb * (1.0 - blend) + texture(tex2, vUV).rgb * blend) * exposure, 1.0), vec4(gamma)); 64 | } 65 | #else 66 | void main() { 67 | gl_FragColor = pow(vec4((texture2D(tex, vUV).rgb * (1.0 - blend) + texture2D(tex2, vUV).rgb * blend) * exposure, 1.0), vec4(gamma)); 68 | } 69 | #endif" 70 | :uniforms {:tex2 [:sampler2D 1] 71 | :blend [:float 0.35] 72 | :exposure [:float 1.3] 73 | :gamma [:float 1.25]}})) 74 | 75 | ;; Constructor / factory 76 | 77 | (defn make-pipeline-spec 78 | [w h scale version] 79 | {:width w 80 | :height h 81 | :version version 82 | :fbos {:src {:scale 1} 83 | :ping {:scale scale} 84 | :pong {:scale scale}} 85 | :shaders {:threshold threshold-shader-spec 86 | :blur blur-shader-spec 87 | :final comp-shader-spec} 88 | :passes [{:id :threshold 89 | :target :ping 90 | :shader :threshold 91 | :tex :src} 92 | {:id :blur-h 93 | :target :pong 94 | :shader :blur 95 | :tex :ping 96 | :uniforms {:horizontal true}} 97 | {:id :blur-v 98 | :target :ping 99 | :shader :blur 100 | :tex :pong 101 | :uniforms {:horizontal false}} 102 | {:id :final 103 | :shader :final 104 | :tex [:src :ping] 105 | :viewport (r/rect w h)}]}) 106 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/jogl/buffers.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.jogl.buffers 2 | (:import 3 | [com.jogamp.opengl.util GLBuffers] 4 | [java.nio Buffer DoubleBuffer FloatBuffer ShortBuffer IntBuffer])) 5 | 6 | ;; Native buffer wrappers for Clojure / JOGL 7 | ;; TODO refactor to avoid 2x copy via array, fill directly 8 | 9 | (defn ^FloatBuffer float-buffer 10 | [n-or-coll] 11 | (if (number? n-or-coll) 12 | (FloatBuffer/allocate (int n-or-coll)) 13 | (-> n-or-coll float-array FloatBuffer/wrap))) 14 | 15 | (defn ^FloatBuffer float-buffer-direct 16 | [n-or-coll] 17 | (if (number? n-or-coll) 18 | (GLBuffers/newDirectFloatBuffer (int n-or-coll)) 19 | (-> n-or-coll float-array GLBuffers/newDirectFloatBuffer))) 20 | 21 | (defn ^DoubleBuffer double-buffer 22 | [n-or-coll] 23 | (if (number? n-or-coll) 24 | (DoubleBuffer/allocate (int n-or-coll)) 25 | (-> n-or-coll double-array DoubleBuffer/wrap))) 26 | 27 | (defn ^DoubleBuffer double-buffer-direct 28 | [n-or-coll] 29 | (if (number? n-or-coll) 30 | (GLBuffers/newDirectDoubleBuffer (int n-or-coll)) 31 | (-> n-or-coll double-array GLBuffers/newDirectDoubleBuffer))) 32 | 33 | (defn ^ShortBuffer short-buffer 34 | [n-or-coll] 35 | (if (number? n-or-coll) 36 | (ShortBuffer/allocate (int n-or-coll)) 37 | (-> n-or-coll short-array ShortBuffer/wrap))) 38 | 39 | (defn ^ShortBuffer short-buffer-direct 40 | [n-or-coll] 41 | (if (number? n-or-coll) 42 | (GLBuffers/newDirectShortBuffer (int n-or-coll)) 43 | (-> n-or-coll short-array GLBuffers/newDirectShortBuffer))) 44 | 45 | (defn ^IntBuffer int-buffer 46 | [n-or-coll] 47 | (if (number? n-or-coll) 48 | (IntBuffer/allocate (int n-or-coll)) 49 | (-> n-or-coll int-array IntBuffer/wrap))) 50 | 51 | (defn ^IntBuffer int-buffer-direct 52 | [n-or-coll] 53 | (if (number? n-or-coll) 54 | (GLBuffers/newDirectIntBuffer (int n-or-coll)) 55 | (-> n-or-coll int-array GLBuffers/newDirectIntBuffer))) 56 | 57 | (defn copy-float-buffer 58 | [^FloatBuffer dest ^FloatBuffer src did sid len] 59 | (.position dest (int did)) 60 | (loop [len len, did did, sid sid] 61 | (when (pos? len) 62 | (.put dest (.get src (int sid))) 63 | (recur (dec len) (unchecked-inc did) (unchecked-inc sid))))) 64 | 65 | (defn copy-float-buffer-vec2 66 | [^FloatBuffer dest ^FloatBuffer src did sid] 67 | (doto dest 68 | (.position (int did)) 69 | (.put (.get src (int sid))) 70 | (.put (.get src (unchecked-add-int sid 1))))) 71 | 72 | (defn copy-float-buffer-vec3 73 | [^FloatBuffer dest ^FloatBuffer src did sid] 74 | (doto dest 75 | (.position (int did)) 76 | (.put (.get src (int sid))) 77 | (.put (.get src (unchecked-add-int sid 1))) 78 | (.put (.get src (unchecked-add-int sid 2))))) 79 | 80 | (defn copy-float-buffer-vec4 81 | [^FloatBuffer dest ^FloatBuffer src did sid] 82 | (doto dest 83 | (.position (int did)) 84 | (.put (.get src (int sid))) 85 | (.put (.get src (unchecked-add-int sid 1))) 86 | (.put (.get src (unchecked-add-int sid 2))) 87 | (.put (.get src (unchecked-add-int sid 3))))) 88 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/shaders/basic.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.shaders.basic 2 | (:require 3 | [thi.ng.geom.matrix :refer [M44]])) 4 | 5 | (defn make-shader-spec 6 | ([] 7 | (make-shader-spec nil)) 8 | ([{attr? :color-attrib? is3d? :3d :or {is3d? true}}] 9 | (let [spec {:vs (str "void main(){" 10 | (if attr? "vCol=color;") 11 | "gl_Position=proj*" 12 | (if is3d? 13 | "view*model*vec4(position,1.0)" 14 | "view*model*vec4(position,0.0,1.0)") 15 | ";}") 16 | :fs #?(:clj 17 | (str "out vec4 fragColor;void main(){fragColor=" 18 | (if attr? "vCol" "color") 19 | ";}") 20 | :cljs 21 | (str "void main(){gl_FragColor=" 22 | (if attr? "vCol" "color") 23 | ";}")) 24 | :uniforms {:proj :mat4 25 | :model [:mat4 M44] 26 | :view [:mat4 M44]} 27 | :attribs {:position (if is3d? :vec3 :vec2)}} 28 | spec (if attr? 29 | (-> spec 30 | (assoc-in [:attribs :color] :vec4) 31 | (assoc :varying {:vCol :vec4})) 32 | (assoc-in spec [:uniforms :color] :vec4))] 33 | spec))) 34 | 35 | (defn make-shader-spec-2d 36 | [color-attrib?] (make-shader-spec {:color-attrib? color-attrib? :3d false})) 37 | 38 | (defn make-shader-spec-3d 39 | [color-attrib?] (make-shader-spec {:color-attrib? color-attrib? :3d true})) 40 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/shaders/image.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.shaders.image 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.vector :refer [vec2 vec3]] 5 | [thi.ng.geom.matrix :refer [M44]] 6 | [thi.ng.geom.rect :as r] 7 | [thi.ng.geom.gl.core :as gl] 8 | [thi.ng.geom.gl.shaders :as sh] 9 | [thi.ng.dstruct.core :as d] 10 | [thi.ng.dstruct.streams :as streams] 11 | [thi.ng.math.core :as m] 12 | [thi.ng.glsl.core :as glsl :include-macros true] 13 | #?@(:clj 14 | [[thi.ng.geom.gl.jogl.constants :as glc] 15 | [thi.ng.geom.gl.jogl.buffers :as native]] 16 | :cljs 17 | [[thi.ng.geom.gl.webgl.constants :as glc] 18 | [thi.ng.typedarrays.core :as ta]]))) 19 | 20 | (def shader-spec 21 | {:vs "void main(){vUV=uv;gl_Position=proj*model*vec4(position,0.0,1.0);}" 22 | :fs #?(:clj "out vec4 fragColor;void main(){fragColor=texture(tex,vUV)*tint;}" 23 | :cljs "void main(){gl_FragColor=texture2D(tex,vUV)*tint;}") 24 | :uniforms {:proj :mat4 25 | :model [:mat4 M44] 26 | :tex [:sampler2D 0] 27 | :tint [:vec4 [1 1 1 1]]} 28 | :attribs {:position :vec2 29 | :uv :vec2} 30 | :varying {:vUV :vec2} 31 | :state {:depth-test false 32 | :blend true 33 | :blend-func [glc/src-alpha glc/one-minus-src-alpha]}}) 34 | 35 | (defn make-shader-spec 36 | ([gl] 37 | (make-shader-spec gl nil)) 38 | ([gl opts] 39 | (let [r (or (get opts :rect) (r/rect 1)) 40 | [a b c d] (g/vertices r) 41 | verts (#?(:clj native/float-buffer :cljs ta/float32) 8)] 42 | (streams/into-float-buffer [d c a b] verts 2 0) 43 | {:attribs (gl/make-attribute-buffers 44 | gl glc/static-draw 45 | {:position {:data verts 46 | :size 2} 47 | :uv {:data (#?(:clj native/float-buffer :cljs ta/float32) [0 0, 1 0, 0 1, 1 1]) 48 | :size 2}}) 49 | :uniforms {:tex 0 50 | :proj (gl/ortho)} 51 | :shader (d/merge-deep 52 | (or (get opts :shader) (sh/make-shader-from-spec gl shader-spec)) 53 | {:state (get opts :state)}) 54 | :view-port (get opts :viewport) 55 | :pos (get opts :pos (vec2)) 56 | :width (get opts :width 128) 57 | :height (get opts :height 128) 58 | :mode glc/triangle-strip 59 | :num-vertices 4}))) 60 | 61 | (defn draw 62 | [gl {:keys [viewport pos width height] :as spec}] 63 | (let [[vw vh] (get (or viewport (gl/get-viewport-rect gl)) :size) 64 | x (m/map-interval (nth pos 0) 0 vw -1 1) 65 | y (m/map-interval (nth pos 1) 0 vh -1 1) 66 | s (vec3 (* 2.0 (/ width vw)) (* 2.0 (/ height vh)) 1.0) 67 | spec (assoc-in spec [:uniforms :model] (-> M44 (g/translate (vec3 x y 0)) (g/scale s)))] 68 | (gl/draw-with-shader gl spec))) 69 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/shaders/lambert.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.shaders.lambert 2 | (:require 3 | [thi.ng.glsl.core :as glsl :include-macros true] 4 | [thi.ng.glsl.vertex :as vertex] 5 | [thi.ng.glsl.lighting :as light] 6 | [thi.ng.geom.gl.core :as gl] 7 | [thi.ng.geom.matrix :refer [M44]])) 8 | 9 | (defn- make-shader-spec 10 | [vs-src] 11 | {:vs (->> vs-src 12 | (glsl/glsl-spec-plain 13 | [vertex/mvp vertex/surface-normal light/lambert light/lambert-abs]) 14 | (glsl/assemble)) 15 | :fs #?(:clj "out vec4 fragColor;void main(){fragColor=vCol;}" 16 | :cljs "void main(){gl_FragColor=vCol;}") 17 | :uniforms {:model [:mat4 M44] 18 | :view :mat4 19 | :proj :mat4 20 | :normalMat [:mat4 (gl/auto-normal-matrix :model :view)] 21 | :ambientCol [:vec3 [0 0 0]] 22 | :diffuseCol [:vec3 [1 1 1]] 23 | :lightCol [:vec3 [1 1 1]] 24 | :lightDir [:vec3 [0 0 1]] 25 | :alpha [:float 1]} 26 | :attribs {:position [:vec3 0] 27 | :normal [:vec3 1]} 28 | :varying {:vCol :vec4} 29 | :state {:depth-test true}}) 30 | 31 | (def shader-spec 32 | (make-shader-spec 33 | (glsl/minified " 34 | void main() { 35 | float lam = lambert(surfaceNormal(normal, normalMat), lightDir); 36 | vCol = vec4(ambientCol + diffuseCol * lightCol * lam, alpha); 37 | gl_Position = mvp(position, model, view, proj); 38 | }"))) 39 | 40 | (def shader-spec-attrib 41 | (-> (make-shader-spec 42 | (glsl/minified " 43 | void main() { 44 | float lam = lambert(surfaceNormal(normal, normalMat), lightDir); 45 | vCol = vec4(ambientCol + color.rgb * lightCol * lam, alpha); 46 | gl_Position = mvp(position, model, view, proj); 47 | }")) 48 | (assoc-in [:attribs :color] [:vec4 2]))) 49 | 50 | (def shader-spec-two-sided 51 | (make-shader-spec 52 | (glsl/minified " 53 | void main() { 54 | float lam = lambertAbs(surfaceNormal(normal, normalMat), lightDir); 55 | vCol = vec4(ambientCol + diffuseCol * lightCol * lam, alpha); 56 | gl_Position = mvp(position, model, view, proj); 57 | }"))) 58 | 59 | (def shader-spec-two-sided-attrib 60 | (-> (make-shader-spec 61 | (glsl/minified " 62 | void main() { 63 | float lam = lambertAbs(surfaceNormal(normal, normalMat), lightDir); 64 | vCol = vec4(ambientCol + color.rgb * lightCol * lam, alpha); 65 | gl_Position = mvp(position, model, view, proj); 66 | }")) 67 | (assoc-in [:attribs :color] [:vec4 2]))) 68 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/shaders/phong.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.shaders.phong 2 | (:require 3 | [thi.ng.glsl.core :as glsl :include-macros true] 4 | [thi.ng.glsl.vertex :as vertex] 5 | [thi.ng.glsl.lighting :as light] 6 | [thi.ng.geom.gl.core :as gl] 7 | [thi.ng.geom.matrix :refer [M44]])) 8 | 9 | (def shader-spec 10 | {:vs (glsl/assemble 11 | (glsl/glsl-spec 12 | [vertex/surface-normal] 13 | " 14 | void main(){ 15 | vec4 worldPos = model * vec4(position, 1.0); 16 | vec4 eyePos = view * worldPos; 17 | vEyePos = eyePos.xyz; 18 | vNormal = surfaceNormal(normal, normalMat); 19 | vLightPos = (view * vec4(lightPos, 1.0)).xyz; 20 | gl_Position = proj * eyePos; 21 | }")) 22 | :fs (glsl/assemble 23 | (glsl/glsl-spec 24 | [light/phong light/blinn-phong] 25 | " 26 | #if __VERSION__ >= 300 27 | out vec4 fragColor; 28 | #endif 29 | 30 | void main() { 31 | vec3 L = normalize(vLightPos - vEyePos); 32 | vec3 E = normalize(-vEyePos); 33 | vec3 N = normalize(vNormal); 34 | 35 | float NdotL = max(0.0, (dot(N, L) + wrap) / (1.0 + wrap)); 36 | vec3 color = ambientCol + NdotL * diffuseCol; 37 | 38 | float specular = 0.0; 39 | if (useBlinnPhong) { 40 | specular = blinnPhong(L, E, N); 41 | } else { 42 | specular = phong(L, E, N); 43 | } 44 | color += max(pow(specular, shininess), 0.0) * specularCol; 45 | #if __VERSION__ >= 300 46 | fragColor = vec4(color, 1.0); 47 | #else 48 | gl_FragColor = vec4(color, 1.0); 49 | #endif 50 | }")) 51 | :uniforms {:view :mat4 52 | :proj :mat4 53 | :model [:mat4 M44] 54 | :normalMat [:mat4 (gl/auto-normal-matrix :model :view)] 55 | :shininess [:float 32] 56 | :ambientCol [:vec3 [0 0 0]] 57 | :diffuseCol [:vec3 [0.8 0.8 0.8]] 58 | :specularCol [:vec3 [1 1 1]] 59 | :lightPos [:vec3 [0 0 2]] 60 | :useBlinnPhong [:bool true] 61 | :wrap [:float 0]} 62 | :attribs {:position [:vec3 0] 63 | :normal [:vec3 1]} 64 | :varying {:vNormal :vec3 65 | :vEyePos :vec3 66 | :vLightPos :vec3} 67 | :state {:depth-test true}}) 68 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/shaders/spotlight.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.shaders.spotlight 2 | (:require 3 | [thi.ng.geom.matrix :refer [M44]] 4 | [thi.ng.glsl.lighting :as light] 5 | [thi.ng.glsl.core :as glsl :include-macros true])) 6 | 7 | (def shader-spec 8 | {:vs (glsl/minified " 9 | void main(){ 10 | vNormal = normal; 11 | vWorldPos = model * vec4(position, 1.0); 12 | gl_Position = proj * view * vWorldPos; 13 | }") 14 | :fs (glsl/assemble 15 | (glsl/glsl-spec 16 | [light/spotlight-attenuation light/spotlight-influence 17 | light/lambert light/skylight] 18 | " 19 | #if __VERSION__ >= 300 20 | out vec4 fragColor; 21 | #endif 22 | 23 | vec3 gamma(vec3 color){ 24 | return pow(color, vec3(2.2)); 25 | } 26 | 27 | void main(){ 28 | vec3 worldNormal = normalize(vNormal); 29 | 30 | vec3 camPos = (view * vWorldPos).xyz; 31 | vec3 lightPos = (lightView * vWorldPos).xyz; 32 | vec3 lightPosNormal = normalize(lightPos); 33 | vec3 lightSurfaceNormal = lightRot * worldNormal; 34 | 35 | vec3 excident = (skylight(worldNormal.y) + 36 | lambert(lightSurfaceNormal, -lightPosNormal) * 37 | spotlightInfluence(lightPosNormal, coneAngle, 10.0) * 38 | spotlightAttenuation(lightPos, 10.0)); 39 | #ifdef __VERSION__ >= 300 40 | fragColor = vec4(gamma(excident), 1.0); 41 | #else 42 | gl_FragColor = vec4(gamma(excident), 1.0); 43 | #endif 44 | }")) 45 | :uniforms {:view :mat4 46 | :proj :mat4 47 | :model [:mat4 M44] 48 | :lightView :mat4 49 | :lightRot :mat3 50 | :coneAngle [:float 15]} 51 | :attribs {:position :vec3 52 | :normal :vec3} 53 | :varying {:vNormal :vec3 54 | :vWorldPos :vec4}}) 55 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/shaders/xray.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.shaders.xray 2 | (:require 3 | [thi.ng.geom.matrix :refer [M44]] 4 | [thi.ng.geom.gl.core :as gl] 5 | [thi.ng.glsl.core :as glsl :include-macros true] 6 | [thi.ng.glsl.vertex :as vert] 7 | #?(:clj [thi.ng.geom.gl.jogl.constants :as glc] 8 | :cljs [thi.ng.geom.gl.webgl.constants :as glc]))) 9 | 10 | (def shader-spec 11 | {:vs (glsl/assemble 12 | (glsl/glsl-spec 13 | [vert/surface-normal] 14 | " 15 | void main() { 16 | vIncident = view * model * vec4(position, 1.0); 17 | vNormal = surfaceNormal(normal, normalMat); 18 | gl_Position = proj * vIncident; 19 | }")) 20 | :fs (glsl/minified 21 | " 22 | #if __VERSION__ >= 300 23 | out vec4 fragColor; 24 | #endif 25 | 26 | void main() { 27 | float opac = abs(dot(normalize(-vNormal), normalize(-vIncident.xyz))); 28 | opac = 1.0 - pow(opac, alpha); 29 | #if __VERSION__ >= 300 30 | fragColor = vec4(lightCol * opac, opac); 31 | #else 32 | gl_FragColor = vec4(lightCol * opac, opac); 33 | #endif 34 | }") 35 | :uniforms {:model [:mat4 M44] 36 | :view :mat4 37 | :normalMat [:mat4 (gl/auto-normal-matrix :model :view)] 38 | :proj :mat4 39 | :lightCol [:vec3 [1 1 1]] 40 | :alpha [:float 0.5]} 41 | :attribs {:position :vec3 42 | :normal :vec3} 43 | :varying {:vIncident :vec4 44 | :vNormal :vec3} 45 | :state {:depth-test false 46 | :blend true 47 | :blend-func [glc/src-alpha glc/one]}}) 48 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/utils.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.utils 2 | (:require 3 | [thi.ng.typedarrays.core :as arrays] 4 | [thi.ng.xerror.core :as err]) 5 | (:require-macros 6 | [thi.ng.math.macros :as mm])) 7 | 8 | (defn get-script-text 9 | [id] 10 | (if-let [e (.getElementById js/document id)] 11 | (.-text e) 12 | (err/illegal-arg! (str "Unknown DOM element: " id)))) 13 | 14 | (defn loop-kv 15 | "A combination of map & doseq specialized for maps. Takes a function `f` and 16 | a map, calls `f` with each key & value, discards results." 17 | [f xs] 18 | (loop [xs xs] 19 | (if xs 20 | (let [x (first xs)] 21 | (f (first x) (nth x 1)) 22 | (recur (next xs)))))) 23 | -------------------------------------------------------------------------------- /src/thi/ng/geom/gl/webgl/animator.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.gl.webgl.animator) 2 | 3 | (def animframe-provider 4 | (or 5 | (.-requestAnimationFrame js/self) 6 | (.-webkitRequestAnimationFrame js/self) 7 | (.-mozRequestAnimationFrame js/self) 8 | (.-msRequestAnimationFrame js/self) 9 | (.-oRequestAnimationFrame js/self))) 10 | 11 | (defn now 12 | [] 13 | (or 14 | (.now js/performance) 15 | (.webkitNow js/performance) 16 | (.mozNow js/performance) 17 | (.msNow js/performance) 18 | (.oNow js/performance))) 19 | 20 | (defn animate 21 | ([f] 22 | (animate f nil)) 23 | ([f element] 24 | (let [t0 (.getTime (js/Date.)) 25 | fid (volatile! 0) 26 | f' (fn animate* [] 27 | (if (f (* (- (.getTime (js/Date.)) t0) 1e-3) (vswap! fid inc)) 28 | (if element 29 | (animframe-provider animate* element) 30 | (animframe-provider animate*))))] 31 | (f')))) 32 | -------------------------------------------------------------------------------- /src/thi/ng/geom/macros/matrix.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.macros.matrix 2 | (:require [thi.ng.math.macros :as mm])) 3 | 4 | (defmacro det-item 5 | [a b c d, e f g h, i j k l, m n o p] 6 | `(+ (mm/sub 7 | (mm/mul ~a ~b ~c ~d) 8 | (mm/mul ~e ~f ~g ~h) 9 | (mm/mul ~i ~j ~k ~l)) 10 | (mm/mul ~m ~n ~o ~p))) 11 | 12 | (defmacro inv-item 13 | [a b c d e f g] 14 | `(* (mm/msubadd ~a ~b ~c ~d ~e ~f) ~g)) 15 | -------------------------------------------------------------------------------- /src/thi/ng/geom/macros/voxel.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.macros.voxel) 2 | 3 | (defmacro not-cond-> 4 | "Like clojure.core/cond-> but with inverted test semantics." 5 | [expr & clauses] 6 | (assert (even? (count clauses))) 7 | (let [g (gensym) 8 | pstep (fn [[test step]] `(if ~test ~g (-> ~g ~step)))] 9 | `(let [~g ~expr 10 | ~@(interleave (repeat g) (map pstep (partition 2 clauses)))] 11 | ~g))) 12 | -------------------------------------------------------------------------------- /src/thi/ng/geom/meshface.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.meshface 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.vector :as v :refer [vec2 vec3]])) 5 | 6 | (defn xf-face-verts 7 | [mesh] (map #(first (g/raw % mesh)))) 8 | 9 | (deftype MeshFace 10 | [vertices 11 | #?@(:clj [^:unsynchronized-mutable _hash] 12 | :cljs [^:mutable _hash])] 13 | 14 | g/IVertexAccess 15 | (vertices [_] vertices) 16 | (vertices [_ _] vertices) 17 | 18 | g/IAttributeAccess 19 | (attribs [_ _] nil) 20 | 21 | g/IRawAccess 22 | (raw [_ _] [vertices]) 23 | 24 | Object 25 | (toString [_] (str \[ vertices \])) 26 | #?@(:clj 27 | [(hashCode [_] (or _hash (set! _hash (.hashCode vertices)))) 28 | (equals 29 | [_ o] 30 | (and (instance? MeshFace o) 31 | (clojure.lang.Util/equals vertices (.-vertices ^MeshFace o)))) 32 | 33 | Comparable 34 | (compareTo [_ o] (compare vertices (.-vertices ^MeshFace o))) 35 | 36 | clojure.lang.IHashEq 37 | (hasheq [_] (.hashCode _))] 38 | 39 | :cljs 40 | [IHash 41 | (-hash [_] (or _hash (set! _hash (hash vertices)))) 42 | 43 | IComparable 44 | (-compare [_ o] (compare vertices (.-vertices ^MeshFace o)))])) 45 | 46 | (deftype IndexedMeshFace 47 | [vertices attribs 48 | #?@(:clj [^:unsynchronized-mutable _hash] 49 | :cljs [^:mutable _hash])] 50 | 51 | g/IVertexAccess 52 | (vertices [_ mesh] 53 | (let [idx (-> mesh :vertices :id->v)] 54 | (mapv #(get idx %) vertices))) 55 | 56 | g/IAttributeAccess 57 | (attribs [_ mesh] 58 | (let [mattr (get mesh :attribs)] 59 | (reduce-kv 60 | (fn [acc k v] 61 | (let [idx (-> mattr (get k) (get :id->v))] 62 | (assoc acc k (if (sequential? v) (mapv #(get idx %) v) (get idx v))))) 63 | {} attribs))) 64 | (attribs [_ mesh attr] 65 | (let [idx (-> mesh (get :attribs) (get attr) (get :id->v)) 66 | aval (attribs attr)] 67 | (if (sequential? aval) (mapv idx attribs) (idx aval)))) 68 | 69 | g/IRawAccess 70 | (raw [_ mesh] 71 | [(g/vertices _ mesh) (g/attribs _ mesh)]) 72 | 73 | Object 74 | (toString [_] 75 | (str \[ vertices \space attribs \])) 76 | #?@(:clj 77 | [(hashCode 78 | [_] 79 | (or _hash 80 | (set! _hash 81 | (unchecked-add-int 82 | (unchecked-multiply-int (.hashCode vertices) 31) 83 | (.hashCode attribs))))) 84 | (equals 85 | [_ o] 86 | (and (instance? IndexedMeshFace o) 87 | (clojure.lang.Util/equals vertices (.-vertices ^IndexedMeshFace o)) 88 | (clojure.lang.Util/equals attribs (.-attribs ^IndexedMeshFace o)))) 89 | 90 | Comparable 91 | (compareTo 92 | [_ o] 93 | (let [c (compare vertices (.-vertices ^IndexedMeshFace o))] 94 | (if (zero? c) 95 | (compare attribs (.-attribs ^IndexedMeshFace o)) 96 | c))) 97 | 98 | clojure.lang.IHashEq 99 | (hasheq [_] (.hashCode _))] 100 | 101 | :cljs 102 | [IHash 103 | (-hash 104 | [_] 105 | (or _hash 106 | (set! _hash 107 | (-> (hash vertices) 108 | (imul 31) 109 | (+ (hash attribs)) 110 | (bit-or 0))))) 111 | 112 | IComparable 113 | (-compare 114 | [_ o] 115 | (let [c (compare vertices (.-vertices ^IndexedMeshFace o))] 116 | (if (zero? c) 117 | (compare attribs (.-attribs ^IndexedMeshFace o)) 118 | c)))])) 119 | -------------------------------------------------------------------------------- /src/thi/ng/geom/path.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.path 2 | (:require 3 | [thi.ng.math.core :as m] 4 | [thi.ng.geom.core :as g :refer [*resolution*]] 5 | [thi.ng.geom.vector :as v :refer [vec2]] 6 | #?(:clj [thi.ng.geom.types] :cljs [thi.ng.geom.types :refer [Path2]]) 7 | [thi.ng.geom.utils :as gu] 8 | [thi.ng.geom.bezier :as b] 9 | [thi.ng.xerror.core :as err] 10 | #?(:clj [clojure.xml :as xml])) 11 | #?(:clj (:import [thi.ng.geom.types Path2]))) 12 | 13 | (defn path2 14 | ([segments] 15 | (Path2. (vec segments))) 16 | ([s1 s2 & segments] 17 | (Path2. (vec (cons s1 (cons s2 segments)))))) 18 | 19 | (defmulti sample-segment (fn [s res last?] (get s :type))) 20 | 21 | (defmethod sample-segment :line 22 | [{[a b] :points} res last?] 23 | (gu/sample-segment-with-res a b res last?)) 24 | 25 | (defmethod sample-segment :close 26 | [{[a b] :points} res last?] 27 | (gu/sample-segment-with-res a b res last?)) 28 | 29 | (defmethod sample-segment :bezier 30 | [{points :points} res last?] 31 | (b/sample-with-res res last? points)) 32 | 33 | (defn sample-segments* 34 | [res segments] 35 | (let [last (last segments) 36 | [paths curr] (reduce 37 | (fn [[paths curr] seg] 38 | (let [curr (concat curr (sample-segment seg res (= seg last)))] 39 | (if (= :close (get seg :type)) 40 | [(conj paths curr) []] 41 | [paths curr]))) 42 | [[] []] segments)] 43 | (if (seq curr) 44 | (conj paths curr) 45 | paths))) 46 | 47 | (defn parse-svg-coords 48 | [coords] 49 | (->> coords 50 | (re-seq #"[0-9\.\-\+]+") 51 | #?(:clj (map #(Double/parseDouble %)) :cljs (map js/parseFloat)) 52 | (partition 2) 53 | (mapv vec2))) 54 | 55 | (defn parse-svg-path 56 | ([svg] 57 | (parse-svg-path 58 | (->> svg 59 | (re-seq #"([MLCZz])\s*(((([0-9\.\-]+)\,?){2}\s*){0,3})") 60 | (map (fn [[_ t c]] 61 | [t (parse-svg-coords c)]))) 62 | [0 0] [0 0])) 63 | ([[[type points :as seg] & more] p0 pc] 64 | (when seg 65 | (cond 66 | (= "M" type) 67 | (let [p (first points)] (recur more p p)) 68 | 69 | (= "L" type) 70 | (let [p (first points)] 71 | (lazy-seq (cons {:type :line :points [pc p]} 72 | (parse-svg-path more p0 p)))) 73 | 74 | (= "C" type) 75 | (let [p (last points)] 76 | (lazy-seq (cons {:type :bezier :points (cons pc points)} 77 | (parse-svg-path more p0 p)))) 78 | 79 | (or (= "Z" type) (= "z" type)) 80 | (lazy-seq (cons {:type :close :points [pc p0]} 81 | (parse-svg-path more p0 p0))) 82 | 83 | :default 84 | (err/unsupported! (str "Unsupported path segment type" type)))))) 85 | 86 | #?(:clj 87 | (defn parse-svg 88 | [src res udist] 89 | (->> src 90 | (xml/parse) 91 | (xml-seq) 92 | (filter #(= :path (get % :tag))) 93 | (mapv #(parse-svg-path (-> % (get :attrs) (get :d)))) 94 | (map path2)))) 95 | 96 | (extend-type Path2 97 | 98 | g/IArea 99 | (area [_]) 100 | 101 | g/IClassify 102 | (classify-point [_ p]) 103 | 104 | g/IProximity 105 | (closest-point [_ p]) 106 | 107 | g/IBoundary 108 | (contains-point? [_ p]) 109 | 110 | g/IBounds 111 | (bounds [_]) 112 | 113 | g/IBoundingCircle 114 | (bounding-circle [_] nil) 115 | 116 | g/ICenter 117 | (center 118 | ([_] nil) 119 | ([_ o] nil)) 120 | (centroid [_]) 121 | 122 | g/ICircumference 123 | (circumference [_] nil) 124 | 125 | g/IVertexAccess 126 | (vertices 127 | [_ res] 128 | (first (sample-segments* res (get _ :segments)))) 129 | 130 | g/IEdgeAccess 131 | (edges [_]) 132 | 133 | g/IPolygonConvert 134 | (as-polygon 135 | ([_] nil) 136 | ([_ res] nil)) 137 | 138 | g/ISample 139 | (point-at [_ t]) 140 | (random-point [_]) 141 | (random-point-inside [_]) 142 | (sample-uniform 143 | [_ udist include-last?] 144 | (->> _ 145 | :segments 146 | (sample-segments* 8) 147 | (map #(gu/sample-uniform udist include-last? %)) 148 | (first))) ;; TODO why first? 149 | ) 150 | -------------------------------------------------------------------------------- /src/thi/ng/geom/plane.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.plane 2 | #?(:cljs (:require-macros [thi.ng.math.macros :as mm])) 3 | (:require 4 | [thi.ng.geom.core :as g] 5 | [thi.ng.geom.utils :as gu] 6 | [thi.ng.geom.utils.intersect :as isec] 7 | [thi.ng.geom.vector :as v :refer [vec3]] 8 | [thi.ng.geom.quaternion :as q] 9 | [thi.ng.geom.basicmesh :as bm] 10 | [thi.ng.geom.attribs :as attr] 11 | #?(:clj [thi.ng.geom.types] :cljs [thi.ng.geom.types :refer [AABB Plane Sphere]]) 12 | [thi.ng.xerror.core :as err] 13 | [thi.ng.math.core :as m :refer [*eps* INF+]] 14 | #?(:clj [thi.ng.math.macros :as mm])) 15 | #?(:clj (:import [thi.ng.geom.types AABB Plane Sphere]))) 16 | 17 | ;; A plane in cartesian 3D space can be defined as a point `p` lying 18 | ;; on the plane and normal vector `n` standing perpendicular on the 19 | ;; plane. The latter defines the plane's orientation in space. 20 | 21 | (defn plane 22 | [n w] (Plane. (m/normalize (vec3 n)) w)) 23 | 24 | (defn plane-with-point 25 | [p n] 26 | (let [n (m/normalize (vec3 n))] 27 | (Plane. n (- (m/dot n p))))) 28 | 29 | (defn plane-from-points 30 | ([[a b c]] (plane-from-points a b c)) 31 | ([a b c] 32 | (let [n (gu/ortho-normal a b c)] 33 | (Plane. n (- (m/dot n a)))))) 34 | 35 | (extend-type Plane 36 | 37 | g/IArea 38 | (area [_] INF+) 39 | 40 | g/IBounds 41 | (bounds 42 | [_] 43 | (let [s (vec3 (g/width _) (g/height _) (g/depth _))] 44 | (AABB. (m/madd s -0.5 (g/centroid _)) s))) 45 | (width 46 | [_] (if (m/delta= (m/abs (get _ :n)) v/V3X *eps*) 0.0 INF+)) 47 | (height 48 | [_] (if (m/delta= (m/abs (get _ :n)) v/V3Y *eps*) 0.0 INF+)) 49 | (depth 50 | [_] (if (m/delta= (m/abs (get _ :n)) v/V3Z *eps*) 0.0 INF+)) 51 | 52 | g/IBoundingSphere 53 | (bounding-sphere 54 | [_] (Sphere. (g/centroid _) INF+)) 55 | 56 | g/ICenter 57 | (center 58 | ([_] (Plane. (get _ :n) 0)) 59 | ([_ o] (plane-with-point o (get _ :n)))) 60 | (centroid 61 | ([_] (m/* (get _ :n) (- (get _ :w))))) 62 | 63 | g/IClassify 64 | (classify-point 65 | [_ p] 66 | (-> (get _ :n) (m/dot p) (+ (get _ :w)) (m/signum *eps*))) 67 | 68 | g/IDistance 69 | (dist 70 | [_ p] (+ (m/dot (get _ :n) p) (get _ :w))) 71 | (dist-squared 72 | [_ p] (let [d (g/dist _ p)] (* d d))) 73 | 74 | g/IExtrude 75 | (extrude [_ {}] (err/unsupported!)) 76 | 77 | g/IFlip 78 | (flip 79 | [_] (Plane. (m/- (get _ :n)) (- (get _ :w)))) 80 | 81 | g/IIntersect 82 | (intersect-line 83 | ([_ l] 84 | (let [[p q] (if (map? l) (get l :points) l)] 85 | (isec/intersect-ray-plane? p (m/- q p) (get _ :n) (get _ :w)))) 86 | ([_ p q] 87 | (isec/intersect-ray-plane? p (m/- q p) (get _ :n) (get _ :w)))) 88 | (intersect-ray 89 | ([_ ray] 90 | (let [[p dir] (if (map? ray) [(get ray :p) (get ray :dir)] ray)] 91 | (isec/intersect-ray-plane? p dir (get _ :n) (get _ :w)))) 92 | ([_ p dir] 93 | (isec/intersect-ray-plane? p dir (get _ :n) (get _ :w)))) 94 | (intersect-shape 95 | [_ s] 96 | (cond 97 | (instance? Plane s) 98 | (isec/intersect-plane-plane? (get _ :n) (get _ :w) (get s :n) (get s :w)) 99 | (instance? Sphere s) 100 | (isec/intersect-plane-sphere? (get _ :n) (get _ :w) (get s :p) (get s :r)) 101 | :default (err/illegal-arg! s))) 102 | 103 | g/IMeshConvert 104 | (as-mesh 105 | ([_] (g/as-mesh _ {})) 106 | ([_ {:keys [p width height size mesh attribs] :or {size 1.0}}] 107 | (let [w (* (or width size) 0.5) 108 | h (* (or height size) 0.5) 109 | flip? (m/delta= -1.0 (m/dot (get _ :n) v/V3Z)) 110 | p (g/closest-point _ (or p (vec3))) 111 | q (if flip? 112 | (q/quat 0 0 0 1) 113 | (q/alignment-quat v/V3Z (get _ :n))) 114 | face (mapv 115 | #(m/+ p (g/transform-vector q %)) 116 | [(vec3 (- w) (- h) 0) (vec3 (- w) h 0) 117 | (vec3 w h 0) (vec3 w (- h) 0)]) 118 | face (attr/generate-face-attribs (if flip? face (rseq face)) 0 attribs nil)] 119 | (g/add-face (or mesh (bm/basic-mesh)) face)))) 120 | 121 | g/IProximity 122 | (closest-point 123 | [{:keys [n] :as _} p] 124 | (->> p 125 | (m/dot n) 126 | (+ (get _ :w)) 127 | (m/normalize n) 128 | (m/- p))) 129 | 130 | g/IScale 131 | (scale 132 | [_ s] (plane-with-point (m/* (g/centroid _) s) (get _ :n))) 133 | (scale-size 134 | ([_ s] _)) 135 | 136 | g/ITranslate 137 | (translate 138 | [_ t] (plane-with-point (m/+ (g/centroid _) t) (get _ :n))) 139 | 140 | g/ITransform 141 | (transform 142 | [_ m] (plane-with-point 143 | (g/transform-vector m (g/centroid _)) 144 | (g/transform-vector m (get _ :n)))) 145 | 146 | g/IVolume 147 | (volume [_] 0.0)) 148 | -------------------------------------------------------------------------------- /src/thi/ng/geom/svg/adapter.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.svg.adapter 2 | (:require 3 | [thi.ng.math.core :as m] 4 | [thi.ng.geom.svg.core :as svg] 5 | [thi.ng.geom.core :as g] 6 | #?(:clj [thi.ng.geom.types] 7 | :cljs [thi.ng.geom.types :refer [Circle2 Line2 LineStrip2 Polygon2 Rect2 Triangle2]]) 8 | [thi.ng.dstruct.core :as d]) 9 | #?(:clj 10 | (:import 11 | [thi.ng.geom.types Circle2 Line2 LineStrip2 Polygon2 Rect2 Triangle2]))) 12 | 13 | ;; SVG conversions for geom.types 14 | ;; 15 | ;; This namespace provides some simple wrappers to allow direct use of 16 | ;; the shape entities defined in `src/types.cljc`, without having to 17 | ;; manually convert them into their SVG representations. 18 | ;; 19 | ;; The adapters work by providing implementations of the `ISVGConvert` 20 | ;; protocol for all built-in 2D types and a simple helper function to 21 | ;; recursively transform any such types used within an SVG scene. 22 | ;; 23 | ;; Any 3D entities (e.g. meshes) need to be processed via the 24 | ;; `thi.ng.geom.svg.renderer` namespace. 25 | 26 | 27 | ;; Adapter implementations 28 | 29 | (extend-protocol svg/ISVGConvert 30 | 31 | Line2 32 | (as-svg 33 | [{p :points} {:keys [__start __end] :as opts}] 34 | (if (or __start __end) 35 | (svg/line-decorated (p 0) (p 1) __start __end opts) 36 | (svg/line (p 0) (p 1) opts))) 37 | 38 | Circle2 39 | (as-svg 40 | [_ opts] (svg/circle (get _ :p) (get _ :r) opts)) 41 | 42 | LineStrip2 43 | (as-svg 44 | [{:keys [points]} {:keys [__start __segment __end] :as opts}] 45 | (if (or __start __segment __end) 46 | (svg/line-strip-decorated points __start __segment __end opts) 47 | (svg/line-strip points opts))) 48 | 49 | Polygon2 50 | (as-svg 51 | [_ opts] (svg/polygon (get _ :points) opts)) 52 | 53 | Rect2 54 | (as-svg 55 | [{:keys [p size]} opts] (svg/rect p (size 0) (size 1) opts)) 56 | 57 | Triangle2 58 | (as-svg 59 | [_ opts] (svg/polygon (get _ :points) opts))) 60 | 61 | (defn all-as-svg 62 | [form] 63 | (d/postwalk 64 | (fn [x] (if (satisfies? svg/ISVGConvert x) (svg/as-svg x (meta x)) x)) 65 | form)) 66 | 67 | ;; React.js :key prop injection 68 | 69 | (defn key-attrib-injector 70 | "To be used with inject-element-attribs, generates an unique :key 71 | attrib for each SVG element w/o :key attrib. Returns updated attribs." 72 | [el attribs] (if (get attribs :key) 73 | attribs 74 | (assoc attribs :key (str (gensym) (hash el))))) 75 | 76 | (defn inject-element-attribs 77 | "Walks SVG DOM tree with thi.ng.dstruct.core/postwalk and applies 78 | given function to each element node. The fn takes 2 args: the 79 | element itself and its attribute map. The fn's return value will be 80 | used as the new attribute map." 81 | ([root] 82 | (inject-element-attribs key-attrib-injector root)) 83 | ([f root] 84 | (d/postwalk 85 | (fn [x] 86 | (if (vector? x) 87 | (let [y (nth x 1)] 88 | (if (or (nil? y) (map? y)) 89 | (assoc x 1 (f x y)) 90 | x)) 91 | x)) 92 | root))) 93 | -------------------------------------------------------------------------------- /src/thi/ng/geom/svg/renderer.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.svg.renderer 2 | (:require 3 | [thi.ng.math.core :as m] 4 | [thi.ng.geom.core :as g] 5 | [thi.ng.geom.svg.core :as svg] 6 | [thi.ng.geom.svg.shaders :as shader] 7 | [thi.ng.geom.utils :as gu] 8 | [thi.ng.geom.vector :as v :refer [vec3 V3Z]] 9 | [thi.ng.geom.matrix :as mat :refer [M44]])) 10 | 11 | ;; 3D to 2D projection 12 | 13 | (defn project-face 14 | [mvp vtx points] 15 | (mapv #(mat/project-point-z % mvp vtx) points)) 16 | 17 | (defn project-faces 18 | [mvp vtx faces] 19 | (map 20 | (fn [f] 21 | (let [f' (project-face mvp vtx f) 22 | n' (gu/ortho-normal f')] 23 | [f f' n'])) 24 | faces)) 25 | 26 | (defn cull-backfaces 27 | [norm-fn faces] 28 | (filter (fn [f] (neg? (m/dot (norm-fn f) V3Z))) faces)) 29 | 30 | (defn z-map-faces 31 | [faces] 32 | (mapv 33 | (fn [[f f' n']] [(v/z (gu/centroid f')) f f' n']) 34 | faces)) 35 | 36 | (defn z-sort-faces 37 | [z-fn faces] 38 | (reverse (sort-by z-fn faces))) 39 | 40 | ;; Render functions 41 | ;; TODO add attribute support (at least colors) 42 | 43 | (defn mesh 44 | [mesh mvp screen shader] 45 | (let [faces (project-faces mvp screen (map #(g/vertices % mesh) (g/faces mesh false))) 46 | faces (->> (if (shader/solid? shader) 47 | (cull-backfaces peek faces) 48 | faces) 49 | (z-map-faces) 50 | (z-sort-faces first))] 51 | (svg/group 52 | (shader/uniforms shader) 53 | (if shader 54 | (map (fn [[z f f']] (svg/polygon f' (shader/shade-facet shader f f' z))) faces) 55 | (map (fn [f] (svg/polygon (f 2) nil)) faces))))) 56 | -------------------------------------------------------------------------------- /src/thi/ng/geom/svg/shaders.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.svg.shaders 2 | (:require 3 | [thi.ng.math.core :as m] 4 | [thi.ng.geom.core :as g] 5 | [thi.ng.geom.utils :as gu] 6 | [thi.ng.geom.vector :refer [vec3 V3Z]] 7 | [thi.ng.geom.matrix :as mat :refer [M44]] 8 | [thi.ng.color.core :as col])) 9 | 10 | (defprotocol IShader 11 | (uniforms [_]) 12 | (solid? [_]) 13 | (shade-facet [_ f f' z])) 14 | 15 | (defn normal-rgb 16 | ([] (normal-rgb M44)) 17 | ([tx] 18 | (fn [f _ _] 19 | (-> (gu/ortho-normal f) 20 | (g/transform tx) 21 | (m/madd 0.5 0.5))))) 22 | 23 | (defn translucent 24 | [shader alpha] 25 | (fn [f f' z] (conj (vec (shader f f' z)) alpha))) 26 | 27 | (defn shader 28 | [{:keys [fill stroke uniforms flags]}] 29 | (reify 30 | IShader 31 | (shade-facet [_ f f' z] 32 | (cond-> {} 33 | fill (assoc :fill (col/rgba (if (fn? fill) (fill f f' z) fill))) 34 | stroke (assoc :stroke (col/rgba (if (fn? stroke) (stroke f f' z) stroke))))) 35 | (uniforms [_] uniforms) 36 | (solid? [_] (get flags :solid true)))) 37 | 38 | (defn lambert 39 | [{:keys [view light-dir light-col diffuse ambient]}] 40 | (let [light-col (vec3 light-col) 41 | light-dir (m/normalize (vec3 light-dir)) 42 | diffuse (if (fn? diffuse) diffuse (vec3 diffuse)) 43 | ambient (if (fn? ambient) ambient (vec3 ambient)) 44 | nmat (m/transpose (m/invert view))] 45 | (fn [f f' z] 46 | (let [n (g/transform-vector nmat (gu/ortho-normal f)) 47 | lambert (max 0.0 (m/dot n light-dir)) 48 | diffuse (if (fn? diffuse) (diffuse f f' z) diffuse) 49 | ambient (if (fn? ambient) (ambient f f' z) ambient)] 50 | (-> (m/* diffuse light-col) 51 | (m/madd lambert (m/* ambient light-col))))))) 52 | 53 | (defn phong 54 | [{:keys [model view light-pos light-col 55 | diffuse specular ambient shininess]}] 56 | (let [light-col (vec3 light-col) 57 | light-pos (g/transform-vector view (vec3 light-pos)) 58 | diffuse (if (fn? diffuse) diffuse (vec3 diffuse)) 59 | ambient (if (fn? ambient) ambient (vec3 ambient)) 60 | specular (vec3 specular) 61 | mv (m/* view model) 62 | nmat (m/transpose (m/invert view))] 63 | (fn [f f' z] 64 | (let [eye-pos (g/transform-vector mv (gu/centroid f)) 65 | n (m/normalize (g/transform-vector nmat (gu/ortho-normal f))) 66 | l (m/normalize (m/- light-pos eye-pos)) 67 | e (m/normalize (m/- eye-pos)) 68 | lambert (max 0.0 (m/dot n l)) 69 | diffuse (if (fn? diffuse) (diffuse f f' z) diffuse) 70 | ambient (if (fn? ambient) (ambient f f' z) ambient) 71 | spec (max (Math/pow (m/dot (m/normalize (m/+ l e)) n) shininess) 0.0)] 72 | (-> (m/* diffuse light-col) 73 | (m/madd lambert (m/+ (m/* ambient light-col) (m/* specular spec))) 74 | (m/min [1.0 1.0 1.0])))))) 75 | -------------------------------------------------------------------------------- /src/thi/ng/geom/types.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.types 2 | (:require 3 | [thi.ng.geom.vector]) 4 | #?(:clj (:import [thi.ng.geom.vector Vec2 Vec3]))) 5 | 6 | (defrecord Graph [vertices edges]) 7 | 8 | (defrecord Bezier2 [points]) 9 | 10 | (defrecord Circle2 #?(:clj [^Vec2 p ^double r] :cljs [p r])) 11 | 12 | (defrecord Ellipse2 #?(:clj [^Vec2 p ^double rx ^double ry] :cljs [p rx ry])) 13 | 14 | (defrecord Line2 [points]) 15 | 16 | (defrecord LineStrip2 [points]) 17 | 18 | (defrecord Mesh2 [vertices normals fnormals vnormals edges faces attribs]) 19 | 20 | (defrecord Path2 [segments]) 21 | 22 | (defrecord Polygon2 [points]) 23 | 24 | (defrecord Rect2 #?(:clj [^Vec2 p ^Vec2 size] :cljs [p size])) 25 | 26 | (defrecord Triangle2 [points]) 27 | 28 | ;; 3D 29 | 30 | (defrecord AABB [^Vec3 p size]) 31 | 32 | (defrecord Cuboid [points]) 33 | 34 | (defrecord Bezier3 [points]) 35 | 36 | (defrecord BasicMesh [vertices faces fnormals]) 37 | 38 | (defrecord GMesh [vertices normals fnormals vnormals edges faces]) 39 | 40 | (defrecord IndexedMesh [vertices faces attribs]) 41 | 42 | (defrecord Line3 [points]) 43 | 44 | (defrecord LineStrip3 [points]) 45 | 46 | (defrecord Plane #?(:clj [n ^double w] :cljs [n w])) 47 | 48 | (defrecord Quad3 [points]) 49 | 50 | (defrecord Sphere #?(:clj [^Vec3 p ^double r] :cljs [p r])) 51 | 52 | (defrecord Tetrahedron [points]) 53 | 54 | (defrecord Triangle3 [points]) 55 | -------------------------------------------------------------------------------- /src/thi/ng/geom/utils/delaunay.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.utils.delaunay 2 | #?(:cljs (:require-macros [thi.ng.math.macros :as mm])) 3 | (:require 4 | [thi.ng.geom.core :as g] 5 | [thi.ng.geom.triangle :refer [circumcircle-raw triangle2]] 6 | [thi.ng.math.core :as m :refer [*eps* delta=]] 7 | #?(:clj [thi.ng.math.macros :as mm]))) 8 | 9 | (defn- add-unique-edge! 10 | [edges p q] 11 | (let [e [p q]] 12 | (if (edges e) 13 | (disj! edges e) 14 | (let [e2 [q p]] 15 | (if (edges e2) (disj! edges e2) (conj! edges e)))))) 16 | 17 | (defn- compute-edges 18 | [complete tris [px py]] 19 | (persistent! 20 | (reduce 21 | (fn [state t] 22 | (if (complete t) state 23 | (let [x (- px (t 3)) 24 | y (- py (t 4))] 25 | (if (<= (mm/madd x x y y) (t 5)) 26 | (assoc! state 27 | 0 (let [[a b c] t] 28 | (-> (state 0) 29 | (add-unique-edge! a b) 30 | (add-unique-edge! b c) 31 | (add-unique-edge! c a)))) 32 | (assoc! state 33 | 1 (conj! (state 1) t)))))) 34 | (transient [(transient #{}) (transient [])]) 35 | tris))) 36 | 37 | (defn- triangle-spec 38 | [a b c] 39 | (let [[[ox oy] r] (circumcircle-raw a b c)] 40 | [a b c ox oy (* r r) (+ ox r)])) 41 | 42 | (defn- shared-vertex? 43 | [a1 b1 c1 [a2 b2 c2]] 44 | (or (identical? a1 a2) (identical? a1 b2) (identical? a1 c2) 45 | (identical? b1 a2) (identical? b1 b2) (identical? b1 c2) 46 | (identical? c1 a2) (identical? c1 b2) (identical? c1 c2))) 47 | 48 | ;; Algorithm fails if *all* points are arranged in a circle. A 49 | ;; workaround is to add additional point(s) in the center. 50 | ;; 51 | ;; See: http://astronomy.swin.edu.au/~pbourke/modelling/triangulate/ 52 | 53 | (defn triangulate 54 | [points] 55 | (let [points (sort-by #(% 0) points) 56 | bmin (reduce m/min points) 57 | bmax (reduce m/max points) 58 | bext (m/- bmax bmin) 59 | dm (max (bext 0) (bext 1)) 60 | d2 (* 2.0 dm) 61 | m (m/mix bmin bmax) 62 | [sa sb sc :as s] (triangle-spec (m/- m d2 dm) (m/+ m 0 d2) (m/+ m d2 (- dm)))] 63 | (loop [points points, tris [s], complete (transient #{})] 64 | (if-let [[px :as p] (first points)] 65 | (let [complete (reduce #(if (< (%2 6) px) (conj! % %2) %) complete tris) 66 | [edges tris] (compute-edges complete tris p) 67 | tris (reduce #(conj! % (triangle-spec (%2 0) (%2 1) p)) tris (persistent! edges))] 68 | (recur (rest points) (persistent! tris) complete)) 69 | (->> tris 70 | (reduce conj! complete) 71 | (persistent!) 72 | (remove #(shared-vertex? sa sb sc %)) 73 | (map (fn [t] [(t 1) (t 0) (t 2)]))))))) 74 | -------------------------------------------------------------------------------- /src/thi/ng/geom/utils/subdiv.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.utils.subdiv 2 | #?(:cljs 3 | (:require-macros 4 | [thi.ng.math.macros :as mm])) 5 | (:require 6 | [thi.ng.math.core :as m] 7 | [thi.ng.geom.core :as g] 8 | [thi.ng.geom.vector :as v :refer [vec2 vec3]] 9 | #?(:clj [thi.ng.math.macros :as mm]))) 10 | 11 | ;; Iterative curve subdivision 12 | ;; http://algorithmicbotany.org/papers/subgpu.sig2003.pdf 13 | 14 | ;; See example in: /examples/svg/subdiv.clj 15 | 16 | (defn subdiv-kernel3 17 | [u v [a b c]] 18 | [(->> (m/* c (u 2)) (m/madd b (u 1)) (m/madd a (u 0))) 19 | (->> (m/* c (v 2)) (m/madd b (v 1)) (m/madd a (v 0)))]) 20 | 21 | (defn subdiv-kernel5 22 | [u v [a b c d e]] 23 | [(->> (m/* e (u 4)) (m/madd d (u 3)) (m/madd c (u 2)) (m/madd b (u 1)) (m/madd a (u 0))) 24 | (->> (m/* e (v 4)) (m/madd d (v 3)) (m/madd c (v 2)) (m/madd b (v 1)) (m/madd a (v 0)))]) 25 | 26 | (defn subdivide-closed 27 | ([scheme points] 28 | (subdivide-closed (get scheme :fn) (get scheme :coeff) points)) 29 | ([f [u v] points] 30 | (let [n (count u) 31 | n2 (int (/ n 2))] 32 | (->> (concat (take-last n2 points) points (take n2 points)) 33 | (partition n 1) 34 | (mapcat #(f u v %)))))) 35 | 36 | (def schemes 37 | {:chaikin {:fn subdiv-kernel3 :coeff [[0.25 0.75 0] [0 0.75 0.25]]} 38 | :cubic-bezier {:fn subdiv-kernel3 :coeff [[0.125 0.75 0.125] [0 0.5 0.5]]}}) 39 | -------------------------------------------------------------------------------- /src/thi/ng/geom/version.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.version) 2 | 3 | (def ^:export version "1.0.0-RC3") 4 | -------------------------------------------------------------------------------- /test/thi/ng/geom/test/core/protocols.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.test.core.protocols 2 | #?(:cljs 3 | (:require-macros 4 | [cemerick.cljs.test :refer (is deftest with-test run-tests testing)])) 5 | (:require 6 | [thi.ng.math.core :as m] 7 | [thi.ng.geom.core :as g] 8 | [thi.ng.geom.matrix] 9 | [thi.ng.geom.quaternion] 10 | [thi.ng.geom.vector] 11 | #?(:clj 12 | [clojure.test :refer :all] 13 | :cljs 14 | [cemerick.cljs.test])) 15 | #?(:clj 16 | (:import 17 | [thi.ng.geom.matrix Matrix32 Matrix44] 18 | [thi.ng.geom.quaternion Quat4] 19 | [thi.ng.geom.vector Vec2 Vec3]))) 20 | 21 | (def proto-ids 22 | {:conj m/IConjugate 23 | :cross m/ICrossProduct 24 | :det m/IDeterminant 25 | :dist g/IDistance 26 | :dot m/IDotProduct 27 | :head g/IHeading 28 | :inv m/IInvert 29 | :limit m/ILimit 30 | :mag m/IMagnitude 31 | :mat g/IMatrixConvert 32 | :math m/IMathOps 33 | :mimax m/IMinMax 34 | :mix m/IInterpolate 35 | :norm m/INormalize 36 | :polar g/IPolar 37 | :refl g/IReflect 38 | :rotate g/IRotate 39 | :rot3d g/IRotate3D 40 | :scale g/IScale 41 | :shear g/IShear 42 | :translate g/ITranslate 43 | :tx g/ITransform 44 | :vtx g/IVectorTransform}) 45 | 46 | (def vec-common 47 | #{:cross :dist :dot :head :inv :limit :mag :math :mix 48 | :norm :polar :refl :rotate :scale :translate :tx}) 49 | 50 | (def mat-common 51 | #{:math :det :inv :rotate :scale :tx :vtx}) 52 | 53 | #?(:clj 54 | (defn satisfies-all? 55 | [type & protos] 56 | (testing 57 | (.getName type) 58 | (doseq [p protos] 59 | (is (true? (extends? (proto-ids p) type)) 60 | (str (get-in proto-ids [p :on-interface]))))))) 61 | 62 | #?(:clj 63 | (deftest proto-implementation-check 64 | (dorun 65 | (map 66 | (fn [[t protos]] (apply satisfies-all? t protos)) 67 | { 68 | thi.ng.geom.matrix.Matrix32 69 | (conj mat-common :shear) 70 | 71 | thi.ng.geom.matrix.Matrix44 72 | mat-common 73 | 74 | thi.ng.geom.quaternion.Quat4 75 | #{:conj :dot :inv :mag :mat :math :mix :norm :scale :vtx} 76 | 77 | thi.ng.geom.vector.Vec2 78 | vec-common 79 | 80 | thi.ng.geom.vector.Vec3 81 | (conj vec-common :rot3d) 82 | })))) 83 | -------------------------------------------------------------------------------- /test/thi/ng/geom/test/mesh/core.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.test.mesh.core 2 | #?(:cljs 3 | (:require-macros 4 | [cemerick.cljs.test :refer (is deftest with-test run-tests testing)])) 5 | (:require 6 | [thi.ng.geom.core :as g] 7 | [thi.ng.geom.vector :refer [vec2 vec3]] 8 | [thi.ng.geom.types] 9 | [thi.ng.geom.aabb :as a] 10 | [thi.ng.geom.circle :as c] 11 | [thi.ng.geom.rect :as r] 12 | [thi.ng.geom.sphere :as s] 13 | [thi.ng.geom.triangle :as t] 14 | [thi.ng.math.core :as m] 15 | #?(:clj 16 | [clojure.test :refer :all] 17 | :cljs 18 | [cemerick.cljs.test]))) 19 | 20 | (deftest test-main 21 | (is true "is true")) 22 | -------------------------------------------------------------------------------- /test/thi/ng/geom/test/physics/core.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.test.physics.core 2 | #?(:cljs 3 | (:require-macros 4 | [cemerick.cljs.test :refer (is deftest with-test run-tests testing)])) 5 | (:require 6 | [thi.ng.geom.core :as g] 7 | [thi.ng.geom.vector :refer [vec2 vec3]] 8 | [thi.ng.geom.physics.core :as ph] 9 | [thi.ng.math.core :as m] 10 | #?(:clj 11 | [clojure.test :refer :all] 12 | :cljs 13 | [cemerick.cljs.test]))) 14 | 15 | (deftest test-main 16 | (is true "is true")) 17 | -------------------------------------------------------------------------------- /test/thi/ng/geom/test/svg/core.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.test.svg.core 2 | #?(:cljs 3 | (:require-macros 4 | [cemerick.cljs.test :refer (is deftest with-test run-tests testing)])) 5 | (:require 6 | [thi.ng.geom.core :as g] 7 | [thi.ng.geom.vector :refer [vec2 vec3]] 8 | [thi.ng.geom.svg.core :as svg] 9 | [thi.ng.math.core :as m] 10 | #?(:clj 11 | [clojure.test :refer :all] 12 | :cljs 13 | [cemerick.cljs.test]))) 14 | 15 | (deftest test-main 16 | (is true "is true")) 17 | -------------------------------------------------------------------------------- /test/thi/ng/geom/test/types/bezier.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.test.types.bezier 2 | #?(:cljs 3 | (:require-macros 4 | [cemerick.cljs.test :refer (is deftest)])) 5 | (:require 6 | [thi.ng.math.core :as m] 7 | [thi.ng.geom.core :as g] 8 | [thi.ng.geom.types] 9 | [thi.ng.geom.bezier :as b] 10 | [thi.ng.geom.vector :as v] 11 | #?(:clj 12 | [clojure.test :refer :all] 13 | :cljs 14 | [cemerick.cljs.test]))) 15 | 16 | (deftest test-flip 17 | (let [bezier (b/bezier2 [(v/vec2) (v/vec2 2 2) (v/vec2 4 0)]) 18 | flip-bezier (g/flip bezier)] 19 | (is (m/delta= (g/point-at bezier 0.4) (v/vec2 1.6 1.6))) 20 | (is (m/delta= (g/point-at flip-bezier 0.6) (v/vec2 1.6 1.6))) 21 | (is (m/delta= (g/point-at bezier 0.5) (g/point-at flip-bezier 0.5))) 22 | (is (m/delta= (g/point-at bezier 0.1) (g/point-at flip-bezier 0.9)))) 23 | (let [bezier (b/bezier3 [(v/vec3) (v/vec3 2 2 2) (v/vec3 4 0 0)]) 24 | flip-bezier (g/flip bezier)] 25 | (is (m/delta= (g/point-at bezier 0.6) (v/vec3 2.4 1.6 1.6))) 26 | (is (m/delta= (g/point-at flip-bezier 0.4) (v/vec3 2.4 1.6 1.6))) 27 | (is (m/delta= (g/point-at bezier 0.5) (g/point-at flip-bezier 0.5))) 28 | (is (m/delta= (g/point-at bezier 0.1) (g/point-at flip-bezier 0.9))))) 29 | -------------------------------------------------------------------------------- /test/thi/ng/geom/test/types/cuboid.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.test.types.cuboid 2 | #?(:cljs 3 | (:require-macros 4 | [cemerick.cljs.test :refer [is deftest]])) 5 | (:require 6 | [thi.ng.math.core :as m] 7 | [thi.ng.geom.core :as g] 8 | [thi.ng.geom.utils :as gu] 9 | [thi.ng.geom.vector :refer [vec3]] 10 | [thi.ng.geom.matrix :refer [M44]] 11 | [thi.ng.geom.types] 12 | [thi.ng.geom.aabb :as a] 13 | [thi.ng.geom.plane :as pl] 14 | [thi.ng.geom.cuboid :as cu] 15 | [thi.ng.geom.sphere :as s] 16 | [thi.ng.geom.gmesh :as gm] 17 | [thi.ng.geom.basicmesh :as bm] 18 | [thi.ng.geom.triangle :as t] 19 | #?(:clj 20 | [clojure.test :refer :all] 21 | :cljs 22 | [cemerick.cljs.test]))) 23 | 24 | (deftest test-ctors 25 | (is true)) 26 | 27 | (deftest test-impls 28 | (is true)) 29 | -------------------------------------------------------------------------------- /test/thi/ng/geom/test/types/line.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.test.types.line 2 | #?(:cljs 3 | (:require-macros 4 | [cemerick.cljs.test :refer (is deftest)])) 5 | (:require 6 | [thi.ng.math.core :as m] 7 | [thi.ng.geom.core :as g] 8 | [thi.ng.geom.types] 9 | [thi.ng.geom.line :as l] 10 | [thi.ng.geom.vector :as v] 11 | #?(:clj 12 | [clojure.test :refer :all] 13 | :cljs 14 | [cemerick.cljs.test]))) 15 | 16 | (deftest test-flip 17 | (let [line (l/line2 (v/vec2) (v/vec2 1 10)) 18 | flip-line (g/flip line)] 19 | (is (m/delta= (g/point-at line 0.4) (v/vec2 0.4 4))) 20 | (is (m/delta= (g/point-at flip-line 0.6) (v/vec2 0.4 4))) 21 | (is (m/delta= (g/point-at line 0.5) (g/point-at flip-line 0.5))) 22 | (is (m/delta= (g/point-at line 0.1) (g/point-at flip-line 0.9)))) 23 | (let [line (l/line3 (v/vec3) (v/vec3 1 10 1)) 24 | flip-line (g/flip line)] 25 | (is (m/delta= (g/point-at line 0.4) (v/vec3 0.4 4 0.4))) 26 | (is (m/delta= (g/point-at flip-line 0.6) (v/vec3 0.4 4 0.4))) 27 | (is (m/delta= (g/point-at line 0.5) (g/point-at flip-line 0.5))) 28 | (is (m/delta= (g/point-at line 0.1) (g/point-at flip-line 0.9))))) 29 | -------------------------------------------------------------------------------- /test/thi/ng/geom/test/types/polygon.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.test.types.polygon 2 | #?(:cljs 3 | (:require-macros 4 | [cemerick.cljs.test :refer (is deftest)])) 5 | (:require 6 | [thi.ng.geom.core :as g] 7 | [thi.ng.geom.vector :refer [vec2]] 8 | [thi.ng.geom.types] 9 | [thi.ng.geom.polygon :as p] 10 | #?(:clj 11 | [clojure.test :refer :all] 12 | :cljs 13 | [cemerick.cljs.test]))) 14 | 15 | (deftest test-flip 16 | (let [poly (p/polygon2 [[0 0] [1 0] [1 1] [0 1]]) 17 | flipped-poly (g/flip poly)] 18 | (is (= (-> poly g/as-mesh g/faces count) 19 | (-> flipped-poly g/as-mesh g/faces count)) 20 | "flipped polygon tesselates to same number of faces"))) 21 | -------------------------------------------------------------------------------- /test/thi/ng/geom/test/types/utils.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.test.types.utils 2 | #?(:cljs 3 | (:require-macros 4 | [cemerick.cljs.test :refer (is deftest with-test run-tests testing)])) 5 | (:require 6 | [thi.ng.geom.core :as g] 7 | [thi.ng.geom.vector :refer [vec2 vec3]] 8 | [thi.ng.geom.types] 9 | [thi.ng.geom.aabb :as a] 10 | [thi.ng.geom.circle :as c] 11 | [thi.ng.geom.rect :as r] 12 | [thi.ng.geom.sphere :as s] 13 | [thi.ng.geom.triangle :as t] 14 | [thi.ng.geom.utils :as gu] 15 | [thi.ng.math.core :as m] 16 | #?(:clj 17 | [clojure.test :refer :all] 18 | :cljs 19 | [cemerick.cljs.test]))) 20 | 21 | (defn bounds= 22 | [a b] (and (m/delta= (get a :p) (get b :p)) (m/delta= (get a :size) (get b :size)))) 23 | 24 | (deftest test-fit-into-aabb 25 | (let [b1 (a/aabb (vec3 10 20 30) (vec3 1))] 26 | (is (bounds= 27 | (a/aabb) 28 | (gu/coll-bounds (gu/fit-all-into-bounds (a/aabb) [(s/sphere -1 1) (a/aabb 2 1)]))) 29 | "fit 1") 30 | (is (bounds= 31 | (a/aabb [0.5 1.5 0] [1 1 5]) 32 | (gu/coll-bounds (gu/fit-all-into-bounds (a/aabb 2 4 5) [(s/sphere 1 1) (a/aabb [0 1 9] 1)]))) 33 | "fit 2") 34 | (is (bounds= 35 | (a/aabb (vec3 10.25 20.25 30) (vec3 0.5 0.5 1)) 36 | (gu/coll-bounds (gu/fit-all-into-bounds b1 [(t/triangle3 [[0 0 -1] [1 0 1] [1 1 0]])]))) 37 | "fit 3") 38 | (is (bounds= 39 | b1 40 | (gu/coll-bounds (gu/fit-all-into-bounds b1 [(t/triangle3 [[-1 0 -1] [0 0 0] [0 1 0]])]))) 41 | "fit 4") 42 | )) 43 | 44 | (deftest test-fit-into-rect 45 | (let [b1 (r/rect (vec2 10 20) 1)] 46 | (is (bounds= 47 | (r/rect) 48 | (gu/coll-bounds (gu/fit-all-into-bounds (r/rect) [(c/circle (vec2 -1) 1) (r/rect (vec2 2) 1)]))) 49 | "fit 1") 50 | (is (bounds= 51 | (r/rect (vec2 10.25 20) 0.5 1) 52 | (gu/coll-bounds (gu/fit-all-into-bounds b1 [(t/triangle2 [[0 -1] [1 0] [0 1]])]))) 53 | "fit 2") 54 | (is (bounds= 55 | b1 56 | (gu/coll-bounds (gu/fit-all-into-bounds b1 [(t/triangle2 [[-1 0] [0 0] [0 1]])]))) 57 | "fit 3") 58 | )) 59 | -------------------------------------------------------------------------------- /test/thi/ng/geom/test/viz/core.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.test.viz.core 2 | (:require 3 | [thi.ng.geom.core :as g] 4 | [thi.ng.geom.viz.core :as viz] 5 | [thi.ng.geom.svg.core :as svg] 6 | [thi.ng.math.core :as m] 7 | #?(:clj 8 | [clojure.test :refer :all] 9 | :cljs 10 | [cemerick.cljs.test :refer-macros [is deftest]]))) 11 | 12 | (deftest test-main 13 | (is true "is true")) 14 | -------------------------------------------------------------------------------- /test/thi/ng/geom/test/voxel/core.cljc: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geom.test.voxel.core 2 | #?(:cljs 3 | (:require-macros 4 | [cemerick.cljs.test :refer (is deftest with-test run-tests testing)])) 5 | (:require 6 | [thi.ng.geom.core :as g] 7 | [thi.ng.geom.vector :refer [vec3]] 8 | [thi.ng.geom.voxel.svo :as svo] 9 | [thi.ng.geom.voxel.isosurface :as iso] 10 | #?(:clj 11 | [clojure.test :refer :all] 12 | :cljs 13 | [cemerick.cljs.test]))) 14 | 15 | (deftest test-main 16 | (is true "is true")) 17 | -------------------------------------------------------------------------------- /update-changelog.sh: -------------------------------------------------------------------------------- 1 | echo -e "** $2 - `date +%Y-%m-%d`\n" > CHANGELOG.$$ 2 | git log $1...$2 --pretty=format:'| [[https://github.com/thi-ng/geom/commit/%H][%h]] | %s |' >> CHANGELOG.$$ 3 | echo -e "\n" >> CHANGELOG.$$ 4 | cat CHANGELOG.org >> CHANGELOG.$$ 5 | mv CHANGELOG.$$ CHANGELOG.org 6 | --------------------------------------------------------------------------------