1 /*
2 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package shade.shaders;
26
27 import hat.Accelerator;
28 import hat.Accelerator.Compute;
29 import hat.ComputeContext;
30
31 import hat.ComputeContext.Kernel;
32 import hat.KernelContext;
33 import hat.NDRange;
34 import hat.backend.Backend;
35 import hat.buffer.F32Array;
36 import hat.types.F32;
37 import hat.types.mat2;
38 import hat.types.vec2;
39 import hat.types.vec3;
40 import hat.types.vec4;
41 import jdk.incubator.code.Reflect;
42 import optkl.ifacemapper.MappableIface;
43 import hat.buffer.Uniforms;
44 import shade.ShaderViewer;
45 import java.lang.invoke.MethodHandles;
46
47 import static hat.types.F32.PIx2;
48 import static hat.types.F32.abs;
49 import static hat.types.F32.cos;
50 import static hat.types.F32.fract;
51 import static hat.types.F32.log;
52 import static hat.types.F32.max;
53 import static hat.types.F32.min;
54 import static hat.types.F32.sin;
55 import static hat.types.F32.smoothstep;
56 import static hat.types.mat2.mat2;
57 import static hat.types.vec2.abs;
58 import static hat.types.vec2.add;
59 import static hat.types.vec2.div;
60 import static hat.types.vec2.dot;
61 import static hat.types.vec2.floor;
62 import static hat.types.vec2.fract;
63 import static hat.types.vec2.length;
64 import static hat.types.vec2.mul;
65 import static hat.types.vec2.sub;
66 import static hat.types.vec2.vec2;
67 import static hat.types.vec3.add;
68 import static hat.types.vec3.cos;
69 import static hat.types.vec3.mix;
70 import static hat.types.vec3.mul;
71 import static hat.types.vec3.pow;
72 import static hat.types.vec3.vec3;
73 import static hat.types.vec4.normalize;
74 import static hat.types.vec4.vec4;
75
76 public class TruchetShader {
77
78 @Reflect public static mat2 rot(float a) {
79 // mat2 rot(float a) {return mat2(cos(a),sin(a),-sin(a),cos(a));}
80 return mat2(cos(a), sin(a), -sin(a), cos(a));
81 }
82
83 @Reflect public static vec3 hue(float t, float f) {
84 // return f+f*cos(PI2*t*(vec3(1,.75,.75)+vec3(.96,.57,.12)));
85 return add(f, mul(f, cos(mul(PIx2 * t,
86 add(vec3(1f, .75f, .75f), vec3(.96f, .57f, .12f))
87 ))));
88 }
89
90 @Reflect public static float hash21(vec2 a) {
91 // return fract(sin(dot(a,vec2(27.69,32.58)))*43758.53);
92 return fract(sin(dot(a, vec2(27.69f, 32.58f))) * 43758.53f);
93 }
94
95 @Reflect public static float box(vec2 p, vec2 b) {
96 //vec2 d = abs(p)-b;
97 vec2 d = sub(abs(p), b);
98 // return length(max(d,0.)) + min(max(d.x,d.y),0.);}
99 return length(vec2.max(d, 0f)) + min(max(d.x(), d.y()), 0f);
100 }
101
102 @Reflect public static vec2 pattern(vec2 p, float sc) {
103 mat2 r90 = rot(1.5707f);
104 // vec2 uv = p;
105
106 //vec2 id = floor(p*sc);
107 vec2 id = floor(mul(p, sc));
108 //p = fract(p*sc)-.5;
109 p = sub(fract(mul(p, sc)), .5f);
110
111 float rnd = hash21(id);
112
113 // turn tiles
114 if (rnd > .5f) {
115 p = mul(p, r90);
116 }
117 rnd = fract(rnd * 32.54f);
118 if (rnd > .4f) {
119 p = mul(p, r90);
120 }
121 if (rnd > .8f) {
122 p = mul(p, r90);
123 }
124
125 // randomize hash for type
126 rnd = fract(rnd * 47.13f);
127
128 float tk = .075f;
129 // kind of messy and long winded
130 float d = box(sub(p, vec2(.6f, .7f)), vec2(.25f, .75f)) - .15f;
131 float l = box(sub(p, vec2(.7f, .5f)), vec2(.75f, .15f)) - .15f;
132 float b = box(add(p, vec2(0f, .7f)), vec2(.05f, .25f)) - .15f;
133 float r = box(add(p, vec2(.6f, 0f)), vec2(.15f, .05f)) - .15f;
134 d = abs(d) - tk;
135
136 if (rnd > .92f) {
137 d = box(sub(p, vec2(-.6f, .5f)), vec2(.25f, .15f)) - .15f;
138 l = box(sub(p, vec2(.6f, .6f)), vec2(.25f)) - .15f;
139 b = box(add(p, vec2(.6f, .6f)), vec2(.25f)) - .15f;
140 r = box(sub(p, vec2(.6f, -.6f)), vec2(.25f)) - .15f;
141 d = abs(d) - tk;
142
143 } else if (rnd > .6f) {
144 d = F32.abs(p.x() - .2f) - tk;//length(p.x()-.2f)-tk;
145 l = box(sub(p, vec2(-.6f, .5f)), vec2(.25f, .15f)) - .15f;
146 b = box(add(p, vec2(.6f, .6f)), vec2(.25f)) - .15f;
147 r = box(sub(p, vec2(.3f, 0f)), vec2(.25f, .05f)) - .15f;
148 }
149
150 l = abs(l) - tk;
151 b = abs(b) - tk;
152 r = abs(r) - tk;
153
154 float e = min(d, min(l, min(b, r)));
155
156 if (rnd > .6f) {
157 r = max(r, -box(sub(p, vec2(.2f, .2f)), vec2(tk * 1.3f)));
158 d = max(d, -box(add(p, vec2(-.2f, .2f)), vec2(tk * 1.3f)));
159 } else {
160 l = max(l, -box(sub(p, vec2(.2f, .2f)), vec2(tk * 1.3f)));
161 }
162
163 d = min(d, min(l, min(b, r)));
164
165 return vec2(d, e);
166 }
167
168 @Reflect public static vec4 createPixel(vec2 fres, float ftime, vec2 fmouse, vec2 fragCoord){
169
170
171 vec3 color = vec3(0f);
172 // vec2 uv = (2.*F-R.xy)/max(R.x,R.y);
173 var uv = div(sub(mul(2f,fragCoord),fres),max(fres.x(),fres.y()));
174
175 // uv *= rot(T*.095);
176 // uv = mul(uv, rot(fTime * .095f));
177
178 // uv = vec2(log(length(uv)), atan(uv.y, uv.x)*6./PI2);
179 // Original.
180 //uv = vec2(log(length(uv)), atan(uv.y, uv.x))*8./6.2831853;
181
182 uv = vec2(log(length(uv)), F32.atan(uv.y(), uv.x()) * 6f / (PIx2));
183
184 float scale = 8f;
185 for (float i = 0f; i < 4f; i++) {
186 float ff = (i * .05f) + .2f;
187 // uv.x+=T*ff;
188 uv = add(uv, vec2(ftime * ff, 0f));
189
190 float fwidth = 0.0001f;
191 float px = fwidth;//fwidth(uv.x*scale);
192 // vec2 d = pattern(uv,scale);
193 vec2 d = pattern(uv, scale);
194 // vec3 clr = hue(sin(uv.x+(i*8.))*.2+.4,(.5+i)*.15);
195 vec3 clr = hue(sin(uv.x() + (i * 8f)) * .2f + .4f, (.5f + i) * .15f);
196 // C = mix(C,vec3(.001),smoothstep(px,-px,d.y-.04));
197 color = mix(color, vec3(.001f), smoothstep(px, -px, d.y() - .04f));
198 // C = mix(C,clr,smoothstep(px,-px,d.x));
199 color = mix(color, clr, smoothstep(px, -px, d.x()));
200 scale *= .5f;
201 }
202
203 // Output to screen
204 color = pow(color, vec3(.4545f));
205 return normalize(vec4(color, 1.0f));
206 }
207
208 @Reflect public static vec4 mainImage(Uniforms uniforms, vec4 fragColor, vec2 fragCoord) {
209 return createPixel(vec2(uniforms.iResolution().x(),uniforms.iResolution().y()),uniforms.iTime(),vec2(uniforms.iMouse().x(),uniforms.iMouse().y()),fragCoord);
210 }
211 @Reflect
212 public static void penumbra(@MappableIface.RO KernelContext kc, @MappableIface.RO Uniforms uniforms, @MappableIface.RW F32Array f32Array) {
213 int width = (int) uniforms.iResolution().x();
214 int height = (int) uniforms.iResolution().y();
215 var fragColor = mainImage(uniforms, vec4.vec4(0f), vec2.vec2((float)(kc.gix % width), (float)(height-(kc.gix / width))));
216 f32Array.array(kc.gix * 3, fragColor.x());
217 f32Array.array(kc.gix * 3+1, fragColor.y());
218 f32Array.array(kc.gix * 3+2, fragColor.z());
219 }
220
221 @Reflect
222 static public void compute(final ComputeContext computeContext, @MappableIface.RO Uniforms uniforms, @MappableIface.RO F32Array image, int width, int height) {
223 computeContext.dispatchKernel(NDRange.of1D(width * height), (@Reflect Kernel) kc -> penumbra(kc, uniforms, image));
224 }
225
226 private static void update( Accelerator acc, Uniforms uniforms, F32Array f32Array, int width, int height) {
227 acc.compute((@Reflect Compute) cc -> compute(cc, uniforms, f32Array, width, height));
228 }
229
230 static void main(String[] args) {
231 var acc = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
232 var shader = ShaderViewer.of(acc, TruchetShader.class,1024, 1024);
233 shader.startLoop((uniforms, f32Array) -> update( acc, uniforms, f32Array, shader.view.getWidth(), shader.view.getHeight()));
234 }
235 }
236