diff --git a/app/jni/src/Game.cpp b/app/jni/src/Game.cpp index 74f492b..baeab75 100644 --- a/app/jni/src/Game.cpp +++ b/app/jni/src/Game.cpp @@ -2,166 +2,247 @@ #include "AnimatedModel.h" #include "BoneAnimatedModel.h" #include "Utils.h" -//#include "OpenGlExtensions.h" #include #include "TextureManager.h" #include "TextModel.h" #include #include -namespace ZL -{ - const char* CONST_ZIP_FILE = ""; - -Game::Game() - : window(nullptr) - , glContext(nullptr) - , newTickCount(0) - , lastTickCount(0) -{ -} - -Game::~Game() { - if (glContext) { - SDL_GL_DeleteContext(glContext); - } - if (window) { - SDL_DestroyWindow(window); - } - SDL_Quit(); -} - -void Game::setup() { - glContext = SDL_GL_CreateContext(ZL::Environment::window); - - // ZL::BindOpenGlFunctions(); - // ZL::CheckGlError(); - - // 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); -#else - renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE); +#ifdef __ANDROID__ +#include #endif - //Load texture - spaceshipTexture = std::make_unique(CreateTextureDataFromPng("./resources/sship001x.png")); - spaceshipBase = LoadFromTextFile02("./resources/spaceship004.txt"); - spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0))); - spaceship.AssignFrom(spaceshipBase); - spaceship.RefreshVBO(); - */ +namespace ZL { + const char *CONST_ZIP_FILE = ""; - renderer.InitOpenGL(); - -} - -void Game::drawScene() { - static const std::string defaultShaderName = "default"; - static const std::string vPositionName = "vPosition"; - static const std::string vTexCoordName = "vTexCoord"; - static const std::string textureUniformName = "Texture"; - - glClearColor(0.0f, 0.5f, 1.0f, 1.0f); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - glViewport(0, 0, Environment::width, Environment::height); - - /*CheckGlError(); - - renderer.shaderManager.PushShader(defaultShaderName); - renderer.RenderUniform1i(textureUniformName, 0); - renderer.EnableVertexAttribArray(vPositionName); - renderer.EnableVertexAttribArray(vTexCoordName); - - renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, - static_cast(Environment::width) / static_cast(Environment::height), - 1, 1000); - renderer.PushMatrix(); - - renderer.LoadIdentity(); - renderer.TranslateMatrix({ 0,0, -1.0f*Environment::zoom }); - renderer.RotateMatrix(QuatFromRotateAroundX(M_PI/6.0)); - //renderer.RotateMatrix(QuatFromRotateAroundX(Environment::cameraAlpha)); - - glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID()); - renderer.DrawVertexRenderStruct(spaceship); - - renderer.PopMatrix(); - renderer.PopProjectionMatrix(); - renderer.DisableVertexAttribArray(vPositionName); - renderer.DisableVertexAttribArray(vTexCoordName); - - renderer.shaderManager.PopShader();*/ - - //CheckGlError(); -} - -void Game::processTickCount() { - - if (lastTickCount == 0) { - lastTickCount = SDL_GetTicks64(); - return; + Game::Game() + : window(nullptr), glContext(nullptr), newTickCount(0), lastTickCount(0), + resourcesLoaded(false), modelLoaded(false) { } - newTickCount = SDL_GetTicks64(); - if (newTickCount - lastTickCount > CONST_TIMER_INTERVAL) { - size_t delta = (newTickCount - lastTickCount > CONST_MAX_TIME_INTERVAL) ? - CONST_MAX_TIME_INTERVAL : newTickCount - lastTickCount; - - //gameObjects.updateScene(delta); - - Environment::cameraAlpha = Environment::cameraAlpha + delta * M_PI / 10000.f; - - lastTickCount = newTickCount; - } -} - -void Game::render() { - SDL_GL_MakeCurrent(ZL::Environment::window, glContext); - //ZL::CheckGlError(); - - glClearColor(0.0f, 1.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - drawScene(); - processTickCount(); - - SDL_GL_SwapWindow(ZL::Environment::window); -} - -void Game::update() { - SDL_Event event; - while (SDL_PollEvent(&event)) { - if (event.type == SDL_QUIT) { - Environment::exitGameLoop = true; - + Game::~Game() { + if (glContext) { + SDL_GL_DeleteContext(glContext); } - else if (event.type == SDL_MOUSEWHEEL) { - static const float zoomstep = 2.0f; - if (event.wheel.y > 0) { - Environment::zoom -= zoomstep; - } - else if (event.wheel.y < 0) { - Environment::zoom += zoomstep; - } - if (Environment::zoom < zoomstep) { - Environment::zoom = zoomstep; - } - /*if (Environment::zoom > 4) { - Environment::zoom = 4; - }*/ + if (window) { + SDL_DestroyWindow(window); + } + SDL_Quit(); + } - //this->modelMeshRender.data.Scale(0.5); - //this->modelMeshRender.RefreshVBO(); + void Game::setup() { + glContext = SDL_GL_CreateContext(ZL::Environment::window); + + // Initialize renderer + renderer.InitOpenGL(); + +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_INFO, "Game", "Start for Android"); + + const char* testFiles[] = { + "resources/spaceship004.txt", + "shaders/default.vertex", + "shaders/default_android.fragment", + "shaders/defaultColor.vertex", + "shaders/defaultColor_android.fragment", + "resources/sship001x.bmp", + 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()); + } } + try { + __android_log_print(ANDROID_LOG_INFO, "Game", "Shaders..."); + + renderer.shaderManager.AddShaderFromFiles("default", + "shaders/default.vertex", + "shaders/default_android.fragment", + CONST_ZIP_FILE); + + renderer.shaderManager.AddShaderFromFiles("defaultColor", + "shaders/defaultColor.vertex", + "shaders/defaultColor_android.fragment", + CONST_ZIP_FILE); + + __android_log_print(ANDROID_LOG_INFO, "Game", "Textures..."); + try { + spaceshipTexture = std::make_shared( + CreateTextureDataFromBmp32("resources/sship001x.bmp") + ); + } catch (const std::exception& e) { + spaceshipTexture = nullptr; + } + + __android_log_print(ANDROID_LOG_INFO, "Game", "Model..."); + + std::string modelPaths[] = { + "resources/spaceship004.txt", + "" + }; + + bool modelLoadSuccess = false; + for (int i = 0; !modelLoadSuccess && !modelPaths[i].empty(); i++) { + try { + spaceshipBase = LoadFromTextFile02(modelPaths[i]); + spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0))); + spaceship.AssignFrom(spaceshipBase); + spaceship.RefreshVBO(); + modelLoaded = true; + modelLoadSuccess = true; + __android_log_print(ANDROID_LOG_INFO, "Game", "Model loaded successfully from: %s", modelPaths[i].c_str()); + } catch (const std::exception& e) { + __android_log_print(ANDROID_LOG_WARN, "Game", "Failed to load model from %s: %s", + modelPaths[i].c_str(), e.what()); + } + } + + resourcesLoaded = (spaceshipTexture != nullptr && modelLoaded); + + } catch (const std::exception& e) { + __android_log_print(ANDROID_LOG_ERROR, "Game", "Setup failed: %s", e.what()); + resourcesLoaded = false; + } +#else + // Десктопная версия + renderer.shaderManager.AddShaderFromFiles("default", + "./shaders/default.vertex", + "./shaders/default_desktop.fragment", + CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("defaultColor", + "./shaders/defaultColor.vertex", + "./shaders/defaultColor_desktop.fragment", + CONST_ZIP_FILE); + + //Load texture + spaceshipTexture = std::make_shared( + CreateTextureDataFromPng("./resources/sship001x.png")); + spaceshipBase = LoadFromTextFile02("./resources/spaceship004.txt"); + spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0))); + spaceship.AssignFrom(spaceshipBase); + spaceship.RefreshVBO(); + resourcesLoaded = true; + modelLoaded = true; +#endif + } + + void Game::drawScene() { + static const std::string defaultShaderName = "default"; + static const std::string vPositionName = "vPosition"; + static const std::string vTexCoordName = "vTexCoord"; + static const std::string textureUniformName = "Texture"; + + glClearColor(0.0f, 0.5f, 1.0f, 1.0f); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + glViewport(0, 0, Environment::width, Environment::height); + + if (!resourcesLoaded) { + glClearColor(0.2f, 0.3f, 0.8f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + return; + } + + renderer.shaderManager.PushShader(defaultShaderName); + renderer.RenderUniform1i(textureUniformName, 0); + renderer.EnableVertexAttribArray(vPositionName); + renderer.EnableVertexAttribArray(vTexCoordName); + + renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, + static_cast(Environment::width) / + static_cast(Environment::height), + 1, 1000); + renderer.PushMatrix(); + + renderer.LoadIdentity(); + renderer.TranslateMatrix({0, 0, -1.0f * Environment::zoom}); + renderer.RotateMatrix(QuatFromRotateAroundX(M_PI / 6.0)); + //renderer.RotateMatrix(QuatFromRotateAroundX(Environment::cameraAlpha)); + + if (spaceshipTexture) { + glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID()); + renderer.DrawVertexRenderStruct(spaceship); + } else { + renderer.DrawVertexRenderStruct(spaceship); + } + + renderer.PopMatrix(); + renderer.PopProjectionMatrix(); + renderer.DisableVertexAttribArray(vPositionName); + renderer.DisableVertexAttribArray(vTexCoordName); + + renderer.shaderManager.PopShader(); + } + + void Game::processTickCount() { + + if (lastTickCount == 0) { + lastTickCount = SDL_GetTicks64(); + return; + } + + newTickCount = SDL_GetTicks64(); + if (newTickCount - lastTickCount > CONST_TIMER_INTERVAL) { + size_t delta = (newTickCount - lastTickCount > CONST_MAX_TIME_INTERVAL) ? + CONST_MAX_TIME_INTERVAL : newTickCount - lastTickCount; + + //gameObjects.updateScene(delta); + + Environment::cameraAlpha = Environment::cameraAlpha + delta * M_PI / 10000.f; + + lastTickCount = newTickCount; + } + } + + void Game::render() { + SDL_GL_MakeCurrent(ZL::Environment::window, glContext); + + glClearColor(0.0f, 1.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + drawScene(); + processTickCount(); + + 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_MOUSEWHEEL) { + static const float zoomstep = 2.0f; + if (event.wheel.y > 0) { + Environment::zoom -= zoomstep; + } else if (event.wheel.y < 0) { + Environment::zoom += zoomstep; + } + if (Environment::zoom < zoomstep) { + Environment::zoom = zoomstep; + } + /*if (Environment::zoom > 4) { + Environment::zoom = 4; + }*/ + + //this->modelMeshRender.data.Scale(0.5); + //this->modelMeshRender.RefreshVBO(); + } + + + } + render(); } - render(); -} } // namespace ZL \ No newline at end of file diff --git a/app/jni/src/Game.h b/app/jni/src/Game.h index 3d163f9..0b70142 100644 --- a/app/jni/src/Game.h +++ b/app/jni/src/Game.h @@ -1,6 +1,5 @@ #pragma once -//#include "OpenGlExtensions.h" #include "Renderer.h" #include "Environment.h" #include "TextureManager.h" @@ -9,34 +8,41 @@ namespace ZL { -class Game { -public: - Game(); - ~Game(); + class Game { + public: + Game(); - void setup(); - void update(); - void render(); + ~Game(); - bool shouldExit() const { return Environment::exitGameLoop; } + void setup(); -private: - void processTickCount(); - void drawScene(); + void update(); - SDL_Window* window; - SDL_GLContext glContext; - Renderer renderer; + void render(); - size_t newTickCount; - size_t lastTickCount; + bool shouldExit() const { return Environment::exitGameLoop; } - static const size_t CONST_TIMER_INTERVAL = 10; - static const size_t CONST_MAX_TIME_INTERVAL = 1000; + private: + void processTickCount(); - std::shared_ptr spaceshipTexture; - VertexDataStruct spaceshipBase; - VertexRenderStruct spaceship; -}; + void drawScene(); + + SDL_Window *window; + SDL_GLContext glContext; + Renderer renderer; + + size_t newTickCount; + size_t lastTickCount; + + bool resourcesLoaded; + bool modelLoaded; + + static const size_t CONST_TIMER_INTERVAL = 10; + static const size_t CONST_MAX_TIME_INTERVAL = 1000; + + std::shared_ptr spaceshipTexture; + VertexDataStruct spaceshipBase; + VertexRenderStruct spaceship; + }; } // namespace ZL \ No newline at end of file diff --git a/app/jni/src/ShaderManager.cpp b/app/jni/src/ShaderManager.cpp index 4330509..6aa8db4 100644 --- a/app/jni/src/ShaderManager.cpp +++ b/app/jni/src/ShaderManager.cpp @@ -1,212 +1,222 @@ #include "ShaderManager.h" #include +#include +#ifdef __ANDROID__ +#include +#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 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(strlen(vertexCode.c_str())); - int fragmentCodeLength = static_cast(strlen(fragmentCode.c_str())); + int vertexCodeLength = static_cast(strlen(vertexCode.c_str())); + int fragmentCodeLength = static_cast(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, &infoLogLength, infoLog); + glCompileShader(fragmentShader); + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled); + glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog); - if (!vertexShaderCompiled) - { - throw std::runtime_error("Failed to compile vertex shader code!"); - } - - if (!fragmentShaderCompiled) - { - throw std::runtime_error("Failed to compile fragment shader code!"); - } + 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!"); + } - shaderProgram = glCreateProgram(); + 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!"); + } - glAttachShader(shaderProgram, vertexShader); - glAttachShader(shaderProgram, fragmentShader); + shaderProgram = glCreateProgram(); - glLinkProgram(shaderProgram); + glAttachShader(shaderProgram, vertexShader); + glAttachShader(shaderProgram, fragmentShader); - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); + glLinkProgram(shaderProgram); - glGetProgramiv(shaderProgram, GL_LINK_STATUS, &programLinked); - glGetProgramInfoLog(shaderProgram, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog); - - if (!programLinked) - { - shaderProgram = 0; - throw std::runtime_error("Failed to link shader program!"); - } + glDeleteShader(vertexShader); + glDeleteShader(fragmentShader); + + 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 + 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 vertexShaderData; + std::vector 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(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 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 vertexShaderData; - std::vector 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(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 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(shaderManager) - { - shaderManager.PushShader(shaderName); - } - - ShaderSetter::~ShaderSetter() - { - shaderManager.PopShader(); - } + ShaderSetter::~ShaderSetter() { + shaderManager.PopShader(); + } } \ No newline at end of file diff --git a/app/jni/src/TextModel.cpp b/app/jni/src/TextModel.cpp index e185f82..e8d619e 100644 --- a/app/jni/src/TextModel.cpp +++ b/app/jni/src/TextModel.cpp @@ -5,386 +5,393 @@ #include #include -namespace ZL -{ - - - VertexDataStruct LoadFromTextFile(const std::string& fileName, const std::string& ZIPFileName) - { - VertexDataStruct result; - std::ifstream filestream; - std::istringstream zipStream; - - if (!ZIPFileName.empty()) - { - std::vector fileData = readFileFromZIP(fileName, ZIPFileName); - std::string fileContents(fileData.begin(), fileData.end()); - zipStream.str(fileContents); - } - else - { - filestream.open(fileName); - } - - // Создаем ссылку f на нужный поток – после этого код ниже остается без изменений - std::istream& f = (!ZIPFileName.empty()) ? static_cast(zipStream) : static_cast(filestream); - - - //Skip first 5 lines - std::string tempLine; - - std::getline(f, tempLine); - - static const std::regex pattern_count(R"(\d+)"); - static const std::regex pattern_float(R"([-]?\d+\.\d+)"); - static const std::regex pattern_int(R"([-]?\d+)"); - - - std::smatch match; - - int numberVertices; - - if (std::regex_search(tempLine, match, pattern_count)) { - std::string number_str = match.str(); - numberVertices = std::stoi(number_str); - } - else { - throw std::runtime_error("No number found in the input string."); - } - - std::vector vertices; - - vertices.resize(numberVertices); - for (int i = 0; i < numberVertices; i++) - { - std::getline(f, tempLine); - - std::vector floatValues; - - auto b = tempLine.cbegin(); - auto e = tempLine.cend(); - while (std::regex_search(b, e, match, pattern_float)) { - floatValues.push_back(std::stof(match.str())); - b = match.suffix().first; - } +#ifdef __ANDROID__ +#include +#endif +namespace ZL { - vertices[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] }; - } - std::cout << "UV Coordinates" << std::endl; + VertexDataStruct LoadFromTextFile(const std::string &fileName, const std::string &ZIPFileName) { + VertexDataStruct result; + std::ifstream filestream; + std::istringstream zipStream; - std::getline(f, tempLine); //===UV Coordinates: + if (!ZIPFileName.empty()) { + std::vector fileData = readFileFromZIP(fileName, ZIPFileName); + std::string fileContents(fileData.begin(), fileData.end()); + zipStream.str(fileContents); + } else { + filestream.open(fileName); + } - std::getline(f, tempLine); //triangle count - int numberTriangles; + // Создаем ссылку f на нужный поток – после этого код ниже остается без изменений + std::istream &f = (!ZIPFileName.empty()) ? static_cast(zipStream) + : static_cast(filestream); - if (std::regex_search(tempLine, match, pattern_count)) { - std::string number_str = match.str(); - numberTriangles = std::stoi(number_str); - } - else { - throw std::runtime_error("No number found in the input string."); - } + //Skip first 5 lines + std::string tempLine; - // Now process UVs - std::vector> uvCoords; + std::getline(f, tempLine); - uvCoords.resize(numberTriangles); + static const std::regex pattern_count(R"(\d+)"); + static const std::regex pattern_float(R"([-]?\d+\.\d+)"); + static const std::regex pattern_int(R"([-]?\d+)"); - for (int i = 0; i < numberTriangles; i++) - { - std::getline(f, tempLine); //Face 0 - int uvCount; - std::getline(f, tempLine); - if (std::regex_search(tempLine, match, pattern_count)) { - std::string number_str = match.str(); - uvCount = std::stoi(number_str); - } - else { - throw std::runtime_error("No number found in the input string."); - } + std::smatch match; - if (uvCount != 3) - { - throw std::runtime_error("more than 3 uvs"); - } + int numberVertices; - std::vector floatValues; + if (std::regex_search(tempLine, match, pattern_count)) { + std::string number_str = match.str(); + numberVertices = std::stoi(number_str); + } else { + throw std::runtime_error("No number found in the input string."); + } - for (int j = 0; j < 3; j++) - { - std::getline(f, tempLine); //UV - - auto b = tempLine.cbegin(); - auto e = tempLine.cend(); - floatValues.clear(); - while (std::regex_search(b, e, match, pattern_float)) { - floatValues.push_back(std::stof(match.str())); - b = match.suffix().first; - } + std::vector vertices; - if (floatValues.size() != 2) - { - throw std::runtime_error("more than 2 uvs---"); - } + vertices.resize(numberVertices); + for (int i = 0; i < numberVertices; i++) { + std::getline(f, tempLine); - uvCoords[i][j] = Vector2f{ floatValues[0],floatValues[1] }; - } - } + std::vector floatValues; - std::cout << "Normals go" << std::endl; + auto b = tempLine.cbegin(); + auto e = tempLine.cend(); + while (std::regex_search(b, e, match, pattern_float)) { + floatValues.push_back(std::stof(match.str())); + b = match.suffix().first; + } - std::getline(f, tempLine); //===Normals: + vertices[i] = Vector3f{floatValues[0], floatValues[1], floatValues[2]}; + } + std::cout << "UV Coordinates" << std::endl; - std::vector normals; + std::getline(f, tempLine); //===UV Coordinates: - normals.resize(numberVertices); - for (int i = 0; i < numberVertices; i++) - { - std::getline(f, tempLine); + std::getline(f, tempLine); //triangle count + int numberTriangles; - std::vector floatValues; + if (std::regex_search(tempLine, match, pattern_count)) { + std::string number_str = match.str(); + numberTriangles = std::stoi(number_str); + } else { + throw std::runtime_error("No number found in the input string."); + } - auto b = tempLine.cbegin(); - auto e = tempLine.cend(); - while (std::regex_search(b, e, match, pattern_float)) { - floatValues.push_back(std::stof(match.str())); - b = match.suffix().first; - } - normals[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] }; - } + // Now process UVs + std::vector > uvCoords; - std::cout << "Triangles go:" << std::endl; + uvCoords.resize(numberTriangles); - std::getline(f, tempLine); //===Triangles: 3974 + for (int i = 0; i < numberTriangles; i++) { + std::getline(f, tempLine); //Face 0 + int uvCount; + std::getline(f, tempLine); + if (std::regex_search(tempLine, match, pattern_count)) { + std::string number_str = match.str(); + uvCount = std::stoi(number_str); + } else { + throw std::runtime_error("No number found in the input string."); + } - std::vector> triangles; + if (uvCount != 3) { + throw std::runtime_error("more than 3 uvs"); + } - triangles.resize(numberTriangles); - for (int i = 0; i < numberTriangles; i++) - { - std::getline(f, tempLine); + std::vector floatValues; - std::vector intValues; + for (int j = 0; j < 3; j++) { + std::getline(f, tempLine); //UV - auto b = tempLine.cbegin(); - auto e = tempLine.cend(); - while (std::regex_search(b, e, match, pattern_int)) { - intValues.push_back(std::stoi(match.str())); - b = match.suffix().first; - } - - triangles[i] = { intValues[0], intValues[1], intValues[2] }; - } - - - std::cout << "Process vertices" << std::endl; + auto b = tempLine.cbegin(); + auto e = tempLine.cend(); + floatValues.clear(); + while (std::regex_search(b, e, match, pattern_float)) { + floatValues.push_back(std::stof(match.str())); + b = match.suffix().first; + } + if (floatValues.size() != 2) { + throw std::runtime_error("more than 2 uvs---"); + } + uvCoords[i][j] = Vector2f{floatValues[0], floatValues[1]}; + } + } - // Now let's process vertices - - for (int i = 0; i < numberTriangles; i++) - { - - result.PositionData.push_back(vertices[triangles[i][0]]); - result.PositionData.push_back(vertices[triangles[i][1]]); - result.PositionData.push_back(vertices[triangles[i][2]]); - - /* - result.NormalData.push_back(normals[triangles[i][0]]); - result.NormalData.push_back(normals[triangles[i][1]]); - result.NormalData.push_back(normals[triangles[i][2]]); - */ - result.TexCoordData.push_back(uvCoords[i][0]); - result.TexCoordData.push_back(uvCoords[i][1]); - result.TexCoordData.push_back(uvCoords[i][2]); - - } - - //Swap from Blender format to OpenGL format - for (int i = 0; i < result.PositionData.size(); i++) - { - Vector3f tempVec = result.PositionData[i]; - result.PositionData[i].v[0] = tempVec.v[1]; - result.PositionData[i].v[1] = tempVec.v[2]; - result.PositionData[i].v[2] = tempVec.v[0]; - - /* - tempVec = result.NormalData[i]; - result.NormalData[i].v[0] = tempVec.v[1]; - result.NormalData[i].v[1] = tempVec.v[2]; - result.NormalData[i].v[2] = tempVec.v[0];*/ + std::cout << "Normals go" << std::endl; - } + std::getline(f, tempLine); //===Normals: - return result; - } - - VertexDataStruct LoadFromTextFile02(const std::string& fileName, const std::string& ZIPFileName) - { - VertexDataStruct result; - std::ifstream filestream; - std::istringstream zipStream; + std::vector normals; - // --- 1. Открытие потока (без изменений) --- - if (!ZIPFileName.empty()) - { - std::vector fileData = readFileFromZIP(fileName, ZIPFileName); - std::string fileContents(fileData.begin(), fileData.end()); - zipStream.str(fileContents); - } - else - { - filestream.open(fileName); - if (!filestream.is_open()) { - throw std::runtime_error("Failed to open file: " + fileName); - } - } - - std::istream& f = (!ZIPFileName.empty()) ? static_cast(zipStream) : static_cast(filestream); - - std::string tempLine; - std::smatch match; - - // Обновленные регулярки - // pattern_float стал чуть надежнее для чисел вида "0" или "-1" без точки, если вдруг Python округлит до int - static const std::regex pattern_count(R"(\d+)"); - static const std::regex pattern_float(R"([-]?\d+(\.\d+)?)"); - static const std::regex pattern_int(R"([-]?\d+)"); - - // --- 2. Парсинг Вершин (Pos + Norm + UV) --- - - // Ищем заголовок ===Vertices - while (std::getline(f, tempLine)) { - if (tempLine.find("===Vertices") != std::string::npos) break; - } - - int numberVertices = 0; - if (std::regex_search(tempLine, match, pattern_count)) { - numberVertices = std::stoi(match.str()); - } - else { - throw std::runtime_error("Vertices header not found or invalid."); - } - - // Временные буферы для хранения "уникальных" вершин перед разверткой по индексам - std::vector tempPositions(numberVertices); - std::vector tempNormals(numberVertices); - std::vector tempUVs(numberVertices); - - for (int i = 0; i < numberVertices; i++) - { - std::getline(f, tempLine); - // Строка вида: V 0: Pos(x, y, z) Norm(x, y, z) UV(u, v) - - std::vector floatValues; - floatValues.reserve(8); // Ожидаем ровно 8 чисел (3 pos + 3 norm + 2 uv) - - auto b = tempLine.cbegin(); - auto e = tempLine.cend(); - while (std::regex_search(b, e, match, pattern_float)) { - floatValues.push_back(std::stof(match.str())); - b = match.suffix().first; - } - - // Проверка целостности строки (ID вершины regex может поймать первым, но нас интересуют данные) - // Обычно ID идет первым (0), потом 3+3+2 float. Итого 9 чисел, если считать ID. - // Ваш Python пишет "V 0:", regex поймает 0. Потом 8 флоатов. - - // Если regex ловит ID вершины как float (что вероятно), нам нужно смещение. - // ID - floatValues[0] - // Pos - [1], [2], [3] - // Norm - [4], [5], [6] - // UV - [7], [8] - - if (floatValues.size() < 9) { - throw std::runtime_error("Malformed vertex line at index " + std::to_string(i)); - } - - tempPositions[i] = Vector3f{ floatValues[1], floatValues[2], floatValues[3] }; - tempNormals[i] = Vector3f{ floatValues[4], floatValues[5], floatValues[6] }; - tempUVs[i] = Vector2f{ floatValues[7], floatValues[8] }; - } - - // --- 3. Парсинг Треугольников (Индексов) --- - - // Пропускаем пустые строки до заголовка треугольников - while (std::getline(f, tempLine)) { - if (tempLine.find("===Triangles") != std::string::npos) break; - } - - int numberTriangles = 0; - if (std::regex_search(tempLine, match, pattern_count)) { - numberTriangles = std::stoi(match.str()); - } - else { - throw std::runtime_error("Triangles header not found."); - } - - // Резервируем память в result, чтобы избежать лишних аллокаций - result.PositionData.reserve(numberTriangles * 3); - result.NormalData.reserve(numberTriangles * 3); - result.TexCoordData.reserve(numberTriangles * 3); - - for (int i = 0; i < numberTriangles; i++) - { - std::getline(f, tempLine); - // Строка вида: Tri: 0 1 2 - - std::vector indices; - indices.reserve(3); - - auto b = tempLine.cbegin(); - auto e = tempLine.cend(); - while (std::regex_search(b, e, match, pattern_int)) { - indices.push_back(std::stoi(match.str())); - b = match.suffix().first; - } - - if (indices.size() != 3) { - throw std::runtime_error("Malformed triangle line at index " + std::to_string(i)); - } - - // --- 4. Заполнение VertexDataStruct (Flattening) --- - // Берем данные из временных буферов по индексам и кладем в итоговый массив - - for (int k = 0; k < 3; k++) { - int idx = indices[k]; - result.PositionData.push_back(tempPositions[idx]); - result.NormalData.push_back(tempNormals[idx]); - result.TexCoordData.push_back(tempUVs[idx]); - } - } - - // --- 5. Конвертация координат (Blender -> OpenGL/Engine) --- - // Сохраняем вашу логику смены осей: X->Z, Y->X, Z->Y - - for (size_t i = 0; i < result.PositionData.size(); i++) - { - Vector3f originalPos = result.PositionData[i]; - result.PositionData[i].v[0] = originalPos.v[1]; // New X = Old Y - result.PositionData[i].v[1] = originalPos.v[2]; // New Y = Old Z - result.PositionData[i].v[2] = originalPos.v[0]; // New Z = Old X - - Vector3f originalNorm = result.NormalData[i]; - result.NormalData[i].v[0] = originalNorm.v[1]; - result.NormalData[i].v[1] = originalNorm.v[2]; - result.NormalData[i].v[2] = originalNorm.v[0]; - } - - std::cout << "Model loaded: " << numberVertices << " verts, " << numberTriangles << " tris." << std::endl; - - return result; - } + normals.resize(numberVertices); + for (int i = 0; i < numberVertices; i++) { + std::getline(f, tempLine); + std::vector floatValues; + auto b = tempLine.cbegin(); + auto e = tempLine.cend(); + while (std::regex_search(b, e, match, pattern_float)) { + floatValues.push_back(std::stof(match.str())); + b = match.suffix().first; + } + + normals[i] = Vector3f{floatValues[0], floatValues[1], floatValues[2]}; + } + + std::cout << "Triangles go:" << std::endl; + + std::getline(f, tempLine); //===Triangles: 3974 + + + std::vector > triangles; + + triangles.resize(numberTriangles); + for (int i = 0; i < numberTriangles; i++) { + std::getline(f, tempLine); + + std::vector intValues; + + auto b = tempLine.cbegin(); + auto e = tempLine.cend(); + while (std::regex_search(b, e, match, pattern_int)) { + intValues.push_back(std::stoi(match.str())); + b = match.suffix().first; + } + + triangles[i] = {intValues[0], intValues[1], intValues[2]}; + } + + + std::cout << "Process vertices" << std::endl; + + + + // Now let's process vertices + + for (int i = 0; i < numberTriangles; i++) { + + result.PositionData.push_back(vertices[triangles[i][0]]); + result.PositionData.push_back(vertices[triangles[i][1]]); + result.PositionData.push_back(vertices[triangles[i][2]]); + + /* + result.NormalData.push_back(normals[triangles[i][0]]); + result.NormalData.push_back(normals[triangles[i][1]]); + result.NormalData.push_back(normals[triangles[i][2]]); + */ + result.TexCoordData.push_back(uvCoords[i][0]); + result.TexCoordData.push_back(uvCoords[i][1]); + result.TexCoordData.push_back(uvCoords[i][2]); + + } + + //Swap from Blender format to OpenGL format + for (int i = 0; i < result.PositionData.size(); i++) { + Vector3f tempVec = result.PositionData[i]; + result.PositionData[i].v[0] = tempVec.v[1]; + result.PositionData[i].v[1] = tempVec.v[2]; + result.PositionData[i].v[2] = tempVec.v[0]; + + /* + tempVec = result.NormalData[i]; + result.NormalData[i].v[0] = tempVec.v[1]; + result.NormalData[i].v[1] = tempVec.v[2]; + result.NormalData[i].v[2] = tempVec.v[0];*/ + + } + + return result; + + } + + VertexDataStruct + LoadFromTextFile02(const std::string &fileName, const std::string &ZIPFileName) { + VertexDataStruct result; + +#ifdef __ANDROID__ + // Для Android используем SDL_RWops для чтения файлов + __android_log_print(ANDROID_LOG_INFO, "TextModel", + "LoadFromTextFile02 called for Android: %s", fileName.c_str()); + + // Читаем файл с помощью readTextFile + std::string fileContent = readTextFile(fileName); + if (fileContent.empty()) { + __android_log_print(ANDROID_LOG_ERROR, "TextModel", + "Failed to read file: %s", fileName.c_str()); + throw std::runtime_error("Failed to read file: " + fileName); + } + + __android_log_print(ANDROID_LOG_INFO, "TextModel", + "File read successfully, size: %zu", fileContent.size()); + + std::istringstream f(fileContent); +#else + // Оригинальный код для десктопа + std::ifstream filestream; + std::istringstream zipStream; + + if (!ZIPFileName.empty()) { + std::vector fileData = readFileFromZIP(fileName, ZIPFileName); + std::string fileContents(fileData.begin(), fileData.end()); + zipStream.str(fileContents); + f = static_cast(zipStream); + } else { + filestream.open(fileName); + if (!filestream.is_open()) { + throw std::runtime_error("Failed to open file: " + fileName); + } + f = static_cast(filestream); + } +#endif + + std::string tempLine; + std::smatch match; + + // Обновленные регулярки + static const std::regex pattern_count(R"(\d+)"); + static const std::regex pattern_float(R"([-]?\d+(\.\d+)?)"); + static const std::regex pattern_int(R"([-]?\d+)"); + + // --- 2. Парсинг Вершин (Pos + Norm + UV) --- + + // Ищем заголовок ===Vertices + while (std::getline(f, tempLine)) { + if (tempLine.find("===Vertices") != std::string::npos) break; + } + + int numberVertices = 0; + if (std::regex_search(tempLine, match, pattern_count)) { + numberVertices = std::stoi(match.str()); + } else { + throw std::runtime_error("Vertices header not found or invalid."); + } + + // Временные буферы для хранения "уникальных" вершин перед разверткой по индексам + std::vector tempPositions(numberVertices); + std::vector tempNormals(numberVertices); + std::vector tempUVs(numberVertices); + + for (int i = 0; i < numberVertices; i++) { + std::getline(f, tempLine); + // Строка вида: V 0: Pos(x, y, z) Norm(x, y, z) UV(u, v) + + std::vector floatValues; + floatValues.reserve(9); // ID + 3 pos + 3 norm + 2 uv + + auto b = tempLine.cbegin(); + auto e = tempLine.cend(); + while (std::regex_search(b, e, match, pattern_float)) { + floatValues.push_back(std::stof(match.str())); + b = match.suffix().first; + } + + // Проверка, что у нас достаточно данных + if (floatValues.size() < 9) { +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_WARN, "TextModel", + "Warning: vertex line has only %zu values, expected 9", + floatValues.size()); +#endif + // Попробуем с меньшим количеством, возможно данные упрощенные + if (floatValues.size() >= 8) { + // Без ID + tempPositions[i] = Vector3f{floatValues[0], floatValues[1], floatValues[2]}; + tempNormals[i] = Vector3f{floatValues[3], floatValues[4], floatValues[5]}; + tempUVs[i] = Vector2f{floatValues[6], floatValues[7]}; + continue; + } + throw std::runtime_error("Malformed vertex line at index " + std::to_string(i)); + } + + // ID - floatValues[0] + // Pos - [1], [2], [3] + // Norm - [4], [5], [6] + // UV - [7], [8] + tempPositions[i] = Vector3f{floatValues[1], floatValues[2], floatValues[3]}; + tempNormals[i] = Vector3f{floatValues[4], floatValues[5], floatValues[6]}; + tempUVs[i] = Vector2f{floatValues[7], floatValues[8]}; + } + + // --- 3. Парсинг Треугольников (Индексов) --- + + // Пропускаем пустые строки до заголовка треугольников + while (std::getline(f, tempLine)) { + if (tempLine.find("===Triangles") != std::string::npos) break; + } + + int numberTriangles = 0; + if (std::regex_search(tempLine, match, pattern_count)) { + numberTriangles = std::stoi(match.str()); + } else { + throw std::runtime_error("Triangles header not found."); + } + + // Резервируем память в result, чтобы избежать лишних аллокаций + result.PositionData.reserve(numberTriangles * 3); + result.NormalData.reserve(numberTriangles * 3); + result.TexCoordData.reserve(numberTriangles * 3); + + for (int i = 0; i < numberTriangles; i++) { + std::getline(f, tempLine); + // Строка вида: Tri: 0 1 2 + + std::vector indices; + indices.reserve(3); + + auto b = tempLine.cbegin(); + auto e = tempLine.cend(); + while (std::regex_search(b, e, match, pattern_int)) { + indices.push_back(std::stoi(match.str())); + b = match.suffix().first; + } + + if (indices.size() != 3) { + throw std::runtime_error("Malformed triangle line at index " + std::to_string(i)); + } + + // --- 4. Заполнение VertexDataStruct (Flattening) --- + for (int k = 0; k < 3; k++) { + int idx = indices[k]; + result.PositionData.push_back(tempPositions[idx]); + result.NormalData.push_back(tempNormals[idx]); + result.TexCoordData.push_back(tempUVs[idx]); + } + } + + // --- 5. Конвертация координат (Blender -> OpenGL/Engine) --- + for (size_t i = 0; i < result.PositionData.size(); i++) { + Vector3f originalPos = result.PositionData[i]; + result.PositionData[i].v[0] = originalPos.v[1]; // New X = Old Y + result.PositionData[i].v[1] = originalPos.v[2]; // New Y = Old Z + result.PositionData[i].v[2] = originalPos.v[0]; // New Z = Old X + + Vector3f originalNorm = result.NormalData[i]; + result.NormalData[i].v[0] = originalNorm.v[1]; + result.NormalData[i].v[1] = originalNorm.v[2]; + result.NormalData[i].v[2] = originalNorm.v[0]; + } + +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_INFO, "TextModel", + "Model loaded successfully: %d verts, %d tris", + numberVertices, numberTriangles); +#else + std::cout << "Model loaded: " << numberVertices << " verts, " << numberTriangles << " tris." + << std::endl; +#endif + + return result; + } } \ No newline at end of file diff --git a/app/jni/src/TextModel.h b/app/jni/src/TextModel.h index df2a491..f9c32da 100644 --- a/app/jni/src/TextModel.h +++ b/app/jni/src/TextModel.h @@ -5,8 +5,14 @@ #include -namespace ZL -{ - VertexDataStruct LoadFromTextFile(const std::string& fileName, const std::string& ZIPFileName = ""); - VertexDataStruct LoadFromTextFile02(const std::string& fileName, const std::string& ZIPFileName = ""); +#ifdef __ANDROID__ +#include +#endif + +namespace ZL { + VertexDataStruct + LoadFromTextFile(const std::string &fileName, const std::string &ZIPFileName = ""); + + VertexDataStruct + LoadFromTextFile02(const std::string &fileName, const std::string &ZIPFileName = ""); } \ No newline at end of file diff --git a/app/jni/src/Utils.cpp b/app/jni/src/Utils.cpp index 2be53fd..97dde49 100644 --- a/app/jni/src/Utils.cpp +++ b/app/jni/src/Utils.cpp @@ -6,95 +6,139 @@ #include #include //#include +#include -namespace ZL -{ +#ifdef __ANDROID__ +#include +#endif - std::string readTextFile(const std::string& filename) - { - std::ifstream f(filename); +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 str((std::istreambuf_iterator(f)), std::istreambuf_iterator()); + Sint64 size = SDL_RWsize(file); + if (size <= 0) { + SDL_RWclose(file); + return ""; + } - return str; - } + std::string content(size, '\0'); + if (SDL_RWread(file, &content[0], size, 1) != 1) { + SDL_RWclose(file); + return ""; + } - std::vector readFile(const std::string& filename) - { - std::ifstream file(filename, std::ios::binary); + SDL_RWclose(file); + return content; +#else + std::ifstream f(filename); + if (!f.is_open()) { + return ""; + } + return std::string((std::istreambuf_iterator(f)), + std::istreambuf_iterator()); +#endif + } - file.unsetf(std::ios::skipws); + std::vector readFile(const std::string &filename) { +#ifdef __ANDROID__ + SDL_RWops* file = SDL_RWFromFile(filename.c_str(), "rb"); + if (!file) { + return {}; + } - std::streampos fileSize; + Sint64 size = SDL_RWsize(file); + if (size <= 0) { + SDL_RWclose(file); + return {}; + } - file.seekg(0, std::ios::end); - fileSize = file.tellg(); - file.seekg(0, std::ios::beg); + std::vector data(size); + if (SDL_RWread(file, data.data(), size, 1) != 1) { + SDL_RWclose(file); + return {}; + } - std::vector vec; - vec.reserve(fileSize); + SDL_RWclose(file); + return data; +#else + std::ifstream file(filename, std::ios::binary | std::ios::ate); + if (!file) { + return {}; + } - vec.insert(vec.begin(), - std::istream_iterator(file), - std::istream_iterator()); + std::streamsize size = file.tellg(); + if (size <= 0) { + return {}; + } - return vec; - } - - std::vector readFileFromZIP(const std::string& filename, const std::string& zipfilename) { - /*const std::string zipPath = zipfilename; - int zipErr; - zip_t* archive = zip_open(zipPath.c_str(), ZIP_RDONLY, &zipErr); - if (!archive) { - throw std::runtime_error("Ошибка открытия ZIP: " + zipPath); - } - - std::string cleanFilename = filename; - if (cleanFilename.rfind("./", 0) == 0) { - cleanFilename = cleanFilename.substr(2); - } - - std::cout << "Ищем в ZIP: " << cleanFilename << std::endl; - - zip_file_t* zipFile = zip_fopen(archive, cleanFilename.c_str(), 0); - if (!zipFile) { - zip_close(archive); - throw std::runtime_error("Файл не найден в ZIP: " + cleanFilename); - } - - zip_stat_t fileStat; - if (zip_stat(archive, cleanFilename.c_str(), 0, &fileStat) != 0) { - zip_fclose(zipFile); - zip_close(archive); - throw std::runtime_error("Ошибка чтения ZIP-статистики."); - } - - std::vector fileData; - fileData.resize(fileStat.size); - - zip_fread(zipFile, fileData.data(), fileData.size()); - - zip_fclose(zipFile); - zip_close(archive); - - return fileData;*/ - return {}; - } + file.seekg(0, std::ios::beg); + std::vector buffer(size); - bool findString(const char* in, char* list) - { - size_t thisLength = strlen(in); - while (*list != 0) - { - size_t length = strcspn(list, " "); + if (!file.read(buffer.data(), size)) { + return {}; + } - if (thisLength == length) - if (!strncmp(in, list, length)) - return true; + return buffer; +#endif + } - list += length; - list += 1; - } - return false; - } -}; + std::vector readFileFromZIP(const std::string &filename, const std::string &zipfilename) { + /*const std::string zipPath = zipfilename; + int zipErr; + zip_t* archive = zip_open(zipPath.c_str(), ZIP_RDONLY, &zipErr); + if (!archive) { + throw std::runtime_error("Ошибка открытия ZIP: " + zipPath); + } + + std::string cleanFilename = filename; + if (cleanFilename.rfind("./", 0) == 0) { + cleanFilename = cleanFilename.substr(2); + } + + std::cout << "Ищем в ZIP: " << cleanFilename << std::endl; + + zip_file_t* zipFile = zip_fopen(archive, cleanFilename.c_str(), 0); + if (!zipFile) { + zip_close(archive); + throw std::runtime_error("Файл не найден в ZIP: " + cleanFilename); + } + + zip_stat_t fileStat; + if (zip_stat(archive, cleanFilename.c_str(), 0, &fileStat) != 0) { + zip_fclose(zipFile); + zip_close(archive); + throw std::runtime_error("Ошибка чтения ZIP-статистики."); + } + + std::vector fileData; + fileData.resize(fileStat.size); + + zip_fread(zipFile, fileData.data(), fileData.size()); + + zip_fclose(zipFile); + zip_close(archive); + + return fileData;*/ + return {}; + } + + bool findString(const char *in, char *list) { + size_t thisLength = strlen(in); + while (*list != 0) { + size_t length = strcspn(list, " "); + if (thisLength == length && !strncmp(in, list, length)) + return true; + list += length + 1; + } + return false; + } +}; \ No newline at end of file diff --git a/app/jni/src/main.cpp b/app/jni/src/main.cpp index d871c37..62d8724 100644 --- a/app/jni/src/main.cpp +++ b/app/jni/src/main.cpp @@ -1,25 +1,48 @@ #include "Game.h" #include "Environment.h" +#ifdef __ANDROID__ +#include +#endif + ZL::Game game; #ifdef __ANDROID__ extern "C" int SDL_main(int argc, char* argv[]) { #else -int main(int argc, char* argv[]) { + +int main(int argc, char *argv[]) { #endif #ifdef __ANDROID__ + // Инициализация 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; - SDL_GetCurrentDisplayMode(0, &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); #else constexpr int CONST_WIDTH = 1280; constexpr int CONST_HEIGHT = 720; ZL::Environment::width = CONST_WIDTH; ZL::Environment::height = CONST_HEIGHT; + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { + SDL_Log("SDL init failed: %s", SDL_GetError()); + return 1; + } #endif #ifdef EMSCRIPTEN @@ -52,15 +75,18 @@ int main(int argc, char* argv[]) { ZL::Environment::window = win; #else - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { - SDL_Log("SDL init failed: %s", SDL_GetError()); - return 1; - } #ifdef __ANDROID__ - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); 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", @@ -69,9 +95,12 @@ int main(int argc, char* argv[]) { SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN ); #else + // Для десктопа SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); ZL::Environment::window = SDL_CreateWindow( "Space Ship Game", @@ -81,11 +110,63 @@ int main(int argc, char* argv[]) { ); #endif - SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window); - SDL_GL_MakeCurrent(ZL::Environment::window, ctx); + if (!ZL::Environment::window) { +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_ERROR, "Game", "Failed to create window: %s", SDL_GetError()); +#else + SDL_Log("Failed to create window: %s", SDL_GetError()); +#endif + SDL_Quit(); + return 1; + } + +#ifdef __ANDROID__ + #endif - game.setup(); + SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window); + if (!ctx) { +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GL_CreateContext failed: %s", SDL_GetError()); +#else + SDL_Log("SDL_GL_CreateContext failed: %s", SDL_GetError()); +#endif + SDL_DestroyWindow(ZL::Environment::window); + SDL_Quit(); + return 1; + } + + if (SDL_GL_MakeCurrent(ZL::Environment::window, ctx) != 0) { +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GL_MakeCurrent failed: %s", SDL_GetError()); +#else + SDL_Log("SDL_GL_MakeCurrent failed: %s", SDL_GetError()); +#endif + SDL_GL_DeleteContext(ctx); + SDL_DestroyWindow(ZL::Environment::window); + SDL_Quit(); + return 1; + } + + // Настройка VSync + if (SDL_GL_SetSwapInterval(1) < 0) { +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_WARN, "Game", "Unable to set VSync: %s", SDL_GetError()); +#endif + } +#endif + + // Настройка игры + try { + game.setup(); + } catch (const std::exception &e) { +#ifdef __ANDROID__ + __android_log_print(ANDROID_LOG_ERROR, "Game", "Game setup failed: %s", e.what()); +#else + std::cerr << "Game setup failed: " << e.what() << std::endl; +#endif + return 1; + } #ifdef EMSCRIPTEN emscripten_set_main_loop(MainLoop, 0, 1); diff --git a/app/src/main/assets/resources/sship001x.bmp b/app/src/main/assets/resources/sship001x.bmp new file mode 100644 index 0000000..9b43296 Binary files /dev/null and b/app/src/main/assets/resources/sship001x.bmp differ diff --git a/app/src/main/assets/shaders/defaultColor_android.fragment b/app/src/main/assets/shaders/defaultColor_android.fragment index cabdaf3..6219ec5 100644 --- a/app/src/main/assets/shaders/defaultColor_android.fragment +++ b/app/src/main/assets/shaders/defaultColor_android.fragment @@ -1,8 +1,7 @@ -#version 100 precision mediump float; +varying vec3 color; -varying vec3 fragmentColor; - -void main(void) { - gl_FragColor = vec4(fragmentColor, 1.0); +void main() +{ + gl_FragColor = vec4(color, 1.0); } \ No newline at end of file diff --git a/app/src/main/assets/shaders/default_android.fragment b/app/src/main/assets/shaders/default_android.fragment index 47511da..5350311 100644 --- a/app/src/main/assets/shaders/default_android.fragment +++ b/app/src/main/assets/shaders/default_android.fragment @@ -1,9 +1,9 @@ -#version 100 precision mediump float; - -varying vec2 TexCoordOut; uniform sampler2D Texture; +varying vec2 texCoord; -void main(void) { - gl_FragColor = texture2D(Texture, TexCoordOut); +void main() +{ + vec4 color = texture2D(Texture, texCoord); + gl_FragColor = color; } \ No newline at end of file diff --git a/app/src/main/assets/test.png b/app/src/main/assets/test.png deleted file mode 100644 index d7aff3c..0000000 Binary files a/app/src/main/assets/test.png and /dev/null differ