1 module xmain_d2d
is aliced
;
17 // ////////////////////////////////////////////////////////////////////////// //
22 // ////////////////////////////////////////////////////////////////////////// //
23 __gshared LevelMap map
;
26 // ////////////////////////////////////////////////////////////////////////// //
27 __gshared SimpleWindow sdwindow
;
30 public enum vlWidth
= 800;
31 public enum vlHeight
= 800;
32 __gshared
int scale
= 1;
33 __gshared
bool scanlines
= false;
36 // ////////////////////////////////////////////////////////////////////////// //
37 enum MaxLightSize
= 512;
40 // ////////////////////////////////////////////////////////////////////////// //
42 __gshared FBO
[MaxLightSize
+1] fboOccluders
, fboShadowMap
;
43 __gshared Shader shadToPolar
, shadBlur
;
45 __gshared FBO fboLevel
, fboOrigBack
;
46 __gshared Shader shadScanlines
, shadLiquid
;
49 // ////////////////////////////////////////////////////////////////////////// //
51 glEnable(GL_TEXTURE_2D
);
52 glDisable(GL_LIGHTING
);
55 glDisable(GL_DEPTH_TEST
);
58 shadScanlines
= new Shader("scanlines", loadTextFile("data/shaders/srscanlines.frag"));
59 shadLiquid
= new Shader("liquid", loadTextFile("data/shaders/srliquid.frag"));
61 shadLiquid
["iChannel0"] = 0;
62 //shadLiquid["iChannel1"] = 1;
66 shadToPolar
= new Shader("topolar", loadTextFile("data/shaders/srlight_topolar.frag"));
67 shadBlur
= new Shader("blur", loadTextFile("data/shaders/srlight_blur.frag"));
73 foreach (int sz
; 1..MaxLightSize
+1) {
74 fboOccluders
[sz
] = new FBO(sz
, sz
); // create occluders FBO
75 fboShadowMap
[sz
] = new FBO(sz
, 1); // create 1d shadowmap FBO
79 glMatrixMode(GL_MODELVIEW
);
86 shadLiquid["iResolution"] = SVec2F(map.texgl.ptr[map.Water].width, map.texgl.ptr[map.Water].height);
90 fboLevel
= new FBO(map
.width
*8, map
.height
*8, Texture
.Option
.Nearest
);
92 fboOrigBack
= new FBO(map
.width
*8, map
.height
*8, Texture
.Option
.Nearest
); // original background
96 orthoCamera(map.width*8, map.height*8);
97 drawAtXY(map.texgl.ptr[map.Back], 0, 0);
101 // build noise texture for liquid shaders
103 glActiveTexture(GL_TEXTURE0+1);
105 import std.random : uniform;
106 auto img = new TrueColorImage(64, 64);
107 foreach (int y; 0..img.width) {
108 foreach (int x; 0..img.height) {
109 ubyte b = cast(ubyte)uniform(0, 256);
110 img.imageData.colors[y*img.width+x] = Color(b, b, b, 255);
113 auto tex = new Texture(img);
118 glActiveTexture(GL_TEXTURE0
+0);
119 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0);
120 orthoCamera(vlWidth
, vlHeight
);
124 // ////////////////////////////////////////////////////////////////////////// //
125 void renderLight() (int lightX
, int lightY
, in auto ref SVec4F lcol
, int lightSize
) {
126 if (lightSize
< 2) return;
128 if (lightSize
> MaxLightSize
) lightSize
= MaxLightSize
;
129 // is this light visible?
130 if (lightX
<= -lightSize
/2 || lightY
<= -lightSize
/2 || lightX
-lightSize
/2 >= map
.width
*8 || lightY
-lightSize
/2 >= map
.height
*8) return;
132 // draw shadow casters to fboOccludersId, light should be in the center
134 fboOccluders
[lightSize
].exec({
135 glColor3f(0.0f, 0.0f, 0.0f);
136 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
137 glClear(GL_COLOR_BUFFER_BIT
);
138 orthoCamera(lightSize
, lightSize
);
139 drawAtXY(map
.texgl
.ptr
[map
.LightMask
], lightSize
/2-lightX
, lightSize
/2-lightY
);
142 // build 1d shadow map to fboShadowMapId
143 fboShadowMap
[lightSize
].exec({
145 glColor3f(0.0f, 0.0f, 0.0f);
146 shadToPolar
["lightTexSize"] = SVec2F(lightSize
, lightSize
);
147 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
148 glClear(GL_COLOR_BUFFER_BIT
);
149 orthoCamera(lightSize
, 1);
150 drawAtXY(fboOccluders
[lightSize
].tex
.tid
, 0, 0, lightSize
, 1);
157 shadBlur
["lightTexSize"] = SVec2F(lightSize
, lightSize
);
159 glBlendFunc(GL_SRC_ALPHA
, GL_ONE
);
161 glColor4f(lcol
.x
, lcol
.y
, lcol
.z
, lcol
.w
);
162 orthoCamera(map
.width
*8, map
.height
*8);
163 drawAtXY(fboShadowMap
[lightSize
].tex
.tid
, lightX
-lightSize
/2, lightY
-lightSize
/2, lightSize
, lightSize
, mirrorY
:true);
169 // ////////////////////////////////////////////////////////////////////////// //
170 __gshared
int lightX
= vlWidth
/2, lightY
= vlHeight
/2;
171 __gshared
int mapOfsX
, mapOfsY
;
172 __gshared
bool movement
= false;
175 void renderScene () {
176 enum BackIntens
= 0.05f;
180 glClearColor(BackIntens
, BackIntens
, BackIntens
, 1.0f);
181 glClear(GL_COLOR_BUFFER_BIT
);
182 //glColor3f(0.0f, 0.0f, 0.0f);
184 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
185 orthoCamera(map
.width
*8, map
.height
*8);
188 glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
189 //drawAtXY(map.texgl.ptr[map.Back], 0, 0);
192 __gshared
float iGlobalTime
= 0.0;
194 shadLiquid
["iGlobalTime"] = iGlobalTime
;
195 shadLiquid
["liquidColorMul"] = SVec4F(1.0f, 1.0f, 1.0f, 1.0f);
196 shadLiquid
["liquidColor"] = SVec4F(0.0f, 0.0f, 0.4f, 1.0f);
197 drawAtXY(map
.texgl
.ptr
[map
.Water
], 0, 0);
198 shadLiquid
["liquidColorMul"] = SVec4F(0.6f, 0.6f, 0.6f, 1.0f);
199 shadLiquid
["liquidColor"] = SVec4F(0.6f, 0.1f, 0.0f, 1.0f);
200 drawAtXY(map
.texgl
.ptr
[map
.Lava
], 0, 0);
201 shadLiquid
["liquidColorMul"] = SVec4F(1.0f, 1.0f, 1.0f, 1.0f);
202 shadLiquid
["liquidColor"] = SVec4F(0.1f, 0.4f, 0.0f, 1.0f);
203 drawAtXY(map
.texgl
.ptr
[map
.Acid
], 0, 0);
205 //drawAtXY(map.texgl.ptr[map.LightMask], 0, 0);
211 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
212 glClear(GL_COLOR_BUFFER_BIT
);
213 //glEnable(GL_BLEND);
214 //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
215 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
216 orthoCamera(map
.width
*8, map
.height
*8);
218 drawAtXY(map
.texgl
.ptr
[map
.Back
], 0, 0);
225 glBlendFunc(GL_SRC_ALPHA
, GL_ONE
);
227 glActiveTexture(GL_TEXTURE0
+1);
228 glBindTexture(GL_TEXTURE_2D
, /*map.texgl.ptr[map.Back].tid*/fboOrigBack
.tex
.tid
);
229 //glBindTexture(GL_TEXTURE_2D, map.texgl.ptr[map.Back].tid);
230 glActiveTexture(GL_TEXTURE0
+0);
232 renderLight( 27, map
.height
*8-1-391-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 100);
233 renderLight(542, map
.height
*8-1-424-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 100);
234 renderLight(377, map
.height
*8-1-368-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 32);
235 renderLight(147, map
.height
*8-1-288-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 64);
236 renderLight( 71, map
.height
*8-1-200-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
237 renderLight(249, map
.height
*8-1-200-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
238 renderLight(426, map
.height
*8-1-200-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
239 renderLight(624, map
.height
*8-1-200-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
240 renderLight(549, map
.height
*8-1-298-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 64);
241 renderLight( 74, map
.height
*8-1-304-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 32);
243 renderLight(24*8+4, map
.height
*8-1-(24+18)*8-2, SVec4F(0.6f, 0.0f, 0.0f, 1.0f), 128);
244 foreach (immutable _
; 0..10) {
245 renderLight(lightX
, lightY
, SVec4F(0.3f, 0.3f, 0.0f, 1.0f), 256);
248 glActiveTexture(GL_TEXTURE0
+1);
249 glBindTexture(GL_TEXTURE_2D
, 0);
250 glActiveTexture(GL_TEXTURE0
+0);
255 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
256 glColor3f(1.0f, 1.0f, 1.0f);
257 orthoCamera(map
.width
*8, map
.height
*8);
258 drawAtXY(map
.texgl
.ptr
[map
.LightMask
], 0, 0);
260 drawAtXY(map
.texgl
.ptr
[map
.Front
], 0, 0);
265 shadScanlines
["scanlines"] = scanlines
;
266 glClearColor(BackIntens
, BackIntens
, BackIntens
, 1.0f);
267 glClear(GL_COLOR_BUFFER_BIT
);
268 orthoCamera(vlWidth
, vlHeight
);
269 //orthoCamera(map.width*8*scale, map.height*8*scale);
270 //glMatrixMode(GL_MODELVIEW);
272 //glTranslatef(0.375, 0.375, 0); // to be pixel-perfect
273 drawAtXY(fboLevel
.tex
.tid
, -mapOfsX
, -mapOfsY
, map
.width
*8*scale
, map
.height
*8*scale
);
281 // ////////////////////////////////////////////////////////////////////////// //
283 shared int diedie
= 0;
286 void renderThread () {
288 MonoTime prevFrameStartTime
= MonoTime
.currTime
;
289 version(use_vsync
) {} else MonoTime ltt
= MonoTime
.currTime
;
290 MonoTime lasttime
= MonoTime
.currTime
;
292 enum MaxFPSFrames
= 16;
293 float frtimes
= 0.0f;
298 if (sdwindow
.closed
) break;
299 if (atomicLoad(diedie
) > 0) break;
301 time
= MonoTime
.currTime
;
304 // max 60 FPS; capped by vsync
305 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((time-ltt).total!"msecs")); }
306 if (!first
&& (time
-ltt
).total
!"msecs" < 16) {
307 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((time-ltt).total!"msecs")); }
308 import core
.sys
.posix
.signal
: timespec
;
309 import core
.sys
.posix
.time
: nanosleep
;
312 ts
.tv_nsec
= (16-cast(int)((time
-ltt
).total
!"msecs"))*1000*1000; // milli to nano
313 nanosleep(&ts
, null); // idc how much time was passed
314 time
= MonoTime
.currTime
;
321 auto frameTime
= cast(float)(time
-prevFrameStartTime
).total
!"msecs"/1000.0f;
322 prevFrameStartTime
= time
;
324 //{ import core.stdc.stdio; printf("frametime: %f\n", frameTime*1000.0f); }
325 //{ import core.stdc.stdio; printf("FPS: %d\n", cast(int)(1.0f/frameTime)); }
326 frtimes
+= frameTime
;
327 if (++framenum
>= MaxFPSFrames || frtimes
>= 3.0f) {
328 import std
.string
: format
;
329 int newFPS
= cast(int)(cast(float)MaxFPSFrames
/frtimes
+0.5);
330 if (newFPS
!= prevFPS
) {
331 sdwindow
.title
= "%s / FPS:%s".format("D2D", newFPS
);
341 scope(exit
) sdwindow
.mtUnlock();
342 ctset
= sdwindow
.setAsCurrentOpenGlContextNT
;
345 { import core
.stdc
.stdio
; printf(" FUUUU\n"); }
346 //glXMakeCurrent(sdwindow.display, 0, null);
347 import core
.sys
.posix
.signal
: timespec
;
348 import core
.sys
.posix
.time
: nanosleep
;
351 ts
.tv_nsec
= 16*1000*1000; // milli to nano
352 nanosleep(&ts
, null); // idc how much time was passed
353 time
= MonoTime
.currTime
;
358 scope(exit
) sdwindow
.mtUnlock();
359 sdwindow
.swapOpenGlBuffers();
361 sdwindow
.releaseCurrentOpenGlContext();
366 } catch (Exception e
) {
367 import core
.stdc
.stdio
;
368 fprintf(stderr
, "FUUUUUUUUUUUUUUUUUUUUUUUUUU\n");
370 if (sdwindow
.closed
) break;
371 if (atomicLoad(diedie
) > 0) break;
372 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((time-ltt).total!"msecs")); }
373 import core
.sys
.posix
.signal
: timespec
;
374 import core
.sys
.posix
.time
: nanosleep
;
377 ts
.tv_nsec
= 100*1000*1000; // milli to nano
378 nanosleep(&ts
, null); // idc how much time was passed
381 atomicStore(diedie
, 2);
385 // ////////////////////////////////////////////////////////////////////////// //
386 void closeWindow () {
387 if (atomicLoad(diedie
) != 2) {
388 atomicStore(diedie
, 1);
389 sdwindow
.mtUnlock(); // 'cause we are locked
390 while (atomicLoad(diedie
) != 2) {}
391 sdwindow
.mtLock(); // restore lock
393 if (!sdwindow
.closed
) {
400 // ////////////////////////////////////////////////////////////////////////// //
401 __gshared Thread renderTid
;
405 static void setDP () {
409 import std
.file
: thisExePath
;
410 import std
.path
: dirName
;
411 setDataPath(thisExePath
.dirName
);
413 addWad("/home/ketmar/k8prj/doom2d-tl/data/doom2d.wad");
414 //addWad("/home/ketmar/k8prj/doom2d-tl/data/meat.wad");
415 //addWad("/home/ketmar/k8prj/doom2d-tl/data/megadm.wad");
416 //addWad("/home/ketmar/k8prj/doom2d-tl/data/megadm1.wad");
417 //addWad("/home/ketmar/k8prj/doom2d-tl/data/superdm.wad");
418 //addWad("/home/ketmar/k8prj/doom2d-tl/data/zadoomka.wad");
421 setOpenGLContextVersion(3, 2); // up to GLSL 150
422 //openGLContextCompatible = false;
427 map
= new LevelMap("maps/map01.d2m");
432 sdwindow
= new SimpleWindow(vlWidth
, vlHeight
, "D2D", OpenGlOptions
.yes
, Resizablity
.fixedSize
);
434 sdwindow
.visibleForTheFirstTime
= delegate () {
435 sdwindow
.setAsCurrentOpenGlContext(); // make this window active
436 glbindLoadFunctions();
439 import core.stdc.stdio;
440 printf("GL version: %s\n", glGetString(GL_VERSION));
442 glGetIntegerv(GL_MAJOR_VERSION, &h);
443 glGetIntegerv(GL_MINOR_VERSION, &l);
444 printf("version: %d.%d\n", h, l);
445 printf("shader version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
447 glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS, &svcount);
449 printf("%d shader versions supported:\n", svcount);
450 foreach (GLuint n; 0..svcount) printf(" %d: %s\n", n, glGetStringi(GL_SHADING_LANGUAGE_VERSION, n));
454 glGetIntegerv(GL_NUM_EXTENSIONS, &ecount);
456 printf("%d extensions supported:\n", ecount);
457 foreach (GLuint n; 0..ecount) printf(" %d: %s\n", n, glGetStringi(GL_EXTENSIONS, n));
462 // check if we have sufficient shader version here
466 glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS
, &svcount
);
468 foreach (GLuint n
; 0..svcount
) {
469 import core
.stdc
.string
: strncmp
;
470 auto v
= glGetStringi(GL_SHADING_LANGUAGE_VERSION
, n
);
471 if (v
is null) continue;
472 if (strncmp(v
, "120", 3) != 0) continue;
473 if (v
[3] > ' ') continue;
478 if (!found
) assert(0, "can't find OpenGL GLSL 120");
480 auto adr
= glGetProcAddress("glTexParameterf");
481 if (adr
is null) assert(0);
484 sdwindow
.vsync
= false;
485 //sdwindow.useGLFinish = false;
487 //sdwindow.redrawOpenGlScene();
488 if (!sdwindow
.releaseCurrentOpenGlContext()) { import core
.stdc
.stdio
; printf("can't release OpenGL context(1)\n"); }
490 renderTid
= new Thread(&renderThread
);
495 //sdwindow.redrawOpenGlScene = delegate () { renderScene(); };
497 enum MSecsPerFrame
= 1000/30; /* 30 is FPS */
499 uint[8] frameTimes
= 1000;
500 enum { Left
, Right
, Up
, Down
}
501 bool[4] pressed
= false;
503 sdwindow
.eventLoop(MSecsPerFrame
,
505 if (sdwindow
.closed
) return;
506 if (pressed
[Left
]) mapOfsX
-= 8;
507 if (pressed
[Right
]) mapOfsX
+= 8;
508 if (pressed
[Up
]) mapOfsY
+= 8;
509 if (pressed
[Down
]) mapOfsY
-= 8;
510 import std
.math
: cos
, sin
;
511 __gshared
float itime
= 0.0;
514 mapOfsX
= cast(int)(800.0/2.0+cos(itime
)*220.0);
515 mapOfsY
= cast(int)(800.0/2.0+120.0+sin(itime
)*160.0);
517 if (scale
== 1) mapOfsX
= mapOfsY
= 0;
518 //sdwindow.redrawOpenGlSceneNow();
520 delegate (KeyEvent event
) {
521 if (sdwindow
.closed
) return;
522 if (event
.pressed
&& event
.key
== Key
.Escape
) { closeWindow(); return; }
524 case Key
.Left
: pressed
[Left
] = event
.pressed
; break;
525 case Key
.Right
: pressed
[Right
] = event
.pressed
; break;
526 case Key
.Up
: pressed
[Up
] = event
.pressed
; break;
527 case Key
.Down
: pressed
[Down
] = event
.pressed
; break;
531 delegate (MouseEvent event
) {
532 lightX
= event
.x
/scale
;
533 lightY
= vlHeight
/scale
-event
.y
/scale
;
534 lightX
+= mapOfsX
/scale
;
535 lightY
+= mapOfsY
/scale
;
537 delegate (dchar ch
) {
538 if (ch
== 'q') { closeWindow(); return; }
539 if (ch
== 's') scanlines
= !scanlines
;
540 if (ch
== '1') scale
= 1;
541 if (ch
== '2') scale
= 2;
542 if (ch
== ' ') movement
= !movement
;