Various stuff 14.1.
This commit is contained in:
parent
59707f1339
commit
dd48dcaed6
@ -75,6 +75,9 @@ set(CLIENT_ONLY_SOURCES
|
|||||||
"src/gfx/buffer_object.cpp"
|
"src/gfx/buffer_object.cpp"
|
||||||
"src/gfx/buffer_object.hpp"
|
"src/gfx/buffer_object.hpp"
|
||||||
"src/gfx/draw_list.hpp"
|
"src/gfx/draw_list.hpp"
|
||||||
|
"src/gfx/font.hpp"
|
||||||
|
"src/gfx/font.cpp"
|
||||||
|
"src/gfx/hud.hpp"
|
||||||
"src/gfx/renderer.hpp"
|
"src/gfx/renderer.hpp"
|
||||||
"src/gfx/renderer.cpp"
|
"src/gfx/renderer.cpp"
|
||||||
"src/gfx/shader_defs.hpp"
|
"src/gfx/shader_defs.hpp"
|
||||||
@ -83,6 +86,8 @@ set(CLIENT_ONLY_SOURCES
|
|||||||
"src/gfx/shader.hpp"
|
"src/gfx/shader.hpp"
|
||||||
"src/gfx/shader.cpp"
|
"src/gfx/shader.cpp"
|
||||||
"src/gfx/surface.hpp"
|
"src/gfx/surface.hpp"
|
||||||
|
"src/gfx/text.hpp"
|
||||||
|
"src/gfx/text.cpp"
|
||||||
"src/gfx/texture.cpp"
|
"src/gfx/texture.cpp"
|
||||||
"src/gfx/texture.hpp"
|
"src/gfx/texture.hpp"
|
||||||
"src/gfx/uniform_buffer.hpp"
|
"src/gfx/uniform_buffer.hpp"
|
||||||
|
|||||||
@ -6,4 +6,5 @@ assets::MapCache assets::CacheManager::map_cache_;
|
|||||||
assets::VehicleCache assets::CacheManager::vehicle_cache_;
|
assets::VehicleCache assets::CacheManager::vehicle_cache_;
|
||||||
|
|
||||||
CLIENT_ONLY(assets::TextureCache assets::CacheManager::texture_cache_;)
|
CLIENT_ONLY(assets::TextureCache assets::CacheManager::texture_cache_;)
|
||||||
CLIENT_ONLY(assets::SoundCache assets::CacheManager::sound_cache_;)
|
CLIENT_ONLY(assets::SoundCache assets::CacheManager::sound_cache_;)
|
||||||
|
CLIENT_ONLY(assets::FontCache assets::CacheManager::font_cache_;)
|
||||||
@ -10,6 +10,7 @@
|
|||||||
#ifdef CLIENT
|
#ifdef CLIENT
|
||||||
#include "audio/sound.hpp"
|
#include "audio/sound.hpp"
|
||||||
#include "gfx/texture.hpp"
|
#include "gfx/texture.hpp"
|
||||||
|
#include "gfx/font.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace assets
|
namespace assets
|
||||||
@ -56,6 +57,12 @@ class SoundCache final : public Cache<audio::Sound>
|
|||||||
protected:
|
protected:
|
||||||
PtrType Load(const std::string& key) override { return audio::Sound::LoadFromFile(key); }
|
PtrType Load(const std::string& key) override { return audio::Sound::LoadFromFile(key); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FontCache final : public Cache<gfx::Font>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
PtrType Load(const std::string& key) override { return gfx::Font::LoadFromFile(key); }
|
||||||
|
};
|
||||||
#endif // CLIENT
|
#endif // CLIENT
|
||||||
|
|
||||||
class SkeletonCache final : public Cache<Skeleton>
|
class SkeletonCache final : public Cache<Skeleton>
|
||||||
@ -109,6 +116,11 @@ public:
|
|||||||
{
|
{
|
||||||
return sound_cache_.Get(filename);
|
return sound_cache_.Get(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<const gfx::Font> GetFont(const std::string& filename)
|
||||||
|
{
|
||||||
|
return font_cache_.Get(filename);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -118,6 +130,7 @@ private:
|
|||||||
static VehicleCache vehicle_cache_;
|
static VehicleCache vehicle_cache_;
|
||||||
CLIENT_ONLY(static TextureCache texture_cache_;)
|
CLIENT_ONLY(static TextureCache texture_cache_;)
|
||||||
CLIENT_ONLY(static SoundCache sound_cache_;)
|
CLIENT_ONLY(static SoundCache sound_cache_;)
|
||||||
|
CLIENT_ONLY(static FontCache font_cache_;)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace assets
|
} // namespace assets
|
||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "utils/bufferput.hpp"
|
||||||
|
|
||||||
assets::MeshBuilder::MeshBuilder(gfx::MeshFlags mflags) : mflags_(mflags) {}
|
assets::MeshBuilder::MeshBuilder(gfx::MeshFlags mflags) : mflags_(mflags) {}
|
||||||
|
|
||||||
void assets::MeshBuilder::BeginSurface(gfx::SurfaceFlags sflags, const std::string& name, std::shared_ptr<const gfx::Texture> texture)
|
void assets::MeshBuilder::BeginSurface(gfx::SurfaceFlags sflags, const std::string& name, std::shared_ptr<const gfx::Texture> texture)
|
||||||
@ -35,13 +37,6 @@ void assets::MeshBuilder::AddTriangle(const MeshTriangle& t)
|
|||||||
tris_.push_back(t);
|
tris_.push_back(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
|
||||||
static void BufferPut(std::vector<char>& buffer, const T& val)
|
|
||||||
{
|
|
||||||
const char* data = reinterpret_cast<const char*>(&val);
|
|
||||||
buffer.insert(buffer.end(), data, data + sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int GetVertexAttrFlags(gfx::MeshFlags mflags)
|
static int GetVertexAttrFlags(gfx::MeshFlags mflags)
|
||||||
{
|
{
|
||||||
int attrs = gfx::VA_POSITION | gfx::VA_NORMAL | gfx::VA_UV;
|
int attrs = gfx::VA_POSITION | gfx::VA_NORMAL | gfx::VA_UV;
|
||||||
|
|||||||
@ -25,6 +25,8 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
|
|||||||
iss >> v.normal.x >> v.normal.y >> v.normal.z;
|
iss >> v.normal.x >> v.normal.y >> v.normal.z;
|
||||||
iss >> v.uv.x >> v.uv.y;
|
iss >> v.uv.x >> v.uv.y;
|
||||||
|
|
||||||
|
v.uv.y = 1.0f - v.uv.y; // FLIP FOR GL
|
||||||
|
|
||||||
// TODO: LUV & bone data
|
// TODO: LUV & bone data
|
||||||
|
|
||||||
mb.AddVertex(v);
|
mb.AddVertex(v);
|
||||||
@ -70,9 +72,9 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
|
|||||||
{
|
{
|
||||||
iss >> texture_name;
|
iss >> texture_name;
|
||||||
}
|
}
|
||||||
else if (flag == "+doublesided")
|
else if (flag == "+2sided")
|
||||||
{
|
{
|
||||||
CLIENT_ONLY(sflags |= gfx::SF_DOUBLE_SIDED;)
|
CLIENT_ONLY(sflags |= gfx::SF_2SIDED;)
|
||||||
}
|
}
|
||||||
else if (flag == "+transparent")
|
else if (flag == "+transparent")
|
||||||
{
|
{
|
||||||
|
|||||||
@ -8,12 +8,12 @@ namespace assets
|
|||||||
|
|
||||||
enum VehicleWheelType
|
enum VehicleWheelType
|
||||||
{
|
{
|
||||||
WHEEL_REAR = 1,
|
WHEEL_RIGHT = 1,
|
||||||
WHEEL_RIGHT = 2,
|
WHEEL_REAR = 2,
|
||||||
|
|
||||||
WHEEL_FL = 0,
|
WHEEL_FL = 0,
|
||||||
WHEEL_FR = WHEEL_RIGHT,
|
WHEEL_FR = WHEEL_RIGHT,
|
||||||
WHEEL_RL = WHEEL_REAR | WHEEL_RIGHT,
|
WHEEL_RL = WHEEL_REAR,
|
||||||
WHEEL_RR = WHEEL_REAR | WHEEL_RIGHT,
|
WHEEL_RR = WHEEL_REAR | WHEEL_RIGHT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include "net/defs.hpp"
|
#include "net/defs.hpp"
|
||||||
#include "net/outmessage.hpp"
|
#include "net/outmessage.hpp"
|
||||||
|
#include "assets/cache.hpp"
|
||||||
#include "gameview/worldview.hpp"
|
#include "gameview/worldview.hpp"
|
||||||
|
|
||||||
App::App()
|
App::App()
|
||||||
@ -12,6 +12,11 @@ App::App()
|
|||||||
std::cout << "Initializing App..." << std::endl;
|
std::cout << "Initializing App..." << std::endl;
|
||||||
|
|
||||||
audiomaster_.SetMasterVolume(0.2f);
|
audiomaster_.SetMasterVolume(0.2f);
|
||||||
|
|
||||||
|
font_ = assets::CacheManager::GetFont("data/comic32.font");
|
||||||
|
|
||||||
|
InitChat();
|
||||||
|
AddChatMessage("Test!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::Frame()
|
void App::Frame()
|
||||||
@ -47,7 +52,10 @@ void App::Frame()
|
|||||||
renderer_.ClearDepth();
|
renderer_.ClearDepth();
|
||||||
|
|
||||||
dlist_.Clear();
|
dlist_.Clear();
|
||||||
|
gfx::DrawListParams params;
|
||||||
|
params.screen_width = viewport_size_.x;
|
||||||
|
params.screen_height = viewport_size_.y;
|
||||||
|
|
||||||
const game::view::WorldView* world;
|
const game::view::WorldView* world;
|
||||||
if (session_ && (world = session_->GetWorld()))
|
if (session_ && (world = session_->GetWorld()))
|
||||||
{
|
{
|
||||||
@ -57,14 +65,17 @@ void App::Frame()
|
|||||||
glm::mat4 proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 3000.0f);
|
glm::mat4 proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 3000.0f);
|
||||||
glm::mat4 view = session_->GetViewMatrix();
|
glm::mat4 view = session_->GetViewMatrix();
|
||||||
|
|
||||||
gfx::DrawListParams params;
|
|
||||||
params.view_proj = proj * view;
|
params.view_proj = proj * view;
|
||||||
|
|
||||||
renderer_.DrawList(dlist_, params);
|
|
||||||
|
|
||||||
glm::mat4 camera_world = glm::inverse(view);
|
glm::mat4 camera_world = glm::inverse(view);
|
||||||
audiomaster_.SetListenerOrientation(camera_world);
|
audiomaster_.SetListenerOrientation(camera_world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// draw chat
|
||||||
|
UpdateChat();
|
||||||
|
DrawChat(dlist_);
|
||||||
|
|
||||||
|
renderer_.DrawList(dlist_, params);
|
||||||
|
|
||||||
if (time_ - last_send_time_ > 0.040f)
|
if (time_ - last_send_time_ > 0.040f)
|
||||||
{
|
{
|
||||||
@ -79,6 +90,7 @@ void App::Frame()
|
|||||||
void App::Connected()
|
void App::Connected()
|
||||||
{
|
{
|
||||||
std::cout << "WS connected" << std::endl;
|
std::cout << "WS connected" << std::endl;
|
||||||
|
AddChatMessagePrefix("WebSocket", "^7f7připojeno");
|
||||||
|
|
||||||
// init session
|
// init session
|
||||||
session_ = std::make_unique<game::view::ClientSession>(*this);
|
session_ = std::make_unique<game::view::ClientSession>(*this);
|
||||||
@ -94,12 +106,17 @@ void App::ProcessMessage(net::InMessage& msg)
|
|||||||
if (!session_)
|
if (!session_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//size_t s = msg.End() - msg.Ptr();
|
||||||
|
// AddChatMessage("recvd: ^f00;" + std::to_string(s));
|
||||||
|
|
||||||
session_->ProcessMessage(msg);
|
session_->ProcessMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::Disconnected(const std::string& reason)
|
void App::Disconnected(const std::string& reason)
|
||||||
{
|
{
|
||||||
std::cout << "WS disconnected" << std::endl;
|
std::cout << "WS disconnected" << std::endl;
|
||||||
|
AddChatMessagePrefix("WebSocket", "^f77spojení je píči");
|
||||||
|
|
||||||
|
|
||||||
// close session
|
// close session
|
||||||
session_.reset();
|
session_.reset();
|
||||||
@ -116,7 +133,71 @@ void App::MouseMove(const glm::vec2& delta)
|
|||||||
session_->ProcessMouseMove(delta_yaw, delta_pitch);
|
session_->ProcessMouseMove(delta_yaw, delta_pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
App::~App()
|
void App::AddChatMessage(const std::string& text)
|
||||||
|
{
|
||||||
|
auto& ch = chat_.emplace_back();
|
||||||
|
ch.timeout = time_ + 10.0f;
|
||||||
|
ch.text = std::make_unique<gfx::Text>(font_, 0xFF'FF'FF'FF);
|
||||||
|
ch.text->SetText(text);
|
||||||
|
UpdateChat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::AddChatMessagePrefix(const std::string& prefix, const std::string& text)
|
||||||
|
{
|
||||||
|
AddChatMessage("^aaa[^ddd" + prefix + "^aaa]^r " + text);
|
||||||
|
}
|
||||||
|
|
||||||
|
App::~App() {}
|
||||||
|
|
||||||
|
void App::Send(std::vector<char> data)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void App::InitChat()
|
||||||
|
{
|
||||||
|
chatpos_.resize(30); // max messages on screen
|
||||||
|
const float chat_scale = 1.0f;
|
||||||
|
for (size_t i = 0; i < chatpos_.size(); ++i)
|
||||||
|
{
|
||||||
|
auto& hudp = chatpos_[i];
|
||||||
|
hudp.pos.y = (i+1) * font_->GetLineHeight() * chat_scale;
|
||||||
|
hudp.scale.x = chat_scale;
|
||||||
|
hudp.scale.y = -chat_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::UpdateChat()
|
||||||
|
{
|
||||||
|
// remove expired or over the limit messages
|
||||||
|
while (!chat_.empty() && (chat_.size() > chatpos_.size() ||chat_[0].timeout < time_))
|
||||||
|
{
|
||||||
|
chat_.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::DrawChat(gfx::DrawList& dlist)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < chat_.size(); ++i)
|
||||||
|
{
|
||||||
|
const auto& va = chat_[i].text->GetVA();
|
||||||
|
|
||||||
|
if (va.GetNumIndices() < 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float t_rem = chat_[i].timeout - time_;
|
||||||
|
const float fade = 1.0f;
|
||||||
|
if (t_rem < fade)
|
||||||
|
{
|
||||||
|
chat_[i].color.a = t_rem / fade;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::DrawHudCmd cmd;
|
||||||
|
cmd.pos = &chatpos_[i];
|
||||||
|
cmd.texture = chat_[i].text->GetFont()->GetTexture().get();
|
||||||
|
cmd.va = &va;
|
||||||
|
cmd.color = &chat_[i].color;
|
||||||
|
dlist.AddHUD(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,15 +1,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
#include "game/player_input.hpp"
|
#include "game/player_input.hpp"
|
||||||
#include "gfx/renderer.hpp"
|
#include "gfx/renderer.hpp"
|
||||||
|
#include "gfx/text.hpp"
|
||||||
#include "audio/master.hpp"
|
#include "audio/master.hpp"
|
||||||
#include "net/msg_producer.hpp"
|
#include "net/msg_producer.hpp"
|
||||||
#include "net/inmessage.hpp"
|
#include "net/inmessage.hpp"
|
||||||
|
|
||||||
#include "gameview/client_session.hpp"
|
#include "gameview/client_session.hpp"
|
||||||
|
|
||||||
|
struct ChatMessage
|
||||||
|
{
|
||||||
|
std::unique_ptr<gfx::Text> text;
|
||||||
|
float timeout = 0.0f;
|
||||||
|
glm::vec4 color = glm::vec4(1.0f);
|
||||||
|
};
|
||||||
|
|
||||||
class App : public net::MsgProducer
|
class App : public net::MsgProducer
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -32,11 +41,18 @@ public:
|
|||||||
|
|
||||||
audio::Master& GetAudioMaster() { return audiomaster_; }
|
audio::Master& GetAudioMaster() { return audiomaster_; }
|
||||||
|
|
||||||
|
void AddChatMessage(const std::string& text);
|
||||||
|
void AddChatMessagePrefix(const std::string& prefix, const std::string& text);
|
||||||
|
|
||||||
~App();
|
~App();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Send(std::vector<char> data);
|
void Send(std::vector<char> data);
|
||||||
|
|
||||||
|
void InitChat();
|
||||||
|
void UpdateChat();
|
||||||
|
void DrawChat(gfx::DrawList& dlist);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float time_ = 0.0f;
|
float time_ = 0.0f;
|
||||||
float last_send_time_ = 0.0f;
|
float last_send_time_ = 0.0f;
|
||||||
@ -53,4 +69,9 @@ private:
|
|||||||
audio::Master audiomaster_;
|
audio::Master audiomaster_;
|
||||||
|
|
||||||
std::unique_ptr<game::view::ClientSession> session_;
|
std::unique_ptr<game::view::ClientSession> session_;
|
||||||
|
|
||||||
|
std::shared_ptr<const gfx::Font> font_;
|
||||||
|
|
||||||
|
std::deque<ChatMessage> chat_;
|
||||||
|
std::vector<gfx::HudPosition> chatpos_;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -198,7 +198,7 @@ static EM_BOOL OnWSError(int type, const EmscriptenWebSocketErrorEvent *ev, void
|
|||||||
return EM_TRUE;
|
return EM_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool WSInit()
|
static bool WSInit(const char* url)
|
||||||
{
|
{
|
||||||
if (!emscripten_websocket_is_supported())
|
if (!emscripten_websocket_is_supported())
|
||||||
{
|
{
|
||||||
@ -206,7 +206,7 @@ static bool WSInit()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
EmscriptenWebSocketCreateAttributes ws_attrs = {
|
EmscriptenWebSocketCreateAttributes ws_attrs = {
|
||||||
WS_URL,
|
url,
|
||||||
NULL,
|
NULL,
|
||||||
EM_TRUE
|
EM_TRUE
|
||||||
};
|
};
|
||||||
@ -234,7 +234,7 @@ using namespace easywsclient;
|
|||||||
|
|
||||||
static std::unique_ptr<WebSocket> s_ws;
|
static std::unique_ptr<WebSocket> s_ws;
|
||||||
|
|
||||||
static bool WSInit()
|
static bool WSInit(const char* url)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -249,7 +249,7 @@ static bool WSInit()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
s_ws = std::unique_ptr<WebSocket>(WebSocket::from_url(WS_URL));
|
s_ws = std::unique_ptr<WebSocket>(WebSocket::from_url(url));
|
||||||
|
|
||||||
if (!s_ws)
|
if (!s_ws)
|
||||||
return false;
|
return false;
|
||||||
@ -368,7 +368,7 @@ static void Frame()
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void Main() {
|
static void Main() {
|
||||||
if (!WSInit())
|
if (!WSInit(WS_URL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
InitSDL();
|
InitSDL();
|
||||||
@ -386,6 +386,7 @@ static void Main() {
|
|||||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||||
|
|
||||||
s_app = std::make_unique<App>();
|
s_app = std::make_unique<App>();
|
||||||
|
s_app->AddChatMessagePrefix("WebSocket", "připojování na " + std::string(WS_URL));
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef EMSCRIPTEN
|
||||||
emscripten_set_main_loop(Frame, 0, true);
|
emscripten_set_main_loop(Frame, 0, true);
|
||||||
|
|||||||
@ -8,7 +8,20 @@ game::OpenWorld::OpenWorld() : World("openworld") {}
|
|||||||
void game::OpenWorld::PlayerJoined(Player& player)
|
void game::OpenWorld::PlayerJoined(Player& player)
|
||||||
{
|
{
|
||||||
// spawn him car
|
// spawn him car
|
||||||
auto& vehicle = Spawn<Vehicle>("pickup");
|
// random model
|
||||||
|
const char* vehicles[] = { "pickup", "passat" };
|
||||||
|
auto vehicle_name = vehicles[rand() % (sizeof(vehicles) / sizeof(vehicles[0]))];
|
||||||
|
|
||||||
|
// ranodm color
|
||||||
|
glm::vec3 color;
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
net::ColorQ qcol;
|
||||||
|
qcol.value = rand() % 256;
|
||||||
|
color[i] = qcol.Decode();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& vehicle = Spawn<Vehicle>(vehicle_name, color);
|
||||||
player.Control(&vehicle);
|
player.Control(&vehicle);
|
||||||
|
|
||||||
player_vehicles_[&player] = vehicle.GetEntNum();
|
player_vehicles_[&player] = vehicle.GetEntNum();
|
||||||
|
|||||||
@ -12,32 +12,24 @@ static std::shared_ptr<const assets::VehicleModel> LoadVehicleModelByName(const
|
|||||||
return assets::CacheManager::GetVehicleModel("data/" + model_name + ".veh");
|
return assets::CacheManager::GetVehicleModel("data/" + model_name + ".veh");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Shape
|
game::Vehicle::Vehicle(World& world, std::string model_name, const glm::vec3& color)
|
||||||
{
|
|
||||||
btBoxShape box;
|
|
||||||
btCompoundShape compound;
|
|
||||||
|
|
||||||
Shape() : box(btVector3(1, 1, 0.1))
|
|
||||||
{
|
|
||||||
btTransform t(btQuaternion(0, 0, 0), btVector3(0, 0, 2));
|
|
||||||
compound.addChildShape(t, &box);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
game::Vehicle::Vehicle(World& world, std::string model_name)
|
|
||||||
: Entity(world, net::ET_VEHICLE), model_name_(model_name), model_(LoadVehicleModelByName(model_name)),
|
: Entity(world, net::ET_VEHICLE), model_name_(model_name), model_(LoadVehicleModelByName(model_name)),
|
||||||
motion_(root_.local)
|
motion_(root_.local),
|
||||||
|
color_(color)
|
||||||
{
|
{
|
||||||
root_.local.position.z = 10.0f;
|
root_.local.position.z = 10.0f;
|
||||||
|
|
||||||
// setup chassis rigidbody
|
// setup chassis rigidbody
|
||||||
float mass = 1300.0f;
|
float mass = 1300.0f;
|
||||||
static Shape shape;
|
|
||||||
|
btCollisionShape* shape = model_->GetModel()->GetColShape();
|
||||||
|
if (!shape)
|
||||||
|
throw std::runtime_error("Making vehicle with no shape");
|
||||||
|
|
||||||
btVector3 local_inertia(0, 0, 0);
|
btVector3 local_inertia(0, 0, 0);
|
||||||
shape.compound.calculateLocalInertia(mass, local_inertia);
|
shape->calculateLocalInertia(mass, local_inertia);
|
||||||
|
|
||||||
btRigidBody::btRigidBodyConstructionInfo rb_info(mass, &motion_, &shape.compound, local_inertia);
|
btRigidBody::btRigidBodyConstructionInfo rb_info(mass, &motion_, shape, local_inertia);
|
||||||
body_ = std::make_unique<btRigidBody>(rb_info);
|
body_ = std::make_unique<btRigidBody>(rb_info);
|
||||||
body_->setActivationState(DISABLE_DEACTIVATION);
|
body_->setActivationState(DISABLE_DEACTIVATION);
|
||||||
|
|
||||||
@ -52,7 +44,7 @@ game::Vehicle::Vehicle(World& world, std::string model_name)
|
|||||||
btVector3 wheelDirectionCS0(0, 0, -1);
|
btVector3 wheelDirectionCS0(0, 0, -1);
|
||||||
btVector3 wheelAxleCS(1, 0, 0);
|
btVector3 wheelAxleCS(1, 0, 0);
|
||||||
|
|
||||||
wheel_z_offset_ = 0.4f;
|
wheel_z_offset_ = 0.5f;
|
||||||
|
|
||||||
const auto& wheels = model_->GetWheels();
|
const auto& wheels = model_->GetWheels();
|
||||||
|
|
||||||
@ -63,10 +55,10 @@ game::Vehicle::Vehicle(World& world, std::string model_name)
|
|||||||
|
|
||||||
for (const auto& wheeldef : wheels)
|
for (const auto& wheeldef : wheels)
|
||||||
{
|
{
|
||||||
float wheelRadius = .35f;
|
float wheelRadius = wheeldef.radius;
|
||||||
|
|
||||||
float friction = 5.0f;
|
float friction = 2.0f; // 5.0f;
|
||||||
float suspensionStiffness = 60.0f;
|
float suspensionStiffness = 50.0f;
|
||||||
// float suspensionDamping = 2.3f;
|
// float suspensionDamping = 2.3f;
|
||||||
// float suspensionCompression = 4.4f;
|
// float suspensionCompression = 4.4f;
|
||||||
float suspensionRestLength = 0.6f;
|
float suspensionRestLength = 0.6f;
|
||||||
@ -116,6 +108,7 @@ void game::Vehicle::SendInitData(Player& player, net::OutMessage& msg) const
|
|||||||
{
|
{
|
||||||
net::ModelName name(model_name_);
|
net::ModelName name(model_name_);
|
||||||
msg.Write(name);
|
msg.Write(name);
|
||||||
|
net::WriteRGB(msg, color_); // primary color
|
||||||
}
|
}
|
||||||
|
|
||||||
game::Vehicle::~Vehicle()
|
game::Vehicle::~Vehicle()
|
||||||
|
|||||||
@ -27,7 +27,7 @@ class Vehicle : public Entity, public Controllable
|
|||||||
public:
|
public:
|
||||||
using Super = Entity;
|
using Super = Entity;
|
||||||
|
|
||||||
Vehicle(World& world, std::string model_name);
|
Vehicle(World& world, std::string model_name, const glm::vec3& color);
|
||||||
|
|
||||||
virtual void Update() override;
|
virtual void Update() override;
|
||||||
virtual void SendInitData(Player& player, net::OutMessage& msg) const override;
|
virtual void SendInitData(Player& player, net::OutMessage& msg) const override;
|
||||||
@ -45,6 +45,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
std::string model_name_;
|
std::string model_name_;
|
||||||
std::shared_ptr<const assets::VehicleModel> model_;
|
std::shared_ptr<const assets::VehicleModel> model_;
|
||||||
|
glm::vec3 color_;
|
||||||
|
|
||||||
collision::MotionState motion_;
|
collision::MotionState motion_;
|
||||||
std::unique_ptr<btRigidBody> body_;
|
std::unique_ptr<btRigidBody> body_;
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
game::view::VehicleView::VehicleView(WorldView& world, std::shared_ptr<const assets::VehicleModel> model)
|
game::view::VehicleView::VehicleView(WorldView& world, std::shared_ptr<const assets::VehicleModel> model, const glm::vec3& color)
|
||||||
: EntityView(world), model_(std::move(model))
|
: EntityView(world), model_(std::move(model))
|
||||||
{
|
{
|
||||||
auto& modelwheels = model_->GetWheels();
|
auto& modelwheels = model_->GetWheels();
|
||||||
@ -17,18 +17,21 @@ game::view::VehicleView::VehicleView(WorldView& world, std::shared_ptr<const ass
|
|||||||
wheels_[i].node.parent = &root_;
|
wheels_[i].node.parent = &root_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
color_ = glm::vec4(color, 1.0f);
|
||||||
|
|
||||||
snd_accel_ = assets::CacheManager::GetSound("data/auto.snd");
|
snd_accel_ = assets::CacheManager::GetSound("data/auto.snd");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<game::view::VehicleView> game::view::VehicleView::InitFromMsg(WorldView& world, net::InMessage& msg)
|
std::unique_ptr<game::view::VehicleView> game::view::VehicleView::InitFromMsg(WorldView& world, net::InMessage& msg)
|
||||||
{
|
{
|
||||||
net::ModelName modelname;
|
net::ModelName modelname;
|
||||||
if (!msg.Read(modelname))
|
glm::vec3 color;
|
||||||
|
if (!msg.Read(modelname) || !net::ReadRGB(msg, color))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto model = assets::CacheManager::GetVehicleModel("data/" + std::string(modelname) + ".veh");
|
auto model = assets::CacheManager::GetVehicleModel("data/" + std::string(modelname) + ".veh");
|
||||||
|
|
||||||
return std::make_unique<VehicleView>(world, std::move(model));
|
return std::make_unique<VehicleView>(world, std::move(model), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool game::view::VehicleView::ProcessMsg(net::EntMsgType type, net::InMessage& msg)
|
bool game::view::VehicleView::ProcessMsg(net::EntMsgType type, net::InMessage& msg)
|
||||||
@ -66,10 +69,14 @@ void game::view::VehicleView::Update(const UpdateInfo& info)
|
|||||||
// rotate
|
// rotate
|
||||||
wheelstate.rotation += info.delta_time * wheelstate.speed;
|
wheelstate.rotation += info.delta_time * wheelstate.speed;
|
||||||
|
|
||||||
wheeltrans.rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
|
wheeltrans.rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
|
||||||
wheeltrans.rotation = glm::rotate(wheeltrans.rotation, wheelstate.steering, glm::vec3(0, 0, 1));
|
wheeltrans.rotation = glm::rotate(wheeltrans.rotation, wheelstate.steering, glm::vec3(0, 0, 1));
|
||||||
wheeltrans.rotation = glm::rotate(wheeltrans.rotation, wheelstate.rotation, glm::vec3(1, 0, 0));
|
wheeltrans.rotation = glm::rotate(wheeltrans.rotation, wheelstate.rotation, glm::vec3(1, 0, 0));
|
||||||
|
|
||||||
|
const auto& type = wheels[i].type;
|
||||||
|
if (type == assets::WHEEL_FL || type == assets::WHEEL_RL)
|
||||||
|
wheeltrans.rotation = glm::rotate(wheeltrans.rotation, glm::radians(180.0f), glm::vec3(0, 1, 0));
|
||||||
|
|
||||||
wheels_[i].node.UpdateMatrix();
|
wheels_[i].node.UpdateMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,6 +106,7 @@ void game::view::VehicleView::Draw(gfx::DrawList& dlist)
|
|||||||
gfx::DrawSurfaceCmd cmd;
|
gfx::DrawSurfaceCmd cmd;
|
||||||
cmd.surface = &surface;
|
cmd.surface = &surface;
|
||||||
cmd.matrices = &root_.matrix;
|
cmd.matrices = &root_.matrix;
|
||||||
|
cmd.color = &color_;
|
||||||
dlist.AddSurface(cmd);
|
dlist.AddSurface(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ class VehicleView : public EntityView
|
|||||||
{
|
{
|
||||||
using Super = EntityView;
|
using Super = EntityView;
|
||||||
public:
|
public:
|
||||||
VehicleView(WorldView& world, std::shared_ptr<const assets::VehicleModel> model);
|
VehicleView(WorldView& world, std::shared_ptr<const assets::VehicleModel> model, const glm::vec3& color);
|
||||||
static std::unique_ptr<VehicleView> InitFromMsg(WorldView& world, net::InMessage& msg);
|
static std::unique_ptr<VehicleView> InitFromMsg(WorldView& world, net::InMessage& msg);
|
||||||
|
|
||||||
virtual bool ProcessMsg(net::EntMsgType type, net::InMessage& msg) override;
|
virtual bool ProcessMsg(net::EntMsgType type, net::InMessage& msg) override;
|
||||||
@ -35,6 +35,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<const assets::VehicleModel> model_;
|
std::shared_ptr<const assets::VehicleModel> model_;
|
||||||
|
glm::vec4 color_;
|
||||||
|
|
||||||
std::vector<VehicleWheelViewInfo> wheels_;
|
std::vector<VehicleWheelViewInfo> wheels_;
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "assets/skeleton.hpp"
|
#include "assets/skeleton.hpp"
|
||||||
#include "surface.hpp"
|
#include "surface.hpp"
|
||||||
|
#include "hud.hpp"
|
||||||
|
|
||||||
namespace gfx
|
namespace gfx
|
||||||
{
|
{
|
||||||
@ -18,13 +19,27 @@ struct DrawSurfaceCmd
|
|||||||
float dist = 0.0f; // distance to camera - for transparnt sorting
|
float dist = 0.0f; // distance to camera - for transparnt sorting
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DrawHudCmd
|
||||||
|
{
|
||||||
|
const VertexArray* va = nullptr;
|
||||||
|
const Texture* texture = nullptr;
|
||||||
|
const HudPosition* pos = nullptr;
|
||||||
|
const glm::vec4* color = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
struct DrawList
|
struct DrawList
|
||||||
{
|
{
|
||||||
std::vector<DrawSurfaceCmd> surfaces;
|
std::vector<DrawSurfaceCmd> surfaces;
|
||||||
|
std::vector<DrawHudCmd> huds;
|
||||||
|
|
||||||
void AddSurface(const DrawSurfaceCmd& cmd) { surfaces.emplace_back(cmd); }
|
void AddSurface(const DrawSurfaceCmd& cmd) { surfaces.emplace_back(cmd); }
|
||||||
|
void AddHUD(const DrawHudCmd& cmd) { huds.emplace_back(cmd); }
|
||||||
|
|
||||||
void Clear() { surfaces.clear(); }
|
void Clear()
|
||||||
|
{
|
||||||
|
surfaces.clear();
|
||||||
|
huds.clear();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gfx
|
} // namespace gfx
|
||||||
46
src/gfx/font.cpp
Normal file
46
src/gfx/font.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "font.hpp"
|
||||||
|
|
||||||
|
#include "assets/cache.hpp"
|
||||||
|
#include "assets/cmdfile.hpp"
|
||||||
|
|
||||||
|
std::shared_ptr<const gfx::Font> gfx::Font::LoadFromFile(const std::string& path)
|
||||||
|
{
|
||||||
|
auto font = std::make_shared<Font>();
|
||||||
|
|
||||||
|
glm::vec2 size(1.0f);
|
||||||
|
|
||||||
|
auto PxToUv = [&](const glm::vec2& pos_px) { return pos_px / size; };
|
||||||
|
|
||||||
|
assets::LoadCMDFile(path, [&](const std::string& cmd, std::istringstream& iss) {
|
||||||
|
if (cmd == "c")
|
||||||
|
{
|
||||||
|
Codepoint cp = 0;
|
||||||
|
glm::vec2 c_pos(0.0f);
|
||||||
|
glm::vec2 c_size(0.0f);
|
||||||
|
glm::vec3 c_offset(0.0f);
|
||||||
|
float xadv = 0.0f;
|
||||||
|
|
||||||
|
iss >> cp >> c_pos.x >> c_pos.y >> c_size.x >> c_size.y >> c_offset.x >> c_offset.y >> xadv;
|
||||||
|
|
||||||
|
auto& glyph = font->glyphs_.Alloc(cp);
|
||||||
|
glyph.uv0 = PxToUv(c_pos);
|
||||||
|
glyph.uv1 = PxToUv(c_pos + c_size);
|
||||||
|
glyph.offset = c_offset;
|
||||||
|
glyph.size = c_size;
|
||||||
|
glyph.advance = xadv;
|
||||||
|
}
|
||||||
|
else if (cmd == "texture")
|
||||||
|
{
|
||||||
|
std::string tex_name;
|
||||||
|
iss >> tex_name >> size.x >> size.y;
|
||||||
|
|
||||||
|
font->texture_ = assets::CacheManager::GetTexture("data/" + tex_name + ".png");
|
||||||
|
}
|
||||||
|
else if (cmd == "size")
|
||||||
|
{
|
||||||
|
iss >> font->line_height_;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
101
src/gfx/font.hpp
Normal file
101
src/gfx/font.hpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include "texture.hpp"
|
||||||
|
|
||||||
|
namespace gfx
|
||||||
|
{
|
||||||
|
|
||||||
|
using Codepoint = uint32_t;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class CodepointMap
|
||||||
|
{
|
||||||
|
static constexpr size_t MAX_ARRAY_CODEPOINT = 128;
|
||||||
|
|
||||||
|
struct ArrayItem
|
||||||
|
{
|
||||||
|
T data;
|
||||||
|
bool used = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
CodepointMap() = default;
|
||||||
|
|
||||||
|
T& Alloc(Codepoint codepoint)
|
||||||
|
{
|
||||||
|
if (codepoint < MAX_ARRAY_CODEPOINT)
|
||||||
|
{
|
||||||
|
array_[codepoint].used = true;
|
||||||
|
return array_[codepoint].data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return map_[codepoint]; // Use map for larger codepoints
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* Get(Codepoint codepoint) const
|
||||||
|
{
|
||||||
|
if (codepoint < MAX_ARRAY_CODEPOINT)
|
||||||
|
{
|
||||||
|
if (array_[codepoint].used)
|
||||||
|
{
|
||||||
|
return &array_[codepoint].data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto it = map_.find(codepoint);
|
||||||
|
if (it != map_.end())
|
||||||
|
{
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr; // Not found
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<ArrayItem, MAX_ARRAY_CODEPOINT> array_; // For common ASCII codepoints
|
||||||
|
std::map<Codepoint, T> map_;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FontGlyphData
|
||||||
|
{
|
||||||
|
glm::vec2 uv0;
|
||||||
|
glm::vec2 uv1;
|
||||||
|
glm::vec2 offset;
|
||||||
|
glm::vec2 size;
|
||||||
|
float advance = 0.0f; // Advance width for the codepoint
|
||||||
|
};
|
||||||
|
|
||||||
|
class Font
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Font() = default;
|
||||||
|
static std::shared_ptr<const Font> LoadFromFile(const std::string& path);
|
||||||
|
|
||||||
|
const FontGlyphData* GetCodepointGlyph(Codepoint codepoint) const
|
||||||
|
{
|
||||||
|
const FontGlyphData* data = glyphs_.Get(codepoint);
|
||||||
|
return data ? data : glyphs_.Get(0); // try return missing codepoint glyph if missing
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<const Texture>& GetTexture() const { return texture_; }
|
||||||
|
|
||||||
|
float GetLineHeight() const { return line_height_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<const Texture> texture_; // Texture atlas for the font
|
||||||
|
CodepointMap<FontGlyphData> glyphs_;
|
||||||
|
|
||||||
|
float line_height_ = 0.0f; // Line height in pixels, used for text layout
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gfx
|
||||||
15
src/gfx/hud.hpp
Normal file
15
src/gfx/hud.hpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
namespace gfx
|
||||||
|
{
|
||||||
|
|
||||||
|
struct HudPosition
|
||||||
|
{
|
||||||
|
glm::vec2 anchor = glm::vec2(0.0f); // <0;1>
|
||||||
|
glm::vec2 pos = glm::vec2(0.0f); // px or px multiplies (scale != 1)
|
||||||
|
glm::vec2 scale = glm::vec2(1.0f);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
@ -15,10 +16,12 @@ gfx::Renderer::Renderer()
|
|||||||
ShaderSources::MakeShader(mesh_shader_.shader, SS_MESH_VERT, SS_MESH_FRAG);
|
ShaderSources::MakeShader(mesh_shader_.shader, SS_MESH_VERT, SS_MESH_FRAG);
|
||||||
ShaderSources::MakeShader(skel_mesh_shader_.shader, SS_SKEL_MESH_VERT, SS_SKEL_MESH_FRAG);
|
ShaderSources::MakeShader(skel_mesh_shader_.shader, SS_SKEL_MESH_VERT, SS_SKEL_MESH_FRAG);
|
||||||
ShaderSources::MakeShader(solid_shader_, SS_SOLID_VERT, SS_SOLID_FRAG);
|
ShaderSources::MakeShader(solid_shader_, SS_SOLID_VERT, SS_SOLID_FRAG);
|
||||||
|
ShaderSources::MakeShader(hud_shader_, SS_HUD_VERT, SS_HUD_FRAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx::Renderer::Begin(size_t width, size_t height)
|
void gfx::Renderer::Begin(size_t width, size_t height)
|
||||||
{
|
{
|
||||||
|
current_shader_ = nullptr;
|
||||||
glViewport(0, 0, width, height);
|
glViewport(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,6 +39,7 @@ void gfx::Renderer::ClearDepth()
|
|||||||
void gfx::Renderer::DrawList(gfx::DrawList& list, const DrawListParams& params)
|
void gfx::Renderer::DrawList(gfx::DrawList& list, const DrawListParams& params)
|
||||||
{
|
{
|
||||||
DrawSurfaceList(list.surfaces, params);
|
DrawSurfaceList(list.surfaces, params);
|
||||||
|
DrawHudList(list.huds, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx::Renderer::InvalidateShaders()
|
void gfx::Renderer::InvalidateShaders()
|
||||||
@ -106,12 +110,14 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
|||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
glCullFace(GL_BACK);
|
glCullFace(GL_BACK);
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
InvalidateShaders();
|
InvalidateShaders();
|
||||||
|
|
||||||
// cache to eliminate fake state changes
|
// cache to eliminate fake state changes
|
||||||
const gfx::Texture* last_texture = nullptr;
|
const gfx::Texture* last_texture = nullptr;
|
||||||
const gfx::VertexArray* last_vao = nullptr;
|
const gfx::VertexArray* last_vao = nullptr;
|
||||||
bool last_double_sided = false;
|
bool last_twosided = false;
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0); // for all future bindings
|
glActiveTexture(GL_TEXTURE0); // for all future bindings
|
||||||
|
|
||||||
@ -122,19 +128,19 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
|||||||
// mesh flags
|
// mesh flags
|
||||||
const bool skeletal_flag = surface->mflags & MF_SKELETAL;
|
const bool skeletal_flag = surface->mflags & MF_SKELETAL;
|
||||||
// surface flags
|
// surface flags
|
||||||
const bool double_sided_flag = surface->sflags & SF_DOUBLE_SIDED;
|
const bool twosided_flag = surface->sflags & SF_2SIDED;
|
||||||
const bool transparent_flag = surface->sflags & SF_TRANSPARENT;
|
const bool transparent_flag = surface->sflags & SF_TRANSPARENT;
|
||||||
const bool object_color_flag = surface->sflags & SF_OBJECT_COLOR;
|
const bool object_color_flag = surface->sflags & SF_OBJECT_COLOR;
|
||||||
|
|
||||||
// adjust state
|
// sync 2sided
|
||||||
if (last_double_sided != double_sided_flag)
|
if (last_twosided != twosided_flag)
|
||||||
{
|
{
|
||||||
if (double_sided_flag)
|
if (twosided_flag)
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
else
|
else
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
last_double_sided = double_sided_flag;
|
last_twosided = twosided_flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
// select shader
|
// select shader
|
||||||
@ -144,19 +150,36 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
|||||||
// set model matrix
|
// set model matrix
|
||||||
if (cmd.matrices)
|
if (cmd.matrices)
|
||||||
{
|
{
|
||||||
glUniformMatrix4fv(mshader.shader->U(gfx::SU_MODEL), 1, GL_FALSE, &cmd.matrices[0][0][0]);
|
glUniformMatrix4fv(mshader.shader->U(SU_MODEL), 1, GL_FALSE, &cmd.matrices[0][0][0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // use identity if no matrix provided
|
{ // use identity if no matrix provided
|
||||||
static const glm::mat4 identity(1.0f);
|
static const glm::mat4 identity(1.0f);
|
||||||
glUniformMatrix4fv(mshader.shader->U(gfx::SU_MODEL), 1, GL_FALSE, &identity[0][0]);
|
glUniformMatrix4fv(mshader.shader->U(SU_MODEL), 1, GL_FALSE, &identity[0][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set color
|
// set color
|
||||||
glm::vec4 color = (object_color_flag && cmd.color) ? glm::vec4(*cmd.color) : glm::vec4(1.0f);
|
bool cull_alpha = true;
|
||||||
|
glm::vec4 color = glm::vec4(1.0f);
|
||||||
|
|
||||||
|
if (object_color_flag && cmd.color)
|
||||||
|
{
|
||||||
|
// use object color and disable alpha cull
|
||||||
|
cull_alpha = false;
|
||||||
|
color = glm::vec4(*cmd.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sync cull_alpha
|
||||||
|
if (mshader.cull_alpha != cull_alpha)
|
||||||
|
{
|
||||||
|
glUniform1i(mshader.shader->U(SU_CULL_ALPHA), cull_alpha ? 1 : 0);
|
||||||
|
mshader.cull_alpha = cull_alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sync color
|
||||||
if (mshader.color != color)
|
if (mshader.color != color)
|
||||||
{
|
{
|
||||||
glUniform4fv(mshader.shader->U(gfx::SU_COLOR), 1, &color[0]);
|
glUniform4fv(mshader.shader->U(SU_COLOR), 1, &color[0]);
|
||||||
mshader.color = color;
|
mshader.color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,3 +209,75 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gfx::Renderer::DrawHudList(std::span<DrawHudCmd> queue, const DrawListParams& params)
|
||||||
|
{
|
||||||
|
// cannot sort anything here, must be drawn in FIFO order for correct overlay
|
||||||
|
|
||||||
|
Shader* shader = hud_shader_.get();
|
||||||
|
current_shader_ = shader;
|
||||||
|
glUseProgram(shader->GetId());
|
||||||
|
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
float w = static_cast<float>(params.screen_width);
|
||||||
|
float h = static_cast<float>(params.screen_height);
|
||||||
|
glm::vec2 screen_size_px(w, h);
|
||||||
|
glm::vec2 ndc_scale(2.0f / screen_size_px.x, -2.0f / screen_size_px.y);
|
||||||
|
constexpr glm::vec2 ndc_offset(-1.0f, 1.0f);
|
||||||
|
|
||||||
|
const gfx::Texture* last_texture = nullptr;
|
||||||
|
const gfx::VertexArray* last_vao = nullptr;
|
||||||
|
glm::vec4 last_color = glm::vec4(-1.0f);
|
||||||
|
|
||||||
|
for (const auto& cmd : queue)
|
||||||
|
{
|
||||||
|
if (!cmd.va || !cmd.texture || !cmd.pos)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid hud draw");
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate transform
|
||||||
|
const auto& hp = *cmd.pos;
|
||||||
|
|
||||||
|
glm::vec2 pos_px = hp.anchor * screen_size_px + hp.pos;
|
||||||
|
glm::vec2 trans_ndc = ndc_offset + pos_px * ndc_scale;
|
||||||
|
|
||||||
|
glm::mat3 matrix(1.0f);
|
||||||
|
matrix[0][0] = hp.scale.x * ndc_scale.x;
|
||||||
|
matrix[1][1] = hp.scale.y * ndc_scale.y;
|
||||||
|
matrix[2][0] = trans_ndc.x;
|
||||||
|
matrix[2][1] = trans_ndc.y;
|
||||||
|
|
||||||
|
glUniformMatrix3fv(shader->U(SU_MODEL), 1, GL_FALSE, &matrix[0][0]);
|
||||||
|
|
||||||
|
//sync color
|
||||||
|
glm::vec4 color = cmd.color ? *cmd.color : glm::vec4(1.0f);
|
||||||
|
if (last_color != color)
|
||||||
|
{
|
||||||
|
glUniform4fv(shader->U(SU_COLOR), 1, &color[0]);
|
||||||
|
last_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind texture
|
||||||
|
if (last_texture != cmd.texture)
|
||||||
|
{
|
||||||
|
GLuint tex_id = cmd.texture ? cmd.texture->GetId() : 0;
|
||||||
|
glBindTexture(GL_TEXTURE_2D, tex_id);
|
||||||
|
last_texture = cmd.texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind vao
|
||||||
|
if (last_vao = cmd.va)
|
||||||
|
{
|
||||||
|
glBindVertexArray(cmd.va->GetVAOId());
|
||||||
|
last_vao = cmd.va;
|
||||||
|
}
|
||||||
|
|
||||||
|
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(cmd.va->GetNumIndices()), GL_UNSIGNED_INT, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -11,6 +11,8 @@ namespace gfx
|
|||||||
struct DrawListParams
|
struct DrawListParams
|
||||||
{
|
{
|
||||||
glm::mat4 view_proj;
|
glm::mat4 view_proj;
|
||||||
|
size_t screen_width = 0;
|
||||||
|
size_t screen_height = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MeshShader
|
struct MeshShader
|
||||||
@ -20,6 +22,7 @@ namespace gfx
|
|||||||
// cached state to avoid redundant uniform updates which are expensive especially on WebGL
|
// cached state to avoid redundant uniform updates which are expensive especially on WebGL
|
||||||
bool global_setup = false;
|
bool global_setup = false;
|
||||||
glm::vec4 color = glm::vec4(-1.0f); // invalid to force initial setup
|
glm::vec4 color = glm::vec4(-1.0f); // invalid to force initial setup
|
||||||
|
bool cull_alpha = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Renderer
|
class Renderer
|
||||||
@ -38,6 +41,7 @@ namespace gfx
|
|||||||
MeshShader mesh_shader_;
|
MeshShader mesh_shader_;
|
||||||
MeshShader skel_mesh_shader_;
|
MeshShader skel_mesh_shader_;
|
||||||
std::unique_ptr<Shader> solid_shader_;
|
std::unique_ptr<Shader> solid_shader_;
|
||||||
|
std::unique_ptr<Shader> hud_shader_;
|
||||||
|
|
||||||
const Shader* current_shader_ = nullptr;
|
const Shader* current_shader_ = nullptr;
|
||||||
|
|
||||||
@ -46,6 +50,7 @@ namespace gfx
|
|||||||
void SetupMeshShader(MeshShader& mshader, const DrawListParams& params);
|
void SetupMeshShader(MeshShader& mshader, const DrawListParams& params);
|
||||||
|
|
||||||
void DrawSurfaceList(std::span<DrawSurfaceCmd> queue, const DrawListParams& params);
|
void DrawSurfaceList(std::span<DrawSurfaceCmd> queue, const DrawListParams& params);
|
||||||
|
void DrawHudList(std::span<DrawHudCmd> queue, const DrawListParams& params);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,8 @@ static const char* const s_uni_names[] = {
|
|||||||
"u_model", // SU_MODEL
|
"u_model", // SU_MODEL
|
||||||
"u_view_proj", // SU_VIEW_PROJ
|
"u_view_proj", // SU_VIEW_PROJ
|
||||||
"u_tex", // SU_TEX
|
"u_tex", // SU_TEX
|
||||||
"u_color" // SU_COLOR
|
"u_color", // SU_COLOR
|
||||||
|
"u_cull_alpha", // SU_COLOR
|
||||||
};
|
};
|
||||||
|
|
||||||
// Vytvori shader z daneho zdroje
|
// Vytvori shader z daneho zdroje
|
||||||
|
|||||||
@ -14,6 +14,7 @@ namespace gfx
|
|||||||
SU_VIEW_PROJ,
|
SU_VIEW_PROJ,
|
||||||
SU_TEX,
|
SU_TEX,
|
||||||
SU_COLOR,
|
SU_COLOR,
|
||||||
|
SU_CULL_ALPHA,
|
||||||
|
|
||||||
SU_COUNT
|
SU_COUNT
|
||||||
};
|
};
|
||||||
|
|||||||
@ -79,7 +79,7 @@ SHADER_HEADER
|
|||||||
R"GLSL(
|
R"GLSL(
|
||||||
layout (location = 0) in vec3 a_pos;
|
layout (location = 0) in vec3 a_pos;
|
||||||
layout (location = 1) in vec3 a_normal;
|
layout (location = 1) in vec3 a_normal;
|
||||||
layout (location = 2) in vec3 a_color;
|
layout (location = 2) in vec4 a_color;
|
||||||
layout (location = 3) in vec2 a_uv;
|
layout (location = 3) in vec2 a_uv;
|
||||||
|
|
||||||
)GLSL"
|
)GLSL"
|
||||||
@ -96,8 +96,8 @@ void main() {
|
|||||||
vec3 world_normal = normalize(mat3(u_model) * a_normal);
|
vec3 world_normal = normalize(mat3(u_model) * a_normal);
|
||||||
gl_Position = u_view_proj * world_pos;
|
gl_Position = u_view_proj * world_pos;
|
||||||
|
|
||||||
v_uv = vec2(a_uv.x, 1.0 - a_uv.y);
|
v_uv = a_uv;
|
||||||
v_color = ComputeLights(world_pos.xyz, world_normal) * a_color;
|
v_color = ComputeLights(world_pos.xyz, world_normal) * a_color.rgb;
|
||||||
}
|
}
|
||||||
)GLSL",
|
)GLSL",
|
||||||
|
|
||||||
@ -108,11 +108,25 @@ in vec2 v_uv;
|
|||||||
in vec3 v_color;
|
in vec3 v_color;
|
||||||
|
|
||||||
uniform sampler2D u_tex;
|
uniform sampler2D u_tex;
|
||||||
|
uniform vec4 u_color;
|
||||||
|
uniform bool u_cull_alpha;
|
||||||
|
|
||||||
layout (location = 0) out vec4 o_color;
|
layout (location = 0) out vec4 o_color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
o_color = vec4(texture(u_tex, v_uv));
|
o_color = vec4(texture(u_tex, v_uv));
|
||||||
|
|
||||||
|
if (u_cull_alpha)
|
||||||
|
{
|
||||||
|
if (o_color.a < 0.5)
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// blend with bg
|
||||||
|
o_color = mix(u_color, o_color, o_color.a);
|
||||||
|
}
|
||||||
|
|
||||||
o_color.rgb *= v_color; // Apply vertex color
|
o_color.rgb *= v_color; // Apply vertex color
|
||||||
//o_color = vec4(1.0, 0.0, 0.0, 1.0);
|
//o_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
@ -155,7 +169,7 @@ void main() {
|
|||||||
vec3 world_normal = normalize(mat3(u_model) * mat3(bone_transform) * a_normal);
|
vec3 world_normal = normalize(mat3(u_model) * mat3(bone_transform) * a_normal);
|
||||||
gl_Position = u_view_proj * world_pos;
|
gl_Position = u_view_proj * world_pos;
|
||||||
|
|
||||||
v_uv = vec2(a_uv.x, 1.0 - a_uv.y);
|
v_uv = a_uv;
|
||||||
|
|
||||||
v_color = ComputeLights(world_pos.xyz, world_normal);
|
v_color = ComputeLights(world_pos.xyz, world_normal);
|
||||||
}
|
}
|
||||||
@ -209,6 +223,44 @@ void main() {
|
|||||||
|
|
||||||
)GLSL",
|
)GLSL",
|
||||||
|
|
||||||
|
// SS_HUD_VERT
|
||||||
|
SHADER_HEADER
|
||||||
|
R"GLSL(
|
||||||
|
layout (location = 0) in vec3 a_pos;
|
||||||
|
layout (location = 2) in vec4 a_color;
|
||||||
|
layout (location = 3) in vec2 a_uv;
|
||||||
|
|
||||||
|
uniform mat3 u_model;
|
||||||
|
uniform vec4 u_color;
|
||||||
|
|
||||||
|
out vec4 v_color;
|
||||||
|
out vec2 v_uv;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 pos2d = u_model * vec3(a_pos.xy, 1.0);
|
||||||
|
gl_Position = vec4(pos2d.xy, 0.0, 1.0);
|
||||||
|
v_color = a_color * u_color;
|
||||||
|
v_uv = a_uv;
|
||||||
|
}
|
||||||
|
)GLSL",
|
||||||
|
|
||||||
|
// SS_HUD_FRAG
|
||||||
|
SHADER_HEADER
|
||||||
|
R"GLSL(
|
||||||
|
|
||||||
|
in vec4 v_color;
|
||||||
|
in vec2 v_uv;
|
||||||
|
|
||||||
|
uniform sampler2D u_tex;
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 o_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
o_color = texture(u_tex, v_uv);
|
||||||
|
o_color *= v_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
)GLSL",
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,9 @@ namespace gfx
|
|||||||
SS_SOLID_VERT,
|
SS_SOLID_VERT,
|
||||||
SS_SOLID_FRAG,
|
SS_SOLID_FRAG,
|
||||||
|
|
||||||
|
SS_HUD_VERT,
|
||||||
|
SS_HUD_FRAG,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShaderSources
|
class ShaderSources
|
||||||
|
|||||||
@ -20,7 +20,7 @@ using SurfaceFlags = uint8_t;
|
|||||||
enum SurfaceFlag : SurfaceFlags
|
enum SurfaceFlag : SurfaceFlags
|
||||||
{
|
{
|
||||||
SF_NONE = 0x00,
|
SF_NONE = 0x00,
|
||||||
SF_DOUBLE_SIDED = 0x01,
|
SF_2SIDED = 0x01,
|
||||||
SF_TRANSPARENT = 0x02,
|
SF_TRANSPARENT = 0x02,
|
||||||
SF_OBJECT_COLOR = 0x08, // use object level tint
|
SF_OBJECT_COLOR = 0x08, // use object level tint
|
||||||
};
|
};
|
||||||
|
|||||||
162
src/gfx/text.cpp
Normal file
162
src/gfx/text.cpp
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
#include "text.hpp"
|
||||||
|
|
||||||
|
#include "utils/bufferput.hpp"
|
||||||
|
|
||||||
|
gfx::Text::Text(std::shared_ptr<const Font> font, uint32_t color)
|
||||||
|
: font_(std::move(font)), va_(VA_POSITION | VA_UV | VA_COLOR, VF_CREATE_EBO | VF_DYNAMIC), color_(color)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t DecodeUTF8Codepoint(const char*& p)
|
||||||
|
{
|
||||||
|
if (!*p)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((*p & 0b10000000) == 0)
|
||||||
|
{ // 1-byte sequence
|
||||||
|
return *p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t codepoint = 0;
|
||||||
|
|
||||||
|
if ((*p & 0b11100000) == 0b11000000)
|
||||||
|
{ // 2-byte seq
|
||||||
|
codepoint = (*p++ & 0b00011111) << 6;
|
||||||
|
if (!*p)
|
||||||
|
return 0;
|
||||||
|
codepoint |= (*p++ & 0b00111111);
|
||||||
|
}
|
||||||
|
else if ((*p & 0b11110000) == 0b11100000)
|
||||||
|
{ // 3-byte seq
|
||||||
|
codepoint = (*p++ & 0b00001111) << 12;
|
||||||
|
if (!*p)
|
||||||
|
return 0;
|
||||||
|
codepoint |= (*p++ & 0b00111111) << 6;
|
||||||
|
if (!*p)
|
||||||
|
return 0;
|
||||||
|
codepoint |= (*p++ & 0b00111111);
|
||||||
|
}
|
||||||
|
else if ((*p & 0b11111000) == 0b11110000)
|
||||||
|
{ // 4-byte seq
|
||||||
|
codepoint = (*p++ & 0b00000111) << 18;
|
||||||
|
if (!*p)
|
||||||
|
return 0;
|
||||||
|
codepoint |= (*p++ & 0b00111111) << 12;
|
||||||
|
if (!*p)
|
||||||
|
return 0;
|
||||||
|
codepoint |= (*p++ & 0b00111111) << 6;
|
||||||
|
if (!*p)
|
||||||
|
return 0;
|
||||||
|
codepoint |= (*p++ & 0b00111111);
|
||||||
|
}
|
||||||
|
|
||||||
|
return codepoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct TextVertex
|
||||||
|
{
|
||||||
|
glm::vec3 pos;
|
||||||
|
uint32_t color;
|
||||||
|
glm::vec2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void PutVertex(std::vector<TextVertex>& buf, const glm::vec3 pos, const glm::vec2& uv, uint32_t color)
|
||||||
|
{
|
||||||
|
//BufferPut(buf, pos);
|
||||||
|
//BufferPut(buf, color);
|
||||||
|
//BufferPut(buf, uv);
|
||||||
|
buf.emplace_back(TextVertex{pos, color, uv});
|
||||||
|
}
|
||||||
|
|
||||||
|
void gfx::Text::SetText(const char* text)
|
||||||
|
{
|
||||||
|
static std::vector<TextVertex> vertices;
|
||||||
|
static std::vector<uint32_t> indices;
|
||||||
|
vertices.clear();
|
||||||
|
indices.clear();
|
||||||
|
|
||||||
|
float space_size = font_->GetLineHeight() * 0.3f;
|
||||||
|
|
||||||
|
glm::vec2 cursor(0.0f, 0.0f);
|
||||||
|
|
||||||
|
uint32_t cp = 0;
|
||||||
|
const char* p = text;
|
||||||
|
|
||||||
|
uint32_t color = color_;
|
||||||
|
|
||||||
|
while (cp = DecodeUTF8Codepoint(p))
|
||||||
|
{
|
||||||
|
if (cp == ' ')
|
||||||
|
{
|
||||||
|
cursor.x += space_size; // Move cursor for space
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (cp == '^')
|
||||||
|
{
|
||||||
|
if (!(cp = DecodeUTF8Codepoint(p)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (cp == 'r') // reset color
|
||||||
|
{
|
||||||
|
color = color_;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
color = 0;
|
||||||
|
|
||||||
|
// parse color
|
||||||
|
for (size_t i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
color >>= 8;
|
||||||
|
uint32_t ch;
|
||||||
|
if (cp >= '0' && cp <= '9')
|
||||||
|
ch = cp - '0';
|
||||||
|
else if (cp >= 'a' && cp <= 'f')
|
||||||
|
ch = cp - 'a' + 10;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
color |= (ch << 16);
|
||||||
|
color |= (ch << 20);
|
||||||
|
|
||||||
|
if (!(cp = DecodeUTF8Codepoint(p)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
color |= 0xFF000000; // alpha=1
|
||||||
|
|
||||||
|
//if (cp != ';')
|
||||||
|
// break;
|
||||||
|
|
||||||
|
//continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FontGlyphData* glyph = font_->GetCodepointGlyph(cp);
|
||||||
|
|
||||||
|
if (!glyph)
|
||||||
|
continue; // Dont even have "missing" glyph, font is shit
|
||||||
|
|
||||||
|
glm::vec2 p0 = cursor + glyph->offset;
|
||||||
|
glm::vec2 p1 = p0 + glyph->size;
|
||||||
|
|
||||||
|
uint32_t base_index = vertices.size();
|
||||||
|
|
||||||
|
PutVertex(vertices, glm::vec3(p0.x, -p0.y, 0.0f), glyph->uv0, color);
|
||||||
|
PutVertex(vertices, glm::vec3(p1.x, -p0.y, 0.0f), glm::vec2(glyph->uv1.x, glyph->uv0.y), color);
|
||||||
|
PutVertex(vertices, glm::vec3(p1.x, -p1.y, 0.0f), glyph->uv1, color);
|
||||||
|
PutVertex(vertices, glm::vec3(p0.x, -p1.y, 0.0f), glm::vec2(glyph->uv0.x, glyph->uv1.y), color);
|
||||||
|
|
||||||
|
indices.push_back(base_index + 0);
|
||||||
|
indices.push_back(base_index + 1);
|
||||||
|
indices.push_back(base_index + 2);
|
||||||
|
indices.push_back(base_index + 0);
|
||||||
|
indices.push_back(base_index + 2);
|
||||||
|
indices.push_back(base_index + 3);
|
||||||
|
|
||||||
|
cursor.x += glyph->advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_.SetVBOData(vertices.data(), vertices.size() * sizeof(TextVertex));
|
||||||
|
va_.SetIndices(indices.data(), indices.size());
|
||||||
|
}
|
||||||
26
src/gfx/text.hpp
Normal file
26
src/gfx/text.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "font.hpp"
|
||||||
|
#include "vertex_array.hpp"
|
||||||
|
|
||||||
|
namespace gfx
|
||||||
|
{
|
||||||
|
|
||||||
|
class Text
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Text(std::shared_ptr<const Font> font, uint32_t color);
|
||||||
|
|
||||||
|
void SetText(const char* text);
|
||||||
|
void SetText(const std::string& text) { SetText(text.c_str()); }
|
||||||
|
|
||||||
|
const std::shared_ptr<const Font>& GetFont() const { return font_; }
|
||||||
|
const VertexArray& GetVA() const { return va_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<const Font> font_;
|
||||||
|
VertexArray va_;
|
||||||
|
uint32_t color_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace gfx
|
||||||
@ -25,7 +25,7 @@ static void GetGLFilterModes(bool linear, bool mipmaps, GLenum& filter_min, GLen
|
|||||||
if (mipmaps)
|
if (mipmaps)
|
||||||
{
|
{
|
||||||
// Mipmaps always linear
|
// Mipmaps always linear
|
||||||
filter_min = GL_NEAREST_MIPMAP_LINEAR;
|
filter_min = GL_LINEAR_MIPMAP_LINEAR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,4 +76,6 @@ using QuatQ = Quantized<uint16_t, -1, 1, 1>;
|
|||||||
using WheelZOffsetQ = Quantized<uint8_t, -1, 1, 1>;
|
using WheelZOffsetQ = Quantized<uint8_t, -1, 1, 1>;
|
||||||
using RotationSpeedQ = Quantized<uint16_t, -300, 300, 1>;
|
using RotationSpeedQ = Quantized<uint16_t, -300, 300, 1>;
|
||||||
|
|
||||||
|
using ColorQ = Quantized<uint8_t, 0, 1>;
|
||||||
|
|
||||||
} // namespace net
|
} // namespace net
|
||||||
@ -8,6 +8,8 @@
|
|||||||
namespace net
|
namespace net
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// TRANSFORMS
|
||||||
|
|
||||||
inline void WritePosition(OutMessage& msg, const glm::vec3& pos)
|
inline void WritePosition(OutMessage& msg, const glm::vec3& pos)
|
||||||
{
|
{
|
||||||
msg.Write<PositionQ>(pos.x);
|
msg.Write<PositionQ>(pos.x);
|
||||||
@ -54,4 +56,18 @@ inline bool ReadTransform(InMessage& msg, Transform& trans)
|
|||||||
return ReadPosition(msg, trans.position) && ReadRotation(msg, trans.rotation);
|
return ReadPosition(msg, trans.position) && ReadRotation(msg, trans.rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// COLOR
|
||||||
|
|
||||||
|
inline void WriteRGB(OutMessage& msg, const glm::vec3& color)
|
||||||
|
{
|
||||||
|
msg.Write<ColorQ>(color.r);
|
||||||
|
msg.Write<ColorQ>(color.g);
|
||||||
|
msg.Write<ColorQ>(color.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ReadRGB(InMessage& msg, glm::vec3& color)
|
||||||
|
{
|
||||||
|
return msg.Read<ColorQ>(color.r) && msg.Read<ColorQ>(color.g) && msg.Read<ColorQ>(color.b);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
10
src/utils/bufferput.hpp
Normal file
10
src/utils/bufferput.hpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline void BufferPut(std::vector<char>& buffer, const T& val)
|
||||||
|
{
|
||||||
|
const char* data = reinterpret_cast<const char*>(&val);
|
||||||
|
buffer.insert(buffer.end(), data, data + sizeof(T));
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user