This commit is contained in:
Vlad committed 2026-01-12 14:55:16 +06:00
commit ec30cbe810
2195 files changed
+8017 -321451

No files matched your search

+6 -1
View File
@@ -1,8 +1,13 @@
#include "Environment.h"
#include "utils/Utils.h"
#include <GL/gl.h>
#ifdef __ANDROID__
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#else
#include <GL/gl.h>
#endif
namespace ZL {
int Environment::windowHeaderHeight = 0;
+2
View File
@@ -2,7 +2,9 @@
#ifdef __linux__
#include <SDL2/SDL.h>
#endif
#ifndef __ANDROID__
#include "render/OpenGlExtensions.h"
#endif
#include <Eigen/Dense>
namespace ZL {
+203 -215
View File
@@ -9,18 +9,20 @@
#include <random>
#include <cmath>
#include <algorithm>
#ifdef __ANDROID__
#include <android/log.h>
#endif
namespace ZL
{
#ifdef EMSCRIPTEN
const char* CONST_ZIP_FILE = "space-game001a.zip";
const char* CONST_ZIP_FILE = "resources.zip";
#else
const char* CONST_ZIP_FILE = "../assets.zip";
const char* CONST_ZIP_FILE = "";
#endif
static bool g_exitBgAnimating = false;
Eigen::Quaternionf generateRandomQuaternion(std::mt19937& gen)
{
@@ -36,7 +38,6 @@ namespace ZL
return randomQuat.normalized();
}
std::vector<BoxCoords> generateRandomBoxCoords(int N)
{
const float MIN_DISTANCE = 3.0f;
@@ -129,66 +130,88 @@ namespace ZL
ZL::BindOpenGlFunctions();
ZL::CheckGlError();
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "Game", "Start for Android");
const char* testFiles[] = {
"resources/shaders/default.vertex",
"resources/shaders/default_web.fragment",
nullptr
};
for (int i = 0; testFiles[i] != nullptr; i++) {
SDL_RWops* file = SDL_RWFromFile(testFiles[i], "rb");
if (file) {
Sint64 size = SDL_RWsize(file);
__android_log_print(ANDROID_LOG_INFO, "Game", "Found: %s (size: %lld)", testFiles[i], size);
SDL_RWclose(file);
}
else {
__android_log_print(ANDROID_LOG_WARN, "Game", "Not found: %s (SDL error: %s)",
testFiles[i], SDL_GetError());
}
}
__android_log_print(ANDROID_LOG_ERROR, "ShaderManager",
"Step 1xxxxxxx");
#endif
// Initialize renderer
#ifdef EMSCRIPTEN
/*renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultColorPlanet", "./shaders/defaultColorPlanet.vertex", "./shaders/defaultColorPlanet_web.fragment", CONST_ZIP_FILE);
*/
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("env_sky", "./shaders/env_sky.vertex", "./shaders/env_sky_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetBake", "./shaders/planet_bake.vertex", "./shaders/planet_bake_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetStone", "./shaders/planet_stone.vertex", "./shaders/planet_stone_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetLand", "./shaders/planet_land.vertex", "./shaders/planet_land_web.fragment", CONST_ZIP_FILE);
#else
#ifndef SIMPLIFIED
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("env_sky", "./shaders/env_sky.vertex", "./shaders/env_sky_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetBake", "./shaders/planet_bake.vertex", "./shaders/planet_bake_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetStone", "./shaders/planet_stone.vertex", "./shaders/planet_stone_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetLand", "./shaders/planet_land.vertex", "./shaders/planet_land_desktop.fragment", CONST_ZIP_FILE);
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);
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "resources/shaders/defaultAtmosphere.vertex", "resources/shaders/defaultAtmosphere_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetBake", "resources/shaders/planet_bake.vertex", "resources/shaders/planet_bake_web.fragment", CONST_ZIP_FILE);
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
/*renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("env_sky", "./shaders/default_env.vertex", "./shaders/default_env_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/default_texture.vertex", "./shaders/default_texture_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetBake", "./shaders/default_texture.vertex", "./shaders/default_texture_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetStone", "./shaders/default_texture.vertex", "./shaders/default_texture_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetLand", "./shaders/default_texture.vertex", "./shaders/default_texture_desktop.fragment", CONST_ZIP_FILE);
*/
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("env_sky", "./shaders/env_sky.vertex", "./shaders/env_sky_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "./shaders/defaultAtmosphere.vertex", "./shaders/defaultAtmosphere_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetBake", "./shaders/planet_bake.vertex", "./shaders/planet_bake_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetStone", "./shaders/planet_stone.vertex", "./shaders/planet_stone_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetLand", "./shaders/planet_land.vertex", "./shaders/planet_land_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("default", "resources/shaders/default.vertex", "resources/shaders/default_web.fragment", CONST_ZIP_FILE);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "ShaderManager",
"Step 2xxxxxxx");
#endif
renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/default_env.vertex", "resources/shaders/default_env_web.fragment", CONST_ZIP_FILE);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Step 2");
#endif
renderer.shaderManager.AddShaderFromFiles("defaultAtmosphere", "resources/shaders/default_texture.vertex", "resources/shaders/default_texture_web.fragment", CONST_ZIP_FILE);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Step 3");
#endif
renderer.shaderManager.AddShaderFromFiles("planetBake", "resources/shaders/default_texture.vertex", "resources/shaders/default_texture_web.fragment", CONST_ZIP_FILE);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Step 4");
#endif
renderer.shaderManager.AddShaderFromFiles("planetStone", "resources/shaders/default_texture.vertex", "resources/shaders/default_texture_web.fragment", CONST_ZIP_FILE);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Step 5");
#endif
renderer.shaderManager.AddShaderFromFiles("planetLand", "resources/shaders/default_texture.vertex", "resources/shaders/default_texture_web.fragment", CONST_ZIP_FILE);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Step 1");
#endif
#endif
//#ifndef SIMPLIFIED
bool cfgLoaded = sparkEmitter.loadFromJsonFile("config/spark_config.json", renderer, CONST_ZIP_FILE);
bool projCfgLoaded = projectileEmitter.loadFromJsonFile("config/spark_projectile_config.json", renderer, CONST_ZIP_FILE);
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);
projectileEmitter.setEmissionPoints(std::vector<Vector3f>());
uiManager.loadFromFile("config/ui.json", renderer, CONST_ZIP_FILE);
uiManager.loadFromFile("resources/config/ui.json", renderer, CONST_ZIP_FILE);
uiManager.loadFromFile("config/ui.json", renderer, CONST_ZIP_FILE);
uiManager.startAnimationOnNode("backgroundNode", "bgScroll");
static bool isExitButtonAnimating = false;
uiManager.setAnimationCallback("settingsButton", "buttonsExit", [this]() {
std::cerr << "Settings button animation finished -> переход в настройки" << std::endl;
if (uiManager.pushMenuFromFile("config/settings.json", this->renderer, CONST_ZIP_FILE)) {
if (uiManager.pushMenuFromFile("resources/config/settings.json", this->renderer, CONST_ZIP_FILE)) {
uiManager.setButtonCallback("Opt1", [this](const std::string& n) {
std::cerr << "Opt1 pressed: " << n << std::endl;
});
@@ -246,32 +269,45 @@ namespace ZL
}
}
});
uiManager.setButtonCallback("shootButton", [this](const std::string& name) {
uint64_t now = SDL_GetTicks64();
if (now - lastProjectileFireTime >= static_cast<uint64_t>(projectileCooldownMs)) {
lastProjectileFireTime = now;
fireProjectiles();
}
});
uiManager.setSliderCallback("musicVolumeSlider", [this](const std::string& name, float value) {
uiManager.setSliderCallback("velocitySlider", [this](const std::string& name, float value) {
Environment::shipVelocity = value * 1000.f;
});
/*uiManager.setSliderCallback("musicVolumeSlider", [this](const std::string& name, float value) {
std::cerr << "Music volume slider changed to: " << value << std::endl;
musicVolume = value;
Environment::shipVelocity = musicVolume * 20.0f;
});
//#endif
//#endif*/
cubemapTexture = std::make_shared<Texture>(
std::array<TextureDataStruct, 6>{
CreateTextureDataFromBmp24("./resources/sky/space_rt.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_lf.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_up.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_dn.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_bk.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_ft.bmp", CONST_ZIP_FILE)
CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE),
CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE),
CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE),
CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE),
CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE),
CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE)
});
cubemap.data = ZL::CreateCubemap(500);
cubemap.RefreshVBO();
//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));
//spaceshipBase = LoadFromTextFile02("./resources/spaceship006x.txt", CONST_ZIP_FILE);
@@ -286,8 +322,8 @@ namespace ZL
//Boxes
boxTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/box/box.png", CONST_ZIP_FILE));
boxBase = LoadFromTextFile02("./resources/box/box.txt", CONST_ZIP_FILE);
boxTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/box/box.png", CONST_ZIP_FILE));
boxBase = LoadFromTextFile02("resources/box/box.txt", CONST_ZIP_FILE);
std::cout << "Init step 1 " << std::endl;
@@ -306,73 +342,15 @@ namespace ZL
boxRenderArr[i].RefreshVBO();
}
std::cout << "Init step 4 " << std::endl;
#ifndef SIMPLIFIED
if (!cfgLoaded)
{
throw std::runtime_error("Failed to load spark emitter config file!");
}
#endif
/* buttonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/button.png", CONST_ZIP_FILE));
button.data.PositionData.push_back({ 100, 100, 0 });
button.data.PositionData.push_back({ 100, 150, 0 });
button.data.PositionData.push_back({ 300, 150, 0 });
button.data.PositionData.push_back({ 100, 100, 0 });
button.data.PositionData.push_back({ 300, 150, 0 });
button.data.PositionData.push_back({ 300, 100, 0 });
button.data.TexCoordData.push_back({ 0,0 });
button.data.TexCoordData.push_back({ 0,1 });
button.data.TexCoordData.push_back({ 1,1 });
button.data.TexCoordData.push_back({ 0,0 });
button.data.TexCoordData.push_back({ 1,1 });
button.data.TexCoordData.push_back({ 1,0 });
button.RefreshVBO();*/
/*
musicVolumeBarTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarTexture.png", CONST_ZIP_FILE));
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
musicVolumeBar.data.PositionData.push_back({ 1190, 600, 0 });
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
musicVolumeBar.data.PositionData.push_back({ 1200, 100, 0 });
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
musicVolumeBar.data.TexCoordData.push_back({ 0,1 });
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
musicVolumeBar.data.TexCoordData.push_back({ 1,0 });
musicVolumeBar.RefreshVBO();
musicVolumeBarButtonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarButton.png", CONST_ZIP_FILE));
float musicVolumeBarButtonButtonCenterY = 350.0f;
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
musicVolumeBarButton.data.TexCoordData.push_back({ 0,1 });
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
musicVolumeBarButton.data.TexCoordData.push_back({ 1,0 });
musicVolumeBarButton.RefreshVBO();*/
std::cout << "Init step 5 " << std::endl;
renderer.InitOpenGL();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -380,6 +358,8 @@ namespace ZL
std::cout << "Init step 6 " << std::endl;
planetObject.init();
planetObject.taskManager = &taskManager;
std::cout << "Init step 7 " << std::endl;
//rockTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", CONST_ZIP_FILE));
@@ -476,18 +456,18 @@ namespace ZL
renderer.TranslateMatrix({ 0, -Environment::zoom * 0.03f, 0 });
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
renderer.DrawVertexRenderStruct(spaceship);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (const auto& p : projectiles) {
if (p && p->isActive()) {
p->draw(renderer);
}
}
//#ifndef SIMPLIFIED
sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
projectileEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
//#endif
glDisable(GL_BLEND);
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
@@ -539,37 +519,6 @@ namespace ZL
renderer.shaderManager.PopShader();
CheckGlError();
}
/*void Game::UpdateVolumeKnob() {
float musicVolumeBarButtonButtonCenterY = volumeBarMinY + musicVolume * (volumeBarMaxY - volumeBarMinY);
auto& pos = musicVolumeBarButton.data.PositionData;
pos[0] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
pos[1] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
pos[2] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
pos[3] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
pos[4] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
pos[5] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
musicVolumeBarButton.RefreshVBO();
}
void Game::UpdateVolumeFromMouse(int mouseX, int mouseY) {
int uiX = mouseX;
int uiY = Environment::height - mouseY;
Environment::shipVelocity = (musicVolume) * (20.0);
if (uiY < volumeBarMinY || uiY > volumeBarMaxY)
{
return;
}
float t = (uiY - volumeBarMinY) / (volumeBarMaxY - volumeBarMinY);
if (t < 0.0f) t = 0.0f;
if (t > 1.0f) t = 1.0f;
musicVolume = t;
UpdateVolumeKnob();
}*/
void Game::drawUI()
{
@@ -586,27 +535,11 @@ namespace ZL
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
//renderer.PushProjectionMatrix(Environment::width, Environment::height, -1, 1);
//renderer.PushMatrix();
//renderer.LoadIdentity();
//glBindTexture(GL_TEXTURE_2D, buttonTexture->getTexID());
//renderer.DrawVertexRenderStruct(button);
//glBindTexture(GL_TEXTURE_2D, musicVolumeBarTexture->getTexID());
//renderer.DrawVertexRenderStruct(musicVolumeBar);
//glBindTexture(GL_TEXTURE_2D, musicVolumeBarButtonTexture->getTexID());
//renderer.DrawVertexRenderStruct(musicVolumeBarButton);
//renderer.PopMatrix();
//renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
glEnable(GL_BLEND);
uiManager.draw(renderer);
glDisable(GL_BLEND);
renderer.shaderManager.PopShader();
CheckGlError();
}
@@ -650,10 +583,7 @@ namespace ZL
drawShip();
drawBoxes();
//#ifndef SIMPLIFIED
drawUI();
//#endif
CheckGlError();
}
@@ -669,11 +599,9 @@ namespace ZL
size_t delta = (newTickCount - lastTickCount > CONST_MAX_TIME_INTERVAL) ?
CONST_MAX_TIME_INTERVAL : newTickCount - lastTickCount;
//#ifndef SIMPLIFIED
//gameObjects.updateScene(delta);
sparkEmitter.update(static_cast<float>(delta));
//#endif
planetObject.update(static_cast<float>(delta));
if (Environment::tapDownHold) {
float diffx = Environment::tapDownCurrentPos(0) - Environment::tapDownStartPos(0);
@@ -707,7 +635,6 @@ namespace ZL
Environment::shipPosition = Environment::shipPosition + velocityDirectionAdjusted;
}
//#ifndef SIMPLIFIED
for (auto& p : projectiles) {
if (p && p->isActive()) {
p->update(static_cast<float>(delta), renderer);
@@ -764,7 +691,7 @@ namespace ZL
for (const auto& lo : localOffsets) {
Vector3f worldPos = Environment::shipPosition + Environment::shipMatrix * lo;
Vector3f worldVel = worldForward * projectileSpeed;
Vector3f worldVel = worldForward * (projectileSpeed + Environment::shipVelocity);
for (auto& p : projectiles) {
if (!p->isActive()) {
@@ -787,30 +714,47 @@ namespace ZL
SDL_GL_SwapWindow(ZL::Environment::window);
}
void Game::update() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
Environment::exitGameLoop = true;
}
else if (event.type == SDL_MOUSEBUTTONDOWN) {
#ifdef __ANDROID__
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_AC_BACK) {
Environment::exitGameLoop = true;
}
#endif
#ifdef __ANDROID__
if (event.type == SDL_FINGERDOWN) {
// Координаты Finger в SDL нормализованы от 0.0 до 1.0
int mx = static_cast<int>(event.tfinger.x * Environment::width);
int my = static_cast<int>(event.tfinger.y * Environment::height);
handleDown(mx, my);
}
else if (event.type == SDL_FINGERUP) {
int mx = static_cast<int>(event.tfinger.x * Environment::width);
int my = static_cast<int>(event.tfinger.y * Environment::height);
handleUp(mx, my);
}
else if (event.type == SDL_FINGERMOTION) {
int mx = static_cast<int>(event.tfinger.x * Environment::width);
int my = static_cast<int>(event.tfinger.y * Environment::height);
handleMotion(mx, my);
}
#else
if (event.type == SDL_MOUSEBUTTONDOWN) {
int mx = event.button.x;
int my = event.button.y;
int uiX = mx;
int uiY = Environment::height - my;
uiManager.onMouseDown(uiX, uiY);
uiManager.onMouseDown(mx, my);
bool uiHandled = false;
//#ifndef SIMPLIFIED
if (event.button.button == SDL_BUTTON_LEFT && !uiManager.isUiInteraction()) {
uint64_t now = SDL_GetTicks64();
if (now - lastProjectileFireTime >= static_cast<uint64_t>(projectileCooldownMs)) {
lastProjectileFireTime = now;
fireProjectiles();
}
}
//#endif
for (const auto& button : uiManager.findButton("") ? std::vector<std::shared_ptr<UiButton>>{} : std::vector<std::shared_ptr<UiButton>>{}) {
(void)button;
}
@@ -831,35 +775,22 @@ namespace ZL
Environment::tapDownCurrentPos(0) = mx;
Environment::tapDownCurrentPos(1) = my;
}
handleDown(mx, my);
}
else if (event.type == SDL_MOUSEBUTTONUP) {
if (event.type == SDL_MOUSEBUTTONUP) {
int mx = event.button.x;
int my = event.button.y;
int uiX = mx;
int uiY = Environment::height - my;
uiManager.onMouseUp(uiX, uiY);
if (!uiManager.isUiInteraction()) {
Environment::tapDownHold = false;
}
handleUp(mx, my);
}
else if (event.type == SDL_MOUSEMOTION) {
if (event.type == SDL_MOUSEMOTION) {
int mx = event.motion.x;
int my = event.motion.y;
int uiX = mx;
int uiY = Environment::height - my;
handleMotion(mx, my);
uiManager.onMouseMove(uiX, uiY);
if (Environment::tapDownHold && !uiManager.isUiInteraction()) {
Environment::tapDownCurrentPos(0) = mx;
Environment::tapDownCurrentPos(1) = my;
}
}
else if (event.type == SDL_MOUSEWHEEL) {
if (event.type == SDL_MOUSEWHEEL) {
static const float zoomstep = 2.0f;
if (event.wheel.y > 0) {
Environment::zoom -= zoomstep;
@@ -871,7 +802,7 @@ namespace ZL
Environment::zoom = zoomstep;
}
}
else if (event.type == SDL_KEYUP)
if (event.type == SDL_KEYUP)
{
if (event.key.keysym.sym == SDLK_i)
{
@@ -890,8 +821,65 @@ namespace ZL
Environment::shipVelocity -= 50.f;
}
}
#endif
}
render();
}
void Game::handleDown(int mx, int my)
{
int uiX = mx;
int uiY = Environment::height - my;
uiManager.onMouseDown(uiX, uiY);
bool uiHandled = false;
for (const auto& button : uiManager.findButton("") ? std::vector<std::shared_ptr<UiButton>>{} : std::vector<std::shared_ptr<UiButton>>{}) {
(void)button;
}
auto pressedSlider = [&]() -> std::shared_ptr<UiSlider> {
for (const auto& slider : uiManager.findSlider("") ? std::vector<std::shared_ptr<UiSlider>>{} : std::vector<std::shared_ptr<UiSlider>>{}) {
(void)slider;
}
return nullptr;
}();
if (!uiManager.isUiInteraction()) {
Environment::tapDownHold = true;
Environment::tapDownStartPos(0) = mx;
Environment::tapDownStartPos(1) = my;
Environment::tapDownCurrentPos(0) = mx;
Environment::tapDownCurrentPos(1) = my;
}
}
void Game::handleUp(int mx, int my)
{
int uiX = mx;
int uiY = Environment::height - my;
uiManager.onMouseUp(uiX, uiY);
if (!uiManager.isUiInteraction()) {
Environment::tapDownHold = false;
}
}
void Game::handleMotion(int mx, int my)
{
int uiX = mx;
int uiY = Environment::height - my;
uiManager.onMouseMove(uiX, uiY);
if (Environment::tapDownHold && !uiManager.isUiInteraction()) {
Environment::tapDownCurrentPos(0) = mx;
Environment::tapDownCurrentPos(1) = my;
}
}
} // namespace ZL
+14 -3
View File
@@ -7,6 +7,8 @@
#include "planet/PlanetObject.h"
#include "UiManager.h"
#include "Projectile.h"
#include "utils/TaskManager.h"
#include <queue>
namespace ZL {
@@ -40,6 +42,10 @@ namespace ZL {
void fireProjectiles();
void handleDown(int mx, int my);
void handleUp(int mx, int my);
void handleMotion(int mx, int my);
SDL_Window* window;
SDL_GLContext glContext;
Renderer renderer;
@@ -66,12 +72,12 @@ namespace ZL {
//bool isDraggingVolume = false;
float musicVolume = 0.0f;
/*
float velocitySlider = 0.0f;
float volumeBarMinX = 1190.0f;
float volumeBarMaxX = 1200.0f;
float volumeBarMinY = 100.0f;
float volumeBarMaxY = 600.0f;
float volumeBarMaxY = 600.0f;*/
//float musicVolumeBarButtonButtonCenterX = 1195.0f;
//float musicVolumeBarButtonButtonRadius = 25.0f;
//void UpdateVolumeFromMouse(int mouseX, int mouseY);
@@ -103,6 +109,11 @@ namespace ZL {
uint64_t lastProjectileFireTime = 0;
int maxProjectiles = 32;
std::vector<Vector3f> shipLocalEmissionPoints;
TaskManager taskManager;
};
+2 -1
View File
@@ -13,6 +13,7 @@ namespace ZL {
using json = nlohmann::json;
SparkEmitter::SparkEmitter()
: emissionRate(100.0f), isActive(true), drawDataDirty(true), maxParticles(200),
shaderProgramName("default"), particleSize(0.04f), biasX(0.3f), configured(false) {
@@ -76,7 +77,7 @@ namespace ZL {
std::sort(sortedParticles.begin(), sortedParticles.end(),
[](const auto& a, const auto& b) {
return a.second > b.second;
return a.second < b.second;
});
for (const auto& [particlePtr, depth] : sortedParticles) {
+25 -10
View File
@@ -4,7 +4,9 @@
#include <fstream>
#include <iostream>
#include <sstream>
#ifdef __ANDROID__
#include <android/log.h>
#endif
namespace ZL
{
@@ -224,25 +226,38 @@ namespace ZL
VertexDataStruct LoadFromTextFile02(const std::string& fileName, const std::string& ZIPFileName)
{
VertexDataStruct result;
std::ifstream filestream;
std::istringstream zipStream;
std::istringstream f;
// --- 1. Открытие потока (без изменений) ---
if (!ZIPFileName.empty())
{
std::vector<char> fileData = readFileFromZIP(fileName, ZIPFileName);
std::string fileContents(fileData.begin(), fileData.end());
zipStream.str(fileContents);
f.str(fileContents);
}
else
{
filestream.open(fileName);
if (!filestream.is_open()) {
throw std::runtime_error("Failed to open file: " + fileName);
}
}
#ifdef __ANDROID__
// Для Android используем SDL_RWops для чтения файлов
__android_log_print(ANDROID_LOG_INFO, "TextModel",
"LoadFromTextFile02 called for Android: %s", fileName.c_str());
#endif
// Читаем файл с помощью readTextFile
std::string fileContent = readTextFile(fileName);
if (fileContent.empty()) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "TextModel",
"Failed to read file: %s", fileName.c_str());
#endif
throw std::runtime_error("Failed to read file: " + fileName);
}
std::istream& f = (!ZIPFileName.empty()) ? static_cast<std::istream&>(zipStream) : static_cast<std::istream&>(filestream);
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "TextModel",
"File read successfully, size: %zu", fileContent.size());
#endif
f.str(fileContent);
}
std::string tempLine;
std::smatch match;
+98 -1
View File
@@ -1,14 +1,110 @@
#include "Game.h"
#include "Environment.h"
#include <iostream>
#ifdef __ANDROID__
#include <android/log.h>
#endif
ZL::Game game;
void MainLoop() {
game.update();
}
int main(int argc, char* argv[]) {
#ifdef __ANDROID__
extern "C" int SDL_main(int argc, char* argv[]) {
// Инициализация SDL перед получением информации о дисплее
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
__android_log_print(ANDROID_LOG_ERROR, "Game", "SDL init failed: %s", SDL_GetError());
return 1;
}
SDL_DisplayMode displayMode;
if (SDL_GetCurrentDisplayMode(0, &displayMode) != 0) {
__android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GetCurrentDisplayMode failed: %s", SDL_GetError());
SDL_Quit();
return 1;
}
ZL::Environment::width = displayMode.w;
ZL::Environment::height = displayMode.h;
__android_log_print(ANDROID_LOG_INFO, "Game", "Display resolution: %dx%d",
ZL::Environment::width, ZL::Environment::height);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
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_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
ZL::Environment::window = SDL_CreateWindow(
"Space Ship Game",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
ZL::Environment::width, ZL::Environment::height,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
);
if (!ZL::Environment::window) {
__android_log_print(ANDROID_LOG_ERROR, "Game", "Failed to create window: %s", SDL_GetError());
SDL_Quit();
return 1;
}
SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window);
if (!ctx) {
__android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GL_CreateContext failed: %s", SDL_GetError());
SDL_DestroyWindow(ZL::Environment::window);
SDL_Quit();
return 1;
}
if (SDL_GL_MakeCurrent(ZL::Environment::window, ctx) != 0) {
__android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GL_MakeCurrent failed: %s", SDL_GetError());
SDL_GL_DeleteContext(ctx);
SDL_DestroyWindow(ZL::Environment::window);
SDL_Quit();
return 1;
}
// Настройка VSync
if (SDL_GL_SetSwapInterval(1) < 0) {
__android_log_print(ANDROID_LOG_WARN, "Game", "Unable to set VSync: %s", SDL_GetError());
}
// Настройка игры
try {
game.setup();
} catch (const std::exception &e) {
__android_log_print(ANDROID_LOG_ERROR, "Game", "Game setup failed: %s", e.what());
return 1;
}
while (!game.shouldExit()) {
game.update();
SDL_Delay(16);
}
return 0;
}
#else
int main(int argc, char *argv[]) {
try
{
constexpr int CONST_WIDTH = 1280;
constexpr int CONST_HEIGHT = 720;
@@ -86,3 +182,4 @@ int main(int argc, char* argv[]) {
return 0;
}
#endif
+2 -5
View File
@@ -32,7 +32,7 @@ namespace ZL {
, currentLod(0)
{
currentLod = planetMeshLods.size() - 1; // Start with max LOD
/*
initialVertexMap = {
{{ 0.0f, 1.0f, 0.0f}, "A"},
{{ 0.0f, -1.0f, 0.0f}, "B"},
@@ -40,7 +40,7 @@ namespace ZL {
{{-1.0f, 0.0f, 0.0f}, "D"},
{{ 0.0f, 0.0f, 1.0f}, "E"},
{{ 0.0f, 0.0f, -1.0f}, "F"}
};
};*/
}
void PlanetData::init() {
@@ -51,12 +51,9 @@ namespace ZL {
planetMeshLods[i].Move(PLANET_CENTER_OFFSET);
}
//#ifndef SIMPLIFIED
planetAtmosphereLod = generateSphere(5, 0);
planetAtmosphereLod.Scale(PLANET_RADIUS * 1.03);
planetAtmosphereLod.Move(PLANET_CENTER_OFFSET);
//#endif
}
const LodLevel& PlanetData::getLodLevel(int level) const {
+1 -6
View File
@@ -25,12 +25,7 @@ namespace ZL {
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2);
#ifdef SIMPLIFIED
constexpr static int MAX_LOD_LEVELS = 1;
#else
constexpr static int MAX_LOD_LEVELS = 6;
#endif
struct Triangle
{
@@ -94,7 +89,7 @@ namespace ZL {
int currentLod; // Ëîãè÷åñêèé òåêóùèé óðîâåíü äåòàëèçàöèè
std::map<Vector3f, VertexID, Vector3fComparator> initialVertexMap;
//std::map<Vector3f, VertexID, Vector3fComparator> initialVertexMap;
// Âíóòðåííèå ìåòîäû ãåíåðàöèè
std::vector<Triangle> subdivideTriangles(const std::vector<Triangle>& inputTriangles, float noiseCoeff);
+92 -19
View File
@@ -4,11 +4,11 @@
#include "render/OpenGlExtensions.h"
#include "Environment.h"
#include "StoneObject.h"
#include "utils/TaskManager.h"
namespace ZL {
#ifdef EMSCRIPTEN
#if defined EMSCRIPTEN || defined __ANDROID__
using std::min;
using std::max;
#endif
@@ -17,6 +17,7 @@ namespace ZL {
Matrix3f GetRotationForTriangle(const Triangle& tri) {
Vector3f vA = tri.data[0];
Vector3f vB = tri.data[1];
Vector3f vC = tri.data[2];
@@ -74,23 +75,21 @@ namespace ZL {
planetRenderStruct.RefreshVBO();
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand2.png", CONST_ZIP_FILE));
stoneTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", CONST_ZIP_FILE));
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/sand2.png", CONST_ZIP_FILE));
stoneTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/rockdark3.png", CONST_ZIP_FILE));
//#ifndef SIMPLIFIED
// Атмосфера
planetAtmosphereRenderStruct.data = planetData.getAtmosphereLod().vertexData;
if (planetAtmosphereRenderStruct.data.PositionData.size() > 0)
{
planetAtmosphereRenderStruct.RefreshVBO();
}
//#endif
planetStones = CreateStoneGroupData(778, planetData.getLodLevel(lodIndex));
stonesToRender = planetStones.inflate(planetStones.allInstances.size());
//stonesToRender = planetStones.inflate(planetStones.allInstances.size());
stonesToRender.resize(planetStones.allInstances.size());
planetStones.initStatuses();
stoneToBake = planetStones.inflateOne(0, 0.75);
}
@@ -98,6 +97,75 @@ namespace ZL {
void PlanetObject::update(float deltaTimeMs) {
// 1. Проверка порога движения (оптимизация из текущего кода)
float movementThreshold = 1.0f;
if ((Environment::shipPosition - lastUpdatePos).squaredNorm() < movementThreshold * movementThreshold
&& !triangleIndicesToDraw.empty()) {
processMainThreadTasks(); // Все равно обрабатываем очередь OpenGL задач
return;
}
lastUpdatePos = Environment::shipPosition;
// 2. Получаем список видимых треугольников
auto newIndices = planetData.getTrianglesUnderCameraNew2(Environment::shipPosition);
std::sort(newIndices.begin(), newIndices.end());
// 3. Анализируем, что нужно загрузить
for (int triIdx : newIndices) {
if (planetStones.statuses[triIdx] == ChunkStatus::Empty) {
// Помечаем, чтобы не спамить задачами
planetStones.statuses[triIdx] = ChunkStatus::Generating;
// Отправляем тяжелую математику в TaskManager
taskManager->EnqueueBackgroundTask([this, triIdx]() {
// Выполняется в фоновом потоке: только генерация геометрии в RAM
float scaleModifier = 1.0f;
VertexDataStruct generatedData = planetStones.inflateOneDataOnly(triIdx, scaleModifier);
// Передаем задачу на загрузку в GPU в очередь главного потока
this->EnqueueMainThreadTask([this, triIdx, data = std::move(generatedData)]() mutable {
// Проверяем актуальность: если треугольник всё еще в списке видимых
auto it = std::find(triangleIndicesToDraw.begin(), triangleIndicesToDraw.end(), triIdx);
if (it != triangleIndicesToDraw.end()) {
stonesToRender[triIdx].data = std::move(data);
stonesToRender[triIdx].RefreshVBO(); // OpenGL вызов
planetStones.statuses[triIdx] = ChunkStatus::Live;
}
else {
// Если уже не нужен — просто сбрасываем статус
planetStones.statuses[triIdx] = ChunkStatus::Empty;
}
});
});
}
}
// 4. Очистка (Unload)
// Если статус Live, но треугольника нет в новых индексах — освобождаем GPU память
for (size_t i = 0; i < planetStones.statuses.size(); ++i) {
if (planetStones.statuses[i] == ChunkStatus::Live) {
bool isVisible = std::binary_search(newIndices.begin(), newIndices.end(), (int)i);
if (!isVisible) {
// Очищаем данные и VBO (деструкторы shared_ptr в VertexRenderStruct сделают glDeleteBuffers)
stonesToRender[i].data.PositionData.clear();
stonesToRender[i].vao.reset();
stonesToRender[i].positionVBO.reset();
stonesToRender[i].normalVBO.reset();
stonesToRender[i].tangentVBO.reset();
stonesToRender[i].binormalVBO.reset();
stonesToRender[i].colorVBO.reset();
stonesToRender[i].texCoordVBO.reset();
planetStones.statuses[i] = ChunkStatus::Empty;
}
}
}
triangleIndicesToDraw = std::move(newIndices);
// 5. Выполняем одну задачу из очереди OpenGL (RefreshVBO и т.д.)
processMainThreadTasks();
/*
float movementThreshold = 1.0f;
if ((Environment::shipPosition - lastUpdatePos).squaredNorm() < movementThreshold * movementThreshold && !triangleIndicesToDraw.empty()) {
return;
@@ -111,7 +179,7 @@ namespace ZL {
if (newIndices != triangleIndicesToDraw) {
triangleIndicesToDraw = std::move(newIndices);
}
}*/
}
@@ -205,7 +273,6 @@ namespace ZL {
void PlanetObject::draw(Renderer& renderer) {
//#ifndef SIMPLIFIED
{
if (stoneMapFB == nullptr)
{
@@ -221,10 +288,6 @@ namespace ZL {
stoneMapFB->GenerateMipmaps();
}
//#endif
//bakeStoneTexture(renderer);
glViewport(0, 0, Environment::width, Environment::height);
//--------------------------
@@ -232,10 +295,7 @@ namespace ZL {
drawPlanet(renderer);
drawStones(renderer);
//#ifndef SIMPLIFIED
drawAtmosphere(renderer);
//#endif
}
void PlanetObject::drawPlanet(Renderer& renderer)
@@ -382,7 +442,7 @@ namespace ZL {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID());
/*
for (int i : triangleIndicesToDraw)
//for (int i = 0; i < stonesToRender.size(); i++)
{
@@ -390,7 +450,20 @@ namespace ZL {
{
renderer.DrawVertexRenderStruct(stonesToRender[i]);
}
}*/
for (int i : triangleIndicesToDraw) {
// КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ:
// Проверяем, что данные не просто существуют, а загружены в GPU
if (planetStones.statuses[i] == ChunkStatus::Live) {
// Дополнительная проверка на наличие данных (на всякий случай)
if (stonesToRender[i].data.PositionData.size() > 0) {
renderer.DrawVertexRenderStruct(stonesToRender[i]);
}
}
// Если статус Generating или Empty — мы просто пропускаем этот индекс.
// Камни появятся на экране плавно, как только отработает TaskManager и RefreshVBO.
}
CheckGlError();
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
+31
View File
@@ -16,8 +16,11 @@
#include "PlanetData.h"
#include "StoneObject.h"
#include "render/FrameBuffer.h"
#include <queue>
#include <mutex>
namespace ZL {
class TaskManager;
class PlanetObject {
public:
@@ -39,6 +42,8 @@ namespace ZL {
Vector3f lastUpdatePos;
TaskManager* taskManager = nullptr;
public:
PlanetObject();
@@ -51,6 +56,32 @@ namespace ZL {
void drawAtmosphere(Renderer& renderer);
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
+31 -41
View File
@@ -1,7 +1,6 @@
#include "StoneObject.h"
#include "utils/Utils.h"
#include <GL/gl.h>
#include <random>
#include <cmath>
#include "render/Renderer.h"
@@ -9,36 +8,20 @@
namespace ZL {
#ifdef EMSCRIPTEN
#if defined EMSCRIPTEN || defined __ANDROID__
using std::min;
using std::max;
#endif
#ifdef SIMPLIFIED
const float StoneParams::BASE_SCALE = 1000.0f; // Общий размер камня
const float StoneParams::MIN_AXIS_SCALE = 1.0f; // Минимальное растяжение/сжатие по оси
const float StoneParams::MAX_AXIS_SCALE = 1.0f; // Максимальное растяжение/сжатие по оси
const float StoneParams::MIN_PERTURBATION = 0.0f; // Минимальное радиальное возмущение вершины
const float StoneParams::MAX_PERTURBATION = 0.0f; // Максимальное радиальное возмущение вершины
const int StoneParams::STONES_PER_TRIANGLE = 2;
#else
const float StoneParams::BASE_SCALE = 10.0f; // Общий размер камня
const float StoneParams::MIN_AXIS_SCALE = 1.0f; // Минимальное растяжение/сжатие по оси
const float StoneParams::MAX_AXIS_SCALE = 1.0f; // Максимальное растяжение/сжатие по оси
const float StoneParams::MIN_PERTURBATION = 0.0f; // Минимальное радиальное возмущение вершины
const float StoneParams::MAX_PERTURBATION = 0.0f; // Максимальное радиальное возмущение вершины
const int StoneParams::STONES_PER_TRIANGLE = 40;
#endif
/*const float StoneParams::MIN_AXIS_SCALE = 0.5f; // Минимальное растяжение/сжатие по оси
const float StoneParams::MAX_AXIS_SCALE = 1.5f; // Максимальное растяжение/сжатие по оси
const float StoneParams::MIN_PERTURBATION = 0.05f; // Минимальное радиальное возмущение вершины
const float StoneParams::MAX_PERTURBATION = 0.25f; // Максимальное радиальное возмущение вершины
*/
//const int StoneParams::STONES_PER_TRIANGLE = 1;
// Вспомогательная функция для получения случайного числа в диапазоне [min, max]
@@ -297,34 +280,12 @@ namespace ZL {
std::vector<VertexRenderStruct> StoneGroup::inflate(int count)
{
//static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337);
std::vector<VertexRenderStruct> result;
result.resize(count);
for (int tIdx = 0; tIdx < count; tIdx++)
{
result[tIdx] = inflateOne(tIdx, 1.0f);
/*
for (const auto& inst : allInstances[tIdx]) {
Matrix3f rotMat = QuatToMatrix(inst.rotation);
for (size_t j = 0; j < baseStone.PositionData.size(); ++j) {
Vector3f p = baseStone.PositionData[j];
Vector3f n = baseStone.NormalData[j];
p.v[0] *= inst.scale.v[0];
p.v[1] *= inst.scale.v[1];
p.v[2] *= inst.scale.v[2];
result[tIdx].data.PositionData.push_back(MultMatrixVector(rotMat, p) + inst.position);
result[tIdx].data.NormalData.push_back(MultMatrixVector(rotMat, n));
result[tIdx].data.TexCoordData.push_back(baseStone.TexCoordData[j]);
}
result[tIdx].RefreshVBO();
}*/
}
return result;
@@ -361,4 +322,33 @@ namespace ZL {
return result;
}
VertexDataStruct StoneGroup::inflateOneDataOnly(int index, float scaleModifier)
{
static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337);
VertexDataStruct result;
for (const auto& inst : allInstances[index]) {
Matrix3f rotMat = inst.rotation.toRotationMatrix();
for (size_t j = 0; j < baseStone.PositionData.size(); ++j) {
Vector3f p = baseStone.PositionData[j];
Vector3f n = baseStone.NormalData[j];
p(0) *= inst.scale(0) * scaleModifier;
p(1) *= inst.scale(1) * scaleModifier;
p(2) *= inst.scale(2) * scaleModifier;
result.PositionData.push_back(rotMat * p + inst.position);
result.NormalData.push_back(rotMat * n);
result.TexCoordData.push_back(baseStone.TexCoordData[j]);
}
}
return result;
}
} // namespace ZL
+15
View File
@@ -22,6 +22,13 @@ namespace ZL {
Eigen::Quaternionf rotation;
};
enum class ChunkStatus {
Empty, // Äàííûõ íåò
Generating, // Çàäà÷à â TaskManager (CPU)
ReadyToUpload, // Äàííûå â ïàìÿòè, æäóò î÷åðåäè â ãëàâíûé ïîòîê
Live // Çàãðóæåíî â GPU è ãîòîâî ê îòðèñîâêå
};
struct StoneGroup {
// mesh.PositionData è ïðî÷èå áóäóò çàïîëíÿòüñÿ â inflate()
VertexDataStruct mesh;
@@ -32,6 +39,14 @@ namespace ZL {
std::vector<VertexRenderStruct> inflate(int count);
VertexRenderStruct inflateOne(int index, float scaleModifier);
VertexDataStruct inflateOneDataOnly(int index, float scaleModifier);
std::vector<ChunkStatus> statuses;
// Èíèöèàëèçàöèÿ ñòàòóñîâ ïðè ñîçäàíèè ãðóïïû
void initStatuses() {
statuses.assign(allInstances.size(), ChunkStatus::Empty);
}
};
// Òåïåðü âîçâðàùàåò çàãîòîâêó ñî âñåìè ïàðàìåòðàìè, íî áåç òÿæåëîãî ìåøà
+4 -4
View File
@@ -1,5 +1,5 @@
#pragma once
#include "OpenGlExtensions.h"
#include "render/OpenGlExtensions.h"
#include <memory>
namespace ZL {
@@ -9,10 +9,10 @@ namespace ZL {
GLuint fbo = 0;
GLuint textureID = 0;
int width, height;
bool useMipmaps; // Флаг использования мип-мапов
bool useMipmaps; // ���� ������������� ���-�����
public:
// Добавляем параметр в конструктор по умолчанию false
// ��������� �������� � ����������� �� ��������� false
FrameBuffer(int w, int h, bool useMipmaps = false);
~FrameBuffer();
@@ -22,7 +22,7 @@ namespace ZL {
void Bind();
void Unbind();
// Метод для принудительной генерации мип-мапов после рендера
// ����� ��� �������������� ��������� ���-����� ����� �������
void GenerateMipmaps();
GLuint getTextureID() const { return textureID; }
+9 -5
View File
@@ -10,13 +10,17 @@
#include "emscripten.h"
#endif
#ifdef __linux__
#include <GL/gl.h>
#include <GL/glu.h>
#include <GLES3/gl3.h>
#ifdef __ANDROID__
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#else
#ifdef __linux__
#include <GL/gl.h>
#include <GL/glu.h>
#include <GLES3/gl3.h>
#endif
#endif
#include <exception>
#include <stdexcept>
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+11 -4
View File
@@ -50,17 +50,17 @@ namespace ZL {
Matrix4f r;
// Масштабирование
// ���������������
r.data()[0] = 2.f / width;
r.data()[5] = 2.f / height;
r.data()[10] = -1.f / depthRange;
// Обнуление неиспользуемых компонентов
// ��������� �������������� �����������
r.data()[1] = r.data()[2] = r.data()[3] = 0;
r.data()[4] = r.data()[6] = r.data()[7] = 0;
r.data()[8] = r.data()[9] = r.data()[11] = 0;
// Трансляция (смещение)
// ���������� (��������)
r.data()[12] = -(xmax + xmin) / width;
r.data()[13] = -(ymax + ymin) / height;
r.data()[14] = zNear / depthRange;
@@ -120,20 +120,23 @@ namespace ZL {
VAOHolder::VAOHolder()
{
#ifndef EMSCRIPTEN
#ifndef ANDROID
glGenVertexArrays(1, &vao);
#endif
#endif
}
VAOHolder::~VAOHolder()
{
#ifndef EMSCRIPTEN
#ifndef ANDROID
#ifdef __linux__
glDeleteVertexArrays(1, &vao);
#else
//Windows
glDeleteVertexArray(1, &vao);
#endif
#endif
#endif
}
@@ -365,12 +368,14 @@ namespace ZL {
//Check if main thread, check if data is not empty...
#ifndef EMSCRIPTEN
#ifndef __ANDROID__
if (!vao)
{
vao = std::make_shared<VAOHolder>();
}
glBindVertexArray(vao->getBuffer());
#endif
#endif
if (!positionVBO)
{
@@ -509,7 +514,9 @@ namespace ZL {
glActiveTexture(GL_TEXTURE0);
#ifndef EMSCRIPTEN
#ifndef __ANDROID__
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
#endif
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LEQUAL);
+2 -1
View File
@@ -1,6 +1,7 @@
#pragma once
#include "OpenGlExtensions.h"
#include "render/OpenGlExtensions.h"
#include <exception>
#include <stdexcept>
#include "ShaderManager.h"
+182 -187
View File
@@ -1,227 +1,222 @@
#include "ShaderManager.h"
#include <iostream>
#include <SDL.h>
#ifdef __ANDROID__
#include <android/log.h>
#endif
namespace ZL {
ShaderResource::ShaderResource(const std::string& vertexCode, const std::string& fragmentCode)
{
ShaderResource::ShaderResource(const std::string &vertexCode, const std::string &fragmentCode) {
const int CONST_INFOLOG_LENGTH = 256;
const int CONST_INFOLOG_LENGTH = 256;
char infoLog[CONST_INFOLOG_LENGTH];
int infoLogLength;
char infoLog2[CONST_INFOLOG_LENGTH];
int infoLogLength2;
char infoLog[CONST_INFOLOG_LENGTH];
int infoLogLength;
int vertexShaderCompiled;
int fragmentShaderCompiled;
int programLinked;
int vertexShaderCompiled;
int fragmentShaderCompiled;
int programLinked;
GLuint vertexShader;
GLuint fragmentShader;
GLuint vertexShader;
GLuint fragmentShader;
int vertexCodeLength = static_cast<int>(strlen(vertexCode.c_str()));
int fragmentCodeLength = static_cast<int>(strlen(fragmentCode.c_str()));
int vertexCodeLength = static_cast<int>(strlen(vertexCode.c_str()));
int fragmentCodeLength = static_cast<int>(strlen(fragmentCode.c_str()));
const char* vc = &vertexCode[0];
const char* fc = &fragmentCode[0];
const char *vc = &vertexCode[0];
const char *fc = &fragmentCode[0];
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &(vc), &vertexCodeLength);
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &(vc), &vertexCodeLength);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &(fc), &fragmentCodeLength);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &(fc), &fragmentCodeLength);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &vertexShaderCompiled);
glGetShaderInfoLog(vertexShader, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &vertexShaderCompiled);
glGetShaderInfoLog(vertexShader, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled);
glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength2, infoLog2);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled);
glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog);
if (!vertexShaderCompiled)
{
#ifdef EMSCRIPTEN
std::cout << "Failed to compile vertex shader code!" << std::endl;
std::cout << infoLog << std::endl;
if (!vertexShaderCompiled) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "ShaderManager",
"Failed to compile vertex shader: %s", infoLog);
#endif
throw std::runtime_error("Failed to compile vertex shader code!");
}
if (!fragmentShaderCompiled)
{
#ifdef EMSCRIPTEN
std::cout << "Failed to compile fragment shader code!" << std::endl;
std::cout << infoLog2 << std::endl;
throw std::runtime_error("Failed to compile vertex shader code!");
}
if (!fragmentShaderCompiled) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "ShaderManager",
"Failed to compile fragment shader: %s", infoLog);
#endif
throw std::runtime_error("Failed to compile fragment shader code!");
}
throw std::runtime_error("Failed to compile fragment shader code!");
}
shaderProgram = glCreateProgram();
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &programLinked);
glGetProgramInfoLog(shaderProgram, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog);
if (!programLinked)
{
#ifdef EMSCRIPTEN
std::cout << "Failed to link shader program!" << std::endl;
std::cout << infoLog << std::endl;
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &programLinked);
glGetProgramInfoLog(shaderProgram, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog);
if (!programLinked) {
shaderProgram = 0;
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "ShaderManager",
"Failed to link shader program: %s", infoLog);
#endif
shaderProgram = 0;
throw std::runtime_error("Failed to link shader program!");
}
throw std::runtime_error("Failed to link shader program!");
}
//================= Parsing all uniforms ================
int dummySize; //Dummy
int dummyLen; //Dummy
GLenum dummyEnum;
int activeUniforms;
const int CONST_UNIFORM_NAME_LENGTH = 256;
char uniformName[CONST_UNIFORM_NAME_LENGTH];
glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORMS, &activeUniforms);
for (int i = 0; i < activeUniforms; i++) {
glGetActiveUniform(shaderProgram, i, CONST_UNIFORM_NAME_LENGTH, &dummyLen, &dummySize,
&dummyEnum, uniformName);
uniformList[uniformName] = glGetUniformLocation(shaderProgram, uniformName);
}
//================= Parsing all attributes ================
int activeAttribs;
const int CONST_ATTRIB_NAME_LENGTH = 256;
char attribName[CONST_ATTRIB_NAME_LENGTH];
glGetProgramiv(shaderProgram, GL_ACTIVE_ATTRIBUTES, &activeAttribs);
for (int i = 0; i < activeAttribs; i++) {
glGetActiveAttrib(shaderProgram, i, CONST_ATTRIB_NAME_LENGTH, &dummyLen, &dummySize,
&dummyEnum, attribName);
attribList[attribName] = glGetAttribLocation(shaderProgram, attribName);
}
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Shader created successfully, program ID: %u", shaderProgram);
#endif
}
ShaderResource::~ShaderResource() {
if (shaderProgram != 0) {
glDeleteProgram(shaderProgram);
shaderProgram = 0;
}
}
GLuint ShaderResource::getShaderProgram() {
return shaderProgram;
}
int dummySize; //Dummy
int dummyLen; //Dummy
GLenum dummyEnum;
void ShaderManager::AddShaderFromFiles(const std::string &shaderName,
const std::string &vertexShaderFileName,
const std::string &fragmentShaderFileName,
const std::string &ZIPFileName) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Loading shader: %s", shaderName.c_str());
__android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Vertex shader: %s", vertexShaderFileName.c_str());
__android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Fragment shader: %s", fragmentShaderFileName.c_str());
#endif
std::string vertexShader;
std::string fragmentShader;
if (!ZIPFileName.empty()) {
std::vector<char> vertexShaderData;
std::vector<char> fragmentShaderData;
vertexShaderData = readFileFromZIP(vertexShaderFileName, ZIPFileName);
fragmentShaderData = readFileFromZIP(fragmentShaderFileName, ZIPFileName);
vertexShader = std::string(vertexShaderData.begin(), vertexShaderData.end());
fragmentShader = std::string(fragmentShaderData.begin(), fragmentShaderData.end());
} else {
vertexShader = readTextFile(vertexShaderFileName);
fragmentShader = readTextFile(fragmentShaderFileName);
}
///std::cout << "Shader: "<< vertexShader << std::endl;
shaderResourceMap[shaderName] = std::make_shared<ShaderResource>(vertexShader,
fragmentShader);
}
void ShaderManager::PushShader(const std::string &shaderName) {
if (shaderStack.size() >= CONST_MAX_SHADER_STACK_SIZE) {
throw std::runtime_error("Shader stack overflow!");
}
if (shaderResourceMap.find(shaderName) == shaderResourceMap.end()) {
throw std::runtime_error("Shader does not exist!");
}
shaderStack.push(shaderName);
glUseProgram(shaderResourceMap[shaderName]->getShaderProgram());
}
//================= Parsing all uniforms ================
void ShaderManager::PopShader() {
if (shaderStack.size() == 0) {
throw std::runtime_error("Shader stack underflow!");
}
int activeUniforms;
shaderStack.pop();
const int CONST_UNIFORM_NAME_LENGTH = 256;
char uniformName[CONST_UNIFORM_NAME_LENGTH];
if (shaderStack.size() == 0) {
glUseProgram(0);
} else {
glUseProgram(shaderResourceMap[shaderStack.top()]->getShaderProgram());
}
}
glGetProgramiv(shaderProgram, GL_ACTIVE_UNIFORMS, &activeUniforms);
for (int i = 0; i < activeUniforms; i++)
{
glGetActiveUniform(shaderProgram, i, CONST_UNIFORM_NAME_LENGTH, &dummyLen, &dummySize, &dummyEnum, uniformName);
uniformList[uniformName] = glGetUniformLocation(shaderProgram, uniformName);
}
//================= Parsing all attributes ================
int activeAttribs;
const int CONST_ATTRIB_NAME_LENGTH = 256;
char attribName[CONST_ATTRIB_NAME_LENGTH];
glGetProgramiv(shaderProgram, GL_ACTIVE_ATTRIBUTES, &activeAttribs);
for (int i = 0; i < activeAttribs; i++)
{
glGetActiveAttrib(shaderProgram, i, CONST_ATTRIB_NAME_LENGTH, &dummyLen, &dummySize, &dummyEnum, attribName);
attribList[attribName] = glGetAttribLocation(shaderProgram, attribName);
}
}
ShaderResource::~ShaderResource()
{
if (shaderProgram != 0)
{
glDeleteProgram(shaderProgram);
shaderProgram = 0;
}
}
GLuint ShaderResource::getShaderProgram()
{
return shaderProgram;
}
std::shared_ptr <ShaderResource> ShaderManager::GetCurrentShader() {
if (shaderStack.size() == 0) {
throw std::runtime_error("Shader stack underflow!");
}
void ShaderManager::AddShaderFromFiles(const std::string& shaderName, const std::string& vertexShaderFileName, const std::string& fragmentShaderFileName, const std::string& ZIPFileName)
{
return shaderResourceMap[shaderStack.top()];
std::string vertexShader;
std::string fragmentShader;
if (!ZIPFileName.empty()){
std::vector<char> vertexShaderData;
std::vector<char> fragmentShaderData;
vertexShaderData = readFileFromZIP(vertexShaderFileName, ZIPFileName);
fragmentShaderData = readFileFromZIP(fragmentShaderFileName, ZIPFileName);
vertexShader = std::string(vertexShaderData.begin(), vertexShaderData.end());
fragmentShader = std::string(fragmentShaderData.begin(), fragmentShaderData.end());
}else{
vertexShader = readTextFile(vertexShaderFileName);
fragmentShader = readTextFile(fragmentShaderFileName);
}
///std::cout << "Shader: "<< vertexShader << std::endl;
shaderResourceMap[shaderName] = std::make_shared<ShaderResource>(vertexShader, fragmentShader);
}
void ShaderManager::PushShader(const std::string& shaderName)
{
if (shaderStack.size() >= CONST_MAX_SHADER_STACK_SIZE)
{
throw std::runtime_error("Shader stack overflow!");
}
if (shaderResourceMap.find(shaderName) == shaderResourceMap.end())
{
throw std::runtime_error("Shader does not exist!");
}
shaderStack.push(shaderName);
glUseProgram(shaderResourceMap[shaderName]->getShaderProgram());
}
}
void ShaderManager::PopShader()
{
if (shaderStack.size() == 0)
{
throw std::runtime_error("Shader stack underflow!");
}
ShaderSetter::ShaderSetter(ShaderManager &inShaderManager, const std::string &shaderName)
: shaderManager(inShaderManager) {
shaderManager.PushShader(shaderName);
}
shaderStack.pop();
if (shaderStack.size() == 0)
{
glUseProgram(0);
}
else
{
glUseProgram(shaderResourceMap[shaderStack.top()]->getShaderProgram());
}
}
std::shared_ptr<ShaderResource> ShaderManager::GetCurrentShader()
{
if (shaderStack.size() == 0)
{
throw std::runtime_error("Shader stack underflow!");
}
return shaderResourceMap[shaderStack.top()];
}
ShaderSetter::ShaderSetter(ShaderManager& inShaderManager, const std::string& shaderName)
: shaderManager(inShaderManager)
{
shaderManager.PushShader(shaderName);
}
ShaderSetter::~ShaderSetter()
{
shaderManager.PopShader();
}
ShaderSetter::~ShaderSetter() {
shaderManager.PopShader();
}
}
+2 -1
View File
@@ -1,5 +1,6 @@
#pragma once
#include "OpenGlExtensions.h"
#include "render/OpenGlExtensions.h"
#include "utils/Utils.h"
namespace ZL {
+53 -51
View File
@@ -20,20 +20,20 @@ namespace ZL
glBindTexture(GL_TEXTURE_2D, texID);
CheckGlError();
// Настройка фильтрации в зависимости от выбранного типа
// ��������� ���������� � ����������� �� ���������� ����
if (texData.mipmap == TextureDataStruct::GENERATE) {
// Используем трилинейную фильтрацию для устранения мерцания
// ���������� ����������� ���������� ��� ���������� ��������
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else {
// Обычная линейная фильтрация (будет мерцать на удалении)
// ������� �������� ���������� (����� ������� �� ��������)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
CheckGlError();
// Загрузка данных базового уровня (Level 0)
// �������� ������ �������� ������ (Level 0)
GLint format = (texData.bitSize == TextureDataStruct::BS_24BIT) ? GL_RGB : GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, 0, format,
@@ -43,7 +43,7 @@ namespace ZL
CheckGlError();
// Генерация мип-мапов, если это необходимо
// ��������� ���-�����, ���� ��� ����������
if (texData.mipmap == TextureDataStruct::GENERATE) {
glGenerateMipmap(GL_TEXTURE_2D);
CheckGlError();
@@ -52,7 +52,7 @@ namespace ZL
Texture::Texture(const std::array<TextureDataStruct, 6>& texDataArray)
{
// Проверка, что все грани имеют одинаковые размеры
// ��������, ��� ��� ����� ����� ���������� �������
width = texDataArray[0].width;
height = texDataArray[0].height;
@@ -73,33 +73,35 @@ namespace ZL
CheckGlError();
// Настройка параметров для Cubemap
// ��������� ���������� ��� Cubemap
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Используем GL_LINEAR для MIN_FILTER, так как мипмапы здесь не генерируются
// Если бы использовались мипмапы (e.g., GL_LINEAR_MIPMAP_LINEAR), нужно было бы вызвать glGenerateMipmap.
// ���������� GL_LINEAR ��� MIN_FILTER, ��� ��� ������� ����� �� ������������
// ���� �� �������������� ������� (e.g., GL_LINEAR_MIPMAP_LINEAR), ����� ���� �� ������� glGenerateMipmap.
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// Обязательные параметры обертки для Cubemap
// ������������ ��������� ������� ��� Cubemap
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// GL_TEXTURE_WRAP_R не поддерживается в WebGL 1.0/OpenGL ES 2.0 и вызывает ошибку.
// Ограничиваем его вызов только для настольных платформ.
// GL_TEXTURE_WRAP_R �� �������������� � WebGL 1.0/OpenGL ES 2.0 � �������� ������.
// ������������ ��� ����� ������ ��� ���������� ��������.
#ifndef EMSCRIPTEN
#ifndef __ANDROID__
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
#endif
#endif
CheckGlError(); // Проверка после установки параметров
CheckGlError(); // �������� ����� ��������� ����������
// Загрузка данных для каждой из 6 граней
// GL_TEXTURE_CUBE_MAP_POSITIVE_X + i дает грани: +X (0), -X (1), +Y (2), -Y (3), +Z (4), -Z (5)
// �������� ������ ��� ������ �� 6 ������
// GL_TEXTURE_CUBE_MAP_POSITIVE_X + i ���� �����: +X (0), -X (1), +Y (2), -Y (3), +Z (4), -Z (5)
for (int i = 0; i < 6; ++i)
{
GLint internalFormat;
GLenum format;
// В WebGL 1.0/OpenGL ES 2.0 внутренний формат (internalFormat)
// должен строго соответствовать формату данных (format).
// � WebGL 1.0/OpenGL ES 2.0 ���������� ������ (internalFormat)
// ������ ������ ��������������� ������� ������ (format).
if (texDataArray[i].bitSize == TextureDataStruct::BS_24BIT)
{
internalFormat = GL_RGB; // internalFormat
@@ -112,20 +114,20 @@ namespace ZL
}
glTexImage2D(
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, // Целевая грань
0, // Уровень MIP-текстуры
internalFormat, // Внутренний формат (должен совпадать с форматом)
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, // ������� �����
0, // ������� MIP-��������
internalFormat, // ���������� ������ (������ ��������� � ��������)
static_cast<GLsizei>(width),
static_cast<GLsizei>(height),
0, // Граница (всегда 0)
format, // Формат исходных данных
GL_UNSIGNED_BYTE, // Тип данных
texDataArray[i].data.data() // Указатель на данные
0, // ������� (������ 0)
format, // ������ �������� ������
GL_UNSIGNED_BYTE, // ��� ������
texDataArray[i].data.data() // ��������� �� ������
);
CheckGlError();
}
// Снимаем привязку для чистоты
// ������� �������� ��� �������
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}
@@ -253,48 +255,48 @@ namespace ZL
#ifdef PNG_ENABLED
// Структура для хранения данных о файле/массиве и текущей позиции чтения
// ��������� ��� �������� ������ � �����/������� � ������� ������� ������
struct png_data_t {
const char* data;
size_t size;
size_t offset;
};
// Пользовательская функция чтения для libpng
// 'png_ptr' - указатель на структуру png
// 'out_ptr' - куда записывать прочитанные данные
// 'bytes_to_read' - сколько байт нужно прочитать
// ���������������� ������� ������ ��� libpng
// 'png_ptr' - ��������� �� ��������� png
// 'out_ptr' - ���� ���������� ����������� ������
// 'bytes_to_read' - ������� ���� ����� ���������
void user_read_data(png_structp png_ptr, png_bytep out_ptr, png_size_t bytes_to_read) {
// Получаем указатель на нашу структуру png_data_t, которую мы установили с помощью png_set_read_fn
// �������� ��������� �� ���� ��������� png_data_t, ������� �� ���������� � ������� png_set_read_fn
png_data_t* data = (png_data_t*)png_get_io_ptr(png_ptr);
if (data->offset + bytes_to_read > data->size) {
// Попытка прочитать больше, чем есть в массиве.
// Вместо вызова стандартной ошибки, мы можем просто прочитать остаток или вызвать ошибку.
// В этом случае мы вызовем ошибку libpng.
// ������� ��������� ������, ��� ���� � �������.
// ������ ������ ����������� ������, �� ����� ������ ��������� ������� ��� ������� ������.
// � ���� ������ �� ������� ������ libpng.
png_error(png_ptr, "PNG Read Error: Attempted to read past end of data buffer.");
bytes_to_read = data->size - data->offset; // Устанавливаем, чтобы прочитать оставшееся
bytes_to_read = data->size - data->offset; // �������������, ����� ��������� ����������
}
// Копируем данные из нашего массива в буфер libpng
// �������� ������ �� ������ ������� � ����� libpng
std::memcpy(out_ptr, data->data + data->offset, bytes_to_read);
// Обновляем смещение
// ��������� ��������
data->offset += bytes_to_read;
}
// Пользовательская функция предупреждений (по желанию, можно использовать nullptr)
// ���������������� ������� �������������� (�� �������, ����� ������������ nullptr)
void user_warning_fn(png_structp png_ptr, png_const_charp warning_msg) {
// Здесь можно реализовать логирование предупреждений
// ����� ����� ����������� ����������� ��������������
//throw std::runtime_error();
std::cout << "PNG Warning: " << warning_msg << std::endl;
}
// Пользовательская функция ошибок (обязательна для setjmp)
// ���������������� ������� ������ (����������� ��� setjmp)
void user_error_fn(png_structp png_ptr, png_const_charp error_msg) {
// Здесь можно реализовать логирование ошибок
// ����� ����� ����������� ����������� ������
std::cout << "PNG Error: " << error_msg << std::endl;
// Обязательно вызываем longjmp для выхода из процесса чтения/записи PNG
// ����������� �������� longjmp ��� ������ �� �������� ������/������ PNG
longjmp(png_jmpbuf(png_ptr), 1);
}
@@ -302,7 +304,7 @@ namespace ZL
{
TextureDataStruct texData;
// Структура для управления чтением из массива
// ��������� ��� ���������� ������� �� �������
png_data_t png_data = { fileArr.data(), fileArr.size(), 0 };
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
@@ -316,18 +318,18 @@ namespace ZL
throw std::runtime_error("Could not create PNG info structure");
}
// === Установка пользовательских функций чтения и обработки ошибок ===
// 1. Установка обработчика ошибок и longjmp
// === ��������� ���������������� ������� ������ � ��������� ������ ===
// 1. ��������� ����������� ������ � longjmp
if (setjmp(png_jmpbuf(png))) {
png_destroy_read_struct(&png, &info, nullptr);
throw std::runtime_error("Error during PNG read (longjmp was executed)");
}
// 2. Установка пользовательских функций для обработки ошибок и предупреждений
// Вместо nullptr в error_ptr и warning_ptr можно передать указатель на свою структуру данных, если необходимо
// 2. ��������� ���������������� ������� ��� ��������� ������ � ��������������
// ������ nullptr � error_ptr � warning_ptr ����� �������� ��������� �� ���� ��������� ������, ���� ����������
png_set_error_fn(png, nullptr, user_error_fn, user_warning_fn);
// 3. Установка пользовательской функции чтения и передача ей нашей структуры png_data
// 3. ��������� ���������������� ������� ������ � �������� �� ����� ��������� png_data
png_set_read_fn(png, &png_data, user_read_data);
// ===================================================================
@@ -338,7 +340,7 @@ namespace ZL
png_byte color_type = png_get_color_type(png, info);
png_byte bit_depth = png_get_bit_depth(png, info);
// === Блок преобразований (оставлен без изменений) ===
// === ���� �������������� (�������� ��� ���������) ===
if (bit_depth == 16)
png_set_strip_16(png);
@@ -363,7 +365,7 @@ namespace ZL
png_read_update_info(png, info);
// ====================================================
// === Чтение пикселей (оставлен без изменений) ===
// === ������ �������� (�������� ��� ���������) ===
png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * texData.height);
for (int y = 0; y < texData.height; y++) {
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info));
@@ -422,7 +424,7 @@ namespace ZL
throw std::runtime_error("Could not read file data into memory");
}
// Вызываем новую функцию, которая работает с массивом байт
// �������� ����� �������, ������� �������� � �������� ����
return CreateTextureDataFromPng(fileArr);
}
+10 -10
View File
@@ -1,9 +1,9 @@
#pragma once
#include "OpenGlExtensions.h"
#include "render/OpenGlExtensions.h"
#include "utils/Utils.h"
#ifdef EMSCRIPTEN
#if defined EMSCRIPTEN || defined __ANDROID__
#define PNG_ENABLED
#endif
@@ -20,18 +20,18 @@ namespace ZL
BS_32BIT
};
// Íîâîå ïåðå÷èñëåíèå äëÿ óïðàâëåíèÿ ìèï-ìàïïèíãîì
// ����� ������������ ��� ���������� ���-���������
enum MipmapType {
NONE, // Áåç ìèï-ìàïîâ (GL_LINEAR)
GENERATE // Àâòîìàòè÷åñêàÿ ãåíåðàöèÿ (GL_LINEAR_MIPMAP_LINEAR)
NONE, // ��� ���-����� (GL_LINEAR)
GENERATE // �������������� ��������� (GL_LINEAR_MIPMAP_LINEAR)
};
BitSize bitSize;
#ifdef SIMPLIFIED
MipmapType mipmap = NONE; // Ïî óìîë÷àíèþ âêëþ÷åíî
#else
MipmapType mipmap = GENERATE; // Ïî óìîë÷àíèþ âêëþ÷åíî
#endif
/*#ifdef SIMPLIFIED
MipmapType mipmap = NONE; // �� ��������� ��������
#else*/
MipmapType mipmap = GENERATE; // �� ��������� ��������
//#endif
};
class Texture
{
View File
Whitespace-only changes.
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <boost/asio.hpp>
#include <functional>
#include <vector>
#include <thread>
#include <memory>
namespace ZL {
class TaskManager {
private:
boost::asio::io_context ioContext;
std::unique_ptr<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> workGuard;
std::vector<std::thread> workers;
public:
//TaskManager(size_t threadCount = std::thread::hardware_concurrency()) {
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) {
boost::asio::post(ioContext, task);
}
// Graceful shutdown
~TaskManager() {
workGuard.reset(); // Ðàçðåøàåì ioContext.run() çàâåðøèòüñÿ, êîãäà çàäà÷ íå îñòàíåòñÿ
ioContext.stop(); // Îïöèîíàëüíî: íåìåäëåííàÿ îñòàíîâêà
for (auto& t : workers) {
if (t.joinable()) t.join();
}
}
};
} // namespace ZL
+72 -21
View File
@@ -10,40 +10,91 @@
#include <filesystem>
#include <string>
#include <cctype>
#include <SDL.h>
#ifdef __ANDROID__
#include <android/log.h>
#endif
namespace ZL
{
std::string readTextFile(const std::string &filename) {
#ifdef __ANDROID__
SDL_RWops* file = SDL_RWFromFile(filename.c_str(), "rb");
if (!file) {
#ifdef DEBUG
__android_log_print(ANDROID_LOG_ERROR, "Utils",
"Failed to open: %s", filename.c_str());
#endif
return "";
}
std::string readTextFile(const std::string& filename)
{
std::ifstream f(filename);
Sint64 size = SDL_RWsize(file);
if (size <= 0) {
SDL_RWclose(file);
return "";
}
std::string str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
std::string content(size, '\0');
if (SDL_RWread(file, &content[0], size, 1) != 1) {
SDL_RWclose(file);
return "";
}
return str;
}
SDL_RWclose(file);
return content;
#else
std::ifstream f(filename);
if (!f.is_open()) {
return "";
}
return std::string((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>());
#endif
}
std::vector<char> readFile(const std::string& filename)
{
std::ifstream file(filename, std::ios::binary);
std::vector<char> readFile(const std::string &filename) {
#ifdef __ANDROID__
SDL_RWops* file = SDL_RWFromFile(filename.c_str(), "rb");
if (!file) {
return {};
}
file.unsetf(std::ios::skipws);
Sint64 size = SDL_RWsize(file);
if (size <= 0) {
SDL_RWclose(file);
return {};
}
std::streampos fileSize;
std::vector<char> data(size);
if (SDL_RWread(file, data.data(), size, 1) != 1) {
SDL_RWclose(file);
return {};
}
file.seekg(0, std::ios::end);
fileSize = file.tellg();
file.seekg(0, std::ios::beg);
SDL_RWclose(file);
return data;
#else
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (!file) {
return {};
}
std::vector<char> vec;
vec.reserve(static_cast<size_t>(fileSize));
std::streamsize size = file.tellg();
if (size <= 0) {
return {};
}
vec.insert(vec.begin(),
std::istream_iterator<char>(file),
std::istream_iterator<char>());
file.seekg(0, std::ios::beg);
std::vector<char> buffer(size);
return vec;
}
if (!file.read(buffer.data(), size)) {
return {};
}
return buffer;
#endif
}
std::vector<char> readFileFromZIP(const std::string& filename, const std::string& zipfilename) {
#ifdef EMSCRIPTEN
+2
View File
@@ -7,6 +7,8 @@
#include <stack>
#include <memory>
#include <unordered_map>
#include <array>
namespace ZL
{
std::string readTextFile(const std::string& filename);