forked from Wren6991/Ship-Sandbox
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathShipSandbox TODO.txt
1809 lines (1728 loc) · 79.9 KB
/
ShipSandbox TODO.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
=================================================
Current perf
=================================================
- fps: 27.1 (Samsung: TBD (Krafting)) (Mattia's: 27.5 (Krafting))
- GameController::DoStep: 33.80%
- Ship::Update: 32.75% (Incl) 0.00% (Excl)
- UpdateDynamics: 25.79%
- UpdateSpringForces: 18.47%
- UpdatePointForces: 4.00%
- HandleCollisionsWithSeafloor: 2.35%
- Integrate: 0.97%
- GravitateWater: 4.89%
- BalancePressure: 1.23%
- UpdateStrains: 0.82%
- LeakWater: 0.02%
- DiffuseLight: 0.89%
- WaterSurface::Update: 0.14%
- sinf: 0.10%
- MainFrame::RenderGame: 59.44%
- Ship::Render: 52.65% (Incl) 0.00% (Excl)
- ShipRenderContext::RenderSprings: 30.39%
- ShipRenderContext::RenderTriangles: 21.66%
- ShipRenderContext::RenderRopes: 0.42%
- Points::Upload: 0.14%
- RenderContext::RenderCloudsEnd: 2.85%
=================================================
Prev perf (before point et al destructuring)
=================================================
- fps: 17.8/18.1 (Samsung: TBD (Krafting)) (Mattia's: TBD (Krafting))
- GameController::DoStep: 56.52%
- Ship::Update: 55.82% (Incl) 1.50% (Excl)
- UpdateDynamics: 41.74%
- UpdateSpringForces: 24.76%
- UpdatePointForces: 6.77%
- HandleCollisionsWithSeafloor: 5.11%
- Integrate: 5.08%
- GravitateWater: 6.58%
- BalancePressure: 5.84%
- LeakWater: 0.16%
- DiffuseLight: 0.65%
- WaterSurface::Update: 0.05%
- MainFrame::RenderGame: 35.98%
- Ship::Render: 31.92% (Incl) 0.39% (Excl)
- ShipRenderContext::RenderSprings: 17.91%
- ShipRenderContext::RenderTriangles: 13.24%
- ShipRenderContext::RenderRopes: 0.30%
- RenderContext::RenderCloudsEnd: 1.69%
=================================================
- Redo perf profile (should be unchanged)
- Release
+++++++++++++++++++++++++++++++++++++++++++++++
- Technical Debt:
+ Move definition of ElementIndex et al into GameTypes.h
- Move also pinned points to a PinnedPoints class, just like Bombs
- Textures are json files, with world sizes, offset, and lighting boolean
- SEE MOLESKINE
- Then:
- Change bomb rendering: takes vector of frame indices, no optionals needed
- Remove hardcoded sizes and offsets
- Cloud size
- Water size
- Land size
- Bombs sizes and offsets
- Optimizations:
- See if can avoid other IsDeleted checks, via zero'ing of coefficients
- UpdatePointForces:
- Precalculate things that do not depend on position nor velocity
- Stored either in buffers (if we go for exploded Pos, Vel, etc.) or in Point (if we don't go for that)
- Technically, would have to store separately effectiveMassMultiplier (*Mass) and effectiveBuoyancy (*Mass)
- Test: but could cheat and use water height based on initial positions only, in which case
we store directly StaticForce == Gravity + Water Drag (?REALLY?)
- StaticForce used directly in Integrate() added to Force
- Or better if added to Force at UpdatePointDynamics()?
- Split Spring::WaterPermeability in two, with pre-calculated values:
- WaterGravitationFactor
- WaterPropagationFactor
- GravitateWater:
- Calculate once and for all cos theta's at first iteration
- !!! Actually, calculate WaterGravityFactorA = dt*0.6*(1+cos_theta)/2, WaterGravityFactorB = -dt*0.6*(1-cos_theta)/2
float cos_theta_select = (1.0f + cos_theta) / 2.0f;
float correction = 0.60f * cos_theta_select * pointA->GetWater() - 0.60f * (1.0f - cos_theta_select) * pointB->GetWater();
correction *= GameParameters::SimulationStepTimeDuration<float>;
- Test (check disassembly) with templated lambda (Spring const &)->void
- First one calculates factors and stores them in Spring
- All others empty
- All iters take factors from Spring after calling lambda
- If SSE2 works, see if can parallelize also:
- BalancePressure, GravitateWater, SpringDynamics
- See shuffled loading and storing of 4 arbitrary floats in ETH deck
- Water and Land interpolations:
- 1: see if it's better to store delta's and/or other pre-calculated things
- 2: see if can do semi-integer x-axis interpolation
- Release:
- Do final round with all ships
- Post on Forum
- Gfx:
- Option to enable drawing of force vectors for each point
- Texture atlas:
- Test first if with a single texture bind per ship (which will look crappy!) there's a significant
performance difference
- Check the three boxes
- Optimizations:
- More connected components => slower (multiple batches); try
to draw one single batch then, using Z buffer
- Assign Z based on connected component ID
- See if drawing springs & triangles with Z buffer and depth test helps (for springs' fragment shader, may be it takes
shortcuts if it knows it's behind)
- AmbientLightIntensity:
+ Use also in RenderContext::RenderStart() for clear (sky) color
+ Phase 1: pgup/down
- Phase 2: with clock - TBD
- Magnifying glass
- https://www.opengl.org/discussion_boards/showthread.php/154811-magnifying-glass-effect
- https://www.shadertoy.com/view/4tdXDl
- ocean depth bitmaps
- Save photos (opens SaveAs FileDialog)
- Text (for query tool):
- see https://github.com/wxWidgets/wxWidgets/blob/master/samples/opengl/pyramid/pyramid.cpp
- Dynamics:
- Ephemeral Particles:
- Carve out room at tail of Points for ephemeral particles
- No need to mark as deleted to hide them
- Tail managed as circular queue, used when creating new ones - eventually smothering oldest
ones (started more anciently, but not necessarily closest to death as each has own lifetime)
- TODO: not really circular queue, dead not last must be reused
- Points has new buffers:
- EphemeralType (uint8 enum)
- None (set at non-ephemeral and at dead ephimerals)
- Sparkle
- EphemeralLife (float between 0.0 and 1.0)
- EphemeralXTODOX: union of structs
- SparkleXTODOX:
- TODO
- Smothering done by Ship (UpdateEphemeralParticles) as:
- TODO:
- Points methods:
- TODO: create/kill, create has first overload that takes all the dynamics params, including Material, and
type-specific params
- Rendering:
- Points::UploadEphemeralParticles():
- (Ship)RenderContext::TODOHERE
- Do chainsaw sparkles with Ephemeral Particles
- At Ship::Chainsaw
- Test:
- Self-adjustment of kSpring and kDamp based off paper's formula (H and L bounds)
- Debug to see if bounds ever exceeded
- See if can draw a bit more often
- Frontier:
- Only for non-rope points - rope points never take part in frontier
- Preliminaries:
- Make sure endpoints in triangle are always in CW order
- In order to correctly draw dangling (i.e. same connected component) parts on top of all of the connected component's
frontiers, we'd need to have the dangling parts disconnected from the connected component, which means that we should
not follow ropes during connected component detection
- Still vulnerable to dangling parts not connected via ropes (e.g. masts) though: frontier would be drawn on top of it
- Might get away with drawing frontiers - *enlarged* - before all of the rest? The enlarged part would be visible
only through holes and around external frontiers
- TODO: all the following might have to be revisited
- Realize that a node can belong to up to 4 frontiers (center of 4 holes)
- And a point deletion might cause a merge of the four
- Frontier is set of points, marked as frontier, and connected to each other via
nextInFrontier * and prevInFrontier * (in CW order)
- Algo:
- There are multiple frontiers, 0 is external, N is internal, isolated
- Calculate frontier at ship create, based off structural matrix, using geometry
- At each point deletion:
- 2 cases: OR: only later check if one of the connected points is already a frontier
(a deleted frontier point is bound to be connected to two other points of the same frontier, for each frontier)
- Point deleted is a frontier point:
- TODO
- Point deleted is NOT a frontier point:
- All its connected points become a frontier
- If one of the connected points is already a frontier, then the new frontier points
take that frontierId
- TODO
- Water drag
- The one already there assumes velocity always normal to surface, but we should consider surface normal instead
- Experiment with:
- Runge-Kutta
- Semi-implicit Euler (https://www.scss.tcd.ie/Michael.Manzke/CS7057/cs7057-1516-14-MassSpringSystems-mm.pdf)
- Water:
- Sinking detection is broken - it currently only considers total water that entered the ship, which comes proportionally to external
water pressure; all this water could be confined to a tiny volume, and yet we trigger sinking
- Option 1: make it based on total number of points that have water instead, i.e. wet points
- ...which requires Points to keep track of point's water going from 0.0 to > 0.0, at all possible
avenues of change (LeakWater, BalancePressure, etc.)
- Or can just be calculated at end of each update with simple pass through water buffer
- Option 2: make it based on total number of points whose Y is underwater
- Could be done @ Ship::UpdatePoint() when the count of underwater points reaches threshold for the first time
- Just reset count before loop
- HOWEVER: a big part of the ship could be below water but dry...
- So: should try a combination of current mTotalWater and 3/4ths of points below water
+ Did original game propagate water also through hull springs? YES. How did hull thin dividers work? THEY DIDN'T WORK
+ Add Point::Hull Characteristic, and don't leak/propagate(incl. gravitate) water if at least one of the two points is hull
+ Alternatively: just make a spring hull if one point is hull; test it
- BalancePressure: see if shouldn't average water among two points - do we lose waves if we do so?
- GravitateWater: can avoid checking sign of cos theta - using minus to still move water from higher to lower?
- BalancePressure: use gradient, it seems we stuff too much water into points with already too much water
- GravitateWater: try inverse visit (from H to L)
- Requires PointerVector::rbegin,rend
- Try directional BalancePressure?
- Make waves with Shallow Water Equations plus breaking waves
- And if frontier works, change height when frontier touches water for the first time
- DestroyAt:
- Test: Ship::SpringDestroyHandler() only destroys triangles that contain A-B
- Should definitely make both A and B leak, as they both now have an adjacent hole
- Controls:
- SettingsDialog: save settings, and defaults
- JSON for both game & render params, assembled & saved by gamecontroller, who also loads it on startup if exists
- GameParameters::ToJson()->picojson::value
- GameParameters::FromJson(picojson::value) (sets own)
- Save Settings: saves current to personal_settings.json
- where? see wxwidgets or portable way
- Standard paths: http://docs.wxwidgets.org/3.1/classwx_standard_paths.html#a4752213ef4d7bdc71170b9e5c3691f0f
- Call App::SetAppName() at startup
- Pass user folder path to GameController at startup, so latter doesn't have to deal with wxWidgets
+ https://softwareengineering.stackexchange.com/questions/3956/best-way-to-save-application-settings/3990#3990?newreg=bffd79f524c14afe84f2178cd3211a94
- personal_settings.json loaded at startup if exists, else default_settings.json
- Save Settings As: saves with filename, nothing else
- Load Settings: loads with filename, changes own settings
- Reset Settings: loads default_settings.json, changes own settings
- Sounds:
+ Reset sound controller at ResetAndLoadShip()
- Water rushing-in
- Continuously-playing sound
- Volume time-interpolated off total quantity of water that entered ships during step
- Communicated via new event
- Volume = -1/(Qw+1) + 1
- Histograms:
- class Histogram
- map<float, float in [0,1]>
- class Statistics (various Histograms, etc.)
- Histogram pointWaterHistogram
- ...
- World::GetStatistics() -> Statistics
- Visits all points across ships, no need to merge histograms
- Exposed by GameController as well
- StatisticsDialog
- Pre-created member of MainFrame
- Has GameController
- Shown depending on menu (like LoggingDialog)
- exposes Update() invoked by MainFrame, always, after simulation step
- Update():
- if not visible, return;
- Get and draw Statistics
- Histogram control (panel? Check wx literature)
- Lights
+ need Optional()
+ Material:
+ use picojson
+ Material.ElectricalProperties (optional)
+ type (Material::ElectricalProperties::ElectricalElementType=lamp, cable, generator)
+ flat list of all electrical properties, some apply some don't
+ class Lamp()
+ points to Point and Point points optionally to ElectricalElement (base abstract of Lamp, Cable, Generator)
+ ElectricalElement::GetType(){return mType;}: non-virtual, it's optimized by compiler
- Move electrical components to ElectricalComponents class, an ElementContainer but also like bombs, with update and state machines
(but no render)
- Buffer of pointers
- Buffer of ElementIndex of points
- Same at Points: electrical elements are indices
- Add additional buffers that might simplify electrical connectivity test, e.g. Type and VisitedGen
- Current Propagation Algo (Ship::UpdateCurrentConnectivity()):
+ create new generation seq number; if new is 0 => 1
- Consider adding a new "ConductsElectricity" buffer to Springs, set to true or folse at Add() depending
on whether or not both endpoints' materials have ConductsElectricity=true
- ConductsElectricity replaces all the other useless electrical properties
- This simplifies current connectivity graph visit
- Alternative is to check at visit time whether other endpoint has a non-None attached ElectricalElement index,
but this means lots of useless cache misses for getting point's buffer content (only a small percentage of points
have an ElectricalElement attached)
- ElectricalElement has SetVisited(curGen), bool IsVisited(curGen), operating on buffers
- @Sip::Update, electrical section: if mAreElementsDirty: invoke UpdateCurrentConnectivity()
- Visit whole electrical graph, as:
- For each generator point:
- if not visited=>flood all connected ElectricalElements from here
- for each node: set to visited
- No need to have a visited set, just call ElElement->IsVisited(curGen)
- Then, lamps will be considered lighted if visited at this generation
- OLD: generators and cumulative current calculation:
- visit all generator points and count the points in their graphs; for each connected component:
- # nodes in component => current
- propagate from each of these points to all adjacent cables until light
- at a light: add up all incoming currents (compare seq number to decide whether to zero or not)
and then lower them by distance(==ohm), and then update gen number of lamp
- Then, ElectricalElements::Update(currentGenerationNumber)
- Calls Lamp->Update(currentGenerationNumber):
- TODO: draw state machine
- Looks at own (generationVisitNumber, state) and:
- Updates state
- Eventually starts flicker state machine:
+ Based off clock time, not simulation step
- iff: state==On and generationVisitNumber != current
- Invokes IGameEventHandler->OnLightFlicker()
- Sets gen_number = 0
- If revisited, state machine will transition to lighted again
- Flicker state machine is based off clock time, not simulation step
- Use random choices
- Sets own lightIntensity = f(generationVisitNumber, state, flicker state machine)
- Then, go ahead with DiffuseLight as now
+ Diffusion:
+ Can test it by itself, by using light material and by cheating with current!
+ After current propagation:
+ Zero out mLight of each point (use generation sequence number? useful for other Point properties?)
+ No, easier and probably faster to do it in same pass as LeakWater - LeakWaterAndZeroLight()
+ Diffusion: propagate mLight to adjacent points (incl. other lamps),
inv. proportional to distance^2, with a graph flood stopping at max distance
+ Point.GetColour() takes also into account mLight (from itself, not from lamp)
and makes alpha blend just like water
+ Need "off" color to use at lamp point when Lamp is off (different than structural color),
used when rendering point in springs/triangles/points
+ Not used when using textures, of course
+ Needs material's Color to split in StructuralColor and RenderColor (set to the same except for lamps)
- Diffusion improvement: see if can simply add light (rather than max'ing it)
- Need to ensure sum is always < 1.0
- May be via adding +1 to distance?
- Smoke
- Smoke-material points, emitting particles with a lifetime and a transparency connected to age
- Multiple ships:
- Better after collision detection
- When ship loaded (added):
- World adds it not to mShips, but as opt<Ship> mPendingShip
- Not considered in Update(), but considered in Render()
- MainFrame begins new PendingShipPlace tool
- OnMouseMove: tell GameController (->World) mouse position as GameController::MovePendingShipTo(screen coords)
- Ship::MoveTo(world x, y):
- Moves all Points by (x,y)-mCurrentRepresentativePosition
- Ship::mCurrentRepresentativePosition (init'd as {0,0}) tracks current "center"
- mCurrentRepresentativePosition = (x,y)
- OnLDown:
- Tell GameController (DropPendingShip(x, y)) which:
- Tells World via World::DropPendingShip(x, y):
- Final Ship::MoveTo()
- Move ship from mPendingShip into mShips
- Fires IGameEventHandler::OnPendingShipPlaced(shipId)
- EventTicker: say this and other Reset/Load
- SoundController: play sound
- Stop PendingShipPlace tool
==============================================================================
==============================================================================
==============================================================================
==============================================================================
==============================================================================
==== DONE
==============================================================================
==============================================================================
==============================================================================
==============================================================================
==============================================================================
+ Build glfw yourself
+ clone from git
+ build
+ fix Ship's CMake
+ C:\Users\Neurodancer\source\build\glfw\src\Release
+ move to source/build:
+ ShipSandbox
IF WX:
+ build WX (Debug, Release)
+ add WX to CMakeFiles.txt
C:\Users\Neurodancer\source\repos\wxWidgets\include
C:\Users\Neurodancer\source\repos\wxWidgets\lib\vc_x64_lib
names: wxmsw31u[d]_core.lib wxbase31u[d].lib
+ remove titanicapp.*, titanicmain.* from CMakeFiles.txt
+ do a simple main with wx
+ rebuild WX with C++ Runtime being statically linked
+ test
+ see getting rid of whole wx.h and only include wxwindow
+ get rid of GLFW in all source files
+ setup CMakeFiles.txt: Remove GLFW
+ resuscitate old code, merging it with new existing structure:
+ mainApp - mainApp class, main #define
+ mainFrame - entire frame
+ test
+ remove titanicapp.*, titanicmain.*, main_old.cpp
+ one-shot timer
+ nuke GLFW from hard disk (repo, build)
+ add logger and fix missing ship
+ Get perf baseline and start Readme.md and Changes.txt
===========
+ cherry-pick that typo fix
+ logging window: try http://docs.wxwidgets.org/3.0/classwx_text_ctrl.html
+ rename members of Frame, cleanup code
+ Render/Game"Settings" -> "Parameters"
+ LoggingWindow -> "Dialog"
+ SettingsDialog:
+ Add spacing
+ Taller sliders
+ Min and Max
+ add textboxes 4 vals
+ ApplySettings()
+ GameController takes (& gives) absolute vals, & provides GetXMax/MinValue() (from YYYParameters)
+ Helper funcs in SettingsDialog do conversions
+ ReadSettings()
+ Other controls for other settings
+ rename members, cleanup code
+ MainFrame:
+ LogWindow bug when minimizing and maximizing main frame
+ Do we need mMainGLCanvas and context to be unique_ptr's?
+ Render once @ beginning
+ Check if OnPaint is the right one
+ Maximize
+ ReloadLastSelected
+ See if canvas.setcontext is necessary
+ Watch out for resize
+ +/- for zoom *IN MENU*
+ remove wxEVT_CHAR_HOOK at panel and use menu hotkey and event instead
+ Investigate dirty lines
+ Use own exception
+ Fix DestroyAt
+ Add DestroyRadius to GameParameters (not in SettingsDialog yet)
+ Fix final destroyer
+ Setup UnitTests
+ Build GTest Debug and Release
+ Create UnitTests project in CMake
+ First unit test: vectors
+ GameException: cctor with string
+ Utils::Convert(string)->wstring
+ Rebuild Devil but make it a dll with static runtime
+ Move DevIL init to GameController
+ No DevIL dep's in ShipSandbox
+ DevIL_INCLUDEs from GameLib are not public
+ Move to picojson
+ Nuke SDK
+ Remove public-ness of JSonCPP
+ Settings:
+ Destroy Radius
+ "World"XYZ if really it is world
+ Frustum? For 2D? Try Ortho?
+ Change MainFrame's build info
+ separate Version.h
+ Mask with copyright at all source files (copy from XXmain)
+ Already capitalized
+ Those to be capitalized
+ material
+ Rename
+ cctors:
+ from picojson obj
+ Create()->UQ_PTR
+ private cctor
+ all members const
+ optional Material::ElectricalProperties
+ Also Renderer becomes a namespace, not a class
+ render
+ Renderer
+ move ScreenToWorld here
+ All static methods, inline
+ util
+ phys:
+ Rename as Ship, World, Point, etc.
+ TODO: see first if can split into separate files
+ commit & push first
+ cpp's in namespace
+ Physics.h: includes all and each .h and .cpp includes Physics.h
+ Private vs Public attributes:
+ No friends
+ All members mPrivate
+ All getters and setters (when needed)
+ vec
+ Perf optimizations:
+ Move back to baseline
+ Take profile X 2
+ set these flags and see impact (on Release)
+ Ox
+ fp:fast
+ Flags for non-MSVC:
<Compiler>
<Add option="-O3" />
<Add option="-ffast-math" />
<Add option="-fno-math-errno" />
<Add option="-funsafe-math-optimizations" />
<Add option="-ffinite-math-only" />
<Add option="-fno-trapping-math" />
</Compiler>
+ Make all render() const
+ Make all render() inline
+ Make all vector funcs inline in .h
+ Take full baseline first
+ FPS: 17.3/17.7
+ We don't need redundant triangles
+ Row visit: for each point *after* the very first of a streak, only do triangles up to 90 degrees
+ But keep doing all springs
+ use boolean isInShip, init=false, set to true at end of single-point processing if point exists and set to false otherwise
+ Before: 5231 points, 19932 springs, 19569 triangles
+ After: 5231 points, 19932 springs, 9819 triangles
+ FPS: 19.2/19.3
+ Fix division by zero
+ Do fix
+ FPS: 19.1
+ SSE2:
+ Test first: Integrate:
+ 1a: pack Pos, Vel, Force from 2 points into local vec4f
+ For loop with two points at a time
+ 1b: create buffers with all Pos, Vel, Forces, and call function with restricted pointers: IT USES PACKED SSE's!
+ Undo
+ Vertex cache optimizations with Forsyth's algo:
+ Break out ShipBuilder, friend
+ Use own LRU cache and calculate current ACMR for triangles and springs
+ Spring ACMR: 0.516807
+ Triangle ACMR: 1.01986
+ Do triangle vertex cache optimization
+ New ACMR: 0.68174
+ FPS improvement: 19.1 -> 19.0
+ Check if self-covering within same connected component now looks weird
+ Test on samsung: 18.5/18.8 -> 18.5/18.6/18.8/19.0
+ REVERT, IT'S (MARGINALLY) WORSE!
+ Do spring vertex cache optimization
+ New ACMR: 0.325156
+ New FPS: 19.4/19.7
+ FPS: 19.3/19.5
+ ShipRendering: upload triangles, ropes, springs only when they change
+ Have VBOs per connected component
+ FPS: 19.0/19.4/19.7/19.9
+ Point & Spring Destructuring:
+ Starting FPS: 19.0/19.4/19.7/19.9
+ Main goal: improve cache locality
+ Secondary goal: make vectorization-friendly
+ Replace Point, Spring, Triangle with Points, Springs, Triangles
+ Base is ElementContainer
+ Defines aliases (ElementCount, ElementIndex) - uint32
+ ElementCount GetCount() const
- Number of elements
- passed at cctor
+ They contain N buffers:
+ Points: Position, Velocity, Force, MassFactor, Color, Water, IsDeleted ...
+ All scalars of a point that are only used for both x and y (e.g. MassFactor) are stored
(and updated, if any) twice, as vec2f (only MassFactor?)
+ All scalars of a point that are used as scalars (e.g. Buoyancy) are stored once
+ Test first to see if N buffers make a difference vs 1 larger buffer:
+ 1: Do Position, Velocity, Force, and MassFactors first in single Newtonz buffer
+ Get baseline 1:
- DoStep: 39.99%
- Ship::Update: 39.05%
- UpdateDynamics: 27.42%
- SpringForces: 20.18%
- PointForces: 3.77%
- CollisionsWithSeaFloor: 2.19%
- Integrate: 1.27%
- GravitateWater: 5.70%
- BalancePressure: 4.58%
- UpdateStrain: 1.03%
- Render: 51.69%
+ FPS=24.0/24.2/24.4
+ 2: Do separate Position, Velocity, Force, and MassFactors
+ Get baseline 2:
- DoStep: 39.01%
- Ship::Update: 38.01%
- UpdateDynamics: 27.44%
- SpringForces: 19.97%
- PointForces: 3.65%
- CollisionsWithSeaFloor: 2.24%
- Integrate: 1.57%
- GravitateWater: 4.87%
- BalancePressure: 4.51%
- UpdateStrain: 0.90%
- Render: 52.69%
+ FPS=24.1/24.3/24.7/25.0
+ Make buffer __restrict
+ FPS=24.8/24.9/25.1
+ If makes sense to explode:
+ Also explode ConnectedComponent
+ Phase 2: Springs: Points, dynamics coefficients, water coefficients, ...
+ Phase 2: Triangles: Points, Network
+ Phase 2: Change all ElementContainer::ElementIndex into ElementIndex
+ Structure of buffers:
+ For SSE2, need to be simple floats
+ For handling, need to be structured
+ Buffers are class Buffer
+ Need to be mem-aligned
+ cctor(size)
+ data()/size()/emplace_back()
+ uq_ptr
+ They expose buffer getters for each buffer (as the structured type, e.g. vec2f *, or PointNetwork *, or float * for lonely scalars)
+ e.g. vec2f* GetPositionBuffer()
+ When needed also exposed as floats as well (e.g. Position, for Integrate())
+ e.g. float* GetPositionBufferAsFloat()
+ size math left to caller
+ When needed, they expose getters and generally operations on single elements, via 32-bit index argument (aliased as ElementIndex)
+ e.g. void Destroy(ElementIndex)
+ e.g. float GetMass(ElementIndex)
+ Destroy(ElementIndex) takes care of telling ship that element count is dirty
+ Phase 3: set directly in Ship at initiation of Destroy chain, whenever we know we destroy something
+ Do at Spring::UpdateStrain: returns bool, true if destroyed
+ Do at tool's Destroy
+ Then get rid of two-phase ship cctor - plain cctor with moved ElementRepo's
+ So can also remove move assignment at Points
+ Pointers to points are replaced by 32-bit indices
+ Funcs that need to follow pointers (e.g. Destroy() and SpringDynamics()) also must take whole containers
+ Phase 2: also pointers to Springs & Triangles
+ ShipBuilder creates Points & moves into ship
+ Points' ConnectedXYZ are updated at ShipBuilder time
+ Remove code from Spring and Triangle and ElectricalElement-Cable-etc. cctors
+ Do Ship
+ Loop over indices, invoking Points::GetWhatever(index)
+ End of Phase 1: FPS=22.0/22.3/22.6
+ Phase 1.5: check assembly for:
+ 1: loop over indices, invoking Points::GetWhatever(index)
+ 2: loop over indices, taking buffers first and then dereferencing buffer with index
+ RESULT: IDENTICAL
+ Decide whether to keep bunch of GetWhatever(index) (both R and W) vs buffers
+ Check also disassembly of index iterator
+ End of Phase 1.5: FPS=23.2/23.3/23.4
+ To check:
+ UpdateDrawForces: see assembly difference for displacement.length() optimization
+ NO, actually compiler autonomously saves length for later, and explicit
code looks a bit different
+ UpdateSpringForces(): see assembly to check whether point.Force's are updated twice
+ YES
+ Update force once with sum of forces
+ HandleCollisionsWithSeaFloor(): see assembly to check for twice GetPosition()
+ YES, read once into xmm4 and re-used later
+ End of checks after Phase 1.5: FPS=24.0/24.2/24.4
+ Containers expose own Upload(RenderContext &)
+ Phase 3: direct upload of buffers into GPU via RenderContext
+ Nuke ShipRenderContext::mPointBuffer & friends
+ Phase 3: move texture coordinates and colors into Points, which uploads
at Upload() via own mAreImmutablePropertiesUploaded state
+ Nuke Ship::mIsPointCountDirty
+ Nuke ElementRepository, as at this moment no one should be using it anymore
+ Phase 3: Nuke PointerContainer
+ Phase 3: Nuke ShipElement, if it's now only implemented by ElectricalElement
+ See if managed to not need to tell Ship as well, see above
+ Phase 3:
+ Fix power-of-2 calculation at Buffer::cctor()
+ Fix World::GetNearestPointIndexAt, by making use of Ship::GetPointPosition(idx)
+ See square root optimization, here and @ Destroy()
+ Also fix its use at MainFrame, by making use of Ship::GetStuff()
+ Fix all warnings
+ Phase 2: Integrate():
+ After NewtonzBuffer exploded
+ Test 1: use Points.GetWhatever(idx)
+ FPS=24.7/24.8/25.0
+ Test 2: use __restrict pointers
+ Just simple 1-Point-Component loop, compiler makes times four
+ Pointers are locally declared as __restrict, and adjusts count (i.e. times 2) and uses
indices in pointers
+ Verify assembly
+ FPS=24.9/25.1/25.2
+ Phase 1:
+ Beginning FPS=19.0/19.4/19.7/19.9
+ Ending FPS=22.0/22.3/22.6
+ Phase 1.5:
+ Beginning FPS=22.0/22.3/22.6
+ Ending FPS=24.0/24.2/24.4
+ Phase 2:
+ Beginning FPS=24.0/24.2/24.4
+ After exploded Newtonz FPS=24.8/24.9/25.1
+ Ending FPS=26.3/26.5
+ Phase 3:
+ Beginning FPS=26.3/26.5
+ Ending FPS=26.6/26.8/26.9/27.0
+ Fix 4 BPP images
+ Need ilCopyPixels to convert to standard format (BPP:3, Format: RGB, Type: U_BYTE)
+ Material::"Electrical" (and "Sound")
+ See if destroy's lack of point allows for water to flow in
+ FileDialog: filters based off image formats that are supported
+ Jelly ball: see orig code for doubles
+ Less ocean depth max
+ Data/
+ InitialShip.png [also change @ code]
+ Materials
+ see if it makes sense that ship::points is set<x, set<y, points>>
+ nuke wxSmith
+ Verify all is fine afterwards
+ set icon
+ Debug builds:
+ Enable /Fp:strict and set fpcontrol via /DFLOATING_POINT_CHECKS
+ See if SEH needed (/EHa)
+ Mouse pointer based off current tool
+ Only on Canvas, normal outside
+ Move IsPaused member out of game controller & parameters; handled by MainFrame via status of mPauseMenuItem
+ DrawAt: the longer it's pressed, the stronger it gets
+ Requires TimerTick to also update force and invoke DrawTo when l is down and current tool is Draw
+ Also radius of Smash, same thing
+ Tool strength modulation:
+ Also modulate cursor (red bar rising)
+ Build 10 images (and then cursors) off the base image
+ @ tool application, also call SetCursorStrength(strength, minStrength, maxStrength)
+ Calculated which one of the (xyzCursors.size()-1) to set, of current tool's cursor
+ Phys rearc:
+ Confirmed: destroy breaks due to iterator invalidation
+ In order to allow for ship building unit tests:
+ static unique_ptr<Ship> Ship::Create(unsigned char const * structureImageData, un_map<vec3f, Material*>)
+ void World::AddShip(unique_ptr<Ship> && newShip)
+ Game::LoadShip(filename) still loads the image, and then Ship::Create and World::AddShip
+ Ship_BuildsFromStructureImage_XXX unit test:
+ Make structureImageData and verify points, springs, triangles, etc., also indexes & relationships
+ Might actually want Material::cctor to be public
+ Destroy unit tests:
+ Make structureImageData
+ DestroyAt
+ Verify points, springs, triangles, etc., also indexes & relationships
+ Verify crashes in Debug!
+ Do phys renames and file split above
+ Verify unit tests (1) & runs normally & no fps regression
+ Commit & push
+ Take new perf baseline (FPS and percentages): 8/9
+ Repository rearc:
+ PointerContainer:
+ Flag is via getter (IsDeleted())
+ Also rename other GetIsXYZ() -> IsXYD() and SetXYD()
+ RegisterDeletion(): increments counter
+ ShrinkToFit:
+ Only if deletion counter != 0
+ Allocate new and copy pointer by pointer that's not deleted
+ assert counts at the end
+ Fix unit tests (need to register deletion, and add case with no registration but deletion)
+ Replace parentWorld with parentShip at all elements
+ See also if can get rid of accessing World altogether, in lieu of GameParameters or specific parameter(s) of it (e.g. gravity)
+ Spring
+ Triangle
+ Point
+ Physics::ShipElement<TElement>
+ Provides IsDeleted()
+ Has mParentShip * const (set via cctor) and getter
+ public Destroy()
+ mIsDeleted = true
+ mParentShip->RegisterDestruction<TElement>((TElement *)this)
+ Everything derives from it, publicly
+ Ship maintains lifetime of points, springs, and triangles in backbones
+ Springs: PointerContainer
+ Others: depends, if fast iterator access in arbitrary order is needed => PointerContainer,
else use set (even if never iterated, makes faster deletion)
+ RegisterDestruction<TElement>(TElement *element):
+ For things in PointerContainer: invokes PointerContainer::RegisterDeletion()
+ For things in sets, maps: invokes set/map.erase(element) // it's a shortcut!
+ In these cases, mIsDeleted setting is redundant, but heh...
+ Fix crash at Destroy
+ Remove all TODOs
+ Rethink pointer container: it should iterate Element* rather than Element&
+ New FPS: 11/11/12
+ Fix disappearing ship
+ Make PointerContainer Log a Debug afterwards, instead of Info
+ Nuke all the other TODO's
+ Run with strict floating point
+ Disable exc with overflow & verify that's how we get to NaN
+ Commit & push
+ See if chunk splitting reprocesses same point twice
+ See if connected triangles (at point) should also be vector instead of set
+ Requires Triangle.DestroyFromPoint(Point *) which avoids coming back to caller, to not invalidate iterator
+ Test mAllTriangles in PointerContainer
+ Should make faster render:
+ Before: FPS with pause=18/19
+ After: FPS with pause=19
+ If not good, undo - KEPT!
+ Try Adjancency rearc:
+ Commit and push first
+ Each adjacency arc exists for each non-hull spring, and lives
as long as the spring lives;
we might then get rid of these and just visit the non-hull springs,
provided that we adjust GravitateWater and BalancePressure
for the fact that each arc
would now be visited only once
+ However, for electrical elements we still want to visit the spring-connected graph,
regardless of hull-ness this time;
we then want each point to know its N attached springs (arcs), which
we maintain as a vector<Spring *> (there's max 8)
+ Actually: FixedSizeVector<TElement, Size>, w/erase that shifts and returns bool
+ Remove: use vector::erase(std::remove(val)), or self-done for just one
+ Adjust GravitateWater and BalancePressure
for the fact that each arc
is now visited only once
+ GravitateWater: change to visit springs, and do realize that one of the points
always has cos > and the other cos <
+ BalancePressure: for each pair in which one has water > 1.0, do delta
+ Don't take shortcuts, and add comments about this
+ Point: expose same API as triangles
+ Spring:
+ cctor adds itself to its endpoints
+ dctor removes itself from its endpoints
+ Make sure it's the same code as triangles
+ Then remove code from Ship construction
+ Replace adjacencymap visit with spring visit (of non-hull only)
+ Remove ship.adjacencymap
+ Requires Spring.DestroyFromPoint(Point *) which avoids coming back to caller, to not invalidate iterator
+ Then see if Point->Destroy() can avoid enumerating all springs to find the ones affected
- Check speedup
+ x::Destroy() // Removes all references to self that are found in counterparties
// Invokes Destroy() on counterparties it "owns" (e.g. Point->Spring)
// Basically: replaces dctors (which now have to go away)
// Then, calls base ShipElement::Destroy()
+ At the end of each Update(), Ship calls shrink_to_fit on owned pointer container(s)
+ Also removes points et al that were deleted on previous DestroyAt()
+ Remember to exclude IsDeleted() things during enumerations!
+ And assert(!IsDeleted()) when it's impossible the're deleted (e.g. if accessed via relationship that should
have been cut if that element was deleted)
+ Remove TODO's from unit test and verify (2) & runs normally & no fps regression
+ Complete unit tests with all new relationships
+ Commit & push
+ Take new perf baseline (FPS)
+ Final refactor physics:
+ No friends
+ Clear all warnings
+ Args by ref - no vector copies!
+ phys getters (e.g. point.GetColour()) inline
+ Make other inlines
+ Fix include files
+ Formulas optimizations
+ Point forces: gravity may be applied twice with different magnitude but same vector
+ gameparams/world::(waterpressure, strength, ): are these "factors" or "global" really?
+ See if FP:fast really makes a difference (Release only)
+ All TODO's
+ Commit & push
+ Verify unit tests & runs normally & no fps regression
+ Menu entry to reset pan and zoom
+ Get rid of unicode
+ Can, really?
+ Add splash screen
+ Controls:
+ Smooth pan and zoom
+ Takes 1 sec to get to final value (which is stored immediately as real value)
+ Zoom: inverse
+ 0 - 1000
+ Renderer::ZoomToWorldY(zoom) == 70/(zoom + 0.001)
+ Also called by GameController's Screen2World
+ also move GameController's Screen2World implementation to Renderer
+ See if needs to be exponentially-slider'ed as well
+ Settings:
+ Strength Adjustment must be settable exponentially (slider=>exp)
+ Formula done by gamecontroller at AdjustStrengthAdjustment(), or by SettingsDialog directly
+ Page up and page down in menu
+ Ship name in title
+ MainFrame implements OnShipLoaded() and OnGameReset(), populates mShipNames vector with ship names, and calls SetTitle()
+ SetTitle appends Utils::Join(vec<str>, ' + ') to current title
+ Radio: draw points, springs, structure, texture
+ (Bit) Flag @ GameController->RenderContext->Ship
+ Inspected as bit glag by Ship as well @ Render() to avoid useless uploads
+ Larger points
+ SettingsDialog
+ Better grouping, see RadioBox?
+ Space bar for pause
+ When pause, also pause sounds and music
+ MainFrame: AboutDialog is member & shown on demand
+ Make stiffness adjustment
+ Points::SetStiffnessAdjustment(stiffnessAdjustment):
+ Called by Ship at each Update()
+ If != last, recalc coefficient/s
+ Set max and min zoom (or monsters awaken when you zoom out too much)
+ Reset view (ESC) should also reset camera pan
+ SettingsDialog: bomb blast radius
+ SettingsDialog:
+ Break into N Liner/ExponentialSliderControl
+ Init'd with:
+ CurrentValue
+ Max and Min
+ std::function for OnValueChanged(float newValue)
+ Find solution to ugly slider value rounding
+ Calc tick_size == (Max-Min)/100, floored to round float increment ... see doc'n on floats
+ Then calc # ticks == floor((Max-Min)/tick_size)
+ Re-set default values to round values
+ Tool cursors: cursor should change when mouse down
+ Remove up and down from hierarchy - no cursors in hierarchy (other than mCurrent), and ModulateCursor()
takes vector
+ Do own up and down at:
+ Smash
+ Grab (times 2: positive and negative)
+ Pin, instead, does not change
+ Undo its dual cursors
+ ToolController class, called directly by MainFrame
+ Has GameController shared_ptr
+ SetTool(tool enum from ToolController)
+ OnMouseDown/Up/etc.()
+ RC Bomb detection via events is still left to MainFrame
+ Tool class:
+ ToolController has pointer to the current tool; might be null
+ ShowCurrentCursor(): shows the current cursor; invoked by ToolController at end of initialization
to show the first cursor, and might be invoked via ToolController by MainFrame in the future
to re-show cursor after having stolen it
+ Test:
+ Shift up and down detection
+ Gfx:
+ Do ropes with two endpoints (000xxx)
+ Throw exception if doesn't find two endpoints
+ Algo:
+ Step 1: build vector<PointInfo> & Matrix<opt<pointIndex>> & vector<RopeInfo>
+ Step 2: visit RopeInfos and add to PointInfo's and SpringInfo's
+ Step 3: visit PointMatrix & ...
+ Starting perf:
+ Default ship: 14.1/14.3
+ Ropes test: 12.2/12.3
+ Need to always use color when rendering springs:
+ Spring::Type (Hull, Rope)
+ No exposed, just IsHull() & IsRope()
+ Make it a bit flag
+ Separate RenderContext method for Ropes, stored in separate Element (RopeElement, structurally == SpringElement)
+ Upper bound for # of spring ropes given # of points in connected component:
+ N
+ Upper bound of 'normal' springs doesn't change
+ Render: draw ropes after springs and triangles (we want them on top of triangles!), still by connected component
+ Use own program
+ Ending perf:
+ Default ship: 14.2
+ Ropes test: 12.3
+ Don't make triangles of 3 rope points if at least one is connected to ropes only
+ Fix Base III?
+ Flip order of rendering when structure: triangles first, then ropes
+ Need private subparts of Render()
+ Ending perf:
+ Default ship: 14.5
+ Ropes test: 12.3
+ Add ropes to Titanic
+ Make wood non-hull
+ Fix unit tests
+ Make max(fixedSizeVector) == 9
+ Not for triangles - generated rope points will never participate in triangles
+ Material/Rope rearc:
+ MaterialDatabase
+ Loads itself from json
+ From ResourceLoader invoked by GameController at init'n
+ Guarantees:
+ Exactly one material with isRope=true
+ Color is #000000
+ No colors clash, and no colors fall within rope range
+ Replace in GameController, ResourceLoader
+ Remove ropeMaterial kung-fu @ Ship::Create and use material->IsRope
+ GameController also gives rope renderColour to RenderContext at cctor
+ Which sets shader's hardcoded parameter
+ Try light diffusion rearc:
+ No more at C++, but rather in OpenGL as in the following example (written for ShipTriangles only but valid also for springs
and points):
+ Prerequisite: draw ship triangles by connected component (see above)
+ Turn off diffusion
+ For each component: pass array of all lamps in that component; each lamp has {x, y, intensity};
+ Draw each connected component N times (use additive blending), once for each lamp,
each time passing the single lamp properties as uniform to shaders,
which calculate distance and do final light blending
+ Check right way of doing blending
+ REJECTED: perf was awful; this multiple-pass way of doing it hurts too much
+ Texture mapping:
+ UploadLandAndWaterStart()/./End()
+ Just specify land y and water y
+ Impl:
+ y:
+ To LandBuffer
+ To WaterBuffer
+ RenderLand()
+ RenderWater()
+ Land (sand)
+ bottom is not anymore a param but it's filled by RenderLadn(.) with +/- mWorldHeight/2
+ only param is x and y (world y)
+ texture coordinates are world coordinates
+ Magic number is based on desired tile world size
+ Water
+ Use "water transparency" uniform in shader that sets alpha value in result of texture
+ Make texture stretch wrt vertical height of water strip
+ Change map, this one's ugly
+ Clouds
+ Use N textures, each has own rectangular size
+ RenderContext loads all available textures and uses them for the clouds, modulo