├── data
├── a16.png
├── crosshair.gltf
├── crosshair2.gltf
├── ship.gltf
└── station.gltf
├── screenshots
├── header.gif
└── lowres.png
├── packages.config
├── src
├── SpaceDust.h
├── Actor.h
├── GameCamera.h
├── MathUtils.h
├── Actor.cpp
├── Ship.h
├── GameCamera.cpp
├── SpaceDust.cpp
├── Ergo.cpp
└── Ship.cpp
├── LICENSE
├── Ergo.sln
├── Ergo.vcxproj.filters
├── readme.md
├── Ergo.vcxproj
└── .gitignore
/data/a16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brihernandez/Ergo/HEAD/data/a16.png
--------------------------------------------------------------------------------
/screenshots/header.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brihernandez/Ergo/HEAD/screenshots/header.gif
--------------------------------------------------------------------------------
/screenshots/lowres.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brihernandez/Ergo/HEAD/screenshots/lowres.png
--------------------------------------------------------------------------------
/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/SpaceDust.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | class SpaceDust
7 | {
8 | public:
9 | SpaceDust(float size, int count);
10 |
11 | void UpdateViewPosition(Vector3 viewPosition);
12 | void Draw(Vector3 viewPosition, Vector3 velocity, bool drawDots) const;
13 |
14 | private:
15 | std::vector Points;
16 | std::vector Colors;
17 | float Extent;
18 | };
19 |
--------------------------------------------------------------------------------
/src/Actor.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class Actor
6 | {
7 | public:
8 | Actor();
9 |
10 | Vector3 Position;
11 | Vector3 Velocity;
12 | Quaternion Rotation;
13 |
14 | Vector3 GetForward() const;
15 | Vector3 GetBack() const;
16 | Vector3 GetRight() const;
17 | Vector3 GetLeft() const;
18 | Vector3 GetUp() const;
19 | Vector3 GetDown() const;
20 |
21 | Vector3 TransformPoint(Vector3 point) const;
22 | void RotateLocalEuler(Vector3 axis, float degrees);
23 | };
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2022 Brian Hernandez
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/src/GameCamera.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class Ship;
6 |
7 | class GameCamera
8 | {
9 | public:
10 |
11 | GameCamera(bool isPerspective, float fieldOfView);
12 |
13 | ///
14 | /// Automatically moves the camera to follow a target ship.
15 | ///
16 | void FollowShip(const Ship& ship, float deltaTime);
17 |
18 | ///
19 | /// Moves the camera to the given positions. Smoothing is automatically applied.
20 | ///
21 | void MoveTo(Vector3 position, Vector3 target, Vector3 up, float deltaTime);
22 |
23 | ///
24 | /// Immediately moves the camera to the given positions with no smoothing.
25 | ///
26 | void SetPosition(Vector3 position, Vector3 target, Vector3 up);
27 |
28 | ///
29 | /// Required to tell raylib that any further 3D calls will be made with this camera.
30 | /// Must be paired with EndDrawing().
31 | ///
32 | void Begin3DDrawing() const;
33 |
34 | ///
35 | /// Requires to tell raylib to stop 3D rendering with this camera.
36 | ///
37 | void EndDrawing() const;
38 |
39 | Vector3 GetPosition() const;
40 |
41 | private:
42 | Camera3D Camera;
43 |
44 | Vector3 SmoothPosition;
45 | Vector3 SmoothTarget;
46 | Vector3 SmoothUp;
47 | };
48 |
--------------------------------------------------------------------------------
/src/MathUtils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | // ==================================================================================
6 | // For more info on SmoothDamp see:
7 | // https://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
8 | // ==================================================================================
9 |
10 | inline float SmoothDamp(float from, float to, float speed, float dt)
11 | {
12 | return Lerp(from, to, 1 - expf(-speed * dt));
13 | }
14 |
15 | inline Vector3 SmoothDamp(Vector3 from, Vector3 to, float speed, float dt)
16 | {
17 | return Vector3{
18 | Lerp(from.x, to.x, 1 - expf(-speed * dt)),
19 | Lerp(from.y, to.y, 1 - expf(-speed * dt)),
20 | Lerp(from.z, to.z, 1 - expf(-speed * dt))};
21 | }
22 |
23 | inline Quaternion SmoothDamp(Quaternion from, Quaternion to, float speed, float dt)
24 | {
25 | return QuaternionSlerp( from, to, 1 - expf(-speed * dt));
26 | }
27 |
28 | //
29 | //inline float InverseLerp(float from, float to, float value)
30 | //{
31 | // return (value - from) / (to - from);
32 | //}
33 | //
34 | //inline float Remap(float fromMin, float fromMax, float toMin, float toMax, float value)
35 | //{
36 | // float t = InverseLerp(fromMin, fromMax, value);
37 | // return Lerp(toMin, toMax, t);
38 | //
39 | //}
40 |
--------------------------------------------------------------------------------
/Ergo.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.2.32630.192
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Ergo", "Ergo.vcxproj", "{26599881-5658-45ED-9275-096CFAE1063C}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {26599881-5658-45ED-9275-096CFAE1063C}.Debug|x64.ActiveCfg = Debug|x64
17 | {26599881-5658-45ED-9275-096CFAE1063C}.Debug|x64.Build.0 = Debug|x64
18 | {26599881-5658-45ED-9275-096CFAE1063C}.Debug|x86.ActiveCfg = Debug|Win32
19 | {26599881-5658-45ED-9275-096CFAE1063C}.Debug|x86.Build.0 = Debug|Win32
20 | {26599881-5658-45ED-9275-096CFAE1063C}.Release|x64.ActiveCfg = Release|x64
21 | {26599881-5658-45ED-9275-096CFAE1063C}.Release|x64.Build.0 = Release|x64
22 | {26599881-5658-45ED-9275-096CFAE1063C}.Release|x86.ActiveCfg = Release|Win32
23 | {26599881-5658-45ED-9275-096CFAE1063C}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {01F1F47A-3D73-41A1-8C21-8096026FD224}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/src/Actor.cpp:
--------------------------------------------------------------------------------
1 | #include "Actor.h"
2 |
3 | #include
4 |
5 | Actor::Actor()
6 | {
7 | Position = Vector3Zero();
8 | Velocity = Vector3Zero();
9 | Rotation = QuaternionIdentity();
10 | }
11 |
12 | Vector3 Actor::GetForward() const
13 | {
14 | return Vector3RotateByQuaternion(
15 | Vector3{ 0, 0, 1 },
16 | Rotation);
17 | }
18 |
19 | Vector3 Actor::GetBack() const
20 | {
21 | return Vector3RotateByQuaternion(
22 | Vector3{ 0, 0, -1 },
23 | Rotation);
24 | }
25 |
26 | Vector3 Actor::GetRight() const
27 | {
28 | return Vector3RotateByQuaternion(
29 | Vector3{ -1, 0, 0 },
30 | Rotation);
31 | }
32 |
33 | Vector3 Actor::GetLeft() const
34 | {
35 | return Vector3RotateByQuaternion(
36 | Vector3{ 1, 0, 0 },
37 | Rotation);
38 | }
39 |
40 | Vector3 Actor::GetUp() const
41 | {
42 | return Vector3RotateByQuaternion(
43 | Vector3{ 0, 1, 0 },
44 | Rotation);
45 | }
46 |
47 | Vector3 Actor::GetDown() const
48 | {
49 | return Vector3RotateByQuaternion(
50 | Vector3{ 0, -1, 0 },
51 | Rotation);
52 | }
53 |
54 | Vector3 Actor::TransformPoint(Vector3 point) const
55 | {
56 | auto mPos = MatrixTranslate(Position.x, Position.y, Position.z);
57 | auto mRot = QuaternionToMatrix(Rotation);
58 | auto matrix = MatrixMultiply(mRot, mPos);
59 | return Vector3Transform(point, matrix);
60 | }
61 |
62 | void Actor::RotateLocalEuler(Vector3 axis, float degrees)
63 | {
64 | auto radians = degrees * DEG2RAD;
65 | Rotation = QuaternionMultiply(
66 | Rotation,
67 | QuaternionFromAxisAngle(axis, radians));
68 | }
69 |
--------------------------------------------------------------------------------
/src/Ship.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Actor.h"
4 |
5 | struct TrailRung
6 | {
7 | Vector3 LeftPoint;
8 | Vector3 RightPoint;
9 | float TimeToLive;
10 | };
11 |
12 | class Ship : public Actor
13 | {
14 | public:
15 | float InputForward = 0;
16 | float InputLeft = 0;
17 | float InputUp = 0;
18 |
19 | float InputPitchDown = 0;
20 | float InputRollRight = 0;
21 | float InputYawLeft = 0;
22 |
23 | float MaxSpeed = 20;
24 | float ThrottleResponse = 10;
25 | float TurnRate = 180;
26 | float TurnResponse = 10;
27 |
28 | float Length = 1.0f;
29 | float Width = 1.0f;
30 |
31 | Color TrailColor = DARKGREEN;
32 |
33 | Ship(const char* modelPath, const char* texturePath, Color color);
34 | ~Ship();
35 |
36 | void Update(float deltaTime);
37 | void Draw(bool showDebugAxes) const;
38 | void DrawTrail() const;
39 |
40 | private:
41 | Model ShipModel = {};
42 | Color ShipColor = {};
43 |
44 | static const int RungCount = 16;
45 | TrailRung Rungs[RungCount];
46 |
47 | float SmoothForward = 0;
48 | float SmoothLeft = 0;
49 | float SmoothUp = 0;
50 |
51 | float SmoothPitchDown = 0;
52 | float SmoothRollRight = 0;
53 | float SmoothYawLeft = 0;
54 |
55 | float VisualBank = 0;
56 |
57 | void PositionActiveTrailRung();
58 | Vector3 LastRungPosition = { 0, 0, 0 };
59 | int RungIndex = 0;
60 | };
61 |
62 | class Crosshair
63 | {
64 | public:
65 | Crosshair(const char* modelPath);
66 | ~Crosshair();
67 |
68 | void PositionCrosshairOnShip(const Ship& ship, float distance);
69 | void DrawCrosshair() const;
70 |
71 | private:
72 | Model CrosshairModel = {};
73 | };
74 |
--------------------------------------------------------------------------------
/src/GameCamera.cpp:
--------------------------------------------------------------------------------
1 | #include "GameCamera.h"
2 |
3 | #include
4 |
5 | #include "Ship.h"
6 | #include "MathUtils.h"
7 |
8 | GameCamera::GameCamera(bool isPerspective, float fieldOfView)
9 | {
10 | Camera = Camera3D();
11 | Camera.position = Vector3{ 0, 10, -10 };
12 | Camera.target = Vector3{ 0, 0, 0 };
13 | Camera.up = Vector3{ 0, 1, 0 };
14 |
15 | Camera.fovy = fieldOfView;
16 | Camera.projection = isPerspective
17 | ? CameraProjection::CAMERA_PERSPECTIVE
18 | : CameraProjection::CAMERA_ORTHOGRAPHIC;
19 |
20 | SmoothPosition = Vector3Zero();
21 | SmoothTarget = Vector3Zero();
22 | SmoothUp = Vector3Zero();
23 | }
24 |
25 | void GameCamera::FollowShip(const Ship& ship, float deltaTime)
26 | {
27 | Vector3 position = ship.TransformPoint({ 0, 1, -3 });
28 | Vector3 shipForwards = Vector3Scale(ship.GetForward(), 25);
29 | Vector3 target = Vector3Add(ship.Position, shipForwards);
30 | Vector3 up = ship.GetUp();
31 |
32 | MoveTo(position, target, up, deltaTime);
33 | }
34 |
35 | void GameCamera::MoveTo(Vector3 position, Vector3 target, Vector3 up, float deltaTime)
36 | {
37 | Camera.position = SmoothDamp(
38 | Camera.position, position,
39 | 10, deltaTime);
40 |
41 | Camera.target = SmoothDamp(
42 | Camera.target, target,
43 | 5, deltaTime);
44 |
45 | Camera.up = SmoothDamp(
46 | Camera.up, up,
47 | 5, deltaTime);
48 | }
49 |
50 | void GameCamera::SetPosition(Vector3 position, Vector3 target, Vector3 up)
51 | {
52 | Camera.position = position;
53 | Camera.target = target;
54 | Camera.up = up;
55 |
56 | SmoothPosition = position;
57 | SmoothTarget = target;
58 | SmoothUp = up;
59 | }
60 |
61 | Vector3 GameCamera::GetPosition() const
62 | {
63 | return Camera.position;
64 | }
65 |
66 | void GameCamera::Begin3DDrawing() const
67 | {
68 | BeginMode3D(Camera);
69 | }
70 |
71 | void GameCamera::EndDrawing() const
72 | {
73 | EndMode3D();
74 | }
75 |
--------------------------------------------------------------------------------
/Ergo.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 |
35 |
36 | Header Files
37 |
38 |
39 | Header Files
40 |
41 |
42 | Header Files
43 |
44 |
45 | Header Files
46 |
47 |
48 | Header Files
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/SpaceDust.cpp:
--------------------------------------------------------------------------------
1 | #include "SpaceDust.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | inline float GetPrettyBadRandomFloat(float min, float max)
9 | {
10 | auto value = static_cast(GetRandomValue((int)min * 1000, (int)max * 1000));
11 | value /= 1000.f;
12 | return value;
13 | }
14 |
15 | SpaceDust::SpaceDust(float size, int count)
16 | {
17 | Points = std::vector();
18 | Points.reserve(count);
19 | Extent = size * .5f;
20 |
21 | for (int i = 0; i < count; ++i)
22 | {
23 | auto point = Vector3{
24 | GetPrettyBadRandomFloat(-Extent, Extent),
25 | GetPrettyBadRandomFloat(-Extent, Extent),
26 | GetPrettyBadRandomFloat(-Extent, Extent)
27 | };
28 | Points.push_back(point);
29 |
30 | auto color = Color{
31 | (unsigned char)GetRandomValue(192, 255),
32 | (unsigned char)GetRandomValue(192, 255),
33 | (unsigned char)GetRandomValue(192, 255),
34 | 255
35 | };
36 | Colors.push_back(color);
37 | }
38 | }
39 |
40 | void SpaceDust::UpdateViewPosition(Vector3 viewPosition)
41 | {
42 | float size = Extent * 2;
43 | for (auto& p : Points)
44 | {
45 | while (p.x > viewPosition.x + Extent)
46 | p.x -= size;
47 | while (p.x < viewPosition.x - Extent)
48 | p.x += size;
49 |
50 | while (p.y > viewPosition.y + Extent)
51 | p.y -= size;
52 | while (p.y < viewPosition.y - Extent)
53 | p.y += size;
54 |
55 | while (p.z > viewPosition.z + Extent)
56 | p.z -= size;
57 | while (p.z < viewPosition.z - Extent)
58 | p.z += size;
59 | }
60 | }
61 |
62 | void SpaceDust::Draw(Vector3 viewPosition, Vector3 velocity, bool drawDots) const
63 | {
64 | BeginBlendMode(BlendMode::BLEND_ADDITIVE);
65 |
66 | for (int i = 0; i < Points.size(); ++i)
67 | {
68 | float distance = Vector3Distance(viewPosition, Points[i]);
69 |
70 | float farLerp = Clamp(Normalize(distance, Extent * .9f, Extent), 0, 1);
71 | unsigned char farAlpha = (unsigned char)Lerp(255, 0, farLerp);
72 |
73 | const float cubeSize = 0.01f;
74 |
75 | if (drawDots)
76 | {
77 | DrawSphereWires(
78 | Points[i],
79 | cubeSize,
80 | 2, 4,
81 | { Colors[i].r, Colors[i].g, Colors[i].b, farAlpha });
82 | }
83 |
84 | DrawLine3D(
85 | Vector3Add(Points[i], Vector3Scale(velocity, 0.02f)),
86 | Points[i],
87 | { Colors[i].r, Colors[i].g, Colors[i].b, farAlpha });
88 | }
89 |
90 | rlDrawRenderBatchActive();
91 | EndBlendMode();
92 | }
93 |
--------------------------------------------------------------------------------
/data/crosshair.gltf:
--------------------------------------------------------------------------------
1 | {
2 | "asset" : {
3 | "generator" : "Khronos glTF Blender I/O v1.8.19",
4 | "version" : "2.0"
5 | },
6 | "scene" : 0,
7 | "scenes" : [
8 | {
9 | "name" : "Scene",
10 | "nodes" : [
11 | 0
12 | ]
13 | }
14 | ],
15 | "nodes" : [
16 | {
17 | "mesh" : 0,
18 | "name" : "Crosshair"
19 | }
20 | ],
21 | "meshes" : [
22 | {
23 | "name" : "Plane",
24 | "primitives" : [
25 | {
26 | "attributes" : {
27 | "POSITION" : 0,
28 | "NORMAL" : 1,
29 | "TEXCOORD_0" : 2
30 | },
31 | "indices" : 3
32 | }
33 | ]
34 | }
35 | ],
36 | "accessors" : [
37 | {
38 | "bufferView" : 0,
39 | "componentType" : 5126,
40 | "count" : 24,
41 | "max" : [
42 | 1.2412012815475464,
43 | 0.9573875665664673,
44 | 0.09539321810007095
45 | ],
46 | "min" : [
47 | -1.2412012815475464,
48 | -0.9573875665664673,
49 | 0.09539308398962021
50 | ],
51 | "type" : "VEC3"
52 | },
53 | {
54 | "bufferView" : 1,
55 | "componentType" : 5126,
56 | "count" : 24,
57 | "type" : "VEC3"
58 | },
59 | {
60 | "bufferView" : 2,
61 | "componentType" : 5126,
62 | "count" : 24,
63 | "type" : "VEC2"
64 | },
65 | {
66 | "bufferView" : 3,
67 | "componentType" : 5123,
68 | "count" : 24,
69 | "type" : "SCALAR"
70 | }
71 | ],
72 | "bufferViews" : [
73 | {
74 | "buffer" : 0,
75 | "byteLength" : 288,
76 | "byteOffset" : 0
77 | },
78 | {
79 | "buffer" : 0,
80 | "byteLength" : 288,
81 | "byteOffset" : 288
82 | },
83 | {
84 | "buffer" : 0,
85 | "byteLength" : 192,
86 | "byteOffset" : 576
87 | },
88 | {
89 | "buffer" : 0,
90 | "byteLength" : 48,
91 | "byteOffset" : 768
92 | }
93 | ],
94 | "buffers" : [
95 | {
96 | "byteLength" : 816,
97 | "uri" : "data:application/octet-stream;base64,rxWUP1yiSj9zXcM9rxWUP1yiSj9zXcM9r9+eP7gafj5zXcM9KLYaP1oXdT+FXcM9upmHPyAeNT96XcM9upmHPyAeNT96XcM9rxWUv1yiSj9zXcM9rxWUv1yiSj9zXcM9r9+ev7gafj5zXcM9KLYav1oXdT+FXcM9upmHvyAeNT96XcM9upmHvyAeNT96XcM9rxWUP1yiSr9zXcM9rxWUP1yiSr9zXcM9r9+eP7gafr5zXcM9KLYaP1oXdb+FXcM9upmHPyAeNb96XcM9upmHPyAeNb96XcM9rxWUv1yiSr9zXcM9rxWUv1yiSr9zXcM9r9+ev7gafr5zXcM9KLYav1oXdb+FXcM9upmHvyAeNb96XcM9upmHvyAeNb96XcM9WTv9tCEmBbMAAIC/3cyqtPeiv7QAAIC/WTv9tCEmBbMAAIC/3cyqtPeiv7QAAIC/WTv9tCEmBbMAAIC/3cyqtPeiv7QAAIC/3cyqNPeiv7QAAIC/WTv9NCEmBbMAAIC/WTv9NCEmBbMAAIC/3cyqNPeiv7QAAIC/3cyqNPeiv7QAAIC/WTv9NCEmBbMAAIC/WTv9tCEmBTMAAIC/3cyqtPeivzQAAIC/WTv9tCEmBTMAAIC/3cyqtPeivzQAAIC/WTv9tCEmBTMAAIC/3cyqtPeivzQAAIC/3cyqNPeivzQAAIC/WTv9NCEmBTMAAIC/WTv9NCEmBTMAAIC/3cyqNPeivzQAAIC/3cyqNPeivzQAAIC/WTv9NCEmBTMAAIC/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/BQADAAEAAgAEAAAACgAGAAkACAAHAAsAEQANAA8ADgAMABAAFgAVABIAFAAXABMA"
98 | }
99 | ]
100 | }
101 |
--------------------------------------------------------------------------------
/data/crosshair2.gltf:
--------------------------------------------------------------------------------
1 | {
2 | "asset" : {
3 | "generator" : "Khronos glTF Blender I/O v1.8.19",
4 | "version" : "2.0"
5 | },
6 | "scene" : 0,
7 | "scenes" : [
8 | {
9 | "name" : "Scene",
10 | "nodes" : [
11 | 0
12 | ]
13 | }
14 | ],
15 | "nodes" : [
16 | {
17 | "mesh" : 0,
18 | "name" : "Crosshair"
19 | }
20 | ],
21 | "meshes" : [
22 | {
23 | "name" : "Plane",
24 | "primitives" : [
25 | {
26 | "attributes" : {
27 | "POSITION" : 0,
28 | "NORMAL" : 1,
29 | "TEXCOORD_0" : 2
30 | },
31 | "indices" : 3
32 | }
33 | ]
34 | }
35 | ],
36 | "accessors" : [
37 | {
38 | "bufferView" : 0,
39 | "componentType" : 5126,
40 | "count" : 24,
41 | "max" : [
42 | 1.3044021129608154,
43 | 0.8965469598770142,
44 | 2.3914719804452034e-07
45 | ],
46 | "min" : [
47 | -1.3044021129608154,
48 | -0.8965469598770142,
49 | 2.2876140093330832e-08
50 | ],
51 | "type" : "VEC3"
52 | },
53 | {
54 | "bufferView" : 1,
55 | "componentType" : 5126,
56 | "count" : 24,
57 | "type" : "VEC3"
58 | },
59 | {
60 | "bufferView" : 2,
61 | "componentType" : 5126,
62 | "count" : 24,
63 | "type" : "VEC2"
64 | },
65 | {
66 | "bufferView" : 3,
67 | "componentType" : 5123,
68 | "count" : 24,
69 | "type" : "SCALAR"
70 | }
71 | ],
72 | "bufferViews" : [
73 | {
74 | "buffer" : 0,
75 | "byteLength" : 288,
76 | "byteOffset" : 0
77 | },
78 | {
79 | "buffer" : 0,
80 | "byteLength" : 288,
81 | "byteOffset" : 288
82 | },
83 | {
84 | "buffer" : 0,
85 | "byteLength" : 192,
86 | "byteOffset" : 576
87 | },
88 | {
89 | "buffer" : 0,
90 | "byteLength" : 48,
91 | "byteOffset" : 768
92 | }
93 | ],
94 | "buffers" : [
95 | {
96 | "byteLength" : 816,
97 | "uri" : "data:application/octet-stream;base64,Lej0PuiDbD4qgcQy6uiQPyrDMj9mLxU06uiQPyrDMj9mLxU0pvamPxqEZT8kZIA0v9iHP5KDSD/MgjQ0v9iHP5KDSD/MgjQ0Lej0vuiDbD4qgcQy6uiQvyrDMj9mLxU06uiQvyrDMj9mLxU0pvamvxqEZT8kZIA0v9iHv5KDSD/MgjQ0v9iHv5KDSD/MgjQ0Lej0PuiDbL4qgcQy6uiQPyrDMr9mLxU06uiQPyrDMr9mLxU0pvamPxqEZb8kZIA0v9iHP5KDSL/MgjQ0v9iHP5KDSL/MgjQ0Lej0vuiDbL4qgcQy6uiQvyrDMr9mLxU06uiQvyrDMr9mLxU0pvamvxqEZb8kZIA0v9iHv5KDSL/MgjQ0v9iHv5KDSL/MgjQ0vMc2sw1NpTQAAIC/vMc2sw1NpTQAAIC/R3bMM8zv4jQAAIC/R3bMM8zv4jQAAIC/vMc2sw1NpTQAAIC/R3bMM8zv4jQAAIC/vMc2Mw1NpTQAAIC/R3bMs8zv4jQAAIC/vMc2Mw1NpTQAAIC/R3bMs8zv4jQAAIC/R3bMs8zv4jQAAIC/vMc2Mw1NpTQAAIC/vMc2sw1NpbQAAIC/vMc2sw1NpbQAAIC/R3bMM8zv4rQAAIC/R3bMM8zv4rQAAIC/vMc2sw1NpbQAAIC/R3bMM8zv4rQAAIC/vMc2Mw1NpbQAAIC/R3bMs8zv4rQAAIC/vMc2Mw1NpbQAAIC/R3bMs8zv4rQAAIC/R3bMs8zv4rQAAIC/vMc2Mw1NpbQAAIC/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AAAAAAAAgD8AAAAAAACAPwAAAAAAAIA/AgAFAAMAAAAEAAEABwAJAAoABgAIAAsADgAPABEADAANABAAEwAWABUAEgAXABQA"
98 | }
99 | ]
100 | }
101 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Ergo
2 | 
3 |
4 | Fly a little ship around in a raylib project. The main purpose of this project was to figure out how to handle arbitrary rotations, since the built in rotation functions don't make this easy.
5 |
6 | This *ended up* being another take on simple arcade space flight mechanics. Specifically, this is probably how I'd do a Rogue Squadron kind of game.
7 |
8 | I'm really happy with the space dust and trails too. They look really neat, but I needed some help from the raylib Discord to get the transparencies working correctly. Sometimes you need to force a render batch with `rlDrawRenderBatchActive()` when messing with transparencies and the depth buffer.
9 |
10 | The game can be controlled with either WASD/Arrow keys, or a gamepad.
11 |
12 | ## Rotations
13 | Check `Actor.cpp` and `Ship.cpp` for some silly looking and probably very ineffecient functions to rotate a quaternion representing the ship's rotation.
14 |
15 | Getting a forward (or any direction) vector from some actor is something that needs to be very commonly done. I'm pretty sure there's a smarter way to do this, but I get it by multiplying the forward vector by the ship's Rotation:
16 |
17 | ```cpp
18 | Vector3 Actor::GetForward() const
19 | {
20 | return Vector3RotateByQuaternion(
21 | Vector3{ 0, 0, 1 },
22 | Rotation);
23 | }
24 | ```
25 |
26 | Rotating an object in local space is another essential piece of code. In Unity this is a very simple [`Transform.Rotate(Vector3, Space.Self)`](https://docs.unity3d.com/ScriptReference/Transform.Rotate.html), but for raylib you have to write your own. This seemed to work.
27 |
28 | ```cpp
29 | void Actor::RotateLocalEuler(Vector3 axis, float degrees)
30 | {
31 | auto radians = degrees * DEG2RAD;
32 | Rotation = QuaternionMultiply(
33 | Rotation,
34 | QuaternionFromAxisAngle(axis, radians));
35 | }
36 | ```
37 |
38 | While not rotation specific, transforming a point from local space to world space is another essential function. In Unity this is just [`Transform.TransformPoint()`](https://docs.unity3d.com/ScriptReference/Transform.TransformPoint.html), but as far as I can tell raylib's `Transform` struct is very basic and used only by model rendering.
39 |
40 | ```cpp
41 | Vector3 Actor::TransformPoint(Vector3 point) const
42 | {
43 | auto mPos = MatrixTranslate(Position.x, Position.y, Position.z);
44 | auto mRot = QuaternionToMatrix(Rotation);
45 | auto matrix = MatrixMultiply(mRot, mPos);
46 | return Vector3Transform(point, matrix);
47 | }
48 | ```
49 |
50 | ## Smoothing and Ship Flight
51 | I've been asked about how this looks so smooth a lot, and it's [SmoothDamps all the way down](https://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/). I use the SmoothDamp function in *everything* I work on because it's an easy way to add smoothing in a way that isn't (usually) affected by framerate.
52 |
53 | ```cpp
54 | inline float SmoothDamp(float from, float to, float speed, float dt)
55 | {
56 | return Lerp(from, to, 1 - expf(-speed * dt));
57 | }
58 | ```
59 |
60 | In this specific implementation, smoothing is applied to the inputs the player gives, and the ship's own velocity. For rotations, the smoothing is applied only to the input, not to any kind of angular velocity.
61 |
62 | For example, here's the smoothing applied to the ship input.
63 | ```cpp
64 | // Give the ship some momentum when accelerating.
65 | SmoothForward = SmoothDamp(SmoothForward, InputForward, ThrottleResponse, deltaTime);
66 | SmoothLeft = SmoothDamp(SmoothLeft, InputLeft, ThrottleResponse, deltaTime);
67 | SmoothUp = SmoothDamp(SmoothUp, InputUp, ThrottleResponse, deltaTime);
68 | ```
69 |
70 | After the velocity the ship should have is figured out, smoothing is applied to move the current velocity to the target velocity.
71 | ```cpp
72 | Velocity = SmoothDamp(Velocity, targetVelocity, 2.5, deltaTime);
73 | Position = Vector3Add(Position, Vector3Scale(Velocity, deltaTime));
74 | ```
75 |
76 | ## Arbitrary Render Resolution
77 | 
78 |
79 | There's also some messy code in there for rendering the game at an arbitrary resolution and separate from the display resolution. This is something that always interests me because I have an unhealthy rose-tinted nostalgia for DOS games.
80 |
81 | This rendering mode can be used by uncommenting `#define RENDER_SMALL` at the top of the `Ergo.cpp`.
82 |
--------------------------------------------------------------------------------
/src/Ergo.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "Actor.h"
4 | #include "Ship.h"
5 | #include "SpaceDust.h"
6 | #include "GameCamera.h"
7 | #include "MathUtils.h"
8 |
9 | //#define RENDER_SMALL
10 |
11 | int g_ScreenWidth = 800;
12 | int g_ScreenHeight = 600;
13 |
14 | #ifdef RENDER_SMALL
15 | int g_RenderWidth = 400;
16 | int g_RenderHeight = 300;
17 | #endif // RENDER_SMALL
18 |
19 | void DrawStandardFPS()
20 | {
21 | BeginBlendMode(BlendMode::BLEND_ADDITIVE);
22 | DrawText(TextFormat("FPS %d", GetFPS()), 10, 10, 10, GREEN);
23 | EndBlendMode();
24 | }
25 |
26 | void ApplyInputToShip(Ship& ship)
27 | {
28 | ship.InputForward = 0;
29 | if (IsKeyDown(KEY_W)) ship.InputForward += 1;
30 | if (IsKeyDown(KEY_S)) ship.InputForward -= 1;
31 |
32 | ship.InputForward -= GetGamepadAxisMovement(0, GamepadAxis::GAMEPAD_AXIS_LEFT_Y);
33 | ship.InputForward = Clamp(ship.InputForward, -1, 1);
34 |
35 | ship.InputLeft = 0;
36 | if (IsKeyDown(KEY_D)) ship.InputLeft -= 1;
37 | if (IsKeyDown(KEY_A)) ship.InputLeft += 1;
38 |
39 | ship.InputLeft -= GetGamepadAxisMovement(0, GamepadAxis::GAMEPAD_AXIS_LEFT_X);
40 | ship.InputLeft = Clamp(ship.InputLeft, -1, 1);
41 |
42 | ship.InputUp = 0;
43 | if (IsKeyDown(KEY_SPACE)) ship.InputUp += 1;
44 | if (IsKeyDown(KEY_LEFT_CONTROL)) ship.InputUp -= 1;
45 |
46 | auto triggerRight = GetGamepadAxisMovement(0, GamepadAxis::GAMEPAD_AXIS_RIGHT_TRIGGER);
47 | triggerRight = Remap(triggerRight, -1, 1, 0, 1);
48 |
49 | auto triggerLeft = GetGamepadAxisMovement(0, GamepadAxis::GAMEPAD_AXIS_LEFT_TRIGGER);
50 | triggerLeft = Remap(triggerLeft, -1, 1, 0, 1);
51 |
52 | ship.InputUp += triggerRight;
53 | ship.InputUp -= triggerLeft;
54 | ship.InputUp = Clamp(ship.InputUp, -1, 1);
55 |
56 | ship.InputYawLeft = 0;
57 | if (IsKeyDown(KEY_RIGHT)) ship.InputYawLeft -= 1;
58 | if (IsKeyDown(KEY_LEFT)) ship.InputYawLeft += 1;
59 |
60 | ship.InputYawLeft -= GetGamepadAxisMovement(0, GamepadAxis::GAMEPAD_AXIS_RIGHT_X);
61 | ship.InputYawLeft = Clamp(ship.InputYawLeft, -1, 1);
62 |
63 | ship.InputPitchDown = 0;
64 | if (IsKeyDown(KEY_UP)) ship.InputPitchDown += 1;
65 | if (IsKeyDown(KEY_DOWN)) ship.InputPitchDown -= 1;
66 |
67 | ship.InputPitchDown += GetGamepadAxisMovement(0, GamepadAxis::GAMEPAD_AXIS_RIGHT_Y);
68 | ship.InputPitchDown = Clamp(ship.InputPitchDown, -1, 1);
69 |
70 | ship.InputRollRight = 0;
71 | if (IsKeyDown(KEY_Q)) ship.InputRollRight -= 1;
72 | if (IsKeyDown(KEY_E)) ship.InputRollRight += 1;
73 | }
74 |
75 | int main()
76 | {
77 | SetConfigFlags(ConfigFlags::FLAG_MSAA_4X_HINT | ConfigFlags::FLAG_VSYNC_HINT);
78 | InitWindow(g_ScreenWidth, g_ScreenHeight, "Ergo");
79 |
80 | #ifdef RENDER_SMALL
81 | // Set up low resolution rendering independent from the window resolution.
82 | auto renderRatio = (float)g_ScreenWidth / (float)g_RenderWidth;
83 | RenderTexture2D renderTarget = LoadRenderTexture(g_RenderWidth, g_RenderHeight);
84 | SetTextureFilter(renderTarget.texture, TextureFilter::TEXTURE_FILTER_POINT);
85 |
86 |
87 | // Target height is flipped (in the source rectangle) due to OpenGL reasons.
88 | Rectangle sourceRect = { 0, 0, (float)renderTarget.texture.width, -(float)renderTarget.texture.height };
89 | Rectangle destRect = { -renderRatio, -renderRatio, g_ScreenWidth + (renderRatio * 2), g_ScreenHeight + (renderRatio * 2) };
90 | Camera2D screenSpaceCamera = { 0 };
91 | screenSpaceCamera.zoom = 1.0f;
92 | #endif // RENDER_SMALL
93 |
94 | Ship player("data/ship.gltf", "data/a16.png", RAYWHITE);
95 | Ship other("data/ship.gltf", "data/a16.png", RAYWHITE);
96 | other.TrailColor = MAROON;
97 | other.Position = { 10, 2, 10 };
98 | SpaceDust dust = SpaceDust(25, 255);
99 |
100 | GameCamera cameraFlight = GameCamera(true, 50);
101 | GameCamera cameraHUD = GameCamera(false, 50);
102 | cameraHUD.SetPosition({ 0, 0, -10 }, { 0, 0, 0 }, { 0, 1, 0 });
103 |
104 | // Test station.
105 | Texture2D texture = LoadTexture("data/a16.png");
106 | texture.mipmaps = 0;
107 | SetTextureFilter(texture, TEXTURE_FILTER_POINT);
108 | Model stationModel = LoadModel("data/station.gltf");
109 | stationModel.materials[0].maps[MaterialMapIndex::MATERIAL_MAP_ALBEDO].texture = texture;
110 | stationModel.transform = MatrixTranslate(0, 5, 50);
111 |
112 | Crosshair crosshairNear = Crosshair("data/crosshair2.gltf");
113 | Crosshair crosshairFar = Crosshair("data/crosshair2.gltf");
114 |
115 | while (!WindowShouldClose())
116 | {
117 | auto deltaTime = GetFrameTime();
118 |
119 | // Capture input
120 | {
121 | ApplyInputToShip(player);
122 | ApplyInputToShip(other);
123 | }
124 |
125 | // Gameplay updates
126 | {
127 | player.Update(deltaTime);
128 | other.Update(deltaTime);
129 |
130 | crosshairNear.PositionCrosshairOnShip(player, 10);
131 | crosshairFar.PositionCrosshairOnShip(player, 30);
132 | }
133 |
134 | // Camera movement and visual effects
135 | {
136 | cameraFlight.FollowShip(player, deltaTime);
137 | dust.UpdateViewPosition(cameraFlight.GetPosition());
138 | }
139 |
140 | // Render
141 | #ifdef RENDER_SMALL
142 | BeginTextureMode(renderTarget);
143 | #else
144 | BeginDrawing();
145 | #endif
146 | {
147 | ClearBackground({32, 32, 64, 255});
148 |
149 | cameraFlight.Begin3DDrawing();
150 | {
151 | // Opaques
152 | {
153 | DrawGrid(10, 10);
154 |
155 | player.Draw(false);
156 | other.Draw(false);
157 |
158 | DrawModel(stationModel, Vector3Zero(), 1, WHITE);
159 | }
160 |
161 | // Transparencies
162 | {
163 | player.DrawTrail();
164 | other.DrawTrail();
165 |
166 | crosshairNear.DrawCrosshair();
167 | crosshairFar.DrawCrosshair();
168 |
169 | dust.Draw(cameraFlight.GetPosition(), player.Velocity, false);
170 | }
171 | }
172 | cameraFlight.EndDrawing();
173 |
174 | //cameraHUD.Begin3DDrawing();
175 | //{
176 | // // Test for drawing 3D geometry to an orthrographic "HUD".
177 | // DrawSphereWires({sinf(GetTime()) * 12}, 3, 8, 8, RED);
178 | //}
179 | //cameraHUD.EndDrawing();
180 |
181 | DrawStandardFPS();
182 | }
183 | #ifdef RENDER_SMALL
184 | EndTextureMode();
185 | #else
186 | EndDrawing();
187 | #endif
188 |
189 | #ifdef RENDER_SMALL
190 | // Draw the render texture target to the screen.
191 | BeginDrawing();
192 | {
193 | ClearBackground(RED);
194 |
195 | BeginMode2D(screenSpaceCamera);
196 | DrawTexturePro(renderTarget.texture, sourceRect, destRect, { 0, 0 }, 0, WHITE);
197 | EndMode2D();
198 | }
199 | EndDrawing();
200 | #endif // RENDER_SMALL
201 | }
202 |
203 | CloseWindow();
204 |
205 | return 0;
206 | }
207 |
--------------------------------------------------------------------------------
/src/Ship.cpp:
--------------------------------------------------------------------------------
1 | #include "Ship.h"
2 |
3 | #include "MathUtils.h"
4 |
5 | #include
6 | #include
7 |
8 | static const float RungDistance = 2.0f;
9 | static const float RungTimeToLive = 2.0f;
10 |
11 | Ship::Ship(const char* modelPath, const char* texturePath, Color color)
12 | {
13 | Texture2D texture = LoadTexture(texturePath);
14 | texture.mipmaps = 0;
15 | SetTextureFilter(texture, TEXTURE_FILTER_POINT);
16 |
17 | ShipModel = LoadModel(modelPath);
18 | ShipModel.materials[0].maps[MaterialMapIndex::MATERIAL_MAP_ALBEDO].texture = texture;
19 |
20 | Rotation = QuaternionFromEuler(1, 2, 0);
21 |
22 | ShipColor = color;
23 |
24 | LastRungPosition = Position;
25 | }
26 |
27 | Ship::~Ship()
28 | {
29 | UnloadModel(ShipModel);
30 | }
31 |
32 | void Ship::Update(float deltaTime)
33 | {
34 | // Give the ship some momentum when accelerating.
35 | SmoothForward = SmoothDamp(SmoothForward, InputForward, ThrottleResponse, deltaTime);
36 | SmoothLeft = SmoothDamp(SmoothLeft, InputLeft, ThrottleResponse, deltaTime);
37 | SmoothUp = SmoothDamp(SmoothUp, InputUp, ThrottleResponse, deltaTime);
38 |
39 | // Flying in reverse should be slower.
40 | auto forwardSpeedMultipilier = SmoothForward > 0.0f ? 1.0f : 0.33f;
41 |
42 | auto targetVelocity = Vector3Zero();
43 | targetVelocity = Vector3Add(
44 | targetVelocity,
45 | Vector3Scale(GetForward(), MaxSpeed * forwardSpeedMultipilier * SmoothForward));
46 | targetVelocity = Vector3Add(
47 | targetVelocity,
48 | Vector3Scale(GetUp(), MaxSpeed * .5f * SmoothUp));
49 | targetVelocity = Vector3Add(
50 | targetVelocity,
51 | Vector3Scale(GetLeft(), MaxSpeed * .5f * SmoothLeft));
52 |
53 | Velocity = SmoothDamp(Velocity, targetVelocity, 2.5, deltaTime);
54 | Position = Vector3Add(Position, Vector3Scale(Velocity, deltaTime));
55 |
56 | // Give the ship some inertia when turning. These are the pilot controlled rotations.
57 | SmoothPitchDown = SmoothDamp(SmoothPitchDown, InputPitchDown, TurnResponse, deltaTime);
58 | SmoothRollRight = SmoothDamp(SmoothRollRight, InputRollRight, TurnResponse, deltaTime);
59 | SmoothYawLeft = SmoothDamp(SmoothYawLeft, InputYawLeft, TurnResponse, deltaTime);
60 |
61 | RotateLocalEuler( { 0, 0, 1 }, SmoothRollRight * TurnRate * deltaTime);
62 | RotateLocalEuler({ 1, 0, 0 }, SmoothPitchDown * TurnRate * deltaTime);
63 | RotateLocalEuler({ 0, 1, 0 }, SmoothYawLeft * TurnRate * deltaTime);
64 |
65 | //// Auto-roll from yaw
66 | //// Movement like a 3D space sim. This only feels good if there's no horizon auto-align.
67 | //RotateLocalEuler({ 0, 0, -1 }, SmoothYawLeft * TurnRate * .5f * deltaTime);
68 |
69 | // Auto-roll to align to horizon
70 | if (fabs(GetForward().y) < 0.8)
71 | {
72 | float autoSteerInput = GetRight().y;
73 | RotateLocalEuler({ 0, 0, 1 }, autoSteerInput * TurnRate * .5f * deltaTime);
74 | }
75 |
76 | // When yawing and strafing, there's some bank added to the model for visual flavor.
77 | float targetVisualBank = (-30 * DEG2RAD * SmoothYawLeft) + (-15 * DEG2RAD * SmoothLeft);
78 | VisualBank = SmoothDamp(VisualBank, targetVisualBank, 10, deltaTime);
79 | Quaternion visualRotation = QuaternionMultiply(
80 | Rotation, QuaternionFromAxisAngle({ 0, 0, 1 }, VisualBank));
81 |
82 | // Sync up the raylib representation of the model with the ship's position so that processing
83 | // doesn't have to happen at the render stage.
84 | auto transform = MatrixTranslate(Position.x, Position.y, Position.z);
85 | transform = MatrixMultiply(QuaternionToMatrix(visualRotation), transform);
86 | ShipModel.transform = transform;
87 |
88 | // The currently active trail rung is dragged directly behind the ship for a smoother trail.
89 | PositionActiveTrailRung();
90 | if (Vector3Distance(Position, LastRungPosition) > RungDistance)
91 | {
92 | RungIndex = (RungIndex + 1) % RungCount;
93 | LastRungPosition = Position;
94 | }
95 |
96 | for (int i = 0; i < RungCount; ++i)
97 | Rungs[i].TimeToLive -= deltaTime;
98 | }
99 |
100 | void Ship::PositionActiveTrailRung()
101 | {
102 | Rungs[RungIndex].TimeToLive = RungTimeToLive;
103 | float halfWidth = Width / 2.f;
104 | float halfLength = Length / 2.f;
105 | Rungs[RungIndex].LeftPoint = TransformPoint({ -halfWidth, 0.0f, -halfLength });
106 | Rungs[RungIndex].RightPoint = TransformPoint({ halfWidth, 0.0f, -halfLength });
107 | }
108 |
109 | void Ship::Draw(bool showDebugAxes) const
110 | {
111 | DrawModel(ShipModel, Vector3Zero(), 1, ShipColor);
112 |
113 | if (showDebugAxes)
114 | {
115 | BeginBlendMode(BlendMode::BLEND_ADDITIVE);
116 | DrawLine3D(Position, Vector3Add(Position, GetForward()), { 0, 0, 255, 255 });
117 | DrawLine3D(Position, Vector3Add(Position, GetLeft()), { 255, 0, 0, 255 });
118 | DrawLine3D(Position, Vector3Add(Position, GetUp()), { 0, 255, 0, 255 });
119 | EndBlendMode();
120 | }
121 | }
122 |
123 | void Ship::DrawTrail() const
124 | {
125 | BeginBlendMode(BlendMode::BLEND_ADDITIVE);
126 | rlDisableDepthMask();
127 |
128 | for (int i = 0; i < RungCount; ++i)
129 | {
130 | if (Rungs[i].TimeToLive <= 0)
131 | continue;
132 |
133 | auto& thisRung = Rungs[i % RungCount];
134 |
135 | Color color = TrailColor;
136 | color.a = 255 * thisRung.TimeToLive / RungTimeToLive;
137 | Color fill = color;
138 | fill.a = color.a / 4;
139 |
140 | // The current rung is dragged along behind the ship, so the crossbar shouldn't be drawn.
141 | // If the crossbar is drawn when the ship is slow, it looks weird having a line behind it.
142 | if (i != RungIndex)
143 | DrawLine3D(thisRung.LeftPoint, thisRung.RightPoint, color);
144 |
145 | auto& nextRung = Rungs[(i + 1) % RungCount];
146 | if (nextRung.TimeToLive > 0 && thisRung.TimeToLive < nextRung.TimeToLive)
147 | {
148 | DrawLine3D(nextRung.LeftPoint, thisRung.LeftPoint, color);
149 | DrawLine3D(nextRung.RightPoint, thisRung.RightPoint, color);
150 |
151 | DrawTriangle3D(thisRung.LeftPoint, thisRung.RightPoint, nextRung.LeftPoint, fill);
152 | DrawTriangle3D(nextRung.LeftPoint, thisRung.RightPoint, nextRung.RightPoint, fill);
153 |
154 | DrawTriangle3D(nextRung.LeftPoint, thisRung.RightPoint, thisRung.LeftPoint, fill);
155 | DrawTriangle3D(nextRung.RightPoint, thisRung.RightPoint, nextRung.LeftPoint, fill);
156 | }
157 | }
158 |
159 | rlDrawRenderBatchActive();
160 | rlEnableDepthMask();
161 | EndBlendMode();
162 | }
163 |
164 | Crosshair::Crosshair(const char* modelPath)
165 | {
166 | CrosshairModel = LoadModel(modelPath);
167 | }
168 |
169 | Crosshair::~Crosshair()
170 | {
171 | UnloadModel(CrosshairModel);
172 | }
173 |
174 | void Crosshair::PositionCrosshairOnShip(const Ship& ship, float distance)
175 | {
176 | auto crosshairPos = Vector3Add(Vector3Scale(ship.GetForward(), distance), ship.Position);
177 | auto crosshairTransform = MatrixTranslate(crosshairPos.x, crosshairPos.y, crosshairPos.z);
178 | crosshairTransform = MatrixMultiply(QuaternionToMatrix(ship.Rotation), crosshairTransform);
179 | CrosshairModel.transform = crosshairTransform;
180 | }
181 |
182 | void Crosshair::DrawCrosshair() const
183 | {
184 | BeginBlendMode(BlendMode::BLEND_ADDITIVE);
185 | rlDisableDepthTest();
186 |
187 | DrawModel(CrosshairModel, Vector3Zero(), 1, DARKGREEN);
188 | //DrawModelWires(Model, Vector3Zero(), 1, DARKGREEN);
189 |
190 | rlEnableDepthTest();
191 | EndBlendMode();
192 | }
193 |
--------------------------------------------------------------------------------
/data/ship.gltf:
--------------------------------------------------------------------------------
1 | {
2 | "asset" : {
3 | "generator" : "Khronos glTF Blender I/O v1.8.19",
4 | "version" : "2.0"
5 | },
6 | "scene" : 0,
7 | "scenes" : [
8 | {
9 | "name" : "Scene",
10 | "nodes" : [
11 | 0
12 | ]
13 | }
14 | ],
15 | "nodes" : [
16 | {
17 | "mesh" : 0,
18 | "name" : "Ship"
19 | }
20 | ],
21 | "materials" : [
22 | {
23 | "doubleSided" : true,
24 | "name" : "Mat",
25 | "pbrMetallicRoughness" : {
26 | "baseColorTexture" : {
27 | "index" : 0
28 | },
29 | "metallicFactor" : 0,
30 | "roughnessFactor" : 0.5
31 | }
32 | }
33 | ],
34 | "meshes" : [
35 | {
36 | "name" : "Cube",
37 | "primitives" : [
38 | {
39 | "attributes" : {
40 | "POSITION" : 0,
41 | "NORMAL" : 1,
42 | "TEXCOORD_0" : 2
43 | },
44 | "indices" : 3,
45 | "material" : 0
46 | }
47 | ]
48 | }
49 | ],
50 | "textures" : [
51 | {
52 | "sampler" : 0,
53 | "source" : 0
54 | }
55 | ],
56 | "images" : [
57 | {
58 | "bufferView" : 4,
59 | "mimeType" : "image/png",
60 | "name" : "Image_0"
61 | }
62 | ],
63 | "accessors" : [
64 | {
65 | "bufferView" : 0,
66 | "componentType" : 5126,
67 | "count" : 108,
68 | "max" : [
69 | 0.4801882207393646,
70 | 0.11864282190799713,
71 | 0.76969313621521
72 | ],
73 | "min" : [
74 | -0.4801882207393646,
75 | -0.14245106279850006,
76 | -0.27048659324645996
77 | ],
78 | "type" : "VEC3"
79 | },
80 | {
81 | "bufferView" : 1,
82 | "componentType" : 5126,
83 | "count" : 108,
84 | "type" : "VEC3"
85 | },
86 | {
87 | "bufferView" : 2,
88 | "componentType" : 5126,
89 | "count" : 108,
90 | "type" : "VEC2"
91 | },
92 | {
93 | "bufferView" : 3,
94 | "componentType" : 5123,
95 | "count" : 108,
96 | "type" : "SCALAR"
97 | }
98 | ],
99 | "bufferViews" : [
100 | {
101 | "buffer" : 0,
102 | "byteLength" : 1296,
103 | "byteOffset" : 0
104 | },
105 | {
106 | "buffer" : 0,
107 | "byteLength" : 1296,
108 | "byteOffset" : 1296
109 | },
110 | {
111 | "buffer" : 0,
112 | "byteLength" : 864,
113 | "byteOffset" : 2592
114 | },
115 | {
116 | "buffer" : 0,
117 | "byteLength" : 216,
118 | "byteOffset" : 3456
119 | },
120 | {
121 | "buffer" : 0,
122 | "byteLength" : 147,
123 | "byteOffset" : 3672
124 | }
125 | ],
126 | "samplers" : [
127 | {
128 | "magFilter" : 9728,
129 | "minFilter" : 9984
130 | }
131 | ],
132 | "buffers" : [
133 | {
134 | "byteLength" : 3820,
135 | "uri" : "data:application/octet-stream;base64,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"
136 | }
137 | ]
138 | }
139 |
--------------------------------------------------------------------------------
/Ergo.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {26599881-5658-45ed-9275-096cfae1063c}
25 | Ergo
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v143
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v143
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v143
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | false
78 |
79 |
80 | true
81 |
82 |
83 | false
84 |
85 |
86 |
87 | Level3
88 | true
89 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
90 | true
91 |
92 |
93 | Console
94 | true
95 |
96 |
97 |
98 |
99 | Level3
100 | true
101 | true
102 | true
103 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
104 | true
105 |
106 |
107 | Console
108 | true
109 | true
110 | true
111 |
112 |
113 |
114 |
115 | Level3
116 | true
117 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
118 | true
119 | $(SolutionDir)include
120 | stdcpp20
121 |
122 |
123 | Console
124 | true
125 |
126 |
127 |
128 |
129 | Level3
130 | true
131 | true
132 | true
133 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
134 | true
135 | $(SolutionDir)include
136 | stdcpp20
137 |
138 |
139 | Console
140 | true
141 | true
142 | true
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 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/data/station.gltf:
--------------------------------------------------------------------------------
1 | {
2 | "asset" : {
3 | "generator" : "Khronos glTF Blender I/O v1.8.19",
4 | "version" : "2.0"
5 | },
6 | "scene" : 0,
7 | "scenes" : [
8 | {
9 | "name" : "Scene",
10 | "nodes" : [
11 | 0
12 | ]
13 | }
14 | ],
15 | "nodes" : [
16 | {
17 | "mesh" : 0,
18 | "name" : "Station"
19 | }
20 | ],
21 | "materials" : [
22 | {
23 | "doubleSided" : true,
24 | "name" : "Mat",
25 | "pbrMetallicRoughness" : {
26 | "baseColorTexture" : {
27 | "index" : 0
28 | },
29 | "metallicFactor" : 0,
30 | "roughnessFactor" : 0.5
31 | }
32 | }
33 | ],
34 | "meshes" : [
35 | {
36 | "name" : "Cube.001",
37 | "primitives" : [
38 | {
39 | "attributes" : {
40 | "POSITION" : 0,
41 | "NORMAL" : 1,
42 | "TEXCOORD_0" : 2
43 | },
44 | "indices" : 3,
45 | "material" : 0
46 | }
47 | ]
48 | }
49 | ],
50 | "textures" : [
51 | {
52 | "sampler" : 0,
53 | "source" : 0
54 | }
55 | ],
56 | "images" : [
57 | {
58 | "bufferView" : 4,
59 | "mimeType" : "image/png",
60 | "name" : "Image_0"
61 | }
62 | ],
63 | "accessors" : [
64 | {
65 | "bufferView" : 0,
66 | "componentType" : 5126,
67 | "count" : 254,
68 | "max" : [
69 | 15.12708854675293,
70 | 2.145261764526367,
71 | 11.004926681518555
72 | ],
73 | "min" : [
74 | -15.12708854675293,
75 | -2.945413589477539,
76 | -7.182535648345947
77 | ],
78 | "type" : "VEC3"
79 | },
80 | {
81 | "bufferView" : 1,
82 | "componentType" : 5126,
83 | "count" : 254,
84 | "type" : "VEC3"
85 | },
86 | {
87 | "bufferView" : 2,
88 | "componentType" : 5126,
89 | "count" : 254,
90 | "type" : "VEC2"
91 | },
92 | {
93 | "bufferView" : 3,
94 | "componentType" : 5123,
95 | "count" : 402,
96 | "type" : "SCALAR"
97 | }
98 | ],
99 | "bufferViews" : [
100 | {
101 | "buffer" : 0,
102 | "byteLength" : 3048,
103 | "byteOffset" : 0
104 | },
105 | {
106 | "buffer" : 0,
107 | "byteLength" : 3048,
108 | "byteOffset" : 3048
109 | },
110 | {
111 | "buffer" : 0,
112 | "byteLength" : 2032,
113 | "byteOffset" : 6096
114 | },
115 | {
116 | "buffer" : 0,
117 | "byteLength" : 804,
118 | "byteOffset" : 8128
119 | },
120 | {
121 | "buffer" : 0,
122 | "byteLength" : 147,
123 | "byteOffset" : 8932
124 | }
125 | ],
126 | "samplers" : [
127 | {
128 | "magFilter" : 9728,
129 | "minFilter" : 9984
130 | }
131 | ],
132 | "buffers" : [
133 | {
134 | "byteLength" : 9080,
135 | "uri" : "data:application/octet-stream;base64,aqVhwRYaAz8KYEU/aqVhwRYaAz8KYEU/aqVhwRYaAz8KYEU/aqVhwWv4p78KYEU/aqVhwWv4p78KYEU/aqVhwWv4p78KYEU/aqVhwRYaAz++GiZAaqVhwRYaAz++GiZAaqVhwRYaAz++GiZAaqVhwWv4p7++GiZAaqVhwWv4p7++GiZAaqVhwWv4p7++GiZAjghywaiBPMAYUIdAjghywaiBPMAYUIdAjghywaiBPMAYUIdAjghywaiBPMAYUIdAjghywfhLCUAYUIdAjghywfhLCUAYUIdAjghywfhLCUAYUIdAjghywfhLCUAYUIdAjghywaiBPMDAtVy/jghywaiBPMDAtVy/jghywaiBPMDAtVy/jghywfhLCUDAtVy/jghywfhLCUDAtVy/jghywfhLCUDAtVy/JpUgwaiBPMAYUIdAJpUgwaiBPMAYUIdAJpUgwaiBPMAYUIdAJpUgwaiBPMAYUIdAJpUgwfhLCUAYUIdAJpUgwfhLCUAYUIdAJpUgwfhLCUAYUIdAJpUgwfhLCUAYUIdAJpUgwaiBPMDAtVy/JpUgwaiBPMDAtVy/JpUgwaiBPMDAtVy/JpUgwaiBPMDAtVy/JpUgwfhLCUDAtVy/JpUgwfhLCUDAtVy/JpUgwfhLCUDAtVy/JpUgwfhLCUDAtVy/AghRwPhLCUDAtVy/AghRwPhLCUDAtVy/AghRwPhLCUDAtVy/AghRwKiBPMDAtVy/AghRwKiBPMDAtVy/AghRwKiBPMDAtVy/AghRwPhLCUAYUIdAAghRwPhLCUAYUIdAAghRwPhLCUAYUIdAAghRwPhLCUAYUIdAAghRwKiBPMAYUIdAAghRwKiBPMAYUIdAAghRwKiBPMAYUIdAAghRwKiBPMAYUIdAaLUFwfhLCUDAtVy/aLUFwfhLCUDAtVy/aLUFwfhLCUDAtVy/aLUFwfhLCUDAtVy/aLUFwaiBPMDAtVy/aLUFwaiBPMDAtVy/aLUFwaiBPMDAtVy/aLUFwaiBPMDAtVy/aLUFwfhLCUAYUIdAaLUFwfhLCUAYUIdAaLUFwfhLCUAYUIdAaLUFwfhLCUAYUIdAaLUFwaiBPMAYUIdAaLUFwaiBPMAYUIdAaLUFwaiBPMAYUIdAaLUFwaiBPMAYUIdAAAAAAGv4p7++GiZAAAAAAGv4p7++GiZAAAAAAGv4p7++GiZAAAAAABYaAz++GiZAAAAAABYaAz++GiZAAAAAABYaAz++GiZAAAAAAGv4p78KYEU/AAAAAGv4p78KYEU/AAAAAGv4p78KYEU/AAAAABYaAz8KYEU/AAAAABYaAz8KYEU/AAAAABYaAz8KYEU/jghywWIocD9V1+XAjghywWIocD9V1+XAjghywWIocD9V1+XAjghywZF/3r9V1+XAjghywZF/3r9V1+XAjghywZF/3r9V1+XAJpUgwZF/3r9V1+XAJpUgwZF/3r9V1+XAJpUgwZF/3r9V1+XAJpUgwWIocD9V1+XAJpUgwWIocD9V1+XAJpUgwWIocD9V1+XAAghRwGIocD9V1+XAAghRwGIocD9V1+XAAghRwGIocD9V1+XAAghRwJF/3r9V1+XAAghRwJF/3r9V1+XAAghRwJF/3r9V1+XAaLUFwWIocD9V1+XAaLUFwWIocD9V1+XAaLUFwWIocD9V1+XAaLUFwZF/3r9V1+XAaLUFwZF/3r9V1+XAaLUFwZF/3r9V1+XAjghywc/e2b8uFDBBjghywc/e2b8uFDBBjghywc/e2b8uFDBBjghywd7mZj8uFDBBjghywd7mZj8uFDBBjghywd7mZj8uFDBBJpUgwd7mZj8uFDBBJpUgwd7mZj8uFDBBJpUgwd7mZj8uFDBBJpUgwc/e2b8uFDBBJpUgwc/e2b8uFDBBJpUgwc/e2b8uFDBBAghRwN7mZj8uFDBBAghRwN7mZj8uFDBBAghRwN7mZj8uFDBBaLUFwd7mZj8uFDBBaLUFwd7mZj8uFDBBaLUFwd7mZj8uFDBBaLUFwc/e2b8uFDBBaLUFwc/e2b8uFDBBaLUFwc/e2b8uFDBBAghRwM/e2b8uFDBBAghRwM/e2b8uFDBBAghRwM/e2b8uFDBBaqVhQRYaAz8KYEU/aqVhQRYaAz8KYEU/aqVhQRYaAz8KYEU/aqVhQWv4p78KYEU/aqVhQWv4p78KYEU/aqVhQWv4p78KYEU/aqVhQRYaAz++GiZAaqVhQRYaAz++GiZAaqVhQRYaAz++GiZAaqVhQWv4p7++GiZAaqVhQWv4p7++GiZAaqVhQWv4p7++GiZAjghyQaiBPMAYUIdAjghyQaiBPMAYUIdAjghyQaiBPMAYUIdAjghyQaiBPMAYUIdAjghyQfhLCUAYUIdAjghyQfhLCUAYUIdAjghyQfhLCUAYUIdAjghyQfhLCUAYUIdAjghyQaiBPMDAtVy/jghyQaiBPMDAtVy/jghyQaiBPMDAtVy/jghyQfhLCUDAtVy/jghyQfhLCUDAtVy/jghyQfhLCUDAtVy/JpUgQaiBPMAYUIdAJpUgQaiBPMAYUIdAJpUgQaiBPMAYUIdAJpUgQaiBPMAYUIdAJpUgQfhLCUAYUIdAJpUgQfhLCUAYUIdAJpUgQfhLCUAYUIdAJpUgQfhLCUAYUIdAJpUgQaiBPMDAtVy/JpUgQaiBPMDAtVy/JpUgQaiBPMDAtVy/JpUgQaiBPMDAtVy/JpUgQfhLCUDAtVy/JpUgQfhLCUDAtVy/JpUgQfhLCUDAtVy/JpUgQfhLCUDAtVy/AghRQPhLCUDAtVy/AghRQPhLCUDAtVy/AghRQPhLCUDAtVy/AghRQPhLCUDAtVy/AghRQKiBPMDAtVy/AghRQKiBPMDAtVy/AghRQKiBPMDAtVy/AghRQKiBPMDAtVy/AghRQPhLCUAYUIdAAghRQPhLCUAYUIdAAghRQPhLCUAYUIdAAghRQPhLCUAYUIdAAghRQKiBPMAYUIdAAghRQKiBPMAYUIdAAghRQKiBPMAYUIdAAghRQKiBPMAYUIdAaLUFQfhLCUDAtVy/aLUFQfhLCUDAtVy/aLUFQfhLCUDAtVy/aLUFQfhLCUDAtVy/aLUFQaiBPMDAtVy/aLUFQaiBPMDAtVy/aLUFQaiBPMDAtVy/aLUFQaiBPMDAtVy/aLUFQfhLCUAYUIdAaLUFQfhLCUAYUIdAaLUFQfhLCUAYUIdAaLUFQfhLCUAYUIdAaLUFQaiBPMAYUIdAaLUFQaiBPMAYUIdAaLUFQaiBPMAYUIdAaLUFQaiBPMAYUIdAjghyQWIocD9V1+XAjghyQWIocD9V1+XAjghyQWIocD9V1+XAjghyQZF/3r9V1+XAjghyQZF/3r9V1+XAjghyQZF/3r9V1+XAJpUgQZF/3r9V1+XAJpUgQZF/3r9V1+XAJpUgQZF/3r9V1+XAJpUgQWIocD9V1+XAJpUgQWIocD9V1+XAJpUgQWIocD9V1+XAAghRQGIocD9V1+XAAghRQGIocD9V1+XAAghRQGIocD9V1+XAAghRQJF/3r9V1+XAAghRQJF/3r9V1+XAAghRQJF/3r9V1+XAaLUFQWIocD9V1+XAaLUFQWIocD9V1+XAaLUFQWIocD9V1+XAaLUFQZF/3r9V1+XAaLUFQZF/3r9V1+XAaLUFQZF/3r9V1+XAjghyQc/e2b8uFDBBjghyQc/e2b8uFDBBjghyQc/e2b8uFDBBjghyQd7mZj8uFDBBjghyQd7mZj8uFDBBjghyQd7mZj8uFDBBJpUgQd7mZj8uFDBBJpUgQd7mZj8uFDBBJpUgQd7mZj8uFDBBJpUgQc/e2b8uFDBBJpUgQc/e2b8uFDBBJpUgQc/e2b8uFDBBAghRQN7mZj8uFDBBAghRQN7mZj8uFDBBAghRQN7mZj8uFDBBaLUFQd7mZj8uFDBBaLUFQd7mZj8uFDBBaLUFQd7mZj8uFDBBaLUFQc/e2b8uFDBBaLUFQc/e2b8uFDBBaLUFQc/e2b8uFDBBAghRQM/e2b8uFDBBAghRQM/e2b8uFDBBAghRQM/e2b8uFDBBAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAACAvwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIC/AACAvwAAAAAAAACAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAACAAACAvwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAvwAAAAAAAACA//9/vwAAAAB8Gx20AAAAAAAAgL8AAACAAAAAAATMe79Cyzg+AACAvwAAAAAAAACA//9/vwAAAAB8Gx20AAAAAATMez9Cyzg+AAAAAAAAgD8AAACAAACAvwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAG10e7+OGkC+AACAvwAAAAAAAACAAAAAAG10ez+OGkC+AAAAAAAAgD8AAACAAAAAAAAAgL8AAACAAAAAAATMe79Cyzg+//9/PwAAAAB8G52zAACAPwAAAAAAAACAAAAAAATMez9Cyzg+AAAAAAAAgD8AAACA//9/PwAAAAB8G52zAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAG10e7+OGkC+AACAPwAAAADW36azAACAPwAAAAAAAACAAAAAAG10ez+OGkC+AAAAAAAAgD8AAACAAACAPwAAAADW36azAACAPwAAAAAAAACAAAAAAG10ez+PGkC+AAAAAP//fz8AAACAAACAPwAAAAAAAACAAAAAAP//f78AAACAAAAAAG10e7+PGkC+AACAPwAAAAAAAACAAAAAAAPMez9Eyzg+AAAAAP//fz8AAACA//9/PwAAAAB8Gx0zAACAPwAAAAAAAACAAAAAAP//f78AAACAAAAAAAPMe79Eyzg+//9/PwAAAAB8Gx0zAACAPwAAAAAAAACAAACAvwAAAADW36azAACAvwAAAAAAAACAAAAAAG10ez+PGkC+AAAAAP//fz8AAACAAACAvwAAAADW36azAACAvwAAAAAAAACAAAAAAP//f78AAACAAAAAAG10e7+PGkC+AACAvwAAAAAAAACA//9/vwAAAAB8G50zAAAAAAPMez9Eyzg+AAAAAP//fz8AAACAAACAvwAAAAAAAACA//9/vwAAAAB8G50zAAAAAP//f78AAACAAAAAAAPMe79Eyzg+AAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAPwAAAAAAAACAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAG10ez+OGkC+AACAvwAAAAAAAACAAAAAAG10e7+OGkC+AAAAAAAAAAAAAIC/AAAAAG10e7+OGkC+AAAAAAAAAAAAAIC/AACAPwAAAADW36azAAAAAAAAAAAAAIC/AAAAAG10ez+OGkC+AACAPwAAAADW36azAAAAAAAAAAAAAIC/AAAAAG10ez+PGkC+AACAPwAAAAAAAACAAAAAAG10e7+PGkC+AAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAACAvwAAAADW36azAAAAAAAAAAAAAIC/AAAAAG10ez+PGkC+AACAvwAAAADW36azAAAAAG10e7+PGkC+AAAAAAAAAAAAAIC///9/vwAAAAB8Gx20AAAAAATMe79Cyzg+AAAAAAAAAAAAAIA///9/vwAAAAB8Gx20AAAAAAAAAAAAAIA/AAAAAATMez9Cyzg+AAAAAAAAAAAAAIA/AAAAAATMez9Cyzg+//9/PwAAAAB8G52zAAAAAATMe79Cyzg+AAAAAAAAAAAAAIA///9/PwAAAAB8G52zAAAAAAAAAAAAAIA/AAAAAAPMez9Eyzg+//9/PwAAAAB8Gx0z//9/vwAAAAB8G50zAAAAAAAAAAAAAIA/AAAAAAPMez9Eyzg+//9/vwAAAAB8G50zAAAAAAPMe79Eyzg+AAAAAAAAAAAAAIA/AAAAAAPMe79Eyzg+AAAAAAAAAAAAAIA///9/PwAAAAB8Gx0zAAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAATMe79Cyzg+//9/PwAAAAB8G52zAACAPwAAAAAAAACAAAAAAATMez9Cyzg+AAAAAAAAgD8AAACA//9/PwAAAAB8G52zAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAG10e7+OGkC+AACAPwAAAAAAAACAAAAAAG10ez+OGkC+AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAACAvwAAAAAAAACA//9/vwAAAAB8Gx2zAAAAAAAAgL8AAACAAAAAAATMe79Cyzg+AACAvwAAAAAAAACA//9/vwAAAAB8Gx2zAAAAAATMez9Cyzg+AAAAAAAAgD8AAACAAACAvwAAAADW36azAACAvwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAG10e7+OGkC+AACAvwAAAADW36azAACAvwAAAAAAAACAAAAAAG10ez+OGkC+AAAAAAAAgD8AAACAAACAvwAAAADW3yayAACAvwAAAAAAAACAAAAAAG10ez+PGkC+AAAAAP//fz8AAACAAACAvwAAAADW3yayAACAvwAAAAAAAACAAAAAAP//f78AAACAAAAAAG10e7+PGkC+AACAvwAAAAAAAACA//9/vwAAAAB8Gx0zAAAAAAPMez9Eyzg+AAAAAP//fz8AAACAAACAvwAAAAAAAACA//9/vwAAAAB8Gx0zAAAAAP//f78AAACAAAAAAAPMe79Eyzg+AAAAAG10ez+PGkC+AAAAAP//fz8AAACAAACAPwAAAADW36azAACAPwAAAAAAAACAAAAAAP//f78AAACAAAAAAG10e7+PGkC+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EorAPsNTwz4e2a0+NGfkPgAA0D3DU8M+EorAPgQATgBIAAQASAAKAEkASwAHAEkABwALAFAAUwBNAFAATQBKAAUAAQBRAAUAUQBPAAkABgAAAAkAAAADAAwAEAAXAAwAFwAUABQAFwBUABQAVABXACUAKQAhACUAIQAdADAAQgB9ADAAfQB5ABUAIgAaABUAGgAOACcAGQATACcAEwAfACsAOwBDACsAQwAxAD4ALQA0AD4ANABGADYAMgB6ADYAegCDAC8ALAAzAC8AMwA3ABgAJgBeABgAXgBWAEQAQAA5AEQAOQA9AFIAAgAIAFIACABMAFkAVQBdAFkAXQBbAGsAZwBgAGsAYABkAC4APwBqAC4AagBjACwALwBlACwAZQBiACgAJABcACgAXABfACMAFgBYACMAWABaADwAOABmADwAZgBpADoAKgBhADoAYQBoAHYAcgBwAHYAcABuAIIAeAB8AIIAfACAABEADQBsABEAbABvAA8AGwB1AA8AdQBtAEcANQCBAEcAgQB/AEEARQB+AEEAfgB7AB4AEgBxAB4AcQBzABwAIAB0ABwAdAB3AIcAjQBIAIcASABOAEkAjgCKAEkAigBLAIgATwBRAIgAUQCEAI8AiQCGAI8AhgCMAJMAmgCdAJMAnQCXAJoA0wDQAJoA0ACdAKcAngCiAKcAogCrALgA9AD2ALgA9gDGAJgAkACgAJgAoACoAK0ApQCVAK0AlQCcALEAuQDHALEAxwC/AMIAygC8AMIAvAC0ALsA+wDyALsA8gC3ALMAugC2ALMAtgCvAJsAzwDZAJsA2QCsAM0AxQDBAM0AwQDJAFIATACLAFIAiwCFANIA1gDYANIA2ADOAOQA3wDbAOQA2wDgALUA3gDjALUA4wDDAK4A2gDdAK4A3QCyAKoA1wDUAKoA1ACmAKkA1QDRAKkA0QCZAMQA5QDiAMQA4gDAAL4A4QDcAL4A3ACwAPEA5wDpAPEA6QDtAP0A+QD1AP0A9QDzAJYA6wDoAJYA6ACSAJEA5gDwAJEA8AChAMsA+AD8AMsA/AC9AMgA9wD6AMgA+gDMAKQA7gDqAKQA6gCUAJ8A7wDsAJ8A7ACjAIlQTkcNChoKAAAADUlIRFIAAAAEAAAABAgGAAAAqfGefgAAAAFzUkdCAK7OHOkAAABNSURBVAiZY2RgYPhvaDWRQfrXEoZUET0GFo+QEAY9RkEGGcZvDJf0cxhYLHRUGC6IrGMI/+/BcEiHjYFFRtuSwVr2BMN5lisMcVKfGQA5WBF3NdL7TgAAAABJRU5ErkJgggA="
136 | }
137 | ]
138 | }
139 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ##### Windows
2 | # Windows thumbnail cache files
3 | Thumbs.db
4 | Thumbs.db:encryptable
5 | ehthumbs.db
6 | ehthumbs_vista.db
7 |
8 | # Dump file
9 | *.stackdump
10 |
11 | # Folder config file
12 | [Dd]esktop.ini
13 |
14 | # Recycle Bin used on file shares
15 | $RECYCLE.BIN/
16 |
17 | # Windows Installer files
18 | *.cab
19 | *.msi
20 | *.msix
21 | *.msm
22 | *.msp
23 |
24 | # Windows shortcuts
25 | *.lnk
26 |
27 | ##### Linux
28 | *~
29 |
30 | # temporary files which can be created if a process still has a handle open of a deleted file
31 | .fuse_hidden*
32 |
33 | # KDE directory preferences
34 | .directory
35 |
36 | # Linux trash folder which might appear on any partition or disk
37 | .Trash-*
38 |
39 | # .nfs files are created when an open file is removed but is still being accessed
40 | .nfs*
41 |
42 | ##### MacOS
43 | # General
44 | .DS_Store
45 | .AppleDouble
46 | .LSOverride
47 |
48 | # Thumbnails
49 | ._*
50 |
51 | # Files that might appear in the root of a volume
52 | .DocumentRevisions-V100
53 | .fseventsd
54 | .Spotlight-V100
55 | .TemporaryItems
56 | .Trashes
57 | .VolumeIcon.icns
58 | .com.apple.timemachine.donotpresent
59 |
60 | # Directories potentially created on remote AFP share
61 | .AppleDB
62 | .AppleDesktop
63 | Network Trash Folder
64 | Temporary Items
65 | .apdisk
66 |
67 | ##### Android
68 | # Built application files
69 | *.apk
70 | *.ap_
71 | *.aab
72 |
73 | # Files for the ART/Dalvik VM
74 | *.dex
75 |
76 | # Java class files
77 | *.class
78 |
79 | # Generated files
80 | bin/
81 | gen/
82 | out/
83 | # Uncomment the following line in case you need and you don't have the release build type files in your app
84 | # release/
85 |
86 | # Gradle files
87 | .gradle/
88 | build/
89 |
90 | # Local configuration file (sdk path, etc)
91 | local.properties
92 |
93 | # Proguard folder generated by Eclipse
94 | proguard/
95 |
96 | # Log Files
97 | *.log
98 |
99 | # Android Studio Navigation editor temp files
100 | .navigation/
101 |
102 | # Android Studio captures folder
103 | captures/
104 |
105 | # IntelliJ
106 | *.iml
107 | .idea/workspace.xml
108 | .idea/tasks.xml
109 | .idea/gradle.xml
110 | .idea/assetWizardSettings.xml
111 | .idea/dictionaries
112 | .idea/libraries
113 | # Android Studio 3 in .gitignore file.
114 | .idea/caches
115 | .idea/modules.xml
116 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
117 | .idea/navEditor.xml
118 |
119 | # Keystore files
120 | # Uncomment the following lines if you do not want to check your keystore files in.
121 | #*.jks
122 | #*.keystore
123 |
124 | # External native build folder generated in Android Studio 2.2 and later
125 | .externalNativeBuild
126 |
127 | # Google Services (e.g. APIs or Firebase)
128 | # google-services.json
129 |
130 | # Freeline
131 | freeline.py
132 | freeline/
133 | freeline_project_description.json
134 |
135 | # fastlane
136 | fastlane/report.xml
137 | fastlane/Preview.html
138 | fastlane/screenshots
139 | fastlane/test_output
140 | fastlane/readme.md
141 |
142 | # Version control
143 | vcs.xml
144 |
145 | # lint
146 | lint/intermediates/
147 | lint/generated/
148 | lint/outputs/
149 | lint/tmp/
150 | # lint/reports/
151 |
152 | ##### Backup
153 | *.bak
154 | *.gho
155 | *.ori
156 | *.orig
157 | *.tmp
158 |
159 | ##### GPG
160 | secring.*
161 |
162 | ##### Dropbox
163 | # Dropbox settings and caches
164 | .dropbox
165 | .dropbox.attr
166 | .dropbox.cache
167 |
168 | ##### SynopsysVCS
169 | # Waveform formats
170 | *.vcd
171 | *.vpd
172 | *.evcd
173 | *.fsdb
174 |
175 | # Default name of the simulation executable. A different name can be
176 | # specified with this switch (the associated daidir database name is
177 | # also taken from here): -o /
178 | simv
179 |
180 | # Generated for Verilog and VHDL top configs
181 | simv.daidir/
182 | simv.db.dir/
183 |
184 | # Infrastructure necessary to co-simulate SystemC models with
185 | # Verilog/VHDL models. An alternate directory may be specified with this
186 | # switch: -Mdir=
187 | csrc/
188 |
189 | # Log file - the following switch allows to specify the file that will be
190 | # used to write all messages from simulation: -l
191 | *.log
192 |
193 | # Coverage results (generated with urg) and database location. The
194 | # following switch can also be used: urg -dir .vdb
195 | simv.vdb/
196 | urgReport/
197 |
198 | # DVE and UCLI related files.
199 | DVEfiles/
200 | ucli.key
201 |
202 | # When the design is elaborated for DirectC, the following file is created
203 | # with declarations for C/C++ functions.
204 | vc_hdrs.h
205 |
206 | ##### SVN
207 | .svn/
208 |
209 | ##### Mercurial
210 | .hg/
211 | .hgignore
212 | .hgsigs
213 | .hgsub
214 | .hgsubstate
215 | .hgtags
216 |
217 | ##### Bazaar
218 | .bzr/
219 | .bzrignore
220 |
221 | ##### CVS
222 | /CVS/*
223 | **/CVS/*
224 | .cvsignore
225 | */.cvsignore
226 |
227 | ##### TortoiseGit
228 | # Project-level settings
229 | /.tgitconfig
230 |
231 | ##### PuTTY
232 | # Private key
233 | *.ppk
234 |
235 | ##### Vim
236 | # Swap
237 | [._]*.s[a-v][a-z]
238 | !*.svg # comment out if you don't need vector files
239 | [._]*.sw[a-p]
240 | [._]s[a-rt-v][a-z]
241 | [._]ss[a-gi-z]
242 | [._]sw[a-p]
243 |
244 | # Session
245 | Session.vim
246 | Sessionx.vim
247 |
248 | # Temporary
249 | .netrwhist
250 | *~
251 | # Auto-generated tag files
252 | tags
253 | # Persistent undo
254 | [._]*.un~
255 |
256 | ##### Emacs
257 | # -*- mode: gitignore; -*-
258 | *~
259 | \#*\#
260 | /.emacs.desktop
261 | /.emacs.desktop.lock
262 | *.elc
263 | auto-save-list
264 | tramp
265 | .\#*
266 |
267 | # Org-mode
268 | .org-id-locations
269 | *_archive
270 |
271 | # flymake-mode
272 | *_flymake.*
273 |
274 | # eshell files
275 | /eshell/history
276 | /eshell/lastdir
277 |
278 | # elpa packages
279 | /elpa/
280 |
281 | # reftex files
282 | *.rel
283 |
284 | # AUCTeX auto folder
285 | /auto/
286 |
287 | # cask packages
288 | .cask/
289 | dist/
290 |
291 | # Flycheck
292 | flycheck_*.el
293 |
294 | # server auth directory
295 | /server/
296 |
297 | # projectiles files
298 | .projectile
299 |
300 | # directory configuration
301 | .dir-locals.el
302 |
303 | # network security
304 | /network-security.data
305 |
306 | ##### SublimeText
307 | # Cache files for Sublime Text
308 | *.tmlanguage.cache
309 | *.tmPreferences.cache
310 | *.stTheme.cache
311 |
312 | # Workspace files are user-specific
313 | *.sublime-workspace
314 |
315 | # Project files should be checked into the repository, unless a significant
316 | # proportion of contributors will probably not be using Sublime Text
317 | # *.sublime-project
318 |
319 | # SFTP configuration file
320 | sftp-config.json
321 | sftp-config-alt*.json
322 |
323 | # Package control specific files
324 | Package Control.last-run
325 | Package Control.ca-list
326 | Package Control.ca-bundle
327 | Package Control.system-ca-bundle
328 | Package Control.cache/
329 | Package Control.ca-certs/
330 | Package Control.merged-ca-bundle
331 | Package Control.user-ca-bundle
332 | oscrypto-ca-bundle.crt
333 | bh_unicode_properties.cache
334 |
335 | # Sublime-github package stores a github token in this file
336 | # https://packagecontrol.io/packages/sublime-github
337 | GitHub.sublime-settings
338 |
339 | ##### Notepad++
340 | # Notepad++ backups #
341 | *.bak
342 |
343 | ##### TextMate
344 | *.tmproj
345 | *.tmproject
346 | tmtags
347 |
348 | ##### VisualStudioCode
349 | .vscode/*
350 | !.vscode/settings.json
351 | !.vscode/tasks.json
352 | !.vscode/launch.json
353 | !.vscode/extensions.json
354 | *.code-workspace
355 |
356 | # Local History for Visual Studio Code
357 | .history/
358 |
359 | ##### NetBeans
360 | **/nbproject/private/
361 | **/nbproject/Makefile-*.mk
362 | **/nbproject/Package-*.bash
363 | build/
364 | nbbuild/
365 | dist/
366 | nbdist/
367 | .nb-gradle/
368 |
369 | ##### JetBrains
370 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
371 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
372 |
373 | # User-specific stuff
374 | .idea/**/workspace.xml
375 | .idea/**/tasks.xml
376 | .idea/**/usage.statistics.xml
377 | .idea/**/dictionaries
378 | .idea/**/shelf
379 |
380 | # Generated files
381 | .idea/**/contentModel.xml
382 |
383 | # Sensitive or high-churn files
384 | .idea/**/dataSources/
385 | .idea/**/dataSources.ids
386 | .idea/**/dataSources.local.xml
387 | .idea/**/sqlDataSources.xml
388 | .idea/**/dynamic.xml
389 | .idea/**/uiDesigner.xml
390 | .idea/**/dbnavigator.xml
391 |
392 | # Gradle
393 | .idea/**/gradle.xml
394 | .idea/**/libraries
395 |
396 | # Gradle and Maven with auto-import
397 | # When using Gradle or Maven with auto-import, you should exclude module files,
398 | # since they will be recreated, and may cause churn. Uncomment if using
399 | # auto-import.
400 | # .idea/artifacts
401 | # .idea/compiler.xml
402 | # .idea/jarRepositories.xml
403 | # .idea/modules.xml
404 | # .idea/*.iml
405 | # .idea/modules
406 | # *.iml
407 | # *.ipr
408 |
409 | # CMake
410 | cmake-build-*/
411 |
412 | # Mongo Explorer plugin
413 | .idea/**/mongoSettings.xml
414 |
415 | # File-based project format
416 | *.iws
417 |
418 | # IntelliJ
419 | out/
420 |
421 | # mpeltonen/sbt-idea plugin
422 | .idea_modules/
423 |
424 | # JIRA plugin
425 | atlassian-ide-plugin.xml
426 |
427 | # Cursive Clojure plugin
428 | .idea/replstate.xml
429 |
430 | # Crashlytics plugin (for Android Studio and IntelliJ)
431 | com_crashlytics_export_strings.xml
432 | crashlytics.properties
433 | crashlytics-build.properties
434 | fabric.properties
435 |
436 | # Editor-based Rest Client
437 | .idea/httpRequests
438 |
439 | # Android studio 3.1+ serialized cache file
440 | .idea/caches/build_file_checksums.ser
441 |
442 | ##### Eclipse
443 | .metadata
444 | bin/
445 | tmp/
446 | *.tmp
447 | *.bak
448 | *.swp
449 | *~.nib
450 | local.properties
451 | .settings/
452 | .loadpath
453 | .recommenders
454 |
455 | # External tool builders
456 | .externalToolBuilders/
457 |
458 | # Locally stored "Eclipse launch configurations"
459 | *.launch
460 |
461 | # PyDev specific (Python IDE for Eclipse)
462 | *.pydevproject
463 |
464 | # CDT-specific (C/C++ Development Tooling)
465 | .cproject
466 |
467 | # CDT- autotools
468 | .autotools
469 |
470 | # Java annotation processor (APT)
471 | .factorypath
472 |
473 | # PDT-specific (PHP Development Tools)
474 | .buildpath
475 |
476 | # sbteclipse plugin
477 | .target
478 |
479 | # Tern plugin
480 | .tern-project
481 |
482 | # TeXlipse plugin
483 | .texlipse
484 |
485 | # STS (Spring Tool Suite)
486 | .springBeans
487 |
488 | # Code Recommenders
489 | .recommenders/
490 |
491 | # Annotation Processing
492 | .apt_generated/
493 | .apt_generated_test/
494 |
495 | # Scala IDE specific (Scala & Java development for Eclipse)
496 | .cache-main
497 | .scala_dependencies
498 | .worksheet
499 |
500 | # Uncomment this line if you wish to ignore the project description file.
501 | # Typically, this file would be tracked if it contains build/dependency configurations:
502 | #.project
503 |
504 | ##### Qt
505 | # C++ objects and libs
506 | *.slo
507 | *.lo
508 | *.o
509 | *.a
510 | *.la
511 | *.lai
512 | *.so
513 | *.so.*
514 | *.dll
515 | *.dylib
516 |
517 | # Qt-es
518 | object_script.*.Release
519 | object_script.*.Debug
520 | *_plugin_import.cpp
521 | /.qmake.cache
522 | /.qmake.stash
523 | *.pro.user
524 | *.pro.user.*
525 | *.qbs.user
526 | *.qbs.user.*
527 | *.moc
528 | moc_*.cpp
529 | moc_*.h
530 | qrc_*.cpp
531 | ui_*.h
532 | *.qmlc
533 | *.jsc
534 | Makefile*
535 | *build-*
536 | *.qm
537 | *.prl
538 |
539 | # Qt unit tests
540 | target_wrapper.*
541 |
542 | # QtCreator
543 | *.autosave
544 |
545 | # QtCreator Qml
546 | *.qmlproject.user
547 | *.qmlproject.user.*
548 |
549 | # QtCreator CMake
550 | CMakeLists.txt.user*
551 |
552 | # QtCreator 4.8< compilation database
553 | compile_commands.json
554 |
555 | # QtCreator local machine specific files for imported projects
556 | *creator.user*
557 |
558 | ##### VisualStudio
559 | ##### VisualStudio
560 | ## Ignore Visual Studio temporary files, build results, and
561 | ## files generated by popular Visual Studio add-ons.
562 | ##
563 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
564 |
565 | # User-specific files
566 | *.rsuser
567 | *.suo
568 | *.user
569 | *.userosscache
570 | *.sln.docstates
571 |
572 | # User-specific files (MonoDevelop/Xamarin Studio)
573 | *.userprefs
574 |
575 | # Mono auto generated files
576 | mono_crash.*
577 |
578 | # Build results
579 | [Dd]ebug/
580 | [Dd]ebugPublic/
581 | [Rr]elease/
582 | [Rr]eleases/
583 | x64/
584 | x86/
585 | [Ww][Ii][Nn]32/
586 | [Aa][Rr][Mm]/
587 | [Aa][Rr][Mm]64/
588 | bld/
589 | [Bb]in/
590 | [Oo]bj/
591 | [Ll]og/
592 | [Ll]ogs/
593 |
594 | # Visual Studio 2015/2017 cache/options directory
595 | .vs/
596 | # Uncomment if you have tasks that create the project's static files in wwwroot
597 | #wwwroot/
598 |
599 | # Visual Studio 2017 auto generated files
600 | Generated\ Files/
601 |
602 | # MSTest test Results
603 | [Tt]est[Rr]esult*/
604 | [Bb]uild[Ll]og.*
605 |
606 | # NUnit
607 | *.VisualState.xml
608 | TestResult.xml
609 | nunit-*.xml
610 |
611 | # Build Results of an ATL Project
612 | [Dd]ebugPS/
613 | [Rr]eleasePS/
614 | dlldata.c
615 |
616 | # Benchmark Results
617 | BenchmarkDotNet.Artifacts/
618 |
619 | # .NET Core
620 | project.lock.json
621 | project.fragment.lock.json
622 | artifacts/
623 |
624 | # ASP.NET Scaffolding
625 | ScaffoldingReadMe.txt
626 |
627 | # StyleCop
628 | StyleCopReport.xml
629 |
630 | # Files built by Visual Studio
631 | *_i.c
632 | *_p.c
633 | *_h.h
634 | *.ilk
635 | *.meta
636 | *.obj
637 | *.iobj
638 | *.pch
639 | *.pdb
640 | *.ipdb
641 | *.pgc
642 | *.pgd
643 | *.rsp
644 | *.sbr
645 | *.tlb
646 | *.tli
647 | *.tlh
648 | *.tmp
649 | *.tmp_proj
650 | *_wpftmp.csproj
651 | *.log
652 | *.vspscc
653 | *.vssscc
654 | .builds
655 | *.pidb
656 | *.svclog
657 | *.scc
658 |
659 | # Chutzpah Test files
660 | _Chutzpah*
661 |
662 | # Visual C++ cache files
663 | ipch/
664 | *.aps
665 | *.ncb
666 | *.opendb
667 | *.opensdf
668 | *.sdf
669 | *.cachefile
670 | *.VC.db
671 | *.VC.VC.opendb
672 |
673 | # Visual Studio profiler
674 | *.psess
675 | *.vsp
676 | *.vspx
677 | *.sap
678 |
679 | # Visual Studio Trace Files
680 | *.e2e
681 |
682 | # TFS 2012 Local Workspace
683 | $tf/
684 |
685 | # Guidance Automation Toolkit
686 | *.gpState
687 |
688 | # ReSharper is a .NET coding add-in
689 | _ReSharper*/
690 | *.[Rr]e[Ss]harper
691 | *.DotSettings.user
692 |
693 | # TeamCity is a build add-in
694 | _TeamCity*
695 |
696 | # DotCover is a Code Coverage Tool
697 | *.dotCover
698 |
699 | # AxoCover is a Code Coverage Tool
700 | .axoCover/*
701 | !.axoCover/settings.json
702 |
703 | # Coverlet is a free, cross platform Code Coverage Tool
704 | coverage*[.json, .xml, .info]
705 |
706 | # Visual Studio code coverage results
707 | *.coverage
708 | *.coveragexml
709 |
710 | # NCrunch
711 | _NCrunch_*
712 | .*crunch*.local.xml
713 | nCrunchTemp_*
714 |
715 | # MightyMoose
716 | *.mm.*
717 | AutoTest.Net/
718 |
719 | # Web workbench (sass)
720 | .sass-cache/
721 |
722 | # Installshield output folder
723 | [Ee]xpress/
724 |
725 | # DocProject is a documentation generator add-in
726 | DocProject/buildhelp/
727 | DocProject/Help/*.HxT
728 | DocProject/Help/*.HxC
729 | DocProject/Help/*.hhc
730 | DocProject/Help/*.hhk
731 | DocProject/Help/*.hhp
732 | DocProject/Help/Html2
733 | DocProject/Help/html
734 |
735 | # Click-Once directory
736 | publish/
737 |
738 | # Publish Web Output
739 | *.[Pp]ublish.xml
740 | *.azurePubxml
741 | # Note: Comment the next line if you want to checkin your web deploy settings,
742 | # but database connection strings (with potential passwords) will be unencrypted
743 | *.pubxml
744 | *.publishproj
745 |
746 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
747 | # checkin your Azure Web App publish settings, but sensitive information contained
748 | # in these scripts will be unencrypted
749 | PublishScripts/
750 |
751 | # NuGet Packages
752 | *.nupkg
753 | # NuGet Symbol Packages
754 | *.snupkg
755 | # The packages folder can be ignored because of Package Restore
756 | **/[Pp]ackages/*
757 | # except build/, which is used as an MSBuild target.
758 | !**/[Pp]ackages/build/
759 | # Uncomment if necessary however generally it will be regenerated when needed
760 | #!**/[Pp]ackages/repositories.config
761 | # NuGet v3's project.json files produces more ignorable files
762 | *.nuget.props
763 | *.nuget.targets
764 |
765 | # Microsoft Azure Build Output
766 | csx/
767 | *.build.csdef
768 |
769 | # Microsoft Azure Emulator
770 | ecf/
771 | rcf/
772 |
773 | # Windows Store app package directories and files
774 | AppPackages/
775 | BundleArtifacts/
776 | Package.StoreAssociation.xml
777 | _pkginfo.txt
778 | *.appx
779 | *.appxbundle
780 | *.appxupload
781 |
782 | # Visual Studio cache files
783 | # files ending in .cache can be ignored
784 | *.[Cc]ache
785 | # but keep track of directories ending in .cache
786 | !?*.[Cc]ache/
787 |
788 | # Others
789 | ClientBin/
790 | ~$*
791 | *~
792 | *.dbmdl
793 | *.dbproj.schemaview
794 | *.jfm
795 | *.pfx
796 | *.publishsettings
797 | orleans.codegen.cs
798 |
799 | # Including strong name files can present a security risk
800 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
801 | #*.snk
802 |
803 | # Since there are multiple workflows, uncomment next line to ignore bower_components
804 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
805 | #bower_components/
806 |
807 | # RIA/Silverlight projects
808 | Generated_Code/
809 |
810 | # Backup & report files from converting an old project file
811 | # to a newer Visual Studio version. Backup files are not needed,
812 | # because we have git ;-)
813 | _UpgradeReport_Files/
814 | Backup*/
815 | UpgradeLog*.XML
816 | UpgradeLog*.htm
817 | ServiceFabricBackup/
818 | *.rptproj.bak
819 |
820 | # SQL Server files
821 | *.mdf
822 | *.ldf
823 | *.ndf
824 |
825 | # Business Intelligence projects
826 | *.rdl.data
827 | *.bim.layout
828 | *.bim_*.settings
829 | *.rptproj.rsuser
830 | *- [Bb]ackup.rdl
831 | *- [Bb]ackup ([0-9]).rdl
832 | *- [Bb]ackup ([0-9][0-9]).rdl
833 |
834 | # Microsoft Fakes
835 | FakesAssemblies/
836 |
837 | # GhostDoc plugin setting file
838 | *.GhostDoc.xml
839 |
840 | # Node.js Tools for Visual Studio
841 | .ntvs_analysis.dat
842 | node_modules/
843 |
844 | # Visual Studio 6 build log
845 | *.plg
846 |
847 | # Visual Studio 6 workspace options file
848 | *.opt
849 |
850 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
851 | *.vbw
852 |
853 | # Visual Studio LightSwitch build output
854 | **/*.HTMLClient/GeneratedArtifacts
855 | **/*.DesktopClient/GeneratedArtifacts
856 | **/*.DesktopClient/ModelManifest.xml
857 | **/*.Server/GeneratedArtifacts
858 | **/*.Server/ModelManifest.xml
859 | _Pvt_Extensions
860 |
861 | # Paket dependency manager
862 | .paket/paket.exe
863 | paket-files/
864 |
865 | # FAKE - F# Make
866 | .fake/
867 |
868 | # CodeRush personal settings
869 | .cr/personal
870 |
871 | # Python Tools for Visual Studio (PTVS)
872 | __pycache__/
873 | *.pyc
874 |
875 | # Cake - Uncomment if you are using it
876 | # tools/**
877 | # !tools/packages.config
878 |
879 | # Tabs Studio
880 | *.tss
881 |
882 | # Telerik's JustMock configuration file
883 | *.jmconfig
884 |
885 | # BizTalk build output
886 | *.btp.cs
887 | *.btm.cs
888 | *.odx.cs
889 | *.xsd.cs
890 |
891 | # OpenCover UI analysis results
892 | OpenCover/
893 |
894 | # Azure Stream Analytics local run output
895 | ASALocalRun/
896 |
897 | # MSBuild Binary and Structured Log
898 | *.binlog
899 |
900 | # NVidia Nsight GPU debugger configuration file
901 | *.nvuser
902 |
903 | # MFractors (Xamarin productivity tool) working folder
904 | .mfractor/
905 |
906 | # Local History for Visual Studio
907 | .localhistory/
908 |
909 | # BeatPulse healthcheck temp database
910 | healthchecksdb
911 |
912 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
913 | MigrationBackup/
914 |
915 | # Ionide (cross platform F# VS Code tools) working folder
916 | .ionide/
917 |
918 | # Fody - auto-generated XML schema
919 | FodyWeavers.xsd
920 |
921 | ##### Gradle
922 | .gradle
923 | **/build/
924 | !src/**/build/
925 |
926 | # Ignore Gradle GUI config
927 | gradle-app.setting
928 |
929 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
930 | !gradle-wrapper.jar
931 |
932 | # Cache of project
933 | .gradletasknamecache
934 |
935 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
936 | # gradle/wrapper/gradle-wrapper.properties
937 |
938 | ##### CMake
939 | CMakeLists.txt.user
940 | CMakeCache.txt
941 | CMakeFiles
942 | CMakeScripts
943 | Testing
944 | Makefile
945 | cmake_install.cmake
946 | install_manifest.txt
947 | compile_commands.json
948 | CTestTestfile.cmake
949 | _deps
950 |
951 | ##### C++
952 | # Prerequisites
953 | *.d
954 |
955 | # Compiled Object files
956 | *.slo
957 | *.lo
958 | *.o
959 | *.obj
960 |
961 | # Precompiled Headers
962 | *.gch
963 | *.pch
964 |
965 | # Compiled Dynamic libraries
966 | *.so
967 | *.dylib
968 | *.dll
969 |
970 | # Fortran module files
971 | *.mod
972 | *.smod
973 |
974 | # Compiled Static libraries
975 | *.lai
976 | *.la
977 | *.a
978 | *.lib
979 |
980 | # Executables
981 | *.exe
982 | *.out
983 | *.app
984 |
985 | # C/C++ binary extension file
986 | *.bin
987 |
988 | ##### C
989 | # Prerequisites
990 | *.d
991 |
992 | # Object files
993 | *.o
994 | *.ko
995 | *.obj
996 | *.elf
997 |
998 | # Linker output
999 | *.ilk
1000 | *.map
1001 | *.exp
1002 |
1003 | # Precompiled Headers
1004 | *.gch
1005 | *.pch
1006 |
1007 | # Libraries
1008 | *.lib
1009 | *.a
1010 | *.la
1011 | *.lo
1012 |
1013 | # Shared objects (inc. Windows DLLs)
1014 | *.dll
1015 | *.so
1016 | *.so.*
1017 | *.dylib
1018 |
1019 | # Executables
1020 | *.exe
1021 | *.out
1022 | *.app
1023 | *.i*86
1024 | *.x86_64
1025 | *.hex
1026 |
1027 | # Debug files
1028 | *.dSYM/
1029 | *.su
1030 | *.idb
1031 | *.pdb
1032 |
1033 | # Kernel Module Compile Results
1034 | *.mod*
1035 | *.cmd
1036 | .tmp_versions/
1037 | modules.order
1038 | Module.symvers
1039 | Mkfile.old
1040 | dkms.conf
1041 |
1042 | # Raspberry Pi Pico Object file
1043 | *.uf2
1044 | # Raspberry Pi Pico disassembler file
1045 | *.dis
1046 |
--------------------------------------------------------------------------------