1 module xmain_d2d
is aliced
;
25 // ////////////////////////////////////////////////////////////////////////// //
30 // ////////////////////////////////////////////////////////////////////////// //
31 __gshared SimpleWindow sdwindow
;
34 public enum vlWidth
= 800;
35 public enum vlHeight
= 800;
36 __gshared
int scale
= 1;
37 __gshared
bool scanlines
= false;
40 // ////////////////////////////////////////////////////////////////////////// //
42 __gshared
ubyte[] prevFrameActorsData
;
43 __gshared
uint[65536] prevFrameActorOfs
; // uint.max-1: dead; uint.max: last
44 __gshared MonoTime lastthink
= MonoTime
.zero
; // for interpolator
45 __gshared MonoTime nextthink
= MonoTime
.zero
;
46 __gshared
bool frameInterpolation
= true;
49 // ////////////////////////////////////////////////////////////////////////// //
50 enum MaxLightRadius
= 512;
53 // ////////////////////////////////////////////////////////////////////////// //
55 __gshared FBO
[MaxLightRadius
+1] fboOccluders
, fboShadowMap
;
56 __gshared Shader shadToPolar
, shadBlur
, shadBlurOcc
;
58 __gshared FBO fboLevel
, fboLevelLight
, fboOrigBack
;
59 __gshared Shader shadScanlines
;
60 __gshared Shader shadLiquidDistort
;
63 // ////////////////////////////////////////////////////////////////////////// //
65 glEnable(GL_TEXTURE_2D
);
66 glDisable(GL_LIGHTING
);
69 glDisable(GL_DEPTH_TEST
);
72 shadScanlines
= new Shader("scanlines", loadTextFile("data/shaders/srscanlines.frag"));
74 shadLiquidDistort
= new Shader("liquid_distort", loadTextFile("data/shaders/srliquid_distort.frag"));
75 shadLiquidDistort
.exec((Shader shad
) { shad
["tex0"] = 0; });
78 shadToPolar
= new Shader("light_topolar", loadTextFile("data/shaders/srlight_topolar.frag"));
79 shadBlur
= new Shader("light_blur", loadTextFile("data/shaders/srlight_blur.frag"));
80 shadBlur
.exec((Shader shad
) {
85 shadBlurOcc
= new Shader("light_blur_occ", loadTextFile("data/shaders/srlight_blur_occ.frag"));
86 shadBlurOcc
.exec((Shader shad
) {
92 foreach (int sz
; 2..MaxLightRadius
+1) {
93 fboOccluders
[sz
] = new FBO(sz
*2, sz
*2, Texture
.Option
.Clamp
, Texture
.Option
.Linear
); // create occluders FBO
94 fboShadowMap
[sz
] = new FBO(sz
*2, 1, Texture
.Option
.Clamp
); // create 1d shadowmap FBO
98 glMatrixMode(GL_MODELVIEW
);
103 fboLevel
= new FBO(map
.width
*8, map
.height
*8, Texture
.Option
.Nearest
); // final level render will be here
104 fboLevelLight
= new FBO(map
.width
*8, map
.height
*8, Texture
.Option
.Nearest
); // level lights will be rendered here
105 //fboForeground = new FBO(map.width*8, map.height*8, Texture.Option.Nearest); // level foreground
106 fboOrigBack
= new FBO(map
.width
*8, map
.height
*8, Texture
.Option
.Nearest
); // background+foreground
108 shadBlur
.exec((Shader shad
) { shad
["mapPixSize"] = SVec2F(map
.width
*8, map
.height
*8); });
109 shadBlurOcc
.exec((Shader shad
) { shad
["mapPixSize"] = SVec2F(map
.width
*8, map
.height
*8); });
111 glActiveTexture(GL_TEXTURE0
+0);
112 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0);
113 orthoCamera(vlWidth
, vlHeight
);
115 Actor
.resetStorage();
118 // save first snapshot
119 prevFrameActorsData
= new ubyte[](Actor
.actorSize
*65536); // ~15-20 megabytes
120 prevFrameActorOfs
[] = uint.max
; // just for fun
121 Actor
.saveSnapshot(prevFrameActorsData
[], prevFrameActorOfs
.ptr
);
123 { import core
.memory
: GC
; GC
.collect(); }
127 // ////////////////////////////////////////////////////////////////////////// //
128 void renderLight() (int lightX
, int lightY
, in auto ref SVec4F lcol
, int lightRadius
) {
129 if (lightRadius
< 2) return;
130 if (lightRadius
> MaxLightRadius
) lightRadius
= MaxLightRadius
;
131 int lightSize
= lightRadius
*2;
132 // is this light visible?
133 if (lightX
<= -lightRadius || lightY
<= -lightRadius || lightX
-lightRadius
>= map
.width
*8 || lightY
-lightRadius
>= map
.height
*8) return;
135 // draw shadow casters to fboOccludersId, light should be in the center
138 fboOccluders
[lightRadius
].exec({
139 //glDisable(GL_BLEND);
140 glColor3f(0.0f, 0.0f, 0.0f);
141 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
142 glClear(GL_COLOR_BUFFER_BIT
);
143 orthoCamera(lightSize
, lightSize
);
144 drawAtXY(map
.texgl
.ptr
[map
.LightMask
], lightRadius
-lightX
, lightRadius
-lightY
);
147 // build 1d shadow map to fboShadowMapId
148 fboShadowMap
[lightRadius
].exec({
149 shadToPolar
.exec((Shader shad
) {
150 //glDisable(GL_BLEND);
151 glColor3f(0.0f, 0.0f, 0.0f);
152 shad
["lightTexSize"] = SVec2F(lightSize
, lightSize
);
153 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
154 glClear(GL_COLOR_BUFFER_BIT
);
155 orthoCamera(lightSize
, 1);
156 drawAtXY(fboOccluders
[lightRadius
].tex
.tid
, 0, 0, lightSize
, 1);
160 // build light texture for blending
161 fboOccluders
[lightRadius
].exec({
162 // no need to clear it, shader will take care of that
163 //glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
164 //glClear(GL_COLOR_BUFFER_BIT);
165 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
166 //glDisable(GL_BLEND);
167 shadBlur
.exec((Shader shad
) {
168 shad
["lightTexSize"] = SVec2F(lightSize
, lightSize
);
169 shad
["lightColor"] = SVec4F(lcol
.x
, lcol
.y
, lcol
.z
, lcol
.w
);
170 shad
["lightPos"] = SVec2F(lightX
, lightY
);
171 orthoCamera(lightSize
, lightSize
);
172 drawAtXY(fboShadowMap
[lightRadius
].tex
.tid
, 0, 0, lightSize
, lightSize
);
176 // blend light texture
179 glBlendFunc(GL_SRC_ALPHA
, GL_ONE
);
180 orthoCamera(map
.width
*8, map
.height
*8);
181 drawAtXY(fboOccluders
[lightRadius
].tex
, lightX
-lightRadius
, lightY
-lightRadius
, mirrorY
:true);
182 // and blend it again, somewhat bigger, with the shader that will touch only occluders
184 shadBlurOcc
.exec((Shader shad
) {
185 shad
["lightTexSize"] = SVec2F(lightSize
, lightSize
);
186 shad
["lightColor"] = SVec4F(lcol
.x
, lcol
.y
, lcol
.z
, lcol
.w
);
187 shad
["lightPos"] = SVec2F(lightX
, lightY
);
188 drawAtXY(fboOccluders
[lightRadius
].tex
.tid
, lightX
-lightRadius
-szmore
, lightY
-lightRadius
-szmore
, lightSize
+szmore
*2, lightSize
+szmore
*2, mirrorY
:true);
194 // ////////////////////////////////////////////////////////////////////////// //
195 __gshared
int lightX
= vlWidth
/2, lightY
= vlHeight
/2;
196 __gshared
int mapOfsX
, mapOfsY
;
197 __gshared
bool movement
= false;
198 __gshared
float iLiquidTime
= 0.0;
201 void renderScene (MonoTime curtime
) {
202 //enum BackIntens = 0.05f;
203 enum BackIntens
= 0.0f;
205 float atob
= cast(float)((curtime
-lastthink
).total
!"msecs")/cast(float)((nextthink
-lastthink
).total
!"msecs");
206 //{ import core.stdc.stdio; printf("atob=%f\n", cast(double)atob); }
209 int framelen = cast(int)((nextthink-lastthink).total!"msecs");
210 int curfp = cast(int)((curtime-lastthink).total!"msecs");
211 { import core.stdc.stdio; printf("framelen=%d; curfp=%d\n", framelen, curfp); }
217 // build background layer
219 //glDisable(GL_BLEND);
220 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
221 glClear(GL_COLOR_BUFFER_BIT
);
222 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
223 orthoCamera(map
.width
*8, map
.height
*8);
225 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
228 drawAtXY(map.skytexgl.tid, mapOfsX/2-map.MapSize*8, mapOfsY/2-map.MapSize*8, map.MapSize*8, map.MapSize*8);
229 drawAtXY(map.skytexgl.tid, mapOfsX/2-map.MapSize*8, mapOfsY/2, map.MapSize*8, map.MapSize*8);
230 drawAtXY(map.skytexgl.tid, mapOfsX/2, mapOfsY/2-map.MapSize*8, map.MapSize*8, map.MapSize*8);
231 drawAtXY(map.skytexgl.tid, mapOfsX/2, mapOfsY/2, map.MapSize*8, map.MapSize*8);
233 drawAtXY(map
.skytexgl
.tid
, 0, 0, map
.MapSize
*8, map
.MapSize
*8);
235 drawAtXY(map
.texgl
.ptr
[map
.Back
], 0, 0);
236 // draw distorted liquid areas
237 shadLiquidDistort
.exec((Shader shad
) {
238 shad
["iDistortTime"] = iLiquidTime
;
239 drawAtXY(map
.texgl
.ptr
[map
.AllLiquids
], 0, 0);
241 // monsters, items; we'll do linear interpolation here
242 // we need this for saved frame anyway, so let's play dirty and speed up the things
243 uint fxofs
= Actor
.fields
["x"].ofs
;
244 uint fyofs
= Actor
.fields
["y"].ofs
;
245 uint fzAnimstateofs
= Actor
.fields
["zAnimstate"].ofs
;
246 uint fdirofs
= Actor
.fields
["dir"].ofs
;
247 uint fzAnimidxofs
= Actor
.fields
["zAnimidx"].ofs
;
248 uint fclasstypeofs
= Actor
.fields
["classtype"].ofs
;
249 uint fclassnameofs
= Actor
.fields
["classname"].ofs
;
250 glColor3f(1.0f, 1.0f, 1.0f);
251 Actor
.forEach((ActorId me
) {
252 // `act` is always valid here
253 auto aptr
= me
.data
.ptr
;
254 auto ctstr
= StrId(*cast(uint*)(aptr
+fclasstypeofs
));
255 auto cnstr
= StrId(*cast(uint*)(aptr
+fclassnameofs
));
256 if (auto adef
= findActorDef(ctstr
, cnstr
)) {
257 ctstr
= StrId(*cast(uint*)(aptr
+fzAnimstateofs
));
258 if (auto isp
= adef
.animSpr(ctstr
, *cast(uint*)(aptr
+fdirofs
), *cast(int*)(aptr
+fzAnimidxofs
))) {
259 auto ofs
= prevFrameActorOfs
.ptr
[me
.id
&0xffff];
260 if (frameInterpolation
&& ofs
< uint.max
-1) {
261 import core
.stdc
.math
: roundf
;
262 auto xptr
= prevFrameActorsData
.ptr
+ofs
;
263 int ox
= *cast(int*)(xptr
+fxofs
);
264 int nx
= *cast(int*)(aptr
+fxofs
);
265 int oy
= *cast(int*)(xptr
+fyofs
);
266 int ny
= *cast(int*)(aptr
+fyofs
);
267 int x
= cast(int)(ox
+roundf((nx
-ox
)*atob
));
268 int y
= cast(int)(oy
+roundf((ny
-oy
)*atob
));
269 //conwriteln("actor ", me.id, "; o=(", ox, ",", oy, "); n=(", nx, ",", ny, "); p=(", x, ",", y, ")");
270 drawAtXY(isp
.tex
, x
-isp
.vga
.sx
, y
-isp
.vga
.sy
);
272 int nx
= *cast(int*)(aptr
+fxofs
)-isp
.vga
.sx
;
273 int ny
= *cast(int*)(aptr
+fyofs
)-isp
.vga
.sy
;
274 //conwriteln("actor ", me.id, "; nx=", nx, "; ny=", ny);
275 drawAtXY(isp
.tex
, nx
, ny
);
278 conwriteln("no animation for actor ", me
.id
, " (", me
.classtype
!string
, ":", me
.classname
!string
, ")");
281 conwriteln("not found actor ", me
.id
, " (", me
.classtype
!string
, ":", me
.classname
!string
, ")");
284 if (auto adef = findActorDef(me.classtype!StrId, me.classname!StrId)) {
285 if (auto isp = adef.animSpr(me.zAnimstate!StrId, me.dir!uint, me.zAnimidx!int)) {
286 int y = me.y!int-isp.vga.sy;
287 drawAtXY(isp.tex, me.x!int-isp.vga.sx, y);
288 //conwriteln("found animation for actor ", me.id, " (", me.classtype!string, ":", me.classname!string, ")", " (", adef.fullname, ")");
290 conwriteln("no animation for actor ", me.id, " (", me.classtype!string, ":", me.classname!string, ")");
293 conwriteln("not found actor ", me.id, " (", me.classtype!string, ":", me.classname!string, ")");
297 // do liquid coloring
298 drawAtXY(map
.texgl
.ptr
[map
.LiquidMask
], 0, 0);
299 // foreground -- hide secrets, draw lifts and such
300 drawAtXY(map
.texgl
.ptr
[map
.Front
], 0, 0);
307 glClearColor(BackIntens
, BackIntens
, BackIntens
, 1.0f);
308 //glClearColor(0.15f, 0.15f, 0.15f, 1.0f);
309 ////glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
310 glClear(GL_COLOR_BUFFER_BIT
);
313 // texture 1 is background
314 glActiveTexture(GL_TEXTURE0
+1);
315 glBindTexture(GL_TEXTURE_2D
, fboOrigBack
.tex
.tid
);
316 // texture 2 is occluders
317 glActiveTexture(GL_TEXTURE0
+2);
318 glBindTexture(GL_TEXTURE_2D
, map
.texgl
.ptr
[map
.LightMask
].tid
);
319 // done texture assign
320 glActiveTexture(GL_TEXTURE0
+0);
324 renderLight( 27, 391-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 100);
325 renderLight(542, 424-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 100);
326 renderLight(377, 368-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 32);
327 renderLight(147, 288-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 64);
328 renderLight( 71, 200-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
329 renderLight(249, 200-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
330 renderLight(426, 200-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
331 renderLight(624, 200-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
332 renderLight(549, 298-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 64);
333 renderLight( 74, 304-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 32);
335 renderLight(24*8+4, (24+18)*8-2+LYOfs
, SVec4F(0.6f, 0.0f, 0.0f, 1.0f), 128);
337 foreach (immutable _
; 0..1) {
338 renderLight(lightX
, lightY
, SVec4F(0.3f, 0.3f, 0.0f, 1.0f), 96);
341 glActiveTexture(GL_TEXTURE0
+1);
342 glBindTexture(GL_TEXTURE_2D
, 0);
343 glActiveTexture(GL_TEXTURE0
+2);
344 glBindTexture(GL_TEXTURE_2D
, 0);
345 glActiveTexture(GL_TEXTURE0
+0);
350 shadScanlines.exec((Shader shad) {
351 shad["scanlines"] = scanlines;
352 glClearColor(BackIntens, BackIntens, BackIntens, 1.0f);
353 glClear(GL_COLOR_BUFFER_BIT);
354 orthoCamera(vlWidth, vlHeight);
355 //orthoCamera(map.width*8*scale, map.height*8*scale);
356 //glMatrixMode(GL_MODELVIEW);
358 //glTranslatef(0.375, 0.375, 0); // to be pixel-perfect
359 // somehow, FBO objects are mirrored; wtf?!
360 drawAtXY(fboLevel.tex.tid, -mapOfsX, -mapOfsY, map.width*8*scale, map.height*8*scale, mirrorY:true);
364 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0);
366 orthoCamera(vlWidth
, vlHeight
);
367 drawAtXY(fboLevelLight
.tex
.tid
, -mapOfsX
, -mapOfsY
, map
.width
*8*scale
, map
.height
*8*scale
, mirrorY
:true);
371 // ////////////////////////////////////////////////////////////////////////// //
373 shared int diedie
= 0;
375 enum D2DFrameTime
= 55; // milliseconds
377 void renderThread () {
379 MonoTime prevFrameStartTime
= MonoTime
.currTime
;
380 version(use_vsync
) {} else MonoTime ltt
= MonoTime
.currTime
;
381 MonoTime lasttime
= MonoTime
.currTime
;
382 nextthink
= MonoTime
.currTime
;
383 lastthink
= nextthink
; // for interpolator
384 nextthink
+= dur
!"msecs"(D2DFrameTime
);
385 MonoTime fstime
, fetime
;
386 enum MaxFPSFrames
= 16;
387 float frtimes
= 0.0f;
390 int hushFrames
= 6; // ignore first `hushFrames` frames overtime
392 if (sdwindow
.closed
) break;
393 if (atomicLoad(diedie
) > 0) break;
395 fstime
= MonoTime
.currTime
;
398 if (nextthink
<= fstime
) {
401 nextthink
+= dur
!"msecs"(D2DFrameTime
);
402 // save snapshot for interpolator
403 Actor
.saveSnapshot(prevFrameActorsData
[], prevFrameActorOfs
.ptr
);
407 int thinkTime
= cast(int)((MonoTime
.currTime
-fstime
).total
!"msecs");
408 if (thinkTime
> 9) { import core
.stdc
.stdio
; printf("spent on thinking: %d msecs\n", thinkTime
); }
414 scope(exit
) sdwindow
.mtUnlock();
415 ctset
= sdwindow
.setAsCurrentOpenGlContextNT
;
418 { import core
.stdc
.stdio
; printf(" FUUUU\n"); }
419 //glXMakeCurrent(sdwindow.display, 0, null);
420 import core
.sys
.posix
.signal
: timespec
;
421 import core
.sys
.posix
.time
: nanosleep
;
424 ts
.tv_nsec
= 16*1000*1000; // milli to nano
425 nanosleep(&ts
, null); // idc how much time was passed
429 iLiquidTime
= cast(float)((fstime
-MonoTime
.zero
).total
!"msecs"%10000000)/18.0f*0.04f;
432 scope(exit
) sdwindow
.mtUnlock();
433 sdwindow
.swapOpenGlBuffers();
435 sdwindow
.releaseCurrentOpenGlContext();
438 fetime
= MonoTime
.currTime
;
439 // wait for 16 ms if we still have some time
442 // max 60 FPS; capped by vsync
443 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((fetime-fstime).total!"msecs")); }
444 if ((fetime
-fstime
).total
!"msecs" < 16) {
445 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((fetime-fstime).total!"msecs")); }
446 import core
.sys
.posix
.signal
: timespec
;
447 import core
.sys
.posix
.time
: nanosleep
;
450 ts
.tv_nsec
= (16-cast(int)((fetime
-fstime
).total
!"msecs"))*1000*1000; // milli to nano
451 nanosleep(&ts
, null); // idc how much time was passed
452 fetime
= MonoTime
.currTime
;
457 { import core
.stdc
.stdio
; printf(" spent whole %d msecs\n", cast(int)((fetime
-fstime
).total
!"msecs")); }
463 auto frameTime
= cast(float)(fetime
-prevFrameStartTime
).total
!"msecs"/1000.0f;
464 prevFrameStartTime
= fetime
;
465 frtimes
+= frameTime
;
466 if (++framenum
>= MaxFPSFrames || frtimes
>= 3.0f) {
467 import std
.string
: format
;
468 int newFPS
= cast(int)(cast(float)MaxFPSFrames
/frtimes
+0.5);
469 if (newFPS
!= prevFPS
) {
470 sdwindow
.title
= "%s / FPS:%s".format("D2D", newFPS
);
478 } catch (Exception e
) {
479 import core
.stdc
.stdio
;
480 fprintf(stderr
, "FUUUUUUUUUUUUUUUUUUUUUUUUUU\n");
482 if (sdwindow
.closed
) break;
483 if (atomicLoad(diedie
) > 0) break;
484 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((time-ltt).total!"msecs")); }
485 import core
.sys
.posix
.signal
: timespec
;
486 import core
.sys
.posix
.time
: nanosleep
;
489 ts
.tv_nsec
= 100*1000*1000; // milli to nano
490 nanosleep(&ts
, null); // idc how much time was passed
493 atomicStore(diedie
, 2);
497 // ////////////////////////////////////////////////////////////////////////// //
498 void closeWindow () {
499 if (atomicLoad(diedie
) != 2) {
500 atomicStore(diedie
, 1);
501 while (atomicLoad(diedie
) != 2) {}
503 if (!sdwindow
.closed
) {
510 // ////////////////////////////////////////////////////////////////////////// //
511 __gshared Thread renderTid
;
514 void main (string
[] args
) {
515 FuncPool
.dumpCode
= false;
516 FuncPool
.dumpCodeSize
= false;
517 dacsDumpSemantic
= false;
519 version(rdmd
) { dacsOptimize
= 0; }
520 bool compileOnly
= false;
522 for (usize idx
= 1; idx
< args
.length
; ++idx
) {
524 if (args
[idx
] == "--dump-code") FuncPool
.dumpCode
= true;
525 else if (args
[idx
] == "--dump-code-size") FuncPool
.dumpCodeSize
= true;
526 else if (args
[idx
] == "--dump-semantic") dacsDumpSemantic
= true;
527 else if (args
[idx
] == "--dump-all") { FuncPool
.dumpCode
= true; FuncPool
.dumpCodeSize
= true; dacsDumpSemantic
= true; }
528 else if (args
[idx
] == "--compile") compileOnly
= true;
529 else if (args
[idx
] == "--compile-only") compileOnly
= true;
530 else if (args
[idx
] == "--messages") ++dacsMessages
;
531 else if (args
[idx
] == "--no-copro") dacsOptimizeNoCoPro
= true;
532 else if (args
[idx
] == "--no-deadass") dacsOptimizeNoDeadAss
= true;
533 else if (args
[idx
] == "--no-purekill") dacsOptimizeNoPureKill
= true;
534 else if (args
[idx
].length
> 2 && args
[idx
][0..2] == "-O") {
535 import std
.conv
: to
;
536 ubyte olevel
= to
!ubyte(args
[idx
][2..$]);
537 dacsOptimize
= olevel
;
541 foreach (immutable c
; idx
+1..args
.length
) args
.ptr
[c
-1] = args
.ptr
[c
];
547 static void setDP () {
551 import std
.file
: thisExePath
;
552 import std
.path
: dirName
;
553 setDataPath(thisExePath
.dirName
);
555 addPK3(getDataPath
~"base.pk3"); loadWadScripts();
556 //addWad("/home/ketmar/k8prj/doom2d-tl/data/doom2d.wad"); loadWadScripts();
557 //addWad("/home/ketmar/k8prj/doom2d-tl/data/meat.wad"); loadWadScripts();
558 //addWad("/home/ketmar/k8prj/doom2d-tl/data/megadm.wad"); loadWadScripts();
559 //addWad("/home/ketmar/k8prj/doom2d-tl/data/megadm1.wad"); loadWadScripts();
560 //addWad("/home/ketmar/k8prj/doom2d-tl/data/superdm.wad"); loadWadScripts();
561 //addWad("/home/ketmar/k8prj/doom2d-tl/data/zadoomka.wad"); loadWadScripts();
562 scriptLoadingComplete();
567 if (compileOnly
) return;
573 setOpenGLContextVersion(3, 2); // up to GLSL 150
574 //openGLContextCompatible = false;
576 map
= new LevelMap("maps/map01.d2m");
580 map
.getThingPos(1/*ThingId.Player1*/, &mapOfsX
, &mapOfsY
);
582 mapOfsX
= (mapOfsX
*2)-vlWidth
/2;
583 if (mapOfsX
+vlWidth
> map
.width
*16) mapOfsX
= map
.width
*16-vlWidth
;
584 if (mapOfsX
< 0) mapOfsX
= 0;
585 mapOfsY
= (mapOfsY
*2)-vlHeight
/2;
586 if (mapOfsY
+vlHeight
> map
.height
*16) mapOfsY
= map
.height
*16-vlHeight
;
587 if (mapOfsY
< 0) mapOfsY
= 0;
590 sdwindow
= new SimpleWindow(vlWidth
, vlHeight
, "D2D", OpenGlOptions
.yes
, Resizablity
.fixedSize
);
592 sdwindow
.visibleForTheFirstTime
= delegate () {
593 sdwindow
.setAsCurrentOpenGlContext(); // make this window active
594 glbindLoadFunctions();
597 import core.stdc.stdio;
598 printf("GL version: %s\n", glGetString(GL_VERSION));
600 glGetIntegerv(GL_MAJOR_VERSION, &h);
601 glGetIntegerv(GL_MINOR_VERSION, &l);
602 printf("version: %d.%d\n", h, l);
603 printf("shader version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
605 glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS, &svcount);
607 printf("%d shader versions supported:\n", svcount);
608 foreach (GLuint n; 0..svcount) printf(" %d: %s\n", n, glGetStringi(GL_SHADING_LANGUAGE_VERSION, n));
612 glGetIntegerv(GL_NUM_EXTENSIONS, &ecount);
614 printf("%d extensions supported:\n", ecount);
615 foreach (GLuint n; 0..ecount) printf(" %d: %s\n", n, glGetStringi(GL_EXTENSIONS, n));
620 // check if we have sufficient shader version here
624 glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS
, &svcount
);
626 foreach (GLuint n
; 0..svcount
) {
627 import core
.stdc
.string
: strncmp
;
628 auto v
= glGetStringi(GL_SHADING_LANGUAGE_VERSION
, n
);
629 if (v
is null) continue;
630 if (strncmp(v
, "120", 3) != 0) continue;
631 if (v
[3] > ' ') continue;
636 if (!found
) assert(0, "can't find OpenGL GLSL 120");
638 auto adr
= glGetProcAddress("glTexParameterf");
639 if (adr
is null) assert(0);
642 sdwindow
.vsync
= false;
643 //sdwindow.useGLFinish = false;
645 //sdwindow.redrawOpenGlScene();
646 if (!sdwindow
.releaseCurrentOpenGlContext()) { import core
.stdc
.stdio
; printf("can't release OpenGL context(1)\n"); }
648 renderTid
= new Thread(&renderThread
);
653 //sdwindow.redrawOpenGlScene = delegate () { renderScene(); };
655 enum MSecsPerFrame
= 1000/30; /* 30 is FPS */
657 uint[8] frameTimes
= 1000;
658 enum { Left
, Right
, Up
, Down
}
659 bool[4] pressed
= false;
660 bool altMove
= false;
662 sdwindow
.eventLoop(MSecsPerFrame
,
664 if (sdwindow
.closed
) return;
665 if (pressed
[Left
]) mapOfsX
-= 8;
666 if (pressed
[Right
]) mapOfsX
+= 8;
667 if (pressed
[Up
]) mapOfsY
-= 8;
668 if (pressed
[Down
]) mapOfsY
+= 8;
669 import std
.math
: cos
, sin
;
670 __gshared
float itime
= 0.0;
673 mapOfsX
= cast(int)(800.0/2.0+cos(itime
)*220.0);
674 mapOfsY
= cast(int)(800.0/2.0+120.0+sin(itime
)*160.0);
676 if (scale
== 1) mapOfsX
= mapOfsY
= 0;
677 //sdwindow.redrawOpenGlSceneNow();
679 delegate (KeyEvent event
) {
680 if (sdwindow
.closed
) return;
681 if (event
.pressed
&& event
.key
== Key
.Escape
) { closeWindow(); return; }
683 case Key
.X
: if (event
.pressed
) altMove
= !altMove
; break;
684 case Key
.Left
: if (altMove
) pressed
[Left
] = event
.pressed
; break;
685 case Key
.Right
: if (altMove
) pressed
[Right
] = event
.pressed
; break;
686 case Key
.Up
: if (altMove
) pressed
[Up
] = event
.pressed
; break;
687 case Key
.Down
: if (altMove
) pressed
[Down
] = event
.pressed
; break;
692 case Key
.Left
: case Key
.Pad4
: plrKeyUpDown(0, PLK_LEFT
, event
.pressed
); break;
693 case Key
.Right
: case Key
.Pad6
: plrKeyUpDown(0, PLK_RIGHT
, event
.pressed
); break;
694 case Key
.Up
: case Key
.Pad8
: plrKeyUpDown(0, PLK_UP
, event
.pressed
); break;
695 case Key
.Down
: case Key
.Pad2
: plrKeyUpDown(0, PLK_DOWN
, event
.pressed
); break;
696 case Key
.Alt
: plrKeyUpDown(0, PLK_JUMP
, event
.pressed
); break;
697 case Key
.Ctrl
: plrKeyUpDown(0, PLK_FIRE
, event
.pressed
); break;
698 case Key
.Shift
: plrKeyUpDown(0, PLK_USE
, event
.pressed
); break;
703 delegate (MouseEvent event
) {
704 lightX
= event
.x
/scale
;
705 lightY
= event
.y
/scale
;
706 lightX
+= mapOfsX
/scale
;
707 lightY
+= mapOfsY
/scale
;
709 delegate (dchar ch
) {
710 if (ch
== 'q') { closeWindow(); return; }
711 if (ch
== 's') scanlines
= !scanlines
;
712 if (ch
== '1') scale
= 1;
713 if (ch
== '2') scale
= 2;
714 if (ch
== 'i') frameInterpolation
= !frameInterpolation
;
715 if (ch
== ' ') movement
= !movement
;
718 } catch (Exception e
) {
719 import std
.stdio
: stderr
;
720 stderr
.writeln("FUUUUUUUUUUUU\n", e
.toString
);