2 module xmain_mt
/* is aliced*/;
13 // ////////////////////////////////////////////////////////////////////////// //
14 //version = use_vsync;
17 // ////////////////////////////////////////////////////////////////////////// //
18 enum WindowTitle
= "ShaderToy emulator";
21 // ////////////////////////////////////////////////////////////////////////// //
22 //#extension GL_ARB_compatibility : enable
25 uniform vec3 iResolution
; // viewport resolution (in pixels)
26 uniform vec4 iMouse
; // mouse pixel coords
27 uniform
float iGlobalTime
; // shader playback time (in seconds)
28 uniform
float iGlobalFrame
; // ???
29 uniform
float iTimeDelta
; // how long last frame took to render, in seconds (TODO)
30 uniform
float iFrame
; // buffer shaders seems to have this
31 uniform vec3 iChannelResolution
[4]; // channel resolution (in pixels)
32 uniform
float iChannelTime
[4]; // channel playback time (in sec)
33 uniform vec4 iDate
; // (year, month, day, time in seconds)
34 //uniform float iGlobalDelta; // i don't know
35 //uniform float iSampleRate; // sound sample rate (i.e., 44100)
40 vec2 fc
= vec2(gl_FragCoord
.x
, gl_FragCoord
.y
);
41 mainImage(gl_FragColor
, fc
);
46 // ////////////////////////////////////////////////////////////////////////// //
51 __gshared SimpleWindow sdwindow
;
54 public enum vlWidth
= 800;
55 public enum vlHeight
= 500;
56 public enum scale
= 1;
58 public enum vlEffectiveWidth
= vlWidth
*scale
;
59 public enum vlEffectiveHeight
= vlHeight
*scale
;
62 // ////////////////////////////////////////////////////////////////////////// //
63 __gshared string basePath
;
64 __gshared string shaderFile
;
65 __gshared string shaderSource
;
66 __gshared Texture
[4] textures
; // 4 texture samplers
67 __gshared TextureCube
[4] texturesCube
; // 4 cube texture samplers (can be null)
68 __gshared Texture texMain
;
69 __gshared Shader shader
;
70 __gshared Shader
[4] shaderbufs
; // a,b,c,d
71 __gshared
int[4] bufmap
= -1; // bufmap[texnum] == bufN (or -1)
72 __gshared FBO
[4] buffbos
;
73 __gshared GLuint listQuad
;
76 // ////////////////////////////////////////////////////////////////////////// //
78 static auto loadShader (string sname
, string src
) {
79 string spre
= ShaderPre
~"\n";
80 // setup texture samplers
81 foreach (int idx
; 0..4) {
82 import std
.string
: format
;
83 if (texturesCube
[idx
] !is null) {
84 spre
~= "uniform samplerCube iChannel%s;\n".format(idx
);
86 spre
~= "uniform sampler2D iChannel%s;\n".format(idx
);
90 auto shader
= new Shader(sname
, spre
~src
~"\n"~ShaderMain
);
92 shader
["iResolution"] = SVec3F(vlWidth
, vlHeight
, 0.0f);
93 foreach (int idx
; 0..4) {
94 char[9] vname
= "iChannel0";
95 vname
[$-1] = cast(char)('0'+idx
);
96 int bufidx
= bufmap
[idx
];
97 if (bufidx
< 0) bufidx
= idx
;
98 shader
[vname
[]] = cast(int)bufidx
;
100 auto cri
= shader
.varId("iChannelResolution");
101 float[3][4] cres
= void;
102 foreach (int idx
; 0..4) {
103 if (texturesCube
[idx
]) {
104 cres
[idx
][0] = texturesCube
[idx
].width
;
105 cres
[idx
][1] = texturesCube
[idx
].height
;
107 int bufidx
= bufmap
[idx
];
108 if (bufidx
< 0) bufidx
= idx
;
109 cres
[idx
][0] = textures
[bufidx
].width
;
110 cres
[idx
][1] = textures
[bufidx
].height
;
114 glUniform3fv(cri
, 4, &cres
[0][0]);
119 glEnable(GL_TEXTURE_2D
);
120 glDisable(GL_LIGHTING
);
121 glDisable(GL_DITHER
);
123 glDisable(GL_DEPTH_TEST
);
128 import std
.stdio
: File
;
130 foreach (/*immutable*/ line
; File(shaderFile
.setExtension(".tex")).byLine
) {
133 if (line
== "bufa" || line
== "bufb" || line
== "bufc" || line
== "bufd") {
135 int bufidx
= line
[3]-'a';
136 bufmap
[num
] = bufidx
;
137 tex
= new Texture(vlWidth
, vlHeight
, true, Texture
.Option
.fp
, Texture
.Option
.nearest
, Texture
.Option
.clamp
); // it's floating point, i guess
138 } else if (line
.length
> 4 && line
[0..4] == "cube") {
139 // load cubemap texture
140 import std
.string
: format
;
142 string fn
= basePath
~"/textures/cube/%s_%%s.png".format(line
);
143 auto texc
= new TextureCube(fn
);
144 texturesCube
[num
++] = texc
;
145 if (num
>= textures
.length
) break;
147 } catch (Exception e
) {
149 writeln("can't load cube texture '", line
, "'");
154 import std
.string
: format
;
156 string fn
= basePath
~"/textures/tex%s.png".format(line
);
157 tex
= new Texture(fn
);
158 } catch (Exception e
) {
160 writeln("can't load texture '", line
, "'");
164 textures
[num
++] = tex
;
165 if (num
>= textures
.length
) break;
167 } catch (Exception e
) {}
168 //foreach (immutable num; 0..4) if (textures[num] is null) textures[num] = new Texture(512, 512);
169 foreach (immutable num
; 0..4) {
170 if (textures
[num
] is null && texturesCube
[num
] is null) {
171 //textures[num] = new Texture(basePath~"/textures/tex00.png");
172 textures
[num
] = new Texture(vlWidth
, vlHeight
, true/*, Texture.Option.fp*/);
175 texMain
= new Texture(vlWidth
, vlHeight
, true);
177 foreach (int idx
; 0..4) {
178 glActiveTexture(GL_TEXTURE0
+idx
);
179 if (texturesCube
[idx
] !is null) {
180 glBindTexture(GL_TEXTURE_CUBE_MAP
, texturesCube
[idx
].tid
);
182 int bufidx
= bufmap
[idx
];
183 if (bufidx
< 0) bufidx
= idx
;
184 glBindTexture(GL_TEXTURE_2D
, textures
[bufidx
].tid
);
187 glActiveTexture(GL_TEXTURE4
);
188 glBindTexture(GL_TEXTURE_2D
, texMain
.tid
);
191 shader
= loadShader("shader", shaderSource
);
193 // load buffer shaders, if necessary
194 foreach (int idx
; 0..4) {
195 int bufidx
= bufmap
[idx
];
196 if (bufidx
< 0) continue;
197 if (shaderbufs
[bufidx
] is null) {
199 import std
.file
: readText
;
200 import std
.string
: format
;
201 import std
.path
: dirName
, setExtension
;
202 string fname
= shaderFile
.setExtension("")~"_buf%c.frag".format(cast(char)('a'+bufidx
));
203 { import std
.stdio
; writeln("reading buffer shader: '", fname
, "'"); }
204 shaderbufs
[bufidx
] = loadShader("buf%c".format(cast(char)('a'+bufidx
)), readText(fname
));
206 buffbos
[bufidx
] = new FBO(textures
[bufidx
]);
212 glMatrixMode(GL_PROJECTION);
214 glOrtho(0, vlWidth, vlHeight, 0, -1, 1);
216 orthoCamera(vlWidth
, vlHeight
);
218 glMatrixMode(GL_MODELVIEW
);
221 // create display list for quad
227 listQuad
= glGenLists(1);
228 glNewList(listQuad
, GL_COMPILE
);
230 glTexCoord2f(0.0f, 0.0f); glVertex2i(x0
, y0
); // top-left
231 glTexCoord2f(1.0f, 0.0f); glVertex2i(x1
, y0
); // top-right
232 glTexCoord2f(1.0f, 1.0f); glVertex2i(x1
, y1
); // bottom-right
233 glTexCoord2f(0.0f, 1.0f); glVertex2i(x0
, y1
); // bottom-left
237 //glDeleteLists(index, 1);
241 // ////////////////////////////////////////////////////////////////////////// //
242 __gshared
int mouseX
= 0, mouseY
= vlHeight
-1;
243 __gshared
bool mBut0
= false, mBut1
= false;
244 __gshared
float globalTime
= 0.0f, frameTime
= 0.0f;
245 __gshared
float globalFrame
= 0.0f;
246 __gshared
bool paused
= false;
247 shared int diedie
= 0;
250 // ////////////////////////////////////////////////////////////////////////// //
251 void setShaderArgs (Shader shader
) {
252 //shader["iMouse"] = SVec4F(mouseX, vlHeight-1-mouseY, cast(float)mouseX/cast(float)(vlWidth-1), cast(float)(vlHeight-1-mouseY)/cast(float)(vlHeight-1));
254 shader
["iMouse"] = SVec4F(mouseX
, vlHeight
-1-mouseY
, mouseX
, vlHeight
-1-mouseY
);
256 shader
["iMouse"] = SVec4F(mouseX
, vlHeight
-1-mouseY
, 0.0f, 0.0f);
258 //prevmouseX = mouseX;
259 //prevmouseY = (vlHeight-1-mouseY);
260 shader
["iGlobalTime"] = globalTime
;
261 shader
["iChannelTime"] = SVec4F(globalTime
, globalTime
, globalTime
, globalTime
);
262 shader
["iGlobalFrame"] = globalFrame
;
263 shader
["iFrame"] = globalFrame
;
264 shader
["iTimeDelta"] = frameTime
;
265 auto vid
= shader
.varId("iDate");
268 auto now
= Clock
.currTime
;
273 cast(float)now
.hour
*3600.0f+cast(float)now
.minute
*60.0f+cast(float)now
.second
+cast(float)now
.fracSecs
.total
!"msecs"/1000.0f
279 void renderFrame (bool paused
) {
280 // first update buffers, if any
282 foreach (int idx
; 0..4) {
283 if (auto sd
= shaderbufs
[idx
]) {
287 glCallList(listQuad
);
294 setShaderArgs(shader
);
295 glCallList(listQuad
);
300 // ////////////////////////////////////////////////////////////////////////// //
301 void renderThread () {
302 bool oldpaused
= paused
;
303 MonoTime prevFrameStartTime
= MonoTime
.currTime
;
304 version(use_vsync
) {} else MonoTime ltt
= MonoTime
.currTime
;
305 MonoTime lasttime
= MonoTime
.currTime
;
307 enum MaxFPSFrames
= 16;
308 float frtimes
= 0.0f;
313 if (sdwindow
.closed
) break;
314 if (atomicLoad(diedie
) > 0) break;
316 time
= MonoTime
.currTime
;
319 // max 60 FPS; capped by vsync
320 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((time-ltt).total!"msecs")); }
321 if (!first
&& (time
-ltt
).total
!"msecs" < 16) {
322 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((time-ltt).total!"msecs")); }
323 import core
.sys
.posix
.signal
: timespec
;
324 import core
.sys
.posix
.time
: nanosleep
;
327 ts
.tv_nsec
= (16-cast(int)((time
-ltt
).total
!"msecs"))*1000*1000; // milli to nano
328 nanosleep(&ts
, null); // idc how much time was passed
329 time
= MonoTime
.currTime
;
336 if (oldpaused
!= pau
) {
338 prevFrameStartTime
= time
;
342 globalTime
+= cast(float)(time
-lasttime
).total
!"msecs"/1000.0f;
345 debug { import core
.stdc
.stdio
; printf("globalTime=%f\n", globalTime
); }
347 frameTime
= cast(float)(time
-prevFrameStartTime
).total
!"msecs"/1000.0f;
348 prevFrameStartTime
= time
;
350 //{ import core.stdc.stdio; printf("frametime: %f\n", frameTime*1000.0f); }
351 //{ import core.stdc.stdio; printf("FPS: %d\n", cast(int)(1.0f/frameTime)); }
352 frtimes
+= frameTime
;
353 if (++framenum
>= MaxFPSFrames || frtimes
>= 3.0f) {
354 import std
.string
: format
;
355 int newFPS
= cast(int)(cast(float)MaxFPSFrames
/frtimes
+0.5);
356 if (newFPS
!= prevFPS
) {
357 sdwindow
.title
= "%s / FPS:%s".format(WindowTitle
, newFPS
);
364 //debug { import core.stdc.stdio; printf("XLockDisplay()\n"); }
365 //XLockDisplay(sdwindow.display);
366 debug { import core
.stdc
.stdio
; printf("glXMakeCurrent()\n"); }
367 if (glXMakeCurrent(sdwindow
.display
, sdwindow
.window
, sdwindow
.glc
) == 0) {
368 { import core
.stdc
.stdio
; printf(" FUUUU\n"); }
370 debug { import core
.stdc
.stdio
; printf("renderFrame()\n"); }
372 debug { import core
.stdc
.stdio
; printf("glXSwapBuffers()\n"); }
373 glXSwapBuffers(sdwindow
.display
, sdwindow
.window
);
374 debug { import core
.stdc
.stdio
; printf("glFinish()\n"); }
377 debug { import core
.stdc
.stdio
; printf("glXMakeCurrent(0)\n"); }
378 glXMakeCurrent(sdwindow
.display
, 0, null);
379 //debug { import core.stdc.stdio; printf("XUnlockDisplay()\n"); }
380 //XUnlockDisplay(sdwindow.display);
383 atomicStore(diedie
, 2);
387 // ////////////////////////////////////////////////////////////////////////// //
388 void closeWindow () {
389 if (atomicLoad(diedie
) != 2) {
390 atomicStore(diedie
, 1);
391 while (atomicLoad(diedie
) != 2) {}
393 if (!sdwindow
.closed
) {
400 // ////////////////////////////////////////////////////////////////////////// //
401 void main (string
[] args
) {
402 if (args
.length
< 2) assert(0, "filename?");
403 if (XInitThreads() == 0) assert(0, "XMT fucked");
406 import std
.algorithm
: startsWith
, endsWith
;
407 import std
.file
: readText
, thisExePath
;
408 import std
.path
: dirName
;
410 basePath
= "/home/ketmar/DUMMY-FUCK-MC/glsl_raymarching/d_glsl";
412 basePath
= thisExePath
.dirName
;
414 shaderFile
= args
[1];
415 if (shaderFile
.endsWith(".frag")) shaderFile
= shaderFile
[0..$-5];
416 if (shaderFile
.length
&& shaderFile
[0] != '.') {
417 if (shaderFile
.startsWith("shaders/")) shaderFile
= shaderFile
[8..$];
418 shaderFile
= basePath
~"/shaders/"~shaderFile
~".frag";
420 shaderFile
= shaderFile
~".frag";
421 shaderSource
= readText(shaderFile
);
426 sdwindow
= new SimpleWindow(vlEffectiveWidth
, vlEffectiveHeight
, WindowTitle
, OpenGlOptions
.yes
, Resizablity
.fixedSize
);
428 sdwindow
.visibleForTheFirstTime
= delegate () {
429 sdwindow
.setAsCurrentOpenGlContext(); // make this window active
431 sdwindow
.vsync
= true;
433 sdwindow
.vsync
= false;
435 //sdwindow.useGLFinish = false;
438 //sdwindow.redrawOpenGlScene();
440 sdwindow.swapOpenGlBuffers();
444 if (glXMakeCurrent(sdwindow.display, 0, null) == 0) { import core.stdc.stdio; printf("can't release OpenGL context(0)\n"); }
450 sdwindow
.eventLoop(100,
452 if (sdwindow
.closed
) return;
454 if (glXMakeCurrent(sdwindow
.display
, 0, null) == 0) { import core
.stdc
.stdio
; printf("can't release OpenGL context(1)\n"); }
455 renderTid
= new Thread(&renderThread
);
458 //sdwindow.redrawOpenGlSceneNow();
460 delegate (KeyEvent event
) {
461 if (sdwindow
.closed
) return;
462 if (event
.pressed
&& event
.key
== Key
.Escape
) closeWindow();
464 delegate (MouseEvent event
) {
465 if (sdwindow
.closed
) return;
466 mouseX
= event
.x
/scale
;
467 mouseY
= event
.y
/scale
;
468 if (event
.type
== MouseEventType
.buttonPressed
) {
469 if (event
.button
== MouseButton
.left
) mBut0
= true;
470 if (event
.button
== MouseButton
.right
) mBut1
= true;
471 } else if (event
.type
== MouseEventType
.buttonReleased
) {
472 if (event
.button
== MouseButton
.left
) mBut0
= false;
473 if (event
.button
== MouseButton
.right
) mBut1
= false;
476 delegate (dchar ch
) {
477 if (ch
== 'q') closeWindow();
478 if (ch
== '0') { mouseX
= mouseY
= 0; }
479 if (ch
== ' ') { paused
= !paused
; }