Compare commits

..

No commits in common. "main" and "android" have entirely different histories.

267 changed files with 17183 additions and 86539 deletions

3
.gitattributes vendored
View File

@ -1,3 +0,0 @@
*.bmp filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text

447
.gitignore vendored Executable file → Normal file
View File

@ -1,407 +1,62 @@
## Ignore Visual Studio temporary files, build results, and # Built application files
## files generated by popular Visual Studio add-ons. *.apk
## *.ap_
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore *.aab
.vscode/ # Files for the ART/Dalvik VM
*.dex
# User-specific files # Java class files
*.rsuser *.class
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio) # Generated files
*.userprefs bin/
gen/
out/
# Mono auto generated files # Gradle files
mono_crash.* .gradle/
......................................................................... build/
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Nuget personal access tokens and Credentials
nuget.config
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
.idea/ .idea/
# Local configuration file (sdk path, etc)
local.properties
sdl_app # CMake build files
CMakeFiles/
cmake_install.cmake
CMakeCache.txt
Makefile
*.cmake
*.sln.iml # Android Studio
*.iml
.idea/
.cxx/
.gradle/
.DS_Store
/captures/
.externalNativeBuild/
images.zip # NDK
script.py .obj/
*.o
*.so
jumpingbird.* # SDL2 (если используешь)
jumpingbird.data libs/
build obj/
build-emcmake
thirdparty
proj-web/build # Временные файлы
proj-windows/build *.swp
public *.swo
*~
.thumbs.db
desktop.ini
# Проектные специфичные
app/build/
*.log
app/jni/libpng
app/jni/SDL
app/jni/zlib

175
Readme.md
View File

@ -1,175 +0,0 @@
# Windows
download from https://cmake.org/download/
Windows x64 Installer: cmake-4.2.0-windows-x86_64.msi
download from https://github.com/libsdl-org/SDL/releases/tag/release-2.32.10
SDL2-2.32.10-win32-x64.zip
SDL2-2.32.10:
```
cd C:\..\SDL-realese-2.32.10
mkdir build
cd build
cmake -G "Visual Studio 18 2026" -DCMAKE_INSTALL_PREFIX=install ..
cmake --build . --config Debug
cmake --install . --config Debug
```
download from https://www.zlib.net/
zlib source code, version 1.3.1, zipfile format (1616K, SHA-256 hash 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17):
US (zlib.net)
zlib-1.3.1:
```
cd C:\..\zlib-1.3.1
mkdir build
cd build
cmake -G "Visual Studio 18 2026" -DCMAKE_INSTALL_PREFIX=install ..
cmake --build . --config Debug
cmake --install . --config Debug
```
download from https://github.com/pnggroup/libpng/releases/tag/v1.6.51
Source code (zip)
libpng-1.6.51:
```
cd C:\..\libpng-1.6.51
mkdir build
cd build
```
To build libpng, you need to specify the path to the zlib installation directory as follows:
```
cmake -DCMAKE_PREFIX_PATH="../zlib-1.3.1/build/install" -DCMAKE_INSTALL_PREFIX=install -G "Visual Studio 18 2026" ..
cmake --build . --config Debug
cmake --install . --config Debug
```
Настройка проекта в Visual Studio:
Перейдите в Project Properties (правый клик на проект, "Properties").
C/C++ - ОБЩИЕ; Дополнительные каталоги включаемых файлов, проверить чтобы был добавлен путь к папке include:(пример)
..\SDL-release-2.32.10\include;..\libpng-1.6.51\build\install\include;C:\Work\OpenAL 1.1 SDK\include;..\Projects\libogg\include;..\vorbis\include
Компоновщик - ОБЩИЕ; Доподнительные каталоги библиотек (пример)
..\SDL-release-2.32.10\build\install\lib;..\libpng-1.6.51\build\install\lib;..\zlib-1.3.1\build\install\lib
Компоновщик - ВВОД; Дополнительные зависимости, добавить zlibstaticd.lib (пример)
zlibstaticd.lib;libpng16_staticd.lib;SDL2d.lib;SDL2maind.lib;opengl32.lib;glu32.lib;shell32.lib;opengl32.lib;glu32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib
в папку ..\projectGAME01\x64\Debug добавить файл SDL2d.dll
который можно скопировать из папки ..\SDL-release-2.32.10\build\Debug
# Script to run:
```
C:\Work\Projects\emsdk\emsdk.bat activate latest
C:\Work\Projects\emsdk\emsdk_env.bat
emcc main.cpp Game.cpp Math.cpp Physics.cpp Renderer.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -sTOTAL_MEMORY=33554432 -sUSE_SDL_IMAGE=2 -sSDL2_IMAGE_FORMATS="[""png""]" -sUSE_SDL=2 --preload-file background.bmp --preload-file bird.bmp32 --preload-file default.fragment --preload-file default.vertex --preload-file game_over.bmp32 --preload-file pipe.bmp32 -o space-game001.html
```
```
zlib-1.3.1:
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=install ..
then run ALL_BUILD and INSTALL in Visual Studio
lpng1645:
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=install -DZLIB_ROOT=C:\Work\Projects\zlib-1.3.1\build\install ..
then run ALL_BUILD and INSTALL in Visual Studio
```
https://github.com/Bly7/OBJ-Loader/blob/master/Source/OBJ_Loader.h
https://github.com/gametutorials/tutorials/blob/master/OpenGL/MD3%20Animation/Main.cpp
linux:
```
g++ Game.cpp main.cpp Math.cpp OpenGlExtensions.cpp Physics.cpp Renderer.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp BoneAnimatedModel.cpp ObjLoader.cpp cmakeaudioplayer/src/AudioPlayer.cpp TextModel.cpp Inventory.cpp -o sdl_app -O2 -std=c++17 \
-I cmakeaudioplayer/include \
$(pkg-config --cflags --libs sdl2 gl) \
$(pkg-config --cflags --libs vorbis vorbisfile ogg) \
-lopenal
```
# Emscripten new
```
cd build-emcmake/
emcmake cmake -DCMAKE_INSTALL_PREFIX=install ..
cmake --build .
cmake --install .
emcc main.cpp Game.cpp Environment.cpp GameObjectManager.cpp BoneAnimatedModel.cpp GameWorld.cpp InputManager.cpp Inventory.cpp ObjLoader.cpp QuestScripts.cpp RenderSystem.cpp Math.cpp Physics.cpp Renderer.cpp TextModel.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -IC:\Users\ASUS\Desktop\fishrungame2\ZeptoLabTest1\thirdparty\libzip-1.11.3\build-emcmake\install\include -LC:\Users\ASUS\Desktop\fishrungame2\ZeptoLabTest1\thirdparty\libzip-1.11.3\build-emcmake\install\lib -lzip -sTOTAL_MEMORY=33554432 -sUSE_SDL_IMAGE=2 -sSDL2_IMAGE_FORMATS="[""png""]" -sUSE_SDL=2 --preload-file background.bmp --preload-file bird.bmp32 --preload-file default.fragment --preload-file default.vertex --preload-file game_over.bmp32 --preload-file pipe.bmp32 -o jumpingbird.html
emcc main.cpp Game.cpp Environment.cpp GameObjectManager.cpp BoneAnimatedModel.cpp GameWorld.cpp InputManager.cpp Inventory.cpp ObjLoader.cpp QuestScripts.cpp RenderSystem.cpp Math.cpp Physics.cpp Renderer.cpp TextModel.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sTOTAL_MEMORY=4294967296 -sINITIAL_MEMORY=3221225472 -sMAXIMUM_MEMORY=4294967296 -sALLOW_MEMORY_GROWTH=1 -I./thirdparty/libzip-1.11.3/build-emcmake/install/include -I./thirdparty/zlib-1.3.1/install/include -L./thirdparty/libzip-1.11.3/build-emcmake/install/lib -L./thirdparty/zlib-1.3.1/install/lib -lzip -lz -sUSE_SDL_IMAGE=2 -sSDL2_IMAGE_FORMATS='["png"]' -sUSE_SDL=2 --preload-file data.zip -o jumpingbird.html
# Windows:
emcc --clear-cache
embuilder build sdl2 sdl2_ttf sdl2_image sdl2_image_jpg sdl2_image_png
emcc main.cpp Game.cpp Environment.cpp BoneAnimatedModel.cpp ZLMath.cpp Renderer.cpp TextModel.cpp ShaderManager.cpp TextureManager.cpp Utils.cpp OpenGlExtensions.cpp -O2 -std=c++14 -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sTOTAL_MEMORY=4294967296 -sINITIAL_MEMORY=3221225472 -sMAXIMUM_MEMORY=4294967296 -sALLOW_MEMORY_GROWTH=1 -I./thirdparty/libzip-1.11.3/build-emcmake/install/include -L./thirdparty/libzip-1.11.3/build-emcmake/install/lib -lzip -lz -sUSE_SDL_IMAGE=2 -sUSE_SDL=2 -sUSE_LIBPNG=1 --preload-file space-game001.zip -o space-game001.html
emrun --no_browser --port 8080 .
```
# Emscripten new
```
emcc src/main.cpp src/Game.cpp src/Environment.cpp src/BoneAnimatedModel.cpp src/TextModel.cpp src/Projectile.cpp src/SparkEmitter.cpp src/UiManager.cpp src/render/Renderer.cpp src/render/ShaderManager.cpp src/render/TextureManager.cpp src/render/FrameBuffer.cpp src/render/OpenGlExtensions.cpp src/utils/Utils.cpp src/utils/TaskManager.cpp src/utils/Perlin.cpp src/planet/PlanetData.cpp src/planet/PlanetObject.cpp src/planet/StoneObject.cpp -O2 -std=c++17 -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sTOTAL_MEMORY=4294967296 -sINITIAL_MEMORY=3221225472 -sMAXIMUM_MEMORY=4294967296 -sALLOW_MEMORY_GROWTH=1 -fexceptions -I./thirdparty1/eigen-5.0.0 -I./src -I./thirdparty/libzip-1.11.3/build-emcmake/install/include -IC:/Boost/include/boost-1_84 -L./thirdparty/libzip-1.11.3/build-emcmake/install/lib -lzip -lz -sUSE_SDL_IMAGE=2 -sUSE_SDL=2 -sUSE_LIBPNG=1 --preload-file space-game001.zip -o space-game001.html
```
# License
Code: MIT
Art: CC-BY
# Cmake Run Linux
Run using cmakelist
make -j$(nproc) -C build #Компилируем
./build/sdl_app #Запускаем
Для постройки без звука
rm -rf build #Очищаем build папку
cmake -B build -DAUDIO=1 #Пересоздаём конфигурацию CMake

View File

@ -60,9 +60,11 @@ android {
if (buildAsLibrary) { if (buildAsLibrary) {
libraryVariants.all { variant -> libraryVariants.all { variant ->
variant.outputs.all { output -> variant.outputs.each { output ->
if (output.outputFileName != null && output.outputFileName.endsWith(".aar")) { def outputFile = output.outputFile
output.outputFileName = "org.libsdl.app.aar" if (outputFile != null && outputFile.name.endsWith(".aar")) {
def fileName = "org.libsdl.app.aar";
output.outputFile = new File(outputFile.parent, fileName);
} }
} }
} }

41
app/jni/CMakeLists.txt Normal file
View File

@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 3.6)
project(GAME)
if(POLICY CMP0079)
cmake_policy(SET CMP0079 NEW)
endif()
# Копируем pnglibconf.h.prebuilt
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/libpng/scripts/pnglibconf.h.prebuilt
${CMAKE_CURRENT_SOURCE_DIR}/libpng/pnglibconf.h
)
# Сначала zlib
add_subdirectory(zlib)
# ВАЖНО: Установите опции ДО add_subdirectory(libpng)
# Libpng создает ДВЕ цели: png_shared (shared) и png_static (static)
# Мы хотим статическую библиотеку для Android
set(PNG_STATIC ON CACHE BOOL "Build static library" FORCE)
set(PNG_SHARED OFF CACHE BOOL "Don't build shared library" FORCE)
set(PNG_TESTS OFF CACHE BOOL "Disable tests" FORCE)
set(PNG_TOOLS OFF CACHE BOOL "Disable tools" FORCE)
set(PNG_EXECUTABLES OFF CACHE BOOL "Disable executables" FORCE)
set(PNG_DEBUG OFF CACHE BOOL "Disable debug" FORCE)
set(SKIP_INSTALL_ALL ON CACHE BOOL "Skip installation" FORCE)
# Для Android отключаем оптимизации
set(PNG_HARDWARE_OPTIMIZATIONS OFF CACHE BOOL "Disable hardware optimizations" FORCE)
set(PNG_ARM_NEON "off" CACHE STRING "Disable ARM NEON" FORCE)
# Добавляем libpng
add_subdirectory(libpng)
# Затем SDL
add_subdirectory(SDL)
# И ваш код
add_subdirectory(src)

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include "render/Renderer.h" #include "Renderer.h"
#include "render/TextureManager.h" #include "TextureManager.h"
namespace ZL namespace ZL
{ {

View File

@ -1,4 +1,4 @@
#include "BoneAnimatedModel.h" #include "BoneAnimatedModel.h"
#include <regex> #include <regex>
#include <string> #include <string>
#include <fstream> #include <fstream>
@ -119,9 +119,9 @@ namespace ZL
b = match.suffix().first; b = match.suffix().first;
} }
bones[i].boneMatrixWorld.data()[0] = floatValues[0]; bones[i].boneMatrixWorld.m[0] = floatValues[0];
bones[i].boneMatrixWorld.data()[0 + 1 * 3] = floatValues[1]; bones[i].boneMatrixWorld.m[0 + 1 * 3] = floatValues[1];
bones[i].boneMatrixWorld.data()[0 + 2 * 3] = floatValues[2]; bones[i].boneMatrixWorld.m[0 + 2 * 3] = floatValues[2];
std::getline(f, tempLine); std::getline(f, tempLine);
@ -134,9 +134,9 @@ namespace ZL
b = match.suffix().first; b = match.suffix().first;
} }
bones[i].boneMatrixWorld.data()[1] = floatValues[0]; bones[i].boneMatrixWorld.m[1] = floatValues[0];
bones[i].boneMatrixWorld.data()[1 + 1 * 3] = floatValues[1]; bones[i].boneMatrixWorld.m[1 + 1 * 3] = floatValues[1];
bones[i].boneMatrixWorld.data()[1 + 2 * 3] = floatValues[2]; bones[i].boneMatrixWorld.m[1 + 2 * 3] = floatValues[2];
std::getline(f, tempLine); std::getline(f, tempLine);
@ -149,9 +149,9 @@ namespace ZL
b = match.suffix().first; b = match.suffix().first;
} }
bones[i].boneMatrixWorld.data()[2] = floatValues[0]; bones[i].boneMatrixWorld.m[2] = floatValues[0];
bones[i].boneMatrixWorld.data()[2 + 1 * 3] = floatValues[1]; bones[i].boneMatrixWorld.m[2 + 1 * 3] = floatValues[1];
bones[i].boneMatrixWorld.data()[2 + 2 * 3] = floatValues[2]; bones[i].boneMatrixWorld.m[2 + 2 * 3] = floatValues[2];
//----------- matrix end //----------- matrix end
std::getline(f, tempLine); //parent std::getline(f, tempLine); //parent
@ -489,10 +489,10 @@ namespace ZL
b = match.suffix().first; b = match.suffix().first;
} }
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[0] = floatValues[0]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[0] = floatValues[0];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[0 + 1 * 4] = floatValues[1]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[0 + 1 * 4] = floatValues[1];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[0 + 2 * 4] = floatValues[2]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[0 + 2 * 4] = floatValues[2];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[0 + 3 * 4] = floatValues[3]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[0 + 3 * 4] = floatValues[3];
std::getline(f, tempLine); std::getline(f, tempLine);
@ -504,10 +504,10 @@ namespace ZL
b = match.suffix().first; b = match.suffix().first;
} }
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[1] = floatValues[0]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[1] = floatValues[0];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[1 + 1 * 4] = floatValues[1]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[1 + 1 * 4] = floatValues[1];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[1 + 2 * 4] = floatValues[2]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[1 + 2 * 4] = floatValues[2];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[1 + 3 * 4] = floatValues[3]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[1 + 3 * 4] = floatValues[3];
std::getline(f, tempLine); std::getline(f, tempLine);
b = tempLine.cbegin(); b = tempLine.cbegin();
@ -518,10 +518,10 @@ namespace ZL
b = match.suffix().first; b = match.suffix().first;
} }
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[2] = floatValues[0]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[2] = floatValues[0];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[2 + 1 * 4] = floatValues[1]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[2 + 1 * 4] = floatValues[1];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[2 + 2 * 4] = floatValues[2]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[2 + 2 * 4] = floatValues[2];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[2 + 3 * 4] = floatValues[3]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[2 + 3 * 4] = floatValues[3];
std::getline(f, tempLine); std::getline(f, tempLine);
@ -533,10 +533,10 @@ namespace ZL
b = match.suffix().first; b = match.suffix().first;
} }
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[3] = floatValues[0]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[3] = floatValues[0];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[3 + 1 * 4] = floatValues[1]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[3 + 1 * 4] = floatValues[1];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[3 + 2 * 4] = floatValues[2]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[3 + 2 * 4] = floatValues[2];
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[3 + 3 * 4] = floatValues[3]; animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.m[3 + 3 * 4] = floatValues[3];
//std::getline(f, tempLine);// ignore last matrix line //std::getline(f, tempLine);// ignore last matrix line
@ -602,79 +602,88 @@ namespace ZL
for (int i = 0; i < currentBones.size(); i++) for (int i = 0; i < currentBones.size(); i++)
{ {
currentBones[i].boneStartWorld(0) = oneFrameBones[i].boneStartWorld(0) + t * (nextFrameBones[i].boneStartWorld(0) - oneFrameBones[i].boneStartWorld(0)); currentBones[i].boneStartWorld.v[0] = oneFrameBones[i].boneStartWorld.v[0] + t * (nextFrameBones[i].boneStartWorld.v[0] - oneFrameBones[i].boneStartWorld.v[0]);
currentBones[i].boneStartWorld(1) = oneFrameBones[i].boneStartWorld(1) + t * (nextFrameBones[i].boneStartWorld(1) - oneFrameBones[i].boneStartWorld(1)); currentBones[i].boneStartWorld.v[1] = oneFrameBones[i].boneStartWorld.v[1] + t * (nextFrameBones[i].boneStartWorld.v[1] - oneFrameBones[i].boneStartWorld.v[1]);
currentBones[i].boneStartWorld(2) = oneFrameBones[i].boneStartWorld(2) + t * (nextFrameBones[i].boneStartWorld(2) - oneFrameBones[i].boneStartWorld(2)); currentBones[i].boneStartWorld.v[2] = oneFrameBones[i].boneStartWorld.v[2] + t * (nextFrameBones[i].boneStartWorld.v[2] - oneFrameBones[i].boneStartWorld.v[2]);
Matrix3f oneFrameBonesMatrix; Matrix3f oneFrameBonesMatrix;
oneFrameBonesMatrix = oneFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0); oneFrameBonesMatrix.m[0] = oneFrameBones[i].boneMatrixWorld.m[0];
/* oneFrameBonesMatrix.m[1] = oneFrameBones[i].boneMatrixWorld.m[1];
oneFrameBonesMatrix.data()[0] = oneFrameBones[i].boneMatrixWorld.m[0]; oneFrameBonesMatrix.m[2] = oneFrameBones[i].boneMatrixWorld.m[2];
oneFrameBonesMatrix.data()[1] = oneFrameBones[i].boneMatrixWorld.m[1];
oneFrameBonesMatrix.data()[2] = oneFrameBones[i].boneMatrixWorld.m[2];
oneFrameBonesMatrix.data()[3] = oneFrameBones[i].boneMatrixWorld.m[0 + 1*4]; oneFrameBonesMatrix.m[3] = oneFrameBones[i].boneMatrixWorld.m[0 + 1*4];
oneFrameBonesMatrix.data()[4] = oneFrameBones[i].boneMatrixWorld.m[1 + 1*4]; oneFrameBonesMatrix.m[4] = oneFrameBones[i].boneMatrixWorld.m[1 + 1*4];
oneFrameBonesMatrix.data()[5] = oneFrameBones[i].boneMatrixWorld.m[2 + 1*4]; oneFrameBonesMatrix.m[5] = oneFrameBones[i].boneMatrixWorld.m[2 + 1*4];
oneFrameBonesMatrix.m[6] = oneFrameBones[i].boneMatrixWorld.m[0 + 2*4];
oneFrameBonesMatrix.m[7] = oneFrameBones[i].boneMatrixWorld.m[1 + 2*4];
oneFrameBonesMatrix.m[8] = oneFrameBones[i].boneMatrixWorld.m[2 + 2*4];
oneFrameBonesMatrix.data()[6] = oneFrameBones[i].boneMatrixWorld.m[0 + 2*4];
oneFrameBonesMatrix.data()[7] = oneFrameBones[i].boneMatrixWorld.m[1 + 2*4];
oneFrameBonesMatrix.data()[8] = oneFrameBones[i].boneMatrixWorld.m[2 + 2*4];
*/
Matrix3f nextFrameBonesMatrix; Matrix3f nextFrameBonesMatrix;
nextFrameBonesMatrix = nextFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0); nextFrameBonesMatrix.m[0] = nextFrameBones[i].boneMatrixWorld.m[0];
/* nextFrameBonesMatrix.m[1] = nextFrameBones[i].boneMatrixWorld.m[1];
nextFrameBonesMatrix.data()[0] = nextFrameBones[i].boneMatrixWorld.m[0]; nextFrameBonesMatrix.m[2] = nextFrameBones[i].boneMatrixWorld.m[2];
nextFrameBonesMatrix.data()[1] = nextFrameBones[i].boneMatrixWorld.m[1];
nextFrameBonesMatrix.data()[2] = nextFrameBones[i].boneMatrixWorld.m[2];
nextFrameBonesMatrix.data()[3] = nextFrameBones[i].boneMatrixWorld.m[0 + 1 * 4]; nextFrameBonesMatrix.m[3] = nextFrameBones[i].boneMatrixWorld.m[0 + 1 * 4];
nextFrameBonesMatrix.data()[4] = nextFrameBones[i].boneMatrixWorld.m[1 + 1 * 4]; nextFrameBonesMatrix.m[4] = nextFrameBones[i].boneMatrixWorld.m[1 + 1 * 4];
nextFrameBonesMatrix.data()[5] = nextFrameBones[i].boneMatrixWorld.m[2 + 1 * 4]; nextFrameBonesMatrix.m[5] = nextFrameBones[i].boneMatrixWorld.m[2 + 1 * 4];
nextFrameBonesMatrix.data()[6] = nextFrameBones[i].boneMatrixWorld.m[0 + 2 * 4]; nextFrameBonesMatrix.m[6] = nextFrameBones[i].boneMatrixWorld.m[0 + 2 * 4];
nextFrameBonesMatrix.data()[7] = nextFrameBones[i].boneMatrixWorld.m[1 + 2 * 4]; nextFrameBonesMatrix.m[7] = nextFrameBones[i].boneMatrixWorld.m[1 + 2 * 4];
nextFrameBonesMatrix.data()[8] = nextFrameBones[i].boneMatrixWorld.m[2 + 2 * 4]; nextFrameBonesMatrix.m[8] = nextFrameBones[i].boneMatrixWorld.m[2 + 2 * 4];
*/
Eigen::Quaternionf q1 = Eigen::Quaternionf(oneFrameBonesMatrix).normalized();
Eigen::Quaternionf q2 = Eigen::Quaternionf(nextFrameBonesMatrix).normalized();
Eigen::Quaternionf q1_norm = q1.normalized();
Eigen::Quaternionf q2_norm = q2.normalized();
Eigen::Quaternionf result = q1_norm.slerp(t, q2_norm); Vector4f q1 = MatrixToQuat(oneFrameBonesMatrix);
Vector4f q2 = MatrixToQuat(nextFrameBonesMatrix);
Vector4f q1_norm = q1.normalized();
Vector4f q2_norm = q2.normalized();
Matrix3f boneMatrixWorld3 = result.toRotationMatrix(); Vector4f result = slerp(q1_norm, q2_norm, t);
currentBones[i].boneMatrixWorld = Eigen::Matrix4f::Identity(); Matrix3f boneMatrixWorld3 = QuatToMatrix(result);
// Копируем 3x3 матрицу в верхний левый угол
currentBones[i].boneMatrixWorld.block<3, 3>(0, 0) = boneMatrixWorld3;
// Копируем позицию в последний столбец (первые 3 элемента)
currentBones[i].boneMatrixWorld.block<3, 1>(0, 3) = currentBones[i].boneStartWorld;
currentBones[i].boneMatrixWorld = MakeMatrix4x4(boneMatrixWorld3, currentBones[i].boneStartWorld);
Matrix4f currentBoneMatrixWorld4 = currentBones[i].boneMatrixWorld; Matrix4f currentBoneMatrixWorld4 = currentBones[i].boneMatrixWorld;
Matrix4f startBoneMatrixWorld4 = animations[0].keyFrames[0].bones[i].boneMatrixWorld; Matrix4f startBoneMatrixWorld4 = animations[0].keyFrames[0].bones[i].boneMatrixWorld;
Matrix4f inverstedStartBoneMatrixWorld4 = startBoneMatrixWorld4.inverse(); Matrix4f inverstedStartBoneMatrixWorld4 = InverseMatrix(startBoneMatrixWorld4);
skinningMatrixForEachBone[i] = currentBoneMatrixWorld4 * inverstedStartBoneMatrixWorld4; skinningMatrixForEachBone[i] = MultMatrixMatrix(currentBoneMatrixWorld4, inverstedStartBoneMatrixWorld4);
} }
/*
for (int i = 0; i < currentBones.size(); i++)
{
currentBones[i].boneStartWorld = oneFrameBones[i].boneStartWorld;
currentBones[i].boneMatrixWorld = oneFrameBones[i].boneMatrixWorld;
//Matrix4f currentBoneMatrixWorld4 = MakeMatrix4x4(currentBones[i].boneMatrixWorld, currentBones[i].boneStartWorld);
//Matrix4f startBoneMatrixWorld4 = MakeMatrix4x4(animations[0].keyFrames[0].bones[i].boneMatrixWorld, animations[0].keyFrames[0].bones[i].boneStartWorld);
Matrix4f currentBoneMatrixWorld4 = currentBones[i].boneMatrixWorld;
Matrix4f startBoneMatrixWorld4 = animations[0].keyFrames[0].bones[i].boneMatrixWorld;
Matrix4f inverstedStartBoneMatrixWorld4 = InverseMatrix(startBoneMatrixWorld4);
skinningMatrixForEachBone[i] = MultMatrixMatrix(currentBoneMatrixWorld4, inverstedStartBoneMatrixWorld4);
if (i == 10)
{
std::cout << i << std::endl;
}
}*/
for (int i = 0; i < mesh.PositionData.size(); i++) for (int i = 0; i < mesh.PositionData.size(); i++)
{ {
Vector4f originalPos = { Vector4f originalPos = {
startMesh.PositionData[i](0), startMesh.PositionData[i].v[0],
startMesh.PositionData[i](1), startMesh.PositionData[i].v[1],
startMesh.PositionData[i](2), 1.0}; startMesh.PositionData[i].v[2], 1.0};
Vector4f finalPos = Vector4f{0.f, 0.f, 0.f, 0.f}; Vector4f finalPos = Vector4f{0.f, 0.f, 0.f, 0.f};
bool vMoved = false; bool vMoved = false;
//Vector3f finalPos = Vector3f{ 0.f, 0.f, 0.f };
for (int j = 0; j < MAX_BONE_COUNT; j++) for (int j = 0; j < MAX_BONE_COUNT; j++)
{ {
@ -682,11 +691,11 @@ namespace ZL
{ {
vMoved = true; vMoved = true;
//finalPos = finalPos + MultVectorMatrix(originalPos, skinningMatrixForEachBone[verticesBoneWeight[i][j].boneIndex]) * verticesBoneWeight[i][j].weight; //finalPos = finalPos + MultVectorMatrix(originalPos, skinningMatrixForEachBone[verticesBoneWeight[i][j].boneIndex]) * verticesBoneWeight[i][j].weight;
finalPos = finalPos + (skinningMatrixForEachBone[verticesBoneWeight[i][j].boneIndex] * originalPos) * verticesBoneWeight[i][j].weight; finalPos = finalPos + MultMatrixVector(skinningMatrixForEachBone[verticesBoneWeight[i][j].boneIndex], originalPos) * verticesBoneWeight[i][j].weight;
} }
} }
if (abs(finalPos(0) - originalPos(0)) > 1 || abs(finalPos(1) - originalPos(1)) > 1 || abs(finalPos(2) - originalPos(2)) > 1) if (abs(finalPos.v[0] - originalPos.v[0]) > 1 || abs(finalPos.v[1] - originalPos.v[1]) > 1 || abs(finalPos.v[2] - originalPos.v[2]) > 1)
{ {
} }
@ -696,9 +705,9 @@ namespace ZL
finalPos = originalPos; finalPos = originalPos;
} }
mesh.PositionData[i](0) = finalPos(0); mesh.PositionData[i].v[0] = finalPos.v[0];
mesh.PositionData[i](1) = finalPos(1); mesh.PositionData[i].v[1] = finalPos.v[1];
mesh.PositionData[i](2) = finalPos(2); mesh.PositionData[i].v[2] = finalPos.v[2];
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "render/Renderer.h" #include "Math.h"
#include "Renderer.h"
#include <unordered_map> #include <unordered_map>

View File

@ -0,0 +1,62 @@
cmake_minimum_required(VERSION 3.6)
project(MY_APP CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(main SHARED
SDL_android_main.c
main.cpp
Utils.h
Utils.cpp
TextureManager.h
TextureManager.cpp
TextModel.h
TextModel.cpp
ShaderManager.h
ShaderManager.cpp
Renderer.h
Renderer.cpp
Math.h
Math.cpp
Environment.h
Environment.cpp
BoneAnimatedModel.h
BoneAnimatedModel.cpp
AnimatedModel.h
Game.h
Game.cpp
)
# Подключаем заголовки
target_include_directories(main PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../SDL/include
${CMAKE_CURRENT_SOURCE_DIR}/../zlib
${CMAKE_CURRENT_SOURCE_DIR}/../libpng
)
# ВАЖНО: Линкуемся с png_static (статика) или png_shared (динамика)
# Так как мы установили PNG_STATIC=ON и PNG_SHARED=OFF,
# должна создаться цель png_static
target_link_libraries(main
png_static # ЭТО ПРАВИЛЬНОЕ ИМЯ ЦЕЛИ!
z
SDL2
)
if(ANDROID)
# OpenGL ES 2.0 или 3.0 для Android
find_library(OPENGLES2_LIB GLESv2)
find_library(OPENGLES1_LIB GLESv1_CM)
target_link_libraries(main
${OPENGLES2_LIB} # OpenGL ES 2.0/3.0
${OPENGLES1_LIB} # OpenGL ES 1.x (если нужно)
log
android
OpenSLES
dl
)
endif()

View File

@ -0,0 +1,35 @@
#include "Environment.h"
#include "Utils.h"
//#include <GL/gl.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
namespace ZL {
int Environment::windowHeaderHeight = 0;
int Environment::width = 0;
int Environment::height = 0;
float Environment::zoom = 20.f;
bool Environment::leftPressed = false;
bool Environment::rightPressed = false;
bool Environment::upPressed = false;
bool Environment::downPressed = false;
Vector3f Environment::cameraShift = {0, 0, 0};
Vector3f Environment::characterPos = {0, 0, 0};
float Environment::cameraPhi = 0.f;
float Environment::cameraAlpha = 0.3*M_PI / 2.0;
bool Environment::settings_inverseVertical = false;
SDL_Window* Environment::window = nullptr;
bool Environment::showMouse = false;
bool Environment::exitGameLoop = false;
} // namespace ZL

40
app/jni/src/Environment.h Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include "Math.h"
#ifdef __linux__
#include <SDL2/SDL.h>
#endif
//#include "OpenGlExtensions.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
namespace ZL {
class Environment {
public:
static int windowHeaderHeight;
static int width;
static int height;
static float zoom;
static bool leftPressed;
static bool rightPressed;
static bool upPressed;
static bool downPressed;
static Vector3f cameraShift;
static Vector3f characterPos;
static float cameraPhi;
static float cameraAlpha;
static bool settings_inverseVertical;
static SDL_Window* window;
static bool showMouse;
static bool exitGameLoop;
};
} // namespace ZL

248
app/jni/src/Game.cpp Normal file
View File

@ -0,0 +1,248 @@
#include "Game.h"
#include "AnimatedModel.h"
#include "BoneAnimatedModel.h"
#include "Utils.h"
#include <iostream>
#include "TextureManager.h"
#include "TextModel.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#ifdef __ANDROID__
#include <android/log.h>
#endif
namespace ZL {
const char *CONST_ZIP_FILE = "";
Game::Game()
: window(nullptr), glContext(nullptr), newTickCount(0), lastTickCount(0),
resourcesLoaded(false), modelLoaded(false) {
}
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);
// 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();
}
} // namespace ZL

48
app/jni/src/Game.h Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include "Renderer.h"
#include "Environment.h"
#include "TextureManager.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
namespace ZL {
class Game {
public:
Game();
~Game();
void setup();
void update();
void render();
bool shouldExit() const { return Environment::exitGameLoop; }
private:
void processTickCount();
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

734
app/jni/src/Math.cpp Normal file
View File

@ -0,0 +1,734 @@
#include "Math.h"
#include <exception>
#include <cmath>
namespace ZL {
Vector2f operator+(const Vector2f& x, const Vector2f& y)
{
Vector2f result;
result.v[0] = x.v[0] + y.v[0];
result.v[1] = x.v[1] + y.v[1];
return result;
}
Vector2f operator-(const Vector2f& x, const Vector2f& y)
{
Vector2f result;
result.v[0] = x.v[0] - y.v[0];
result.v[1] = x.v[1] - y.v[1];
return result;
}
Vector3f operator+(const Vector3f& x, const Vector3f& y)
{
Vector3f result;
result.v[0] = x.v[0] + y.v[0];
result.v[1] = x.v[1] + y.v[1];
result.v[2] = x.v[2] + y.v[2];
return result;
}
Vector3f operator-(const Vector3f& x, const Vector3f& y)
{
Vector3f result;
result.v[0] = x.v[0] - y.v[0];
result.v[1] = x.v[1] - y.v[1];
result.v[2] = x.v[2] - y.v[2];
return result;
}
Vector4f operator+(const Vector4f& x, const Vector4f& y)
{
Vector4f result;
result.v[0] = x.v[0] + y.v[0];
result.v[1] = x.v[1] + y.v[1];
result.v[2] = x.v[2] + y.v[2];
result.v[3] = x.v[3] + y.v[3];
return result;
}
Vector4f operator-(const Vector4f& x, const Vector4f& y)
{
Vector4f result;
result.v[0] = x.v[0] - y.v[0];
result.v[1] = x.v[1] - y.v[1];
result.v[2] = x.v[2] - y.v[2];
result.v[3] = x.v[3] - y.v[3];
return result;
}
Matrix3f Matrix3f::Identity()
{
Matrix3f r;
r.m[0] = 1.f;
r.m[1] = 0.f;
r.m[2] = 0.f;
r.m[3] = 0.f;
r.m[4] = 1.f;
r.m[5] = 0.f;
r.m[6] = 0.f;
r.m[7] = 0.f;
r.m[8] = 1.f;
return r;
}
Matrix4f Matrix4f::Identity()
{
Matrix4f r;
r.m[0] = 1.f;
r.m[1] = 0.f;
r.m[2] = 0.f;
r.m[3] = 0.f;
r.m[4] = 0.f;
r.m[5] = 1.f;
r.m[6] = 0.f;
r.m[7] = 0.f;
r.m[8] = 0.f;
r.m[9] = 0.f;
r.m[10] = 1.f;
r.m[11] = 0.f;
r.m[12] = 0.f;
r.m[13] = 0.f;
r.m[14] = 0.f;
r.m[15] = 1.f;
return r;
}
Matrix4f operator*(const Matrix4f& m1, const Matrix4f& m2)
{
Matrix4f r;
r.m[0] = m1.m[0] * m2.m[0] + m1.m[4] * m2.m[1] + m1.m[8] * m2.m[2] + m1.m[12] * m2.m[3];
r.m[1] = m1.m[1] * m2.m[0] + m1.m[5] * m2.m[1] + m1.m[9] * m2.m[2] + m1.m[13] * m2.m[3];
r.m[2] = m1.m[2] * m2.m[0] + m1.m[6] * m2.m[1] + m1.m[10] * m2.m[2] + m1.m[14] * m2.m[3];
r.m[3] = m1.m[3] * m2.m[0] + m1.m[7] * m2.m[1] + m1.m[11] * m2.m[2] + m1.m[15] * m2.m[3];
r.m[4] = m1.m[0] * m2.m[4] + m1.m[4] * m2.m[5] + m1.m[8] * m2.m[6] + m1.m[12] * m2.m[7];
r.m[5] = m1.m[1] * m2.m[4] + m1.m[5] * m2.m[5] + m1.m[9] * m2.m[6] + m1.m[13] * m2.m[7];
r.m[6] = m1.m[2] * m2.m[4] + m1.m[6] * m2.m[5] + m1.m[10] * m2.m[6] + m1.m[14] * m2.m[7];
r.m[7] = m1.m[3] * m2.m[4] + m1.m[7] * m2.m[5] + m1.m[11] * m2.m[6] + m1.m[15] * m2.m[7];
r.m[8] = m1.m[0] * m2.m[8] + m1.m[4] * m2.m[9] + m1.m[8] * m2.m[10] + m1.m[12] * m2.m[11];
r.m[9] = m1.m[1] * m2.m[8] + m1.m[5] * m2.m[9] + m1.m[9] * m2.m[10] + m1.m[13] * m2.m[11];
r.m[10] = m1.m[2] * m2.m[8] + m1.m[6] * m2.m[9] + m1.m[10] * m2.m[10] + m1.m[14] * m2.m[11];
r.m[11] = m1.m[3] * m2.m[8] + m1.m[7] * m2.m[9] + m1.m[11] * m2.m[10] + m1.m[15] * m2.m[11];
r.m[12] = m1.m[0] * m2.m[12] + m1.m[4] * m2.m[13] + m1.m[8] * m2.m[14] + m1.m[12] * m2.m[15];
r.m[13] = m1.m[1] * m2.m[12] + m1.m[5] * m2.m[13] + m1.m[9] * m2.m[14] + m1.m[13] * m2.m[15];
r.m[14] = m1.m[2] * m2.m[12] + m1.m[6] * m2.m[13] + m1.m[10] * m2.m[14] + m1.m[14] * m2.m[15];
r.m[15] = m1.m[3] * m2.m[12] + m1.m[7] * m2.m[13] + m1.m[11] * m2.m[14] + m1.m[15] * m2.m[15];
return r;
}
Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar)
{
float depthRange = zFar - zNear;
if (depthRange <= 0)
{
throw std::runtime_error("zFar must be greater than zNear");
}
Matrix4f r;
r.m[0] = 2.f / width;
r.m[1] = 0;
r.m[2] = 0;
r.m[3] = 0;
r.m[4] = 0;
r.m[5] = 2.f / height;
r.m[6] = 0;
r.m[7] = 0;
r.m[8] = 0;
r.m[9] = 0;
r.m[10] = -1 / depthRange;
r.m[11] = 0;
r.m[12] = -1;
r.m[13] = -1;
r.m[14] = zNear / depthRange;
r.m[15] = 1;
return r;
}
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar)
{
float tanHalfFovy = tan(fovY / 2.f);
Matrix4f r;
if (zNear >= zFar || aspectRatio == 0)
{
throw std::runtime_error("Invalid perspective parameters");
}
r.m[0] = 1.f / (aspectRatio * tanHalfFovy);
r.m[1] = 0;
r.m[2] = 0;
r.m[3] = 0;
r.m[4] = 0;
r.m[5] = 1.f / (tanHalfFovy);
r.m[6] = 0;
r.m[7] = 0;
r.m[8] = 0;
r.m[9] = 0;
r.m[10] = -(zFar + zNear) / (zFar - zNear);
r.m[11] = -1;
r.m[12] = 0;
r.m[13] = 0;
r.m[14] = -(2.f * zFar * zNear) / (zFar - zNear);
r.m[15] = 0;
return r;
}
Matrix3f QuatToMatrix(const Vector4f& q)
{
Matrix3f m;
float wx, wy, wz, xx, yy, yz, xy, xz, zz, s, x2, y2, z2;
s = 2.0f / (q.v[0] * q.v[0] + q.v[1] * q.v[1] + q.v[2] * q.v[2] + q.v[3] * q.v[3]);
x2 = q.v[0] * s;
y2 = q.v[1] * s;
z2 = q.v[2] * s;
wx = q.v[3] * x2; wy = q.v[3] * y2; wz = q.v[3] * z2;
xx = q.v[0] * x2; xy = q.v[1] * x2; xz = q.v[2] * x2;
yy = q.v[1] * y2; yz = q.v[2] * y2;
zz = q.v[2] * z2;
m.m[0] = 1.0f - (yy + zz);
m.m[1] = xy + wz;
m.m[2] = xz - wy;
m.m[3] = xy - wz;
m.m[4] = 1.0f - (xx + zz);
m.m[5] = yz + wx;
m.m[6] = xz + wy;
m.m[7] = yz - wx;
m.m[8] = 1.0f - (xx + yy);
return m;
}
Vector4f MatrixToQuat(const Matrix3f& m)
{
Vector4f r;
float trace = m.m[0] + m.m[4] + m.m[8];
if (trace > 0)
{
float s = 0.5f / sqrtf(trace + 1.0f);
r.v[3] = 0.25f / s;
r.v[0] = (m.m[5] - m.m[7]) * s;
r.v[1] = (m.m[6] - m.m[2]) * s;
r.v[2] = (m.m[1] - m.m[3]) * s;
}
else if (m.m[0] > m.m[4] && m.m[0] > m.m[8])
{
float s = 2.0f * sqrtf(1.0f + m.m[0] - m.m[4] - m.m[8]);
r.v[3] = (m.m[5] - m.m[7]) / s;
r.v[0] = 0.25f * s;
r.v[1] = (m.m[1] + m.m[3]) / s;
r.v[2] = (m.m[6] + m.m[2]) / s;
}
else if (m.m[4] > m.m[8])
{
float s = 2.0f * sqrtf(1.0f + m.m[4] - m.m[0] - m.m[8]);
r.v[3] = (m.m[6] - m.m[2]) / s;
r.v[0] = (m.m[1] + m.m[3]) / s;
r.v[1] = 0.25f * s;
r.v[2] = (m.m[5] + m.m[7]) / s;
}
else
{
float s = 2.0f * sqrtf(1.0f + m.m[8] - m.m[0] - m.m[4]);
r.v[3] = (m.m[1] - m.m[3]) / s;
r.v[0] = (m.m[6] + m.m[2]) / s;
r.v[1] = (m.m[5] + m.m[7]) / s;
r.v[2] = 0.25f * s;
}
return r.normalized();
}
Vector4f QuatFromRotateAroundX(float angle)
{
Vector4f result;
result.v[0] = sinf(angle * 0.5f);
result.v[1] = 0.f;
result.v[2] = 0.f;
result.v[3] = cosf(angle * 0.5f);
return result;
}
Vector4f QuatFromRotateAroundY(float angle)
{
Vector4f result;
result.v[0] = 0.f;
result.v[1] = sinf(angle * 0.5f);
result.v[2] = 0.f;
result.v[3] = cosf(angle * 0.5f);
return result;
}
Vector4f QuatFromRotateAroundZ(float angle)
{
Vector4f result;
result.v[0] = 0.f;
result.v[1] = 0.f;
result.v[2] = sinf(angle * 0.5f);
result.v[3] = cosf(angle * 0.5f);
return result;
}
Matrix3f TransposeMatrix(const Matrix3f& m)
{
Matrix3f r;
r.m[0] = m.m[0];
r.m[1] = m.m[3];
r.m[2] = m.m[6];
r.m[3] = m.m[1];
r.m[4] = m.m[4];
r.m[5] = m.m[7];
r.m[6] = m.m[2];
r.m[7] = m.m[5];
r.m[8] = m.m[8];
return r;
}
Matrix3f InverseMatrix(const Matrix3f& m)
{
float d;
Matrix3f r;
d = m.m[0] * (m.m[4] * m.m[8] - m.m[5] * m.m[7]);
d -= m.m[1] * (m.m[3] * m.m[8] - m.m[6] * m.m[5]);
d += m.m[2] * (m.m[3] * m.m[7] - m.m[6] * m.m[4]);
if (fabs(d) < 0.01f)
{
throw std::runtime_error("Error: matrix cannot be inversed!");
}
else
{
r.m[0] = (m.m[4] * m.m[8] - m.m[5] * m.m[7]) / d;
r.m[1] = -(m.m[1] * m.m[8] - m.m[2] * m.m[7]) / d;
r.m[2] = (m.m[1] * m.m[5] - m.m[2] * m.m[4]) / d;
r.m[3] = -(m.m[3] * m.m[8] - m.m[5] * m.m[6]) / d;
r.m[4] = (m.m[0] * m.m[8] - m.m[2] * m.m[6]) / d;
r.m[5] = -(m.m[0] * m.m[5] - m.m[2] * m.m[3]) / d;
r.m[6] = (m.m[3] * m.m[7] - m.m[6] * m.m[4]) / d;
r.m[7] = -(m.m[0] * m.m[7] - m.m[6] * m.m[1]) / d;
r.m[8] = (m.m[0] * m.m[4] - m.m[1] * m.m[3]) / d;
};
return r;
}
Matrix4f InverseMatrix(const Matrix4f& mat)
{
Matrix4f inv;
float det;
inv.m[0] = mat.m[5] * mat.m[10] * mat.m[15] -
mat.m[5] * mat.m[11] * mat.m[14] -
mat.m[9] * mat.m[6] * mat.m[15] +
mat.m[9] * mat.m[7] * mat.m[14] +
mat.m[13] * mat.m[6] * mat.m[11] -
mat.m[13] * mat.m[7] * mat.m[10];
inv.m[4] = -mat.m[4] * mat.m[10] * mat.m[15] +
mat.m[4] * mat.m[11] * mat.m[14] +
mat.m[8] * mat.m[6] * mat.m[15] -
mat.m[8] * mat.m[7] * mat.m[14] -
mat.m[12] * mat.m[6] * mat.m[11] +
mat.m[12] * mat.m[7] * mat.m[10];
inv.m[8] = mat.m[4] * mat.m[9] * mat.m[15] -
mat.m[4] * mat.m[11] * mat.m[13] -
mat.m[8] * mat.m[5] * mat.m[15] +
mat.m[8] * mat.m[7] * mat.m[13] +
mat.m[12] * mat.m[5] * mat.m[11] -
mat.m[12] * mat.m[7] * mat.m[9];
inv.m[12] = -mat.m[4] * mat.m[9] * mat.m[14] +
mat.m[4] * mat.m[10] * mat.m[13] +
mat.m[8] * mat.m[5] * mat.m[14] -
mat.m[8] * mat.m[6] * mat.m[13] -
mat.m[12] * mat.m[5] * mat.m[10] +
mat.m[12] * mat.m[6] * mat.m[9];
inv.m[1] = -mat.m[1] * mat.m[10] * mat.m[15] +
mat.m[1] * mat.m[11] * mat.m[14] +
mat.m[9] * mat.m[2] * mat.m[15] -
mat.m[9] * mat.m[3] * mat.m[14] -
mat.m[13] * mat.m[2] * mat.m[11] +
mat.m[13] * mat.m[3] * mat.m[10];
inv.m[5] = mat.m[0] * mat.m[10] * mat.m[15] -
mat.m[0] * mat.m[11] * mat.m[14] -
mat.m[8] * mat.m[2] * mat.m[15] +
mat.m[8] * mat.m[3] * mat.m[14] +
mat.m[12] * mat.m[2] * mat.m[11] -
mat.m[12] * mat.m[3] * mat.m[10];
inv.m[9] = -mat.m[0] * mat.m[9] * mat.m[15] +
mat.m[0] * mat.m[11] * mat.m[13] +
mat.m[8] * mat.m[1] * mat.m[15] -
mat.m[8] * mat.m[3] * mat.m[13] -
mat.m[12] * mat.m[1] * mat.m[11] +
mat.m[12] * mat.m[3] * mat.m[9];
inv.m[13] = mat.m[0] * mat.m[9] * mat.m[14] -
mat.m[0] * mat.m[10] * mat.m[13] -
mat.m[8] * mat.m[1] * mat.m[14] +
mat.m[8] * mat.m[2] * mat.m[13] +
mat.m[12] * mat.m[1] * mat.m[10] -
mat.m[12] * mat.m[2] * mat.m[9];
inv.m[2] = mat.m[1] * mat.m[6] * mat.m[15] -
mat.m[1] * mat.m[7] * mat.m[14] -
mat.m[5] * mat.m[2] * mat.m[15] +
mat.m[5] * mat.m[3] * mat.m[14] +
mat.m[13] * mat.m[2] * mat.m[7] -
mat.m[13] * mat.m[3] * mat.m[6];
inv.m[6] = -mat.m[0] * mat.m[6] * mat.m[15] +
mat.m[0] * mat.m[7] * mat.m[14] +
mat.m[4] * mat.m[2] * mat.m[15] -
mat.m[4] * mat.m[3] * mat.m[14] -
mat.m[12] * mat.m[2] * mat.m[7] +
mat.m[12] * mat.m[3] * mat.m[6];
inv.m[10] = mat.m[0] * mat.m[5] * mat.m[15] -
mat.m[0] * mat.m[7] * mat.m[13] -
mat.m[4] * mat.m[1] * mat.m[15] +
mat.m[4] * mat.m[3] * mat.m[13] +
mat.m[12] * mat.m[1] * mat.m[7] -
mat.m[12] * mat.m[3] * mat.m[5];
inv.m[14] = -mat.m[0] * mat.m[5] * mat.m[14] +
mat.m[0] * mat.m[6] * mat.m[13] +
mat.m[4] * mat.m[1] * mat.m[14] -
mat.m[4] * mat.m[2] * mat.m[13] -
mat.m[12] * mat.m[1] * mat.m[6] +
mat.m[12] * mat.m[2] * mat.m[5];
inv.m[3] = -mat.m[1] * mat.m[6] * mat.m[11] +
mat.m[1] * mat.m[7] * mat.m[10] +
mat.m[5] * mat.m[2] * mat.m[11] -
mat.m[5] * mat.m[3] * mat.m[10] -
mat.m[9] * mat.m[2] * mat.m[7] +
mat.m[9] * mat.m[3] * mat.m[6];
inv.m[7] = mat.m[0] * mat.m[6] * mat.m[11] -
mat.m[0] * mat.m[7] * mat.m[10] -
mat.m[4] * mat.m[2] * mat.m[11] +
mat.m[4] * mat.m[3] * mat.m[10] +
mat.m[8] * mat.m[2] * mat.m[7] -
mat.m[8] * mat.m[3] * mat.m[6];
inv.m[11] = -mat.m[0] * mat.m[5] * mat.m[11] +
mat.m[0] * mat.m[7] * mat.m[9] +
mat.m[4] * mat.m[1] * mat.m[11] -
mat.m[4] * mat.m[3] * mat.m[9] -
mat.m[8] * mat.m[1] * mat.m[7] +
mat.m[8] * mat.m[3] * mat.m[5];
inv.m[15] = mat.m[0] * mat.m[5] * mat.m[10] -
mat.m[0] * mat.m[6] * mat.m[9] -
mat.m[4] * mat.m[1] * mat.m[10] +
mat.m[4] * mat.m[2] * mat.m[9] +
mat.m[8] * mat.m[1] * mat.m[6] -
mat.m[8] * mat.m[2] * mat.m[5];
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
det = mat.m[0] * inv.m[0] + mat.m[1] * inv.m[4] + mat.m[2] * inv.m[8] + mat.m[3] * inv.m[12];
if (std::fabs(det) < 0.01f)
{
throw std::runtime_error("Error: matrix cannot be inversed!");
}
// <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
det = 1.0f / det;
for (int i = 0; i < 16; i++)
{
inv.m[i] *= det;
}
return inv;
}
Matrix3f CreateZRotationMatrix(float angle)
{
Matrix3f result = Matrix3f::Identity();
result.m[0] = cosf(angle);
result.m[1] = -sinf(angle);
result.m[3] = sinf(angle);
result.m[4] = cosf(angle);
return result;
}
Matrix4f MultMatrixMatrix(const Matrix4f& m1, const Matrix4f& m2)
{
Matrix4f rx;
rx.m[0] = m1.m[0] * m2.m[0] + m1.m[4] * m2.m[1] + m1.m[8] * m2.m[2] + m1.m[12] * m2.m[3];
rx.m[1] = m1.m[1] * m2.m[0] + m1.m[5] * m2.m[1] + m1.m[9] * m2.m[2] + m1.m[13] * m2.m[3];
rx.m[2] = m1.m[2] * m2.m[0] + m1.m[6] * m2.m[1] + m1.m[10] * m2.m[2] + m1.m[14] * m2.m[3];
rx.m[3] = m1.m[3] * m2.m[0] + m1.m[7] * m2.m[1] + m1.m[11] * m2.m[2] + m1.m[15] * m2.m[3];
rx.m[4] = m1.m[0] * m2.m[4] + m1.m[4] * m2.m[5] + m1.m[8] * m2.m[6] + m1.m[12] * m2.m[7];
rx.m[5] = m1.m[1] * m2.m[4] + m1.m[5] * m2.m[5] + m1.m[9] * m2.m[6] + m1.m[13] * m2.m[7];
rx.m[6] = m1.m[2] * m2.m[4] + m1.m[6] * m2.m[5] + m1.m[10] * m2.m[6] + m1.m[14] * m2.m[7];
rx.m[7] = m1.m[3] * m2.m[4] + m1.m[7] * m2.m[5] + m1.m[11] * m2.m[6] + m1.m[15] * m2.m[7];
rx.m[8] = m1.m[0] * m2.m[8] + m1.m[4] * m2.m[9] + m1.m[8] * m2.m[10] + m1.m[12] * m2.m[11];
rx.m[9] = m1.m[1] * m2.m[8] + m1.m[5] * m2.m[9] + m1.m[9] * m2.m[10] + m1.m[13] * m2.m[11];
rx.m[10] = m1.m[2] * m2.m[8] + m1.m[6] * m2.m[9] + m1.m[10] * m2.m[10] + m1.m[14] * m2.m[11];
rx.m[11] = m1.m[3] * m2.m[8] + m1.m[7] * m2.m[9] + m1.m[11] * m2.m[10] + m1.m[15] * m2.m[11];
rx.m[12] = m1.m[0] * m2.m[12] + m1.m[4] * m2.m[13] + m1.m[8] * m2.m[14] + m1.m[12] * m2.m[15];
rx.m[13] = m1.m[1] * m2.m[12] + m1.m[5] * m2.m[13] + m1.m[9] * m2.m[14] + m1.m[13] * m2.m[15];
rx.m[14] = m1.m[2] * m2.m[12] + m1.m[6] * m2.m[13] + m1.m[10] * m2.m[14] + m1.m[14] * m2.m[15];
rx.m[15] = m1.m[3] * m2.m[12] + m1.m[7] * m2.m[13] + m1.m[11] * m2.m[14] + m1.m[15] * m2.m[15];
return rx;
}
Matrix3f MultMatrixMatrix(const Matrix3f& m1, const Matrix3f& m2)
{
Matrix3f r;
r.m[0] = m1.m[0] * m2.m[0] + m1.m[3] * m2.m[1] + m1.m[6] * m2.m[2];
r.m[1] = m1.m[1] * m2.m[0] + m1.m[4] * m2.m[1] + m1.m[7] * m2.m[2];
r.m[2] = m1.m[2] * m2.m[0] + m1.m[5] * m2.m[1] + m1.m[8] * m2.m[2];
r.m[3] = m1.m[0] * m2.m[3] + m1.m[3] * m2.m[4] + m1.m[6] * m2.m[5];
r.m[4] = m1.m[1] * m2.m[3] + m1.m[4] * m2.m[4] + m1.m[7] * m2.m[5];
r.m[5] = m1.m[2] * m2.m[3] + m1.m[5] * m2.m[4] + m1.m[8] * m2.m[5];
r.m[6] = m1.m[0] * m2.m[6] + m1.m[3] * m2.m[7] + m1.m[6] * m2.m[8] ;
r.m[7] = m1.m[1] * m2.m[6] + m1.m[4] * m2.m[7] + m1.m[7] * m2.m[8];
r.m[8] = m1.m[2] * m2.m[6] + m1.m[5] * m2.m[7] + m1.m[8] * m2.m[8];
return r;
}
Matrix3f MakeTranslationMatrix(const Vector3f& p)
{
Matrix3f r = Matrix3f::Identity();
r.m[12] = p.v[0];
r.m[13] = p.v[1];
r.m[14] = p.v[2];
return r;
}
Matrix3f MakeScaleMatrix(float scale)
{
Matrix3f r = Matrix3f::Identity();
r.m[0] = scale;
r.m[5] = scale;
r.m[10] = scale;
return r;
}
Matrix3f MakeRotationMatrix(const Vector3f& p)
{
Matrix3f r = Matrix3f::Identity();
r.m[12] = p.v[0];
r.m[13] = p.v[1];
r.m[14] = p.v[2];
return r;
}
Vector3f operator*(Vector3f v, float scale)
{
Vector3f r = v;
r.v[0] = v.v[0] * scale;
r.v[1] = v.v[1] * scale;
r.v[2] = v.v[2] * scale;
return r;
}
Vector4f operator*(Vector4f v, float scale)
{
Vector4f r = v;
r.v[0] = v.v[0] * scale;
r.v[1] = v.v[1] * scale;
r.v[2] = v.v[2] * scale;
r.v[3] = v.v[3] * scale;
return r;
}
Vector3f MultVectorMatrix(Vector3f v, Matrix3f mt)
{
Vector3f r;
r.v[0] = v.v[0] * mt.m[0] + v.v[1] * mt.m[1] + v.v[2] * mt.m[2];
r.v[1] = v.v[0] * mt.m[3] + v.v[1] * mt.m[4] + v.v[2] * mt.m[5];
r.v[2] = v.v[0] * mt.m[6] + v.v[1] * mt.m[7] + v.v[2] * mt.m[8];
return r;
}
Vector4f MultVectorMatrix(Vector4f v, Matrix4f mt)
{
Vector4f r;
r.v[0] = v.v[0] * mt.m[0] + v.v[1] * mt.m[1] + v.v[2] * mt.m[2] + v.v[3] * mt.m[3];
r.v[1] = v.v[0] * mt.m[4] + v.v[1] * mt.m[5] + v.v[2] * mt.m[6] + v.v[3] * mt.m[7];
r.v[2] = v.v[0] * mt.m[8] + v.v[1] * mt.m[9] + v.v[2] * mt.m[10] + v.v[3] * mt.m[11];
r.v[3] = v.v[0] * mt.m[12] + v.v[1] * mt.m[13] + v.v[2] * mt.m[14] + v.v[3] * mt.m[15];
return r;
}
Vector4f MultMatrixVector(Matrix4f mt, Vector4f v)
{
Vector4f r;
r.v[0] = v.v[0] * mt.m[0] + v.v[1] * mt.m[4] + v.v[2] * mt.m[8] + v.v[3] * mt.m[12];
r.v[1] = v.v[0] * mt.m[1] + v.v[1] * mt.m[5] + v.v[2] * mt.m[9] + v.v[3] * mt.m[13];
r.v[2] = v.v[0] * mt.m[2] + v.v[1] * mt.m[6] + v.v[2] * mt.m[10] + v.v[3] * mt.m[14];
r.v[3] = v.v[0] * mt.m[3] + v.v[1] * mt.m[7] + v.v[2] * mt.m[11] + v.v[3] * mt.m[15];
return r;
}
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, float t)
{
const float epsilon = 1e-6f;
// Нормализация входных кватернионов
Vector4f q1_norm = q1.normalized();
Vector4f q2_norm = q2.normalized();
float cosTheta = q1_norm.dot(q2_norm);
// Если q1 и q2 близки к противоположным направлениям, корректируем q2
Vector4f q2_adjusted = q2_norm;
if (cosTheta < 0.0f) {
q2_adjusted.v[0] = -q2_adjusted.v[0];
q2_adjusted.v[1] = -q2_adjusted.v[1];
q2_adjusted.v[2] = -q2_adjusted.v[2];
q2_adjusted.v[3] = -q2_adjusted.v[3];
cosTheta = -cosTheta;
}
// Если кватернионы близки, используем линейную интерполяцию
if (cosTheta > 1.0f - epsilon) {
Vector4f result;
result.v[0] = q1_norm.v[0] + t * (q2_adjusted.v[0] - q1_norm.v[0]);
result.v[1] = q1_norm.v[1] + t * (q2_adjusted.v[1] - q1_norm.v[1]);
result.v[2] = q1_norm.v[2] + t * (q2_adjusted.v[2] - q1_norm.v[2]);
result.v[3] = q1_norm.v[3] + t * (q2_adjusted.v[3] - q1_norm.v[3]);
return result.normalized();
}
// Иначе используем сферическую интерполяцию
float theta = std::acos(cosTheta);
float sinTheta = std::sin(theta);
float coeff1 = std::sin((1.0f - t) * theta) / sinTheta;
float coeff2 = std::sin(t * theta) / sinTheta;
Vector4f result;
result.v[0] = coeff1 * q1_norm.v[0] + coeff2 * q2_adjusted.v[0];
result.v[1] = coeff1 * q1_norm.v[1] + coeff2 * q2_adjusted.v[1];
result.v[2] = coeff1 * q1_norm.v[2] + coeff2 * q2_adjusted.v[2];
result.v[3] = coeff1 * q1_norm.v[3] + coeff2 * q2_adjusted.v[3];
return result.normalized();
}
Matrix4f MakeMatrix4x4(const Matrix3f& m, const Vector3f pos)
{
Matrix4f r;
r.m[0] = m.m[0];
r.m[1] = m.m[1];
r.m[2] = m.m[2];
r.m[3] = 0;
r.m[4] = m.m[3];
r.m[5] = m.m[4];
r.m[6] = m.m[5];
r.m[7] = 0;
r.m[8] = m.m[6];
r.m[9] = m.m[7];
r.m[10] = m.m[8];
r.m[11] = 0;
r.m[12] = pos.v[0];
r.m[13] = pos.v[1];
r.m[14] = pos.v[2];
r.m[15] = 1.0;
return r;
}
};

110
app/jni/src/Math.h Normal file
View File

@ -0,0 +1,110 @@
#pragma once
#include <array>
#include <exception>
#include <stdexcept>
#include <cmath>
namespace ZL {
struct Vector4f
{
std::array<float, 4> v = { 0.f, 0.f, 0.f, 0.f };
Vector4f normalized() const {
double norm = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
Vector4f r;
r.v[0] = v[0] / norm;
r.v[1] = v[1] / norm;
r.v[2] = v[2] / norm;
r.v[3] = v[3] / norm;
return r;
}
double dot(const Vector4f& other) const {
return v[0] * other.v[0] + v[1] * other.v[1] + v[2] * other.v[2] + v[3] * other.v[3];
}
};
struct Vector3f
{
std::array<float, 3> v = { 0.f, 0.f, 0.f };
};
struct Vector2f
{
std::array<float, 2> v = {0.f, 0.f};
};
Vector2f operator+(const Vector2f& x, const Vector2f& y);
Vector2f operator-(const Vector2f& x, const Vector2f& y);
Vector3f operator+(const Vector3f& x, const Vector3f& y);
Vector3f operator-(const Vector3f& x, const Vector3f& y);
Vector4f operator+(const Vector4f& x, const Vector4f& y);
Vector4f operator-(const Vector4f& x, const Vector4f& y);
struct Matrix3f
{
std::array<float, 9> m = { 0.f, 0.f, 0.f,
0.f, 0.f, 0.f,
0.f, 0.f, 0.f, };
static Matrix3f Identity();
};
struct Matrix4f
{
std::array<float, 16> m = { 0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f,
0.f, 0.f, 0.f, 0.f };
static Matrix4f Identity();
float& operator()(int row, int col) {
//return m[row * 4 + col]; //OpenGL specific
return m[col * 4 + row];
}
const float& operator()(int row, int col) const {
//return m[row * 4 + col];
return m[col * 4 + row];
}
};
Matrix4f operator*(const Matrix4f& m1, const Matrix4f& m2);
Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar);
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar);
Matrix3f QuatToMatrix(const Vector4f& q);
Vector4f MatrixToQuat(const Matrix3f& m);
Vector4f QuatFromRotateAroundX(float angle);
Vector4f QuatFromRotateAroundY(float angle);
Vector4f QuatFromRotateAroundZ(float angle);
Vector3f operator*(Vector3f v, float scale);
Vector4f operator*(Vector4f v, float scale);
Vector3f MultVectorMatrix(Vector3f v, Matrix3f mt);
Vector4f MultVectorMatrix(Vector4f v, Matrix4f mt);
Vector4f MultMatrixVector(Matrix4f mt, Vector4f v);
Vector4f slerp(const Vector4f& q1, const Vector4f& q2, float t);
Matrix3f InverseMatrix(const Matrix3f& m);
Matrix4f InverseMatrix(const Matrix4f& m);
Matrix3f MultMatrixMatrix(const Matrix3f& m1, const Matrix3f& m2);
Matrix4f MultMatrixMatrix(const Matrix4f& m1, const Matrix4f& m2);
Matrix4f MakeMatrix4x4(const Matrix3f& m, const Vector3f pos);
};

View File

@ -1,104 +1,8 @@
#include "render/Renderer.h" #include "Renderer.h"
#include <cmath> #include <cmath>
namespace ZL { namespace ZL {
Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar)
{
float depthRange = zFar - zNear;
if (depthRange <= 0)
{
throw std::runtime_error("zFar must be greater than zNear");
}
Matrix4f r;
r.data()[0] = 2.f / width;
r.data()[1] = 0;
r.data()[2] = 0;
r.data()[3] = 0;
r.data()[4] = 0;
r.data()[5] = 2.f / height;
r.data()[6] = 0;
r.data()[7] = 0;
r.data()[8] = 0;
r.data()[9] = 0;
r.data()[10] = -1 / depthRange;
r.data()[11] = 0;
r.data()[12] = -1;
r.data()[13] = -1;
r.data()[14] = zNear / depthRange;
r.data()[15] = 1;
return r;
}
Matrix4f MakeOrthoMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar)
{
float width = xmax - xmin;
float height = ymax - ymin;
float depthRange = zFar - zNear;
if (width <= 0 || height <= 0 || depthRange <= 0)
{
throw std::runtime_error("Invalid dimensions for orthogonal matrix");
}
Matrix4f r;
r.data()[0] = 2.f / width;
r.data()[5] = 2.f / height;
r.data()[10] = -1.f / depthRange;
r.data()[1] = r.data()[2] = r.data()[3] = 0;
r.data()[4] = r.data()[6] = r.data()[7] = 0;
r.data()[8] = r.data()[9] = r.data()[11] = 0;
r.data()[12] = -(xmax + xmin) / width;
r.data()[13] = -(ymax + ymin) / height;
r.data()[14] = zNear / depthRange;
r.data()[15] = 1.f;
return r;
}
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar)
{
float tanHalfFovy = tan(fovY / 2.f);
Matrix4f r;
if (zNear >= zFar || aspectRatio == 0)
{
throw std::runtime_error("Invalid perspective parameters");
}
r.data()[0] = 1.f / (aspectRatio * tanHalfFovy);
r.data()[1] = 0;
r.data()[2] = 0;
r.data()[3] = 0;
r.data()[4] = 0;
r.data()[5] = 1.f / (tanHalfFovy);
r.data()[6] = 0;
r.data()[7] = 0;
r.data()[8] = 0;
r.data()[9] = 0;
r.data()[10] = -(zFar + zNear) / (zFar - zNear);
r.data()[11] = -1;
r.data()[12] = 0;
r.data()[13] = 0;
r.data()[14] = -(2.f * zFar * zNear) / (zFar - zNear);
r.data()[15] = 0;
return r;
}
VBOHolder::VBOHolder() VBOHolder::VBOHolder()
{ {
glGenBuffers(1, &Buffer); glGenBuffers(1, &Buffer);
@ -117,8 +21,10 @@ namespace ZL {
VAOHolder::VAOHolder() VAOHolder::VAOHolder()
{ {
#ifndef EMSCRIPTEN #ifndef EMSCRIPTEN
#ifndef ANDROID #if defined(_WIN32) || defined(__linux__) && !defined(__ANDROID__)
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &vao);
#else
vao = 0;
#endif #endif
#endif #endif
} }
@ -126,13 +32,8 @@ namespace ZL {
VAOHolder::~VAOHolder() VAOHolder::~VAOHolder()
{ {
#ifndef EMSCRIPTEN #ifndef EMSCRIPTEN
#ifndef ANDROID #if defined(_WIN32) || defined(__linux__) && !defined(__ANDROID__)
#ifdef __linux__ glDeleteVertexArrays(1, &vao);
glDeleteVertexArrays(1, &vao);
#else
//Windows
glDeleteVertexArray(1, &vao);
#endif
#endif #endif
#endif #endif
} }
@ -149,10 +50,10 @@ namespace ZL {
Vector2f posTo = center + halfWidthHeight; Vector2f posTo = center + halfWidthHeight;
Vector3f pos1 = { posFrom(0), posFrom(1), zLevel }; Vector3f pos1 = { posFrom.v[0], posFrom.v[1], zLevel };
Vector3f pos2 = { posFrom(0), posTo(1), zLevel }; Vector3f pos2 = { posFrom.v[0], posTo.v[1], zLevel };
Vector3f pos3 = { posTo(0), posTo(1), zLevel }; Vector3f pos3 = { posTo.v[0], posTo.v[1], zLevel };
Vector3f pos4 = { posTo(0), posFrom(1), zLevel }; Vector3f pos4 = { posTo.v[0], posFrom.v[1], zLevel };
Vector2f texCoordPos1 = { 0.0f, 0.0f }; Vector2f texCoordPos1 = { 0.0f, 0.0f };
@ -185,16 +86,16 @@ namespace ZL {
Vector2f posTo = center + halfWidthHeight; Vector2f posTo = center + halfWidthHeight;
float sectionWidth = halfWidthHeight(0) * 2.f; float sectionWidth = halfWidthHeight.v[0] * 2.f;
VertexDataStruct result; VertexDataStruct result;
for (size_t i = 0; i < sectionCount; i++) for (size_t i = 0; i < sectionCount; i++)
{ {
Vector3f pos1 = { posFrom(0)+sectionWidth*i, posFrom(1), zLevel }; Vector3f pos1 = { posFrom.v[0]+sectionWidth*i, posFrom.v[1], zLevel };
Vector3f pos2 = { posFrom(0) + sectionWidth * i, posTo(1), zLevel }; Vector3f pos2 = { posFrom.v[0] + sectionWidth * i, posTo.v[1], zLevel };
Vector3f pos3 = { posTo(0) + sectionWidth * i, posTo(1), zLevel }; Vector3f pos3 = { posTo.v[0] + sectionWidth * i, posTo.v[1], zLevel };
Vector3f pos4 = { posTo(0) + sectionWidth * i, posFrom(1), zLevel }; Vector3f pos4 = { posTo.v[0] + sectionWidth * i, posFrom.v[1], zLevel };
result.PositionData.push_back(pos1); result.PositionData.push_back(pos1);
result.PositionData.push_back(pos2); result.PositionData.push_back(pos2);
@ -295,83 +196,17 @@ namespace ZL {
return result; return result;
} }
VertexDataStruct CreateCubemap(float scale)
{
VertexDataStruct cubemapVertexDataStruct;
// +x
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale });
// -x
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale });
// +y
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale });
// -y
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale });
// +z
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale });
// -z
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale });
cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale });
return cubemapVertexDataStruct;
}
void VertexRenderStruct::RefreshVBO() void VertexRenderStruct::RefreshVBO()
{ {
//Check if main thread, check if data is not empty... //Check if main thread, check if data is not empty...
#ifndef EMSCRIPTEN #ifndef EMSCRIPTEN
#ifndef __ANDROID__ #if defined(_WIN32) || defined(__linux__) && !defined(__ANDROID__)
if (!vao) if (!vao)
{ {
vao = std::make_shared<VAOHolder>(); vao = std::make_shared<VAOHolder>();
} }
glBindVertexArray(vao->getBuffer());
glBindVertexArray(vao->getBuffer());
#endif #endif
#endif #endif
if (!positionVBO) if (!positionVBO)
@ -381,7 +216,7 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, positionVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, positionVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.PositionData.size() * 12, &data.PositionData[0], GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.PositionData.size() * 12, &data.PositionData[0], GL_STATIC_DRAW);
if (data.TexCoordData.size() > 0) if (data.TexCoordData.size() > 0)
{ {
@ -392,9 +227,10 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, texCoordVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, texCoordVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.TexCoordData.size() * 8, &data.TexCoordData[0], GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.TexCoordData.size() * 8, &data.TexCoordData[0], GL_STATIC_DRAW);
} }
if (data.NormalData.size() > 0) if (data.NormalData.size() > 0)
{ {
if (!normalVBO) if (!normalVBO)
@ -404,7 +240,7 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, normalVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, normalVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.NormalData.size() * 12, &data.NormalData[0], GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.NormalData.size() * 12, &data.NormalData[0], GL_STATIC_DRAW);
} }
if (data.TangentData.size() > 0) if (data.TangentData.size() > 0)
@ -416,7 +252,7 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, tangentVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, tangentVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.TangentData.size() * 12, &data.TangentData[0], GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.TangentData.size() * 12, &data.TangentData[0], GL_STATIC_DRAW);
} }
if (data.BinormalData.size() > 0) if (data.BinormalData.size() > 0)
@ -428,7 +264,7 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, binormalVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, binormalVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.BinormalData.size() * 12, &data.BinormalData[0], GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.BinormalData.size() * 12, &data.BinormalData[0], GL_STATIC_DRAW);
} }
if (data.ColorData.size() > 0) if (data.ColorData.size() > 0)
@ -440,7 +276,7 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, colorVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, colorVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.ColorData.size() * 12, &data.ColorData[0], GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.ColorData.size() * 12, &data.ColorData[0], GL_STATIC_DRAW);
} }
} }
@ -463,9 +299,9 @@ namespace ZL {
{ {
for (int i = 0; i < PositionData.size(); i++) for (int i = 0; i < PositionData.size(); i++)
{ {
auto value = PositionData[i](1); auto value = PositionData[i].v[1];
PositionData[i](1) = PositionData[i](2); PositionData[i].v[1] = PositionData[i].v[2];
PositionData[i](2) = value; PositionData[i].v[2] = value;
} }
} }
@ -475,22 +311,22 @@ namespace ZL {
for (int i = 0; i < PositionData.size(); i++) for (int i = 0; i < PositionData.size(); i++)
{ {
PositionData[i] = PositionData[i].transpose() * m; PositionData[i] = MultVectorMatrix(PositionData[i], m);
} }
for (int i = 0; i < NormalData.size(); i++) for (int i = 0; i < NormalData.size(); i++)
{ {
NormalData[i] = NormalData[i].transpose() * m; NormalData[i] = MultVectorMatrix(NormalData[i], m);
} }
for (int i = 0; i < TangentData.size(); i++) for (int i = 0; i < TangentData.size(); i++)
{ {
TangentData[i] = TangentData[i].transpose() * m; TangentData[i] = MultVectorMatrix(TangentData[i], m);
} }
for (int i = 0; i < BinormalData.size(); i++) for (int i = 0; i < BinormalData.size(); i++)
{ {
BinormalData[i] = BinormalData[i].transpose() * m; BinormalData[i] = MultVectorMatrix(BinormalData[i], m);
} }
} }
@ -511,14 +347,14 @@ namespace ZL {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
#ifndef EMSCRIPTEN #ifndef EMSCRIPTEN
#ifndef __ANDROID__ #if defined(_WIN32) || defined(__linux__) && !defined(__ANDROID__)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif #endif
#endif #endif
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
CheckGlError(); //CheckGlError();
} }
void Renderer::PushProjectionMatrix(float width, float height, float zNear, float zFar) void Renderer::PushProjectionMatrix(float width, float height, float zNear, float zFar)
@ -533,18 +369,6 @@ namespace ZL {
} }
} }
void Renderer::PushProjectionMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar)
{
Matrix4f m = MakeOrthoMatrix(xmin, xmax, ymin, ymax, zNear, zFar);
ProjectionMatrixStack.push(m);
SetMatrix();
if (ProjectionMatrixStack.size() > CONST_MATRIX_STACK_SIZE)
{
throw std::runtime_error("Projection matrix stack overflow!!!!");
}
}
void Renderer::PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar) void Renderer::PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar)
{ {
Matrix4f m = MakePerspectiveMatrix(fovY, aspectRatio, zNear, zFar); Matrix4f m = MakePerspectiveMatrix(fovY, aspectRatio, zNear, zFar);
@ -573,12 +397,6 @@ namespace ZL {
return ProjectionModelViewMatrix; return ProjectionModelViewMatrix;
} }
Matrix4f Renderer::GetCurrentModelViewMatrix()
{
return ModelviewMatrixStack.top();
}
void Renderer::SetMatrix() void Renderer::SetMatrix()
{ {
if (ProjectionMatrixStack.size() <= 0) if (ProjectionMatrixStack.size() <= 0)
@ -591,16 +409,15 @@ namespace ZL {
throw std::runtime_error("Modelview matrix stack out!"); throw std::runtime_error("Modelview matrix stack out!");
} }
Matrix4f& modelViewMatrix = ModelviewMatrixStack.top(); ProjectionModelViewMatrix = ProjectionMatrixStack.top() * ModelviewMatrixStack.top();
ProjectionModelViewMatrix = ProjectionMatrixStack.top() * modelViewMatrix;
static const std::string ProjectionModelViewMatrixName = "ProjectionModelViewMatrix"; static const std::string ProjectionModelViewMatrixName = "ProjectionModelViewMatrix";
RenderUniformMatrix4fv(ProjectionModelViewMatrixName, false, ProjectionModelViewMatrix.data()); //static const std::string ProjectionMatrixName = "ProjectionMatrix";
static const std::string ModelViewMatrixName = "ModelViewMatrix"; RenderUniformMatrix4fv(ProjectionModelViewMatrixName, false, &ProjectionModelViewMatrix.m[0]);
RenderUniformMatrix4fv(ModelViewMatrixName, false, modelViewMatrix.data()); //RenderUniformMatrix4fv(ProjectionMatrixName, false, &ProjectionMatrixStack.top().m[0]);
} }
@ -617,7 +434,6 @@ namespace ZL {
{ {
throw std::runtime_error("Modelview matrix stack overflow!!!!"); throw std::runtime_error("Modelview matrix stack overflow!!!!");
} }
SetMatrix();
} }
void Renderer::LoadIdentity() void Renderer::LoadIdentity()
@ -637,9 +453,9 @@ namespace ZL {
{ {
Matrix4f m = Matrix4f::Identity(); Matrix4f m = Matrix4f::Identity();
m.data()[12] = p(0); m.m[12] = p.v[0];
m.data()[13] = p(1); m.m[13] = p.v[1];
m.data()[14] = p(2); m.m[14] = p.v[2];
m = ModelviewMatrixStack.top() * m; m = ModelviewMatrixStack.top() * m;
@ -657,9 +473,9 @@ namespace ZL {
void Renderer::ScaleMatrix(float scale) void Renderer::ScaleMatrix(float scale)
{ {
Matrix4f m = Matrix4f::Identity(); Matrix4f m = Matrix4f::Identity();
m.data()[0] = scale; m.m[0] = scale;
m.data()[5] = scale; m.m[5] = scale;
m.data()[10] = scale; m.m[10] = scale;
m = ModelviewMatrixStack.top() * m; m = ModelviewMatrixStack.top() * m;
@ -677,9 +493,9 @@ namespace ZL {
void Renderer::ScaleMatrix(const Vector3f& scale) void Renderer::ScaleMatrix(const Vector3f& scale)
{ {
Matrix4f m = Matrix4f::Identity(); Matrix4f m = Matrix4f::Identity();
m.data()[0] = scale(0); m.m[0] = scale.v[0];
m.data()[5] = scale(1); m.m[5] = scale.v[1];
m.data()[10] = scale(2); m.m[10] = scale.v[2];
m = ModelviewMatrixStack.top() * m; m = ModelviewMatrixStack.top() * m;
@ -694,33 +510,22 @@ namespace ZL {
SetMatrix(); SetMatrix();
} }
void Renderer::RotateMatrix(const Eigen::Quaternionf& q) void Renderer::RotateMatrix(const Vector4f& q)
{ {
Matrix3f m3 = q.toRotationMatrix(); Matrix3f m3 = QuatToMatrix(q);
Matrix4f m = Matrix4f::Identity(); Matrix4f m = Matrix4f::Identity();
m.m[0] = m3.m[0];
m.m[1] = m3.m[1];
m.m[2] = m3.m[2];
m.block<3, 3>(0, 0) = m3; m.m[4] = m3.m[3];
m.m[5] = m3.m[4];
m.m[6] = m3.m[5];
m = ModelviewMatrixStack.top() * m; m.m[8] = m3.m[6];
m.m[9] = m3.m[7];
if (ModelviewMatrixStack.size() == 0) m.m[10] = m3.m[8];
{
throw std::runtime_error("Modelview matrix stack underflow!!!!");
}
ModelviewMatrixStack.pop();
ModelviewMatrixStack.push(m);
SetMatrix();
}
void Renderer::RotateMatrix(const Matrix3f& m3)
{
Matrix4f m = Matrix4f::Identity();
m.block<3, 3>(0, 0) = m3;
m = ModelviewMatrixStack.top() * m; m = ModelviewMatrixStack.top() * m;
@ -758,16 +563,20 @@ namespace ZL {
SetMatrix(); SetMatrix();
} }
void Renderer::RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value)
void Renderer::EnableVertexAttribArray(const std::string& attribName)
{
auto shader = shaderManager.GetCurrentShader();
if (shader->attribList.find(attribName) != shader->attribList.end())
glEnableVertexAttribArray(shader->attribList[attribName]);
}
void Renderer::DisableVertexAttribArray(const std::string& attribName)
{ {
auto shader = shaderManager.GetCurrentShader(); auto shader = shaderManager.GetCurrentShader();
if (shader->attribList.find(attribName) != shader->attribList.end())
auto uniform = shader->uniformList.find(uniformName); glDisableVertexAttribArray(shader->attribList[attribName]);
if (uniform != shader->uniformList.end())
{
glUniformMatrix3fv(uniform->second, 1, transpose, value);
}
} }
@ -795,15 +604,6 @@ namespace ZL {
} }
} }
void Renderer::RenderUniform4fv(const std::string& uniformName, const float* value)
{
auto shader = shaderManager.GetCurrentShader();
auto uniform = shader->uniformList.find(uniformName);
if (uniform != shader->uniformList.end()) {
glUniform4fv(uniform->second, 1, value);
}
}
void Renderer::RenderUniform1i(const std::string& uniformName, const int value) void Renderer::RenderUniform1i(const std::string& uniformName, const int value)
{ {
auto shader = shaderManager.GetCurrentShader(); auto shader = shaderManager.GetCurrentShader();
@ -817,18 +617,6 @@ namespace ZL {
} }
void Renderer::RenderUniform1f(const std::string& uniformName, float value)
{
auto shader = shaderManager.GetCurrentShader();
auto uniform = shader->uniformList.find(uniformName);
if (uniform != shader->uniformList.end())
{
glUniform1fv(uniform->second, 1, &value);
}
}
void Renderer::VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer) void Renderer::VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer)
@ -847,25 +635,8 @@ namespace ZL {
glVertexAttribPointer(shader->attribList[attribName], 3, GL_FLOAT, GL_FALSE, stride, pointer); glVertexAttribPointer(shader->attribList[attribName], 3, GL_FLOAT, GL_FALSE, stride, pointer);
} }
void Renderer::DisableVertexAttribArray(const std::string& attribName)
{
auto shader = shaderManager.GetCurrentShader();
auto it = shader->attribList.find(attribName);
if (it != shader->attribList.end())
glDisableVertexAttribArray(it->second);
}
void Renderer::DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct) void Renderer::DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct)
{ {
#ifndef EMSCRIPTEN
#ifndef __ANDROID__
if (VertexRenderStruct.vao) {
glBindVertexArray(VertexRenderStruct.vao->getBuffer());
shaderManager.EnableVertexAttribArrays();
}
#endif
#endif
static const std::string vNormal("vNormal"); static const std::string vNormal("vNormal");
static const std::string vTangent("vTangent"); static const std::string vTangent("vTangent");
static const std::string vBinormal("vBinormal"); static const std::string vBinormal("vBinormal");
@ -873,57 +644,40 @@ namespace ZL {
static const std::string vTexCoord("vTexCoord"); static const std::string vTexCoord("vTexCoord");
static const std::string vPosition("vPosition"); static const std::string vPosition("vPosition");
// On WebGL (and when not using VAO), vertex attribute arrays must be explicitly //glBindVertexArray(VertexRenderStruct.vao->getBuffer());
// enabled before drawing. Desktop with VAO can rely on stored state; WebGL cannot.
//Check if main thread, check if data is not empty...
if (VertexRenderStruct.data.NormalData.size() > 0) if (VertexRenderStruct.data.NormalData.size() > 0)
{ {
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.normalVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.normalVBO->getBuffer());
VertexAttribPointer3fv(vNormal, 0, NULL); VertexAttribPointer3fv(vNormal, 0, NULL);
} }
else
{
DisableVertexAttribArray(vNormal);
}
if (VertexRenderStruct.data.TangentData.size() > 0) if (VertexRenderStruct.data.TangentData.size() > 0)
{ {
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.tangentVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.tangentVBO->getBuffer());
VertexAttribPointer3fv(vTangent, 0, NULL); VertexAttribPointer3fv(vTangent, 0, NULL);
} }
else
{
DisableVertexAttribArray(vTangent);
}
if (VertexRenderStruct.data.BinormalData.size() > 0) if (VertexRenderStruct.data.BinormalData.size() > 0)
{ {
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.binormalVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.binormalVBO->getBuffer());
VertexAttribPointer3fv(vBinormal, 0, NULL); VertexAttribPointer3fv(vBinormal, 0, NULL);
} }
else
{
DisableVertexAttribArray(vBinormal);
}
if (VertexRenderStruct.data.ColorData.size() > 0) if (VertexRenderStruct.data.ColorData.size() > 0)
{ {
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.colorVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.colorVBO->getBuffer());
VertexAttribPointer3fv(vColor, 0, NULL); VertexAttribPointer3fv(vColor, 0, NULL);
} }
else
{
DisableVertexAttribArray(vColor);
}
if (VertexRenderStruct.data.TexCoordData.size() > 0) if (VertexRenderStruct.data.TexCoordData.size() > 0)
{ {
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoordVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoordVBO->getBuffer());
VertexAttribPointer2fv(vTexCoord, 0, NULL); VertexAttribPointer2fv(vTexCoord, 0, NULL);
} }
else
{
DisableVertexAttribArray(vTexCoord);
}
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.positionVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.positionVBO->getBuffer());
VertexAttribPointer3fv(vPosition, 0, NULL); VertexAttribPointer3fv(vPosition, 0, NULL);
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(VertexRenderStruct.data.PositionData.size())); glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(VertexRenderStruct.data.PositionData.size()));
} }
void worldToScreenCoordinates(Vector3f objectPos, void worldToScreenCoordinates(Vector3f objectPos,
@ -931,11 +685,11 @@ namespace ZL {
int screenWidth, int screenHeight, int screenWidth, int screenHeight,
int& screenX, int& screenY) { int& screenX, int& screenY) {
Vector4f inx = { objectPos(0), objectPos(1), objectPos(2), 1.0f }; Vector4f inx = { objectPos.v[0], objectPos.v[1], objectPos.v[2], 1.0f };
Vector4f clipCoords = projectionModelView * inx; Vector4f clipCoords = MultMatrixVector(projectionModelView, inx);
float ndcX = clipCoords(0) / clipCoords(3); float ndcX = clipCoords.v[0] / clipCoords.v[3];
float ndcY = clipCoords(1) / clipCoords(3); float ndcY = clipCoords.v[1] / clipCoords.v[3];
screenX = (int)((ndcX + 1.0f) * 0.5f * screenWidth); screenX = (int)((ndcX + 1.0f) * 0.5f * screenWidth);
screenY = (int)((1.0f + ndcY) * 0.5f * screenHeight); screenY = (int)((1.0f + ndcY) * 0.5f * screenHeight);

View File

@ -1,27 +1,15 @@
#pragma once #pragma once
#include "render/OpenGlExtensions.h"
//#include "OpenGlExtensions.h"
#include "Math.h"
#include <exception> #include <exception>
#include <stdexcept> #include <stdexcept>
#include "ShaderManager.h" #include "ShaderManager.h"
#include <Eigen/Dense> #include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
namespace ZL { namespace ZL {
using Eigen::Vector2f;
using Eigen::Vector3f;
using Eigen::Vector4f;
using Eigen::Matrix3f;
using Eigen::Matrix4f;
Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar);
Matrix4f MakeOrthoMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar);
Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar);
constexpr size_t CONST_MATRIX_STACK_SIZE = 64; constexpr size_t CONST_MATRIX_STACK_SIZE = 64;
class VBOHolder { class VBOHolder {
@ -89,7 +77,6 @@ namespace ZL {
VertexDataStruct CreateRect2D(Vector2f center, Vector2f halfWidthHeight, float zLevel); VertexDataStruct CreateRect2D(Vector2f center, Vector2f halfWidthHeight, float zLevel);
VertexDataStruct CreateRectHorizontalSections2D(Vector2f center, Vector2f halfWidthHeight, float zLevel, size_t sectionCount); VertexDataStruct CreateRectHorizontalSections2D(Vector2f center, Vector2f halfWidthHeight, float zLevel, size_t sectionCount);
VertexDataStruct CreateCube3D(float scale); VertexDataStruct CreateCube3D(float scale);
VertexDataStruct CreateCubemap(float scale = 1000.f);
class Renderer class Renderer
@ -107,7 +94,6 @@ namespace ZL {
void InitOpenGL(); void InitOpenGL();
void PushProjectionMatrix(float width, float height, float zNear = 0.f, float zFar = 1.f); void PushProjectionMatrix(float width, float height, float zNear = 0.f, float zFar = 1.f);
void PushProjectionMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar);
void PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar); void PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar);
void PopProjectionMatrix(); void PopProjectionMatrix();
@ -116,30 +102,31 @@ namespace ZL {
void TranslateMatrix(const Vector3f& p); void TranslateMatrix(const Vector3f& p);
void ScaleMatrix(float scale); void ScaleMatrix(float scale);
void ScaleMatrix(const Vector3f& scale); void ScaleMatrix(const Vector3f& scale);
void RotateMatrix(const Eigen::Quaternionf& q); void RotateMatrix(const Vector4f& q);
void RotateMatrix(const Matrix3f& m3);
void PushSpecialMatrix(const Matrix4f& m); void PushSpecialMatrix(const Matrix4f& m);
void PopMatrix(); void PopMatrix();
Matrix4f GetProjectionModelViewMatrix(); Matrix4f GetProjectionModelViewMatrix();
Matrix4f GetCurrentModelViewMatrix();
void SetMatrix(); void SetMatrix();
void RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value);
void EnableVertexAttribArray(const std::string& attribName);
void DisableVertexAttribArray(const std::string& attribName);
void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value); void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value);
void RenderUniform1i(const std::string& uniformName, const int value); void RenderUniform1i(const std::string& uniformName, const int value);
void RenderUniform3fv(const std::string& uniformName, const float* value); void RenderUniform3fv(const std::string& uniformName, const float* value);
void RenderUniform4fv(const std::string& uniformName, const float* value);
void RenderUniform1f(const std::string& uniformName, float value);
void VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer); void VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer);
void VertexAttribPointer3fv(const std::string& attribName, int stride, const char* pointer); void VertexAttribPointer3fv(const std::string& attribName, int stride, const char* pointer);
void DisableVertexAttribArray(const std::string& attribName);
void DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct); void DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct);
}; };

View File

@ -1,4 +1,4 @@
#include "ShaderManager.h" #include "ShaderManager.h"
#include <iostream> #include <iostream>
#include <SDL.h> #include <SDL.h>
@ -14,8 +14,7 @@ namespace ZL {
char infoLog[CONST_INFOLOG_LENGTH]; char infoLog[CONST_INFOLOG_LENGTH];
int infoLogLength; int infoLogLength;
char infoLog2[CONST_INFOLOG_LENGTH];
int infoLogLength2;
int vertexShaderCompiled; int vertexShaderCompiled;
int fragmentShaderCompiled; int fragmentShaderCompiled;
int programLinked; int programLinked;
@ -41,13 +40,12 @@ namespace ZL {
glCompileShader(fragmentShader); glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled); glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentShaderCompiled);
glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength2, infoLog2); glGetShaderInfoLog(fragmentShader, CONST_INFOLOG_LENGTH, &infoLogLength, infoLog);
if (!vertexShaderCompiled) { if (!vertexShaderCompiled) {
#ifdef __ANDROID__ #ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "ShaderManager", __android_log_print(ANDROID_LOG_ERROR, "ShaderManager",
"Failed to compile vertex shader: %s", infoLog); "Failed to compile vertex shader: %s", infoLog);
#endif #endif
throw std::runtime_error("Failed to compile vertex shader code!"); throw std::runtime_error("Failed to compile vertex shader code!");
} }
@ -55,7 +53,7 @@ namespace ZL {
if (!fragmentShaderCompiled) { if (!fragmentShaderCompiled) {
#ifdef __ANDROID__ #ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "ShaderManager", __android_log_print(ANDROID_LOG_ERROR, "ShaderManager",
"Failed to compile fragment shader: %s", infoLog); "Failed to compile fragment shader: %s", infoLog);
#endif #endif
throw std::runtime_error("Failed to compile fragment shader code!"); throw std::runtime_error("Failed to compile fragment shader code!");
} }
@ -77,7 +75,7 @@ namespace ZL {
shaderProgram = 0; shaderProgram = 0;
#ifdef __ANDROID__ #ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "ShaderManager", __android_log_print(ANDROID_LOG_ERROR, "ShaderManager",
"Failed to link shader program: %s", infoLog); "Failed to link shader program: %s", infoLog);
#endif #endif
throw std::runtime_error("Failed to link shader program!"); throw std::runtime_error("Failed to link shader program!");
} }
@ -118,7 +116,7 @@ namespace ZL {
#ifdef __ANDROID__ #ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "ShaderManager", __android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Shader created successfully, program ID: %u", shaderProgram); "Shader created successfully, program ID: %u", shaderProgram);
#endif #endif
} }
@ -141,11 +139,11 @@ namespace ZL {
const std::string &ZIPFileName) { const std::string &ZIPFileName) {
#ifdef __ANDROID__ #ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "ShaderManager", __android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Loading shader: %s", shaderName.c_str()); "Loading shader: %s", shaderName.c_str());
__android_log_print(ANDROID_LOG_INFO, "ShaderManager", __android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Vertex shader: %s", vertexShaderFileName.c_str()); "Vertex shader: %s", vertexShaderFileName.c_str());
__android_log_print(ANDROID_LOG_INFO, "ShaderManager", __android_log_print(ANDROID_LOG_INFO, "ShaderManager",
"Fragment shader: %s", fragmentShaderFileName.c_str()); "Fragment shader: %s", fragmentShaderFileName.c_str());
#endif #endif
std::string vertexShader; std::string vertexShader;
@ -167,6 +165,7 @@ namespace ZL {
fragmentShader = readTextFile(fragmentShaderFileName); fragmentShader = readTextFile(fragmentShaderFileName);
} }
///std::cout << "Shader: "<< vertexShader << std::endl;
shaderResourceMap[shaderName] = std::make_shared<ShaderResource>(vertexShader, shaderResourceMap[shaderName] = std::make_shared<ShaderResource>(vertexShader,
fragmentShader); fragmentShader);
} }
@ -180,26 +179,9 @@ namespace ZL {
throw std::runtime_error("Shader does not exist!"); throw std::runtime_error("Shader does not exist!");
} }
if (shaderStack.size() > 0)
{
auto& prevShaderAttribList = shaderResourceMap[shaderStack.top()]->attribList;
for (auto& attrib : prevShaderAttribList)
{
glDisableVertexAttribArray(attrib.second);
}
}
shaderStack.push(shaderName); shaderStack.push(shaderName);
auto& shaderResource = shaderResourceMap[shaderName]; glUseProgram(shaderResourceMap[shaderName]->getShaderProgram());
glUseProgram(shaderResource->getShaderProgram());
auto& shaderAttribList = shaderResource->attribList;
for (auto& attrib : shaderAttribList)
{
glEnableVertexAttribArray(attrib.second);
}
} }
@ -208,39 +190,12 @@ namespace ZL {
throw std::runtime_error("Shader stack underflow!"); throw std::runtime_error("Shader stack underflow!");
} }
auto& prevShaderAttribList = shaderResourceMap[shaderStack.top()]->attribList;
for (auto& attrib : prevShaderAttribList)
{
glDisableVertexAttribArray(attrib.second);
}
shaderStack.pop(); shaderStack.pop();
if (shaderStack.size() == 0) { if (shaderStack.size() == 0) {
glUseProgram(0); glUseProgram(0);
} else { } else {
auto& shaderResource = shaderResourceMap[shaderStack.top()]; glUseProgram(shaderResourceMap[shaderStack.top()]->getShaderProgram());
glUseProgram(shaderResource->getShaderProgram());
auto& shaderAttribList = shaderResource->attribList;
for (auto& attrib : shaderAttribList)
{
glEnableVertexAttribArray(attrib.second);
}
}
}
void ShaderManager::EnableVertexAttribArrays()
{
if (shaderStack.size() != 0) {
auto& shaderResource = shaderResourceMap[shaderStack.top()];
auto& shaderAttribList = shaderResource->attribList;
for (auto& attrib : shaderAttribList)
{
glEnableVertexAttribArray(attrib.second);
}
} }
} }

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
//#include "OpenGlExtensions.h"
#include "render/OpenGlExtensions.h" #include "Utils.h"
#include "utils/Utils.h" #include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
namespace ZL { namespace ZL {
@ -42,7 +43,6 @@ namespace ZL {
void PushShader(const std::string& shaderName); void PushShader(const std::string& shaderName);
void PopShader(); void PopShader();
void EnableVertexAttribArrays();
std::shared_ptr<ShaderResource> GetCurrentShader(); std::shared_ptr<ShaderResource> GetCurrentShader();
}; };

397
app/jni/src/TextModel.cpp Normal file
View File

@ -0,0 +1,397 @@
#include "TextModel.h"
#include <regex>
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#ifdef __ANDROID__
#include <android/log.h>
#endif
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;
}
vertices[i] = Vector3f{floatValues[0], floatValues[1], floatValues[2]};
}
std::cout << "UV Coordinates" << std::endl;
std::getline(f, tempLine); //===UV Coordinates:
std::getline(f, tempLine); //triangle count
int numberTriangles;
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.");
}
// Now process UVs
std::vector <std::array<Vector2f, 3>> uvCoords;
uvCoords.resize(numberTriangles);
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.");
}
if (uvCount != 3) {
throw std::runtime_error("more than 3 uvs");
}
std::vector<float> floatValues;
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;
}
if (floatValues.size() != 2) {
throw std::runtime_error("more than 2 uvs---");
}
uvCoords[i][j] = Vector2f{floatValues[0], floatValues[1]};
}
}
std::cout << "Normals go" << std::endl;
std::getline(f, tempLine); //===Normals:
std::vector <Vector3f> normals;
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;
}
}

18
app/jni/src/TextModel.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "Math.h"
#include "Renderer.h"
#include <unordered_map>
#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

@ -0,0 +1,285 @@
#include "TextureManager.h"
#ifdef PNG_ENABLED
#include "png.h"
#endif
namespace ZL
{
Texture::Texture(const TextureDataStruct& texData)
{
width = texData.width;
height = texData.height;
glGenTextures(1, &texID);
if (texID == 0)
{
throw std::runtime_error("glGenTextures did not work");
}
glBindTexture(GL_TEXTURE_2D, texID);
//CheckGlError();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//CheckGlError();
//This should be only for Windows
//glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
//CheckGlError();
if (texData.bitSize == TextureDataStruct::BS_24BIT)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, static_cast<GLsizei>(texData.width), static_cast<GLsizei>(texData.height), 0, GL_RGB, GL_UNSIGNED_BYTE, &texData.data[0]);
}
else
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<GLsizei>(texData.width), static_cast<GLsizei>(texData.height), 0, GL_RGBA, GL_UNSIGNED_BYTE, &texData.data[0]);
}
//CheckGlError();
}
Texture::~Texture()
{
glDeleteTextures(1, &texID);
texID = 0;
}
GLuint Texture::getTexID()
{
return texID;
}
size_t Texture::getWidth()
{
return width;
}
size_t Texture::getHeight()
{
return height;
}
TextureDataStruct CreateTextureDataFromBmp24(const std::string& fullFileName, const std::string& ZIPFileName)
{
TextureDataStruct texData;
std::vector<char> fileArr;
fileArr = !ZIPFileName.empty() ? readFileFromZIP(fullFileName, ZIPFileName) : readFile(fullFileName);
size_t fileSize = fileArr.size();
if (fileSize < 22)
{
throw std::runtime_error("File is too short or not correct!");
}
//This refers to BITMAPV5HEADER
texData.width = *reinterpret_cast<uint32_t*>(&fileArr[18]);
texData.height = *reinterpret_cast<uint32_t*>(&fileArr[22]);
texData.bitSize = TextureDataStruct::BS_24BIT;
size_t dataSize = texData.width * texData.height * 3;
texData.data.resize(dataSize);
size_t pos = *reinterpret_cast<uint32_t*>(&fileArr[10]);
size_t x = 0;
for (size_t i = 0; i < texData.width; i++)
for (size_t j = 0; j < texData.height; j++)
{
if (pos + 3 > fileSize)
{
throw std::runtime_error("File is too short!");
}
x = (i * texData.height + j) + (i * texData.height + j) + (i * texData.height + j);
texData.data[x + 2] = fileArr[pos++];
texData.data[x + 1] = fileArr[pos++];
texData.data[x + 0] = fileArr[pos++];
}
return texData;
}
TextureDataStruct CreateTextureDataFromBmp32(const std::string& fullFileName, const std::string& ZIPFileName)
{
TextureDataStruct texData;
std::vector<char> fileArr;
fileArr = !ZIPFileName.empty() ? readFileFromZIP(fullFileName, ZIPFileName) : readFile(fullFileName);
size_t fileSize = fileArr.size();
if (fileSize < 22)
{
throw std::runtime_error("File is too short or not correct!");
}
//This refers to BITMAPV5HEADER
texData.width = *reinterpret_cast<uint32_t*>(&fileArr[18]);
texData.height = *reinterpret_cast<uint32_t*>(&fileArr[22]);
texData.bitSize = TextureDataStruct::BS_32BIT;
size_t dataSize = texData.width * texData.height * 4;
texData.data.resize(dataSize);
size_t pos = *reinterpret_cast<uint32_t*>(&fileArr[10]);
size_t x = 0;
for (size_t i = 0; i < texData.width; i++)
for (size_t j = 0; j < texData.height; j++)
{
if (pos + 4 > fileSize)
{
throw std::runtime_error("File is too short!");
}
x = (i * texData.height + j) + (i * texData.height + j) + (i * texData.height + j) + (i * texData.height + j);
texData.data[x + 2] = fileArr[pos++];
texData.data[x + 1] = fileArr[pos++];
texData.data[x + 0] = fileArr[pos++];
texData.data[x + 3] = fileArr[pos++];
}
return texData;
}
#ifdef PNG_ENABLED
TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName)
{
TextureDataStruct texData;
FILE* file = fopen(fullFileName.c_str(), "rb");
if (!file) {
fclose(file);
throw std::runtime_error("Could not open file " + fullFileName);
}
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!png) {
fclose(file);
throw std::runtime_error("Could not create PNG read structure");
}
png_infop info = png_create_info_struct(png);
if (!info) {
fclose(file);
png_destroy_read_struct(&png, nullptr, nullptr);
throw std::runtime_error("Could not create PNG info structure");
}
if (setjmp(png_jmpbuf(png))) {
png_destroy_read_struct(&png, &info, nullptr);
fclose(file);
throw std::runtime_error("Error during PNG read");
}
png_init_io(png, file);
png_read_info(png, info);
texData.width = png_get_image_width(png, info);
texData.height = png_get_image_height(png, info);
png_byte color_type = png_get_color_type(png, info);
png_byte bit_depth = png_get_bit_depth(png, info);
if (bit_depth == 16)
png_set_strip_16(png);
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png);
if (png_get_valid(png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png);
if (color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_PALETTE)
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
png_read_update_info(png, info);
png_bytep* row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * texData.height);
for (int y = 0; y < texData.height; y++) {
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png, info));
}
png_read_image(png, row_pointers);
fclose(file);
bool has_alpha = (color_type & PNG_COLOR_MASK_ALPHA) || (png_get_valid(png, info, PNG_INFO_tRNS));
size_t dataSize;
if (has_alpha)
{
texData.bitSize = TextureDataStruct::BS_32BIT;
}
else
{
texData.bitSize = TextureDataStruct::BS_24BIT;
}
int channels = has_alpha ? 4 : 3;
dataSize = texData.width * texData.height * channels;
texData.data.resize(dataSize);
//for (int y = 0; y < texData.height; y++) { //Go in reverse because of UV coord start point
for (int y = texData.height-1; y >= 0; y--) {
//png_bytep row = row_pointers[y];//Go in reverse because of UV coord start point
png_bytep row = row_pointers[texData.height - 1 - y];
for (int x = 0; x < texData.width; x++) {
png_bytep px = &(row[x * 4]);
texData.data[(y * texData.width + x) * channels + 0] = px[0]; // R
texData.data[(y * texData.width + x) * channels + 1] = px[1]; // G
texData.data[(y * texData.width + x) * channels + 2] = px[2]; // B
if (has_alpha) {
texData.data[(y * texData.width + x) * channels + 3] = px[3]; // A
}
}
//free(row_pointers[y]);//Go in reverse because of UV coord start point
free(row_pointers[texData.height - 1 - y]);//Go in reverse because of UV coord start point
}
free(row_pointers);
png_destroy_read_struct(&png, &info, nullptr);
return texData;
}
#endif
}

View File

@ -1,35 +1,26 @@
#pragma once #pragma once
#include "render/OpenGlExtensions.h" //#include "OpenGlExtensions.h"
#include "utils/Utils.h" #include "Utils.h"
#include <GLES2/gl2.h>
#if defined EMSCRIPTEN || defined __ANDROID__ #include <GLES2/gl2ext.h>
#define PNG_ENABLED
#endif
namespace ZL namespace ZL
{ {
struct TextureDataStruct { struct TextureDataStruct
{
size_t width; size_t width;
size_t height; size_t height;
std::vector<char> data; std::vector<char> data;
enum BitSize {
enum Format { BS_24BIT,
R8, // Для шрифтов (GL_RED) BS_32BIT
RGB, // BS_24BIT
RGBA // BS_32BIT
}; };
BitSize bitSize;
enum MipmapType {
NONE,
GENERATE
};
Format format = RGBA;
MipmapType mipmap = GENERATE;
}; };
class Texture class Texture
{ {
size_t width = 0; size_t width = 0;
@ -40,9 +31,6 @@ namespace ZL
Texture(const TextureDataStruct& texData); Texture(const TextureDataStruct& texData);
//Cubemap texture:
Texture(const std::array<TextureDataStruct, 6>& texDataArray);
~Texture(); ~Texture();
GLuint getTexID(); GLuint getTexID();
@ -56,8 +44,6 @@ namespace ZL
TextureDataStruct CreateTextureDataFromBmp24(const std::string& fullFileName, const std::string& ZIPFileName=""); TextureDataStruct CreateTextureDataFromBmp24(const std::string& fullFileName, const std::string& ZIPFileName="");
TextureDataStruct CreateTextureDataFromBmp32(const std::string& fullFileName, const std::string& ZIPFileName=""); TextureDataStruct CreateTextureDataFromBmp32(const std::string& fullFileName, const std::string& ZIPFileName="");
#ifdef PNG_ENABLED #ifdef PNG_ENABLED
TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName, const std::string& ZIPFileName = ""); TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName);
#endif #endif
} }

144
app/jni/src/Utils.cpp Normal file
View File

@ -0,0 +1,144 @@
#include "Utils.h"
#include <cstring>
#include <iterator>
#include <vector>
#include <iostream>
#include <algorithm>
#include <fstream>
//#include <zip.h>
#include <SDL.h>
#ifdef __ANDROID__
#include <android/log.h>
#endif
namespace ZL {
std::string readTextFile(const std::string &filename) {
#ifdef __ANDROID__
SDL_RWops* file = SDL_RWFromFile(filename.c_str(), "rb");
if (!file) {
#ifdef DEBUG
__android_log_print(ANDROID_LOG_ERROR, "Utils",
"Failed to open: %s", filename.c_str());
#endif
return "";
}
Sint64 size = SDL_RWsize(file);
if (size <= 0) {
SDL_RWclose(file);
return "";
}
std::string content(size, '\0');
if (SDL_RWread(file, &content[0], size, 1) != 1) {
SDL_RWclose(file);
return "";
}
SDL_RWclose(file);
return content;
#else
std::ifstream f(filename);
if (!f.is_open()) {
return "";
}
return std::string((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>());
#endif
}
std::vector<char> readFile(const std::string &filename) {
#ifdef __ANDROID__
SDL_RWops* file = SDL_RWFromFile(filename.c_str(), "rb");
if (!file) {
return {};
}
Sint64 size = SDL_RWsize(file);
if (size <= 0) {
SDL_RWclose(file);
return {};
}
std::vector<char> data(size);
if (SDL_RWread(file, data.data(), size, 1) != 1) {
SDL_RWclose(file);
return {};
}
SDL_RWclose(file);
return data;
#else
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (!file) {
return {};
}
std::streamsize size = file.tellg();
if (size <= 0) {
return {};
}
file.seekg(0, std::ios::beg);
std::vector<char> buffer(size);
if (!file.read(buffer.data(), size)) {
return {};
}
return buffer;
#endif
}
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,4 +1,4 @@
#pragma once #pragma once
#include <string> #include <string>
#include <vector> #include <vector>
@ -7,8 +7,6 @@
#include <stack> #include <stack>
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
#include <array>
namespace ZL namespace ZL
{ {
std::string readTextFile(const std::string& filename); std::string readTextFile(const std::string& filename);

199
app/jni/src/main.cpp Normal file
View File

@ -0,0 +1,199 @@
#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[]) {
#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;
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
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cerr << "SDL_Init failed: " << SDL_GetError() << std::endl;
return 1;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_Window* win = SDL_CreateWindow("Space Ship Game",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
ZL::Environment::width, ZL::Environment::height,
SDL_WINDOW_OPENGL);
if (!win) {
std::cerr << "SDL_CreateWindow failed: " << SDL_GetError() << std::endl;
return 1;
}
SDL_GLContext glContext = SDL_GL_CreateContext(win);
if (!glContext) {
std::cerr << "SDL_GL_CreateContext failed: " << SDL_GetError() << std::endl;
return 1;
}
SDL_GL_MakeCurrent(win, glContext);
ZL::Environment::window = win;
#else
#ifdef __ANDROID__
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
ZL::Environment::window = SDL_CreateWindow(
"Space Ship Game",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
ZL::Environment::width, ZL::Environment::height,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
);
#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",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
ZL::Environment::width, ZL::Environment::height,
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
);
#endif
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
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);
#else
bool running = true;
while (running && !game.shouldExit()) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
running = false;
}
#ifdef __ANDROID__
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_AC_BACK) {
running = false;
}
#endif
}
game.update();
#ifdef __ANDROID__
SDL_Delay(16);
#else
SDL_Delay(2);
#endif
}
#endif
return 0;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 KiB

View File

@ -1,11 +1,11 @@
attribute vec3 vPosition; attribute vec3 vPosition;
attribute vec2 vTexCoord; attribute vec3 vColor;
varying vec2 texCoord; varying vec3 color;
uniform mat4 ProjectionModelViewMatrix; uniform mat4 ProjectionModelViewMatrix;
void main() void main()
{ {
gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0); gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0);
texCoord = vTexCoord; color = vColor;
} }

View File

@ -0,0 +1,7 @@
precision mediump float;
varying vec3 color;
void main()
{
gl_FragColor = vec4(color, 1.0);
}

View File

@ -1,4 +1,4 @@
//precisionmediump float; //precision mediump float;
varying vec3 color; varying vec3 color;
void main() void main()

View File

@ -0,0 +1,9 @@
precision mediump float;
uniform sampler2D Texture;
varying vec2 texCoord;
void main()
{
vec4 color = texture2D(Texture, texCoord);
gl_FragColor = color;
}

View File

@ -0,0 +1,12 @@
//precision mediump float;
uniform sampler2D Texture;
varying vec2 texCoord;
void main()
{
vec4 color = texture2D(Texture,texCoord).rgba;
gl_FragColor = vec4(color.rgb*0.9 + vec3(0.1, 0.1, 0.1), 1.0);
//gl_FragColor = color;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,86 +0,0 @@
import bpy
import bmesh
mesh_name = "chassis_low"
output_path = "C:\\Work\\Projects\\space-game001\\blender scripts\\output\\spaceship005.txt"
mesh_obj = bpy.data.objects.get(mesh_name)
if mesh_obj and mesh_obj.type == 'MESH':
# Обязательно применяем трансформации, чтобы координаты были актуальными
# Но для чистоты эксперимента берем mesh data как есть
# Работаем с копией меша, чтобы применить триангуляцию (если нужно)
# и не испортить сцену, но пока используем bmesh напрямую
bm = bmesh.new()
bm.from_mesh(mesh_obj.data)
# Получаем слой UV
uv_layer = bm.loops.layers.uv.active
# Словарь для хранения уникальных вершин:
# Ключ: (x, y, z, nx, ny, nz, u, v) -> Значение: новый_индекс
unique_verts_map = {}
final_vertices = [] # Список для записи в файл
final_indices = [] # Список индексов треугольников
# Проходим по всем фейсам
for face in bm.faces:
face_indices = []
# Проходим по углам (loops) фейса
for loop in face.loops:
vert = loop.vert
# 1. Координаты (округляем для надежности сравнения float)
co = (round(vert.co.x, 6), round(vert.co.y, 6), round(vert.co.z, 6))
# 2. Нормаль (если используете Smooth shading, берите vert.normal, если Flat - face.normal)
# Для простоты берем нормаль вершины
no = (round(vert.normal.x, 6), round(vert.normal.y, 6), round(vert.normal.z, 6))
# 3. UV координаты
if uv_layer:
raw_uv = loop[uv_layer].uv
uv = (round(raw_uv.x, 6), round(raw_uv.y, 6))
else:
uv = (0.0, 0.0)
# Собираем уникальный ключ данных вершины
vert_data_key = (co, no, uv)
# Проверяем, есть ли такая комбинация уже
if vert_data_key in unique_verts_map:
index = unique_verts_map[vert_data_key]
else:
index = len(final_vertices)
unique_verts_map[vert_data_key] = index
final_vertices.append(vert_data_key)
face_indices.append(index)
# Триангуляция "на лету" (если фейс - квадрат, делим на два треугольника)
# Простейший метод fan (0, 1, 2), (0, 2, 3)...
for i in range(1, len(face_indices) - 1):
final_indices.append(face_indices[0])
final_indices.append(face_indices[i])
final_indices.append(face_indices[i+1])
# --- ЗАПИСЬ В ФАЙЛ ---
with open(output_path, "w") as file:
file.write(f"===Vertices (Split by UV/Normal): {len(final_vertices)}\n")
# Формат строки: ID: X Y Z | NX NY NZ | U V
for idx, v_data in enumerate(final_vertices):
co, no, uv = v_data
file.write(f"V {idx}: Pos({co[0]}, {co[1]}, {co[2]}) Norm({no[0]}, {no[1]}, {no[2]}) UV({uv[0]}, {uv[1]})\n")
file.write(f"\n===Triangles (Indices): {len(final_indices) // 3}\n")
# Записываем тройками
for i in range(0, len(final_indices), 3):
file.write(f"Tri: {final_indices[i]} {final_indices[i+1]} {final_indices[i+2]}\n")
bm.free()
print(f"Export done. Original verts: {len(mesh_obj.data.vertices)}, Split verts: {len(final_vertices)}")
else:
print("Mesh not found")

View File

@ -1,49 +0,0 @@
# cmake/FetchDependencies.cmake
set(THIRDPARTY_DIR "${CMAKE_CURRENT_LIST_DIR}/../thirdparty")
if(NOT EXISTS "${THIRDPARTY_DIR}")
file(MAKE_DIRECTORY "${THIRDPARTY_DIR}")
endif()
macro(check_and_download URL ARCHIVE_NAME EXTRACTED_DIR_NAME CHECK_FILE)
set(ARCHIVE_PATH "${THIRDPARTY_DIR}/${ARCHIVE_NAME}")
set(SRC_PATH "${THIRDPARTY_DIR}/${EXTRACTED_DIR_NAME}")
if(NOT EXISTS "${ARCHIVE_PATH}")
message(STATUS "Downloading ${ARCHIVE_NAME}...")
file(DOWNLOAD "${URL}" "${ARCHIVE_PATH}" SHOW_PROGRESS)
endif()
if(NOT EXISTS "${SRC_PATH}/${CHECK_FILE}")
message(STATUS "Extracting ${ARCHIVE_NAME}...")
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xvf "${ARCHIVE_PATH}"
WORKING_DIRECTORY "${THIRDPARTY_DIR}"
)
endif()
endmacro()
# 1) ZLIB (Нужна только для инклудов, если не используете emscripten порты)
check_and_download("https://www.zlib.net/zlib131.zip" "zlib131.zip" "zlib-1.3.1" "CMakeLists.txt")
# 2) SDL2
check_and_download("https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.32.10.zip" "release-2.32.10.zip" "SDL-release-2.32.10" "CMakeLists.txt")
# 3) LibPNG
check_and_download("https://github.com/pnggroup/libpng/archive/refs/tags/v1.6.51.zip" "v1.6.51.zip" "libpng-1.6.51" "CMakeLists.txt")
# 4) LibZip
check_and_download("https://github.com/nih-at/libzip/archive/refs/tags/v1.11.4.zip" "v1.11.4.zip" "libzip-1.11.4" "CMakeLists.txt")
# 5) Eigen
check_and_download("https://gitlab.com/libeigen/eigen/-/archive/5.0.0/eigen-5.0.0.zip" "eigen-5.0.0.zip" "eigen-5.0.0" "signature_of_eigen3_matrix_library")
# 6) Boost
check_and_download("https://archives.boost.io/release/1.90.0/source/boost_1_90_0.zip" "boost_1_90_0.zip" "boost_1_90_0" "boost")
# 7) FreeType
check_and_download("https://download.savannah.gnu.org/releases/freetype/freetype-2.14.1.tar.gz" "freetype-2.14.1.tar.gz" "freetype-2.14.1" "CMakeLists.txt")
# 8) SDL_ttf
check_and_download("https://github.com/libsdl-org/SDL_ttf/archive/refs/tags/release-2.24.0.zip" "release-2.24.0.zip" "SDL_ttf-release-2.24.0" "CMakeLists.txt")

View File

@ -1,549 +0,0 @@
# cmake/ThirdParty.cmake
include("${CMAKE_CURRENT_LIST_DIR}/FetchDependencies.cmake")
macro(log msg)
message(STATUS "[ThirdParty] ${msg}")
endmacro()
set(BUILD_CONFIGS Debug Release)
# ===========================================
# 1) ZLIB (zlib131.zip zlib-1.3.1) - без изменений
# ===========================================
set(ZLIB_SRC_DIR "${THIRDPARTY_DIR}/zlib-1.3.1")
set(ZLIB_BUILD_DIR "${ZLIB_SRC_DIR}/build")
set(ZLIB_INSTALL_DIR "${ZLIB_SRC_DIR}/install")
file(MAKE_DIRECTORY "${ZLIB_BUILD_DIR}")
# проверяем, собран ли уже zlib
set(_have_zlib FALSE)
foreach(candidate
"${ZLIB_INSTALL_DIR}/lib/zlibstatic.lib"
)
if(EXISTS "${candidate}")
set(_have_zlib TRUE)
break()
endif()
endforeach()
if(NOT _have_zlib)
log("Configuring zlib ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-S "${ZLIB_SRC_DIR}"
-B "${ZLIB_BUILD_DIR}"
-DCMAKE_INSTALL_PREFIX=${ZLIB_INSTALL_DIR}
RESULT_VARIABLE _zlib_cfg_res
)
if(NOT _zlib_cfg_res EQUAL 0)
message(FATAL_ERROR "zlib configure failed")
endif()
foreach(cfg IN LISTS BUILD_CONFIGS)
log("Building ZLIB (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${ZLIB_BUILD_DIR}" --config ${cfg}
RESULT_VARIABLE _zlib_build_res
)
if(NOT _zlib_build_res EQUAL 0)
message(FATAL_ERROR "ZLIB build failed for configuration ${cfg}")
endif()
log("Installing ZLIB (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--install "${ZLIB_BUILD_DIR}" --config ${cfg}
RESULT_VARIABLE _zlib_inst_res
)
if(NOT _zlib_inst_res EQUAL 0)
message(FATAL_ERROR "ZLIB install failed for configuration ${cfg}")
endif()
endforeach()
endif()
# ИСПРАВЛЕНИЕ: Используем свойства для конкретных конфигураций
add_library(zlib_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(zlib_external_lib PROPERTIES
# Динамическая линковка (если zlib.lib - это импорт-библиотека для zlibd.dll)
#IMPORTED_LOCATION_DEBUG "${ZLIB_INSTALL_DIR}/lib/zlibd.lib"
#IMPORTED_LOCATION_RELEASE "${ZLIB_INSTALL_DIR}/lib/zlib.lib"
# Можно также указать статические библиотеки, если вы хотите их использовать
IMPORTED_LOCATION_DEBUG "${ZLIB_INSTALL_DIR}/lib/zlibstaticd.lib"
IMPORTED_LOCATION_RELEASE "${ZLIB_INSTALL_DIR}/lib/zlibstatic.lib"
INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INSTALL_DIR}/include"
)
# ===========================================
# 2) SDL2 (release-2.32.10.zip SDL-release-2.32.10) - без изменений
# ===========================================
set(SDL2_SRC_DIR "${THIRDPARTY_DIR}/SDL-release-2.32.10")
set(SDL2_BUILD_DIR "${SDL2_SRC_DIR}/build")
set(SDL2_INSTALL_DIR "${SDL2_SRC_DIR}/install")
file(MAKE_DIRECTORY "${SDL2_BUILD_DIR}")
set(_have_sdl2 FALSE)
foreach(candidate
"${SDL2_INSTALL_DIR}/lib/SDL2.lib"
"${SDL2_INSTALL_DIR}/lib/SDL2-static.lib"
"${SDL2_INSTALL_DIR}/lib/SDL2d.lib"
)
if(EXISTS "${candidate}")
set(_have_sdl2 TRUE)
break()
endif()
endforeach()
if(NOT _have_sdl2)
log("Configuring SDL2 ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-S "${SDL2_SRC_DIR}"
-B "${SDL2_BUILD_DIR}"
-DCMAKE_INSTALL_PREFIX=${SDL2_INSTALL_DIR}
-DCMAKE_PREFIX_PATH=${ZLIB_INSTALL_DIR} # путь к zlib для SDL2
RESULT_VARIABLE _sdl_cfg_res
)
if(NOT _sdl_cfg_res EQUAL 0)
message(FATAL_ERROR "SDL2 configure failed")
endif()
# --- ИЗМЕНЕНИЕ: Цикл по конфигурациям Debug и Release ---
foreach(cfg IN LISTS BUILD_CONFIGS)
log("Building SDL2 (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${SDL2_BUILD_DIR}" --config ${cfg}
RESULT_VARIABLE _sdl_build_res
)
if(NOT _sdl_build_res EQUAL 0)
message(FATAL_ERROR "SDL2 build failed for configuration ${cfg}")
endif()
log("Installing SDL2 (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--install "${SDL2_BUILD_DIR}" --config ${cfg}
RESULT_VARIABLE _sdl_inst_res
)
if(NOT _sdl_inst_res EQUAL 0)
message(FATAL_ERROR "SDL2 install failed for configuration ${cfg}")
endif()
endforeach()
# ------------------------------------------------------
endif()
# ИСПРАВЛЕНИЕ: SDL2: Используем свойства для конкретных конфигураций
add_library(SDL2_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(SDL2_external_lib PROPERTIES
# Динамическая линковка SDL2
IMPORTED_LOCATION_DEBUG "${SDL2_INSTALL_DIR}/lib/SDL2d.lib"
IMPORTED_LOCATION_RELEASE "${SDL2_INSTALL_DIR}/lib/SDL2.lib"
# Оба include-пути: и include, и include/SDL2
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INSTALL_DIR}/include;${SDL2_INSTALL_DIR}/include/SDL2"
)
# SDL2main (обычно статическая)
add_library(SDL2main_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(SDL2main_external_lib PROPERTIES
# ИСПРАВЛЕНО: Указываем пути для Debug и Release, используя
# соглашение, что Debug имеет суффикс 'd', а Release нет.
IMPORTED_LOCATION_DEBUG "${SDL2_INSTALL_DIR}/lib/SDL2maind.lib"
IMPORTED_LOCATION_RELEASE "${SDL2_INSTALL_DIR}/lib/SDL2main.lib"
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INSTALL_DIR}/include"
)
log("-----${SDL2_INSTALL_DIR}/lib/SDL2maind.lib")
# ===========================================
# 3) libpng (v1.6.51.zip libpng-1.6.51) - без изменений
# ===========================================
set(LIBPNG_SRC_DIR "${THIRDPARTY_DIR}/libpng-1.6.51")
set(LIBPNG_BUILD_DIR "${LIBPNG_SRC_DIR}/build")
set(LIBPNG_INSTALL_DIR "${LIBPNG_SRC_DIR}/install") # на будущее
file(MAKE_DIRECTORY "${LIBPNG_BUILD_DIR}")
# Проверяем, есть ли уже .lib (build/Debug или install/lib)
set(_libpng_candidates
"${LIBPNG_BUILD_DIR}/Debug/libpng16_staticd.lib"
"${LIBPNG_BUILD_DIR}/Release/libpng16_static.lib"
)
set(_have_png FALSE)
foreach(candidate IN LISTS _libpng_candidates)
if(EXISTS "${candidate}")
set(_have_png TRUE)
break()
endif()
endforeach()
if(NOT _have_png)
log("Configuring libpng ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-S "${LIBPNG_SRC_DIR}"
-B "${LIBPNG_BUILD_DIR}"
-DCMAKE_INSTALL_PREFIX=${LIBPNG_INSTALL_DIR}
-DCMAKE_PREFIX_PATH=${ZLIB_INSTALL_DIR}
-DZLIB_ROOT=${ZLIB_INSTALL_DIR}
RESULT_VARIABLE _png_cfg_res
)
if(NOT _png_cfg_res EQUAL 0)
message(FATAL_ERROR "libpng configure failed")
endif()
# --- ИЗМЕНЕНИЕ: Цикл по конфигурациям Debug и Release ---
foreach(cfg IN LISTS BUILD_CONFIGS)
log("Building libpng (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${LIBPNG_BUILD_DIR}" --config ${cfg}
RESULT_VARIABLE _png_build_res
)
if(NOT _png_build_res EQUAL 0)
message(FATAL_ERROR "libpng build failed for configuration ${cfg}")
endif()
# Поскольку вы не используете "cmake --install" для libpng,
# здесь нет необходимости в дополнительном шаге установки.
# Файлы .lib будут сгенерированы в подкаталоге ${LIBPNG_BUILD_DIR}/${cfg} (например, build/Debug или build/Release).
endforeach()
# ------------------------------------------------------
endif()
add_library(libpng_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(libpng_external_lib PROPERTIES
# Предполагая, что libpng использует статический вариант
IMPORTED_LOCATION_DEBUG "${LIBPNG_BUILD_DIR}/Debug/libpng16_staticd.lib"
IMPORTED_LOCATION_RELEASE "${LIBPNG_BUILD_DIR}/Release/libpng16_static.lib"
# png.h, pngconf.h в SRC, pnglibconf.h в BUILD
INTERFACE_INCLUDE_DIRECTORIES "${LIBPNG_SRC_DIR};${LIBPNG_BUILD_DIR}"
)
# ===========================================
# 4) libzip (v1.11.4.zip libzip-1.11.4) - НОВАЯ ЗАВИСИМОСТЬ
# ===========================================
set(LIBZIP_SRC_DIR "${THIRDPARTY_DIR}/libzip-1.11.4")
set(LIBZIP_BUILD_DIR "${LIBZIP_SRC_DIR}/build")
#set(LIBZIP_INSTALL_DIR "${LIBZIP_SRC_DIR}/install")
set(LIBZIP_BASE_DIR "${LIBZIP_SRC_DIR}/install")
file(MAKE_DIRECTORY "${LIBZIP_BUILD_DIR}")
# Проверяем, собран ли уже libzip
set(_have_zip FALSE)
foreach(candidate
"${LIBZIP_BASE_DIR}-Debug/lib/zip.lib"
"${LIBZIP_BASE_DIR}-Release/lib/zip.lib"
)
if(EXISTS "${candidate}")
set(_have_zip TRUE)
break()
endif()
endforeach()
if(NOT _have_zip)
foreach(cfg IN LISTS BUILD_CONFIGS)
log("Configuring libzip (${cfg})...")
execute_process(
COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-S "${LIBZIP_SRC_DIR}"
-B "${LIBZIP_SRC_DIR}/build-${cfg}"
-DCMAKE_INSTALL_PREFIX=${LIBZIP_BASE_DIR}-${cfg}
-DCMAKE_PREFIX_PATH=${ZLIB_INSTALL_DIR}
-DZLIB_ROOT=${ZLIB_INSTALL_DIR}
-DENABLE_COMMONCRYPTO=OFF
-DENABLE_GNUTLS=OFF
-DENABLE_MBEDTLS=OFF
-DENABLE_OPENSSL=OFF
-DENABLE_WINDOWS_CRYPTO=OFF
-DENABLE_FUZZ=OFF
RESULT_VARIABLE _zip_cfg_res
)
if(NOT _zip_cfg_res EQUAL 0)
message(FATAL_ERROR "libzip configure failed")
endif()
log("Building libzip (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND} --build "${LIBZIP_SRC_DIR}/build-${cfg}" --config ${cfg} -v
RESULT_VARIABLE _zip_build_res
)
if(NOT _zip_build_res EQUAL 0)
message(FATAL_ERROR "libzip build failed for configuration ${cfg}")
endif()
log("Installing libzip (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND} --install "${LIBZIP_SRC_DIR}/build-${cfg}" --config ${cfg} -v
RESULT_VARIABLE _zip_inst_res
)
if(NOT _zip_inst_res EQUAL 0)
message(FATAL_ERROR "libzip install failed for configuration ${cfg}")
endif()
endforeach()
endif()
add_library(libzip_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(libzip_external_lib PROPERTIES
IMPORTED_LOCATION_DEBUG "${LIBZIP_BASE_DIR}-Debug/lib/zip.lib" # ИСПРАВЛЕНО
IMPORTED_LOCATION_RELEASE "${LIBZIP_BASE_DIR}-Release/lib/zip.lib" # ИСПРАВЛЕНО
INTERFACE_INCLUDE_DIRECTORIES "$<IF:$<CONFIG:Debug>,${LIBZIP_BASE_DIR}-Debug/include,${LIBZIP_BASE_DIR}-Release/include>"
# libzip требует zlib для линковки
INTERFACE_LINK_LIBRARIES zlib_external_lib
)
# ===========================================
# 5) FreeType (2.14.1) - dependency for SDL_ttf
# ===========================================
set(FREETYPE_SRC_DIR "${THIRDPARTY_DIR}/freetype-2.14.1")
set(FREETYPE_BASE_DIR "${FREETYPE_SRC_DIR}/install")
set(_have_freetype TRUE)
foreach(cfg IN LISTS BUILD_CONFIGS)
if(NOT EXISTS "${FREETYPE_BASE_DIR}-${cfg}/lib/freetype.lib" AND
NOT EXISTS "${FREETYPE_BASE_DIR}-${cfg}/lib/freetyped.lib")
set(_have_freetype FALSE)
endif()
endforeach()
if(NOT _have_freetype)
foreach(cfg IN LISTS BUILD_CONFIGS)
log("Configuring FreeType (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-S "${FREETYPE_SRC_DIR}"
-B "${FREETYPE_SRC_DIR}/build-${cfg}"
-DCMAKE_INSTALL_PREFIX=${FREETYPE_BASE_DIR}-${cfg}
-DCMAKE_PREFIX_PATH="${ZLIB_INSTALL_DIR};${LIBPNG_INSTALL_DIR}"
-DCMAKE_DISABLE_FIND_PACKAGE_HarfBuzz=TRUE
-DCMAKE_DISABLE_FIND_PACKAGE_BZip2=TRUE
-DFT_DISABLE_BROTLI=ON
-DBUILD_SHARED_LIBS=OFF
RESULT_VARIABLE _ft_cfg_res
)
if(NOT _ft_cfg_res EQUAL 0)
message(FATAL_ERROR "FreeType configure failed for ${cfg}")
endif()
log("Building FreeType (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${FREETYPE_SRC_DIR}/build-${cfg}" --config ${cfg}
RESULT_VARIABLE _ft_build_res
)
if(NOT _ft_build_res EQUAL 0)
message(FATAL_ERROR "FreeType build failed for ${cfg}")
endif()
log("Installing FreeType (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--install "${FREETYPE_SRC_DIR}/build-${cfg}" --config ${cfg}
RESULT_VARIABLE _ft_inst_res
)
if(NOT _ft_inst_res EQUAL 0)
message(FATAL_ERROR "FreeType install failed for ${cfg}")
endif()
endforeach()
endif()
set(_ft_debug_lib "")
foreach(cand
"${FREETYPE_BASE_DIR}-Debug/lib/freetyped.lib"
"${FREETYPE_BASE_DIR}-Debug/lib/freetype.lib"
)
if(EXISTS "${cand}")
set(_ft_debug_lib "${cand}")
break()
endif()
endforeach()
set(_ft_release_lib "")
foreach(cand
"${FREETYPE_BASE_DIR}-Release/lib/freetype.lib"
)
if(EXISTS "${cand}")
set(_ft_release_lib "${cand}")
break()
endif()
endforeach()
if(_ft_debug_lib STREQUAL "" OR _ft_release_lib STREQUAL "")
message(FATAL_ERROR "FreeType libs not found in ${FREETYPE_BASE_DIR}-Debug/Release")
endif()
add_library(freetype_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(freetype_external_lib PROPERTIES
IMPORTED_LOCATION_DEBUG "${_ft_debug_lib}"
IMPORTED_LOCATION_RELEASE "${_ft_release_lib}"
)
target_include_directories(freetype_external_lib INTERFACE
"$<IF:$<CONFIG:Debug>,${FREETYPE_BASE_DIR}-Debug/include/freetype2,${FREETYPE_BASE_DIR}-Release/include/freetype2>"
"$<IF:$<CONFIG:Debug>,${FREETYPE_BASE_DIR}-Debug/include,${FREETYPE_BASE_DIR}-Release/include>"
)
# ===========================================
# 6) SDL_ttf (2.24.0)
# ===========================================
set(SDL2TTF_SRC_DIR "${THIRDPARTY_DIR}/SDL_ttf-release-2.24.0")
set(SDL2TTF_BASE_DIR "${SDL2TTF_SRC_DIR}/install")
set(_have_sdl2ttf TRUE)
foreach(cfg IN LISTS BUILD_CONFIGS)
if(NOT EXISTS "${SDL2TTF_BASE_DIR}-${cfg}/lib/SDL2_ttf.lib" AND
NOT EXISTS "${SDL2TTF_BASE_DIR}-${cfg}/lib/SDL2_ttfd.lib")
set(_have_sdl2ttf FALSE)
endif()
endforeach()
if(NOT _have_sdl2ttf)
foreach(cfg IN LISTS BUILD_CONFIGS)
if(cfg STREQUAL "Debug")
set(_SDL2_LIB "${SDL2_INSTALL_DIR}/lib/SDL2d.lib")
else()
set(_SDL2_LIB "${SDL2_INSTALL_DIR}/lib/SDL2.lib")
endif()
set(_FT_PREFIX "${FREETYPE_BASE_DIR}-${cfg}")
set(_FT_LIB "")
foreach(cand
"${_FT_PREFIX}/lib/freetyped.lib"
"${_FT_PREFIX}/lib/freetype.lib"
)
if(EXISTS "${cand}")
set(_FT_LIB "${cand}")
break()
endif()
endforeach()
if(_FT_LIB STREQUAL "")
message(FATAL_ERROR "FreeType library not found for ${cfg}")
endif()
log("Configuring SDL_ttf (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-S "${SDL2TTF_SRC_DIR}"
-B "${SDL2TTF_SRC_DIR}/build-${cfg}"
-DCMAKE_INSTALL_PREFIX=${SDL2TTF_BASE_DIR}-${cfg}
-DCMAKE_PREFIX_PATH=${_FT_PREFIX};${SDL2_INSTALL_DIR}
-DSDL2_LIBRARY=${_SDL2_LIB}
-DSDL2_INCLUDE_DIR=${SDL2_INSTALL_DIR}/include/SDL2
-DFREETYPE_LIBRARY=${_FT_LIB}
-DFREETYPE_INCLUDE_DIR=${_FT_PREFIX}/include/freetype2
-DFREETYPE_INCLUDE_DIRS=${_FT_PREFIX}/include/freetype2
-DSDL2TTF_VENDORED=OFF
-DSDL2TTF_SAMPLES=OFF
RESULT_VARIABLE _ttf_cfg_res
)
if(NOT _ttf_cfg_res EQUAL 0)
message(FATAL_ERROR "SDL_ttf configure failed for ${cfg}")
endif()
log("Building SDL_ttf (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${SDL2TTF_SRC_DIR}/build-${cfg}" --config ${cfg}
RESULT_VARIABLE _ttf_build_res
)
if(NOT _ttf_build_res EQUAL 0)
message(FATAL_ERROR "SDL_ttf build failed for ${cfg}")
endif()
log("Installing SDL_ttf (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--install "${SDL2TTF_SRC_DIR}/build-${cfg}" --config ${cfg}
RESULT_VARIABLE _ttf_inst_res
)
if(NOT _ttf_inst_res EQUAL 0)
message(FATAL_ERROR "SDL_ttf install failed for ${cfg}")
endif()
endforeach()
endif()
set(_ttf_debug_lib "")
foreach(cand
"${SDL2TTF_BASE_DIR}-Debug/lib/SDL2_ttfd.lib"
"${SDL2TTF_BASE_DIR}-Debug/lib/SDL2_ttf.lib"
)
if(EXISTS "${cand}")
set(_ttf_debug_lib "${cand}")
break()
endif()
endforeach()
set(_ttf_release_lib "")
foreach(cand
"${SDL2TTF_BASE_DIR}-Release/lib/SDL2_ttf.lib"
)
if(EXISTS "${cand}")
set(_ttf_release_lib "${cand}")
break()
endif()
endforeach()
if(_ttf_debug_lib STREQUAL "" OR _ttf_release_lib STREQUAL "")
message(FATAL_ERROR "SDL_ttf libs not found in install-Debug / install-Release")
endif()
add_library(SDL2_ttf_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(SDL2_ttf_external_lib PROPERTIES
IMPORTED_LOCATION_DEBUG "${_ttf_debug_lib}"
IMPORTED_LOCATION_RELEASE "${_ttf_release_lib}"
INTERFACE_INCLUDE_DIRECTORIES
"$<IF:$<CONFIG:Debug>,${SDL2TTF_BASE_DIR}-Debug/include,${SDL2TTF_BASE_DIR}-Release/include>;$<IF:$<CONFIG:Debug>,${SDL2TTF_BASE_DIR}-Debug/include/SDL2,${SDL2TTF_BASE_DIR}-Release/include/SDL2>"
INTERFACE_LINK_LIBRARIES
"SDL2_external_lib;freetype_external_lib"
)
# ===========================================
# 7) Eigen (5.0.0.zip eigen-5.0.0) - HEADER-ONLY
# ===========================================
set(EIGEN_SRC_DIR "${THIRDPARTY_DIR}/eigen-5.0.0")
if(NOT TARGET eigen_external_lib)
add_library(eigen_external_lib INTERFACE)
target_include_directories(eigen_external_lib INTERFACE "${EIGEN_SRC_DIR}")
endif()
# ===========================================
# 8) Boost (1.90.0) - HEADER-ONLY
# ===========================================
set(BOOST_VERSION "1.90.0")
set(BOOST_ARCHIVE_NAME "boost_1_90_0.zip")
set(BOOST_ARCHIVE "${THIRDPARTY_DIR}/${BOOST_ARCHIVE_NAME}")
# Внутри архива папка называется boost_1_90_0
set(BOOST_SRC_DIR "${THIRDPARTY_DIR}/boost_1_90_0")
if(NOT TARGET boost_external_lib)
add_library(boost_external_lib INTERFACE)
# Boost заголовки находятся непосредственно в корне распакованной папки
target_include_directories(boost_external_lib INTERFACE "${BOOST_SRC_DIR}")
endif()

View File

@ -1,36 +0,0 @@
cmake_minimum_required(VERSION 3.10)
project(AudioPlayer)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Use pkg-config to find Vorbis
#find_package(PkgConfig REQUIRED)
#pkg_check_modules(VORBIS REQUIRED vorbis vorbisfile)
#pkg_check_modules(OGG REQUIRED ogg)
find_package(OpenAL REQUIRED)
add_library(audioplayer
src/AudioPlayer.cpp
include/AudioPlayer.hpp
)
target_include_directories(audioplayer
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${OPENAL_INCLUDE_DIR}
${VORBIS_INCLUDE_DIRS}
${OGG_INCLUDE_DIRS}
)
target_link_libraries(audioplayer
PUBLIC
${OPENAL_LIBRARY}
${VORBIS_LIBRARIES}
${OGG_LIBRARIES}
)
# Test executable
add_executable(test_audio examples/test_audio.cpp)
target_link_libraries(test_audio PRIVATE audioplayer stdc++fs)
#git add ../../sounds

View File

@ -1,32 +0,0 @@
#include "AudioPlayer.hpp"
#include <iostream>
#include <thread>
#include <chrono>
#include <string>
int main() {
try {
AudioPlayer player;
const std::string filename = "Symphony No.6 (1st movement).ogg";
std::cout << "🔍 Looking for file: " << filename << " in sounds directory...\n";
if (!player.playFromSoundsDir(filename)) {
std::cout << "❌ Failed to play audio file\n";
return 1;
}
std::cout << "✅ Playing symphony...\n";
// Check status for 30 seconds
for (int i = 0; i < 30; ++i) {
std::cout << "📊 Status: " << (player.isPlaying() ? "Playing ▶️" : "Stopped ⏹️") << "\n";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
} catch (const std::exception& e) {
std::cerr << "❌ Error: " << e.what() << "\n";
return 1;
}
}

View File

@ -1,37 +0,0 @@
#pragma once
#include <string>
#include <AL/al.h>
#include <AL/alc.h>
#include <vorbis/vorbisfile.h>
#include <vector>
#include <cstdint>
class AudioPlayer {
public:
AudioPlayer();
~AudioPlayer();
// Для музыки с зацикливанием (если filename пустой - продолжает играть текущую)
bool playMusic(const std::string& filename = "");
// Для одноразовых звуковых эффектов
bool playSound(const std::string& filename);
void stop();
bool isPlaying() const;
private:
ALCdevice* device;
ALCcontext* context;
ALuint musicSource; // Источник для музыки
ALuint soundSource; // Источник для звуков
ALuint musicBuffer; // Буфер для музыки
ALuint soundBuffer; // Буфер для звуков
bool playing;
std::string currentMusic; // Хранит имя текущего музыкального файла
std::vector<char> loadOgg(const std::string& filename, ALuint buffer);
std::string findFileInSounds(const std::string& filename);
bool isOggFile(const std::string& filename) const;
};

View File

@ -1,194 +0,0 @@
#include "AudioPlayer.hpp"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <cstdint>
#include <algorithm>
AudioPlayer::AudioPlayer() : device(nullptr), context(nullptr),
musicSource(0), soundSource(0), musicBuffer(0), soundBuffer(0), playing(false) {
device = alcOpenDevice(nullptr);
if (!device) {
throw std::runtime_error("Failed to open audio device");
}
context = alcCreateContext(device, nullptr);
if (!context) {
alcCloseDevice(device);
throw std::runtime_error("Failed to create audio context");
}
alcMakeContextCurrent(context);
alGenSources(1, &musicSource);
alGenSources(1, &soundSource);
alGenBuffers(1, &musicBuffer);
alGenBuffers(1, &soundBuffer);
}
AudioPlayer::~AudioPlayer() {
if (musicSource)
alDeleteSources(1, &musicSource);
if (soundSource)
alDeleteSources(1, &soundSource);
if (musicBuffer)
alDeleteBuffers(1, &musicBuffer);
if (soundBuffer)
alDeleteBuffers(1, &soundBuffer);
if (context) {
alcMakeContextCurrent(nullptr);
alcDestroyContext(context);
}
if (device)
alcCloseDevice(device);
}
bool AudioPlayer::isOggFile(const std::string& filename) const {
std::string ext = std::filesystem::path(filename).extension().string();
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
return ext == ".ogg";
}
std::string AudioPlayer::findFileInSounds(const std::string& filename) {
// Primary search path - "sounds" directory next to executable
std::filesystem::path soundsDir = std::filesystem::current_path() / "sounds";
// Alternative search paths
std::vector<std::filesystem::path> altPaths = {
std::filesystem::current_path() / ".." / "sounds", // One level up
std::filesystem::current_path() / ".." / ".." / "sounds", // Two levels up
"/home/albert/gay-jam/ZeptoLabTest1/sounds" // Absolute path
};
std::cout << "🔍 Searching for \"" << filename << "\" in:\n";
std::cout << " " << soundsDir << "\n";
if (std::filesystem::exists(soundsDir / filename)) {
return (soundsDir / filename).string();
}
// Try alternative paths
for (const auto& path : altPaths) {
std::cout << " " << path << "\n";
if (std::filesystem::exists(path / filename)) {
return (path / filename).string();
}
}
throw std::runtime_error("❌ File not found: " + filename);
}
std::vector<char> AudioPlayer::loadOgg(const std::string& filename, ALuint buffer) {
FILE* file = fopen(filename.c_str(), "rb");
if (!file) {
throw std::runtime_error("Cannot open file: " + filename);
}
OggVorbis_File vf;
if (ov_open_callbacks(file, &vf, nullptr, 0, OV_CALLBACKS_DEFAULT) < 0) {
fclose(file);
throw std::runtime_error("Input not an Ogg file: " + filename);
}
vorbis_info* vi = ov_info(&vf, -1);
std::vector<char> audioData;
char data[4096];
int bitstream;
long bytes;
do {
bytes = ov_read(&vf, data, sizeof(data), 0, 2, 1, &bitstream);
if (bytes > 0) {
audioData.insert(audioData.end(), data, data + bytes);
}
} while (bytes > 0);
// Setup the buffer with the audio data
alBufferData(buffer,
(vi->channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16,
audioData.data(),
audioData.size(),
vi->rate);
ov_clear(&vf);
return audioData;
}
bool AudioPlayer::playMusic(const std::string& filename) {
try {
// Если filename пустой, просто проверяем играет ли музыка
if (filename.empty()) {
if (!isPlaying()) {
alSourcei(musicSource, AL_LOOPING, AL_TRUE); // Включаем зацикливание
alSourcePlay(musicSource);
}
return true;
}
// Если filename не пустой, загружаем новую музыку
if (!isOggFile(filename)) {
std::cerr << "❌ Error: Music file must be an .ogg file\n";
return false;
}
std::string fullPath = findFileInSounds(filename);
std::cout << "✅ Found music file: " << fullPath << "\n";
// Останавливаем текущую музыку
alSourceStop(musicSource);
// Загружаем и настраиваем новую музыку
loadOgg(fullPath, musicBuffer);
alSourcei(musicSource, AL_BUFFER, musicBuffer);
alSourcei(musicSource, AL_LOOPING, AL_TRUE); // Включаем зацикливание
std::cout << "▶️ Starting music playback... " << musicSource << std::endl;
std::cout << "▶️ Music buffer... " << musicBuffer << std::endl;
alSourcePlay(musicSource);
currentMusic = filename;
playing = true;
return true;
} catch (const std::exception& e) {
std::cerr << "❌ Error playing music: " << e.what() << std::endl;
return false;
}
}
bool AudioPlayer::playSound(const std::string& filename) {
try {
if (!isOggFile(filename)) {
std::cerr << "❌ Error: Sound file must be an .ogg file\n";
return false;
}
std::string fullPath = findFileInSounds(filename);
std::cout << "✅ Found sound file: " << fullPath << "\n";
// Загружаем и настраиваем звук
loadOgg(fullPath, soundBuffer);
alSourcei(soundSource, AL_BUFFER, soundBuffer);
alSourcei(soundSource, AL_LOOPING, AL_FALSE); // Выключаем зацикливание
std::cout << "▶️ Playing sound effect...\n";
alSourcePlay(soundSource);
return true;
} catch (const std::exception& e) {
std::cerr << "❌ Error playing sound: " << e.what() << std::endl;
return false;
}
}
void AudioPlayer::stop() {
alSourceStop(musicSource);
alSourceStop(soundSource);
playing = false;
}
bool AudioPlayer::isPlaying() const {
ALint state;
alGetSourcei(musicSource, AL_SOURCE_STATE, &state);
return state == AL_PLAYING;
}

View File

@ -1,156 +0,0 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": 1280,
"height": 720,
"children": [
{
"type": "FrameLayout",
"name": "leftPanel",
"x": 100,
"y": 100,
"width": 320,
"height": 400,
"children": [
{
"type": "LinearLayout",
"name": "mainButtons",
"orientation": "vertical",
"spacing": 10,
"x": 0,
"y": 0,
"width": 300,
"height": 300,
"children": [
{
"type": "Button",
"name": "playButton",
"x": 100,
"y": 300,
"width": 200,
"height": 50,
"animations": {
"buttonsExit": {
"repeat": false,
"steps": [
{
"type": "move",
"to": [
-400,
0
],
"duration": 1.0,
"easing": "easein"
}
]
}
},
"textures": {
"normal": "./resources/button.png",
"hover": "./resources/sand.png",
"pressed": "./resources/button.png"
}
},
{
"type": "Button",
"name": "settingsButton",
"x": 100,
"y": 200,
"width": 200,
"height": 50,
"animations": {
"buttonsExit": {
"repeat": false,
"steps": [
{
"type": "wait",
"duration": 0.5
},
{
"type": "move",
"to": [
-400,
0
],
"duration": 1.0,
"easing": "easein"
}
]
}
},
"textures": {
"normal": "./resources/sand.png",
"hover": "./resources/button.png",
"pressed": "./resources/sand.png"
}
},
{
"type": "Button",
"name": "exitButton",
"x": 100,
"y": 100,
"width": 200,
"height": 50,
"animations": {
"buttonsExit": {
"repeat": false,
"steps": [
{
"type": "wait",
"duration": 1.0
},
{
"type": "move",
"to": [
-400,
0
],
"duration": 1.0,
"easing": "easein"
}
]
},
"bgScroll": {
"repeat": true,
"steps": [
{
"type": "move",
"to": [
1280,
0
],
"duration": 5.0,
"easing": "linear"
}
]
}
},
"textures": {
"normal": "./resources/rock.png",
"hover": "./resources/button.png",
"pressed": "./resources/rock.png"
}
}
]
}
]
},
{
"type": "Slider",
"name": "musicVolumeSlider",
"x": 1140,
"y": 100,
"width": 10,
"height": 500,
"value": 0.5,
"orientation": "vertical",
"textures": {
"track": "./resources/musicVolumeBarTexture.png",
"knob": "./resources/musicVolumeBarButton.png"
}
}
]
}
}

View File

@ -1,6 +1,6 @@
#Sat Jan 10 10:31:05 MSK 2026 #Thu Nov 11 18:20:34 PST 2021
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View File

View File

@ -1,65 +0,0 @@
# Built application files
*.apk
*.ap_
*.aab
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Gradle files
.gradle/
build/
.idea/
# Local configuration file (sdk path, etc)
local.properties
# CMake build files
CMakeFiles/
cmake_install.cmake
CMakeCache.txt
Makefile
*.cmake
# Android Studio
*.iml
.idea/
.cxx/
.gradle/
.DS_Store
/captures/
.externalNativeBuild/
# NDK
.obj/
*.o
*.so
# SDL2 (если используешь)
libs/
obj/
# Временные файлы
*.swp
*.swo
*~
.thumbs.db
desktop.ini
# Проектные специфичные
app/build/
*.log
app/jni/libpng
app/jni/SDL
app/jni/zlib
app/src/main/assets/resources

View File

@ -1,68 +0,0 @@
cmake_minimum_required(VERSION 3.6)
project(GAME)
if(POLICY CMP0079)
cmake_policy(SET CMP0079 NEW)
endif()
# ==============================================================================
# 1. АВТО-ЗАГРУЗКА ИСХОДНИКОВ
# ==============================================================================
# Путь относительно текущего файла к папке с общими скриптами
include("${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/FetchDependencies.cmake")
# Теперь мы уверены, что папка thirdparty заполнена исходниками.
# Определяем базовый путь для удобства:
set(TP_ROOT "${THIRDPARTY_DIR}")
# ==============================================================================
# 2. НАСТРОЙКА ЗАВИСИМОСТЕЙ (СОБИРАЕМ ИЗ ИСХОДНИКОВ)
# ==============================================================================
# --- ZLIB ---
add_subdirectory("${TP_ROOT}/zlib-1.3.1" zlib-build)
# --- LIBPNG ---
set(PNG_STATIC ON CACHE BOOL "Build static library" FORCE)
set(PNG_SHARED OFF CACHE BOOL "Don't build shared library" FORCE)
set(PNG_TESTS OFF CACHE BOOL "Disable tests" FORCE)
set(PNG_TOOLS OFF CACHE BOOL "Disable tools" FORCE)
set(PNG_EXECUTABLES OFF CACHE BOOL "Disable executables" FORCE)
set(PNG_DEBUG OFF CACHE BOOL "Disable debug" FORCE)
set(SKIP_INSTALL_ALL ON CACHE BOOL "Skip installation" FORCE)
set(PNG_HARDWARE_OPTIMIZATIONS OFF CACHE BOOL "Disable hardware optimizations" FORCE)
set(PNG_ARM_NEON "off" CACHE STRING "Disable ARM NEON" FORCE)
add_subdirectory("${TP_ROOT}/libpng-1.6.51" libpng-build)
# --- SDL2 ---
# Android-версия SDL требует специфичных настроек, но add_subdirectory обычно подхватывает их сама
add_subdirectory("${TP_ROOT}/SDL-release-2.32.10" sdl-build)
# --- LIBZIP ---
# Отключаем поиск системных крипто-библиотек, так как в NDK их может не быть в стандартных путях
set(ENABLE_GNUTLS OFF CACHE BOOL "" FORCE)
set(ENABLE_OPENSSL OFF CACHE BOOL "" FORCE)
set(ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL "" FORCE)
set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE)
set(ENABLE_MBEDTLS OFF CACHE BOOL "" FORCE)
add_subdirectory("${TP_ROOT}/libzip-1.11.4" libzip-build)
# --- EIGEN & BOOST (Header-only) ---
# Мы создаем интерфейсные таргеты здесь, чтобы они были доступны в подпапке src
if(NOT TARGET eigen_external_lib)
add_library(eigen_external_lib INTERFACE)
target_include_directories(eigen_external_lib INTERFACE "${TP_ROOT}/eigen-5.0.0")
endif()
if(NOT TARGET boost_external_lib)
add_library(boost_external_lib INTERFACE)
target_include_directories(boost_external_lib INTERFACE "${TP_ROOT}/boost_1_90_0")
endif()
# ==============================================================================
# 3. ОСНОВНОЙ КОД
# ==============================================================================
add_subdirectory(src)

View File

@ -1,92 +0,0 @@
cmake_minimum_required(VERSION 3.6)
project(MY_APP CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Определение путей
set(SOURCE_RES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../resources")
set(TARGET_RES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../src/main/assets/resources")
# Получаем список всех файлов в исходной директории для отслеживания зависимостей
file(GLOB_RECURSE RES_FILES RELATIVE "${SOURCE_RES_DIR}" "${SOURCE_RES_DIR}/*")
set(COPY_COMMANDS "")
foreach(RES_FILE ${RES_FILES})
set(SRC "${SOURCE_RES_DIR}/${RES_FILE}")
set(DST "${TARGET_RES_DIR}/${RES_FILE}")
# Команда копирования конкретного файла, если он изменился
add_custom_command(
OUTPUT "${DST}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${TARGET_RES_DIR}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SRC}" "${DST}"
DEPENDS "${SRC}"
COMMENT "Syncing resource: ${RES_FILE}"
)
list(APPEND RES_OUTPUTS "${DST}")
endforeach()
# Создаем кастомную цель, которая будет запускать процесс копирования
add_custom_target(sync_resources ALL DEPENDS ${RES_OUTPUTS})
add_library(main SHARED
SDL_android_main.c
../../../../src/BoneAnimatedModel.cpp
../../../../src/Environment.cpp
../../../../src/Game.cpp
../../../../src/main.cpp
../../../../src/Projectile.cpp
../../../../src/SparkEmitter.cpp
../../../../src/TextModel.cpp
../../../../src/UiManager.cpp
../../../../src/utils/Perlin.cpp
../../../../src/utils/TaskManager.cpp
../../../../src/utils/Utils.cpp
../../../../src/planet/PlanetData.cpp
../../../../src/planet/PlanetObject.cpp
../../../../src/planet/StoneObject.cpp
../../../../src/render/FrameBuffer.cpp
../../../../src/render/Renderer.cpp
../../../../src/render/ShaderManager.cpp
../../../../src/render/TextureManager.cpp
../../../../src/render/OpenGlExtensions.cpp
)
# Подключаем заголовки
target_include_directories(main PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../SDL/include
${CMAKE_CURRENT_SOURCE_DIR}/../zlib
${CMAKE_CURRENT_SOURCE_DIR}/../libpng
${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/eigen-5.0.0
${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/boost_1_90_0
${CMAKE_CURRENT_SOURCE_DIR}/../../../../src
${CMAKE_CURRENT_SOURCE_DIR}/../libzip
)
# ВАЖНО: Линкуемся с png_static (статика) или png_shared (динамика)
# Так как мы установили PNG_STATIC=ON и PNG_SHARED=OFF,
# должна создаться цель png_static
target_link_libraries(main
png_static # ЭТО ПРАВИЛЬНОЕ ИМЯ ЦЕЛИ!
z
SDL2
)
find_library(OPENGLES2_LIB GLESv2)
target_link_libraries(main
${OPENGLES2_LIB} # OpenGL ES 2.0/3.0
log
android
OpenSLES
dl
zip
)
add_dependencies(main sync_resources)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,181 +0,0 @@
cmake_minimum_required(VERSION 3.15)
# Фикс для Ninja на Windows
if(NOT CMAKE_MAKE_PROGRAM AND WIN32)
set(POTENTIAL_NINJA "${CMAKE_CURRENT_SOURCE_DIR}/ninja/ninja.exe")
if(EXISTS "${POTENTIAL_NINJA}")
set(CMAKE_MAKE_PROGRAM "${POTENTIAL_NINJA}" CACHE FILEPATH "Path to ninja" FORCE)
endif()
endif()
project(space-game001 CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# --- АВТО-ЗАГРУЗКА ЗАВИСИМОСТЕЙ ---
include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FetchDependencies.cmake")
# Теперь гарантированно есть папка ../thirdparty со всеми исходниками
# Список исходных файлов (без изменений)
set(SOURCES
../src/main.cpp
../src/Game.cpp
../src/Game.h
../src/Environment.cpp
../src/Environment.h
../src/render/Renderer.cpp
../src/render/Renderer.h
../src/render/ShaderManager.cpp
../src/render/ShaderManager.h
../src/render/TextureManager.cpp
../src/render/TextureManager.h
../src/TextModel.cpp
../src/TextModel.h
../src/AudioPlayerAsync.cpp
../src/AudioPlayerAsync.h
../src/BoneAnimatedModel.cpp
../src/BoneAnimatedModel.h
../src/render/OpenGlExtensions.cpp
../src/render/OpenGlExtensions.h
../src/utils/Utils.cpp
../src/utils/Utils.h
../src/SparkEmitter.cpp
../src/SparkEmitter.h
../src/planet/PlanetObject.cpp
../src/planet/PlanetObject.h
../src/planet/PlanetData.cpp
../src/planet/PlanetData.h
../src/utils/Perlin.cpp
../src/utils/Perlin.h
../src/utils/TaskManager.cpp
../src/utils/TaskManager.h
../src/planet/StoneObject.cpp
../src/planet/StoneObject.h
../src/render/FrameBuffer.cpp
../src/render/FrameBuffer.h
../src/UiManager.cpp
../src/UiManager.h
../src/Projectile.h
../src/Projectile.cpp
../src/network/NetworkInterface.h
../src/network/LocalClient.h
../src/network/LocalClient.cpp
../src/network/ClientState.h
../src/network/ClientState.cpp
../src/network/WebSocketClientBase.h
../src/network/WebSocketClientBase.cpp
../src/network/WebSocketClientEmscripten.h
../src/network/WebSocketClientEmscripten.cpp
../src/render/TextRenderer.h
../src/render/TextRenderer.cpp
../src/MenuManager.h
../src/MenuManager.cpp
../src/Space.h
../src/Space.cpp
../src/GameConstants.h
../src/GameConstants.cpp
)
add_executable(space-game001 ${SOURCES})
# Настройка путей к инклудам (используем скачанные исходники)
target_include_directories(space-game001 PRIVATE
../src
../thirdparty/eigen-5.0.0
../thirdparty/boost_1_90_0
)
# Сборка libzip через add_subdirectory (Emscripten соберет её из исходников)
# Опции для либзипа, чтобы он не искал лишнего в системе
set(ENABLE_GNUTLS OFF CACHE BOOL "" FORCE)
set(ENABLE_OPENSSL OFF CACHE BOOL "" FORCE)
set(ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL "" FORCE)
set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE)
add_subdirectory("../thirdparty/libzip-1.11.4" libzip-build)
target_link_libraries(space-game001 PRIVATE zip z websocket.js)
# Эмскриптен-флаги
set(EMSCRIPTEN_FLAGS
"-sUSE_SDL=2"
"-sUSE_SDL_IMAGE=2"
"-sUSE_LIBPNG=1"
"-sUSE_ZLIB=1"
"-sUSE_SDL_TTF=2"
#"-pthread"
#"-sUSE_PTHREADS=1"
"-fexceptions"
"-DNETWORK"
)
target_compile_options(space-game001 PRIVATE ${EMSCRIPTEN_FLAGS} "-O2")
# Only loading.png and the shaders used before resources.zip is ready are preloaded.
# resources.zip is downloaded asynchronously at runtime and served as a separate file.
set(EMSCRIPTEN_LINK_FLAGS
${EMSCRIPTEN_FLAGS}
"-O2"
#"-sPTHREAD_POOL_SIZE=4"
"-sALLOW_MEMORY_GROWTH=1"
"-sFULL_ES3=1"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/loading.png@resources/loading.png"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/shaders@resources/shaders"
)
# Применяем настройки линковки
target_link_options(space-game001 PRIVATE ${EMSCRIPTEN_LINK_FLAGS})
# Для совместимости со старыми версиями CMake, если target_link_options недостаточно
string(REPLACE ";" " " EMSCRIPTEN_LINK_FLAGS_STR "${EMSCRIPTEN_LINK_FLAGS}")
set_target_properties(space-game001 PROPERTIES
LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS_STR}"
SUFFIX ".html"
)
# --- Ресурсы и Деплой (без изменений) ---
set(RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../resources")
set(RESOURCES_ZIP "${CMAKE_CURRENT_BINARY_DIR}/resources.zip")
get_filename_component(RESOURCES_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.." ABSOLUTE)
add_custom_command(
OUTPUT "${RESOURCES_ZIP}"
COMMAND ${CMAKE_COMMAND} -E tar "cf" "${RESOURCES_ZIP}" --format=zip "resources"
WORKING_DIRECTORY "${RESOURCES_PARENT_DIR}"
DEPENDS "${RESOURCES_PARENT_DIR}/resources"
)
add_custom_target(pack_resources DEPENDS "${RESOURCES_ZIP}")
add_dependencies(space-game001 pack_resources)
# Определяем путь к директории установки (относительно папки билда)
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/public")
# 1. Устанавливаем основной HTML файл
install(TARGETS space-game001
RUNTIME DESTINATION .
)
# 2. Устанавливаем сопутствующие файлы (JS, WASM и сгенерированный архив данных)
# Emscripten создает их в той же папке, что и таргет
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/space-game001.js"
"${CMAKE_CURRENT_BINARY_DIR}/space-game001.wasm"
"${CMAKE_CURRENT_BINARY_DIR}/space-game001.data"
DESTINATION .
)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/space-game001plain.html"
DESTINATION .
)
# resources.zip is served separately and downloaded asynchronously at runtime
install(FILES "${RESOURCES_ZIP}" DESTINATION .)
add_custom_command(TARGET space-game001 POST_BUILD
COMMAND ${CMAKE_COMMAND} --install .
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
COMMENT "Automatically deploying to public directory..."
)

View File

@ -1,39 +0,0 @@
# how to build
If emsdk is not installed, you need to clone it from here: https://github.com/emscripten-core/emsdk
and install:
```
C:\Work\Projects\emsdk\emsdk.bat install latest
```
Then activate the environment:
```
C:\Work\Projects\emsdk\emsdk.bat activate latest
C:\Work\Projects\emsdk\emsdk_env.bat
```
Optionally clear cache:
```
emcc --clear-cache
embuilder build sdl2 sdl2_ttf sdl2_image sdl2_image_jpg sdl2_image_png
```
Build:
```
mkdir build
cd build
emcmake cmake -G Ninja ..
cmake --build .
```
Optionally install:
```
cmake --install .
```
Run:
```
emrun --no_browser --port 8080 public
```

Binary file not shown.

View File

@ -1,2 +0,0 @@
<!doctypehtml><html lang=en-us><head><meta charset=utf-8><meta content="text/html; charset=utf-8"http-equiv=Content-Type><title>Emscripten-Generated Code</title><style>body{font-family:arial;margin:0;padding:none}.emscripten{padding-right:0;margin-left:auto;margin-right:auto;display:block}div.emscripten{text-align:center}div.emscripten_border{border:1px solid #000}canvas.emscripten{border:0 none;background-color:#000}#emscripten_logo{display:inline-block;margin:0;padding:6px;width:265px}.spinner{height:30px;width:30px;margin:0;margin-top:20px;margin-left:20px;display:inline-block;vertical-align:top;-webkit-animation:rotation .8s linear infinite;-moz-animation:rotation .8s linear infinite;-o-animation:rotation .8s linear infinite;animation:rotation .8s linear infinite;border-left:5px solid #ebebeb;border-right:5px solid #ebebeb;border-bottom:5px solid #ebebeb;border-top:5px solid #787878;border-radius:100%;background-color:#bdd72e}@-webkit-keyframes rotation{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(360deg)}}@-moz-keyframes rotation{from{-moz-transform:rotate(0)}to{-moz-transform:rotate(360deg)}}@-o-keyframes rotation{from{-o-transform:rotate(0)}to{-o-transform:rotate(360deg)}}@keyframes rotation{from{transform:rotate(0)}to{transform:rotate(360deg)}}#status{display:inline-block;vertical-align:top;margin-top:30px;margin-left:20px;font-weight:700;color:#787878}#progress{height:20px;width:300px}#controls{display:inline-block;float:right;vertical-align:top;margin-top:30px;margin-right:20px}#output{width:100%;height:200px;margin:0 auto;margin-top:10px;border-left:0;border-right:0px;padding-left:0;padding-right:0;display:block;background-color:#000;color:#fff;font-family:'Lucida Console',Monaco,monospace;outline:0}</style></head><body><script src="https://cdn.jsdelivr.net/npm/eruda"></script>
<script>eruda.init();</script><a href=http://emscripten.org><img id=emscripten_logo src=""></a><div class=spinner id=spinner></div><div class=emscripten id=status>Downloading...</div><span id=controls><span><input type=checkbox id=resize>Resize canvas</span> <span><input type=checkbox id=pointerLock checked>Lock/hide mouse pointer    </span><span><input type=button onclick='Module.requestFullscreen(document.getElementById("pointerLock").checked,document.getElementById("resize").checked)'value=Fullscreen></span></span><div class=emscripten><progress hidden id=progress max=100 value=0></progress></div><div class=emscripten_border><canvas class=emscripten id=canvas oncontextmenu=event.preventDefault() tabindex=-1></canvas></div><textarea id=output rows=8></textarea><script>var statusElement=document.getElementById("status"),progressElement=document.getElementById("progress"),spinnerElement=document.getElementById("spinner"),canvasElement=document.getElementById("canvas"),outputElement=document.getElementById("output");outputElement&&(outputElement.value=""),canvasElement.addEventListener("webglcontextlost",(e=>{alert("WebGL context lost. You will need to reload the page."),e.preventDefault()}),!1);var Module={print(...e){if(console.log(...e),outputElement){var t=e.join(" ");outputElement.value+=t+"\n",outputElement.scrollTop=outputElement.scrollHeight}},canvas:canvasElement,setStatus(e){if(Module.setStatus.last||(Module.setStatus.last={time:Date.now(),text:""}),e!==Module.setStatus.last.text){var t=e.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/),n=Date.now();t&&n-Module.setStatus.last.time<30||(Module.setStatus.last.time=n,Module.setStatus.last.text=e,t?(e=t[1],progressElement.value=100*parseInt(t[2]),progressElement.max=100*parseInt(t[4]),progressElement.hidden=!1,spinnerElement.hidden=!1):(progressElement.value=null,progressElement.max=null,progressElement.hidden=!0,e||(spinnerElement.style.display="none")),statusElement.innerHTML=e)}},totalDependencies:0,monitorRunDependencies(e){this.totalDependencies=Math.max(this.totalDependencies,e),Module.setStatus(e?"Preparing... ("+(this.totalDependencies-e)+"/"+this.totalDependencies+")":"All downloads complete.")}};Module.setStatus("Downloading..."),window.onerror=e=>{Module.setStatus("Exception thrown, see JavaScript console"),spinnerElement.style.display="none",Module.setStatus=e=>{e&&console.error("[post-exception status] "+e)}}</script><script async src="space-game001.js" crossorigin="anonymous"></script></body></html>

View File

@ -1,216 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Space Game</title>
<style>
body, html {
margin: 0; padding: 0; width: 100%; height: 100%;
overflow: hidden; background-color: #000;
position: fixed;
}
#canvas {
display: block;
position: absolute;
top: 0; left: 0;
width: 100vw; height: 100vh;
border: none;
}
#fs-button {
position: absolute;
top: 10px; right: 10px;
padding: 10px;
z-index: 10;
background: rgba(255,255,255,0.3);
color: white; border: 1px solid white;
cursor: pointer;
font-family: sans-serif;
border-radius: 5px;
}
#status { color: white; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
/* Nick modal */
#nickOverlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0,0,0,0.85);
z-index: 9999;
}
#nickBox {
background: #111;
border: 1px solid #444;
padding: 24px;
width: 320px;
box-shadow: 0 8px 24px rgba(0,0,0,0.6);
text-align: center;
}
#nickBox h2 { margin: 0 0 12px 0; font-size: 18px; color: #eee; }
#nickBox input[type="text"] {
width: 100%;
padding: 10px;
font-size: 16px;
box-sizing: border-box;
margin-bottom: 12px;
border: 1px solid #333;
background: #000;
color: #fff;
}
#nickBox button {
padding: 10px 16px;
font-size: 16px;
background: #2a9fd6;
border: none;
color: #fff;
cursor: pointer;
}
#nickSkip { margin-left: 8px; background: #666; }
</style>
</head>
<body>
<button id="fs-button">Fullscreen</button>
<div id="status">Downloading...</div>
<canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex="-1"></canvas>
<!--
<script>
var statusElement = document.getElementById("status");
var canvas = document.getElementById("canvas");
var Module = {
canvas: canvas,
setStatus: function(text) {
statusElement.innerHTML = text;
statusElement.style.display = text ? 'block' : 'none';
}
};
document.getElementById('fs-button').addEventListener('click', function() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen().catch(e => {
console.error(`Error attempting to enable full-screen mode: ${e.message}`);
});
} else {
document.exitFullscreen();
}
});
window.addEventListener("orientationchange", function() {
setTimeout(() => {
window.dispatchEvent(new Event('resize'));
}, 200);
});
</script>
<script async src="space-game001.js"></script>-->
<div id="nickOverlay" style="display:none;">
<div id="nickBox">
<h2>Enter your nickname</h2>
<input id="nickInput" type="text" maxlength="32" placeholder="Player" />
<div>
<button id="nickSubmit">Start</button>
</div>
</div>
</div>
<script>
// Utility: подготовить глобальный Module до загрузки Emscripten-скрипта
function prepareModuleEnvironment() {
window.Module = window.Module || {};
var canvasEl = document.getElementById('canvas');
// Устанавливаем canvas для Emscripten, чтобы createContext не падал
window.Module.canvas = canvasEl;
// Подготовим заглушку setStatus, если ещё нет
window.Module.setStatus = window.Module.setStatus || function (text) {
var statusElement = document.getElementById("status");
statusElement.innerHTML = text;
statusElement.style.display = text ? 'block' : 'none';
};
}
// Show overlay only if no nickname saved.
function loadGameScript() {
var s = document.createElement('script');
s.src = 'space-game001.js';
s.async = true;
document.body.appendChild(s);
}
function showNickOverlay() {
var overlay = document.getElementById('nickOverlay');
overlay.style.display = 'flex';
var input = document.getElementById('nickInput');
input.focus();
}
function hideNickOverlay() {
var overlay = document.getElementById('nickOverlay');
overlay.style.display = 'none';
}
function saveNickAndStart(nick) {
try {
if (!nick || nick.trim() === '') nick = 'Player';
localStorage.setItem('spacegame_nick', nick);
} catch (e) {
console.warn('localStorage not available', e);
}
hideNickOverlay();
// перед загрузкой скрипта гарантируем, что Module.canvas задан
prepareModuleEnvironment();
loadGameScript();
}
document.addEventListener('DOMContentLoaded', function() {
// Готовим Module сразу — даже если откроется модалка, поле canvas будет доступно для скрипта (если он загружается позже)
prepareModuleEnvironment();
var stored = null;
try {
stored = localStorage.getItem('spacegame_nick');
} catch (e) {
console.warn('localStorage not available', e);
}
if (stored && stored.trim() !== '') {
// Nick is present — start immediately
loadGameScript();
} else {
// Show modal to request nickname before loading WASM
showNickOverlay();
var submit = document.getElementById('nickSubmit');
var skip = document.getElementById('nickSkip');
var input = document.getElementById('nickInput');
submit.addEventListener('click', function() {
saveNickAndStart(input.value);
});
skip.addEventListener('click', function() {
saveNickAndStart('Player');
});
input.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
saveNickAndStart(input.value);
}
});
}
});
window.addEventListener("orientationchange", function() {
// Chrome на Android обновляет innerWidth/Height не мгновенно.
// Ждем завершения анимации поворота.
setTimeout(() => {
// В Emscripten это вызовет ваш onWindowResized в C++
window.dispatchEvent(new Event('resize'));
}, 200);
});
</script>
</body>
</html>

View File

@ -1,180 +0,0 @@
cmake_minimum_required(VERSION 3.16)
project(space-game001 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ThirdParty.cmake)
# ===========================================
# Основной проект space-game001
# ===========================================
add_executable(space-game001
../src/main.cpp
../src/Game.cpp
../src/Game.h
../src/Environment.cpp
../src/Environment.h
../src/render/Renderer.cpp
../src/render/Renderer.h
../src/render/ShaderManager.cpp
../src/render/ShaderManager.h
../src/render/TextureManager.cpp
../src/render/TextureManager.h
../src/TextModel.cpp
../src/TextModel.h
../src/AudioPlayerAsync.cpp
../src/AudioPlayerAsync.h
../src/BoneAnimatedModel.cpp
../src/BoneAnimatedModel.h
../src/render/OpenGlExtensions.cpp
../src/render/OpenGlExtensions.h
../src/utils/Utils.cpp
../src/utils/Utils.h
../src/SparkEmitter.cpp
../src/SparkEmitter.h
../src/planet/PlanetObject.cpp
../src/planet/PlanetObject.h
../src/planet/PlanetData.cpp
../src/planet/PlanetData.h
../src/utils/Perlin.cpp
../src/utils/Perlin.h
../src/utils/TaskManager.cpp
../src/utils/TaskManager.h
../src/planet/StoneObject.cpp
../src/planet/StoneObject.h
../src/render/FrameBuffer.cpp
../src/render/FrameBuffer.h
../src/UiManager.cpp
../src/UiManager.h
../src/Projectile.h
../src/Projectile.cpp
../src/network/NetworkInterface.h
../src/network/LocalClient.h
../src/network/LocalClient.cpp
../src/network/ClientState.h
../src/network/ClientState.cpp
../src/network/WebSocketClient.h
../src/network/WebSocketClient.cpp
../src/network/WebSocketClientBase.h
../src/network/WebSocketClientBase.cpp
../src/network/WebSocketClientEmscripten.h
../src/network/WebSocketClientEmscripten.cpp
../src/render/TextRenderer.h
../src/render/TextRenderer.cpp
../src/MenuManager.h
../src/MenuManager.cpp
../src/Space.h
../src/Space.cpp
../src/GameConstants.h
../src/GameConstants.cpp
)
# Установка проекта по умолчанию для Visual Studio
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT space-game001)
# include-пути проекта
target_include_directories(space-game001 PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../src"
)
set_target_properties(space-game001 PROPERTIES
OUTPUT_NAME "space-game001"
)
# Определения препроцессора:
# PNG_ENABLED включает код PNG в TextureManager
# SDL_MAIN_HANDLED отключает переопределение main -> SDL_main
target_compile_definitions(space-game001 PRIVATE
WIN32_LEAN_AND_MEAN
PNG_ENABLED
SDL_MAIN_HANDLED
NETWORK
# SIMPLIFIED
)
# Линкуем с SDL2main, если он вообще установлен
target_link_libraries(space-game001 PRIVATE SDL2main_external_lib)
# Линкуем сторонние библиотеки
target_link_libraries(space-game001 PRIVATE
SDL2_external_lib
libpng_external_lib
zlib_external_lib
libzip_external_lib
freetype_external_lib
SDL2_ttf_external_lib
eigen_external_lib
boost_external_lib
)
# Линкуем OpenGL (Windows)
if(WIN32)
target_link_libraries(space-game001 PRIVATE opengl32)
endif()
# ===========================================
# Копирование SDL2d.dll и zlibd.dll рядом с exe
# ===========================================
if (WIN32)
# SDL2: в Debug - SDL2d.dll, в Release - SDL2.dll
set(SDL2_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2_INSTALL_DIR}/bin/SDL2d.dll,${SDL2_INSTALL_DIR}/bin/SDL2.dll>")
set(SDL2_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:space-game001>/SDL2d.dll,$<TARGET_FILE_DIR:space-game001>/SDL2.dll>")
set(LIBZIP_DLL_SRC "$<IF:$<CONFIG:Debug>,${LIBZIP_BASE_DIR}-Debug/bin/zip.dll,${LIBZIP_BASE_DIR}-Release/bin/zip.dll>")
set(ZLIB_DLL_SRC "$<IF:$<CONFIG:Debug>,${ZLIB_INSTALL_DIR}/bin/zlibd.dll,${ZLIB_INSTALL_DIR}/bin/zlib.dll>")
set(ZLIB_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:space-game001>/zlibd.dll,$<TARGET_FILE_DIR:space-game001>/zlib.dll>")
set(SDL2TTF_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2TTF_BASE_DIR}-Debug/bin/SDL2_ttfd.dll,${SDL2TTF_BASE_DIR}-Release/bin/SDL2_ttf.dll>")
add_custom_command(TARGET space-game001 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying DLLs to output folder..."
# Копируем SDL2 (целевое имя всегда SDL2.dll)
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${SDL2_DLL_SRC}"
"${SDL2_DLL_DST}"
# Копируем LIBZIP (целевое имя всегда zip.dll)
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${LIBZIP_DLL_SRC}"
"$<TARGET_FILE_DIR:space-game001>/zip.dll"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${ZLIB_DLL_SRC}"
"${ZLIB_DLL_DST}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${SDL2TTF_DLL_SRC}"
"$<TARGET_FILE_DIR:space-game001>"
)
endif()
# ===========================================
# Копирование ресурсов после сборки
# ===========================================
# Какие папки с ресурсами нужно копировать
set(RUNTIME_RESOURCE_DIRS
"resources"
)
# Копируем ресурсы и шейдеры в папку exe и в корень build/
foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS)
add_custom_command(TARGET space-game001 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying ${resdir} to runtime folders..."
# 1) туда, где лежит exe (build/Debug, build/Release и т.п.)
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/../${resdir}"
"$<TARGET_FILE_DIR:space-game001>/${resdir}"
# 2) в корень build, если захочешь запускать из этой папки
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/../${resdir}"
"${CMAKE_BINARY_DIR}/${resdir}"
)
endforeach()

BIN
resources/Cargo_Base_color_sRGB.png (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
resources/black.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/blue_transparent.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/box/box.png (Stored with Git LFS)

Binary file not shown.

View File

@ -1,29 +0,0 @@
===Vertices (Split by UV/Normal): 14
V 0: Pos(1.0, 1.0, 1.0) Norm(0.57735, 0.57735, 0.57735) UV(0.5, 0.5)
V 1: Pos(-1.0, 1.0, 1.0) Norm(-0.57735, 0.57735, 0.57735) UV(0.75, 0.5)
V 2: Pos(-1.0, -1.0, 1.0) Norm(-0.57735, -0.57735, 0.57735) UV(0.75, 0.75)
V 3: Pos(1.0, -1.0, 1.0) Norm(0.57735, -0.57735, 0.57735) UV(0.5, 0.75)
V 4: Pos(1.0, -1.0, -1.0) Norm(0.57735, -0.57735, -0.57735) UV(0.25, 0.75)
V 5: Pos(-1.0, -1.0, 1.0) Norm(-0.57735, -0.57735, 0.57735) UV(0.5, 1.0)
V 6: Pos(-1.0, -1.0, -1.0) Norm(-0.57735, -0.57735, -0.57735) UV(0.25, 1.0)
V 7: Pos(-1.0, -1.0, -1.0) Norm(-0.57735, -0.57735, -0.57735) UV(0.25, 0.0)
V 8: Pos(-1.0, -1.0, 1.0) Norm(-0.57735, -0.57735, 0.57735) UV(0.5, 0.0)
V 9: Pos(-1.0, 1.0, 1.0) Norm(-0.57735, 0.57735, 0.57735) UV(0.5, 0.25)
V 10: Pos(-1.0, 1.0, -1.0) Norm(-0.57735, 0.57735, -0.57735) UV(0.25, 0.25)
V 11: Pos(-1.0, 1.0, -1.0) Norm(-0.57735, 0.57735, -0.57735) UV(0.0, 0.5)
V 12: Pos(1.0, 1.0, -1.0) Norm(0.57735, 0.57735, -0.57735) UV(0.25, 0.5)
V 13: Pos(-1.0, -1.0, -1.0) Norm(-0.57735, -0.57735, -0.57735) UV(0.0, 0.75)
===Triangles (Indices): 12
Tri: 0 1 2
Tri: 0 2 3
Tri: 4 3 5
Tri: 4 5 6
Tri: 7 8 9
Tri: 7 9 10
Tri: 11 12 4
Tri: 11 4 13
Tri: 12 0 3
Tri: 12 3 4
Tri: 10 9 0
Tri: 10 0 12

BIN
resources/button_minus.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_minus_disabled.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_minus_pressed.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_players.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_plus.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_plus_disabled.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_plus_pressed.png (Stored with Git LFS)

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More