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 // ////////////////////////////////////////////////////////////////////////// //
41 enum MaxLightRadius
= 512;
44 // ////////////////////////////////////////////////////////////////////////// //
46 __gshared FBO
[MaxLightRadius
+1] fboOccluders
, fboShadowMap
;
47 __gshared Shader shadToPolar
, shadBlur
;
49 __gshared FBO fboLevel
, fboOrigBack
;
50 __gshared Shader shadScanlines
;
51 __gshared Shader shadLiquidDistort
, shadLiquidColor
;
54 // ////////////////////////////////////////////////////////////////////////// //
56 glEnable(GL_TEXTURE_2D
);
57 glDisable(GL_LIGHTING
);
60 glDisable(GL_DEPTH_TEST
);
63 shadScanlines
= new Shader("scanlines", loadTextFile("data/shaders/srscanlines.frag"));
65 shadLiquidDistort
= new Shader("liquid_distort", loadTextFile("data/shaders/srliquid_distort.frag"));
66 shadLiquidDistort
.exec({ shadLiquidDistort
["tex0"] = 0; });
68 shadLiquidColor
= new Shader("liquid_color", loadTextFile("data/shaders/srliquid_color.frag"));
69 shadLiquidColor
.exec({ shadLiquidColor
["tex0"] = 0; });
72 shadToPolar
= new Shader("topolar", loadTextFile("data/shaders/srlight_topolar.frag"));
73 shadBlur
= new Shader("blur", loadTextFile("data/shaders/srlight_blur.frag"));
79 foreach (int sz
; 2..MaxLightRadius
+1) {
80 fboOccluders
[sz
] = new FBO(sz
*2, sz
*2, Texture
.Option
.Clamp
); // create occluders FBO
81 fboShadowMap
[sz
] = new FBO(sz
*2, 1, Texture
.Option
.Clamp
); // create 1d shadowmap FBO
85 glMatrixMode(GL_MODELVIEW
);
90 fboLevel
= new FBO(map
.width
*8, map
.height
*8, Texture
.Option
.Nearest
); // final level render will be here
91 fboOrigBack
= new FBO(map
.width
*8, map
.height
*8, Texture
.Option
.Nearest
); // original background
94 shadBlur
["mapPixSize"] = SVec2F(map
.width
*8, map
.height
*8);
97 // build noise texture for liquid shaders
99 glActiveTexture(GL_TEXTURE0+1);
101 import std.random : uniform;
102 auto img = new TrueColorImage(64, 64);
103 foreach (int y; 0..img.width) {
104 foreach (int x; 0..img.height) {
105 ubyte b = cast(ubyte)uniform(0, 256);
106 img.imageData.colors[y*img.width+x] = Color(b, b, b, 255);
109 auto tex = new Texture(img);
114 glActiveTexture(GL_TEXTURE0
+0);
115 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0);
116 orthoCamera(vlWidth
, vlHeight
);
118 Actor
.resetStorage();
120 //map.initActors(); // this will precache sprites too
121 //map.doAllActorTicks();
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 glColor3f(0.0f, 0.0f, 0.0f);
140 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
141 glClear(GL_COLOR_BUFFER_BIT
);
142 orthoCamera(lightSize
, lightSize
);
143 drawAtXY(map
.texgl
.ptr
[map
.LightMask
], lightRadius
-lightX
, lightRadius
-lightY
);
146 // build 1d shadow map to fboShadowMapId
147 fboShadowMap
[lightRadius
].exec({
149 glColor3f(0.0f, 0.0f, 0.0f);
150 shadToPolar
["lightTexSize"] = SVec2F(lightSize
, lightSize
);
151 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
152 glClear(GL_COLOR_BUFFER_BIT
);
153 orthoCamera(lightSize
, 1);
154 drawAtXY(fboOccluders
[lightRadius
].tex
.tid
, 0, 0, lightSize
, 1);
161 shadBlur
["lightTexSize"] = SVec2F(lightSize
, lightSize
);
163 glBlendFunc(GL_SRC_ALPHA
, GL_ONE
);
165 glColor4f(lcol
.x
, lcol
.y
, lcol
.z
, lcol
.w
);
166 orthoCamera(map
.width
*8, map
.height
*8);
167 drawAtXY(fboShadowMap
[lightRadius
].tex
.tid
, lightX
-lightRadius
, lightY
-lightRadius
, lightSize
, lightSize
);
173 // ////////////////////////////////////////////////////////////////////////// //
174 __gshared
int lightX
= vlWidth
/2, lightY
= vlHeight
/2;
175 __gshared
int mapOfsX
, mapOfsY
;
176 __gshared
bool movement
= false;
179 void renderScene () {
180 enum BackIntens
= 0.05f;
186 glClearColor(BackIntens
, BackIntens
, BackIntens
, 1.0f);
187 glClear(GL_COLOR_BUFFER_BIT
);
190 // build background layer
194 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
195 glClear(GL_COLOR_BUFFER_BIT
);
196 //glEnable(GL_BLEND);
197 //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
198 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
199 orthoCamera(map
.width
*8, map
.height
*8);
201 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
204 drawAtXY(map.skytexgl.tid, mapOfsX/2-map.MapSize*8, mapOfsY/2-map.MapSize*8, map.MapSize*8, map.MapSize*8);
205 drawAtXY(map.skytexgl.tid, mapOfsX/2-map.MapSize*8, mapOfsY/2, map.MapSize*8, map.MapSize*8);
206 drawAtXY(map.skytexgl.tid, mapOfsX/2, mapOfsY/2-map.MapSize*8, map.MapSize*8, map.MapSize*8);
207 drawAtXY(map.skytexgl.tid, mapOfsX/2, mapOfsY/2, map.MapSize*8, map.MapSize*8);
209 drawAtXY(map
.skytexgl
.tid
, 0, 0, map
.MapSize
*8, map
.MapSize
*8);
211 drawAtXY(map
.texgl
.ptr
[map
.Back
], 0, 0);
212 // draw distorted liquid areas
213 shadLiquidDistort
.exec({
214 __gshared
float iGlobalTime
= 0.0;
216 shadLiquidDistort
["iGlobalTime"] = iGlobalTime
;
217 shadLiquidDistort
["liquidColorMul"] = SVec4F(1.0f, 1.0f, 1.0f, 1.0f);
218 drawAtXY(map
.texgl
.ptr
[map
.Water
], 0, 0);
219 shadLiquidDistort
["liquidColorMul"] = SVec4F(0.6f, 0.6f, 0.6f, 1.0f);
220 drawAtXY(map
.texgl
.ptr
[map
.Lava
], 0, 0);
221 shadLiquidDistort
["liquidColorMul"] = SVec4F(1.0f, 1.0f, 1.0f, 1.0f);
222 drawAtXY(map
.texgl
.ptr
[map
.Acid
], 0, 0);
225 glColor3f(1.0f, 1.0f, 1.0f);
227 foreach (auto actor; actors) {
228 if (actor.frame is null || actor.dead) continue;
229 //conwriteln("(", actor.x, ", ", actor.y, ") ", actor.frame.tex.tid, " ", actor.frame.tex.width, "x", actor.frame.tex.height);
230 //drawAtXY(actor.frame.tex, actor.x/*-actor.frame.vga.sx*/, actor.y/*-actor.frame.vga.sy*/);
231 //int y = LevelMap.MapSize*8-actor.y-1/*-(actor.height-actor.frame.vga.sy)*/;
232 //int y = LevelMap.MapSize*8-actor.y+(actor.frame.vga.sy-actor.frame.vga.height);
233 int y = actor.y-actor.frame.vga.sy;
234 drawAtXY(actor.frame.tex, actor.x-actor.frame.vga.sx, y);
237 Actor
.forEach((ActorId me
) {
238 // `act` is always valid here
239 if (auto adef
= findActorDef(me
.classtype
!StrId
, me
.classname
!StrId
)) {
240 if (auto isp
= adef
.animSpr(me
.zAnimstate
!StrId
, me
.dir
!uint, me
.zAnimidx
!int)) {
241 int y
= me
.y
!int-isp
.vga
.sy
;
242 drawAtXY(isp
.tex
, me
.x
!int-isp
.vga
.sx
, y
);
243 //conwriteln("found animation for actor ", me.id, " (", me.classtype!string, ":", me.classname!string, ")", " (", adef.fullname, ")");
245 conwriteln("no animation for actor ", me
.id
, " (", me
.classtype
!string
, ":", me
.classname
!string
, ")");
248 conwriteln("not found actor ", me
.id
, " (", me
.classtype
!string
, ":", me
.classname
!string
, ")");
255 glBlendFunc(GL_SRC_ALPHA
, GL_ONE
);
257 glActiveTexture(GL_TEXTURE0
+1);
258 glBindTexture(GL_TEXTURE_2D
, /*map.texgl.ptr[map.Back].tid*/fboOrigBack
.tex
.tid
);
259 //glBindTexture(GL_TEXTURE_2D, map.texgl.ptr[map.Back].tid);
260 glActiveTexture(GL_TEXTURE0
+0);
264 renderLight( 27, 391-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 100);
265 renderLight(542, 424-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 100);
266 renderLight(377, 368-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 32);
267 renderLight(147, 288-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 64);
268 renderLight( 71, 200-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
269 renderLight(249, 200-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
270 renderLight(426, 200-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
271 renderLight(624, 200-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 128);
272 renderLight(549, 298-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 64);
273 renderLight( 74, 304-0+LYOfs
, SVec4F(0.0f, 0.0f, 0.0f, 0.0f), 32);
275 renderLight(24*8+4, (24+18)*8-2+LYOfs
, SVec4F(0.6f, 0.0f, 0.0f, 1.0f), 128);
276 foreach (immutable _
; 0..1) {
277 renderLight(lightX
, lightY
, SVec4F(0.3f, 0.3f, 0.0f, 1.0f), 96);
280 //glActiveTexture(GL_TEXTURE0+1);
281 //glBindTexture(GL_TEXTURE_2D, 0);
282 //glActiveTexture(GL_TEXTURE0+0);
284 // draw final opaque and full-lit parts
288 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
289 glColor3f(1.0f, 1.0f, 1.0f);
290 orthoCamera(map.width*8, map.height*8);
292 drawAtXY(map.texgl.ptr[map.LightMask], 0, 0);
293 // foreground -- hide secrets, draw lifts and such
294 drawAtXY(map.texgl.ptr[map.Front], 0, 0);
295 // now do liquid coloring
296 shadLiquidColor.exec({
298 //glEnable(GL_BLEND);
299 // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
300 //glBlendFunc(GL_SRC_ALPHA, GL_ONE);
301 //glDisable(GL_BLEND);
302 //glColor3f(1.0f, 1.0f, 1.0f);
303 shadLiquidColor["liquidColor"] = SVec4F(0.0f, 0.0f, 0.4f, 0.5f);
304 drawAtXY(map.texgl.ptr[map.Water], 0, 0);
305 shadLiquidColor["liquidColor"] = SVec4F(0.6f, 0.0f, 0.0f, 0.4f);
306 drawAtXY(map.texgl.ptr[map.Lava], 0, 0);
307 shadLiquidColor["liquidColor"] = SVec4F(0.1f, 0.4f, 0.0f, 0.5f);
308 drawAtXY(map.texgl.ptr[map.Acid], 0, 0);
315 shadScanlines
["scanlines"] = scanlines
;
316 glClearColor(BackIntens
, BackIntens
, BackIntens
, 1.0f);
317 glClear(GL_COLOR_BUFFER_BIT
);
318 orthoCamera(vlWidth
, vlHeight
);
319 //orthoCamera(map.width*8*scale, map.height*8*scale);
320 //glMatrixMode(GL_MODELVIEW);
322 //glTranslatef(0.375, 0.375, 0); // to be pixel-perfect
323 // somehow, FBO objects are mirrored; wtf?!
324 drawAtXY(fboLevel
.tex
.tid
, -mapOfsX
, -mapOfsY
, map
.width
*8*scale
, map
.height
*8*scale
, mirrorY
:true);
330 // ////////////////////////////////////////////////////////////////////////// //
332 shared int diedie
= 0;
334 enum D2DFrameTime
= 55; // milliseconds
336 void renderThread () {
338 MonoTime prevFrameStartTime
= MonoTime
.currTime
;
339 version(use_vsync
) {} else MonoTime ltt
= MonoTime
.currTime
;
340 MonoTime lasttime
= MonoTime
.currTime
;
341 MonoTime nextthink
= MonoTime
.currTime
;
342 nextthink
+= dur
!"msecs"(D2DFrameTime
);
343 MonoTime fstime
, fetime
;
344 enum MaxFPSFrames
= 16;
345 float frtimes
= 0.0f;
348 int hushFrames
= 6; // ignore first `hushFrames` frames overtime
350 if (sdwindow
.closed
) break;
351 if (atomicLoad(diedie
) > 0) break;
353 fstime
= MonoTime
.currTime
;
356 if (nextthink
<= fstime
) {
358 nextthink
+= dur
!"msecs"(D2DFrameTime
);
360 //{ import core.stdc.stdio; printf("spent on thinking: %d msecs\n", cast(int)((MonoTime.currTime-fstime).total!"msecs")); }
366 scope(exit
) sdwindow
.mtUnlock();
367 ctset
= sdwindow
.setAsCurrentOpenGlContextNT
;
370 { import core
.stdc
.stdio
; printf(" FUUUU\n"); }
371 //glXMakeCurrent(sdwindow.display, 0, null);
372 import core
.sys
.posix
.signal
: timespec
;
373 import core
.sys
.posix
.time
: nanosleep
;
376 ts
.tv_nsec
= 16*1000*1000; // milli to nano
377 nanosleep(&ts
, null); // idc how much time was passed
383 scope(exit
) sdwindow
.mtUnlock();
384 sdwindow
.swapOpenGlBuffers();
386 sdwindow
.releaseCurrentOpenGlContext();
389 fetime
= MonoTime
.currTime
;
390 // wait for 16 ms if we still have some time
393 // max 60 FPS; capped by vsync
394 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((fetime-fstime).total!"msecs")); }
395 if ((fetime
-fstime
).total
!"msecs" < 16) {
396 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((fetime-fstime).total!"msecs")); }
397 import core
.sys
.posix
.signal
: timespec
;
398 import core
.sys
.posix
.time
: nanosleep
;
401 ts
.tv_nsec
= (16-cast(int)((fetime
-fstime
).total
!"msecs"))*1000*1000; // milli to nano
402 nanosleep(&ts
, null); // idc how much time was passed
403 fetime
= MonoTime
.currTime
;
408 { import core
.stdc
.stdio
; printf(" spent whole %d msecs\n", cast(int)((fetime
-fstime
).total
!"msecs")); }
414 auto frameTime
= cast(float)(fetime
-prevFrameStartTime
).total
!"msecs"/1000.0f;
415 prevFrameStartTime
= fetime
;
416 frtimes
+= frameTime
;
417 if (++framenum
>= MaxFPSFrames || frtimes
>= 3.0f) {
418 import std
.string
: format
;
419 int newFPS
= cast(int)(cast(float)MaxFPSFrames
/frtimes
+0.5);
420 if (newFPS
!= prevFPS
) {
421 sdwindow
.title
= "%s / FPS:%s".format("D2D", newFPS
);
429 } catch (Exception e
) {
430 import core
.stdc
.stdio
;
431 fprintf(stderr
, "FUUUUUUUUUUUUUUUUUUUUUUUUUU\n");
433 if (sdwindow
.closed
) break;
434 if (atomicLoad(diedie
) > 0) break;
435 //{ import core.stdc.stdio; printf(" spent only %d msecs\n", cast(int)((time-ltt).total!"msecs")); }
436 import core
.sys
.posix
.signal
: timespec
;
437 import core
.sys
.posix
.time
: nanosleep
;
440 ts
.tv_nsec
= 100*1000*1000; // milli to nano
441 nanosleep(&ts
, null); // idc how much time was passed
444 atomicStore(diedie
, 2);
448 // ////////////////////////////////////////////////////////////////////////// //
449 void closeWindow () {
450 if (atomicLoad(diedie
) != 2) {
451 atomicStore(diedie
, 1);
452 while (atomicLoad(diedie
) != 2) {}
454 if (!sdwindow
.closed
) {
461 // ////////////////////////////////////////////////////////////////////////// //
462 __gshared Thread renderTid
;
465 void main (string
[] args
) {
466 FuncPool
.dumpCode
= false;
467 FuncPool
.dumpCodeSize
= false;
468 dacsDumpSemantic
= false;
470 version(rdmd
) { dacsOptimize
= 0; }
471 bool compileOnly
= false;
473 for (usize idx
= 1; idx
< args
.length
; ++idx
) {
475 if (args
[idx
] == "--dump-code") FuncPool
.dumpCode
= true;
476 else if (args
[idx
] == "--dump-code-size") FuncPool
.dumpCodeSize
= true;
477 else if (args
[idx
] == "--dump-semantic") dacsDumpSemantic
= true;
478 else if (args
[idx
] == "--compile") compileOnly
= true;
479 else if (args
[idx
] == "--messages") ++dacsMessages
;
480 else if (args
[idx
].length
> 2 && args
[idx
][0..2] == "-O") {
481 import std
.conv
: to
;
482 ubyte olevel
= to
!ubyte(args
[idx
][2..$]);
483 dacsOptimize
= olevel
;
487 foreach (immutable c
; idx
+1..args
.length
) args
.ptr
[c
-1] = args
.ptr
[c
];
493 static void setDP () {
497 import std
.file
: thisExePath
;
498 import std
.path
: dirName
;
499 setDataPath(thisExePath
.dirName
);
501 addPK3(getDataPath
~"base.pk3"); loadWadScripts();
502 //addWad("/home/ketmar/k8prj/doom2d-tl/data/doom2d.wad"); loadWadScripts();
503 //addWad("/home/ketmar/k8prj/doom2d-tl/data/meat.wad"); loadWadScripts();
504 //addWad("/home/ketmar/k8prj/doom2d-tl/data/megadm.wad"); loadWadScripts();
505 //addWad("/home/ketmar/k8prj/doom2d-tl/data/megadm1.wad"); loadWadScripts();
506 //addWad("/home/ketmar/k8prj/doom2d-tl/data/superdm.wad"); loadWadScripts();
507 //addWad("/home/ketmar/k8prj/doom2d-tl/data/zadoomka.wad"); loadWadScripts();
512 if (compileOnly
) return;
517 setOpenGLContextVersion(3, 2); // up to GLSL 150
518 //openGLContextCompatible = false;
520 map
= new LevelMap("maps/map01.d2m");
524 map
.getThingPos(1/*ThingId.Player1*/, &mapOfsX
, &mapOfsY
);
526 mapOfsX
= (mapOfsX
*2)-vlWidth
/2;
527 if (mapOfsX
+vlWidth
> map
.width
*16) mapOfsX
= map
.width
*16-vlWidth
;
528 if (mapOfsX
< 0) mapOfsX
= 0;
529 mapOfsY
= (mapOfsY
*2)-vlHeight
/2;
530 if (mapOfsY
+vlHeight
> map
.height
*16) mapOfsY
= map
.height
*16-vlHeight
;
531 if (mapOfsY
< 0) mapOfsY
= 0;
534 sdwindow
= new SimpleWindow(vlWidth
, vlHeight
, "D2D", OpenGlOptions
.yes
, Resizablity
.fixedSize
);
536 sdwindow
.visibleForTheFirstTime
= delegate () {
537 sdwindow
.setAsCurrentOpenGlContext(); // make this window active
538 glbindLoadFunctions();
541 import core.stdc.stdio;
542 printf("GL version: %s\n", glGetString(GL_VERSION));
544 glGetIntegerv(GL_MAJOR_VERSION, &h);
545 glGetIntegerv(GL_MINOR_VERSION, &l);
546 printf("version: %d.%d\n", h, l);
547 printf("shader version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
549 glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS, &svcount);
551 printf("%d shader versions supported:\n", svcount);
552 foreach (GLuint n; 0..svcount) printf(" %d: %s\n", n, glGetStringi(GL_SHADING_LANGUAGE_VERSION, n));
556 glGetIntegerv(GL_NUM_EXTENSIONS, &ecount);
558 printf("%d extensions supported:\n", ecount);
559 foreach (GLuint n; 0..ecount) printf(" %d: %s\n", n, glGetStringi(GL_EXTENSIONS, n));
564 // check if we have sufficient shader version here
568 glGetIntegerv(GL_NUM_SHADING_LANGUAGE_VERSIONS
, &svcount
);
570 foreach (GLuint n
; 0..svcount
) {
571 import core
.stdc
.string
: strncmp
;
572 auto v
= glGetStringi(GL_SHADING_LANGUAGE_VERSION
, n
);
573 if (v
is null) continue;
574 if (strncmp(v
, "120", 3) != 0) continue;
575 if (v
[3] > ' ') continue;
580 if (!found
) assert(0, "can't find OpenGL GLSL 120");
582 auto adr
= glGetProcAddress("glTexParameterf");
583 if (adr
is null) assert(0);
586 sdwindow
.vsync
= false;
587 //sdwindow.useGLFinish = false;
589 //sdwindow.redrawOpenGlScene();
590 if (!sdwindow
.releaseCurrentOpenGlContext()) { import core
.stdc
.stdio
; printf("can't release OpenGL context(1)\n"); }
592 renderTid
= new Thread(&renderThread
);
597 //sdwindow.redrawOpenGlScene = delegate () { renderScene(); };
599 enum MSecsPerFrame
= 1000/30; /* 30 is FPS */
601 uint[8] frameTimes
= 1000;
602 enum { Left
, Right
, Up
, Down
}
603 bool[4] pressed
= false;
605 sdwindow
.eventLoop(MSecsPerFrame
,
607 if (sdwindow
.closed
) return;
608 if (pressed
[Left
]) mapOfsX
-= 8;
609 if (pressed
[Right
]) mapOfsX
+= 8;
610 if (pressed
[Up
]) mapOfsY
-= 8;
611 if (pressed
[Down
]) mapOfsY
+= 8;
612 import std
.math
: cos
, sin
;
613 __gshared
float itime
= 0.0;
616 mapOfsX
= cast(int)(800.0/2.0+cos(itime
)*220.0);
617 mapOfsY
= cast(int)(800.0/2.0+120.0+sin(itime
)*160.0);
619 if (scale
== 1) mapOfsX
= mapOfsY
= 0;
620 //sdwindow.redrawOpenGlSceneNow();
622 delegate (KeyEvent event
) {
623 if (sdwindow
.closed
) return;
624 if (event
.pressed
&& event
.key
== Key
.Escape
) { closeWindow(); return; }
626 case Key
.Left
: pressed
[Left
] = event
.pressed
; break;
627 case Key
.Right
: pressed
[Right
] = event
.pressed
; break;
628 case Key
.Up
: pressed
[Up
] = event
.pressed
; break;
629 case Key
.Down
: pressed
[Down
] = event
.pressed
; break;
633 delegate (MouseEvent event
) {
634 lightX
= event
.x
/scale
;
635 lightY
= event
.y
/scale
;
636 lightX
+= mapOfsX
/scale
;
637 lightY
+= mapOfsY
/scale
;
639 delegate (dchar ch
) {
640 if (ch
== 'q') { closeWindow(); return; }
641 if (ch
== 's') scanlines
= !scanlines
;
642 if (ch
== '1') scale
= 1;
643 if (ch
== '2') scale
= 2;
644 if (ch
== ' ') movement
= !movement
;