Merge branch 'main' into spark

This commit is contained in:
Vladislav Khorev 2026-01-15 09:32:35 +03:00
commit 90ad3392cb
11 changed files with 5461 additions and 117 deletions

BIN
resources/MainCharacter_Base_color_sRGB.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -27,7 +27,7 @@
{ {
"type": "Button", "type": "Button",
"name": "playButton", "name": "playButton",
"x": 100, "x": -1000,
"y": 500, "y": 500,
"width": 200, "width": 200,
"height": 50, "height": 50,
@ -56,7 +56,7 @@
{ {
"type": "Button", "type": "Button",
"name": "settingsButton", "name": "settingsButton",
"x": 100, "x": -1000,
"y": 400, "y": 400,
"width": 200, "width": 200,
"height": 50, "height": 50,
@ -89,7 +89,7 @@
{ {
"type": "Button", "type": "Button",
"name": "exitButton", "name": "exitButton",
"x": 100, "x": -1000,
"y": 300, "y": 300,
"width": 200, "width": 200,
"height": 50, "height": 50,

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,8 @@ namespace ZL {
int Environment::windowHeaderHeight = 0; int Environment::windowHeaderHeight = 0;
int Environment::width = 0; int Environment::width = 0;
int Environment::height = 0; int Environment::height = 0;
float Environment::zoom = 18.f; float Environment::zoom = 36.f;
bool Environment::leftPressed = false; bool Environment::leftPressed = false;
bool Environment::rightPressed = false; bool Environment::rightPressed = false;

View File

@ -23,6 +23,8 @@ namespace ZL
static bool g_exitBgAnimating = false; static bool g_exitBgAnimating = false;
float x = 0;
Eigen::Quaternionf generateRandomQuaternion(std::mt19937& gen) Eigen::Quaternionf generateRandomQuaternion(std::mt19937& gen)
{ {
@ -107,6 +109,7 @@ namespace ZL
, glContext(nullptr) , glContext(nullptr)
, newTickCount(0) , newTickCount(0)
, lastTickCount(0) , lastTickCount(0)
, planetObject(renderer, taskManager, mainThreadHandler)
{ {
projectiles.reserve(maxProjectiles); projectiles.reserve(maxProjectiles);
for (int i = 0; i < maxProjectiles; ++i) { for (int i = 0; i < maxProjectiles; ++i) {
@ -307,17 +310,24 @@ namespace ZL
//Load texture //Load texture
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/DefaultMaterial_BaseColor_shine.png", CONST_ZIP_FILE));
spaceshipBase = LoadFromTextFile02("resources/spaceship006.txt", CONST_ZIP_FILE);
spaceshipBase.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI / 2.0, Eigen::Vector3f::UnitY())).toRotationMatrix());// QuatFromRotateAroundY(M_PI / 2.0).toRotationMatrix());
//spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/DefaultMaterial_BaseColor_shine.png", CONST_ZIP_FILE));
//spaceshipBase = LoadFromTextFile02("resources/spaceship006.txt", CONST_ZIP_FILE);
//spaceshipBase.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI / 2.0, Eigen::Vector3f::UnitY())).toRotationMatrix());// QuatFromRotateAroundY(M_PI / 2.0).toRotationMatrix());
//spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/cap_D.png", CONST_ZIP_FILE)); //spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/cap_D.png", CONST_ZIP_FILE));
//spaceshipBase = LoadFromTextFile02("./resources/spaceship006x.txt", CONST_ZIP_FILE); //spaceshipBase = LoadFromTextFile02("./resources/spaceship006x.txt", CONST_ZIP_FILE);
//spaceshipBase.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI / 2.0, Eigen::Vector3f::UnitY())).toRotationMatrix());// QuatFromRotateAroundY(M_PI / 2.0).toRotationMatrix()); //spaceshipBase.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI / 2.0, Eigen::Vector3f::UnitY())).toRotationMatrix());// QuatFromRotateAroundY(M_PI / 2.0).toRotationMatrix());
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/MainCharacter_Base_color_sRGB.png", CONST_ZIP_FILE));
spaceshipBase = LoadFromTextFile02("resources/spaceshipnew001.txt", CONST_ZIP_FILE);
spaceshipBase.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY())).toRotationMatrix());// QuatFromRotateAroundY(M_PI / 2.0).toRotationMatrix());
spaceshipBase.Move(Vector3f{ 1.2, 0, -5 });
//spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 }); //spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 });
//spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 }); //spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 });
//spaceshipBase.Move(Vector3f{ -0.52998, 0, 10 });
spaceship.AssignFrom(spaceshipBase); spaceship.AssignFrom(spaceshipBase);
spaceship.RefreshVBO(); spaceship.RefreshVBO();
@ -361,8 +371,6 @@ namespace ZL
std::cout << "Init step 6 " << std::endl; std::cout << "Init step 6 " << std::endl;
planetObject.init(); planetObject.init();
planetObject.taskManager = &taskManager;
std::cout << "Init step 7 " << std::endl; std::cout << "Init step 7 " << std::endl;
//rockTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", CONST_ZIP_FILE)); //rockTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", CONST_ZIP_FILE));
@ -455,8 +463,8 @@ namespace ZL
renderer.LoadIdentity(); renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
renderer.TranslateMatrix({ 0, -6.f, 0 }); //Ship camera offset
renderer.TranslateMatrix({ 0, -Environment::zoom * 0.03f, 0 });
if (shipAlive) { if (shipAlive) {
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID()); glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
renderer.DrawVertexRenderStruct(spaceship); renderer.DrawVertexRenderStruct(spaceship);
@ -471,7 +479,10 @@ namespace ZL
} }
if (shipAlive) { if (shipAlive) {
renderer.PushMatrix();
renderer.TranslateMatrix({ 0, 0, 16 });
sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height); sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
renderer.PopMatrix();
projectileEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height); projectileEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
} }
@ -999,15 +1010,18 @@ namespace ZL
if (event.key.keysym.sym == SDLK_o) if (event.key.keysym.sym == SDLK_o)
{ {
Environment::shipVelocity += 50.f; Environment::shipVelocity += 50.f;
//x = x + 2.0;
} }
if (event.key.keysym.sym == SDLK_l) if (event.key.keysym.sym == SDLK_l)
{ {
Environment::shipVelocity -= 50.f; Environment::shipVelocity -= 50.f;
//x = x - 2.0;
} }
} }
#endif #endif
} }
render(); render();
mainThreadHandler.processMainThreadTasks();
} }
void Game::handleDown(int mx, int my) void Game::handleDown(int mx, int my)

View File

@ -12,7 +12,7 @@
namespace ZL { namespace ZL {
struct BoxCoords struct BoxCoords
{ {
Vector3f pos; Vector3f pos;
@ -29,9 +29,11 @@ namespace ZL {
void update(); void update();
void render(); void render();
bool shouldExit() const { return Environment::exitGameLoop; } bool shouldExit() const { return Environment::exitGameLoop; }
Renderer renderer;
TaskManager taskManager;
MainThreadHandler mainThreadHandler;
private: private:
void processTickCount(); void processTickCount();
void drawScene(); void drawScene();
@ -48,42 +50,16 @@ namespace ZL {
SDL_Window* window; SDL_Window* window;
SDL_GLContext glContext; SDL_GLContext glContext;
Renderer renderer;
size_t newTickCount; size_t newTickCount;
size_t lastTickCount; size_t lastTickCount;
//std::shared_ptr<Texture> rockTexture;
std::vector<BoxCoords> boxCoordsArr; std::vector<BoxCoords> boxCoordsArr;
std::vector<VertexRenderStruct> boxRenderArr; std::vector<VertexRenderStruct> boxRenderArr;
//std::shared_ptr<Texture> buttonTexture;
//VertexRenderStruct button;
//std::shared_ptr<Texture> musicVolumeBarTexture;
//VertexRenderStruct musicVolumeBar;
//std::shared_ptr<Texture> musicVolumeBarButtonTexture;
//VertexRenderStruct musicVolumeBarButton;
//bool isDraggingVolume = false;
/*
float velocitySlider = 0.0f;
float volumeBarMinX = 1190.0f;
float volumeBarMaxX = 1200.0f;
float volumeBarMinY = 100.0f;
float volumeBarMaxY = 600.0f;*/
//float musicVolumeBarButtonButtonCenterX = 1195.0f;
//float musicVolumeBarButtonButtonRadius = 25.0f;
//void UpdateVolumeFromMouse(int mouseX, int mouseY);
//void UpdateVolumeKnob();
static const size_t CONST_TIMER_INTERVAL = 10; static const size_t CONST_TIMER_INTERVAL = 10;
static const size_t CONST_MAX_TIME_INTERVAL = 1000; static const size_t CONST_MAX_TIME_INTERVAL = 1000;
@ -111,8 +87,7 @@ namespace ZL {
int maxProjectiles = 32; int maxProjectiles = 32;
std::vector<Vector3f> shipLocalEmissionPoints; std::vector<Vector3f> shipLocalEmissionPoints;
TaskManager taskManager;
bool shipAlive = true; bool shipAlive = true;
bool gameOver = false; bool gameOver = false;
std::vector<bool> boxAlive; std::vector<bool> boxAlive;

View File

@ -157,8 +157,8 @@ namespace ZL {
renderer.EnableVertexAttribArray(vPositionName); renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName); renderer.EnableVertexAttribArray(vTexCoordName);
float aspectRatio = static_cast<float>(screenWidth) / static_cast<float>(screenHeight); //float aspectRatio = static_cast<float>(screenWidth) / static_cast<float>(screenHeight);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, aspectRatio, Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR); //renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, aspectRatio, Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
glBindTexture(GL_TEXTURE_2D, texture->getTexID()); glBindTexture(GL_TEXTURE_2D, texture->getTexID());
@ -166,13 +166,13 @@ namespace ZL {
glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendFunc(GL_SRC_ALPHA, GL_ONE);
renderer.PushMatrix(); renderer.PushMatrix();
renderer.LoadIdentity(); //renderer.LoadIdentity();
renderer.TranslateMatrix({ 0, 0, -1.0f * zoom }); //renderer.TranslateMatrix({ 0, 0, -1.0f * zoom });
renderer.DrawVertexRenderStruct(sparkQuad); renderer.DrawVertexRenderStruct(sparkQuad);
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); //renderer.PopProjectionMatrix();
glDisable(GL_BLEND); glDisable(GL_BLEND);

View File

@ -57,9 +57,11 @@ namespace ZL {
return rot; return rot;
} }
PlanetObject::PlanetObject() PlanetObject::PlanetObject(Renderer& iRenderer, TaskManager& iTaskManager, MainThreadHandler& iMainThreadHandler)
: renderer(iRenderer),
taskManager(iTaskManager),
mainThreadHandler(iMainThreadHandler)
{ {
} }
void PlanetObject::init() { void PlanetObject::init() {
@ -101,7 +103,7 @@ namespace ZL {
float movementThreshold = 1.0f; float movementThreshold = 1.0f;
if ((Environment::shipPosition - lastUpdatePos).squaredNorm() < movementThreshold * movementThreshold if ((Environment::shipPosition - lastUpdatePos).squaredNorm() < movementThreshold * movementThreshold
&& !triangleIndicesToDraw.empty()) { && !triangleIndicesToDraw.empty()) {
processMainThreadTasks(); // Все равно обрабатываем очередь OpenGL задач //processMainThreadTasks(); // Все равно обрабатываем очередь OpenGL задач
return; return;
} }
lastUpdatePos = Environment::shipPosition; lastUpdatePos = Environment::shipPosition;
@ -117,13 +119,13 @@ namespace ZL {
planetStones.statuses[triIdx] = ChunkStatus::Generating; planetStones.statuses[triIdx] = ChunkStatus::Generating;
// Отправляем тяжелую математику в TaskManager // Отправляем тяжелую математику в TaskManager
taskManager->EnqueueBackgroundTask([this, triIdx]() { taskManager.EnqueueBackgroundTask([this, triIdx]() {
// Выполняется в фоновом потоке: только генерация геометрии в RAM // Выполняется в фоновом потоке: только генерация геометрии в RAM
float scaleModifier = 1.0f; float scaleModifier = 1.0f;
VertexDataStruct generatedData = planetStones.inflateOneDataOnly(triIdx, scaleModifier); VertexDataStruct generatedData = planetStones.inflateOneDataOnly(triIdx, scaleModifier);
// Передаем задачу на загрузку в GPU в очередь главного потока // Передаем задачу на загрузку в GPU в очередь главного потока
this->EnqueueMainThreadTask([this, triIdx, data = std::move(generatedData)]() mutable { this->mainThreadHandler.EnqueueMainThreadTask([this, triIdx, data = std::move(generatedData)]() mutable {
// Проверяем актуальность: если треугольник всё еще в списке видимых // Проверяем актуальность: если треугольник всё еще в списке видимых
auto it = std::find(triangleIndicesToDraw.begin(), triangleIndicesToDraw.end(), triIdx); auto it = std::find(triangleIndicesToDraw.begin(), triangleIndicesToDraw.end(), triIdx);
if (it != triangleIndicesToDraw.end()) { if (it != triangleIndicesToDraw.end()) {
@ -164,22 +166,7 @@ namespace ZL {
triangleIndicesToDraw = std::move(newIndices); triangleIndicesToDraw = std::move(newIndices);
// 5. Выполняем одну задачу из очереди OpenGL (RefreshVBO и т.д.) // 5. Выполняем одну задачу из очереди OpenGL (RefreshVBO и т.д.)
processMainThreadTasks(); //processMainThreadTasks();
/*
float movementThreshold = 1.0f;
if ((Environment::shipPosition - lastUpdatePos).squaredNorm() < movementThreshold * movementThreshold && !triangleIndicesToDraw.empty()) {
return;
}
lastUpdatePos = Environment::shipPosition;
auto newIndices = planetData.getTrianglesUnderCameraNew2(Environment::shipPosition);
// Сортировка важна для сравнения векторов
std::sort(newIndices.begin(), newIndices.end());
if (newIndices != triangleIndicesToDraw) {
triangleIndicesToDraw = std::move(newIndices);
}*/
} }

View File

@ -21,6 +21,7 @@
namespace ZL { namespace ZL {
class TaskManager; class TaskManager;
class MainThreadHandler;
class PlanetObject { class PlanetObject {
public: public:
@ -42,10 +43,12 @@ namespace ZL {
Vector3f lastUpdatePos; Vector3f lastUpdatePos;
TaskManager* taskManager = nullptr; // External items, set outside
Renderer& renderer;
TaskManager& taskManager;
MainThreadHandler& mainThreadHandler;
public: public:
PlanetObject(); PlanetObject(Renderer& iRenderer, TaskManager& iTaskManager, MainThreadHandler& iMainThreadHandler);
void init(); void init();
void update(float deltaTimeMs); void update(float deltaTimeMs);
@ -56,32 +59,6 @@ namespace ZL {
void drawAtmosphere(Renderer& renderer); void drawAtmosphere(Renderer& renderer);
float distanceToPlanetSurface(const Vector3f& viewerPosition); float distanceToPlanetSurface(const Vector3f& viewerPosition);
std::queue<std::function<void()>> mainThreadTasks;
std::mutex mainThreadMutex;
void EnqueueMainThreadTask(std::function<void()> task) {
std::lock_guard<std::mutex> lock(mainThreadMutex);
mainThreadTasks.push(task);
}
// Выполнение задач по одной (или пачкой) за кадр
void processMainThreadTasks() {
std::function<void()> task;
// Извлекаем только одну задачу, чтобы не блокировать update надолго
{
std::lock_guard<std::mutex> lock(mainThreadMutex);
if (!mainThreadTasks.empty()) {
task = std::move(mainThreadTasks.front());
mainThreadTasks.pop();
}
}
if (task) {
task(); // Здесь выполняется RefreshVBO или загрузка текстуры
}
}
}; };
} // namespace ZL } // namespace ZL

View File

@ -0,0 +1,50 @@
#include "TaskManager.h"
namespace ZL
{
TaskManager::TaskManager(size_t threadCount) {
workGuard = std::make_unique<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>>(ioContext.get_executor());
for (size_t i = 0; i < threadCount; ++i) {
workers.emplace_back([this]() {
ioContext.run();
});
}
}
void TaskManager::EnqueueBackgroundTask(std::function<void()> task) {
boost::asio::post(ioContext, task);
}
TaskManager::~TaskManager() {
workGuard.reset(); // Ðàçðåøàåì ioContext.run() çàâåðøèòüñÿ, êîãäà çàäà÷ íå îñòàíåòñÿ
ioContext.stop(); // Îïöèîíàëüíî: íåìåäëåííàÿ îñòàíîâêà
for (auto& t : workers) {
if (t.joinable()) t.join();
}
}
void MainThreadHandler::EnqueueMainThreadTask(std::function<void()> task) {
std::lock_guard<std::mutex> lock(mainThreadMutex);
mainThreadTasks.push(task);
}
void MainThreadHandler::processMainThreadTasks() {
std::function<void()> task;
// Èçâëåêàåì òîëüêî îäíó çàäà÷ó, ÷òîáû íå áëîêèðîâàòü update íàäîëãî
{
std::lock_guard<std::mutex> lock(mainThreadMutex);
if (!mainThreadTasks.empty()) {
task = std::move(mainThreadTasks.front());
mainThreadTasks.pop();
}
}
if (task) {
task(); // Çäåñü âûïîëíÿåòñÿ RefreshVBO èëè çàãðóçêà òåêñòóðû
}
}
}

View File

@ -4,6 +4,8 @@
#include <vector> #include <vector>
#include <thread> #include <thread>
#include <memory> #include <memory>
#include <queue>
namespace ZL { namespace ZL {
@ -14,30 +16,28 @@ namespace ZL {
std::vector<std::thread> workers; std::vector<std::thread> workers;
public: public:
//TaskManager(size_t threadCount = std::thread::hardware_concurrency()) { //TaskManager(size_t threadCount = std::thread::hardware_concurrency());
TaskManager(size_t threadCount = 2) { TaskManager(size_t threadCount = 2);
workGuard = std::make_unique<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>>(ioContext.get_executor());
for (size_t i = 0; i < threadCount; ++i) {
workers.emplace_back([this]() {
ioContext.run();
});
}
}
// Ìåòîä äëÿ äîáàâëåíèÿ ôîíîâîé çàäà÷è // Ìåòîä äëÿ äîáàâëåíèÿ ôîíîâîé çàäà÷è
void EnqueueBackgroundTask(std::function<void()> task) { void EnqueueBackgroundTask(std::function<void()> task);
boost::asio::post(ioContext, task);
}
// Graceful shutdown // Graceful shutdown
~TaskManager() { ~TaskManager();
workGuard.reset(); // Ðàçðåøàåì ioContext.run() çàâåðøèòüñÿ, êîãäà çàäà÷ íå îñòàíåòñÿ };
ioContext.stop(); // Îïöèîíàëüíî: íåìåäëåííàÿ îñòàíîâêà
for (auto& t : workers) {
if (t.joinable()) t.join(); class MainThreadHandler
} {
} private:
std::queue<std::function<void()>> mainThreadTasks;
std::mutex mainThreadMutex;
public:
void EnqueueMainThreadTask(std::function<void()> task);
// Âûïîëíåíèå çàäà÷ ïî îäíîé (èëè ïà÷êîé) çà êàäð
void processMainThreadTasks();
}; };
} // namespace ZL } // namespace ZL