├── .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 |
--------------------------------------------------------------------------------
/assets/svg/svgdemo04-spiral.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/assets/svg/svgdemo06-decorators.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/assets/viz/intervals-3.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/assets/viz/intervals.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/assets/viz/radarplot-minmax.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------