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 static hat.KernelContext.*;
32 import hat.NDRange;
33 import hat.backend.Backend;
34 import hat.buffer.F32Array;
35 import hat.types.F32;
36 import hat.types.mat2;
37 import hat.types.vec2;
38 import hat.types.vec3;
39 import hat.types.vec4;
40 import jdk.incubator.code.Reflect;
41 import optkl.ifacemapper.MappableIface;
42 import hat.buffer.Uniforms;
43 import shade.ShaderViewer;
44 import java.lang.invoke.MethodHandles;
45
46 import static hat.types.F32.PIx2;
47 import static hat.types.F32.abs;
48 import static hat.types.F32.cos;
49 import static hat.types.F32.fract;
50 import static hat.types.F32.log;
51 import static hat.types.F32.max;
52 import static hat.types.F32.min;
53 import static hat.types.F32.sin;
54 import static hat.types.F32.smoothstep;
55 import static hat.types.mat2.mat2;
56 import static hat.types.vec2.abs;
57 import static hat.types.vec2.add;
58 import static hat.types.vec2.div;
59 import static hat.types.vec2.dot;
60 import static hat.types.vec2.floor;
61 import static hat.types.vec2.fract;
62 import static hat.types.vec2.length;
63 import static hat.types.vec2.mul;
64 import static hat.types.vec2.sub;
65 import static hat.types.vec2.vec2;
66 import static hat.types.vec3.add;
67 import static hat.types.vec3.cos;
68 import static hat.types.vec3.mix;
69 import static hat.types.vec3.mul;
70 import static hat.types.vec3.pow;
71 import static hat.types.vec3.vec3;
72 import static hat.types.vec4.normalize;
73 import static hat.types.vec4.vec4;
74
75 public class TruchetShader {
76
77 @Reflect public static mat2 rot(float a) {
78 // mat2 rot(float a) {return mat2(cos(a),sin(a),-sin(a),cos(a));}
79 return mat2(cos(a), sin(a), -sin(a), cos(a));
80 }
81
82 @Reflect public static vec3 hue(float t, float f) {
83 // return f+f*cos(PI2*t*(vec3(1,.75,.75)+vec3(.96,.57,.12)));
84 return add(f, mul(f, cos(mul(PIx2 * t,
85 add(vec3(1f, .75f, .75f), vec3(.96f, .57f, .12f))
86 ))));
87 }
88
89 @Reflect public static float hash21(vec2 a) {
90 // return fract(sin(dot(a,vec2(27.69,32.58)))*43758.53);
91 return fract(sin(dot(a, vec2(27.69f, 32.58f))) * 43758.53f);
92 }
93
94 @Reflect public static float box(vec2 p, vec2 b) {
95 //vec2 d = abs(p)-b;
96 vec2 d = sub(abs(p), b);
97 // return length(max(d,0.)) + min(max(d.x,d.y),0.);}
98 return length(vec2.max(d, 0f)) + min(max(d.x(), d.y()), 0f);
99 }
100
101 @Reflect public static vec2 pattern(vec2 p, float sc) {
102 mat2 r90 = rot(1.5707f);
103 // vec2 uv = p;
104
105 //vec2 id = floor(p*sc);
106 vec2 id = floor(mul(p, sc));
107 //p = fract(p*sc)-.5;
108 p = sub(fract(mul(p, sc)), .5f);
109
110 float rnd = hash21(id);
111
112 // turn tiles
113 if (rnd > .5f) {
114 p = mul(p, r90);
115 }
116 rnd = fract(rnd * 32.54f);
117 if (rnd > .4f) {
118 p = mul(p, r90);
119 }
120 if (rnd > .8f) {
121 p = mul(p, r90);
122 }
123
124 // randomize hash for type
125 rnd = fract(rnd * 47.13f);
126
127 float tk = .075f;
128 // kind of messy and long winded
129 float d = box(sub(p, vec2(.6f, .7f)), vec2(.25f, .75f)) - .15f;
130 float l = box(sub(p, vec2(.7f, .5f)), vec2(.75f, .15f)) - .15f;
131 float b = box(add(p, vec2(0f, .7f)), vec2(.05f, .25f)) - .15f;
132 float r = box(add(p, vec2(.6f, 0f)), vec2(.15f, .05f)) - .15f;
133 d = abs(d) - tk;
134
135 if (rnd > .92f) {
136 d = box(sub(p, vec2(-.6f, .5f)), vec2(.25f, .15f)) - .15f;
137 l = box(sub(p, vec2(.6f, .6f)), vec2(.25f)) - .15f;
138 b = box(add(p, vec2(.6f, .6f)), vec2(.25f)) - .15f;
139 r = box(sub(p, vec2(.6f, -.6f)), vec2(.25f)) - .15f;
140 d = abs(d) - tk;
141
142 } else if (rnd > .6f) {
143 d = F32.abs(p.x() - .2f) - tk;//length(p.x()-.2f)-tk;
144 l = box(sub(p, vec2(-.6f, .5f)), vec2(.25f, .15f)) - .15f;
145 b = box(add(p, vec2(.6f, .6f)), vec2(.25f)) - .15f;
146 r = box(sub(p, vec2(.3f, 0f)), vec2(.25f, .05f)) - .15f;
147 }
148
149 l = abs(l) - tk;
150 b = abs(b) - tk;
151 r = abs(r) - tk;
152
153 float e = min(d, min(l, min(b, r)));
154
155 if (rnd > .6f) {
156 r = max(r, -box(sub(p, vec2(.2f, .2f)), vec2(tk * 1.3f)));
157 d = max(d, -box(add(p, vec2(-.2f, .2f)), vec2(tk * 1.3f)));
158 } else {
159 l = max(l, -box(sub(p, vec2(.2f, .2f)), vec2(tk * 1.3f)));
160 }
161
162 d = min(d, min(l, min(b, r)));
163
164 return vec2(d, e);
165 }
166
167 @Reflect public static vec4 createPixel(vec2 fres, float ftime, vec2 fmouse, vec2 fragCoord){
168
169
170 vec3 color = vec3(0f);
171 // vec2 uv = (2.*F-R.xy)/max(R.x,R.y);
172 var uv = div(sub(mul(2f,fragCoord),fres),max(fres.x(),fres.y()));
173
174 // uv *= rot(T*.095);
175 // uv = mul(uv, rot(fTime * .095f));
176
177 // uv = vec2(log(length(uv)), atan(uv.y, uv.x)*6./PI2);
178 // Original.
179 //uv = vec2(log(length(uv)), atan(uv.y, uv.x))*8./6.2831853;
180
181 uv = vec2(log(length(uv)), F32.atan(uv.y(), uv.x()) * 6f / (PIx2));
182
183 float scale = 8f;
184 for (float i = 0f; i < 4f; i++) {
185 float ff = (i * .05f) + .2f;
186 // uv.x+=T*ff;
187 uv = add(uv, vec2(ftime * ff, 0f));
188
189 float fwidth = 0.0001f;
190 float px = fwidth;//fwidth(uv.x*scale);
191 // vec2 d = pattern(uv,scale);
192 vec2 d = pattern(uv, scale);
193 // vec3 clr = hue(sin(uv.x+(i*8.))*.2+.4,(.5+i)*.15);
194 vec3 clr = hue(sin(uv.x() + (i * 8f)) * .2f + .4f, (.5f + i) * .15f);
195 // C = mix(C,vec3(.001),smoothstep(px,-px,d.y-.04));
196 color = mix(color, vec3(.001f), smoothstep(px, -px, d.y() - .04f));
197 // C = mix(C,clr,smoothstep(px,-px,d.x));
198 color = mix(color, clr, smoothstep(px, -px, d.x()));
199 scale *= .5f;
200 }
201
202 // Output to screen
203 color = pow(color, vec3(.4545f));
204 return normalize(vec4(color, 1.0f));
205 }
206
207 @Reflect public static vec4 mainImage(Uniforms uniforms, vec4 fragColor, vec2 fragCoord) {
208 return createPixel(vec2(uniforms.iResolution().x(),uniforms.iResolution().y()),uniforms.iTime(),vec2(uniforms.iMouse().x(),uniforms.iMouse().y()),fragCoord);
209 }
210 @Reflect
211 public static void penumbra( @MappableIface.RO Uniforms uniforms, @MappableIface.RW F32Array f32Array) {
212 int width = (int) uniforms.iResolution().x();
213 int height = (int) uniforms.iResolution().y();
214 var fragColor = mainImage(uniforms, vec4.vec4(0f), vec2.vec2((float)(GIX() % width), (float)(height-(GIX() / width))));
215 f32Array.array(GIX() * 3, fragColor.x());
216 f32Array.array(GIX() * 3+1, fragColor.y());
217 f32Array.array(GIX() * 3+2, fragColor.z());
218 }
219
220 @Reflect
221 static public void compute(final ComputeContext computeContext, @MappableIface.RO Uniforms uniforms, @MappableIface.RO F32Array image, int width, int height) {
222 computeContext.dispatchKernel(NDRange.of1D(width * height), () -> penumbra( uniforms, image));
223 }
224
225 private static void update( Accelerator acc, Uniforms uniforms, F32Array f32Array, int width, int height) {
226 acc.compute((@Reflect Compute) cc -> compute(cc, uniforms, f32Array, width, height));
227 }
228
229 static void main(String[] args) {
230 var acc = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
231 var shader = ShaderViewer.of(acc, TruchetShader.class,1024, 1024);
232 shader.startLoop((uniforms, f32Array) -> update( acc, uniforms, f32Array, shader.view.getWidth(), shader.view.getHeight()));
233 }
234 }
235