webglmusti 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/.gitattributes +2 -0
  2. package/idea_list.txt +13 -0
  3. package/index.html +17 -0
  4. package/package.json +20 -0
  5. package/public/apple.png +0 -0
  6. package/public/base.png +0 -0
  7. package/public/car.png +0 -0
  8. package/public/drop.png +0 -0
  9. package/public/font16-Sheet.png +0 -0
  10. package/public/font16-Sheet.txt +52 -0
  11. package/public/letters-Sheet.png +0 -0
  12. package/public/letters-Sheet.txt +27 -0
  13. package/public/letters_Sheet.png +0 -0
  14. package/public/letters_Sheet.txt +4 -0
  15. package/public/vite.svg +1 -0
  16. package/src/App/ResourceSim/car.ts +172 -0
  17. package/src/App/ResourceSim/grid.ts +993 -0
  18. package/src/App/ResourceSim/grid_app.ts +1326 -0
  19. package/src/App/ResourceSim/grid_test.test.ts +18 -0
  20. package/src/App/ResourceSim/node_graph.ts +293 -0
  21. package/src/App/ResourceSim/nodes.ts +151 -0
  22. package/src/App/ResourceSim/resource.ts +8 -0
  23. package/src/App/ResourceSim/texts.ts +6 -0
  24. package/src/App/card/card.test.ts +22 -0
  25. package/src/App/card/card.ts +763 -0
  26. package/src/App/puzzle_box/app.ts +10 -0
  27. package/src/App/puzzle_box/engine.ts +374 -0
  28. package/src/App/puzzle_box/renderer.ts +102 -0
  29. package/src/App/puzzle_box/test.test.ts +49 -0
  30. package/src/App/water/water.ts +206 -0
  31. package/src/Interface/button.ts +345 -0
  32. package/src/Interface/interface_element.ts +30 -0
  33. package/src/Interface/internal_window.ts +100 -0
  34. package/src/Interface/options.ts +332 -0
  35. package/src/Interface/text_input.ts +183 -0
  36. package/src/WebGL/Matrix/matrix.test.ts +30 -0
  37. package/src/WebGL/Matrix/matrix.ts +293 -0
  38. package/src/WebGL/Shaders/Fragment/Program/circle.ts +49 -0
  39. package/src/WebGL/Shaders/Fragment/Program/circle_only.ts +47 -0
  40. package/src/WebGL/Shaders/Fragment/Program/circle_outline.ts +54 -0
  41. package/src/WebGL/Shaders/Fragment/Program/colour.ts +39 -0
  42. package/src/WebGL/Shaders/Fragment/Program/colour_alpha.ts +37 -0
  43. package/src/WebGL/Shaders/Fragment/Program/line.ts +39 -0
  44. package/src/WebGL/Shaders/Fragment/Program/multi_colour_centre_circle_path.ts +69 -0
  45. package/src/WebGL/Shaders/Fragment/Program/multi_colour_path.ts +69 -0
  46. package/src/WebGL/Shaders/Fragment/Program/path_centre_circle.ts +69 -0
  47. package/src/WebGL/Shaders/Fragment/Program/rect_outline.ts +39 -0
  48. package/src/WebGL/Shaders/Fragment/Program/solid_path.ts +64 -0
  49. package/src/WebGL/Shaders/Fragment/Program/sprite_sheet.ts +54 -0
  50. package/src/WebGL/Shaders/Fragment/Program/sprite_sheet_colour.ts +62 -0
  51. package/src/WebGL/Shaders/Fragment/Program/texture.ts +34 -0
  52. package/src/WebGL/Shaders/Fragment/Source/circle.frag +19 -0
  53. package/src/WebGL/Shaders/Fragment/Source/circle_only.frag +15 -0
  54. package/src/WebGL/Shaders/Fragment/Source/circle_outline.frag +23 -0
  55. package/src/WebGL/Shaders/Fragment/Source/colour.frag +9 -0
  56. package/src/WebGL/Shaders/Fragment/Source/colour_alpha.frag +7 -0
  57. package/src/WebGL/Shaders/Fragment/Source/fragment.frag +5 -0
  58. package/src/WebGL/Shaders/Fragment/Source/fragment_source.ts +15 -0
  59. package/src/WebGL/Shaders/Fragment/Source/line.frag +12 -0
  60. package/src/WebGL/Shaders/Fragment/Source/multi_colour_centre_circle_path.frag +36 -0
  61. package/src/WebGL/Shaders/Fragment/Source/multi_colour_path.frag +34 -0
  62. package/src/WebGL/Shaders/Fragment/Source/path_centre_circle.frag +29 -0
  63. package/src/WebGL/Shaders/Fragment/Source/rect_outline.frag +20 -0
  64. package/src/WebGL/Shaders/Fragment/Source/solid_path.frag +24 -0
  65. package/src/WebGL/Shaders/Fragment/Source/sprite_sheet.frag +17 -0
  66. package/src/WebGL/Shaders/Fragment/Source/sprite_sheet_colour.frag +19 -0
  67. package/src/WebGL/Shaders/Fragment/Source/texture.frag +11 -0
  68. package/src/WebGL/Shaders/Fragment/fragment.ts +43 -0
  69. package/src/WebGL/Shaders/Fragment/fragment_old.ts +261 -0
  70. package/src/WebGL/Shaders/Vertex/Program/mvp2d.ts +41 -0
  71. package/src/WebGL/Shaders/Vertex/Program/transform2d.ts +39 -0
  72. package/src/WebGL/Shaders/Vertex/Source/mvp2d.vert +17 -0
  73. package/src/WebGL/Shaders/Vertex/Source/mvp_i_2d.vert +18 -0
  74. package/src/WebGL/Shaders/Vertex/Source/simple.vert +9 -0
  75. package/src/WebGL/Shaders/Vertex/Source/transform2d.vert +13 -0
  76. package/src/WebGL/Shaders/Vertex/Source/transform2d_rel.vert +16 -0
  77. package/src/WebGL/Shaders/Vertex/Source/translate2d.vert +7 -0
  78. package/src/WebGL/Shaders/Vertex/Source/vertex_source.ts +13 -0
  79. package/src/WebGL/Shaders/Vertex/vertex.ts +10 -0
  80. package/src/WebGL/Shaders/Vertex/vertex_old.ts +289 -0
  81. package/src/WebGL/Shaders/custom.ts +129 -0
  82. package/src/WebGL/Shaders/shader.ts +197 -0
  83. package/src/WebGL/Shapes/Line.ts +29 -0
  84. package/src/WebGL/Shapes/Shapes.ts +189 -0
  85. package/src/WebGL/Texture/texture.ts +214 -0
  86. package/src/WebGL/Util/file.ts +24 -0
  87. package/src/WebGL/app.ts +150 -0
  88. package/src/WebGL/colour.ts +71 -0
  89. package/src/WebGL/globals.ts +353 -0
  90. package/src/WebGL/index.ts +3 -0
  91. package/src/WebGL/mixin.ts +2 -0
  92. package/src/global.d.ts +13 -0
  93. package/src/index.ts +4 -0
  94. package/src/main.ts +139 -0
  95. package/src/utils/array.ts +154 -0
  96. package/src/utils/assert.ts +8 -0
  97. package/src/utils/file.ts +0 -0
  98. package/src/utils/mixin.ts +22 -0
  99. package/src/utils/numbers.ts +11 -0
  100. package/src/utils/utils.test.ts +23 -0
  101. package/src/vite-env.d.ts +1 -0
  102. package/tsconfig.json +25 -0
@@ -0,0 +1,1326 @@
1
+ import * as Matrix from "../../WebGL/Matrix/matrix";
2
+ import * as App from "./../../WebGL/app";
3
+ import * as Grid from "./grid";
4
+
5
+ //webgl imports
6
+ import * as Shader from "../../WebGL/Shaders/custom";
7
+ import * as Shapes from '../../WebGL/Shapes/Shapes';
8
+ import * as Texture from "../../WebGL/Texture/texture";
9
+ import * as Colour from "../../WebGL/colour";
10
+ import * as WebGL from "../../WebGL/globals";
11
+
12
+ import * as Node from "./nodes";
13
+ import * as Resource from "./resource";
14
+ import * as Car from "./car";
15
+ import * as NodeGraph from "./node_graph"
16
+
17
+ import * as ArrayUtils from "../../utils/array";
18
+ import * as NumberUtils from "../../utils/numbers";
19
+
20
+ import * as Texts from "./texts";
21
+
22
+ //interface imports
23
+ import * as Options from "./../../Interface/options";
24
+ import * as InternalWindow from "./../../Interface/internal_window";
25
+ import * as Button from "../../Interface/button";
26
+ import * as TextInput from "../../Interface/text_input";
27
+
28
+
29
+ interface Point extends Button.Point{};
30
+
31
+ type Int32 = number;
32
+ type Float = number;
33
+ type VoidFunction = () => void;
34
+ const EmptyFunction: VoidFunction = () => {};
35
+
36
+ function randomPick<T>(arr: T[]): T{
37
+ const p = Math.floor(Math.random()*arr.length);
38
+ return arr[p];
39
+ }
40
+
41
+ //filter out any positions that are too close the avoid position, anything within distance
42
+ function filterPositionsTooClose(positions: Grid.GridPosition[], avoid: Grid.GridPosition, distance: number): Grid.GridPosition[]{
43
+ const filtered = [];
44
+ for(const pos of positions){
45
+ if(Grid.GridPosition.manhattanDistance(pos, avoid) >= distance){
46
+ filtered.push(pos);
47
+ }
48
+ }
49
+ return filtered;
50
+ }
51
+
52
+
53
+ function intersectionGridPosition(arr1: Grid.GridPosition[], arr2: Grid.GridPosition[]): Grid.GridPosition[]{
54
+ const arr1Positions: Map<number, Set<number>> = new Map();
55
+ const intersection = [];
56
+ for(const pos of arr1){
57
+ if(arr1Positions.has(pos.x)){
58
+ arr1Positions.get(pos.x)!.add(pos.y);
59
+ }else{
60
+ arr1Positions.set(pos.x, new Set([pos.y]));
61
+ }
62
+ }
63
+ for(const pos of arr2){
64
+ if(arr1Positions.has(pos.x)){
65
+ if(arr1Positions.get(pos.x)!.has(pos.y)){
66
+ intersection.push(pos);
67
+ }
68
+ }
69
+ }
70
+ return intersection;
71
+ }
72
+
73
+ function addIfInside(grid: Grid.RectGrid, positions: Grid.GridPosition[], pos: Grid.GridPosition){
74
+ if(grid.isInsideGrid(pos.x, pos.y)){
75
+ positions.push(pos);
76
+ }
77
+ }
78
+
79
+ function getLocationsAway(grid: Grid.RectGrid, pos: Grid.GridPosition, away: number): Grid.GridPosition[]{
80
+ if(away == 0){
81
+ return [new Grid.GridPosition(pos.x, pos.y)];
82
+ }
83
+ const positions: Grid.GridPosition[] = [];
84
+ addIfInside(grid, positions, new Grid.GridPosition(pos.x, pos.y-away));
85
+ for(let i = -away+1; i < 0; i++){
86
+ const dx = i + away;
87
+ addIfInside(grid, positions,new Grid.GridPosition(pos.x-dx, pos.y-i));
88
+ addIfInside(grid, positions,new Grid.GridPosition(pos.x-dx, pos.y+i));
89
+ }
90
+ addIfInside(grid, positions,new Grid.GridPosition(pos.x-away, pos.y));
91
+ addIfInside(grid, positions,new Grid.GridPosition(pos.x+away, pos.y));
92
+ for(let i = 1; i < away; i++){
93
+ const dx = i - away;
94
+ addIfInside(grid, positions,new Grid.GridPosition(pos.x-dx, pos.y-i));
95
+ addIfInside(grid, positions,new Grid.GridPosition(pos.x-dx, pos.y+i));
96
+ }
97
+ addIfInside(grid, positions,new Grid.GridPosition(pos.x, pos.y+away));
98
+ return positions;
99
+ }
100
+
101
+ function generateKeyLocations(grid: Grid.RectGrid, n_locations: Int32=5): Grid.GridPosition[]{
102
+ const locations: Grid.GridPosition[] = [];
103
+ locations.push(new Grid.GridPosition(0, 0)); //start at corner
104
+ let away = getLocationsAway(grid, locations.at(-1)!, 8);
105
+ locations.push(randomPick(away));
106
+ while(locations.length < n_locations){
107
+ away = getLocationsAway(grid, locations.at(-1)!, 7);
108
+
109
+ const pick = randomPick(away);
110
+ locations.push(pick);
111
+ }
112
+
113
+
114
+ return locations;
115
+ }
116
+
117
+ export class MultiGridObject{
118
+ width: Int32;
119
+ height: Int32;
120
+ active_cells: boolean[];
121
+ constructor(w: Int32, h: Int32){
122
+ this.width = w;
123
+ this.height = h;
124
+ this.active_cells = [];
125
+ }
126
+ }
127
+
128
+ const WallEditStateEnum = {
129
+ Default: 0,
130
+ Adding: 1,
131
+ Deleting: 2,
132
+ Selecting: 3
133
+ } as const;
134
+
135
+ type WallEditState = (typeof WallEditStateEnum)[keyof typeof WallEditStateEnum];
136
+
137
+ const GridCellSectionEnum = {
138
+ ...Grid.DirectionEnum,
139
+ Center: 4
140
+ } as const;
141
+
142
+ type GridCellSection = (typeof GridCellSectionEnum)[keyof typeof GridCellSectionEnum];
143
+
144
+ export class WallEngine extends App.BaseEngine{
145
+ grid: Grid.WallGrid;
146
+ rect_grid: Grid.RectGrid;
147
+
148
+ mouse_over_cell: Grid.GridPosition | undefined;
149
+ true_mouse: Matrix.Point2D | undefined;
150
+ grid_true_mouse: Matrix.Point2D | undefined;
151
+
152
+ highlighted_positions: Grid.GridPosition[];
153
+ is_circle_positions: boolean;
154
+
155
+ key_positions: Grid.GridPosition[];
156
+ adding_position: Grid.GridPosition | undefined;
157
+ adding_path_hori_first: boolean;
158
+
159
+ selected_key1: Grid.GridPosition | undefined;
160
+ selected_key2: Grid.GridPosition | undefined;
161
+
162
+ test_objects: MultiGridObject[];
163
+
164
+ highlight_path: Grid.GridPositionWithDirections[];
165
+
166
+ car_collection: Car.CarCollection;
167
+
168
+ buttons: Button.ButtonSet;
169
+ toggle_buttons: Button.ToggleButtonSet;
170
+
171
+ hovered_node: Node.KeyNode | undefined;
172
+ nodes: Node.KeyNode[];
173
+ node_size: Float;
174
+
175
+ view: Matrix.TransformationMatrix3x3;
176
+
177
+ overlay_element: HTMLDivElement | undefined;
178
+
179
+ last_time: Float;
180
+
181
+ node_graph: NodeGraph.RoadGraph;
182
+
183
+ active_nodes: Map<Int32, Node.KeyNode>;
184
+ node_id: Int32;
185
+
186
+ edit_state: WallEditState;
187
+ hover_grid_side: GridCellSection | undefined;
188
+
189
+ selected_nodes: Set<Int32>;
190
+
191
+ hovered_car: Int32 | undefined;
192
+ selected_car: Int32 | undefined;
193
+ car_buttons: Button.SingleSelectToggleButtonSet;
194
+
195
+ test_text_box: TextInput.TextInput;
196
+
197
+ graph_updated_status: boolean;
198
+
199
+ //test_options: Options.SingleSelectOptions;
200
+ //edit_state_options: Options.SingleSelectOptions;
201
+ select_options: Options.SingleSelectOptions[];
202
+ test_drop_option: Options.DropdownOptions;
203
+
204
+ test_internal_window: InternalWindow.InternalWindow;
205
+
206
+ constructor(){
207
+ super();
208
+ const w = 10; const h = 10;
209
+ const s = 80;
210
+ this.test_drop_option = new Options.DropdownOptions(100, 100, 80, 20, []);
211
+ this.grid = new Grid.WallGrid(w,h);
212
+ this.rect_grid = new Grid.RectGrid(w, h, s);
213
+ this.mouse_over_cell = undefined;
214
+ this.highlighted_positions = [];
215
+ this.key_positions = [];
216
+
217
+ this.active_nodes = new Map();
218
+ this.node_id = 0;
219
+
220
+ this.is_circle_positions = false;
221
+ this.nodes = [];
222
+
223
+ this.node_size = 0.15;
224
+
225
+ this.car_collection = new Car.CarCollection();
226
+
227
+ this.test_objects = [];
228
+ this.adding_path_hori_first = true;
229
+ this.highlight_path = [];
230
+
231
+ this.buttons = new Button.ButtonSet();
232
+ this.toggle_buttons = new Button.ToggleButtonSet();
233
+ this.graph_updated_status = false;
234
+ this.test_internal_window = new InternalWindow.InternalWindow(100, 50, 200, 200);
235
+
236
+ // adding buttons
237
+ const butt_x = 810;
238
+
239
+ this.select_options = [];
240
+ const edit_state_options = new Options.SingleSelectOptions(["Off", "Add", "Del", "Sel"], butt_x+90, 80, 15);
241
+ edit_state_options.onSelected = (id: Int32) => {
242
+ switch(id){
243
+ case 0:
244
+ this.edit_state = WallEditStateEnum.Default;
245
+ break;
246
+ case 1:
247
+ this.edit_state = WallEditStateEnum.Adding;
248
+ break;
249
+ case 2:
250
+ this.edit_state = WallEditStateEnum.Deleting;
251
+ break;
252
+ case 3:
253
+ this.edit_state = WallEditStateEnum.Selecting;
254
+ break;
255
+ default:
256
+ break;
257
+ }
258
+ }
259
+
260
+ this.select_options.push(edit_state_options);
261
+
262
+ const car_plan_button = new Button.BasicButton(butt_x, 10, 80, 25, 9);
263
+ car_plan_button.text = "New Plan";
264
+ car_plan_button.onPressed = () => {
265
+ //console.log(this.car.last_key);
266
+ this.key_positions = generateKeyLocations(this.rect_grid, 3);
267
+ /*
268
+ if(this.car.last_key){
269
+ const next_key = this.randomKeyOtherThan1(this.car.last_key);
270
+ const path = this.grid.shortestPath(this.car.last_key, next_key);
271
+ //console.log(path);
272
+ if(path != undefined && this.car.plan == undefined){
273
+ const track = Grid.GridAlgorithms.pathToTrack(path);
274
+ this.car.setPlan(track);
275
+ }
276
+ }*/
277
+ }
278
+ this.buttons.addButton(car_plan_button);
279
+
280
+ const example_plan_button = new Button.BasicButton(butt_x, 130, 80, 25, 7);
281
+ example_plan_button.text = "New Example";
282
+ example_plan_button.onPressed = () => {
283
+ this.clearGrid();
284
+ this.key_positions = generateKeyLocations(this.rect_grid, 3);
285
+ if(this.key_positions.length >= 2){
286
+ for(let i = 1; i < this.key_positions.length; i++){
287
+ const path = Grid.GridPosition.randomPointToPoint1TurnTrack(this.key_positions[i-1], this.key_positions[i]);
288
+ this.grid.addTrack(path);
289
+ this.grid.grid[this.key_positions[i].y][this.key_positions[i].x].is_key = true;
290
+ if(i == this.key_positions.length-1){
291
+ //this.car.setPlan(path);
292
+ }
293
+ }
294
+ this.grid.grid[this.key_positions[0].y][this.key_positions[0].x].is_key = true;
295
+ }
296
+ const sh_path = this.grid.shortestPath(this.key_positions[0], this.key_positions[1]);
297
+ this.createKeyNodes();
298
+ }
299
+
300
+ this.buttons.addButton(example_plan_button);
301
+
302
+ const generate_graph_button = new Button.BasicButton(butt_x, 160, 80, 25, 8);
303
+ generate_graph_button.text = "Gen Graph";
304
+ generate_graph_button.onPressed = () => {
305
+ this.node_graph.generate(this.grid, this.active_nodes);
306
+ this.graph_updated_status = true;
307
+ };
308
+
309
+ this.buttons.addButton(generate_graph_button);
310
+
311
+ const validate_button = new Button.BasicButton(butt_x, 190, 80, 25, 8);
312
+ validate_button.text = "Validate";
313
+ validate_button.onPressed = () => {
314
+ const valid = this.validateGrid();
315
+ console.log(valid);
316
+ };
317
+ this.buttons.addButton(validate_button);
318
+
319
+ const clear_button = new Button.BasicButton(butt_x, 220, 80, 25, 8);
320
+ clear_button.text = "Clear Grid";
321
+ clear_button.onPressed = () => {
322
+ this.clearGrid();
323
+ this.graph_updated_status = false;
324
+ };
325
+ this.buttons.addButton(clear_button);
326
+
327
+ const short_path_button = new Button.BasicButton(butt_x, 250, 80, 25, 6);
328
+ short_path_button.text = "Shortest Path";
329
+ short_path_button.onPressed = () => {
330
+ if(this.selected_nodes.size == 2){
331
+ const it = this.selected_nodes.values();
332
+ const first = it.next().value!;
333
+ const second = it.next().value!;
334
+ console.log(`finding shortest path from ${first} to ${second}`);
335
+ const path = this.node_graph.shortestPath(first, second);
336
+ if(path != undefined){
337
+ //todo
338
+ }
339
+ }else{
340
+ console.log("needs 2 nodes selected");
341
+ }
342
+ }
343
+ this.buttons.addButton(short_path_button);
344
+
345
+ const add_car_button = new Button.BasicButton(butt_x, 280, 80, 25, 8);
346
+ add_car_button.text = "Add car";
347
+ add_car_button.onPressed = () => {
348
+ if(this.selected_nodes.size == 1){
349
+ const id = this.selected_nodes.values().next().value!;
350
+ const node = this.active_nodes.get(id)!;
351
+ console.log(node);
352
+ this.addCar(node);
353
+ //const car = new Car.ResourceCar(node);
354
+ //this.cars.push(car);
355
+ console.log("adding car");
356
+ }
357
+ }
358
+ this.buttons.addButton(add_car_button);
359
+
360
+ const car_path_button = new Button.BasicButton(butt_x, 310, 80, 25, 8);
361
+ car_path_button.text = "Car Path To";
362
+ car_path_button.onPressed = () => {
363
+ if(this.selected_nodes.size == 1 && this.selected_car != undefined){
364
+ const car = this.car_collection.get(this.selected_car)!;
365
+ if(!car.isReadyToGo()){
366
+ console.log("car already on journey");
367
+
368
+ }else if(this.graph_updated_status){
369
+ console.log("Graph not updated to visuals");
370
+
371
+ }else{
372
+ //check graph path to node
373
+ const from_id = car.starting_node.getId();
374
+ const to_id = this.selected_nodes.values().next().value!;
375
+ if(from_id === to_id){
376
+ console.log("car already at location");
377
+ }else{
378
+ const shortest_path = this.node_graph.shortestPath(from_id, to_id);
379
+ console.log(shortest_path);
380
+
381
+ }
382
+ }
383
+ }else{
384
+ console.log("requires selected node and selected car");
385
+ }
386
+ };
387
+ this.buttons.addButton(car_path_button);
388
+
389
+ const car_delete_button = new Button.BasicButton(butt_x, 340, 80, 25, 8);
390
+ car_delete_button.text = "Car Del";
391
+ car_delete_button.onPressed = () => {
392
+ this.deleteSelectedCar();
393
+ };
394
+ this.buttons.addButton(car_delete_button);
395
+
396
+ const add_button = new Button.ToggleButton(butt_x, 45, 80, 20, 10);
397
+ add_button.on_text = "Add On";
398
+ add_button.off_text = "Add Off";
399
+ add_button.onToggleOn = () => {
400
+ delete_button.toggleOff();
401
+ select_button.toggleOff();
402
+ this.edit_state = WallEditStateEnum.Adding;
403
+ };
404
+ add_button.onToggleOff = () => {
405
+ this.edit_state = WallEditStateEnum.Default;
406
+ };
407
+
408
+ this.toggle_buttons.addButton(add_button);
409
+
410
+ const delete_button = new Button.ToggleButton(butt_x, 70, 80, 20, 10);
411
+ delete_button.on_text = "Del On";
412
+ delete_button.off_text = "Del Off";
413
+ delete_button.onToggleOn = () => {
414
+ add_button.toggleOff();
415
+ select_button.toggleOff();
416
+ this.edit_state = WallEditStateEnum.Deleting;
417
+ };
418
+ delete_button.onToggleOff = () => {
419
+ this.edit_state = WallEditStateEnum.Default;
420
+ }
421
+ this.toggle_buttons.addButton(delete_button);
422
+
423
+ const select_button = new Button.ToggleButton(butt_x, 95, 80, 20, 10);
424
+ select_button.on_text = "Sel On";
425
+ select_button.off_text = "Sel Off";
426
+ select_button.onToggleOn = () => {
427
+ delete_button.toggleOff();
428
+ add_button.toggleOff();
429
+ this.edit_state = WallEditStateEnum.Selecting;
430
+ }
431
+ select_button.onToggleOff = () => {
432
+ this.edit_state = WallEditStateEnum.Default;
433
+ }
434
+
435
+ this.toggle_buttons.addButton(select_button);
436
+
437
+ this.car_buttons = new Button.SingleSelectToggleButtonSet();
438
+
439
+ this.view = Matrix.TransformationMatrix3x3.identity();
440
+
441
+ this.last_time = 0;
442
+
443
+ this.node_graph = new NodeGraph.RoadGraph();
444
+ //this.node_graph.generate(this.grid, this.a); // now generated by button press
445
+
446
+ this.edit_state = WallEditStateEnum.Default;
447
+ this.hover_grid_side = undefined;
448
+
449
+ this.selected_nodes = new Set();
450
+
451
+ this.hovered_car = undefined;
452
+ this.selected_car = undefined;
453
+
454
+ this.test_text_box = new TextInput.TextInput(200, 810, 600, 20);
455
+ }
456
+ addKeyNode(node: Node.KeyNode){
457
+ if(this.grid.getNodeId(node.x, node.y) != undefined){
458
+ console.log("node already here");
459
+ return;
460
+ }
461
+ //console.log(node);
462
+ this.grid.setNodeId(node.x, node.y, this.node_id);
463
+ //console.log(this.grid.getTile(node.x, node.y));
464
+ //this.nodes.push(node);
465
+ node.setId(this.node_id);
466
+ this.active_nodes.set(this.node_id, node);
467
+ console.log(`adding node ${this.node_id.toString()}`);
468
+ this.node_id++;
469
+ this.updateHoveredNode();
470
+
471
+ this.graph_updated_status = false;
472
+ }
473
+ deleteKeyNode(node: Node.KeyNode){
474
+ this.selected_nodes.delete(node.getId());
475
+ this.grid.getTile(node.x, node.y)!.clearKey();
476
+ //this.grid.setCellKeyNode(node.x, node.y, false);
477
+ console.log(`clearing node ${this.node_id.toString()}`);
478
+ this.active_nodes.delete(node.getId());
479
+ console.log(`deleting node ${this.node_id.toString()}`);
480
+ this.updateHoveredNode();
481
+ this.graph_updated_status = false;
482
+ }
483
+ clearGrid(){
484
+ this.grid.clear();
485
+ this.clearKeyNodes();
486
+ this.clearCars();
487
+ this.graph_updated_status = false;
488
+ }
489
+ clearKeyNodes(){
490
+ for(const [id, node] of this.active_nodes){
491
+ this.deleteKeyNode(node);
492
+ //todo delete car on node
493
+ }
494
+ this.active_nodes.clear();
495
+ this.graph_updated_status = false;
496
+ }
497
+ clearCars(){
498
+ this.car_collection.clear();
499
+ }
500
+
501
+ deleteSelectedCar(){
502
+ if(this.selected_car != undefined)
503
+ this.car_collection.delete(this.selected_car);
504
+ }
505
+
506
+ addCar(node: Node.KeyNode){
507
+ this.car_collection.addCarOnNode(node);
508
+ }
509
+
510
+ //a valid grid has nodes on all nodes with one direction attached.
511
+ //also requires neighbouring nodes to have opposite directions active
512
+ validateGrid(): boolean{
513
+ for(let y = 0; y < this.grid.width; y++){
514
+ for(let x = 0; x < this.grid.height; x++){
515
+ const tile = this.grid.getTile(x, y)!;
516
+ if(x == 0 && tile.directionHasPath(Grid.DirectionEnum.Left)){
517
+ console.log("Outside map left");
518
+ return false;
519
+ }
520
+ if(y == 0 && tile.directionHasPath(Grid.DirectionEnum.Up)){
521
+ console.log("Outside map up");
522
+ return false;
523
+ }
524
+ if(y == this.grid.height-1 && tile.directionHasPath(Grid.DirectionEnum.Down)){
525
+ console.log("Outside map down");
526
+ return false;
527
+ }
528
+ if(x == this.grid.width-1 && tile.directionHasPath(Grid.DirectionEnum.Right)){
529
+ console.log("Outside map right");
530
+ return false
531
+ }
532
+ for(const dir of tile.getDirections()){
533
+ const pos = new Grid.GridPosition(x, y);
534
+ const next_position = Grid.DirectionUtil.copyMovePosition(dir, pos);
535
+ const next_tile = this.grid.getTile(next_position.x, next_position.y)!;
536
+ const opp = Grid.DirectionUtil.opposite(dir);
537
+ if(!next_tile.directionHasPath(opp)){
538
+ //no connecting
539
+ console.log(`No connecting path from ${pos.x}, ${pos.y} to ${next_position.x}, ${next_position.y}`);
540
+ return false;
541
+ }
542
+ }
543
+ if(tile.getDirections().length == 1 && tile.node_id == undefined){
544
+ console.log(`Position: ${x} ${y} has no key node with only one exit path`);
545
+ return false;
546
+ }
547
+ }
548
+ }
549
+ return true;
550
+ }
551
+ quickFixGrid(){
552
+ //adds unfinished paths, adds nodes on deadends, and removes paths on map edges
553
+ //TODO
554
+ }
555
+ addOverlayElement(overlay: HTMLDivElement){
556
+ this.overlay_element = overlay;
557
+ }
558
+ onFinishLoading(){
559
+ if(this.overlay_element != undefined){
560
+ this.overlay_element.textContent = "";
561
+ }
562
+ }
563
+ createKeyNodes(){
564
+ this.nodes = [];
565
+ const rand_arr = ArrayUtils.random0ToN(this.key_positions.length);
566
+ //console.log(rand_arr);
567
+ const res_node = new Node.ResourceGeneratorNode(this.key_positions[rand_arr[0]].x, this.key_positions[rand_arr[0]].y);
568
+ this.addKeyNode(res_node);
569
+
570
+ const deliver_node = new Node.RequirementNode(this.key_positions[rand_arr[1]].x, this.key_positions[rand_arr[1]].y);
571
+ this.addKeyNode(deliver_node);
572
+
573
+ for(let i = 2; i < this.key_positions.length; i++){
574
+ const node = new Node.KeyNode(this.key_positions[rand_arr[i]].x, this.key_positions[rand_arr[i]].y);
575
+ //this.nodes.push(new Node.KeyNode(this.key_positions[rand_arr[i]].x, this.key_positions[rand_arr[i]].y));
576
+ this.addKeyNode(node);
577
+ }
578
+
579
+ }
580
+ randomKeyOtherThan1(not_included: Grid.GridPosition){
581
+ const others = this.key_positions.filter((p) => {
582
+ return !(not_included.x === p.x && not_included.y === p.y);
583
+ });
584
+ return others[Math.floor(Math.random()*others.length)];
585
+ }
586
+
587
+ addKeyPosition(x: Int32, y: Int32){
588
+ this.key_positions.push(new Grid.GridPosition(x, y));
589
+ }
590
+
591
+ sideOnGrid(pos: WebGL.Matrix.Point2D | undefined): GridCellSection | undefined{
592
+ if(pos != undefined){
593
+ const dx = pos.x % 1;
594
+ const dy = pos.y % 1;
595
+
596
+
597
+ const dist = 0.015;
598
+ if(NumberUtils.distanceSq(dx, dy, 0.5, 0.5) < dist){
599
+ this.hover_grid_side = GridCellSectionEnum.Center;
600
+ }else{
601
+ const dir = Grid.DirectionUtil.fromFloatsInGridDecimal(dx, dy);
602
+ this.hover_grid_side = dir;
603
+ }
604
+ }else{
605
+ this.hover_grid_side = undefined;
606
+ }
607
+ return this.hover_grid_side;
608
+ }
609
+
610
+ protected override handleKeyDown(ev: KeyboardEvent){
611
+ if(ev.key == 'q'){
612
+ this.is_circle_positions = !this.is_circle_positions;
613
+ if(this.mouse_over_cell != undefined){
614
+ this.setHighlightedPositions(this.mouse_over_cell);
615
+ }
616
+ }else if(ev.key == 'w'){
617
+ //run path closest
618
+ if(this.highlight_path.length > 0){
619
+ for(const dir_pos of this.highlight_path){
620
+ this.grid.setCellStateFromActive(dir_pos.position.x, dir_pos.position.y, dir_pos.directions, Grid.TileStateEnum.Path);
621
+ }
622
+ this.highlight_path = [];
623
+ }
624
+ else if(this.selected_key1 != undefined && this.selected_key2 != undefined){
625
+ console.log("find path");
626
+ const path = this.grid.shortestPath(this.selected_key1, this.selected_key2);
627
+ console.log(path);
628
+ if(path != undefined){
629
+ //this.highlight_path = path;
630
+ const dir_path_positions = Grid.GridAlgorithms.positionPathToDirectionPath(path);
631
+ for(const dir_pos of dir_path_positions){
632
+ this.grid.setCellStateFromActive(dir_pos.position.x, dir_pos.position.y, dir_pos.directions, Grid.TileStateEnum.Highlight);
633
+ }
634
+ this.highlight_path = dir_path_positions;
635
+ console.log(dir_path_positions);
636
+ console.log(this.grid);
637
+ }
638
+ }
639
+ }else if(ev.key == 'a'){
640
+ this.view.translate(-this.rect_grid.size, 0);
641
+ }else if(ev.key == 'd'){
642
+ this.view.translate(this.rect_grid.size, 0);
643
+ }else if(ev.key == 'Escape'){
644
+ this.deselectKeyNodes();
645
+ this.deselectCar();
646
+ }
647
+ this.test_text_box.onKeyDown(ev);
648
+ }
649
+ protected override handleMouseMove(ev: MouseEvent): void {
650
+ const true_mouse = new Matrix.Point2D(ev.offsetX, ev.offsetY);
651
+ this.true_mouse = true_mouse;
652
+ const inv = this.view.copy();
653
+ inv.invert();
654
+ this.grid_true_mouse = inv.transformPoint(true_mouse);
655
+ this.grid_true_mouse.x/=this.rect_grid.size;
656
+ this.grid_true_mouse.y/=this.rect_grid.size;
657
+ const side = this.sideOnGrid(this.grid_true_mouse);
658
+ const pos = this.rect_grid.getPosition(ev.offsetX, ev.offsetY);
659
+ if(pos != undefined){
660
+ if(this.mouse_over_cell == undefined || (this.mouse_over_cell.x != pos.x || this.mouse_over_cell.y != pos.y)){
661
+ this.setHighlightedPositions(pos);
662
+ }
663
+ }else{
664
+ this.highlighted_positions = [];
665
+ }
666
+ this.buttons.updateMouse(true_mouse);
667
+ this.toggle_buttons.updateMouse(true_mouse);
668
+ this.mouse_over_cell = pos;
669
+
670
+ const true_grid = this.getGridTruePosition(ev.offsetX, ev.offsetY);
671
+
672
+ this.updateHoveredNode();
673
+ this.test_text_box.onMouseMove(true_mouse);
674
+ for(const opt of this.select_options){
675
+ opt.onMouseMove(true_mouse);
676
+ }
677
+ this.test_internal_window.mouseMove(true_mouse);
678
+ }
679
+
680
+ protected override handleMouseDown(ev: MouseEvent){
681
+ if(this.mouse_over_cell != undefined){
682
+ const cell = this.mouse_over_cell;
683
+ if(this.hovered_car != undefined){
684
+ this.selectCar(this.hovered_car);
685
+ }
686
+
687
+ //node selection
688
+ else if(this.edit_state === WallEditStateEnum.Selecting){
689
+ const grid_tile = this.grid.getTile(this.mouse_over_cell.x, this.mouse_over_cell.y);
690
+ if(grid_tile != undefined && grid_tile.isKeyNode()){
691
+ if(this.selected_nodes.has(grid_tile.node_id!)){
692
+ grid_tile.is_selected = false;
693
+ this.selected_nodes.delete(grid_tile.node_id!);
694
+ }else{
695
+ grid_tile.is_selected = true;
696
+ this.selected_nodes.add(grid_tile.node_id!);
697
+ }
698
+ }
699
+ }
700
+
701
+ // edit walls with mouse input
702
+ else if(this.edit_state === WallEditStateEnum.Adding){
703
+ if(this.hover_grid_side != undefined){
704
+ const changed = this.editSide(cell, this.hover_grid_side, Grid.TileStateEnum.Path);
705
+ console.log(changed);
706
+ //todo use changed, i.e. devalidates graph
707
+ }
708
+
709
+ }else if(this.edit_state === WallEditStateEnum.Deleting){
710
+ if(this.hover_grid_side != undefined){
711
+ const changed = this.editSide(cell, this.hover_grid_side, Grid.TileStateEnum.Nothing);
712
+ console.log(changed);
713
+ //todo use changed, i.e. devalidates graph
714
+ }
715
+ }
716
+ }
717
+
718
+ this.buttons.mouseDown();
719
+ this.toggle_buttons.mouseDown();
720
+ if(this.true_mouse != undefined){
721
+ this.test_text_box.onMouseDown(this.true_mouse);
722
+ for(const opt of this.select_options){
723
+ opt.onMouseDown();
724
+ }
725
+ this.test_internal_window.mouseDown(this.true_mouse);
726
+ }
727
+ }
728
+
729
+
730
+ protected override handleMouseUp(ev: MouseEvent): void {
731
+ this.buttons.mouseUp();
732
+ this.toggle_buttons.mouseUp();
733
+ this.test_text_box.onMouseUp();
734
+ for(const opt of this.select_options){
735
+ opt.onMouseUp();
736
+ }
737
+ this.test_internal_window.mouseUp();
738
+ }
739
+
740
+
741
+ editSide(cell: Grid.GridPosition, side: GridCellSection, value: Grid.TileState): boolean{
742
+ const side_to_direction = {
743
+ [GridCellSectionEnum.Left]: Grid.DirectionEnum.Left,
744
+ [GridCellSectionEnum.Down]: Grid.DirectionEnum.Down,
745
+ [GridCellSectionEnum.Right]: Grid.DirectionEnum.Right,
746
+ [GridCellSectionEnum.Up]: Grid.DirectionEnum.Up
747
+ }
748
+ const tile = this.grid.getTileFromPosition(cell)!;
749
+ let changed = false;
750
+ if(side === GridCellSectionEnum.Center){
751
+ const node_id = this.grid.getNodeId(cell.x, cell.y);
752
+ if(value === Grid.TileStateEnum.Path){
753
+ //adding node
754
+ changed = node_id == undefined;
755
+ const new_node = new Node.KeyNode(cell.x, cell.y);
756
+ this.addKeyNode(new_node);
757
+ }else{
758
+ //deleting node
759
+ changed = node_id != undefined;
760
+ if(node_id != undefined){
761
+ const node = this.active_nodes.get(node_id);
762
+ if(node != undefined) this.deleteKeyNode(node);
763
+ }
764
+ }
765
+ }else{
766
+ changed = tile.getSideState(side) != value;
767
+ this.grid.setCellState(cell.x, cell.y, side_to_direction[side], value);
768
+ }
769
+ return changed;
770
+ }
771
+ updateHoveredNode(){
772
+ this.hovered_node = undefined;
773
+ if(this.grid_true_mouse != undefined){
774
+ for(const [id, node] of this.active_nodes){
775
+ const dist = node.distanceSq(this.grid_true_mouse);
776
+ if(dist < this.node_size*this.node_size){
777
+ this.hovered_node = node;
778
+ }
779
+ }
780
+ }
781
+ }
782
+
783
+ deselectKeyNodes(){
784
+ for(const [id, node] of this.active_nodes){
785
+ this.grid.setSelected(node.x, node.y, false);
786
+ }
787
+ this.selected_nodes.clear();
788
+ }
789
+ deselectCar(){
790
+ if(this.selected_car != undefined){
791
+ this.car_collection.get(this.selected_car)!.is_selected = false;
792
+ this.selected_car = undefined;
793
+ }
794
+ }
795
+ selectCar(car_id: Int32){
796
+ //console.log("select");
797
+ this.car_collection.select(car_id);
798
+ this.selected_car = car_id;
799
+ }
800
+
801
+
802
+ setHighlightedPositions(pos: Grid.GridPosition){
803
+ if(this.is_circle_positions){
804
+ this.highlighted_positions = Grid.GridAlgorithms.positionsWithin2Ranges(20,36).map((p) => new Grid.GridPosition(pos.x+p.x, pos.y+p.y));
805
+ this.highlighted_positions = filterPositionsTooClose(this.highlighted_positions, new Grid.GridPosition(0, 0), 3);
806
+ }else{
807
+ this.highlighted_positions = ArrayUtils.flatten(Grid.GridPosition.allPositionsDistanceAway(pos, 6));
808
+ this.highlighted_positions = Grid.GridPosition.filterInsideGrid(this.highlighted_positions, this.rect_grid);
809
+ this.highlighted_positions = filterPositionsTooClose(this.highlighted_positions, new Grid.GridPosition(0, 0), 3);
810
+ }
811
+ }
812
+
813
+ getGridTruePosition(x: Float, y: Float): Matrix.Point2D{
814
+ const inv = this.view.copy();
815
+ inv.invert();
816
+ this.grid_true_mouse = inv.transformPoint(new Matrix.Point2D(x, y));
817
+ this.grid_true_mouse.x/=this.rect_grid.size;
818
+ this.grid_true_mouse.y/=this.rect_grid.size;
819
+ return this.grid_true_mouse;
820
+ }
821
+
822
+ gridPointCarCollision(grid_point: Matrix.Point2D): Int32 | undefined{
823
+ for(const [id, car] of this.car_collection.cars){
824
+ const left = car.x-car.size*0.5;
825
+ const right = car.x+car.size*0.5;
826
+ const top = car.y-car.size*0.5;
827
+ const bot = car.y+car.size*0.5;
828
+
829
+ if(left < grid_point.x && grid_point.x < right && top < grid_point.y && grid_point.y < bot){
830
+ return id;
831
+ }
832
+ }
833
+ return undefined;
834
+ }
835
+
836
+ update(time: Float){
837
+ const update_time = time - this.last_time;
838
+ for(const [id, node] of this.active_nodes){
839
+ node.update(update_time);
840
+ }
841
+ this.car_collection.update(update_time)
842
+ if(this.grid_true_mouse != undefined){
843
+ const highlighted_car = this.gridPointCarCollision(this.grid_true_mouse);
844
+ this.hovered_car = highlighted_car;
845
+ //console.log(highlighted_car);
846
+ }else{
847
+ this.hovered_car = undefined;
848
+ }
849
+
850
+ TextInput.TextGlobals.update(update_time);
851
+
852
+ this.last_time = time;
853
+ }
854
+ }
855
+
856
+ interface MultiColourTileShader{
857
+ setLeftColour:(r: Float, g: Float, b: Float) => void;
858
+ setBotColour:(r: Float, g: Float, b: Float) => void;
859
+ setRightColour:(r: Float, g: Float, b: Float) => void;
860
+ setTopColour:(r: Float, g: Float, b: Float) => void;
861
+ setMidColour:(r: Float, g: Float, b: Float) => void;
862
+ }
863
+
864
+ interface DirectionTileShader extends TileShader{
865
+ setLeft:(v: number) => void;
866
+ setBot:(v: number) => void;
867
+ setRight:(v: number) => void;
868
+ setTop:(v: number) => void;
869
+ }
870
+
871
+ interface TileShader{
872
+ use: () => void;
873
+ setSize: (s: Float) => void;
874
+ setMvp: (mat: Matrix.Matrix3x3) => void;
875
+ }
876
+
877
+ export class WallRenderer implements App.IEngineRenderer<WallEngine>{
878
+ grid_tile_shader: Shader.MVPSolidPathProgram;
879
+ pri_tile_shader: Shader.MVPPathCenterCircleProgram;
880
+ solid_shader: Shader.MVPColourProgram;
881
+ sprite_sheet_shader: Shader.MVPSpriteSheetProgram;
882
+ multi_colour_tile_shader: Shader.MVPMultiColourPathProgram;
883
+ multi_colour_centre_circle_shader: Shader.MVPMultiColourCentreCirclePathProgram;
884
+
885
+ text_drawer: WebGL.TextDrawer;
886
+ fonts: WebGL.FontLoader;
887
+
888
+ tile_state_colours: Map<Grid.TileState, Colour.ColourRGB>;
889
+ background_colour: Colour.ColourRGB;
890
+ key_colour: Colour.ColourRGB;
891
+
892
+ texture_shader: Shader.MVPTextureProgram;
893
+ vp: Matrix.TransformationMatrix3x3;
894
+ perspective: Matrix.TransformationMatrix3x3;
895
+ draw_width: Int32;
896
+ draw_height: Int32;
897
+
898
+ textures: Texture.TextureCollection;
899
+
900
+ white: Colour.ColourRGB;
901
+
902
+ overlay_element: HTMLDivElement | undefined;
903
+
904
+ constructor(w: Int32, h: Int32){
905
+ this.grid_tile_shader = new Shader.MVPSolidPathProgram();
906
+ this.pri_tile_shader = new Shader.MVPPathCenterCircleProgram();
907
+ this.multi_colour_tile_shader = new Shader.MVPMultiColourPathProgram();
908
+ this.multi_colour_centre_circle_shader = new Shader.MVPMultiColourCentreCirclePathProgram();
909
+ this.solid_shader = new Shader.MVPColourProgram();
910
+ this.sprite_sheet_shader = new Shader.MVPSpriteSheetProgram();
911
+ this.texture_shader = new Shader.MVPTextureProgram();
912
+
913
+ this.text_drawer = new WebGL.TextDrawer();
914
+ this.fonts = new WebGL.FontLoader();
915
+
916
+ this.draw_width = w;
917
+ this.draw_height = h;
918
+ this.perspective = Matrix.TransformationMatrix3x3.orthographic(0, w, h, 0);
919
+ this.vp = Matrix.TransformationMatrix3x3.identity();
920
+
921
+ this.textures = new Texture.TextureCollection();
922
+
923
+ this.tile_state_colours = new Map();
924
+ this.tile_state_colours.set(Grid.TileStateEnum.Nothing, Colour.ColourUtils.yellow());
925
+ this.tile_state_colours.set(Grid.TileStateEnum.Highlight, Colour.ColourUtils.red());
926
+ this.tile_state_colours.set(Grid.TileStateEnum.Path, Colour.ColourUtils.blue());
927
+ this.tile_state_colours.set(Grid.TileStateEnum.Preview, Colour.ColourUtils.fromRGB(0.3, 0.4, 1));
928
+
929
+ this.background_colour = Colour.ColourUtils.yellow();
930
+ this.key_colour = Colour.ColourUtils.pink();
931
+
932
+ //set some default shader properties
933
+ this.multi_colour_centre_circle_shader.use();
934
+ this.multi_colour_centre_circle_shader.setSize(0.1);
935
+ this.multi_colour_centre_circle_shader.setCircleRadius(0.17);
936
+ this.multi_colour_centre_circle_shader.setBackgroundColour(this.background_colour.red, this.background_colour.green, this.background_colour.blue);
937
+
938
+ this.multi_colour_tile_shader.use();
939
+ this.multi_colour_tile_shader.setSize(0.1);
940
+ this.multi_colour_tile_shader.setBackgroundColour(this.background_colour.red, this.background_colour.green, this.background_colour.blue);
941
+
942
+ this.white = WebGL.Colour.ColourUtils.white();
943
+
944
+ }
945
+ resize(w: Int32, h: Int32){
946
+ this.perspective = Matrix.TransformationMatrix3x3.orthographic(0, w, h, 0);
947
+ }
948
+ loadTextures(onLoad:VoidFunction=EmptyFunction){
949
+ //load textures
950
+ if(this.overlay_element != undefined){
951
+ this.overlay_element.textContent = "Loading Textures...";
952
+ }
953
+ setTimeout(() => {
954
+ const texture_names = ["car.png", "base.png"];
955
+ this.textures.addFromUrl("car", "car.png");
956
+ this.textures.addFromUrl("drop", "drop.png");
957
+ this.textures.addFromUrl("apple", "apple.png");
958
+
959
+ this.textures.load(() => this.loadFonts(onLoad));
960
+ }, 200)
961
+ }
962
+ loadFonts(onLoad:VoidFunction=EmptyFunction){
963
+ if(this.overlay_element != undefined){
964
+ this.overlay_element.textContent = "Loading Fonts...";
965
+ }
966
+ setTimeout(() => {
967
+ const font_name = "letters-Sheet.png";
968
+ const fn = "font16-Sheet.png";
969
+ //this.fonts.addFont(font_name);
970
+ this.fonts.addFont(fn);
971
+ this.fonts.loadFonts(() => {
972
+ //this.text_drawer.setFont(this.fonts.getFont(font_name)!);
973
+ this.text_drawer.setFont(this.fonts.getFont(fn)!);
974
+ this.text_drawer.loadFont();
975
+ console.log("finished loading");
976
+ if(onLoad) onLoad();
977
+ });
978
+ }, 100);
979
+ }
980
+ addOverlayElement(overlay: HTMLDivElement){
981
+ this.overlay_element = overlay;
982
+ }
983
+ drawKeyTile(engine: WallEngine, x: Int32, y: Int32){
984
+ //expects shader vars setup
985
+ const gs = engine.rect_grid.size;
986
+ const tx = x*gs;
987
+ const ty = y*gs;
988
+ this.pri_tile_shader.use();
989
+ const is_key1 = engine.selected_key1 != undefined && engine.selected_key1.x == x && engine.selected_key1.y == y;
990
+ const is_key2 = engine.selected_key2 != undefined && engine.selected_key2.x == x && engine.selected_key2.y == y;
991
+ if(is_key1 || is_key2){
992
+ this.pri_tile_shader.setColour(1, 0, 1);
993
+ }else{
994
+ this.pri_tile_shader.setColour(0, 1, 1);
995
+ }
996
+
997
+ const model = Matrix.TransformationMatrix3x3.translate(tx, ty);
998
+ model.multiply(Matrix.TransformationMatrix3x3.scale(gs, gs));
999
+
1000
+ this.setTile(this.pri_tile_shader, engine.grid, x, y);
1001
+ this.pri_tile_shader.setMvp(this.vp.multiplyCopy(model));
1002
+ Shapes.Quad.drawRelative();
1003
+ }
1004
+ drawMultiKeyTile(engine: WallEngine, x: Int32, y: Int32){
1005
+ this.multi_colour_centre_circle_shader.use();
1006
+ const gs = engine.rect_grid.size;
1007
+ const model = WebGL.WebGL.rectangleModel(x*gs, y*gs, gs, gs);
1008
+ this.multi_colour_centre_circle_shader.setMvp(this.vp.multiplyCopy(model));
1009
+ //this.multi_colour_centre_circle_shader.setCircleRadius(0.1);
1010
+ this.setMultiTile(engine, this.multi_colour_centre_circle_shader, x, y, true);
1011
+ Shapes.Quad.draw();
1012
+ //this.setMultiTile(this.multi_colour_centre_circle_shader, engine.grid.grid[y][x].);
1013
+ }
1014
+ drawMultiWallTile(engine: WallEngine, x: Int32, y: Int32){
1015
+ this.multi_colour_tile_shader.use();
1016
+ const gs = engine.rect_grid.size;
1017
+ const model = WebGL.WebGL.rectangleModel(x*gs, y*gs, gs, gs);
1018
+ this.multi_colour_tile_shader.setMvp(this.vp.multiplyCopy(model));
1019
+ this.setMultiTile(engine, this.multi_colour_tile_shader, x, y, false);
1020
+ Shapes.Quad.draw();
1021
+ }
1022
+ drawWallTile(shader: DirectionTileShader, engine: WallEngine, x: Int32, y: Int32){
1023
+ const gs = engine.rect_grid.size;
1024
+ const tx = x*gs;
1025
+ const ty = y*gs;
1026
+ const model = Matrix.TransformationMatrix3x3.translate(tx, ty);
1027
+ model.multiply(Matrix.TransformationMatrix3x3.scale(gs, gs));
1028
+ shader.use();
1029
+ this.setTile(shader, engine.grid, x, y);
1030
+ shader.setSize(0.2);
1031
+ shader.setMvp(this.vp.multiplyCopy(model));
1032
+ Shapes.Quad.drawRelative();
1033
+ }
1034
+ drawCar(car: Car.ResourceCar, engine: WallEngine){
1035
+ const gs = engine.rect_grid.size;
1036
+ const cs = car.size*gs;
1037
+
1038
+ if(car.is_selected){
1039
+ const outline_size = 4;
1040
+ //const half_outline = outline_size*0.5;
1041
+ //draw outline
1042
+ this.solid_shader.use();
1043
+ this.solid_shader.setColour(1, 1, 1);
1044
+
1045
+ const outline_model = WebGL.WebGL.rectangleModel(
1046
+ car.x*gs, car.y*gs,
1047
+ cs+outline_size, cs+outline_size
1048
+ );
1049
+ this.solid_shader.setMvp(this.perspective.multiplyCopy(outline_model));
1050
+
1051
+ WebGL.Shapes.CenterQuad.draw();
1052
+ }
1053
+
1054
+ this.texture_shader.use();
1055
+ this.textures.active("car", 2);
1056
+ this.texture_shader.setTextureId(2);
1057
+ const model = WebGL.WebGL.rectangleModel(car.x*gs, car.y*gs, cs, cs);
1058
+ model.rotate(car.rotation+Math.PI);
1059
+ this.texture_shader.setMvp(this.vp.multiplyCopy(model));
1060
+ Shapes.CenterQuad.draw();
1061
+ }
1062
+ render(engine: WallEngine){
1063
+ //const perspective = Matrix.TransformationMatrix3x3.orthographic(0, 500, 500, 0);
1064
+ const gs = engine.rect_grid.size;
1065
+ this.vp = this.perspective.multiplyCopy(engine.view);
1066
+
1067
+ //const ctx = WebGL.gl;
1068
+ //setup shader vars
1069
+ this.grid_tile_shader.use();
1070
+ this.grid_tile_shader.setBackgroundColour(1.0, 1.0, 0.0);
1071
+ this.grid_tile_shader.setColour(0.0, 0.0, 1.0);
1072
+
1073
+ this.pri_tile_shader.use();
1074
+ this.pri_tile_shader.setCircleRadius(0.18);
1075
+ this.pri_tile_shader.setSize(0.2);
1076
+ this.pri_tile_shader.setColour(0, 1, 1);
1077
+ this.pri_tile_shader.setBackgroundColour(1, 1, 0);
1078
+
1079
+ for(let y = 0; y < engine.grid.height; y++){
1080
+ for(let x = 0; x < engine.grid.width; x++){
1081
+ if(engine.grid.grid[y][x].is_key){
1082
+ this.drawMultiKeyTile(engine, x, y);
1083
+ }
1084
+ else{
1085
+ this.drawMultiWallTile(engine, x, y);
1086
+ }
1087
+ }
1088
+ }
1089
+
1090
+ this.drawGridLines(engine);
1091
+
1092
+ for(const [id, car] of engine.car_collection.cars){
1093
+ this.drawCar(car, engine);
1094
+ }
1095
+
1096
+ this.displayNodeSheet(engine);
1097
+
1098
+
1099
+ //draw buttons
1100
+ engine.buttons.draw(this.perspective, this.solid_shader, this.text_drawer);
1101
+ engine.toggle_buttons.draw(this.perspective, this.solid_shader, this.text_drawer);
1102
+
1103
+ if(engine.true_mouse){
1104
+ //console.log(engine.true_mouse)
1105
+ const text = `x ${engine.true_mouse.x}, y ${engine.true_mouse.y}`;
1106
+ this.text_drawer.drawText(this.vp, 40, 300, text, 15);
1107
+ }
1108
+ if(engine.grid_true_mouse){
1109
+ const text = `x ${engine.grid_true_mouse.x.toFixed(2)}, y ${engine.grid_true_mouse.y.toFixed(2)}`;
1110
+ this.text_drawer.drawText(this.vp, 40, 400, text, 15);
1111
+ }
1112
+
1113
+ if(engine.hover_grid_side != undefined){
1114
+ const text = engine.hover_grid_side === GridCellSectionEnum.Center ? "Center"
1115
+ : Grid.DirectionUtil.toString(engine.hover_grid_side as Grid.GridDirection);
1116
+ this.text_drawer.drawText(this.vp, 20, 700, text, 15);
1117
+ }
1118
+
1119
+ if(engine.hovered_car != undefined){
1120
+ this.displayCarDetails(engine.car_collection.get(engine.hovered_car)!, engine);
1121
+ }
1122
+
1123
+
1124
+ // status texts
1125
+ const graph_status_text = engine.graph_updated_status ? Texts.SimStatus.graph_is_update : Texts.SimStatus.graph_needs_update;
1126
+ this.text_drawer.drawText(this.perspective, 0, 0, graph_status_text, 10);
1127
+
1128
+ engine.test_text_box.draw(this.perspective, this.solid_shader, this.text_drawer);
1129
+ for(const opt of engine.select_options){
1130
+ opt.draw(this.perspective, this.solid_shader, this.text_drawer);
1131
+ }
1132
+
1133
+ engine.test_internal_window.draw(this.perspective, this.solid_shader);
1134
+ this.drawInWindowTest(engine.test_internal_window);
1135
+ engine.test_drop_option.draw(this.perspective, this.solid_shader, this.text_drawer);
1136
+ }
1137
+ drawGridLines(engine: WallEngine){
1138
+ this.solid_shader.use();
1139
+ this.solid_shader.setColour(0.1,0.1,0.1);
1140
+ const line_thickness = 2;
1141
+ const half_thickness = line_thickness/2;
1142
+ for(let y = 0; y <= engine.grid.height; y++){
1143
+ const model = WebGL.WebGL.rectangleModel(0, y*engine.rect_grid.size-half_thickness, engine.rect_grid.pixel_width, line_thickness);
1144
+ this.solid_shader.setMvp(this.vp.multiplyCopy(model));
1145
+ Shapes.Quad.drawRelative();
1146
+ }
1147
+ for(let x = 0; x <= engine.grid.width; x++){
1148
+ const model = WebGL.WebGL.rectangleModel(x*engine.rect_grid.size-half_thickness, 0, line_thickness, engine.rect_grid.pixel_height)
1149
+ this.solid_shader.setMvp(this.vp.multiplyCopy(model));
1150
+ Shapes.Quad.drawRelative();
1151
+ }
1152
+ Shapes.Quad.draw();
1153
+ }
1154
+ setMultiTile(engine: WallEngine, shader: MultiColourTileShader, x: Int32, y: Int32, center_circle: boolean=false){
1155
+ const tile = engine.grid.grid[y][x];
1156
+ const direction_tile_functions = [
1157
+ {var: tile.left, colour_func: shader.setLeftColour},
1158
+ {var: tile.right, colour_func: shader.setRightColour},
1159
+ {var: tile.bottom, colour_func: shader.setTopColour},
1160
+ {var: tile.top, colour_func: shader.setBotColour}
1161
+ ];
1162
+ for(const var_func of direction_tile_functions){
1163
+ const colour = this.tile_state_colours.get(var_func.var)!;
1164
+ var_func.colour_func.apply(shader, [colour.red, colour.green, colour.blue]);
1165
+ }
1166
+ if(tile.is_selected){
1167
+ shader.setMidColour(this.key_colour.red, this.key_colour.green, this.key_colour.blue);
1168
+ }else if(!center_circle && tile.bottom == Grid.TileStateEnum.Nothing && tile.left == Grid.TileStateEnum.Nothing
1169
+ && tile.top == Grid.TileStateEnum.Nothing && tile.right == Grid.TileStateEnum.Nothing){
1170
+ shader.setMidColour(this.background_colour.red, this.background_colour.green, this.background_colour.blue);
1171
+ }else{
1172
+ const c = this.tile_state_colours.get(Grid.TileStateEnum.Path)!;
1173
+ shader.setMidColour(c.red, c.green, c.blue);
1174
+ }
1175
+ //this.setMultiTile(shader, tile.);
1176
+ }
1177
+ drawResource(res: Resource.Resource, x: Float, y: Float, size: Float){
1178
+ this.texture_shader.use();
1179
+ switch(res){
1180
+ case Resource.ResourceEnum.Water:
1181
+ this.textures.active("drop", 3);
1182
+ this.texture_shader.setTextureId(3);
1183
+ break;
1184
+ case Resource.ResourceEnum.Apple:
1185
+ break;
1186
+ }
1187
+ const model = WebGL.WebGL.rectangleModel(x, y, size, size);
1188
+ this.texture_shader.setMvp(this.perspective.multiplyCopy(model));
1189
+ Shapes.Quad.draw();
1190
+ }
1191
+ drawResourceInventory(node: Node.KeyNode, x: Int32, y: Int32, res_size: Int32, num_size: Int32){
1192
+ let rx = x;
1193
+ //const res_size = 15;
1194
+ //const num_size = 5;
1195
+ for(const [res, amount] of node.inventory){
1196
+ this.drawResource(res, rx, y, res_size);
1197
+ const str = amount.toString()
1198
+ const offset = str.length*num_size;
1199
+ this.text_drawer.drawText(this.perspective, rx+res_size-offset, y+res_size-num_size, str, num_size);
1200
+ rx += res_size;
1201
+ }
1202
+ }
1203
+ displayNodeSheet(engine: WallEngine){
1204
+ if(engine.hovered_node != undefined && engine.true_mouse != undefined){
1205
+ //background
1206
+ const text_size = 12;
1207
+ const x = engine.true_mouse.x+20;
1208
+ const y = engine.true_mouse.y;
1209
+ const ui_height = engine.hovered_node.drawNodeUI(this.perspective, this.solid_shader, this.text_drawer, x, y, text_size);
1210
+ this.drawResourceInventory(engine.hovered_node, x, y+ui_height, 20, 10);
1211
+
1212
+ /*
1213
+ if(engine.hovered_node.type === Node.NodeTypeEnum.Resource){
1214
+ const res_node = engine.hovered_node as Node.ResourceGeneratorNode;
1215
+ //show resources in node //TODO
1216
+ this.text_drawer.drawText(this.perspective, x, y+31, "Res", 15);
1217
+ this.drawResource(res_node.resource, x, y+46);
1218
+ this.text_drawer.drawText(this.perspective, x+15, y+46, res_node.getResourceInventory(res_node.resource).toString(), 15);
1219
+
1220
+ }else if(engine.hovered_node.type === Node.NodeTypeEnum.Requirement){
1221
+ const req_node = engine.hovered_node as Node.RequirementNode;
1222
+ this.text_drawer.drawText(this.perspective, x, y+31, "Req", 15);
1223
+ this.drawResource(req_node.require_resource, x, y+46);
1224
+ }*/
1225
+
1226
+ /*
1227
+ this.solid_shader.use();
1228
+ const back_model = WebGL.WebGL.rectangleModel(x, y, 70, 70);
1229
+ this.solid_shader.setColour(0, 0, 0);
1230
+ this.solid_shader.setMvp(this.perspective.multiplyCopy(back_model));
1231
+ Shapes.Quad.draw();
1232
+
1233
+ //details
1234
+ this.text_drawer.drawTextColour(this.perspective, x, y, engine.hovered_node.x.toFixed(0), 15, this.white);
1235
+ this.text_drawer.drawTextColour(this.perspective, x, y+15, engine.hovered_node.y.toFixed(0), 15, this.white);*/
1236
+ }
1237
+ //engine.
1238
+ }
1239
+ displayResourceNodeSheet(engine: WallEngine){
1240
+ if(engine.hovered_node != undefined && engine.true_mouse != undefined){
1241
+ //background
1242
+ const x = engine.true_mouse.x+20;
1243
+ const y = engine.true_mouse.y;
1244
+ engine.hovered_node.drawNodeUI(this.perspective, this.solid_shader, this.text_drawer, x, y);
1245
+ }
1246
+ }
1247
+ displayCarDetails(car: Car.ResourceCar, engine: WallEngine){
1248
+ //displaying on bottom left
1249
+ const y = engine.rect_grid.pixel_height + 10;
1250
+ const text_size = 10;
1251
+ let car_text = `id ${car.id.toString()}`;
1252
+ if(car.is_selected){
1253
+ car_text += " selected";
1254
+ }
1255
+ this.text_drawer.drawText(this.perspective, 10, y, car_text, text_size);
1256
+ const x_text = `x ${car.x.toFixed(2)}`;
1257
+ this.text_drawer.drawText(this.perspective, 10, y+text_size, x_text, text_size);
1258
+ const y_text = `y ${car.y.toFixed(2)}`;
1259
+ this.text_drawer.drawText(this.perspective, 10, y+(text_size*2), y_text, text_size);
1260
+
1261
+ const car_node_id = car.starting_node.getId();
1262
+ const st_node_text = `Start node id ${car_node_id.toString()}`;
1263
+ this.text_drawer.drawText(this.perspective, 10, y+(text_size*3), st_node_text, text_size);
1264
+
1265
+ const target_node_text = car.target_node != undefined ?
1266
+ `Target node id ${car.target_node.getId().toString()}` : "No Target";
1267
+ this.text_drawer.drawText(this.perspective, 10, y+(text_size*4), target_node_text, text_size);
1268
+ }
1269
+ drawInWindowTest(window: InternalWindow.InternalWindow){
1270
+ if(window.visible){
1271
+ const p = window.getWindowPosition();
1272
+ this.text_drawer.drawText(this.perspective, p.x+10, p.y+10, "Hello world", 10);
1273
+ }
1274
+ }
1275
+ /*
1276
+ setMultiTile(shader: MultiColourTileShader, left: boolean, top: boolean, right: boolean, bot: boolean, active_colour: Colour.ColourRGB, inactive_colour: Colour.ColourRGB){
1277
+ if(left || top || right || bot){
1278
+ shader.setMidColour(active_colour.red, active_colour.green, active_colour.blue);
1279
+ }else{
1280
+ shader.setMidColour(inactive_colour.red, inactive_colour.green, inactive_colour.blue);
1281
+ }
1282
+ if(left){
1283
+ shader.setLeftColour(active_colour.red, active_colour.green, active_colour.blue);
1284
+ }else{
1285
+ shader.setLeftColour(inactive_colour.red, inactive_colour.green, inactive_colour.blue);
1286
+ }
1287
+ if(bot){
1288
+ shader.setTopColour(active_colour.red, active_colour.green, active_colour.blue);
1289
+ }else{
1290
+ shader.setTopColour(inactive_colour.red, inactive_colour.green, inactive_colour.blue);
1291
+ }
1292
+ if(right){
1293
+ shader.setRightColour(active_colour.red, active_colour.green, active_colour.blue);
1294
+ }else{
1295
+ shader.setRightColour(inactive_colour.red, inactive_colour.green, inactive_colour.blue);
1296
+ }
1297
+ if(top){
1298
+ shader.setBotColour(active_colour.red, active_colour.green, active_colour.blue);
1299
+ }else{
1300
+ shader.setBotColour(inactive_colour.red, inactive_colour.green, inactive_colour.blue);
1301
+ }
1302
+ }*/
1303
+ setTile(shader: DirectionTileShader, grid: Grid.WallGrid, x: Int32, y: Int32){
1304
+ if(!grid.isInside(x, y)) return;
1305
+ if(grid.grid[y][x].left){
1306
+ shader.setLeft(1.0);
1307
+ }else{
1308
+ shader.setLeft(0.0);
1309
+ }
1310
+ if(grid.grid[y][x].bottom){
1311
+ shader.setTop(1.0);
1312
+ }else{
1313
+ shader.setTop(0.0);
1314
+ }
1315
+ if(grid.grid[y][x].right){
1316
+ shader.setRight(1.0);
1317
+ }else{
1318
+ shader.setRight(0.0);
1319
+ }
1320
+ if(grid.grid[y][x].top){
1321
+ shader.setBot(1.0);
1322
+ }else{
1323
+ shader.setBot(0.0);
1324
+ }
1325
+ }
1326
+ }