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
;
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", import("scanlines.frag"));
59 shadLiquid
= new Shader("liquid", import("srliquid.frag"));
62 shadToPolar
= new Shader("topolar", import("srlight_topolar.frag"));
63 shadBlur
= new Shader("blur", import("srlight_blur.frag"));
68 foreach (int sz
; 1..MaxLightSize
+1) {
69 // create occluders FBO
70 fboOccluders
[sz
] = new FBO(sz
, sz
);
71 // create 1d shadowmap FBO
72 fboShadowMap
[sz
] = new FBO(sz
, 1);
76 glMatrixMode(GL_MODELVIEW
);
80 fboLevel
= new FBO(map
.width
*8, map
.height
*8, Texture
.Option
.Nearest
);
82 // build noise texture for liquid shaders
83 glActiveTexture(GL_TEXTURE0
+1);
85 import std
.random
: uniform
;
86 auto img
= new TrueColorImage(64, 64);
87 foreach (int y
; 0..img
.width
) {
88 foreach (int x
; 0..img
.height
) {
89 ubyte b
= cast(ubyte)uniform(0, 256);
90 img
.imageData
.colors
[y
*img
.width
+x
] = Color(b
, b
, b
, 255);
93 auto tex
= new Texture(img
);
97 glActiveTexture(GL_TEXTURE0
+0);
98 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0);
99 orthoCamera(vlWidth
, vlHeight
);
103 // ////////////////////////////////////////////////////////////////////////// //
104 void renderLight() (int lightX
, int lightY
, in auto ref SVec4F lcol
, int lightSize
) {
105 if (lightSize
< 2) return;
107 if (lightSize
> MaxLightSize
) lightSize
= MaxLightSize
;
108 // is this light visible?
109 if (lightX
<= -lightSize
/2 || lightY
<= -lightSize
/2 || lightX
-lightSize
/2 >= map
.width
*8 || lightY
-lightSize
/2 >= map
.height
*8) return;
111 // draw shadow casters to fboOccludersId, light should be in the center
113 fboOccluders
[lightSize
].exec({
114 glColor3f(0.0f, 0.0f, 0.0f);
115 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
116 glClear(GL_COLOR_BUFFER_BIT
);
117 orthoCamera(lightSize
, lightSize
);
118 drawAtXY(map
.texgl
.ptr
[map
.LightMask
], lightSize
/2-lightX
, lightSize
/2-lightY
);
121 // build 1d shadow map to fboShadowMapId
122 fboShadowMap
[lightSize
].exec({
124 glColor3f(0.0f, 0.0f, 0.0f);
125 shadToPolar
["lightTexSize"] = SVec2F(lightSize
, lightSize
);
126 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
127 glClear(GL_COLOR_BUFFER_BIT
);
128 orthoCamera(lightSize
, 1);
129 drawAtXY(fboOccluders
[lightSize
].tex
.tid
, 0, 0, lightSize
, 1);
136 shadBlur
["lightTexSize"] = SVec2F(lightSize
, lightSize
);
138 glBlendFunc(GL_SRC_ALPHA
, GL_ONE
);
140 //glColor3f(1.0f, 1.0f, 0.0f);
141 glColor4f(lcol
.x
, lcol
.y
, lcol
.z
, lcol
.w
);
142 orthoCamera(map
.width
*8, map
.height
*8);
143 drawAtXY(fboShadowMap
[lightSize
].tex
.tid
, lightX
-lightSize
/2, lightY
-lightSize
/2, lightSize
, lightSize
, mirrorY
:true);
149 // ////////////////////////////////////////////////////////////////////////// //
150 __gshared
int lightX
= vlWidth
/2, lightY
= vlHeight
/2;
151 __gshared
int mapOfsX
, mapOfsY
;
152 __gshared
bool movement
= false;
155 void renderScene () {
156 enum BackIntens
= 0.05f;
160 glClearColor(BackIntens
, BackIntens
, BackIntens
, 1.0f);
161 glClear(GL_COLOR_BUFFER_BIT
);
162 //glColor3f(0.0f, 0.0f, 0.0f);
164 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
165 orthoCamera(map
.width
*8, map
.height
*8);
168 glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
169 //drawAtXY(map.texgl.ptr[map.Back], 0, 0);
172 __gshared
float iGlobalTime
= 0.0;
174 //shadLiquid["iResolution"] = SVec2F(vlWidth, vlHeight);
175 shadLiquid
["iResolution"] = SVec2F(map
.texgl
.ptr
[map
.Water
].width
, map
.texgl
.ptr
[map
.Water
].height
);
176 shadLiquid
["iGlobalTime"] = iGlobalTime
;
177 shadLiquid
["iChannel0"] = 0;
178 shadLiquid
["iChannel1"] = 1;
179 shadLiquid
["liquidColorMul"] = SVec4F(1.0f, 1.0f, 1.0f, 1.0f);
180 shadLiquid
["liquidColor"] = SVec4F(0.0f, 0.0f, 0.4f, 1.0f);
181 drawAtXY(map
.texgl
.ptr
[map
.Water
], 0, 0);
182 shadLiquid
["liquidColorMul"] = SVec4F(0.6f, 0.6f, 0.6f, 1.0f);
183 shadLiquid
["liquidColor"] = SVec4F(0.6f, 0.1f, 0.0f, 1.0f);
184 drawAtXY(map
.texgl
.ptr
[map
.Lava
], 0, 0);
185 shadLiquid
["liquidColorMul"] = SVec4F(1.0f, 1.0f, 1.0f, 1.0f);
186 shadLiquid
["liquidColor"] = SVec4F(0.1f, 0.4f, 0.0f, 1.0f);
187 drawAtXY(map
.texgl
.ptr
[map
.Acid
], 0, 0);
189 //drawAtXY(map.texgl.ptr[map.LightMask], 0, 0);
194 glBlendFunc(GL_SRC_ALPHA
, GL_ONE
);
196 glActiveTexture(GL_TEXTURE0
+1);
197 glBindTexture(GL_TEXTURE_2D
, map
.texgl
.ptr
[map
.Back
].tid
);
198 glActiveTexture(GL_TEXTURE0
+0);
200 renderLight( 27, map
.height
*8-1-391-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 100);
201 renderLight(542, map
.height
*8-1-424-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 100);
202 renderLight(377, map
.height
*8-1-368-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 32);
203 renderLight(147, map
.height
*8-1-288-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 64);
204 renderLight( 71, map
.height
*8-1-200-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
205 renderLight(249, map
.height
*8-1-200-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
206 renderLight(426, map
.height
*8-1-200-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
207 renderLight(624, map
.height
*8-1-200-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
208 renderLight(549, map
.height
*8-1-298-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 64);
209 renderLight( 74, map
.height
*8-1-304-0, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 32);
211 renderLight(24*8+4, map
.height
*8-1-(24+18)*8-2, SVec4F(0.6f, 0.0f, 0.0f, 1.0f), 128);
212 foreach (immutable _
; 0..20) {
213 renderLight(lightX
, lightY
, SVec4F(0.3f, 0.3f, 0.0f, 1.0f), 256);
219 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
220 glColor3f(1.0f, 1.0f, 1.0f);
221 orthoCamera(map
.width
*8, map
.height
*8);
222 drawAtXY(map
.texgl
.ptr
[map
.LightMask
], 0, 0);
224 drawAtXY(map
.texgl
.ptr
[map
.Front
], 0, 0);
228 glClearColor(BackIntens
, BackIntens
, BackIntens
, 1.0f);
229 glClear(GL_COLOR_BUFFER_BIT
);
230 glUseProgram(shadScanlines
.prg
);
231 shadScanlines
["scanlines"] = scanlines
;
232 orthoCamera(vlWidth
, vlHeight
);
233 drawAtXY(fboLevel
.tex
.tid
, -mapOfsX
, -mapOfsY
, map
.width
*8*scale
, map
.height
*8*scale
);
239 // ////////////////////////////////////////////////////////////////////////// //
241 shared int diedie
= 0;
244 void renderThread () {
245 MonoTime prevFrameStartTime
= MonoTime
.currTime
;
246 version(use_vsync
) {} else MonoTime ltt
= MonoTime
.currTime
;
247 MonoTime lasttime
= MonoTime
.currTime
;
249 enum MaxFPSFrames
= 16;
250 float frtimes
= 0.0f;
255 if (sdwindow
.closed
) break;
256 if (atomicLoad(diedie
) > 0) break;
258 time
= MonoTime
.currTime
;
261 // max 60 FPS; capped by vsync
262 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((time-ltt).total!"msecs")); }
263 if (!first
&& (time
-ltt
).total
!"msecs" < 16) {
264 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((time-ltt).total!"msecs")); }
265 import core
.sys
.posix
.signal
: timespec
;
266 import core
.sys
.posix
.time
: nanosleep
;
269 ts
.tv_nsec
= (16-cast(int)((time
-ltt
).total
!"msecs"))*1000*1000; // milli to nano
270 nanosleep(&ts
, null); // idc how much time was passed
271 time
= MonoTime
.currTime
;
278 auto frameTime
= cast(float)(time
-prevFrameStartTime
).total
!"msecs"/1000.0f;
279 prevFrameStartTime
= time
;
281 //{ import core.stdc.stdio; printf("frametime: %f\n", frameTime*1000.0f); }
282 //{ import core.stdc.stdio; printf("FPS: %d\n", cast(int)(1.0f/frameTime)); }
283 frtimes
+= frameTime
;
284 if (++framenum
>= MaxFPSFrames || frtimes
>= 3.0f) {
285 import std
.string
: format
;
286 int newFPS
= cast(int)(cast(float)MaxFPSFrames
/frtimes
+0.5);
287 if (newFPS
!= prevFPS
) {
288 sdwindow
.title
= "%s / FPS:%s".format("D2D", newFPS
);
295 XLockDisplay(sdwindow
.display
);
296 if (glXMakeCurrent(sdwindow
.display
, sdwindow
.window
, sdwindow
.glc
) == 0) {
297 XUnlockDisplay(sdwindow
.display
);
298 { import core
.stdc
.stdio
; printf(" FUUUU\n"); }
299 //glXMakeCurrent(sdwindow.display, 0, null);
300 import core
.sys
.posix
.signal
: timespec
;
301 import core
.sys
.posix
.time
: nanosleep
;
304 ts
.tv_nsec
= 16*1000*1000; // milli to nano
305 nanosleep(&ts
, null); // idc how much time was passed
306 time
= MonoTime
.currTime
;
309 XUnlockDisplay(sdwindow
.display
);
311 XLockDisplay(sdwindow
.display
);
312 glXSwapBuffers(sdwindow
.display
, sdwindow
.window
);
314 glXMakeCurrent(sdwindow
.display
, 0, null);
315 XUnlockDisplay(sdwindow
.display
);
318 atomicStore(diedie
, 2);
322 // ////////////////////////////////////////////////////////////////////////// //
323 void closeWindow () {
324 if (atomicLoad(diedie
) != 2) {
325 atomicStore(diedie
, 1);
326 while (atomicLoad(diedie
) != 2) {}
328 if (!sdwindow
.closed
) {
335 // ////////////////////////////////////////////////////////////////////////// //
336 __gshared Thread renderTid
;
340 static void setDP () {
344 import std
.file
: thisExePath
;
345 import std
.path
: dirName
;
346 setDataPath(thisExePath
.dirName
);
348 addWad("/home/ketmar/k8prj/doom2d-tl/data/doom2d.wad");
349 //addWad("/home/ketmar/k8prj/doom2d-tl/data/meat.wad");
350 //addWad("/home/ketmar/k8prj/doom2d-tl/data/megadm.wad");
351 //addWad("/home/ketmar/k8prj/doom2d-tl/data/megadm1.wad");
352 //addWad("/home/ketmar/k8prj/doom2d-tl/data/superdm.wad");
353 //addWad("/home/ketmar/k8prj/doom2d-tl/data/zadoomka.wad");
359 map
= new LevelMap("maps/map01.d2m");
363 sdwindow
= new SimpleWindow(vlWidth
, vlHeight
, "D2D", OpenGlOptions
.yes
, Resizablity
.fixedSize
);
365 sdwindow
.visibleForTheFirstTime
= delegate () {
366 sdwindow
.setAsCurrentOpenGlContext(); // make this window active
367 sdwindow
.vsync
= false;
368 //sdwindow.useGLFinish = false;
370 //sdwindow.redrawOpenGlScene();
372 if (glXMakeCurrent(sdwindow
.display
, 0, null) == 0) { import core
.stdc
.stdio
; printf("can't release OpenGL context(1)\n"); }
373 renderTid
= new Thread(&renderThread
);
378 //sdwindow.redrawOpenGlScene = delegate () { renderScene(); };
380 enum MSecsPerFrame
= 1000/30; /* 30 is FPS */
382 uint[8] frameTimes
= 1000;
383 enum { Left
, Right
, Up
, Down
}
384 bool[4] pressed
= false;
386 sdwindow
.eventLoop(MSecsPerFrame
,
388 if (sdwindow
.closed
) return;
389 if (pressed
[Left
]) mapOfsX
-= 8;
390 if (pressed
[Right
]) mapOfsX
+= 8;
391 if (pressed
[Up
]) mapOfsY
+= 8;
392 if (pressed
[Down
]) mapOfsY
-= 8;
393 import std
.math
: cos
, sin
;
394 __gshared
float itime
= 0.0;
397 mapOfsX
= cast(int)(800.0/2.0+cos(itime
)*220.0);
398 mapOfsY
= cast(int)(800.0/2.0+120.0+sin(itime
)*160.0);
400 if (scale
== 1) mapOfsX
= mapOfsY
= 0;
401 //sdwindow.redrawOpenGlSceneNow();
403 delegate (KeyEvent event
) {
404 if (sdwindow
.closed
) return;
405 if (event
.pressed
&& event
.key
== Key
.Escape
) { closeWindow(); return; }
407 case Key
.Left
: pressed
[Left
] = event
.pressed
; break;
408 case Key
.Right
: pressed
[Right
] = event
.pressed
; break;
409 case Key
.Up
: pressed
[Up
] = event
.pressed
; break;
410 case Key
.Down
: pressed
[Down
] = event
.pressed
; break;
414 delegate (MouseEvent event
) {
415 lightX
= event
.x
/scale
;
416 lightY
= vlHeight
/scale
-event
.y
/scale
;
417 lightX
+= mapOfsX
/scale
;
418 lightY
+= mapOfsY
/scale
;
420 delegate (dchar ch
) {
421 if (ch
== 'q') { closeWindow(); return; }
422 if (ch
== 's') scanlines
= !scanlines
;
423 if (ch
== '1') scale
= 1;
424 if (ch
== '2') scale
= 2;
425 if (ch
== ' ') movement
= !movement
;