nice
This commit is contained in:
16
imgui.ini
Normal file
16
imgui.ini
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[Window][Debug##Default]
|
||||||
|
Pos=20,60
|
||||||
|
Size=400,400
|
||||||
|
|
||||||
|
[Window][Dear ImGui Demo]
|
||||||
|
Pos=1116,220
|
||||||
|
Size=927,695
|
||||||
|
|
||||||
|
[Window][Dear ImGui Debug Log]
|
||||||
|
Pos=60,60
|
||||||
|
Size=670,354
|
||||||
|
|
||||||
|
[Window][Example: Console]
|
||||||
|
Pos=958,210
|
||||||
|
Size=520,600
|
||||||
|
|
||||||
183
include/td/Maths.h
Normal file
183
include/td/Maths.h
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
static constexpr float PI = 3.141592653f;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Vec2 {
|
||||||
|
union {
|
||||||
|
T x;
|
||||||
|
T r;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
T y;
|
||||||
|
T g;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Vec2(T X = 0, T Y = 0) : x(X), y(Y) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool operator==(const Vec2<T>& vec2, const Vec2<T>& other) {
|
||||||
|
return vec2.x == other.x && vec2.y == other.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Vec3 {
|
||||||
|
union {
|
||||||
|
T x;
|
||||||
|
T r;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
T y;
|
||||||
|
T g;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
T z;
|
||||||
|
T b;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Vec3(T X = 0, T Y = 0, T Z = 0) : x(X), y(Y), z(Z) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool operator==(const Vec3<T>& vec3, const Vec3<T>& other) {
|
||||||
|
return vec3.x == other.x && vec3.y == other.y && vec3.z == other.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Vec4 {
|
||||||
|
union {
|
||||||
|
T x;
|
||||||
|
T r;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
T y;
|
||||||
|
T g;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
T z;
|
||||||
|
T b;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
T w;
|
||||||
|
T a;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Vec4(Vec3<T> vec, T W = 1) : x(vec.x), y(vec.y), z(vec.z), w(W) {}
|
||||||
|
constexpr Vec4(T X = 0, T Y = 0, T Z = 0, T W = 0) : x(X), y(Y), z(Z), w(W) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool operator==(const Vec4<T>& vec4, const Vec4<T>& other) {
|
||||||
|
return vec4.x == other.x && vec4.y == other.y && vec4.z == other.z && vec4.w = other.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
using Vec2i = Vec2<int>;
|
||||||
|
using Vec2u = Vec2<unsigned int>;
|
||||||
|
using Vec2f = Vec2<float>;
|
||||||
|
using Vec2d = Vec2<double>;
|
||||||
|
|
||||||
|
using Vec3i = Vec3<int>;
|
||||||
|
using Vec3u = Vec3<unsigned int>;
|
||||||
|
using Vec3f = Vec3<float>;
|
||||||
|
using Vec3d = Vec3<double>;
|
||||||
|
|
||||||
|
using Vec4i = Vec4<int>;
|
||||||
|
using Vec4u = Vec4<unsigned int>;
|
||||||
|
using Vec4f = Vec4<float>;
|
||||||
|
using Vec4d = Vec4<double>;
|
||||||
|
|
||||||
|
using Color = Vec3<unsigned char>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Mat4 {
|
||||||
|
static const std::size_t MATRIX_SIZE = 4;
|
||||||
|
|
||||||
|
T x0, x1, x2, x3;
|
||||||
|
T y0, y1, y2, y3;
|
||||||
|
T z0, z1, z2, z3;
|
||||||
|
T w0, w1, w2, w3;
|
||||||
|
|
||||||
|
T operator[](std::size_t offset) const {
|
||||||
|
return reinterpret_cast<const T*>(this)[offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator[](std::size_t offset) {
|
||||||
|
return reinterpret_cast<T*>(this)[offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
T* data() {
|
||||||
|
return reinterpret_cast<T*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* data() const {
|
||||||
|
return reinterpret_cast<const T*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
T at(std::size_t row, std::size_t column) const {
|
||||||
|
return operator[](row * MATRIX_SIZE + column);
|
||||||
|
}
|
||||||
|
|
||||||
|
T& at(std::size_t row, std::size_t column) {
|
||||||
|
return operator[](row * MATRIX_SIZE + column);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Mat4<float> Mat4f;
|
||||||
|
typedef Mat4<int> Mat4i;
|
||||||
|
typedef Mat4<double> Mat4d;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool operator==(const Mat4<T>& mat, const Mat4<T>& other) {
|
||||||
|
return mat.x0 == other.x0 && mat.y0 == other.y0 && mat.z0 == other.z0 && mat.w0 == other.w0 && mat.x1 == other.x1 &&
|
||||||
|
mat.y1 == other.y1 && mat.z1 == other.z1 && mat.w1 == other.w1 && mat.x2 == other.x2 && mat.y2 == other.y2 &&
|
||||||
|
mat.z2 == other.z2 && mat.w2 == other.w2 && mat.x3 == other.x3 && mat.y3 == other.y3 && mat.z3 == other.z3 &&
|
||||||
|
mat.w3 == other.w3;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace maths {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Mat4<T> Transpose(const Mat4<T>& mat) {
|
||||||
|
Mat4<T> result;
|
||||||
|
|
||||||
|
result.x1 = mat.y0;
|
||||||
|
result.x2 = mat.z0;
|
||||||
|
result.x3 = mat.w0;
|
||||||
|
result.y0 = mat.x1;
|
||||||
|
result.y2 = mat.z1;
|
||||||
|
result.y3 = mat.w1;
|
||||||
|
result.z0 = mat.x2;
|
||||||
|
result.z1 = mat.y2;
|
||||||
|
result.z3 = mat.w2;
|
||||||
|
result.w0 = mat.x3;
|
||||||
|
result.w1 = mat.y3;
|
||||||
|
result.w2 = mat.z3;
|
||||||
|
result.x0 = mat.x0;
|
||||||
|
result.y1 = mat.y1;
|
||||||
|
result.z2 = mat.z2;
|
||||||
|
result.w3 = mat.w3;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat4f Perspective(float fovY, float aspectRatio, float zNear, float zFar);
|
||||||
|
Mat4f Look(const Vec3f& eye, const Vec3f& center, const Vec3f& up);
|
||||||
|
|
||||||
|
Mat4f Inverse(const Mat4f& mat);
|
||||||
|
|
||||||
|
} // namespace maths
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace td
|
||||||
@@ -7,8 +7,9 @@ namespace td {
|
|||||||
|
|
||||||
using FpFloat = fpm::fixed_16_16;
|
using FpFloat = fpm::fixed_16_16;
|
||||||
|
|
||||||
enum class Team : std::uint8_t {
|
enum class TeamColor : std::int8_t {
|
||||||
Blue = 0,
|
None = -1,
|
||||||
|
Blue,
|
||||||
Red,
|
Red,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -67,4 +68,11 @@ struct EntityCoords {
|
|||||||
|
|
||||||
using PeerID = std::uint16_t;
|
using PeerID = std::uint16_t;
|
||||||
|
|
||||||
|
enum class Direction : std::uint8_t {
|
||||||
|
PositiveX = 1 << 0,
|
||||||
|
NegativeX = 1 << 1,
|
||||||
|
PositiveY = 1 << 2,
|
||||||
|
NegativeY = 1 << 3,
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|||||||
@@ -1,300 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \file DataBuffer.h
|
|
||||||
* \brief File containing the td::DataBuffer class
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstring>
|
|
||||||
#include <string>
|
|
||||||
#include <td/common/VarInt.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace td {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \class DataBuffer
|
|
||||||
* \brief Class used to manipulate memory
|
|
||||||
*/
|
|
||||||
class DataBuffer {
|
|
||||||
private:
|
|
||||||
typedef std::vector<std::uint8_t> Data;
|
|
||||||
Data m_Buffer;
|
|
||||||
std::size_t m_ReadOffset;
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef Data::iterator iterator;
|
|
||||||
typedef Data::const_iterator const_iterator;
|
|
||||||
typedef Data::reference reference;
|
|
||||||
typedef Data::const_reference const_reference;
|
|
||||||
typedef Data::difference_type difference_type;
|
|
||||||
|
|
||||||
DataBuffer();
|
|
||||||
DataBuffer(const DataBuffer& other);
|
|
||||||
DataBuffer(const DataBuffer& other, difference_type offset);
|
|
||||||
DataBuffer(DataBuffer&& other);
|
|
||||||
DataBuffer(const std::string& str);
|
|
||||||
|
|
||||||
DataBuffer& operator=(const DataBuffer& other);
|
|
||||||
DataBuffer& operator=(DataBuffer&& other);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Append data to the buffer
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
void Append(const T& data) {
|
|
||||||
std::size_t size = sizeof(data);
|
|
||||||
std::size_t end_pos = m_Buffer.size();
|
|
||||||
m_Buffer.resize(m_Buffer.size() + size);
|
|
||||||
std::memcpy(&m_Buffer[end_pos], &data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Append data to the buffer
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
DataBuffer& operator<<(const T& data) {
|
|
||||||
Append(data);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Append a string to the buffer
|
|
||||||
* \warning Don't use it for binary data !
|
|
||||||
* \param str The string to append
|
|
||||||
*/
|
|
||||||
DataBuffer& operator<<(const std::string& str);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Append data to the buffer from another const buffer
|
|
||||||
* \param data The buffer to append
|
|
||||||
*/
|
|
||||||
DataBuffer& operator<<(const DataBuffer& data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Append a vector to the buffer by first writing the size
|
|
||||||
* \param data The vector to append
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
DataBuffer& operator<<(const std::vector<T>& data) {
|
|
||||||
*this << VarInt{data.size()};
|
|
||||||
for (const auto& element : data) {
|
|
||||||
*this << element;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Append an array to the buffer by first writing the size
|
|
||||||
* \param data The buffer to append
|
|
||||||
*/
|
|
||||||
template <typename T, std::size_t Size>
|
|
||||||
DataBuffer& operator<<(const std::array<T, Size>& data) {
|
|
||||||
for (const auto& element : data) {
|
|
||||||
*this << element;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Read some data from the buffer and assign to desired variable
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
DataBuffer& operator>>(T& data) {
|
|
||||||
assert(m_ReadOffset + sizeof(T) <= GetSize());
|
|
||||||
data = *(reinterpret_cast<T*>(&m_Buffer[m_ReadOffset]));
|
|
||||||
m_ReadOffset += sizeof(T);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Read some data from the buffer and assign to the new buffer
|
|
||||||
* \param data The buffer to assign
|
|
||||||
*/
|
|
||||||
DataBuffer& operator>>(DataBuffer& data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Read a string from the buffer
|
|
||||||
* \param str The string to assign in the new buffer
|
|
||||||
* \warning Don't use it for binary data !
|
|
||||||
*/
|
|
||||||
DataBuffer& operator>>(std::string& str);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Read a vector (size + data) from the buffer
|
|
||||||
* \pre The vector is assumed to be empty
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
DataBuffer& operator>>(std::vector<T>& data) {
|
|
||||||
VarInt arraySize;
|
|
||||||
*this >> arraySize;
|
|
||||||
for (std::size_t i = 0; i < arraySize.GetValue(); i++) {
|
|
||||||
T newElement;
|
|
||||||
*this >> newElement;
|
|
||||||
data.push_back(newElement);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Read an array from the buffer
|
|
||||||
*/
|
|
||||||
template <std::size_t Size, typename T>
|
|
||||||
DataBuffer& operator>>(std::array<T, Size>& data) {
|
|
||||||
for (std::size_t i = 0; i < Size; i++) {
|
|
||||||
T newElement;
|
|
||||||
*this >> newElement;
|
|
||||||
data[i] = newElement;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Write some data to the buffer
|
|
||||||
* \param buffer The buffer to write
|
|
||||||
* \param amount The amount of data to write
|
|
||||||
*/
|
|
||||||
void WriteSome(const char* buffer, std::size_t amount);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Write some data to the buffer
|
|
||||||
* \param buffer The buffer to write
|
|
||||||
* \param amount The amount of data to write
|
|
||||||
*/
|
|
||||||
void WriteSome(const std::uint8_t* buffer, std::size_t amount);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Read some data from the buffer
|
|
||||||
* \param buffer The buffer to Read
|
|
||||||
* \param amount The amount of data from the buffer
|
|
||||||
*/
|
|
||||||
void ReadSome(char* buffer, std::size_t amount);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Read some data from the buffer
|
|
||||||
* \param buffer The buffer to Read
|
|
||||||
* \param amount The amount of data from the buffer
|
|
||||||
*/
|
|
||||||
void ReadSome(std::uint8_t* buffer, std::size_t amount);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Read some data from the buffer
|
|
||||||
* \param buffer The buffer to Read
|
|
||||||
* \param amount The amount of data from the buffer
|
|
||||||
*/
|
|
||||||
void ReadSome(DataBuffer& buffer, std::size_t amount);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Resize the buffer
|
|
||||||
* \param size The new size of the buffer
|
|
||||||
*/
|
|
||||||
void Resize(std::size_t size) {
|
|
||||||
m_Buffer.resize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Reserve some space in the buffer
|
|
||||||
* \param amount The amount of space to reserve
|
|
||||||
*/
|
|
||||||
void Reserve(std::size_t amount) {
|
|
||||||
m_Buffer.reserve(amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Clear the buffer
|
|
||||||
*/
|
|
||||||
void Clear() {
|
|
||||||
m_Buffer.clear();
|
|
||||||
m_ReadOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief When the buffer has been read entirely
|
|
||||||
*/
|
|
||||||
bool IsFinished() const {
|
|
||||||
return m_ReadOffset >= m_Buffer.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get the buffer data
|
|
||||||
*/
|
|
||||||
std::uint8_t* data() {
|
|
||||||
return m_Buffer.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get the buffer data
|
|
||||||
*/
|
|
||||||
const std::uint8_t* data() const {
|
|
||||||
return m_Buffer.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get the read offset
|
|
||||||
*/
|
|
||||||
std::size_t GetReadOffset() const {
|
|
||||||
return m_ReadOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Set the read offset
|
|
||||||
* \param pos The new read offset
|
|
||||||
*/
|
|
||||||
void SetReadOffset(std::size_t pos);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get the size of the buffer
|
|
||||||
*/
|
|
||||||
std::size_t GetSize() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get the remaining size of the buffer
|
|
||||||
*/
|
|
||||||
std::size_t GetRemaining() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Read a file into the buffer
|
|
||||||
* \param fileName The name of the file to read
|
|
||||||
*/
|
|
||||||
bool ReadFile(const std::string& fileName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Write a file into the buffer
|
|
||||||
* \param fileName The name of the file to write to
|
|
||||||
*/
|
|
||||||
bool WriteFile(const std::string& fileName) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Allocate the buffer on the heap
|
|
||||||
* \warning Don't forget to free the data !
|
|
||||||
*/
|
|
||||||
std::uint8_t* HeapAllocatedData() const {
|
|
||||||
std::uint8_t* newBuffer = new std::uint8_t[GetSize()];
|
|
||||||
std::memcpy(newBuffer, data(), GetSize());
|
|
||||||
return newBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Operator == to compare two DataBuffer
|
|
||||||
*/
|
|
||||||
bool operator==(const DataBuffer& other) const {
|
|
||||||
return m_Buffer == other.m_Buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator begin();
|
|
||||||
iterator end();
|
|
||||||
const_iterator begin() const;
|
|
||||||
const_iterator end() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Operator << to write a DataBuffer to an ostream
|
|
||||||
*/
|
|
||||||
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer);
|
|
||||||
|
|
||||||
} // namespace td
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \file VarInt.h
|
|
||||||
* \brief File containing the td::VarInt class
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace td {
|
|
||||||
|
|
||||||
class DataBuffer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \class VarInt
|
|
||||||
* \brief Variable-length format such that smaller numbers use fewer bytes.
|
|
||||||
*/
|
|
||||||
class VarInt {
|
|
||||||
private:
|
|
||||||
std::uint64_t m_Value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
VarInt() : m_Value(0) {}
|
|
||||||
/**
|
|
||||||
* \brief Construct a variable integer from a value
|
|
||||||
* \param value The value of the variable integer
|
|
||||||
*/
|
|
||||||
VarInt(std::uint64_t value) : m_Value(value) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get the value of the variable integer
|
|
||||||
*/
|
|
||||||
std::uint64_t GetValue() const {
|
|
||||||
return m_Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get the length of the serialized variable integer
|
|
||||||
*/
|
|
||||||
std::size_t GetSerializedLength() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Serialize the variable integer
|
|
||||||
* \param out The buffer to write the serialized variable integer to
|
|
||||||
* \param var The variable integer to serialize
|
|
||||||
*/
|
|
||||||
friend DataBuffer& operator<<(DataBuffer& out, const VarInt& var);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Deserialize the variable integer
|
|
||||||
* \param in The buffer to read the serialized variable integer from
|
|
||||||
* \param var The variable integer to deserialize
|
|
||||||
*/
|
|
||||||
friend DataBuffer& operator>>(DataBuffer& in, VarInt& var);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace td
|
|
||||||
@@ -1,13 +1,45 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <td/game/GameHistory.h>
|
#include <td/game/World.h>
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
|
enum class GameState : std::uint8_t {
|
||||||
|
Lobby,
|
||||||
|
Game,
|
||||||
|
EndGame,
|
||||||
|
Disconnected,
|
||||||
|
Closed
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<std::uint8_t, Player> PlayerList;
|
||||||
|
|
||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
private:
|
protected:
|
||||||
GameHistory m_History;
|
World* m_World;
|
||||||
|
|
||||||
|
GameState m_GameState = GameState::Lobby;
|
||||||
|
PlayerList m_Players;
|
||||||
|
public:
|
||||||
|
Game(World* world);
|
||||||
|
virtual ~Game();
|
||||||
|
|
||||||
|
virtual void Tick(std::uint64_t delta);
|
||||||
|
|
||||||
|
GameState GetGameState() const { return m_GameState; }
|
||||||
|
void SetGameState(GameState gameState) { m_GameState = gameState; };
|
||||||
|
|
||||||
|
const World* GetWorld() const { return m_World; }
|
||||||
|
World* GetWorld() { return m_World; }
|
||||||
|
|
||||||
|
const PlayerList& GetPlayers() const { return m_Players; }
|
||||||
|
PlayerList& GetPlayers() { return m_Players; }
|
||||||
|
|
||||||
|
const Player* GetPlayerById(PlayerID id) const;
|
||||||
|
Player* GetPlayerById(PlayerID id);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
|
|||||||
260
include/td/game/Mobs.h
Normal file
260
include/td/game/Mobs.h
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/game/Towers.h>
|
||||||
|
|
||||||
|
#include <td/Maths.h>
|
||||||
|
#include <td/Types.h>
|
||||||
|
#include <td/game/Team.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace game {
|
||||||
|
|
||||||
|
struct WalkableTile;
|
||||||
|
|
||||||
|
enum class EffectType : std::uint8_t {
|
||||||
|
Slowness = 0,
|
||||||
|
Stun,
|
||||||
|
Fire,
|
||||||
|
Poison,
|
||||||
|
Heal,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MobType : std::uint8_t {
|
||||||
|
Zombie = 0,
|
||||||
|
Spider,
|
||||||
|
Skeleton,
|
||||||
|
Pigman,
|
||||||
|
Creeper,
|
||||||
|
Silverfish,
|
||||||
|
Blaze,
|
||||||
|
Witch,
|
||||||
|
Slime,
|
||||||
|
Giant,
|
||||||
|
|
||||||
|
MOB_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::uint32_t MobID;
|
||||||
|
typedef std::uint8_t MobLevel;
|
||||||
|
typedef std::vector<TowerType> TowerImmunities;
|
||||||
|
typedef std::vector<EffectType> EffectImmunities;
|
||||||
|
|
||||||
|
class MobStats {
|
||||||
|
private:
|
||||||
|
float m_Damage;
|
||||||
|
float m_Speed;
|
||||||
|
Vec2f m_Size;
|
||||||
|
std::uint16_t m_MoneyCost;
|
||||||
|
std::uint16_t m_ExpCost;
|
||||||
|
std::uint16_t m_MaxLife;
|
||||||
|
std::uint16_t m_ExpReward;
|
||||||
|
public:
|
||||||
|
MobStats(float damage, float speed, Vec2f size, std::uint16_t moneyCost,
|
||||||
|
std::uint16_t expCost, std::uint16_t expReward,
|
||||||
|
std::uint16_t maxLife) : m_Damage(damage), m_Speed(speed),
|
||||||
|
m_Size(size), m_MoneyCost(moneyCost), m_ExpCost(expCost),
|
||||||
|
m_MaxLife(maxLife), m_ExpReward(expReward) {
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetDamage() const { return m_Damage; }
|
||||||
|
float GetMovementSpeed() const { return m_Speed; }
|
||||||
|
const Vec2f& GetSize() const { return m_Size; }
|
||||||
|
std::uint16_t GetMoneyCost() const { return m_MoneyCost; }
|
||||||
|
std::uint16_t GetExpCost() const { return m_ExpCost; }
|
||||||
|
std::uint16_t GetExpReward() const { return m_ExpReward; }
|
||||||
|
std::uint16_t GetMaxLife() const { return m_MaxLife; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EffectDuration {
|
||||||
|
EffectType type;
|
||||||
|
float duration; // in seconds
|
||||||
|
Tower* tower; // the tower that gived the effect
|
||||||
|
};
|
||||||
|
|
||||||
|
const MobStats* GetMobStats(MobType type, std::uint8_t level);
|
||||||
|
const TowerImmunities& GetMobTowerImmunities(MobType type, std::uint8_t level);
|
||||||
|
const EffectImmunities& GetMobEffectImmunities(MobType type, std::uint8_t level);
|
||||||
|
|
||||||
|
class Mob : public utils::shape::Rectangle {
|
||||||
|
protected:
|
||||||
|
float m_Health;
|
||||||
|
private:
|
||||||
|
MobID m_ID;
|
||||||
|
PlayerID m_Sender;
|
||||||
|
MobLevel m_Level;
|
||||||
|
Direction m_Direction;
|
||||||
|
std::vector<EffectDuration> m_Effects;
|
||||||
|
const Tower* m_LastDamage; // the last tower that damaged the mob
|
||||||
|
float m_HitCooldown;
|
||||||
|
|
||||||
|
// utils::Timer m_EffectFireTimer;
|
||||||
|
// utils::Timer m_EffectPoisonTimer;
|
||||||
|
// utils::Timer m_EffectHealTimer;
|
||||||
|
|
||||||
|
TeamCastle* m_CastleTarget;
|
||||||
|
// utils::CooldownTimer m_AttackTimer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level),
|
||||||
|
m_HitCooldown(0), m_CastleTarget(nullptr) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual MobType GetType() const = 0;
|
||||||
|
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
|
||||||
|
virtual bool OnDeath(World* world) { return true; }
|
||||||
|
|
||||||
|
MobID GetMobID() const { return m_ID; }
|
||||||
|
const TowerImmunities& GetTowerImmunities() const { return GetMobTowerImmunities(GetType(), m_Level); }
|
||||||
|
const EffectImmunities& GetEffectImmunities() const { return GetMobEffectImmunities(GetType(), m_Level); }
|
||||||
|
PlayerID GetSender() const { return m_Sender; }
|
||||||
|
MobLevel GetLevel() const { return m_Level; }
|
||||||
|
const MobStats* GetStats() const { return GetMobStats(GetType(), m_Level); }
|
||||||
|
void SetHealth(float newHealth) { m_Health = newHealth; }
|
||||||
|
float GetHealth() const { return m_Health; }
|
||||||
|
bool IsDead() const { return m_Health <= 0; }
|
||||||
|
bool IsAlive() const { return m_Health > 0; }
|
||||||
|
const Tower* GetLastDamageTower() { return m_LastDamage; }
|
||||||
|
bool HasReachedEnemyCastle() { return m_CastleTarget != nullptr; }
|
||||||
|
|
||||||
|
void Damage(float dmg, const Tower* damager) {
|
||||||
|
m_Health = std::max(0.0f, m_Health - dmg);
|
||||||
|
m_LastDamage = damager;
|
||||||
|
m_HitCooldown = 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Heal(float heal) {
|
||||||
|
m_Health = std::min(static_cast<float>(GetStats()->GetMaxLife()), m_Health + heal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMobReachedCastle(TeamCastle* castle) { m_CastleTarget = castle; } // used when mob is in front of the castle
|
||||||
|
|
||||||
|
bool IsImmuneTo(TowerType type);
|
||||||
|
|
||||||
|
bool IsImmuneTo(EffectType type);
|
||||||
|
void AddEffect(EffectType type, float durationSec, Tower* tower);
|
||||||
|
bool HasEffect(EffectType type);
|
||||||
|
|
||||||
|
bool HasTakenDamage() { return m_HitCooldown > 0; }
|
||||||
|
|
||||||
|
float GetTileX() { return GetCenterX() - static_cast<float>(static_cast<std::int32_t>(GetCenterX())); } // returns a float between 0 and 1 excluded
|
||||||
|
float GetTileY() { return GetCenterY() - static_cast<float>(static_cast<std::int32_t>(GetCenterY())); } // returns a float between 0 and 1 excluded
|
||||||
|
|
||||||
|
Direction GetDirection() const { return m_Direction; }
|
||||||
|
void SetDirection(Direction dir) { m_Direction = dir; }
|
||||||
|
protected:
|
||||||
|
void InitMob() {
|
||||||
|
m_Health = static_cast<float>(GetStats()->GetMaxLife());
|
||||||
|
SetSize(GetStats()->GetSize().x, GetStats()->GetSize().y);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void UpdateEffects(std::uint64_t delta, World* world);
|
||||||
|
void AttackCastle(std::uint64_t delta, World* world);
|
||||||
|
void Move(std::uint64_t delta, World* world);
|
||||||
|
void Walk(std::uint64_t delta, World* world);
|
||||||
|
void MoveBack(const TeamCastle& castle, World* world);
|
||||||
|
void ChangeDirection(const WalkableTile& tile, World* world);
|
||||||
|
bool IsTouchingCastle(const TeamCastle& castle) const;
|
||||||
|
EffectDuration& GetEffect(EffectType type);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr<Mob> MobPtr;
|
||||||
|
|
||||||
|
class Zombie : public Mob {
|
||||||
|
public:
|
||||||
|
Zombie(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
|
||||||
|
|
||||||
|
virtual MobType GetType() const { return MobType::Zombie; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Spider : public Mob {
|
||||||
|
public:
|
||||||
|
Spider(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
|
||||||
|
|
||||||
|
virtual MobType GetType() const { return MobType::Spider; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Skeleton : public Mob {
|
||||||
|
public:
|
||||||
|
Skeleton(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
|
||||||
|
|
||||||
|
virtual MobType GetType() const { return MobType::Skeleton; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class PigMan : public Mob {
|
||||||
|
public:
|
||||||
|
PigMan(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
|
||||||
|
|
||||||
|
virtual MobType GetType() const { return MobType::Pigman; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Creeper : public Mob {
|
||||||
|
public:
|
||||||
|
Creeper(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
|
||||||
|
|
||||||
|
virtual MobType GetType() const { return MobType::Creeper; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Silverfish : public Mob {
|
||||||
|
public:
|
||||||
|
Silverfish(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
|
||||||
|
|
||||||
|
virtual MobType GetType() const { return MobType::Silverfish; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Blaze : public Mob {
|
||||||
|
public:
|
||||||
|
Blaze(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
|
||||||
|
|
||||||
|
virtual MobType GetType() const { return MobType::Blaze; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Witch : public Mob {
|
||||||
|
public:
|
||||||
|
Witch(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
|
||||||
|
|
||||||
|
virtual MobType GetType() const { return MobType::Witch; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Slime : public Mob {
|
||||||
|
public:
|
||||||
|
Slime(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
|
||||||
|
|
||||||
|
virtual MobType GetType() const { return MobType::Slime; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Giant : public Mob {
|
||||||
|
public:
|
||||||
|
Giant(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { InitMob(); }
|
||||||
|
|
||||||
|
virtual MobType GetType() const { return MobType::Giant; }
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace MobFactory {
|
||||||
|
|
||||||
|
MobPtr CreateMob(MobID id, MobType type, std::uint8_t level, PlayerID sender);
|
||||||
|
std::string GetMobName(MobType type);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class MobListener {
|
||||||
|
public:
|
||||||
|
virtual void OnMobSpawn(Mob* mob) {}
|
||||||
|
virtual void OnMobDie(Mob* mob) {}
|
||||||
|
|
||||||
|
virtual void OnMobDamage(Mob* target, float damage, Tower* damager) {}
|
||||||
|
|
||||||
|
virtual void OnMobTouchCastle(Mob* damager, TeamCastle* enemyCastle) {}
|
||||||
|
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// typedef utils::ObjectNotifier<MobListener> MobNotifier;
|
||||||
|
|
||||||
|
} // namespace game
|
||||||
|
} // namespace td
|
||||||
|
|
||||||
86
include/td/game/Team.h
Normal file
86
include/td/game/Team.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/Types.h>
|
||||||
|
|
||||||
|
#include <td/misc/Shapes.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace game {
|
||||||
|
|
||||||
|
class Player;
|
||||||
|
|
||||||
|
class Spawn : public utils::shape::Rectangle {
|
||||||
|
private:
|
||||||
|
Direction m_Direction;
|
||||||
|
public:
|
||||||
|
Spawn() {
|
||||||
|
SetWidth(5);
|
||||||
|
SetHeight(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
Direction GetDirection() const { return m_Direction; }
|
||||||
|
|
||||||
|
void SetDirection(Direction direction) { m_Direction = direction; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Team;
|
||||||
|
|
||||||
|
class TeamCastle : public utils::shape::Rectangle {
|
||||||
|
private:
|
||||||
|
const Team* m_Team;
|
||||||
|
float m_Life;
|
||||||
|
public:
|
||||||
|
static constexpr int CastleMaxLife = 1000;
|
||||||
|
|
||||||
|
TeamCastle(const Team* team) : m_Team(team), m_Life(CastleMaxLife) {
|
||||||
|
SetWidth(5);
|
||||||
|
SetHeight(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TeamCastle() : TeamCastle(nullptr) {}
|
||||||
|
|
||||||
|
float GetLife() const { return m_Life; }
|
||||||
|
|
||||||
|
const Team* GetTeam() const { return m_Team; }
|
||||||
|
void SetTeam(const Team* team) { m_Team = team; }
|
||||||
|
|
||||||
|
void SetLife(float life) { m_Life = life; }
|
||||||
|
void Damage(float damage) { m_Life = std::max(0.0f, m_Life - damage); }
|
||||||
|
|
||||||
|
void SetShape(utils::shape::Rectangle rect) {
|
||||||
|
SetCenter(rect.GetCenter());
|
||||||
|
SetSize(rect.GetSize());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Team {
|
||||||
|
private:
|
||||||
|
std::vector<Player*> m_Players;
|
||||||
|
TeamColor m_Color;
|
||||||
|
Spawn m_Spawn;
|
||||||
|
TeamCastle m_TeamCastle;
|
||||||
|
public:
|
||||||
|
Team(TeamColor color) : m_Color(color) {}
|
||||||
|
|
||||||
|
void AddPlayer(Player* newPlayer);
|
||||||
|
void RemovePlayer(const Player* player);
|
||||||
|
|
||||||
|
TeamColor GetColor() const;
|
||||||
|
|
||||||
|
const Spawn& GetSpawn() const { return m_Spawn; }
|
||||||
|
Spawn& GetSpawn() { return m_Spawn; }
|
||||||
|
|
||||||
|
const TeamCastle& GetCastle() const { return m_TeamCastle; }
|
||||||
|
TeamCastle& GetCastle() { return m_TeamCastle; }
|
||||||
|
|
||||||
|
std::uint8_t GetPlayerCount() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::array<Team, 2> TeamList;
|
||||||
|
|
||||||
|
} // namespace game
|
||||||
|
} // namespace td
|
||||||
266
include/td/game/Towers.h
Normal file
266
include/td/game/Towers.h
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <td/misc/Shapes.h>
|
||||||
|
|
||||||
|
#include <td/Types.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace game {
|
||||||
|
|
||||||
|
class World;
|
||||||
|
class Mob;
|
||||||
|
|
||||||
|
typedef std::shared_ptr<Mob> MobPtr;
|
||||||
|
|
||||||
|
enum class TowerType : std::uint8_t {
|
||||||
|
Archer = 0,
|
||||||
|
Ice,
|
||||||
|
Sorcerer,
|
||||||
|
Zeus,
|
||||||
|
Mage,
|
||||||
|
Artillery,
|
||||||
|
Quake,
|
||||||
|
Poison,
|
||||||
|
|
||||||
|
Leach,
|
||||||
|
Turret,
|
||||||
|
Necromancer,
|
||||||
|
|
||||||
|
TowerCount
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class TowerSize : std::uint8_t {
|
||||||
|
Little = 3, // 3x3
|
||||||
|
Big = 5, // 5x5
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class TowerPath : std::uint8_t {
|
||||||
|
Top = 0,
|
||||||
|
Base, // Base Path
|
||||||
|
Bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
class TowerStats {
|
||||||
|
private:
|
||||||
|
float m_Rate;
|
||||||
|
float m_Damage;
|
||||||
|
std::uint8_t m_Range;
|
||||||
|
public:
|
||||||
|
TowerStats(float rate, float damage, std::uint8_t range) : m_Rate(rate), m_Damage(damage),
|
||||||
|
m_Range(range) {
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetDamageRate() const { return m_Rate; }
|
||||||
|
float GetDamage() const { return m_Damage; }
|
||||||
|
std::uint8_t GetRange() const { return m_Range; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class TowerLevel {
|
||||||
|
private:
|
||||||
|
// 1, 2, 3, 4
|
||||||
|
std::uint8_t m_Level : 3;
|
||||||
|
// 0 : base path 1 : top path (if there is bottom path) 2 : bottom path (if there is top path)
|
||||||
|
TowerPath m_Path : 2;
|
||||||
|
public:
|
||||||
|
TowerLevel() : m_Level(1), m_Path(TowerPath::Base) {}
|
||||||
|
TowerLevel(std::uint8_t level, TowerPath path) : m_Level(level), m_Path(path) {}
|
||||||
|
|
||||||
|
std::uint8_t GetLevel() const { return m_Level; }
|
||||||
|
TowerPath GetPath() const { return m_Path; }
|
||||||
|
|
||||||
|
void SetLevel(std::uint8_t level) { m_Level = level; }
|
||||||
|
void SetPath(TowerPath path) { m_Path = path; }
|
||||||
|
|
||||||
|
// operator to sort maps
|
||||||
|
friend bool operator<(const TowerLevel& level, const TowerLevel& other) {
|
||||||
|
return level.GetLevel() + static_cast<std::uint8_t>(level.GetPath()) * 4 <
|
||||||
|
other.GetLevel() + static_cast<std::uint8_t>(other.GetPath()) * 4;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const TowerStats* GetTowerStats(TowerType type, TowerLevel level);
|
||||||
|
|
||||||
|
typedef std::uint16_t TowerID;
|
||||||
|
|
||||||
|
class Tower : public utils::shape::Circle {
|
||||||
|
private:
|
||||||
|
TowerID m_ID;
|
||||||
|
TowerType m_Type;
|
||||||
|
TowerLevel m_Level{};
|
||||||
|
PlayerID m_Builder;
|
||||||
|
protected:
|
||||||
|
// utils::CooldownTimer m_Timer;
|
||||||
|
public:
|
||||||
|
Tower(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) : utils::shape::Circle(x + 0.5f, y + 0.5f, 0), m_ID(id), m_Type(type), m_Builder(builder)
|
||||||
|
// m_Timer(GetStats()->GetDamageRate() * 1000)
|
||||||
|
{ // converting seconds to millis
|
||||||
|
SetRadius(GetStats()->GetRange());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual TowerType GetType() const = 0;
|
||||||
|
virtual TowerSize GetSize() const = 0;
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world) = 0;
|
||||||
|
|
||||||
|
void Upgrade(std::uint8_t level, TowerPath path) {
|
||||||
|
m_Level.SetLevel(level);
|
||||||
|
m_Level.SetPath(path);
|
||||||
|
// m_Timer.SetCooldown(GetStats()->GetDamageRate() * 1000); // converting seconds to millis
|
||||||
|
// m_Timer.Reset();
|
||||||
|
SetRadius(GetStats()->GetRange());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint16_t GetID() const { return m_ID; }
|
||||||
|
const TowerLevel& GetLevel() const { return m_Level; }
|
||||||
|
const TowerStats* GetStats() const { return GetTowerStats(m_Type, m_Level); }
|
||||||
|
PlayerID GetBuilder() const { return m_Builder; }
|
||||||
|
|
||||||
|
bool IsMobInRange(MobPtr mob);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr<Tower> TowerPtr;
|
||||||
|
|
||||||
|
namespace TowerFactory {
|
||||||
|
|
||||||
|
TowerPtr CreateTower(TowerType type, TowerID id, std::int32_t x, std::int32_t y, PlayerID builder);
|
||||||
|
std::string GetTowerName(TowerType type);
|
||||||
|
|
||||||
|
} // namespace TowerFactory
|
||||||
|
|
||||||
|
|
||||||
|
class TowerInfo {
|
||||||
|
private:
|
||||||
|
std::string m_Name, m_Description;
|
||||||
|
bool m_IsBigTower;
|
||||||
|
public:
|
||||||
|
TowerInfo(std::string&& name, std::string&& description, bool big) : m_Name(std::move(name)),
|
||||||
|
m_Description(std::move(description)), m_IsBigTower(big) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& GetName() const { return m_Name; }
|
||||||
|
const std::string& GetDescription() const { return m_Description; }
|
||||||
|
|
||||||
|
bool IsBigTower() const { return m_IsBigTower; }
|
||||||
|
};
|
||||||
|
|
||||||
|
const TowerInfo& GetTowerInfo(TowerType type);
|
||||||
|
|
||||||
|
// ---------- Little Towers ----------
|
||||||
|
|
||||||
|
class LittleTower : public Tower {
|
||||||
|
public:
|
||||||
|
LittleTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerSize GetSize() const { return TowerSize::Little; }
|
||||||
|
|
||||||
|
virtual TowerType GetType() const = 0;
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArcherTower : public LittleTower {
|
||||||
|
public:
|
||||||
|
ArcherTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
|
||||||
|
|
||||||
|
constexpr static float ExplosionRadius = 1.5f;
|
||||||
|
constexpr static float FireDurationSec = 10.0f;
|
||||||
|
|
||||||
|
virtual TowerType GetType() const { return TowerType::Archer; }
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
};
|
||||||
|
|
||||||
|
class IceTower : public LittleTower {
|
||||||
|
public:
|
||||||
|
IceTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerType GetType() const { return TowerType::Ice; }
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
};
|
||||||
|
|
||||||
|
class MageTower : public LittleTower {
|
||||||
|
public:
|
||||||
|
MageTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerType GetType() const { return TowerType::Mage; }
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
};
|
||||||
|
|
||||||
|
class PoisonTower : public LittleTower {
|
||||||
|
public:
|
||||||
|
PoisonTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerType GetType() const { return TowerType::Poison; }
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
};
|
||||||
|
|
||||||
|
class QuakeTower : public LittleTower {
|
||||||
|
public:
|
||||||
|
QuakeTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerType GetType() const { return TowerType::Quake; }
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ArtilleryTower : public LittleTower {
|
||||||
|
public:
|
||||||
|
ArtilleryTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerType GetType() const { return TowerType::Artillery; }
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SorcererTower : public LittleTower {
|
||||||
|
public:
|
||||||
|
SorcererTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerType GetType() const { return TowerType::Sorcerer; }
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ZeusTower : public LittleTower {
|
||||||
|
public:
|
||||||
|
ZeusTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerType GetType() const { return TowerType::Zeus; }
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------- Big Towers ----------
|
||||||
|
|
||||||
|
class BigTower : public Tower {
|
||||||
|
public:
|
||||||
|
BigTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerSize GetSize() const { return TowerSize::Big; }
|
||||||
|
|
||||||
|
virtual TowerType GetType() const = 0;
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TurretTower : public BigTower {
|
||||||
|
public:
|
||||||
|
TurretTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerType GetType() const { return TowerType::Turret; }
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
};
|
||||||
|
|
||||||
|
class NecromancerTower : public BigTower {
|
||||||
|
public:
|
||||||
|
NecromancerTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerType GetType() const { return TowerType::Necromancer; }
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
};
|
||||||
|
|
||||||
|
class LeachTower : public BigTower {
|
||||||
|
public:
|
||||||
|
LeachTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
|
||||||
|
|
||||||
|
virtual TowerType GetType() const { return TowerType::Leach; }
|
||||||
|
virtual void Tick(std::uint64_t delta, World* world);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace game
|
||||||
|
} // namespace td
|
||||||
137
include/td/game/World.h
Normal file
137
include/td/game/World.h
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/game/WorldTypes.h>
|
||||||
|
#include <td/protocol/packet/Packets.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace game {
|
||||||
|
|
||||||
|
class World {
|
||||||
|
protected:
|
||||||
|
TowerTileColorPalette m_TowerPlacePalette;
|
||||||
|
Color m_WalkablePalette;
|
||||||
|
std::vector<Color> m_DecorationPalette;
|
||||||
|
Color m_Background;
|
||||||
|
|
||||||
|
std::unordered_map<ChunkCoord, ChunkPtr> m_Chunks;
|
||||||
|
|
||||||
|
SpawnColorPalette m_SpawnColorPalette;
|
||||||
|
|
||||||
|
TilePalette m_TilePalette;
|
||||||
|
|
||||||
|
MobList m_Mobs;
|
||||||
|
|
||||||
|
TowerList m_Towers;
|
||||||
|
|
||||||
|
TeamList m_Teams;
|
||||||
|
|
||||||
|
public:
|
||||||
|
World();
|
||||||
|
|
||||||
|
bool LoadMap(const protocol::pdata::WorldHeader& worldHeader);
|
||||||
|
bool LoadMap(const protocol::pdata::WorldData& worldData);
|
||||||
|
|
||||||
|
bool LoadMapFromFile(const std::string& fileName);
|
||||||
|
bool SaveMap(const std::string& fileName) const;
|
||||||
|
|
||||||
|
void Tick(std::uint64_t delta);
|
||||||
|
|
||||||
|
void SpawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir);
|
||||||
|
|
||||||
|
TowerPtr PlaceTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder);
|
||||||
|
TowerPtr RemoveTower(TowerID id);
|
||||||
|
|
||||||
|
TilePtr GetTile(std::int32_t x, std::int32_t y) const;
|
||||||
|
|
||||||
|
const TowerTileColorPalette& GetTowerTileColorPalette() const {
|
||||||
|
return m_TowerPlacePalette;
|
||||||
|
}
|
||||||
|
const Color& GetWalkableTileColor() const {
|
||||||
|
return m_WalkablePalette;
|
||||||
|
}
|
||||||
|
const std::vector<Color>& GetDecorationPalette() const {
|
||||||
|
return m_DecorationPalette;
|
||||||
|
}
|
||||||
|
const Color& GetBackgroundColor() const {
|
||||||
|
return m_Background;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TilePalette& GetTilePalette() const {
|
||||||
|
return m_TilePalette;
|
||||||
|
}
|
||||||
|
|
||||||
|
TilePtr GetTilePtr(TileIndex index) const {
|
||||||
|
if (index == 0)
|
||||||
|
return nullptr;
|
||||||
|
return m_TilePalette.at(index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanPlaceLittleTower(const Vec2f& worldPos, PlayerID player) const;
|
||||||
|
bool CanPlaceBigTower(const Vec2f& worldPos, PlayerID player) const;
|
||||||
|
|
||||||
|
TowerPtr GetTower(const Vec2f& position) const; // returns null if no tower is here
|
||||||
|
|
||||||
|
const std::unordered_map<ChunkCoord, ChunkPtr>& GetChunks() const {
|
||||||
|
return m_Chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Color& GetSpawnColor(TeamColor color) const {
|
||||||
|
return m_SpawnColorPalette[static_cast<std::size_t>(color)];
|
||||||
|
}
|
||||||
|
const SpawnColorPalette& GetSpawnColors() const {
|
||||||
|
return m_SpawnColorPalette;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MobList& GetMobList() const {
|
||||||
|
return m_Mobs;
|
||||||
|
}
|
||||||
|
MobList& GetMobList() {
|
||||||
|
return m_Mobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Color* GetTileColor(TilePtr tile) const;
|
||||||
|
|
||||||
|
Team& GetRedTeam() {
|
||||||
|
return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)];
|
||||||
|
}
|
||||||
|
const Team& GetRedTeam() const {
|
||||||
|
return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)];
|
||||||
|
}
|
||||||
|
|
||||||
|
Team& GetBlueTeam() {
|
||||||
|
return m_Teams[static_cast<std::uint8_t>(TeamColor::Blue)];
|
||||||
|
}
|
||||||
|
const Team& GetBlueTeam() const {
|
||||||
|
return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)];
|
||||||
|
}
|
||||||
|
|
||||||
|
Team& GetTeam(TeamColor team) {
|
||||||
|
return m_Teams[static_cast<std::uint8_t>(team)];
|
||||||
|
}
|
||||||
|
const Team& GetTeam(TeamColor team) const {
|
||||||
|
return m_Teams[static_cast<std::uint8_t>(team)];
|
||||||
|
}
|
||||||
|
|
||||||
|
const TeamList& GetTeams() const {
|
||||||
|
return m_Teams;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TowerList& GetTowers() const {
|
||||||
|
return m_Towers;
|
||||||
|
}
|
||||||
|
|
||||||
|
TowerPtr GetTowerById(TowerID tower);
|
||||||
|
|
||||||
|
const Player* GetPlayerById(PlayerID id) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void TickMobs(std::uint64_t delta);
|
||||||
|
void CleanDeadMobs();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace game
|
||||||
|
} // namespace td
|
||||||
119
include/td/game/WorldTypes.h
Normal file
119
include/td/game/WorldTypes.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/Maths.h>
|
||||||
|
#include <td/game/Mobs.h>
|
||||||
|
#include <td/game/Team.h>
|
||||||
|
#include <td/game/Towers.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace game {
|
||||||
|
struct ChunkCoord {
|
||||||
|
std::int16_t x, y;
|
||||||
|
|
||||||
|
friend bool operator==(const td::game::ChunkCoord& first, const td::game::ChunkCoord& other) {
|
||||||
|
return first.x == other.x && first.y == other.y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Game;
|
||||||
|
|
||||||
|
enum class TileType : std::uint8_t {
|
||||||
|
None = 0,
|
||||||
|
Tower,
|
||||||
|
Walk,
|
||||||
|
Decoration,
|
||||||
|
/*Heal,
|
||||||
|
Lava,
|
||||||
|
Bedrock,
|
||||||
|
Freeze,
|
||||||
|
Ice,*/
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr Color BLACK{0, 0, 0};
|
||||||
|
static constexpr Color WHITE{255, 255, 255};
|
||||||
|
|
||||||
|
static constexpr Color RED{255, 0, 0};
|
||||||
|
static constexpr Color GREEN{0, 255, 0};
|
||||||
|
static constexpr Color BLUE{0, 0, 255};
|
||||||
|
|
||||||
|
struct Tile {
|
||||||
|
virtual TileType GetType() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TowerTile : Tile {
|
||||||
|
std::uint8_t color_palette_ref;
|
||||||
|
TeamColor team_owner;
|
||||||
|
|
||||||
|
virtual TileType GetType() const {
|
||||||
|
return TileType::Tower;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WalkableTile : Tile {
|
||||||
|
Direction direction;
|
||||||
|
|
||||||
|
virtual TileType GetType() const {
|
||||||
|
return TileType::Walk;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DecorationTile : Tile {
|
||||||
|
std::uint16_t color_palette_ref;
|
||||||
|
|
||||||
|
virtual TileType GetType() const {
|
||||||
|
return TileType::Decoration;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr<Tile> TilePtr;
|
||||||
|
typedef std::vector<std::uint16_t> ChunkPalette;
|
||||||
|
|
||||||
|
typedef std::shared_ptr<WalkableTile> WalkableTilePtr;
|
||||||
|
|
||||||
|
typedef std::uint32_t TileIndex;
|
||||||
|
|
||||||
|
// 32 x 32 area
|
||||||
|
struct Chunk {
|
||||||
|
enum { ChunkWidth = 32, ChunkHeight = 32, ChunkSize = ChunkWidth * ChunkHeight };
|
||||||
|
typedef std::array<std::uint16_t, ChunkSize> ChunkData;
|
||||||
|
|
||||||
|
// stores index of tile palette
|
||||||
|
ChunkData tiles{0};
|
||||||
|
ChunkPalette palette;
|
||||||
|
|
||||||
|
TileIndex GetTileIndex(std::uint16_t tileNumber) const {
|
||||||
|
TileIndex chunkPaletteIndex = tiles.at(tileNumber);
|
||||||
|
if (chunkPaletteIndex == 0) // index 0 means empty tile index 1 = first tile
|
||||||
|
return 0;
|
||||||
|
return palette.at(chunkPaletteIndex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr<Chunk> ChunkPtr;
|
||||||
|
|
||||||
|
typedef std::array<Color, 2> TowerTileColorPalette;
|
||||||
|
|
||||||
|
typedef std::vector<TilePtr> TilePalette;
|
||||||
|
|
||||||
|
typedef std::vector<MobPtr> MobList;
|
||||||
|
|
||||||
|
typedef std::array<Color, 2> SpawnColorPalette;
|
||||||
|
|
||||||
|
typedef std::vector<TowerPtr> TowerList;
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace game
|
||||||
|
|
||||||
|
} // namespace td
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct hash<td::game::ChunkCoord> {
|
||||||
|
std::size_t operator()(const td::game::ChunkCoord& key) const noexcept {
|
||||||
|
return std::hash<std::int16_t>()(key.x << 16 | key.y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace std
|
||||||
43
include/td/input/Display.h
Normal file
43
include/td/input/Display.h
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_video.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
class Display {
|
||||||
|
public:
|
||||||
|
Display(int a_Width, int a_Height, const std::string& a_Title);
|
||||||
|
~Display();
|
||||||
|
|
||||||
|
void PollEvents();
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
bool IsCloseRequested() {
|
||||||
|
return m_ShouldClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetAspectRatio() {
|
||||||
|
return m_AspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetWindowWidth() {
|
||||||
|
return m_LastWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetWindowHeight() {
|
||||||
|
return m_LastHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDL_Window* m_Window;
|
||||||
|
SDL_GLContext m_GLContext;
|
||||||
|
|
||||||
|
int m_LastWidth, m_LastHeight;
|
||||||
|
float m_AspectRatio;
|
||||||
|
|
||||||
|
bool m_ShouldClose;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace td
|
||||||
96
include/td/misc/Shapes.h
Normal file
96
include/td/misc/Shapes.h
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace utils {
|
||||||
|
namespace shape {
|
||||||
|
|
||||||
|
class Point {
|
||||||
|
private:
|
||||||
|
float m_X, m_Y;
|
||||||
|
public:
|
||||||
|
Point() : m_X(0), m_Y(0) {}
|
||||||
|
Point(float x, float y) : m_X(x), m_Y(y) {}
|
||||||
|
|
||||||
|
float GetX() const { return m_X; }
|
||||||
|
float GetY() const { return m_Y; }
|
||||||
|
|
||||||
|
void SetX(float x) { m_X = x; }
|
||||||
|
void SetY(float y) { m_Y = y; }
|
||||||
|
|
||||||
|
float Distance(const Point& point) const;
|
||||||
|
float DistanceSquared(const Point& point) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Circle;
|
||||||
|
|
||||||
|
class Rectangle {
|
||||||
|
private:
|
||||||
|
Point m_Center;
|
||||||
|
float m_Width, m_Height;
|
||||||
|
public:
|
||||||
|
Rectangle() {}
|
||||||
|
|
||||||
|
const Point& GetCenter() const { return m_Center; }
|
||||||
|
float GetCenterX() const { return m_Center.GetX(); }
|
||||||
|
float GetCenterY() const { return m_Center.GetY(); }
|
||||||
|
|
||||||
|
float GetWidth() const { return m_Width; }
|
||||||
|
float GetHeight() const { return m_Height; }
|
||||||
|
|
||||||
|
Point GetTopLeft() const { return { m_Center.GetX() - (m_Width / 2.0f), m_Center.GetY() - (m_Height / 2.0f) }; }
|
||||||
|
Point GetBottomRight() const { return { m_Center.GetX() + (m_Width / 2.0f), m_Center.GetY() + (m_Height / 2.0f) }; }
|
||||||
|
|
||||||
|
void SetCenter(const Point& center) { m_Center = center; }
|
||||||
|
void SetCenterX(float x) { m_Center.SetX(x); }
|
||||||
|
void SetCenterY(float y) { m_Center.SetY(y); }
|
||||||
|
|
||||||
|
void SetSize(float width, float height) { SetWidth(width); SetHeight(height); }
|
||||||
|
void SetSize(Point size) { SetSize(size.GetX(), size.GetY()); }
|
||||||
|
Point GetSize() { return { m_Width, m_Height }; }
|
||||||
|
|
||||||
|
void SetWidth(float width) { m_Width = width; }
|
||||||
|
void SetHeight(float height) { m_Height = height; }
|
||||||
|
|
||||||
|
bool CollidesWith(const Point& point) const;
|
||||||
|
bool CollidesWith(const Rectangle& rect) const;
|
||||||
|
bool CollidesWith(const Circle& circle) const;
|
||||||
|
|
||||||
|
// distance from the closest side of the rectangle
|
||||||
|
float Distance(const Circle& circle) const;
|
||||||
|
float DistanceSquared(const Circle& circle) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Circle {
|
||||||
|
private:
|
||||||
|
Point m_Center;
|
||||||
|
float m_Radius;
|
||||||
|
public:
|
||||||
|
Circle(float x, float y, float radius) : m_Center(x, y), m_Radius(radius) {}
|
||||||
|
Circle() : m_Radius(0) {}
|
||||||
|
|
||||||
|
const Point& GetCenter() const { return m_Center; }
|
||||||
|
float GetCenterX() const { return m_Center.GetX(); }
|
||||||
|
float GetCenterY() const { return m_Center.GetY(); }
|
||||||
|
|
||||||
|
float GetRadius() const { return m_Radius; }
|
||||||
|
|
||||||
|
void SetCenter(const Point& center) { m_Center = center; }
|
||||||
|
void SetCenterX(float x) { m_Center.SetX(x); }
|
||||||
|
void SetCenterY(float y) { m_Center.SetY(y); }
|
||||||
|
|
||||||
|
void SetRadius(float radius) { m_Radius = radius; }
|
||||||
|
|
||||||
|
bool CollidesWith(const Point& point) const;
|
||||||
|
bool CollidesWith(const Rectangle& rect) const;
|
||||||
|
bool CollidesWith(const Circle& circle) const;
|
||||||
|
|
||||||
|
// distance from the closest side of the rectangle
|
||||||
|
float Distance(const Rectangle& rect) const;
|
||||||
|
float DistanceSquared(const Rectangle& rect) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace shape
|
||||||
|
} // namespace utils
|
||||||
|
} // namespace td
|
||||||
@@ -36,7 +36,7 @@ struct UseItem {
|
|||||||
|
|
||||||
struct TeamChange {
|
struct TeamChange {
|
||||||
sp::BitField<PlayerID, 7> m_Player;
|
sp::BitField<PlayerID, 7> m_Player;
|
||||||
sp::BitField<Team, 1> m_NewTeam;
|
sp::BitField<TeamColor, 1> m_NewTeam;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlayerJoin {
|
struct PlayerJoin {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <td/protocol/command/Commands.h>
|
#include <td/protocol/command/Commands.h>
|
||||||
#include <td/common/Array.h>
|
#include <td/common/Array.h>
|
||||||
|
#include <td/game/WorldTypes.h>
|
||||||
|
|
||||||
// Make it dynamic ?
|
// Make it dynamic ?
|
||||||
#define LOCKSTEP_BUFFER_SIZE 10
|
#define LOCKSTEP_BUFFER_SIZE 10
|
||||||
@@ -60,7 +61,6 @@ struct ChatMessage {
|
|||||||
// TODO: handle players joining in the first second
|
// TODO: handle players joining in the first second
|
||||||
|
|
||||||
struct BeginGame {
|
struct BeginGame {
|
||||||
MapData m_Map;
|
|
||||||
std::vector<PlayerInfo> m_BlueTeam;
|
std::vector<PlayerInfo> m_BlueTeam;
|
||||||
std::vector<PlayerInfo> m_RedTeam;
|
std::vector<PlayerInfo> m_RedTeam;
|
||||||
// optional, used for players joining mid game
|
// optional, used for players joining mid game
|
||||||
@@ -72,6 +72,24 @@ struct LockSteps {
|
|||||||
Array<LockStep, LOCKSTEP_BUFFER_SIZE> m_LockSteps;
|
Array<LockStep, LOCKSTEP_BUFFER_SIZE> m_LockSteps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct WorldHeader {
|
||||||
|
game::TowerTileColorPalette m_TowerPlacePalette;
|
||||||
|
Color m_WalkablePalette;
|
||||||
|
std::vector<Color> m_DecorationPalette;
|
||||||
|
Color m_Background;
|
||||||
|
|
||||||
|
game::SpawnColorPalette m_SpawnColorPalette;
|
||||||
|
|
||||||
|
game::TilePalette m_TilePalette;
|
||||||
|
|
||||||
|
game::Spawn m_RedSpawn, m_BlueSpawn;
|
||||||
|
game::TeamCastle m_RedCastle, m_BlueCastle;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WorldData {
|
||||||
|
std::unordered_map<game::ChunkCoord, game::ChunkPtr> m_Chunks;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace pdata
|
} // namespace pdata
|
||||||
} // namespace protocol
|
} // namespace protocol
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ enum class PacketID : std::uint8_t {
|
|||||||
LoggingSuccess,
|
LoggingSuccess,
|
||||||
PlayerJoin,
|
PlayerJoin,
|
||||||
PlayerLeave,
|
PlayerLeave,
|
||||||
PlayerLogin
|
PlayerLogin,
|
||||||
|
WorldHeader,
|
||||||
|
WorldData,
|
||||||
};
|
};
|
||||||
|
|
||||||
class PacketHandler;
|
class PacketHandler;
|
||||||
@@ -49,13 +51,15 @@ using LoggingSuccessPacket = PacketMessage<pdata::LoggingSuccess, PacketID::Logg
|
|||||||
using PlayerJoinPacket = PacketMessage<pdata::PlayerJoin, PacketID::PlayerJoin>;
|
using PlayerJoinPacket = PacketMessage<pdata::PlayerJoin, PacketID::PlayerJoin>;
|
||||||
using PlayerLeavePacket = PacketMessage<pdata::PlayerLeave, PacketID::PlayerLeave>;
|
using PlayerLeavePacket = PacketMessage<pdata::PlayerLeave, PacketID::PlayerLeave>;
|
||||||
using PlayerLoginPacket = PacketMessage<pdata::PlayerLogin, PacketID::PlayerLogin>;
|
using PlayerLoginPacket = PacketMessage<pdata::PlayerLogin, PacketID::PlayerLogin>;
|
||||||
|
using WorldHeaderPacket = PacketMessage<pdata::WorldHeader, PacketID::WorldHeader>;
|
||||||
|
using WorldDataPacket = PacketMessage<pdata::WorldData, PacketID::WorldData>;
|
||||||
|
|
||||||
|
|
||||||
} // namespace packets
|
} // namespace packets
|
||||||
|
|
||||||
using AllPackets = std::tuple<packets::BeginGamePacket, packets::ChatMessagePacket, packets::DisconnectPacket,
|
using AllPackets = std::tuple<packets::BeginGamePacket, packets::ChatMessagePacket, packets::DisconnectPacket,
|
||||||
packets::KeepAlivePacket, packets::LockStepsPacket, packets::LoggingSuccessPacket, packets::PlayerJoinPacket,
|
packets::KeepAlivePacket, packets::LockStepsPacket, packets::LoggingSuccessPacket, packets::PlayerJoinPacket,
|
||||||
packets::PlayerLeavePacket, packets::PlayerLoginPacket>;
|
packets::PlayerLeavePacket, packets::PlayerLoginPacket, packets::WorldHeaderPacket, packets::WorldDataPacket>;
|
||||||
|
|
||||||
class PacketHandler : public sp::MessageHandler<AllPackets> {};
|
class PacketHandler : public sp::MessageHandler<AllPackets> {};
|
||||||
|
|
||||||
|
|||||||
37
include/td/render/Camera.h
Normal file
37
include/td/render/Camera.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/Maths.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
class Camera {
|
||||||
|
private:
|
||||||
|
Mat4f m_ViewMatrix;
|
||||||
|
Mat4f m_ProjectionMatrix;
|
||||||
|
Mat4f m_InvViewMatrix;
|
||||||
|
Mat4f m_InvProjectionMatrix;
|
||||||
|
|
||||||
|
float m_CamDistance = 25.0f;
|
||||||
|
Vec3f m_CamPos{0, m_CamDistance, 0};
|
||||||
|
Vec2f m_CamLook{};
|
||||||
|
|
||||||
|
float m_Yaw = -PI / 2.0f;
|
||||||
|
float m_Pitch = -PI / 2.0f + 0.0000001f;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Mat4f& GetViewMatrix() const {
|
||||||
|
return m_ViewMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Mat4f& GetProjectionMatrix() const {
|
||||||
|
return m_ProjectionMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdatePerspective(float a_AspectRatio);
|
||||||
|
|
||||||
|
void SetCamPos(const Vec3f& a_NewPos);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace render
|
||||||
|
} // namespace td
|
||||||
8
include/td/render/OpenGL.h
Normal file
8
include/td/render/OpenGL.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef TD_GL_LOADER_GLEW
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#else
|
||||||
|
#include <glbinding/gl/gl.h>
|
||||||
|
using namespace gl;
|
||||||
|
#endif
|
||||||
47
include/td/render/Renderer.h
Normal file
47
include/td/render/Renderer.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/render/Camera.h>
|
||||||
|
#include <td/render/loader/GLLoader.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
class Renderer {
|
||||||
|
protected:
|
||||||
|
Camera& m_Camera;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Renderer(Camera& a_Camera) : m_Camera(a_Camera) {}
|
||||||
|
virtual ~Renderer() {}
|
||||||
|
|
||||||
|
virtual void Render() = 0;
|
||||||
|
|
||||||
|
void Render(const GL::VertexArray& a_Vao);
|
||||||
|
};
|
||||||
|
|
||||||
|
class RenderPipeline {
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<Renderer>> m_Renderers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RenderPipeline();
|
||||||
|
~RenderPipeline() = default;
|
||||||
|
|
||||||
|
void AddRenderer(std::unique_ptr<Renderer>&& a_Renderer) {
|
||||||
|
m_Renderers.push_back(std::move(a_Renderer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear() {
|
||||||
|
m_Renderers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render() {
|
||||||
|
for (auto& renderer : m_Renderers) {
|
||||||
|
renderer->Render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace render
|
||||||
|
} // namespace td
|
||||||
86
include/td/render/loader/GLLoader.h
Normal file
86
include/td/render/loader/GLLoader.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sp/common/NonCopyable.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace GL {
|
||||||
|
|
||||||
|
struct VertexAttribPointer {
|
||||||
|
unsigned int m_Index;
|
||||||
|
unsigned int m_Size;
|
||||||
|
unsigned int m_Offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ElementBuffer : private sp::NonCopyable {
|
||||||
|
private:
|
||||||
|
unsigned int m_ID = 0;
|
||||||
|
std::size_t m_TriangleCount;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ElementBuffer(ElementBuffer&& other) {
|
||||||
|
std::swap(m_ID, other.m_ID);
|
||||||
|
m_TriangleCount = other.m_TriangleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit ElementBuffer(const std::vector<unsigned int>& indicies);
|
||||||
|
~ElementBuffer();
|
||||||
|
|
||||||
|
void Bind() const;
|
||||||
|
void Unbind() const;
|
||||||
|
|
||||||
|
std::size_t GetTriangleCount() const {
|
||||||
|
return m_TriangleCount;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class VertexBuffer : private sp::NonCopyable {
|
||||||
|
private:
|
||||||
|
unsigned int m_ID = 0, m_DataStride;
|
||||||
|
std::vector<VertexAttribPointer> m_VertexAttribs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
VertexBuffer(VertexBuffer&& other) {
|
||||||
|
std::swap(m_ID, other.m_ID);
|
||||||
|
m_VertexAttribs = std::move(other.m_VertexAttribs);
|
||||||
|
m_DataStride = other.m_DataStride;
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexBuffer(const std::vector<float>& data, unsigned int stride);
|
||||||
|
~VertexBuffer();
|
||||||
|
|
||||||
|
void Bind() const;
|
||||||
|
void Unbind() const;
|
||||||
|
void AddVertexAttribPointer(unsigned int index, unsigned int coordinateSize, unsigned int offset);
|
||||||
|
void BindVertexAttribs() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VertexArray : private sp::NonCopyable {
|
||||||
|
private:
|
||||||
|
unsigned int m_ID = 0;
|
||||||
|
ElementBuffer m_ElementBuffer;
|
||||||
|
std::vector<VertexBuffer> m_VertexBuffers; // use to destroy vbos when become unused
|
||||||
|
public:
|
||||||
|
VertexArray(VertexArray&& other) : m_ElementBuffer(std::move(other.m_ElementBuffer)) {
|
||||||
|
std::swap(m_ID, other.m_ID);
|
||||||
|
m_VertexBuffers = std::move(other.m_VertexBuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexArray(ElementBuffer&& indicies);
|
||||||
|
~VertexArray();
|
||||||
|
|
||||||
|
std::size_t GetVertexCount() const {
|
||||||
|
return m_ElementBuffer.GetTriangleCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindVertexBuffer(VertexBuffer&& vbo);
|
||||||
|
void Bind() const;
|
||||||
|
void Unbind() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void BindElementArrayBuffer();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace GL
|
||||||
|
} // namespace td
|
||||||
25
include/td/render/loader/WorldLoader.h
Normal file
25
include/td/render/loader/WorldLoader.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/game/World.h>
|
||||||
|
#include <td/render/loader/GLLoader.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
namespace WorldLoader {
|
||||||
|
|
||||||
|
struct RenderData {
|
||||||
|
std::vector<float> positions;
|
||||||
|
std::vector<float> colors;
|
||||||
|
};
|
||||||
|
|
||||||
|
GL::VertexArray LoadMobModel();
|
||||||
|
GL::VertexArray LoadWorldModel(const td::game::World* world);
|
||||||
|
GL::VertexArray LoadTileSelectModel();
|
||||||
|
RenderData LoadTowerModel(game::TowerPtr tower);
|
||||||
|
|
||||||
|
} // namespace WorldLoader
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace render
|
||||||
|
} // namespace td
|
||||||
25
include/td/render/renderer/WorldRenderer.h
Normal file
25
include/td/render/renderer/WorldRenderer.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/game/World.h>
|
||||||
|
#include <td/render/Renderer.h>
|
||||||
|
#include <td/render/shader/WorldShader.h>
|
||||||
|
#include <td/render/loader/GLLoader.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
class WorldRenderer : public Renderer {
|
||||||
|
private:
|
||||||
|
const game::World& m_World;
|
||||||
|
shader::WorldShader m_Shader;
|
||||||
|
std::unique_ptr<GL::VertexArray> m_WorldVao;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WorldRenderer(Camera& a_Camera, const game::World& a_World);
|
||||||
|
virtual ~WorldRenderer();
|
||||||
|
|
||||||
|
virtual void Render() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace render
|
||||||
|
} // namespace td
|
||||||
30
include/td/render/shader/EntityShader.h
Normal file
30
include/td/render/shader/EntityShader.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/render/shader/ShaderProgram.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace shader {
|
||||||
|
|
||||||
|
class EntityShader : public ShaderProgram {
|
||||||
|
private:
|
||||||
|
unsigned int m_LocationProjectionMatrix = 0;
|
||||||
|
unsigned int m_LocationViewMatrix = 0;
|
||||||
|
unsigned int m_LocationPosition = 0;
|
||||||
|
unsigned int m_LocationColorEffect = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void GetAllUniformLocation();
|
||||||
|
|
||||||
|
public:
|
||||||
|
EntityShader();
|
||||||
|
|
||||||
|
void LoadShader();
|
||||||
|
|
||||||
|
void SetColorEffect(const Vec3f& color);
|
||||||
|
void SetProjectionMatrix(const Mat4f& proj) const;
|
||||||
|
void SetViewMatrix(const Mat4f& view) const;
|
||||||
|
void SetModelPos(const Vec3f& pos) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace shader
|
||||||
|
} // namespace td
|
||||||
43
include/td/render/shader/ShaderProgram.h
Executable file
43
include/td/render/shader/ShaderProgram.h
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/Maths.h>
|
||||||
|
#include <td/render/OpenGL.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace shader {
|
||||||
|
|
||||||
|
class ShaderProgram {
|
||||||
|
public:
|
||||||
|
ShaderProgram();
|
||||||
|
virtual ~ShaderProgram();
|
||||||
|
|
||||||
|
void Start() const;
|
||||||
|
void Stop() const;
|
||||||
|
|
||||||
|
void LoadProgramFile(const std::string& vertexFile, const std::string& fragmentFile);
|
||||||
|
void LoadProgram(const std::string& vertexSource, const std::string& fragmentSource);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void GetAllUniformLocation() = 0;
|
||||||
|
int GetUniformLocation(const std::string& uniformName) const;
|
||||||
|
|
||||||
|
void LoadFloat(unsigned int location, float value) const;
|
||||||
|
void LoadInt(unsigned int location, int value) const;
|
||||||
|
void LoadVector(unsigned int location, const Vec2f& vector) const;
|
||||||
|
void LoadVector(unsigned int location, const Vec3f& vector) const;
|
||||||
|
void LoadBoolean(unsigned int location, bool value) const;
|
||||||
|
void LoadMat4(unsigned int location, const Mat4f& mat) const;
|
||||||
|
void CleanUp() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_ProgramID;
|
||||||
|
unsigned int m_VertexShaderID;
|
||||||
|
unsigned int m_FragmentShaderID;
|
||||||
|
|
||||||
|
unsigned int LoadShaderFromFile(const std::string& file, GLenum type);
|
||||||
|
unsigned int LoadShader(const std::string& source, GLenum type);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace shader
|
||||||
|
} // namespace td
|
||||||
21
include/td/render/shader/WorldShader.h
Normal file
21
include/td/render/shader/WorldShader.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <td/render/shader/ShaderProgram.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace shader {
|
||||||
|
|
||||||
|
class WorldShader : public ShaderProgram {
|
||||||
|
private:
|
||||||
|
unsigned int m_LocationProjection = 0, m_LocationView = 0;
|
||||||
|
protected:
|
||||||
|
void GetAllUniformLocation();
|
||||||
|
public:
|
||||||
|
WorldShader();
|
||||||
|
|
||||||
|
void SetProjectionMatrix(const Mat4f& proj) const;
|
||||||
|
void SetViewMatrix(const Mat4f& view) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace shader
|
||||||
|
} // namespace td
|
||||||
212
src/main.cpp
212
src/main.cpp
@@ -1,18 +1,210 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
// #include <td/protocol/packet/PacketVisitor.h>
|
|
||||||
#include <td/game/GameHistory.h>
|
|
||||||
#include <td/protocol/command/Commands.h>
|
|
||||||
|
|
||||||
class Test : public td::protocol::CommandHandler {};
|
#include <sp/common/DataBuffer.h>
|
||||||
|
#include <sp/extensions/Compress.h>
|
||||||
|
#include <td/input/Display.h>
|
||||||
|
|
||||||
|
#include <td/game/World.h>
|
||||||
|
#include <td/protocol/packet/Packets.h>
|
||||||
|
#include <td/render/renderer/WorldRenderer.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace game {
|
||||||
|
|
||||||
|
sp::DataBuffer& operator>>(sp::DataBuffer& buffer, game::TilePtr& tile) {
|
||||||
|
game::TileType tileType;
|
||||||
|
buffer >> tileType;
|
||||||
|
switch (tileType) {
|
||||||
|
case game::TileType::Tower: {
|
||||||
|
auto tilePtr = std::make_shared<game::TowerTile>();
|
||||||
|
buffer >> tilePtr->color_palette_ref >> tilePtr->team_owner;
|
||||||
|
tile = tilePtr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case game::TileType::Walk: {
|
||||||
|
auto tilePtr = std::make_shared<game::WalkableTile>();
|
||||||
|
buffer >> tilePtr->direction;
|
||||||
|
tile = tilePtr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case game::TileType::Decoration: {
|
||||||
|
auto tilePtr = std::make_shared<game::DecorationTile>();
|
||||||
|
buffer >> tilePtr->color_palette_ref;
|
||||||
|
tile = tilePtr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
} // namespace game
|
||||||
|
} // namespace td
|
||||||
|
|
||||||
|
namespace sp {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void ReadMessage(DataBuffer& a_Buffer, td::protocol::pdata::WorldHeader& a_Header) {
|
||||||
|
a_Buffer >> a_Header.m_TowerPlacePalette >> a_Header.m_WalkablePalette;
|
||||||
|
|
||||||
|
std::uint16_t decoPaletteSize;
|
||||||
|
a_Buffer >> decoPaletteSize;
|
||||||
|
|
||||||
|
std::size_t decoPalletteSizeByte = decoPaletteSize * sizeof(td::Color);
|
||||||
|
|
||||||
|
a_Header.m_DecorationPalette.resize(decoPaletteSize);
|
||||||
|
|
||||||
|
memcpy(reinterpret_cast<std::uint8_t*>(a_Header.m_DecorationPalette.data()), a_Buffer.data() + a_Buffer.GetReadOffset(),
|
||||||
|
decoPalletteSizeByte);
|
||||||
|
|
||||||
|
a_Buffer.SetReadOffset(a_Buffer.GetReadOffset() + decoPalletteSizeByte);
|
||||||
|
|
||||||
|
a_Buffer >> a_Header.m_Background;
|
||||||
|
|
||||||
|
td::utils::shape::Rectangle redCastle, blueCastle;
|
||||||
|
|
||||||
|
a_Buffer >> a_Header.m_RedSpawn >> redCastle;
|
||||||
|
a_Buffer >> a_Header.m_BlueSpawn >> blueCastle;
|
||||||
|
|
||||||
|
a_Header.m_RedCastle.SetShape(redCastle);
|
||||||
|
a_Header.m_BlueCastle.SetShape(blueCastle);
|
||||||
|
|
||||||
|
std::uint64_t tilePaletteSize;
|
||||||
|
a_Buffer >> tilePaletteSize;
|
||||||
|
|
||||||
|
a_Header.m_TilePalette.reserve(tilePaletteSize);
|
||||||
|
|
||||||
|
for (std::uint64_t tileNumber = 0; tileNumber < tilePaletteSize; tileNumber++) {
|
||||||
|
td::game::TilePtr tile;
|
||||||
|
a_Buffer >> tile;
|
||||||
|
a_Header.m_TilePalette.push_back(tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Buffer >> a_Header.m_SpawnColorPalette;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef std::vector<uint64_t> ChunkPackedData;
|
||||||
|
|
||||||
|
const int BITS_IN_BYTE = 8;
|
||||||
|
const int BITS_IN_LONG = BITS_IN_BYTE * sizeof(std::uint64_t);
|
||||||
|
|
||||||
|
static unsigned int countBits(unsigned int number) {
|
||||||
|
// log function in base 2
|
||||||
|
// take only integer part
|
||||||
|
return static_cast<unsigned int>(std::log2(number) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void ReadMessage(DataBuffer& a_Buffer, td::protocol::pdata::WorldData& a_WorldData) {
|
||||||
|
std::uint64_t chunkCount;
|
||||||
|
a_Buffer >> chunkCount;
|
||||||
|
|
||||||
|
for (std::uint64_t chunkNumber = 0; chunkNumber < chunkCount; chunkNumber++) {
|
||||||
|
td::game::ChunkPtr chunk = std::make_shared<td::game::Chunk>();
|
||||||
|
|
||||||
|
td::game::ChunkCoord chunkCoords;
|
||||||
|
a_Buffer >> chunkCoords.x >> chunkCoords.y;
|
||||||
|
|
||||||
|
std::uint64_t chunkPaletteSize;
|
||||||
|
// std::reverse(reinterpret_cast<std::uint8_t*>(&chunkPaletteSize), reinterpret_cast<std::uint8_t*>(&chunkPaletteSize) + 4);
|
||||||
|
a_Buffer >> chunkPaletteSize;
|
||||||
|
|
||||||
|
td::game::ChunkPalette chunkPalette(chunkPaletteSize);
|
||||||
|
|
||||||
|
memcpy(reinterpret_cast<void*>(chunkPalette.data()), a_Buffer.data() + a_Buffer.GetReadOffset(),
|
||||||
|
chunkPaletteSize * sizeof(td::game::ChunkPalette::value_type));
|
||||||
|
a_Buffer.SetReadOffset(a_Buffer.GetReadOffset() + chunkPaletteSize * sizeof(td::game::ChunkPalette::value_type));
|
||||||
|
|
||||||
|
chunk->palette = chunkPalette;
|
||||||
|
|
||||||
|
std::uint8_t bitsPerTile = countBits(chunkPaletteSize);
|
||||||
|
|
||||||
|
// A bitmask that contains bitsPerTile set bits
|
||||||
|
td::game::Chunk::ChunkData::value_type individualValueMask = ((1 << bitsPerTile) - 1);
|
||||||
|
|
||||||
|
ChunkPackedData chunkData(td::game::Chunk::ChunkSize / (BITS_IN_BYTE * sizeof(ChunkPackedData::value_type) / bitsPerTile), 0);
|
||||||
|
|
||||||
|
memcpy(reinterpret_cast<void*>(chunkData.data()), a_Buffer.data() + a_Buffer.GetReadOffset(),
|
||||||
|
chunkData.size() * sizeof(ChunkPackedData::value_type));
|
||||||
|
a_Buffer.SetReadOffset(a_Buffer.GetReadOffset() + chunkData.size() * sizeof(ChunkPackedData::value_type));
|
||||||
|
|
||||||
|
for (unsigned int tileNumber = 0; tileNumber < td::game::Chunk::ChunkSize; tileNumber++) {
|
||||||
|
std::size_t startLong = (tileNumber * bitsPerTile) / BITS_IN_LONG;
|
||||||
|
std::size_t startOffset = (tileNumber * bitsPerTile) % BITS_IN_LONG;
|
||||||
|
std::size_t endLong = ((tileNumber + 1) * bitsPerTile - 1) / BITS_IN_LONG;
|
||||||
|
|
||||||
|
td::game::Chunk::ChunkData::value_type value;
|
||||||
|
if (startLong == endLong) {
|
||||||
|
value = (chunkData[startLong] >> startOffset);
|
||||||
|
} else {
|
||||||
|
int endOffset = BITS_IN_LONG - startOffset;
|
||||||
|
value = (chunkData[startLong] >> startOffset | chunkData[endLong] << endOffset);
|
||||||
|
}
|
||||||
|
value &= individualValueMask;
|
||||||
|
|
||||||
|
chunk->tiles[tileNumber] = value;
|
||||||
|
}
|
||||||
|
a_WorldData.m_Chunks.insert({chunkCoords, chunk});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace sp
|
||||||
|
|
||||||
|
class WorldApply : public td::protocol::PacketHandler {
|
||||||
|
private:
|
||||||
|
td::game::World& m_World;
|
||||||
|
public:
|
||||||
|
WorldApply(td::game::World& a_World) : m_World(a_World) {}
|
||||||
|
|
||||||
|
void Handle(const td::protocol::pdata::WorldHeader& a_Header) override {
|
||||||
|
m_World.LoadMap(a_Header);
|
||||||
|
}
|
||||||
|
void Handle(const td::protocol::pdata::WorldData& a_Data) override {
|
||||||
|
m_World.LoadMap(a_Data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
// Test visitor;
|
sp::DataBuffer buffer;
|
||||||
// td::protocol::packets::ChatMessage chat{{"coucou"}};
|
buffer.ReadFile("test/tdmap.tdmap2");
|
||||||
// visitor.Check(chat);
|
|
||||||
|
|
||||||
|
sp::DataBuffer buffer1 = sp::zlib::Decompress(buffer, 84);
|
||||||
|
buffer.SetReadOffset(buffer.GetReadOffset() + 83);
|
||||||
|
sp::DataBuffer buffer2 = sp::zlib::Decompress(buffer, 511);
|
||||||
|
|
||||||
|
td::protocol::packets::WorldHeaderPacket header;
|
||||||
|
header.Read(buffer1);
|
||||||
|
|
||||||
|
td::protocol::packets::WorldDataPacket data;
|
||||||
|
data.Read(buffer2);
|
||||||
|
|
||||||
|
td::game::World w;
|
||||||
|
WorldApply wa(w);
|
||||||
|
|
||||||
|
td::protocol::PacketDispatcher d;
|
||||||
|
d.RegisterHandler(td::protocol::PacketID::WorldData, &wa);
|
||||||
|
d.RegisterHandler(td::protocol::PacketID::WorldHeader, &wa);
|
||||||
|
|
||||||
|
d.Dispatch(header);
|
||||||
|
d.Dispatch(data);
|
||||||
|
|
||||||
|
td::Display display(1920, 1080, "Tower-Defense 2");
|
||||||
|
|
||||||
|
td::render::Camera cam;
|
||||||
|
cam.SetCamPos({77, 25, 13});
|
||||||
|
cam.UpdatePerspective(display.GetAspectRatio());
|
||||||
|
|
||||||
|
td::render::RenderPipeline renderer;
|
||||||
|
renderer.AddRenderer(std::make_unique<td::render::WorldRenderer>(cam, w));
|
||||||
|
|
||||||
|
while (!display.IsCloseRequested()) {
|
||||||
|
display.PollEvents();
|
||||||
|
renderer.Render();
|
||||||
|
display.Update();
|
||||||
|
}
|
||||||
|
|
||||||
td::protocol::commands::UpgradeTowerCommand com{1, 2};
|
|
||||||
std::cout << (unsigned)com.GetId() << std::endl;
|
|
||||||
td::protocol::CommandDispatcher disptacher;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
169
src/td/Maths.cpp
Normal file
169
src/td/Maths.cpp
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
#include <td/Maths.h>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace maths {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T Length(const Vec3<T>& vect) {
|
||||||
|
return std::sqrt(vect.x * vect.x + vect.y * vect.y + vect.z * vect.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vec3<T> Normalize(const Vec3<T>& vect) {
|
||||||
|
T length = Length(vect);
|
||||||
|
|
||||||
|
return {vect.x / length, vect.y / length, vect.z / length};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vec4<T> Normalize(const Vec4<T>& vect) {
|
||||||
|
T length = std::sqrt(vect.x * vect.x + vect.y * vect.y + vect.z * vect.z + vect.w * vect.w);
|
||||||
|
|
||||||
|
return {vect.x / length, vect.y / length, vect.z / length, vect.w / length};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T Dot(const Vec3<T>& vect, const Vec3<T>& other) {
|
||||||
|
return vect.x * other.x + vect.y * other.y + vect.z * other.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vec3<T> Cross(const Vec3<T>& vect, const Vec3<T>& other) {
|
||||||
|
return {
|
||||||
|
vect.y * other.z - vect.z * other.y,
|
||||||
|
vect.z * other.x - vect.x * other.z,
|
||||||
|
vect.x * other.y - vect.y * other.x,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T Dot(const Vec4<T>& vect, const Vec4<T>& other) {
|
||||||
|
return vect.x * other.x + vect.y * other.y + vect.z * other.z + vect.w * other.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T Distance(const Vec3<T>& vect, const Vec3<T>& other) {
|
||||||
|
return Length(vect - other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vec4<T> Dot(const Mat4<T>& mat, const Vec4<T>& vect) {
|
||||||
|
return {mat.x0 * vect.x + mat.x1 * vect.y + mat.x2 * vect.z + mat.x3 * vect.w,
|
||||||
|
mat.y0 * vect.x + mat.y1 * vect.y + mat.y2 * vect.z + mat.y3 * vect.w,
|
||||||
|
mat.z0 * vect.x + mat.z1 * vect.y + mat.z2 * vect.z + mat.z3 * vect.w,
|
||||||
|
mat.w0 * vect.x + mat.w1 * vect.y + mat.w2 * vect.z + mat.w3 * vect.w};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Mat4<T> Dot(const Mat4<T>& mat, const Mat4<T>& other) {
|
||||||
|
Mat4<T> result{};
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < Mat4<T>::MATRIX_SIZE; i++) {
|
||||||
|
for (std::size_t j = 0; j < Mat4<T>::MATRIX_SIZE; j++) {
|
||||||
|
for (std::size_t k = 0; k < Mat4<T>::MATRIX_SIZE; k++) {
|
||||||
|
result.at(i, j) += mat.at(i, k) * other.at(k, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Mat4<T> Identity() {
|
||||||
|
Mat4<T> result{};
|
||||||
|
|
||||||
|
result.x0 = static_cast<T>(1);
|
||||||
|
result.y1 = static_cast<T>(1);
|
||||||
|
result.z2 = static_cast<T>(1);
|
||||||
|
result.w3 = static_cast<T>(1);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat4f Perspective(float fovY, float aspectRatio, float zNear, float zFar) {
|
||||||
|
const float tanHalfFovy = std::tan(fovY / 2.0f);
|
||||||
|
|
||||||
|
Mat4f result{};
|
||||||
|
result.x0 = 1.0f / (aspectRatio * tanHalfFovy);
|
||||||
|
result.y1 = 1.0f / (tanHalfFovy);
|
||||||
|
result.z2 = -(zFar + zNear) / (zFar - zNear);
|
||||||
|
result.z3 = -1.0f;
|
||||||
|
result.w2 = -(2.0f * zFar * zNear) / (zFar - zNear);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat4f Look(const Vec3f& eye, const Vec3f& center, const Vec3f& up) {
|
||||||
|
const Vec3f f = Normalize(center);
|
||||||
|
const Vec3f s = Normalize(Cross(f, up));
|
||||||
|
const Vec3f u = Cross(s, f);
|
||||||
|
|
||||||
|
Mat4f result = Identity<float>();
|
||||||
|
result.x0 = s.x;
|
||||||
|
result.y0 = s.y;
|
||||||
|
result.z0 = s.z;
|
||||||
|
result.x1 = u.x;
|
||||||
|
result.y1 = u.y;
|
||||||
|
result.z1 = u.z;
|
||||||
|
result.x2 = -f.x;
|
||||||
|
result.y2 = -f.y;
|
||||||
|
result.z2 = -f.z;
|
||||||
|
result.w0 = -Dot(s, eye);
|
||||||
|
result.w1 = -Dot(u, eye);
|
||||||
|
result.w2 = Dot(f, eye);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat4f Inverse(const Mat4f& mat) {
|
||||||
|
float s0 = mat.at(0, 0) * mat.at(1, 1) - mat.at(1, 0) * mat.at(0, 1);
|
||||||
|
float s1 = mat.at(0, 0) * mat.at(1, 2) - mat.at(1, 0) * mat.at(0, 2);
|
||||||
|
float s2 = mat.at(0, 0) * mat.at(1, 3) - mat.at(1, 0) * mat.at(0, 3);
|
||||||
|
float s3 = mat.at(0, 1) * mat.at(1, 2) - mat.at(1, 1) * mat.at(0, 2);
|
||||||
|
float s4 = mat.at(0, 1) * mat.at(1, 3) - mat.at(1, 1) * mat.at(0, 3);
|
||||||
|
float s5 = mat.at(0, 2) * mat.at(1, 3) - mat.at(1, 2) * mat.at(0, 3);
|
||||||
|
|
||||||
|
float c5 = mat.at(2, 2) * mat.at(3, 3) - mat.at(3, 2) * mat.at(2, 3);
|
||||||
|
float c4 = mat.at(2, 1) * mat.at(3, 3) - mat.at(3, 1) * mat.at(2, 3);
|
||||||
|
float c3 = mat.at(2, 1) * mat.at(3, 2) - mat.at(3, 1) * mat.at(2, 2);
|
||||||
|
float c2 = mat.at(2, 0) * mat.at(3, 3) - mat.at(3, 0) * mat.at(2, 3);
|
||||||
|
float c1 = mat.at(2, 0) * mat.at(3, 2) - mat.at(3, 0) * mat.at(2, 2);
|
||||||
|
float c0 = mat.at(2, 0) * mat.at(3, 1) - mat.at(3, 0) * mat.at(2, 1);
|
||||||
|
|
||||||
|
float det = s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0;
|
||||||
|
|
||||||
|
assert(det != 0 && "Determinant equals 0 !");
|
||||||
|
|
||||||
|
float invdet = 1.0 / det;
|
||||||
|
|
||||||
|
Mat4f result;
|
||||||
|
|
||||||
|
result.at(0, 0) = (mat.at(1, 1) * c5 - mat.at(1, 2) * c4 + mat.at(1, 3) * c3) * invdet;
|
||||||
|
result.at(0, 1) = (-mat.at(0, 1) * c5 + mat.at(0, 2) * c4 - mat.at(0, 3) * c3) * invdet;
|
||||||
|
result.at(0, 2) = (mat.at(3, 1) * s5 - mat.at(3, 2) * s4 + mat.at(3, 3) * s3) * invdet;
|
||||||
|
result.at(0, 3) = (-mat.at(2, 1) * s5 + mat.at(2, 2) * s4 - mat.at(2, 3) * s3) * invdet;
|
||||||
|
|
||||||
|
result.at(1, 0) = (-mat.at(1, 0) * c5 + mat.at(1, 2) * c2 - mat.at(1, 3) * c1) * invdet;
|
||||||
|
result.at(1, 1) = (mat.at(0, 0) * c5 - mat.at(0, 2) * c2 + mat.at(0, 3) * c1) * invdet;
|
||||||
|
result.at(1, 2) = (-mat.at(3, 0) * s5 + mat.at(3, 2) * s2 - mat.at(3, 3) * s1) * invdet;
|
||||||
|
result.at(1, 3) = (mat.at(2, 0) * s5 - mat.at(2, 2) * s2 + mat.at(2, 3) * s1) * invdet;
|
||||||
|
|
||||||
|
result.at(2, 0) = (mat.at(1, 0) * c4 - mat.at(1, 1) * c2 + mat.at(1, 3) * c0) * invdet;
|
||||||
|
result.at(2, 1) = (-mat.at(0, 0) * c4 + mat.at(0, 1) * c2 - mat.at(0, 3) * c0) * invdet;
|
||||||
|
result.at(2, 2) = (mat.at(3, 0) * s4 - mat.at(3, 1) * s2 + mat.at(3, 3) * s0) * invdet;
|
||||||
|
result.at(2, 3) = (-mat.at(2, 0) * s4 + mat.at(2, 1) * s2 - mat.at(2, 3) * s0) * invdet;
|
||||||
|
|
||||||
|
result.at(3, 0) = (-mat.at(1, 0) * c3 + mat.at(1, 1) * c1 - mat.at(1, 2) * c0) * invdet;
|
||||||
|
result.at(3, 1) = (mat.at(0, 0) * c3 - mat.at(0, 1) * c1 + mat.at(0, 2) * c0) * invdet;
|
||||||
|
result.at(3, 2) = (-mat.at(3, 0) * s3 + mat.at(3, 1) * s1 - mat.at(3, 2) * s0) * invdet;
|
||||||
|
result.at(3, 3) = (mat.at(2, 0) * s3 - mat.at(2, 1) * s1 + mat.at(2, 2) * s0) * invdet;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace maths
|
||||||
|
} // namespace td
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
#include <td/common/DataBuffer.h>
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <td/misc/Format.h>
|
|
||||||
#include <td/misc/Log.h>
|
|
||||||
|
|
||||||
namespace td {
|
|
||||||
|
|
||||||
DataBuffer::DataBuffer() : m_ReadOffset(0) {}
|
|
||||||
|
|
||||||
DataBuffer::DataBuffer(const DataBuffer& other) : m_Buffer(other.m_Buffer), m_ReadOffset(other.m_ReadOffset) {}
|
|
||||||
|
|
||||||
DataBuffer::DataBuffer(DataBuffer&& other) : m_Buffer(std::move(other.m_Buffer)), m_ReadOffset(std::move(other.m_ReadOffset)) {}
|
|
||||||
|
|
||||||
DataBuffer::DataBuffer(const std::string& str) : m_Buffer(str.begin(), str.end()), m_ReadOffset(0) {}
|
|
||||||
|
|
||||||
DataBuffer::DataBuffer(const DataBuffer& other, Data::difference_type offset) : m_ReadOffset(0) {
|
|
||||||
m_Buffer.reserve(other.GetSize() - static_cast<std::size_t>(offset));
|
|
||||||
std::copy(other.m_Buffer.begin() + offset, other.m_Buffer.end(), std::back_inserter(m_Buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
DataBuffer& DataBuffer::operator<<(const std::string& str) {
|
|
||||||
std::size_t strlen = str.length() + 1; // including null character
|
|
||||||
Resize(GetSize() + strlen);
|
|
||||||
std::memcpy(m_Buffer.data() + GetSize() - strlen, str.data(), strlen);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataBuffer& DataBuffer::operator<<(const DataBuffer& data) {
|
|
||||||
m_Buffer.insert(m_Buffer.end(), data.begin(), data.end());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataBuffer& DataBuffer::operator>>(std::string& str) {
|
|
||||||
std::size_t stringSize = strlen(reinterpret_cast<const char*>(m_Buffer.data()) + m_ReadOffset) + 1; // including null character
|
|
||||||
str.resize(stringSize);
|
|
||||||
std::copy(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset),
|
|
||||||
m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset + stringSize), str.begin());
|
|
||||||
m_ReadOffset += stringSize;
|
|
||||||
str.resize(stringSize - 1);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataBuffer& DataBuffer::operator>>(DataBuffer& data) {
|
|
||||||
data.Resize(GetSize() - m_ReadOffset);
|
|
||||||
std::copy(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset), m_Buffer.end(), data.begin());
|
|
||||||
m_ReadOffset = m_Buffer.size();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataBuffer::WriteSome(const char* buffer, std::size_t amount) {
|
|
||||||
std::size_t end_pos = m_Buffer.size();
|
|
||||||
m_Buffer.resize(m_Buffer.size() + amount);
|
|
||||||
std::memcpy(m_Buffer.data() + end_pos, buffer, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataBuffer::WriteSome(const std::uint8_t* buffer, std::size_t amount) {
|
|
||||||
std::size_t end_pos = m_Buffer.size();
|
|
||||||
m_Buffer.resize(m_Buffer.size() + amount);
|
|
||||||
std::memcpy(m_Buffer.data() + end_pos, buffer, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataBuffer::ReadSome(char* buffer, std::size_t amount) {
|
|
||||||
assert(m_ReadOffset + amount <= GetSize());
|
|
||||||
std::copy_n(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset), amount, buffer);
|
|
||||||
m_ReadOffset += amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DataBuffer::ReadSome(std::uint8_t* buffer, std::size_t amount) {
|
|
||||||
assert(m_ReadOffset + amount <= GetSize());
|
|
||||||
std::copy_n(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset), amount, buffer);
|
|
||||||
m_ReadOffset += amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DataBuffer::ReadSome(DataBuffer& buffer, std::size_t amount) {
|
|
||||||
assert(m_ReadOffset + amount <= GetSize());
|
|
||||||
buffer.Resize(amount);
|
|
||||||
std::copy_n(m_Buffer.begin() + static_cast<difference_type>(m_ReadOffset), amount, buffer.begin());
|
|
||||||
m_ReadOffset += amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DataBuffer& DataBuffer::operator=(const DataBuffer& other) {
|
|
||||||
m_Buffer = other.m_Buffer;
|
|
||||||
m_ReadOffset = other.m_ReadOffset;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataBuffer& DataBuffer::operator=(DataBuffer&& other) {
|
|
||||||
m_Buffer = std::move(other.m_Buffer);
|
|
||||||
m_ReadOffset = std::move(other.m_ReadOffset);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataBuffer::SetReadOffset(std::size_t pos) {
|
|
||||||
assert(pos <= GetSize());
|
|
||||||
m_ReadOffset = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t DataBuffer::GetSize() const {
|
|
||||||
return m_Buffer.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t DataBuffer::GetRemaining() const {
|
|
||||||
return m_Buffer.size() - m_ReadOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataBuffer::iterator DataBuffer::begin() {
|
|
||||||
return m_Buffer.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
DataBuffer::iterator DataBuffer::end() {
|
|
||||||
return m_Buffer.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
DataBuffer::const_iterator DataBuffer::begin() const {
|
|
||||||
return m_Buffer.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
DataBuffer::const_iterator DataBuffer::end() const {
|
|
||||||
return m_Buffer.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer) {
|
|
||||||
for (unsigned char u : buffer)
|
|
||||||
os << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(u) << " ";
|
|
||||||
os << std::dec;
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DataBuffer::ReadFile(const std::string& fileName) {
|
|
||||||
try {
|
|
||||||
std::ifstream file(fileName, std::istream::binary);
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << file.rdbuf();
|
|
||||||
const std::string& s = ss.str();
|
|
||||||
m_Buffer = DataBuffer::Data(s.begin(), s.end());
|
|
||||||
m_ReadOffset = 0;
|
|
||||||
} catch (std::exception& e) {
|
|
||||||
utils::LOGE(utils::Format("[IO] Failed to read file %s ! reason : %s", fileName.c_str(), e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return m_Buffer.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DataBuffer::WriteFile(const std::string& fileName) const {
|
|
||||||
try {
|
|
||||||
std::ofstream file(fileName, std::ostream::binary);
|
|
||||||
file.write(reinterpret_cast<const char*>(m_Buffer.data()), static_cast<std::streamsize>(m_Buffer.size()));
|
|
||||||
file.flush();
|
|
||||||
} catch (std::exception& e) {
|
|
||||||
utils::LOGE(utils::Format("[IO] Failed to read file %s ! reason : %s", fileName.c_str(), e.what()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace td
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
#include <td/common/VarInt.h>
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <td/common/DataBuffer.h>
|
|
||||||
|
|
||||||
namespace td {
|
|
||||||
|
|
||||||
static constexpr int SEGMENT_BITS = 0x7F;
|
|
||||||
static constexpr int CONTINUE_BIT = 0x80;
|
|
||||||
|
|
||||||
std::size_t VarInt::GetSerializedLength() const {
|
|
||||||
DataBuffer buffer;
|
|
||||||
buffer << *this;
|
|
||||||
return buffer.GetSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
DataBuffer& operator<<(DataBuffer& out, const VarInt& var) {
|
|
||||||
std::uint64_t value = var.m_Value;
|
|
||||||
while (true) {
|
|
||||||
if ((value & ~static_cast<std::uint64_t>(SEGMENT_BITS)) == 0) {
|
|
||||||
out << static_cast<std::uint8_t>(value);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out << static_cast<std::uint8_t>((value & SEGMENT_BITS) | CONTINUE_BIT);
|
|
||||||
|
|
||||||
value >>= 7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DataBuffer& operator>>(DataBuffer& in, VarInt& var) {
|
|
||||||
var.m_Value = 0;
|
|
||||||
unsigned int position = 0;
|
|
||||||
std::uint8_t currentByte;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
in.ReadSome(¤tByte, 1);
|
|
||||||
var.m_Value |= static_cast<std::uint64_t>(currentByte & SEGMENT_BITS) << position;
|
|
||||||
|
|
||||||
if ((currentByte & CONTINUE_BIT) == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
position += 7;
|
|
||||||
|
|
||||||
if (position >= 8 * sizeof(var.m_Value))
|
|
||||||
throw std::runtime_error("VarInt is too big");
|
|
||||||
}
|
|
||||||
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace td
|
|
||||||
59
src/td/game/World.cpp
Normal file
59
src/td/game/World.cpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#include <td/game/World.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace game {
|
||||||
|
|
||||||
|
World::World() : m_Teams{Team{TeamColor::Red}, Team{TeamColor::Blue}} {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const Color* World::GetTileColor(TilePtr tile) const {
|
||||||
|
switch (tile->GetType()) {
|
||||||
|
case TileType::Tower: {
|
||||||
|
TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get());
|
||||||
|
return &m_TowerPlacePalette[towerTile->color_palette_ref];
|
||||||
|
}
|
||||||
|
case TileType::Walk: {
|
||||||
|
return &m_WalkablePalette;
|
||||||
|
}
|
||||||
|
case TileType::Decoration: {
|
||||||
|
DecorationTile* towerTile = dynamic_cast<DecorationTile*>(tile.get());
|
||||||
|
return &m_DecorationPalette[towerTile->color_palette_ref];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool World::LoadMap(const protocol::pdata::WorldHeader& a_WorldHeader) {
|
||||||
|
m_TowerPlacePalette = a_WorldHeader.m_TowerPlacePalette;
|
||||||
|
m_WalkablePalette = a_WorldHeader.m_WalkablePalette;
|
||||||
|
m_DecorationPalette = a_WorldHeader.m_DecorationPalette;
|
||||||
|
m_Background = a_WorldHeader.m_Background;
|
||||||
|
|
||||||
|
GetRedTeam().GetSpawn() = a_WorldHeader.m_RedSpawn;
|
||||||
|
GetBlueTeam().GetSpawn() = a_WorldHeader.m_BlueSpawn;
|
||||||
|
|
||||||
|
m_SpawnColorPalette = a_WorldHeader.m_SpawnColorPalette;
|
||||||
|
|
||||||
|
GetRedTeam().GetCastle() = a_WorldHeader.m_RedCastle;
|
||||||
|
GetRedTeam().GetCastle().SetTeam(&GetRedTeam());
|
||||||
|
|
||||||
|
GetBlueTeam().GetCastle() = a_WorldHeader.m_BlueCastle;
|
||||||
|
GetBlueTeam().GetCastle().SetTeam(&GetBlueTeam());
|
||||||
|
|
||||||
|
m_TilePalette = a_WorldHeader.m_TilePalette;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool World::LoadMap(const protocol::pdata::WorldData& a_WorldData) {
|
||||||
|
m_Chunks = a_WorldData.m_Chunks;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace game
|
||||||
|
} // namespace td
|
||||||
156
src/td/input/Display.cpp
Normal file
156
src/td/input/Display.cpp
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
#include <td/input/Display.h>
|
||||||
|
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_impl_opengl3.h>
|
||||||
|
#include <imgui_impl_sdl3.h>
|
||||||
|
|
||||||
|
#include <td/misc/Format.h>
|
||||||
|
#include <td/misc/Log.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
Display::Display(int a_Width, int a_Height, const std::string& a_Title) :
|
||||||
|
m_LastWidth(0), m_LastHeight(0), m_AspectRatio(1), m_ShouldClose(false) {
|
||||||
|
|
||||||
|
m_Window = SDL_CreateWindow(a_Title.c_str(), a_Width, a_Height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||||
|
|
||||||
|
m_LastWidth = a_Width;
|
||||||
|
m_LastHeight = a_Height;
|
||||||
|
m_AspectRatio = (float)m_LastWidth / m_LastHeight;
|
||||||
|
|
||||||
|
// Prepare and create context
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||||
|
#else
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||||
|
#endif
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
|
||||||
|
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||||
|
|
||||||
|
m_GLContext = SDL_GL_CreateContext(m_Window);
|
||||||
|
|
||||||
|
if (!m_GLContext) {
|
||||||
|
utils::LOGE(utils::Format("Could not create context! SDL error: %s", SDL_GetError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int major, minor, mask;
|
||||||
|
int r, g, b, a, depth;
|
||||||
|
SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &mask);
|
||||||
|
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
|
||||||
|
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);
|
||||||
|
|
||||||
|
SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r);
|
||||||
|
SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g);
|
||||||
|
SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b);
|
||||||
|
SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &a);
|
||||||
|
|
||||||
|
SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depth);
|
||||||
|
|
||||||
|
const char* mask_desc;
|
||||||
|
|
||||||
|
if (mask & SDL_GL_CONTEXT_PROFILE_CORE) {
|
||||||
|
mask_desc = "core";
|
||||||
|
} else if (mask & SDL_GL_CONTEXT_PROFILE_COMPATIBILITY) {
|
||||||
|
mask_desc = "compatibility";
|
||||||
|
} else if (mask & SDL_GL_CONTEXT_PROFILE_ES) {
|
||||||
|
mask_desc = "es";
|
||||||
|
} else {
|
||||||
|
mask_desc = "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::LOG(utils::Format(
|
||||||
|
"GL Context : %i.%i %s, Color : R:%i G:%i B:%i A:%i, Depth bits : %i", major, minor, mask_desc, r, g, b, a, depth));
|
||||||
|
|
||||||
|
SDL_GL_MakeCurrent(m_Window, m_GLContext);
|
||||||
|
|
||||||
|
GLenum error = glewInit();
|
||||||
|
if (error) {
|
||||||
|
utils::LOGE(utils::Format("Error initializing glew : %s", glewGetErrorString(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// WindowResizeEvent(WindowWidth, WindowHeight);
|
||||||
|
|
||||||
|
// Setup Dear ImGui context
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
(void)io;
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||||
|
|
||||||
|
// Setup Dear ImGui style
|
||||||
|
ImGui::StyleColorsDark();
|
||||||
|
// ImGui::StyleColorsLight();
|
||||||
|
|
||||||
|
// Setup scaling
|
||||||
|
float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
|
||||||
|
ImGuiStyle& style = ImGui::GetStyle();
|
||||||
|
style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this
|
||||||
|
// requires resetting Style + calling this again)
|
||||||
|
style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave
|
||||||
|
// both here for documentation purpose)
|
||||||
|
|
||||||
|
// Setup Platform/Renderer backends
|
||||||
|
ImGui_ImplSDL3_InitForOpenGL(m_Window, m_GLContext);
|
||||||
|
ImGui_ImplOpenGL3_Init("#version 330");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Display::PollEvents() {
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_EVENT_QUIT:
|
||||||
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED: {
|
||||||
|
m_ShouldClose = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SDL_EVENT_WINDOW_RESIZED: {
|
||||||
|
m_LastWidth = event.window.data1;
|
||||||
|
m_LastHeight = event.window.data2;
|
||||||
|
m_AspectRatio = (float)m_LastWidth / m_LastHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ImGui_ImplSDL3_ProcessEvent(&event);
|
||||||
|
}
|
||||||
|
// Start the Dear ImGui frame
|
||||||
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
ImGui_ImplSDL3_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Display::Update() {
|
||||||
|
ImGui::Render();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
||||||
|
// glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
|
||||||
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
SDL_GL_SwapWindow(m_Window);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Display::~Display() {
|
||||||
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
|
ImGui_ImplSDL3_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
SDL_GL_DestroyContext(m_GLContext);
|
||||||
|
SDL_DestroyWindow(m_Window);
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace td
|
||||||
26
src/td/render/Camera.cpp
Normal file
26
src/td/render/Camera.cpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include <td/render/Camera.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
void Camera::UpdatePerspective(float a_AspectRatio) {
|
||||||
|
m_ProjectionMatrix = maths::Perspective(80.0f / 180.0f * PI, a_AspectRatio, 0.1f, 160.0f);
|
||||||
|
m_InvProjectionMatrix = maths::Inverse(m_ProjectionMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::SetCamPos(const Vec3f& a_NewPos) {
|
||||||
|
Vec3f front = {
|
||||||
|
std::cos(m_Yaw) * std::cos(m_Pitch),
|
||||||
|
std::sin(m_Pitch),
|
||||||
|
std::sin(m_Yaw) * std::cos(m_Pitch)
|
||||||
|
};
|
||||||
|
|
||||||
|
m_CamPos = a_NewPos;
|
||||||
|
m_ViewMatrix = maths::Look(m_CamPos, front, { 0, 1, 0 });
|
||||||
|
m_InvViewMatrix = maths::Transpose(maths::Inverse(m_ViewMatrix)); // why transpose ? I don't know
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace render
|
||||||
|
} // namespace td
|
||||||
26
src/td/render/Renderer.cpp
Normal file
26
src/td/render/Renderer.cpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include <td/render/Renderer.h>
|
||||||
|
|
||||||
|
#include <td/render/OpenGL.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
void Renderer::Render(const GL::VertexArray& a_Vao) {
|
||||||
|
a_Vao.Bind();
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, a_Vao.GetVertexCount());
|
||||||
|
// glDrawElements(GL_TRIANGLES, a_Vao.GetVertexCount(), GL_UNSIGNED_INT, nullptr);
|
||||||
|
a_Vao.Unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderPipeline::RenderPipeline() {
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
glFrontFace(GL_CCW);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace render
|
||||||
|
} // namespace td
|
||||||
99
src/td/render/loader/GLLoader.cpp
Normal file
99
src/td/render/loader/GLLoader.cpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#include <td/render/loader/GLLoader.h>
|
||||||
|
|
||||||
|
#include <td/render/OpenGL.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace GL {
|
||||||
|
|
||||||
|
VertexArray::~VertexArray() {
|
||||||
|
if (m_ID != 0)
|
||||||
|
glDeleteVertexArrays(1, &m_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexArray::VertexArray(ElementBuffer&& indicies) : m_ElementBuffer(std::move(indicies)) {
|
||||||
|
glGenVertexArrays(1, &m_ID);
|
||||||
|
Bind();
|
||||||
|
BindElementArrayBuffer();
|
||||||
|
// Unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexArray::Bind() const {
|
||||||
|
glBindVertexArray(m_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexArray::Unbind() const {
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexArray::BindVertexBuffer(VertexBuffer&& VertexBuffer) {
|
||||||
|
VertexBuffer.Bind();
|
||||||
|
VertexBuffer.BindVertexAttribs();
|
||||||
|
m_VertexBuffers.push_back(std::move(VertexBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexArray::BindElementArrayBuffer() {
|
||||||
|
m_ElementBuffer.Bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexBuffer::~VertexBuffer() {
|
||||||
|
if (m_ID != 0)
|
||||||
|
glDeleteBuffers(1, &m_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexBuffer::VertexBuffer(const std::vector<float>& data, unsigned int stride) : m_DataStride(stride) {
|
||||||
|
glGenBuffers(1, &m_ID);
|
||||||
|
Bind();
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(data.size() * sizeof(float)), nullptr, GL_STATIC_DRAW);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, static_cast<GLsizeiptr>(data.size() * sizeof(float)), data.data());
|
||||||
|
Unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexBuffer::Bind() const {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, m_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexBuffer::Unbind() const {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexBuffer::AddVertexAttribPointer(unsigned int index, unsigned int coordinateSize, unsigned int offset) {
|
||||||
|
VertexAttribPointer pointer {
|
||||||
|
.m_Index = index,
|
||||||
|
.m_Size = coordinateSize,
|
||||||
|
.m_Offset = offset
|
||||||
|
};
|
||||||
|
m_VertexAttribs.push_back(pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexBuffer::BindVertexAttribs() const {
|
||||||
|
for (const VertexAttribPointer& pointer : m_VertexAttribs) {
|
||||||
|
glVertexAttribPointer(pointer.m_Index, static_cast<GLint>(pointer.m_Size), GL_FLOAT, false, m_DataStride * sizeof(float),
|
||||||
|
reinterpret_cast<GLvoid*>(static_cast<std::size_t>(pointer.m_Offset)));
|
||||||
|
glEnableVertexAttribArray(pointer.m_Index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementBuffer::ElementBuffer(const std::vector<unsigned int>& indicies) {
|
||||||
|
m_TriangleCount = indicies.size();
|
||||||
|
glGenBuffers(1, &m_ID);
|
||||||
|
Bind();
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLsizeiptr>(indicies.size() * sizeof(unsigned int)), nullptr, GL_STATIC_DRAW);
|
||||||
|
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, static_cast<GLsizeiptr>(indicies.size() * sizeof(unsigned int)), indicies.data());
|
||||||
|
Unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementBuffer::~ElementBuffer() {
|
||||||
|
if (m_ID != 0)
|
||||||
|
glDeleteBuffers(1, &m_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElementBuffer::Bind() const {
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElementBuffer::Unbind() const {
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace GL
|
||||||
|
} // namespace td
|
||||||
218
src/td/render/loader/WorldLoader.cpp
Normal file
218
src/td/render/loader/WorldLoader.cpp
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
#include <td/render/loader/WorldLoader.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <td/game/World.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
namespace WorldLoader {
|
||||||
|
|
||||||
|
const static int POSITION_VERTEX_SIZE = 3;
|
||||||
|
const static int TEXTURE_VERTEX_SIZE = 2;
|
||||||
|
|
||||||
|
GL::VertexArray LoadWorldModel(const td::game::World* world) {
|
||||||
|
std::vector<float> positions;
|
||||||
|
std::vector<float> colors;
|
||||||
|
|
||||||
|
for (const auto& chunkInfo : world->GetChunks()) {
|
||||||
|
const td::game::ChunkCoord& coords = chunkInfo.first;
|
||||||
|
td::game::ChunkPtr chunk = chunkInfo.second;
|
||||||
|
|
||||||
|
std::int32_t chunkX = coords.x * td::game::Chunk::ChunkWidth;
|
||||||
|
std::int32_t chunkY = coords.y * td::game::Chunk::ChunkHeight;
|
||||||
|
|
||||||
|
for (int tileY = 0; tileY < td::game::Chunk::ChunkHeight; tileY++) {
|
||||||
|
for (int tileX = 0; tileX < td::game::Chunk::ChunkWidth; tileX++) {
|
||||||
|
int tileNumber = tileY * td::game::Chunk::ChunkWidth + tileX;
|
||||||
|
td::game::TileIndex tileIndex = chunk->GetTileIndex(tileNumber);
|
||||||
|
td::game::TilePtr tile = world->GetTilePtr(tileIndex);
|
||||||
|
|
||||||
|
if (tile == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
positions.insert(
|
||||||
|
positions.end(), {static_cast<float>(chunkX + tileX + 1), 0, static_cast<float>(chunkY + tileY),
|
||||||
|
static_cast<float>(chunkX + tileX), 0, static_cast<float>(chunkY + tileY),
|
||||||
|
static_cast<float>(chunkX + tileX), 0, static_cast<float>(chunkY + tileY + 1),
|
||||||
|
|
||||||
|
static_cast<float>(chunkX + tileX + 1), 0, static_cast<float>(chunkY + tileY),
|
||||||
|
static_cast<float>(chunkX + tileX), 0, static_cast<float>(chunkY + tileY + 1),
|
||||||
|
static_cast<float>(chunkX + tileX + 1), 0, static_cast<float>(chunkY + tileY + 1)});
|
||||||
|
|
||||||
|
const td::Color* tileColor = world->GetTileColor(tile);
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
int color = 255;
|
||||||
|
color |= tileColor->r << 24;
|
||||||
|
color |= tileColor->g << 16;
|
||||||
|
color |= tileColor->b << 8;
|
||||||
|
|
||||||
|
int newColorIndex = colors.size();
|
||||||
|
colors.push_back(0);
|
||||||
|
|
||||||
|
memcpy(colors.data() + newColorIndex, &color, 1 * sizeof(int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int spawnColor = 0; spawnColor < 2; spawnColor++) {
|
||||||
|
const game::Spawn& spawn = world->GetTeam(TeamColor(spawnColor)).GetSpawn();
|
||||||
|
float fromX = spawn.GetTopLeft().GetX(), toX = spawn.GetBottomRight().GetX();
|
||||||
|
float fromY = spawn.GetTopLeft().GetY(), toY = spawn.GetBottomRight().GetY();
|
||||||
|
|
||||||
|
positions.insert(positions.end(), {fromX, 0, fromY, fromX, 0, toY, toX, 0, fromY, fromX, 0, toY, toX, 0, toY, toX, 0, fromY});
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
int color = 255;
|
||||||
|
color |= world->GetSpawnColor(TeamColor(spawnColor)).r << 24;
|
||||||
|
color |= world->GetSpawnColor(TeamColor(spawnColor)).g << 16;
|
||||||
|
color |= world->GetSpawnColor(TeamColor(spawnColor)).b << 8;
|
||||||
|
|
||||||
|
int newColorIndex = colors.size();
|
||||||
|
colors.push_back(0);
|
||||||
|
|
||||||
|
memcpy(colors.data() + newColorIndex, &color, 1 * sizeof(int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int castleColor = 0; castleColor < 2; castleColor++) {
|
||||||
|
const game::TeamCastle& castle = world->GetTeam(TeamColor(castleColor)).GetCastle();
|
||||||
|
float fromX = castle.GetTopLeft().GetX(), toX = castle.GetBottomRight().GetX();
|
||||||
|
float fromY = castle.GetTopLeft().GetY(), toY = castle.GetBottomRight().GetY();
|
||||||
|
|
||||||
|
positions.insert(positions.end(), {fromX, 0, fromY, fromX, 0, toY, toX, 0, fromY, fromX, 0, toY, toX, 0, toY, toX, 0, fromY});
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
int color = 255;
|
||||||
|
color |= world->GetSpawnColor(TeamColor(castleColor)).r << 24;
|
||||||
|
color |= world->GetSpawnColor(TeamColor(castleColor)).g << 16;
|
||||||
|
color |= world->GetSpawnColor(TeamColor(castleColor)).b << 8;
|
||||||
|
|
||||||
|
int newColorIndex = colors.size();
|
||||||
|
colors.push_back(0);
|
||||||
|
|
||||||
|
memcpy(colors.data() + newColorIndex, &color, 1 * sizeof(int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GL::VertexBuffer positionVBO(positions, POSITION_VERTEX_SIZE);
|
||||||
|
positionVBO.AddVertexAttribPointer(0, POSITION_VERTEX_SIZE, 0);
|
||||||
|
GL::VertexBuffer colorVBO(colors, 1);
|
||||||
|
colorVBO.AddVertexAttribPointer(1, 1, 0);
|
||||||
|
|
||||||
|
std::vector<unsigned int> indexes(positions.size() / 3, 0);
|
||||||
|
for (size_t i = 0; i < indexes.size(); i++) {
|
||||||
|
indexes[i] = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GL::ElementBuffer indexVBO(indexes);
|
||||||
|
|
||||||
|
GL::VertexArray worldVao(std::move(indexVBO)); // each pos = 3 vertecies
|
||||||
|
worldVao.Bind();
|
||||||
|
worldVao.BindVertexBuffer(std::move(positionVBO));
|
||||||
|
worldVao.BindVertexBuffer(std::move(colorVBO));
|
||||||
|
worldVao.Unbind();
|
||||||
|
return worldVao;
|
||||||
|
}
|
||||||
|
|
||||||
|
GL::VertexArray LoadTileSelectModel() {
|
||||||
|
std::vector<float> positions = {
|
||||||
|
-0.5f,
|
||||||
|
-0.5f,
|
||||||
|
-1.0f,
|
||||||
|
|
||||||
|
0.5f,
|
||||||
|
-0.5f,
|
||||||
|
-1.0f,
|
||||||
|
|
||||||
|
0.0f,
|
||||||
|
0.5f,
|
||||||
|
-1.0f,
|
||||||
|
|
||||||
|
1,
|
||||||
|
.01,
|
||||||
|
1,
|
||||||
|
|
||||||
|
0,
|
||||||
|
.01,
|
||||||
|
1,
|
||||||
|
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
};
|
||||||
|
|
||||||
|
int color = 255 << 24 | 255 << 16 | 255 << 8 | 150;
|
||||||
|
float colorFloat;
|
||||||
|
|
||||||
|
memcpy(reinterpret_cast<std::uint8_t*>(&colorFloat), &color, sizeof(float));
|
||||||
|
|
||||||
|
std::vector<float> colors(6, colorFloat);
|
||||||
|
|
||||||
|
GL::VertexBuffer positionVBO(positions, POSITION_VERTEX_SIZE);
|
||||||
|
positionVBO.AddVertexAttribPointer(0, POSITION_VERTEX_SIZE, 0);
|
||||||
|
GL::VertexBuffer colorVBO(colors, 1);
|
||||||
|
colorVBO.AddVertexAttribPointer(1, 1, 0);
|
||||||
|
|
||||||
|
std::vector<unsigned int> indexes(positions.size() / 3, 0);
|
||||||
|
for (size_t i = 0; i < indexes.size(); i++) {
|
||||||
|
indexes[i] = i + 1;
|
||||||
|
}
|
||||||
|
GL::ElementBuffer indexVBO(indexes);
|
||||||
|
|
||||||
|
GL::VertexArray tileSelectVao(std::move(indexVBO));
|
||||||
|
tileSelectVao.Bind();
|
||||||
|
tileSelectVao.BindVertexBuffer(std::move(positionVBO));
|
||||||
|
tileSelectVao.BindVertexBuffer(std::move(colorVBO));
|
||||||
|
tileSelectVao.Unbind();
|
||||||
|
|
||||||
|
return tileSelectVao;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderData LoadTowerModel(game::TowerPtr tower) {
|
||||||
|
RenderData renderData;
|
||||||
|
|
||||||
|
float towerX, towerDX;
|
||||||
|
float towerY, towerDY;
|
||||||
|
|
||||||
|
if (tower->GetSize() == game::TowerSize::Little) {
|
||||||
|
towerX = tower->GetCenterX() - 1.5f;
|
||||||
|
towerDX = tower->GetCenterX() + 1.5f;
|
||||||
|
|
||||||
|
towerY = tower->GetCenterY() - 1.5f;
|
||||||
|
towerDY = tower->GetCenterY() + 1.5f;
|
||||||
|
} else {
|
||||||
|
towerX = tower->GetCenterX() - 2.5f;
|
||||||
|
towerDX = tower->GetCenterX() + 2.5f;
|
||||||
|
|
||||||
|
towerY = tower->GetCenterY() - 2.5f;
|
||||||
|
towerDY = tower->GetCenterY() + 2.5f;
|
||||||
|
}
|
||||||
|
std::vector<float> positions = {towerDX, 0.001, towerY, towerX, 0.001, towerY, towerX, 0.001, towerDY, towerDX, 0.001, towerY,
|
||||||
|
towerX, 0.001, towerDY, towerDX, 0.001, towerDY};
|
||||||
|
|
||||||
|
renderData.positions = positions;
|
||||||
|
|
||||||
|
std::uint8_t towerType = static_cast<std::uint8_t>(tower->GetType());
|
||||||
|
std::uint8_t r = 10 * towerType + 40, g = 5 * towerType + 30, b = 10 * towerType + 20;
|
||||||
|
|
||||||
|
float colorFloat;
|
||||||
|
int color = r << 24 | g << 16 | b << 8 | 255;
|
||||||
|
memcpy(&colorFloat, &color, sizeof(int));
|
||||||
|
|
||||||
|
std::vector<float> colors(6, colorFloat);
|
||||||
|
renderData.colors = colors;
|
||||||
|
|
||||||
|
return renderData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace WorldLoader
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace render
|
||||||
|
} // namespace td
|
||||||
26
src/td/render/renderer/WorldRenderer.cpp
Normal file
26
src/td/render/renderer/WorldRenderer.cpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include <td/render/renderer/WorldRenderer.h>
|
||||||
|
|
||||||
|
#include <td/render/loader/WorldLoader.h>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
WorldRenderer::WorldRenderer(Camera& a_Camera, const game::World& a_World) : Renderer(a_Camera), m_World(a_World){
|
||||||
|
m_WorldVao = std::make_unique<GL::VertexArray>(std::move(WorldLoader::LoadWorldModel(&a_World)));
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldRenderer::~WorldRenderer() {}
|
||||||
|
|
||||||
|
void WorldRenderer::Render() {
|
||||||
|
m_Shader.Start();
|
||||||
|
m_Shader.SetProjectionMatrix(m_Camera.GetProjectionMatrix());
|
||||||
|
m_Shader.SetViewMatrix(m_Camera.GetViewMatrix());
|
||||||
|
Renderer::Render(*m_WorldVao);
|
||||||
|
ImGui::ShowDemoWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace render
|
||||||
|
} // namespace td
|
||||||
123
src/td/render/shader/EntityShader.cpp
Normal file
123
src/td/render/shader/EntityShader.cpp
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#include <td/render/shader/EntityShader.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace shader {
|
||||||
|
|
||||||
|
// TODO: update ES shaders
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
static const char vertexSource[] =
|
||||||
|
R"(#version 300 es
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 position;
|
||||||
|
layout(location = 1) in int color;
|
||||||
|
|
||||||
|
uniform mat4 viewMatrix;
|
||||||
|
uniform mat4 projectionMatrix;
|
||||||
|
uniform vec3 modelPosition;
|
||||||
|
|
||||||
|
flat out int pass_color;
|
||||||
|
|
||||||
|
void main(void){
|
||||||
|
pass_color = color;
|
||||||
|
gl_Position = projectionMatrix * viewMatrix * vec4(position + modelPosition, 1.0);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
static const char fragmentSource[] =
|
||||||
|
R"(#version 300 es
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
flat in int pass_color;
|
||||||
|
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
uniform vec3 ColorEffect;
|
||||||
|
|
||||||
|
void main(void){
|
||||||
|
|
||||||
|
float r = float(pass_color >> 24 & 0xFF) / 255.0;
|
||||||
|
float g = float(pass_color >> 16 & 0xFF) / 255.0;
|
||||||
|
float b = float(pass_color >> 8 & 0xFF) / 255.0;
|
||||||
|
float a = float(pass_color & 0xFF) / 255.0;
|
||||||
|
vec3 intermediate_color = vec3(r, g, b) * ColorEffect;
|
||||||
|
out_color = vec4(intermediate_color, a);
|
||||||
|
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
#else
|
||||||
|
static const char vertexSource[] = R"(
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 position;
|
||||||
|
layout(location = 1) in vec2 textureCoords;
|
||||||
|
|
||||||
|
uniform mat4 viewMatrix;
|
||||||
|
uniform mat4 projectionMatrix;
|
||||||
|
uniform vec3 modelPosition;
|
||||||
|
|
||||||
|
out vec2 pass_textureCoords;
|
||||||
|
|
||||||
|
void main(void){
|
||||||
|
pass_textureCoords = textureCoords;
|
||||||
|
gl_Position = projectionMatrix * viewMatrix * vec4(position + modelPosition, 1.0);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
static const char fragmentSource[] = R"(
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
in vec2 pass_textureCoords;
|
||||||
|
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
uniform vec3 ColorEffect;
|
||||||
|
uniform sampler2D textureSampler;
|
||||||
|
|
||||||
|
void main(void){
|
||||||
|
|
||||||
|
vec4 color = vec4(ColorEffect, 1.0) * texture(textureSampler, pass_textureCoords);
|
||||||
|
|
||||||
|
if (color.a <= 0.1)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
out_color = color;
|
||||||
|
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EntityShader::EntityShader() : ShaderProgram() {}
|
||||||
|
|
||||||
|
void EntityShader::LoadShader() {
|
||||||
|
ShaderProgram::LoadProgram(vertexSource, fragmentSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityShader::GetAllUniformLocation() {
|
||||||
|
m_LocationColorEffect = static_cast<unsigned int>(GetUniformLocation("ColorEffect"));
|
||||||
|
m_LocationViewMatrix = static_cast<unsigned int>(GetUniformLocation("viewMatrix"));
|
||||||
|
m_LocationPosition = static_cast<unsigned int>(GetUniformLocation("modelPosition"));
|
||||||
|
m_LocationProjectionMatrix = static_cast<unsigned int>(GetUniformLocation("projectionMatrix"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityShader::SetColorEffect(const Vec3f& color) {
|
||||||
|
LoadVector(m_LocationColorEffect, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityShader::SetProjectionMatrix(const Mat4f& proj) const {
|
||||||
|
LoadMat4(m_LocationProjectionMatrix, proj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityShader::SetViewMatrix(const Mat4f& view) const {
|
||||||
|
LoadMat4(m_LocationViewMatrix, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityShader::SetModelPos(const Vec3f& pos) const {
|
||||||
|
LoadVector(m_LocationPosition, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace shader
|
||||||
|
} // namespace td
|
||||||
145
src/td/render/shader/ShaderProgram.cpp
Executable file
145
src/td/render/shader/ShaderProgram.cpp
Executable file
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* ShaderProgram.cpp
|
||||||
|
*
|
||||||
|
* Created on: 31 janv. 2020
|
||||||
|
* Author: simon
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <td/render/shader/ShaderProgram.h>
|
||||||
|
#include <td/misc/Log.h>
|
||||||
|
#include <td/misc/Format.h>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace shader {
|
||||||
|
|
||||||
|
ShaderProgram::ShaderProgram() :
|
||||||
|
m_ProgramID(0), m_VertexShaderID(0), m_FragmentShaderID(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderProgram::~ShaderProgram() {
|
||||||
|
CleanUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderProgram::Start() const {
|
||||||
|
glUseProgram(m_ProgramID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderProgram::Stop() const {
|
||||||
|
glUseProgram(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ShaderProgram::GetUniformLocation(const std::string& uniformName) const {
|
||||||
|
const int location = glGetUniformLocation(m_ProgramID, uniformName.c_str());
|
||||||
|
if (location == -1) {
|
||||||
|
utils::LOGD(utils::Format("Warning ! Uniform variable %s not found !", uniformName.c_str()));
|
||||||
|
}
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderProgram::LoadFloat(unsigned int location, float value) const {
|
||||||
|
glUniform1f(static_cast<GLint>(location), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderProgram::LoadInt(unsigned int location, int value) const {
|
||||||
|
glUniform1i(static_cast<GLint>(location), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderProgram::LoadVector(unsigned int location,
|
||||||
|
const Vec2f& vector) const {
|
||||||
|
glUniform2f(static_cast<GLint>(location), vector.x, vector.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderProgram::LoadVector(unsigned int location,
|
||||||
|
const Vec3f& vector) const {
|
||||||
|
glUniform3f(static_cast<GLint>(location), vector.x, vector.y, vector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderProgram::LoadBoolean(unsigned int location, bool value) const {
|
||||||
|
glUniform1i(static_cast<GLint>(location), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderProgram::LoadMat4(unsigned int location, const Mat4f& mat) const {
|
||||||
|
glUniformMatrix4fv(static_cast<GLint>(location), 1, false, reinterpret_cast<const float*>(&mat));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderProgram::CleanUp() const {
|
||||||
|
Stop();
|
||||||
|
glDetachShader(m_ProgramID, m_VertexShaderID);
|
||||||
|
glDetachShader(m_ProgramID, m_FragmentShaderID);
|
||||||
|
glDeleteShader(m_VertexShaderID);
|
||||||
|
glDeleteShader(m_FragmentShaderID);
|
||||||
|
glDeleteProgram(m_ProgramID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderProgram::LoadProgramFile(const std::string& vertexFile,
|
||||||
|
const std::string& fragmentFile) {
|
||||||
|
m_VertexShaderID = static_cast<unsigned int>(LoadShaderFromFile(vertexFile, GL_VERTEX_SHADER));
|
||||||
|
m_FragmentShaderID = static_cast<unsigned int>(LoadShaderFromFile(fragmentFile, GL_FRAGMENT_SHADER));
|
||||||
|
m_ProgramID = glCreateProgram();
|
||||||
|
glAttachShader(m_ProgramID, m_VertexShaderID);
|
||||||
|
glAttachShader(m_ProgramID, m_FragmentShaderID);
|
||||||
|
glLinkProgram(m_ProgramID);
|
||||||
|
glValidateProgram(m_ProgramID);
|
||||||
|
GetAllUniformLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderProgram::LoadProgram(const std::string& vertexSource,
|
||||||
|
const std::string& fragmentSource) {
|
||||||
|
m_VertexShaderID = static_cast<unsigned int>(LoadShader(vertexSource, GL_VERTEX_SHADER));
|
||||||
|
m_FragmentShaderID = static_cast<unsigned int>(LoadShader(fragmentSource, GL_FRAGMENT_SHADER));
|
||||||
|
m_ProgramID = glCreateProgram();
|
||||||
|
glAttachShader(m_ProgramID, m_VertexShaderID);
|
||||||
|
glAttachShader(m_ProgramID, m_FragmentShaderID);
|
||||||
|
glLinkProgram(m_ProgramID);
|
||||||
|
glValidateProgram(m_ProgramID);
|
||||||
|
GetAllUniformLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ShaderProgram::LoadShader(const std::string& source, GLenum type) {
|
||||||
|
unsigned int shaderID = glCreateShader(type);
|
||||||
|
|
||||||
|
const char* c_str = source.c_str();
|
||||||
|
int* null = 0;
|
||||||
|
glShaderSource(shaderID, 1, &c_str, null); // @suppress("Function cannot be resolved")
|
||||||
|
glCompileShader(shaderID);
|
||||||
|
GLint compilesuccessful;
|
||||||
|
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &compilesuccessful);
|
||||||
|
if (compilesuccessful == false) {
|
||||||
|
GLsizei size;
|
||||||
|
glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &size);
|
||||||
|
std::vector<char> shaderError(static_cast<std::size_t>(size));
|
||||||
|
glGetShaderInfoLog(shaderID, size, &size, shaderError.data());
|
||||||
|
|
||||||
|
utils::LOGE("Could not compile shader !");
|
||||||
|
|
||||||
|
utils::LOGE(shaderError.data());
|
||||||
|
|
||||||
|
utils::LOGD(utils::Format("\nShader source : \n"
|
||||||
|
"------------------------------------------------------------------------------------------------------------------------------------\n"
|
||||||
|
"%s\n"
|
||||||
|
"------------------------------------------------------------------------------------------------------------------------------------\n"
|
||||||
|
, source.c_str()));
|
||||||
|
}
|
||||||
|
return shaderID;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ShaderProgram::LoadShaderFromFile(const std::string& file, GLenum type) {
|
||||||
|
std::stringstream stream;
|
||||||
|
std::ifstream fileStream(file);
|
||||||
|
|
||||||
|
if (fileStream) {
|
||||||
|
stream << fileStream.rdbuf();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadShader(stream.str(), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace shader
|
||||||
|
} // namespace td
|
||||||
102
src/td/render/shader/WorldShader.cpp
Normal file
102
src/td/render/shader/WorldShader.cpp
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#include <td/render/shader/WorldShader.h>
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
namespace shader {
|
||||||
|
|
||||||
|
// TODO: GLES Shaders
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
static const char vertexSource[] =
|
||||||
|
R"(#version 300 es
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 position;
|
||||||
|
layout(location = 1) in int color;
|
||||||
|
|
||||||
|
uniform mat4 viewMatrix;
|
||||||
|
uniform mat4 projectionMatrix;
|
||||||
|
|
||||||
|
flat out int pass_color;
|
||||||
|
|
||||||
|
void main(void){
|
||||||
|
pass_color = color;
|
||||||
|
gl_Position = projectionMatrix * viewMatrix * vec4(position, 1.0);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
static const char fragmentSource[] =
|
||||||
|
R"(#version 300 es
|
||||||
|
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
flat in int pass_color;
|
||||||
|
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main(void){
|
||||||
|
|
||||||
|
float r = float(pass_color >> 24 & 0xFF) / 255.0;
|
||||||
|
float g = float(pass_color >> 16 & 0xFF) / 255.0;
|
||||||
|
float b = float(pass_color >> 8 & 0xFF) / 255.0;
|
||||||
|
float a = float(pass_color & 0xFF) / 255.0;
|
||||||
|
out_color = vec4(r, g, b, a);
|
||||||
|
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
#else
|
||||||
|
static const char vertexSource[] = R"(
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 position;
|
||||||
|
layout(location = 1) in int color;
|
||||||
|
|
||||||
|
uniform mat4 viewMatrix;
|
||||||
|
uniform mat4 projectionMatrix;
|
||||||
|
|
||||||
|
flat out int pass_color;
|
||||||
|
|
||||||
|
void main(void){
|
||||||
|
pass_color = color;
|
||||||
|
gl_Position = projectionMatrix * viewMatrix * vec4(position, 1.0);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
static const char fragmentSource[] = R"(
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
flat in int pass_color;
|
||||||
|
|
||||||
|
out vec4 out_color;
|
||||||
|
|
||||||
|
void main(void){
|
||||||
|
|
||||||
|
float r = float(pass_color >> 24 & 0xFF) / 255.0;
|
||||||
|
float g = float(pass_color >> 16 & 0xFF) / 255.0;
|
||||||
|
float b = float(pass_color >> 8 & 0xFF) / 255.0;
|
||||||
|
float a = float(pass_color & 0xFF) / 255.0;
|
||||||
|
out_color = vec4(r, g, b, a);
|
||||||
|
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WorldShader::WorldShader() : ShaderProgram() {
|
||||||
|
ShaderProgram::LoadProgram(vertexSource, fragmentSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldShader::GetAllUniformLocation() {
|
||||||
|
m_LocationProjection = static_cast<unsigned int>(GetUniformLocation("projectionMatrix"));
|
||||||
|
m_LocationView = static_cast<unsigned int>(GetUniformLocation("viewMatrix"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldShader::SetProjectionMatrix(const Mat4f& proj) const {
|
||||||
|
LoadMat4(m_LocationProjection, proj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldShader::SetViewMatrix(const Mat4f& view) const {
|
||||||
|
LoadMat4(m_LocationView, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace shader
|
||||||
|
} // namespace td
|
||||||
BIN
test/tdmap.tdmap2
Normal file
BIN
test/tdmap.tdmap2
Normal file
Binary file not shown.
14
xmake.lua
14
xmake.lua
@@ -1,16 +1,22 @@
|
|||||||
add_rules("mode.debug", "mode.release")
|
add_rules("mode.debug", "mode.release")
|
||||||
|
|
||||||
add_repositories("nazara-repo https://github.com/NazaraEngine/xmake-repo.git")
|
|
||||||
add_repositories("persson-repo https://git.ale-pri.com/Persson-dev/xmake-repo.git")
|
add_repositories("persson-repo https://git.ale-pri.com/Persson-dev/xmake-repo.git")
|
||||||
|
|
||||||
add_requires("fpm", "enet6", "nazarautils", "splib 2.0.0")
|
add_requires("imgui 1.92.0", {configs = {sdl3 = true, opengl3 = true}})
|
||||||
|
add_requires("splib 2.0.0", "zlib")
|
||||||
|
add_requires("libsdl3 3.2.16", "glew", "fpm", "enet6")
|
||||||
|
|
||||||
set_languages("c++17")
|
set_languages("c++17")
|
||||||
|
|
||||||
|
set_warnings("all")
|
||||||
|
|
||||||
target("Tower-Defense2")
|
target("Tower-Defense2")
|
||||||
add_includedirs("include", {public = true})
|
add_includedirs("include", {public = true})
|
||||||
set_kind("static")
|
set_kind("binary")
|
||||||
add_files("src/**.cpp")
|
add_files("src/**.cpp")
|
||||||
add_packages("splib", "fpm", "enet6", "nazarautils", {public = true})
|
add_packages("libsdl3", "imgui", "glew", "splib", "zlib", "fpm", "enet6", {public = true})
|
||||||
|
set_rundir(".")
|
||||||
|
add_defines("TD_GL_LOADER_GLEW")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user