i'm an idiot: let threads consume working queue!
[raymarch.git] / objfn.d
blobcf471cdd46f87f07e71fad347c2368cf0a96f458
1 module objfn;
3 import vecs;
6 // lerp
7 Vec3 mix() (in auto ref Vec3 v0, in auto ref Vec3 v1, RmFloat t) {
8 pragma(inline, true);
9 immutable RmFloat t1 = rmFloat!1.0-t;
10 return Vec3(
11 t1*v0.x+t*v1.x,
12 t1*v0.y+t*v1.y,
13 t1*v0.z+t*v1.z,
18 RmFloat mix() (RmFloat v0, RmFloat v1, RmFloat a) {
19 pragma(inline, true);
20 immutable RmFloat t1 = rmFloat!1.0-t;
21 return t1*v0+t*v1;
25 // hermite interpolation
26 RmFloat smoothstep() (RmFloat edge0, RmFloat edge1, RmFloat x) {
27 static if (__VERSION__ > 2067) pragma(inline, true);
28 immutable RmFloat t = clamp((x-edge0)/(edge1-edge0), rmFloat!0.0, rmFloat!1.0);
29 return t*t*(rmFloat!3.0-rmFloat!2.0*t);
33 RmFloat clamp() (RmFloat x, RmFloat minv, RmFloat maxv) {
34 //pragma(inline, true);
35 import std.algorithm : min, max;
36 return max(min(x, maxv), minv);
40 RmFloat fract() (RmFloat x) {
41 //pragma(inline, true);
42 import std.math : floor;
43 return x-floor(x);
47 // is this correct?
48 RmFloat mod() (RmFloat x, RmFloat y) {
49 //pragma(inline, true);
50 import std.math : floor;
51 // x minus the product of y and floor(x/y)
52 return x-y*floor(x/y);
56 // ////////////////////////////////////////////////////////////////////////// //
57 // raymarch composition functions
58 // repetition
59 RmFloat objopRep(string objfunc) (in auto ref Vec3 pp, in auto ref Vec3 c) {
60 static if (__VERSION__ > 2067) pragma(inline, true);
61 // the following MUST be `p`
62 immutable auto p = Vec3(mod(p.x, c.x), mod(p.y, c.y), mod(p.z, c.z))-c*rmFloat!0.5;
63 return mixin(objfunc);
66 RmFloat objopScale(string objfunc) (in auto ref Vec3 pp, RmFloat s) {
67 static if (__VERSION__ > 2067) pragma(inline, true);
68 immutable auto p = pp/s;
69 return mixin(objfunc)*s;
72 RmFloat objopShift(string objfunc) (in auto ref Vec3 pp, in auto ref Vec3 sv) {
73 static if (__VERSION__ > 2067) pragma(inline, true);
74 immutable auto p = pp+sv;
75 return mixin(objfunc);
78 // rotation/translation
80 Vec3 objopTx(string objfunc) (in auto ref Vec3 pp, in auto ref Mat4 mt) {
81 immutable auto p = m.invert*pp;
82 return mixin(objfunc);
86 RmFloat objopUnion() (RmFloat obj0, RmFloat obj1) {
87 static if (__VERSION__ > 2067) pragma(inline, true);
88 return (obj0 < obj1 ? obj0 : obj1); // min
91 RmFloat objopSub() (RmFloat a, RmFloat b) {
92 static if (__VERSION__ > 2067) pragma(inline, true);
93 return (a > -b ? a : -b);
96 // intersection
97 RmFloat objopInter() (RmFloat a, RmFloat b) {
98 static if (__VERSION__ > 2067) pragma(inline, true);
99 return (obj0 > obj1 ? obj0 : obj1); // max
102 // returns object number
103 int objopUnion() (ref RmFloat dest, RmFloat obj0, RmFloat obj1, int oid0, int oid1) {
104 static if (__VERSION__ > 2067) pragma(inline, true);
105 if (obj0 < obj1) {
106 dest = obj0;
107 return oid0;
108 } else {
109 dest = obj1;
110 return oid1;
114 // returns object number
115 int objopSub() (ref RmFloat dest, RmFloat a, RmFloat b, int oid0, int oid1) {
116 static if (__VERSION__ > 2067) pragma(inline, true);
117 b = -b;
118 if (a > b) {
119 dest = a;
120 return oid0;
121 } else {
122 dest = b;
123 return oid1;
127 // returns object number
128 int objopInter() (ref RmFloat dest, RmFloat obj0, RmFloat obj1, int oid0, int oid1) {
129 static if (__VERSION__ > 2067) pragma(inline, true);
130 if (obj0 > obj1) {
131 dest = obj0;
132 return oid0;
133 } else {
134 dest = obj1;
135 return oid1;
140 // ////////////////////////////////////////////////////////////////////////// //
141 // raymarch composition functions that doesn't preserve distance
142 // you will probably need to decrease your step size, if you are using a raymarcher to sample this
143 // the displacement example below is using sin(20*p.x)*sin(20*p.y)*sin(20*p.z) as displacement pattern
145 RmFloat objopDisplace(string objfunc) (in auto ref Vec3 p) {
146 RmFloat d1 = mixin(objfunc);
147 RmFloat d2 = displacement(p);
148 return d1+d2;
153 // exponential smooth min (k = 32);
154 RmFloat sminExp (RmFloat a, RmFloat b, RmFloat k) {
155 import std.math : exp, log;
156 RmFloat res = exp(-k*a)+exp(-k*b);
157 return -log(res)/k;
160 // power smooth min (k = 8);
161 RmFloat sminPow (RmFloat a, RmFloat b, RmFloat k) {
162 import std.math : pow;
163 a = pow(a, k);
164 b = pow(b, k);
165 return pow((a*b)/(a+b), rmFloat!1.0/k);
168 // polynomial smooth min (k = 0.1);
170 RmFloat sminPoly (RmFloat a, RmFloat b, RmFloat k) {
171 import std.math : clamp, exp, log;
172 RmFloat h = clamp(rmFloat!0.5+rmFloat!0.5*(b-a)/k, rmFloat!0.0, rmFloat!1.0);
173 return mix(b, a, h)-k*h*(rmFloat!1.0-h);
177 RmFloat objopBlend(alias sminfn, string objfunc0, string objfunc1) (in auto ref Vec3 p) {
178 RmFloat d1 = mixin(objfunc0);
179 RmFloat d2 = mixin(objfunc1);
180 return sminfn(d1, d2);
184 RmFloat objopTwist (string objfunc) (in auto ref Vec3 pp) {
185 import std.math : cos, sin;
186 immutable RmFloat c = cos(rmFloat!10.0*pp.z+rmFloat!10.0);
187 immutable RmFloat s = sin(rmFloat!10.0*pp.z+rmFloat!10.0);
188 //immutable auto m = Mat2(c, -s, s, c);
189 // Mat2
191 RmFloat[2][2] mm = [
192 [c, -s],
193 [s, c]
196 // multiple matrix2 by vector2
197 //immutable auto p = Vec3(m*p.xz, p.y);
199 RmFloat v2x = mm.ptr[0].ptr[0]*pp.x+mm.ptr[0].ptr[1]*pp.z;
200 RmFloat v2y = mm.ptr[1].ptr[0]*pp.x+mm.ptr[1].ptr[1]*pp.z;
202 RmFloat v2x = c*pp.x-s*pp.y;
203 RmFloat v2y = s*pp.x+c*pp.y;
204 immutable auto p = Vec3(v2x, v2y, pp.z);
205 return mixin(objfunc);
209 // ////////////////////////////////////////////////////////////////////////// //
210 import std.algorithm : maxf = max, minf = min;
212 // raymarch object functions
213 // as our functions are very simple, use strings and `mixin` to simulate inlining ;-)
214 enum floorHeight = rmFloat!2.0;
215 enum objfuncFloor = q{(p.y+floorHeight)};
217 // n must be normalized (invalid formula, broken by k8)
218 static immutable planeN = Vec3(rmFloat!0.0, rmFloat!0.0, rmFloat!0.0);
219 enum planeD = rmFloat!12.0;
220 enum objfuncPlane = q{(p.dot(planeN)+planeD)};
222 enum torusOuterRadius = rmFloat!2.4;
223 enum torusRadius = rmFloat!0.6;
224 enum objfuncTorus = q{(Vec3.length(p.length-torusOuterRadius, p.z)-torusRadius)};
226 // sphere, signed
227 enum shpereRadius = rmFloat!1.9;
228 enum objfuncSphere = q{(p.length-shpereRadius)};
230 // round box, unsigned
231 static immutable roundboxSize = Vec3(rmFloat!2.0, rmFloat!0.7, rmFloat!2.0);
232 enum roundboxRadius = rmFloat!0.2;
233 enum objfuncRoundbox = q{((p.abs-roundboxSize).minmax!"max"(rmFloat!0.0).length-roundboxRadius)};
235 // box, signed (interestingly, this is more complex than round box ;-)
236 static immutable boxSize = Vec3(rmFloat!2.0, rmFloat!0.7, rmFloat!2.0);
237 __gshared Vec3 boxTemp;
238 enum objfuncBox = q{(boxTemp = p.abs-boxSize, minf(maxf(boxTemp.x, maxf(boxTemp.y, boxTemp.z)), rmFloat!0.0)+boxTemp.minmax!"max"(rmFloat!0.0).length)};
240 // box, unsigned
241 static immutable boxuSize = Vec3(rmFloat!2.0, rmFloat!0.7, rmFloat!2.0);
242 enum objfuncBoxu = q{((p.abs-boxuSize).minmax!"max"(rmFloat!0.0).length)};
244 // cylinder, signed
245 static immutable cylParams = Vec3(rmFloat!0.0, rmFloat!0.0, rmFloat!0.6); // x, y, width
246 enum objfuncCyl = q{(Vec3.length(p.x-cylParams.x, p.z-cylParams.y)-cylParams.z)};