1 /*
2 Copyright (C) 2015, by Laszlo Szeremi under the Boost license.
3 
4 VDP Engine
5 */
6 
7 
8 module app;
9 
10 import std.stdio;
11 import std..string;
12 import std.conv;
13 import std.format;
14 import std.random;
15 
16 import bindbc.sdl;
17 //import derelict.freeimage.freeimage;
18 
19 //import system.config;
20 
21 import PixelPerfectEngine.graphics.outputScreen;
22 import PixelPerfectEngine.graphics.raster;
23 import PixelPerfectEngine.graphics.layers;
24 
25 import PixelPerfectEngine.graphics.bitmap;
26 //import PixelPerfectEngine.collision;
27 import PixelPerfectEngine.system.input;
28 import PixelPerfectEngine.system.file;
29 import PixelPerfectEngine.system.etc;
30 import PixelPerfectEngine.system.config;
31 //import PixelPerfectEngine.system.binarySearchTree;
32 import PixelPerfectEngine.system.common;
33 
34 public import editor;
35 //import PixelPerfectEngine.extbmp.extbmp;
36 
37 public Editor prg;
38 
39 int main(string[] args){
40 	initialzeSDL();
41 
42 	if (args.length > 1) {
43 		if (args[1] == "--test") {
44 			bool testTransformableTileLayer;
45 			if (args.length > 2) 
46 				if (args[2] == "transform")
47 					testTransformableTileLayer = true;
48 			TileLayerTest lprg = new TileLayerTest(testTransformableTileLayer, 8, 8);
49 			lprg.whereTheMagicHappens;
50 			return 0;
51 		}
52 	}
53 
54 	prg = new Editor(args);
55 	prg.whereTheMagicHappens;
56 	return 0;
57 }
58 
59 class TileLayerTest : SystemEventListener, InputListener{
60 	bool isRunning, up, down, left, right, scrup, scrdown, scrleft, scrright;
61 	OutputScreen output;
62 	Raster r;
63 	TileLayer t;
64 	TileLayer textLayer;
65 	TransformableTileLayer!(Bitmap8Bit,16,16) tt;
66 	Bitmap8Bit[] tiles;
67 	Bitmap8Bit dlangMan;
68 	SpriteLayer s;
69 	InputHandler ih;
70 	float theta;
71 	int framecounter;
72 	this (bool testTransformableTileLayer, int mapWidth, int mapHeight) {
73 		theta = 0;
74 		isRunning = true;
75 		Image tileSource = loadImage(File("../assets/sci-fi-tileset.png"));
76 		//Image tileSource = loadImage(File("../assets/_system/concreteGUIE0.tga"));
77 		Image spriteSource = loadImage(File("../assets/d-man.tga"));
78 		Image fontSource = loadImage(File("../system/codepage_8_8.png"));
79 		output = new OutputScreen("TileLayer test", 424 * 4, 240 * 4);
80 		r = new Raster(424,240,output,0);
81 		output.setMainRaster(r);
82 		t = new TileLayer(16,16, RenderingMode.Copy);
83 		textLayer = new TileLayer(8,8, RenderingMode.AlphaBlend);
84 		textLayer.paletteOffset = 512;
85 		textLayer.masterVal = 127;
86 		textLayer.loadMapping(53, 30, new MappingElement[](53 * 30));
87 		tt = new TransformableTileLayer!(Bitmap8Bit,16,16)(RenderingMode.Copy);
88 		s = new SpriteLayer(RenderingMode.AlphaBlend);
89 		if (testTransformableTileLayer) r.addLayer(tt, 0);
90 		else r.addLayer(t, 0);
91 		r.addLayer(s, 1);
92 		r.addLayer(textLayer, 65_536);
93 		//writeln(r.layerMap);
94 		//c = new CollisionDetector();
95 		dlangMan = loadBitmapFromImage!Bitmap8Bit(spriteSource);
96 		//CollisionModel cm = new CollisionModel(dlangMan.width, dlangMan.height, dlangMan.generateStandardCollisionModel());
97 		//dlangMan.offsetIndexes(256,false);
98 		s.addSprite(dlangMan, 65_536, 0, 0, 1);
99 		writeln(s.getDisplayListItem(65_536).toString);
100 		//s.scaleSpriteHoriz(0,-1024);
101 		//s.scaleSpriteVert(0,-1024);
102 		for(int i = 1 ; i < 10 ; i++){
103 			s.addSprite(dlangMan, i, uniform(0,320), uniform(0,240), 1);
104 			//assert(check, "DisplayList Error!");
105 		}
106 		//s.collisionDetector[1] = c;
107 		//c.source = s;
108 		//c.addCollisionModel(cm,0);
109 		//c.addCollisionModel(cm,1);
110 		//c.addCollisionListener(this);
111 		//tiles.length = tileSource.bitmapID.length;
112 		tiles = loadBitmapSheetFromImage!Bitmap8Bit(tileSource, 16, 16);//loadBitmapSheetFromFile!Bitmap8Bit("../assets/sci-fi-tileset.png",16,16);
113 		//tiles = loadBitmapSheetFromFile!(Bitmap8Bit)("../assets/sci-fi-tileset.png", 16, 16);
114 		if (testTransformableTileLayer) {
115 			for (int i; i < tiles.length; i++) {
116 				tt.addTile(tiles[i], cast(wchar)i);
117 			}
118 		} else {
119 			for (int i; i < tiles.length; i++) {
120 				t.addTile(tiles[i], cast(wchar)i);
121 			}
122 		}
123 		{
124 			Bitmap8Bit[] fontSet = loadBitmapSheetFromImage!Bitmap8Bit(fontSource, 8, 8);
125 			for (ushort i; i < fontSet.length; i++) {
126 				textLayer.addTile(fontSet[i], i, 1);
127 			}
128 		}
129 		//wchar[] mapping;
130 		MappingElement[] mapping;
131 		mapping.length = mapWidth * mapHeight;//64*64;
132 		//attrMapping.length = 256*256;
133 		for(int i; i < mapping.length; i++){
134 			//mapping[i] = to!wchar(uniform(0x0000,0x00AA));
135 			const int rnd = uniform(0,1024);
136 			//attrMapping[i] = BitmapAttrib(rnd & 1 ? true : false, rnd & 2 ? true : false);
137 			mapping[i] = MappingElement(cast(wchar)(rnd & 63), BitmapAttrib(rnd & 1024 ? true : false, rnd & 512 ? true : false));
138 			//mapping[i] = MappingElement(0x0, BitmapAttrib(false,false));
139 		}
140 		ih = new InputHandler();
141 		ih.systemEventListener = this;
142 		ih.inputListener = this;
143 		/+ih.kb ~= KeyBinding(0, SDL_SCANCODE_UP,0, "up", Devicetype.KEYBOARD, KeyModifier.All);
144 		ih.kb ~= KeyBinding(0, SDL_SCANCODE_DOWN,0, "down", Devicetype.KEYBOARD, KeyModifier.All);
145 		ih.kb ~= KeyBinding(0, SDL_SCANCODE_LEFT,0, "left", Devicetype.KEYBOARD, KeyModifier.All);
146 		ih.kb ~= KeyBinding(0, SDL_SCANCODE_RIGHT,0, "right", Devicetype.KEYBOARD, KeyModifier.All);
147 		ih.kb ~= KeyBinding(0, ScanCode.np8,0, "scrup", Devicetype.KEYBOARD, KeyModifier.All);
148 		ih.kb ~= KeyBinding(0, ScanCode.np2,0, "scrdown", Devicetype.KEYBOARD, KeyModifier.All);
149 		ih.kb ~= KeyBinding(0, ScanCode.np4,0, "scrleft", Devicetype.KEYBOARD, KeyModifier.All);
150 		ih.kb ~= KeyBinding(0, ScanCode.np6,0, "scrright", Devicetype.KEYBOARD, KeyModifier.All);
151 		ih.kb ~= KeyBinding(0, ScanCode.F1,0, "A+", Devicetype.KEYBOARD, KeyModifier.All);
152 		ih.kb ~= KeyBinding(0, ScanCode.F2,0, "A-", Devicetype.KEYBOARD, KeyModifier.All);
153 		ih.kb ~= KeyBinding(0, ScanCode.F3,0, "B+", Devicetype.KEYBOARD, KeyModifier.All);
154 		ih.kb ~= KeyBinding(0, ScanCode.F4,0, "B-", Devicetype.KEYBOARD, KeyModifier.All);
155 		ih.kb ~= KeyBinding(0, ScanCode.F5,0, "C+", Devicetype.KEYBOARD, KeyModifier.All);
156 		ih.kb ~= KeyBinding(0, ScanCode.F6,0, "C-", Devicetype.KEYBOARD, KeyModifier.All);
157 		ih.kb ~= KeyBinding(0, ScanCode.F7,0, "D+", Devicetype.KEYBOARD, KeyModifier.All);
158 		ih.kb ~= KeyBinding(0, ScanCode.F8,0, "D-", Devicetype.KEYBOARD, KeyModifier.All);
159 		ih.kb ~= KeyBinding(0, ScanCode.F9,0, "x0+", Devicetype.KEYBOARD, KeyModifier.All);
160 		ih.kb ~= KeyBinding(0, ScanCode.F10,0, "x0-", Devicetype.KEYBOARD, KeyModifier.All);
161 		ih.kb ~= KeyBinding(0, ScanCode.PAGEUP,0, "y0+", Devicetype.KEYBOARD, KeyModifier.All);
162 		ih.kb ~= KeyBinding(0, ScanCode.PAGEDOWN,0, "y0-", Devicetype.KEYBOARD, KeyModifier.All);
163 		ih.kb ~= KeyBinding(0, ScanCode.NP_PLUS,0, "theta+", Devicetype.KEYBOARD, KeyModifier.All);
164 		ih.kb ~= KeyBinding(0, ScanCode.NP_MINUS,0, "theta-", Devicetype.KEYBOARD, KeyModifier.All);
165 		ih.kb ~= KeyBinding(0, ScanCode.n1,0, "sV+", Devicetype.KEYBOARD, KeyModifier.All);
166 		ih.kb ~= KeyBinding(0, ScanCode.n2,0, "sV-", Devicetype.KEYBOARD, KeyModifier.All);
167 		ih.kb ~= KeyBinding(0, ScanCode.n3,0, "sH+", Devicetype.KEYBOARD, KeyModifier.All);
168 		ih.kb ~= KeyBinding(0, ScanCode.n4,0, "sH-", Devicetype.KEYBOARD, KeyModifier.All);
169 		ih.kb ~= KeyBinding(0, ScanCode.Q,0, "HM", Devicetype.KEYBOARD, KeyModifier.All);
170 		ih.kb ~= KeyBinding(0, ScanCode.W,0, "VM", Devicetype.KEYBOARD, KeyModifier.All);+/
171 		{
172 			import PixelPerfectEngine.system.input.scancode;
173 			ih.addBinding(BindingCode(ScanCode.UP, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("up"));
174 			ih.addBinding(BindingCode(ScanCode.DOWN, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("down"));
175 			ih.addBinding(BindingCode(ScanCode.LEFT, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("left"));
176 			ih.addBinding(BindingCode(ScanCode.RIGHT, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("right"));
177 			ih.addBinding(BindingCode(ScanCode.np8, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrup"));
178 			ih.addBinding(BindingCode(ScanCode.np2, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrdown"));
179 			ih.addBinding(BindingCode(ScanCode.np4, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrleft"));
180 			ih.addBinding(BindingCode(ScanCode.np6, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrright"));
181 			ih.addBinding(BindingCode(ScanCode.Q, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("A+"));
182 			ih.addBinding(BindingCode(ScanCode.A, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("A-"));
183 			ih.addBinding(BindingCode(ScanCode.W, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("B+"));
184 			ih.addBinding(BindingCode(ScanCode.S, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("B-"));
185 			ih.addBinding(BindingCode(ScanCode.E, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("C+"));
186 			ih.addBinding(BindingCode(ScanCode.D, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("C-"));
187 			ih.addBinding(BindingCode(ScanCode.R, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("D+"));
188 			ih.addBinding(BindingCode(ScanCode.F, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("D-"));
189 			ih.addBinding(BindingCode(ScanCode.T, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("x0+"));
190 			ih.addBinding(BindingCode(ScanCode.G, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("x0-"));
191 			ih.addBinding(BindingCode(ScanCode.Y, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("y0+"));
192 			ih.addBinding(BindingCode(ScanCode.H, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("y0-"));
193 			ih.addBinding(BindingCode(ScanCode.PAGEUP, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("alpha+"));
194 			ih.addBinding(BindingCode(ScanCode.PAGEDOWN, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("alpha-"));
195 		}
196 		if (testTransformableTileLayer) {
197 			tt.loadMapping(mapWidth, mapHeight, mapping);
198 			tt.warpMode = WarpMode.TileRepeat;
199 		} else {
200 			t.loadMapping(mapWidth, mapHeight, mapping);
201 			t.warpMode = WarpMode.TileRepeat;
202 		}
203 		//t.setWrapMode(true);
204 		//tt.D = -256;
205 		//loadPaletteFromXMP(tileSource, "default", r);
206 
207 		/*for(int y ; y < 240 ; y++){
208 			for(int x ; x < 240 ; x++){
209 				writeln('[',x,',',y,"] : ", t.transformFunc([x,y]));
210 			}
211 		}*/
212 		Color[] localPal = loadPaletteFromImage(tileSource);
213 		localPal.length = 256;
214 		r.addPaletteChunk(localPal);
215 		localPal = loadPaletteFromImage(spriteSource);
216 		localPal.length = 256;
217 		r.addPaletteChunk(localPal);
218 		r.addPaletteChunk([Color(0x00,0x00,0x00,0xFF),Color(0xff,0xff,0xff,0xFF),Color(0x00,0x00,0x00,0xFF),
219 				Color(0xff,0x00,0x00,0xFF),Color(0x00,0x00,0x00,0xFF),Color(0x00,0xff,0x00,0xFF),Color(0x00,0x00,0x00,0xFF),
220 				Color(0x00,0x00,0xff,0xFF)]);
221 		//writeln(r.palette);
222 		//r.palette[0].alpha = 255;
223 		r.palette[256].base = 0;
224 		//textLayer.writeTextToMap(2,2,0,"Hello world!",BitmapAttrib(true, false));
225 		textLayer.writeTextToMap(0,0,0,"Framerate:",BitmapAttrib(true, false));
226 		//writeln(tt);
227 		//r.palette[0] = 255;
228 		//r.addRefreshListener(output, 0);
229 
230 	}
231 	private @nogc void ttlHBlankInterrupt(ref short[4] localABCD, ref short[2] localsXsY, ref short[2] localx0y0, short y){
232 		localABCD[0]++;
233 	}
234 	public void whereTheMagicHappens(){
235 		while(isRunning){
236 			r.refresh();
237 			ih.test();
238 			if(up) s.relMoveSprite(65_536,0,-1);
239 			if(down) s.relMoveSprite(65_536,0,1);
240 			if(left) s.relMoveSprite(65_536,-1,0);
241 			if(right) s.relMoveSprite(65_536,1,0);
242 			
243 			if(scrup) {
244 				t.relScroll(0,-1);
245 				tt.relScroll(0,-1);
246 				s.relScroll(0,-1);
247 			}
248 			if(scrdown) {
249 				t.relScroll(0,1);
250 				tt.relScroll(0,1);
251 				s.relScroll(0,1);
252 			}
253 			if(scrleft) {
254 				t.relScroll(-1,0);
255 				tt.relScroll(-1,0);
256 				s.relScroll(-1,0);
257 			}
258 			if(scrright) {
259 				t.relScroll(1,0);
260 				tt.relScroll(1,0);
261 				s.relScroll(1,0);
262 			}
263 			
264 			framecounter++;
265 			if(framecounter == 10){
266 				textLayer.writeTextToMap(10,0,0,format("%3.3f"w,r.avgfps),BitmapAttrib(true, false));
267 				framecounter = 0;
268 			}
269 			//t.relScroll(1,0);
270 		}
271 	}
272 	override public void onQuit() {
273 		isRunning = false;
274 	}
275 	public void controllerAdded(uint id) {
276 
277 	}
278 	public void controllerRemoved(uint id) {
279 
280 	}
281 	/+override public void keyPressed(string ID,uint timestamp,uint devicenumber,uint devicetype) {
282 		//writeln(ID);
283 		import PixelPerfectEngine.graphics.transformFunctions;
284 		switch(ID){
285 			case "up": up = true; break;
286 			case "down": down = true; break;
287 			case "left": left = true; break;
288 			case "right": right = true; break;
289 			case "scrup": scrup = true; break;
290 			case "scrdown": scrdown = true; break;
291 			case "scrleft": scrleft = true; break;
292 			case "scrright": scrright = true; break;
293 			case "A+": tt.A = cast(short)(tt.A + 16); break;
294 			case "A-": tt.A = cast(short)(tt.A - 16); break;
295 			case "B+": tt.B = cast(short)(tt.B + 16); break;
296 			case "B-": tt.B = cast(short)(tt.B - 16); break;
297 			case "C+": tt.C = cast(short)(tt.C + 16); break;
298 			case "C-": tt.C = cast(short)(tt.C - 16); break;
299 			case "D+": tt.D = cast(short)(tt.D + 16); break;
300 			case "D-": tt.D = cast(short)(tt.D - 16); break;
301 			case "x0+": tt.x_0 = cast(short)(tt.x_0 + 1); break;
302 			case "x0-": tt.x_0 = cast(short)(tt.x_0 - 1); break;
303 			case "y0+": tt.y_0 = cast(short)(tt.y_0 + 1); break;
304 			case "y0-": tt.y_0 = cast(short)(tt.y_0 - 1); break;
305 			case "sH-":
306 				if(s.getScaleSpriteHoriz(0) == 16){
307 					s.scaleSpriteHoriz(0,-16);
308 					return;
309 				}
310 				s.scaleSpriteHoriz(0,s.getScaleSpriteHoriz(0) - 16);
311 				//writeln(s.getScaleSpriteHoriz(0));
312 				break;
313 			case "sH+":
314 				if(s.getScaleSpriteHoriz(0) == -16){
315 					s.scaleSpriteHoriz(0,16);
316 					return;
317 				}
318 				s.scaleSpriteHoriz(0,s.getScaleSpriteHoriz(0) + 16);
319 				//writeln(s.getScaleSpriteHoriz(0));
320 				break;
321 			case "sV-":
322 				if(s.getScaleSpriteVert(0) == 16){
323 					s.scaleSpriteVert(0,-16);
324 					return;
325 				}
326 				s.scaleSpriteVert(0,s.getScaleSpriteVert(0) - 16);
327 				break;
328 			case "sV+":
329 				if(s.getScaleSpriteVert(0) == -16){
330 					s.scaleSpriteVert(0,16);
331 					return;
332 				}
333 				s.scaleSpriteVert(0,s.getScaleSpriteVert(0) + 16);
334 				break;
335 			case "HM":
336 				s.scaleSpriteHoriz(0,s.getScaleSpriteHoriz(0) * -1);
337 				break;
338 			case "VM":
339 				s.scaleSpriteVert(0,s.getScaleSpriteVert(0) * -1);
340 				break;
341 			case "theta+":
342 				theta += 1;
343 				short[4] newTP = rotateFunction(theta);
344 				tt.A = newTP[0];
345 				tt.B = newTP[1];
346 				tt.C = newTP[2];
347 				tt.D = newTP[3];
348 				break;
349 			case "theta-":
350 				theta -= 1;
351 				short[4] newTP = rotateFunction(theta);
352 				tt.A = newTP[0];
353 				tt.B = newTP[1];
354 				tt.C = newTP[2];
355 				tt.D = newTP[3];
356 				break;
357 			default: break;
358 		}
359 	}
360 	override public void keyReleased(string ID,uint timestamp,uint devicenumber,uint devicetype) {
361 		switch(ID){
362 			case "up": up = false; break;
363 			case "down": down = false; break;
364 			case "left": left = false; break;
365 			case "right": right = false; break;
366 			case "scrup": scrup = false; break;
367 			case "scrdown": scrdown = false; break;
368 			case "scrleft": scrleft = false; break;
369 			case "scrright": scrright = false; break;
370 			default: break;
371 		}
372 	}+/
373 /*public void spriteCollision(CollisionEvent ce){
374 		writeln("COLLISION!!!!11!1111!!!ONEONEONE!!!");
375 	}
376 
377 	public void backgroundCollision(CollisionEvent ce){}*/
378 	/**
379 	 * Called when a keybinding event is generated.
380 	 * The `id` should be generated from a string, usually the name of the binding.
381 	 * `code` is a duplicate of the code used for fast lookup of the binding, which also contains other info (deviceID, etc).
382 	 * `timestamp` is the time lapsed since the start of the program, can be used to measure time between keypresses.
383 	 * NOTE: Hat events on joysticks don't generate keyReleased events, instead they generate keyPressed events on release.
384 	 */
385 	public void keyEvent(uint id, BindingCode code, uint timestamp, bool isPressed) {
386 		writeln(id, ";", code, ";",timestamp, ";",isPressed, ";");
387 		switch (id) {
388 			case 1720810685:	//up
389 				up = isPressed;
390 				break;
391 			case 1672064345:	//down
392 				down = isPressed;
393 				break;
394 			case 2840212248:	//left
395 				left = isPressed;
396 				break;
397 			case 1786548735:	//right
398 				right = isPressed;
399 				break;
400 			case 3938104347:	//scrup
401 				scrup = isPressed;
402 				break;
403 			case 131561283:		//scrdown
404 				scrdown = isPressed;
405 				break;
406 			case 4011913815:	//scrleft
407 				scrleft = isPressed;
408 				break;
409 			case 2073272778:	//scrright
410 				scrright = isPressed;
411 				break;
412 			case 4284782897: 	//A+
413 				tt.A = cast(short)(tt.A + 16);
414 				break;
415 			case 142754382:		//A-
416 				tt.A = cast(short)(tt.A - 16);
417 				break;
418 			case 2060572171:	//B+
419 				tt.B = cast(short)(tt.B + 16);
420 				break;
421 			case 919786464:		//B-
422 				tt.B = cast(short)(tt.B - 16);
423 				break;
424 			case 2857229774:	//C+
425 				tt.C = cast(short)(tt.C + 16);
426 				break;
427 			case 1598464886:	//C-
428 				tt.C = cast(short)(tt.C - 16);
429 				break;
430 			case 2476135441:	//D+
431 				tt.D = cast(short)(tt.D + 16);
432 				break;
433 			case 3708187064:	//D-
434 				tt.D = cast(short)(tt.D - 16);
435 				break;
436 			case 3238134781:	//x0+
437 				tt.x_0 = cast(short)(tt.x_0 + 1);
438 				break;
439 			case 135027337:		//x0-
440 				tt.x_0 = cast(short)(tt.x_0 - 1);
441 				break;
442 			case 983492653:		//y0+
443 				tt.y_0 = cast(short)(tt.y_0 + 1);
444 				break;
445 			case 2733639921:	//y0-
446 				tt.y_0 = cast(short)(tt.y_0 - 1);
447 				break;
448 			default:
449 				break;
450 		}
451 	}
452 	/**
453 	 * Called when an axis is being operated.
454 	 * The `id` should be generated from a string, usually the name of the binding.
455 	 * `code` is a duplicate of the code used for fast lookup of the binding, which also contains other info (deviceID, etc).
456 	 * `timestamp` is the time lapsed since the start of the program, can be used to measure time between keypresses.
457 	 * `value` is the current position of the axis normalized between -1.0 and +1.0 for joysticks, and 0.0 and +1.0 for analog
458 	 * triggers.
459 	 */
460 	public void axisEvent(uint id, BindingCode code, uint timestamp, float value) {
461 
462 	}
463 }