fix some and add spaceship with shaders and textures

This commit is contained in:
Vlad 2025-12-06 21:49:09 +06:00
parent 1c9b1b1969
commit 70db96a52e
11 changed files with 1020 additions and 786 deletions

View File

@ -2,166 +2,247 @@
#include "AnimatedModel.h"
#include "BoneAnimatedModel.h"
#include "Utils.h"
//#include "OpenGlExtensions.h"
#include <iostream>
#include "TextureManager.h"
#include "TextModel.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
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 <android/log.h>
#endif
//Load texture
spaceshipTexture = std::make_unique<Texture>(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<float>(Environment::width) / static_cast<float>(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<Texture>(
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<Texture>(
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<float>(Environment::width) /
static_cast<float>(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

View File

@ -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<Texture> 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 <Texture> spaceshipTexture;
VertexDataStruct spaceshipBase;
VertexRenderStruct spaceship;
};
} // namespace ZL

View File

@ -1,212 +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 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, &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<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(shaderManager)
{
shaderManager.PushShader(shaderName);
}
ShaderSetter::~ShaderSetter()
{
shaderManager.PopShader();
}
ShaderSetter::~ShaderSetter() {
shaderManager.PopShader();
}
}

View File

@ -5,386 +5,393 @@
#include <iostream>
#include <sstream>
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<char> 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<std::istream&>(zipStream) : static_cast<std::istream&>(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<Vector3f> vertices;
vertices.resize(numberVertices);
for (int i = 0; i < numberVertices; i++)
{
std::getline(f, tempLine);
std::vector<float> 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 <android/log.h>
#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<char> 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<std::istream &>(zipStream)
: static_cast<std::istream &>(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<std::array<Vector2f, 3>> 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<float> 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 <Vector (-0.3661, -1.1665)>
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 <Vector3f> 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<float> 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<Vector3f> 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<float> 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 <std::array<Vector2f, 3>> 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<std::array<int, 3>> 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<float> floatValues;
std::vector<int> intValues;
for (int j = 0; j < 3; j++) {
std::getline(f, tempLine); //UV <Vector (-0.3661, -1.1665)>
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 <Vector3f> normals;
// --- 1. Открытие потока (без изменений) ---
if (!ZIPFileName.empty())
{
std::vector<char> 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<std::istream&>(zipStream) : static_cast<std::istream&>(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<Vector3f> tempPositions(numberVertices);
std::vector<Vector3f> tempNormals(numberVertices);
std::vector<Vector2f> 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<float> 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<int> 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<float> 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 <std::array<int, 3>> triangles;
triangles.resize(numberTriangles);
for (int i = 0; i < numberTriangles; i++) {
std::getline(f, tempLine);
std::vector<int> 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<char> fileData = readFileFromZIP(fileName, ZIPFileName);
std::string fileContents(fileData.begin(), fileData.end());
zipStream.str(fileContents);
f = static_cast<std::istream &>(zipStream);
} else {
filestream.open(fileName);
if (!filestream.is_open()) {
throw std::runtime_error("Failed to open file: " + fileName);
}
f = static_cast<std::istream &>(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 <Vector3f> tempPositions(numberVertices);
std::vector <Vector3f> tempNormals(numberVertices);
std::vector <Vector2f> 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<float> 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<int> 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;
}
}

View File

@ -5,8 +5,14 @@
#include <unordered_map>
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 <android/log.h>
#endif
namespace ZL {
VertexDataStruct
LoadFromTextFile(const std::string &fileName, const std::string &ZIPFileName = "");
VertexDataStruct
LoadFromTextFile02(const std::string &fileName, const std::string &ZIPFileName = "");
}

View File

@ -6,95 +6,139 @@
#include <algorithm>
#include <fstream>
//#include <zip.h>
#include <SDL.h>
namespace ZL
{
#ifdef __ANDROID__
#include <android/log.h>
#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<char>(f)), std::istreambuf_iterator<char>());
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<char> 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<char>(f)),
std::istreambuf_iterator<char>());
#endif
}
file.unsetf(std::ios::skipws);
std::vector<char> 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<char> data(size);
if (SDL_RWread(file, data.data(), size, 1) != 1) {
SDL_RWclose(file);
return {};
}
std::vector<char> 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<char>(file),
std::istream_iterator<char>());
std::streamsize size = file.tellg();
if (size <= 0) {
return {};
}
return vec;
}
std::vector<char> 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<char> 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<char> 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<char> 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<char> 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;
}
};

View File

@ -1,25 +1,48 @@
#include "Game.h"
#include "Environment.h"
#ifdef __ANDROID__
#include <android/log.h>
#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);

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

View File

@ -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);
}

View File

@ -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;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB