Compare commits

..

No commits in common. "colobot2" and "colobot-gold-0.1.7-alpha" have entirely different histories.

864 changed files with 71506 additions and 57486 deletions

View File

@ -1,211 +0,0 @@
name: Build
on: [push, pull_request]
jobs:
build-linux:
runs-on: ${{ matrix.host_os }}
container: ${{ matrix.container }}
strategy:
matrix:
target_os: [linux]
host_os: [ubuntu-20.04]
container: ['']
fail-fast: false
steps:
- name: Install Colobot dependencies
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends build-essential cmake libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsndfile1-dev libvorbis-dev libogg-dev libpng-dev libglew-dev libopenal-dev libphysfs-dev gettext git po4a vorbis-tools librsvg2-bin xmlstarlet libglm-dev libmpg123-dev
if: matrix.container == ''
- uses: actions/checkout@v3
- name: Checkout the Google Test submodule
run: git submodule update --init -- lib/googletest
- name: Checkout the nlohmann json submodule
run: git submodule update --init -- lib/json
- name: Create build directory
run: cmake -E make_directory build
- name: Run CMake (for Linux)
run: cmake --preset Linux-CI
if: matrix.target_os == 'linux'
- name: Build
run: cmake --build --preset Linux-CI
- name: Install
run: cmake --build --preset Linux-CI --target install
- name: Patch library path
run: patchelf --set-rpath '.' install/colobot
if: matrix.target_os == 'linux'
- name: Upload build
uses: actions/upload-artifact@v3
with:
name: ${{matrix.target_os}}-debug
path: install
if: matrix.host_os == 'ubuntu-20.04'
- name: Create AppImage
working-directory: build
run: |
# Download app image tool
wget -N https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
chmod +x linuxdeploy-x86_64.AppImage
./linuxdeploy-x86_64.AppImage --appimage-extract
# Create AppImage
NO_STRIP=1 ./squashfs-root/AppRun -e colobot --output appimage --appdir colobot.AppDir -d desktop/colobot.desktop -i ../desktop/colobot.svg
chmod +x Colobot-x86_64.AppImage
# Prepare folder for zip
mkdir -p appimage
cp -rp ../install/data appimage/data
cp -rp ../install/lang appimage/lang
cp -p Colobot-x86_64.AppImage appimage/colobot
if: matrix.target_os == 'linux'
- name: Upload AppImage
uses: actions/upload-artifact@v3
with:
name: ${{matrix.target_os}}-debug-AppImage
path: build/appimage
if: matrix.target_os == 'linux' && matrix.host_os == 'ubuntu-20.04'
- name: Run tests
# TODO: Maybe run Windows tests using wine as well?
working-directory: build
run: ./Colobot-UnitTests --gtest_output=xml:gtestresults.xml
if: matrix.target_os == 'linux'
- name: Upload test results
uses: actions/upload-artifact@v3
with:
name: Test results (${{ matrix.target_os }}, ${{ matrix.host_os }})
path: build/gtestresults.xml
if: matrix.target_os == 'linux'
build-macos:
runs-on: ${{ matrix.host_os }}
container: ${{ matrix.container }}
strategy:
matrix:
target_os: [macos]
host_os: [macos-11, macos-12]
container: ['']
fail-fast: false
steps:
- name: Install Colobot dependencies
run: brew install cmake sdl2 sdl2_image sdl2_ttf glew physfs flac libsndfile libvorbis vorbis-tools gettext libicns librsvg wget xmlstarlet glm
if: matrix.container == ''
- uses: actions/checkout@v3
- name: Checkout the Google Test submodule
run: git submodule update --init -- lib/googletest
- name: Checkout the nlohmann json submodule
run: git submodule update --init -- lib/json
- name: Create build directory
run: cmake -E make_directory build
- name: Run CMake (for Mac)
run: cmake --preset MacOS-CI
if: matrix.target_os == 'macos'
- name: Build
run: cmake --build --preset MacOS-CI
- name: Run tests
# TODO: Maybe run Windows tests using wine as well?
working-directory: build
run: ./Colobot-UnitTests --gtest_output=xml:gtestresults.xml
if: matrix.target_os == 'macos'
- name: Upload test results
uses: actions/upload-artifact@v3
with:
name: Test results (${{ matrix.target_os }}, ${{ matrix.host_os }})
path: build/gtestresults.xml
if: matrix.target_os == 'macos'
build-windows:
runs-on: windows-2019
strategy:
matrix:
include:
- arch: amd64
vcpkg_triplet: 'x64-windows-static'
- arch: x86
vcpkg_triplet: 'x86-windows-static'
steps:
- uses: actions/checkout@v3
- name: Checkout the Google Test submodule
run: git submodule update --init -- lib/googletest
- name: Checkout the nlohmann json submodule
run: git submodule update --init -- lib/json
- name: Install Ninja
uses: seanmiddleditch/gha-setup-ninja@master
- name: Setup VS Environment
uses: seanmiddleditch/gha-setup-vsdevenv@master
with:
arch: ${{ matrix.arch }}
- name: Install Colobot dependencies
uses: lukka/run-vcpkg@v7
with:
setupOnly: true
vcpkgGitCommitId: 'f6a5d4e8eb7476b8d7fc12a56dff300c1c986131'
vcpkgTriplet: ${{ matrix.vcpkg_triplet }}
# SHA-256 hash of the vcpkg.json file, recalculated automatically when it changes
appendedCacheKey: ${{ hashFiles( '**/vcpkg.json' ) }}
additionalCachedPaths: ${{ github.workspace }}/build/vcpkg_installed
- name: Install external tools
working-directory: ${{ github.workspace }}
run: |
echo "Downloading gettext..."
(New-Object System.Net.WebClient).DownloadFile("https://github.com/mlocati/gettext-iconv-windows/releases/download/v0.20.2-v1.16/gettext0.20.2-iconv1.16-static-64.zip", "gettext.zip");
echo "Unpacking gettext..."
7z x -ogettext gettext.zip;
echo "Adding gettext to PATH..."
echo "${{ github.workspace }}\gettext\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
echo "Downloading xmlstarlet..."
(New-Object System.Net.WebClient).DownloadFile("https://downloads.sourceforge.net/project/xmlstar/xmlstarlet/1.6.1/xmlstarlet-1.6.1-win32.zip", "xmlstarlet.zip");
echo "Unpacking xmlstarlet..."
7z x -oxmlstarlet xmlstarlet.zip;
echo "Renaming xml.exe to xmlstarlet.exe"
Rename-Item -Path "${{ github.workspace }}\xmlstarlet\xmlstarlet-1.6.1\xml.exe" -NewName "xmlstarlet.exe"
echo "Adding xmlstarlet to PATH..."
echo "${{ github.workspace }}\xmlstarlet\xmlstarlet-1.6.1" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
echo "Downloading rsvg-convert..."
(New-Object System.Net.WebClient).DownloadFile("https://downloads.sourceforge.net/project/tumagcc/rsvg-convert-2.40.20.7z", "rsvg-convert.zip");
echo "Unpacking xmlstarlet..."
7z x -orsvg-convert rsvg-convert.zip;
echo "Adding rsvg-convert to PATH..."
echo "${{ github.workspace }}\rsvg-convert" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
shell: pwsh
- name: Create build directory
run: cmake -E make_directory build
- name: Run CMake (for Windows)
run: cmake --preset Windows-CI -DVCPKG_TARGET_TRIPLET=${{ matrix.vcpkg_triplet }} -DCMAKE_TOOLCHAIN_FILE=${{ env.VCPKG_ROOT }}\scripts\buildsystems\vcpkg.cmake
- name: Build
run: |
$nproc = (Get-CIMInstance -Class 'CIM_Processor').NumberOfLogicalProcessors
cmake --build --preset Windows-CI -j $nproc
shell: pwsh
- name: Install
run: cmake --build --preset Windows-CI --target install
- name: Upload build
uses: actions/upload-artifact@v3
with:
name: windows-msvc-debug-${{ matrix.arch }}
path: install
- name: Run tests
working-directory: build
run: ./Colobot-UnitTests --gtest_output=xml:gtestresults.xml
- name: Upload test results
uses: actions/upload-artifact@v3
with:
name: 'Test results (windows, MSVC, ${{ matrix.arch }})'
path: build/gtestresults.xml
doc:
runs-on: ubuntu-latest
steps:
- name: Install Colobot dependencies
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends build-essential cmake libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsndfile1-dev libvorbis-dev libogg-dev libpng-dev libglew-dev libopenal-dev libphysfs-dev gettext git po4a vorbis-tools librsvg2-bin xmlstarlet doxygen graphviz libglm-dev libmpg123-dev
- uses: actions/checkout@v3
- name: Create build directory
run: cmake -E make_directory build
- name: Checkout the nlohmann json submodule
run: git submodule update --init -- lib/json
- name: Run CMake
working-directory: build
run: cmake ..
- name: Build docs
working-directory: build
run: make doc
- name: Upload docs
uses: actions/upload-artifact@v3
with:
name: doc
path: build/doc

View File

@ -1,21 +0,0 @@
name: Verify pull request target
on: [pull_request_target]
jobs:
check_pr_target:
runs-on: ubuntu-latest
steps:
- name: Send comment if wrong pull request target
if: github.base_ref == 'master'
uses: peter-evans/create-or-update-comment@v1
with:
issue-number: ${{ github.event.number }}
body: |
Hey! This pull request targets the `master` branch. You should probably target `dev` instead. Make sure to read the [contributing guidelines](https://github.com/colobot/colobot/blob/master/CONTRIBUTING.md#submitting-pull-requests) and [edit the target branch if necessary](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/changing-the-base-branch-of-a-pull-request).
- name: Wrong pull request target
if: github.base_ref == 'master'
run: echo "This pull request targets the master branch. Please edit the pull request to target dev." && exit 1
- name: Correct pull request target
if: github.base_ref != 'master'
run: echo "This pull request targets the correct branch." && exit 0

19
.gitignore vendored
View File

@ -11,12 +11,11 @@ Makefile
/src/libcolobotbase.a
# Ignore the generated documentation
CMakeDoxyfile.in
CMakeDoxygenDefaults.cmake
/doc
/Doxyfile
# Ignore targets
/colobot
/src/CBot/libCBot.so
# Ignore local data
@ -24,7 +23,7 @@ CMakeDoxygenDefaults.cmake
/saves
# Standard build directory
/build*
/build
# Ignore KDevelop files
.kdev4
@ -36,17 +35,3 @@ CMakeDoxygenDefaults.cmake
# Ignore QtCreator temp files
CMakeLists.txt.user
CMakeLists.txt.user.*
# Ignore Visual Studio Code files
/.vscode
# Ignore CLion files
/.idea
# Ignore Visual Studio files
/CMakeSettings.json
/.vs
/out
# Ignore CMakeUserPresets.json
CMakeUserPresets.json

11
.gitmodules vendored
View File

@ -1,12 +1,3 @@
[submodule "data"]
path = data
url = https://github.com/colobot/colobot-data.git
branch = .
update = rebase
[submodule "lib/googletest"]
path = lib/googletest
url = https://github.com/google/googletest.git
ignore = all
[submodule "lib/json"]
path = lib/json
url = https://github.com/nlohmann/json
url = git://github.com/colobot/colobot-data.git

View File

@ -1,175 +0,0 @@
if(CBOT_STATIC)
add_library(CBot STATIC)
else()
add_library(CBot SHARED)
install(TARGETS CBot
LIBRARY DESTINATION ${COLOBOT_INSTALL_LIB_DIR}
ARCHIVE DESTINATION ${COLOBOT_INSTALL_LIB_DIR}
RUNTIME DESTINATION ${COLOBOT_INSTALL_BIN_DIR})
endif()
target_sources(CBot PRIVATE
src/CBot/CBot.h
src/CBot/CBotCStack.cpp
src/CBot/CBotCStack.h
src/CBot/CBotClass.cpp
src/CBot/CBotClass.h
src/CBot/CBotDebug.cpp
src/CBot/CBotDebug.h
src/CBot/CBotDefParam.cpp
src/CBot/CBotDefParam.h
src/CBot/CBotDefines.h
src/CBot/CBotEnums.h
src/CBot/CBotExternalCall.cpp
src/CBot/CBotExternalCall.h
src/CBot/CBotFileUtils.cpp
src/CBot/CBotFileUtils.h
src/CBot/CBotInstr/CBotBlock.cpp
src/CBot/CBotInstr/CBotBlock.h
src/CBot/CBotInstr/CBotBoolExpr.cpp
src/CBot/CBotInstr/CBotBoolExpr.h
src/CBot/CBotInstr/CBotBreak.cpp
src/CBot/CBotInstr/CBotBreak.h
src/CBot/CBotInstr/CBotCase.cpp
src/CBot/CBotInstr/CBotCase.h
src/CBot/CBotInstr/CBotCatch.cpp
src/CBot/CBotInstr/CBotCatch.h
src/CBot/CBotInstr/CBotCondition.cpp
src/CBot/CBotInstr/CBotCondition.h
src/CBot/CBotInstr/CBotDefArray.cpp
src/CBot/CBotInstr/CBotDefArray.h
src/CBot/CBotInstr/CBotDefBoolean.cpp
src/CBot/CBotInstr/CBotDefBoolean.h
src/CBot/CBotInstr/CBotDefClass.cpp
src/CBot/CBotInstr/CBotDefClass.h
src/CBot/CBotInstr/CBotDefFloat.cpp
src/CBot/CBotInstr/CBotDefFloat.h
src/CBot/CBotInstr/CBotDefInt.cpp
src/CBot/CBotInstr/CBotDefInt.h
src/CBot/CBotInstr/CBotDefString.cpp
src/CBot/CBotInstr/CBotDefString.h
src/CBot/CBotInstr/CBotDo.cpp
src/CBot/CBotInstr/CBotDo.h
src/CBot/CBotInstr/CBotEmpty.cpp
src/CBot/CBotInstr/CBotEmpty.h
src/CBot/CBotInstr/CBotExprLitBool.cpp
src/CBot/CBotInstr/CBotExprLitBool.h
src/CBot/CBotInstr/CBotExprLitChar.cpp
src/CBot/CBotInstr/CBotExprLitChar.h
src/CBot/CBotInstr/CBotExprLitNan.cpp
src/CBot/CBotInstr/CBotExprLitNan.h
src/CBot/CBotInstr/CBotExprLitNull.cpp
src/CBot/CBotInstr/CBotExprLitNull.h
src/CBot/CBotInstr/CBotExprLitNum.cpp
src/CBot/CBotInstr/CBotExprLitNum.h
src/CBot/CBotInstr/CBotExprLitString.cpp
src/CBot/CBotInstr/CBotExprLitString.h
src/CBot/CBotInstr/CBotExprRetVar.cpp
src/CBot/CBotInstr/CBotExprRetVar.h
src/CBot/CBotInstr/CBotExprUnaire.cpp
src/CBot/CBotInstr/CBotExprUnaire.h
src/CBot/CBotInstr/CBotExprVar.cpp
src/CBot/CBotInstr/CBotExprVar.h
src/CBot/CBotInstr/CBotExpression.cpp
src/CBot/CBotInstr/CBotExpression.h
src/CBot/CBotInstr/CBotFieldExpr.cpp
src/CBot/CBotInstr/CBotFieldExpr.h
src/CBot/CBotInstr/CBotFor.cpp
src/CBot/CBotInstr/CBotFor.h
src/CBot/CBotInstr/CBotFunction.cpp
src/CBot/CBotInstr/CBotFunction.h
src/CBot/CBotInstr/CBotIf.cpp
src/CBot/CBotInstr/CBotIf.h
src/CBot/CBotInstr/CBotIndexExpr.cpp
src/CBot/CBotInstr/CBotIndexExpr.h
src/CBot/CBotInstr/CBotInstr.cpp
src/CBot/CBotInstr/CBotInstr.h
src/CBot/CBotInstr/CBotInstrCall.cpp
src/CBot/CBotInstr/CBotInstrCall.h
src/CBot/CBotInstr/CBotInstrMethode.cpp
src/CBot/CBotInstr/CBotInstrMethode.h
src/CBot/CBotInstr/CBotInstrUtils.cpp
src/CBot/CBotInstr/CBotInstrUtils.h
src/CBot/CBotInstr/CBotLeftExpr.cpp
src/CBot/CBotInstr/CBotLeftExpr.h
src/CBot/CBotInstr/CBotLeftExprVar.cpp
src/CBot/CBotInstr/CBotLeftExprVar.h
src/CBot/CBotInstr/CBotListArray.cpp
src/CBot/CBotInstr/CBotListArray.h
src/CBot/CBotInstr/CBotListExpression.cpp
src/CBot/CBotInstr/CBotListExpression.h
src/CBot/CBotInstr/CBotListInstr.cpp
src/CBot/CBotInstr/CBotListInstr.h
src/CBot/CBotInstr/CBotLogicExpr.cpp
src/CBot/CBotInstr/CBotLogicExpr.h
src/CBot/CBotInstr/CBotNew.cpp
src/CBot/CBotInstr/CBotNew.h
src/CBot/CBotInstr/CBotParExpr.cpp
src/CBot/CBotInstr/CBotParExpr.h
src/CBot/CBotInstr/CBotPostIncExpr.cpp
src/CBot/CBotInstr/CBotPostIncExpr.h
src/CBot/CBotInstr/CBotPreIncExpr.cpp
src/CBot/CBotInstr/CBotPreIncExpr.h
src/CBot/CBotInstr/CBotRepeat.cpp
src/CBot/CBotInstr/CBotRepeat.h
src/CBot/CBotInstr/CBotReturn.cpp
src/CBot/CBotInstr/CBotReturn.h
src/CBot/CBotInstr/CBotSwitch.cpp
src/CBot/CBotInstr/CBotSwitch.h
src/CBot/CBotInstr/CBotThrow.cpp
src/CBot/CBotInstr/CBotThrow.h
src/CBot/CBotInstr/CBotTry.cpp
src/CBot/CBotInstr/CBotTry.h
src/CBot/CBotInstr/CBotTwoOpExpr.cpp
src/CBot/CBotInstr/CBotTwoOpExpr.h
src/CBot/CBotInstr/CBotWhile.cpp
src/CBot/CBotInstr/CBotWhile.h
src/CBot/CBotProgram.cpp
src/CBot/CBotProgram.h
src/CBot/CBotStack.cpp
src/CBot/CBotStack.h
src/CBot/CBotToken.cpp
src/CBot/CBotToken.h
src/CBot/CBotTypResult.cpp
src/CBot/CBotTypResult.h
src/CBot/CBotUtils.cpp
src/CBot/CBotUtils.h
src/CBot/CBotVar/CBotVar.cpp
src/CBot/CBotVar/CBotVar.h
src/CBot/CBotVar/CBotVarValue.h
src/CBot/CBotVar/CBotVarArray.cpp
src/CBot/CBotVar/CBotVarArray.h
src/CBot/CBotVar/CBotVarBoolean.cpp
src/CBot/CBotVar/CBotVarBoolean.h
src/CBot/CBotVar/CBotVarByte.h
src/CBot/CBotVar/CBotVarChar.h
src/CBot/CBotVar/CBotVarClass.cpp
src/CBot/CBotVar/CBotVarClass.h
src/CBot/CBotVar/CBotVarDouble.h
src/CBot/CBotVar/CBotVarFloat.cpp
src/CBot/CBotVar/CBotVarFloat.h
src/CBot/CBotVar/CBotVarInt.cpp
src/CBot/CBotVar/CBotVarInt.h
src/CBot/CBotVar/CBotVarLong.h
src/CBot/CBotVar/CBotVarPointer.cpp
src/CBot/CBotVar/CBotVarPointer.h
src/CBot/CBotVar/CBotVarShort.h
src/CBot/CBotVar/CBotVarString.cpp
src/CBot/CBotVar/CBotVarString.h
src/CBot/stdlib/Compilation.cpp
src/CBot/stdlib/Compilation.h
src/CBot/stdlib/FileFunctions.cpp
src/CBot/stdlib/MathFunctions.cpp
src/CBot/stdlib/StringFunctions.cpp
src/CBot/stdlib/stdlib.h
src/CBot/stdlib/stdlib_public.h
)
target_include_directories(CBot PUBLIC src)
target_link_libraries(CBot PRIVATE
Colobot-Common
)
if(COLOBOT_LINT_BUILD)
add_fake_header_sources("src/CBot" CBot)
endif()

View File

@ -1,367 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotFileUtils.h"
#include "CBot/CBotClass.h"
#include "CBot/CBotEnums.h"
namespace CBot
{
template<typename T>
static bool WriteBinary(std::ostream &ostr, T value, unsigned padTo = 0)
{
unsigned char chr;
unsigned count = 1;
while (value > 127) // unsigned LEB128
{
++count;
chr = (value & 0x7F) | 0x80;
if (!ostr.write(reinterpret_cast<char*>(&chr), 1)) return false;
value >>= 7;
}
chr = value & 0x7F;
if (count < padTo) chr |= 0x80;
if (!ostr.write(reinterpret_cast<char*>(&chr), 1)) return false;
if (count < padTo)
{
while (++count < padTo)
if (!(ostr << '\x80')) return false;
if (!(ostr << '\x00')) return false;
}
return true;
}
template<typename T>
static bool ReadBinary(std::istream &istr, T &value)
{
value = 0;
unsigned char chr;
unsigned shift = 0;
while (true) // unsigned LEB128
{
if (!istr.read(reinterpret_cast<char*>(&chr), 1)) return false;
if (shift < sizeof(T) * 8)
value |= static_cast<T>(chr & 0x7F) << shift;
shift += 7;
if ((chr & 0x80) == 0) break;
}
return true;
}
template<typename T>
static bool WriteSignedBinary(std::ostream &ostr, T value, unsigned padTo = 0)
{
signed char sign = value >> (8 * sizeof(T) - 1);
unsigned count = 0;
while (true) // signed LEB128
{
++count;
unsigned char chr = value & 0x7F;
value >>= 7;
if (!(value != sign || ((chr ^ sign) & 0x40) != 0))
{
if (count < padTo) chr |= 0x80;
if (!ostr.write(reinterpret_cast<char*>(&chr), 1)) return false;
break;
}
chr |= 0x80;
if (!ostr.put(chr)) return false;
}
if (count < padTo)
{
char chr = (sign < 0) ? 0x7F : 0x00;
while (++count < padTo)
if (!ostr.put(chr | 0x80)) return false;
if (!ostr.put(chr)) return false;
}
return true;
}
template<typename T>
static bool ReadSignedBinary(std::istream &istr, T &value)
{
value = 0;
unsigned char chr;
unsigned shift = 0;
while (true) // signed LEB128
{
if (!istr.read(reinterpret_cast<char*>(&chr), 1)) return false;
if (shift < sizeof(T) * 8 - 1)
value |= (static_cast<T>(chr & 0x7F) << shift);
shift += 7;
if ((chr & 0x80) == 0) break;
}
if (shift >= 8 * sizeof(T) - 1) shift = 8 * sizeof(T) - 1;
if ((chr & 0x40) != 0)
value |= static_cast<T>(-1) << shift;
return true;
}
bool WriteWord(std::ostream &ostr, unsigned short w)
{
return WriteBinary<unsigned short>(ostr, w);
}
bool ReadWord(std::istream &istr, unsigned short &w)
{
return ReadBinary<unsigned short>(istr, w);
}
bool WriteByte(std::ostream &ostr, char c)
{
if (!ostr.put(c)) return false;
return true;
}
bool ReadByte(std::istream &istr, char& c)
{
if (!istr.get(c)) return false;
return true;
}
bool WriteShort(std::ostream &ostr, short s)
{
return WriteSignedBinary<short>(ostr, s);
}
bool ReadShort(std::istream &istr, short &s)
{
return ReadSignedBinary<short>(istr, s);
}
bool WriteUInt32(std::ostream &ostr, uint32_t i)
{
return WriteBinary<uint32_t>(ostr, i);
}
bool ReadUInt32(std::istream &istr, uint32_t &i)
{
return ReadBinary<uint32_t>(istr, i);
}
bool WriteInt(std::ostream &ostr, int i)
{
return WriteSignedBinary<int>(ostr, i);
}
bool ReadInt(std::istream &istr, int &i)
{
return ReadSignedBinary<int>(istr, i);
}
bool WriteLong(std::ostream &ostr, long l, unsigned padTo)
{
return WriteSignedBinary<long>(ostr, l, padTo);
}
bool ReadLong(std::istream &istr, long &l)
{
return ReadSignedBinary<long>(istr, l);
}
bool WriteFloat(std::ostream &ostr, float f)
{
union TypeConverter
{
float fValue;
uint32_t iValue;
};
TypeConverter u;
u.fValue = 0.0f;
u.iValue = 0;
u.fValue = f;
return WriteBinary<uint32_t>(ostr, u.iValue);
}
bool ReadFloat(std::istream &istr, float &f)
{
union TypeConverter
{
float fValue;
uint32_t iValue;
};
TypeConverter u;
u.fValue = 0.0f;
u.iValue = 0;
if (!ReadBinary<uint32_t>(istr, u.iValue)) return false;
f = u.fValue;
return true;
}
bool WriteDouble(std::ostream &ostr, double d)
{
union TypeConverter
{
double dValue;
uint64_t iValue;
};
TypeConverter u;
u.dValue = 0.0;
u.iValue = 0;
u.dValue = d;
return WriteBinary<uint64_t>(ostr, u.iValue);
}
bool ReadDouble(std::istream &istr, double &d)
{
union TypeConverter
{
double dValue;
uint64_t iValue;
};
TypeConverter u;
u.dValue = 0.0;
u.iValue = 0;
if (!ReadBinary<uint64_t>(istr, u.iValue)) return false;
d = u.dValue;
return true;
}
bool WriteString(std::ostream &ostr, const std::string &s)
{
if (!WriteBinary<size_t>(ostr, s.size())) return false;
if (!ostr.write(&(s[0]), s.size())) return false;
return true;
}
bool ReadString(std::istream &istr, std::string &s)
{
size_t length = 0;
if (!ReadBinary<size_t>(istr, length)) return false;
s.resize(length);
if (length != 0)
{
if (!istr.read(&(s[0]), length)) return false;
}
return true;
}
bool WriteType(std::ostream &ostr, const CBotTypResult &type)
{
int typ = type.GetType();
if ( typ == CBotTypIntrinsic ) typ = CBotTypClass;
if ( !WriteWord(ostr, typ) ) return false;
if ( typ == CBotTypClass )
{
CBotClass* p = type.GetClass();
if (!WriteString(ostr, p->GetName())) return false;
}
if ( type.Eq( CBotTypArrayBody ) ||
type.Eq( CBotTypArrayPointer ) )
{
if (!WriteWord(ostr, type.GetLimite())) return false;
if (!WriteType(ostr, type.GetTypElem())) return false;
}
if ( type.Eq(CBotTypPointer) )
{
if (type.GetClass() != nullptr)
{
if (!WriteString(ostr, type.GetClass()->GetName())) return false;
}
else if (!WriteString(ostr, "")) return false;
}
return true;
}
bool ReadType(std::istream &istr, CBotTypResult &type)
{
unsigned short w, ww;
if (!ReadWord(istr, w)) return false;
type.SetType(w);
if ( type.Eq( CBotTypIntrinsic ) )
{
type = CBotTypResult( w, "point" );
}
if ( type.Eq( CBotTypClass ) )
{
std::string s;
if (!ReadString(istr, s)) return false;
type = CBotTypResult( w, s );
}
if ( type.Eq( CBotTypArrayPointer ) ||
type.Eq( CBotTypArrayBody ) )
{
CBotTypResult r;
if (!ReadWord(istr, ww)) return false;
if (!ReadType(istr, r)) return false;
type = CBotTypResult( w, r );
type.SetLimite(static_cast<short>(ww));
}
if ( type.Eq(CBotTypPointer) )
{
std::string className;
if (!ReadString(istr, className)) return false;
type = CBotTypResult(w, className);
}
return true;
}
bool WriteStream(std::ostream &ostr, std::istream& istr)
{
if (!istr.seekg(0, istr.end)) return false;
auto size = istr.tellg();
if (size == 0) return WriteLong(ostr, 0);
if (!WriteLong(ostr, size)) return false;
if (!istr.seekg(0, istr.beg)) return false;
while (size > 0)
{
size -= 1;
if (!ostr.put(istr.get())) return false;
}
return true;
}
bool ReadStream(std::istream& istr, std::ostream &ostr)
{
long length;
if (!ReadLong(istr, length)) return false;
if (length == 0) return true;
while (length-- > 0)
{
if (!ostr.put(istr.get())) return false;
}
return true;
}
} // namespace CBot

View File

@ -1,217 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include <cstdint>
#include <iostream>
#include <string>
namespace CBot
{
class CBotVar;
class CBotTypResult;
/*!
* \brief Save a linked list if variables
* \param ostr Output stream
* \param pVar First variable in the list
* \return true on success
*/
bool SaveVars(std::ostream &ostr, CBotVar* pVar);
/*!
* \brief WriteWord
* \param ostr Output stream
* \param w
* \return true on success
*/
bool WriteWord(std::ostream &ostr, unsigned short w);
/*!
* \brief ReadWord
* \param istr Input stream
* \param[out] w
* \return true on success
*/
bool ReadWord(std::istream &istr, unsigned short &w);
/*!
* \brief WriteByte
* \param ostr Output stream
* \param c
* \return true on success
*/
bool WriteByte(std::ostream &ostr, char c);
/*!
* \brief ReadByte
* \param istr Input stream
* \param[out] c
* \return true on success
*/
bool ReadByte(std::istream &istr, char& c);
/*!
* \brief WriteShort
* \param ostr Output stream
* \param s
* \return true on success
*/
bool WriteShort(std::ostream &ostr, short s);
/*!
* \brief ReadShort
* \param istr Input stream
* \param[out] s
* \return true on success
*/
bool ReadShort(std::istream &istr, short &s);
/*!
* \brief WriteUInt32
* \param ostr Output stream
* \param i
* \return true on success
*/
bool WriteUInt32(std::ostream &ostr, uint32_t i);
/*!
* \brief ReadUInt32
* \param istr Input stream
* \param[out] i
* \return true on success
*/
bool ReadUInt32(std::istream &istr, uint32_t &i);
/*!
* \brief WriteInt
* \param ostr Output stream
* \param i
* \return true on success
*/
bool WriteInt(std::ostream &ostr, int i);
/*!
* \brief ReadInt
* \param istr Input stream
* \param[out] i
* \return true on success
*/
bool ReadInt(std::istream &istr, int &i);
/*!
* \brief WriteLong
* \param ostr Output stream
* \param l
* \param padTo minimum number of bytes to write
* \return true on success
*/
bool WriteLong(std::ostream &ostr, long l, unsigned padTo = 0);
/*!
* \brief ReadLong
* \param istr Input stream
* \param[out] l
* \return true on success
*/
bool ReadLong(std::istream &istr, long &l);
/*!
* \brief WriteFloat
* \param ostr Output stream
* \param f
* \return true on success
*/
bool WriteFloat(std::ostream &ostr, float f);
/*!
* \brief ReadFloat
* \param istr Input stream
* \param[out] f
* \return true on success
*/
bool ReadFloat(std::istream &istr, float &f);
/*!
* \brief WriteDouble
* \param ostr Output stream
* \param d
* \return true on success
*/
bool WriteDouble(std::ostream &ostr, double d);
/*!
* \brief ReadDouble
* \param istr Input stream
* \param[out] d
* \return true on success
*/
bool ReadDouble(std::istream &istr, double &d);
/*!
* \brief WriteString
* \param ostr Output stream
* \param s
* \return true on success
*/
bool WriteString(std::ostream &ostr, const std::string &s);
/*!
* \brief ReadString
* \param istr Input stream
* \param[out] s
* \return true on success
*/
bool ReadString(std::istream &istr, std::string &s);
/*!
* \brief WriteType
* \param ostr Output stream
* \param type
* \return true on success
*/
bool WriteType(std::ostream &ostr, const CBotTypResult &type);
/*!
* \brief ReadType
* \param istr Input stream
* \param[out] type
* \return true on success
*/
bool ReadType(std::istream &istr, CBotTypResult &type);
/*!
* \brief WriteStream
* \param ostr Output stream
* \param istr Input stream
* \return true on success
*/
bool WriteStream(std::ostream &ostr, std::istream& istr);
/*!
* \brief ReadStream
* \param istr Input stream
* \param ostr Output stream
* \return true on success
*/
bool ReadStream(std::istream& istr, std::ostream &ostr);
} // namespace CBot

View File

@ -1,137 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotInstr/CBotCase.h"
#include "CBot/CBotInstr/CBotTwoOpExpr.h"
#include "CBot/CBotStack.h"
#include "CBot/CBotCStack.h"
namespace CBot
{
////////////////////////////////////////////////////////////////////////////////
CBotCase::CBotCase()
{
m_instr = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
CBotCase::~CBotCase()
{
delete m_instr;
}
CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack, std::unordered_map<long, CBotInstr*>& labels)
{
CBotToken* pp = p; // preserves at the ^ token (starting position)
if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return nullptr; // should never happen
pStack->SetStartError(pp->GetStart());
long labelValue = 0;
if (pp->GetType() == ID_CASE)
{
CBotInstr* i = nullptr;
if (nullptr != (i = CBotTwoOpExpr::Compile(p, pStack, nullptr, true)))
{
if (pStack->GetType() <= CBotTypLong)
{
CBotStack* pile = CBotStack::AllocateStack();
while ( !i->Execute(pile) );
labelValue = pile->GetVar()->GetValLong();
pile->Delete();
if (labels.count(labelValue) > 0)
{
pStack->SetError(CBotErrRedefCase, p->GetStart());
}
}
else
pStack->SetError(CBotErrBadNum, p->GetStart());
delete i;
}
else
pStack->SetError(CBotErrBadNum, p->GetStart());
}
if (pStack->IsOk() && IsOfType(p, ID_DOTS))
{
CBotCase* newCase = new CBotCase();
newCase->SetToken(pp);
if (pp->GetType() == ID_CASE)
labels[labelValue] = newCase;
return newCase;
}
pStack->SetError(CBotErrNoDoubleDots, p->GetStart());
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotCase::Execute(CBotStack* &pj)
{
if (m_instr == nullptr) return true;
CBotStack* pile = pj->AddStack(this, CBotStack::BlockVisibilityType::BLOCK);
int state = pile->GetState();
CBotInstr* p = m_instr;
while (state-- > 0) p = p->GetNext();
while (p != nullptr)
{
if (!p->Execute(pile)) return false;
pile->IncState();
p = p->GetNext();
}
pile->Delete();
return pj->IsOk();
}
////////////////////////////////////////////////////////////////////////////////
void CBotCase::RestoreState(CBotStack* &pj, bool bMain)
{
if (!bMain) return;
CBotStack* pile = pj->RestoreStack(this);
if (pile == nullptr) return;
CBotInstr* p = m_instr;
int state = pile->GetState();
while (p != nullptr && state-- > 0)
{
p->RestoreState(pile, bMain);
p = p->GetNext();
}
if (p != nullptr) p->RestoreState(pile, bMain);
}
std::map<std::string, CBotInstr*> CBotCase::GetDebugLinks()
{
auto links = CBotInstr::GetDebugLinks();
links["m_instr"] = m_instr;
return links;
}
} // namespace CBot

View File

@ -1,151 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotInstr/CBotExprLitChar.h"
#include "CBot/CBotStack.h"
#include "CBot/CBotCStack.h"
#include "CBot/CBotVar/CBotVar.h"
namespace CBot
{
CBotExprLitChar::CBotExprLitChar()
{
}
CBotExprLitChar::~CBotExprLitChar()
{
}
CBotInstr* CBotExprLitChar::Compile(CBotToken* &p, CBotCStack* pStack)
{
CBotCStack* pStk = pStack->TokenStack();
const auto& s = p->GetString();
auto it = s.cbegin();
if (++it != s.cend())
{
if (*it != '\'') // not empty quotes ?
{
uint32_t valchar = 0;
int pos = p->GetStart() + 1;
if (*it != '\\') valchar = *(it++); // not escape sequence ?
else if (++it != s.cend())
{
pStk->SetStartError(pos++);
unsigned char c = *(it++);
if (c == '\"' || c == '\'' || c == '\\') valchar = c;
else if (c == 'a') valchar = '\a'; // alert bell
else if (c == 'b') valchar = '\b'; // backspace
else if (c == 'f') valchar = '\f'; // form feed
else if (c == 'n') valchar = '\n'; // new line
else if (c == 'r') valchar = '\r'; // carriage return
else if (c == 't') valchar = '\t'; // horizontal tab
else if (c == 'v') valchar = '\v'; // vertical tab
else if (c == 'u' || c == 'U') // unicode escape
{
if (it != s.cend())
{
std::string hex = "";
size_t maxlen = (c == 'u') ? 4 : 8;
for (size_t i = 0; i < maxlen; i++)
{
if (!CharInList(*it, "0123456789ABCDEFabcdef")) break;
++pos;
hex += *it;
if (++it == s.cend()) break;
}
if (maxlen == hex.length()) // unicode character
{
try
{
valchar = std::stoi(hex, nullptr, 16);
if (0x10FFFF < valchar || (0xD7FF < valchar && valchar < 0xE000))
pStk->SetError(CBotErrUnicodeName, pos + 1);
}
catch (const std::out_of_range& e)
{
pStk->SetError(CBotErrHexRange, pos + 1);
}
}
else
pStk->SetError(CBotErrHexDigits, pos + 1);
}
else
pStk->SetError(CBotErrHexDigits, pos + 1);
}
else
pStk->SetError(CBotErrBadEscape, pos + 1);
}
if (it == s.cend() || *it != '\'')
pStk->SetError(CBotErrEndQuote, p);
if (pStk->IsOk())
{
CBotExprLitChar* inst = new CBotExprLitChar();
inst->m_valchar = valchar;
inst->SetToken(p);
p = p->GetNext();
CBotVar* var = CBotVar::Create("", CBotTypChar);
pStk->SetVar(var);
return pStack->Return(inst, pStk);
}
}
pStk->SetError(CBotErrCharEmpty, p);
}
pStk->SetError(CBotErrEndQuote, p);
return pStack->Return(nullptr, pStk);
}
bool CBotExprLitChar::Execute(CBotStack* &pj)
{
CBotStack* pile = pj->AddStack(this);
if (pile->IfStep()) return false;
CBotVar* var = CBotVar::Create("", CBotTypChar);
var->SetValChar(m_valchar);
pile->SetVar(var);
return pj->Return(pile);
}
void CBotExprLitChar::RestoreState(CBotStack* &pj, bool bMain)
{
if (bMain) pj->RestoreStack(this);
}
std::string CBotExprLitChar::GetDebugData()
{
return m_token.GetString();
}
} // namespace CBot

View File

@ -1,199 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotInstr/CBotExprLitNum.h"
#include "CBot/CBotStack.h"
#include "CBot/CBotCStack.h"
#include "CBot/CBotVar/CBotVar.h"
#include "CBot/CBotUtils.h"
#include <limits>
#include <sstream>
namespace CBot
{
template <>
CBotExprLitNum<int>::CBotExprLitNum(int val) : m_numtype(CBotTypInt), m_value(val)
{
}
template <>
CBotExprLitNum<long>::CBotExprLitNum(long val) : m_numtype(CBotTypLong), m_value(val)
{
}
template <>
CBotExprLitNum<float>::CBotExprLitNum(float val) : m_numtype(CBotTypFloat), m_value(val)
{
}
template <>
CBotExprLitNum<double>::CBotExprLitNum(double val) : m_numtype(CBotTypDouble), m_value(val)
{
}
template <typename T>
CBotExprLitNum<T>::~CBotExprLitNum()
{
}
CBotInstr* CompileExprLitNum(CBotToken* &p, CBotCStack* pStack)
{
CBotCStack* pStk = pStack->TokenStack();
const auto& s = p->GetString();
CBotInstr* inst = nullptr;
CBotType numtype = CBotTypInt;
if (p->GetType() == TokenTypDef)
{
inst = new CBotExprLitNum<int>(static_cast<int>(p->GetKeywordId()));
}
else
{
if (s.find('.') != std::string::npos || ( s.find('x') == std::string::npos && ( s.find_first_of("eE") != std::string::npos ) ))
{
double val = GetNumFloat(s);
if (val > static_cast<double>(std::numeric_limits<float>::max()))
{
numtype = CBotTypDouble;
inst = new CBotExprLitNum<double>(val);
}
else
{
numtype = CBotTypFloat;
inst = new CBotExprLitNum<float>(static_cast<float>(val));
}
}
else
{
long val = GetNumInt(s);
if (val > std::numeric_limits<int>::max())
{
numtype = CBotTypLong;
inst = new CBotExprLitNum<long>(val);
}
else
{
inst = new CBotExprLitNum<int>(static_cast<int>(val));
}
}
}
inst->SetToken(p);
if (pStk->NextToken(p))
{
CBotVar* var = CBotVar::Create("", numtype);
pStk->SetVar(var);
return pStack->Return(inst, pStk);
}
delete inst;
return pStack->Return(nullptr, pStk);
}
CBotInstr* CompileSizeOf(CBotToken* &p, CBotCStack* pStack)
{
CBotToken* pp = p;
if (!IsOfType(p, TokenTypVar)) return nullptr;
if (pp->GetString() == "sizeof" && IsOfType(p, ID_OPENPAR))
{
CBotCStack* pStk = pStack->TokenStack();
int value;
if (IsOfType(p, ID_BYTE)) value = sizeof(signed char);
else if (IsOfType(p, ID_SHORT)) value = sizeof(short);
else if (IsOfType(p, ID_CHAR)) value = sizeof(uint32_t);
else if (IsOfType(p, ID_INT)) value = sizeof(int);
else if (IsOfType(p, ID_LONG)) value = sizeof(long);
else if (IsOfType(p, ID_FLOAT)) value = sizeof(float);
else if (IsOfType(p, ID_DOUBLE)) value = sizeof(double);
else
{
p = pp;
return pStack->Return(nullptr, pStk);
}
if (IsOfType(p, ID_CLOSEPAR))
{
auto inst = new CBotExprLitNum<int>(value);
inst->SetToken(pp);
CBotVar* var = CBotVar::Create("", CBotTypInt);
pStk->SetVar(var);
return pStack->Return(inst, pStk);
}
pStk->SetError(CBotErrClosePar, p->GetStart());
return pStack->Return(nullptr, pStk);
}
p = pp;
return nullptr;
}
template <typename T>
bool CBotExprLitNum<T>::Execute(CBotStack* &pj)
{
CBotStack* pile = pj->AddStack(this);
if (pile->IfStep()) return false;
CBotVar* var = CBotVar::Create("", m_numtype);
if (m_token.GetType() == TokenTypDef)
{
var->SetValInt(m_value, m_token.GetString());
}
else
{
*var = m_value;
}
pile->SetVar(var); // place on the stack
return pj->Return(pile); // it's ok
}
template <typename T>
void CBotExprLitNum<T>::RestoreState(CBotStack* &pj, bool bMain)
{
if (bMain) pj->RestoreStack(this);
}
template <typename T>
std::string CBotExprLitNum<T>::GetDebugData()
{
std::stringstream ss;
switch (m_numtype)
{
case CBotTypInt : ss << "(int) "; break;
case CBotTypLong : ss << "(long) "; break;
case CBotTypFloat : ss << "(float) "; break;
case CBotTypDouble: ss << "(double) "; break;
default: assert(false);
}
ss << m_value;
return ss.str();
}
} // namespace CBot

View File

@ -1,207 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotInstr/CBotExprLitString.h"
#include "CBot/CBotStack.h"
#include "CBot/CBotCStack.h"
#include "CBot/CBotVar/CBotVar.h"
#include <stdexcept>
namespace CBot
{
////////////////////////////////////////////////////////////////////////////////
CBotExprLitString::CBotExprLitString()
{
}
////////////////////////////////////////////////////////////////////////////////
CBotExprLitString::~CBotExprLitString()
{
}
////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotExprLitString::Compile(CBotToken* &p, CBotCStack* pStack)
{
CBotCStack* pStk = pStack->TokenStack();
const auto& s = p->GetString();
auto it = s.cbegin();
if (++it != s.cend())
{
int pos = p->GetStart();
std::string valstring = "";
while (it != s.cend() && *it != '\"')
{
++pos;
if (*it != '\\') // not escape sequence ?
{
valstring += *(it++);
continue;
}
if (++it == s.cend()) break;
pStk->SetStartError(pos);
if (CharInList(*it, "01234567")) // octal
{
std::string octal = "";
for (int i = 0; i < 3; i++)
{
if (!CharInList(*it, "01234567")) break;
++pos;
octal += *it;
if (++it == s.cend()) break;
}
unsigned int val = std::stoi(octal, nullptr, 8);
if (val <= 255)
{
valstring.push_back(val);
continue;
}
pStk->SetError(CBotErrOctalRange, pos + 1);
}
else
{
++pos;
unsigned char c = *(it++);
if (c == '\"' || c == '\'' || c == '\\') valstring += c;
else if (c == 'a') valstring += '\a'; // alert bell
else if (c == 'b') valstring += '\b'; // backspace
else if (c == 'f') valstring += '\f'; // form feed
else if (c == 'n') valstring += '\n'; // new line
else if (c == 'r') valstring += '\r'; // carriage return
else if (c == 't') valstring += '\t'; // horizontal tab
else if (c == 'v') valstring += '\v'; // vertical tab
else if (c == 'x' || c == 'u' || c == 'U') // hex or unicode
{
if (it != s.cend())
{
std::string hex = "";
bool isHexCode = (c == 'x');
size_t maxlen = (c == 'u') ? 4 : 8;
for (size_t i = 0; isHexCode || i < maxlen; i++)
{
if (!CharInList(*it, "0123456789ABCDEFabcdef")) break;
++pos;
hex += *it;
if (++it == s.cend()) break;
}
if (!hex.empty())
{
unsigned int val = 0;
try
{
val = std::stoi(hex, nullptr, 16);
}
catch (const std::out_of_range& e)
{
pStk->SetError(CBotErrHexRange, pos + 1);
}
if (pStk->IsOk())
{
if (isHexCode) // hexadecimal
{
if (val <= 255)
{
valstring.push_back(val);
continue;
}
pStk->SetError(CBotErrHexRange, pos + 1);
}
else if (maxlen == hex.length()) // unicode character
{
if (val < 0xD800 || (0xDFFF < val && val < 0x110000))
{
valstring += CodePointToUTF8(val);
continue;
}
pStk->SetError(CBotErrUnicodeName, pos + 1);
}
}
}
}
pStk->SetError(CBotErrHexDigits, pos + 1);
}
else
pStk->SetError(CBotErrBadEscape, pos + 1); // unknown escape code
}
if (!pStk->IsOk()) break;
}
if (it == s.cend() || *it != '\"')
pStk->SetError(CBotErrEndQuote, p);
if (pStk->IsOk())
{
CBotExprLitString* inst = new CBotExprLitString();
inst->m_valstring.swap(valstring);
inst->SetToken(p);
p = p->GetNext();
CBotVar* var = CBotVar::Create("", CBotTypString);
pStk->SetVar(var);
return pStack->Return(inst, pStk);
}
}
pStk->SetError(CBotErrEndQuote, p);
return pStack->Return(nullptr, pStk);
}
////////////////////////////////////////////////////////////////////////////////
bool CBotExprLitString::Execute(CBotStack* &pj)
{
CBotStack* pile = pj->AddStack(this);
if (pile->IfStep()) return false;
CBotVar* var = CBotVar::Create("", CBotTypString);
var->SetValString(m_valstring);
pile->SetVar(var); // put on the stack
return pj->Return(pile);
}
////////////////////////////////////////////////////////////////////////////////
void CBotExprLitString::RestoreState(CBotStack* &pj, bool bMain)
{
if (bMain) pj->RestoreStack(this);
}
std::string CBotExprLitString::GetDebugData()
{
return m_token.GetString();
}
} // namespace CBot

View File

@ -1,209 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include <sstream>
#include "CBot/CBotInstr/CBotExprRetVar.h"
#include "CBot/CBotInstr/CBotExpression.h"
#include "CBot/CBotInstr/CBotInstrMethode.h"
#include "CBot/CBotInstr/CBotIndexExpr.h"
#include "CBot/CBotInstr/CBotFieldExpr.h"
#include "CBot/CBotStack.h"
namespace CBot
{
////////////////////////////////////////////////////////////////////////////////
CBotExprRetVar::CBotExprRetVar()
{
}
////////////////////////////////////////////////////////////////////////////////
CBotExprRetVar::~CBotExprRetVar()
{
}
////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotExprRetVar::Compile(CBotToken*& p, CBotCStack* pStack, bool bMethodsOnly)
{
if (p->GetType() == ID_DOT)
{
CBotVar* var = pStack->GetVar();
if (var == nullptr) return nullptr;
CBotCStack* pStk = pStack->TokenStack();
CBotInstr* inst = new CBotExprRetVar();
while (true)
{
pStk->SetStartError(p->GetStart());
if (var->GetType() == CBotTypArrayPointer)
{
if (bMethodsOnly) goto err;
if (IsOfType( p, ID_OPBRK ))
{
CBotIndexExpr* i = new CBotIndexExpr();
i->m_expr = CBotExpression::Compile(p, pStk);
inst->AddNext3(i);
var = var->GetItem(0,true);
if (i->m_expr == nullptr || pStk->GetType() != CBotTypInt)
{
pStk->SetError(CBotErrBadIndex, p->GetStart());
goto err;
}
if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK ))
{
pStk->SetError(CBotErrCloseIndex, p->GetStart());
goto err;
}
continue;
}
}
if (var->GetType(CBotVar::GetTypeMode::CLASS_AS_POINTER) == CBotTypPointer)
{
if (IsOfType(p, ID_DOT))
{
CBotToken* pp = p;
if (p->GetType() == TokenTypVar)
{
if (p->GetNext()->GetType() == ID_OPENPAR)
{
CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var, bMethodsOnly);
if (!pStk->IsOk()) goto err;
inst->AddNext3(i);
return pStack->Return(inst, pStk);
}
else if (bMethodsOnly)
{
p = p->GetPrev();
goto err;
}
else
{
CBotFieldExpr* i = new CBotFieldExpr();
i->SetToken(pp);
inst->AddNext3(i);
CBotVar* preVar = var;
var = var->GetItem(p->GetString());
if (var != nullptr)
{
i->SetUniqNum(var->GetUniqNum());
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var))
{
pStk->SetError(CBotErrPrivate, pp);
goto err;
}
}
}
if (var != nullptr)
{
p = p->GetNext();
continue;
}
pStk->SetError(CBotErrUndefItem, p);
goto err;
}
pStk->SetError(CBotErrUndefClass, p);
goto err;
}
}
break;
}
pStk->SetCopyVar(var);
if (pStk->IsOk()) return pStack->Return(inst, pStk);
pStk->SetError(CBotErrUndefVar, p);
err:
delete inst;
return pStack->Return(nullptr, pStk);
}
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotExprRetVar::Execute(CBotStack* &pj)
{
CBotStack* pile = pj->AddStack();
CBotStack* pile1 = pile;
CBotVar* pVar;
if (pile1->GetState() == 0)
{
pVar = pj->GetVar();
pVar->Update(pj->GetUserPtr());
if (pVar->GetType(CBotVar::GetTypeMode::CLASS_AS_POINTER) == CBotTypNullPointer)
{
pile1->SetError(CBotErrNull, &m_token);
return pj->Return(pile1);
}
if ( !m_next3->ExecuteVar(pVar, pile, &m_token, true, false) )
return false;
if (pVar)
pile1->SetCopyVar(pVar);
else
return pj->Return(pile1);
pile1->IncState();
}
pVar = pile1->GetVar();
if (pVar == nullptr)
{
return pj->Return(pile1);
}
if (pVar->IsUndefined())
{
pile1->SetError(CBotErrNotInit, &m_token);
return pj->Return(pile1);
}
return pj->Return(pile1);
}
////////////////////////////////////////////////////////////////////////////////
void CBotExprRetVar::RestoreState(CBotStack* &pj, bool bMain)
{
if (!bMain) return;
CBotStack* pile = pj->RestoreStack();
if ( pile == nullptr ) return;
if (pile->GetState() == 0)
m_next3->RestoreStateVar(pile, bMain);
}
std::string CBotExprRetVar::GetDebugData()
{
std::stringstream ss;
ss << m_token.GetString() << "func(...).something" << std::endl;
return ss.str();
}
} // namespace CBot

View File

@ -1,63 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "CBot/CBotInstr/CBotInstr.h"
namespace CBot
{
/**
* \brief Access a member/element of the variable on the stack
*
*
*
*/
class CBotExprRetVar : public CBotInstr
{
public:
CBotExprRetVar();
~CBotExprRetVar();
static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack, bool bMethodsOnly = false);
/*!
* \brief Execute
* \param pj
* \return
*/
bool Execute(CBotStack* &pj) override;
/*!
* \brief RestoreState
* \param pj
* \param bMain
*/
void RestoreState(CBotStack* &pj, bool bMain) override;
protected:
virtual const std::string GetDebugName() override { return "CBotExprRetVar"; }
virtual std::string GetDebugData() override;
private:
};
} // namespace CBot

View File

@ -1,370 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "CBot/CBotInstr/CBotInstr.h"
#include <set>
namespace CBot
{
/**
* \brief A function declaration in the code
*
* Examples:
* \code
* void test() { ... }
* void test(int a, float b) { ... }
* int test(int a, float b, string c) { ... }
* public bool test(int a, float b, string c, SomeClass d) { ... }
* extern void test() { ... }
* void classname::test() { ... }
* \endcode
*/
class CBotFunction : public CBotInstr
{
public:
CBotFunction();
~CBotFunction();
/*!
* \brief Compile Compiles a new function
* \param p
* \param pStack
* \param pFunc
* \param bLocal allows of the declaration of parameters on the same level
* as the elements belonging to the class for methods.
* \return
*/
static CBotFunction* Compile(CBotToken* &p,
CBotCStack* pStack,
CBotFunction* pFunc,
bool bLocal = true);
/*!
* \brief Pre-compile a new function
* \param p[in, out] Pointer to first token of the function, will be updated to point to first token after the function definition
* \param pStack Compile stack
* \param pClass If this is a class method, pointer to class this function is part of, otherwise nullptr
*
* This function is used to find the beginning and end of function definition.
*
* If any errors in the code are detected, this function will set the error on compile stack and return nullptr.
*
* \return Precompiled function, or nullptr in case of error
*/
static CBotFunction* Compile1(CBotToken* &p,
CBotCStack* pStack,
CBotClass* pClass);
/*!
* \brief Execute
* \param ppVars
* \param pj
* \param pInstance
* \return
*/
bool Execute(CBotVar** ppVars,
CBotStack* &pj,
CBotVar* pInstance = nullptr);
using CBotInstr::Execute;
/*!
* \brief RestoreState
* \param ppVars
* \param pj
* \param pInstance
*/
void RestoreState(CBotVar** ppVars,
CBotStack* &pj,
CBotVar* pInstance = nullptr);
using CBotInstr::RestoreState;
/*!
* \brief Compile a function call
*
* See FindLocalOrPublic for more detailed explanation
*
* \param name Name of the function
* \param ppVars List of function arguments
* \param nIdent[in, out] Unique identifier of the function
* \param program The current program, to search for functions.
* \return Type returned by the function or error code
* \see FindLocalOrPublic
*/
static CBotTypResult CompileCall(const std::string &name, CBotVar** ppVars,
long &nIdent, CBotProgram* program);
/*!
* \brief Finds a local or public function
*
* <p>First, it looks for a function according to its unique identifier.<br>
* If the identifier is not found, looks by name and parameters.
*
* \param localFunctionList Linked list of local functions to search in, can be null
* \param nIdent[in, out] Unique identifier of the function
* \param name Name of the function
* \param ppVars List of function arguments
* \param TypeOrError Type returned by the function or error code
* \param baseProg Initial program, for context of the object/bot
* \return Pointer to found CBotFunction instance, or nullptr in case of no match or ambiguity (see TypeOrError for error code)
*/
static CBotFunction* FindLocalOrPublic(const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name,
CBotVar** ppVars, CBotTypResult &TypeOrError, CBotProgram* baseProg);
/*!
* \brief Find all functions that match the name and arguments.
* \param functionList List of functions to search, can be empty.
* \param name Name of the function to find.
* \param ppVars Arguments to compare with parameters.
* \param TypeOrError Contains a CBotError when no useable function has been found.
* \param funcMap Container for suitable functions and their signature values.
* \param pClass Pointer to class when searching for methods.
*/
static void SearchList(const std::list<CBotFunction*>& functionList,
const std::string& name, CBotVar** ppVars, CBotTypResult& TypeOrError,
std::map<CBotFunction*, int>& funcMap, CBotClass* pClass = nullptr);
/*!
* \brief Find all public functions that match the name and arguments.
* \param name Name of the function to find.
* \param ppVars Arguments to compare with parameters.
* \param TypeOrError Contains a CBotError when no useable function has been found.
* \param funcMap Container for suitable functions and their signature values.
* \param pClass Pointer to class when searching for methods.
*/
static void SearchPublic(const std::string& name, CBotVar** ppVars, CBotTypResult& TypeOrError,
std::map<CBotFunction*, int>& funcMap, CBotClass* pClass = nullptr);
/*!
* \brief Find the function with the lowest signature value. If there is more
* than one of the same signature value, TypeOrError is set to CBotErrAmbiguousCall.
* \param funcMap List of functions and their signature values, can be empty.
* \param[out] nIdent Unique identifier of the function.
* \param TypeOrError Type returned by the function or error code.
* \return Pointer to the function with the lowest signature or nullptr.
*/
static CBotFunction* BestFunction(std::map<CBotFunction*, int>& funcMap,
long& nIdent, CBotTypResult& TypeOrError);
/*!
* \brief DoCall Fait un appel à une fonction.
* \param program
* \param localFunctionList
* \param nIdent
* \param name
* \param ppVars
* \param pStack
* \param pToken
* \return
*/
static int DoCall(CBotProgram* program, const std::list<CBotFunction*>& localFunctionList, long &nIdent, const std::string &name,
CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken);
/*!
* \brief RestoreCall
* \param localFunctionList
* \param nIdent
* \param name
* \param ppVars
* \param pStack
*/
static void RestoreCall(const std::list<CBotFunction*>& localFunctionList,
long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack);
/*!
* \brief Find a method matching the name and arguments.
* \param name Name of the method to find.
* \param ppVars Arguments to compare with parameters.
* \param[out] nIdent Unique identifier of the method.
* \param pStack Current compilation stack frame.
* \param pClass Pointer to the class.
* \return The return type for the method or a CBotError.
*/
static CBotTypResult CompileMethodCall(const std::string& name, CBotVar** ppVars,
long& nIdent, CBotCStack* pStack, CBotClass* pClass);
/*!
* \brief Find a method by its unique identifier or by name and parameters.
* \param[in,out] nIdent Unique identifier of the method.
* \param name Name of the method to find.
* \param ppVars Arguments to compare with parameters.
* \param TypeOrError The return type for the method or a CBotError.
* \param pClass Pointer to the class.
* \param program The current program, to search for out-of-class methods.
* \return Pointer to the method that best matches the given arguments or nullptr.
*/
static CBotFunction* FindMethod(long& nIdent, const std::string& name,
CBotVar** ppVars, CBotTypResult& TypeOrError,
CBotClass* pClass, CBotProgram* program);
/*!
* \brief DoCall Makes call of a method
* \param nIdent
* \param name
* \param pThis
* \param ppVars
* \param pStack
* \param pToken
* \param pClass
* \return
*/
static int DoCall(long &nIdent, const std::string &name, CBotVar* pThis,
CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass);
/*!
* \brief RestoreCall
* \param nIdent
* \param name
* \param pThis
* \param ppVars
* \param pStack
* \param pClass
* \return Returns true if the method call was restored.
*/
static bool RestoreCall(long &nIdent, const std::string &name, CBotVar* pThis,
CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass);
/*!
* \brief CheckParam See if the "signature" of parameters is identical.
* \param pParam
* \return
*/
bool CheckParam(CBotDefParam* pParam);
/*!
* \brief AddPublic
* \param pfunc
*/
static void AddPublic(CBotFunction* pfunc);
/*!
* \brief GetName
* \return
*/
const std::string& GetName();
/*!
* \brief GetParams
* \return
*/
std::string GetParams();
/*!
* \brief Get the name of the class for a method.
* \return The name of a class or empty string if it's not a method.
*/
const std::string& GetClassName() const;
/*!
* \brief IsPublic
* \return
*/
bool IsPublic();
/*!
* \brief Check if a method is protected.
* \return true if a method was compiled with "protected" keyword.
*/
bool IsProtected() const;
/*!
* \brief Check if a method is private.
* \return true if a method was compiled with "private" keyword.
*/
bool IsPrivate() const;
/*!
* \brief IsExtern
* \return
*/
bool IsExtern();
/*!
* \brief GetPosition
* \param start
* \param stop
* \param modestart
* \param modestop
* \return
*/
bool GetPosition(int& start, int& stop,
CBotGet modestart,
CBotGet modestop);
/*!
* \brief Check if the function has a return statment that will execute.
* \return true if a return statment was found.
*/
bool HasReturn() override;
protected:
virtual const std::string GetDebugName() override { return "CBotFunction"; }
virtual std::string GetDebugData() override;
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;
private:
friend class CBotDebug;
long m_nFuncIdent;
//! Synchronized method.
bool m_bSynchro;
//! Parameter list.
CBotDefParam* m_param;
//! The instruction block.
CBotInstr* m_block;
//! If returns CBotTypClass.
CBotToken m_retToken;
//! Complete type of the result.
CBotTypResult m_retTyp;
//! Public function.
bool m_bPublic;
//! Protected method.
bool m_bProtect = false;
//! Private method.
bool m_bPrivate = false;
//! Extern function.
bool m_bExtern;
//! Name of the class we are part of
std::string m_MasterClass;
//! Token of the class we are part of
CBotToken m_classToken;
CBotProgram* m_pProg;
//! For the position of the word "extern".
CBotToken m_extern;
CBotToken m_openpar;
CBotToken m_closepar;
CBotToken m_openblk;
CBotToken m_closeblk;
//! List of public functions
static std::set<CBotFunction*> m_publicFunctions;
friend class CBotProgram;
friend class CBotClass;
friend class CBotCStack;
};
} // namespace CBot

View File

@ -1,165 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotInstr/CBotRepeat.h"
#include "CBot/CBotInstr/CBotBlock.h"
#include "CBot/CBotInstr/CBotExpression.h"
#include "CBot/CBotCStack.h"
#include "CBot/CBotStack.h"
namespace CBot
{
CBotRepeat::CBotRepeat()
{
m_expr = nullptr;
m_block = nullptr;
}
CBotRepeat::~CBotRepeat()
{
delete m_expr;
delete m_block;
}
CBotInstr* CBotRepeat::Compile(CBotToken* &p, CBotCStack* pStack)
{
CBotRepeat* inst = new CBotRepeat(); // creates the object
CBotToken* pp = p; // preserves at the ^ token (starting position)
if ( IsOfType( p, TokenTypVar ) && IsOfType( p, ID_DOTS ) )
inst->m_label = pp->GetString(); // register the name of label
inst->SetToken(p);
if (!IsOfType(p, ID_REPEAT)) return nullptr; // should never happen
CBotCStack* pStk = pStack->TokenStack(pp);
if ( IsOfType(p, ID_OPENPAR ) )
{
CBotToken* ppp = p; // preserves the ^ token (starting position)
if ( nullptr != (inst->m_expr = CBotExpression::Compile( p, pStk )) )
{
if ( pStk->GetType() < CBotTypLong )
{
if ( IsOfType(p, ID_CLOSEPAR ) )
{
IncLvl(inst->m_label);
inst->m_block = CBotBlock::CompileBlkOrInst( p, pStk, true );
DecLvl();
if ( pStk->IsOk() ) // the statement block is ok (it may be empty!)
return pStack->Return(inst, pStk);
}
pStack->SetError(CBotErrClosePar, p->GetStart());
}
pStk->SetStartError(ppp->GetStart());
pStk->SetError(CBotErrBadType1, p->GetStart());
}
pStack->SetError(CBotErrBadNum, p);
}
pStack->SetError(CBotErrOpenPar, p->GetStart());
delete inst;
return pStack->Return(nullptr, pStk);
}
// execution of intruction "repeat"
bool CBotRepeat::Execute(CBotStack* &pj)
{
CBotStack* pile = pj->AddStack(this); // adds an item to the stack
// or find in case of recovery
if ( pile->IfStep() ) return false;
while( true ) switch( pile->GetState() ) // executes the loop
{ // there are two possible states (depending on recovery)
case 0:
// evaluates the number of iterations
if ( !m_expr->Execute(pile) ) return false; // interrupted here ?
// the result of the condition is on the stack
// terminates if an error or if the condition is false
int n;
if ( !pile->IsOk() || ( n = pile->GetVal() ) < 1 )
return pj->Return(pile); // releases the stack
// puts the number of iterations +1 to the "state"
if (!pile->SetState(n+1)) return false; // ready for further
continue; // continue as a result
case 1:
// normal end of the loop
return pj->Return(pile); // releases the stack
default:
// evaluates the associated statement block
if ( m_block != nullptr && !m_block->Execute(pile) )
{
if (pile->IfContinue(pile->GetState()-1, m_label)) continue; // if continued, will return to test
return pj->BreakReturn(pile, m_label); // releases the stack
}
// terminates if there is an error
if (!pile->IsOk()) return pj->Return(pile); // releases the stack
// returns to the test again
if (!pile->SetState(pile->GetState()-1, 0)) return false;
continue;
}
}
void CBotRepeat::RestoreState(CBotStack* &pj, bool bMain)
{
if ( !bMain ) return;
CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack
if ( pile == nullptr ) return;
switch( pile->GetState() )
{ // there are two possible states (depending on recovery)
case 0:
// evaluates the condition
m_expr->RestoreState(pile, bMain);
return;
case 1:
// evaluates the associated statement block
if ( m_block != nullptr ) m_block->RestoreState(pile, bMain);
return;
}
}
std::string CBotRepeat::GetDebugData()
{
return !m_label.empty() ? "m_label = " + m_label : "";
}
std::map<std::string, CBotInstr*> CBotRepeat::GetDebugLinks()
{
auto links = CBotInstr::GetDebugLinks();
links["m_expr"] = m_expr;
links["m_block"] = m_block;
return links;
}
} // namespace CBot

View File

@ -1,62 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "CBot/CBotInstr/CBotInstr.h"
namespace CBot
{
/**
* \brief The "repeat" loop - repeat (times) { ... }
*/
class CBotRepeat : public CBotInstr
{
public:
CBotRepeat();
~CBotRepeat();
/// Static method used for compilation
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
/// Execute
bool Execute(CBotStack* &pj) override;
/// Restore state
void RestoreState(CBotStack* &pj, bool bMain) override;
protected:
virtual const std::string GetDebugName() override { return "CBotRepeat"; }
virtual std::string GetDebugData() override;
virtual std::map<std::string, CBotInstr*> GetDebugLinks() override;
private:
/// Number of iterations
CBotInstr* m_expr;
/// Instructions
CBotInstr* m_block;
/// Label
std::string m_label; // a label if there is
};
} // namespace CBot

View File

@ -1,48 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotVar/CBotVarBoolean.h"
namespace CBot
{
void CBotVarBoolean::And(CBotVar* left, CBotVar* right)
{
SetValInt(left->GetValInt() && right->GetValInt());
}
void CBotVarBoolean::Or(CBotVar* left, CBotVar* right)
{
SetValInt(left->GetValInt() || right->GetValInt());
}
void CBotVarBoolean::XOr(CBotVar* left, CBotVar* right)
{
SetValInt(left->GetValInt() ^ right->GetValInt());
}
void CBotVarBoolean::Not()
{
SetValInt(!GetValInt());
}
bool CBotVarBoolean::Save1State(std::ostream &ostr)
{
return WriteByte(ostr, m_val); // the value of the variable
}
} // namespace CBot

View File

@ -1,57 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "CBot/CBotVar/CBotVarValue.h"
namespace CBot
{
/**
* \brief CBotVar subclass for managing 32-bit Unicode values (::CBotTypChar)
*/
class CBotVarChar : public CBotVarInteger<uint32_t, CBotTypChar>
{
public:
CBotVarChar(const CBotToken &name) : CBotVarInteger(name) {}
std::string GetValString() const override
{
if (m_binit == CBotVar::InitType::UNDEF)
return UndefinedTokenString();
if (0x10FFFF < m_val || (0xD7FF < m_val && m_val < 0xE000))
return "\xEF\xBF\xBD"; // replacement character U+FFFD
return CodePointToUTF8(m_val);
}
void SR(CBotVar* left, CBotVar* right) override
{
SetValChar(left->GetValChar() >> right->GetValInt());
}
bool Save1State(std::ostream &ostr) override
{
return WriteUInt32(ostr, m_val);
}
};
} // namespace CBot

View File

@ -1,30 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotVar/CBotVarFloat.h"
namespace CBot
{
bool CBotVarFloat::Save1State(std::ostream &ostr)
{
return WriteFloat(ostr, m_val); // the value of the variable
}
} // namespace CBot

View File

@ -1,88 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotVar/CBotVarInt.h"
namespace CBot
{
void CBotVarInt::Copy(CBotVar* pSrc, bool bName)
{
CBotVarNumber::Copy(pSrc, bName);
CBotVarInt* p = static_cast<CBotVarInt*>(pSrc);
m_defnum = p->m_defnum;
}
void CBotVarInt::SetValInt(int val, const std::string& defnum)
{
CBotVarNumber::SetValInt(val, defnum);
m_defnum = defnum;
}
std::string CBotVarInt::GetValString() const
{
if (!m_defnum.empty()) return m_defnum;
return CBotVarValue::GetValString();
}
void CBotVarInt::Neg()
{
CBotVarNumber::Neg();
m_defnum.clear();
}
void CBotVarInt::Inc()
{
CBotVarNumber::Inc();
m_defnum.clear();
}
void CBotVarInt::Dec()
{
CBotVarNumber::Dec();
m_defnum.clear();
}
void CBotVarInt::SR(CBotVar* left, CBotVar* right)
{
SetValInt(static_cast<unsigned>(left->GetValInt()) >> right->GetValInt());
}
void CBotVarInt::Not()
{
m_val = ~m_val;
m_defnum.clear();
}
bool CBotVarInt::Save0State(std::ostream &ostr)
{
if (!m_defnum.empty())
{
if(!WriteWord(ostr, 200)) return false; // special marker
if(!WriteString(ostr, m_defnum)) return false;
}
return CBotVar::Save0State(ostr);
}
bool CBotVarInt::Save1State(std::ostream &ostr)
{
return WriteInt(ostr, m_val);
}
} // namespace CBot

View File

@ -1,64 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "CBot/CBotVar/CBotVarValue.h"
namespace CBot
{
/**
* \brief CBotVar subclass for managing integer values (::CBotTypInt)
*/
class CBotVarInt : public CBotVarInteger<int, CBotTypInt>
{
public:
CBotVarInt(const CBotToken &name) : CBotVarInteger(name) {}
void SetValInt(int val, const std::string& s = "") override;
std::string GetValString() const override;
void Copy(CBotVar* pSrc, bool bName = true) override;
void Neg() override;
void Inc() override;
void Dec() override;
void Not() override;
void SR(CBotVar* left, CBotVar* right) override;
bool Save0State(std::ostream &ostr) override;
bool Save1State(std::ostream &ostr) override;
protected:
void SetValue(int val) override
{
CBotVarNumberBase::SetValue(val);
m_defnum.clear();
}
protected:
//! The name if given by DefineNum.
std::string m_defnum;
friend class CBotVar;
};
} // namespace CBot

View File

@ -1,45 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "CBot/CBotVar/CBotVarString.h"
namespace CBot
{
void CBotVarString::Add(CBotVar* left, CBotVar* right)
{
SetValString(left->GetValString() + right->GetValString());
}
bool CBotVarString::Eq(CBotVar* left, CBotVar* right)
{
return left->GetValString() == right->GetValString();
}
bool CBotVarString::Ne(CBotVar* left, CBotVar* right)
{
return left->GetValString() != right->GetValString();
}
bool CBotVarString::Save1State(std::ostream &ostr)
{
return WriteString(ostr, m_val);
}
} // namespace CBot

View File

@ -1,87 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "CBot/CBotVar/CBotVarValue.h"
namespace CBot
{
/**
* \brief CBotVar subclass for managing string values (::CBotTypString)
*/
class CBotVarString : public CBotVarValue<std::string, CBotTypString>
{
public:
CBotVarString(const CBotToken &name) : CBotVarValue(name) {}
void SetValString(const std::string& val) override
{
m_val = val;
m_binit = CBotVar::InitType::DEF;
}
void SetValInt(int val, const std::string& s = "") override
{
SetValString(ToString(val));
}
void SetValFloat(float val) override
{
SetValString(ToString(val));
}
int GetValInt() const override
{
return FromString<int>(GetValString());
}
float GetValFloat() const override
{
return FromString<float>(GetValString());
}
void Add(CBotVar* left, CBotVar* right) override;
bool Eq(CBotVar* left, CBotVar* right) override;
bool Ne(CBotVar* left, CBotVar* right) override;
bool Save1State(std::ostream &ostr) override;
private:
template<typename T>
static std::string ToString(T val)
{
std::ostringstream ss;
ss << val;
return ss.str();
}
template<typename T>
static T FromString(std::string val)
{
std::istringstream ss(val);
T v;
ss >> v;
return v;
}
};
} // namespace CBot

View File

@ -1,295 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "CBot/CBotVar/CBotVar.h"
#include "CBot/CBotEnums.h"
#include "CBot/CBotToken.h"
#include <sstream>
#include <cmath>
namespace CBot
{
/**
* \brief A variable holding a simple value (bool, int, float, string)
*/
template <typename T, CBotType type>
class CBotVarValue : public CBotVar
{
public:
/**
* \brief Constructor. Do not call directly, use CBotVar::Create()
*/
CBotVarValue(const CBotToken& name) : CBotVar(name)
{
m_type = type;
}
void Copy(CBotVar* pSrc, bool bName = true) override
{
CBotVar::Copy(pSrc, bName);
CBotVarValue* p = static_cast<CBotVarValue*>(pSrc);
m_val = p->m_val;
}
void SetValString(const std::string& val) override
{
std::istringstream s(val);
s >> m_val;
m_binit = CBotVar::InitType::DEF;
}
std::string GetValString() const override
{
if (m_binit == CBotVar::InitType::UNDEF)
return UndefinedTokenString();
std::ostringstream s;
s << std::boolalpha << m_val;
return s.str();
}
protected:
virtual void SetValue(T val)
{
this->m_val = val;
this->m_binit = CBotVar::InitType::DEF;
}
protected:
//! The value
T m_val;
};
/**
* \brief A number based variable (bool, int, float)
*/
template <typename T, CBotType type>
class CBotVarNumberBase : public CBotVarValue<T, type>
{
public:
CBotVarNumberBase(const CBotToken &name) : CBotVarValue<T, type>(name)
{
this->m_val = static_cast<T>(0);
}
void SetValByte(signed char val) override
{
this->SetValue(static_cast<T>(val));
}
void SetValShort(short val) override
{
this->SetValue(static_cast<T>(val));
}
void SetValChar(uint32_t val) override
{
this->SetValue(static_cast<T>(val));
}
void SetValInt(int val, const std::string &s = "") override
{
this->SetValue(static_cast<T>(val));
}
void SetValLong(long val) override
{
this->SetValue(static_cast<T>(val));
}
void SetValFloat(float val) override
{
this->SetValue(static_cast<T>(val));
}
void SetValDouble(double val) override
{
this->SetValue(static_cast<T>(val));
}
signed char GetValByte() const override
{
return static_cast<signed char>(this->m_val);
}
short GetValShort() const override
{
return static_cast<short>(this->m_val);
}
uint32_t GetValChar() const override
{
return static_cast<uint32_t>(this->m_val);
}
int GetValInt() const override
{
return static_cast<int>(this->m_val);
}
long GetValLong() const override
{
return static_cast<long>(this->m_val);
}
float GetValFloat() const override
{
return static_cast<float>(this->m_val);
}
double GetValDouble() const override
{
return static_cast<double>(this->m_val);
}
bool Eq(CBotVar* left, CBotVar* right) override
{
return static_cast<T>(*left) == static_cast<T>(*right);
}
bool Ne(CBotVar* left, CBotVar* right) override
{
return static_cast<T>(*left) != static_cast<T>(*right);
}
};
/**
* \brief A number variable (int, float)
*/
template <typename T, CBotType type>
class CBotVarNumber : public CBotVarNumberBase<T, type>
{
public:
CBotVarNumber(const CBotToken &name) : CBotVarNumberBase<T, type>(name) {}
void Mul(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) * static_cast<T>(*right));
}
void Power(CBotVar* left, CBotVar* right) override
{
this->SetValue(pow(static_cast<T>(*left), static_cast<T>(*right)));
}
CBotError Div(CBotVar* left, CBotVar* right) override
{
T r = static_cast<T>(*right);
if ( r == static_cast<T>(0) ) return CBotErrZeroDiv;
this->SetValue(static_cast<T>(*left) / r);
return CBotNoErr;
}
CBotError Modulo(CBotVar* left, CBotVar* right) override
{
T r = static_cast<T>(*right);
if ( r == static_cast<T>(0) ) return CBotErrZeroDiv;
this->SetValue(fmod(static_cast<T>(*left), r));
return CBotNoErr;
}
void Add(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) + static_cast<T>(*right));
}
void Sub(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) - static_cast<T>(*right));
}
void Neg() override
{
this->m_val = - this->m_val;
}
void Inc() override
{
this->m_val++;
}
void Dec() override
{
this->m_val--;
}
bool Lo(CBotVar* left, CBotVar* right) override
{
return static_cast<T>(*left) < static_cast<T>(*right);
}
bool Hi(CBotVar* left, CBotVar* right) override
{
return static_cast<T>(*left) > static_cast<T>(*right);
}
bool Ls(CBotVar* left, CBotVar* right) override
{
return static_cast<T>(*left) <= static_cast<T>(*right);
}
bool Hs(CBotVar* left, CBotVar* right) override
{
return static_cast<T>(*left) >= static_cast<T>(*right);
}
};
/**
* \brief An integer variable (byte, short, char, int, long)
*/
template <typename T, CBotType type>
class CBotVarInteger : public CBotVarNumber<T, type>
{
public:
CBotVarInteger(const CBotToken &name) : CBotVarNumber<T, type>(name) {}
CBotError Modulo(CBotVar* left, CBotVar* right) override
{
T r = static_cast<T>(*right);
if ( r == static_cast<T>(0) ) return CBotErrZeroDiv;
this->SetValue(static_cast<T>(*left) % r);
return CBotNoErr;
}
void XOr(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) ^ static_cast<T>(*right));
}
void And(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) & static_cast<T>(*right));
}
void Or(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) | static_cast<T>(*right));
}
void SL(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) << right->GetValInt());
}
void ASR(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) >> right->GetValInt());
}
void Not() override
{
this->m_val = ~(this->m_val);
}
};
} // namespace CBot

View File

@ -3,26 +3,22 @@
# Contains global options and definitions
##
cmake_minimum_required(VERSION 3.21)
cmake_minimum_required(VERSION 2.8)
project(colobot
VERSION 0.2.1.0
LANGUAGES C CXX
)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS NO)
project(colobot C CXX)
##
# Project version
##
set(COLOBOT_VERSION_CODENAME "Gold")
set(COLOBOT_VERSION_MAJOR 0)
set(COLOBOT_VERSION_MINOR 1)
set(COLOBOT_VERSION_REVISION 7)
# Used on official releases
#set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha")
set(COLOBOT_VERSION_RELEASE_CODENAME "-alpha")
# Used on unreleased, development builds
set(COLOBOT_VERSION_UNRELEASED "+alpha")
#set(COLOBOT_VERSION_UNRELEASED "+alpha")
# Append git characteristics to version
if(DEFINED COLOBOT_VERSION_UNRELEASED)
@ -42,10 +38,10 @@ if(DEFINED COLOBOT_VERSION_UNRELEASED)
set(COLOBOT_VERSION_DISPLAY "${COLOBOT_VERSION_CODENAME}-${COLOBOT_VERSION_UNRELEASED}")
endif()
else()
set(COLOBOT_VERSION_DISPLAY "${CMAKE_PROJECT_VERSION}${COLOBOT_VERSION_RELEASE_CODENAME}")
set(COLOBOT_VERSION_DISPLAY "${COLOBOT_VERSION_MAJOR}.${COLOBOT_VERSION_MINOR}.${COLOBOT_VERSION_REVISION}${COLOBOT_VERSION_RELEASE_CODENAME}")
endif()
set(COLOBOT_VERSION_FULL "${CMAKE_PROJECT_VERSION}${COLOBOT_VERSION_UNRELEASED}${COLOBOT_VERSION_RELEASE_CODENAME}")
set(COLOBOT_VERSION_FULL "${COLOBOT_VERSION_MAJOR}.${COLOBOT_VERSION_MINOR}.${COLOBOT_VERSION_REVISION}${COLOBOT_VERSION_UNRELEASED}${COLOBOT_VERSION_RELEASE_CODENAME}")
message(STATUS "Building Colobot \"${COLOBOT_VERSION_CODENAME}\" (${COLOBOT_VERSION_FULL})")
set(BUILD_NUMBER 0)
@ -64,36 +60,30 @@ if("${CMAKE_SYSTEM_NAME}" MATCHES "Windows")
set(PLATFORM_GNU 0)
set(PLATFORM_LINUX 0)
set(PLATFORM_MACOSX 0)
set(PLATFORM_FREEBSD 0)
set(PLATFORM_OTHER 0)
# Platform-dependent implementation of system.h
set(SYSTEM_CPP_MODULE "system_windows.cpp")
set(SYSTEM_H_MODULE "system_windows.h")
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
message(STATUS "Build for Linux system")
set(PLATFORM_WINDOWS 0)
set(PLATFORM_LINUX 1)
set(PLATFORM_GNU 1)
set(PLATFORM_MACOSX 0)
set(PLATFORM_FREEBSD 0)
set(PLATFORM_OTHER 0)
# Platform-dependent implementation of system.h
set(SYSTEM_CPP_MODULE "system_linux.cpp")
set(SYSTEM_H_MODULE "system_linux.h")
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "kFreeBSD" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "GNU")
message(STATUS "Build for kFreeBSD system")
set(PLATFORM_WINDOWS 0)
set(PLATFORM_LINUX 0)
set(PLATFORM_GNU 1)
set(PLATFORM_MACOSX 0)
set(PLATFORM_FREEBSD 0)
set(PLATFORM_OTHER 0)
# Platform-dependent implementation of system.h
set(SYSTEM_CPP_MODULE "system_other.cpp")
set(SYSTEM_H_MODULE "system_other.h")
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
message(STATUS "Build for Mac OSX system")
set(PLATFORM_WINDOWS 0)
@ -101,42 +91,19 @@ elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
set(PLATFORM_GNU 0)
set(PLATFORM_MACOSX 1)
set(PLATFORM_OTHER 0)
set(PLATFORM_FREEBSD 0)
# Platform-dependent implementation of system.h
set(SYSTEM_CPP_MODULE "system_macosx.cpp")
set(SYSTEM_H_MODULE "system_macosx.h")
# Fix compilation errors in MacOS SDK files
set(CMAKE_CXX_FLAGS "${NORMAL_CXX_FLAGS} -Wno-nullability-extension -Wno-nullability-completeness -Wno-expansion-to-defined -Wno-four-char-constants -Wno-gnu-zero-variadic-macro-arguments -Wno-variadic-macros -Wno-zero-length-array")
# To avoid CMake warning
set(CMAKE_MACOSX_RPATH 1)
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
message(STATUS "Build for FreeBSD system")
set(PLATFORM_WINDOWS 0)
set(PLATFORM_LINUX 0)
set(PLATFORM_GNU 0)
set(PLATFORM_MACOSX 0)
set(PLATFORM_FREEBSD 1)
set(PLATFORM_OTHER 0)
# Platform-dependent implementation of system.h
# On FreeBSD we can use *_other
set(SYSTEM_CPP_MODULE "system_other.cpp")
set(SYSTEM_H_MODULE "system_other.h")
# To avoid CMake warning
set(CMAKE_MACOSX_RPATH 1)
else()
message(STATUS "Build for other system")
set(PLATFORM_WINDOWS 0)
set(PLATFORM_LINUX 0)
set(PLATFORM_GNU 0)
set(PLATFORM_MACOSX 0)
set(PLATFORM_FREEBSD 0)
set(PLATFORM_OTHER 1)
# Platform-dependent implementation of system.h
set(SYSTEM_CPP_MODULE "system_other.cpp")
set(SYSTEM_H_MODULE "system_other.h")
endif()
@ -148,9 +115,7 @@ endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
# Include cmake directory with some additional scripts
list(PREPEND CMAKE_MODULE_PATH
${PROJECT_SOURCE_DIR}/cmake
)
set(CMAKE_MODULE_PATH "${colobot_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
# Compiler detection
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
@ -160,13 +125,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
message(STATUS "Detected GCC version 4.7+")
set(NORMAL_CXX_FLAGS "-Wall -Wold-style-cast -pedantic-errors -Wmissing-declarations -lstdc++fs -fPIC")
set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -Wno-error=deprecated-declarations") # updated version of physfs is not available on some platforms so we keep using deprecated functions, see #958
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -Wsuggest-override")
endif()
set(NORMAL_CXX_FLAGS "-std=gnu++11 -Wall -Wold-style-cast")
set(RELEASE_CXX_FLAGS "-O2")
set(DEBUG_CXX_FLAGS "-g -O0")
set(TEST_CXX_FLAGS "-pthread")
@ -178,12 +137,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
message(STATUS "Detected Clang version 3.1+")
if (${PLATFORM_FREEBSD})
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=bfd")
endif()
set(NORMAL_CXX_FLAGS "-Wall -Wold-style-cast -pedantic-errors -Wmissing-prototypes")
set(NORMAL_CXX_FLAGS "${NORMAL_CXX_FLAGS} -Wno-error=deprecated-declarations") # updated version of physfs is not available on some platforms so we keep using deprecated functions, see #958
set(NORMAL_CXX_FLAGS "-std=c++11 -Wall -Wold-style-cast")
set(RELEASE_CXX_FLAGS "-O2")
set(DEBUG_CXX_FLAGS "-g -O0")
set(TEST_CXX_FLAGS "-pthread")
@ -191,22 +145,11 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
message(STATUS "Detected MSVC compiler")
# Disable some useless warnings
set(NORMAL_CXX_FLAGS "/wd\"4244\" /wd\"4309\" /wd\"4800\" /wd\"4996\" /wd\"4351\"")
if(USE_STATIC_RUNTIME)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
else()
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
endif()
set(NORMAL_CXX_FLAGS "/wd\"4244\" /wd\"4309\" /wd\"4800\" /wd\"4996\" /wd\"4351\"") # disable some useless warnings
set(RELEASE_CXX_FLAGS "")
set(DEBUG_CXX_FLAGS "")
set(TEST_CXX_FLAGS "")
add_definitions(-DNOEXCEPT= -DHAS_MSVC_EXCEPTION_BUG)
# Increase the stack size to 8 MB (the default is 1 MB), needed for CBOT
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:8388608")
# Needed for Debug information (it's set to "No" by default for some reason)
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS} /DEBUG /NODEFAULTLIB:MSVCRTD /NODEFAULTLIB:LIBCMT")
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS} /DEBUG")
else()
message(FATAL_ERROR "Your C++ compiler doesn't seem to be supported.")
endif()
@ -216,6 +159,9 @@ endif()
# These are specific to GCC/MinGW/clang; for other compilers, change as necessary
# The flags are used throughout src/ and test/ subdirs
# Special flags for boost
add_definitions(-DBOOST_NO_SCOPED_ENUMS -DBOOST_NO_CXX11_SCOPED_ENUMS)
set(COLOBOT_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${NORMAL_CXX_FLAGS}")
set(COLOBOT_CXX_FLAGS_RELEASE "${RELEASE_CXX_FLAGS}")
set(COLOBOT_CXX_FLAGS_DEBUG "${DEBUG_CXX_FLAGS}")
@ -232,23 +178,20 @@ option(DEV_BUILD "Enable development build (enables some debugging tools, local
# Official build - changes text on the crash screen
# PLEASE DO NOT USE ON UNOFFICIAL BUILDS. Thanks.
option(COLOBOT_OFFICIAL_BUILD "Official build (changes crash screen text)" OFF)
option(OFFICIAL_BUILD "Official build (changes crash screen text)" OFF)
# Hardcode relative paths instead of absolute paths
option(USE_RELATIVE_PATHS "Generate relative paths from absolute paths" OFF)
# Portable build - load all data from the base directory
# Portable build - load all data from current directory
option(PORTABLE "Portable build" OFF)
# Portable saves - suitable for e.g. putting the whole game on external storage and moving your saves with it
option(PORTABLE_SAVES "Portable saves" OFF)
# Building tests can be enabled/disabled
option(TESTS "Build tests" OFF)
# Building tool programs can be enabled/disabled
option(TOOLS "Build tool programs" OFF)
# CBot can also be a static library
option(CBOT_STATIC "Build CBot as static libary" OFF)
# Generate desktop files, manpage, etc.
option(DESKTOP "Generate desktop files, manpages, etc" ON)
@ -258,24 +201,19 @@ option(INSTALL_DOCS "Install Doxygen-generated documentation" OFF)
# Build OpenAL sound support
option(OPENAL_SOUND "Build OpenAL sound support" ON)
# Link runtime library statically (currently only works for MSVC)
option(USE_STATIC_RUNTIME "Link the runtime library statically" OFF)
# CBot can also be a static library
option(CBOT_STATIC "Build CBot as static libary" OFF)
# This is useful in case you want to use static boost libraries
option(BOOST_STATIC "Link with static boost libraries" OFF)
# This is useful on Windows, if linking against standard GLEW dll fails
option(GLEW_STATIC "Link statically with GLEW" OFF)
# Link statically with LibSndFile
option(SNDFILE_STATIC "Link statically with LibSndFile" OFF)
# Sometimes helpful if there is a different version of gtest installed on system vs bundled
option(FORCE_BUNDLED_GTEST "Force the use of bundled gtest" OFF)
# This is for use with colobot-lint tool
option(COLOBOT_LINT_BUILD "Generate some additional CMake targets for use with colobot-lint" OFF)
# Default build type if not given is debug
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "Build type not specified - assuming debug")
@ -287,15 +225,6 @@ if(DEV_BUILD)
message(STATUS "Building with development extensions")
endif()
##
# Additional settings for MSYS
##
include("${colobot_SOURCE_DIR}/cmake/msys.cmake")
##
# Additional functions for colobot-lint
##
include("${colobot_SOURCE_DIR}/cmake/colobot-lint.cmake")
##
# Searching for packages
@ -308,29 +237,22 @@ find_package(SDL2_ttf REQUIRED)
find_package(PNG 1.2 REQUIRED)
find_package(Gettext REQUIRED)
find_package(PhysFS REQUIRED)
find_package(glm CONFIG REQUIRED)
# Add target alias glm::glm for older versions of the library
if(NOT TARGET glm::glm)
add_library(glm::glm ALIAS glm)
endif()
set(Boost_USE_STATIC_LIBS ${BOOST_STATIC})
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(nlohmann_json 3.10 QUIET)
set(Boost_ADDITIONALVERSION "1.51" "1.51.0")
find_package(Boost COMPONENTS system filesystem regex REQUIRED)
if(NOT nlohmann_json_FOUND)
message(STATUS "Using nlohmann_json git submodule")
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(lib/json)
endif()
set(GLEW_USE_STATIC_LIBS ${GLEW_STATIC})
find_package(GLEW REQUIRED)
if (OPENAL_SOUND)
find_package(OpenAL REQUIRED)
include_directories(${OPENAL_INCLUDE_DIR})
find_package(LibSndFile REQUIRED)
endif()
find_package(SndFile REQUIRED)
if(NOT ASSERTS)
add_definitions(-DNDEBUG)
@ -346,20 +268,38 @@ if(DEV_BUILD)
add_definitions(-DDEV_BUILD)
endif()
##
# Additional settings to use when cross-compiling with MXE (http://mxe.cc/)
##
include("${colobot_SOURCE_DIR}/cmake/mxe.cmake")
##
# Additional settings for MSYS
##
include("${colobot_SOURCE_DIR}/cmake/msys.cmake")
##
# Additional functions for colobot-lint
##
include("${colobot_SOURCE_DIR}/cmake/colobot-lint.cmake")
##
# MSVC specific settings
##
set(WINGETOPT 0)
if(MSVC)
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
message(STATUS "Adding MSVC-specific options")
set(CBOT_STATIC 1) # only this works for some reason
set(WINGETOPT 1) # use wingetopt library
endif()
##
# Localename
##
set(LOCALENAME_INCLUDE_DIR ${colobot_SOURCE_DIR}/lib/localename)
add_subdirectory(lib/localename)
@ -367,6 +307,7 @@ add_subdirectory(lib/localename)
# Wingetopt
##
if(WINGETOPT)
set(WINGETOPT_INCLUDE_DIR ${colobot_SOURCE_DIR}/lib/wingetopt/src)
add_subdirectory(lib/wingetopt)
endif()
@ -391,19 +332,21 @@ endif()
##
# Installation paths defined before compiling sources
if(PORTABLE)
set(COLOBOT_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot binary directory")
set(COLOBOT_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot libraries directory")
set(COLOBOT_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/data CACHE PATH "Colobot shared data directory")
set(COLOBOT_INSTALL_I18N_DIR ${CMAKE_INSTALL_PREFIX}/lang CACHE PATH "Colobot translations directory")
set(COLOBOT_INSTALL_DOC_DIR ${CMAKE_INSTALL_PREFIX}/doc CACHE PATH "Colobot documentation directory")
set(USE_RELATIVE_PATHS ON)
elseif(PLATFORM_WINDOWS)
set(COLOBOT_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot binary directory")
set(COLOBOT_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot libraries directory")
set(COLOBOT_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/data CACHE PATH "Colobot shared data directory")
set(COLOBOT_INSTALL_I18N_DIR ${CMAKE_INSTALL_PREFIX}/lang CACHE PATH "Colobot translations directory")
set(COLOBOT_INSTALL_DOC_DIR ${CMAKE_INSTALL_PREFIX}/doc CACHE PATH "Colobot documentation directory")
if(PLATFORM_WINDOWS)
if(MXE)
# We need to use STRING because PATH doesn't accept relative paths
set(COLOBOT_INSTALL_BIN_DIR ./ CACHE STRING "Colobot binary directory")
set(COLOBOT_INSTALL_LIB_DIR ./ CACHE STRING "Colobot libraries directory")
set(COLOBOT_INSTALL_DATA_DIR ./data CACHE STRING "Colobot shared data directory")
set(COLOBOT_INSTALL_I18N_DIR ./lang CACHE STRING "Colobot translations directory")
set(COLOBOT_INSTALL_DOC_DIR ./doc CACHE STRING "Colobot documentation directory")
else()
set(COLOBOT_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot binary directory")
set(COLOBOT_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot libraries directory")
set(COLOBOT_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/data CACHE PATH "Colobot shared data directory")
set(COLOBOT_INSTALL_I18N_DIR ${CMAKE_INSTALL_PREFIX}/lang CACHE PATH "Colobot translations directory")
set(COLOBOT_INSTALL_DOC_DIR ${CMAKE_INSTALL_PREFIX}/doc CACHE PATH "Colobot documentation directory")
endif()
elseif(PLATFORM_MACOSX)
set(COLOBOT_INSTALL_BIN_DIR ../MacOS CACHE STRING "Colobot binary directory")
set(COLOBOT_INSTALL_LIB_DIR ../MacOS CACHE STRING "Colobot libraries directory")
@ -418,63 +361,36 @@ else()
set(COLOBOT_INSTALL_DOC_DIR ${CMAKE_INSTALL_PREFIX}/share/doc/colobot CACHE PATH "Colobot documentation directory")
endif()
# Generate relative paths from absolute paths
if(USE_RELATIVE_PATHS)
message(STATUS "Generating relative paths")
file(RELATIVE_PATH COLOBOT_DATA_DIR ${COLOBOT_INSTALL_BIN_DIR} ${COLOBOT_INSTALL_DATA_DIR})
file(RELATIVE_PATH COLOBOT_I18N_DIR ${COLOBOT_INSTALL_BIN_DIR} ${COLOBOT_INSTALL_I18N_DIR})
add_definitions(-DUSE_RELATIVE_PATHS)
else()
set(COLOBOT_DATA_DIR ${COLOBOT_INSTALL_DATA_DIR})
set(COLOBOT_I18N_DIR ${COLOBOT_INSTALL_I18N_DIR})
endif()
# Subdirectory with common implementation
add_subdirectory(colobot-common)
# Add CBot
add_subdirectory(CBot)
# Add base Colobot implementation
add_subdirectory(colobot-base)
# Add Colobot executable
add_subdirectory(colobot-app)
# Subdirectory with sources
add_subdirectory(src)
add_subdirectory(po)
if(TOOLS)
add_subdirectory(tools)
endif()
if(DESKTOP)
add_subdirectory(desktop)
endif()
if(TESTS)
# Google Test library
find_package(GTest 1.11.0 QUIET)
if(NOT(FORCE_BUNDLED_GTEST) AND GTEST_FOUND)
message(STATUS "Using system gtest library in ${GTEST_BOTH_LIBRARIES}")
elseif(EXISTS "${colobot_SOURCE_DIR}/lib/googletest/googletest/CMakeLists.txt")
message(STATUS "Using gtest git submodule")
set(GOOGLETEST_VERSION "1.11.0")
add_subdirectory("${colobot_SOURCE_DIR}/lib/googletest/googletest" "lib/googletest/googletest")
# Add aliases so target names are compatible with the find_package above
add_library(GTest::GTest ALIAS gtest)
add_library(GTest::Main ALIAS gtest_main)
find_path(GTEST_SRC_DIR NAMES src/gtest.cc src/gtest-all.cc PATHS /usr/src PATH_SUFFIXES gtest)
find_path(GTEST_INCLUDE_DIR gtest/gtest.h PATHS /usr/include)
if(NOT(FORCE_BUNDLED_GTEST) AND GTEST_SRC_DIR AND GTEST_INCLUDE_DIR)
message(STATUS "Using system gtest library in ${GTEST_SRC_DIR}")
else()
message(FATAL_ERROR "Could not find gtest, cannot enable testing")
message(STATUS "Using bundled gtest library")
set(GTEST_SRC_DIR ${colobot_SOURCE_DIR}/lib/gtest)
set(GTEST_INCLUDE_DIR ${colobot_SOURCE_DIR}/lib/gtest/include)
endif()
add_subdirectory(${GTEST_SRC_DIR} lib/gtest)
# Hippomocks library
add_subdirectory(${colobot_SOURCE_DIR}/lib/hippomocks)
set(HIPPOMOCKS_INCLUDE_DIR ${colobot_SOURCE_DIR}/lib/hippomocks)
# Tests targets
enable_testing()
include(GoogleTest)
add_subdirectory(test)
endif()

View File

@ -1,83 +0,0 @@
{
"version": 3,
"cmakeMinimumRequired": {
"major": 3,
"minor": 21,
"patch": 0
},
"configurePresets": [
{
"name": "CI",
"description": "Base configuration for CI pipeline",
"hidden": true,
"binaryDir": "${sourceDir}/build",
"installDir": "${sourceDir}/install"
},
{
"name": "Windows-CI",
"description": "Windows configuration for CI pipeline",
"generator": "Ninja",
"inherits": ["CI"],
"cacheVariables": {
"CMAKE_C_COMPILER": "cl.exe",
"CMAKE_CXX_COMPILER": "cl.exe",
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"USE_STATIC_RUNTIME": true,
"CBOT_STATIC": true,
"GLEW_STATIC": true,
"SNDFILE_STATIC": true,
"DEV_BUILD": true,
"PORTABLE": true,
"TOOLS": true,
"TESTS": true,
"DESKTOP": true
}
},
{
"name": "Linux-CI",
"description": "Linux configuration for CI pipeline",
"inherits": ["CI"],
"cacheVariables": {
"CMAKE_SKIP_INSTALL_RPATH": true,
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"CBOT_STATIC": true,
"DEV_BUILD": true,
"PORTABLE": true,
"TOOLS": true,
"TESTS": true,
"DESKTOP": true
}
},
{
"name": "MacOS-CI",
"description": "MacOS configuration for CI pipeline",
"inherits": ["CI"],
"cacheVariables": {
"CMAKE_SKIP_INSTALL_RPATH": true,
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"DEV_BUILD": true,
"PORTABLE": true,
"TESTS": true,
"DESKTOP": true,
"OPENAL_LIBRARY": "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/OpenAL.framework/OpenAL.tbd"
}
}
],
"buildPresets": [
{
"name": "Windows-CI",
"configurePreset": "Windows-CI",
"configuration": "RelWithDebInfo"
},
{
"name": "Linux-CI",
"configurePreset": "Linux-CI",
"configuration": "RelWithDebInfo"
},
{
"name": "MacOS-CI",
"configurePreset": "MacOS-CI",
"configuration": "RelWithDebInfo"
}
]
}

View File

@ -3,97 +3,26 @@
So you want to contribute to Colobot: Gold Edition? That's awesome! Before you start, read this page, it contains a lot of useful information on how to do so.
## General information
Before you start, read more about technical details of the project. They can be found in our [Game Design Document](http://compiled.colobot.info/jenkins/job/colobot-gold-gdd/lastSuccessfulBuild/artifact/Colobot_Gold_Edition-Game_Design_Document.pdf) ([live editor](http://krzysh.pl:3000/project/545e90d99e8bceed2284797e)).
Before you start, read more about technical details of the project. They can be found in:
* [Developer README](docs/README-dev.md)
* [Doxygen documentation (doc)](https://github.com/colobot/colobot/actions)
* [Working with translations](https://github.com/colobot/colobot/wiki/Working-with-translations)
* [Working with models](https://github.com/colobot/colobot/wiki/Working-with-Colobot:-Gold-Edition-models)
* [Common issues](https://github.com/colobot/colobot/wiki/Common-Issues)
You may also find some useful information on the our (outdated) [dev wiki](http://colobot.info/wiki/dev).
## Before you start coding
* If you want to fix a bug, please first check the related [issue on GitHub's bug tracker](https://github.com/colobot/colobot/issues). If there isn't one, make it.
* If you want to add a new feature or make any change to gameplay, please first discuss it either [on Discord](https://discord.gg/56Fm9kb) or in the related issue on GitHub. When your issue gets *accepted* label, that means that your suggestion got accepted and is waiting for somebody to work on it. Always wait for your suggestion to be accepted before you start writing any code.
* If you want to add a new feature or make any change to gameplay, please first discuss it either [on the forums](http://colobot.info/forum) or in the related issue on GitHub. When your issue gets *accepted* label, that means that your suggestion got accepted and is waiting for somebody to work on it. Always wait for your suggestion to be accepted before you start writing any code.
* Before you start, check *"Assignee"* field in the issue and read the comments to see if nobody else is working on the same issue. If somebody is assigned to it, but there was no activity for a long time, you can take it over. Also, please post a comment on the issue that you want to help us, so other people don't waste time working at that issue in the same time.
## Coding style
See the [related page on dev wiki](http://colobot.info/wiki/dev/Coding_rules) for general guidelines, or [this file](https://github.com/colobot/colobot-lint/blob/master/RULES.md) for detailed description.
When writing code, please adhere to the following rules:
* Indent with spaces, 1 indentation level = 4 spaces. Unix line endings. And don't leave whitespace at the end of lines. Thank you.
* Put braces in new lines.
Like that:
```c++
if (a == b)
{
// ...
}
else
{
// ...
}
```
NOT like that:
```c++
if (a == b) {
// ...
} else {
// ...
}
```
You may omit braces if there is only one line in block:
```c++
if (a == b)
doStuff();
```
* Name functions beginning with upper case, e.g. `FooBar()`
* Name classes beginning with C, e.g. `class CSomeClass`
* Name accessors like so: `SetValue()` and `GetValue()`
* Name structs and enums beginning with uppercase letter, e.g. `struct SomeStruct`
* Enum values should begin with a prefix and underscore and should be all uppercase, e.g. `SOME_ENUM_VALUE`
* Use constant values instead of #define's, e.g. `const int MAX_SPACE = 1000;` instead of `#define MAX_SPACE 1000` (names should be all uppercase as in example)
* Don't use C-style casts, e.g. `(type)(foo)`. Use new C++-style casts, e.g. `static_cast<type>(foo)`.
* Don't use global variables - use static class members whenever possible.
* Provide full namespace qualifier wherever possible, e.g. Math::MultiplyMatrices to avoid confusion.
* Document the new code in Doxygen. Even a short description is better than nothing at all. Also, if you are changing/rewriting old code, please do the same.
* Put comments in your code but not explaining its structure or what it does (Doxygen is for that), but **why** it does so.
* Whenever possible, please write unit tests for your code. Tests should go into `test/` subdirectory in each of the code directories.
* You can use STL classes where needed.
* Throwing exceptions is allowed, with the exception of CBot code (which has no automated memory management yet, so memory leaks could possibly occur)
Also, when writing `#include`s:
* first - in `.cpp` modules - associated `.h` header, e.g. `#include "app/app.h"` in `app.cpp`
* then - local includes, e.g. `#include "common/logger.h"` (listed in alphabetical order for clarity)
* and last - global includes, e.g. `#include <SDL/SDL.h>`, `#include <vector>`
We also have an automated tool for checking the code style. See [colobot-lint repository](https://github.com/colobot/colobot-lint) for details.
See [colobot-lint repository](https://github.com/colobot/colobot-lint) for automated tool that checks the coding style.
If your pull request breaks the coding style, you will have to fix it before it gets merged.
## Commiting rules
Please adhere to the following rules:
* Commits should have meaningful descriptions.
* Commits should not break the build nor tests.
* Changes in one commit should not be too extensive, unless necessary.
* Merges to *master* branch must be discussed beforehand and should include fully finished features if possible.
## Submitting pull requests
After you finish working on your issue and want your code to be merged into the main repository, you should submit a **pull request**. Go to [this page](https://github.com/colobot/colobot/pulls) and select "New pull request". All pull requests should ALWAYS be submitted to the *dev* branch. After your PR gets reviewed by our development team, it will be merged to *dev* branch, and on the next release - to the *master* branch.
After you finish working on your issue and want your code to be merged into the main repository, you should submit a **pull request**. Go to [this page](https://github.com/colobot/colobot/pulls) and select "New pull request". All pull request should ALWAYS be submitted to the *dev* branch. After your PR gets reviewed by our development team, it will be merged to *dev* branch, and on the next release - to the *master* branch.
If you need more help, see [GitHub's help page on Pull Requests](https://help.github.com/articles/using-pull-requests/).
## Need help?
Ask on our [Discord server](https://discord.gg/56Fm9kb) or [GitHub Discussions](https://github.com/colobot/colobot/discussions). We're here to help :)
Ask on our official Freenode channel (#colobot @ irc.freenode.net) or on our [forums](http://colobot.info/forum/). We're here to help :)

View File

@ -351,7 +351,7 @@ IDL_PROPERTY_SUPPORT = YES
# all members of a group must be documented explicitly.
# The default value is: NO.
DISTRIBUTE_GROUP_DOC = YES
DISTRIBUTE_GROUP_DOC = NO
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
@ -859,7 +859,7 @@ EXAMPLE_RECURSIVE = NO
# that contain images that are to be included in the documentation (see the
# \image command).
IMAGE_PATH = "@CMAKE_CURRENT_SOURCE_DIR@/docs/images"
IMAGE_PATH =
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
@ -993,7 +993,7 @@ USE_HTAGS = NO
# See also: Section \class.
# The default value is: YES.
VERBATIM_HEADERS = NO
VERBATIM_HEADERS = YES
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the

91
INSTALL-MXE.md Normal file
View File

@ -0,0 +1,91 @@
# Cross-compiling with MXE
MXE works for any BSD-compatible system (including Linux).
It is a complete package with cross-compiler to Win32 (a MinGW variant)
and includes scripts to automatically download and build many 3rd party
libraries and tools.
To cross-compile Colobot using MXE:
1. See the MXE website (http://mxe.cc) for list of required packages and make sure
you have them installed.
2. Download MXE and unpack it in the directory, where you want to keep it
permanently. During the build, MXE will write that path to many files,
so moving that directory can be tricky.
3. `cd` to the MXE root directory.
It already contains a universal Makefile for everything.
Usage is simply `make name_of_package`.
It will automatically check for dependencies, etc.
The packages will be installed in the MXE directory under `usr/i686-w64-mingw32.static`.
You need to `make gcc` first for basic compiler and then do the same
for some additional libraries. In the end, you should have the following
packages installed (this is the final listing of `usr/i686-w64-mingw32.static/installed/`):
* binutils
* boost
* bzip2
* cairo
* dbus
* expat
* flac
* fontconfig
* freetype
* freetype-bootstrap
* gcc
* gcc-gmp
* gcc-isl
* gcc-mpc
* gcc-mpfr
* gettext
* glew
* glib
* harfbuzz
* icu4c
* jpeg
* libffi
* libiconv
* libpng
* libsndfile
* libwebp
* lzo
* mingw-w64
* mxe-conf
* ogg
* openal
* pcre
* physfs
* pixman
* pkgconf
* portaudio
* sdl2
* sdl2_image
* sdl2_ttf
* tiff
* vorbis
* xz
* zlib
4. Now `cd` to directory with colobot sources.
It is recommended that you create a separate directory for out-of-source build:
`mkdir build-mxe && cd build-mxe`
In order to cross-compile a CMake project, you have to specify a CMake toolchain file.
MXE has such file in MXE's directory: `usr/i686-w64-mingw32.static/share/cmake/mxe-conf.cmake`
So you should use the following cmake command: `cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/mxe-conf.cmake ..`
CMake files in Colobot should detect that MXE is being used and they will
modify flags, paths, etc. as required. You should not run into any problems.
5. `make` should now compile the game with the resulting executable as `colobot.exe`.
The exe is linked against all libraries *statically*, so there are no dependencies
on external DLLs. However, the resulting binary will be huge with all these libraries,
so you might want to do: `strip colobot.exe`.
6. If you want to create a Colobot installer, you need to additionally build `nsis`
in MXE. Then you can create the NSIS installer that way:
`PATH=/path/to/mxe/binaries:$PATH make package`
where `/path/to/mxe/binaries` is path to cross-compiled MXE binaries available
in MXE's directory under `usr/i686-w64-mingw32.static/bin`.
This will create a versioned colobot-$version.exe installer that will install Colobot
in system directories, add a shortcut in the start menu and setup an uninstaller.

View File

@ -4,11 +4,11 @@ To compile Colobot on MacOS X, you need to first get Developer Command Line Tool
After installing Developer Command Line Tools, you should have basic tools like clang and git installed. After that, you can grab other required packages with Homebrew. So as in instructions on [the project page](http://brew.sh/):
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
And then:
```bash
brew install cmake sdl2 sdl2_image sdl2_ttf glew physfs flac libsndfile libvorbis vorbis-tools gettext libicns librsvg wget xmlstarlet
brew install cmake sdl2 sdl2_image sdl2_ttf boost glew physfs flac libsndfile libvorbis vorbis-tools gettext libicns librsvg wget
```
Gettext is installed in separate directory without adding the files to system path, so in order to get it working normally, you should call also:
```bash
@ -20,7 +20,7 @@ If you've installed everything correctly, the simple way of compiling Colobot wi
git clone --recursive https://github.com/colobot/colobot.git
mkdir colobot/build
cd colobot/build
cmake -DOPENAL_LIBRARY=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/OpenAL.framework/OpenAL.tbd ../
cmake ../
make
```

View File

@ -27,15 +27,24 @@ any of the missions.
### Compiling on Windows
You can also compile directly on Windows with MSYS2/MinGW-w64 or Visual Studio since version 2015.
The recommended way of compiling for Windows is using Linux in a cross-compilation environment called MXE.
This is the way our build bot service (http://compiled.colobot.info/) prepares the release packages.
You can also compile directly on Windows with MSYS2/MinGW-w64 or MSVC 2013 but this is a bit more difficult to set up.
#### Cross-compiling using MXE
MXE (M cross environment, http://mxe.cc/) is a very good cross-compiling framework, complete with a suite of libraries
that make it extremely easy to port applications to Win32. It runs on pretty much any *nix flavor and generates generic,
statically linked Win32 binaries. More information is available in
[INSTALL-MXE.md](INSTALL-MXE.md) file.
#### Compiling with MSYS2/MinGW-w64
See the [INSTALL-MSYS2.md](docs/INSTALL-MSYS2.md) file for details.
See [this wiki page](http://colobot.info/wiki/dev/Compiling_GOLD_on_Windows_with_MSYS2) for details.
#### Compiling with MSVC (Visual Studio)
#### Compiling with MSVC
See [this wiki page](https://github.com/colobot/colobot/wiki/How-to-Build-Colobot:-Gold-Edition-Using-MSVC) for details.
As of 0.1.5-alpha it's possible to compile binary with MSVC 2013. See [this post](http://colobot.info/forum/showthread.php?tid=595&pid=5831#pid5831) for details.
### Compiling on Linux
@ -44,24 +53,25 @@ Since there are so many Linux flavors, it is difficult to write generic instruct
you will need to compile colobot.
You will need:
* C++17 compiler
* CMake >= 3.16
* recent compiler (GCC >= 4.7, or Clang >= 3.1) since we are using some features of C++11
* CMake >= 2.8
* Boost >= 1.51 (header files + components: filesystem and regex)
* SDL2
* SDL2_image
* SDL2_ttf
* GLEW
* libpng
* gettext
* libsndfile
* libvorbis
* libogg
* OpenAL (OpenAL-Soft)
* GLEW >= 1.8.0
* libpng >= 1.2
* gettext >= 0.18
* libsndfile >= 1.0.25
* libvorbis >= 1.3.2
* libogg >= 1.3.0
* OpenAL (OpenAL-Soft) >= 1.13
* PhysFS
* oggenc (to generate music files)
On Ubuntu (and probably any other Debian-based system), you can use the following command to install all required packages:
```
$ apt-get install build-essential cmake libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsndfile1-dev libvorbis-dev libogg-dev libpng-dev libglew-dev libopenal-dev libphysfs-dev gettext git po4a vorbis-tools
$ apt-get install build-essential cmake libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsndfile1-dev libvorbis-dev libogg-dev libpng12-dev libglew-dev libopenal-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-regex-dev libphysfs-dev gettext git po4a vorbis-tools
```
Make sure you install the packages along with header files (often distributed in separate *-dev packages). If you miss any requirements,
@ -115,7 +125,7 @@ So if you provided prefix "/some/prefix", you can run:
### Compiling on MacOS X
As of 0.1.2-alpha, we have added MacOS X support. See [INSTALL-MacOSX.md](docs/INSTALL-MacOSX.md)
As of 0.1.2-alpha, we have added MacOS X support. See [INSTALL-MacOSX.md](https://github.com/colobot/colobot/blob/master/INSTALL-MacOSX.md)
file for details.

View File

@ -1,6 +1,6 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify

View File

@ -1,56 +1,50 @@
<img src="https://raw.githubusercontent.com/colobot/colobot-misc/master/logos/ColobotGE-logo.svg" align="center">
# Colobot: Gold Edition
<div align="center">
<a href="https://colobot.info/"><img src="https://img.shields.io/badge/colobot.info-F5C700.svg?logo=wordpress&logoColor=white" alt="colobot.info"></a>
<a href="https://discord.gg/56Fm9kb"><img src="https://img.shields.io/badge/Discord-5865F2.svg?logo=discord&logoColor=white" alt="Discord"></a>
<a href="https://github.com/colobot/colobot/discussions"><img src="https://img.shields.io/badge/Discussions-24292F.svg?logo=github" alt="GitHub Discussions"></a>
<a href="https://www.moddb.com/games/colobot-gold-edition"><img src="https://img.shields.io/badge/ModDB-CC0000.svg?logo=modrinth&logoColor=white" alt="ModDB"></a>
<a href="https://www.youtube.com/@Colobot"><img src="https://img.shields.io/badge/YouTube-EA3223.svg?logo=youtube" alt="YouTube"></a>
<a href="https://www.reddit.com/r/Colobot"><img src="https://img.shields.io/badge/Reddit-FF4300.svg?logo=reddit&logoColor=white" alt="Reddit"></a>
<a href="https://twitter.com/ColobotGame"><img src="https://img.shields.io/badge/Twitter-009EF7.svg?logo=twitter&logoColor=white" alt="Twitter"></a>
<a href="https://www.facebook.com/colobotgame"><img src="https://img.shields.io/badge/Facebook-1877F2.svg?logo=facebook&logoColor=white" alt="Facebook"></a>
</div>
Welcome to the Colobot: Gold Edition project code repository
This is the main repository for the open-source _Colobot: Gold Edition_ project developed by [TerranovaTeam](https://github.com/orgs/colobot/people) and community contributors, based on the original game by [Epsitec](https://www.epsitec.ch).
This is official repository for the open-source Colobot: Gold Edition project developed by TerranovaTeam, part of International Colobot Community (ICC, previously known as Polish Portal of Colobot/PPC) with the official site at: [colobot.info](http://colobot.info/).
This repository contains only the source code of the project. The game also requires data files which are provided as a git submodule and are hosted in a [separate repository](https://github.com/colobot/colobot-data).
The source code contained here was released by Epsitec -- the original creator of the game -- on open source (GPLv3) license. The code was given and the rights granted specifically to ICC community in March 2012. Since then, we have been developing the game further.
## Features
More information for developers (in English) can be found on the [developer wiki](http://colobot.info/wiki/dev/) or [our forum](http://colobot.info/forum/). However, the freshest source of information is our IRC channels (see below).
- Multiplatform - play the game on any modern OS.
- New game modes - challenge yourself in _Missions+_ or challenge your friends in _CodeBattles_.
- Mod support - download custom levels and assets from [our ModDB page](https://www.moddb.com/games/colobot-gold-edition).
- Improved visuals, QoL additions, bug fixes, and [other improvements](https://colobot.info/category/news/updates).
This repository contains only the source code of the project. The game requires also data files which are now provided as git submodule and are hosted in [separate repository](https://github.com/colobot/colobot-data).
## Download
### Stable releases
## Status
Official builds for Windows, Linux, MacOS are available here:\
[![Latest release](https://img.shields.io/github/v/release/colobot/colobot.svg?color=F5C700)](https://colobot.info/download-colobot-gold)
The original version of the game, as released to us by Epsitec, is available as download at [our download site](http://colobot.info/files/) along with original source code and related data files. However, we will not develop this version further, as we focused our efforts on new versions of the game. The original version is also known as Colobot Classic.
Linux packages:\
[![latest packaged version(s)](https://repology.org/badge/latest-versions/colobot.svg)](https://repology.org/project/colobot/versions)\
[![Debian Unstable package](https://repology.org/badge/version-for-repo/debian_unstable/colobot.svg)](http://packages.debian.org/sid/colobot)\
[![AUR package](https://repology.org/badge/version-for-repo/aur/colobot-gold.svg)](https://aur.archlinux.org/packages/colobot-gold)\
[![openSUSE games Tumbleweed package](https://repology.org/badge/version-for-repo/opensuse_games_tumbleweed/colobot.svg)](http://software.opensuse.org/download.html?project=games&package=colobot)\
[![Fedora Rawhide package](https://repology.org/badge/version-for-repo/fedora_rawhide/colobot.svg)](https://src.fedoraproject.org/rpms/colobot)\
[![GNU Guix package](https://repology.org/badge/version-for-repo/gnuguix/colobot.svg)](https://packages.guix.gnu.org/packages/colobot)\
[![Void Linux x86_64 package](https://repology.org/badge/version-for-repo/void_x86_64/colobot.svg)](https://github.com/void-linux/void-packages/tree/master/srcpkgs/colobot)
We are now working on refreshed and updated version of original game, codename Colobot Gold and this is the version currently hosted in this repository. The goal is to rewrite the game engine to be multi-platform, refresh the graphics, include some enhancements and refactor the code to make the game easier to modify.
### Development builds
The project at this point is in alpha stage - the game is mostly playable, both on Windows and Linux, and most major bugs have been corrected. We are now working steadily towards subsequent beta releases, correcting other bugs and introducing enhancements and new features. There is a lot of work ahead and we will gladly accept any and all help.
Development builds are compiled every push to the repository by GitHub Actions:\
[![Workflows](https://img.shields.io/github/last-commit/colobot/colobot/dev.svg)](https://github.com/colobot/colobot/actions)
In the future, we will begin development on a new installment in the Colobot series, codename Colobot 2. We have many ideas for the new game and we are still discussing them. Generally, the development of this version will begin only after finishing Colobot Gold (it will be probably hosted in another repository, forked off the Colobot Gold code).
## Compiling from source
Instructions on how to build the game from sources are available for the following environments:
- [Linux](INSTALL.md)
- [Windows (MSYS2)](docs/INSTALL-MSYS2.md)
- [Windows (MSVC)](https://github.com/colobot/colobot/wiki/How-to-Build-Colobot%3A-Gold-Edition-Using-MSVC)
- [MacOS](docs/INSTALL-MacOSX.md)
## Download packages
We provide compiled packages of most recent versions using an [automated build bot service](http://compiled.colobot.info/). Available versions include packages for Windows and Linux in both Release and Debug configurations.
On some Linux distributions there are also distribution packages available:
* Debian Sid (unstable): http://packages.debian.org/sid/colobot
* Arch Linux (AUR): https://aur.archlinux.org/packages/colobot-gold
* openSUSE: http://software.opensuse.org/download.html?project=games&package=colobot
## Compiling and running the game
If you want to compile colobot yourself, see [INSTALL.md](INSTALL.md) file.
## Contributing
If you want to contribute to the project, see [CONTRIBUTING.md](CONTRIBUTING.md).
If you want to contribute to the project, see [CONTRIBUTING.md](CONTRIBUTING.md) file. It contains a lot of useful information on how to get started.
## Contact
If you want to help in the project, please contact us on our IRC channels or [our forum](http://colobot.info/forum/).
### IRC channels
* [#colobot on Freenode](irc://freenode.net#colobot) - main development channel (English);
* [#colobot on pirc.pl](irc://pirc.pl#colobot) - Polish community channel;

View File

@ -1,132 +0,0 @@
CMake - Cross Platform Makefile Generator
Copyright 2000-2020 Kitware, Inc. and Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Kitware, Inc. nor the names of Contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
The following individuals and institutions are among the Contributors:
* Aaron C. Meadows <cmake@shadowguarddev.com>
* Adriaan de Groot <groot@kde.org>
* Aleksey Avdeev <solo@altlinux.ru>
* Alexander Neundorf <neundorf@kde.org>
* Alexander Smorkalov <alexander.smorkalov@itseez.com>
* Alexey Sokolov <sokolov@google.com>
* Alex Merry <alex.merry@kde.org>
* Alex Turbov <i.zaufi@gmail.com>
* Andreas Pakulat <apaku@gmx.de>
* Andreas Schneider <asn@cryptomilk.org>
* André Rigland Brodtkorb <Andre.Brodtkorb@ifi.uio.no>
* Axel Huebl, Helmholtz-Zentrum Dresden - Rossendorf
* Benjamin Eikel
* Bjoern Ricks <bjoern.ricks@gmail.com>
* Brad Hards <bradh@kde.org>
* Christopher Harvey
* Christoph Grüninger <foss@grueninger.de>
* Clement Creusot <creusot@cs.york.ac.uk>
* Daniel Blezek <blezek@gmail.com>
* Daniel Pfeifer <daniel@pfeifer-mail.de>
* Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
* Eran Ifrah <eran.ifrah@gmail.com>
* Esben Mose Hansen, Ange Optimization ApS
* Geoffrey Viola <geoffrey.viola@asirobots.com>
* Google Inc
* Gregor Jasny
* Helio Chissini de Castro <helio@kde.org>
* Ilya Lavrenov <ilya.lavrenov@itseez.com>
* Insight Software Consortium <insightsoftwareconsortium.org>
* Jan Woetzel
* Julien Schueller
* Kelly Thompson <kgt@lanl.gov>
* Laurent Montel <montel@kde.org>
* Konstantin Podsvirov <konstantin@podsvirov.pro>
* Mario Bensi <mbensi@ipsquad.net>
* Martin Gräßlin <mgraesslin@kde.org>
* Mathieu Malaterre <mathieu.malaterre@gmail.com>
* Matthaeus G. Chajdas
* Matthias Kretz <kretz@kde.org>
* Matthias Maennich <matthias@maennich.net>
* Michael Hirsch, Ph.D. <www.scivision.co>
* Michael Stürmer
* Miguel A. Figueroa-Villanueva
* Mike Jackson
* Mike McQuaid <mike@mikemcquaid.com>
* Nicolas Bock <nicolasbock@gmail.com>
* Nicolas Despres <nicolas.despres@gmail.com>
* Nikita Krupen'ko <krnekit@gmail.com>
* NVIDIA Corporation <www.nvidia.com>
* OpenGamma Ltd. <opengamma.com>
* Patrick Stotko <stotko@cs.uni-bonn.de>
* Per Øyvind Karlsen <peroyvind@mandriva.org>
* Peter Collingbourne <peter@pcc.me.uk>
* Petr Gotthard <gotthard@honeywell.com>
* Philip Lowman <philip@yhbt.com>
* Philippe Proulx <pproulx@efficios.com>
* Raffi Enficiaud, Max Planck Society
* Raumfeld <raumfeld.com>
* Roger Leigh <rleigh@codelibre.net>
* Rolf Eike Beer <eike@sf-mail.de>
* Roman Donchenko <roman.donchenko@itseez.com>
* Roman Kharitonov <roman.kharitonov@itseez.com>
* Ruslan Baratov
* Sebastian Holtermann <sebholt@xwmw.org>
* Stephen Kelly <steveire@gmail.com>
* Sylvain Joubert <joubert.sy@gmail.com>
* The Qt Company Ltd.
* Thomas Sondergaard <ts@medical-insight.com>
* Tobias Hunger <tobias.hunger@qt.io>
* Todd Gamblin <tgamblin@llnl.gov>
* Tristan Carel
* University of Dundee
* Vadim Zhukov
* Will Dicharry <wdicharry@stellarscience.com>
See version control history for details of individual contributions.
The above copyright and license notice applies to distributions of
CMake in source and binary form. Third-party software packages supplied
with CMake under compatible licenses provide their own copyright notices
documented in corresponding subdirectories or source files.
------------------------------------------------------------------------------
CMake was initially developed by Kitware with the following sponsorship:
* National Library of Medicine at the National Institutes of Health
as part of the Insight Segmentation and Registration Toolkit (ITK).
* US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
Visualization Initiative.
* National Alliance for Medical Image Computing (NAMIC) is funded by the
National Institutes of Health through the NIH Roadmap for Medical Research,
Grant U54 EB005149.
* Kitware, Inc.

View File

@ -1,69 +0,0 @@
# - Find FLAC
# Find the native FLAC includes and libraries
#
# FLAC_INCLUDE_DIRS - where to find FLAC headers.
# FLAC_LIBRARIES - List of libraries when using libFLAC.
# FLAC_FOUND - True if libFLAC found.
# FLAC_DEFINITIONS - FLAC compile definitons
# From https://github.com/erikd/libsndfile/
if (FLAC_INCLUDE_DIR)
# Already in cache, be silent
set (FLAC_FIND_QUIETLY TRUE)
endif ()
find_package (Ogg QUIET)
find_package (PkgConfig QUIET)
pkg_check_modules(PC_FLAC QUIET flac)
set(FLAC_VERSION ${PC_FLAC_VERSION})
find_path (FLAC_INCLUDE_DIR FLAC/stream_decoder.h
HINTS
${PC_FLAC_INCLUDEDIR}
${PC_FLAC_INCLUDE_DIRS}
${FLAC_ROOT}
)
# MSVC built libraries can name them *_static, which is good as it
# distinguishes import libraries from static libraries with the same extension.
find_library (FLAC_LIBRARY
NAMES
FLAC
libFLAC
libFLAC_dynamic
libFLAC_static
HINTS
${PC_FLAC_LIBDIR}
${PC_FLAC_LIBRARY_DIRS}
${FLAC_ROOT}
)
# Handle the QUIETLY and REQUIRED arguments and set FLAC_FOUND to TRUE if
# all listed variables are TRUE.
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (FLAC
REQUIRED_VARS
FLAC_LIBRARY
FLAC_INCLUDE_DIR
Ogg_FOUND
VERSION_VAR
FLAC_VERSION
)
if (FLAC_FOUND)
set (FLAC_INCLUDE_DIRS ${FLAC_INCLUDE_DIR})
set (FLAC_LIBRARIES ${FLAC_LIBRARY} ${OGG_LIBRARIES})
if (NOT TARGET FLAC::FLAC)
add_library(FLAC::FLAC UNKNOWN IMPORTED)
set_target_properties(FLAC::FLAC PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${FLAC_INCLUDE_DIR}"
IMPORTED_LOCATION "${FLAC_LIBRARY}"
INTERFACE_LINK_LIBRARIES Ogg::ogg
)
endif ()
endif ()
mark_as_advanced(FLAC_INCLUDE_DIR FLAC_LIBRARY)

View File

@ -1,342 +1,51 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindGLEW
--------
Find the OpenGL Extension Wrangler Library (GLEW)
Input Variables
^^^^^^^^^^^^^^^
The following variables may be set to influence this module's behavior:
``GLEW_USE_STATIC_LIBS``
to find and create :prop_tgt:`IMPORTED` target for static linkage.
``GLEW_VERBOSE``
to output a detailed log of this module.
Imported Targets
^^^^^^^^^^^^^^^^
This module defines the following :ref:`Imported Targets <Imported Targets>`:
``GLEW::glew``
The GLEW shared library.
``GLEW::glew_s``
The GLEW static library, if ``GLEW_USE_STATIC_LIBS`` is set to ``TRUE``.
``GLEW::GLEW``
Duplicates either ``GLEW::glew`` or ``GLEW::glew_s`` based on availability.
Result Variables
^^^^^^^^^^^^^^^^
This module defines the following variables:
``GLEW_INCLUDE_DIRS``
include directories for GLEW
``GLEW_LIBRARIES``
libraries to link against GLEW
``GLEW_SHARED_LIBRARIES``
libraries to link against shared GLEW
``GLEW_STATIC_LIBRARIES``
libraries to link against static GLEW
``GLEW_FOUND``
true if GLEW has been found and can be used
``GLEW_VERSION``
GLEW version
``GLEW_VERSION_MAJOR``
GLEW major version
``GLEW_VERSION_MINOR``
GLEW minor version
``GLEW_VERSION_MICRO``
GLEW micro version
#]=======================================================================]
include(FindPackageHandleStandardArgs)
find_package(GLEW CONFIG QUIET)
if(GLEW_FOUND)
find_package_handle_standard_args(GLEW DEFAULT_MSG GLEW_CONFIG)
return()
endif()
if(GLEW_VERBOSE)
message(STATUS "FindGLEW: did not find GLEW CMake config file. Searching for libraries.")
endif()
if(APPLE)
find_package(OpenGL QUIET)
if(OpenGL_FOUND)
if(GLEW_VERBOSE)
message(STATUS "FindGLEW: Found OpenGL Framework.")
message(STATUS "FindGLEW: OPENGL_LIBRARIES: ${OPENGL_LIBRARIES}")
endif()
else()
if(GLEW_VERBOSE)
message(STATUS "FindGLEW: could not find GLEW library.")
endif()
return()
endif()
endif()
function(__glew_set_find_library_suffix shared_or_static)
if((UNIX AND NOT APPLE) AND "${shared_or_static}" MATCHES "SHARED")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" PARENT_SCOPE)
elseif((UNIX AND NOT APPLE) AND "${shared_or_static}" MATCHES "STATIC")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
elseif(APPLE AND "${shared_or_static}" MATCHES "SHARED")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib;.so" PARENT_SCOPE)
elseif(APPLE AND "${shared_or_static}" MATCHES "STATIC")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE)
elseif(WIN32 AND "${shared_or_static}" MATCHES "SHARED")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" PARENT_SCOPE)
elseif(WIN32 AND "${shared_or_static}" MATCHES "STATIC")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib;.dll.a" PARENT_SCOPE)
endif()
if(GLEW_VERBOSE)
message(STATUS "FindGLEW: CMAKE_FIND_LIBRARY_SUFFIXES for ${shared_or_static}: ${CMAKE_FIND_LIBRARY_SUFFIXES}")
endif()
endfunction()
if(GLEW_VERBOSE)
if(DEFINED GLEW_USE_STATIC_LIBS)
message(STATUS "FindGLEW: GLEW_USE_STATIC_LIBS: ${GLEW_USE_STATIC_LIBS}.")
else()
message(STATUS "FindGLEW: GLEW_USE_STATIC_LIBS is undefined. Treated as FALSE.")
endif()
endif()
find_path(GLEW_INCLUDE_DIR GL/glew.h)
mark_as_advanced(GLEW_INCLUDE_DIR)
set(GLEW_INCLUDE_DIRS ${GLEW_INCLUDE_DIR})
if(GLEW_VERBOSE)
message(STATUS "FindGLEW: GLEW_INCLUDE_DIR: ${GLEW_INCLUDE_DIR}")
message(STATUS "FindGLEW: GLEW_INCLUDE_DIRS: ${GLEW_INCLUDE_DIRS}")
endif()
if("${CMAKE_GENERATOR_PLATFORM}" MATCHES "x64" OR "${CMAKE_GENERATOR}" MATCHES "Win64")
set(_arch "x64")
else()
set(_arch "Win32")
endif()
set(__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
__glew_set_find_library_suffix(SHARED)
find_library(GLEW_SHARED_LIBRARY_RELEASE
NAMES GLEW glew glew32
PATH_SUFFIXES lib lib64 libx32 lib/Release/${_arch}
PATHS ENV GLEW_ROOT)
find_library(GLEW_SHARED_LIBRARY_DEBUG
NAMES GLEWd glewd glew32d
PATH_SUFFIXES lib lib64
PATHS ENV GLEW_ROOT)
__glew_set_find_library_suffix(STATIC)
find_library(GLEW_STATIC_LIBRARY_RELEASE
NAMES GLEW glew glew32s
PATH_SUFFIXES lib lib64 libx32 lib/Release/${_arch}
PATHS ENV GLEW_ROOT)
find_library(GLEW_STATIC_LIBRARY_DEBUG
NAMES GLEWds glewds glew32ds
PATH_SUFFIXES lib lib64
PATHS ENV GLEW_ROOT)
set(CMAKE_FIND_LIBRARY_SUFFIXES ${__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES})
unset(__GLEW_CURRENT_FIND_LIBRARY_SUFFIXES)
include(SelectLibraryConfigurations)
select_library_configurations(GLEW_SHARED)
select_library_configurations(GLEW_STATIC)
if(NOT GLEW_USE_STATIC_LIBS)
set(GLEW_LIBRARIES ${GLEW_SHARED_LIBRARY})
else()
set(GLEW_LIBRARIES ${GLEW_STATIC_LIBRARY})
endif()
if(GLEW_VERBOSE)
message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY_RELEASE: ${GLEW_SHARED_LIBRARY_RELEASE}")
message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY_RELEASE: ${GLEW_STATIC_LIBRARY_RELEASE}")
message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY_DEBUG: ${GLEW_SHARED_LIBRARY_DEBUG}")
message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY_DEBUG: ${GLEW_STATIC_LIBRARY_DEBUG}")
message(STATUS "FindGLEW: GLEW_SHARED_LIBRARY: ${GLEW_SHARED_LIBRARY}")
message(STATUS "FindGLEW: GLEW_STATIC_LIBRARY: ${GLEW_STATIC_LIBRARY}")
message(STATUS "FindGLEW: GLEW_LIBRARIES: ${GLEW_LIBRARIES}")
endif()
# Read version from GL/glew.h file
if(EXISTS "${GLEW_INCLUDE_DIR}/GL/glew.h")
file(STRINGS "${GLEW_INCLUDE_DIR}/GL/glew.h" _contents REGEX "^VERSION_.+ [0-9]+")
if(_contents)
string(REGEX REPLACE ".*VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MAJOR "${_contents}")
string(REGEX REPLACE ".*VERSION_MINOR[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MINOR "${_contents}")
string(REGEX REPLACE ".*VERSION_MICRO[ \t]+([0-9]+).*" "\\1" GLEW_VERSION_MICRO "${_contents}")
set(GLEW_VERSION "${GLEW_VERSION_MAJOR}.${GLEW_VERSION_MINOR}.${GLEW_VERSION_MICRO}")
endif()
endif()
if(GLEW_VERBOSE)
message(STATUS "FindGLEW: GLEW_VERSION_MAJOR: ${GLEW_VERSION_MAJOR}")
message(STATUS "FindGLEW: GLEW_VERSION_MINOR: ${GLEW_VERSION_MINOR}")
message(STATUS "FindGLEW: GLEW_VERSION_MICRO: ${GLEW_VERSION_MICRO}")
message(STATUS "FindGLEW: GLEW_VERSION: ${GLEW_VERSION}")
endif()
find_package_handle_standard_args(GLEW
REQUIRED_VARS GLEW_INCLUDE_DIRS GLEW_LIBRARIES
VERSION_VAR GLEW_VERSION)
if(NOT GLEW_FOUND)
if(GLEW_VERBOSE)
message(STATUS "FindGLEW: could not find GLEW library.")
endif()
return()
endif()
if(NOT TARGET GLEW::glew AND NOT GLEW_USE_STATIC_LIBS)
if(GLEW_VERBOSE)
message(STATUS "FindGLEW: Creating GLEW::glew imported target.")
endif()
add_library(GLEW::glew UNKNOWN IMPORTED)
set_target_properties(GLEW::glew
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
if(APPLE)
set_target_properties(GLEW::glew
PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
endif()
if(GLEW_SHARED_LIBRARY_RELEASE)
set_property(TARGET GLEW::glew
APPEND
PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(GLEW::glew
PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_SHARED_LIBRARY_RELEASE}")
endif()
if(GLEW_SHARED_LIBRARY_DEBUG)
set_property(TARGET GLEW::glew
APPEND
PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(GLEW::glew
PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_SHARED_LIBRARY_DEBUG}")
endif()
elseif(NOT TARGET GLEW::glew_s AND GLEW_USE_STATIC_LIBS)
if(GLEW_VERBOSE)
message(STATUS "FindGLEW: Creating GLEW::glew_s imported target.")
endif()
add_library(GLEW::glew_s UNKNOWN IMPORTED)
set_target_properties(GLEW::glew_s
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
if(APPLE)
set_target_properties(GLEW::glew_s
PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
endif()
if(GLEW_STATIC_LIBRARY_RELEASE)
set_property(TARGET GLEW::glew_s
APPEND
PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(GLEW::glew_s
PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_STATIC_LIBRARY_RELEASE}")
endif()
if(GLEW_STATIC_LIBRARY_DEBUG)
set_property(TARGET GLEW::glew_s
APPEND
PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(GLEW::glew_s
PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_STATIC_LIBRARY_DEBUG}")
endif()
endif()
if(NOT TARGET GLEW::GLEW)
if(GLEW_VERBOSE)
message(STATUS "FindGLEW: Creating GLEW::GLEW imported target.")
endif()
add_library(GLEW::GLEW UNKNOWN IMPORTED)
set_target_properties(GLEW::GLEW
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLEW_INCLUDE_DIRS}")
if(APPLE)
set_target_properties(GLEW::GLEW
PROPERTIES INTERFACE_LINK_LIBRARIES OpenGL::GL)
endif()
if(TARGET GLEW::glew)
if(GLEW_SHARED_LIBRARY_RELEASE)
set_property(TARGET GLEW::GLEW
APPEND
PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(GLEW::GLEW
PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_SHARED_LIBRARY_RELEASE}")
endif()
if(GLEW_SHARED_LIBRARY_DEBUG)
set_property(TARGET GLEW::GLEW
APPEND
PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(GLEW::GLEW
PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_SHARED_LIBRARY_DEBUG}")
endif()
elseif(TARGET GLEW::glew_s)
if(GLEW_STATIC_LIBRARY_RELEASE)
set_property(TARGET GLEW::GLEW
APPEND
PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(GLEW::GLEW
PROPERTIES IMPORTED_LOCATION_RELEASE "${GLEW_STATIC_LIBRARY_RELEASE}")
endif()
if(GLEW_STATIC_LIBRARY_DEBUG AND GLEW_USE_STATIC_LIBS)
set_property(TARGET GLEW::GLEW
APPEND
PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(GLEW::GLEW
PROPERTIES IMPORTED_LOCATION_DEBUG "${GLEW_STATIC_LIBRARY_DEBUG}")
endif()
elseif(GLEW_VERBOSE)
message(WARNING "FindGLEW: no `GLEW::glew` or `GLEW::glew_s` target was created. Something went wrong in FindGLEW target creation.")
endif()
endif()
# CMake module to find GLEW
# Borrowed from http://code.google.com/p/nvidia-texture-tools/
# MIT license Copyright (c) 2007 NVIDIA Corporation
# Try to find GLEW library and include path.
# Once done this will define
#
# GLEW_FOUND
# GLEW_INCLUDE_PATH
# GLEW_LIBRARY
#
IF (WIN32)
FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h
$ENV{PROGRAMFILES}/GLEW/include
${PROJECT_SOURCE_DIR}/src/nvgl/glew/include
DOC "The directory where GL/glew.h resides")
FIND_LIBRARY( GLEW_LIBRARY
NAMES glew GLEW glew32 glew32s
PATHS
/mingw/bin # for MinGW's MSYS
/mingw/lib
${PROJECT_SOURCE_DIR}/glew/bin # or in local directory
${PROJECT_SOURCE_DIR}/glew/lib
DOC "The GLEW library")
ELSE (WIN32)
FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h
/usr/include
/usr/local/include
/sw/include
/opt/local/include
DOC "The directory where GL/glew.h resides")
FIND_LIBRARY( GLEW_LIBRARY
NAMES GLEW glew
PATHS
/usr/lib64
/usr/lib
/usr/local/lib64
/usr/local/lib
/sw/lib
/opt/local/lib
DOC "The GLEW library")
ENDIF (WIN32)
IF (GLEW_INCLUDE_PATH)
SET( GLEW_FOUND 1 CACHE STRING "Set to 1 if GLEW is found, 0 otherwise")
ELSE (GLEW_INCLUDE_PATH)
SET( GLEW_FOUND 0 CACHE STRING "Set to 1 if GLEW is found, 0 otherwise")
ENDIF (GLEW_INCLUDE_PATH)
MARK_AS_ADVANCED( GLEW_FOUND )

218
cmake/FindGettext.cmake Normal file
View File

@ -0,0 +1,218 @@
##
# Patched version of original CMake module
# Added variable GETTEXT_INSTALL_PREFIX to optionally override installation path of resulting translations
##
# - Find GNU gettext tools
# This module looks for the GNU gettext tools. This module defines the
# following values:
# GETTEXT_MSGMERGE_EXECUTABLE: the full path to the msgmerge tool.
# GETTEXT_MSGFMT_EXECUTABLE: the full path to the msgfmt tool.
# GETTEXT_FOUND: True if gettext has been found.
# GETTEXT_VERSION_STRING: the version of gettext found (since CMake 2.8.8)
#
# Additionally it provides the following macros:
# GETTEXT_CREATE_TRANSLATIONS ( outputFile [ALL] file1 ... fileN )
# This will create a target "translations" which will convert the
# given input po files into the binary output mo file. If the
# ALL option is used, the translations will also be created when
# building the default target.
# GETTEXT_PROCESS_POT( <potfile> [ALL] [INSTALL_DESTINATION <destdir>] LANGUAGES <lang1> <lang2> ... )
# Process the given pot file to mo files.
# If INSTALL_DESTINATION is given then automatically install rules will be created,
# the language subdirectory will be taken into account (by default use share/locale/).
# If ALL is specified, the pot file is processed when building the all traget.
# It creates a custom target "potfile".
# GETTEXT_PROCESS_PO_FILES( <lang> [ALL] [INSTALL_DESTINATION <dir>] PO_FILES <po1> <po2> ... )
# Process the given po files to mo files for the given language.
# If INSTALL_DESTINATION is given then automatically install rules will be created,
# the language subdirectory will be taken into account (by default use share/locale/).
# If ALL is specified, the po files are processed when building the all traget.
# It creates a custom target "pofiles".
#=============================================================================
# Copyright 2007-2009 Kitware, Inc.
# Copyright 2007 Alexander Neundorf <neundorf@kde.org>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
find_program(GETTEXT_MSGMERGE_EXECUTABLE msgmerge)
find_program(GETTEXT_MSGFMT_EXECUTABLE msgfmt)
if(GETTEXT_MSGMERGE_EXECUTABLE)
execute_process(COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --version
OUTPUT_VARIABLE gettext_version
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (gettext_version MATCHES "^msgmerge \\(.*\\) [0-9]")
string(REGEX REPLACE "^msgmerge \\([^\\)]*\\) ([0-9\\.]+[^ \n]*).*" "\\1" GETTEXT_VERSION_STRING "${gettext_version}")
endif()
unset(gettext_version)
endif()
set(GETTEXT_INSTALL_PREFIX share/locale)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Gettext
REQUIRED_VARS GETTEXT_MSGMERGE_EXECUTABLE GETTEXT_MSGFMT_EXECUTABLE
VERSION_VAR GETTEXT_VERSION_STRING)
include(CMakeParseArguments)
function(_GETTEXT_GET_UNIQUE_TARGET_NAME _name _unique_name)
set(propertyName "_GETTEXT_UNIQUE_COUNTER_${_name}")
get_property(currentCounter GLOBAL PROPERTY "${propertyName}")
if(NOT currentCounter)
set(currentCounter 1)
endif()
set(${_unique_name} "${_name}_${currentCounter}" PARENT_SCOPE)
math(EXPR currentCounter "${currentCounter} + 1")
set_property(GLOBAL PROPERTY ${propertyName} ${currentCounter} )
endfunction()
macro(GETTEXT_CREATE_TRANSLATIONS _potFile _firstPoFileArg)
# make it a real variable, so we can modify it here
set(_firstPoFile "${_firstPoFileArg}")
set(_gmoFiles)
get_filename_component(_potName ${_potFile} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
set(_addToAll)
if(${_firstPoFile} STREQUAL "ALL")
set(_addToAll "ALL")
set(_firstPoFile)
endif()
foreach (_currentPoFile ${_firstPoFile} ${ARGN})
get_filename_component(_absFile ${_currentPoFile} ABSOLUTE)
get_filename_component(_abs_PATH ${_absFile} PATH)
get_filename_component(_lang ${_absFile} NAME_WE)
set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo)
add_custom_command(
OUTPUT ${_gmoFile}
COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_absFile} ${_absPotFile}
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_absFile}
DEPENDS ${_absPotFile} ${_absFile}
)
install(FILES ${_gmoFile} DESTINATION ${GETTEXT_INSTALL_PREFIX}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
set(_gmoFiles ${_gmoFiles} ${_gmoFile})
endforeach ()
if(NOT TARGET translations)
add_custom_target(translations)
endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME(translations uniqueTargetName)
add_custom_target(${uniqueTargetName} ${_addToAll} DEPENDS ${_gmoFiles})
add_dependencies(translations ${uniqueTargetName})
endmacro()
function(GETTEXT_PROCESS_POT_FILE _potFile)
set(_gmoFiles)
set(_options ALL)
set(_oneValueArgs INSTALL_DESTINATION)
set(_multiValueArgs LANGUAGES)
CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
get_filename_component(_potName ${_potFile} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
foreach (_lang ${_parsedArguments_LANGUAGES})
set(_poFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.po")
set(_gmoFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo")
add_custom_command(
OUTPUT "${_poFile}"
COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_poFile} ${_absPotFile}
DEPENDS ${_absPotFile}
)
add_custom_command(
OUTPUT "${_gmoFile}"
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_poFile}
DEPENDS ${_absPotFile} ${_poFile}
)
if(_parsedArguments_INSTALL_DESTINATION)
install(FILES ${_gmoFile} DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
endif()
list(APPEND _gmoFiles ${_gmoFile})
endforeach ()
if(NOT TARGET potfiles)
add_custom_target(potfiles)
endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME( potfiles uniqueTargetName)
if(_parsedArguments_ALL)
add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
else()
add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
endif()
add_dependencies(potfiles ${uniqueTargetName})
endfunction()
function(GETTEXT_PROCESS_PO_FILES _lang)
set(_options ALL)
set(_oneValueArgs INSTALL_DESTINATION)
set(_multiValueArgs PO_FILES)
set(_gmoFiles)
CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
foreach(_current_PO_FILE ${_parsedArguments_PO_FILES})
get_filename_component(_name ${_current_PO_FILE} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _basename ${_name})
set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo)
add_custom_command(OUTPUT ${_gmoFile}
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_current_PO_FILE}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
DEPENDS ${_current_PO_FILE}
)
if(_parsedArguments_INSTALL_DESTINATION)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES/ RENAME ${_basename}.mo)
endif()
list(APPEND _gmoFiles ${_gmoFile})
endforeach()
if(NOT TARGET pofiles)
add_custom_target(pofiles)
endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME( pofiles uniqueTargetName)
if(_parsedArguments_ALL)
add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
else()
add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
endif()
add_dependencies(pofiles ${uniqueTargetName})
endfunction()

View File

@ -1,68 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindIntl
--------
Find the Gettext libintl headers and libraries.
This module reports information about the Gettext libintl
installation in several variables. General variables::
Intl_FOUND - true if the libintl headers and libraries were found
Intl_INCLUDE_DIRS - the directory containing the libintl headers
Intl_LIBRARIES - libintl libraries to be linked
The following cache variables may also be set::
Intl_INCLUDE_DIR - the directory containing the libintl headers
Intl_LIBRARY - the libintl library (if any)
.. note::
On some platforms, such as Linux with GNU libc, the gettext
functions are present in the C standard library and libintl
is not required. ``Intl_LIBRARIES`` will be empty in this
case.
.. note::
If you wish to use the Gettext tools (``msgmerge``,
``msgfmt``, etc.), use :module:`FindGettext`.
#]=======================================================================]
# Written by Roger Leigh <rleigh@codelibre.net>
# Modified by Mateusz Przybył <matt@przybyl.io>
# Find include directory
find_path(Intl_INCLUDE_DIR
NAMES "libintl.h"
DOC "libintl include directory")
mark_as_advanced(Intl_INCLUDE_DIR)
# Find all Intl libraries
find_library(Intl_LIBRARY NAMES intl libintl
DOC "libintl libraries (if not in the C library)")
mark_as_advanced(Intl_LIBRARY)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Intl
FOUND_VAR Intl_FOUND
REQUIRED_VARS Intl_INCLUDE_DIR Intl_LIBRARY
FAIL_MESSAGE "Failed to find Gettext libintl")
if(Intl_FOUND)
set(Intl_INCLUDE_DIRS "${Intl_INCLUDE_DIR}")
if(Intl_LIBRARY)
set(Intl_LIBRARIES "${Intl_LIBRARY}")
else()
unset(Intl_LIBRARIES)
endif()
endif()
# Export targets
if(Intl_FOUND AND NOT TARGET Gettext::Intl)
add_library(Gettext::Intl UNKNOWN IMPORTED)
set_target_properties(Gettext::Intl PROPERTIES
IMPORTED_LOCATION "${Intl_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${Intl_INCLUDE_DIR}")
endif()

View File

@ -0,0 +1,23 @@
# Base Io build system
# Written by Jeremy Tregunna <jeremy.tregunna@me.com>
#
# Find libsndfile.
FIND_PATH(LIBSNDFILE_INCLUDE_DIR sndfile.h)
SET(LIBSNDFILE_NAMES ${LIBSNDFILE_NAMES} sndfile libsndfile)
FIND_LIBRARY(LIBSNDFILE_LIBRARY NAMES ${LIBSNDFILE_NAMES} PATH)
IF(LIBSNDFILE_INCLUDE_DIR AND LIBSNDFILE_LIBRARY)
SET(LIBSNDFILE_FOUND TRUE)
ENDIF(LIBSNDFILE_INCLUDE_DIR AND LIBSNDFILE_LIBRARY)
IF(LIBSNDFILE_FOUND)
IF(NOT LibSndFile_FIND_QUIETLY)
MESSAGE(STATUS "Found LibSndFile: ${LIBSNDFILE_LIBRARY}")
ENDIF (NOT LibSndFile_FIND_QUIETLY)
ELSE(LIBSNDFILE_FOUND)
IF(LibSndFile_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find sndfile")
ENDIF(LibSndFile_FIND_REQUIRED)
ENDIF (LIBSNDFILE_FOUND)

View File

@ -1,63 +0,0 @@
# - Find ogg
# Find the native ogg includes and libraries
#
# OGG_INCLUDE_DIRS - where to find ogg.h, etc.
# OGG_LIBRARIES - List of libraries when using ogg.
# OGG_FOUND - True if ogg found.
# From https://github.com/erikd/libsndfile/
if (OGG_INCLUDE_DIR)
# Already in cache, be silent
set(OGG_FIND_QUIETLY TRUE)
endif ()
find_package (PkgConfig QUIET)
pkg_check_modules (PC_OGG QUIET ogg>=1.3.0)
set (OGG_VERSION ${PC_OGG_VERSION})
find_path (OGG_INCLUDE_DIR ogg/ogg.h
HINTS
${PC_OGG_INCLUDEDIR}
${PC_OGG_INCLUDE_DIRS}
${OGG_ROOT}
)
# MSVC built ogg may be named ogg_static.
# The provided project files name the library with the lib prefix.
find_library (OGG_LIBRARY
NAMES
ogg
ogg_static
libogg
libogg_static
HINTS
${PC_OGG_LIBDIR}
${PC_OGG_LIBRARY_DIRS}
${OGG_ROOT}
)
# Handle the QUIETLY and REQUIRED arguments and set OGG_FOUND
# to TRUE if all listed variables are TRUE.
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (Ogg
REQUIRED_VARS
OGG_LIBRARY
OGG_INCLUDE_DIR
VERSION_VAR
OGG_VERSION
)
if (OGG_FOUND)
set (OGG_LIBRARIES ${OGG_LIBRARY})
set (OGG_INCLUDE_DIRS ${OGG_INCLUDE_DIR})
if(NOT TARGET Ogg::ogg)
add_library(Ogg::ogg UNKNOWN IMPORTED)
set_target_properties(Ogg::ogg PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${OGG_INCLUDE_DIRS}"
IMPORTED_LOCATION "${OGG_LIBRARIES}"
)
endif ()
endif ()
mark_as_advanced (OGG_INCLUDE_DIR OGG_LIBRARY)

View File

@ -1,105 +0,0 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindOpenAL
----------
Finds Open Audio Library (OpenAL).
This module defines ``OPENAL_LIBRARY OPENAL_FOUND``, if
false, do not try to link to OpenAL ``OPENAL_INCLUDE_DIR``, where to find
the headers.
``$OPENALDIR`` is an environment variable that would correspond to the
``./configure --prefix=$OPENALDIR`` used in building OpenAL.
Created by Eric Wing. This was influenced by the ``FindSDL.cmake``
module.
Modified by Mateusz Przybył <matt@przybyl.io>.
#]=======================================================================]
# This makes the presumption that you are include al.h like
# #include "al.h"
# and not
# #include <AL/al.h>
# The reason for this is that the latter is not entirely portable.
# Windows/Creative Labs does not by default put their headers in AL/ and
# OS X uses the convention <OpenAL/al.h>.
#
# For Windows, Creative Labs seems to have added a registry key for their
# OpenAL 1.1 installer. I have added that key to the list of search paths,
# however, the key looks like it could be a little fragile depending on
# if they decide to change the 1.00.0000 number for bug fix releases.
# Also, they seem to have laid down groundwork for multiple library platforms
# which puts the library in an extra subdirectory. Currently there is only
# Win32 and I have hardcoded that here. This may need to be adjusted as
# platforms are introduced.
# The OpenAL 1.0 installer doesn't seem to have a useful key I can use.
# I do not know if the Nvidia OpenAL SDK has a registry key.
#
# For OS X, remember that OpenAL was added by Apple in 10.4 (Tiger).
# To support the framework, I originally wrote special framework detection
# code in this module which I have now removed with CMake's introduction
# of native support for frameworks.
# In addition, OpenAL is open source, and it is possible to compile on Panther.
# Furthermore, due to bugs in the initial OpenAL release, and the
# transition to OpenAL 1.1, it is common to need to override the built-in
# framework.
# Per my request, CMake should search for frameworks first in
# the following order:
# ~/Library/Frameworks/OpenAL.framework/Headers
# /Library/Frameworks/OpenAL.framework/Headers
# /System/Library/Frameworks/OpenAL.framework/Headers
#
# On OS X, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of
# OPENAL_LIBRARY to override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
find_path(OPENAL_INCLUDE_DIR al.h
HINTS
ENV OPENALDIR
PATH_SUFFIXES include/AL include/OpenAL include AL OpenAL
PATHS
~/Library/Frameworks
/Library/Frameworks
/opt
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_OpenAL_ARCH_DIR libs/Win64)
else()
set(_OpenAL_ARCH_DIR libs/Win32)
endif()
find_library(OPENAL_LIBRARY
NAMES OpenAL al openal OpenAL32
HINTS
ENV OPENALDIR
PATH_SUFFIXES libx32 lib64 lib libs64 libs ${_OpenAL_ARCH_DIR}
PATHS
~/Library/Frameworks
/Library/Frameworks
/opt
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir]
)
unset(_OpenAL_ARCH_DIR)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenAL DEFAULT_MSG OPENAL_LIBRARY OPENAL_INCLUDE_DIR)
mark_as_advanced(OPENAL_LIBRARY OPENAL_INCLUDE_DIR)
# Export targets
# Note: OpenAL exports targets itself by OpenALConfig.cmake,
# However, the file is not for some reason provided in packages in some Linux distros, e.g. Ubuntu 18.04
# Hence this Find*.cmake file.
if(OpenAL_FOUND AND NOT TARGET OpenAL::OpenAL)
add_library(OpenAL::OpenAL UNKNOWN IMPORTED)
set_target_properties(OpenAL::OpenAL PROPERTIES
IMPORTED_LOCATION "${OPENAL_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${OPENAL_INCLUDE_DIR}"
)
endif()

View File

@ -1,69 +0,0 @@
# - Find opus
# Find the native opus includes and libraries
#
# OPUS_INCLUDE_DIRS - where to find opus.h, etc.
# OPUS_LIBRARIES - List of libraries when using opus.
# OPUS_FOUND - True if Opus found.
# From https://github.com/erikd/libsndfile/
if (OPUS_INCLUDE_DIR)
# Already in cache, be silent
set(OPUS_FIND_QUIETLY TRUE)
endif ()
find_package (Ogg QUIET)
find_package (PkgConfig QUIET)
pkg_check_modules(PC_OPUS QUIET opus>=1.1)
set (OPUS_VERSION ${PC_OPUS_VERSION})
find_path (OPUS_INCLUDE_DIR opus/opus.h
HINTS
${PC_OPUS_INCLUDEDIR}
${PC_OPUS_INCLUDE_DIRS}
${OPUS_ROOT}
)
# MSVC built opus may be named opus_static.
# The provided project files name the library with the lib prefix.
find_library (OPUS_LIBRARY
NAMES
opus
opus_static
libopus
libopus_static
HINTS
${PC_OPUS_LIBDIR}
${PC_OPUS_LIBRARY_DIRS}
${OPUS_ROOT}
)
# Handle the QUIETLY and REQUIRED arguments and set OPUS_FOUND
# to TRUE if all listed variables are TRUE.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args (Opus
REQUIRED_VARS
OPUS_LIBRARY
OPUS_INCLUDE_DIR
OGG_FOUND
VERSION_VAR
OPUS_VERSION
)
if (OPUS_FOUND)
set (OPUS_LIBRARIES ${OPUS_LIBRARY})
set (OPUS_INCLUDE_DIRS ${OPUS_INCLUDE_DIR})
if (NOT TARGET Opus::opus)
add_library (Opus::opus UNKNOWN IMPORTED)
set_target_properties (Opus::opus PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${OPUS_INCLUDE_DIRS}"
IMPORTED_LOCATION "${OPUS_LIBRARIES}"
)
endif ()
endif ()
mark_as_advanced(OPUS_INCLUDE_DIR OPUS_LIBRARY)

View File

@ -7,7 +7,7 @@ IF (WIN32)
FIND_PATH( PHYSFS_INCLUDE_PATH physfs.h
DOC "The directory where physfs.h resides")
FIND_LIBRARY( PHYSFS_LIBRARY
NAMES physfs physfs-static
NAMES physfs
PATHS /mingw/lib
DOC "The PhysFS library")
ELSE (WIN32)
@ -33,12 +33,4 @@ ELSE (GLEW_INCLUDE_PATH)
SET( PHYSFS_FOUND 0 CACHE STRING "Set to 1 if PhysFS is found, 0 otherwise")
ENDIF (PHYSFS_INCLUDE_PATH)
MARK_AS_ADVANCED( PHYSFS_FOUND PHYSFS_INCLUDE_PATH PHYSFS_LIBRARY )
# Targets
if(PHYSFS_FOUND AND NOT TARGET PhysFS::PhysFS)
add_library(PhysFS::PhysFS UNKNOWN IMPORTED)
set_target_properties(PhysFS::PhysFS PROPERTIES
IMPORTED_LOCATION "${PHYSFS_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${PHYSFS_INCLUDE_PATH}")
endif()
MARK_AS_ADVANCED( PHYSFS_FOUND )

View File

@ -1,388 +1,163 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
# Locate SDL2 library
# This module defines
# SDL2_LIBRARY, the name of the library to link against
# SDL2_FOUND, if false, do not try to link to SDL2
# SDL2_INCLUDE_DIR, where to find SDL.h
#
# This module responds to the the flag:
# SDL2_BUILDING_LIBRARY
# If this is defined, then no SDL2main will be linked in because
# only applications need main().
# Otherwise, it is assumed you are building an application and this
# module will attempt to locate and set the the proper link flags
# as part of the returned SDL2_LIBRARY variable.
#
# Don't forget to include SDLmain.h and SDLmain.m your project for the
# OS X framework based version. (Other versions link to -lSDL2main which
# this module will try to find on your behalf.) Also for OS X, this
# module will automatically add the -framework Cocoa on your behalf.
#
#
# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
# as appropriate. These values are used to generate the final SDL2_LIBRARY
# variable, but when these values are unset, SDL2_LIBRARY does not get created.
#
#
# $SDL2DIR is an environment variable that would
# correspond to the ./configure --prefix=$SDL2DIR
# used in building SDL2.
# l.e.galup 9-20-02
#
# Modified by Eric Wing.
# Added code to assist with automated building by using environmental variables
# and providing a more controlled/consistent search behavior.
# Added new modifications to recognize OS X frameworks and
# additional Unix paths (FreeBSD, etc).
# Also corrected the header search path to follow "proper" SDL guidelines.
# Added a search for SDL2main which is needed by some platforms.
# Added a search for threads which is needed by some platforms.
# Added needed compile switches for MinGW.
#
# On OSX, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of
# SDL2_LIBRARY to override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
#
# Note that the header path has changed from SDL2/SDL.h to just SDL.h
# This needed to change because "proper" SDL convention
# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
# reasons because not all systems place things in SDL2/ (see FreeBSD).
# Copyright 2019 Amine Ben Hassouna <amine.benhassouna@gmail.com>
# Copyright 2000-2019 Kitware, Inc. and Contributors
# All rights reserved.
#=============================================================================
# Copyright 2003-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Kitware, Inc. nor the names of Contributors
# may be used to endorse or promote products derived from this
# software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#[=======================================================================[.rst:
FindSDL2
--------
Locate SDL2 library
This module defines the following 'IMPORTED' targets:
::
SDL2::Core
The SDL2 library, if found.
Libraries should link to SDL2::Core
SDL2::Main
The SDL2main library, if found.
Applications should link to SDL2::Main instead of SDL2::Core
This module will set the following variables in your project:
::
SDL2_LIBRARIES, the name of the library to link against
SDL2_INCLUDE_DIRS, where to find SDL.h
SDL2_FOUND, if false, do not try to link to SDL2
SDL2MAIN_FOUND, if false, do not try to link to SDL2main
SDL2_VERSION_STRING, human-readable string containing the version of SDL2
This module responds to the following cache variables:
::
SDL2_PATH
Set a custom SDL2 Library path (default: empty)
SDL2_NO_DEFAULT_PATH
Disable search SDL2 Library in default path.
If SDL2_PATH (default: ON)
Else (default: OFF)
SDL2_INCLUDE_DIR
SDL2 headers path.
SDL2_LIBRARY
SDL2 Library (.dll, .so, .a, etc) path.
SDL2MAIN_LIBRAY
SDL2main Library (.a) path.
SDL2_BUILDING_LIBRARY
This flag is useful only when linking to SDL2_LIBRARIES insead of
SDL2::Main. It is required only when building a library that links to
SDL2_LIBRARIES, because only applications need main() (No need to also
link to SDL2main).
If this flag is defined, then no SDL2main will be added to SDL2_LIBRARIES
and no SDL2::Main target will be created.
Don't forget to include SDLmain.h and SDLmain.m in your project for the
OS X framework based version. (Other versions link to -lSDL2main which
this module will try to find on your behalf.) Also for OS X, this
module will automatically add the -framework Cocoa on your behalf.
Additional Note: If you see an empty SDL2_LIBRARY in your project
configuration, it means CMake did not find your SDL2 library
(SDL2.dll, libsdl2.so, SDL2.framework, etc). Set SDL2_LIBRARY to point
to your SDL2 library, and configure again. Similarly, if you see an
empty SDL2MAIN_LIBRARY, you should set this value as appropriate. These
values are used to generate the final SDL2_LIBRARIES variable and the
SDL2::Core and SDL2::Main targets, but when these values are unset,
SDL2_LIBRARIES, SDL2::Core and SDL2::Main does not get created.
$SDL2DIR is an environment variable that would correspond to the
./configure --prefix=$SDL2DIR used in building SDL2. l.e.galup 9-20-02
Created by Amine Ben Hassouna:
Adapt FindSDL.cmake to SDL2 (FindSDL2.cmake).
Add cache variables for more flexibility:
SDL2_PATH, SDL2_NO_DEFAULT_PATH (for details, see doc above).
Mark 'Threads' as a required dependency for non-OSX systems.
Modernize the FindSDL2.cmake module by creating specific targets:
SDL2::Core and SDL2::Main (for details, see doc above).
Original FindSDL.cmake module:
Modified by Eric Wing. Added code to assist with automated building
by using environmental variables and providing a more
controlled/consistent search behavior. Added new modifications to
recognize OS X frameworks and additional Unix paths (FreeBSD, etc).
Also corrected the header search path to follow "proper" SDL
guidelines. Added a search for SDLmain which is needed by some
platforms. Added a search for threads which is needed by some
platforms. Added needed compile switches for MinGW.
On OSX, this will prefer the Framework version (if found) over others.
People will have to manually change the cache value of SDL2_LIBRARY to
override this selection or set the SDL2_PATH variable or the CMake
environment CMAKE_INCLUDE_PATH to modify the search paths.
Note that the header path has changed from SDL/SDL.h to just SDL.h
This needed to change because "proper" SDL convention is #include
"SDL.h", not <SDL/SDL.h>. This is done for portability reasons
because not all systems place things in SDL/ (see FreeBSD).
#]=======================================================================]
# Define options for searching SDL2 Library in a custom path
set(SDL2_PATH "" CACHE STRING "Custom SDL2 Library path")
set(_SDL2_NO_DEFAULT_PATH OFF)
if(SDL2_PATH)
set(_SDL2_NO_DEFAULT_PATH ON)
endif()
set(SDL2_NO_DEFAULT_PATH ${_SDL2_NO_DEFAULT_PATH}
CACHE BOOL "Disable search SDL2 Library in default path")
unset(_SDL2_NO_DEFAULT_PATH)
set(SDL2_NO_DEFAULT_PATH_CMD)
if(SDL2_NO_DEFAULT_PATH)
set(SDL2_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH)
endif()
# Search for the SDL2 include directory
find_path(SDL2_INCLUDE_DIR SDL.h
HINTS
ENV SDL2DIR
${SDL2_NO_DEFAULT_PATH_CMD}
PATH_SUFFIXES SDL2
# path suffixes to search inside ENV{SDL2DIR}
include/SDL2 include
PATHS ${SDL2_PATH}
DOC "Where the SDL2 headers can be found"
SET(SDL2_SEARCH_PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local
/usr
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
)
set(SDL2_INCLUDE_DIRS "${SDL2_INCLUDE_DIR}")
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(VC_LIB_PATH_SUFFIX lib/x64)
else()
set(VC_LIB_PATH_SUFFIX lib/x86)
endif()
# SDL-2.0 is the name used by FreeBSD ports...
# don't confuse it for the version number.
find_library(SDL2_LIBRARY
NAMES SDL2 SDL-2.0 SDL2-static
HINTS
ENV SDL2DIR
${SDL2_NO_DEFAULT_PATH_CMD}
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
PATHS ${SDL2_PATH}
DOC "Where the SDL2 Library can be found"
FIND_PATH(SDL2_INCLUDE_DIR SDL.h
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES include/SDL2 include
PATHS ${SDL2_SEARCH_PATHS}
)
set(SDL2_LIBRARIES "${SDL2_LIBRARY}")
FIND_LIBRARY(SDL2_LIBRARY_TEMP
NAMES SDL2
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES lib64 lib
PATHS ${SDL2_SEARCH_PATHS}
)
if(NOT SDL2_BUILDING_LIBRARY)
if(NOT SDL2_INCLUDE_DIR MATCHES ".framework")
# Non-OS X framework versions expect you to also dynamically link to
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
# seem to provide SDL2main for compatibility even though they don't
# necessarily need it.
if(SDL2_PATH)
set(SDL2MAIN_LIBRARY_PATHS "${SDL2_PATH}")
endif()
if(NOT SDL2_NO_DEFAULT_PATH)
set(SDL2MAIN_LIBRARY_PATHS
/sw
/opt/local
/opt/csw
/opt
"${SDL2MAIN_LIBRARY_PATHS}"
)
endif()
find_library(SDL2MAIN_LIBRARY
NAMES SDL2main
HINTS
ENV SDL2DIR
${SDL2_NO_DEFAULT_PATH_CMD}
PATH_SUFFIXES lib lib/manual-link ${VC_LIB_PATH_SUFFIX}
PATHS ${SDL2MAIN_LIBRARY_PATHS}
DOC "Where the SDL2main library can be found"
)
unset(SDL2MAIN_LIBRARY_PATHS)
endif()
endif()
IF(NOT SDL2_BUILDING_LIBRARY)
IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
# Non-OS X framework versions expect you to also dynamically link to
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
# seem to provide SDL2main for compatibility even though they don't
# necessarily need it.
FIND_LIBRARY(SDL2MAIN_LIBRARY
NAMES SDL2main
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES lib64 lib
PATHS ${SDL2_SEARCH_PATHS}
)
ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# SDL2 may require threads on your system.
# The Apple build may not need an explicit flag because one of the
# frameworks may already provide it.
# But for non-OSX systems, I will use the CMake Threads package.
if(NOT APPLE)
find_package(Threads QUIET)
if(NOT Threads_FOUND)
set(SDL2_THREADS_NOT_FOUND "Could NOT find Threads (Threads is required by SDL2).")
if(SDL2_FIND_REQUIRED)
message(FATAL_ERROR ${SDL2_THREADS_NOT_FOUND})
else()
if(NOT SDL2_FIND_QUIETLY)
message(STATUS ${SDL2_THREADS_NOT_FOUND})
endif()
return()
endif()
unset(SDL2_THREADS_NOT_FOUND)
endif()
endif()
IF(NOT APPLE)
FIND_PACKAGE(Threads)
ENDIF(NOT APPLE)
# MinGW needs an additional link flag, -mwindows
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -mwindows
if(MINGW)
set(MINGW32_LIBRARY mingw32 "-mwindows" CACHE STRING "link flags for MinGW")
endif()
# MinGW needs an additional library, mwindows
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
# (Actually on second look, I think it only needs one of the m* libraries.)
IF(MINGW)
SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
ENDIF(MINGW)
if(SDL2_LIBRARY)
# For SDL2main
if(SDL2MAIN_LIBRARY AND NOT SDL2_BUILDING_LIBRARY)
list(FIND SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" _SDL2_MAIN_INDEX)
if(_SDL2_MAIN_INDEX EQUAL -1)
set(SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" ${SDL2_LIBRARIES})
endif()
unset(_SDL2_MAIN_INDEX)
endif()
IF(SDL2_LIBRARY_TEMP)
# For SDL2main
IF(NOT SDL2_BUILDING_LIBRARY)
IF(SDL2MAIN_LIBRARY)
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(SDL2MAIN_LIBRARY)
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
# CMake doesn't display the -framework Cocoa string in the UI even
# though it actually is there if I modify a pre-used variable.
# I think it has something to do with the CACHE STRING.
# So I use a temporary variable until the end so I can set the
# "real" variable in one-shot.
if(APPLE)
set(SDL2_LIBRARIES ${SDL2_LIBRARIES} -framework Cocoa)
endif()
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
# CMake doesn't display the -framework Cocoa string in the UI even
# though it actually is there if I modify a pre-used variable.
# I think it has something to do with the CACHE STRING.
# So I use a temporary variable until the end so I can set the
# "real" variable in one-shot.
IF(APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
ENDIF(APPLE)
# For threads, as mentioned Apple doesn't need this.
# In fact, there seems to be a problem if I used the Threads package
# and try using this line, so I'm just skipping it entirely for OS X.
if(NOT APPLE)
set(SDL2_LIBRARIES ${SDL2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
endif()
# For threads, as mentioned Apple doesn't need this.
# In fact, there seems to be a problem if I used the Threads package
# and try using this line, so I'm just skipping it entirely for OS X.
IF(NOT APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
ENDIF(NOT APPLE)
# For MinGW library
if(MINGW)
set(SDL2_LIBRARIES ${MINGW32_LIBRARY} ${SDL2_LIBRARIES})
endif()
# For MinGW library
IF(MINGW)
SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(MINGW)
endif()
# Set the final string here so the GUI reflects the final state.
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
ENDIF(SDL2_LIBRARY_TEMP)
# Read SDL2 version
if(SDL2_INCLUDE_DIR AND EXISTS "${SDL2_INCLUDE_DIR}/SDL_version.h")
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$")
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$")
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$")
string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MAJOR "${SDL2_VERSION_MAJOR_LINE}")
string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MINOR "${SDL2_VERSION_MINOR_LINE}")
string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_PATCH "${SDL2_VERSION_PATCH_LINE}")
set(SDL2_VERSION_STRING ${SDL2_VERSION_MAJOR}.${SDL2_VERSION_MINOR}.${SDL2_VERSION_PATCH})
unset(SDL2_VERSION_MAJOR_LINE)
unset(SDL2_VERSION_MINOR_LINE)
unset(SDL2_VERSION_PATCH_LINE)
unset(SDL2_VERSION_MAJOR)
unset(SDL2_VERSION_MINOR)
unset(SDL2_VERSION_PATCH)
endif()
INCLUDE(FindPackageHandleStandardArgs)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2
REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR
VERSION_VAR SDL2_VERSION_STRING)
if(SDL2MAIN_LIBRARY)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2main
REQUIRED_VARS SDL2MAIN_LIBRARY SDL2_INCLUDE_DIR
VERSION_VAR SDL2_VERSION_STRING)
endif()
mark_as_advanced(SDL2_PATH
SDL2_NO_DEFAULT_PATH
SDL2_LIBRARY
SDL2MAIN_LIBRARY
SDL2_INCLUDE_DIR
SDL2_BUILDING_LIBRARY)
# SDL2:: targets (SDL2::Core and SDL2::Main)
if(SDL2_FOUND)
# SDL2::Core target
if(SDL2_LIBRARY AND NOT TARGET SDL2::Core)
add_library(SDL2::Core UNKNOWN IMPORTED)
set_target_properties(SDL2::Core PROPERTIES
IMPORTED_LOCATION "${SDL2_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}")
if(APPLE)
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
# For more details, please see above.
set_property(TARGET SDL2::Core APPEND PROPERTY
INTERFACE_LINK_OPTIONS -framework Cocoa)
else()
# For threads, as mentioned Apple doesn't need this.
# For more details, please see above.
set_property(TARGET SDL2::Core APPEND PROPERTY
INTERFACE_LINK_LIBRARIES Threads::Threads)
endif()
endif()
# SDL2::Main target
# Applications should link to SDL2::Main instead of SDL2::Core
# For more details, please see above.
if(NOT SDL2_BUILDING_LIBRARY AND NOT TARGET SDL2::Main)
if(SDL2_INCLUDE_DIR MATCHES ".framework" OR NOT SDL2MAIN_LIBRARY)
add_library(SDL2::Main INTERFACE IMPORTED)
set_property(TARGET SDL2::Main PROPERTY
INTERFACE_LINK_LIBRARIES SDL2::Core)
elseif(SDL2MAIN_LIBRARY)
# MinGW requires that the mingw32 library is specified before the
# libSDL2main.a static library when linking.
# The SDL2::MainInternal target is used internally to make sure that
# CMake respects this condition.
add_library(SDL2::MainInternal UNKNOWN IMPORTED)
set_property(TARGET SDL2::MainInternal PROPERTY
IMPORTED_LOCATION "${SDL2MAIN_LIBRARY}")
set_property(TARGET SDL2::MainInternal PROPERTY
INTERFACE_LINK_LIBRARIES SDL2::Core)
add_library(SDL2::Main INTERFACE IMPORTED)
if(MINGW)
# MinGW needs an additional link flag '-mwindows' and link to mingw32
set_property(TARGET SDL2::Main PROPERTY
INTERFACE_LINK_LIBRARIES "mingw32" "-mwindows")
endif()
set_property(TARGET SDL2::Main APPEND PROPERTY
INTERFACE_LINK_LIBRARIES SDL2::MainInternal)
endif()
endif()
endif()
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)

View File

@ -1,222 +1,158 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
# Locate SDL2_image library
# This module defines
# SDL2_IMAGE_LIBRARY, the name of the library to link against
# SDL2_IMAGE_FOUND, if false, do not try to link to SDL2_image
# SDL2_IMAGE_INCLUDE_DIR, where to find SDL_image.h
#
# Additional Note: If you see an empty SDL2_IMAGE_LIBRARY_TEMP in your configuration
# and no SDL2_IMAGE_LIBRARY, it means CMake did not find your SDL2_Image library
# (SDL2_image.dll, libsdl2_image.so, SDL2_image.framework, etc).
# Set SDL2_IMAGE_LIBRARY_TEMP to point to your SDL2 library, and configure again.
# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
# as appropriate. These values are used to generate the final SDL2_IMAGE_LIBRARY
# variable, but when these values are unset, SDL2_IMAGE_LIBRARY does not get created.
#
# $SDL2 is an environment variable that would
# correspond to the ./configure --prefix=$SDL2
# used in building SDL2.
# l.e.galup 9-20-02
#
# Modified by Eric Wing.
# Added code to assist with automated building by using environmental variables
# and providing a more controlled/consistent search behavior.
# Added new modifications to recognize OS X frameworks and
# additional Unix paths (FreeBSD, etc).
# Also corrected the header search path to follow "proper" SDL2 guidelines.
# Added a search for SDL2main which is needed by some platforms.
# Added a search for threads which is needed by some platforms.
# Added needed compile switches for MinGW.
#
# On OSX, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of
# SDL2_IMAGE_LIBRARY to override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
#
# Note that the header path has changed from SDL2/SDL.h to just SDL.h
# This needed to change because "proper" SDL2 convention
# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
# reasons because not all systems place things in SDL2/ (see FreeBSD).
#
# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake
# module with the minor edit of changing "SDL" to "SDL2" where necessary. This
# was not created for redistribution, and exists temporarily pending official
# SDL2 CMake modules.
#
# Note that on windows this will only search for the 32bit libraries, to search
# for 64bit change x86/i686-w64 to x64/x86_64-w64
# Copyright 2019 Amine Ben Hassouna <amine.benhassouna@gmail.com>
# Copyright 2000-2019 Kitware, Inc. and Contributors
# All rights reserved.
#=============================================================================
# Copyright 2003-2009 Kitware, Inc.
#
# CMake - Cross Platform Makefile Generator
# Copyright 2000-2014 Kitware, Inc.
# Copyright 2000-2011 Insight Software Consortium
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the names of Kitware, Inc., the Insight Software Consortium,
# nor the names of their contributors may be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Kitware, Inc. nor the names of Contributors
# may be used to endorse or promote products derived from this
# software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#[=======================================================================[.rst:
FindSDL2_image
--------------
Locate SDL2_image library
This module defines the following 'IMPORTED' target:
::
SDL2::Image
The SDL2_image library, if found.
Have SDL2::Core as a link dependency.
This module will set the following variables in your project:
::
SDL2_IMAGE_LIBRARIES, the name of the library to link against
SDL2_IMAGE_INCLUDE_DIRS, where to find the headers
SDL2_IMAGE_FOUND, if false, do not try to link against
SDL2_IMAGE_VERSION_STRING - human-readable string containing the
version of SDL2_image
This module responds to the following cache variables:
::
SDL2_IMAGE_PATH
Set a custom SDL2_image Library path (default: empty)
SDL2_IMAGE_NO_DEFAULT_PATH
Disable search SDL2_image Library in default path.
If SDL2_IMAGE_PATH (default: ON)
Else (default: OFF)
SDL2_IMAGE_INCLUDE_DIR
SDL2_image headers path.
SDL2_IMAGE_LIBRARY
SDL2_image Library (.dll, .so, .a, etc) path.
Additional Note: If you see an empty SDL2_IMAGE_LIBRARY in your project
configuration, it means CMake did not find your SDL2_image library
(SDL2_image.dll, libsdl2_image.so, etc). Set SDL2_IMAGE_LIBRARY to point
to your SDL2_image library, and configure again. This value is used to
generate the final SDL2_IMAGE_LIBRARIES variable and the SDL2::Image target,
but when this value is unset, SDL2_IMAGE_LIBRARIES and SDL2::Image does not
get created.
$SDL2IMAGEDIR is an environment variable that would correspond to the
./configure --prefix=$SDL2IMAGEDIR used in building SDL2_image.
$SDL2DIR is an environment variable that would correspond to the
./configure --prefix=$SDL2DIR used in building SDL2.
Created by Amine Ben Hassouna:
Adapt FindSDL_image.cmake to SDL2_image (FindSDL2_image.cmake).
Add cache variables for more flexibility:
SDL2_IMAGE_PATH, SDL2_IMAGE_NO_DEFAULT_PATH (for details, see doc above).
Add SDL2 as a required dependency.
Modernize the FindSDL2_image.cmake module by creating a specific target:
SDL2::Image (for details, see doc above).
Original FindSDL_image.cmake module:
Created by Eric Wing. This was influenced by the FindSDL.cmake
module, but with modifications to recognize OS X frameworks and
additional Unix paths (FreeBSD, etc).
#]=======================================================================]
# SDL2 Library required
find_package(SDL2 QUIET)
if(NOT SDL2_FOUND)
set(SDL2_IMAGE_SDL2_NOT_FOUND "Could NOT find SDL2 (SDL2 is required by SDL2_image).")
if(SDL2_image_FIND_REQUIRED)
message(FATAL_ERROR ${SDL2_IMAGE_SDL2_NOT_FOUND})
else()
if(NOT SDL2_image_FIND_QUIETLY)
message(STATUS ${SDL2_IMAGE_SDL2_NOT_FOUND})
endif()
return()
endif()
unset(SDL2_IMAGE_SDL2_NOT_FOUND)
endif()
# Define options for searching SDL2_image Library in a custom path
set(SDL2_IMAGE_PATH "" CACHE STRING "Custom SDL2_image Library path")
set(_SDL2_IMAGE_NO_DEFAULT_PATH OFF)
if(SDL2_IMAGE_PATH)
set(_SDL2_IMAGE_NO_DEFAULT_PATH ON)
endif()
set(SDL2_IMAGE_NO_DEFAULT_PATH ${_SDL2_IMAGE_NO_DEFAULT_PATH}
CACHE BOOL "Disable search SDL2_image Library in default path")
unset(_SDL2_IMAGE_NO_DEFAULT_PATH)
set(SDL2_IMAGE_NO_DEFAULT_PATH_CMD)
if(SDL2_IMAGE_NO_DEFAULT_PATH)
set(SDL2_IMAGE_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH)
endif()
# Search for the SDL2_image include directory
find_path(SDL2_IMAGE_INCLUDE_DIR SDL_image.h
HINTS
ENV SDL2IMAGEDIR
ENV SDL2DIR
${SDL2_IMAGE_NO_DEFAULT_PATH_CMD}
PATH_SUFFIXES SDL2
# path suffixes to search inside ENV{SDL2DIR}
# and ENV{SDL2IMAGEDIR}
include/SDL2 include
PATHS ${SDL2_IMAGE_PATH}
DOC "Where the SDL2_image headers can be found"
FIND_PATH(SDL2_IMAGE_INCLUDE_DIR SDL_image.h
HINTS
${SDL2}
$ENV{SDL2}
$ENV{SDL2_IMAGE}
PATH_SUFFIXES include/SDL2 include SDL2
i686-w64-mingw32/include/SDL2
x86_64-w64-mingw32/include/SDL2
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/include/SDL2
/usr/include/SDL2
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(VC_LIB_PATH_SUFFIX lib/x64)
else()
set(VC_LIB_PATH_SUFFIX lib/x86)
endif()
# Lookup the 64 bit libs on x64
IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
FIND_LIBRARY(SDL2_IMAGE_LIBRARY_TEMP
NAMES SDL2_image
HINTS
${SDL2}
$ENV{SDL2}
$ENV{SDL2_IMAGE}
PATH_SUFFIXES lib64 lib
lib/x64
x86_64-w64-mingw32/lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
# On 32bit build find the 32bit libs
ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8)
FIND_LIBRARY(SDL2_IMAGE_LIBRARY_TEMP
NAMES SDL2_image
HINTS
${SDL2}
$ENV{SDL2}
$ENV{SDL2_IMAGE}
PATH_SUFFIXES lib
lib/x86
i686-w64-mingw32/lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8)
# Search for the SDL2_image library
find_library(SDL2_IMAGE_LIBRARY
NAMES SDL2_image SDL2_image-static
HINTS
ENV SDL2IMAGEDIR
ENV SDL2DIR
${SDL2_IMAGE_NO_DEFAULT_PATH_CMD}
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
PATHS ${SDL2_IMAGE_PATH}
DOC "Where the SDL2_image Library can be found"
)
SET(SDL2_IMAGE_FOUND "NO")
IF(SDL2_IMAGE_LIBRARY_TEMP)
# Set the final string here so the GUI reflects the final state.
SET(SDL2_IMAGE_LIBRARY ${SDL2_IMAGE_LIBRARY_TEMP} CACHE STRING "Where the SDL2_image Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL2_IMAGE_LIBRARY_TEMP "${SDL2_IMAGE_LIBRARY_TEMP}" CACHE INTERNAL "")
SET(SDL2_IMAGE_FOUND "YES")
ENDIF(SDL2_IMAGE_LIBRARY_TEMP)
# Read SDL2_image version
if(SDL2_IMAGE_INCLUDE_DIR AND EXISTS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h")
file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+[0-9]+$")
file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+[0-9]+$")
file(STRINGS "${SDL2_IMAGE_INCLUDE_DIR}/SDL_image.h" SDL2_IMAGE_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+[0-9]+$")
string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MAJOR "${SDL2_IMAGE_VERSION_MAJOR_LINE}")
string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_MINOR "${SDL2_IMAGE_VERSION_MINOR_LINE}")
string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_IMAGE_VERSION_PATCH "${SDL2_IMAGE_VERSION_PATCH_LINE}")
set(SDL2_IMAGE_VERSION_STRING ${SDL2_IMAGE_VERSION_MAJOR}.${SDL2_IMAGE_VERSION_MINOR}.${SDL2_IMAGE_VERSION_PATCH})
unset(SDL2_IMAGE_VERSION_MAJOR_LINE)
unset(SDL2_IMAGE_VERSION_MINOR_LINE)
unset(SDL2_IMAGE_VERSION_PATCH_LINE)
unset(SDL2_IMAGE_VERSION_MAJOR)
unset(SDL2_IMAGE_VERSION_MINOR)
unset(SDL2_IMAGE_VERSION_PATCH)
endif()
INCLUDE(FindPackageHandleStandardArgs)
set(SDL2_IMAGE_LIBRARIES ${SDL2_IMAGE_LIBRARY})
set(SDL2_IMAGE_INCLUDE_DIRS ${SDL2_IMAGE_INCLUDE_DIR})
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_IMAGE REQUIRED_VARS SDL2_IMAGE_LIBRARY SDL2_IMAGE_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_image
REQUIRED_VARS SDL2_IMAGE_LIBRARIES SDL2_IMAGE_INCLUDE_DIRS
VERSION_VAR SDL2_IMAGE_VERSION_STRING)
mark_as_advanced(SDL2_IMAGE_PATH
SDL2_IMAGE_NO_DEFAULT_PATH
SDL2_IMAGE_LIBRARY
SDL2_IMAGE_INCLUDE_DIR)
if(SDL2_IMAGE_FOUND)
# SDL2::Image target
if(SDL2_IMAGE_LIBRARY AND NOT TARGET SDL2::Image)
add_library(SDL2::Image UNKNOWN IMPORTED)
set_target_properties(SDL2::Image PROPERTIES
IMPORTED_LOCATION "${SDL2_IMAGE_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_IMAGE_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES SDL2::Core)
endif()
endif()

View File

@ -1,222 +1,157 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
# Locate SDL2_ttf library
# This module defines
# SDL2_TTF_LIBRARY, the name of the library to link against
# SDL2_TTF_FOUND, if false, do not try to link to SDL2_ttf
# SDL2_TTF_INCLUDE_DIR, where to find SDL_image.h
#
# Additional Note: If you see an empty SDL2_TTF_LIBRARY_TEMP in your configuration
# and no SDL2_TTF_LIBRARY, it means CMake did not find your SDL2_Image library
# (SDL2_ttf.dll, libsdl2_image.so, SDL2_ttf.framework, etc).
# Set SDL2_TTF_LIBRARY_TEMP to point to your SDL2 library, and configure again.
# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
# as appropriate. These values are used to generate the final SDL2_TTF_LIBRARY
# variable, but when these values are unset, SDL2_TTF_LIBRARY does not get created.
#
# $SDL2 is an environment variable that would
# correspond to the ./configure --prefix=$SDL2
# used in building SDL2.
# l.e.galup 9-20-02
#
# Modified by Eric Wing.
# Added code to assist with automated building by using environmental variables
# and providing a more controlled/consistent search behavior.
# Added new modifications to recognize OS X frameworks and
# additional Unix paths (FreeBSD, etc).
# Also corrected the header search path to follow "proper" SDL2 guidelines.
# Added a search for SDL2main which is needed by some platforms.
# Added a search for threads which is needed by some platforms.
# Added needed compile switches for MinGW.
#
# On OSX, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of
# SDL2_TTF_LIBRARY to override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
#
# Note that the header path has changed from SDL2/SDL.h to just SDL.h
# This needed to change because "proper" SDL2 convention
# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
# reasons because not all systems place things in SDL2/ (see FreeBSD).
#
# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake
# module with the minor edit of changing "SDL" to "SDL2" where necessary. This
# was not created for redistribution, and exists temporarily pending official
# SDL2 CMake modules.
#
# Note that on windows this will only search for the 32bit libraries, to search
# for 64bit change x86/i686-w64 to x64/x86_64-w64
# Copyright 2019 Amine Ben Hassouna <amine.benhassouna@gmail.com>
# Copyright 2000-2019 Kitware, Inc. and Contributors
# All rights reserved.
#=============================================================================
# Copyright 2003-2009 Kitware, Inc.
#
# CMake - Cross Platform Makefile Generator
# Copyright 2000-2014 Kitware, Inc.
# Copyright 2000-2011 Insight Software Consortium
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the names of Kitware, Inc., the Insight Software Consortium,
# nor the names of their contributors may be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Kitware, Inc. nor the names of Contributors
# may be used to endorse or promote products derived from this
# software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#[=======================================================================[.rst:
FindSDL2_ttf
------------
Locate SDL2_ttf library
This module defines the following 'IMPORTED' target:
::
SDL2::TTF
The SDL2_ttf library, if found.
Have SDL2::Core as a link dependency.
This module will set the following variables in your project:
::
SDL2_TTF_LIBRARIES, the name of the library to link against
SDL2_TTF_INCLUDE_DIRS, where to find the headers
SDL2_TTF_FOUND, if false, do not try to link against
SDL2_TTF_VERSION_STRING - human-readable string containing the
version of SDL2_ttf
This module responds to the following cache variables:
::
SDL2_TTF_PATH
Set a custom SDL2_ttf Library path (default: empty)
SDL2_TTF_NO_DEFAULT_PATH
Disable search SDL2_ttf Library in default path.
If SDL2_TTF_PATH (default: ON)
Else (default: OFF)
SDL2_TTF_INCLUDE_DIR
SDL2_ttf headers path.
SDL2_TTF_LIBRARY
SDL2_ttf Library (.dll, .so, .a, etc) path.
Additional Note: If you see an empty SDL2_TTF_LIBRARY in your project
configuration, it means CMake did not find your SDL2_ttf library
(SDL2_ttf.dll, libsdl2_ttf.so, etc). Set SDL2_TTF_LIBRARY to point
to your SDL2_ttf library, and configure again. This value is used to
generate the final SDL2_TTF_LIBRARIES variable and the SDL2::TTF target,
but when this value is unset, SDL2_TTF_LIBRARIES and SDL2::TTF does not
get created.
$SDL2TTFDIR is an environment variable that would correspond to the
./configure --prefix=$SDL2TTFDIR used in building SDL2_ttf.
$SDL2DIR is an environment variable that would correspond to the
./configure --prefix=$SDL2DIR used in building SDL2.
Created by Amine Ben Hassouna:
Adapt FindSDL_ttf.cmake to SDL2_ttf (FindSDL2_ttf.cmake).
Add cache variables for more flexibility:
SDL2_TTF_PATH, SDL2_TTF_NO_DEFAULT_PATH (for details, see doc above).
Add SDL2 as a required dependency.
Modernize the FindSDL2_ttf.cmake module by creating a specific target:
SDL2::TTF (for details, see doc above).
Original FindSDL_ttf.cmake module:
Created by Eric Wing. This was influenced by the FindSDL.cmake
module, but with modifications to recognize OS X frameworks and
additional Unix paths (FreeBSD, etc).
#]=======================================================================]
# SDL2 Library required
find_package(SDL2 QUIET)
if(NOT SDL2_FOUND)
set(SDL2_TTF_SDL2_NOT_FOUND "Could NOT find SDL2 (SDL2 is required by SDL2_ttf).")
if(SDL2_ttf_FIND_REQUIRED)
message(FATAL_ERROR ${SDL2_TTF_SDL2_NOT_FOUND})
else()
if(NOT SDL2_ttf_FIND_QUIETLY)
message(STATUS ${SDL2_TTF_SDL2_NOT_FOUND})
endif()
return()
endif()
unset(SDL2_TTF_SDL2_NOT_FOUND)
endif()
# Define options for searching SDL2_ttf Library in a custom path
set(SDL2_TTF_PATH "" CACHE STRING "Custom SDL2_ttf Library path")
set(_SDL2_TTF_NO_DEFAULT_PATH OFF)
if(SDL2_TTF_PATH)
set(_SDL2_TTF_NO_DEFAULT_PATH ON)
endif()
set(SDL2_TTF_NO_DEFAULT_PATH ${_SDL2_TTF_NO_DEFAULT_PATH}
CACHE BOOL "Disable search SDL2_ttf Library in default path")
unset(_SDL2_TTF_NO_DEFAULT_PATH)
set(SDL2_TTF_NO_DEFAULT_PATH_CMD)
if(SDL2_TTF_NO_DEFAULT_PATH)
set(SDL2_TTF_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH)
endif()
# Search for the SDL2_ttf include directory
find_path(SDL2_TTF_INCLUDE_DIR SDL_ttf.h
HINTS
ENV SDL2TTFDIR
ENV SDL2DIR
${SDL2_TTF_NO_DEFAULT_PATH_CMD}
PATH_SUFFIXES SDL2
# path suffixes to search inside ENV{SDL2DIR}
# and ENV{SDL2TTFDIR}
include/SDL2 include
PATHS ${SDL2_TTF_PATH}
DOC "Where the SDL2_ttf headers can be found"
FIND_PATH(SDL2_TTF_INCLUDE_DIR SDL_ttf.h
HINTS
${SDL2}
$ENV{SDL2}
$ENV{SDL2_TTF}
PATH_SUFFIXES include/SDL2 include SDL2
i686-w64-mingw32/include/SDL2
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/include/SDL2
/usr/include/SDL2
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(VC_LIB_PATH_SUFFIX lib/x64)
else()
set(VC_LIB_PATH_SUFFIX lib/x86)
endif()
# Lookup the 64 bit libs on x64
IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
FIND_LIBRARY(SDL2_TTF_LIBRARY_TEMP
NAMES SDL2_ttf
HINTS
${SDL2}
$ENV{SDL2}
$ENV{SDL2_TTF}
PATH_SUFFIXES lib64 lib
lib/x64
x86_64-w64-mingw32/lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
# On 32bit build find the 32bit libs
ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8)
FIND_LIBRARY(SDL2_TTF_LIBRARY_TEMP
NAMES SDL2_ttf
HINTS
${SDL2}
$ENV{SDL2}
$ENV{SDL2_TTF}
PATH_SUFFIXES lib
lib/x86
i686-w64-mingw32/lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8)
# Search for the SDL2_ttf library
find_library(SDL2_TTF_LIBRARY
NAMES SDL2_ttf
HINTS
ENV SDL2TTFDIR
ENV SDL2DIR
${SDL2_TTF_NO_DEFAULT_PATH_CMD}
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
PATHS ${SDL2_TTF_PATH}
DOC "Where the SDL2_ttf Library can be found"
)
SET(SDL2_TTF_FOUND "NO")
IF(SDL2_TTF_LIBRARY_TEMP)
# Set the final string here so the GUI reflects the final state.
SET(SDL2_TTF_LIBRARY ${SDL2_TTF_LIBRARY_TEMP} CACHE STRING "Where the SDL2_ttf Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL2_TTF_LIBRARY_TEMP "${SDL2_TTF_LIBRARY_TEMP}" CACHE INTERNAL "")
SET(SDL2_TTF_FOUND "YES")
ENDIF(SDL2_TTF_LIBRARY_TEMP)
# Read SDL2_ttf version
if(SDL2_TTF_INCLUDE_DIR AND EXISTS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h")
file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+[0-9]+$")
file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+[0-9]+$")
file(STRINGS "${SDL2_TTF_INCLUDE_DIR}/SDL_ttf.h" SDL2_TTF_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+[0-9]+$")
string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MAJOR "${SDL2_TTF_VERSION_MAJOR_LINE}")
string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_MINOR "${SDL2_TTF_VERSION_MINOR_LINE}")
string(REGEX REPLACE "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_TTF_VERSION_PATCH "${SDL2_TTF_VERSION_PATCH_LINE}")
set(SDL2_TTF_VERSION_STRING ${SDL2_TTF_VERSION_MAJOR}.${SDL2_TTF_VERSION_MINOR}.${SDL2_TTF_VERSION_PATCH})
unset(SDL2_TTF_VERSION_MAJOR_LINE)
unset(SDL2_TTF_VERSION_MINOR_LINE)
unset(SDL2_TTF_VERSION_PATCH_LINE)
unset(SDL2_TTF_VERSION_MAJOR)
unset(SDL2_TTF_VERSION_MINOR)
unset(SDL2_TTF_VERSION_PATCH)
endif()
INCLUDE(FindPackageHandleStandardArgs)
set(SDL2_TTF_LIBRARIES ${SDL2_TTF_LIBRARY})
set(SDL2_TTF_INCLUDE_DIRS ${SDL2_TTF_INCLUDE_DIR})
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_TTF REQUIRED_VARS SDL2_TTF_LIBRARY SDL2_TTF_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_ttf
REQUIRED_VARS SDL2_TTF_LIBRARIES SDL2_TTF_INCLUDE_DIRS
VERSION_VAR SDL2_TTF_VERSION_STRING)
mark_as_advanced(SDL2_TTF_PATH
SDL2_TTF_NO_DEFAULT_PATH
SDL2_TTF_LIBRARY
SDL2_TTF_INCLUDE_DIR)
if(SDL2_TTF_FOUND)
# SDL2::TTF target
if(SDL2_TTF_LIBRARY AND NOT TARGET SDL2::TTF)
add_library(SDL2::TTF UNKNOWN IMPORTED)
set_target_properties(SDL2::TTF PROPERTIES
IMPORTED_LOCATION "${SDL2_TTF_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_TTF_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES SDL2::Core)
endif()
endif()

View File

@ -1,31 +0,0 @@
# Note: LibSndFile exports targets itself with SndFileConfig.cmake,
# However, the file is not for some reason provided in packages in some Linux distros, e.g. Ubuntu 18.04
# Hence this Find*.cmake file.
FIND_PATH(SndFile_INCLUDE_DIR sndfile.h)
FIND_LIBRARY(SndFile_LIBRARY NAMES sndfile libsndfile sndfile-1)
find_package_handle_standard_args(
SndFile
DEFAULT_MSG
SndFile_LIBRARY
SndFile_INCLUDE_DIR
)
# Export targets
if(SndFile_FOUND AND NOT TARGET SndFile::sndfile)
add_library(SndFile::sndfile UNKNOWN IMPORTED)
set_target_properties(SndFile::sndfile PROPERTIES
IMPORTED_LOCATION "${SndFile_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${SndFile_INCLUDE_DIR}")
# If we want to statically link it, we also need its dependencies
if(SNDFILE_STATIC)
find_package(Ogg REQUIRED)
find_package(Opus REQUIRED)
find_package(FLAC REQUIRED)
find_package(Vorbis REQUIRED)
find_package(VorbisEnc REQUIRED)
set_property(TARGET SndFile::sndfile APPEND PROPERTY
INTERFACE_LINK_LIBRARIES Ogg::ogg Opus::opus FLAC::FLAC Vorbis::vorbis Vorbis::VorbisEnc)
endif()
endif()

View File

@ -1,161 +0,0 @@
# - Find vorbisenc
# Find the native vorbisenc includes and libraries
#
# VORBIS_INCLUDE_DIRS - where to find vorbis.h, etc.
# VORBIS_LIBRARIES - List of libraries when using vorbis.
# VORBIS_FOUND - True if vorbis found.
# From https://github.com/erikd/libsndfile/
if (Vorbis_Vorbis_INCLUDE_DIR)
# Already in cache, be silent
set (Vorbis_FIND_QUIETLY TRUE)
endif ()
set (Vorbis_Vorbis_FIND_QUIETLY TRUE)
set (Vorbis_Enc_FIND_QUIETLY TRUE)
set (Vorbis_File_FIND_QUIETLY TRUE)
find_package (Ogg QUIET)
find_package (PkgConfig QUIET)
pkg_check_modules (PC_Vorbis_Vorbis QUIET vorbis)
pkg_check_modules (PC_Vorbis_Enc QUIET vorbisenc)
pkg_check_modules (PC_Vorbis_File QUIET vorbisfile)
set (Vorbis_VERSION ${PC_VORBIS_VERSION})
find_path (Vorbis_Vorbis_INCLUDE_DIR vorbis/codec.h
HINTS
${PC_Vorbis_Vorbis_INCLUDEDIR}
${PC_Vorbis_Vorbis_INCLUDE_DIRS}
${Vorbis_ROOT}
)
find_path (Vorbis_Enc_INCLUDE_DIR vorbis/vorbisenc.h
HINTS
${PC_Vorbis_Enc_INCLUDEDIR}
${PC_Vorbis_Enc_INCLUDE_DIRS}
${Vorbis_ROOT}
)
find_path (Vorbis_File_INCLUDE_DIR vorbis/vorbisfile.h
HINTS
${PC_Vorbis_File_INCLUDEDIR}
${PC_Vorbis_File_INCLUDE_DIRS}
${Vorbis_ROOT}
)
find_library (Vorbis_Vorbis_LIBRARY
NAMES
vorbis
vorbis_static
libvorbis
libvorbis_static
HINTS
${PC_Vorbis_Vorbis_LIBDIR}
${PC_Vorbis_Vorbis_LIBRARY_DIRS}
${Vorbis_ROOT}
)
find_library (Vorbis_Enc_LIBRARY
NAMES
vorbisenc
vorbisenc_static
libvorbisenc
libvorbisenc_static
HINTS
${PC_Vorbis_Enc_LIBDIR}
${PC_Vorbis_Enc_LIBRARY_DIRS}
${Vorbis_ROOT}
)
find_library (Vorbis_File_LIBRARY
NAMES
vorbisfile
vorbisfile_static
libvorbisfile
libvorbisfile_static
HINTS
${PC_Vorbis_File_LIBDIR}
${PC_Vorbis_File_LIBRARY_DIRS}
${Vorbis_ROOT}
)
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (Vorbis_Vorbis
REQUIRED_VARS
Vorbis_Vorbis_LIBRARY
Vorbis_Vorbis_INCLUDE_DIR
Ogg_FOUND
NAME_MISMATCHED
)
find_package_handle_standard_args (Vorbis_Enc
REQUIRED_VARS
Vorbis_Enc_LIBRARY
Vorbis_Enc_INCLUDE_DIR
Vorbis_Vorbis_FOUND
NAME_MISMATCHED
)
find_package_handle_standard_args (Vorbis_File
REQUIRED_VARS
Vorbis_File_LIBRARY
Vorbis_File_INCLUDE_DIR
Vorbis_Vorbis_FOUND
NAME_MISMATCHED
)
if (Vorbis_Vorbis_FOUND)
set (Vorbis_Vorbis_INCLUDE_DIRS ${VORBIS_INCLUDE_DIR})
set (Vorbis_Vorbis_LIBRARIES ${VORBIS_LIBRARY} ${OGG_LIBRARIES})
if (NOT TARGET Vorbis::vorbis)
add_library (Vorbis::vorbis UNKNOWN IMPORTED)
set_target_properties (Vorbis::vorbis PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_Vorbis_INCLUDE_DIR}"
IMPORTED_LOCATION "${Vorbis_Vorbis_LIBRARY}"
INTERFACE_LINK_LIBRARIES Ogg::ogg
)
endif ()
if (Vorbis_Enc_FOUND)
set (Vorbis_Enc_INCLUDE_DIRS ${Vorbis_Enc_INCLUDE_DIR})
set (Vorbis_Enc_LIBRARIES ${Vorbis_Enc_LIBRARY} ${Vorbis_Enc_LIBRARIES})
if (NOT TARGET Vorbis::vorbisenc)
add_library (Vorbis::vorbisenc UNKNOWN IMPORTED)
set_target_properties (Vorbis::vorbisenc PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_Enc_INCLUDE_DIR}"
IMPORTED_LOCATION "${Vorbis_Enc_LIBRARY}"
INTERFACE_LINK_LIBRARIES Vorbis::vorbis
)
endif ()
endif ()
if (Vorbis_File_FOUND)
set (Vorbis_File_INCLUDE_DIRS ${Vorbis_File_INCLUDE_DIR})
set (Vorbis_File_LIBRARIES ${Vorbis_File_LIBRARY} ${Vorbis_File_LIBRARIES})
if (NOT TARGET Vorbis::vorbisfile)
add_library (Vorbis::vorbisfile UNKNOWN IMPORTED)
set_target_properties (Vorbis::vorbisfile PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_File_INCLUDE_DIR}"
IMPORTED_LOCATION "${Vorbis_File_LIBRARY}"
INTERFACE_LINK_LIBRARIES Vorbis::vorbis
)
endif ()
endif ()
endif ()
find_package_handle_standard_args (Vorbis
REQUIRED_VARS
Vorbis_Vorbis_LIBRARY
Vorbis_Vorbis_INCLUDE_DIR
Ogg_FOUND
HANDLE_COMPONENTS
VERSION_VAR Vorbis_VERSION)
mark_as_advanced (Vorbis_Vorbis_INCLUDE_DIR Vorbis_Vorbis_LIBRARY)
mark_as_advanced (Vorbis_Enc_INCLUDE_DIR Vorbis_Enc_LIBRARY)
mark_as_advanced (Vorbis_File_INCLUDE_DIR Vorbis_File_LIBRARY)

View File

@ -1,66 +0,0 @@
# - Find vorbisenc
# Find the native vorbisenc includes and libraries
#
# VORBISENC_INCLUDE_DIRS - where to find vorbisenc.h, etc.
# VORBISENC_LIBRARIES - List of libraries when using vorbisenc.
# VORBISENC_FOUND - True if vorbisenc found.
# From https://github.com/erikd/libsndfile/
if (VORBISENC_INCLUDE_DIR)
# Already in cache, be silent
set (VORBISENC_FIND_QUIETLY TRUE)
endif ()
find_package (Vorbis QUIET)
find_package (PkgConfig QUIET)
pkg_check_modules (PC_VORBISENC QUIET vorbisenc)
set (VORBISENC_VERSION ${PC_VORBISENC_VERSION})
find_path (VORBISENC_INCLUDE_DIR vorbis/vorbisenc.h
HINTS
${PC_VORBISENC_INCLUDEDIR}
${PC_VORBISENC_INCLUDE_DIRS}
${VORBISENC_ROOT}
)
find_library (VORBISENC_LIBRARY
NAMES
vorbisenc
vorbisenc_static
libvorbisenc
libvorbisenc_static
HINTS
${PC_VORBISENC_LIBDIR}
${PC_VORBISENC_LIBRARY_DIRS}
${VORBISENC_ROOT}
)
# Handle the QUIETLY and REQUIRED arguments and set VORBISENC_FOUND
# to TRUE if all listed variables are TRUE.
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (VorbisEnc
REQUIRED_VARS
VORBISENC_LIBRARY
VORBISENC_INCLUDE_DIR
VORBIS_FOUND
VERSION_VAR
VORBISENC_VERSION
)
if (VORBISENC_FOUND)
set (VORBISENC_INCLUDE_DIRS ${VORBISENC_INCLUDE_DIR})
set (VORBISENC_LIBRARIES ${VORBISENC_LIBRARY} ${VORBIS_LIBRARIES})
if (NOT TARGET Vorbis::VorbisEnc)
add_library (Vorbis::VorbisEnc UNKNOWN IMPORTED)
set_target_properties (Vorbis::VorbisEnc PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${VORBISENC_INCLUDE_DIR}"
IMPORTED_LOCATION "${VORBISENC_LIBRARY}"
INTERFACE_LINK_LIBRARIES Vorbis::vorbis
)
endif ()
endif ()
mark_as_advanced (VORBISENC_INCLUDE_DIR VORBISENC_LIBRARY)

View File

@ -4,20 +4,17 @@
# This adds a new target with generated fake source files that include single header files
# It is a workaround for how CMake and Clang handle header files in compilation database
# And we need that to check each header file in the project exactly once, the same as .cpp modules
# Note: This is modifying an existing target by adding fake source files.
##
macro(add_fake_header_sources subdir the_target)
macro(add_fake_header_sources subdir)
set(all_fake_header_src_files "")
set(fake_headers_src_dir ${colobot_BINARY_DIR}/fake_header_sources)
file(MAKE_DIRECTORY ${fake_headers_src_dir})
get_target_property(the_target_sources ${the_target} SOURCES)
file(GLOB_RECURSE all_header_files RELATIVE ${colobot_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
foreach(source_file IN LISTS the_target_sources)
string(REGEX MATCH [[^.*\.h$]] is_header_file ${source_file})
if(is_header_file)
file(RELATIVE_PATH header_file ${colobot_SOURCE_DIR} ${colobot_SOURCE_DIR}/${subdir}/${source_file})
if(all_header_files)
foreach(header_file ${all_header_files})
string(REGEX REPLACE "\\.h$" ".cpp" fake_header_src_file "${fake_headers_src_dir}/${header_file}")
get_filename_component(fake_header_src_dir ${fake_header_src_file} PATH)
@ -25,8 +22,10 @@ macro(add_fake_header_sources subdir the_target)
file(WRITE ${fake_header_src_file} "#include \"${header_file}\"\n\n")
target_sources(${the_target} PRIVATE ${fake_header_src_file})
target_include_directories(${the_target} PUBLIC ${colobot_SOURCE_DIR})
endif()
endforeach()
list(APPEND all_fake_header_src_files ${fake_header_src_file})
endforeach()
include_directories(${colobot_SOURCE_DIR})
add_library(colobot_${subdir}_fake_header_srcs STATIC ${all_fake_header_src_files})
endif()
endmacro()

View File

@ -1,5 +1,5 @@
# Hacks for MSYS
if (MSYS)
if (MSYS AND (NOT MXE))
message(STATUS "Detected MSYS build")
set(PLATFORM_WINDOWS 1)

50
cmake/mxe.cmake Normal file
View File

@ -0,0 +1,50 @@
# When cross-compiling with MXE, we need to straighten some things
# Checking is a bit primitive, but this should detect MXE toolchain file
if((${CMAKE_CROSSCOMPILING}) AND (DEFINED MSYS))
message(STATUS "Detected MXE build")
set(MXE 1)
set(PLATFORM_WINDOWS 1)
set(PLATFORM_LINUX 0)
set(PLATFORM_OTHER 0)
# All must be static, CBOT and GLEW too
set(CBOT_STATIC ON)
set(GLEW_STATIC ON)
if (${OPENAL_SOUND})
set(OPENAL_MXE_LIBS
${CMAKE_FIND_ROOT_PATH}/lib/libFLAC.a
${CMAKE_FIND_ROOT_PATH}/lib/libvorbis.a
${CMAKE_FIND_ROOT_PATH}/lib/libvorbisenc.a
${CMAKE_FIND_ROOT_PATH}/lib/libvorbisfile.a
${CMAKE_FIND_ROOT_PATH}/lib/libogg.a
)
endif()
set(MXE_CFLAGS "-DAL_LIBTYPE_STATIC")
set(MXE_LIBS
# For some reason, these have to be absolute paths
${CMAKE_FIND_ROOT_PATH}/lib/libintl.a
${CMAKE_FIND_ROOT_PATH}/lib/libiconv.a
${CMAKE_FIND_ROOT_PATH}/lib/libglew32s.a
${CMAKE_FIND_ROOT_PATH}/lib/libfreetype.a
${CMAKE_FIND_ROOT_PATH}/lib/libopengl32.a
${CMAKE_FIND_ROOT_PATH}/lib/libjpeg.a
${CMAKE_FIND_ROOT_PATH}/lib/libwinmm.a
${CMAKE_FIND_ROOT_PATH}/lib/libdxguid.a
${CMAKE_FIND_ROOT_PATH}/lib/libbz2.a
${CMAKE_FIND_ROOT_PATH}/lib/libimm32.a
${CMAKE_FIND_ROOT_PATH}/lib/libole32.a
${CMAKE_FIND_ROOT_PATH}/lib/liboleaut32.a
${CMAKE_FIND_ROOT_PATH}/lib/libharfbuzz.a
${CMAKE_FIND_ROOT_PATH}/lib/libwebp.a
${CMAKE_FIND_ROOT_PATH}/lib/libversion.a
${CMAKE_FIND_ROOT_PATH}/lib/libglib-2.0.a
${CMAKE_FIND_ROOT_PATH}/lib/libwsock32.a
${CMAKE_FIND_ROOT_PATH}/lib/libws2_32.a
${CMAKE_FIND_ROOT_PATH}/lib/libintl.a
${OPENAL_MXE_LIBS}
)
else()
set(MXE 0)
endif()

View File

@ -1,41 +0,0 @@
# Hide console on Windows (useful for release builds)
option(COLOBOT_HIDE_CONSOLE "Hide console" OFF)
add_executable(colobot)
target_sources(colobot PRIVATE
src/main.cpp
)
if(MSVC)
target_compile_options(colobot PRIVATE /utf-8)
endif()
if(PLATFORM_WINDOWS)
target_sources(colobot PRIVATE ${PROJECT_BINARY_DIR}/desktop/colobot.rc)
endif()
target_link_libraries(colobot Colobot-Base SDL2::Main)
if(COLOBOT_HIDE_CONSOLE)
set_target_properties(colobot PROPERTIES WIN32_EXECUTABLE TRUE)
endif()
# Install
install(TARGETS colobot RUNTIME DESTINATION ${COLOBOT_INSTALL_BIN_DIR})
if(MSVC)
install(FILES $<TARGET_PDB_FILE:colobot>
CONFIGURATIONS Debug RelWithDebInfo
DESTINATION ${COLOBOT_INSTALL_BIN_DIR} OPTIONAL)
endif()
if(NOT CBOT_STATIC)
set_target_properties(colobot PROPERTIES
INSTALL_RPATH ${COLOBOT_INSTALL_LIB_DIR})
endif()
# Linter-specific
if(COLOBOT_LINT_BUILD)
add_fake_header_sources("src" colobot)
endif()

View File

@ -1,590 +0,0 @@
# Compile flags as defined in global CMakeLists
set(CMAKE_CXX_FLAGS ${COLOBOT_CXX_FLAGS})
set(CMAKE_CXX_FLAGS_RELEASE ${COLOBOT_CXX_FLAGS_RELEASE})
set(CMAKE_CXX_FLAGS_DEBUG ${COLOBOT_CXX_FLAGS_DEBUG})
add_subdirectory(graphics/opengl33/shaders)
if(COLOBOT_OFFICIAL_BUILD)
set(OFFICIAL_COLOBOT_BUILD "true")
else()
set(OFFICIAL_COLOBOT_BUILD "false")
endif()
if(DEV_BUILD)
set(DEVELOPMENT_COLOBOT_BUILD "true")
else()
set(DEVELOPMENT_COLOBOT_BUILD "false")
endif()
# Configure file
configure_file(common/config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/common/config.h")
configure_file(common/version.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/common/version.h")
# Todo: split this monstrosity into smaller libraries (graphics, math, ui, etc.)
add_library(Colobot-Base STATIC
app/app.cpp
app/app.h
app/controller.cpp
app/controller.h
app/input.cpp
app/input.h
app/modman.cpp
app/modman.h
app/pathman.cpp
app/pathman.h
app/pausemanager.cpp
app/pausemanager.h
app/signal_handlers.cpp
app/signal_handlers.h
common/config_file.cpp
common/config_file.h
common/error.h
common/event.cpp
common/event.h
common/font_loader.h
common/font_loader.cpp
common/global.h
common/image.cpp
common/image.h
common/ioutils.h
common/key.cpp
common/key.h
common/language.cpp
common/language.h
common/logger.cpp
common/logger.h
common/profiler.cpp
common/profiler.h
common/regex_utils.cpp
common/regex_utils.h
common/resources/inputstream.cpp
common/resources/inputstream.h
common/resources/inputstreambuffer.cpp
common/resources/inputstreambuffer.h
common/resources/outputstream.cpp
common/resources/outputstream.h
common/resources/outputstreambuffer.cpp
common/resources/outputstreambuffer.h
common/resources/resourcemanager.cpp
common/resources/resourcemanager.h
common/resources/sdl_file_wrapper.cpp
common/resources/sdl_file_wrapper.h
common/resources/sdl_memory_wrapper.cpp
common/resources/sdl_memory_wrapper.h
common/resources/sndfile_wrapper.cpp
common/resources/sndfile_wrapper.h
common/restext.cpp
common/restext.h
common/system/system.cpp
common/system/system.h
common/system/system_other.cpp
common/system/system_other.h
common/system/${SYSTEM_CPP_MODULE}
common/system/${SYSTEM_H_MODULE}
common/settings.cpp
common/settings.h
common/singleton.h
common/timeutils.cpp
common/timeutils.h
common/thread/worker_thread.h
graphics/core/color.cpp
graphics/core/color.h
graphics/core/device.h
graphics/core/framebuffer.cpp
graphics/core/framebuffer.h
graphics/core/light.h
graphics/core/material.h
graphics/core/texture.h
graphics/core/transparency.h
graphics/core/triangle.h
graphics/core/type.cpp
graphics/core/type.h
graphics/core/renderers.h
graphics/core/vertex.h
graphics/engine/camera.cpp
graphics/engine/camera.h
graphics/engine/cloud.cpp
graphics/engine/cloud.h
graphics/engine/engine.cpp
graphics/engine/engine.h
graphics/engine/lightman.cpp
graphics/engine/lightman.h
graphics/engine/lightning.cpp
graphics/engine/lightning.h
graphics/engine/oldmodelmanager.cpp
graphics/engine/oldmodelmanager.h
graphics/engine/particle.cpp
graphics/engine/particle.h
graphics/engine/planet.cpp
graphics/engine/planet.h
graphics/engine/pyro.cpp
graphics/engine/pyro.h
graphics/engine/pyro_manager.cpp
graphics/engine/pyro_manager.h
graphics/engine/pyro_type.h
graphics/engine/terrain.cpp
graphics/engine/terrain.h
graphics/engine/text.cpp
graphics/engine/text.h
graphics/engine/water.cpp
graphics/engine/water.h
graphics/model/model.cpp
graphics/model/model.h
graphics/model/model_crash_sphere.h
graphics/model/model_input.cpp
graphics/model/model_input.h
graphics/model/model_io_exception.h
graphics/model/model_io_structs.h
graphics/model/model_gltf.cpp
graphics/model/model_gltf.h
graphics/model/model_manager.cpp
graphics/model/model_manager.h
graphics/model/model_mesh.cpp
graphics/model/model_mesh.h
graphics/model/model_mod.cpp
graphics/model/model_mod.h
graphics/model/model_output.cpp
graphics/model/model_output.h
graphics/model/model_shadow_spot.h
graphics/model/model_triangle.h
graphics/model/model_txt.cpp
graphics/model/model_txt.h
graphics/opengl33/gl33_device.cpp
graphics/opengl33/gl33_device.h
graphics/opengl33/gl33_object_renderer.cpp
graphics/opengl33/gl33_object_renderer.h
graphics/opengl33/gl33_particle_renderer.cpp
graphics/opengl33/gl33_particle_renderer.h
graphics/opengl33/gl33_terrain_renderer.cpp
graphics/opengl33/gl33_terrain_renderer.h
graphics/opengl33/gl33_shadow_renderer.cpp
graphics/opengl33/gl33_shadow_renderer.h
graphics/opengl33/gl33_ui_renderer.cpp
graphics/opengl33/gl33_ui_renderer.h
graphics/opengl33/glframebuffer.cpp
graphics/opengl33/glframebuffer.h
graphics/opengl33/glutil.cpp
graphics/opengl33/glutil.h
level/build_type.h
level/level_category.cpp
level/level_category.h
level/mainmovie.cpp
level/mainmovie.h
level/parser/parser.cpp
level/parser/parser.h
level/parser/parserexceptions.cpp
level/parser/parserexceptions.h
level/parser/parserline.cpp
level/parser/parserline.h
level/parser/parserparam.cpp
level/parser/parserparam.h
level/player_profile.cpp
level/player_profile.h
level/research_type.h
level/robotmain.cpp
level/robotmain.h
level/scene_conditions.cpp
level/scene_conditions.h
level/scoreboard.cpp
level/scoreboard.h
math/all.h
math/const.h
math/func.h
math/geometry.h
math/half.cpp
math/half.h
math/sphere.h
object/auto/auto.cpp
object/auto/auto.h
object/auto/autobase.cpp
object/auto/autobase.h
object/auto/autoconvert.cpp
object/auto/autoconvert.h
object/auto/autoderrick.cpp
object/auto/autoderrick.h
object/auto/autodestroyer.cpp
object/auto/autodestroyer.h
object/auto/autoegg.cpp
object/auto/autoegg.h
object/auto/autofactory.cpp
object/auto/autofactory.h
object/auto/autoflag.cpp
object/auto/autoflag.h
object/auto/autohouston.cpp
object/auto/autohouston.h
object/auto/autojostle.cpp
object/auto/autojostle.h
object/auto/autokid.cpp
object/auto/autokid.h
object/auto/autolabo.cpp
object/auto/autolabo.h
object/auto/automush.cpp
object/auto/automush.h
object/auto/autonest.cpp
object/auto/autonest.h
object/auto/autonuclearplant.cpp
object/auto/autonuclearplant.h
object/auto/autoportico.cpp
object/auto/autoportico.h
object/auto/autopowercaptor.cpp
object/auto/autopowercaptor.h
object/auto/autopowerplant.cpp
object/auto/autopowerplant.h
object/auto/autopowerstation.cpp
object/auto/autopowerstation.h
object/auto/autoradar.cpp
object/auto/autoradar.h
object/auto/autorepair.cpp
object/auto/autorepair.h
object/auto/autoresearch.cpp
object/auto/autoresearch.h
object/auto/autoroot.cpp
object/auto/autoroot.h
object/auto/autotower.cpp
object/auto/autotower.h
object/auto/autovault.cpp
object/auto/autovault.h
object/crash_sphere.h
object/drive_type.cpp
object/drive_type.h
object/implementation/power_container_impl.cpp
object/implementation/power_container_impl.h
object/implementation/program_storage_impl.cpp
object/implementation/program_storage_impl.h
object/implementation/programmable_impl.cpp
object/implementation/programmable_impl.h
object/implementation/task_executor_impl.cpp
object/implementation/task_executor_impl.h
object/interface/controllable_object.h
object/interface/damageable_object.h
object/interface/destroyable_object.h
object/interface/flying_object.h
object/interface/fragile_object.h
object/interface/interactive_object.h
object/interface/jet_flying_object.h
object/interface/jostleable_object.h
object/interface/movable_object.h
object/interface/power_container_object.h
object/interface/program_storage_object.h
object/interface/programmable_object.h
object/interface/ranged_object.h
object/interface/shielded_auto_regen_object.h
object/interface/shielded_object.h
object/interface/slotted_object.h
object/interface/task_executor_object.h
object/interface/trace_drawing_object.cpp
object/interface/trace_drawing_object.h
object/interface/transportable_object.h
object/mission_type.h
object/motion/motion.cpp
object/motion/motion.h
object/motion/motionant.cpp
object/motion/motionant.h
object/motion/motionbee.cpp
object/motion/motionbee.h
object/motion/motionhuman.cpp
object/motion/motionhuman.h
object/motion/motionlevelcontroller.cpp
object/motion/motionlevelcontroller.h
object/motion/motionqueen.cpp
object/motion/motionqueen.h
object/motion/motionspider.cpp
object/motion/motionspider.h
object/motion/motiontoto.cpp
object/motion/motiontoto.h
object/motion/motionvehicle.cpp
object/motion/motionvehicle.h
object/motion/motionworm.cpp
object/motion/motionworm.h
object/object.cpp
object/object.h
object/object_create_exception.h
object/object_create_params.h
object/object_factory.cpp
object/object_factory.h
object/object_interface_type.h
object/object_manager.cpp
object/object_manager.h
object/object_type.cpp
object/object_type.h
object/old_object.cpp
object/old_object.h
object/old_object_interface.cpp
object/old_object_interface.h
object/subclass/base_alien.cpp
object/subclass/base_alien.h
object/subclass/base_building.cpp
object/subclass/base_building.h
object/subclass/base_robot.cpp
object/subclass/base_robot.h
object/subclass/base_vehicle.cpp
object/subclass/base_vehicle.h
object/subclass/exchange_post.cpp
object/subclass/exchange_post.h
object/subclass/shielder.cpp
object/subclass/shielder.h
object/subclass/static_object.cpp
object/subclass/static_object.h
object/task/task.cpp
object/task/task.h
object/task/taskadvance.cpp
object/task/taskadvance.h
object/task/taskbuild.cpp
object/task/taskbuild.h
object/task/taskdeletemark.cpp
object/task/taskdeletemark.h
object/task/taskfire.cpp
object/task/taskfire.h
object/task/taskfireant.cpp
object/task/taskfireant.h
object/task/taskflag.cpp
object/task/taskflag.h
object/task/taskgoto.cpp
object/task/taskgoto.h
object/task/taskgungoal.cpp
object/task/taskgungoal.h
object/task/taskinfo.cpp
object/task/taskinfo.h
object/task/taskmanip.cpp
object/task/taskmanip.h
object/task/taskpen.cpp
object/task/taskpen.h
object/task/taskrecover.cpp
object/task/taskrecover.h
object/task/tasksearch.cpp
object/task/tasksearch.h
object/task/taskshield.cpp
object/task/taskshield.h
object/task/taskspiderexplo.cpp
object/task/taskspiderexplo.h
object/task/tasktake.cpp
object/task/tasktake.h
object/task/taskterraform.cpp
object/task/taskterraform.h
object/task/taskturn.cpp
object/task/taskturn.h
object/task/taskwait.cpp
object/task/taskwait.h
object/tool_type.cpp
object/tool_type.h
physics/physics.cpp
physics/physics.h
script/cbottoken.cpp
script/cbottoken.h
script/script.cpp
script/script.h
script/scriptfunc.cpp
script/scriptfunc.h
sound/sound.cpp
sound/sound.h
sound/sound_type.cpp
sound/sound_type.h
ui/controls/button.cpp
ui/controls/button.h
ui/controls/check.cpp
ui/controls/check.h
ui/controls/color.cpp
ui/controls/color.h
ui/controls/control.cpp
ui/controls/control.h
ui/controls/edit.cpp
ui/controls/edit.h
ui/controls/editvalue.cpp
ui/controls/editvalue.h
ui/controls/enumslider.cpp
ui/controls/enumslider.h
ui/controls/gauge.cpp
ui/controls/gauge.h
ui/controls/group.cpp
ui/controls/group.h
ui/controls/image.cpp
ui/controls/image.h
ui/controls/interface.cpp
ui/controls/interface.h
ui/controls/key.cpp
ui/controls/key.h
ui/controls/label.cpp
ui/controls/label.h
ui/controls/list.cpp
ui/controls/list.h
ui/controls/map.cpp
ui/controls/map.h
ui/controls/scroll.cpp
ui/controls/scroll.h
ui/controls/shortcut.cpp
ui/controls/shortcut.h
ui/controls/slider.cpp
ui/controls/slider.h
ui/controls/target.cpp
ui/controls/target.h
ui/controls/window.cpp
ui/controls/window.h
ui/debug_menu.cpp
ui/debug_menu.h
ui/displayinfo.cpp
ui/displayinfo.h
ui/displaytext.cpp
ui/displaytext.h
ui/filedialog.cpp
ui/filedialog.h
ui/maindialog.cpp
ui/maindialog.h
ui/mainmap.cpp
ui/mainmap.h
ui/mainshort.cpp
ui/mainshort.h
ui/mainui.cpp
ui/mainui.h
ui/object_interface.cpp
ui/object_interface.h
ui/particles_generator.cpp
ui/particles_generator.h
ui/screen/screen.cpp
ui/screen/screen.h
ui/screen/screen_appearance.cpp
ui/screen/screen_appearance.h
ui/screen/screen_io.cpp
ui/screen/screen_io.h
ui/screen/screen_io_read.cpp
ui/screen/screen_io_read.h
ui/screen/screen_io_write.cpp
ui/screen/screen_io_write.h
ui/screen/screen_level_list.cpp
ui/screen/screen_level_list.h
ui/screen/screen_loading.cpp
ui/screen/screen_loading.h
ui/screen/screen_main_menu.cpp
ui/screen/screen_main_menu.h
ui/screen/screen_mod_list.cpp
ui/screen/screen_mod_list.h
ui/screen/screen_player_select.cpp
ui/screen/screen_player_select.h
ui/screen/screen_quit.cpp
ui/screen/screen_quit.h
ui/screen/screen_setup.cpp
ui/screen/screen_setup.h
ui/screen/screen_setup_controls.cpp
ui/screen/screen_setup_controls.h
ui/screen/screen_setup_display.cpp
ui/screen/screen_setup_display.h
ui/screen/screen_setup_game.cpp
ui/screen/screen_setup_game.h
ui/screen/screen_setup_graphics.cpp
ui/screen/screen_setup_graphics.h
ui/screen/screen_setup_sound.cpp
ui/screen/screen_setup_sound.h
ui/screen/screen_welcome.cpp
ui/screen/screen_welcome.h
ui/studio.cpp
ui/studio.h
)
target_include_directories(Colobot-Base PUBLIC
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/..
${CMAKE_CURRENT_BINARY_DIR}
)
# Main libraries
target_link_libraries(Colobot-Base PUBLIC
CBot
Colobot-Common
localename
SDL2::Core
SDL2::Image
SDL2::TTF
OpenGL::GL
PNG::PNG
GLEW::GLEW
glm::glm
PhysFS::PhysFS
SndFile::sndfile
nlohmann_json::nlohmann_json
)
# Optional libraries
if(OPENAL_SOUND)
target_sources(Colobot-Base PRIVATE
sound/oalsound/alsound.cpp
sound/oalsound/buffer.cpp
sound/oalsound/channel.cpp
sound/oalsound/check.cpp
sound/oalsound/alsound.h
sound/oalsound/buffer.h
sound/oalsound/channel.h
sound/oalsound/check.h
)
target_link_libraries(Colobot-Base PUBLIC OpenAL::OpenAL)
endif()
if(WINGETOPT)
target_link_libraries(Colobot-Base PUBLIC wingetopt)
endif()
if(MSVC)
target_compile_options(Colobot-Base PRIVATE /utf-8)
endif()
# Additional libraries per platform
if(PLATFORM_WINDOWS)
# because it isn't included in standard linking libraries
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
# TODO: this shouldn't be needed, the libraries targets should care of those transitive dependencies
# This should be treated as a temporary workaround
if(USE_STATIC_RUNTIME) # Since we're using static runtime, assume every external library is static too
find_package(Intl REQUIRED)
find_library(BZ2_LIBRARY NAMES bz2)
find_library(FREETYPE_LIBRARY NAMES freetype)
find_library(ICONV_LIBRARY NAMES iconv)
find_library(CHARSET_LIBRARY NAMES charset)
find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon-static)
find_library(BROTLIENC_LIBRARY NAMES brotlienc-static)
find_library(BROTLIDEC_LIBRARY NAMES brotlidec-static)
target_link_libraries(Colobot-Base PUBLIC
Gettext::Intl
${BZ2_LIBRARY}
${FREETYPE_LIBRARY}
${ICONV_LIBRARY}
${CHARSET_LIBRARY}
${BROTLICOMMON_LIBRARY}
${BROTLIENC_LIBRARY}
${BROTLIDEC_LIBRARY}
# why
winmm.lib
dxguid.lib
imm32.lib
ole32.lib
oleaut32.lib
version.lib
wsock32.lib
ws2_32.lib
setupapi.lib
)
endif()
else()
target_link_libraries(Colobot-Base PUBLIC -lintl)
endif()
elseif(PLATFORM_GNU)
# nothing
elseif(PLATFORM_LINUX)
# for clock_gettime
target_link_libraries(Colobot-Base PUBLIC -lrt)
elseif(PLATFORM_MACOSX)
find_package(Intl REQUIRED)
target_link_libraries(Colobot-Base PUBLIC Gettext::Intl)
elseif(PLATFORM_FREEBSD)
find_package(Intl REQUIRED)
target_link_libraries(Colobot-Base PUBLIC Gettext::Intl)
endif()
set(COLOBOT_LIBS ${LIBS} PARENT_SCOPE)
# Linter-specific
if(COLOBOT_LINT_BUILD)
add_fake_header_sources("src" Colobot-Base)
endif()

View File

@ -1,359 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "app/modman.h"
#include "common/config.h"
#include "app/app.h"
#include "app/pathman.h"
#include "common/config_file.h"
#include "common/logger.h"
#include "common/stringutils.h"
#include "common/resources/resourcemanager.h"
#include "level/parser/parser.h"
#include <algorithm>
#include <filesystem>
#include <map>
CModManager::CModManager(CApplication* app, CPathManager* pathManager)
: m_app{app},
m_pathManager{pathManager}
{
}
void CModManager::FindMods()
{
m_mods.clear();
m_userChanges = false;
// Load names from the config file
std::vector<std::string> savedModNames;
GetConfigFile().GetArrayProperty("Mods", "Names", savedModNames);
std::vector<bool> savedEnabled;
GetConfigFile().GetArrayProperty("Mods", "Enabled", savedEnabled);
// Transform the data into Mod structures
m_mods.reserve(savedModNames.size());
for (size_t i = 0; i < savedModNames.size(); ++i)
{
Mod mod{};
mod.name = savedModNames[i];
if (i < savedEnabled.size())
{
mod.enabled = savedEnabled[i];
}
mod.path = ""; // Find the path later
m_mods.push_back(mod);
}
// Search the folders for mods
auto rawPaths = m_pathManager->FindMods();
std::map<std::string, std::string> modPaths;
for (const auto& path : rawPaths)
{
auto modName = std::filesystem::path(path).stem().string();
modPaths.insert(std::make_pair(modName, path));
}
// Find paths for already saved mods
auto it = m_mods.begin();
while (it != m_mods.end())
{
auto& mod = *it;
const auto pathsIt = modPaths.find(mod.name);
if (pathsIt != modPaths.end())
{
mod.path = (*pathsIt).second;
modPaths.erase(pathsIt);
++it;
}
else
{
GetLogger()->Warn("Could not find mod %s, removing it from the list\n", mod.name.c_str());
it = m_mods.erase(it);
}
}
// Add the remaining found mods to the end of the list
for (const auto& newMod : modPaths)
{
Mod mod{};
mod.name = newMod.first;
mod.path = newMod.second;
m_mods.push_back(mod);
}
// Load the metadata for each mod
// Unfortunately, the paths are distinguished by their real paths, not mount points
// So we must unmount mods temporarily
for (const auto& path : m_mountedModPaths)
{
UnmountMod(path);
}
for (auto& mod : m_mods)
{
MountMod(mod, "/temp/mod");
LoadModData(mod);
UnmountMod(mod);
}
// Mount back
for (const auto& path : m_mountedModPaths)
{
MountMod(path);
}
}
void CModManager::ReloadMods()
{
UnmountAllMountedMods();
MountAllMods();
ReloadResources();
}
void CModManager::EnableMod(size_t i)
{
m_mods[i].enabled = true;
m_userChanges = true;
}
void CModManager::DisableMod(size_t i)
{
m_mods[i].enabled = false;
m_userChanges = true;
}
size_t CModManager::MoveUp(size_t i)
{
if (i != 0)
{
std::swap(m_mods[i - 1], m_mods[i]);
m_userChanges = true;
return i - 1;
}
else
{
return i;
}
}
size_t CModManager::MoveDown(size_t i)
{
if (i != m_mods.size() - 1)
{
std::swap(m_mods[i], m_mods[i + 1]);
m_userChanges = true;
return i + 1;
}
else
{
return i;
}
}
bool CModManager::Changes()
{
std::vector<std::string> paths;
for (const auto& mod : m_mods)
{
if (mod.enabled)
{
paths.push_back(mod.path);
}
}
return paths != m_mountedModPaths || m_userChanges;
}
void CModManager::MountAllMods()
{
for (const auto& mod : m_mods)
{
if (mod.enabled)
{
MountMod(mod);
m_mountedModPaths.push_back(mod.path);
}
}
}
void CModManager::ReloadResources()
{
m_app->ReloadResources();
}
void CModManager::SaveMods()
{
std::vector<std::string> savedNames;
savedNames.reserve(m_mods.size());
std::transform(m_mods.begin(), m_mods.end(), std::back_inserter(savedNames), [](const Mod& mod) { return mod.name; });
GetConfigFile().SetArrayProperty("Mods", "Names", savedNames);
std::vector<bool> savedEnabled;
savedEnabled.reserve(m_mods.size());
std::transform(m_mods.begin(), m_mods.end(), std::back_inserter(savedEnabled), [](const Mod& mod) { return mod.enabled; });
GetConfigFile().SetArrayProperty("Mods", "Enabled", savedEnabled);
GetConfigFile().Save();
m_userChanges = false;
}
size_t CModManager::CountMods() const
{
return m_mods.size();
}
const Mod& CModManager::GetMod(size_t i) const
{
return m_mods[i];
}
const std::vector<Mod>& CModManager::GetMods() const
{
return m_mods;
}
void CModManager::LoadModData(Mod& mod)
{
auto& data = mod.data;
data.displayName = mod.name;
try
{
CLevelParser levelParser("temp/mod/manifest.txt");
if (levelParser.Exists())
{
levelParser.Load();
CLevelParserLine* line = nullptr;
// DisplayName
line = levelParser.GetIfDefined("DisplayName");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.displayName = line->GetParam("text")->AsString();
}
// Author
line = levelParser.GetIfDefined("Author");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.author = line->GetParam("text")->AsString();
}
// Version
line = levelParser.GetIfDefined("Version");
if (line != nullptr)
{
if (line->GetParam("text")->IsDefined())
{
data.version = line->GetParam("text")->AsString();
}
else if (line->GetParam("major")->IsDefined() && line->GetParam("minor")->IsDefined() && line->GetParam("patch")->IsDefined())
{
auto major = StrUtils::ToString(line->GetParam("major")->AsInt());
auto minor = StrUtils::ToString(line->GetParam("minor")->AsInt());
auto patch = StrUtils::ToString(line->GetParam("patch")->AsInt());
std::ostringstream stream;
stream << major << "." << minor << "." << patch;
data.version = stream.str();
}
}
// Website
line = levelParser.GetIfDefined("Website");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.website = line->GetParam("text")->AsString();
}
// Summary
line = levelParser.GetIfDefined("Summary");
if (line != nullptr && line->GetParam("text")->IsDefined())
{
data.summary = line->GetParam("text")->AsString();
}
}
else
{
GetLogger()->Warn("No manifest file for mod %s\n", mod.name.c_str());
}
}
catch (CLevelParserException& e)
{
GetLogger()->Warn("Failed parsing manifest for mod %s: %s\n", mod.name.c_str(), e.what());
}
// Changes
data.changes = CResourceManager::ListDirectories("temp/mod");
auto levelsIt = std::find(data.changes.begin(), data.changes.end(), "levels");
if (levelsIt != data.changes.end())
{
auto levelsDirs = CResourceManager::ListDirectories("temp/mod/levels");
if (!levelsDirs.empty())
{
std::transform(levelsDirs.begin(), levelsDirs.end(), levelsDirs.begin(), [](const std::string& dir) { return "levels/" + dir; });
levelsIt = data.changes.erase(levelsIt);
data.changes.insert(levelsIt, levelsDirs.begin(), levelsDirs.end());
}
}
}
void CModManager::MountMod(const Mod& mod, const std::string& mountPoint)
{
MountMod(mod.path, mountPoint);
}
void CModManager::MountMod(const std::string& path, const std::string& mountPoint)
{
GetLogger()->Debug("Mounting mod: '%s' at path %s\n", path.c_str(), mountPoint.c_str());
CResourceManager::AddLocation(path, true, mountPoint);
}
void CModManager::UnmountMod(const Mod& mod)
{
UnmountMod(mod.path);
}
void CModManager::UnmountMod(const std::string& path)
{
if (CResourceManager::LocationExists(path))
{
GetLogger()->Debug("Unmounting mod: '%s'\n", path.c_str());
CResourceManager::RemoveLocation(path);
}
}
void CModManager::UnmountAllMountedMods()
{
for (const auto& path : m_mountedModPaths)
{
UnmountMod(path);
}
m_mountedModPaths.clear();
}

View File

@ -1,124 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include <string>
#include <unordered_map>
#include <vector>
class CApplication;
class CPathManager;
struct ModData
{
std::string displayName{};
std::string author{};
std::string version{};
std::string website{};
std::string summary{};
std::vector<std::string> changes{};
};
struct Mod
{
std::string name{};
std::string path{};
bool enabled = false;
ModData data{};
};
/**
* \class CModManager
* \brief This class handles the list of mods.
*
* The order matters since the order in which files are loaded matters,
* because some files can be overwritten.
*
* The changes in the list do not immediately apply.
*/
class CModManager
{
public:
CModManager(CApplication* app, CPathManager* pathManager);
//! Finds all the mods along with their metadata
void FindMods();
//! Applies the current configuration and reloads the application
void ReloadMods();
//! Removes a mod from the list of loaded mods
void EnableMod(size_t i);
//! Adds a mod to the list of loaded mods
void DisableMod(size_t i);
//! Moves the selected mod up in the list so that it's loaded sooner than others, returns the new index
size_t MoveUp(size_t i);
//! Moves the selected mod down in the list so that it's loaded later than others, returns the new index
size_t MoveDown(size_t i);
//! Checks if the list of currently used mods differs from the current configuration or there were changes made by the user
bool Changes();
//! Saves the current configuration of mods to the config file
void SaveMods();
//! Number of mods loaded
size_t CountMods() const;
//! Returns the reference to the mod in given position
const Mod& GetMod(size_t i) const;
//! Returns the list of mods
const std::vector<Mod>& GetMods() const;
private:
// Allow access to MountAllMods() as CApplication doesn't want to reload itself during initialization
friend CApplication;
//! Reloads application resources so the enabled mods are applied
void ReloadResources();
//! Load mod data into mod
void LoadModData(Mod& mod);
//! Updates the paths in Path Manager according to the current mod configuration
void MountAllMods();
void MountMod(const Mod& mod, const std::string& mountPoint = "");
void MountMod(const std::string& path, const std::string& mountPoint = "");
void UnmountMod(const Mod& mod);
void UnmountMod(const std::string& path);
void UnmountAllMountedMods();
private:
CApplication* m_app;
CPathManager* m_pathManager;
//! Paths to mods already in the virtual filesystem
std::vector<std::string> m_mountedModPaths;
//! List of mods
std::vector<Mod> m_mods;
bool m_userChanges = false;
};

View File

@ -1,186 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "app/app.h"
#include "app/pathman.h"
#include "common/config.h"
#include "common/logger.h"
#include "common/resources/resourcemanager.h"
#include "common/system/system.h"
#ifdef PLATFORM_WINDOWS
#include "common/system/system_windows.h"
#endif
#include <filesystem>
CPathManager::CPathManager(CSystemUtils* systemUtils)
: m_dataPath(systemUtils->GetDataPath())
, m_langPath(systemUtils->GetLangPath())
, m_savePath(systemUtils->GetSaveDir())
, m_modSearchDirs{}
{
}
CPathManager::~CPathManager()
{
}
void CPathManager::SetDataPath(const std::string &dataPath)
{
m_dataPath = dataPath;
}
void CPathManager::SetLangPath(const std::string &langPath)
{
m_langPath = langPath;
}
void CPathManager::SetSavePath(const std::string &savePath)
{
m_savePath = savePath;
}
const std::string& CPathManager::GetDataPath()
{
return m_dataPath;
}
const std::string& CPathManager::GetLangPath()
{
return m_langPath;
}
const std::string& CPathManager::GetSavePath()
{
return m_savePath;
}
std::string CPathManager::VerifyPaths()
{
std::filesystem::path dataPath = std::filesystem::u8path(m_dataPath);
if (! (std::filesystem::exists(dataPath) && std::filesystem::is_directory(dataPath)) )
{
GetLogger()->Error("Data directory '%s' doesn't exist or is not a directory\n", m_dataPath.c_str());
return std::string("Could not read from data directory:\n") +
std::string("'") + m_dataPath + std::string("'\n") +
std::string("Please check your installation, or supply a valid data directory by -datadir option.");
}
std::filesystem::path langPath = std::filesystem::u8path(m_langPath);
if (! (std::filesystem::exists(langPath) && std::filesystem::is_directory(langPath)) )
{
GetLogger()->Warn("Language path '%s' is invalid, assuming translation files not installed\n", m_langPath.c_str());
}
std::filesystem::create_directories(std::filesystem::u8path(m_savePath));
std::filesystem::create_directories(std::filesystem::u8path(m_savePath + "/mods"));
return "";
}
void CPathManager::InitPaths()
{
GetLogger()->Info("Data path: %s\n", m_dataPath.c_str());
GetLogger()->Info("Save path: %s\n", m_savePath.c_str());
m_modSearchDirs.push_back(m_dataPath + "/mods");
m_modSearchDirs.push_back(m_savePath + "/mods");
if (!m_modSearchDirs.empty())
{
GetLogger()->Info("Mod search dirs:\n");
for(const std::string& modSearchDir : m_modSearchDirs)
GetLogger()->Info(" * %s\n", modSearchDir.c_str());
}
CResourceManager::AddLocation(m_dataPath);
CResourceManager::SetSaveLocation(m_savePath);
CResourceManager::AddLocation(m_savePath);
GetLogger()->Debug("Finished initalizing data paths\n");
GetLogger()->Debug("PHYSFS search path is:\n");
for (const std::string& path : CResourceManager::GetLocations())
GetLogger()->Debug(" * %s\n", path.c_str());
}
void CPathManager::AddMod(const std::string &path)
{
m_mods.push_back(path);
}
std::vector<std::string> CPathManager::FindMods() const
{
std::vector<std::string> mods;
GetLogger()->Info("Found mods:\n");
for (const auto &searchPath : m_modSearchDirs)
{
for (const auto &modPath : FindModsInDir(searchPath))
{
GetLogger()->Info(" * %s\n", modPath.c_str());
mods.push_back(modPath);
}
}
GetLogger()->Info("Additional mod paths:\n");
for (const auto& modPath : m_mods)
{
if (std::filesystem::exists(modPath))
{
GetLogger()->Info(" * %s\n", modPath.c_str());
mods.push_back(modPath);
}
else
{
GetLogger()->Warn("Mod does not exist: %s\n", modPath.c_str());
}
}
return mods;
}
void CPathManager::AddModSearchDir(const std::string &modSearchDirPath)
{
m_modSearchDirs.push_back(modSearchDirPath);
}
std::vector<std::string> CPathManager::FindModsInDir(const std::string &dir) const
{
std::vector<std::string> ret;
try
{
std::filesystem::directory_iterator iterator(std::filesystem::u8path(dir));
for(; iterator != std::filesystem::directory_iterator(); ++iterator)
{
ret.push_back(iterator->path().u8string());
}
}
catch (std::exception &e)
{
GetLogger()->Warn("Unable to load mods from directory '%s': %s\n", dir.c_str(), e.what());
}
return ret;
}

View File

@ -1,157 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
/**
* \file common/error.h
* \brief Definition of the Error enum
*/
/**
* \enum Error
* \brief Type of error or info message
*/
enum Error
{
ERR_OK = 0, //!< ok
ERR_UNKNOWN = 1, //!< any error
ERR_CONTINUE = 2, //!< continues
ERR_STOP = 3, //!< stops
ERR_CMD = 4, //!< unknown command
ERR_OBJ_BUSY = 5, //!< object is busy
ERR_MANIP_FLY = 101, //!< impossible in flight
ERR_MANIP_BUSY = 102, //!< taking: hands already occupied
ERR_MANIP_NIL = 103, //!< taking: nothing has to take
ERR_MANIP_MOTOR = 105, //!< busy: impossible to move
ERR_MANIP_OCC = 106, //!< busy: location already occupied
ERR_MANIP_RADIO = 108, //!< impossible because radioactive
ERR_MANIP_WATER = 109, //!< not possible under water
ERR_MANIP_EMPTY = 110, //!< nothing to deposit
ERR_BUILD_FLY = 120, //!< not possible in flight
ERR_BUILD_WATER = 121, //!< not possible under water
ERR_BUILD_METALAWAY = 123, //!< lack of metal (too far)
ERR_BUILD_METALNEAR = 124, //!< lack of metal (too close)
ERR_BUILD_METALINEX = 125, //!< lack of metal
ERR_BUILD_FLAT = 126, //!< not enough flat ground
ERR_BUILD_FLATLIT = 127, //!< not enough flat ground space
ERR_BUILD_BUSY = 128, //!< location occupied
ERR_BUILD_BASE = 129, //!< too close to the rocket
ERR_BUILD_NARROW = 130, //!< buildings too close
ERR_BUILD_MOTOR = 131, //!< built: not possible in movement
ERR_BUILD_DISABLED = 132, //!< built: can not produce this object in this mission
ERR_BUILD_RESEARCH = 133, //!< built: can not produce not researched object
ERR_SEARCH_FLY = 140, //!< not possible in flight
ERR_SEARCH_MOTOR = 142, //!< impossible in movement
ERR_TERRA_ENERGY = 151, //!< not enough energy
ERR_FIRE_ENERGY = 161, //!< not enough energy
ERR_RECOVER_ENERGY = 171, //!< not enough energy
ERR_RECOVER_NULL = 172, //!< lack of ruin
ERR_CONVERT_EMPTY = 180, //!< no stone was transformed
ERR_SHIELD_ENERGY = 191, //!< not enough energy
ERR_MOVE_IMPOSSIBLE = 200, //!< move impossible
ERR_GOTO_IMPOSSIBLE = 210, //!< goto impossible
ERR_GOTO_ITER = 211, //!< goto too complicated
ERR_GOTO_BUSY = 212, //!< goto destination occupied
ERR_DERRICK_NULL = 300, //!< no ore underground
ERR_STATION_NULL = 301, //!< no energy underground
ERR_TOWER_POWER = 310, //!< no battery
ERR_TOWER_ENERGY = 311, //!< more energy
ERR_RESEARCH_POWER = 320, //!< no battery
ERR_RESEARCH_ENERGY = 321, //!< more energy
ERR_RESEARCH_TYPE = 322, //!< the wrong type of battery
ERR_RESEARCH_ALREADY = 323, //!< research already done
ERR_ENERGY_NULL = 330, //!< no energy underground
ERR_ENERGY_LOW = 331, //!< not enough energy
ERR_ENERGY_EMPTY = 332, //!< lack of metal
ERR_ENERGY_BAD = 333, //!< transforms only the metal
ERR_BASE_DLOCK = 340, //!< doors locked
ERR_BASE_DHUMAN = 341, //!< you must be on spaceship
ERR_LABO_NULL = 350, //!< nothing to analyze
ERR_LABO_BAD = 351, //!< analyzes only organic ball
ERR_LABO_ALREADY = 352, //!< analysis already made
ERR_NUCLEAR_EMPTY = 362, //!< lack of uranium
ERR_NUCLEAR_BAD = 363, //!< transforms only uranium
ERR_FACTORY_NULL = 370, //!< no metal
ERR_FACTORY_NEAR = 371, //!< vehicle too close
ERR_INFO_NULL = 390, //!< no information terminal
ERR_VEH_VIRUS = 400, //!< vehicle infected by a virus
ERR_BAT_VIRUS = 401, //!< building infected by a virus
ERR_DESTROY_NOTFOUND = 410, //!< not found anything to destroy
ERR_WRONG_OBJ = 420, //!< inappropriate vehicle
ERR_VEH_POWER = 500, //!< no battery
ERR_VEH_ENERGY = 501, //!< more energy
ERR_FLAG_FLY = 510, //!< impossible in flight
ERR_FLAG_WATER = 511, //!< impossible during swimming
ERR_FLAG_MOTOR = 512, //!< impossible in movement
ERR_FLAG_BUSY = 513, //!< taking: already creating flag
ERR_FLAG_CREATE = 514, //!< too many flags
ERR_FLAG_PROXY = 515, //!< too close
ERR_FLAG_DELETE = 516, //!< nothing to remove
ERR_MISSION_NOTERM = 600, //!< Mission not completed
ERR_DELETEMOBILE = 700, //!< vehicle destroyed
ERR_DELETEBUILDING = 701, //!< building destroyed
ERR_ENEMY_OBJECT = 703, //!< can't control enemy object
ERR_OBLIGATORYTOKEN = 800, //!< compulsory instruction missing
ERR_PROHIBITEDTOKEN = 801, //!< instruction prohibited
ERR_AIM_IMPOSSIBLE = 900, //!< cannot aim at specified angle(s)
ERR_WRONG_BOT = 910, //!< inappropriate bot
ERR_NO_QUICK_SLOT = 920, //!< quicksave slot not found
INFO_FIRST = 10000, //! < first information
INFO_BUILD = 10001, //! < construction builded
INFO_CONVERT = 10002, //! < metal available
INFO_RESEARCH = 10003, //! < search ended
INFO_FACTORY = 10004, //! < vehicle manufactured
INFO_LABO = 10005, //! < analysis ended
INFO_ENERGY = 10006, //! < battery available
INFO_NUCLEAR = 10007, //! < nuclear battery available
INFO_FINDING = 10008, //! < useful object found
INFO_MARKPOWER = 10020, //! < location for station found
INFO_MARKURANIUM = 10021, //! < location for derrick found
INFO_MARKSTONE = 10022, //! < location for derrick found
INFO_MARKKEYa = 10023, //! < location for derrick found
INFO_MARKKEYb = 10024, //! < location for derrick found
INFO_MARKKEYc = 10025, //! < location for derrick found
INFO_MARKKEYd = 10026, //! < location for derrick found
INFO_RESEARCHTANK = 10030, //! < research ended
INFO_RESEARCHFLY = 10031, //! < research ended
INFO_RESEARCHTHUMP = 10032, //! < research ended
INFO_RESEARCHCANON = 10033, //! < research ended
INFO_RESEARCHTOWER = 10034, //! < research ended
INFO_RESEARCHPHAZER = 10035, //! < research ended
INFO_RESEARCHSHIELD = 10036, //! < research ended
INFO_RESEARCHATOMIC = 10037, //! < research ended
INFO_RESEARCHBUILDER = 10038, //! < research ended
INFO_WIN = 10040, //! < win
INFO_LOST = 10041, //! < lost
INFO_LOSTq = 10042, //! < lost immediately
INFO_WRITEOK = 10043, //! < record done
INFO_DELETEMOTHER = 10100, //! < insect killed
INFO_DELETEANT = 10101, //! < insect killed
INFO_DELETEBEE = 10102, //! < insect killed
INFO_DELETEWORM = 10103, //! < insect killed
INFO_DELETESPIDER = 10104, //! < insect killed
INFO_BEGINSATCOM = 10105, //! < use your SatCom
INFO_TEAM_FINISH = 10110,
INFO_TEAM_DEAD = 10111,
INFO_TEAM_SCORE = 10112,
ERR_MAX //! < number of values
};

View File

@ -1,89 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "common/font_loader.h"
#include "common/logger.h"
#include "common/stringutils.h"
#include "common/resources/inputstream.h"
#include "common/resources/outputstream.h"
#include "common/system/system.h"
#include "graphics/engine/text.h"
#include <map>
#include <memory>
#include <utility>
#include <cstring>
CFontLoader::CFontLoader()
{
}
CFontLoader::~CFontLoader()
{
}
bool CFontLoader::Init()
{
try
{
std::unique_ptr<std::istream> stream;
auto inputStream = std::make_unique<CInputStream>("/fonts/fonts.ini");
bool good = inputStream->is_open();
stream = std::move(inputStream);
if (good)
{
std::string line;
while (std::getline(*stream, line))
{
auto parts = StrUtils::Split(line, " =");
m_fonts[parts[0]] = parts[1];
}
GetLogger()->Debug("Fonts config file loaded correctly. \n");
}
else
{
return false;
}
}
catch (std::exception & e)
{
GetLogger()->Error("Error on parsing config file: %s\n", e.what());
return false;
}
return true;
}
std::optional<std::string> CFontLoader::GetFont(Gfx::FontType type) const
{
auto iterator = m_fonts.find(ToString(type));
if (iterator == m_fonts.end())
return std::nullopt;
else
return std::string("/fonts/") + iterator->second;
}

View File

@ -1,60 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file common/font_loader.h
* \brief Class for loading fonts from /data/fonts/fonts.ini
*/
#pragma once
#include "common/singleton.h"
#include "graphics/engine/text.h"
#include <string>
#include <optional>
#include <unordered_map>
/**
* \class CFontLoader
*
* \brief Class for loading config file
*
*/
class CFontLoader
{
public:
CFontLoader();
virtual ~CFontLoader();
/** Loads fonts.ini
* \return return true on success
*/
bool Init();
/** Reads given font path from file
* \return return path to font file if font type is configured
*/
std::optional<std::string> GetFont(Gfx::FontType type) const;
private:
std::unordered_map<std::string, std::string> m_fonts;
};

View File

@ -1,88 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "common/profiler.h"
#include "common/system/system.h"
#include <cassert>
using TimeUtils::TimeStamp;
CSystemUtils* CProfiler::m_systemUtils = nullptr;
long long CProfiler::m_performanceCounters[PCNT_MAX] = {0};
long long CProfiler::m_prevPerformanceCounters[PCNT_MAX] = {0};
std::stack<TimeStamp> CProfiler::m_runningPerformanceCounters;
std::stack<PerformanceCounter> CProfiler::m_runningPerformanceCountersType;
void CProfiler::SetSystemUtils(CSystemUtils* systemUtils)
{
m_systemUtils = systemUtils;
}
void CProfiler::StartPerformanceCounter(PerformanceCounter counter)
{
if (counter == PCNT_ALL)
ResetPerformanceCounters();
TimeStamp timeStamp = m_systemUtils->GetCurrentTimeStamp();
m_runningPerformanceCounters.push(timeStamp);
m_runningPerformanceCountersType.push(counter);
}
void CProfiler::StopPerformanceCounter(PerformanceCounter counter)
{
assert(m_runningPerformanceCountersType.top() == counter);
m_runningPerformanceCountersType.pop();
TimeStamp timeStamp = m_systemUtils->GetCurrentTimeStamp();
m_performanceCounters[counter] += TimeUtils::ExactDiff(m_runningPerformanceCounters.top(), timeStamp);
m_runningPerformanceCounters.pop();
if (counter == PCNT_ALL)
SavePerformanceCounters();
}
long long CProfiler::GetPerformanceCounterTime(PerformanceCounter counter)
{
return m_prevPerformanceCounters[counter];
}
float CProfiler::GetPerformanceCounterFraction(PerformanceCounter counter)
{
return static_cast<float>(m_prevPerformanceCounters[counter]) / static_cast<float>(m_prevPerformanceCounters[PCNT_ALL]);
}
void CProfiler::ResetPerformanceCounters()
{
for (int i = 0; i < PCNT_MAX; ++i)
{
m_performanceCounters[i] = 0;
}
}
void CProfiler::SavePerformanceCounters()
{
assert(m_runningPerformanceCounters.empty());
for (int i = 0; i < PCNT_MAX; ++i)
{
m_prevPerformanceCounters[i] = m_performanceCounters[i];
}
}

View File

@ -1,80 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
class CSystemUtils;
#include "common/system/system.h"
#include <stack>
/**
* \enum PerformanceCounter
* \brief Type of counter testing performance
*/
enum PerformanceCounter
{
PCNT_EVENT_PROCESSING, //! < event processing (except update events)
PCNT_UPDATE_ALL, //! < the whole frame update process
PCNT_UPDATE_ENGINE, //! < frame update in CEngine
PCNT_UPDATE_PARTICLE, //! < frame update in CParticle
PCNT_UPDATE_GAME, //! < frame update in CRobotMain
PCNT_UPDATE_CBOT, //! < running CBot code (part of CRobotMain update)
PCNT_RENDER_ALL, //! < the whole rendering process
PCNT_RENDER_PARTICLE_WORLD, //! < rendering the particles in 3D
PCNT_RENDER_PARTICLE_IFACE, //! < rendering the particles in 2D interface
PCNT_RENDER_WATER, //! < rendering the water
PCNT_RENDER_TERRAIN, //! < rendering the terrain
PCNT_RENDER_OBJECTS, //! < rendering the 3D objects
PCNT_RENDER_INTERFACE, //! < rendering 2D interface
PCNT_RENDER_SHADOW_MAP, //! < rendering shadow map
PCNT_SWAP_BUFFERS, //! < swapping buffers and vsync
PCNT_ALL, //! < all counters together
PCNT_MAX
};
class CProfiler
{
public:
static void SetSystemUtils(CSystemUtils* systemUtils);
static void StartPerformanceCounter(PerformanceCounter counter);
static void StopPerformanceCounter(PerformanceCounter counter);
static long long GetPerformanceCounterTime(PerformanceCounter counter);
static float GetPerformanceCounterFraction(PerformanceCounter counter);
private:
static void ResetPerformanceCounters();
static void SavePerformanceCounters();
private:
static CSystemUtils* m_systemUtils;
static long long m_performanceCounters[PCNT_MAX];
static long long m_prevPerformanceCounters[PCNT_MAX];
static std::stack<TimeUtils::TimeStamp> m_runningPerformanceCounters;
static std::stack<PerformanceCounter> m_runningPerformanceCountersType;
};

View File

@ -1,81 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include <condition_variable>
#include <functional>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
/**
* \class CWorkerThread
* \brief Thread that runs functions, one at a time
*/
class CWorkerThread
{
public:
using ThreadFunctionPtr = std::function<void()>;
public:
CWorkerThread() : m_thread{&CWorkerThread::Run, this} {}
~CWorkerThread()
{
{
std::lock_guard<std::mutex> lock{m_mutex};
m_running = false;
m_cond.notify_one();
}
m_thread.join();
}
void Start(ThreadFunctionPtr&& func)
{
std::lock_guard<std::mutex> lock{m_mutex};
m_queue.push(func);
m_cond.notify_one();
}
CWorkerThread(const CWorkerThread&) = delete;
CWorkerThread& operator=(const CWorkerThread&) = delete;
private:
void Run()
{
auto lock = std::unique_lock<std::mutex>(m_mutex);
while (true)
{
m_cond.wait(lock, [&]() { return !m_running || !m_queue.empty(); });
if (!m_running) break;
ThreadFunctionPtr func = std::move(m_queue.front());
m_queue.pop();
func();
}
}
std::thread m_thread;
std::mutex m_mutex;
std::condition_variable m_cond;
bool m_running = true;
std::queue<ThreadFunctionPtr> m_queue;
};

View File

@ -1,54 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "common/timeutils.h"
#include <cassert>
namespace TimeUtils
{
TimeStamp Lerp(TimeStamp a, TimeStamp b, float t)
{
return a + std::chrono::duration_cast<TimeStamp::duration>((b - a) * t);
}
float Diff(TimeStamp before, TimeStamp after, TimeUnit unit)
{
long long exact = ExactDiff(before, after);
float result = 0.0f;
if (unit == TimeUnit::SECONDS)
result = exact * 1e-9;
else if (unit == TimeUnit::MILLISECONDS)
result = exact * 1e-6;
else if (unit == TimeUnit::MICROSECONDS)
result = exact * 1e-3;
else
assert(false);
return result;
}
long long ExactDiff(TimeStamp before, TimeStamp after)
{
return std::chrono::duration_cast<std::chrono::nanoseconds>(after - before).count();
}
} // namespace TimeUtils

View File

@ -1,50 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file common/timeutils.h
* \brief Some useful cross-platform operations on timestamps
*/
#include <chrono>
namespace TimeUtils
{
enum class TimeUnit
{
SECONDS,
MILLISECONDS,
MICROSECONDS
};
using TimeStamp = std::chrono::time_point<std::chrono::high_resolution_clock>;
//! Linearly interpolates between two timestamps.
TimeStamp Lerp(TimeStamp a, TimeStamp b, float t);
//! Returns a difference between two timestamps in given time unit
/** The difference is \a after - \a before. */
float Diff(TimeStamp before, TimeStamp after, TimeUnit unit = TimeUnit::SECONDS);
//! Returns the exact (in nanosecond units) difference between two timestamps
/** The difference is \a after - \a before. */
long long ExactDiff(TimeStamp before, TimeStamp after);
} // namespace TimeUtils

View File

@ -1,14 +0,0 @@
#pragma once
#include <string_view>
namespace Version
{
static inline constexpr bool OFFICIAL_BUILD = @OFFICIAL_COLOBOT_BUILD@;
static inline constexpr bool DEVELOPMENT_BUILD = @DEVELOPMENT_COLOBOT_BUILD@;
static inline constexpr int BUILD_NUMBER = @BUILD_NUMBER@;
static inline constexpr char FULL_NAME[] = "Colobot: Gold Edition @COLOBOT_VERSION_FULL@";
static inline constexpr char VERSION[] = "@CMAKE_PROJECT_VERSION@";
static inline constexpr char VERSION_DISPLAY[] = "@COLOBOT_VERSION_DISPLAY@";
}

View File

@ -1,58 +0,0 @@
/**
* \dir src/graphics
* \brief Graphics engine
*/
/**
* \namespace Gfx
* \brief Namespace for (new) graphics code
*
* This namespace was created to avoid clashing with old code, but now it still serves,
* defining a border between pure graphics engine and other parts of application.
*/
/**
* \page graphics Graphics engine
*
* The graphics engine consists of 3 parts:
* * core - low-level device code (currently with only OpenGL implementation)
* * main engine - managing and displaying 3D environment (terrain, models, water, sky, effects, camera, etc.)
* * 2D interface - classes drawing the 2D interface (menus, buttons, editor, HUD elements)
*
* \section coords Drawing coordinates
*
* \subsection coords2d 2D interface
*
* 2D interface is drawn by setting orthogonal projection yielding the following 2D coordinate system:
*
* \image html 2d_coord.png
*
* Depth test is disabled for 2D interface, so Z coordinates are irrelevant.
*
* The coordinate system is constant and is independent of resolution or screen proportions.
*
* UI elements are laid out by computing these standard coordinates, using 640x480 resoultion as reference.
* That is, their coordinates are computed like so: x = 32.0f/640.0f, y = 400.0f/480.0f.
*
* \subsection coords3d 3D environment
*
* 3D environment is drawn using the following coordinate system:
*
* \image html 3d_canonical_coords.png
*
* The base coordinate system is like depicted above with viewport on Z=0 plane.
* The coordinates are then transformed by world, view and projection matrices to yield screen coordinates.
*
* The base coordinates are also model coordinates. All models must be modelled in this setup.
* Scale should be kept proportional to existing models.
*
* The world matrix defines the transformation from model coordinate system to the point and orientation
* in 3D scene. This matrix is defined one per every <i>graphics engine</i> object.
* (Note the emphasis - the objects as defined in game engine do not necessarily correspond to
* one graphics engine object.)
*
* The view and projection matrices define the viewing point and volume, and are mostly managed by Gfx::CCamera.
* View is defined by Math::LoadViewMatrix() function, that is using 3 vectors: eye position (eyePt),
* target point (lookatPt) and up vector (upVec). Projection is always perspective,
* with changing view angle (focus).
*/

View File

@ -1,395 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/core/device.h
* \brief Abstract graphics device - CDevice class and related structs/enums
*/
#pragma once
#include "graphics/core/color.h"
#include "graphics/core/texture.h"
#include "graphics/core/vertex.h"
#include <glm/glm.hpp>
#include <memory>
#include <string>
#include <vector>
class CImage;
struct ImageData;
// Graphics module namespace
namespace Gfx
{
class CFramebuffer;
class CUIRenderer;
class CTerrainRenderer;
class CShadowRenderer;
class CObjectRenderer;
class CParticleRenderer;
struct FramebufferParams;
struct Light;
struct Material;
struct Vertex;
struct VertexCol;
struct Vertex3D;
enum class CullFace : unsigned char;
enum class PrimitiveType : unsigned char;
enum class TransparencyMode : unsigned char;
/**
* \struct DeviceConfig
* \brief General config for graphics device
*
* These settings are common window options set by SDL.
*/
struct DeviceConfig
{
//! Screen size
glm::ivec2 size = { 800, 600 };
//! Bits per pixel
int bpp = 32;
//! Full screen
bool fullScreen = false;
//! Resizeable window
bool resizeable = true;
//! Double buffering
bool doubleBuf = true;
//! No window frame (also set with full screen)
bool noFrame = false;
//! Size of red channel in bits
int redSize = 8;
//! Size of green channel in bits
int greenSize = 8;
//! Size of blue channel in bits
int blueSize = 8;
//! Size of alpha channel in bits
int alphaSize = 8;
//! Color depth in bits
int depthSize = 24;
//! Stencil depth in bits
int stencilSize = 8;
//! Force hardware acceleration (video mode set will fail on lack of hw accel)
bool hardwareAccel = true;
//! Loads the default values
void LoadDefault()
{
*this = DeviceConfig();
}
};
/**
* \struct DeviceCapabilities
* \brief This structs contains various capabilities of graphics device
*/
struct DeviceCapabilities
{
bool multitexturingSupported = false;
int maxTextures = 1;
int maxTextureSize = 1024;
int maxLights = 8;
bool shadowMappingSupported = false;
bool framebufferSupported = false;
int maxRenderbufferSize = 0;
bool anisotropySupported = false;
int maxAnisotropy = 1;
bool multisamplingSupported = false;
int maxSamples = 1;
};
/**
* \enum FillMode
* \brief Polygon fill mode
*/
enum class FillMode : unsigned char
{
//! Draw only points
POINT,
//! Draw only lines
LINES,
//! Draw full polygons
POLY
};
/**
* \enum FrustumPlane
* \brief Planes of frustum space
*
* Bitset of flags - can be OR'd together.
*/
enum FrustumPlane
{
FRUSTUM_PLANE_LEFT = 0x01,
FRUSTUM_PLANE_RIGHT = 0x02,
FRUSTUM_PLANE_TOP = 0x04,
FRUSTUM_PLANE_BOTTOM = 0x08,
FRUSTUM_PLANE_FRONT = 0x10,
FRUSTUM_PLANE_BACK = 0x20,
FRUSTUM_PLANE_ALL = FRUSTUM_PLANE_LEFT | FRUSTUM_PLANE_RIGHT |
FRUSTUM_PLANE_TOP | FRUSTUM_PLANE_BOTTOM |
FRUSTUM_PLANE_FRONT | FRUSTUM_PLANE_BACK
};
class CFrameBufferPixels
{
public:
virtual ~CFrameBufferPixels() {}
virtual void* GetPixelsData() = 0;
};
class CVertexBuffer
{
protected:
PrimitiveType m_type;
std::vector<Vertex3D> m_data;
public:
CVertexBuffer(PrimitiveType type, size_t size)
: m_type(type), m_data(size, Vertex3D{})
{
}
virtual ~CVertexBuffer()
{
}
virtual void Update() = 0;
PrimitiveType GetType() const
{
return m_type;
}
void SetType(PrimitiveType type)
{
m_type = type;
}
size_t Size() const
{
return m_data.size();
}
void Resize(size_t size)
{
m_data.resize(size);
}
Vertex3D& operator[](size_t index)
{
return m_data[index];
}
const Vertex3D& operator[](size_t index) const
{
return m_data[index];
}
void SetData(const Vertex3D* data, size_t offset, size_t count)
{
std::copy(data, data + count, m_data.data() + offset);
}
auto Data()
{
return m_data.data();
}
auto Data() const
{
return m_data.data();
}
auto begin()
{
return m_data.begin();
}
auto end()
{
return m_data.end();
}
auto begin() const
{
return m_data.begin();
}
auto end() const
{
return m_data.end();
}
};
/**
* \class CDevice
* \brief Abstract interface of graphics device
*
* It is based on DIRECT3DDEVICE class from DirectX to make it easier to port existing code.
* It encapsulates the general graphics device state and provides a common interface
* to graphics-specific functions which will be used throughout the program,
* both in CEngine class and in UI classes. Note that it doesn't contain all functions from DirectX,
* only those that were used in old code.
*
*/
class CDevice
{
protected:
std::string m_errorMessage;
//! Capabilities of this device
//! Should only be changed by code in concrete device implementation
DeviceCapabilities m_capabilities;
public:
virtual ~CDevice() {}
//! Returns last error message or empty string
inline std::string GetError()
{
return m_errorMessage;
}
//! Returns device capabilities
const DeviceCapabilities& GetCapabilities()
{
return m_capabilities;
}
//! Returns a name of this device
virtual std::string GetName() = 0;
//! Initializes the device, setting the initial state
virtual bool Create() = 0;
//! Destroys the device, releasing every acquired resource
virtual void Destroy() = 0;
//! Changes configuration
virtual void ConfigChanged(const DeviceConfig &newConfig) = 0;
//! Begins drawing the 3D scene
virtual void BeginScene() = 0;
//! Ends drawing the 3D scene
virtual void EndScene() = 0;
//! Clears the screen to blank
virtual void Clear() = 0;
//! Returns UI renderer
virtual CUIRenderer* GetUIRenderer() = 0;
//! Returns terrain renderer
virtual CTerrainRenderer* GetTerrainRenderer() = 0;
//! Returns object renderer
virtual CObjectRenderer* GetObjectRenderer() = 0;
//! Returns particle renderer
virtual CParticleRenderer* GetParticleRenderer() = 0;
//! Returns shadow renderer
virtual CShadowRenderer* GetShadowRenderer() = 0;
//! Creates a texture from image; the image can be safely removed after that
virtual Texture CreateTexture(CImage *image, const TextureCreateParams &params) = 0;
//! Creates a texture from raw image data; image data can be freed after that
virtual Texture CreateTexture(ImageData *data, const TextureCreateParams &params) = 0;
//! Creates a depth texture with specific dimensions and depth
virtual Texture CreateDepthTexture(int width, int height, int depth) = 0;
//! Updates a part of texture from raw image data
virtual void UpdateTexture(const Texture& texture, const glm::ivec2& offset, ImageData* data, TextureFormat format) = 0;
//! Deletes a given texture, freeing it from video memory
virtual void DestroyTexture(const Texture &texture) = 0;
//! Deletes all textures created so far
virtual void DestroyAllTextures() = 0;
virtual CVertexBuffer* CreateVertexBuffer(PrimitiveType primitiveType, const Vertex3D* vertices, int vertexCount) = 0;
virtual void DestroyVertexBuffer(CVertexBuffer*) = 0;
//! Changes rendering viewport
virtual void SetViewport(int x, int y, int width, int height) = 0;
//! Sets depth test
virtual void SetDepthTest(bool enabled) = 0;
//! Sets depth mask
virtual void SetDepthMask(bool enabled) = 0;
//! Sets which faces to cull
virtual void SetCullFace(CullFace mode) = 0;
//! Sets transparency mode
virtual void SetTransparency(TransparencyMode mode) = 0;
//! Sets the color mask
virtual void SetColorMask(bool red, bool green, bool blue, bool alpha) = 0;
//! Sets the clear color
virtual void SetClearColor(const Color &color) = 0;
//! Copies content of framebuffer to texture
virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) = 0;
//! Returns the pixels of the entire screen
virtual std::unique_ptr<CFrameBufferPixels> GetFrameBufferPixels() const = 0;
//! Returns framebuffer with given name or nullptr if it doesn't exist
virtual CFramebuffer* GetFramebuffer(std::string name) = 0;
//! Creates new framebuffer with given name or nullptr if it's not possible
virtual CFramebuffer* CreateFramebuffer(std::string name, const FramebufferParams& params) = 0;
//! Deletes framebuffer
virtual void DeleteFramebuffer(std::string name) = 0;
//! Checks if anisotropy is supported
virtual bool IsAnisotropySupported() = 0;
//! Returns max anisotropy level supported
virtual int GetMaxAnisotropyLevel() = 0;
//! Returns max samples supported
virtual int GetMaxSamples() = 0;
//! Checks if shadow mapping is supported
virtual bool IsShadowMappingSupported() = 0;
//! Returns max texture size supported
virtual int GetMaxTextureSize() = 0;
//! Checks if framebuffers are supported
virtual bool IsFramebufferSupported() = 0;
};
} // namespace Gfx

View File

@ -1,114 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/core/material.h
* \brief Material struct
*/
#pragma once
#include "graphics/core/color.h"
#include "graphics/core/transparency.h"
// Graphics module namespace
namespace Gfx
{
/**
* \enum CullFace
* \brief Specifies which faces to cull while rendering polygons
*/
enum class CullFace : unsigned char
{
NONE,
BACK,
FRONT,
BOTH,
};
//! PBR material
struct Material
{
//! Albedo color
Color albedoColor = Color{ 1.0f, 1.0f, 1.0f, 1.0f };
//! Albedo texture
std::string albedoTexture = "";
//! Roughness
float roughness = 1.0;
//! Metalness
float metalness = 0.0;
//! AO strength
float aoStrength = 0.0;
//! AO-roughness-metalness texture
std::string materialTexture = "";
//! Emissive color
Color emissiveColor = Color{ 0.0f, 0.0f, 0.0f, 0.0f };
//! Emissive texture
std::string emissiveTexture = "";
//! Normal map
std::string normalTexture = "";
//! Alpha mode
AlphaMode alphaMode = AlphaMode::NONE;
//! Alpha threshold
float alphaThreshold = 0.5;
// Cull face
CullFace cullFace = CullFace::BACK;
// Special tag
std::string tag = "";
// Recolor name
std::string recolor = "";
// Recolor reference color
Color recolorReference = { 0.0f, 0.0f, 0.0f, 0.0f };
// Legacy functionality
//! Variable detail texture
bool variableDetail = false;
//! Detail texture
std::string detailTexture = "";
bool operator==(const Material& other) const
{
return albedoColor == other.albedoColor
&& albedoTexture == other.albedoTexture
&& roughness == other.roughness
&& metalness == other.metalness
&& materialTexture == other.materialTexture
&& emissiveColor == other.emissiveColor
&& emissiveTexture == other.emissiveTexture
&& normalTexture == other.normalTexture
&& alphaMode == other.alphaMode
&& alphaThreshold == other.alphaThreshold
&& cullFace == other.cullFace
&& tag == other.tag
&& recolor == other.recolor
&& recolorReference == other.recolorReference
&& variableDetail == other.variableDetail
&& detailTexture == other.detailTexture;
}
bool operator!=(const Material& other) const
{
return !operator==(other);
}
};
} // namespace Gfx

View File

@ -1,293 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/core/renderers.h
* \brief Abstract classes representing renderers
*/
#pragma once
#include <glm/glm.hpp>
// Graphics module namespace
namespace Gfx
{
class CVertexBuffer;
enum class CullFace : unsigned char;
enum class TransparencyMode : unsigned char;
struct Color;
struct Texture;
struct Vertex2D;
struct Vertex3D;
struct VertexParticle;
/**
* \enum PrimitiveType
* \brief Type of primitive to render
*/
enum class PrimitiveType : unsigned char
{
POINTS,
LINES,
LINE_STRIP,
LINE_LOOP,
TRIANGLES,
TRIANGLE_STRIP,
TRIANGLE_FAN,
};
struct ShadowParam
{
glm::mat4 matrix;
glm::vec2 uv_offset;
glm::vec2 uv_scale;
};
/**
* \class CRenderer
* \brief Common abstract interface for renderers
*/
class CRenderer
{
public:
virtual ~CRenderer() { }
};
/**
* \class CUIRenderer
* \brief Abstract interface for UI renderers
*/
class CUIRenderer : public CRenderer
{
public:
virtual ~CUIRenderer() { }
//! Sets ortographic projection with given parameters
virtual void SetProjection(float left, float right, float bottom, float top) = 0;
//! Sets texture, setting texture 0 means using white texture
virtual void SetTexture(const Texture& texture) = 0;
//! Sets color
virtual void SetColor(const glm::vec4& color) = 0;
//! Sets transparency mode
virtual void SetTransparency(TransparencyMode mode) = 0;
virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) = 0;
virtual Vertex2D* BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) = 0;
virtual bool EndPrimitive() = 0;
};
/**
* \class CTerrainRenderer
* \brief Abstract interface for terrain renderers
*/
class CTerrainRenderer : public CRenderer
{
public:
virtual ~CTerrainRenderer() { }
virtual void Begin() = 0;
virtual void End() = 0;
//! Sets projection matrix
virtual void SetProjectionMatrix(const glm::mat4& matrix) = 0;
//! Sets view matrix
virtual void SetViewMatrix(const glm::mat4& matrix) = 0;
//! Sets model matrix
virtual void SetModelMatrix(const glm::mat4& matrix) = 0;
//! Sets albedo color
virtual void SetAlbedoColor(const Color& color) = 0;
//! Sets albedo texture
virtual void SetAlbedoTexture(const Texture& texture) = 0;
//! Sets emissive color
virtual void SetEmissiveColor(const Color& color) = 0;
//! Sets emissive texture
virtual void SetEmissiveTexture(const Texture& texture) = 0;
//! Sets material parameters
virtual void SetMaterialParams(float roughness, float metalness, float aoStrength) = 0;
//! Sets material texture
virtual void SetMaterialTexture(const Texture& texture) = 0;
//! Sets detail texture
virtual void SetDetailTexture(const Texture& texture) = 0;
//! Sets shadow map
virtual void SetShadowMap(const Texture& texture) = 0;
//! Sets light parameters
virtual void SetLight(const glm::vec4& position, const float& intensity, const glm::vec3& color) = 0;
//! Sets sky parameters
virtual void SetSky(const Color& color, float intensity) = 0;
//! Sets shadow parameters
virtual void SetShadowParams(int count, const ShadowParam* params) = 0;
//! Sets fog parameters
virtual void SetFog(float min, float max, const glm::vec3& color) = 0;
//! Draws terrain object
virtual void DrawObject(const glm::mat4& matrix, const CVertexBuffer* buffer) = 0;
};
/**
* \class CObjectRenderer
* \brief Abstract interface for object renderers
*/
class CObjectRenderer : public CRenderer
{
public:
virtual ~CObjectRenderer() { }
virtual void Begin() = 0;
virtual void End() = 0;
//! Sets projection matrix
virtual void SetProjectionMatrix(const glm::mat4& matrix) = 0;
//! Sets view matrix
virtual void SetViewMatrix(const glm::mat4& matrix) = 0;
//! Sets model matrix
virtual void SetModelMatrix(const glm::mat4& matrix) = 0;
//! Sets albedo color
virtual void SetAlbedoColor(const Color& color) = 0;
//! Sets albedo texture
virtual void SetAlbedoTexture(const Texture& texture) = 0;
//! Sets emissive color
virtual void SetEmissiveColor(const Color& color) = 0;
//! Sets emissive texture
virtual void SetEmissiveTexture(const Texture& texture) = 0;
//! Sets material parameters
virtual void SetMaterialParams(float roughness, float metalness, float aoStrength) = 0;
//! Sets material texture
virtual void SetMaterialTexture(const Texture& texture) = 0;
//! Sets detail texture
virtual void SetDetailTexture(const Texture& texture) = 0;
//! Sets shadow map
virtual void SetShadowMap(const Texture& texture) = 0;
//! Enables lighting
virtual void SetLighting(bool enabled) = 0;
//! Sets light parameters
virtual void SetLight(const glm::vec4& position, const float& intensity, const glm::vec3& color) = 0;
//! Sets sky parameters
virtual void SetSky(const Color& color, float intensity) = 0;
//! Sets shadow parameters
virtual void SetShadowParams(int count, const ShadowParam* params) = 0;
//! Sets fog parameters
virtual void SetFog(float min, float max, const glm::vec3& color) = 0;
//! Sets alpha scissor
virtual void SetAlphaScissor(float alpha) = 0;
//! Sets recolor parameters
virtual void SetRecolor(bool enabled, const glm::vec3& from = {}, const glm::vec3& to = {}, float threshold = {}) = 0;
//! Sets depth test
virtual void SetDepthTest(bool enabled) = 0;
//! Sets depth mask
virtual void SetDepthMask(bool enabled) = 0;
//! Sets cull face mode
virtual void SetCullFace(CullFace mode) = 0;
//! Sets transparency mode
virtual void SetTransparency(TransparencyMode mode) = 0;
//! Sets UV transform
virtual void SetUVTransform(const glm::vec2& offset, const glm::vec2& scale) = 0;
//! Sets triplanar mode
virtual void SetTriplanarMode(bool enabled) = 0;
//! Sets triplanar scale
virtual void SetTriplanarScale(float scale) = 0;
//! Draws an object
virtual void DrawObject(const CVertexBuffer* buffer) = 0;
//! Draws a primitive
virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex3D* vertices) = 0;
//! Draws a set of primitives
virtual void DrawPrimitives(PrimitiveType type, int drawCount, int count[], const Vertex3D* vertices) = 0;
};
/**
* \class CParticleRenderer
* \brief Abstract interface for particle renderers
*/
class CParticleRenderer : public CRenderer
{
public:
virtual ~CParticleRenderer() { }
virtual void Begin() = 0;
virtual void End() = 0;
//! Sets projection matrix
virtual void SetProjectionMatrix(const glm::mat4& matrix) = 0;
//! Sets view matrix
virtual void SetViewMatrix(const glm::mat4& matrix) = 0;
//! Sets model matrix
virtual void SetModelMatrix(const glm::mat4& matrix) = 0;
//! Sets color
virtual void SetColor(const glm::vec4& color) = 0;
//! Sets texture
virtual void SetTexture(const Texture& texture) = 0;
//! Sets transparency mode
virtual void SetTransparency(TransparencyMode mode) = 0;
//! Draws particles
virtual void DrawParticle(PrimitiveType type, int count, const VertexParticle* vertices) = 0;
};
/**
* \class CShadowRenderer
* \brief Abstract interface for shadow renderers
*/
class CShadowRenderer : public CRenderer
{
public:
virtual ~CShadowRenderer() { }
virtual void Begin() = 0;
virtual void End() = 0;
//! Sets projection matrix
virtual void SetProjectionMatrix(const glm::mat4& matrix) = 0;
//! Sets view matrix
virtual void SetViewMatrix(const glm::mat4& matrix) = 0;
//! Sets model matrix
virtual void SetModelMatrix(const glm::mat4& matrix) = 0;
//! Sets texture
virtual void SetTexture(const Texture& texture) = 0;
//! Sets shadow map
virtual void SetShadowMap(const Texture& texture) = 0;
//! Sets shadow region
virtual void SetShadowRegion(const glm::vec2& offset, const glm::vec2& scale) = 0;
//! Draws terrain object
virtual void DrawObject(const CVertexBuffer* buffer, bool transparent) = 0;
};
} // namespace Gfx

View File

@ -1,163 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/core/texture.h
* \brief Texture struct and related enums
*/
#pragma once
#include <glm/glm.hpp>
// Graphics module namespace
namespace Gfx
{
/**
* \enum TextureFormat
* \brief Format of image data
*/
enum class TextureFormat : unsigned char
{
//! Try to determine automatically (may not work)
AUTO,
//! RGB triplet, 3 bytes
RGB,
//! BGR triplet, 3 bytes
BGR,
//! RGBA triplet, 4 bytes
RGBA,
//! BGRA triplet, 4 bytes
BGRA,
};
/**
* \enum TextureFilter
* \brief General texture filtering mode
*
* Corresponds to typical options in game graphics settings.
*/
enum class TextureFilter : unsigned char
{
//! Nearest-neighbor filtering
NEAREST,
//! Linear filtering
BILINEAR,
//! Linear filtering with mipmapping
TRILINEAR,
};
/**
* \enum TexWrapMode
* \brief Wrapping mode for texture coords
*/
enum class TextureWrapMode : unsigned char
{
//! UVs are clamped to edges
CLAMP,
//! UVs are repeated
REPEAT,
};
/**
* \struct TextureCreateParams
* \brief Parameters for texture creation
*
* These params define how particular texture is created and later displayed.
* They must be specified at texture creation time and cannot be changed later.
*/
struct TextureCreateParams
{
//! Whether to generate mipmaps
bool mipmap = false;
//! Format of source image data
TextureFormat format = TextureFormat::RGB;
//! General texture filtering mode
TextureFilter filter = TextureFilter::NEAREST;
//! Wrap mode for texture coordinates
TextureWrapMode wrap = TextureWrapMode::REPEAT;
//! Pad the image to nearest power of 2 dimensions
bool padToNearestPowerOfTwo = false;
};
/**
* \struct Texture
* \brief Info about a texture
*
* Identifies (through id) a texture created in graphics engine.
* Also contains some additional data.
*/
struct Texture
{
//! ID of the texture in graphics engine; 0 = invalid texture
unsigned int id = 0;
//! Size of texture
glm::ivec2 size = { 0, 0 };
//! Original size of texture (as loaded from image)
glm::ivec2 originalSize = { 0, 0 };
//! Whether the texture has alpha channel
bool alpha = false;
//! Returns whether the texture is valid (ID != 0)
bool Valid() const
{
return id != 0;
}
//! Sets the ID to invalid value (0)
void SetInvalid()
{
id = 0;
}
//! Comparator for use in texture maps and sets
bool operator<(const Texture &other) const
{
// Invalid textures are always "less than" every other texture
if ( (! Valid()) && (! other.Valid()) )
return false;
if (! Valid())
return true;
if (! other.Valid())
return false;
return id < other.id;
}
//! Comparator
bool operator==(const Texture &other) const
{
if (Valid() != other.Valid())
return false;
if ( (! Valid()) && (! other.Valid()) )
return true;
return id == other.id;
}
};
} // namespace Gfx

View File

@ -1,48 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/core/transparency.h
* \brief Structures and functions related to transparency
*/
#pragma once
// Graphics module namespace
namespace Gfx
{
//! Transparency mode
enum class TransparencyMode : unsigned char
{
NONE,
ALPHA,
BLACK,
WHITE,
};
//! Alpha transparency mode
enum class AlphaMode : unsigned char
{
NONE, // opaque material
MASK, // alpha scissor with threshold
BLEND, // alpha blending
};
}

View File

@ -1,46 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/core/triangle.h
* \brief Triangle struct
*/
#pragma once
#include "graphics/core/material.h"
#include "graphics/core/vertex.h"
// Graphics module namespace
namespace Gfx
{
/**
* \struct EngineTriangle
* \brief A triangle drawn by the graphics engine
*/
struct EngineTriangle
{
//! Triangle vertices
Vertex3D triangle[3];
//! Triangle material
Material material;
};
} // namespace Gfx

View File

@ -1,56 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/core/type.cpp
* \brief Type support and conversion
*/
#include "graphics/core/type.h"
#include <cassert>
// Graphics module namespace
namespace Gfx
{
//! Returns size in bytes of given type
int GetTypeSize(Type type)
{
switch (type)
{
case Type::BYTE:
case Type::UBYTE:
return 1;
case Type::SHORT:
case Type::USHORT:
case Type::HALF:
return 2;
case Type::INT:
case Type::UINT:
case Type::FLOAT:
return 4;
case Type::DOUBLE:
return 8;
default:
return 0;
}
}
} // namespace Gfx

View File

@ -1,75 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/core/vertex.h
* \brief Vertex structs
*/
#pragma once
#include "graphics/core/color.h"
#include "graphics/core/type.h"
#include <sstream>
#include <cstdint>
#include <glm/glm.hpp>
// Graphics module namespace
namespace Gfx
{
/**
* \struct Vertex2D
* \brief 2D vertex for interface rendering, contains UV and color
*/
struct Vertex2D
{
glm::vec2 position = { 0.0f, 0.0f };
glm::vec2 uv = { 0.0f, 0.0f };
glm::u8vec4 color = { 255, 255, 255, 255 };
};
/**
* \struct Vertex3D
* \brief 3D vertex for 3D rendering, contains UV, color and normal
*/
struct Vertex3D
{
glm::vec3 position = { 0.0f, 0.0f, 0.0f };
glm::u8vec4 color = { 255, 255, 255, 255 };
glm::vec2 uv = { 0.0f, 0.0f };
glm::vec2 uv2 = { 0.0f, 0.0f };
glm::vec3 normal = { 0.0f, 0.0f, 1.0f };
};
/**
* \struct VertexParticle
* \brief 3D vertex for particle rendering, contains color and UV coordinates
*/
struct VertexParticle
{
glm::vec3 position = { 0.0f, 0.0f, 0.0f };
glm::u8vec4 color = { 255, 255, 255, 255 };
glm::vec2 uv = { 0.0f, 0.0f };
};
} // namespace Gfx

View File

@ -1,417 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/engine/camera.h
* \brief Camera handling - CCamera class
*/
#pragma once
#include "graphics/core/color.h"
class CObject;
class CRobotMain;
class CInput;
struct Event;
// Graphics module namespace
namespace Gfx
{
class CEngine;
class CTerrain;
class CWater;
enum class TransparencyMode : unsigned char;
/**
\enum CameraType
\brief Type of camera */
enum CameraType : unsigned char
{
//! Undefined
CAM_TYPE_NULL = 0,
//! Free camera
CAM_TYPE_FREE,
//! Camera while editing a program
CAM_TYPE_EDIT,
//! Camera on board a robot
CAM_TYPE_ONBOARD,
//! Camera behind a robot
CAM_TYPE_BACK,
//! Static camera following robot
CAM_TYPE_FIX,
//! Camera steady after explosion
CAM_TYPE_EXPLO,
//! Camera during a cutscene
CAM_TYPE_SCRIPT,
//! Visit camera, rotates around given position
CAM_TYPE_VISIT,
//! Static camera height
CAM_TYPE_PLANE,
};
enum CameraSmooth
{
//! Sharp
CAM_SMOOTH_NONE = 0,
//! Normal
CAM_SMOOTH_NORM = 1,
//! Hard
CAM_SMOOTH_HARD = 2,
};
enum CenteringPhase
{
CAM_PHASE_NULL = 0,
CAM_PHASE_START = 1,
CAM_PHASE_WAIT = 2,
CAM_PHASE_STOP = 3,
};
enum CameraEffect
{
//! No effect
CAM_EFFECT_NULL = 0,
//! Digging in
CAM_EFFECT_TERRAFORM = 1,
//! Hard landing
CAM_EFFECT_CRASH = 2,
//! Explosion
CAM_EFFECT_EXPLO = 3,
//! Shot by an enemy
CAM_EFFECT_SHOT = 4,
//! Vibration during construction
CAM_EFFECT_VIBRATION = 5,
//! Overheated reactor
CAM_EFFECT_PET = 6,
};
enum CameraOverEffect
{
//! No effect
CAM_OVER_EFFECT_NULL = 0,
//! Flash red
CAM_OVER_EFFECT_BLOOD = 1,
//! White -> nothing
CAM_OVER_EFFECT_FADEIN_WHITE = 2,
//! Nothing -> white
CAM_OVER_EFFECT_FADEOUT_WHITE = 3,
//! Nothing -> blue
CAM_OVER_EFFECT_FADEOUT_BLACK = 4,
//! Lightning
CAM_OVER_EFFECT_LIGHTNING = 5,
};
/**
\class CCamera
\brief Camera moving in 3D scene
This class manages everything related to animating the camera in 3D scene.
Calculated values are then passed to Gfx::CEngine.
*/
class CCamera
{
public:
CCamera();
~CCamera();
//! Management of an event
bool EventProcess(const Event &event);
/**
* \brief Initializes the camera
* \param eye Initial eye position
* \param lookat Initial lookat position
* \param delay Time of the initial entry animation
*/
void Init(glm::vec3 eye, glm::vec3 lookat, float delay);
//! Sets the object controlling the camera
void SetControllingObject(CObject* object);
//! Gets the object controlling the camera
CObject* GetControllingObject();
//! Change the type of camera
void SetType(CameraType type);
//! Get the type of the camera
CameraType GetType();
//! Set smoothing mode
void SetSmooth(CameraSmooth type);
//! Get smoothing mode
CameraSmooth GetSmooth();
//! Returns the current point of view of the camera
void GetCamera(glm::vec3 &eye, glm::vec3 &lookat);
//! \name Visit camera management (CAM_TYPE_VISIT) - camera in this mode shows a position, constantly rotating around it
//@{
//! Start visit camera
void StartVisit(glm::vec3 goal, float dist);
//! Stop visit camera
void StopVisit();
//@}
//! \name Camera "centering" - moves the camera to show some happening action (e.g. sniffer sniffing)
//@{
//! Move camera to show happening action
bool StartCentering(CObject *object, float angleH, float angleV, float dist, float time);
//! Go back to normal position after showing some happening action
bool StopCentering(CObject *object, float time);
//! Abort centering animation in the current position
void AbortCentering();
//@}
//! \name Camera shake effects
//@{
//! Starts a camera shake effect
void StartEffect(CameraEffect effect, glm::vec3 pos, float force);
//! Removes the camera shake effect
void FlushEffect();
//@}
//! \name Camera overlay effects
//@{
//! Starts camera overlay effect
void StartOver(CameraOverEffect effect, glm::vec3 pos, float force);
//! Removes camera overlay effect
void FlushOver();
//! Specifies camera overlay effect base color
void SetOverBaseColor(Color color);
//@}
//! \name Script camera - cutscenes controlled by external code
//@{
//! Script camera: Set camera position
void SetScriptCamera(glm::vec3 eye, glm::vec3 lookat);
//! Script camera: Animate to given camera position
void SetScriptCameraAnimate(glm::vec3 eye, glm::vec3 lookat);
//! Script camera: Animate to given eye position
void SetScriptCameraAnimateEye(glm::vec3 eye);
//! Script camera: Animate to given lookat position
void SetScriptCameraAnimateLookat(glm::vec3 lookat);
//@}
//! \name Configuration settings
//@{
void SetEffect(bool enable);
bool GetEffect();
void SetBlood(bool enable);
bool GetBlood();
void SetOldCameraScroll(bool scroll);
bool GetOldCameraScroll();
void SetCameraInvertX(bool invert);
bool GetCameraInvertX();
void SetCameraInvertY(bool invert);
bool GetCameraInvertY();
//@}
//! Temporarily freeze camera movement
void SetFreeze(bool freeze);
//! Set camera speed
void SetCameraSpeed(float speed);
protected:
//! Advances the effect of the camera
void EffectFrame(const Event &event);
//! Advanced overlay effect in the foreground
void OverFrame(const Event &event);
bool EventFrameFree(const Event &event, bool keysAllowed);
bool EventFrameBack(const Event &event);
bool EventFrameFix(const Event &event);
bool EventFrameExplo(const Event &event);
bool EventFrameOnBoard(const Event &event);
bool EventFrameVisit(const Event &event);
bool EventFrameScript(const Event &event);
/**
* \brief Calculates camera animation and sends updated camera position to the 3D engine
* \param eyePt Eye point
* \param lookatPt Lookat point
* \param rTime Time since last time this function was called (used to calculate animation)
* \see SetViewParams
*/
void UpdateCameraAnimation(const glm::vec3 &eyePt, const glm::vec3 &lookatPt, float rTime);
/**
* \brief Avoid the obstacles
*
* For CAM_TYPE_BACK: make obstacles transparent
* For CAM_TYPE_FIX or CAM_TYPE_PLANE: adjust eye not to hit the obstacles
*
* \param eye Eye position, may be adjusted
* \param lookat Lookat point
*/
void IsCollision(glm::vec3 &eye, glm::vec3 lookat);
//! Avoid the obstacles (CAM_TYPE_BACK)
void IsCollisionBack();
//! Avoid the obstacles (CAM_TYPE_FIX or CAM_TYPE_PLANE)
void IsCollisionFix(glm::vec3 &eye, glm::vec3 lookat);
//! Adjusts the camera not to enter the ground
glm::vec3 ExcludeTerrain(glm::vec3 eye, glm::vec3 lookat, float &angleH, float &angleV);
//! Adjusts the camera not to enter an object
glm::vec3 ExcludeObject(glm::vec3 eye, glm::vec3 lookat, float &angleH, float &angleV);
/**
* \brief Updates the location and direction of the camera in the 3D engine
* \param eye Eye point
* \param lookat Lookat point
* \param up Up vector
* \see CEngine::SetViewParams
*/
void SetViewParams(const glm::vec3 &eye, const glm::vec3 &lookat, const glm::vec3 &up = glm::vec3(0.0f, 1.0f, 0.0f));
/**
* \brief Calculate camera movement (from user inputs) to apply
* \return glm::vec3 where x, y represent respectively horizontal and vertical angle change in radians and z represents zoom (distance change)
* \remarks Should not be called more often than once every EVENT_FRAME
**/
glm::vec3 CalculateCameraMovement(const Event &event, bool keysAllowed = true);
protected:
CEngine* m_engine;
CRobotMain* m_main;
CTerrain* m_terrain;
CWater* m_water;
CInput* m_input;
//! The type of camera
CameraType m_type;
//! Type of smoothing
CameraSmooth m_smooth;
//! Object linked to the camera
CObject* m_cameraObj;
//! Remaining time of initial camera entry animation
float m_initDelay;
//! Current eye
glm::vec3 m_actualEye{ 0, 0, 0 };
//! Current aim
glm::vec3 m_actualLookat{ 0, 0, 0 };
//! Final eye
glm::vec3 m_finalEye{ 0, 0, 0 };
//! Final lookat
glm::vec3 m_finalLookat{ 0, 0, 0 };
//! Eye position at the moment of entering CAM_TYPE_INFO/CAM_TYPE_VISIT
glm::vec3 m_prevEye{ 0, 0, 0 };
//! Lookat position at the moment of entering CAM_TYPE_INFO/CAM_TYPE_VISIT
glm::vec3 m_prevLookat{ 0, 0, 0 };
float m_focus;
//! CAM_TYPE_FREE: eye
glm::vec3 m_eyePt{ 0, 0, 0 };
//! CAM_TYPE_FREE: horizontal direction
float m_directionH;
//! CAM_TYPE_FREE: vertical direction
float m_directionV;
//! CAM_TYPE_FREE: height above the ground
float m_heightEye;
//! CAM_TYPE_FREE: height above the ground
float m_heightLookat;
//! CAM_TYPE_FREE: speed of movement
float m_speed;
//! CAM_TYPE_BACK: distance
float m_backDist;
//! CAM_TYPE_BACK: minimal distance
float m_backMin;
//! CAM_TYPE_BACK: additional horizontal direction
float m_addDirectionH;
//! CAM_TYPE_BACK: additional vertical direction
float m_addDirectionV;
//! CAM_TYPE_FIX: distance
float m_fixDist;
//! CAM_TYPE_FIX: horizontal direction
float m_fixDirectionH;
//! CAM_TYPE_FIX: vertical direction
float m_fixDirectionV;
//! CAM_TYPE_VISIT: target position
glm::vec3 m_visitGoal{ 0, 0, 0 };
//! CAM_TYPE_VISIT: distance
float m_visitDist;
//! CAM_TYPE_VISIT: relative time
float m_visitTime;
//! CAM_TYPE_VISIT: initial type
CameraType m_visitType;
//! CAM_TYPE_VISIT: direction
float m_visitDirectionV;
//! Last known mouse position, used to calculate change since last frame
glm::vec2 m_mousePos = { 0.5f, 0.5f };
//! Change of mouse position since last frame
glm::vec2 m_mouseDelta = { 0.0f, 0.0f };
//! Change of camera position caused by edge camera
glm::vec2 m_mouseDeltaEdge = { 0.0f, 0.0f };
//! Change of mouse wheel since last frame
float m_mouseWheelDelta = 0.0f;
CenteringPhase m_centeringPhase;
float m_centeringAngleH;
float m_centeringAngleV;
float m_centeringDist;
float m_centeringCurrentH;
float m_centeringCurrentV;
float m_centeringTime;
float m_centeringProgress;
CameraEffect m_effectType;
glm::vec3 m_effectPos{ 0, 0, 0 };
float m_effectForce;
float m_effectProgress;
glm::vec3 m_effectOffset{ 0, 0, 0 };
CameraOverEffect m_overType;
float m_overForce;
float m_overTime;
Color m_overColorBase;
Color m_overColor;
TransparencyMode m_overMode;
float m_overFadeIn;
float m_overFadeOut;
glm::vec3 m_scriptEye{ 0, 0, 0 };
glm::vec3 m_scriptLookat{ 0, 0, 0 };
//! Is camera frozen?
bool m_freeze = false;
//! \name Configuration settings
//@{
bool m_effect;
bool m_blood;
bool m_oldCameraScroll;
bool m_cameraInvertX;
bool m_cameraInvertY;
//@}
};
} // namespace Gfx

File diff suppressed because it is too large Load Diff

View File

@ -1,82 +0,0 @@
/**
* \namespace Gfx::ModelInput
* \brief Functions related to model loading
*/
/**
* \namespace Gfx::ModelOutput
* \brief Functions related to model saving
*/
/**
* \page models Models
*
* Model formats and associated issues are described briefly for graphics designers and developers.
*
* \section format Model format
*
* \todo Update for the new model format
*
* Colobot models are basically a collection of triangles with some associated data.
* <span style="text-decoration: line-through;">In the code, the class Gfx::CModel (src/graphics/model/model.h)
* is responsible for reading/writing model files.</span> Each triangle of model contains the information
* as stored in Gfx::ModelTriangle struct defined in model_triangle.h header, that is:
* * 3 triangle points (coordinates, normals, UV texture coordinates for 2 textures)
* * material (ambient, diffuse, specular colors)
* * file names for 1st and 2nd texture (or, for 2nd texture - variable flag)
* * rendering state
* * <span style="text-decoration: line-through;">min and max values of LOD (= level of details)</span>
*
* \subsection textures Textures
*
* 1st texture is always static - the assigned image name.
*
* 2nd texture can be set explicitly in 2nd texture name, with variable flag set to false.
* It is then static as 1st texture.
*
* But if variable flag is set, the texture will be applied dynamically by the graphics engine.
* It will be one of dirtyXX.png textures, depending on current setup.
*
* \subsection renderstates Rendering states
*
* Rendering state is one of Gfx::CEngine's rendering states, that is a mask of enum Gfx::EngineRenderState values
* from src/graphics/engine/engine.h.
*
* For most purposes, the default render (Gfx::ENG_RSTATE_NORMAL = 0) state will be sufficient.
* This state enables regular one-texture rendering.
*
* To use 2nd texture, set one of Gfx::ENG_RSTATE_DUAL_BLACK or Gfx::ENG_RSTATE_DUAL_WHITE states.
* Other states, enabling specific behavior may be used in rare cases.
*
* \subsection lod Min and max LOD
*
* <span style="text-decoration: line-through;">LOD is used to display different model triangles based
* on distance to viewer. The given triangle will only be displayed if the distance is within bounds [min, max].</span>
*
* <span style="text-decoration: line-through;">For now, use standard definitions of min and max which
* fall into 3 categories:</span>
* * <span style="text-decoration: line-through;">min = 0, max = 100 - max detail</span>
* * <span style="text-decoration: line-through;">min = 100, max = 200 - medium detail</span>
* * <span style="text-decoration: line-through;">min = 200, max = 1 000 000 - low detail</span>
*
* \section fileformats File formats
*
* There are currently 3 file formats recognized by Gfx::ModelInput and Gfx::ModelOutput:
* * old binary format (in 3 versions, though mostly only the 3rd one is used) - this is the format
* of original model files; it is deprecated now and will be removed in the future
* * new text format - preferred for now, as it is easy to handle and convert to other formats as necessary
* * new binary format - contains the same information as new text format
*
* \section blenderimport Import/export in Blender
*
* The plugin to import and export models in Blender is contained in \p tools/blender-scipts.py.
* To use it, install it as per instructions [on Blender wiki](http://wiki.blender.org/index.php/Doc:2.6/Manual/Extensions/Python/Add-Ons).
* It will register new menu entries under File -> Import and File -> Export. Import is always active, but to export,
* you have to select a mesh object first.
*
* Textures are loaded from the same directory as the model file.
*
* Additional data like state, variable texture flag and min and max LOD can be given as user attributes.
*
* If you have any problems, please contact \b piotrdz on ICC forum or IRC channels.
*/

View File

@ -1,713 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/model/model_mod.h"
#include "common/ioutils.h"
#include "common/logger.h"
#include "common/resources/inputstream.h"
#include "graphics/model/model_io_exception.h"
#include "graphics/model/model_io_structs.h"
#include <vector>
#include <nlohmann/json.hpp>
using namespace IOUtils;
using json = nlohmann::json;
namespace Gfx::ModelIO
{
struct BufferView
{
int buffer = 0;
size_t offset = 0;
size_t length = 0;
};
struct Accessor
{
int bufferView = 0;
size_t byteOffset = 0;
int componentType = 0;
int count = 0;
std::string type = "";
};
struct Texture
{
int sampler = -1;
int source = 0;
};
struct Image
{
std::string uri;
};
struct Sampler
{
};
class GLTFLoader
{
public:
std::unique_ptr<CModel> Load(const std::filesystem::path& path);
private:
void ReadBuffers();
void ReadBufferViews();
void ReadMaterials();
void ReadAccessors();
void ReadSamplers();
void ReadImages();
void ReadTextures();
void ReadMeshes();
std::vector<glm::vec3> ReadPositions(int index);
std::vector<glm::vec3> ReadNormals(int index);
std::vector<glm::vec2> ReadUVs(int index);
std::vector<glm::u8vec4> ReadColors(int index);
std::vector<unsigned> ReadIndices(int index);
std::unique_ptr<CModel> m_model;
std::filesystem::path m_directory;
json m_root;
std::vector<std::vector<char>> m_buffers;
std::vector<BufferView> m_bufferViews;
std::vector<Material> m_materials;
std::vector<Accessor> m_accessors;
std::vector<Texture> m_textures;
std::vector<Image> m_images;
std::vector<Sampler> m_samplers;
};
std::unique_ptr<CModel> ReadGLTFModel(const std::filesystem::path& path)
{
GLTFLoader loader;
return loader.Load(path);
}
std::unique_ptr<CModel> GLTFLoader::Load(const std::filesystem::path& path)
{
m_directory = path.parent_path();
CInputStream stream(path);
stream >> m_root;
m_model = std::make_unique<CModel>();
ReadBuffers();
ReadBufferViews();
ReadAccessors();
ReadSamplers();
ReadImages();
ReadTextures();
ReadMaterials();
ReadMeshes();
return std::move(m_model);
}
void GLTFLoader::ReadBuffers()
{
m_buffers.clear();
for (const auto& node : m_root["buffers"])
{
size_t length = node["byteLength"].get<int>();
std::vector<char> buffer(length);
if (node.contains("uri"))
{
auto uri = m_directory / node["uri"].get<std::string>();
CInputStream stream(uri);
stream.read(buffer.data(), buffer.size());
}
else
{
GetLogger()->Error("Base64 not yet supported\n");
}
m_buffers.emplace_back(std::move(buffer));
}
}
void GLTFLoader::ReadBufferViews()
{
m_bufferViews.clear();
for (const auto& node : m_root["bufferViews"])
{
BufferView bufferView{};
bufferView.buffer = node["buffer"].get<int>();
bufferView.offset = node["byteOffset"].get<int>();
bufferView.length = node["byteLength"].get<int>();
m_bufferViews.push_back(bufferView);
}
}
void GLTFLoader::ReadMaterials()
{
m_materials.clear();
for (const auto& material : m_root["materials"])
{
Material mat;
if (material.contains("doubleSided"))
{
mat.cullFace = material["doubleSided"].get<bool>() ? CullFace::NONE : CullFace::BACK;
}
if (material.contains("extras"))
{
const auto& extras = material["extras"];
if (extras.contains("dirt"))
{
int dirt = extras["dirt"].get<int>();
std::string texName = std::string("dirty0") + char('0' + dirt) + ".png";
mat.detailTexture = texName;
}
if (extras.contains("tag"))
{
mat.tag = extras["tag"].get<std::string>();
}
if (extras.contains("recolor"))
{
mat.recolor = extras["recolor"].get<std::string>();
}
if (extras.contains("recolor_ref"))
{
const auto& color = extras["recolor_ref"];
float r = color[0];
float g = color[1];
float b = color[2];
mat.recolorReference = Color(r, g, b);
}
}
if (material.contains("emissiveFactor"))
{
const auto& color = material["emissiveFactor"];
mat.emissiveColor = {
color[0].get<float>(),
color[1].get<float>(),
color[2].get<float>(),
0.0
};
mat.emissiveColor = Gfx::ToLinear(mat.emissiveColor);
}
else
{
mat.emissiveColor = { 0.0, 0.0, 0.0, 0.0 };
}
if (material.contains("emissiveTexture"))
{
const auto& tex = material["emissiveTexture"];
if (tex.contains("index"))
{
int index = tex["index"].get<int>();
const auto& texture = m_textures[index];
const auto& image = m_images[texture.source];
mat.emissiveTexture = image.uri;
}
}
if (material.contains("pbrMetallicRoughness"))
{
const auto& pbr = material["pbrMetallicRoughness"];
if (pbr.contains("baseColorFactor"))
{
const auto& color = pbr["baseColorFactor"];
mat.albedoColor = {
color[0].get<float>(),
color[1].get<float>(),
color[2].get<float>(),
color[3].get<float>()
};
mat.albedoColor = Gfx::ToLinear(mat.albedoColor);
}
else
{
mat.albedoColor = { 1.0, 1.0, 1.0, 1.0 };
}
if (pbr.contains("baseColorTexture"))
{
const auto& tex = pbr["baseColorTexture"];
if (tex.contains("index"))
{
int index = tex["index"].get<int>();
const auto& texture = m_textures[index];
const auto& image = m_images[texture.source];
mat.albedoTexture = image.uri;
}
}
if (pbr.contains("metallicFactor"))
{
mat.metalness = pbr["metallicFactor"].get<float>();
}
else
{
mat.metalness = 1.0;
}
if (pbr.contains("roughnessFactor"))
{
mat.roughness = pbr["roughnessFactor"].get<float>();
}
else
{
mat.roughness = 1.0;
}
if (pbr.contains("metallicRoughnessTexture"))
{
const auto& tex = pbr["metallicRoughnessTexture"];
if (tex.contains("index"))
{
int index = tex["index"].get<int>();
const auto& texture = m_textures[index];
const auto& image = m_images[texture.source];
mat.materialTexture = image.uri;
}
}
if (pbr.contains("occlusionTexture"))
{
const auto& tex = pbr["occlusionTexture"];
if (tex.contains("index"))
{
int index = tex["index"].get<int>();
const auto& texture = m_textures[index];
[[maybe_unused]] const auto& image = m_images[texture.source];
if (tex.contains("strength"))
{
mat.aoStrength = tex["strength"].get<float>();
}
else
{
mat.aoStrength = 1.0f;
}
}
}
}
if (material.contains("normalTexture"))
{
const auto& tex = material["normalTexture"];
if (tex.contains("index"))
{
int index = tex["index"].get<int>();
const auto& texture = m_textures[index];
const auto& image = m_images[texture.source];
mat.normalTexture = image.uri;
}
}
if (material.contains("alphaMode"))
{
auto mode = material["alphaMode"].get<std::string>();
if (mode == "OPAQUE")
mat.alphaMode = AlphaMode::NONE;
else if (mode == "MASK")
mat.alphaMode = AlphaMode::MASK;
else if (mode == "BLEND")
mat.alphaMode = AlphaMode::BLEND;
}
if (material.contains("alphaCutoff"))
{
mat.alphaThreshold = material["alphaCutoff"].get<float>();
}
m_materials.push_back(mat);
}
}
void GLTFLoader::ReadAccessors()
{
m_accessors.clear();
for (const auto& node : m_root["accessors"])
{
Accessor accessor{};
accessor.bufferView = node["bufferView"].get<int>();
if (node.contains("byteOffset"))
accessor.byteOffset = node["byteOffset"].get<int>();
else
accessor.byteOffset = 0;
accessor.count = node["count"].get<int>();
accessor.componentType = node["componentType"].get<int>();
accessor.type = node["type"].get<std::string>();
m_accessors.push_back(accessor);
}
}
void GLTFLoader::ReadSamplers()
{
m_samplers.clear();
for ([[maybe_unused]] const auto& node : m_root["samplers"])
{
Sampler sampler{};
m_samplers.push_back(sampler);
}
}
void GLTFLoader::ReadImages()
{
m_images.clear();
for (const auto& node : m_root["images"])
{
Image image{};
if (node.contains("uri"))
{
image.uri = node["uri"].get<std::string>();
}
m_images.push_back(image);
}
}
void GLTFLoader::ReadTextures()
{
m_textures.clear();
for (const auto& node : m_root["textures"])
{
Texture texture{};
if (node.contains("sampler"))
texture.sampler = node["sampler"].get<int>();
texture.source = node["source"].get<int>();
m_textures.push_back(texture);
}
}
void GLTFLoader::ReadMeshes()
{
m_model = std::make_unique<CModel>();
for (const auto& node : m_root["meshes"])
{
auto name = node["name"].get<std::string>();
auto mesh = std::make_unique<CModelMesh>();
for (const auto& primitive : node["primitives"])
{
const auto& material = m_materials[primitive["material"].get<int>()];
auto part = mesh->AddPart(material);
if (primitive.contains("attributes"))
{
const auto& attributes = primitive["attributes"];
auto positions = ReadPositions(attributes["POSITION"].get<int>());
if (positions.empty()) continue;
part->SetVertices(positions.size());
for (size_t i = 0; i < positions.size(); i++)
part->GetVertex(i).SetPosition(positions[i] * glm::vec3(1.0f, 1.0f, -1.0f));
if (attributes.contains("NORMAL"))
{
part->Add(VertexAttribute::NORMAL);
auto normals = ReadNormals(attributes["NORMAL"].get<int>());
for (size_t i = 0; i < normals.size(); i++)
part->GetVertex(i).SetNormal(normals[i] * glm::vec3(1.0f, 1.0f, -1.0f));
}
if (attributes.contains("TEXCOORD_0"))
{
part->Add(VertexAttribute::UV1);
auto uvs = ReadUVs(attributes["TEXCOORD_0"].get<int>());
for (size_t i = 0; i < uvs.size(); i++)
part->GetVertex(i).SetUV1(uvs[i]);
}
if (attributes.contains("TEXCOORD_1"))
{
part->Add(VertexAttribute::UV2);
auto uvs = ReadUVs(attributes["TEXCOORD_1"].get<int>());
for (size_t i = 0; i < uvs.size(); i++)
part->GetVertex(i).SetUV2(uvs[i]);
}
if (attributes.contains("COLOR_0"))
{
part->Add(VertexAttribute::COLOR);
auto colors = ReadColors(attributes["COLOR_0"].get<int>());
for (size_t i = 0; i < colors.size(); i++)
part->GetVertex(i).SetColor(colors[i]);
}
}
if (primitive.contains("indices"))
{
auto indices = ReadIndices(primitive["indices"].get<int>());
part->SetIndices(indices.size());
for (unsigned i = 0; i < indices.size(); i += 3)
{
part->SetIndex(i + 0, indices[i + 0]);
part->SetIndex(i + 1, indices[i + 2]);
part->SetIndex(i + 2, indices[i + 1]);
}
}
else
{
size_t vertices = part->GetVertexCount();
part->SetIndices(vertices);
for (unsigned i = 0; i < vertices; i += 3)
{
part->SetIndex(i + 0, i + 0);
part->SetIndex(i + 1, i + 2);
part->SetIndex(i + 2, i + 1);
}
}
}
if (mesh->GetPartCount() > 0)
m_model->AddMesh(name, std::move(mesh));
}
}
std::vector<glm::vec3> GLTFLoader::ReadPositions(int index)
{
const auto& accessor = m_accessors[index];
std::vector<glm::vec3> positions(accessor.count);
const auto& bufferView = m_bufferViews[accessor.bufferView];
const auto& buffer = m_buffers[bufferView.buffer];
auto data = reinterpret_cast<const glm::vec3*>(buffer.data() + bufferView.offset);
for (size_t i = 0; i < accessor.count; i++)
positions[i] = data[i];
return positions;
}
std::vector<glm::vec3> GLTFLoader::ReadNormals(int index)
{
const auto& accessor = m_accessors[index];
std::vector<glm::vec3> normals(accessor.count);
const auto& bufferView = m_bufferViews[accessor.bufferView];
const auto& buffer = m_buffers[bufferView.buffer];
auto data = reinterpret_cast<const glm::vec3*>(buffer.data() + bufferView.offset);
for (size_t i = 0; i < accessor.count; i++)
normals[i] = data[i];
return normals;
}
std::vector<glm::vec2> GLTFLoader::ReadUVs(int index)
{
const auto& accessor = m_accessors[index];
std::vector<glm::vec2> uvs(accessor.count);
const auto& bufferView = m_bufferViews[accessor.bufferView];
const auto& buffer = m_buffers[bufferView.buffer];
if (accessor.componentType == 5126)
{
auto data = reinterpret_cast<const glm::vec2*>(buffer.data() + bufferView.offset);
for (size_t i = 0; i < accessor.count; i++)
uvs[i] = data[i];
}
else
{
GetLogger()->Error("Invalid UV type: %d\n", accessor.componentType);
}
return uvs;
}
std::vector<glm::u8vec4> GLTFLoader::ReadColors(int index)
{
const auto& accessor = m_accessors[index];
std::vector<glm::u8vec4> colors(accessor.count);
const auto& bufferView = m_bufferViews[accessor.bufferView];
const auto& buffer = m_buffers[bufferView.buffer];
if (accessor.componentType == 5121)
{
auto data = reinterpret_cast<const glm::u8vec4*>(buffer.data() + bufferView.offset);
for (size_t i = 0; i < accessor.count; i++)
colors[i] = data[i];
}
else if (accessor.componentType == 5123)
{
auto data = reinterpret_cast<const glm::u16vec4*>(buffer.data() + bufferView.offset);
for (size_t i = 0; i < accessor.count; i++)
colors[i] = glm::u8vec4(data[i] / glm::u16vec4(256));
}
else if (accessor.componentType == 5126)
{
auto data = reinterpret_cast<const glm::vec4*>(buffer.data() + bufferView.offset);
for (size_t i = 0; i < accessor.count; i++)
colors[i] = glm::u8vec4(data[i] * 255.0f);
}
else
{
GetLogger()->Error("Invalid color type: %d\n", accessor.componentType);
}
// Fix for bug in Blender where it exports vertex colors in sRGB instead of linear space
for (size_t i = 0; i < colors.size(); i++)
{
auto color = Gfx::IntColorToColor(Gfx::IntColor(colors[i]));
color = Gfx::ToLinear(color);
colors[i] = Gfx::ColorToIntColor(color);
}
return colors;
}
std::vector<unsigned> GLTFLoader::ReadIndices(int index)
{
const auto& accessor = m_accessors[index];
std::vector<unsigned> indices(accessor.count);
const auto& bufferView = m_bufferViews[accessor.bufferView];
const auto& buffer = m_buffers[bufferView.buffer];
// Unsigned byte components
if (accessor.componentType == 5121)
{
auto data = reinterpret_cast<const uint8_t*>(buffer.data() + bufferView.offset);
for (size_t i = 0; i < accessor.count; i++)
indices[i] = data[i];
}
// Unsigned short components
else if (accessor.componentType == 5123)
{
auto data = reinterpret_cast<const uint16_t*>(buffer.data() + bufferView.offset);
for (size_t i = 0; i < accessor.count; i++)
indices[i] = data[i];
}
// Unsigned int components
else if (accessor.componentType == 5125)
{
auto data = reinterpret_cast<const uint32_t*>(buffer.data() + bufferView.offset);
for (size_t i = 0; i < accessor.count; i++)
indices[i] = data[i];
}
return indices;
}
}

View File

@ -1,53 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/model/model_input.h"
#include "graphics/model/model_gltf.h"
#include "graphics/model/model_mod.h"
#include "graphics/model/model_txt.h"
#include "graphics/model/model_io_exception.h"
namespace Gfx
{
std::unique_ptr<CModel> ModelInput::Read(const std::filesystem::path& path)
{
auto extension = path.extension();
if (extension == ".mod")
{
return ModelIO::ReadOldModel(path);
}
else if (extension == ".txt")
{
return ModelIO::ReadTextModel(path);
}
else if (extension == ".gltf")
{
return ModelIO::ReadGLTFModel(path);
}
else
{
throw CModelIOException(std::string("Unknown model format: ") + extension.string());
}
}
} // namespace Gfx

View File

@ -1,461 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/model/model_mesh.h"
#include <array>
namespace Gfx
{
CVertexProxy::CVertexProxy(CModelPart* part, size_t index)
: m_part(part), m_index(index)
{
}
const glm::vec3& CVertexProxy::GetPosition() const
{
return m_part->m_positions.array[m_index];
}
void CVertexProxy::SetPosition(const glm::vec3& position) const
{
m_part->m_positions.array[m_index] = position;
}
const glm::u8vec4& CVertexProxy::GetColor() const
{
return m_part->m_colors.array[m_index];
}
void CVertexProxy::SetColor(const glm::u8vec4& color) const
{
m_part->m_colors.array[m_index] = color;
}
const glm::vec2& CVertexProxy::GetUV1() const
{
return m_part->m_uvs1.array[m_index];
}
void CVertexProxy::SetUV1(const glm::vec2& uv) const
{
m_part->m_uvs1.array[m_index] = uv;
}
const glm::vec2& CVertexProxy::GetUV2() const
{
return m_part->m_uvs2.array[m_index];
}
void CVertexProxy::SetUV2(const glm::vec2& uv) const
{
m_part->m_uvs2.array[m_index] = uv;
}
const glm::vec3& CVertexProxy::GetNormal() const
{
return m_part->m_normals.array[m_index];
}
void CVertexProxy::SetNormal(const glm::vec3& normal) const
{
m_part->m_normals.array[m_index] = normal;
}
const glm::vec4& CVertexProxy::GetTangent() const
{
return m_part->m_tangents.array[m_index];
}
void CVertexProxy::SetTangent(const glm::vec4& tangent) const
{
m_part->m_tangents.array[m_index] = tangent;
}
const glm::u8vec4& CVertexProxy::GetBoneIndices() const
{
return m_part->m_boneIndices.array[m_index];
}
void CVertexProxy::SetBoneIndices(const glm::u8vec4& indices) const
{
m_part->m_boneIndices.array[m_index] = indices;
}
const glm::vec4& CVertexProxy::GetBoneWeights() const
{
return m_part->m_boneWeights.array[m_index];
}
void CVertexProxy::SetBoneWeights(const glm::vec4& weights) const
{
m_part->m_boneWeights.array[m_index] = weights;
}
CModelPart::CModelPart(const Material& material, size_t vertices, size_t indices)
: m_material(material) {
m_positions.array.resize(vertices);
m_indices.array.resize(indices);
}
const Material& CModelPart::GetMaterial() const
{
return m_material;
}
void CModelPart::SetVertices(size_t count)
{
m_positions.array.resize(count);
if (m_colors.enabled) m_colors.array.resize(count);
if (m_uvs1.enabled) m_uvs1.array.resize(count);
if (m_uvs2.enabled) m_uvs2.array.resize(count);
if (m_normals.enabled) m_normals.array.resize(count);
if (m_tangents.enabled) m_tangents.array.resize(count);
if (m_boneIndices.enabled) m_boneIndices.array.resize(count);
if (m_boneWeights.enabled) m_boneWeights.array.resize(count);
}
void CModelPart::SetIndices(size_t count)
{
m_indices.enabled = count > 0;
m_indices.array.resize(count);
}
bool CModelPart::Has(VertexAttribute array) const
{
switch (array)
{
case VertexAttribute::POSITION:
return true;
case VertexAttribute::COLOR:
return m_colors.enabled;
case VertexAttribute::UV1:
return m_uvs1.enabled;
case VertexAttribute::UV2:
return m_uvs2.enabled;
case VertexAttribute::NORMAL:
return m_normals.enabled;
case VertexAttribute::TANGENT:
return m_tangents.enabled;
case VertexAttribute::BONE_INDICES:
return m_boneIndices.enabled;
case VertexAttribute::BONE_WEIGHTS:
return m_boneWeights.enabled;
default:
return false;
}
}
void CModelPart::Add(VertexAttribute attribute)
{
switch (attribute)
{
case VertexAttribute::COLOR:
m_colors.enabled = true;
m_colors.array.resize(m_positions.array.size());
break;
case VertexAttribute::UV1:
m_uvs1.enabled = true;
m_uvs1.array.resize(m_positions.array.size());
break;
case VertexAttribute::UV2:
m_uvs2.enabled = true;
m_uvs2.array.resize(m_positions.array.size());
break;
case VertexAttribute::NORMAL:
m_normals.enabled = true;
m_normals.array.resize(m_positions.array.size());
break;
case VertexAttribute::TANGENT:
m_tangents.enabled = true;
m_tangents.array.resize(m_positions.array.size());
break;
case VertexAttribute::BONE_INDICES:
m_boneIndices.enabled = true;
m_boneIndices.array.resize(m_positions.array.size());
break;
case VertexAttribute::BONE_WEIGHTS:
m_boneWeights.enabled = true;
m_boneWeights.array.resize(m_positions.array.size());
return;
}
}
void CModelPart::Remove(VertexAttribute attribute)
{
switch (attribute)
{
case VertexAttribute::COLOR:
m_colors.enabled = false;
m_colors.array.resize(0);
return;
case VertexAttribute::UV1:
m_uvs1.enabled = false;
m_uvs1.array.resize(0);
return;
case VertexAttribute::UV2:
m_uvs2.enabled = false;
m_uvs2.array.resize(0);
return;
case VertexAttribute::NORMAL:
m_normals.enabled = false;
m_normals.array.resize(0);
return;
case VertexAttribute::TANGENT:
m_tangents.enabled = false;
m_tangents.array.resize(0);
return;
case VertexAttribute::BONE_INDICES:
m_boneIndices.enabled = false;
m_boneIndices.array.resize(0);
return;
case VertexAttribute::BONE_WEIGHTS:
m_boneWeights.enabled = false;
m_boneWeights.array.resize(0);
return;
}
}
bool CModelPart::IsIndexed() const
{
return m_indices.enabled;
}
size_t CModelPart::GetVertexCount() const
{
return m_positions.array.size();
}
size_t CModelPart::GetIndexCount() const
{
return m_indices.array.size();
}
const std::vector<unsigned int>& CModelPart::GetIndices() const
{
return m_indices.array;
}
CVertexProxy CModelPart::GetVertex(size_t index)
{
return CVertexProxy(this, index);
}
std::uint32_t CModelPart::GetIndex(size_t index)
{
return m_indices.array[index];
}
void CModelPart::AddVertex(const Vertex3D& vertex)
{
m_positions.array.push_back(vertex.position);
if (m_colors.enabled) m_colors.array.push_back(vertex.color);
if (m_uvs1.enabled) m_uvs1.array.push_back(vertex.uv);
if (m_uvs2.enabled) m_uvs2.array.push_back(vertex.uv2);
if (m_normals.enabled) m_normals.array.push_back(vertex.normal);
if (m_tangents.enabled) m_tangents.array.push_back({ 1.0f, 0.0f, 0.0f, 1.0f });
if (m_boneIndices.enabled) m_boneIndices.array.push_back({ 0, 0, 0, 0 });
if (m_boneWeights.enabled) m_boneWeights.array.push_back({ 1.0f, 0.0f, 0.0f, 0.0f });
}
void CModelPart::AddIndex(unsigned int index)
{
if (m_indices.enabled) m_indices.array.push_back(index);
}
void CModelPart::SetIndex(size_t index, unsigned int value)
{
m_indices.array[index] = value;
}
void CModelPart::GetTriangles(std::vector<Gfx::ModelTriangle>& triangles)
{
size_t n = IsIndexed()
? GetIndexCount()
: GetVertexCount();
for (size_t i = 0; i < n - 2; i += 3)
{
std::array<Gfx::Vertex3D, 3> verts;
for (size_t j = 0; j < 3; j++)
{
size_t index = IsIndexed()
? GetIndex(i + j)
: i + j;
auto vertex = GetVertex(index);
verts[j].position = vertex.GetPosition();
if (Has(VertexAttribute::COLOR)) verts[j].color = vertex.GetColor();
else verts[j].color = { 255, 255, 255, 255 };
if (Has(VertexAttribute::UV1)) verts[j].uv = vertex.GetUV1();
else verts[j].uv = { 0, 0 };
if (Has(VertexAttribute::UV2)) verts[j].uv2 = vertex.GetUV2();
else verts[j].uv2 = { 0, 0 };
if (Has(VertexAttribute::NORMAL)) verts[j].normal = vertex.GetNormal();
else verts[j].normal = { 0, 0, 1 };
}
triangles.push_back({ verts[0], verts[1], verts[2], GetMaterial() });
}
}
void CModelMesh::AddTriangle(const ModelTriangle& triangle)
{
for (auto& part : m_parts)
{
if (part->GetMaterial() == triangle.material)
{
part->AddVertex(triangle.p1);
part->AddVertex(triangle.p2);
part->AddVertex(triangle.p3);
return;
}
}
auto part = std::make_unique<CModelPart>(triangle.material, 0, 0);
part->Add(VertexAttribute::COLOR);
part->Add(VertexAttribute::UV1);
part->Add(VertexAttribute::UV2);
part->Add(VertexAttribute::NORMAL);
part->AddVertex(triangle.p1);
part->AddVertex(triangle.p2);
part->AddVertex(triangle.p3);
m_parts.push_back(std::move(part));
}
void CModelMesh::AddTriangle(const Triangle& triangle, const Material& material)
{
for (auto& part : m_parts)
{
if (part->GetMaterial() == material)
{
part->AddVertex(triangle.p1);
part->AddVertex(triangle.p2);
part->AddVertex(triangle.p3);
return;
}
}
auto part = std::make_unique<CModelPart>(material, 0, 0);
part->Add(VertexAttribute::COLOR);
part->Add(VertexAttribute::UV1);
part->Add(VertexAttribute::UV2);
part->Add(VertexAttribute::NORMAL);
part->AddVertex(triangle.p1);
part->AddVertex(triangle.p2);
part->AddVertex(triangle.p3);
m_parts.push_back(std::move(part));
}
size_t CModelMesh::GetPartCount() const
{
return m_parts.size();
}
CModelPart* CModelMesh::GetPart(size_t index) const
{
return m_parts[index].get();
}
CModelPart* CModelMesh::AddPart(const Material& material)
{
for (auto& part : m_parts)
{
if (part->GetMaterial() == material)
{
return part.get();
}
}
auto part = std::make_unique<CModelPart>(material, 0, 0);
m_parts.push_back(std::move(part));
return m_parts.back().get();
}
const glm::vec3& CModelMesh::GetPosition() const
{
return m_position;
}
void CModelMesh::SetPosition(const glm::vec3& position)
{
m_position = position;
}
const glm::vec3& CModelMesh::GetRotation() const
{
return m_rotation;
}
void CModelMesh::SetRotation(const glm::vec3& rotation)
{
m_rotation = rotation;
}
const glm::vec3& CModelMesh::GetScale() const
{
return m_scale;
}
void CModelMesh::SetScale(const glm::vec3& scale)
{
m_scale = scale;
}
const std::string& CModelMesh::GetParent() const
{
return m_parent;
}
void CModelMesh::SetParent(const std::string& parent)
{
m_parent = parent;
}
std::vector<ModelTriangle> CModelMesh::GetTriangles() const
{
std::vector<ModelTriangle> triangles;
for (const auto& part : m_parts)
{
part->GetTriangles(triangles);
}
return triangles;
}
} // namespace Gfx

View File

@ -1,236 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "graphics/model/model_triangle.h"
#include <memory>
#include <vector>
namespace Gfx
{
/**
* \enum VertexAttribute
* \brief An enum for vertex attributes
*/
enum class VertexAttribute
{
POSITION,
COLOR,
UV1,
UV2,
NORMAL,
TANGENT,
BONE_INDICES,
BONE_WEIGHTS,
};
class CModelPart;
/**
* \class CVertexProxy
* \brief Proxy object for manipulating vertex data
*/
class CVertexProxy
{
CModelPart* m_part;
size_t m_index;
public:
CVertexProxy(CModelPart* part, size_t index);
//! Returns vertex position
const glm::vec3& GetPosition() const;
//! Sets vertex position
void SetPosition(const glm::vec3& position) const;
//! Returns vertex color
const glm::u8vec4& GetColor() const;
//! Sets vertex color
void SetColor(const glm::u8vec4& color) const;
//! Returns 1st UV
const glm::vec2& GetUV1() const;
//! Sets 1st UV
void SetUV1(const glm::vec2& uv) const;
//! Returns 2nd UV
const glm::vec2& GetUV2() const;
//! Sets 2nd UV
void SetUV2(const glm::vec2& uv) const;
//! Returns normal
const glm::vec3& GetNormal() const;
//! Sets normal
void SetNormal(const glm::vec3& normal) const;
//! Returns tangent
const glm::vec4& GetTangent() const;
//! Sets tangent
void SetTangent(const glm::vec4& tangent) const;
//! Returns bone indices
const glm::u8vec4& GetBoneIndices() const;
//! Sets bone indices
void SetBoneIndices(const glm::u8vec4& indices) const;
//! Returns bone weights
const glm::vec4& GetBoneWeights() const;
//! Sets bone weights
void SetBoneWeights(const glm::vec4& weights) const;
};
template<typename T>
struct VertexAttributeArray
{
bool enabled = false;
std::vector<T> array = {};
};
/**
* \class CModelPart
* \brief Part of mesh with a common material
*/
class CModelPart
{
public:
//! Creates new part for given material
CModelPart(const Material& material, size_t vertices = 0, size_t indices = 0);
//! Returns this part's material
const Material& GetMaterial() const;
//! Sets the number of vertices
void SetVertices(size_t count);
//! Sets the number of indices
void SetIndices(size_t count);
//! Returns whether this mesh part contains specific vertex attribute
bool Has(VertexAttribute attribute) const;
//! Adds vertex attribute to this mesh part
void Add(VertexAttribute attribute);
//! Removes vertex attribute from this mesh part
void Remove(VertexAttribute attribute);
//! Returns true if this part is indexed
bool IsIndexed() const;
//! Returns the number of vertices in this part
size_t GetVertexCount() const;
//! Returns the number of indices in this part
size_t GetIndexCount() const;
//! Returns the indices in this part
const std::vector<unsigned int>& GetIndices() const;
//! Returns vertex proxy object for manipulating vertex data
CVertexProxy GetVertex(size_t index);
//! Returns vertex index
std::uint32_t GetIndex(size_t index);
//! Adds a vertex
void AddVertex(const Vertex3D& vertex);
//! Adds an index
void AddIndex(unsigned int index);
//! Set index
void SetIndex(size_t index, unsigned int value);
//! Fills the array with converted model triangles
void GetTriangles(std::vector<Gfx::ModelTriangle>& triangles);
friend class CVertexProxy;
private:
//! Material
Material m_material;
//! Positions
VertexAttributeArray<glm::vec3> m_positions;
//! Colors
VertexAttributeArray<glm::u8vec4> m_colors;
//! UVs 1
VertexAttributeArray<glm::vec2> m_uvs1;
//! UVs 2
VertexAttributeArray<glm::vec2> m_uvs2;
//! Normals
VertexAttributeArray<glm::vec3> m_normals;
//! Tangents
VertexAttributeArray<glm::vec4> m_tangents;
//! Bone indices
VertexAttributeArray<glm::u8vec4> m_boneIndices;
//! Bone weights
VertexAttributeArray<glm::vec4> m_boneWeights;
//! Indices
VertexAttributeArray<std::uint32_t> m_indices;
};
/**
* \class CModelMesh
* \brief Mesh data saved in model file
*/
class CModelMesh
{
public:
//! Adds a new triangle
void AddTriangle(const ModelTriangle& triangle);
//! Adds a new triangle
void AddTriangle(const Triangle& triangle, const Material& material);
//! Returns the number of parts
size_t GetPartCount() const;
//! Returns a part with given index
CModelPart* GetPart(size_t index) const;
//! Adds a new part with given material or returns an existing one
CModelPart* AddPart(const Material& material);
//! Returns the mesh position
const glm::vec3& GetPosition() const;
//! Sets the mesh rotation
void SetPosition(const glm::vec3& position);
//! Returns the mesh rotation
const glm::vec3& GetRotation() const;
//! Sets the mesh rotation
void SetRotation(const glm::vec3& rotation);
//! Returns the mesh scale
const glm::vec3& GetScale() const;
//! Sets the mesh scale
void SetScale(const glm::vec3& scale);
//! Returns the name of parent mesh
const std::string& GetParent() const;
//! Sets the name of parent mesh
void SetParent(const std::string& parent);
//! Returns all model triangles of this mesh
std::vector<ModelTriangle> GetTriangles() const;
private:
std::vector<std::unique_ptr<CModelPart>> m_parts;
glm::vec3 m_position = { 0, 0, 0 };
glm::vec3 m_rotation = { 0, 0, 0 };
glm::vec3 m_scale = { 1, 1, 1 };
std::string m_parent;
};
} // namespace Gfx

View File

@ -1,378 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/model/model_mod.h"
#include "common/ioutils.h"
#include "common/stringutils.h"
#include "common/resources/inputstream.h"
#include "graphics/model/model_io_exception.h"
#include "graphics/model/model_io_structs.h"
#include <array>
#include <iostream>
using namespace IOUtils;
namespace Gfx::ModelIO
{
std::vector<ModelTriangle> ReadOldModelV1(std::istream& stream, int totalTriangles);
std::vector<ModelTriangle> ReadOldModelV2(std::istream& stream, int totalTriangles);
std::vector<ModelTriangle> ReadOldModelV3(std::istream& stream, int totalTriangles);
Vertex3D ReadBinaryVertex(std::istream& stream);
Vertex3D ReadBinaryVertexTex2(std::istream& stream);
LegacyMaterial ReadBinaryMaterial(std::istream& stream);
void ConvertOldTex1Name(ModelTriangle& triangle, const char* tex1Name);
void ConvertFromOldRenderState(ModelTriangle& triangle, int state);
ModelLODLevel MinMaxToLodLevel(float min, float max);
std::unique_ptr<CModel> ReadOldModel(const std::filesystem::path& path)
{
CInputStream stream(path);
OldModelHeader header;
try
{
header.revision = ReadBinary<4, int>(stream);
header.version = ReadBinary<4, int>(stream);
header.totalTriangles = ReadBinary<4, int>(stream);
for (int i = 0; i < 10; ++i)
header.reserved[i] = ReadBinary<4, int>(stream);
}
catch (const std::exception& e)
{
throw CModelIOException(std::string("Error reading model file header: ") + e.what());
}
std::vector<ModelTriangle> triangles;
try
{
if (header.revision == 1 && header.version == 0)
{
triangles = ReadOldModelV1(stream, header.totalTriangles);
}
else if (header.revision == 1 && header.version == 1)
{
triangles = ReadOldModelV2(stream, header.totalTriangles);
}
else
{
triangles = ReadOldModelV3(stream, header.totalTriangles);
}
}
catch (const std::exception& e)
{
throw CModelIOException(std::string("Error reading model triangles: ") + e.what());
}
auto mesh = std::make_unique<CModelMesh>();
for (const auto& triangle : triangles)
mesh->AddTriangle(triangle);
auto model = std::make_unique<CModel>();
model->AddMesh("main", std::move(mesh));
return model;
}
std::vector<ModelTriangle> ReadOldModelV1(std::istream& stream, int totalTriangles)
{
std::vector<ModelTriangle> triangles;
for (int i = 0; i < totalTriangles; ++i)
{
OldModelTriangleV1 t;
t.used = ReadBinary<1, char>(stream);
t.selected = ReadBinary<1, char>(stream);
/* padding */ ReadBinary<2, unsigned int>(stream);
t.p1 = ReadBinaryVertex(stream);
t.p2 = ReadBinaryVertex(stream);
t.p3 = ReadBinaryVertex(stream);
auto material = ReadBinaryMaterial(stream);
stream.read(t.texName, 20);
t.min = ReadBinaryFloat(stream);
t.max = ReadBinaryFloat(stream);
ModelLODLevel lodLevel = MinMaxToLodLevel(t.min, t.max);
if (lodLevel == ModelLODLevel::Low ||
lodLevel == ModelLODLevel::Medium)
continue;
ModelTriangle triangle;
triangle.p1 = t.p1;
triangle.p2 = t.p2;
triangle.p3 = t.p3;
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
triangle.p1.color = color;
triangle.p2.color = color;
triangle.p3.color = color;
ConvertOldTex1Name(triangle, t.texName);
triangles.push_back(triangle);
}
return triangles;
}
std::vector<ModelTriangle> ReadOldModelV2(std::istream& stream, int totalTriangles)
{
std::vector<ModelTriangle> triangles;
for (int i = 0; i < totalTriangles; ++i)
{
OldModelTriangleV2 t;
t.used = ReadBinary<1, char>(stream);
t.selected = ReadBinary<1, char>(stream);
/* padding */ ReadBinary<2, unsigned int>(stream);
t.p1 = ReadBinaryVertex(stream);
t.p2 = ReadBinaryVertex(stream);
t.p3 = ReadBinaryVertex(stream);
auto material = ReadBinaryMaterial(stream);
stream.read(t.texName, 20);
t.min = ReadBinaryFloat(stream);
t.max = ReadBinaryFloat(stream);
t.state = ReadBinary<4, long>(stream);
t.reserved1 = ReadBinary<2, short>(stream);
t.reserved2 = ReadBinary<2, short>(stream);
t.reserved3 = ReadBinary<2, short>(stream);
t.reserved4 = ReadBinary<2, short>(stream);
ModelLODLevel lodLevel = MinMaxToLodLevel(t.min, t.max);
if (lodLevel == ModelLODLevel::Low ||
lodLevel == ModelLODLevel::Medium)
continue;
ModelTriangle triangle;
triangle.p1 = t.p1;
triangle.p2 = t.p2;
triangle.p3 = t.p3;
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
triangle.p1.color = color;
triangle.p2.color = color;
triangle.p3.color = color;
ConvertOldTex1Name(triangle, t.texName);
ConvertFromOldRenderState(triangle, t.state);
triangles.push_back(triangle);
}
return triangles;
}
std::vector<ModelTriangle> ReadOldModelV3(std::istream& stream, int totalTriangles)
{
std::vector<ModelTriangle> triangles;
for (int i = 0; i < totalTriangles; ++i)
{
OldModelTriangleV3 t;
t.used = ReadBinary<1, char>(stream);
t.selected = ReadBinary<1, char>(stream);
/* padding */ ReadBinary<2, unsigned int>(stream);
t.p1 = ReadBinaryVertexTex2(stream);
t.p2 = ReadBinaryVertexTex2(stream);
t.p3 = ReadBinaryVertexTex2(stream);
auto material = ReadBinaryMaterial(stream);
stream.read(t.texName, 20);
t.min = ReadBinaryFloat(stream);
t.max = ReadBinaryFloat(stream);
t.state = ReadBinary<4, long>(stream);
t.texNum2 = ReadBinary<2, short>(stream);
t.reserved2 = ReadBinary<2, short>(stream);
t.reserved3 = ReadBinary<2, short>(stream);
t.reserved4 = ReadBinary<2, short>(stream);
ModelLODLevel lodLevel = MinMaxToLodLevel(t.min, t.max);
if (lodLevel == ModelLODLevel::Low ||
lodLevel == ModelLODLevel::Medium)
continue;
ModelTriangle triangle;
triangle.p1 = t.p1;
triangle.p2 = t.p2;
triangle.p3 = t.p3;
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
triangle.p1.color = color;
triangle.p2.color = color;
triangle.p3.color = color;
ConvertOldTex1Name(triangle, t.texName);
ConvertFromOldRenderState(triangle, t.state);
triangle.material.variableDetail = t.texNum2 == 1;
if (!triangle.material.variableDetail && t.texNum2 != 0)
{
std::array<char, 20> tex2Name = {0};
std::snprintf(tex2Name.data(), tex2Name.size(), "dirty%.2d.png", t.texNum2);
triangle.material.detailTexture = tex2Name.data();
}
triangles.push_back(triangle);
}
return triangles;
}
ModelLODLevel MinMaxToLodLevel(float min, float max)
{
if (min == 0.0f && max == 100.0f)
return ModelLODLevel::High;
else if (min == 100.0f && max == 200.0f)
return ModelLODLevel::Medium;
else if (min == 200.0f && max == 1000000.0f)
return ModelLODLevel::Low;
else if (min == 0.0f && max == 1000000.0f)
return ModelLODLevel::Constant;
return ModelLODLevel::Constant;
}
void ConvertOldTex1Name(ModelTriangle& triangle, const char* tex1Name)
{
triangle.material.albedoTexture = tex1Name;
triangle.material.albedoTexture = StrUtils::Replace(
triangle.material.albedoTexture, "bmp", "png");
triangle.material.albedoTexture = StrUtils::Replace(
triangle.material.albedoTexture, "tga", "png");
}
void ConvertFromOldRenderState(ModelTriangle& triangle, int state)
{
if (triangle.material.albedoTexture == "plant.png" || (state & static_cast<int>(ModelRenderState::Alpha)) != 0)
{
triangle.material.alphaMode = AlphaMode::MASK;
triangle.material.alphaThreshold = 0.5f;
}
else
triangle.material.alphaMode = AlphaMode::NONE;
if ((state & static_cast<int>(ModelRenderState::Part1)) != 0)
triangle.material.tag = "tracker_right";
else if ((state & static_cast<int>(ModelRenderState::Part2)) != 0)
triangle.material.tag = "tracker_left";
else if ((state & static_cast<int>(ModelRenderState::Part3)) != 0)
triangle.material.tag = "energy";
else
triangle.material.tag = "";
bool doubleSided = (state & static_cast<int>(ModelRenderState::TwoFace)) != 0;
triangle.material.cullFace = doubleSided ? CullFace::NONE : CullFace::BACK;
}
Vertex3D ReadBinaryVertex(std::istream& stream)
{
Vertex3D vertex;
vertex.position.x = ReadBinaryFloat(stream);
vertex.position.y = ReadBinaryFloat(stream);
vertex.position.z = ReadBinaryFloat(stream);
vertex.normal.x = ReadBinaryFloat(stream);
vertex.normal.y = ReadBinaryFloat(stream);
vertex.normal.z = ReadBinaryFloat(stream);
vertex.uv.x = ReadBinaryFloat(stream);
vertex.uv.y = ReadBinaryFloat(stream);
return vertex;
}
Vertex3D ReadBinaryVertexTex2(std::istream& stream)
{
Vertex3D vertex;
vertex.position.x = ReadBinaryFloat(stream);
vertex.position.y = ReadBinaryFloat(stream);
vertex.position.z = ReadBinaryFloat(stream);
vertex.normal.x = ReadBinaryFloat(stream);
vertex.normal.y = ReadBinaryFloat(stream);
vertex.normal.z = ReadBinaryFloat(stream);
vertex.uv.x = ReadBinaryFloat(stream);
vertex.uv.y = ReadBinaryFloat(stream);
vertex.uv2.x = ReadBinaryFloat(stream);
vertex.uv2.y = ReadBinaryFloat(stream);
return vertex;
}
LegacyMaterial ReadBinaryMaterial(std::istream& stream)
{
LegacyMaterial material;
material.diffuse.r = ReadBinaryFloat(stream);
material.diffuse.g = ReadBinaryFloat(stream);
material.diffuse.b = ReadBinaryFloat(stream);
material.diffuse.a = ReadBinaryFloat(stream);
material.ambient.r = ReadBinaryFloat(stream);
material.ambient.g = ReadBinaryFloat(stream);
material.ambient.b = ReadBinaryFloat(stream);
material.ambient.a = ReadBinaryFloat(stream);
material.specular.r = ReadBinaryFloat(stream);
material.specular.g = ReadBinaryFloat(stream);
material.specular.b = ReadBinaryFloat(stream);
material.specular.a = ReadBinaryFloat(stream);
/* emissive.r = */ ReadBinaryFloat(stream);
/* emissive.g = */ ReadBinaryFloat(stream);
/* emissive.b = */ ReadBinaryFloat(stream);
/* emissive.a = */ ReadBinaryFloat(stream);
/* power = */ ReadBinaryFloat(stream);
return material;
}
}

View File

@ -1,36 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "graphics/model/model.h"
#include <filesystem>
#include <istream>
/**
* \namespace ModelInput
* \brief Namespace with functions to read model files
*/
namespace Gfx::ModelIO
{
std::unique_ptr<CModel> ReadOldModel(const std::filesystem::path& path);
}

View File

@ -1,429 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/model/model_mod.h"
#include "common/ioutils.h"
#include "common/stringutils.h"
#include "common/resources/inputstream.h"
#include "graphics/model/model_io_exception.h"
#include "graphics/model/model_io_structs.h"
using namespace IOUtils;
namespace Gfx::ModelIO
{
void ReadTextModelV1AndV2(CModel& model, std::istream& stream);
void ReadTextModelV3(CModel& model, std::istream& stream);
ModelHeaderV3 ReadTextHeader(std::istream& stream);
std::unique_ptr<CModelMesh> ReadTextMesh(std::istream& stream);
std::string ReadLineString(std::istream& stream, const std::string& expectedPrefix);
void ReadValuePrefix(std::istream& stream, const std::string& expectedPrefix);
Vertex3D ParseVertexTex2(const std::string& text);
LegacyMaterial ParseMaterial(const std::string& text);
glm::vec3 ParseVector(const std::string& text);
ModelCrashSphere ParseCrashSphere(const std::string& text);
ModelShadowSpot ParseShadowSpot(const std::string& text);
Math::Sphere ParseCameraCollisionSphere(const std::string& text);
AlphaMode ParseTransparentMode(const std::string& text);
std::string ParseSpecialMark(const std::string& text);
void ConvertFromOldRenderState(ModelTriangle& triangle, int state);
std::unique_ptr<CModel> ReadTextModel(const std::filesystem::path& path)
{
CInputStream stream(path);
int version = 0;
try
{
version = std::stoi(ReadLineString(stream, "version"));
stream.seekg(std::ios_base::beg);
}
catch (const std::exception& e)
{
throw CModelIOException(std::string("Error reading version number: ") + e.what());
}
auto model = std::make_unique<CModel>();
if (version == 1 || version == 2)
ReadTextModelV1AndV2(*model, stream);
else if (version == 3)
ReadTextModelV3(*model, stream);
else
throw CModelIOException(std::string("Unexpected version number: ") + std::to_string(version));
return model;
}
void ReadTextModelV1AndV2(CModel& model, std::istream& stream)
{
ModelHeaderV1AndV2 header;
try
{
header.version = std::stoi(ReadLineString(stream, "version"));
header.totalTriangles = std::stoi(ReadLineString(stream, "total_triangles"));
}
catch (const std::exception& e)
{
throw CModelIOException(std::string("Error reading model header: ") + e.what());
}
auto mesh = std::make_unique<CModelMesh>();
for (int i = 0; i < header.totalTriangles; ++i)
{
ModelTriangleV1AndV2 t;
std::string p1Text = ReadLineString(stream, "p1");
t.p1 = ParseVertexTex2(p1Text);
std::string p2Text = ReadLineString(stream, "p2");
t.p2 = ParseVertexTex2(p2Text);
std::string p3Text = ReadLineString(stream, "p3");
t.p3 = ParseVertexTex2(p3Text);
std::string matText = ReadLineString(stream, "mat");
auto material = ParseMaterial(matText);
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
t.p1.color = color;
t.p2.color = color;
t.p3.color = color;
t.tex1Name = ReadLineString(stream, "tex1");
t.tex2Name = ReadLineString(stream, "tex2");
std::string varTex2Ch = ReadLineString(stream, "var_tex2");
t.variableTex2 = varTex2Ch == "Y";
if (header.version == 1)
t.lodLevel = static_cast<ModelLODLevel>(std::stoi(ReadLineString(stream, "lod_level")));
t.state = std::stoi(ReadLineString(stream, "state"));
if (t.lodLevel == ModelLODLevel::Low ||
t.lodLevel == ModelLODLevel::Medium)
continue;
ModelTriangle triangle;
triangle.p1 = t.p1;
triangle.p2 = t.p2;
triangle.p3 = t.p3;
triangle.material.albedoTexture = t.tex1Name;
triangle.material.detailTexture = t.tex2Name;
triangle.material.variableDetail = t.variableTex2;
ConvertFromOldRenderState(triangle, t.state);
mesh->AddTriangle(triangle);
}
model.AddMesh("main", std::move(mesh));
}
void ReadTextModelV3(CModel& model, std::istream& stream)
{
ModelHeaderV3 header;
try
{
header = ReadTextHeader(stream);
}
catch (const std::exception& e)
{
throw CModelIOException(std::string("Error reading model header: ") + e.what());
}
for (int i = 0; i < header.totalCrashSpheres; ++i)
{
auto crashSphere = ParseCrashSphere(ReadLineString(stream, "crash_sphere"));
model.AddCrashSphere(crashSphere);
}
if (header.hasShadowSpot)
{
auto shadowSpot = ParseShadowSpot(ReadLineString(stream, "shadow_spot"));
model.SetShadowSpot(shadowSpot);
}
if (header.hasCameraCollisionSphere)
{
auto sphere = ParseCameraCollisionSphere(ReadLineString(stream, "camera_collision_sphere"));
model.SetCameraCollisionSphere(sphere);
}
for (int i = 0; i < header.totalMeshes; ++i)
{
std::string meshName = ReadLineString(stream, "mesh");
auto mesh = ReadTextMesh(stream);
model.AddMesh(meshName, std::move(mesh));
}
}
ModelHeaderV3 ReadTextHeader(std::istream& stream)
{
ModelHeaderV3 header;
header.version = std::stoi(ReadLineString(stream, "version"));
header.totalCrashSpheres = std::stoi(ReadLineString(stream, "total_crash_spheres"));
header.hasShadowSpot = ReadLineString(stream, "has_shadow_spot") == std::string("Y");
header.hasCameraCollisionSphere = ReadLineString(stream, "has_camera_collision_sphere") == std::string("Y");
header.totalMeshes = std::stoi(ReadLineString(stream, "total_meshes"));
return header;
}
std::unique_ptr<CModelMesh> ReadTextMesh(std::istream& stream)
{
auto mesh = std::make_unique<CModelMesh>();
mesh->SetPosition(ParseVector(ReadLineString(stream, "position")));
mesh->SetRotation(ParseVector(ReadLineString(stream, "rotation")));
mesh->SetScale(ParseVector(ReadLineString(stream, "scale")));
mesh->SetParent(ReadLineString(stream, "parent"));
int totalTriangles = std::stoi(ReadLineString(stream, "total_triangles"));
for (int i = 0; i < totalTriangles; ++i)
{
ModelTriangleV3 t;
std::string p1Text = ReadLineString(stream, "p1");
t.p1 = ParseVertexTex2(p1Text);
std::string p2Text = ReadLineString(stream, "p2");
t.p2 = ParseVertexTex2(p2Text);
std::string p3Text = ReadLineString(stream, "p3");
t.p3 = ParseVertexTex2(p3Text);
std::string matText = ReadLineString(stream, "mat");
LegacyMaterial mat = ParseMaterial(matText);
auto diffuse = Gfx::ColorToIntColor(mat.diffuse);
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
t.p1.color = color;
t.p2.color = color;
t.p3.color = color;
t.material.albedoTexture = ReadLineString(stream, "tex1");
t.material.detailTexture = ReadLineString(stream, "tex2");
t.material.variableDetail = ReadLineString(stream, "var_tex2") == std::string("Y");
t.material.alphaMode = ParseTransparentMode(ReadLineString(stream, "trans_mode"));
t.material.tag = ParseSpecialMark(ReadLineString(stream, "mark"));
bool doubleSided = ReadLineString(stream, "dbl_side") == std::string("Y");
t.material.cullFace = doubleSided ? CullFace::NONE : CullFace::BACK;
if (t.material.alphaMode != AlphaMode::NONE)
t.material.alphaThreshold = 0.5f;
mesh->AddTriangle(t);
}
return mesh;
}
std::string ReadLineString(std::istream& stream, const std::string& expectedPrefix)
{
std::string line;
while (true)
{
if (stream.eof())
throw CModelIOException("Unexpected EOF");
std::getline(stream, line);
StrUtils::TrimRight(line);
if (!line.empty() && line[0] != '#')
break;
}
std::stringstream s;
s.str(line);
std::string prefix;
s >> prefix;
if (prefix != expectedPrefix)
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "'");
std::string value;
std::getline(s, value);
StrUtils::TrimLeft(value);
return value;
}
void ReadValuePrefix(std::istream& stream, const std::string& expectedPrefix)
{
std::string prefix;
stream >> prefix;
if (prefix != expectedPrefix)
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "', expected was: '" + expectedPrefix + "'");
}
Vertex3D ParseVertexTex2(const std::string& text)
{
Vertex3D vertex;
std::stringstream stream;
stream.str(text);
ReadValuePrefix(stream, "c");
stream >> vertex.position.x >> vertex.position.y >> vertex.position.z;
ReadValuePrefix(stream, "n");
stream >> vertex.normal.x >> vertex.normal.y >> vertex.normal.z;
ReadValuePrefix(stream, "t1");
stream >> vertex.uv.x >> vertex.uv.y;
ReadValuePrefix(stream, "t2");
stream >> vertex.uv2.x >> vertex.uv2.y;
return vertex;
}
LegacyMaterial ParseMaterial(const std::string& text)
{
LegacyMaterial material;
std::stringstream stream;
stream.str(text);
ReadValuePrefix(stream, "dif");
stream >> material.diffuse.r
>> material.diffuse.g
>> material.diffuse.b
>> material.diffuse.a;
ReadValuePrefix(stream, "amb");
stream >> material.ambient.r
>> material.ambient.g
>> material.ambient.b
>> material.ambient.a;
ReadValuePrefix(stream, "spc");
stream >> material.specular.r
>> material.specular.g
>> material.specular.b
>> material.specular.a;
return material;
}
glm::vec3 ParseVector(const std::string& text)
{
glm::vec3 vector = { 0, 0, 0 };
std::stringstream stream;
stream.str(text);
stream >> vector.x >> vector.y >> vector.z;
return vector;
}
ModelCrashSphere ParseCrashSphere(const std::string& text)
{
ModelCrashSphere crashSphere;
std::stringstream stream;
stream.str(text);
ReadValuePrefix(stream, "pos");
stream >> crashSphere.position.x
>> crashSphere.position.y
>> crashSphere.position.z;
ReadValuePrefix(stream, "rad");
stream >> crashSphere.radius;
ReadValuePrefix(stream, "sound");
stream >> crashSphere.sound;
ReadValuePrefix(stream, "hard");
stream >> crashSphere.hardness;
return crashSphere;
}
ModelShadowSpot ParseShadowSpot(const std::string& text)
{
ModelShadowSpot shadowSpot;
std::stringstream stream;
stream.str(text);
ReadValuePrefix(stream, "rad");
stream >> shadowSpot.radius;
ReadValuePrefix(stream, "int");
stream >> shadowSpot.intensity;
return shadowSpot;
}
Math::Sphere ParseCameraCollisionSphere(const std::string& text)
{
Math::Sphere sphere;
std::stringstream stream;
stream.str(text);
ReadValuePrefix(stream, "pos");
stream >> sphere.pos.x
>> sphere.pos.y
>> sphere.pos.z;
ReadValuePrefix(stream, "rad");
stream >> sphere.radius;
return sphere;
}
AlphaMode ParseTransparentMode(const std::string& text)
{
if (text == "none")
return AlphaMode::NONE;
else if (text == "alpha")
return AlphaMode::MASK;
else
return AlphaMode::NONE;
}
std::string ParseSpecialMark(const std::string& text)
{
if (text == "none")
return "";
else if (text == "part1")
return "tracker_right";
else if (text == "part2")
return "tracker_left";
else if (text == "part3")
return "energy";
else
throw CModelIOException(std::string("Unexpected special mark: '") + text + "'");
}
}

View File

@ -1,36 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
#include "graphics/model/model.h"
#include <filesystem>
#include <istream>
/**
* \namespace ModelInput
* \brief Namespace with functions to read model files
*/
namespace Gfx::ModelIO
{
std::unique_ptr<CModel> ReadTextModel(const std::filesystem::path& path);
}

View File

@ -1,8 +0,0 @@
/**
* \dir src/graphics/opengl33
* \brief OpenGL 3.3 engine implementation
*
* Contains the concrete implementation using OpenGL 3.3 of abstract CDevice class
* from src/graphics/core
*/

View File

@ -1,715 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/opengl33/gl33_device.h"
#include "graphics/opengl33/gl33_object_renderer.h"
#include "graphics/opengl33/gl33_particle_renderer.h"
#include "graphics/opengl33/gl33_shadow_renderer.h"
#include "graphics/opengl33/gl33_terrain_renderer.h"
#include "graphics/opengl33/gl33_ui_renderer.h"
#include "graphics/opengl33/glframebuffer.h"
#include "common/config.h"
#include "common/config_file.h"
#include "common/image.h"
#include "common/logger.h"
#include "common/version.h"
#include "graphics/core/light.h"
#include "graphics/core/material.h"
#include "graphics/core/transparency.h"
#include "graphics/engine/engine.h"
#include "math/geometry.h"
#include <SDL.h>
#include <physfs.h>
#include <cassert>
#include <glm/gtc/type_ptr.hpp>
// Graphics module namespace
namespace Gfx
{
CGL33VertexBuffer::CGL33VertexBuffer(PrimitiveType type, size_t size)
: CVertexBuffer(type, size)
{
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
glGenBuffers(1, &m_vbo);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferData(GL_ARRAY_BUFFER, m_data.size() * sizeof(Vertex3D), nullptr, GL_STATIC_DRAW);
// Vertex coordinate
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), reinterpret_cast<void*>(offsetof(Vertex3D, position)));
// Normal
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), reinterpret_cast<void*>(offsetof(Vertex3D, normal)));
// Color
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex3D), reinterpret_cast<void*>(offsetof(Vertex3D, color)));
// Texture coordinate 0
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), reinterpret_cast<void*>(offsetof(Vertex3D, uv)));
// Texture coordinate 1
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), reinterpret_cast<void*>(offsetof(Vertex3D, uv2)));
}
CGL33VertexBuffer::~CGL33VertexBuffer()
{
glDeleteVertexArrays(1, &m_vao);
glDeleteBuffers(1, &m_vbo);
}
void CGL33VertexBuffer::Update()
{
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_data.size() * sizeof(Vertex3D), m_data.data());
}
CGL33Device::CGL33Device(const DeviceConfig &config)
: m_config(config)
{}
CGL33Device::~CGL33Device()
{
}
std::string CGL33Device::GetName()
{
return std::string("OpenGL 3.3");
}
bool CGL33Device::Create()
{
GetLogger()->Info("Creating CDevice - OpenGL 3.3\n");
if (!InitializeGLEW())
{
m_errorMessage = "An error occurred while initializing GLEW.";
return false;
}
// Extract OpenGL version
int glMajor, glMinor;
int glVersion = GetOpenGLVersion(glMajor, glMinor);
if (glVersion < 32)
{
GetLogger()->Error("Unsupported OpenGL version: %d.%d\n", glMajor, glMinor);
GetLogger()->Error("OpenGL 3.2 or newer is required to use this engine.\n");
m_errorMessage = "It seems your graphics card does not support OpenGL 3.2.\n";
m_errorMessage += "Please make sure you have appropriate hardware and newest drivers installed.\n";
m_errorMessage += "(OpenGL 3.2 is roughly equivalent to Direct3D 10)\n\n";
m_errorMessage += GetHardwareInfo();
return false;
}
else if (glVersion < 33)
{
GetLogger()->Warn("Partially supported OpenGL version: %d.%d\n", glMajor, glMinor);
GetLogger()->Warn("You may experience problems while running the game on this engine.\n");
GetLogger()->Warn("OpenGL 3.3 or newer is recommended.\n");
}
else
{
const char* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
const char* renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
GetLogger()->Info("OpenGL %s\n", version);
GetLogger()->Info("%s\n", renderer);
}
// Detect support of anisotropic filtering
m_capabilities.anisotropySupported = AreExtensionsSupported("GL_EXT_texture_filter_anisotropic");
if (m_capabilities.anisotropySupported)
{
// Obtain maximum anisotropy level available
float level;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &level);
m_capabilities.maxAnisotropy = static_cast<int>(level);
GetLogger()->Info("Anisotropic filtering available\n");
GetLogger()->Info("Maximum anisotropy: %d\n", m_capabilities.maxAnisotropy);
}
else
{
GetLogger()->Info("Anisotropic filtering not available\n");
}
m_capabilities.multisamplingSupported = true;
glGetIntegerv(GL_MAX_SAMPLES, &m_capabilities.maxSamples);
GetLogger()->Info("Multisampling supported, max samples: %d\n", m_capabilities.maxSamples);
// Set just to be sure
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glViewport(0, 0, m_config.size.x, m_config.size.y);
// this is set in shader
m_capabilities.maxLights = 4;
int maxTextures = 0;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextures);
GetLogger()->Info("Maximum texture image units: %d\n", maxTextures);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_capabilities.maxTextureSize);
GetLogger()->Info("Maximum texture size: %d\n", m_capabilities.maxTextureSize);
m_capabilities.multitexturingSupported = true;
m_capabilities.maxTextures = maxTextures;
m_capabilities.shadowMappingSupported = true;
m_capabilities.framebufferSupported = true;
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &m_capabilities.maxRenderbufferSize);
GetLogger()->Info("Maximum renderbuffer size: %d\n", m_capabilities.maxRenderbufferSize);
m_uiRenderer = std::make_unique<CGL33UIRenderer>(this);
m_terrainRenderer = std::make_unique<CGL33TerrainRenderer>(this);
m_objectRenderer = std::make_unique<CGL33ObjectRenderer>(this);
m_particleRenderer = std::make_unique<CGL33ParticleRenderer>(this);
m_shadowRenderer = std::make_unique<CGL33ShadowRenderer>(this);
// create default framebuffer object
FramebufferParams framebufferParams;
framebufferParams.width = m_config.size.x;
framebufferParams.height = m_config.size.y;
framebufferParams.depth = m_config.depthSize;
m_framebuffers["default"] = std::make_unique<CDefaultFramebuffer>(framebufferParams);
GetLogger()->Info("CDevice created successfully\n");
return true;
}
void CGL33Device::Destroy()
{
// delete shader program
glUseProgram(0);
// delete framebuffers
for (auto& framebuffer : m_framebuffers)
framebuffer.second->Destroy();
m_framebuffers.clear();
// Delete the remaining textures
// Should not be strictly necessary, but just in case
DestroyAllTextures();
for (auto buffer : m_buffers)
delete buffer;
m_buffers.clear();
m_uiRenderer = nullptr;
m_terrainRenderer = nullptr;
m_objectRenderer = nullptr;
m_particleRenderer = nullptr;
m_shadowRenderer = nullptr;
}
void CGL33Device::ConfigChanged(const DeviceConfig& newConfig)
{
m_config = newConfig;
// Reset state
glViewport(0, 0, m_config.size.x, m_config.size.y);
// create default framebuffer object
FramebufferParams framebufferParams;
framebufferParams.width = m_config.size.x;
framebufferParams.height = m_config.size.y;
framebufferParams.depth = m_config.depthSize;
m_framebuffers["default"] = std::make_unique<CDefaultFramebuffer>(framebufferParams);
}
void CGL33Device::BeginScene()
{
Clear();
glDisable(GL_BLEND);
m_transparency = TransparencyMode::NONE;
glDisable(GL_DEPTH_TEST);
m_depthTest = false;
glDepthMask(GL_TRUE);
m_depthMask = true;
glFrontFace(GL_CW); // Colobot issue: faces are reversed
m_cullFace = CullFace::NONE;
glDisable(GL_CULL_FACE);
}
void CGL33Device::EndScene()
{
if constexpr (Version::DEVELOPMENT_BUILD)
CheckGLErrors();
}
void CGL33Device::Clear()
{
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
CUIRenderer* CGL33Device::GetUIRenderer()
{
return m_uiRenderer.get();
}
CTerrainRenderer* CGL33Device::GetTerrainRenderer()
{
return m_terrainRenderer.get();
}
CObjectRenderer* CGL33Device::GetObjectRenderer()
{
return m_objectRenderer.get();
}
CParticleRenderer* CGL33Device::GetParticleRenderer()
{
return m_particleRenderer.get();
}
CShadowRenderer* CGL33Device::GetShadowRenderer()
{
return m_shadowRenderer.get();
}
/** If image is invalid, returns invalid texture.
Otherwise, returns pointer to new Texture struct.
This struct must not be deleted in other way than through DeleteTexture() */
Texture CGL33Device::CreateTexture(CImage *image, const TextureCreateParams &params)
{
ImageData *data = image->GetData();
if (data == nullptr)
{
GetLogger()->Error("Invalid texture data\n");
return Texture(); // invalid texture
}
glm::ivec2 originalSize = image->GetSize();
if (params.padToNearestPowerOfTwo)
image->PadToNearestPowerOfTwo();
Texture tex = CreateTexture(data, params);
tex.originalSize = originalSize;
return tex;
}
Texture CGL33Device::CreateTexture(ImageData *data, const TextureCreateParams &params)
{
Texture result;
result.size.x = data->surface->w;
result.size.y = data->surface->h;
result.originalSize = result.size;
glGenTextures(1, &result.id);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, result.id);
// Set texture parameters
GLint minF = GL_NEAREST, magF = GL_NEAREST;
int mipmapLevel = 1;
switch (params.filter)
{
case TextureFilter::NEAREST:
minF = GL_NEAREST;
magF = GL_NEAREST;
break;
case TextureFilter::BILINEAR:
minF = GL_LINEAR;
magF = GL_LINEAR;
break;
case TextureFilter::TRILINEAR:
minF = GL_LINEAR_MIPMAP_LINEAR;
magF = GL_LINEAR;
mipmapLevel = CEngine::GetInstance().GetTextureMipmapLevel();
break;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minF);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magF);
GLint wrap = GL_REPEAT;
switch (params.wrap)
{
case TextureWrapMode::REPEAT:
wrap = GL_REPEAT;
break;
case TextureWrapMode::CLAMP:
wrap = GL_CLAMP;
break;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
// Set mipmap level and automatic mipmap generation if neccesary
if (params.mipmap)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapLevel - 1);
}
else
{
// Has to be set to 0 because no mipmaps are generated
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
}
// Set anisotropy level if available
if (m_capabilities.anisotropySupported)
{
float level = Math::Min(m_capabilities.maxAnisotropy, CEngine::GetInstance().GetTextureAnisotropyLevel());
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, level);
}
PreparedTextureData texData = PrepareTextureData(data, params.format);
result.alpha = texData.alpha;
glPixelStorei(GL_UNPACK_ROW_LENGTH, texData.actualSurface->pitch / texData.actualSurface->format->BytesPerPixel);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texData.actualSurface->w, texData.actualSurface->h,
0, texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels);
if (params.mipmap)
glGenerateMipmap(GL_TEXTURE_2D);
SDL_FreeSurface(texData.convertedSurface);
m_allTextures.insert(result);
return result;
}
Texture CGL33Device::CreateDepthTexture(int width, int height, int depth)
{
Texture result;
result.alpha = false;
result.size.x = width;
result.size.y = height;
glGenTextures(1, &result.id);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, result.id);
GLuint format = GL_DEPTH_COMPONENT;
switch (depth)
{
case 16:
format = GL_DEPTH_COMPONENT16;
break;
case 24:
format = GL_DEPTH_COMPONENT24;
break;
case 32:
format = GL_DEPTH_COMPONENT32;
break;
}
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
return result;
}
void CGL33Device::UpdateTexture(const Texture& texture, const glm::ivec2& offset, ImageData* data, TextureFormat format)
{
if (texture.id == 0) return;
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, texture.id);
PreparedTextureData texData = PrepareTextureData(data, format);
glPixelStorei(GL_UNPACK_ROW_LENGTH, texData.actualSurface->pitch / texData.actualSurface->format->BytesPerPixel);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexSubImage2D(GL_TEXTURE_2D, 0, offset.x, offset.y, texData.actualSurface->w, texData.actualSurface->h,
texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels);
glGenerateMipmap(GL_TEXTURE_2D);
SDL_FreeSurface(texData.convertedSurface);
}
void CGL33Device::DestroyTexture(const Texture &texture)
{
auto it = m_allTextures.find(texture);
if (it != m_allTextures.end())
{
glDeleteTextures(1, &texture.id);
m_allTextures.erase(it);
}
}
void CGL33Device::DestroyAllTextures()
{
// Unbind all texture stages
for (int index = 0; index < 32; ++index)
{
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, 0);
}
for (auto it = m_allTextures.begin(); it != m_allTextures.end(); ++it)
glDeleteTextures(1, &(*it).id);
m_allTextures.clear();
}
CVertexBuffer* CGL33Device::CreateVertexBuffer(PrimitiveType primitiveType, const Vertex3D* vertices, int vertexCount)
{
auto buffer = new CGL33VertexBuffer(primitiveType, vertexCount);
buffer->SetData(vertices, 0, vertexCount);
buffer->Update();
m_buffers.insert(buffer);
return buffer;
}
void CGL33Device::DestroyVertexBuffer(CVertexBuffer* buffer)
{
if (m_buffers.count(buffer) == 0) return;
m_buffers.erase(buffer);
delete buffer;
}
void CGL33Device::SetViewport(int x, int y, int width, int height)
{
glViewport(x, y, width, height);
}
void CGL33Device::SetDepthTest(bool enabled)
{
if (m_depthTest == enabled) return;
m_depthTest = enabled;
if (enabled)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
}
void CGL33Device::SetDepthMask(bool enabled)
{
if (m_depthMask == enabled) return;
m_depthMask = enabled;
glDepthMask(enabled ? GL_TRUE : GL_FALSE);
}
void CGL33Device::SetCullFace(CullFace mode)
{
if (m_cullFace == mode) return;
m_cullFace = mode;
switch (mode)
{
case CullFace::NONE:
glDisable(GL_CULL_FACE);
break;
case CullFace::BACK:
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
break;
case CullFace::FRONT:
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
break;
case CullFace::BOTH:
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT_AND_BACK);
break;
}
}
void CGL33Device::SetTransparency(TransparencyMode mode)
{
if (m_transparency == mode) return;
m_transparency = mode;
switch (mode)
{
case TransparencyMode::NONE:
glDisable(GL_BLEND);
break;
case TransparencyMode::ALPHA:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
break;
case TransparencyMode::BLACK:
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
glBlendEquation(GL_FUNC_ADD);
break;
case TransparencyMode::WHITE:
glEnable(GL_BLEND);
glBlendFunc(GL_DST_COLOR, GL_ZERO);
glBlendEquation(GL_FUNC_ADD);
break;
}
}
void CGL33Device::SetColorMask(bool red, bool green, bool blue, bool alpha)
{
glColorMask(red, green, blue, alpha);
}
void CGL33Device::SetClearColor(const Color &color)
{
glClearColor(color.r, color.g, color.b, color.a);
}
void CGL33Device::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
{
if (texture.id == 0) return;
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, texture.id);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height);
}
std::unique_ptr<CFrameBufferPixels> CGL33Device::GetFrameBufferPixels() const
{
return GetGLFrameBufferPixels(m_config.size);
}
CFramebuffer* CGL33Device::GetFramebuffer(std::string name)
{
auto it = m_framebuffers.find(name);
if (it == m_framebuffers.end())
return nullptr;
return it->second.get();
}
CFramebuffer* CGL33Device::CreateFramebuffer(std::string name, const FramebufferParams& params)
{
// existing framebuffer was found
if (m_framebuffers.find(name) != m_framebuffers.end())
{
return nullptr;
}
auto framebuffer = std::make_unique<CGLFramebuffer>(params);
if (!framebuffer->Create()) return nullptr;
CFramebuffer* framebufferPtr = framebuffer.get();
m_framebuffers[name] = std::move(framebuffer);
return framebufferPtr;
}
void CGL33Device::DeleteFramebuffer(std::string name)
{
// can't delete default framebuffer
if (name == "default") return;
auto it = m_framebuffers.find(name);
if (it != m_framebuffers.end())
{
it->second->Destroy();
m_framebuffers.erase(it);
}
}
bool CGL33Device::IsAnisotropySupported()
{
return m_capabilities.anisotropySupported;
}
int CGL33Device::GetMaxAnisotropyLevel()
{
return m_capabilities.maxAnisotropy;
}
int CGL33Device::GetMaxSamples()
{
return m_capabilities.maxSamples;
}
bool CGL33Device::IsShadowMappingSupported()
{
return true;
}
int CGL33Device::GetMaxTextureSize()
{
return m_capabilities.maxTextureSize;
}
bool CGL33Device::IsFramebufferSupported()
{
return true;
}
} // namespace Gfx

View File

@ -1,192 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/opengl33/gl33_device.h
* \brief OpenGL 3.3 implementation - CGL33Device class
*/
#pragma once
#include "graphics/core/device.h"
#include "graphics/opengl33/glframebuffer.h"
#include "graphics/opengl33/glutil.h"
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include <unordered_set>
// Graphics module namespace
namespace Gfx
{
enum class CullFace : unsigned char;
enum class TransparencyMode : unsigned char;
class CGL33VertexBuffer : public CVertexBuffer
{
GLuint m_vao = 0;
GLuint m_vbo = 0;
public:
CGL33VertexBuffer(PrimitiveType type, size_t size);
virtual ~CGL33VertexBuffer();
virtual void Update() override;
GLuint GetVAO() const
{
return m_vao;
}
GLuint GetVBO() const
{
return m_vbo;
}
};
class CGL33UIRenderer;
class CGL33TerrainRenderer;
class CGL33ObjectRenderer;
class CGL33ParticleRenderer;
class CGL33ShadowRenderer;
/**
\class CGL33Device
\brief Implementation of CDevice interface in OpenGL 3.3
Provides the concrete implementation of 3D device in OpenGL.
This class should be initialized (by calling Initialize() ) only after
setting the video mode by CApplication, once the OpenGL context is defined.
Because of that, CGLDeviceConfig is outside the CDevice class and must be set
in CApplication.
*/
class CGL33Device : public CDevice
{
public:
CGL33Device(const DeviceConfig &config);
virtual ~CGL33Device();
std::string GetName() override;
bool Create() override;
void Destroy() override;
void ConfigChanged(const DeviceConfig &newConfig) override;
void BeginScene() override;
void EndScene() override;
void Clear() override;
CUIRenderer* GetUIRenderer() override;
CTerrainRenderer* GetTerrainRenderer() override;
CObjectRenderer* GetObjectRenderer() override;
CParticleRenderer* GetParticleRenderer() override;
CShadowRenderer* GetShadowRenderer() override;
Texture CreateTexture(CImage *image, const TextureCreateParams &params) override;
Texture CreateTexture(ImageData *data, const TextureCreateParams &params) override;
Texture CreateDepthTexture(int width, int height, int depth) override;
void UpdateTexture(const Texture& texture, const glm::ivec2& offset, ImageData* data, TextureFormat format) override;
void DestroyTexture(const Texture &texture) override;
void DestroyAllTextures() override;
CVertexBuffer* CreateVertexBuffer(PrimitiveType primitiveType, const Vertex3D* vertices, int vertexCount) override;
void DestroyVertexBuffer(CVertexBuffer*) override;
void SetViewport(int x, int y, int width, int height) override;
void SetDepthTest(bool enabled) override;
void SetDepthMask(bool enabled) override;
void SetCullFace(CullFace mode) override;
void SetTransparency(TransparencyMode mode) override;
void SetColorMask(bool red, bool green, bool blue, bool alpha) override;
void SetClearColor(const Color &color) override;
void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) override;
std::unique_ptr<CFrameBufferPixels> GetFrameBufferPixels() const override;
CFramebuffer* GetFramebuffer(std::string name) override;
CFramebuffer* CreateFramebuffer(std::string name, const FramebufferParams& params) override;
void DeleteFramebuffer(std::string name) override;
bool IsAnisotropySupported() override;
int GetMaxAnisotropyLevel() override;
int GetMaxSamples() override;
bool IsShadowMappingSupported() override;
int GetMaxTextureSize() override;
bool IsFramebufferSupported() override;
private:
//! Current config
DeviceConfig m_config;
//! Set of all created textures
std::set<Texture> m_allTextures;
//! Detected capabilities
//! Set of vertex buffers
std::unordered_set<CVertexBuffer*> m_buffers;
//! Total memory allocated in VBOs
unsigned long m_vboMemory = 0;
//! Map of framebuffers
std::map<std::string, std::unique_ptr<CFramebuffer>> m_framebuffers;
//! Interface renderer
std::unique_ptr<CGL33UIRenderer> m_uiRenderer;
//! Terrain renderer
std::unique_ptr<CGL33TerrainRenderer> m_terrainRenderer;
//! Object renderer
std::unique_ptr<CGL33ObjectRenderer> m_objectRenderer;
//! Particle renderer
std::unique_ptr<CGL33ParticleRenderer> m_particleRenderer;
//! Shadow renderer
std::unique_ptr<CGL33ShadowRenderer> m_shadowRenderer;
//! Depth test
bool m_depthTest = false;
//! Depth mask
bool m_depthMask = true;
//! Cull face mode
CullFace m_cullFace = {};
//! Transparency mode
TransparencyMode m_transparency = {};
};
} // namespace Gfx

View File

@ -1,506 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/opengl33/gl33_object_renderer.h"
#include "graphics/opengl33/gl33_device.h"
#include "graphics/opengl33/glutil.h"
#include "graphics/core/material.h"
#include "graphics/core/transparency.h"
#include "graphics/core/vertex.h"
#include "common/logger.h"
#include <GL/glew.h>
#include <glm/ext.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace Gfx;
CGL33ObjectRenderer::CGL33ObjectRenderer(CGL33Device* device)
:m_device(device)
{
GetLogger()->Info("Creating CGL33ObjectRenderer\n");
std::string preamble = LoadSource("shaders/gl33/preamble.glsl");
std::string shadowSource = LoadSource("shaders/gl33/shadow.glsl");
std::string lightingSource = LoadSource("shaders/gl33/lighting.glsl");
std::string vsSource = LoadSource("shaders/gl33/object_vs.glsl");
std::string fsSource = LoadSource("shaders/gl33/object_fs.glsl");
GLint vsShader = CreateShader(GL_VERTEX_SHADER, { preamble, lightingSource, shadowSource, vsSource });
if (vsShader == 0)
{
GetLogger()->Error("Cound not create vertex shader from file 'object_vs.glsl'\n");
return;
}
GLint fsShader = CreateShader(GL_FRAGMENT_SHADER, { preamble, lightingSource, shadowSource, fsSource });
if (fsShader == 0)
{
GetLogger()->Error("Cound not create fragment shader from file 'object_fs.glsl'\n");
return;
}
m_program = LinkProgram({ vsShader, fsShader });
glDeleteShader(vsShader);
glDeleteShader(fsShader);
glUseProgram(m_program);
// Setup uniforms
glm::mat4 identity(1.0f);
m_projectionMatrix = glGetUniformLocation(m_program, "uni_ProjectionMatrix");
m_viewMatrix = glGetUniformLocation(m_program, "uni_ViewMatrix");
m_shadowMatrix = glGetUniformLocation(m_program, "uni_ShadowMatrix");
m_modelMatrix = glGetUniformLocation(m_program, "uni_ModelMatrix");
m_normalMatrix = glGetUniformLocation(m_program, "uni_NormalMatrix");
m_lighting = glGetUniformLocation(m_program, "uni_Lighting");
m_cameraPosition = glGetUniformLocation(m_program, "uni_CameraPosition");
m_lightPosition = glGetUniformLocation(m_program, "uni_LightPosition");
m_lightIntensity = glGetUniformLocation(m_program, "uni_LightIntensity");
m_lightColor = glGetUniformLocation(m_program, "uni_LightColor");
m_skyColor = glGetUniformLocation(m_program, "uni_SkyColor");
m_skyIntensity = glGetUniformLocation(m_program, "uni_SkyIntensity");
m_fogRange = glGetUniformLocation(m_program, "uni_FogRange");
m_fogColor = glGetUniformLocation(m_program, "uni_FogColor");
m_albedoColor = glGetUniformLocation(m_program, "uni_AlbedoColor");
m_emissiveColor = glGetUniformLocation(m_program, "uni_EmissiveColor");
m_roughness = glGetUniformLocation(m_program, "uni_Roughness");
m_metalness = glGetUniformLocation(m_program, "uni_Metalness");
m_aoStrength = glGetUniformLocation(m_program, "uni_AOStrength");
m_triplanarMode = glGetUniformLocation(m_program, "uni_TriplanarMode");
m_triplanarScale = glGetUniformLocation(m_program, "uni_TriplanarScale");
m_alphaScissor = glGetUniformLocation(m_program, "uni_AlphaScissor");
m_recolor = glGetUniformLocation(m_program, "uni_Recolor");
m_recolorFrom = glGetUniformLocation(m_program, "uni_RecolorFrom");
m_recolorTo = glGetUniformLocation(m_program, "uni_RecolorTo");
m_recolorThreshold = glGetUniformLocation(m_program, "uni_RecolorThreshold");
m_uvOffset = glGetUniformLocation(m_program, "uni_UVOffset");
m_uvScale = glGetUniformLocation(m_program, "uni_UVScale");
m_shadowRegions = glGetUniformLocation(m_program, "uni_ShadowRegions");
std::array<GLchar, 256> name;
for (int i = 0; i < 4; i++)
{
snprintf(name.data(), name.size(), "uni_ShadowParam[%d].transform", i);
m_shadows[i].transform = glGetUniformLocation(m_program, name.data());
snprintf(name.data(), name.size(), "uni_ShadowParam[%d].uv_offset", i);
m_shadows[i].offset = glGetUniformLocation(m_program, name.data());
snprintf(name.data(), name.size(), "uni_ShadowParam[%d].uv_scale", i);
m_shadows[i].scale = glGetUniformLocation(m_program, name.data());
}
// Set texture units
auto texture = glGetUniformLocation(m_program, "uni_AlbedoTexture");
glUniform1i(texture, m_albedoIndex);
texture = glGetUniformLocation(m_program, "uni_DetailTexture");
glUniform1i(texture, m_detailIndex);
texture = glGetUniformLocation(m_program, "uni_EmissiveTexture");
glUniform1i(texture, m_emissiveIndex);
texture = glGetUniformLocation(m_program, "uni_MaterialTexture");
glUniform1i(texture, m_materialIndex);
texture = glGetUniformLocation(m_program, "uni_ShadowMap");
glUniform1i(texture, m_shadowIndex);
// White texture
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &m_whiteTexture);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
// Generic buffer
glGenBuffers(1, &m_bufferVBO);
glBindBuffer(GL_COPY_WRITE_BUFFER, m_bufferVBO);
glBufferData(GL_COPY_WRITE_BUFFER, 8 * sizeof(Vertex3D), nullptr, GL_STREAM_DRAW);
glGenVertexArrays(1, &m_bufferVAO);
glBindVertexArray(m_bufferVAO);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
GetLogger()->Info("CGL33ObjectRenderer created successfully\n");
}
CGL33ObjectRenderer::~CGL33ObjectRenderer()
{
glDeleteProgram(m_program);
glDeleteTextures(1, &m_whiteTexture);
glDeleteBuffers(1, &m_bufferVBO);
glDeleteVertexArrays(1, &m_bufferVAO);
}
void CGL33ObjectRenderer::CGL33ObjectRenderer::Begin()
{
glUseProgram(m_program);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glActiveTexture(GL_TEXTURE0 + m_albedoIndex);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glActiveTexture(GL_TEXTURE0 + m_detailIndex);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glActiveTexture(GL_TEXTURE0 + m_emissiveIndex);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glActiveTexture(GL_TEXTURE0 + m_materialIndex);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glActiveTexture(GL_TEXTURE0 + m_shadowIndex);
glBindTexture(GL_TEXTURE_2D, 0);
m_albedoTexture = 0;
m_detailTexture = 0;
m_emissiveTexture = 0;
m_materialTexture = 0;
m_shadowMap = 0;
m_device->SetDepthTest(true);
m_device->SetDepthMask(true);
m_device->SetTransparency(TransparencyMode::NONE);
m_device->SetCullFace(CullFace::BACK);
SetUVTransform({ 0.0f, 0.0f }, { 1.0f, 1.0f });
SetAlphaScissor(0.0f);
SetFog(1e+6f, 1e+6, {});
SetEmissiveColor({ 0, 0, 0, 0 });
SetAlbedoColor({ 1, 1, 1, 1 });
SetMaterialParams(1.0, 0.0, 0.0);
SetRecolor(false);
}
void CGL33ObjectRenderer::CGL33ObjectRenderer::End()
{
glActiveTexture(GL_TEXTURE0 + m_albedoIndex);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0 + m_detailIndex);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0 + m_emissiveIndex);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0 + m_materialIndex);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0 + m_shadowIndex);
glBindTexture(GL_TEXTURE_2D, 0);
m_albedoTexture = 0;
m_detailTexture = 0;
m_emissiveTexture = 0;
m_materialTexture = 0;
m_shadowMap = 0;
}
void CGL33ObjectRenderer::SetProjectionMatrix(const glm::mat4& matrix)
{
glUniformMatrix4fv(m_projectionMatrix, 1, GL_FALSE, value_ptr(matrix));
}
void CGL33ObjectRenderer::SetViewMatrix(const glm::mat4& matrix)
{
glm::mat4 scale(1.0f);
scale[2][2] = -1.0f;
auto viewMatrix = scale * matrix;
auto cameraMatrix = glm::inverse(viewMatrix);
auto cameraPos = cameraMatrix[3];
glUniformMatrix4fv(m_viewMatrix, 1, GL_FALSE, value_ptr(viewMatrix));
glUniform3f(m_cameraPosition, cameraPos.x, cameraPos.y, cameraPos.z);
}
void CGL33ObjectRenderer::SetModelMatrix(const glm::mat4& matrix)
{
auto normalMatrix = glm::transpose(glm::inverse(glm::mat3(matrix)));
glUniformMatrix4fv(m_modelMatrix, 1, GL_FALSE, value_ptr(matrix));
glUniformMatrix3fv(m_normalMatrix, 1, GL_FALSE, value_ptr(normalMatrix));
}
void CGL33ObjectRenderer::SetAlbedoColor(const Color& color)
{
glUniform4f(m_albedoColor, color.r, color.g, color.b, color.a);
}
void CGL33ObjectRenderer::SetAlbedoTexture(const Texture& texture)
{
if (m_albedoTexture == texture.id) return;
m_albedoTexture = texture.id;
glActiveTexture(GL_TEXTURE0 + m_albedoIndex);
if (texture.id == 0)
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
else
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33ObjectRenderer::SetEmissiveColor(const Color& color)
{
glUniform3f(m_emissiveColor, color.r, color.g, color.b);
}
void CGL33ObjectRenderer::SetEmissiveTexture(const Texture& texture)
{
if (m_emissiveTexture == texture.id) return;
m_emissiveTexture = texture.id;
glActiveTexture(GL_TEXTURE0 + m_emissiveIndex);
if (texture.id == 0)
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
else
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33ObjectRenderer::SetMaterialParams(float roughness, float metalness, float aoStrength)
{
glUniform1f(m_roughness, roughness);
glUniform1f(m_metalness, metalness);
glUniform1f(m_aoStrength, aoStrength);
}
void CGL33ObjectRenderer::SetMaterialTexture(const Texture& texture)
{
if (m_materialTexture == texture.id) return;
m_materialTexture = texture.id;
glActiveTexture(GL_TEXTURE0 + m_materialIndex);
if (texture.id == 0)
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
else
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33ObjectRenderer::SetDetailTexture(const Texture& texture)
{
if (m_detailTexture == texture.id) return;
m_detailTexture = texture.id;
glActiveTexture(GL_TEXTURE0 + m_detailIndex);
if (texture.id == 0)
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
else
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33ObjectRenderer::SetShadowMap(const Texture& texture)
{
if (m_shadowMap == texture.id) return;
m_shadowMap = texture.id;
glActiveTexture(GL_TEXTURE0 + m_shadowIndex);
if (texture.id == 0)
glBindTexture(GL_TEXTURE_2D, 0);
else
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33ObjectRenderer::SetLighting(bool enabled)
{
glUniform1i(m_lighting, enabled ? 1 : 0);
}
void CGL33ObjectRenderer::SetLight(const glm::vec4& position, const float& intensity, const glm::vec3& color)
{
glUniform4fv(m_lightPosition, 1, glm::value_ptr(position));
glUniform1f(m_lightIntensity, intensity);
glUniform3f(m_lightColor, color.r, color.g, color.b);
}
void CGL33ObjectRenderer::SetSky(const Color& color, float intensity)
{
glUniform3f(m_skyColor, color.r, color.g, color.b);
glUniform1f(m_skyIntensity, intensity);
}
void CGL33ObjectRenderer::SetShadowParams(int count, const ShadowParam* params)
{
glUniform1i(m_shadowRegions, count);
for (int i = 0; i < count; i++)
{
glUniformMatrix4fv(m_shadows[i].transform, 1, GL_FALSE, glm::value_ptr(params[i].matrix));
glUniform2fv(m_shadows[i].offset, 1, glm::value_ptr(params[i].uv_offset));
glUniform2fv(m_shadows[i].scale, 1, glm::value_ptr(params[i].uv_scale));
}
}
void CGL33ObjectRenderer::SetFog(float min, float max, const glm::vec3& color)
{
glUniform2f(m_fogRange, min, max);
glUniform3f(m_fogColor, color.r, color.g, color.b);
}
void CGL33ObjectRenderer::SetDepthTest(bool enabled)
{
m_device->SetDepthTest(enabled);
}
void CGL33ObjectRenderer::SetDepthMask(bool enabled)
{
m_device->SetDepthMask(enabled);
}
void CGL33ObjectRenderer::SetCullFace(CullFace mode)
{
m_device->SetCullFace(mode);
}
void CGL33ObjectRenderer::SetTransparency(TransparencyMode mode)
{
m_device->SetTransparency(mode);
}
void CGL33ObjectRenderer::SetUVTransform(const glm::vec2& offset, const glm::vec2& scale)
{
glUniform2fv(m_uvOffset, 1, glm::value_ptr(offset));
glUniform2fv(m_uvScale, 1, glm::value_ptr(scale));
}
void CGL33ObjectRenderer::SetTriplanarMode(bool enabled)
{
glUniform1i(m_triplanarMode, enabled ? 1 : 0);
}
void CGL33ObjectRenderer::SetTriplanarScale(float scale)
{
glUniform1f(m_triplanarScale, scale);
}
void CGL33ObjectRenderer::SetAlphaScissor(float alpha)
{
glUniform1f(m_alphaScissor, alpha);
}
void CGL33ObjectRenderer::SetRecolor(bool enabled, const glm::vec3& from, const glm::vec3& to, float threshold)
{
glUniform1i(m_recolor, enabled ? 1 : 0);
if (enabled)
{
auto fromHSV = RGB2HSV(Color(from.r, from.g, from.b, 1.0));
auto toHSV = RGB2HSV(Color(to.r, to.g, to.b, 1.0));
glUniform3f(m_recolorFrom, fromHSV.h, fromHSV.s, fromHSV.v);
glUniform3f(m_recolorTo, toHSV.h, toHSV.s, toHSV.v);
glUniform1f(m_recolorThreshold, threshold);
}
}
void CGL33ObjectRenderer::DrawObject(const CVertexBuffer* buffer)
{
auto b = dynamic_cast<const CGL33VertexBuffer*>(buffer);
if (b == nullptr) return;
glBindVertexArray(b->GetVAO());
glDrawArrays(TranslateGfxPrimitive(b->GetType()), 0, static_cast<GLsizei>(b->Size()));
}
void CGL33ObjectRenderer::DrawPrimitive(PrimitiveType type, int count, const Vertex3D* vertices)
{
DrawPrimitives(type, 1, &count, vertices);
}
void CGL33ObjectRenderer::DrawPrimitives(PrimitiveType type, int drawCount, int count[], const Vertex3D* vertices)
{
m_first.resize(drawCount);
GLint offset = 0;
for (size_t i = 0; i < drawCount; i++)
{
m_first[i] = offset;
offset += count[i];
}
glBindVertexArray(m_bufferVAO);
glBindBuffer(GL_ARRAY_BUFFER, m_bufferVBO);
size_t size = offset * sizeof(Vertex3D);
// Send new vertices to GPU
glBindBuffer(GL_ARRAY_BUFFER, m_bufferVBO);
glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, size, vertices);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D),
reinterpret_cast<void*>(offsetof(Vertex3D, position)));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D),
reinterpret_cast<void*>(offsetof(Vertex3D, normal)));
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex3D),
reinterpret_cast<void*>(offsetof(Vertex3D, color)));
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex3D),
reinterpret_cast<void*>(offsetof(Vertex3D, uv)));
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex3D),
reinterpret_cast<void*>(offsetof(Vertex3D, uv2)));
glMultiDrawArrays(TranslateGfxPrimitive(type), m_first.data(), count, drawCount);
}

View File

@ -1,196 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/opengl33/gl33_object_renderer.h
* \brief OpenGL 3.3 object renderer
*/
#pragma once
#include "graphics/core/renderers.h"
#include <GL/glew.h>
#include <array>
#include <vector>
// Graphics module namespace
namespace Gfx
{
class CGL33Device;
class CGL33ObjectRenderer : public CObjectRenderer
{
public:
CGL33ObjectRenderer(CGL33Device* device);
virtual ~CGL33ObjectRenderer();
virtual void Begin() override;
virtual void End() override;
//! Sets projection matrix
virtual void SetProjectionMatrix(const glm::mat4& matrix) override;
//! Sets view matrix
virtual void SetViewMatrix(const glm::mat4& matrix) override;
//! Sets model matrix
virtual void SetModelMatrix(const glm::mat4& matrix) override;
//! Sets albedo color
virtual void SetAlbedoColor(const Color& color) override;
//! Sets albedo texture
virtual void SetAlbedoTexture(const Texture& texture) override;
//! Sets emissive color
virtual void SetEmissiveColor(const Color& color) override;
//! Sets emissive texture
virtual void SetEmissiveTexture(const Texture& texture) override;
//! Sets material parameters
virtual void SetMaterialParams(float roughness, float metalness, float aoStrength) override;
//! Sets material texture
virtual void SetMaterialTexture(const Texture& texture) override;
//! Sets detail texture
virtual void SetDetailTexture(const Texture& texture) override;
//! Sets shadow map
virtual void SetShadowMap(const Texture& texture) override;
//! Enables lighting
virtual void SetLighting(bool enabled) override;
//! Sets light parameters
virtual void SetLight(const glm::vec4& position, const float& intensity, const glm::vec3& color) override;
//! Sets sky parameters
virtual void SetSky(const Color& color, float intensity) override;
//! Sets shadow parameters
virtual void SetShadowParams(int count, const ShadowParam* params) override;
//! Sets fog parameters
virtual void SetFog(float min, float max, const glm::vec3& color) override;
//! Sets alpha scissor
virtual void SetAlphaScissor(float alpha) override;
//! Sets recolor parameters
virtual void SetRecolor(bool enabled, const glm::vec3& from = {}, const glm::vec3& to = {}, float threshold = {}) override;
virtual void SetDepthTest(bool enabled) override;
virtual void SetDepthMask(bool enabled) override;
//! Sets cull mode parameters
virtual void SetCullFace(CullFace mode) override;
//! Sets transparency mode
virtual void SetTransparency(TransparencyMode mode) override;
//! Sets UV transform
virtual void SetUVTransform(const glm::vec2& offset, const glm::vec2& scale) override;
//! Sets triplanar mode
virtual void SetTriplanarMode(bool enabled) override;
//! Sets triplanar scale
virtual void SetTriplanarScale(float scale) override;
//! Draws an object
virtual void DrawObject(const CVertexBuffer* buffer) override;
//! Draws a primitive
virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex3D* vertices) override;
//! Draws a set of primitives
virtual void DrawPrimitives(PrimitiveType type, int drawCount, int count[], const Vertex3D* vertices) override;
private:
CGL33Device* const m_device;
// Uniform data
GLint m_projectionMatrix = -1;
GLint m_viewMatrix = -1;
GLint m_shadowMatrix = -1;
GLint m_modelMatrix = -1;
GLint m_normalMatrix = -1;
GLint m_lighting = -1;
GLint m_cameraPosition = -1;
GLint m_lightPosition = -1;
GLint m_lightIntensity = -1;
GLint m_lightColor = -1;
GLint m_skyColor = -1;
GLint m_skyIntensity = -1;
GLint m_fogRange = -1;
GLint m_fogColor = -1;
GLint m_albedoColor = -1;
GLint m_emissiveColor = -1;
GLint m_roughness = -1;
GLint m_metalness = -1;
GLint m_aoStrength = -1;
GLint m_triplanarMode = -1;
GLint m_triplanarScale = -1;
GLint m_alphaScissor = -1;
GLint m_recolor = -1;
GLint m_recolorFrom = -1;
GLint m_recolorTo = -1;
GLint m_recolorThreshold = -1;
GLint m_uvOffset = -1;
GLint m_uvScale = -1;
struct ShadowUniforms
{
GLint transform;
GLint offset;
GLint scale;
};
GLint m_shadowRegions = 0;
ShadowUniforms m_shadows[4] = {};
// Shader program
GLuint m_program = 0;
// Texture unit bindings
const int m_albedoIndex = 4;
const int m_detailIndex = 5;
const int m_emissiveIndex = 6;
const int m_materialIndex = 7;
const int m_shadowIndex = 8;
// 1x1 white texture
GLuint m_whiteTexture = 0;
// Currently bound albedo texture
GLuint m_albedoTexture = 0;
// Currently bound detail texture
GLuint m_detailTexture = 0;
// Currently bound emissive texture
GLuint m_emissiveTexture = 0;
// Currently bound material texture
GLuint m_materialTexture = 0;
// Currently bound shadow map
GLuint m_shadowMap = 0;
// Vertex buffer object
GLuint m_bufferVBO = 0;
// Vertex array object
GLuint m_bufferVAO = 0;
// Offsets
std::vector<GLint> m_first;
};
}

View File

@ -1,246 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/opengl33/gl33_particle_renderer.h"
#include "graphics/opengl33/gl33_device.h"
#include "graphics/opengl33/glutil.h"
#include "graphics/core/material.h"
#include "graphics/core/transparency.h"
#include "graphics/core/vertex.h"
#include "common/logger.h"
#include <GL/glew.h>
#include <glm/ext.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <algorithm>
using namespace Gfx;
CGL33ParticleRenderer::CGL33ParticleRenderer(CGL33Device* device)
: m_device(device)
{
GetLogger()->Info("Creating CGL33ParticleRenderer\n");
std::string preamble = LoadSource("shaders/gl33/preamble.glsl");
std::string shadowSource = LoadSource("shaders/gl33/shadow.glsl");
std::string vsSource = LoadSource("shaders/gl33/particle_vs.glsl");
std::string fsSource = LoadSource("shaders/gl33/particle_fs.glsl");
GLint vsShader = CreateShader(GL_VERTEX_SHADER, { preamble, shadowSource, vsSource });
if (vsShader == 0)
{
GetLogger()->Error("Cound not create vertex shader from file 'particle_vs.glsl'\n");
return;
}
GLint fsShader = CreateShader(GL_FRAGMENT_SHADER, { preamble, shadowSource, fsSource });
if (fsShader == 0)
{
GetLogger()->Error("Cound not create fragment shader from file 'particle_fs.glsl'\n");
return;
}
m_program = LinkProgram({ vsShader, fsShader });
glDeleteShader(vsShader);
glDeleteShader(fsShader);
glUseProgram(m_program);
// Setup uniforms
m_projectionMatrix = glGetUniformLocation(m_program, "uni_ProjectionMatrix");
m_viewMatrix = glGetUniformLocation(m_program, "uni_ViewMatrix");
m_modelMatrix = glGetUniformLocation(m_program, "uni_ModelMatrix");
m_fogRange = glGetUniformLocation(m_program, "uni_FogRange");
m_fogColor = glGetUniformLocation(m_program, "uni_FogColor");
m_color = glGetUniformLocation(m_program, "uni_Color");
m_alphaScissor = glGetUniformLocation(m_program, "uni_AlphaScissor");
// Set texture units
auto texture = glGetUniformLocation(m_program, "uni_Texture");
glUniform1i(texture, 10);
glUniform1f(m_alphaScissor, 0.5f);
// White texture
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &m_whiteTexture);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
glUseProgram(0);
// Generic buffer
glGenBuffers(1, &m_bufferVBO);
glBindBuffer(GL_COPY_WRITE_BUFFER, m_bufferVBO);
glBufferData(GL_COPY_WRITE_BUFFER, m_bufferCapacity * sizeof(VertexParticle), nullptr, GL_STREAM_DRAW);
m_bufferOffset = m_bufferCapacity;
glGenVertexArrays(1, &m_bufferVAO);
glBindVertexArray(m_bufferVAO);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
GetLogger()->Info("CGL33ParticleRenderer created successfully\n");
}
CGL33ParticleRenderer::~CGL33ParticleRenderer()
{
glDeleteProgram(m_program);
glDeleteTextures(1, &m_whiteTexture);
}
void CGL33ParticleRenderer::Begin()
{
glUseProgram(m_program);
glActiveTexture(GL_TEXTURE10);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
m_texture = 0;
m_device->SetDepthTest(true);
m_device->SetDepthMask(false);
m_device->SetCullFace(CullFace::NONE);
glUniform4f(m_color, 1.0f, 1.0f, 1.0f, 1.0f);
glBindVertexArray(m_bufferVAO);
glBindBuffer(GL_ARRAY_BUFFER, m_bufferVBO);
}
void CGL33ParticleRenderer::End()
{
glActiveTexture(GL_TEXTURE10);
glBindTexture(GL_TEXTURE_2D, 0);
m_texture = 0;
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void CGL33ParticleRenderer::SetProjectionMatrix(const glm::mat4& matrix)
{
glUniformMatrix4fv(m_projectionMatrix, 1, GL_FALSE, value_ptr(matrix));
}
void CGL33ParticleRenderer::SetViewMatrix(const glm::mat4& matrix)
{
glm::mat4 scale(1.0f);
scale[2][2] = -1.0f;
auto viewMatrix = scale * matrix;
glUniformMatrix4fv(m_viewMatrix, 1, GL_FALSE, value_ptr(viewMatrix));
}
void CGL33ParticleRenderer::SetModelMatrix(const glm::mat4& matrix)
{
glUniformMatrix4fv(m_modelMatrix, 1, GL_FALSE, value_ptr(matrix));
}
void CGL33ParticleRenderer::SetColor(const glm::vec4& color)
{
glUniform4f(m_color, color.r, color.g, color.b, color.a);
}
void CGL33ParticleRenderer::SetTexture(const Texture& texture)
{
if (m_texture == texture.id) return;
m_texture = texture.id;
glActiveTexture(GL_TEXTURE10);
if (texture.id == 0)
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
else
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33ParticleRenderer::SetTransparency(TransparencyMode mode)
{
m_device->SetTransparency(mode);
}
void CGL33ParticleRenderer::DrawParticle(PrimitiveType type, int count, const VertexParticle* vertices)
{
GLuint total = m_bufferOffset + count;
// Buffer full, orphan
if (total >= m_bufferCapacity)
{
glBufferData(GL_ARRAY_BUFFER, m_bufferCapacity * sizeof(VertexParticle), nullptr, GL_STREAM_DRAW);
m_bufferOffset = 0;
// Respecify vertex attributes
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexParticle),
reinterpret_cast<void*>(offsetof(VertexParticle, position)));
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VertexParticle),
reinterpret_cast<void*>(offsetof(VertexParticle, color)));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexParticle),
reinterpret_cast<void*>(offsetof(VertexParticle, uv)));
}
void* ptr = glMapBufferRange(GL_ARRAY_BUFFER,
m_bufferOffset * sizeof(VertexParticle),
count * sizeof(VertexParticle),
GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
if (ptr)
{
auto buffer = reinterpret_cast<VertexParticle*>(ptr);
std::copy_n(vertices, count, buffer);
glUnmapBuffer(GL_ARRAY_BUFFER);
}
else
{
glBufferSubData(GL_ARRAY_BUFFER,
m_bufferOffset * sizeof(VertexParticle),
count * sizeof(VertexParticle),
vertices);
}
glDrawArrays(TranslateGfxPrimitive(type),
m_bufferOffset,
count);
m_bufferOffset += count;
}

View File

@ -1,98 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/opengl33/gl33_particle_renderer.h
* \brief OpenGL 3.3 particle renderer
*/
#pragma once
#include "graphics/core/renderers.h"
#include <GL/glew.h>
#include <array>
#include <vector>
// Graphics module namespace
namespace Gfx
{
class CGL33Device;
class CGL33ParticleRenderer : public CParticleRenderer
{
public:
CGL33ParticleRenderer(CGL33Device* device);
virtual ~CGL33ParticleRenderer();
virtual void Begin() override;
virtual void End() override;
//! Sets projection matrix
virtual void SetProjectionMatrix(const glm::mat4& matrix) override;
//! Sets view matrix
virtual void SetViewMatrix(const glm::mat4& matrix) override;
//! Sets model matrix
virtual void SetModelMatrix(const glm::mat4& matrix) override;
//! Sets color
virtual void SetColor(const glm::vec4& color) override;
//! Sets texture
virtual void SetTexture(const Texture& texture) override;
//! Sets transparency mode
virtual void SetTransparency(TransparencyMode mode) override;
//! Draws particles
virtual void DrawParticle(PrimitiveType type, int count, const VertexParticle* vertices) override;
private:
CGL33Device* const m_device;
// Uniform data
GLint m_projectionMatrix = -1;
GLint m_viewMatrix = -1;
GLint m_modelMatrix = -1;
GLint m_fogRange = -1;
GLint m_fogColor = -1;
GLint m_color = -1;
GLint m_alphaScissor = -1;
// Shader program
GLuint m_program = 0;
// 1x1 white texture
GLuint m_whiteTexture = 0;
// Currently bound primary texture
GLuint m_texture = 0;
// Vertex buffer object
GLuint m_bufferVBO = 0;
// Vertex array object
GLuint m_bufferVAO = 0;
// VBO capacity
GLsizei m_bufferCapacity = 64 * 1024;
// Buffer offset
GLsizei m_bufferOffset = 0;
};
}

View File

@ -1,192 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/opengl33/gl33_shadow_renderer.h"
#include "graphics/opengl33/gl33_device.h"
#include "graphics/opengl33/glutil.h"
#include "graphics/core/material.h"
#include "graphics/core/transparency.h"
#include "graphics/core/vertex.h"
#include "common/logger.h"
#include <GL/glew.h>
#include <glm/ext.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <algorithm>
using namespace Gfx;
CGL33ShadowRenderer::CGL33ShadowRenderer(CGL33Device* device)
: m_device(device)
{
GetLogger()->Info("Creating CGL33ShadowRenderer\n");
GLint shaders[2] = {};
shaders[0] = LoadShader(GL_VERTEX_SHADER, "shaders/gl33/shadow_vs.glsl");
if (shaders[0] == 0)
{
GetLogger()->Error("Cound not create vertex shader from file 'shadow_vs.glsl'\n");
return;
}
shaders[1] = LoadShader(GL_FRAGMENT_SHADER, "shaders/gl33/shadow_fs.glsl");
if (shaders[1] == 0)
{
GetLogger()->Error("Cound not create fragment shader from file 'shadow_fs.glsl'\n");
return;
}
m_program = LinkProgram(2, shaders);
if (m_program == 0)
{
GetLogger()->Error("Cound not link shader program for terrain renderer\n");
return;
}
glDeleteShader(shaders[0]);
glDeleteShader(shaders[1]);
glUseProgram(m_program);
// Setup uniforms
auto texture = glGetUniformLocation(m_program, "uni_Texture");
glUniform1i(texture, 0);
glm::mat4 identity(1.0f);
m_projectionMatrix = glGetUniformLocation(m_program, "uni_ProjectionMatrix");
m_viewMatrix = glGetUniformLocation(m_program, "uni_ViewMatrix");
m_modelMatrix = glGetUniformLocation(m_program, "uni_ModelMatrix");
m_alphaScissor = glGetUniformLocation(m_program, "uni_AlphaScissor");
glUseProgram(0);
glGenFramebuffers(1, &m_framebuffer);
GetLogger()->Info("CGL33ShadowRenderer created successfully\n");
}
CGL33ShadowRenderer::~CGL33ShadowRenderer()
{
glDeleteProgram(m_program);
glDeleteFramebuffers(1, &m_framebuffer);
}
void CGL33ShadowRenderer::Begin()
{
glViewport(0, 0, m_width, m_height);
m_device->SetDepthMask(true);
glClear(GL_DEPTH_BUFFER_BIT);
glUseProgram(m_program);
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(2.0f, 8.0f);
m_device->SetColorMask(false, false, false, false);
m_device->SetDepthTest(true);
m_device->SetDepthMask(true);
m_device->SetTransparency(TransparencyMode::NONE);
m_device->SetCullFace(CullFace::NONE);
}
void CGL33ShadowRenderer::End()
{
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(0.0f, 0.0f);
m_device->SetColorMask(true, true, true, true);
}
void CGL33ShadowRenderer::SetProjectionMatrix(const glm::mat4& matrix)
{
glUniformMatrix4fv(m_projectionMatrix, 1, GL_FALSE, value_ptr(matrix));
}
void CGL33ShadowRenderer::SetViewMatrix(const glm::mat4& matrix)
{
glm::mat4 scale(1.0f);
scale[2][2] = -1.0f;
auto viewMatrix = scale * matrix;
glUniformMatrix4fv(m_viewMatrix, 1, GL_FALSE, value_ptr(viewMatrix));
}
void CGL33ShadowRenderer::SetModelMatrix(const glm::mat4& matrix)
{
glUniformMatrix4fv(m_modelMatrix, 1, GL_FALSE, value_ptr(matrix));
}
void CGL33ShadowRenderer::SetTexture(const Texture& texture)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33ShadowRenderer::SetShadowMap(const Texture& texture)
{
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture.id, 0);
m_width = texture.size.x;
m_height = texture.size.y;
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
GetLogger()->Error("Framebuffer incomplete: %d\n", status);
}
}
void CGL33ShadowRenderer::SetShadowRegion(const glm::vec2& offset, const glm::vec2& scale)
{
int x = static_cast<int>(m_width * offset.x);
int y = static_cast<int>(m_height * offset.y);
int width = static_cast<int>(m_width * scale.x);
int height = static_cast<int>(m_height * scale.y);
glViewport(x, y, width, height);
}
void CGL33ShadowRenderer::DrawObject(const CVertexBuffer* buffer, bool transparent)
{
auto b = dynamic_cast<const CGL33VertexBuffer*>(buffer);
if (b == nullptr) return;
glUniform1i(m_alphaScissor, transparent ? 1 : 0);
glBindVertexArray(b->GetVAO());
glDrawArrays(TranslateGfxPrimitive(b->GetType()), 0, b->Size());
}

View File

@ -1,86 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/opengl33/gl33_shadow_renderer.h
* \brief OpenGL 3.3 shadow renderer
*/
#pragma once
#include "graphics/core/renderers.h"
#include <GL/glew.h>
#include <array>
#include <vector>
// Graphics module namespace
namespace Gfx
{
class CGL33Device;
class CGL33ShadowRenderer : public CShadowRenderer
{
public:
CGL33ShadowRenderer(CGL33Device* device);
virtual ~CGL33ShadowRenderer();
virtual void Begin() override;
virtual void End() override;
//! Sets projection matrix
virtual void SetProjectionMatrix(const glm::mat4& matrix) override;
//! Sets view matrix
virtual void SetViewMatrix(const glm::mat4& matrix) override;
//! Sets model matrix
virtual void SetModelMatrix(const glm::mat4& matrix) override;
//! Sets texture
virtual void SetTexture(const Texture& texture) override;
//! Sets shadow map
virtual void SetShadowMap(const Texture& texture) override;
//! Sets shadow region
virtual void SetShadowRegion(const glm::vec2& offset, const glm::vec2& scale) override;
//! Draws terrain object
virtual void DrawObject(const CVertexBuffer* buffer, bool transparent) override;
private:
CGL33Device* const m_device;
// Uniform data
GLint m_projectionMatrix = -1;
GLint m_viewMatrix = -1;
GLint m_modelMatrix = -1;
GLint m_alphaScissor = -1;
// Shader program
GLuint m_program = 0;
// Framebuffer
GLuint m_framebuffer = 0;
int m_width = 0;
int m_height = 0;
};
} // namespace Gfx

View File

@ -1,377 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/opengl33/gl33_terrain_renderer.h"
#include "graphics/opengl33/gl33_device.h"
#include "graphics/opengl33/glutil.h"
#include "graphics/core/material.h"
#include "graphics/core/transparency.h"
#include "graphics/core/vertex.h"
#include "common/logger.h"
#include <GL/glew.h>
#include <glm/ext.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <algorithm>
using namespace Gfx;
CGL33TerrainRenderer::CGL33TerrainRenderer(CGL33Device* device)
: m_device(device)
{
GetLogger()->Info("Creating CGL33TerrainRenderer\n");
std::string preamble = LoadSource("shaders/gl33/preamble.glsl");
std::string shadowSource = LoadSource("shaders/gl33/shadow.glsl");
std::string lightingSource = LoadSource("shaders/gl33/lighting.glsl");
std::string vsSource = LoadSource("shaders/gl33/terrain_vs.glsl");
std::string fsSource = LoadSource("shaders/gl33/terrain_fs.glsl");
GLint vsShader = CreateShader(GL_VERTEX_SHADER, { preamble, lightingSource, shadowSource, vsSource });
if (vsShader == 0)
{
GetLogger()->Error("Cound not create vertex shader from file 'terrain_vs.glsl'\n");
return;
}
GLint fsShader = CreateShader(GL_FRAGMENT_SHADER, { preamble, lightingSource, shadowSource, fsSource });
if (fsShader == 0)
{
GetLogger()->Error("Cound not create fragment shader from file 'terrain_vs.glsl'\n");
return;
}
m_program = LinkProgram({ vsShader, fsShader });
if (m_program == 0)
{
GetLogger()->Error("Cound not link shader program for terrain renderer\n");
return;
}
glDeleteShader(vsShader);
glDeleteShader(fsShader);
glUseProgram(m_program);
// Setup uniforms
glm::mat4 identity(1.0f);
m_projectionMatrix = glGetUniformLocation(m_program, "uni_ProjectionMatrix");
m_viewMatrix = glGetUniformLocation(m_program, "uni_ViewMatrix");
m_shadowMatrix = glGetUniformLocation(m_program, "uni_ShadowMatrix");
m_modelMatrix = glGetUniformLocation(m_program, "uni_ModelMatrix");
m_normalMatrix = glGetUniformLocation(m_program, "uni_NormalMatrix");
m_cameraPosition = glGetUniformLocation(m_program, "uni_CameraPosition");
m_lightPosition = glGetUniformLocation(m_program, "uni_LightPosition");
m_lightIntensity = glGetUniformLocation(m_program, "uni_LightIntensity");
m_lightColor = glGetUniformLocation(m_program, "uni_LightColor");
m_skyColor = glGetUniformLocation(m_program, "uni_SkyColor");
m_skyIntensity = glGetUniformLocation(m_program, "uni_SkyIntensity");
m_fogRange = glGetUniformLocation(m_program, "uni_FogRange");
m_fogColor = glGetUniformLocation(m_program, "uni_FogColor");
m_albedoColor = glGetUniformLocation(m_program, "uni_AlbedoColor");
m_emissiveColor = glGetUniformLocation(m_program, "uni_EmissiveColor");
m_roughness = glGetUniformLocation(m_program, "uni_Roughness");
m_metalness = glGetUniformLocation(m_program, "uni_Metalness");
m_aoStrength = glGetUniformLocation(m_program, "uni_AOStrength");
m_shadowRegions = glGetUniformLocation(m_program, "uni_ShadowRegions");
std::array<GLchar, 256> name;
for (int i = 0; i < 4; i++)
{
snprintf(name.data(), name.size(), "uni_ShadowParam[%d].transform", i);
m_shadows[i].transform = glGetUniformLocation(m_program, name.data());
snprintf(name.data(), name.size(), "uni_ShadowParam[%d].uv_offset", i);
m_shadows[i].offset = glGetUniformLocation(m_program, name.data());
snprintf(name.data(), name.size(), "uni_ShadowParam[%d].uv_scale", i);
m_shadows[i].scale = glGetUniformLocation(m_program, name.data());
}
// Set texture units
auto texture = glGetUniformLocation(m_program, "uni_AlbedoTexture");
glUniform1i(texture, m_albedoIndex);
texture = glGetUniformLocation(m_program, "uni_DetailTexture");
glUniform1i(texture, m_detailIndex);
texture = glGetUniformLocation(m_program, "uni_EmissiveTexture");
glUniform1i(texture, m_emissiveIndex);
texture = glGetUniformLocation(m_program, "uni_MaterialTexture");
glUniform1i(texture, m_materialIndex);
texture = glGetUniformLocation(m_program, "uni_ShadowMap");
glUniform1i(texture, m_shadowIndex);
// White texture
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &m_whiteTexture);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
glUseProgram(0);
GetLogger()->Info("CGL33TerrainRenderer created successfully\n");
}
CGL33TerrainRenderer::~CGL33TerrainRenderer()
{
glDeleteProgram(m_program);
glDeleteTextures(1, &m_whiteTexture);
}
void CGL33TerrainRenderer::Begin()
{
glUseProgram(m_program);
m_device->SetDepthTest(true);
m_device->SetDepthMask(true);
m_device->SetCullFace(CullFace::BACK);
m_device->SetTransparency(TransparencyMode::NONE);
glActiveTexture(GL_TEXTURE0 + m_albedoIndex);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glActiveTexture(GL_TEXTURE0 + m_detailIndex);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glActiveTexture(GL_TEXTURE0 + m_emissiveIndex);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glActiveTexture(GL_TEXTURE0 + m_materialIndex);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glActiveTexture(GL_TEXTURE0 + m_shadowIndex);
glBindTexture(GL_TEXTURE_2D, 0);
m_albedoTexture = 0;
m_detailTexture = 0;
m_emissiveTexture = 0;
m_materialTexture = 0;
m_shadowMap = 0;
m_device->SetDepthTest(true);
m_device->SetDepthMask(true);
m_device->SetTransparency(TransparencyMode::NONE);
m_device->SetCullFace(CullFace::BACK);
SetFog(1e+6f, 1e+6, {});
}
void CGL33TerrainRenderer::End()
{
glActiveTexture(GL_TEXTURE0 + m_albedoIndex);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0 + m_detailIndex);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0 + m_emissiveIndex);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0 + m_materialIndex);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0 + m_shadowIndex);
glBindTexture(GL_TEXTURE_2D, 0);
m_albedoTexture = 0;
m_detailTexture = 0;
m_emissiveTexture = 0;
m_materialTexture = 0;
m_shadowMap = 0;
}
void CGL33TerrainRenderer::SetProjectionMatrix(const glm::mat4& matrix)
{
glUniformMatrix4fv(m_projectionMatrix, 1, GL_FALSE, value_ptr(matrix));
}
void CGL33TerrainRenderer::SetViewMatrix(const glm::mat4& matrix)
{
glm::mat4 scale(1.0f);
scale[2][2] = -1.0f;
auto viewMatrix = scale * matrix;
auto cameraMatrix = glm::inverse(viewMatrix);
auto cameraPos = cameraMatrix[3];
glUniformMatrix4fv(m_viewMatrix, 1, GL_FALSE, value_ptr(viewMatrix));
glUniform3f(m_cameraPosition, cameraPos.x, cameraPos.y, cameraPos.z);
}
void CGL33TerrainRenderer::SetModelMatrix(const glm::mat4& matrix)
{
auto normalMatrix = glm::transpose(glm::inverse(glm::mat3(matrix)));
glUniformMatrix4fv(m_modelMatrix, 1, GL_FALSE, value_ptr(matrix));
glUniformMatrix3fv(m_normalMatrix, 1, GL_FALSE, value_ptr(normalMatrix));
}
void CGL33TerrainRenderer::SetAlbedoColor(const Color& color)
{
glUniform4f(m_albedoColor, color.r, color.g, color.b, color.a);
}
void CGL33TerrainRenderer::SetAlbedoTexture(const Texture& texture)
{
if (m_albedoTexture == texture.id) return;
m_albedoTexture = texture.id;
glActiveTexture(GL_TEXTURE0 + m_albedoIndex);
if (texture.id == 0)
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
else
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33TerrainRenderer::SetEmissiveColor(const Color& color)
{
glUniform3f(m_emissiveColor, color.r, color.g, color.b);
}
void CGL33TerrainRenderer::SetEmissiveTexture(const Texture& texture)
{
if (m_emissiveTexture == texture.id) return;
m_emissiveTexture = texture.id;
glActiveTexture(GL_TEXTURE0 + m_emissiveIndex);
if (texture.id == 0)
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
else
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33TerrainRenderer::SetMaterialParams(float roughness, float metalness, float aoStrength)
{
glUniform1f(m_roughness, roughness);
glUniform1f(m_metalness, metalness);
glUniform1f(m_aoStrength, aoStrength);
}
void CGL33TerrainRenderer::SetMaterialTexture(const Texture& texture)
{
if (m_materialTexture == texture.id) return;
m_materialTexture = texture.id;
glActiveTexture(GL_TEXTURE0 + m_materialIndex);
if (texture.id == 0)
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
else
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33TerrainRenderer::SetDetailTexture(const Texture& texture)
{
if (m_detailTexture == texture.id) return;
m_detailTexture = texture.id;
glActiveTexture(GL_TEXTURE0 + m_detailIndex);
if (texture.id == 0)
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
else
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33TerrainRenderer::SetShadowMap(const Texture& texture)
{
if (m_shadowMap == texture.id) return;
m_shadowMap = texture.id;
glActiveTexture(GL_TEXTURE0 + m_shadowIndex);
if (texture.id == 0)
glBindTexture(GL_TEXTURE_2D, 0);
else
glBindTexture(GL_TEXTURE_2D, texture.id);
}
void CGL33TerrainRenderer::SetLight(const glm::vec4& position, const float& intensity, const glm::vec3& color)
{
glUniform4fv(m_lightPosition, 1, glm::value_ptr(position));
glUniform1f(m_lightIntensity, intensity);
glUniform3fv(m_lightColor, 1, glm::value_ptr(color));
}
void CGL33TerrainRenderer::SetSky(const Color& color, float intensity)
{
glUniform3f(m_skyColor, color.r, color.g, color.b);
glUniform1f(m_skyIntensity, intensity);
}
void CGL33TerrainRenderer::SetShadowParams(int count, const ShadowParam* params)
{
glUniform1i(m_shadowRegions, count);
for (int i = 0; i < count; i++)
{
glUniformMatrix4fv(m_shadows[i].transform, 1, GL_FALSE, glm::value_ptr(params[i].matrix));
glUniform2fv(m_shadows[i].offset, 1, glm::value_ptr(params[i].uv_offset));
glUniform2fv(m_shadows[i].scale, 1, glm::value_ptr(params[i].uv_scale));
}
}
void CGL33TerrainRenderer::SetFog(float min, float max, const glm::vec3& color)
{
glUniform2f(m_fogRange, min, max);
glUniform3f(m_fogColor, color.r, color.g, color.b);
}
void CGL33TerrainRenderer::DrawObject(const glm::mat4& matrix, const CVertexBuffer* buffer)
{
auto b = dynamic_cast<const CGL33VertexBuffer*>(buffer);
if (b == nullptr) return;
SetModelMatrix(matrix);
glBindVertexArray(b->GetVAO());
glDrawArrays(TranslateGfxPrimitive(b->GetType()), 0, static_cast<GLsizei>(b->Size()));
}

View File

@ -1,151 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/opengl33/gl33_terrain_renderer.h
* \brief OpenGL 3.3 terrain renderer
*/
#pragma once
#include "graphics/core/renderers.h"
#include <GL/glew.h>
#include <array>
#include <vector>
// Graphics module namespace
namespace Gfx
{
struct Texture;
class CGL33Device;
class CGL33TerrainRenderer : public CTerrainRenderer
{
public:
CGL33TerrainRenderer(CGL33Device* device);
virtual ~CGL33TerrainRenderer();
virtual void Begin() override;
virtual void End() override;
//! Sets projection matrix
virtual void SetProjectionMatrix(const glm::mat4& matrix) override;
//! Sets view matrix
virtual void SetViewMatrix(const glm::mat4& matrix) override;
//! Sets model matrix
virtual void SetModelMatrix(const glm::mat4& matrix) override;
//! Sets albedo color
virtual void SetAlbedoColor(const Color& color) override;
//! Sets albedo texture
virtual void SetAlbedoTexture(const Texture& texture) override;
//! Sets emissive color
virtual void SetEmissiveColor(const Color& color) override;
//! Sets emissive texture
virtual void SetEmissiveTexture(const Texture& texture) override;
//! Sets material parameters
virtual void SetMaterialParams(float roughness, float metalness, float aoStrength) override;
//! Sets material texture
virtual void SetMaterialTexture(const Texture& texture) override;
//! Sets detail texture
virtual void SetDetailTexture(const Texture& texture) override;
//! Sets shadow map
virtual void SetShadowMap(const Texture& texture) override;
//! Sets light parameters
virtual void SetLight(const glm::vec4& position, const float& intensity, const glm::vec3& color) override;
//! Sets sky parameters
virtual void SetSky(const Color& color, float intensity) override;
//! Sets shadow parameters
virtual void SetShadowParams(int count, const ShadowParam* params) override;
//! Sets fog parameters
virtual void SetFog(float min, float max, const glm::vec3& color) override;
//! Draws terrain object
virtual void DrawObject(const glm::mat4& matrix, const CVertexBuffer* buffer) override;
private:
CGL33Device* const m_device;
// Uniform data
GLint m_projectionMatrix = -1;
GLint m_viewMatrix = -1;
GLint m_shadowMatrix = -1;
GLint m_modelMatrix = -1;
GLint m_normalMatrix = -1;
GLint m_cameraPosition = -1;
GLint m_lightPosition = -1;
GLint m_lightIntensity = -1;
GLint m_lightColor = -1;
GLint m_skyColor = -1;
GLint m_skyIntensity = -1;
GLint m_fogRange = -1;
GLint m_fogColor = -1;
GLint m_albedoColor = -1;
GLint m_emissiveColor = -1;
GLint m_roughness = -1;
GLint m_metalness = -1;
GLint m_aoStrength = -1;
struct ShadowUniforms
{
GLint transform;
GLint offset;
GLint scale;
};
GLint m_shadowRegions = 0;
ShadowUniforms m_shadows[4] = {};
// Shader program
GLuint m_program = 0;
// Texture unit bindings
const int m_albedoIndex = 4;
const int m_detailIndex = 5;
const int m_emissiveIndex = 6;
const int m_materialIndex = 7;
const int m_shadowIndex = 8;
// 1x1 white texture
GLuint m_whiteTexture = 0;
// Currently bound albedo texture
GLuint m_albedoTexture = 0;
// Currently bound detail texture
GLuint m_detailTexture = 0;
// Currently bound emissive texture
GLuint m_emissiveTexture = 0;
// Currently bound material texture
GLuint m_materialTexture = 0;
// Currently bound shadow map
GLuint m_shadowMap = 0;
};
}

View File

@ -1,286 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/opengl33/gl33_ui_renderer.h"
#include "graphics/opengl33/gl33_device.h"
#include "graphics/opengl33/glutil.h"
#include "graphics/core/material.h"
#include "graphics/core/transparency.h"
#include "graphics/core/vertex.h"
#include "common/logger.h"
#include <GL/glew.h>
#include <glm/ext.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <algorithm>
#include <array>
#include <vector>
using namespace Gfx;
CGL33UIRenderer::CGL33UIRenderer(CGL33Device* device)
: m_device(device)
{
GetLogger()->Info("Creating CGL33UIRenderer\n");
GLint shaders[2] = {};
shaders[0] = LoadShader(GL_VERTEX_SHADER, "shaders/gl33/ui_vs.glsl");
if (shaders[0] == 0)
{
GetLogger()->Error("Cound not create vertex shader from file 'ui_vs.glsl'\n");
return;
}
shaders[1] = LoadShader(GL_FRAGMENT_SHADER, "shaders/gl33/ui_fs.glsl");
if (shaders[1] == 0)
{
GetLogger()->Error("Cound not create fragment shader from file 'ui_fs.glsl'\n");
return;
}
m_program = LinkProgram(2, shaders);
if (m_program == 0)
{
GetLogger()->Error("Cound not link shader program for interface renderer\n");
return;
}
glDeleteShader(shaders[0]);
glDeleteShader(shaders[1]);
glUseProgram(m_program);
// Create uniform buffer
glGenBuffers(1, &m_uniformBuffer);
m_uniforms.projectionMatrix = glm::ortho(0.0f, +1.0f, 0.0f, +1.0f);
m_uniforms.color = { 1.0f, 1.0f, 1.0f, 1.0f };
m_uniformsDirty = true;
UpdateUniforms();
// Bind uniform block to uniform buffer binding
GLuint blockIndex = glGetUniformBlockIndex(m_program, "Uniforms");
glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_uniformBuffer);
glUniformBlockBinding(m_program, blockIndex, 0);
// Set texture unit to 8th
auto texture = glGetUniformLocation(m_program, "uni_Texture");
glUniform1i(texture, 8);
// Generic buffer
glGenBuffers(1, &m_bufferVBO);
glBindBuffer(GL_COPY_WRITE_BUFFER, m_bufferVBO);
glBufferData(GL_COPY_WRITE_BUFFER, m_bufferCapacity * sizeof(Vertex2D), nullptr, GL_STREAM_DRAW);
m_bufferOffset = m_bufferCapacity;
glGenVertexArrays(1, &m_bufferVAO);
glBindVertexArray(m_bufferVAO);
// White texture
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &m_whiteTexture);
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
glUseProgram(0);
GetLogger()->Info("CGL33UIRenderer created successfully\n");
}
CGL33UIRenderer::~CGL33UIRenderer()
{
glDeleteProgram(m_program);
glDeleteTextures(1, &m_whiteTexture);
glDeleteBuffers(1, &m_bufferVBO);
glDeleteVertexArrays(1, &m_bufferVAO);
}
void CGL33UIRenderer::SetProjection(float left, float right, float bottom, float top)
{
m_uniforms.projectionMatrix = glm::ortho(left, right, bottom, top);
m_uniformsDirty = true;
}
void CGL33UIRenderer::SetTexture(const Texture& texture)
{
if (m_currentTexture == texture.id) return;
glActiveTexture(GL_TEXTURE8);
m_currentTexture = texture.id;
if (m_currentTexture == 0)
glBindTexture(GL_TEXTURE_2D, m_whiteTexture);
else
glBindTexture(GL_TEXTURE_2D, m_currentTexture);
}
void CGL33UIRenderer::SetColor(const glm::vec4& color)
{
m_uniforms.color = color;
m_uniformsDirty = true;
}
void CGL33UIRenderer::SetTransparency(TransparencyMode mode)
{
m_device->SetTransparency(mode);
}
Vertex2D* CGL33UIRenderer::BeginPrimitive(PrimitiveType type, int count)
{
return BeginPrimitives(type, 1, &count);
}
Vertex2D* CGL33UIRenderer::BeginPrimitives(PrimitiveType type, int drawCount, const int* counts)
{
glBindVertexArray(m_bufferVAO);
glBindBuffer(GL_ARRAY_BUFFER, m_bufferVBO);
m_currentCount = 0;
for (size_t i = 0; i < drawCount; i++)
{
m_currentCount += counts[i];
}
GLuint total = m_bufferOffset + m_currentCount;
// Buffer full, orphan
if (total >= m_bufferCapacity)
{
glBufferData(GL_ARRAY_BUFFER, m_bufferCapacity * sizeof(Vertex2D), nullptr, GL_STREAM_DRAW);
m_bufferOffset = 0;
// Respecify vertex attributes
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D),
reinterpret_cast<void*>(offsetof(Vertex2D, position)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D),
reinterpret_cast<void*>(offsetof(Vertex2D, uv)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex2D),
reinterpret_cast<void*>(offsetof(Vertex2D, color)));
}
m_first.resize(drawCount);
m_count.resize(drawCount);
GLsizei currentOffset = m_bufferOffset;
for (size_t i = 0; i < drawCount; i++)
{
m_first[i] = currentOffset;
m_count[i] = counts[i];
currentOffset += counts[i];
}
auto ptr = glMapBufferRange(GL_ARRAY_BUFFER,
m_bufferOffset * sizeof(Vertex2D),
m_currentCount * sizeof(Vertex2D),
GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
m_mapped = true;
m_type = type;
m_drawCount = drawCount;
// Mapping failed, use backup buffer
if (ptr == nullptr)
{
m_backup = true;
m_buffer.resize(m_currentCount);
return m_buffer.data();
}
else
{
return reinterpret_cast<Vertex2D*>(ptr);
}
}
bool CGL33UIRenderer::EndPrimitive()
{
if (!m_mapped) return false;
if (m_backup)
{
glBufferSubData(GL_ARRAY_BUFFER,
m_bufferOffset * sizeof(Vertex2D),
m_currentCount * sizeof(Vertex2D),
m_buffer.data());
}
else
{
glUnmapBuffer(GL_ARRAY_BUFFER);
}
glUseProgram(m_program);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_uniformBuffer);
UpdateUniforms();
m_device->SetDepthTest(false);
m_device->SetCullFace(CullFace::NONE);
if (m_drawCount == 1)
glDrawArrays(TranslateGfxPrimitive(m_type), m_first.front(), m_count.front());
else
glMultiDrawArrays(TranslateGfxPrimitive(m_type), m_first.data(), m_count.data(), m_drawCount);
m_bufferOffset += m_currentCount;
m_mapped = false;
m_backup = false;
return true;
}
void CGL33UIRenderer::UpdateUniforms()
{
if (!m_uniformsDirty) return;
glBindBuffer(GL_COPY_WRITE_BUFFER, m_uniformBuffer);
glBufferData(GL_COPY_WRITE_BUFFER, sizeof(Uniforms), nullptr, GL_STREAM_DRAW);
glBufferSubData(GL_COPY_WRITE_BUFFER, 0, sizeof(Uniforms), &m_uniforms);
glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
}

View File

@ -1,110 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
/**
* \file graphics/opengl33/gl33_ui_renderer.h
* \brief OpenGL 3.3 UI renderer
*/
#pragma once
#include "graphics/core/renderers.h"
#include <GL/glew.h>
#include <array>
#include <vector>
// Graphics module namespace
namespace Gfx
{
class CGL33Device;
class CGL33UIRenderer : public CUIRenderer
{
public:
CGL33UIRenderer(CGL33Device* device);
virtual ~CGL33UIRenderer();
virtual void SetProjection(float left, float right, float bottom, float top) override;
virtual void SetTexture(const Texture& texture) override;
virtual void SetColor(const glm::vec4& color) override;
virtual void SetTransparency(TransparencyMode mode) override;
virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) override;
virtual Vertex2D* BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) override;
virtual bool EndPrimitive() override;
private:
void UpdateUniforms();
CGL33Device* const m_device;
// Uniform data
struct Uniforms
{
glm::mat4 projectionMatrix;
glm::vec4 color;
};
Uniforms m_uniforms = {};
// true means uniforms need to be updated
bool m_uniformsDirty = false;
// Uniform buffer object
GLuint m_uniformBuffer = 0;
// Vertex buffer object
GLuint m_bufferVBO = 0;
// Vertex array object
GLuint m_bufferVAO = 0;
// VBO capacity
GLsizei m_bufferCapacity = 128 * 1024;
// Buffer offset
GLsizei m_bufferOffset = 0;
// Buffer mapping state
PrimitiveType m_type = {};
// Number of drawn primitives
GLuint m_drawCount = 0;
// Total count of drawn vertices
GLuint m_currentCount = 0;
// Starting offset for each drawn primitive
std::vector<GLint> m_first;
// Numbers of vertices for each drawn primitive
std::vector<GLsizei> m_count;
// True means currently drawing
bool m_mapped = false;
// True means mapping failed, using auxiliary buffer
bool m_backup = false;
// Buffered vertex data
std::vector<Vertex2D> m_buffer;
// Shader program
GLuint m_program = 0;
// 1x1 white texture
GLuint m_whiteTexture = 0;
// Currently bound texture
GLuint m_currentTexture = 0;
};
}

View File

@ -1,106 +0,0 @@
/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#pragma once
// config.h must be included first
#include "common/config.h"
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <string>
#include <memory>
#include <vector>
struct SDL_Surface;
class CImage;
struct ImageData;
// Graphics module namespace
namespace Gfx
{
class CDevice;
class CFrameBufferPixels;
struct DeviceConfig;
enum class PrimitiveType : unsigned char;
enum class Type : unsigned char;
enum class TextureFormat : unsigned char;
bool InitializeGLEW();
//! Creates OpenGL device
std::unique_ptr<CDevice> CreateDevice(const DeviceConfig &config, const std::string& name);
//! Returns OpenGL version
// \return First digit is major part, second digit is minor part.
int GetOpenGLVersion();
//! Returns OpenGL version
// \return First digit is major part, second digit is minor part.
int GetOpenGLVersion(int &major, int &minor);
//! Checks if extensions in space-delimited list are supported
// \return true if all extensions are supported
bool AreExtensionsSupported(std::string list);
//! Returns information about graphics card
std::string GetHardwareInfo(bool full = false);
//! Clears OpenGL errors
int ClearGLErrors();
//! Checks for OpenGL errors
bool CheckGLErrors();
//! Translate Gfx primitive type to OpenGL primitive type
GLenum TranslateGfxPrimitive(PrimitiveType type);
bool InPlane(glm::vec3 normal, float originPlane, glm::vec3 center, float radius);
GLenum TranslateType(Type type);
std::string GetLastShaderError();
std::string LoadSource(const std::string& path);
GLint CreateShader(GLint type, const std::vector<std::string>& sources);
GLint LoadShader(GLint type, const char* filename);
GLint LinkProgram(int count, const GLint* shaders);
GLint LinkProgram(const std::vector<GLint>& shaders);
// TODO: Moved this here temporarily only to remove code duplication in CGLDeviceXX
struct PreparedTextureData
{
SDL_Surface* actualSurface = nullptr;
SDL_Surface* convertedSurface = nullptr;
GLenum sourceFormat = 0;
bool alpha = false;
};
PreparedTextureData PrepareTextureData(ImageData* imageData, TextureFormat format);
std::unique_ptr<CFrameBufferPixels> GetGLFrameBufferPixels(const glm::ivec2& size);
} // namespace Gfx

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