summaryrefslogtreecommitdiff
path: root/game/network/rail.cpp
blob: ecec0c0bf333c6cac3f7ac8dac35e58736e081b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "rail.h"
#include "game/network/link.h"
#include <GL/glew.h>
#include <array>
#include <cache.h>
#include <cmath>
#include <gfx/gl/shader.h>
#include <gfx/models/texture.h>
#include <gfx/models/vertex.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtx/transform.hpp>
#include <numbers>
#include <utility>

RailLinks::RailLinks() : texture {Texture::cachedTexture.get("rails.jpg")} { }
void RailLinks::tick(TickDuration) { }

static const auto identityModel {glm::identity<glm::mat4>()};

void
RailLinks::render(const Shader & shader) const
{
	shader.setModel(identityModel);
	texture->Bind();
	links.apply(&RailLink::render, shader);
}

template<RailLinkConcept T>
std::shared_ptr<T>
RailLinks::addLink(glm::vec3 a, glm::vec3 b)
{
	const auto node1 = *nodes.insert(std::make_shared<Node>(a)).first;
	const auto node2 = *nodes.insert(std::make_shared<Node>(b)).first;
	// TODO set end flag properly
	return links.create<T>(Link::End {node1, true}, Link::End {node2, true});
}

template std::shared_ptr<RailLinkStraight> RailLinks::addLink(glm::vec3, glm::vec3);
void
RailLink::render(const Shader &) const
{
	meshes.apply(&Mesh::Draw);
}

constexpr const std::array<std::pair<glm::vec3, float>, 4> railCrossSection {{
		//   ___________
		// _/           \_
		//  left to right
		{{-1.F, 0.F, 0.F}, 0.F},
		{{-.75F, .25F, 0.F}, 0.125F},
		{{.75F, .25F, 0.F}, 0.875F},
		{{1.F, 0.F, 0.F}, 1.F},
}};
constexpr const glm::vec3 up {0, 1, 0};
constexpr const glm::vec3 north {0, 0, 1};
const auto oneeighty {glm::rotate(std::numbers::pi_v<float>, up)};

template<typename V>
auto
flat_orientation(const V & diff)
{
	const auto flatdiff {glm::normalize(glm::vec3 {diff.x, 0, diff.z})};
	auto e {glm::orientation(flatdiff, north)};
	// Handle if diff is exactly opposite to north
	return (std::isnan(e[0][0])) ? oneeighty : e;
}

RailLinkStraight::RailLinkStraight(End a, End b) : RailLink(std::move(a), std::move(b))
{
	vertices.reserve(2 * railCrossSection.size());
	indices.reserve(2 * railCrossSection.size());
	const auto diff {ends[1].first->pos - ends[0].first->pos};
	const auto len = glm::length(diff) / 2.F;
	const auto e {flat_orientation(diff)};
	for (int ei = 0; ei < 2; ei++) {
		const auto trans {glm::translate(ends[ei].first->pos) * e};
		for (const auto & rcs : railCrossSection) {
			const glm::vec3 m {(trans * glm::vec4 {rcs.first, 1})};
			vertices.emplace_back(m, glm::vec2 {rcs.second, ei ? len : 0.F}, up);
			if (vertices.size() > railCrossSection.size()) {
				indices.push_back(vertices.size() - railCrossSection.size() - 1);
				indices.push_back(vertices.size() - 1);
			}
		}
	}
	meshes.create<Mesh>(vertices, indices, GL_TRIANGLE_STRIP);
}