checkpoints, move sprite and pad to lib, reload level on reconfig, hitbox config

This commit is contained in:
ohsqueezy 2023-08-01 16:35:19 -04:00
parent b6a7e8bf23
commit 584a85546c
24 changed files with 878 additions and 743 deletions

1
.gitignore vendored
View File

@ -3,7 +3,6 @@
*.data
*.wasm
build/
Cakefoot.x86_64
# Auto complete
compile_commands.json

View File

@ -72,10 +72,8 @@ $(SB_SRC_DIR)Attributes.o : $(addprefix $(SB_SRC_DIR),Log.hpp extension.hpp)
$(SB_SRC_DIR)Model.o : $(addprefix $(SB_SRC_DIR),extension.hpp Attributes.hpp Texture.hpp Carousel.hpp)
$(SB_SRC_DIR)Text.o : $(addprefix $(SB_SRC_DIR),Model.hpp Color.hpp)
$(SRC_DIR)Curve.o : $(addprefix $(SB_SRC_DIR),Attributes.hpp math.hpp extension.hpp)
$(SRC_DIR)Character.o : $(addprefix $(SB_SRC_DIR),Configuration.hpp Switch.hpp Selection.hpp Segment.hpp Timer.hpp) $(addprefix $(SRC_DIR),Sprite.hpp Curve.hpp)
$(SRC_DIR)Pad.o : $(addprefix $(SRC_DIR),Model.hpp Switch.hpp)
$(SRC_DIR)Sprite.o : $(addprefix $(SRC_DIR),Model.hpp)
$(SRC_DIR)Enemy.o : $(addprefix $(SB_SRC_DIR),Timer.hpp Animation.hpp Box.hpp) $(addprefix $(SRC_DIR),Sprite.hpp Curve.hpp Character.hpp)
$(SRC_DIR)Character.o : $(addprefix $(SB_SRC_DIR),Configuration.hpp Switch.hpp Selection.hpp Segment.hpp Timer.hpp Sprite.hpp) $(addprefix $(SRC_DIR), Curve.hpp)
$(SRC_DIR)Enemy.o : $(addprefix $(SB_SRC_DIR),Timer.hpp Animation.hpp Box.hpp Sprite.hpp) $(addprefix $(SRC_DIR), Curve.hpp Character.hpp)
$(SRC_DIR)Cakefoot.o : $(SRC_H_FILES) $(SB_H_FILES)
%.o : %.cpp %.hpp
$(CXX) $(CXXFLAGS) $< -c -o $@

View File

@ -2,7 +2,6 @@
"display":
{
"dimensions": [864, 486],
"dimensions-fake": [240, 480],
"framerate": 60,
"title": "Microsoft Windows 11 Home Edition",
"debug": false,
@ -12,13 +11,15 @@
"fps": true,
"clear color": [0.0, 0.0, 0.0, 1.0],
"playing field aspect": 1.7777777,
"playing field color": [0.2, 0.2, 0.2, 1.0]
"playing field color": [0.2, 0.2, 0.2, 1.0],
"fps indicator scale": 0.018,
"checkpoint distance": 0.1
},
"configuration":
{
"auto-refresh": true,
"auto-refresh-interval": 5.0
"auto-refresh-interval": 1.0
},
"recording":
@ -53,7 +54,8 @@
"debug-to-stdout": true,
"debug-to-file": true,
"info-file-name": "cakefoot_info.log",
"debug-file-name": "cakefoot_debug.log"
"debug-file-name": "cakefoot_debug.log",
"verbose to stdout": false
},
"curve":
@ -68,7 +70,8 @@
"cake-max-speed": 0.72016458,
"cake-min-speed": -0.4115226,
"cake-increment-mod": 0.125,
"cake-decrement-mod": 0.1
"cake-decrement-mod": 0.1,
"hitbox": 0.7
},
"button":

2
lib/sb

@ -1 +1 @@
Subproject commit 55d6e084809e7d7fbe8541f1fe1047ea30f83297
Subproject commit 67fa7e61c3e520326833078849e75bd488daec8d

18
resource/BPmono-LICENSE.txt Executable file
View File

@ -0,0 +1,18 @@
Creative Commons Attribution-No Derivative Works 3.0 Unported
(http://creativecommons.org/licenses/by-nd/3.0/)
You are free:
to Share — to copy, distribute and transmit the work
Under the following conditions:
Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
No Derivative Works. You may not alter, transform, or build upon this work.
For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.
Any of the above conditions can be waived if you get permission from the copyright holder.
Nothing in this license impairs or restricts the author's moral rights.

BIN
resource/checkpoint/off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

BIN
resource/checkpoint/on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

BIN
resource/fish/fish-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

BIN
resource/flame/flame-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

519
resource/levels.json Normal file
View File

@ -0,0 +1,519 @@
{
"pattern": {
"fire grid 1": 12,
"fire grid 2": 17
},
"levels": [
{
"curve": [
[139.000000, 188.000000], [79.000000, 75.000000], [-44.000000, 285.000000], [150.000000, 261.000000], [174.000000, 252.000000],
[177.000000, 190.000000], [225.000000, 198.000000], [195.000000, 190.666667], [133.000000, 260.333333], [218.000000, 254.000000],
[234.000000, 254.666667], [243.000000, 209.333333], [230.000000, 204.000000], [239.333333, 222.666667], [248.666667, 241.333333],
[258.000000, 260.000000], [271.333333, 212.333333], [337.666667, 111.666667], [298.000000, 117.000000], [276.000000, 127.666667],
[284.000000, 210.333333], [277.000000, 265.000000], [271.000000, 165.333333], [348.000000, 164.666667], [298.000000, 238.000000],
[336.666667, 299.666667], [404.333333, 169.333333], [337.000000, 219.000000], [282.666667, 280.333333], [376.333333, 276.666667],
[413.000000, 211.000000], [425.333333, 188.333333], [432.666667, 224.666667], [459.000000, 190.000000], [498.000000, 90.333333],
[473.000000, 38.666667], [447.000000, 134.000000], [406.333333, 394.333333], [482.666667, 278.666667], [454.000000, 219.000000],
[433.000000, 176.666667], [527.000000, 240.333333], [565.000000, 191.000000], [492.333333, 172.333333], [465.666667, 231.666667],
[516.000000, 265.000000], [566.666667, 280.000000], [569.333333, 223.000000], [566.000000, 195.000000], [594.333333, 184.000000],
[604.666667, 237.000000], [681.000000, 202.000000], [651.000000, 179.333333], [614.000000, 189.666667], [599.000000, 210.000000],
[594.000000, 285.333333], [681.000000, 284.666667], [682.000000, 212.000000], [695.333333, 188.000000], [734.666667, 194.000000],
[733.000000, 115.000000], [737.000000, 12.333333], [675.000000, 23.666667], [717.000000, 174.000000], [788.666667, 342.666667],
[830.333333, 205.333333], [674.000000, 169.000000], [756.333333, 184.000000], [782.666667, 175.000000], [800.000000, 155.000000]
]
},
{
"curve": [
[80, 244], [80, 244], [784, 244], [784, 244]
],
"enemies": [
["slicer", 0.25, 5.00, 80],
["slicer", 0.5, 5.00, 80],
["slicer", 0.75, 5.00, 80]
]
},
{
"curve": [
[120, 340],
[140, -25], [724, -25],
[744, 240],
[744, 500], [220, 500],
[250, 300],
[300, 100], [600, 140],
[500, 280],
[450, 350], [350, 350],
[420, 240]
],
"enemies": [
["flame", [1.0, 1.0, 0], 0.25, 0, -1],
["flame", [1.0, 0.5, 0], 0.25, 0, -1],
["flame", [1.0, 0, 0], 0.25, 0, -1],
["flame", [1.0, -0.5, 0], 0.25, 0, -1],
["flame", [0.5, 1.0, 0], 0.25, 0, -1],
["flame", [0.5, 0.5, 0], 0.25, 0, -1],
["flame", [0.5, 0, 0], 0.25, 0, -1],
["flame", [0.5, -0.5, 0], 0.25, 0, -1],
["flame", [0.0, 1.0, 0], 0.25, 0, -1],
["flame", [0.0, 0.5, 0], 0.25, 0, -1],
["flame", [0.0, 0, 0], 0.25, 0, -1],
["flame", [0.0, -0.5, 0], 0.25, 0, -1],
["flame", [-0.5, 1.0, 0], 0.25, 0, -1],
["flame", [-0.5, 0.5, 0], 0.25, 0, -1],
["flame", [-0.5, 0, 0], 0.25, 0, -1],
["flame", [-0.5, -0.5, 0], 0.25, 0, -1],
["flame", [-1.0, 1.0, 0], 0.25, 0, -1],
["flame", [-1.0, 0.5, 0], 0.25, 0, -1],
["flame", [-1.0, 0, 0], 0.25, 0, -1],
["flame", [-1.0, -0.5, 0], 0.25, 0, -1]
],
"checkpoints": [
{
"position": 0.25,
"angle": 1.57
},
{
"position": 0.5,
"angle": 4.71
}
]
},
{
"curve": [
[80, 310], [1164, 0], [-300, 0], [784, 310]
],
"enemies": [
["fish", 0.5, 0.16, 40.000000],
["fish", 0.16, 0.1, 70.000000],
["projector", [432, 400, 0.0], 10.00000, 2.0, 0.3]
]
},
{
"curve": [
[50, 243],
[50, 143], [150, 143],
[150, 243],
[150, 363], [250, 363],
[250, 243],
[250, 103], [350, 103],
[350, 243],
[350, 403], [450, 403],
[450, 243],
[450, 23], [550, 23],
[550, 243],
[550, 483], [650, 483],
[650, 243],
[650, -23], [750, -23],
[750, 243]
],
"enemies": [
["projector", [100, 213, 0.0], 4, 4, 0.3],
["projector", [200, 293, 0.0], 4, 4, 0.3],
["projector", [300, 173, 0.0], 4, 4, 0.3],
["projector", [400, 333, 0.0], 4, 4, 0.3],
["projector", [500, 133, 0.0], 4, 4, 0.3],
["projector", [600, 373, 0.0], 4, 4, 0.3],
["projector", [700, 93, 0.0], 4, 4, 0.3]
],
"checkpoints": [
{
"position": 0.57,
"angle": 1.57
}
]
},
{
"curve": [
[80, 243], [1080, -223], [-216, 709], [784, 243]
],
"enemies": [
["fish", 0.05, 0.15, 40.000000],
["fish", 0.25, 0.15, 40.000000],
["slicer", 0.5, 10, 300],
["fish", 0.75, 0.15, 40.000000],
["fish", 0.95, 0.15, 40.000000]
]
},
{
"curve": [
[250, 243],
[432, 243], [432, 243],
[432, 0],
[432, -243], [432, -243],
[700, -243]
],
"enemies": [
["fish", 0.25, -0.2, 100],
["fish", 0.75, 0.2, 100],
["flame", [-1.77, -0.75, 0], 0.25, 1.57, -1],
["flame", [-1.18, -0.75, 0], 0.25, 1.57, -1],
["flame", [-0.59, -0.75, 0], 0.25, 1.57, -1],
["flame", [0, -0.75, 0], 0.25, 1.57, -1],
["flame", [0.59, -0.75, 0], 0.25, 1.57, -1],
["flame", [1.18, -0.75, 0], 0.25, 1.57, -1],
["slicer", 0.97, 6, 75]
]
},
{
"curve": [
[53.000000, 413.000000], [150.000000, 400.000000], [31.000000, 196.000000], [420.000000, 200.000000], [495.333333, 197.000000],
[566.666667, 198.000000], [563.000000, 79.000000], [572.000000, -19.333333], [716.000000, 62.333333], [700.000000, 359.000000],
[688.333333, 462.000000], [486.666667, 257.000000], [475.000000, 310.000000], [431.333333, 560.000000], [267.666667, 262.000000],
[194.000000, 457.000000]
],
"enemies": [
["slicer", 0.18, 11.00, 142.50],
["slicer", 0.12, 3.00, 65.00],
["slicer", 0.52, 3.00, 50.00],
["slicer", 0.34, 7.25, 212.50],
["slicer", 0.72, 5.00, 72.50],
["slicer", 0.69, 5.00, 72.50],
["slicer", 0.97, 2.75, 35.00],
["slicer", 0.94, 2.25, 60.00],
["slicer", 0.92, 5.00, 72.50]
],
"checkpoints": [
{
"position": 0.62,
"angle": 2.35
}
]
},
{
"curve": [
[83.000000, 231.000000], [83.000000, 37.000000], [55.000000, 90.000000], [220.000000, 226.000000], [499.000000, -77.333333],
[782.000000, 148.333333], [783.000000, 229.000000], [779.333333, 454.666667], [320.666667, 423.333333], [220.000000, 294.000000],
[82.666667, 358.333333], [68.333333, 478.666667], [83.000000, 275.000000]
],
"enemies": [
["fish", 0.11, 0.06, 40.000000],
["fish", 0.25, 0.10, 86.000000],
["fish", 0.31, 0.10, 30.000000],
["fish", 0.33, 0.10, 30.000000],
["fish", 0.42, 0.17, 106.000000],
["fish", 0.56, 0.13, 112.000000],
["fish", 0.75, 0.12, 32.000000],
["fish", 0.90, 0.10, 106.000000],
["fish", 0.90, 0.10, 30.000000],
["fish", 0.675, 0.11, 40.000000],
["fish", 0.67, 0.11, 38.000000],
["fish", 0.665, 0.11, 36.000000],
["fish", 0.6625, 0.11, 34.000000]
],
"checkpoints": [
{
"position": 0.62,
"angle": 2.65
}
]
},
{
"curve": [
[75, 229],
[864, 229], [-354, -255],
[326, 705],
[396, 785], [468, 785],
[538, 705],
[1218, -255], [0, 229],
[789, 229]
],
"enemies": [
["fish", 0.5, 0.05, 190.000000],
["fish", 0.5, 0.075, 190.000000],
["fish", 0.5, 0.1, 190.000000],
["fish", 0.5, 0.125, 190.000000],
["fish", 0.5, 0.15, 190.000000],
["slicer", 0.5, 15, 200],
["slicer", 0.5, 13.5, 200],
["slicer", 0.5, 11.5, 200],
["slicer", 0.5, 8, 200],
["flame", [-1.77, 0.8, 0], 0.25, 4.71, -1],
["flame", [-1.18, 0.8, 0], 0.25, 4.71, -1],
["flame", [-0.59, 0.8, 0], 0.25, 4.71, -1],
["flame", [0, 0.8, 0], 0.25, 4.71, -1],
["flame", [0.59, 0.8, 0], 0.25, 4.71, -1],
["flame", [1.18, 0.8, 0], 0.25, 4.71, -1],
["flame", [-1.1, 1.0, 0], 0.25, 3.14, -1],
["flame", [-1.1, 0.5, 0], 0.25, 3.14, -1],
["flame", [-1.1, 0, 0], 0.25, 3.14, -1],
["flame", [-1.1, -0.5, 0], 0.25, 3.14, -1],
["flame", [1.1, 1.0, 0], 0.25, 0, -1],
["flame", [1.1, 0.5, 0], 0.25, 0, -1],
["flame", [1.1, 0, 0], 0.25, 0, -1],
["flame", [1.1, -0.5, 0], 0.25, 0, -1]
],
"checkpoints": [
{
"position": 0.36,
"angle": 4.2
}
]
},
{
"curve": [
[385.000000, 151.000000], [-363.000000, 234.000000], [287.000000, -241.000000], [288.000000, 258.000000], [252.000000, 668.000000],
[-331.000000, 259.000000], [396.000000, 299.000000], [1232.666667, 266.000000], [542.333333, 715.000000], [498.000000, 258.000000],
[494.333333, -205.000000], [1222.666667, 244.000000], [434.000000, 148.000000]
],
"enemies": [
["projector", [139.000000, 95.000000, 0.0], 5.00000, 4.0, 0.3],
["projector", [154.000000, 373.000000, 0.0], 5.00000, 3.0, 0.3],
["projector", [660.000000, 386.000000, 0.0], 5.00000, 2.0, 0.3],
["projector", [671.000000, 106.000000, 0.0], 5.00000, 1.0, 0.3],
["projector", [668.000000, 239.000000, 0.0], 5.00000, 2.0, 0.3]
]
},
{
"curve": [
[298.000000, 207.000000], [296.000000, 94.000000], [478.000000, 239.000000], [478.000000, 80.000000], [473.333333, 17.333333],
[606.666667, 97.666667], [607.000000, 15.000000], [598.666667, -165.333333], [706.333333, -40.666667], [706.000000, -131.000000],
[694.000000, -279.000000], [819.000000, -138.000000], [819.000000, -269.000000], [801.666667, -415.666667], [1026.333333, -186.333333],
[1016.000000, -538.000000], [1015.333333, -658.000000], [1150.666667, -519.000000], [1151.000000, -671.000000], [1140.333333, -749.333333],
[1316.666667, -628.666667], [1316.000000, -756.000000]
],
"enemies": [
["fish", 0.00952, 0.122718, 106.00000],
["slicer", 0.07619, 5.00000, 60.00000],
["fish", 0.24048, 0.098175, 30.00000],
["fish", 0.22143, 0.098175, 30.00000],
["fish", 0.26190, 0.098175, 30.00000],
["fish", 0.28333, 0.098175, 30.00000],
["slicer", 0.46429, 5.00000, 87.50000],
["slicer", 0.43095, 5.00000, 87.50000],
["slicer", 0.50000, 5.00000, 87.50000],
["fish", 0.44286, 0.110447, 30.00000],
["fish", 0.48333, 0.110447, 30.00000],
["fish", 0.67381, 0.098175, 30.00000],
["slicer", 0.66905, 5.00000, 60.00000],
["slicer", 0.67857, 5.00000, 60.00000],
["fish", 0.70238, 0.098175, 58.00000],
["slicer", 0.77143, 0.75000, 22.50000],
["slicer", 0.79524, 5.00000, 60.00000],
["fish", 0.86667, 0.098175, 30.00000],
["slicer", 0.97381, 11.00000, 290.00000]
],
"checkpoints": [
{
"position": 0.57,
"angle": 4.71
}
]
},
{
"curve": [
[83.000000, 386.000000], [150.000000, 400.000000], [260.000000, 287.000000], [234.000000, 89.000000], [199.000000, 9.000000],
[184.000000, 91.000000], [159.000000, 92.000000], [101.333333, 94.666667], [95.666667, 251.333333], [67.000000, 67.000000],
[36.666667, 20.000000], [88.333333, 31.000000], [99.000000, 32.000000], [151.000000, 15.666667], [139.000000, 38.333333],
[159.000000, 51.000000], [221.666667, 115.666667], [107.333333, 216.333333], [170.000000, 245.000000], [255.333333, 257.666667],
[252.666667, 188.333333], [294.000000, 160.000000], [336.333333, 116.000000], [314.666667, 184.000000], [325.000000, 196.000000],
[344.333333, 256.666667], [351.666667, 221.333333], [365.000000, 234.000000], [366.000000, 259.666667], [367.000000, 285.333333],
[296.000000, 339.000000], [223.666667, 387.666667], [220.333333, 383.333333], [244.000000, 311.000000], [260.333333, 240.000000],
[276.666667, 169.000000], [306.000000, 46.000000], [363.333333, -190.000000], [425.666667, -96.000000], [393.000000, -39.000000],
[362.666667, 21.000000], [487.333333, -66.000000], [517.000000, -36.000000], [608.000000, 54.000000], [605.000000, 772.000000],
[687.000000, 38.000000], [685.666667, -24.666667], [664.333333, 40.666667], [648.000000, 93.000000], [623.666667, 185.666667],
[616.333333, 250.333333], [702.000000, 163.000000], [716.666667, 140.333333], [717.333333, 121.666667], [618.000000, 89.000000],
[538.000000, 61.000000], [495.000000, 146.000000], [468.000000, 86.000000], [439.000000, 17.000000], [410.000000, 64.000000],
[381.000000, 53.000000], [312.666667, 32.666667], [376.333333, 126.333333], [374.000000, 163.000000], [379.000000, 321.333333],
[488.000000, 313.666667], [545.000000, 389.000000], [582.000000, 463.666667], [726.000000, 360.333333], [812.000000, 460.000000],
[834.333333, 489.000000], [836.666667, 452.000000], [849.000000, 448.000000], [883.666667, 394.666667], [931.333333, 457.333333],
[940.000000, 429.000000]
],
"checkpoints": [
{
"position": 0.4,
"angle": 1.9
}
]
},
{
"curve": [
[47.000000, 162.000000], [186.000000, 687.000000], [159.000000, -656.000000], [274.000000, -152.000000], [295.666667, -43.666667],
[390.333333, -147.333333], [416.000000, 97.000000], [456.666667, 450.333333], [551.333333, 454.666667], [600.000000, 86.000000],
[604.000000, 66.333333], [608.000000, 46.666667], [782.000000, -204.000000], [838.666667, -278.333333], [699.333333, -328.666667],
[698.000000, -392.000000], [704.333333, -425.333333], [760.666667, -490.666667], [933.000000, -383.000000]
],
"enemies": [
["fish", 0.02778, 0.245437, 24.00000],
["fish", 0.08333, 0.098175, 54.00000],
["fish", 0.13611, 0.134990, 26.00000],
["fish", 0.11667, 0.134990, 26.00000],
["fish", 0.15556, 0.134990, 26.00000],
["fish", 0.26111, 0.085903, 148.00000],
["fish", 0.29167, 0.134990, 60.00000],
["fish", 0.34444, 0.159534, 40.00000],
["fish", 0.34167, 0.122718, 42.00000],
["fish", 0.34722, 0.159534, 40.00000],
["fish", 0.70278, 0.233165, 60.00000],
["fish", 0.82222, 0.245437, 72.00000],
["fish", 0.61944, 0.184078, 34.00000],
["fish", 0.64167, 0.122718, 84.00000],
["fish", 0.47778, 0.098175, 98.00000],
["fish", 0.47778, 0.098175, 30.00000],
["fish", 0.82222, 0.098175, 30.00000]
],
"checkpoints": [
{
"position": 0.215,
"angle": 4.1
},
{
"position": 0.445,
"angle": 2.0
}
]
},
{
"curve": [
[485.000000, 259.000000], [-1191.000000, -246.000000], [303.000000, 711.000000], [452.000000, 375.000000]
],
"enemies": [
["projector", [136.000000, 299.000000, 0.0], 15.50000, 2.0, 0.3],
["slicer", 0.66667, 7.75000, 57.50000],
["projector", [400.000000, 56.000000, 0.0], 11.25000, 2.25, 0.3],
["slicer", 0.03333, 5.00000, 60.00000],
["slicer", 0.05000, 5.00000, 60.00000],
["slicer", 0.06667, 5.00000, 60.00000],
["slicer", 0.08333, 5.00000, 60.00000],
["slicer", 0.33333, 5.00000, 60.00000],
["slicer", 0.28333, 5.00000, 60.00000],
["slicer", 0.38333, 5.00000, 60.00000],
["slicer", 0.55000, 5.00000, 60.00000],
["slicer", 0.51667, 1.50000, 60.00000],
["slicer", 0.95000, 5.00000, 72.50000],
["slicer", 0.90000, 3.00000, 42.50000],
["slicer", 0.85000, 1.25000, 32.50000]
],
"checkpoints": [
{
"position": 0.485 ,
"angle": 3.9
}
]
},
{
"curve": [
[100.000000, 100.000000], [269.000000, 2051.000000], [409.000000, 451.000000], [450.000000, 131.000000], [653.666667, -1520.666667],
[661.333333, 156.666667], [943.000000, 173.000000]
],
"enemies": [
["slicer", 0.44167, 5.00000, 72.50000],
["slicer", 0.54167, 5.00000, 72.50000],
["slicer", 0.31667, 5.00000, 72.50000],
["slicer", 0.28333, 5.00000, 60.00000],
["slicer", 0.52500, 5.00000, 60.00000],
["slicer", 0.40833, 5.00000, 60.00000],
["slicer", 0.50833, 5.00000, 60.00000],
["fish", 0.49167, 0.098175, 66.00000],
["fish", 0.06667, -0.012272, 328.00000],
["slicer", 0.57500, 5.00000, 60.00000],
["slicer", 0.36667, 5.00000, 60.00000],
["fish", 0.05833, 0.098175, 50.00000],
["fish", 0.07500, -0.098175, 60.00000],
["fish", 0.09167, 0.098175, 58.00000],
["slicer", 0.18333, 5.00000, 60.00000],
["slicer", 0.17500, 5.00000, 60.00000],
["slicer", 0.77500, 9.00000, 147.50000],
["fish", 0.65000, 0.098175, 30.00000],
["fish", 0.67500, -0.085903, 56.00000],
["slicer", 0.80833, 13.00000, 202.50000],
["fish", 0.84167, 0.061359, 26.00000],
["fish", 0.85833, -0.061359, 26.00000]
],
"checkpoints": [
{
"position": 0.387,
"angle": 5.2
}
]
},
{
"curve": [
[106.000000, 451.000000], [265.000000, 374.000000], [885.000000, -416.000000], [739.000000, 357.000000], [-338.000000, -36.333333],
[96.000000, 38.333333], [725.000000, 113.000000], [891.000000, 133.666667], [1208.000000, 255.333333], [-594.000000, 444.000000]
],
"enemies": [
["fish", 0.99444, 0.073631, 30.00000],
["fish", 0.99444, 0.098175, 30.00000],
["fish", 0.35556, 0.196350, 22.00000],
["fish", 0.32778, -0.233165, 40.00000],
["fish", 0.29444, 0.110447, 72.00000],
["fish", 0.37778, -0.220893, 50.00000],
["fish", 0.16111, 0.098175, 18.00000],
["slicer", 0.61667, 5.00000, 60.00000],
["slicer", 0.14444, 5.00000, 60.00000],
["slicer", 0.17778, 5.00000, 60.00000],
["slicer", 0.63889, 5.00000, 60.00000],
["fish", 0.94444, 0.134990, 30.00000],
["fish", 0.93889, 0.159534, 26.00000],
["fish", 0.95000, 0.147262, 26.00000],
["slicer", 0.4, 5.50000, 102.50000],
["slicer", 0.43889, 5.50000, 102.50000],
["slicer", 0.42778, 5.50000, 102.50000],
["slicer", 0.41667, 5.50000, 102.50000],
["slicer", 0.42222, 5.50000, 102.50000],
["slicer", 0.43333, 5.50000, 102.50000],
["slicer", 0.41111, 5.50000, 102.50000],
["slicer", 0.40556, 5.50000, 102.50000],
["slicer", 0.44444, 5.50000, 102.50000],
["slicer", 0.45556, 5.50000, 102.50000],
["slicer", 0.45000, 5.50000, 102.50000],
["slicer", 0.46, 5.50000, 102.50000],
["slicer", 0.97778, 4.25000, 37.50000],
["slicer", 0.98333, 4.25000, 37.50000],
["slicer", 0.97222, 4.25000, 37.50000],
["fish", 0.98333, 0.098175, 30.00000],
["fish", 0.97778, 0.098175, 30.00000],
["fish", 0.97222, 0.098175, 30.00000]
],
"checkpoints": [
{
"position": 0.39,
"angle": 4
},
{
"position": 0.88,
"angle": 5.7
}
]
},
{
"curve": [
[67.000000, 312.000000], [191.000000, 302.000000], [311.000000, 208.000000], [233.000000, 33.000000], [199.000000, -18.000000],
[161.000000, 59.000000], [126.000000, 234.000000], [110.666667, 284.666667], [147.333333, 331.333333], [183.000000, 343.000000],
[226.666667, 348.333333], [267.333333, 326.666667], [299.000000, 300.000000], [330.000000, 261.333333], [289.000000, 231.666667],
[239.000000, 251.000000], [217.333333, 280.333333], [261.666667, 281.666667], [364.000000, 243.000000], [357.666667, 393.000000],
[478.333333, 393.000000], [479.000000, 235.000000], [486.333333, 435.333333], [442.666667, 516.666667], [416.000000, 416.000000],
[455.333333, 312.000000], [509.666667, 353.000000], [568.000000, 316.000000], [595.666667, 300.666667], [624.333333, 279.333333],
[649.000000, 249.000000], [647.000000, 184.333333], [587.000000, 185.666667], [538.000000, 256.000000], [512.000000, 316.666667],
[596.000000, 391.333333], [674.000000, 334.000000], [723.333333, 295.000000], [772.666667, 346.000000], [893.000000, 329.000000]
],
"enemies": [
["projector", [704.000000, 426.000000, 0.0], 1.50000, 2.5, 0.3]
],
"checkpoints": [
{
"position": 0.35,
"angle": 0.2
}
]
}
]
}

BIN
resource/pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

View File

@ -23,8 +23,98 @@ Cakefoot::Cakefoot()
delegate().subscribe(&Cakefoot::respond, this, SDL_MOUSEWHEEL);
/* Set up playing field, the plane that provides the background of the curve, character, and enemies */
playing_field.scale(glm::vec3{_configuration("display", "playing field aspect"), 1.0f, 1.0f});
playing_field.attributes(sb::Attributes(std::vector(6, _configuration("display", "playing field color").get<glm::vec4>())), "color");
sb::Plane playing_field_plane;
playing_field_plane.scale(glm::vec3{_configuration("display", "playing field aspect"), 1.0f, 1.0f});
playing_field_plane.attributes(sb::Attributes(std::vector(6, _configuration("display", "playing field color").get<glm::vec4>())), "color");
playing_field = sb::Sprite(playing_field_plane);
/* Open the configuration and load the curve data per level */
load_curves();
/* loading GL context for 3D */
load_gl_context();
/* Load and fill VBO */
load_vbo();
/* Shrink the FPS indicator, and give it an opaque black background. */
float modifier = _configuration("display", "fps indicator scale");
glm::vec3 scale = {modifier, modifier * window_box().aspect(), 1.0f};
fps.foreground({255.0f, 255.0f, 255.0f, 255.0f});
fps.background({0.0f, 0.0f, 0.0f, 255.0f});
fps.translate({1.0f - scale.x, 1.0f - scale.y, 0.0f});
fps.scale(scale);
/* Load cursors from the system library that will be freed automatically */
poke = std::shared_ptr<SDL_Cursor>(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND), SDL_FreeCursor);
grab = std::shared_ptr<SDL_Cursor>(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL), SDL_FreeCursor);
/* Try to load a font for the buttons. Default to the game object's font if the font doesn't load. */
std::shared_ptr<TTF_Font> button_font = std::shared_ptr<TTF_Font>(
TTF_OpenFont(configuration()["button"]["font"].get<std::string>().c_str(), configuration()["button"]["font size"]), TTF_CloseFont);
std::ostringstream message;
if (button_font.get() == nullptr)
{
message << "Could not load " << configuration()["button"]["font"] << ". Using framework's font.";
sb::Log::log(message, sb::Log::ERROR);
/* Default to framework's font */
button_font = font();
}
else
{
message << "Loaded " << configuration()["button"]["font"];
sb::Log::log(message);
}
/* Set up text buttons */
for (auto& [name, button] : text_buttons)
{
sb::Text text {button_font};
glm::vec2 size = configuration()("button", "text size");
text.foreground(configuration()("button", "text foreground").get<glm::vec4>());
text.background(configuration()("button", "text background").get<glm::vec4>());
text.content(configuration()("button", name + " text"));
text.dimensions(size);
button = sb::Pad<>{text, configuration()("button", name + " translation"), configuration()("button", "text scale"), size.y / size.x};
}
text_buttons["start"].on_state_change([&](bool state){
load_level(1);
});
text_buttons["resume"].on_state_change([&](bool state){
unpaused_timer.on();
});
text_buttons["reset"].on_state_change([&](bool state){
sb::Delegate::post(reset_command_name, false);
});
/* Set up pause button */
sb::Texture pause_texture {configuration()["button"]["pause texture"]};
pause_texture.load();
sb::Plane pause_plane;
pause_plane.texture(pause_texture);
pause_button = sb::Pad<>{pause_plane, configuration()("button", "pause translation"), configuration()("button", "pause scale"), 1.0f};
pause_button.on_state_change([&](bool state){
unpaused_timer.off();
});
/* Set up checkpoint on and off sprites */
checkpoint_on = sb::Sprite {"resource/checkpoint/on.png", glm::vec2(12.0f / 486.0f)};
checkpoint_off = sb::Sprite {"resource/checkpoint/off.png", glm::vec2(12.0f / 486.0f)};
/* Set hitbox */
character.box_size(configuration()("character", "hitbox").get<float>());
/* Load title screen and character graphics */
character.load();
load_level(0);
}
void Cakefoot::load_curves()
{
/* Reset curve list and count of vertex buffer bytes needed for the curves */
curve_byte_count = 0;
curves.clear();
/* Open the levels section of the configuration and iterate through the list of levels. */
nlohmann::json levels = configuration()["levels"];
@ -63,73 +153,6 @@ Cakefoot::Cakefoot()
curves.push_back(curve);
curve_byte_count += curve.size();
}
/* loading GL context for 3D */
load_gl_context();
/* Shrink the FPS indicator, and give it an opaque black background. */
glm::vec3 scale = {0.018f, 0.018f * window_box().aspect(), 1.0f};
fps.foreground({255.0f, 255.0f, 255.0f, 255.0f});
fps.background({0.0f, 0.0f, 0.0f, 255.0f});
fps.translate({1.0f - scale.x, 1.0f - scale.y, 0.0f});
fps.scale(scale);
/* Load cursors from the system library that will be freed automatically */
poke = std::shared_ptr<SDL_Cursor>(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND), SDL_FreeCursor);
grab = std::shared_ptr<SDL_Cursor>(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL), SDL_FreeCursor);
/* Try to load a font for the buttons. Default to the game object's font if the font doesn't load. */
std::shared_ptr<TTF_Font> button_font = std::shared_ptr<TTF_Font>(
TTF_OpenFont(configuration()["button"]["font"].get<std::string>().c_str(), configuration()["button"]["font size"]), TTF_CloseFont);
std::ostringstream message;
if (button_font.get() == nullptr)
{
message << "Could not load " << configuration()["button"]["font"] << ". Using framework's font.";
sb::Log::log(message, sb::Log::ERROR);
/* Default to framework's font */
button_font = font();
}
else
{
message << "Loaded " << configuration()["button"]["font"];
sb::Log::log(message);
}
/* Set up text buttons */
for (auto& [name, button] : text_buttons)
{
sb::Text text {button_font};
glm::vec2 size = configuration()("button", "text size");
text.foreground(configuration()("button", "text foreground").get<glm::vec4>());
text.background(configuration()("button", "text background").get<glm::vec4>());
text.content(configuration()("button", name + " text"));
text.size(size);
button = Pad<>{text, configuration()("button", name + " translation"), configuration()("button", "text scale"), size.y / size.x};
}
text_buttons["start"].on_state_change([&](bool state){
load_level(1);
});
text_buttons["resume"].on_state_change([&](bool state){
unpaused_timer.on();
});
text_buttons["reset"].on_state_change([&](bool state){
sb::Input::post_command(RESET_COMMAND_NAME, false);
});
/* Set up pause button */
sb::Texture pause_texture {configuration()["button"]["pause texture"]};
pause_texture.load();
sb::Plane pause_plane;
pause_plane.texture(pause_texture);
pause_button = Pad<>{pause_plane, configuration()("button", "pause translation"), configuration()("button", "pause scale"), 1.0f};
pause_button.on_state_change([&](bool state){
unpaused_timer.off();
});
/* Load title screen and character graphics */
character.load();
load_level(0);
}
void Cakefoot::load_gl_context()
@ -138,53 +161,27 @@ void Cakefoot::load_gl_context()
/* Generate a vertex array object ID, bind it as current (requirement of OpenGL) */
vao.generate();
sb::Log::gl_errors("after generating VAO");
vao.bind();
/* Generate ID for the vertex buffer object that will hold all vertex data. Using one buffer for all attributes, data
* will be copied in one after the other. */
vbo.generate();
vbo.bind();
sb::Log::gl_errors("after binding VAO");
/* Load shader program */
GLuint vertex_shader = load_shader("src/shaders/shader.vert", GL_VERTEX_SHADER);
GLuint fragment_shader = load_shader("src/shaders/shader.frag", GL_FRAGMENT_SHADER);
shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
sb::Log::gl_errors("after loading vertex shader");
glAttachShader(shader_program, fragment_shader);
sb::Log::gl_errors("after loading shaders");
/*!
* Fill VBO with attribute data:
*
* Postion, UV, and color vertices for a single sb::Plane, playing field colors, and curve.
*/
vbo.allocate(sb::Plane().size() + playing_field.attributes()["color"]->size() + curve_byte_count, GL_STATIC_DRAW);
vbo.add(*sb::Plane::position);
vbo.add(*sb::Plane::uv);
vbo.add(*sb::Plane::color);
vbo.add(*playing_field.attributes()["color"]);
for (Curve& curve : curves)
{
for (sb::Attributes& attr : curve.position)
{
vbo.add(attr);
}
vbo.add(curve.color);
}
sb::Log::gl_errors("after filling VBO");
sb::Log::gl_errors("after loading fragment shader");
/* link shaders */
link_shader(shader_program);
glUseProgram(shader_program);
sb::Log::gl_errors("after linking");
/* Bind UV attributes once at load time because they will not be changing */
sb::Plane::uv->bind("vertex_uv", shader_program);
/* store uniform locations after linking */
uniform["mvp"] = glGetUniformLocation(shader_program, "mvp");
uniform["time"] = glGetUniformLocation(shader_program, "time");
uniform["effect"] = glGetUniformLocation(shader_program, "effect");
uniform["uv transformation"] = glGetUniformLocation(shader_program, "uv_transformation");
uniform["coordinate bound"] = glGetUniformLocation(shader_program, "coordinate_bound");
uniform["model texture"] = glGetUniformLocation(shader_program, "model_texture");
@ -204,6 +201,38 @@ void Cakefoot::load_gl_context()
sb::Log::gl_errors("after GL initialization");
}
void Cakefoot::load_vbo()
{
/* Generate ID for the vertex buffer object that will hold all vertex data. Using one buffer for all attributes, data
* will be copied in one after the other. */
vbo.generate();
vbo.bind();
sb::Log::gl_errors("after generating and binding VBO");
/*!
* Fill VBO with attribute data:
*
* Postion, UV, and color vertices for a single sb::Plane, playing field colors, and curve.
*/
vbo.allocate(sb::Plane().size() + playing_field.attributes("color")->size() + curve_byte_count, GL_STATIC_DRAW);
vbo.add(*sb::Plane::position);
vbo.add(*sb::Plane::uv);
vbo.add(*sb::Plane::color);
vbo.add(*playing_field.attributes("color"));
for (Curve& curve : curves)
{
for (sb::Attributes& attr : curve.position)
{
vbo.add(attr);
}
vbo.add(curve.color);
}
sb::Log::gl_errors("after filling VBO");
/* Bind UV attributes once at load time because they will not be changing */
sb::Plane::uv->bind("vertex_uv", shader_program);
}
Curve& Cakefoot::curve()
{
return curves[curve_index % curves.size()];
@ -225,42 +254,45 @@ void Cakefoot::load_level(int index)
/* Reset enemies list to empty. Open configuration for the current level. Repopulate list of enemies one by one using the list of enemies in the
* configuration. */
this->enemies.clear();
nlohmann::json enemies = _configuration("levels", index, "enemies");
for (std::size_t ii = 0; ii < enemies.size(); ii++)
if (configuration()("levels", index).contains("enemies"))
{
std::string type = enemies[ii][0];
if (type == "slicer")
nlohmann::json enemies = configuration()("levels", index, "enemies");
for (std::size_t ii = 0; ii < enemies.size(); ii++)
{
this->enemies.push_back(
std::make_shared<Slicer>(
curve(), enemies[ii][1].get<float>(), 2.0f * 25.0f * enemies[ii][2].get<float>() / 486.0f, 2.0f * enemies[ii][3].get<float>() / 486.0f)
);
}
else if (type == "fish")
{
this->enemies.push_back(
std::make_shared<Fish>(
curve(), enemies[ii][1].get<float>(), 25.0f * enemies[ii][2].get<float>(), 2.0f * enemies[ii][3].get<float>() / 486.0f)
);
}
else if (type == "projector")
{
this->enemies.push_back(
std::make_shared<Projector>(
character,
(glm::vec3{2.0f * 1.7777f, 2.0f, 1.0f} * enemies[ii][1].get<glm::vec3>() / glm::vec3{864.0, 486.0, 1.0} -
glm::vec3(1.77777, 1.0, 0.0)) * glm::vec3(1.0, -1.0, 0.0),
2.0f * 25.0f * enemies[ii][2].get<float>() / 486.0, enemies[ii][3].get<float>(), enemies[ii][4].get<float>())
);
}
else if (type == "flame")
{
this->enemies.push_back(std::make_shared<Flame>(field, enemies[ii][1], enemies[ii][2], enemies[ii][3], enemies[ii][4]));
std::string type = enemies[ii][0];
if (type == "slicer")
{
this->enemies.push_back(
std::make_shared<Slicer>(
curve(), enemies[ii][1].get<float>(), 2.0f * 25.0f * enemies[ii][2].get<float>() / 486.0f, 2.0f * enemies[ii][3].get<float>() / 486.0f)
);
}
else if (type == "fish")
{
this->enemies.push_back(
std::make_shared<Fish>(
curve(), enemies[ii][1].get<float>(), 25.0f * enemies[ii][2].get<float>(), 2.0f * enemies[ii][3].get<float>() / 486.0f)
);
}
else if (type == "projector")
{
this->enemies.push_back(
std::make_shared<Projector>(
character,
(glm::vec3{2.0f * 1.7777f, 2.0f, 1.0f} * enemies[ii][1].get<glm::vec3>() / glm::vec3{864.0, 486.0, 1.0} -
glm::vec3(1.77777, 1.0, 0.0)) * glm::vec3(1.0, -1.0, 0.0),
2.0f * 25.0f * enemies[ii][2].get<float>() / 486.0, enemies[ii][3].get<float>(), enemies[ii][4].get<float>())
);
}
else if (type == "flame")
{
this->enemies.push_back(std::make_shared<Flame>(field, enemies[ii][1], enemies[ii][2], enemies[ii][3], enemies[ii][4]));
}
}
}
/* Enemies programmed to be added directly (not through the configuration). */
if (index == 5)
if (index == configuration()("pattern", "fire grid 1"))
{
float y = field.top();
glm::vec2 margin {0.59259f, 0.5f};
@ -277,7 +309,7 @@ void Cakefoot::load_level(int index)
y -= margin.y;
}
}
else if (index == 10)
else if (index == configuration()("pattern", "fire grid 2"))
{
float y = field.top();
glm::vec2 margin {0.59259f, 0.5f};
@ -441,6 +473,14 @@ void Cakefoot::respond(SDL_Event& event)
unpaused_timer.on();
}
else if (sb::Delegate::compare(event, "reconfig"))
{
load_curves();
load_vbo();
load_level(level_index);
character.box_size(configuration()("character", "hitbox").get<float>());
}
/* Taken from mallinfo man page, log a profile of the memory when the command is sent. */
else if (sb::Delegate::compare(event, "memory"))
{
@ -499,13 +539,13 @@ void Cakefoot::run()
on_timer.on();
unpaused_timer.on();
/* Start the update loop */
Game::run();
/* Enable auto refresh */
#if defined(__LINUX__)
configuration().enable_auto_refresh("config.json", 5.0f);
configuration().enable_auto_refresh("resource/levels.json");
#endif
/* Start the update loop */
Game::run();
}
void Cakefoot::update(float timestamp)
@ -530,12 +570,36 @@ void Cakefoot::update(float timestamp)
}
else
{
/* Update checkpoint */
if (configuration()("levels", level_index).contains("checkpoints"))
{
for (nlohmann::json checkpoint : configuration()("levels", level_index, "checkpoints"))
{
if (character.relative(curve()) >= checkpoint["position"].get<float>() && character.checkpoint() < checkpoint["position"].get<float>())
{
character.checkpoint(checkpoint["position"].get<float>());
}
}
}
/* Collide with enemies */
bool collision = false;
for (auto& enemy : enemies)
{
enemy->update(unpaused_timer);
if (enemy->collide(character.box(), character.sprite(), {-curve().aspect, -1.0f, -1.0f}, {curve().aspect, 1.0f, 1.0f}))
{
character.beginning(curve());
collision = true;
}
}
/* Reset level */
if (collision)
{
character.spawn(curve());
for (auto& enemy : enemies)
{
enemy->reset();
}
}
}
@ -583,8 +647,31 @@ void Cakefoot::update(float timestamp)
}
curve().color.disable();
/* Draw enemies */
/* Draw checkpoints */
sb::Plane::position->bind("vertex_position", shader_program);
sb::Plane::color->bind("vertex_color", shader_program);
if (configuration()("levels", level_index).contains("checkpoints"))
{
for (nlohmann::json checkpoint : configuration()("levels", level_index, "checkpoints"))
{
sb::Sprite* sprite;
if (checkpoint["position"].get<float>() > character.checkpoint())
{
sprite = &checkpoint_off;
}
else
{
sprite = &checkpoint_on;
}
glm::vec3 position = curve().relative(checkpoint["position"].get<float>());
glm::vec2 delta = sb::angle_to_vector(checkpoint["angle"].get<float>(), configuration()("display", "checkpoint distance"));
position += glm::vec3{delta.x, delta.y, 0.0f};
sprite->translate(curve().wrap(position));
sprite->draw(uniform.at("mvp"), view * rotation_matrix, projection, uniform.at("texture enabled"));
}
}
/* Draw enemies */
for (auto& enemy : enemies)
{
enemy->draw(uniform["mvp"], view * rotation_matrix, projection, uniform["texture enabled"]);

View File

@ -70,43 +70,23 @@ class Cakefoot : public sb::Game
private:
/* Defines for effect IDs that will be passed to the shader program. Since EFFECT_COUNT is last and every value
* is the default integer, it will be set to the number of effects available. */
enum Effect
{
EFFECT_NONE,
EFFECT_COUNT
};
/* Defines for UV transformations available in the fragment shader program */
enum UVTransformation
{
UV_NONE,
UV_SQUIRCLE
};
/* Convention for calling parent class in a consistent way across classes */
typedef sb::Game super;
/* Constants */
inline static const glm::vec3 ZERO_VECTOR_3D {0, 0, 0};
inline static const glm::vec3 Y_UNIT_NORMAL_3D {0, 1, 0};
inline static const glm::mat4 VIEW_MATRIX = glm::lookAt({0.0f, 0.0f, 7.0f}, {0.0f, 0.0f, 0.0f}, Y_UNIT_NORMAL_3D);
/* Global */
inline static std::string RESET_COMMAND_NAME = "reset";
/* Static members */
inline static std::string reset_command_name = "reset";
/* Member vars */
std::shared_ptr<SDL_Cursor> poke, grab;
int effect_id = EFFECT_NONE, previous_frames_per_second = 0, curve_index = 0, curve_byte_count = 0, level_index = 0;
int previous_frames_per_second = 0, curve_index = 0, curve_byte_count = 0, level_index = 0;
std::map<std::string, GLuint> uniform;
GLuint shader_program;
glm::mat4 view {1.0f}, projection {1.0f};
sb::VAO vao;
sb::VBO vbo;
std::map<std::string, Pad<>> text_buttons = {{"start", Pad<>()}, {"resume", Pad<>()}, {"reset", Pad<>()}};
Pad<> pause_button;
Sprite playing_field;
std::map<std::string, sb::Pad<>> text_buttons = {{"start", sb::Pad<>()}, {"resume", sb::Pad<>()}, {"reset", sb::Pad<>()}};
sb::Pad<> pause_button;
sb::Sprite playing_field, checkpoint_on, checkpoint_off;
sb::Timer on_timer, run_timer, unpaused_timer;
Character character{_configuration};
glm::vec3 camera_position {0.0f, 0.0f, 2.0f}, subject_position {0.0f, 0.0f, 0.0f};
@ -116,11 +96,21 @@ private:
std::vector<Curve> curves;
std::vector<std::shared_ptr<Enemy>> enemies;
/*!
* Open configuration and load curve data into the object.
*/
void load_curves();
/*!
* Create GL context via super class and load vertices, UV data, and shaders.
*/
void load_gl_context();
/*!
* Generate, bind, and fill a vertex buffer object with the game's vertex data.
*/
void load_vbo();
/*!
* @return the currently active curve
*/

View File

@ -4,8 +4,13 @@ Character::Character(const Configuration& configuration) : configuration(configu
{
/* Initialize sprite and box to the size of the graphic. */
glm::vec2 size {20.0f / 486.0f};
_sprite = Sprite("resource/cake-frames/cake1.png", size);
_box.size(2.0f * size);
_sprite = sb::Sprite("resource/cake-frames/cake1.png", size);
box_size(1.0f);
}
void Character::box_size(float size)
{
_box.size(size * 2.0f * this->size);
}
void Character::load()
@ -18,24 +23,45 @@ const Box& Character::box() const
return _box;
}
const Sprite& Character::sprite() const
const sb::Sprite& Character::sprite() const
{
return _sprite;
}
void Character::beginning(const Curve& curve)
{
next_point_index = 0;
checkpoint(0.0f);
spawn(curve);
}
void Character::spawn(const Curve& curve)
{
next_point_index = curve.index(checkpoint());
position = curve[next_point_index];
speed = 0.0f;
position = curve.front();
accelerating = false;
}
void Character::checkpoint(float checkpoint)
{
_checkpoint = checkpoint;
}
float Character::checkpoint() const
{
return _checkpoint;
}
bool Character::at_end(const Curve& curve) const
{
return next_point_index > curve.length() - 1;
}
float Character::relative(const Curve& curve) const
{
return float(next_point_index) / curve.length();
}
void Character::update(const Curve& curve, const sb::Timer& timer)
{
/* Adjust speed based on acceleration state and character profile. */
@ -65,7 +91,7 @@ void Character::update(const Curve& curve, const sb::Timer& timer)
glm::vec3 next_point, step;
while (distance_remaining)
{
if (speed < 0.0f && next_point_index == 0)
if (speed < 0.0f && relative(curve) <= checkpoint())
{
speed = 0.0f;
break;

View File

@ -13,12 +13,13 @@ class Character
private:
inline static const std::vector<std::string> PROFILES = {"cake", "ball", "buffalo"};
inline static const std::vector<std::string> profiles {"cake", "beefcake", "buffalo beefcake"};
inline static const glm::vec2 size {20.0f / 486.0f};
const Configuration& configuration;
float speed = 0.0f;
float speed = 0.0f, _checkpoint = 0.0f;
int next_point_index = 0;
Sprite _sprite;
sb::Sprite _sprite;
Box _box;
/*!
@ -30,11 +31,18 @@ private:
public:
sb::Switch<> accelerating = false;
sb::Selection<std::vector<std::string>> profile = PROFILES;
sb::Selection<std::vector<std::string>> profile = profiles;
glm::vec3 position;
Character(const Configuration& configuration);
/*!
* Set the size of the hit box as a percentage of the sprite's size.
*
* @param size percentage of sprite size
*/
void box_size(float size);
/*!
* Load the graphics into the GPU. This is only necessary to run if the object was constructed before the GL context was loaded.
*/
@ -48,19 +56,43 @@ public:
/*!
* @return reference to the character's sprite object for accessing the character's graphics
*/
const Sprite& sprite() const;
const sb::Sprite& sprite() const;
/*!
* @param curve the curve to reset the beginning position to
*/
void beginning(const Curve& curve);
/*!
* @return relative point on the curve where the character should spawn
*/
float checkpoint() const;
/*!
* Update the spawn point.
*
* @param checkpoint relative point on the curve where the character should spawn
*/
void checkpoint(float checkpoint);
/*!
* Place character at checkpoint position on the curve.
*
* @param curve curve to spawn on
*/
void spawn(const Curve& curve);
/*!
* @param curve curve to check against
* @return `true` if the character is at the end of the curve, `false` otherwise
*/
bool at_end(const Curve& curve) const;
/*!
* @return character's relative position on the given curve
*/
float relative(const Curve& curve) const;
/*!
* Check acceleration state and adjust speed. Move character toward the next point on the curve.
*

View File

@ -1,6 +1,6 @@
#include "Enemy.hpp"
bool Enemy::collide(const sb::Box& box, const Sprite& sprite, const glm::vec3& clip_lower, const glm::vec3& clip_upper) const
bool Enemy::collide(const sb::Box& box, const sb::Sprite& sprite, const glm::vec3& clip_lower, const glm::vec3& clip_upper) const
{
sb::Box wrapped = this->box;
wrapped.center(sb::wrap_point({this->box.center(), 0.0f}, clip_lower, clip_upper));
@ -203,7 +203,7 @@ void Projector::draw(GLuint transformation_uniform, const glm::mat4 view, const
}
}
bool Projector::collide(const sb::Box& box, const Sprite& sprite, const glm::vec3& clip_lower, const glm::vec3& clip_upper) const
bool Projector::collide(const sb::Box& box, const sb::Sprite& sprite, const glm::vec3& clip_lower, const glm::vec3& clip_upper) const
{
for (const Projectile& projectile : projectiles)
{
@ -222,7 +222,10 @@ void Projector::charge()
void Projector::release()
{
projectiles.emplace_back(position, character.position, speed);
/* Temporarily hard code the wrapping until figuring out how to reference the current curve in this function. */
glm::vec3 point = sb::wrap_point(character.position, {-1.77777f, -1.0f, 0.0f}, {1.77777f, 1.0f, 1.0f});
projectiles.emplace_back(position, point, speed);
}
Flame::Flame(const sb::Box field, const glm::vec3& position, float speed, float angle, float mirror_interval) :

View File

@ -23,6 +23,10 @@ protected:
public:
/*!
*/
virtual void reset() {};
/*!
* @param timer timer updated every frame to be used for delta time
*/
@ -54,7 +58,7 @@ public:
* @return true if the sprite object's pixels enclosed in the box object collides with the pixels enclosed by
* this enemy's box object
*/
virtual bool collide(const sb::Box& box, const Sprite& sprite, const glm::vec3& clip_lower, const glm::vec3& clip_upper) const;
virtual bool collide(const sb::Box& box, const sb::Sprite& sprite, const glm::vec3& clip_lower, const glm::vec3& clip_upper) const;
};
@ -69,7 +73,7 @@ private:
std::reference_wrapper<const Curve> curve;
float relative = 0.0f, speed = 0.0f, stray = 0.0f;
bool toward_end = true;
Sprite sprite;
sb::Sprite sprite;
/*!
*/
@ -114,7 +118,7 @@ private:
std::reference_wrapper<const Curve> curve;
float relative = 0.0f, speed = 0.0f, radius = 0.0f, angle = 0.0f;
Sprite sprite;
sb::Sprite sprite;
/*!
* @return vertex in world coordinates the fish is rotating around, always lies on the curve
@ -156,7 +160,7 @@ private:
glm::vec3 position = glm::vec3{0.0f}, target = glm::vec3{0.0f};
float speed = 0.0f, angle = 0.0f;
Sprite sprite;
sb::Sprite sprite;
public:
@ -171,10 +175,6 @@ public:
*/
Projectile(const glm::vec3& position, const glm::vec3& target, float speed = 0.51440329f);
/*!
*/
void reset();
/*!
*/
void update(const sb::Timer& timer);
@ -202,7 +202,7 @@ private:
glm::vec3 position = glm::vec3{0.0f};
float speed = 0.0f, rate = 0.0f;
const double& release_delay;
Sprite sprite;
sb::Sprite sprite;
sb::Animation animation_charge = sb::Animation(std::bind(&Projector::charge, this)),
animation_release = sb::Animation(std::bind(&Projector::release, this));
std::vector<Projectile> projectiles;
@ -242,7 +242,7 @@ public:
*
* @see Enemy::collide(const sb::Box&, const Sprite&, const glm::vec3&, const glm::vec3&)
*/
bool collide(const sb::Box& box, const Sprite& sprite, const glm::vec3& clip_lower, const glm::vec3& clip_upper) const;
bool collide(const sb::Box& box, const sb::Sprite& sprite, const glm::vec3& clip_lower, const glm::vec3& clip_upper) const;
};
@ -258,7 +258,7 @@ private:
const sb::Box field;
glm::vec3 position = glm::vec3{0.0f};
float speed = 0.0f, angle = 0.0f;
Sprite sprite;
sb::Sprite sprite;
sb::Animation animation_mirror = sb::Animation(std::bind(&Flame::mirror, this));
/*!

View File

@ -1,234 +0,0 @@
#pragma once
#include <optional>
#include <functional>
#include "Model.hpp"
#include "Switch.hpp"
#include "math.hpp"
/*!
* A Pad is an object containing an sb::Plane which can be clicked to launch an arbitrary user function. It can be sized and placed by setting its
* translation and scale values.
*
* Each instance:
*
* - Has an sb::Plane or derivative (either a custom one provided, or a default constructed one automatically)
* - Has an arbitrary response function for when pressed
* - Can collide with a point (for example, mouse click)
*
* Example:
*
* glm::vec3 w = glm::mat3({{1, 0, 0}, {0, 1, 0}, {-0.6739, -0.74, 1}}) * glm::mat3({{.1, 0, 0}, {0, .1 * (460.0 / 768.0), 0}, {0, 0, 1}}) *
* glm::vec3({-1, -1, 1});
* std::cout << w << std::endl << glm::translate(glm::vec3{-0.6739, -0.74, 0}) *
* glm::scale(glm::vec3{.1, .1 * (460.0 / 768.0), 1}) * glm::vec4{-1, -1, 0, 1} << std::endl;
* Pad p {background.current(), {-0.6739f, -0.74f}, 0.1f, get_display().window_box().aspect(), std::function<void()>()};
* const std::vector<glm::vec2>& p_position = *p.attributes("position");
* glm::vec4 final_position = p.transformation() * glm::vec4{p_position[2].x, p_position[2].y, 0, 1};
* std::cout << p.transformation() << std::endl << final_position << std::endl;
* assert(final_position == glm::vec4({w.x, w.y, 0, 1}));
*/
template<typename ReturnType = void, typename... Arguments>
class Pad
{
private:
using Reaction = std::function<ReturnType(bool, Arguments...)>;
sb::Switch<ReturnType, Arguments...> connection;
sb::Plane plane;
Box box;
public:
/*!
* Construct a Pad object with a default constructed sb::Plane.
*
* @see Pad(sb::Plane, const glm::vec2&, float, float, Reaction, float)
*/
Pad(const glm::vec2& translation = {0.0f, 0.0f}, float scale = 1.0f, float ratio = 1.0f, Reaction on_state_change = Reaction(), float rotation = 0.0f) :
Pad(sb::Plane(), translation, scale, ratio, on_state_change, rotation) {}
/*!
* Construct a pad object from an sb::Plane, a translation amount, a scale factor, and a reaction function. The translation is relative
* to (0.0, 0.0), and the scale is relative to the plane object.
*
* The reaction function must accept a boolean as its first argument, which will be given the state of the pad object's switch.
*
* The plane object will be copied into the pad, so any edits must be made before constructing the pad, unless there is a Pad function
* that applies the edit, such as Pad::scale(float, float).
*
* @param plane plane or plane derivative to represent the pad visually
* @param translation x, y amount to translate the position
* @param scale amount to scale both x and y
* @param ratio ratio to adjust scale of x and y
* @param on_state_change reaction function which accepts a boolean as its first argument
* @param rotation angle in radians to rotate the pad
*/
Pad(const sb::Plane& plane, glm::vec2 translation = {0.0f, 0.0f}, float scale = 1.0f, float ratio = 1.0f,
Reaction on_state_change = Reaction(), float rotation = 0.0f) : plane(plane)
{
box.size({2.0f, 2.0f}, true);
if (translation != glm::vec2{0.0f, 0.0f})
{
this->translate(translation);
}
if (scale != 1.0f || ratio != 1.0f)
{
this->scale(scale, ratio);
}
if (rotation)
{
this->rotate(rotation);
}
this->on_state_change(on_state_change);
}
/*!
* Rotate the pad around its center by 90 degrees. If a count is given, rotate by 90 degrees that many times, so for example,
* a count of 3 will be a 270 degree rotation. If the count is negative, rotate -90 degrees.
*
* @param count number of 90 degree rotations to make, or use a negative count to rotate -90 degrees
*/
void rotate(int count = 1)
{
plane.transform(glm::rotate(count * glm::half_pi<float>(), glm::vec3{0.0f, 0.0f, 1.0f}));
}
/*!
* Scale using a factor and ratio that will transform the pad in the X and Y dimensions. The ratio determines how much each axis
* is scaled. If the ratio is above one, the X-axis's scale will be divided by the ratio. If the ratio is below one, the Y-axis's
* scale will be multiplied by the aspect ratio. If the aspect ratio of the window is given, this will force the pad to display as
* a square, and the ratio will be relative to the shorter axis.
*
* The collision box will be scaled by the same factors.
*
* @param factor amount to scale in both x and y directions
* @param ratio amount to adjust scaling, set to the window aspect ratio to make the pad appear square
*/
const glm::mat4& scale(float factor, float ratio = 1.0f)
{
glm::vec3 scale { factor, factor, 1.0f };
if (ratio > 1.0f)
{
scale.x /= ratio;
}
else if (ratio < 1.0f)
{
scale.y *= ratio;
}
box.scale({scale.x, scale.y}, true);
return plane.scale(scale);
}
/*!
* Set the pad's location in the X and Y dimension using a 2D vector. The collision box will be moved by the same translation.
*
* @param translation x, y distance to translate the pad
*/
const glm::mat4& translate(const glm::vec2& translation)
{
box.move(translation);
return plane.translate({translation.x, translation.y, 0.0f});
}
/*!
* Set the function that will run when a pad object is clicked.
*
* Example, always keep state true and print "Hello, World!" whenever the pad is clicked,
*
* start_button.on_state_change([&](bool state, int count){
* if (state) {
* std::ostringstream message;
* message << "Hello, " << state << " World! " << count;
* sb::Log::log(message);
* start_button.press(1);
* }});
*
* @param on_state_change reaction function which accepts a boolean as its first argument
*/
void on_state_change(Reaction reaction)
{
connection.on_state_change(reaction);
}
/*!
* Returns true if the point at given NDC coordinates collides with the pad's collision box. This only works properly if the
* Pad is flat in the z-dimension.
*
* @param position x, y NDC coordinates to check for collision
* @return true if the point is inside Pad::box, false otherwise
*/
bool collide(const glm::vec2& position, const glm::mat4& view, const glm::mat4& projection) const
{
/* Corners of the box */
std::vector<glm::vec3> corners;
/* Transform each of the corners into NDC coordinates */
for (const glm::vec2& vertex : {box.sw(), box.nw(), box.ne(), box.se()})
{
corners.push_back(sb::world_to_ndc(vertex, projection * view));
}
/* Create a new box using the NDC bottom-left corner */
glm::vec2 control = corners[0];
float width = glm::distance(corners[3], corners[0]);
float height = glm::distance(corners[1], corners[0]);
sb::Box transformed {control, {width, height}};
/* Collide the NDC box with the caller's coordinates */
return transformed.collide(position);
}
/*!
* Set the transformation uniform, bind the texture, and draw the vertices. Build the full transformation matrix
* by combining the Pad object's transformation with the supplied projection and view matrices, and pass it to
* the shader.
*
* The active texture must have been set with its ID passed to the corresponding shader uniform previously.
*
* @param transformation_uniform transformation uniform ID
* @param view the view matrix for transforming from world space to camera space
* @param projection projection matrix for transforming from camera space to clip space
* @param texture_flag_uniform uniform ID for boolean enabling or disabling texture display
*/
void draw(GLuint transformation_uniform, glm::mat4 view, glm::mat4 projection, std::optional<GLuint> texture_flag_uniform = std::nullopt)
{
if (!plane.textures().empty())
{
if (texture_flag_uniform.has_value())
{
glUniform1i(texture_flag_uniform.value(), true);
}
plane.texture().bind();
}
else if (texture_flag_uniform.has_value())
{
glUniform1i(texture_flag_uniform.value(), false);
}
glm::mat4 mvp = projection * view * plane.transformation();
glUniformMatrix4fv(transformation_uniform, 1, GL_FALSE, &mvp[0][0]);
plane.enable();
glDrawArrays(GL_TRIANGLES, 0, plane.attributes("position")->count());
plane.disable();
}
/*!
* Run the reaction function.
*
* @param args arguments to pass to the reaction function
* @return result of the reaction function if it returns a value, or void otherwise
*/
ReturnType press(Arguments... args)
{
return connection.flip(args...);
}
/*!
* @return size in bytes of the pad object's plane object
*/
std::size_t size() const
{
return plane.size();
}
};

View File

@ -1,206 +0,0 @@
#pragma once
#include <vector>
#include <optional>
#include "glm/glm.hpp"
#include "filesystem.hpp"
#include "Model.hpp"
class Sprite : public sb::Plane
{
private:
/* Keep a reference of the matrix transformations generated when the user applys a transformation, so that each can be reapplied
* without having to set all the transformations every time one is changed. */
glm::mat4 _scale {1.0f}, _translation {1.0f}, _rotation {1.0f};
public:
/*!
* Construct a Sprite with an optional scale amount.
*
* @param scale amount to scale
*/
Sprite(glm::vec2 scale = glm::vec2{1.0f})
{
this->scale(scale);
}
/*!
* Construct a Sprite from a texture. The texture is the 2D graphic that displays in the Sprite's location.
*
* @param texture sprite's 2D graphic
* @param scale amount to scale
*/
Sprite(const sb::Texture& texture, glm::vec2 scale = glm::vec2{1.0f}) : Sprite(scale)
{
this->texture(texture);
}
/*!
* Construct a Sprite from a list of textures. Each texture is a frame of the Sprite's animation.
*
* @param textures list of textures
* @param scale amount to scale
*/
Sprite(const std::vector<sb::Texture>& textures, glm::vec2 scale = glm::vec2{1.0f}) : Sprite(scale)
{
for (const sb::Texture& texture : textures)
{
this->texture(texture);
}
}
/*!
* Construct a ::Sprite object from a path to an image file which will converted into a texture.
*
* The texture is loaded into GPU memory if the GL context is active. Otherwise, the path is just attached to
* the texture, and it must be loaded with a call to ::load or Texture::load.
*
* @param path path to an image
* @param scale amount to scale
*/
Sprite(const fs::path& path, glm::vec2 scale = glm::vec2{1.0f}) : Sprite(scale)
{
this->texture(path);
}
/*!
* Construct a ::Sprite object from a list of paths to image files which will be converted into textures.
*
* @see ::Sprite(const fs::path, glm::vec3)
*
* @param paths list of paths to images
* @param scale amount to scale
*/
Sprite(const std::vector<fs::path>& paths, glm::vec2 scale = glm::vec2{1.0f}) : Sprite(scale)
{
for (const fs::path& path : paths)
{
this->texture(path);
}
}
/*!
* Add a previously constructed sb::Texture to the ::Sprite object.
*
* @param texture sb::Texture object to add
*/
void texture(const sb::Texture& texture)
{
Model::texture(texture);
}
/*!
* Add a new texture to ::Sprite from a path to an image file which will converted into a new texture.
*
* The texture is loaded into GPU memory if the GL context is active. Otherwise, the path is just attached to
* the texture, and it must be loaded with a call to Model::load or Texture::load.
*
* @param path path to an image
*/
void texture(const fs::path& path)
{
sb::Texture texture;
if (SDL_GL_GetCurrentContext() != nullptr)
{
texture.load(path);
}
else
{
texture.associate(path);
}
this->texture(texture);
}
/*!
* Get a constant refernce to the texture at the given index. If no index is given, get the texture at index 0. If
* there are no textures, an exception will be thrown.
*
* @param index index of texture to get
*/
const sb::Texture& texture(int index = 0) const
{
return Model::texture(index);
}
/*!
*/
void translate(const glm::vec3& translation)
{
untransform();
_translation = Model::translate(translation);
transform();
}
/*!
* @param step amount to move sprite's translation transformation in three dimensions
*/
void move(const glm::vec3& step)
{
untransform();
_translation += Model::translate(step);
transform();
}
/*!
*/
void scale(const glm::vec2& scale)
{
untransform();
_scale = Model::scale({scale, 1.0f});
transform();
}
/*!
*/
void rotate(float angle, const glm::vec3& axis)
{
untransform();
_rotation = Model::rotate(angle, axis);
transform();
}
/*!
* The translation, scale, and rotation transformations, if previously set, are applied to the object's transformation
* property, along with the optional additional transformation matrix argument.
*
* The existing transformation property will be reset to the identity matrix before this transformation is applied.
*
* @warning This function works differently than Model::transform(const glm::mat4&). To apply an arbitrary transformation
* without having the non-arbitrary transformations applied as well, the rotate, scale, and translate transformations should
* be set to the identity matrix.
*
* @param transformation optional additional transformation to apply
*/
void transform(glm::mat4 transformation = glm::mat4{1.0f})
{
untransform();
Model::transform(_translation * _scale * _rotation * transformation);
}
/*
*/
void draw(GLuint transformation_uniform, const glm::mat4 view = glm::mat4{1.0f}, const glm::mat4 projection = glm::mat4{1.0f},
std::optional<GLuint> texture_flag_uniform = std::nullopt) const
{
if (!textures().empty())
{
if (texture_flag_uniform.has_value())
{
glUniform1i(texture_flag_uniform.value(), true);
}
texture().bind();
}
else if (texture_flag_uniform.has_value())
{
glUniform1i(texture_flag_uniform.value(), false);
}
glm::mat4 mvp = projection * view * transformation();
glUniformMatrix4fv(transformation_uniform, 1, GL_FALSE, &mvp[0][0]);
enable();
glDrawArrays(GL_TRIANGLES, 0, attributes("position")->count());
disable();
}
};

View File

@ -5,79 +5,18 @@
/* The precision declaration is required by OpenGL ES */
precision mediump float;
#define TRANSFORMATION_NONE 0
#define TRANSFORMATION_SQUIRCLE 1
in vec2 fragment_uv;
in vec4 ex_color;
in float x_center_proximity;
in vec3 original_coordinates;
uniform sampler2D model_texture;
uniform int uv_transformation;
uniform float coordinate_bound;
uniform bool texture_enabled;
out vec4 output_color;
/* [-coordinate_bound, coordinate_bound] arbitrary box coordinates to [-1, 1] normalized coordinates */
vec2 normalize_coordinates(vec2 coordinates)
{
return coordinates / coordinate_bound;
}
/* [-1, 1] box coordinates to [0, 1] UV coordinates */
vec2 coordinates_to_uv(vec2 coordinates)
{
return (1.0 + coordinates) / 2.0;
}
/* coordinates in circle with radius <= 1 to box coordinates in [-1, 1] */
vec2 circle_to_box(vec2 circle)
{
float u = circle.x;
float v = circle.y;
float u_sq = pow(u, 2.0);
float v_sq = pow(v, 2.0);
float rt_2 = sqrt(2.0);
float x = 0.5 * sqrt(2.0 + 2.0 * u * rt_2 + u_sq - v_sq) - 0.5 * sqrt(2.0 - 2.0 * u * rt_2 + u_sq - v_sq);
float y = 0.5 * sqrt(2.0 + 2.0 * v * rt_2 - u_sq + v_sq) - 0.5 * sqrt(2.0 - 2.0 * v * rt_2 - u_sq + v_sq);
return vec2(x, y);
}
/* Apply color passed in from the vertex shader, compressing to one of 16 colors. Add retro effect
* by alternately darkening and lightening 2x2 pixel areas in a checker pattern. Add shadowing by
* brightening the color based on how near it is to the center in the X-dimension */
void retro()
{
vec4 shadowed = min(ex_color, 1.0);
float dx = abs(floor(gl_FragCoord[0]) - 480.0) / 480.0;
if (int(floor(gl_FragCoord[0] / 2.0) + floor(gl_FragCoord[1]) / 2.0) % 2 == 0)
{
output_color = shadowed * 1.2;
}
else
{
output_color = shadowed * 0.7;
}
output_color[0] = float(int(output_color[0] * 4.0)) / 4.0;
output_color[1] = float(int(output_color[1] * 4.0)) / 4.0;
output_color[2] = float(int(output_color[2] * 4.0)) / 4.0;
output_color *= x_center_proximity;
}
void main()
{
// if (uv_transformation == TRANSFORMATION_SQUIRCLE)
// {
// vec2 normalized_circle_coordinates = normalize_coordinates(vec2(original_coordinates.x, original_coordinates.z));
// fragment_uv = coordinates_to_uv(circle_to_box(normalized_circle_coordinates));
// }
// output_color = mix(vec4(ex_color, 1), texture(model_texture, fragment_uv) * vec4(ex_color, 1), float(texture_enabled));
// output_color = float(texture_enabled) * texture(model_texture, fragment_uv) * vec4(1, 0, 0, 0) + (1.0 - float(texture_enabled)) * vec4(1, 0, 0, 0);
// output_color = (1.0 - float(texture_enabled)) * vec4(ex_color, 1);
/* Get the texel at the center of the pixel boundaries, rather than the edges. */
// vec2 texture_uv = fragment_uv + 1.0 / vec2(textureSize(model_texture, 0)) / 2.0;
/* Use the input flag to modify the color output. If the flag is enabled, the texture value will be used. Otherwise, the color value will
* be used.
*

View File

@ -5,61 +5,22 @@
/* The precision declaration is required by OpenGL ES */
precision mediump float;
#define PI 3.1415926535897932384626433832795
#define AMPLITUDE 0.2
#define PERIOD .5
#define WAVELENGTH 2.5
#define EFFECT_NONE 0
#define EFFECT_SNAKE 1
#define EFFECT_WOBBLE 2
in vec3 vertex_position;
in vec4 vertex_color;
in vec2 vertex_uv;
uniform mat4 mvp;
uniform float time;
uniform int effect;
out vec4 ex_color;
out float x_center_proximity;
out vec2 fragment_uv;
out vec3 original_coordinates;
/* Offset X-coordinate according to the time step and Y-coordinate to create a wobble effect when run on
* flattened coordinates (after projection matrix has been applied) */
void wobble()
{
gl_Position.x += sin(time * 10.0) * vertex_position.y / 2.0;
}
/* Contort the X-coordinate according the time step and Y-coordinate using the sine function. This contorts
* the model into a sine wave along the Y-axis. It also moves the sine wave along the Y-axis using the time
* step uniform. The shape can be edited by changing the defintions for amplitude (maximum distance from
* Y-axis), wavelength (length in GL model coordinates between peaks), and period (amount of time in
* seconds it takes to loop through one wavelength cycle). */
void snake()
{
gl_Position = vec4(
vertex_position.x + AMPLITUDE * sin(2.0 * PI / PERIOD * (time + vertex_position.y * PERIOD / WAVELENGTH)), vertex_position.yz, 1);
}
void main()
{
// if (effect == EFFECT_SNAKE)
// {
// snake();
// }
// else
// {
gl_Position = vec4(vertex_position, 1);
// }
gl_Position = mvp * gl_Position;
// if (effect == EFFECT_WOBBLE)
// {
// wobble();
// }
/* passing to fragment program */
ex_color = vertex_color;
x_center_proximity = 1.8 - abs(vertex_position[0]);
fragment_uv = vertex_uv;
original_coordinates = vertex_position;
}