merge
This commit is contained in:
commit
82ca994fac
25 files changed
+497
-27
No files matched your search
+175
-4
@@ -112,6 +112,110 @@ namespace ZL
|
||||
return boxCoordsArr;
|
||||
}
|
||||
|
||||
static Eigen::Matrix4f makeViewMatrix_FromYourCamera()
|
||||
{
|
||||
Eigen::Matrix4f Tz = Eigen::Matrix4f::Identity();
|
||||
Tz(2, 3) = -1.0f * ZL::Environment::zoom;
|
||||
|
||||
Eigen::Matrix4f R = Eigen::Matrix4f::Identity();
|
||||
R.block<3, 3>(0, 0) = ZL::Environment::inverseShipMatrix;
|
||||
|
||||
Eigen::Matrix4f Tship = Eigen::Matrix4f::Identity();
|
||||
Tship(0, 3) = -ZL::Environment::shipState.position.x();
|
||||
Tship(1, 3) = -ZL::Environment::shipState.position.y();
|
||||
Tship(2, 3) = -ZL::Environment::shipState.position.z();
|
||||
|
||||
return Tz * R * Tship;
|
||||
}
|
||||
|
||||
static Eigen::Matrix4f makePerspective(float fovyRadians, float aspect, float zNear, float zFar)
|
||||
{
|
||||
// Стандартная перспектива
|
||||
float f = 1.0f / std::tan(fovyRadians * 0.5f);
|
||||
|
||||
Eigen::Matrix4f P = Eigen::Matrix4f::Zero();
|
||||
P(0, 0) = f / aspect;
|
||||
P(1, 1) = f;
|
||||
P(2, 2) = (zFar + zNear) / (zNear - zFar);
|
||||
P(2, 3) = (2.0f * zFar * zNear) / (zNear - zFar);
|
||||
P(3, 2) = -1.0f;
|
||||
return P;
|
||||
}
|
||||
|
||||
bool Game::worldToScreen(const Vector3f& world, float& outX, float& outY, float& outDepth) const
|
||||
{
|
||||
// Матрицы должны совпасть с drawBoxes/drawShip по смыслу
|
||||
float aspect = static_cast<float>(Environment::width) / static_cast<float>(Environment::height);
|
||||
|
||||
Eigen::Matrix4f V = makeViewMatrix_FromYourCamera();
|
||||
Eigen::Matrix4f P = makePerspective(1.0f / 1.5f, aspect, Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||
|
||||
Eigen::Vector4f w(world.x(), world.y(), world.z(), 1.0f);
|
||||
Eigen::Vector4f clip = P * V * w;
|
||||
|
||||
if (clip.w() <= 0.0001f) return false; // позади камеры
|
||||
|
||||
Eigen::Vector3f ndc = clip.head<3>() / clip.w(); // [-1..1]
|
||||
outDepth = ndc.z();
|
||||
|
||||
// В пределах экрана?
|
||||
// (можно оставить, можно клампить)
|
||||
float sx = (ndc.x() * 0.5f + 0.5f) * Environment::width;
|
||||
float sy = (ndc.y() * 0.5f + 0.5f) * Environment::height;
|
||||
|
||||
outX = sx;
|
||||
outY = sy;
|
||||
|
||||
// Можно отсеять те, что вне:
|
||||
if (sx < -200 || sx > Environment::width + 200) return false;
|
||||
if (sy < -200 || sy > Environment::height + 200) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Game::drawBoxesLabels()
|
||||
{
|
||||
if (!textRenderer) return;
|
||||
|
||||
// Текст рисуем как 2D поверх всего 3D, но ДО drawUI или после — как хочешь.
|
||||
// Чтобы подписи были поверх — делай после drawBoxes и до drawUI (как мы и вставили).
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
for (size_t i = 0; i < boxCoordsArr.size(); ++i)
|
||||
{
|
||||
if (i >= boxAlive.size() || !boxAlive[i]) continue;
|
||||
if (i >= boxLabels.size()) continue;
|
||||
|
||||
// ВАЖНО: твои боксы рисуются с Translate({0,0,45000}) + pos
|
||||
Vector3f boxWorld = boxCoordsArr[i].pos + Vector3f{ 0.0f, 0.0f, 45000.0f };
|
||||
|
||||
// Чуть выше бокса по Y (или по Z — как нравится)
|
||||
Vector3f labelWorld = boxWorld + Vector3f{ 0.0f, 2.2f, 0.0f };
|
||||
|
||||
float sx, sy, depth;
|
||||
if (!worldToScreen(labelWorld, sx, sy, depth)) continue;
|
||||
|
||||
// В твоей UI-системе Y обычно перевёрнут (ты делаешь uiY = height - my).
|
||||
// Наш worldToScreen отдаёт Y в системе "низ=0, верх=height" (NDC->screen).
|
||||
// Чтобы совпало с твоей UI-логикой, перевернём:
|
||||
float uiX = sx;
|
||||
float uiY = sy; // если окажется вверх ногами — замени на (Environment::height - sy)
|
||||
|
||||
// Можно делать масштаб по дальности: чем дальше — тем меньше.
|
||||
// depth в NDC: ближе к -1 (near) и к 1 (far). Стабильнее считать по расстоянию:
|
||||
float dist = (Environment::shipState.position - boxWorld).norm();
|
||||
float scale = std::clamp(120.0f / (dist + 1.0f), 0.6f, 1.2f);
|
||||
|
||||
textRenderer->drawText(boxLabels[i], uiX, uiY, scale, /*centered*/true);
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
Game::Game()
|
||||
: window(nullptr)
|
||||
, glContext(nullptr)
|
||||
@@ -142,7 +246,7 @@ namespace ZL
|
||||
ZL::CheckGlError();
|
||||
|
||||
|
||||
#ifndef SIMPLIFIED
|
||||
//#ifndef SIMPLIFIED
|
||||
renderer.shaderManager.AddShaderFromFiles("defaultColor", "resources/shaders/defaultColor.vertex", "resources/shaders/defaultColor_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("default", "resources/shaders/default.vertex", "resources/shaders/default_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/env_sky.vertex", "resources/shaders/env_sky_web.fragment", CONST_ZIP_FILE);
|
||||
@@ -151,14 +255,14 @@ namespace ZL
|
||||
renderer.shaderManager.AddShaderFromFiles("planetStone", "resources/shaders/planet_stone.vertex", "resources/shaders/planet_stone_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("planetLand", "resources/shaders/planet_land.vertex", "resources/shaders/planet_land_web.fragment", CONST_ZIP_FILE);
|
||||
|
||||
#else
|
||||
/*#else
|
||||
renderer.shaderManager.AddShaderFromFiles("default", "resources/shaders/default.vertex", "resources/shaders/default_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/default_env.vertex", "resources/shaders/default_env_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "resources/shaders/default_texture.vertex", "resources/shaders/default_texture_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("planetBake", "resources/shaders/default_texture.vertex", "resources/shaders/default_texture_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("planetStone", "resources/shaders/default_texture.vertex", "resources/shaders/default_texture_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("planetLand", "resources/shaders/default_texture.vertex", "resources/shaders/default_texture_web.fragment", CONST_ZIP_FILE);
|
||||
#endif
|
||||
#endif*/
|
||||
|
||||
bool cfgLoaded = sparkEmitter.loadFromJsonFile("resources/config/spark_config.json", renderer, CONST_ZIP_FILE);
|
||||
bool projCfgLoaded = projectileEmitter.loadFromJsonFile("resources/config/spark_projectile_config.json", renderer, CONST_ZIP_FILE);
|
||||
@@ -338,6 +442,15 @@ namespace ZL
|
||||
|
||||
boxAlive.resize(boxCoordsArr.size(), true);
|
||||
|
||||
textRenderer = std::make_unique<ZL::TextRenderer>();
|
||||
textRenderer->init(renderer, "resources/fonts/DroidSans.ttf", 32);
|
||||
|
||||
boxLabels.clear();
|
||||
boxLabels.reserve(boxCoordsArr.size());
|
||||
for (size_t i = 0; i < boxCoordsArr.size(); ++i) {
|
||||
boxLabels.push_back("Box " + std::to_string(i + 1));
|
||||
}
|
||||
|
||||
if (!cfgLoaded)
|
||||
{
|
||||
throw std::runtime_error("Failed to load spark emitter config file!");
|
||||
@@ -590,7 +703,9 @@ namespace ZL
|
||||
}
|
||||
drawShip();
|
||||
drawRemoteShips();
|
||||
drawRemoteShipsLabels();
|
||||
drawBoxes();
|
||||
drawBoxesLabels();
|
||||
|
||||
drawUI();
|
||||
CheckGlError();
|
||||
@@ -683,6 +798,62 @@ namespace ZL
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
void Game::drawRemoteShipsLabels()
|
||||
{
|
||||
if (!textRenderer) return;
|
||||
|
||||
#ifdef NETWORK
|
||||
// 2D поверх 3D
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Берем удаленных игроков
|
||||
latestRemotePlayers = networkClient->getRemotePlayers();
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
now -= std::chrono::milliseconds(CLIENT_DELAY);
|
||||
|
||||
for (auto const& [id, remotePlayer] : latestRemotePlayers)
|
||||
{
|
||||
if (!remotePlayer.canFetchClientStateAtTime(now))
|
||||
continue;
|
||||
|
||||
ClientState st = remotePlayer.fetchClientStateAtTime(now);
|
||||
|
||||
// Позиция корабля в мире
|
||||
Vector3f shipWorld = st.position;
|
||||
|
||||
float distSq = (Environment::shipState.position - shipWorld).squaredNorm();
|
||||
/*if (distSq > MAX_DIST_SQ) // дальность прорисовки никнейма
|
||||
continue;*/
|
||||
float dist = sqrt(distSq);
|
||||
float alpha = 1.0f; // постоянная видимость
|
||||
/*float alpha = std::clamp(1.f - (dist - FADE_START) / FADE_RANGE, 0.f, 1.f); // дальность прорисовки никнейма
|
||||
if (alpha < 0.01f)
|
||||
continue; */
|
||||
Vector3f labelWorld = shipWorld + Vector3f{ 0.f, -4.f, 0.f }; // регулировка высоты
|
||||
float sx, sy, depth;
|
||||
if (!worldToScreen(labelWorld, sx, sy, depth))
|
||||
continue;
|
||||
|
||||
float uiX = sx, uiY = sy;
|
||||
float scale = std::clamp(BASE_SCALE / (dist * PERSPECTIVE_K + 1.f), MIN_SCALE, MAX_SCALE);
|
||||
|
||||
// Дефолтный лейбл
|
||||
std::string label = "Player (" + std::to_string(st.id) + ") " + std::to_string((int)dist) + "m";
|
||||
|
||||
// TODO: nickname sync
|
||||
|
||||
textRenderer->drawText(label, uiX + 1.f, uiY + 1.f, scale, true, {0.f, 0.f, 0.f, alpha}); // color param
|
||||
textRenderer->drawText(label, uiX, uiY, scale, true, { 1.f, 1.f, 1.f, alpha });
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Game::processTickCount() {
|
||||
|
||||
if (lastTickCount == 0) {
|
||||
@@ -703,7 +874,7 @@ namespace ZL
|
||||
size_t delta = newTickCount - lastTickCount;
|
||||
if (delta > CONST_MAX_TIME_INTERVAL)
|
||||
{
|
||||
throw std::runtime_error("Synchronization is lost");
|
||||
//throw std::runtime_error("Synchronization is lost");
|
||||
}
|
||||
|
||||
auto now_ms = newTickCount;
|
||||
|
||||
Reference in new issue
Block a user