mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-22 14:23:44 -07:00
Merge branch 'Random06457:develop' into develop
This commit is contained in:
commit
c023cc7d15
288 changed files with 12212 additions and 8152 deletions
403
.gitignore
vendored
Normal file
403
.gitignore
vendored
Normal file
|
@ -0,0 +1,403 @@
|
|||
# Cache files
|
||||
__pycache__/
|
||||
.pyc
|
||||
.DS_Store
|
||||
|
||||
# Text editor remnants
|
||||
.vscode/
|
||||
.vs/
|
||||
.idea/
|
||||
CMakeLists.txt
|
||||
cmake-build-debug
|
||||
venv/
|
||||
|
||||
# Project-specific ignores
|
||||
build/
|
||||
expected/
|
||||
notes/
|
||||
baserom/
|
||||
docs/doxygen/
|
||||
*.elf
|
||||
*.sra
|
||||
*.z64
|
||||
*.n64
|
||||
*.v64
|
||||
*.map
|
||||
*.dump
|
||||
out.txt
|
||||
|
||||
# Tool artifacts
|
||||
tools/mipspro7.2_compiler/
|
||||
tools/overlayhelpers/batchdisasm/output/*
|
||||
tools/overlayhelpers/batchdisasm/output2/*
|
||||
tools/overlayhelpers/batchdisasm/mipsdisasm/*
|
||||
tools/disasm/output/*
|
||||
tools/asmsplitter/asm/*
|
||||
tools/asmsplitter/c/*
|
||||
ctx.c
|
||||
tools/*dSYM/
|
||||
graphs/
|
||||
|
||||
# Assets
|
||||
*.png
|
||||
*.jpg
|
||||
*.mdli
|
||||
*.anmi
|
||||
*.obj
|
||||
*.mtl
|
||||
*.fbx
|
||||
!*_custom*
|
||||
.extracted-assets.json
|
||||
|
||||
# Docs
|
||||
!docs/tutorial/
|
||||
|
||||
# Per-user configuration
|
||||
.python-version
|
||||
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
*.out
|
||||
*.o
|
||||
*.d
|
||||
lib/libgfxd/libgfxd.a
|
||||
ExporterTest/ExporterTest.a
|
||||
ZAPDUtils/ZAPDUtils.a
|
||||
.vscode/
|
||||
build/
|
||||
external/
|
||||
ZAPDUtils/build/
|
||||
ZAPD/BuildInfo.h
|
||||
|
||||
DebugObj/*
|
||||
ReleaseObj/*
|
66
BUILDING.md
Normal file
66
BUILDING.md
Normal file
|
@ -0,0 +1,66 @@
|
|||
# Building Ship of Harkinian
|
||||
|
||||
## Windows
|
||||
|
||||
1. Requires [Python](https://www.python.org/downloads/) >= 3.6.
|
||||
2. Install [Visual Studio 2022 Community Edition](https://visualstudio.microsoft.com/vs/community/)
|
||||
3. In the Visual Studio Installer, install `MSVC v142 - VS 2019 C++`.
|
||||
4. Clone the Ship of Harkinian repository.
|
||||
5. Place one or more [compatible](#compatible-roms) roms in the `OTRExporter` directory with namings of your choice.
|
||||
6. Run `OTRExporter/OTRExporter.sln`.
|
||||
7. Switch the solution to `Release x64`.
|
||||
8. Build the solution.
|
||||
9. Launching `OTRExporter/extract_assets.py` will generate an `oot.otr` archive file in `OTRExporter/oot.otr`.
|
||||
10. Run `soh/soh.sln`
|
||||
11. Switch the solution to `Release x86`.
|
||||
12. Build the solution.
|
||||
13. Copy the `OTRExporter/oot.otr` archive file to `soh/Release`.
|
||||
14. Launch `soh.exe`.
|
||||
|
||||
## Linux
|
||||
|
||||
```bash
|
||||
# Clone the repo
|
||||
git clone git@github.com:HarbourMasters/ShipWright.git
|
||||
cd ShipWright
|
||||
# Copy the baserom to the OTRExporter folder
|
||||
cp <path to your ROM> OTRExporter
|
||||
# Build the docker image
|
||||
sudo docker build . -t soh
|
||||
# Run the docker image with the working directory mounted to /soh
|
||||
sudo docker run --rm -it -v $(pwd):/soh soh /bin/bash
|
||||
```
|
||||
Inside the Docker container:
|
||||
```bash
|
||||
# Clone and build StormLib
|
||||
git clone https://github.com/ladislav-zezula/StormLib external/StormLib
|
||||
cmake -B external/StormLib/build -S external/StormLib
|
||||
cmake --build external/StormLib/build
|
||||
cp external/StormLib/build/libstorm.a external
|
||||
cp /usr/local/lib/libGLEW.a external
|
||||
|
||||
cd soh
|
||||
# Extract the assets/Compile the exporter/Run the exporter
|
||||
make setup -j$(nproc) OPTFLAGS=-O0 DEBUG=0
|
||||
# Compile the code
|
||||
make -j $(nproc) OPTFLAGS=-O0 DEBUG=0
|
||||
```
|
||||
|
||||
# Compatible Roms
|
||||
```
|
||||
OOT_PAL_GC checksum 0x09465AC3
|
||||
OOT_PAL_GC_DBG1 checksum 0x871E1C92 (debug non-master quest)
|
||||
```
|
||||
|
||||
# OTRExporter Usage
|
||||
|
||||
The OTRExporter exports an `oot.otr` archive file which Ship of Harkinian requires to play.
|
||||
|
||||
Use the `extract_assets.py` script file to run the exporter using any of the following methods:
|
||||
1) Double click on the script after placing one or more roms in the directory.
|
||||
2) Drag & Drop a rom onto the script.
|
||||
3) In a terminal run `python3 extract_assets.py` after placing one or more roms in the directory.
|
||||
4) In a terminal run `python3 extract_assets.py <path_to_rom>`
|
||||
|
||||
If the script finds multiple roms the user is prompted which to use. Selection is done using the number keys and then pressing the carriage return key.
|
||||
|
38
Dockerfile
Normal file
38
Dockerfile
Normal file
|
@ -0,0 +1,38 @@
|
|||
|
||||
|
||||
FROM ubuntu:21.04 as build
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN dpkg --add-architecture i386 && \
|
||||
apt-get update && \
|
||||
apt-get upgrade -y && \
|
||||
apt-get install -y \
|
||||
binutils:i386 \
|
||||
gcc-10:i386 \
|
||||
g++-10:i386 \
|
||||
python3.10 \
|
||||
python \
|
||||
make \
|
||||
cmake \
|
||||
git \
|
||||
lld \
|
||||
libsdl2-dev:i386 \
|
||||
zlib1g-dev:i386 \
|
||||
libbz2-dev:i386 \
|
||||
libpng-dev:i386 \
|
||||
libgles2-mesa-dev && \
|
||||
ln -sf /usr/bin/python3.10 /usr/bin/python3 && \
|
||||
ln -s /usr/bin/gcc-10 /usr/bin/gcc && \
|
||||
ln -s /usr/bin/gcc-10 /usr/bin/cc && \
|
||||
ln -s /usr/bin/g++-10 /usr/bin/g++ && \
|
||||
ln -s /usr/bin/g++-10 /usr/bin/c++
|
||||
|
||||
RUN git clone https://github.com/Perlmint/glew-cmake.git && \
|
||||
cmake glew-cmake && \
|
||||
make -j$(nproc) && \
|
||||
make install ARCH64=false
|
||||
|
||||
RUN mkdir /soh
|
||||
WORKDIR /soh
|
117
Jenkinsfile
vendored
Normal file
117
Jenkinsfile
vendored
Normal file
|
@ -0,0 +1,117 @@
|
|||
pipeline {
|
||||
agent none
|
||||
|
||||
options {
|
||||
timestamps()
|
||||
skipDefaultCheckout(true)
|
||||
}
|
||||
|
||||
stages {
|
||||
stage ('Build Windows') {
|
||||
environment {
|
||||
MSBUILD='C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Msbuild\\Current\\Bin\\msbuild.exe'
|
||||
CONFIG='Release'
|
||||
OTRPLATFORM='x64'
|
||||
PLATFORM='x86'
|
||||
ZIP='C:\\Program Files\\7-Zip\\7z.exe'
|
||||
PYTHON='C:\\Users\\jenkins\\AppData\\Local\\Programs\\Python\\Python310\\python.exe'
|
||||
CMAKE='C:\\Program Files\\CMake\\bin\\cmake.exe'
|
||||
TOOLSET='v142'
|
||||
}
|
||||
agent {
|
||||
label "SoH-Builders"
|
||||
}
|
||||
steps {
|
||||
checkout([
|
||||
$class: 'GitSCM',
|
||||
branches: scm.branches,
|
||||
doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations,
|
||||
extensions: scm.extensions,
|
||||
userRemoteConfigs: scm.userRemoteConfigs
|
||||
])
|
||||
|
||||
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
|
||||
bat """
|
||||
|
||||
"${env.MSBUILD}" ".\\OTRExporter\\OTRExporter.sln" -t:build -p:Configuration=${env.CONFIG};Platform=${env.OTRPLATFORM};PlatformToolset=${env.TOOLSET};RestorePackagesConfig=true /restore /nodeReuse:false /m
|
||||
|
||||
xcopy "..\\..\\ZELOOTD.z64" "OTRExporter\\"
|
||||
|
||||
cd "OTRExporter"
|
||||
"${env.PYTHON}" ".\\extract_assets.py"
|
||||
cd "..\\"
|
||||
|
||||
"${env.MSBUILD}" ".\\soh\\soh.sln" -t:build -p:Configuration=${env.CONFIG};Platform=${env.PLATFORM};PlatformToolset=${env.TOOLSET} /nodeReuse:false /m
|
||||
|
||||
cd OTRGui
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
"${env.CMAKE}" ..
|
||||
"${env.CMAKE}" --build . --config Release
|
||||
|
||||
cd "..\\..\\"
|
||||
|
||||
move "soh\\Release\\soh.exe" ".\\"
|
||||
move "OTRGui\\build\\assets" ".\\"
|
||||
move ".\\OTRExporter\\x64\\Release\\ZAPD.exe" ".\\assets\\extractor\\"
|
||||
move ".\\OTRGui\\build\\Release\\OTRGui.exe" ".\\"
|
||||
rename README.md readme.txt
|
||||
|
||||
"${env.ZIP}" a soh.7z soh.exe OTRGui.exe assets readme.txt
|
||||
|
||||
"""
|
||||
archiveArtifacts artifacts: 'soh.7z', followSymlinks: false, onlyIfSuccessful: true
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
step([$class: 'WsCleanup']) // Clean workspace
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ('Build Linux') {
|
||||
agent {
|
||||
label "SoH-Linux-Builders"
|
||||
}
|
||||
steps {
|
||||
checkout([
|
||||
$class: 'GitSCM',
|
||||
branches: scm.branches,
|
||||
doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations,
|
||||
extensions: scm.extensions,
|
||||
userRemoteConfigs: scm.userRemoteConfigs
|
||||
])
|
||||
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
|
||||
sh '''
|
||||
|
||||
cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64
|
||||
docker build . -t soh
|
||||
docker run --name sohcont -dit --rm -v $(pwd):/soh soh /bin/bash
|
||||
cp ../../buildsoh.bash soh
|
||||
docker exec sohcont soh/buildsoh.bash
|
||||
|
||||
mkdir build
|
||||
mv soh/soh.elf build/
|
||||
mv OTRGui/build/OTRGui build/
|
||||
mv OTRGui/build/assets build/
|
||||
mv ZAPDTR/ZAPD.out build/assets/extractor/
|
||||
mv README.md build/readme.txt
|
||||
cd build
|
||||
|
||||
7z a soh-linux.7z soh.elf OTRGui assets readme.txt
|
||||
mv soh-linux.7z ../
|
||||
|
||||
'''
|
||||
}
|
||||
sh 'sudo docker container stop sohcont'
|
||||
archiveArtifacts artifacts: 'soh-linux.7z', followSymlinks: false, onlyIfSuccessful: true
|
||||
}
|
||||
post {
|
||||
always {
|
||||
step([$class: 'WsCleanup']) // Clean workspace
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,12 +49,12 @@ void OTRExporter_Animation::Save(ZResource* res, const fs::path& outPath, Binary
|
|||
|
||||
writer->Write((uint32_t)normalAnim->rotationValues.size());
|
||||
|
||||
for (int i = 0; i < normalAnim->rotationValues.size(); i++)
|
||||
for (size_t i = 0; i < normalAnim->rotationValues.size(); i++)
|
||||
writer->Write(normalAnim->rotationValues[i]);
|
||||
|
||||
writer->Write((uint32_t)normalAnim->rotationIndices.size());
|
||||
|
||||
for (int i = 0; i < normalAnim->rotationIndices.size(); i++)
|
||||
for (size_t i = 0; i < normalAnim->rotationIndices.size(); i++)
|
||||
{
|
||||
writer->Write(normalAnim->rotationIndices[i].x);
|
||||
writer->Write(normalAnim->rotationIndices[i].y);
|
||||
|
|
|
@ -10,7 +10,7 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit
|
|||
writer->Write((uint32_t)arr->resList[0]->GetResourceType());
|
||||
writer->Write((uint32_t)arr->arrayCnt);
|
||||
|
||||
for (int i = 0; i < arr->arrayCnt; i++)
|
||||
for (size_t i = 0; i < arr->arrayCnt; i++)
|
||||
{
|
||||
if (arr->resList[i]->GetResourceType() == ZResourceType::Vertex)
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit
|
|||
writer->Write((uint32_t)vec->scalarType);
|
||||
writer->Write((uint32_t)vec->dimensions);
|
||||
|
||||
for (int k = 0; k < vec->dimensions; k++)
|
||||
for (size_t k = 0; k < vec->dimensions; k++)
|
||||
{
|
||||
// OTRTODO: Duplicate code here. Cleanup at a later date...
|
||||
switch (vec->scalarType)
|
||||
|
@ -62,6 +62,8 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit
|
|||
writer->Write(vec->scalars[k].scalarData.u64);
|
||||
break;
|
||||
// OTRTODO: ADD OTHER TYPES
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +100,8 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit
|
|||
writer->Write(scal->scalarData.u64);
|
||||
break;
|
||||
// OTRTODO: ADD OTHER TYPES
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW
|
|||
for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries)
|
||||
{
|
||||
writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame));
|
||||
writer->Write(CMD_F(e->viewAngle));
|
||||
writer->Write(e->viewAngle);
|
||||
writer->Write(CMD_HH(e->posX, e->posY));
|
||||
writer->Write(CMD_HH(e->posZ, e->unused));
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW
|
|||
for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries)
|
||||
{
|
||||
writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame));
|
||||
writer->Write(CMD_F(e->viewAngle));
|
||||
writer->Write(e->viewAngle);
|
||||
writer->Write(CMD_HH(e->posX, e->posY));
|
||||
writer->Write(CMD_HH(e->posZ, e->unused));
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW
|
|||
for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries)
|
||||
{
|
||||
writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame));
|
||||
writer->Write(CMD_F(e->viewAngle));
|
||||
writer->Write(e->viewAngle);
|
||||
writer->Write(CMD_HH(e->posX, e->posY));
|
||||
writer->Write(CMD_HH(e->posZ, e->unused));
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW
|
|||
for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries)
|
||||
{
|
||||
writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame));
|
||||
writer->Write(CMD_F(e->viewAngle));
|
||||
writer->Write(e->viewAngle);
|
||||
writer->Write(CMD_HH(e->posX, e->posY));
|
||||
writer->Write(CMD_HH(e->posZ, e->unused));
|
||||
}
|
||||
|
|
|
@ -29,20 +29,6 @@
|
|||
Ab1, Ad1)) \
|
||||
}
|
||||
|
||||
typedef int32_t Mtx_t[4][4];
|
||||
|
||||
typedef union Mtx
|
||||
{
|
||||
//_Alignas(8)
|
||||
Mtx_t m;
|
||||
int32_t l[16];
|
||||
struct
|
||||
{
|
||||
int16_t i[16];
|
||||
uint16_t f[16];
|
||||
};
|
||||
} Mtx;
|
||||
|
||||
#define gsSPBranchLessZraw2(dl, vtx, zval) \
|
||||
{ _SHIFTL(G_BRANCH_Z,24,8)|_SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12),\
|
||||
(unsigned int)(zval), }
|
||||
|
@ -71,7 +57,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
|
||||
// DEBUG: Write in a marker
|
||||
Declaration* dbgDecl = dList->parent->GetDeclaration(dList->GetRawDataIndex());
|
||||
std::string dbgName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), dbgDecl->varName.c_str());
|
||||
std::string dbgName = StringHelper::Sprintf("%s/%s", GetParentFolderName(res).c_str(), dbgDecl->varName.c_str());
|
||||
uint64_t hash = CRC64(dbgName.c_str());
|
||||
writer->Write((uint32_t)(G_MARKER << 24));
|
||||
writer->Write((uint32_t)0xBEEFBEEF);
|
||||
|
@ -81,7 +67,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
auto dlStart = std::chrono::steady_clock::now();
|
||||
|
||||
//for (auto data : dList->instructions)
|
||||
for (int dataIdx = 0; dataIdx < dList->instructions.size(); dataIdx++)
|
||||
for (size_t dataIdx = 0; dataIdx < dList->instructions.size(); dataIdx++)
|
||||
{
|
||||
auto data = dList->instructions[dataIdx];
|
||||
uint32_t word0 = 0;
|
||||
|
@ -216,7 +202,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
|
||||
pp ^= G_MTX_PUSH;
|
||||
|
||||
mm = (mm & 0x0FFFFFFF) + 0xF0000000;
|
||||
mm = (mm & 0x0FFFFFFF) + 1;
|
||||
|
||||
Gfx value = gsSPMatrix(mm, pp);
|
||||
word0 = value.words.w0;
|
||||
|
@ -243,7 +229,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
|
||||
if (mtxDecl != nullptr)
|
||||
{
|
||||
std::string vName = StringHelper::Sprintf("%s\\%s", (GetParentFolderName(res).c_str()), mtxDecl->varName.c_str());
|
||||
std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), mtxDecl->varName.c_str());
|
||||
|
||||
uint64_t hash = CRC64(vName.c_str());
|
||||
|
||||
|
@ -347,7 +333,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
|
||||
if (dListDecl != nullptr)
|
||||
{
|
||||
std::string vName = StringHelper::Sprintf("%s\\%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str());
|
||||
std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str());
|
||||
|
||||
uint64_t hash = CRC64(vName.c_str());
|
||||
|
||||
|
@ -370,7 +356,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
//std::string fName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), dListDecl2->varName.c_str());
|
||||
std::string fName = OTRExporter_DisplayList::GetPathToRes(res, dListDecl2->varName.c_str());
|
||||
|
||||
if (files.find(fName) == files.end() && !File::Exists("Extract\\" + fName))
|
||||
if (files.find(fName) == files.end() && !File::Exists("Extract/" + fName))
|
||||
{
|
||||
MemoryStream* dlStream = new MemoryStream();
|
||||
BinaryWriter dlWriter = BinaryWriter(dlStream);
|
||||
|
@ -383,7 +369,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
#endif
|
||||
|
||||
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
|
||||
File::WriteAllBytes("Extract\\" + fName, dlStream->ToVector());
|
||||
File::WriteAllBytes("Extract/" + fName, dlStream->ToVector());
|
||||
else
|
||||
files[fName] = dlStream->ToVector();
|
||||
|
||||
|
@ -411,7 +397,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
|
||||
Gfx value;
|
||||
|
||||
u32 dListVal = (data & 0x0FFFFFFF) + 0xF0000000;
|
||||
u32 dListVal = (data & 0x0FFFFFFF) + 1;
|
||||
|
||||
if (pp != 0)
|
||||
value = gsSPBranchList(dListVal);
|
||||
|
@ -444,7 +430,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
|
||||
if (dListDecl != nullptr)
|
||||
{
|
||||
std::string vName = StringHelper::Sprintf("%s\\%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str());
|
||||
std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str());
|
||||
|
||||
uint64_t hash = CRC64(vName.c_str());
|
||||
|
||||
|
@ -467,7 +453,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
//std::string fName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), dListDecl2->varName.c_str());
|
||||
std::string fName = OTRExporter_DisplayList::GetPathToRes(res, dListDecl2->varName.c_str());
|
||||
|
||||
if (files.find(fName) == files.end() && !File::Exists("Extract\\" + fName))
|
||||
if (files.find(fName) == files.end() && !File::Exists("Extract/" + fName))
|
||||
{
|
||||
MemoryStream* dlStream = new MemoryStream();
|
||||
BinaryWriter dlWriter = BinaryWriter(dlStream);
|
||||
|
@ -475,7 +461,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
Save(dList->otherDLists[i], outPath, &dlWriter);
|
||||
|
||||
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
|
||||
File::WriteAllBytes("Extract\\" + fName, dlStream->ToVector());
|
||||
File::WriteAllBytes("Extract/" + fName, dlStream->ToVector());
|
||||
else
|
||||
files[fName] = dlStream->ToVector();
|
||||
}
|
||||
|
@ -533,7 +519,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
int32_t bb = ((data & 0x0000FF0000000000ULL) >> 40) / 2;
|
||||
int32_t cc = ((data & 0x000000FF00000000ULL) >> 32) / 2;
|
||||
int32_t dd = ((data & 0x000000000000FFULL)) / 2;
|
||||
|
||||
|
||||
Gfx test = gsSP1Quadrangle(aa, bb, cc, dd, 0);
|
||||
word0 = test.words.w0;
|
||||
word1 = test.words.w1;
|
||||
|
@ -667,7 +653,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
{
|
||||
int sss = (data & 0x00FFF00000000000) >> 44;
|
||||
int ttt = (data & 0x00000FFF00000000) >> 32;
|
||||
int i = (data & 0x000000000F000000) >> 16;
|
||||
int i = (data & 0x000000000F000000) >> 24;
|
||||
int uuu = (data & 0x0000000000FFF000) >> 12;
|
||||
int vvv= (data & 0x0000000000000FFF);
|
||||
|
||||
|
@ -689,7 +675,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
uint32_t fmt = (__ & 0xE0) >> 5;
|
||||
uint32_t siz = (__ & 0x18) >> 3;
|
||||
|
||||
Gfx value = gsDPSetTextureImage(fmt, siz, www - 1, (seg & 0x0FFFFFFF) + 0xF0000000);
|
||||
Gfx value = gsDPSetTextureImage(fmt, siz, www + 1, (seg & 0x0FFFFFFF) + 1);
|
||||
word0 = value.words.w0;
|
||||
word1 = value.words.w1;
|
||||
|
||||
|
@ -707,7 +693,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
uint32_t fmt = (__ & 0xE0) >> 5;
|
||||
uint32_t siz = (__ & 0x18) >> 3;
|
||||
|
||||
Gfx value = gsDPSetTextureImage(fmt, siz, www - 1, __);
|
||||
Gfx value = gsDPSetTextureImage(fmt, siz, www + 1, __);
|
||||
word0 = value.words.w0 & 0x00FFFFFF;
|
||||
word0 += (G_SETTIMG_OTR << 24);
|
||||
//word1 = value.words.w1;
|
||||
|
@ -721,7 +707,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
ZFile* assocFile = Globals::Instance->GetSegment(GETSEGNUM(seg), res->parent->workerID);
|
||||
std::string assocFileName = assocFile->GetName();
|
||||
std::string fName = "";
|
||||
|
||||
|
||||
if (GETSEGNUM(seg) == SEGMENT_SCENE || GETSEGNUM(seg) == SEGMENT_ROOM)
|
||||
fName = GetPathToRes(res, texName.c_str());
|
||||
else
|
||||
|
@ -753,7 +739,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
Gfx value = gsSPVertex(data & 0xFFFFFFFF, nn, ((aa >> 1) - nn));
|
||||
|
||||
word0 = value.words.w0;
|
||||
word1 = value.words.w1 | 0xF0000000;
|
||||
word1 = value.words.w1 | 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -790,7 +776,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
word0 = hash >> 32;
|
||||
word1 = hash & 0xFFFFFFFF;
|
||||
|
||||
if (files.find(fName) == files.end() && !File::Exists("Extract\\" + fName))
|
||||
if (files.find(fName) == files.end() && !File::Exists("Extract/" + fName))
|
||||
{
|
||||
// Write vertices to file
|
||||
MemoryStream* vtxStream = new MemoryStream();
|
||||
|
@ -800,7 +786,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
|
||||
auto split = StringHelper::Split(vtxDecl->text, "\n");
|
||||
|
||||
for (int i = 0; i < split.size(); i++)
|
||||
for (size_t i = 0; i < split.size(); i++)
|
||||
{
|
||||
std::string line = split[i];
|
||||
|
||||
|
@ -842,7 +828,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
}
|
||||
|
||||
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
|
||||
File::WriteAllBytes("Extract\\" + fName, vtxStream->ToVector());
|
||||
File::WriteAllBytes("Extract/" + fName, vtxStream->ToVector());
|
||||
else
|
||||
files[fName] = vtxStream->ToVector();
|
||||
|
||||
|
@ -858,7 +844,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
writer->Write(word0);
|
||||
writer->Write(word1);
|
||||
}
|
||||
|
@ -872,7 +858,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
|
|||
std::string OTRExporter_DisplayList::GetPathToRes(ZResource* res, std::string varName)
|
||||
{
|
||||
std::string prefix = GetPrefix(res);
|
||||
std::string fName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), varName.c_str());
|
||||
std::string fName = StringHelper::Sprintf("%s/%s", GetParentFolderName(res).c_str(), varName.c_str());
|
||||
|
||||
return fName;
|
||||
}
|
||||
|
@ -886,7 +872,7 @@ std::string OTRExporter_DisplayList::GetParentFolderName(ZResource* res)
|
|||
{
|
||||
auto split = StringHelper::Split(oName, "_");
|
||||
oName = "";
|
||||
for (int i = 0; i < split.size() - 1; i++)
|
||||
for (size_t i = 0; i < split.size() - 1; i++)
|
||||
oName += split[i] + "_";
|
||||
|
||||
oName += "scene";
|
||||
|
@ -897,7 +883,7 @@ std::string OTRExporter_DisplayList::GetParentFolderName(ZResource* res)
|
|||
}
|
||||
|
||||
if (prefix != "")
|
||||
oName = prefix + "\\" + oName;
|
||||
oName = prefix + "/" + oName;
|
||||
|
||||
return oName;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ static void ExporterParseFileMode(const std::string& buildMode, ZFileMode& fileM
|
|||
for (auto item : lst)
|
||||
{
|
||||
auto fileData = File::ReadAllBytes(item);
|
||||
otrArchive->AddFile(StringHelper::Split(item, "Extract\\")[1], (uintptr_t)fileData.data(), fileData.size());
|
||||
otrArchive->AddFile(StringHelper::Split(item, "Extract/")[1], (uintptr_t)fileData.data(), fileData.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,8 +76,12 @@ static void ExporterProgramEnd()
|
|||
for (auto item : lst)
|
||||
{
|
||||
auto fileData = File::ReadAllBytes(item);
|
||||
otrArchive->AddFile(StringHelper::Split(item, "Extract\\")[1], (uintptr_t)fileData.data(), fileData.size());
|
||||
otrArchive->AddFile(StringHelper::Split(item, "Extract/")[1], (uintptr_t)fileData.data(), fileData.size());
|
||||
}
|
||||
|
||||
otrArchive->AddFile("Audiobank", (uintptr_t)Globals::Instance->GetBaseromFile("Audiobank").data(), Globals::Instance->GetBaseromFile("Audiobank").size());
|
||||
otrArchive->AddFile("Audioseq", (uintptr_t)Globals::Instance->GetBaseromFile("Audioseq").data(), Globals::Instance->GetBaseromFile("Audioseq").size());
|
||||
otrArchive->AddFile("Audiotable", (uintptr_t)Globals::Instance->GetBaseromFile("Audiotable").data(), Globals::Instance->GetBaseromFile("Audiotable").size());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +117,7 @@ static void ExporterFileBegin(ZFile* file)
|
|||
|
||||
static void ExporterFileEnd(ZFile* file)
|
||||
{
|
||||
int bp = 0;
|
||||
// delete fileWriter;
|
||||
}
|
||||
|
||||
static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer)
|
||||
|
@ -136,7 +140,7 @@ static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer)
|
|||
{
|
||||
auto split = StringHelper::Split(oName, "_");
|
||||
oName = "";
|
||||
for (int i = 0; i < split.size() - 1; i++)
|
||||
for (size_t i = 0; i < split.size() - 1; i++)
|
||||
oName += split[i] + "_";
|
||||
|
||||
oName += "scene";
|
||||
|
@ -149,14 +153,14 @@ static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer)
|
|||
std::string fName = "";
|
||||
|
||||
if (prefix != "")
|
||||
fName = StringHelper::Sprintf("%s\\%s\\%s", prefix.c_str(), oName.c_str(), rName.c_str());
|
||||
fName = StringHelper::Sprintf("%s/%s/%s", prefix.c_str(), oName.c_str(), rName.c_str());
|
||||
else
|
||||
fName = StringHelper::Sprintf("%s\\%s", oName.c_str(), rName.c_str());
|
||||
fName = StringHelper::Sprintf("%s/%s", oName.c_str(), rName.c_str());
|
||||
|
||||
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
|
||||
files[fName] = strem->ToVector();
|
||||
else
|
||||
File::WriteAllBytes("Extract\\" + fName, strem->ToVector());
|
||||
File::WriteAllBytes("Extract/" + fName, strem->ToVector());
|
||||
}
|
||||
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
|
|
|
@ -39,13 +39,13 @@ D_FILES := $(O_FILES:%.o=%.d)
|
|||
LIB := OTRExporter.a
|
||||
|
||||
INC_DIRS := $(addprefix -I, \
|
||||
../../ZAPD/ZAPD \
|
||||
../../ZAPD/lib/tinyxml2 \
|
||||
../../ZAPD/lib/libgfxd \
|
||||
../../ZAPD/ZAPDUtils \
|
||||
../../OtrLib/otrlib \
|
||||
../../OtrLib/otrlib/Lib/spdlog/include \
|
||||
../../OtrLib/otrlib/Lib/Fast3D/U64 \
|
||||
../../ZAPDTR/ZAPD \
|
||||
../../ZAPDTR/lib/tinyxml2 \
|
||||
../../ZAPDTR/lib/libgfxd \
|
||||
../../ZAPDTR/ZAPDUtils \
|
||||
../../libultraship/libultraship \
|
||||
../../libultraship/libultraship/Lib/spdlog/include \
|
||||
../../libultraship/libultraship/Lib/Fast3D/U64 \
|
||||
)
|
||||
|
||||
# create build directories
|
||||
|
|
|
@ -9,11 +9,11 @@ void OTRExporter_Path::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
|
||||
writer->Write((uint32_t)path->pathways.size());
|
||||
|
||||
for (int k = 0; k < path->pathways.size(); k++)
|
||||
for (size_t k = 0; k < path->pathways.size(); k++)
|
||||
{
|
||||
writer->Write((uint32_t)path->pathways[k].points.size());
|
||||
|
||||
for (int i = 0; i < path->pathways[k].points.size(); i++)
|
||||
for (size_t i = 0; i < path->pathways[k].points.size(); i++)
|
||||
{
|
||||
writer->Write(path->pathways[k].points[i].scalars[0].scalarData.s16);
|
||||
writer->Write(path->pathways[k].points[i].scalars[1].scalarData.s16);
|
||||
|
|
|
@ -46,7 +46,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
for (size_t i = 0; i < room->commands.size(); i++)
|
||||
{
|
||||
ZRoomCommand* cmd = room->commands[i];
|
||||
|
||||
|
||||
writer->Write((uint32_t)cmd->cmdID);
|
||||
|
||||
switch (cmd->cmdID)
|
||||
|
@ -172,7 +172,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
|
||||
writer->Write((uint32_t)cmdCsCam->points.size());
|
||||
|
||||
for (int i = 0; i < cmdCsCam->points.size(); i++)
|
||||
for (size_t i = 0; i < cmdCsCam->points.size(); i++)
|
||||
{
|
||||
writer->Write(cmdCsCam->points[i].scalars[0].scalarData.s16);
|
||||
writer->Write(cmdCsCam->points[i].scalars[1].scalarData.s16);
|
||||
|
@ -183,7 +183,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
case RoomCommand::SetMesh:
|
||||
{
|
||||
SetMesh* cmdMesh = (SetMesh*)cmd;
|
||||
|
||||
|
||||
writer->Write((uint8_t)cmdMesh->data); // 0x01
|
||||
writer->Write(cmdMesh->meshHeaderType);
|
||||
|
||||
|
@ -207,12 +207,12 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
Declaration* dListDeclXlu = poly->parent->GetDeclaration(GETSEGOFFSET(test->xlu));
|
||||
|
||||
if (test->opa != 0)
|
||||
writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str()));
|
||||
writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str()));
|
||||
else
|
||||
writer->Write("");
|
||||
|
||||
|
||||
if (test->xlu != 0)
|
||||
writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclXlu->varName.c_str()));
|
||||
writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclXlu->varName.c_str()));
|
||||
else
|
||||
writer->Write("");
|
||||
|
||||
|
@ -228,7 +228,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
Declaration* bgDecl = poly->parent->GetDeclarationRanged(GETSEGOFFSET(poly->multiList[i].source));
|
||||
|
||||
writer->Write(OTRExporter_DisplayList::GetPathToRes(poly->multiList[i].sourceBackground, bgDecl->varName));
|
||||
|
||||
|
||||
writer->Write(poly->multiList[i].unk_0C);
|
||||
writer->Write(poly->multiList[i].tlut);
|
||||
writer->Write(poly->multiList[i].width);
|
||||
|
@ -338,7 +338,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
|
||||
for (size_t i = 0;i < cmdRoom->romfile->numRooms; i++)
|
||||
{
|
||||
//std::string roomName = StringHelper::Sprintf("%s\\%s_room_%i", (StringHelper::Split(room->GetName(), "_")[0] + "_scene").c_str(), StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i);
|
||||
//std::string roomName = StringHelper::Sprintf("%s/%s_room_%i", (StringHelper::Split(room->GetName(), "_")[0] + "_scene").c_str(), StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i);
|
||||
std::string roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%i", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i));
|
||||
writer->Write(roomName);
|
||||
writer->Write(cmdRoom->romfile->rooms[i].virtualAddressStart);
|
||||
|
@ -383,7 +383,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
uint32_t baseStreamEnd = writer->GetStream().get()->GetLength();
|
||||
|
||||
writer->Write((uint32_t)cmdStartPos->actors.size()); // 0x01
|
||||
|
||||
|
||||
for (const ActorSpawnEntry& entry : cmdStartPos->actors)
|
||||
{
|
||||
writer->Write(entry.actorNum);
|
||||
|
@ -441,7 +441,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
case RoomCommand::SetCutscenes:
|
||||
{
|
||||
SetCutscenes* cmdSetCutscenes = (SetCutscenes*)cmd;
|
||||
|
||||
|
||||
std::string listName;
|
||||
Globals::Instance->GetSegmentedPtrName(cmdSetCutscenes->cmdArg2, room->parent, "CutsceneData", listName, res->parent->workerID);
|
||||
std::string fName = OTRExporter_DisplayList::GetPathToRes(room, listName);
|
||||
|
@ -452,9 +452,9 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
BinaryWriter csWriter = BinaryWriter(csStream);
|
||||
OTRExporter_Cutscene cs;
|
||||
cs.Save(cmdSetCutscenes->cutscenes[0], "", &csWriter);
|
||||
|
||||
|
||||
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
|
||||
File::WriteAllBytes("Extract\\" + fName, csStream->ToVector());
|
||||
File::WriteAllBytes("Extract/" + fName, csStream->ToVector());
|
||||
else
|
||||
files[fName] = csStream->ToVector();
|
||||
|
||||
|
@ -468,7 +468,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
|
||||
writer->Write((uint32_t)cmdSetPathways->pathwayList.pathways.size());
|
||||
|
||||
for (int i = 0; i < cmdSetPathways->pathwayList.pathways.size(); i++)
|
||||
for (size_t i = 0; i < cmdSetPathways->pathwayList.pathways.size(); i++)
|
||||
{
|
||||
Declaration* decl = room->parent->GetDeclaration(GETSEGOFFSET(cmdSetPathways->pathwayList.pathways[i].listSegmentAddress));
|
||||
//std::string path = StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), decl->varName.c_str());
|
||||
|
@ -481,7 +481,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
pathExp.Save(&cmdSetPathways->pathwayList, outPath, &pathWriter);
|
||||
|
||||
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
|
||||
File::WriteAllBytes("Extract\\" + path, pathStream->ToVector());
|
||||
File::WriteAllBytes("Extract/" + path, pathStream->ToVector());
|
||||
else
|
||||
files[path] = pathStream->ToVector();
|
||||
|
||||
|
@ -514,12 +514,12 @@ void OTRExporter_Room::WritePolyDList(BinaryWriter* writer, ZRoom* room, Polygon
|
|||
writer->Write(dlist->unk_06);
|
||||
[[fallthrough]];
|
||||
default:
|
||||
//writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str()));
|
||||
//writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str()));
|
||||
|
||||
if (dlist->opaDList != nullptr)
|
||||
{
|
||||
auto opaDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->opaDList->GetRawDataIndex()));
|
||||
writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), opaDecl->varName.c_str()));
|
||||
writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), opaDecl->varName.c_str()));
|
||||
}
|
||||
else
|
||||
writer->Write("");
|
||||
|
@ -527,7 +527,7 @@ void OTRExporter_Room::WritePolyDList(BinaryWriter* writer, ZRoom* room, Polygon
|
|||
if (dlist->xluDList != nullptr)
|
||||
{
|
||||
auto xluDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->xluDList->GetRawDataIndex()));
|
||||
writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), xluDecl->varName.c_str()));
|
||||
writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), xluDecl->varName.c_str()));
|
||||
}
|
||||
else
|
||||
writer->Write("");
|
||||
|
|
|
@ -8,8 +8,8 @@ void OTRExporter_Text::Save(ZResource* res, const fs::path& outPath, BinaryWrite
|
|||
WriteHeader(txt, outPath, writer, Ship::ResourceType::Text);
|
||||
|
||||
writer->Write((uint32_t)txt->messages.size());
|
||||
|
||||
for (int i = 0; i < txt->messages.size(); i++)
|
||||
|
||||
for (size_t i = 0; i < txt->messages.size(); i++)
|
||||
{
|
||||
writer->Write(txt->messages[i].id);
|
||||
writer->Write(txt->messages[i].textboxType);
|
||||
|
|
|
@ -5,21 +5,23 @@ std::map<Ship::ResourceType, uint32_t> resourceVersions;
|
|||
|
||||
void InitVersionInfo()
|
||||
{
|
||||
resourceVersions[Ship::ResourceType::Animation] = 0;
|
||||
resourceVersions[Ship::ResourceType::Model] = 0;
|
||||
resourceVersions[Ship::ResourceType::Texture] = 0;
|
||||
resourceVersions[Ship::ResourceType::Material] = 0;
|
||||
resourceVersions[Ship::ResourceType::PlayerAnimation] = 0;
|
||||
resourceVersions[Ship::ResourceType::DisplayList] = 0;
|
||||
resourceVersions[Ship::ResourceType::Room] = 0;
|
||||
resourceVersions[Ship::ResourceType::CollisionHeader] = 0;
|
||||
resourceVersions[Ship::ResourceType::Skeleton] = 0;
|
||||
resourceVersions[Ship::ResourceType::SkeletonLimb] = 0;
|
||||
resourceVersions[Ship::ResourceType::Matrix] = 0;
|
||||
resourceVersions[Ship::ResourceType::Path] = 0;
|
||||
resourceVersions[Ship::ResourceType::Vertex] = 0;
|
||||
resourceVersions[Ship::ResourceType::Cutscene] = 0;
|
||||
resourceVersions[Ship::ResourceType::Array] = 0;
|
||||
resourceVersions[Ship::ResourceType::Text] = 0;
|
||||
resourceVersions[Ship::ResourceType::Blob] = 0;
|
||||
resourceVersions = {
|
||||
{ Ship::ResourceType::Animation, 0 },
|
||||
{ Ship::ResourceType::Model, 0 },
|
||||
{ Ship::ResourceType::Texture, 0 },
|
||||
{ Ship::ResourceType::Material, 0 },
|
||||
{ Ship::ResourceType::PlayerAnimation, 0 },
|
||||
{ Ship::ResourceType::DisplayList, 0 },
|
||||
{ Ship::ResourceType::Room, 0 },
|
||||
{ Ship::ResourceType::CollisionHeader, 0 },
|
||||
{ Ship::ResourceType::Skeleton, 0 },
|
||||
{ Ship::ResourceType::SkeletonLimb, 0 },
|
||||
{ Ship::ResourceType::Matrix, 0 },
|
||||
{ Ship::ResourceType::Path, 0 },
|
||||
{ Ship::ResourceType::Vertex, 0 },
|
||||
{ Ship::ResourceType::Cutscene, 0 },
|
||||
{ Ship::ResourceType::Array, 0 },
|
||||
{ Ship::ResourceType::Text, 0 },
|
||||
{ Ship::ResourceType::Blob, 0 },
|
||||
};
|
||||
}
|
BIN
OTRExporter/assets/ship_of_harkinian/fonts/Fipps-Regular.otf
Normal file
BIN
OTRExporter/assets/ship_of_harkinian/fonts/Fipps-Regular.otf
Normal file
Binary file not shown.
Binary file not shown.
|
@ -1,24 +1,15 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse, json, os, signal, time, sys, shutil
|
||||
from multiprocessing import Pool, cpu_count, Event, Manager, ProcessError
|
||||
import os, sys, shutil
|
||||
import shutil
|
||||
from rom_info import Z64Rom
|
||||
import rom_chooser
|
||||
|
||||
def SignalHandler(sig, frame):
|
||||
print(f'Signal {sig} received. Aborting...')
|
||||
mainAbort.set()
|
||||
# Don't exit immediately to update the extracted assets file.
|
||||
|
||||
def BuildOTR():
|
||||
shutil.copyfile("baserom/Audiobank", "Extract/Audiobank")
|
||||
shutil.copyfile("baserom/Audioseq", "Extract/Audioseq")
|
||||
shutil.copyfile("baserom/Audiotable", "Extract/Audiotable")
|
||||
|
||||
def BuildOTR(xmlPath, rom):
|
||||
shutil.copytree("assets", "Extract/assets")
|
||||
|
||||
execStr = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPD/ZAPD.out"
|
||||
|
||||
execStr += " botr -se OTR"
|
||||
execStr = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out"
|
||||
execStr += " ed -i %s -b %s -fl CFG/filelists -o placeholder -osf placeholder -gsf 1 -rconf CFG/Config.xml -se OTR" % (xmlPath, rom)
|
||||
|
||||
print(execStr)
|
||||
exitValue = os.system(execStr)
|
||||
|
@ -28,98 +19,14 @@ def BuildOTR():
|
|||
print("Aborting...", file=os.sys.stderr)
|
||||
print("\n")
|
||||
|
||||
def ExtractFile(xmlPath, outputPath, outputSourcePath):
|
||||
execStr = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPD/ZAPD.out"
|
||||
execStr += " e -eh -i %s -b baserom/ -o %s -osf %s -gsf 1 -rconf CFG/Config.xml -se OTR" % (xmlPath, outputPath, outputSourcePath)
|
||||
|
||||
if "overlays" in xmlPath:
|
||||
execStr += " --static"
|
||||
|
||||
print(execStr)
|
||||
exitValue = os.system(execStr)
|
||||
#exitValue = 0
|
||||
if exitValue != 0:
|
||||
print("\n")
|
||||
print("Error when extracting from file " + xmlPath, file=os.sys.stderr)
|
||||
print("Aborting...", file=os.sys.stderr)
|
||||
print("\n")
|
||||
|
||||
def ExtractFunc(fullPath):
|
||||
*pathList, xmlName = fullPath.split(os.sep)
|
||||
objectName = os.path.splitext(xmlName)[0]
|
||||
|
||||
outPath = os.path.join("..\\soh\\assets\\", *pathList[5:], objectName)
|
||||
os.makedirs(outPath, exist_ok=True)
|
||||
outSourcePath = outPath
|
||||
|
||||
ExtractFile(fullPath, outPath, outSourcePath)
|
||||
|
||||
def initializeWorker(abort, test):
|
||||
global globalAbort
|
||||
globalAbort = abort
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="baserom asset extractor")
|
||||
parser.add_argument("-s", "--single", help="asset path relative to assets/, e.g. objects/gameplay_keep")
|
||||
parser.add_argument("-f", "--force", help="Force the extraction of every xml instead of checking the touched ones.", action="store_true")
|
||||
parser.add_argument("-u", "--unaccounted", help="Enables ZAPD unaccounted detector warning system.", action="store_true")
|
||||
parser.add_argument("-v", "--version", help="Sets game version.")
|
||||
args = parser.parse_args()
|
||||
rom_path = rom_chooser.chooseROM()
|
||||
rom = Z64Rom(rom_path)
|
||||
|
||||
global mainAbort
|
||||
mainAbort = Event()
|
||||
manager = Manager()
|
||||
signal.signal(signal.SIGINT, SignalHandler)
|
||||
|
||||
extractedAssetsTracker = manager.dict()
|
||||
|
||||
xmlVer = "GC_NMQ_D"
|
||||
|
||||
if (args.version == "gc_pal_nmpq"):
|
||||
xmlVer = "GC_NMQ_PAL_F"
|
||||
elif (args.version == "dbg_mq"):
|
||||
xmlVer = "GC_MQ_D"
|
||||
|
||||
asset_path = args.single
|
||||
if asset_path is not None:
|
||||
fullPath = os.path.join("..\\soh\\assets", "xml", asset_path + ".xml")
|
||||
if not os.path.exists(fullPath):
|
||||
print(f"Error. File {fullPath} doesn't exists.", file=os.sys.stderr)
|
||||
exit(1)
|
||||
|
||||
ExtractFunc(fullPath)
|
||||
else:
|
||||
extract_text_path = "assets/text/message_data.h"
|
||||
if os.path.isfile(extract_text_path):
|
||||
extract_text_path = None
|
||||
extract_staff_text_path = "assets/text/message_data_staff.h"
|
||||
if os.path.isfile(extract_staff_text_path):
|
||||
extract_staff_text_path = None
|
||||
|
||||
xmlFiles = []
|
||||
for currentPath, _, files in os.walk(os.path.join("..\\soh\\assets\\xml\\", xmlVer)):
|
||||
for file in files:
|
||||
fullPath = os.path.join(currentPath, file)
|
||||
if file.endswith(".xml"):
|
||||
xmlFiles.append(fullPath)
|
||||
|
||||
try:
|
||||
numCores = 2
|
||||
print("Extracting assets with " + str(numCores) + " CPU cores.")
|
||||
with Pool(numCores, initializer=initializeWorker, initargs=(mainAbort, 0)) as p:
|
||||
p.map(ExtractFunc, xmlFiles)
|
||||
except Exception as e:
|
||||
print("Warning: Multiprocessing exception ocurred.", file=os.sys.stderr)
|
||||
print("Disabling mutliprocessing.", file=os.sys.stderr)
|
||||
|
||||
initializeWorker(mainAbort, 0)
|
||||
for singlePath in xmlFiles:
|
||||
ExtractFunc(singlePath)
|
||||
|
||||
|
||||
BuildOTR()
|
||||
if (os.path.exists("Extract")):
|
||||
shutil.rmtree("Extract")
|
||||
|
||||
BuildOTR("../soh/assets/xml/" + rom.version.xml_ver + "/", rom_path)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
|
53
OTRExporter/extract_baserom.py
Normal file
53
OTRExporter/extract_baserom.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
from multiprocessing import Pool, cpu_count
|
||||
from rom_info import Z64Rom
|
||||
import rom_chooser
|
||||
|
||||
|
||||
rom = None
|
||||
|
||||
def initialize_worker(input_rom):
|
||||
global rom
|
||||
rom = input_rom
|
||||
|
||||
def ExtractFunc(i):
|
||||
|
||||
dma_file = rom.getDmaEntryByIndex(i)
|
||||
dma_data = rom.readDmaEntry(dma_file)
|
||||
|
||||
filename = '../soh/baserom/' + rom.version.file_table[i]
|
||||
print('extracting ' + filename + " (0x%08X, 0x%08X)" % (dma_file.virtStart, dma_file.virtEnd))
|
||||
|
||||
try:
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(dma_data)
|
||||
except IOError:
|
||||
print('failed to write file ' + filename)
|
||||
|
||||
# TODO: handle this better
|
||||
if dma_file.compressed:
|
||||
os.system('tools/yaz0 -d ' + filename + ' ' + filename)
|
||||
|
||||
#####################################################################
|
||||
|
||||
def main():
|
||||
try:
|
||||
os.mkdir('../soh/baserom')
|
||||
except:
|
||||
pass
|
||||
|
||||
rom_path = rom_chooser.chooseROM()
|
||||
input_rom = Z64Rom(rom_path)
|
||||
|
||||
# extract files
|
||||
num_cores = cpu_count()
|
||||
print("Extracting baserom with " + str(num_cores) + " CPU cores.")
|
||||
with Pool(num_cores, initialize_worker, (input_rom,)) as p:
|
||||
p.map(ExtractFunc, range(len(input_rom.version.file_table)))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
37
OTRExporter/rom_chooser.py
Normal file
37
OTRExporter/rom_chooser.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
import os, sys, glob
|
||||
|
||||
from rom_info import Z64Rom
|
||||
|
||||
def chooseROM():
|
||||
roms = []
|
||||
|
||||
for file in glob.glob("*.z64"):
|
||||
if Z64Rom.isValidRom(file):
|
||||
roms.append(file)
|
||||
|
||||
if not (roms):
|
||||
print("Error: No roms located, place one in the OTRExporter directory", file=os.sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if (len(roms) == 1):
|
||||
return roms[0]
|
||||
|
||||
print(str(len(roms))+ " roms found, please select one by pressing 1-"+str(len(roms)))
|
||||
|
||||
for i in range(len(roms)):
|
||||
print(str(i+1)+ ". " + roms[i])
|
||||
|
||||
while(1):
|
||||
try:
|
||||
selection = int(input())
|
||||
except:
|
||||
print("Bad input. Try again with the number keys.")
|
||||
continue
|
||||
|
||||
if (selection < 1 or selection > len(roms)):
|
||||
print("Bad input. Try again.")
|
||||
continue
|
||||
|
||||
else: break
|
||||
|
||||
return roms[selection - 1]
|
87
OTRExporter/rom_info.py
Normal file
87
OTRExporter/rom_info.py
Normal file
|
@ -0,0 +1,87 @@
|
|||
from enum import Enum
|
||||
from tabnanny import check
|
||||
import struct
|
||||
|
||||
class Checksums(Enum):
|
||||
OOT_NTSC_10 = "EC7011B7"
|
||||
OOT_NTSC_11 = "D43DA81F"
|
||||
OOT_NTSC_12 = "693BA2AE"
|
||||
OOT_PAL_10 = "B044B569"
|
||||
OOT_PAL_11 = "B2055FBD"
|
||||
OOT_NTSC_JP_GC_CE = "F7F52DB8"
|
||||
OOT_NTSC_JP_GC = "F611F4BA"
|
||||
OOT_NTSC_US_GC = "F3DD35BA"
|
||||
OOT_PAL_GC = "09465AC3"
|
||||
OOT_NTSC_JP_MQ = "F43B45BA"
|
||||
OOT_NTSC_US_MQ = "F034001A"
|
||||
OOT_PAL_MQ = "1D4136F3"
|
||||
OOT_PAL_GC_DBG1 = "871E1C92"
|
||||
OOT_PAL_GC_DBG2 = "87121EFE"
|
||||
OOT_PAL_GC_MQ_DBG = "917D18F6"
|
||||
OOT_IQUE_TW = "3D81FB3E"
|
||||
OOT_IQUE_CN = "B1E1E07B"
|
||||
OOT_UNKNOWN = "FFFFFFFF"
|
||||
|
||||
@classmethod
|
||||
def has_value(self, value):
|
||||
return value in self._value2member_map_
|
||||
|
||||
class RomVersion:
|
||||
def __init__(self, file_table_path, file_table_off, xml_ver):
|
||||
self.file_table_off = file_table_off
|
||||
self.xml_ver = xml_ver
|
||||
with open(file_table_path, 'r') as f:
|
||||
self.file_table = [line.strip('\n') for line in f]
|
||||
|
||||
ROM_INFO_TABLE = dict()
|
||||
ROM_INFO_TABLE[Checksums.OOT_PAL_GC] = RomVersion("CFG/filelists/gamecube_pal.txt", 0x7170, "GC_NMQ_PAL_F")
|
||||
ROM_INFO_TABLE[Checksums.OOT_PAL_GC_DBG1] = RomVersion("CFG/filelists/dbg.txt", 0x12F70, "GC_NMQ_D")
|
||||
|
||||
class RomDmaEntry:
|
||||
def __init__(self, rom, i):
|
||||
|
||||
off = rom.version.file_table_off + 16 * i
|
||||
|
||||
(self.virtStart, \
|
||||
self.virtEnd, \
|
||||
self.physStart, \
|
||||
self.physEnd) = struct.unpack('>IIII', rom.rom_data[off:off+4*4])
|
||||
|
||||
self.compressed = self.physEnd != 0
|
||||
self.size = self.physEnd - self.physStart \
|
||||
if self.compressed \
|
||||
else self.virtEnd - self.virtStart
|
||||
self.name = rom.version.file_table[i]
|
||||
|
||||
|
||||
class Z64Rom:
|
||||
def __init__(self, file_path):
|
||||
self.file_path = file_path
|
||||
with open(file_path, 'rb') as f:
|
||||
self.rom_data = f.read()
|
||||
|
||||
self.is_valid = len(self.rom_data) > 20 * 1024 * 1024
|
||||
|
||||
if not self.is_valid:
|
||||
return
|
||||
|
||||
# get checkum
|
||||
checksum_str = self.rom_data[16:16+4].hex().upper()
|
||||
self.checksum = Checksums(checksum_str) if Checksums.has_value(checksum_str) else Checksums.OOT_UNKNOWN
|
||||
|
||||
if self.checksum == Checksums.OOT_UNKNOWN:
|
||||
self.is_valid = False
|
||||
return
|
||||
|
||||
# get rom version
|
||||
self.version = ROM_INFO_TABLE[self.checksum]
|
||||
|
||||
def getDmaEntryByIndex(self, i):
|
||||
return RomDmaEntry(self, i)
|
||||
|
||||
def readDmaEntry(self, entry):
|
||||
return self.rom_data[entry.physStart:entry.physStart + entry.size]
|
||||
|
||||
@staticmethod
|
||||
def isValidRom(rom_path):
|
||||
return Z64Rom(rom_path).is_valid
|
|
@ -67,13 +67,13 @@ void OTRGame::init(){
|
|||
mat.shader = shader;
|
||||
}
|
||||
|
||||
if(fs::exists("soh.exe") && !fs::exists("oot.otr")) {
|
||||
if((fs::exists("soh.exe") || fs::exists("soh.elf")) && !fs::exists("oot.otr")) {
|
||||
hide_second_btn = true;
|
||||
sohFolder = ".";
|
||||
}
|
||||
}
|
||||
|
||||
void ExtractRom()
|
||||
void ExtractRom()
|
||||
{
|
||||
WriteResult result;
|
||||
|
||||
|
@ -87,10 +87,11 @@ void ExtractRom()
|
|||
if (MoonUtils::exists("Extract")) MoonUtils::rm("Extract");
|
||||
|
||||
MoonUtils::mkdir("Extract");
|
||||
MoonUtils::copy("tmp/baserom/Audiobank", "Extract/Audiobank");
|
||||
MoonUtils::copy("tmp/baserom/Audioseq", "Extract/Audioseq");
|
||||
MoonUtils::copy("tmp/baserom/Audiotable", "Extract/Audiotable");
|
||||
MoonUtils::copy("tmp/baserom/version", "Extract/version");
|
||||
//MoonUtils::copy("tmp/baserom/Audiobank", "Extract/Audiobank");
|
||||
//MoonUtils::copy("tmp/baserom/Audioseq", "Extract/Audioseq");
|
||||
//MoonUtils::copy("tmp/baserom/Audiotable", "Extract/Audiotable");
|
||||
//MoonUtils::copy("tmp/baserom/version", "Extract/version");
|
||||
MoonUtils::write("Extract/version", (char*)&version.crc, sizeof(version.crc));
|
||||
|
||||
MoonUtils::copy("assets/game/", "Extract/assets/");
|
||||
|
||||
|
@ -187,7 +188,7 @@ void OTRGame::draw() {
|
|||
sohFolder = path;
|
||||
}
|
||||
|
||||
if (UIUtils::GuiIconButton("Cartridge", "Open\nOoT Rom", 32, 50, currentStep != NULLSTR, "Select an Ocarina of Time\nMaster Quest or Vanilla Debug Rom\n\nYou can dump it or lend one from Nintendo")) {
|
||||
if (UIUtils::GuiIconButton("Cartridge", "Open\nOoT Rom", 32, 50, currentStep != NULLSTR, "Select an Ocarina of Time\nGameCube PAL or Vanilla Debug Rom\n\nYou can dump it or lend one from Nintendo")) {
|
||||
const std::string path = NativeFS->LaunchFileExplorer(LaunchType::FILE);
|
||||
if (path != NULLSTR) {
|
||||
const std::string patched_n64 = std::string(patched_rom);
|
||||
|
@ -219,4 +220,4 @@ void setCurrentStep(const std::string& step) {
|
|||
|
||||
void OTRGame::exit(){
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,6 @@ void startWorker(RomVersion version) {
|
|||
|
||||
Util::write("tmp/baserom/version", (char*)&version.crc, sizeof(version.crc));
|
||||
|
||||
|
||||
if (oldExtractMode)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
|
|
110
README.md
110
README.md
|
@ -6,15 +6,22 @@ The Ship does not include assets and as such requires a prior copy of the game t
|
|||
|
||||
## Quick Start
|
||||
|
||||
1) Download The Ship of Harkinian from Discord.
|
||||
2) Requires an `oot debug` rom (not Master Quest).
|
||||
1) Download The Ship of Harkinian from [Discord](https://discord.com/invite/BtBmd55HVH).
|
||||
2) Requires a supported copy of the game (See supported games below).
|
||||
3) Use the OTRGui to generate an `oot.otr` archive file.
|
||||
4) Launch `soh.exe`
|
||||
|
||||
### Supported Games
|
||||
Ocarina of Time Debug (not Master Quest)
|
||||
```
|
||||
Build team: `zelda@srd022j`
|
||||
Build date: `03-02-21 00:49:18` (year-month-day)
|
||||
sha1: cee6bc3c2a634b41728f2af8da54d9bf8cc14099
|
||||
```
|
||||
3) Use the OTRGui to generate an `oot.otr` archive file.
|
||||
4) Launch `soh.exe`
|
||||
Ocarina of Time PAL GameCube
|
||||
```
|
||||
sha1: 0227d7c0074f2d0ac935631990da8ec5914597b4
|
||||
```
|
||||
|
||||
Congratulations, you are now sailing with the Ship of Harkinian! Have fun!
|
||||
|
||||
|
@ -37,7 +44,7 @@ If you still cannot get the tool to work, join our [Discord Server](https://disc
|
|||
|
||||
### Running The Ship of Harkinian
|
||||
|
||||
Launch the game. If the window immediately closes, or if there are visual artifacts, you may have selected the wrong rom in the OTRGui tool.
|
||||
Launch the game. If the window immediately closes, or if there are visual artifacts, you may have selected the wrong rom in the OTRGui tool.
|
||||
|
||||
Currently, DirectX 11 and OpenGL is supported. Change the renderer by opening the `shipofharkinian.ini` configuration file in notepad and add `sdl` to `gfx backend` for OpenGL or leave blank for DirectX.
|
||||
|
||||
|
@ -51,64 +58,57 @@ Official Discord: https://discord.com/invite/BtBmd55HVH
|
|||
|
||||
## Building The Ship of Harkinian
|
||||
|
||||
1. Install [Python](https://www.python.org/ftp/python/3.10.2/python-3.10.2-amd64.exe)
|
||||
2. Install [Visual Studio 2022 Community Edition](https://visualstudio.microsoft.com/vs/community/)
|
||||
2b. In the Visual Studio Installer, install `MSVC v142 - VS 2019 C++`.
|
||||
4. Clone the Ship of Harkinian repository.
|
||||
5. Place `oot debug` rom (not Master Quest) in the `soh` folder named `baserom_original_non_mq`.
|
||||
6. Launch `soh/fixbaserom.py`.
|
||||
7. Launch `soh/extract_baserom.py`.
|
||||
8. Copy the `baserom` folder from the `soh` folder into the `OTRExporter` folder.
|
||||
9. Run `OTRExporter/OTRExporter.sln`.
|
||||
10. Switch the solution to `Release x64`.
|
||||
11. Build the solution.
|
||||
12. Launching `OTRExporter/extract_assets.py` will generate an `oot.otr` archive file in `OTRExporter/oot.otr`.
|
||||
13. Run `soh/soh.sln`
|
||||
14. Switch the solution to `Release x86`.
|
||||
15. Build the solution.
|
||||
16. Copy the `OTRExporter/oot.otr` archive file to `soh/Release`.
|
||||
17. Launch `soh.exe`.
|
||||
Refer to the [building instructions](BUILDING.md) to compile SoH.
|
||||
|
||||
## Troubleshooting The Exporter
|
||||
- Affirm that you have an `/assets` folder filled with XMLs in the same directory as OTRGui.exe
|
||||
- Affirm that `zapd.exe` exists in the `/assets/extractor` folder
|
||||
|
||||
## Nightly Builds
|
||||
Nightly builds of Ship of Harkinian are available at [https://builds.shipofharkinian.com/job/SoH_Multibranch/job/develop]
|
||||
|
||||
|
||||
## The Harbour Masters Are...
|
||||
|
||||
Kenix | Lead Developer/Public Relations - Resource Management Programmer, Audio System Programmer, and General Programmer
|
||||
Jack Walker | Lead Developer - OTR Format Programmer, Resource Load Programmer, and General Programmer
|
||||
Louist103 | Developer - Save System Programmer and General Programmer
|
||||
Emil | Developer - Fast3D Programmer
|
||||
m4xw | Developer - Shipwright, Throwing Baguettes, and General Programmer
|
||||
MelonSpeedruns | Developer - General Programmer
|
||||
Rozlette | Developer - General Programmer
|
||||
JoshDuMan | Developer - General Programmer
|
||||
KiritoDev/Lywx | Developer - General Programmer
|
||||
Theo3 | Developer - General Programmer
|
||||
Random06457 | Developer - Linux Build
|
||||
Kenix | Lead Developer/Public Relations - Resource Management Programmer, Audio System Programmer, and General Programmer
|
||||
Jack Walker | Lead Developer - OTR Format Programmer, Resource Load Programmer, and General Programmer
|
||||
Louist103 | Developer - Save System Programmer and General Programmer
|
||||
Emil | Developer - Fast3D Programmer
|
||||
m4xw | Developer - Shipwright, Throwing Baguettes, and General Programmer
|
||||
MelonSpeedruns | Developer - General Programmer
|
||||
Rozlette | Developer - General Programmer
|
||||
JoshDuMan | Developer - General Programmer
|
||||
KiritoDev/Lywx | Developer - General Programmer
|
||||
Theo3 | Developer - General Programmer
|
||||
Random06457 | Developer - Linux Build
|
||||
|
||||
## Special Thanks
|
||||
|
||||
Decomp & ZAPD | Made this project even possible in the first place!
|
||||
MNGoldenEagle | Patiently explained audio data formats, encouragement, and founding ZSO which was the first source of the game's code and resource format documentation.
|
||||
Rrrrry123 | Speedbunner, encouragement, and community moderation
|
||||
Fierce deity | Encouragement and community moderation
|
||||
mzxrules | For his contributions to decomp
|
||||
zel. | For his contributions to decomp
|
||||
Aloxado | Developer - General Programmer
|
||||
MegaMech | Developer - General Programmer
|
||||
Revo | Tester - GCC support and General Testing
|
||||
zfg | Tester - General Testing
|
||||
Horseless Headman | Tester - General Testing
|
||||
Steven Pritchett | Tester - General Testing
|
||||
Trenton May | Tester - General Testing
|
||||
Zeldaboy14 | Tester - General Testing, encouragement, and community moderation
|
||||
Koby Howell | Tester - General Testing
|
||||
Logg | Tester - General Testing
|
||||
Taylor Daley | Graphic Design
|
||||
Can't Sleep | Graphic Design
|
||||
MicTheMicrophone | Voice actor for the King
|
||||
Amphibibro | Voice actor for Link
|
||||
|
||||
Lemons
|
||||
Decomp & ZAPD | Made this project even possible in the first place!
|
||||
MNGoldenEagle | Patiently explained audio data formats, encouragement, and founding ZSO which was the first source of the game's code and resource format documentation.
|
||||
Rrrrry123 | Speedbunner, encouragement, and community moderation
|
||||
Fierce deity | Encouragement and community moderation
|
||||
mzxrules | For his contributions to decomp
|
||||
zel. | For his contributions to decomp
|
||||
Aloxado | Developer - General Programmer
|
||||
MegaMech | Developer - General Programmer
|
||||
Revo | Tester - GCC support and General Testing
|
||||
zfg | Tester - General Testing
|
||||
Horseless Headman | Tester - General Testing
|
||||
Steven Pritchett | Tester - General Testing
|
||||
Trenton May | Tester - General Testing
|
||||
Zeldaboy14 | Tester - General Testing, encouragement, and community moderation
|
||||
Koby Howell | Tester - General Testing
|
||||
Logg | Tester - General Testing
|
||||
Taylor Daley | Graphic Design
|
||||
Can't Sleep | Graphic Design
|
||||
|
||||
## Video Credits
|
||||
Kenix | Producer / Writer
|
||||
rainbow_fash | Executive Producer
|
||||
TheLegendOfXela | Editor
|
||||
MicTheMicrophone | Gwonam / The King
|
||||
Amphibibro | Link
|
||||
AceHeart | Zelda
|
||||
|
||||
###### Lemons
|
|
@ -1,6 +1,6 @@
|
|||
#include "CollisionExporter.h"
|
||||
|
||||
void ExporterExample_Collision::Save(ZResource* res, [[maybe_unused]] fs::path outPath,
|
||||
void ExporterExample_Collision::Save(ZResource* res, [[maybe_unused]] const fs::path& outPath,
|
||||
BinaryWriter* writer)
|
||||
{
|
||||
ZCollisionHeader* col = (ZCollisionHeader*)res;
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
class ExporterExample_Collision : public ZResourceExporter
|
||||
{
|
||||
public:
|
||||
void Save(ZResource* res, fs::path outPath, BinaryWriter* writer) override;
|
||||
void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override;
|
||||
};
|
|
@ -20,7 +20,7 @@
|
|||
#include "ZRoom/Commands/SetTimeSettings.h"
|
||||
#include "ZRoom/Commands/SetWind.h"
|
||||
|
||||
void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter* writer)
|
||||
void ExporterExample_Room::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
|
||||
{
|
||||
ZRoom* room = dynamic_cast<ZRoom*>(res);
|
||||
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
class ExporterExample_Room : public ZResourceExporter
|
||||
{
|
||||
public:
|
||||
void Save(ZResource* res, fs::path outPath, BinaryWriter* writer) override;
|
||||
void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override;
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
#include "TextureExporter.h"
|
||||
#include "../ZAPD/ZFile.h"
|
||||
|
||||
void ExporterExample_Texture::Save(ZResource* res, [[maybe_unused]] fs::path outPath,
|
||||
void ExporterExample_Texture::Save(ZResource* res, [[maybe_unused]] const fs::path& outPath,
|
||||
BinaryWriter* writer)
|
||||
{
|
||||
ZTexture* tex = (ZTexture*)res;
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
class ExporterExample_Texture : public ZResourceExporter
|
||||
{
|
||||
public:
|
||||
void Save(ZResource* res, fs::path outPath, BinaryWriter* writer) override;
|
||||
void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override;
|
||||
};
|
|
@ -44,7 +44,8 @@ ifneq ($(DEPRECATION_ON),0)
|
|||
endif
|
||||
# CXXFLAGS += -DTEXTURE_DEBUG
|
||||
|
||||
LDFLAGS := -lm -ldl -lpng
|
||||
LDFLAGS := -lm -ldl -lpng \
|
||||
-L../external -L../libultraship -lz -lbz2 -pthread -lpulse -lultraship -lstorm -lSDL2 -lGLEW -lGL -lX11
|
||||
|
||||
# Use LLD if available. Set LLD=0 to not use it
|
||||
ifeq ($(shell command -v ld.lld >/dev/null 2>&1; echo $$?),0)
|
||||
|
@ -59,9 +60,9 @@ UNAME := $(shell uname)
|
|||
UNAMEM := $(shell uname -m)
|
||||
ifneq ($(UNAME), Darwin)
|
||||
LDFLAGS += -Wl,-export-dynamic -lstdc++fs
|
||||
EXPORTERS := -Wl,--whole-archive ExporterTest/ExporterTest.a -Wl,--no-whole-archive
|
||||
EXPORTERS := -Wl,--whole-archive ../OTRExporter/OTRExporter/OTRExporter.a -Wl,--no-whole-archive
|
||||
else
|
||||
EXPORTERS := -Wl,-force_load ExporterTest/ExporterTest.a
|
||||
EXPORTERS := -Wl,-force_load ../OTRExporter/OTRExporter/OTRExporter.a
|
||||
ifeq ($(UNAMEM),arm64)
|
||||
ifeq ($(shell brew list libpng > /dev/null 2>&1; echo $$?),0)
|
||||
LDFLAGS += -L $(shell brew --prefix)/lib
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "ZFile.h"
|
||||
#include "ZTexture.h"
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__CYGWIN__)
|
||||
#ifdef __linux__
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
@ -28,6 +28,31 @@
|
|||
//extern const char gBuildHash[];
|
||||
const char gBuildHash[] = "";
|
||||
|
||||
// LINUX_TODO: remove, those are because of soh <-> lus dependency problems
|
||||
float divisor_num = 0.0f;
|
||||
|
||||
extern "C" void Audio_SetGameVolume(int player_id, float volume)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
extern "C" int ResourceMgr_OTRSigCheck(char* imgData)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DebugConsole_SaveCVars()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DebugConsole_LoadCVars()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath,
|
||||
ZFileMode fileMode, int workerID);
|
||||
|
||||
|
@ -38,7 +63,7 @@ int ExtractFunc(int workerID, int fileListSize, std::string fileListItem, ZFileM
|
|||
|
||||
volatile int numWorkersLeft = 0;
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__CYGWIN__)
|
||||
#ifdef __linux__
|
||||
#define ARRAY_COUNT(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
void ErrorHandler(int sig)
|
||||
{
|
||||
|
@ -196,7 +221,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
else if (arg == "-eh") // Enable Error Handler
|
||||
{
|
||||
#if !defined(_MSC_VER) && !defined(__CYGWIN__)
|
||||
#ifdef __linux__
|
||||
signal(SIGSEGV, ErrorHandler);
|
||||
signal(SIGABRT, ErrorHandler);
|
||||
#else
|
||||
|
@ -302,7 +327,7 @@ int main(int argc, char* argv[])
|
|||
ctpl::thread_pool pool(num_threads / 2);
|
||||
|
||||
bool parseSuccessful;
|
||||
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
int fileListSize = fileList.size();
|
||||
Globals::Instance->singleThreaded = false;
|
||||
|
@ -387,18 +412,6 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
BuildAssetBlob(Globals::Instance->inputPath, Globals::Instance->outputPath);
|
||||
}
|
||||
/*
|
||||
else if (fileMode == ZFileMode::BuildOverlay)
|
||||
{
|
||||
ZOverlay* overlay =
|
||||
ZOverlay::FromBuild(Path::GetDirectoryName(Globals::Instance->inputPath),
|
||||
Path::GetDirectoryName(Globals::Instance->cfgPath));
|
||||
|
||||
if (overlay != nullptr)
|
||||
File::WriteAllText(Globals::Instance->outputPath.string(),
|
||||
overlay->GetSourceOutputCode(""));
|
||||
}
|
||||
*/
|
||||
|
||||
if (exporterSet != nullptr && exporterSet->endProgramFunc != nullptr)
|
||||
exporterSet->endProgramFunc();
|
||||
|
@ -465,6 +478,7 @@ int ExtractFunc(int workerID, int fileListSize, std::string fileListItem, ZFileM
|
|||
|
||||
numWorkersLeft--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath,
|
||||
|
|
|
@ -96,7 +96,7 @@ int OutputFormatter::Write(const std::string& buf)
|
|||
return Write(buf.data(), buf.size());
|
||||
}
|
||||
|
||||
__declspec(thread) OutputFormatter* OutputFormatter::Instance;
|
||||
thread_local OutputFormatter* OutputFormatter::Instance;
|
||||
|
||||
int OutputFormatter::WriteStatic(const char* buf, int count)
|
||||
{
|
||||
|
|
|
@ -25,7 +25,7 @@ private:
|
|||
|
||||
void Flush();
|
||||
|
||||
static __declspec(thread) OutputFormatter* Instance;
|
||||
static thread_local OutputFormatter* Instance;
|
||||
static int WriteStatic(const char* buf, int count);
|
||||
|
||||
public:
|
||||
|
|
|
@ -15,6 +15,124 @@
|
|||
#include "WarningHandler.h"
|
||||
#include "gfxd.h"
|
||||
|
||||
|
||||
#define G_MDSFT_ALPHACOMPARE 0
|
||||
#define G_MDSFT_ZSRCSEL 2
|
||||
#define G_MDSFT_RENDERMODE 3
|
||||
#define G_MDSFT_BLENDER 16
|
||||
|
||||
#define G_RM_FOG_SHADE_A 0xC8000000
|
||||
#define G_RM_FOG_PRIM_A 0xC4000000
|
||||
#define G_RM_PASS 0x0C080000
|
||||
#define G_RM_AA_ZB_OPA_SURF 0x442078
|
||||
#define G_RM_AA_ZB_OPA_SURF2 0x112078
|
||||
#define G_RM_AA_ZB_XLU_SURF 0x4049D8
|
||||
#define G_RM_AA_ZB_XLU_SURF2 0x1049D8
|
||||
#define G_RM_AA_ZB_OPA_DECAL 0x442D58
|
||||
#define G_RM_AA_ZB_OPA_DECAL2 0x112D58
|
||||
#define G_RM_AA_ZB_XLU_DECAL 0x404DD8
|
||||
#define G_RM_AA_ZB_XLU_DECAL2 0x104DD8
|
||||
#define G_RM_AA_ZB_OPA_INTER 0x442478
|
||||
#define G_RM_AA_ZB_OPA_INTER2 0x112478
|
||||
#define G_RM_AA_ZB_XLU_INTER 0x4045D8
|
||||
#define G_RM_AA_ZB_XLU_INTER2 0x1045D8
|
||||
#define G_RM_AA_ZB_XLU_LINE 0x407858
|
||||
#define G_RM_AA_ZB_XLU_LINE2 0x107858
|
||||
#define G_RM_AA_ZB_DEC_LINE 0x407F58
|
||||
#define G_RM_AA_ZB_DEC_LINE2 0x107F58
|
||||
#define G_RM_AA_ZB_TEX_EDGE 0x443078
|
||||
#define G_RM_AA_ZB_TEX_EDGE2 0x113078
|
||||
#define G_RM_AA_ZB_TEX_INTER 0x443478
|
||||
#define G_RM_AA_ZB_TEX_INTER2 0x113478
|
||||
#define G_RM_AA_ZB_SUB_SURF 0x442878
|
||||
#define G_RM_AA_ZB_SUB_SURF2 0x112278
|
||||
#define G_RM_AA_ZB_PCL_SURF 0x40007B
|
||||
#define G_RM_AA_ZB_PCL_SURF2 0x10007B
|
||||
#define G_RM_AA_ZB_OPA_TERR 0x402078
|
||||
#define G_RM_AA_ZB_OPA_TERR2 0x102078
|
||||
#define G_RM_AA_ZB_TEX_TERR 0x403078
|
||||
#define G_RM_AA_ZB_TEX_TERR2 0x103078
|
||||
#define G_RM_AA_ZB_SUB_TERR 0x402278
|
||||
#define G_RM_AA_ZB_SUB_TERR2 0x102278
|
||||
#define G_RM_RA_ZB_OPA_SURF 0x442038
|
||||
#define G_RM_RA_ZB_OPA_SURF2 0x112038
|
||||
#define G_RM_RA_ZB_OPA_DECAL 0x442D18
|
||||
#define G_RM_RA_ZB_OPA_DECAL2 0x112D18
|
||||
#define G_RM_RA_ZB_OPA_INTER 0x442438
|
||||
#define G_RM_RA_ZB_OPA_INTER2 0x112438
|
||||
#define G_RM_AA_OPA_SURF 0x442048
|
||||
#define G_RM_AA_OPA_SURF2 0x112048
|
||||
#define G_RM_AA_XLU_SURF 0x4041C8
|
||||
#define G_RM_AA_XLU_SURF2 0x1041C8
|
||||
#define G_RM_AA_XLU_LINE 0x407048
|
||||
#define G_RM_AA_XLU_LINE2 0x107048
|
||||
#define G_RM_AA_DEC_LINE 0x407248
|
||||
#define G_RM_AA_DEC_LINE2 0x107248
|
||||
#define G_RM_AA_TEX_EDGE 0x443048
|
||||
#define G_RM_AA_TEX_EDGE2 0x113048
|
||||
#define G_RM_AA_SUB_SURF 0x442248
|
||||
#define G_RM_AA_SUB_SURF2 0x112248
|
||||
#define G_RM_AA_PCL_SURF 0x40004B
|
||||
#define G_RM_AA_PCL_SURF2 0x10004B
|
||||
#define G_RM_AA_OPA_TERR 0x402048
|
||||
#define G_RM_AA_OPA_TERR2 0x102048
|
||||
#define G_RM_AA_TEX_TERR 0x403048
|
||||
#define G_RM_AA_TEX_TERR2 0x103048
|
||||
#define G_RM_AA_SUB_TERR 0x402248
|
||||
#define G_RM_AA_SUB_TERR2 0x102248
|
||||
#define G_RM_RA_OPA_SURF 0x442008
|
||||
#define G_RM_RA_OPA_SURF2 0x112008
|
||||
#define G_RM_ZB_OPA_SURF 0x442230
|
||||
#define G_RM_ZB_OPA_SURF2 0x112230
|
||||
#define G_RM_ZB_XLU_SURF 0x404A50
|
||||
#define G_RM_ZB_XLU_SURF2 0x104A50
|
||||
#define G_RM_ZB_OPA_DECAL 0x442E10
|
||||
#define G_RM_ZB_OPA_DECAL2 0x112E10
|
||||
#define G_RM_ZB_XLU_DECAL 0x404E50
|
||||
#define G_RM_ZB_XLU_DECAL2 0x104E50
|
||||
#define G_RM_ZB_CLD_SURF 0x404B50
|
||||
#define G_RM_ZB_CLD_SURF2 0x104B50
|
||||
#define G_RM_ZB_OVL_SURF 0x404F50
|
||||
#define G_RM_ZB_OVL_SURF2 0x104F50
|
||||
#define G_RM_ZB_PCL_SURF 0x0C080233
|
||||
#define G_RM_ZB_PCL_SURF2 0x03020233
|
||||
#define G_RM_OPA_SURF 0x0C084000
|
||||
#define G_RM_OPA_SURF2 0x03024000
|
||||
#define G_RM_XLU_SURF 0x00404200
|
||||
#define G_RM_XLU_SURF2 0x00104240
|
||||
#define G_RM_CLD_SURF 0x00404340
|
||||
#define G_RM_CLD_SURF2 0x00104340
|
||||
#define G_RM_TEX_EDGE 0x0C087008
|
||||
#define G_RM_TEX_EDGE2 0x03027008
|
||||
#define G_RM_PCL_SURF 0x0C084203
|
||||
#define G_RM_PCL_SURF2 0x03024203
|
||||
#define G_RM_ADD 0x04484340
|
||||
#define G_RM_ADD2 0x01124340
|
||||
#define G_RM_NOOP 0x00000000
|
||||
#define G_RM_NOOP2 0x00000000
|
||||
#define G_RM_VISCVG 0x0C844040
|
||||
#define G_RM_VISCVG2 0x03214040
|
||||
#define G_RM_OPA_CI 0x0C080000
|
||||
#define G_RM_OPA_CI2 0x03020000
|
||||
|
||||
#define AA_EN 0x8
|
||||
#define Z_CMP 0x10
|
||||
#define Z_UPD 0x20
|
||||
#define IM_RD 0x40
|
||||
#define CLR_ON_CVG 0x80
|
||||
#define CVG_DST_CLAMP 0
|
||||
#define CVG_DST_WRAP 0x100
|
||||
#define CVG_DST_FULL 0x200
|
||||
#define CVG_DST_SAVE 0x300
|
||||
#define ZMODE_OPA 0
|
||||
#define ZMODE_INTER 0x400
|
||||
#define ZMODE_XLU 0x800
|
||||
#define ZMODE_DEC 0xc00
|
||||
#define CVG_X_ALPHA 0x1000
|
||||
#define ALPHA_CVG_SEL 0x2000
|
||||
#define FORCE_BL 0x4000
|
||||
#define TEX_EDGE 0x0000
|
||||
|
||||
REGISTER_ZFILENODE(DList, ZDisplayList);
|
||||
|
||||
ZDisplayList::ZDisplayList(ZFile* nParent) : ZResource(nParent)
|
||||
|
|
|
@ -166,122 +166,6 @@ enum class OoTSegments
|
|||
FrameBuffer = 16,
|
||||
};
|
||||
|
||||
#define G_MDSFT_ALPHACOMPARE 0
|
||||
#define G_MDSFT_ZSRCSEL 2
|
||||
#define G_MDSFT_RENDERMODE 3
|
||||
#define G_MDSFT_BLENDER 16
|
||||
|
||||
#define G_RM_FOG_SHADE_A 0xC8000000
|
||||
#define G_RM_FOG_PRIM_A 0xC4000000
|
||||
#define G_RM_PASS 0x0C080000
|
||||
#define G_RM_AA_ZB_OPA_SURF 0x442078
|
||||
#define G_RM_AA_ZB_OPA_SURF2 0x112078
|
||||
#define G_RM_AA_ZB_XLU_SURF 0x4049D8
|
||||
#define G_RM_AA_ZB_XLU_SURF2 0x1049D8
|
||||
#define G_RM_AA_ZB_OPA_DECAL 0x442D58
|
||||
#define G_RM_AA_ZB_OPA_DECAL2 0x112D58
|
||||
#define G_RM_AA_ZB_XLU_DECAL 0x404DD8
|
||||
#define G_RM_AA_ZB_XLU_DECAL2 0x104DD8
|
||||
#define G_RM_AA_ZB_OPA_INTER 0x442478
|
||||
#define G_RM_AA_ZB_OPA_INTER2 0x112478
|
||||
#define G_RM_AA_ZB_XLU_INTER 0x4045D8
|
||||
#define G_RM_AA_ZB_XLU_INTER2 0x1045D8
|
||||
#define G_RM_AA_ZB_XLU_LINE 0x407858
|
||||
#define G_RM_AA_ZB_XLU_LINE2 0x107858
|
||||
#define G_RM_AA_ZB_DEC_LINE 0x407F58
|
||||
#define G_RM_AA_ZB_DEC_LINE2 0x107F58
|
||||
#define G_RM_AA_ZB_TEX_EDGE 0x443078
|
||||
#define G_RM_AA_ZB_TEX_EDGE2 0x113078
|
||||
#define G_RM_AA_ZB_TEX_INTER 0x443478
|
||||
#define G_RM_AA_ZB_TEX_INTER2 0x113478
|
||||
#define G_RM_AA_ZB_SUB_SURF 0x442878
|
||||
#define G_RM_AA_ZB_SUB_SURF2 0x112278
|
||||
#define G_RM_AA_ZB_PCL_SURF 0x40007B
|
||||
#define G_RM_AA_ZB_PCL_SURF2 0x10007B
|
||||
#define G_RM_AA_ZB_OPA_TERR 0x402078
|
||||
#define G_RM_AA_ZB_OPA_TERR2 0x102078
|
||||
#define G_RM_AA_ZB_TEX_TERR 0x403078
|
||||
#define G_RM_AA_ZB_TEX_TERR2 0x103078
|
||||
#define G_RM_AA_ZB_SUB_TERR 0x402278
|
||||
#define G_RM_AA_ZB_SUB_TERR2 0x102278
|
||||
#define G_RM_RA_ZB_OPA_SURF 0x442038
|
||||
#define G_RM_RA_ZB_OPA_SURF2 0x112038
|
||||
#define G_RM_RA_ZB_OPA_DECAL 0x442D18
|
||||
#define G_RM_RA_ZB_OPA_DECAL2 0x112D18
|
||||
#define G_RM_RA_ZB_OPA_INTER 0x442438
|
||||
#define G_RM_RA_ZB_OPA_INTER2 0x112438
|
||||
#define G_RM_AA_OPA_SURF 0x442048
|
||||
#define G_RM_AA_OPA_SURF2 0x112048
|
||||
#define G_RM_AA_XLU_SURF 0x4041C8
|
||||
#define G_RM_AA_XLU_SURF2 0x1041C8
|
||||
#define G_RM_AA_XLU_LINE 0x407048
|
||||
#define G_RM_AA_XLU_LINE2 0x107048
|
||||
#define G_RM_AA_DEC_LINE 0x407248
|
||||
#define G_RM_AA_DEC_LINE2 0x107248
|
||||
#define G_RM_AA_TEX_EDGE 0x443048
|
||||
#define G_RM_AA_TEX_EDGE2 0x113048
|
||||
#define G_RM_AA_SUB_SURF 0x442248
|
||||
#define G_RM_AA_SUB_SURF2 0x112248
|
||||
#define G_RM_AA_PCL_SURF 0x40004B
|
||||
#define G_RM_AA_PCL_SURF2 0x10004B
|
||||
#define G_RM_AA_OPA_TERR 0x402048
|
||||
#define G_RM_AA_OPA_TERR2 0x102048
|
||||
#define G_RM_AA_TEX_TERR 0x403048
|
||||
#define G_RM_AA_TEX_TERR2 0x103048
|
||||
#define G_RM_AA_SUB_TERR 0x402248
|
||||
#define G_RM_AA_SUB_TERR2 0x102248
|
||||
#define G_RM_RA_OPA_SURF 0x442008
|
||||
#define G_RM_RA_OPA_SURF2 0x112008
|
||||
#define G_RM_ZB_OPA_SURF 0x442230
|
||||
#define G_RM_ZB_OPA_SURF2 0x112230
|
||||
#define G_RM_ZB_XLU_SURF 0x404A50
|
||||
#define G_RM_ZB_XLU_SURF2 0x104A50
|
||||
#define G_RM_ZB_OPA_DECAL 0x442E10
|
||||
#define G_RM_ZB_OPA_DECAL2 0x112E10
|
||||
#define G_RM_ZB_XLU_DECAL 0x404E50
|
||||
#define G_RM_ZB_XLU_DECAL2 0x104E50
|
||||
#define G_RM_ZB_CLD_SURF 0x404B50
|
||||
#define G_RM_ZB_CLD_SURF2 0x104B50
|
||||
#define G_RM_ZB_OVL_SURF 0x404F50
|
||||
#define G_RM_ZB_OVL_SURF2 0x104F50
|
||||
#define G_RM_ZB_PCL_SURF 0x0C080233
|
||||
#define G_RM_ZB_PCL_SURF2 0x03020233
|
||||
#define G_RM_OPA_SURF 0x0C084000
|
||||
#define G_RM_OPA_SURF2 0x03024000
|
||||
#define G_RM_XLU_SURF 0x00404200
|
||||
#define G_RM_XLU_SURF2 0x00104240
|
||||
#define G_RM_CLD_SURF 0x00404340
|
||||
#define G_RM_CLD_SURF2 0x00104340
|
||||
#define G_RM_TEX_EDGE 0x0C087008
|
||||
#define G_RM_TEX_EDGE2 0x03027008
|
||||
#define G_RM_PCL_SURF 0x0C084203
|
||||
#define G_RM_PCL_SURF2 0x03024203
|
||||
#define G_RM_ADD 0x04484340
|
||||
#define G_RM_ADD2 0x01124340
|
||||
#define G_RM_NOOP 0x00000000
|
||||
#define G_RM_NOOP2 0x00000000
|
||||
#define G_RM_VISCVG 0x0C844040
|
||||
#define G_RM_VISCVG2 0x03214040
|
||||
#define G_RM_OPA_CI 0x0C080000
|
||||
#define G_RM_OPA_CI2 0x03020000
|
||||
|
||||
#define AA_EN 0x8
|
||||
#define Z_CMP 0x10
|
||||
#define Z_UPD 0x20
|
||||
#define IM_RD 0x40
|
||||
#define CLR_ON_CVG 0x80
|
||||
#define CVG_DST_CLAMP 0
|
||||
#define CVG_DST_WRAP 0x100
|
||||
#define CVG_DST_FULL 0x200
|
||||
#define CVG_DST_SAVE 0x300
|
||||
#define ZMODE_OPA 0
|
||||
#define ZMODE_INTER 0x400
|
||||
#define ZMODE_XLU 0x800
|
||||
#define ZMODE_DEC 0xc00
|
||||
#define CVG_X_ALPHA 0x1000
|
||||
#define ALPHA_CVG_SEL 0x2000
|
||||
#define FORCE_BL 0x4000
|
||||
#define TEX_EDGE 0x0000
|
||||
|
||||
class ZDisplayList : public ZResource
|
||||
{
|
||||
|
|
|
@ -823,6 +823,32 @@ void ZFile::GenerateSourceHeaderFiles()
|
|||
|
||||
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
|
||||
File::WriteAllText(headerFilename, formatter.GetOutput());
|
||||
else if (Globals::Instance->sourceOutputPath != "")
|
||||
{
|
||||
std::string xmlPath = xmlFilePath.string();
|
||||
xmlPath = StringHelper::Replace(xmlPath, "\\", "/");
|
||||
auto pathList = StringHelper::Split(xmlPath, "/");
|
||||
std::string outPath = "";
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
outPath += pathList[i] + "/";
|
||||
|
||||
for (int i = 5; i < pathList.size(); i++)
|
||||
{
|
||||
if (i == pathList.size() - 1)
|
||||
{
|
||||
outPath += Path::GetFileNameWithoutExtension(pathList[i]) + "/";
|
||||
outPath += outName.string() + ".h";
|
||||
}
|
||||
else
|
||||
outPath += pathList[i];
|
||||
|
||||
if (i < pathList.size() - 1)
|
||||
outPath += "/";
|
||||
}
|
||||
|
||||
File::WriteAllText(outPath, formatter.GetOutput());
|
||||
}
|
||||
}
|
||||
|
||||
std::string ZFile::GetHeaderInclude() const
|
||||
|
|
|
@ -25,19 +25,19 @@ public:
|
|||
|
||||
ZLimbSkinType skinSegmentType = ZLimbSkinType::SkinType_0; // Skin only
|
||||
segptr_t skinSegment = 0; // Skin only
|
||||
Struct_800A5E28 segmentStruct; // Skin only
|
||||
Struct_800A5E28 segmentStruct = {0}; // Skin only
|
||||
|
||||
// Legacy only
|
||||
float legTransX, legTransY, legTransZ; // Vec3f
|
||||
uint16_t rotX, rotY, rotZ; // Vec3s
|
||||
segptr_t childPtr; // LegacyLimb*
|
||||
segptr_t siblingPtr; // LegacyLimb*
|
||||
float legTransX = 0, legTransY = 0, legTransZ = 0; // Vec3f
|
||||
uint16_t rotX = 0, rotY = 0, rotZ = 0; // Vec3s
|
||||
segptr_t childPtr = 0; // LegacyLimb*
|
||||
segptr_t siblingPtr = 0; // LegacyLimb*
|
||||
|
||||
segptr_t dListPtr = 0;
|
||||
segptr_t dList2Ptr = 0; // LOD and Curve Only
|
||||
|
||||
int16_t transX, transY, transZ;
|
||||
uint8_t childIndex, siblingIndex;
|
||||
int16_t transX = 0, transY = 0, transZ = 0;
|
||||
uint8_t childIndex = 0, siblingIndex = 0;
|
||||
|
||||
ZLimb(ZFile* nParent);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ REGISTER_ZFILENODE(Text, ZText);
|
|||
ZText::ZText(ZFile* nParent) : ZResource(nParent)
|
||||
{
|
||||
RegisterRequiredAttribute("CodeOffset");
|
||||
RegisterOptionalAttribute("LangOffset", "0");
|
||||
}
|
||||
|
||||
void ZText::ParseRawData()
|
||||
|
@ -20,6 +21,16 @@ void ZText::ParseRawData()
|
|||
|
||||
const auto& rawData = parent->GetRawData();
|
||||
uint32_t currentPtr = StringHelper::StrToL(registeredAttributes.at("CodeOffset").value, 16);
|
||||
uint32_t langPtr = currentPtr;
|
||||
bool isPalLang = false;
|
||||
|
||||
if (StringHelper::StrToL(registeredAttributes.at("LangOffset").value, 16) != 0)
|
||||
{
|
||||
langPtr = StringHelper::StrToL(registeredAttributes.at("LangOffset").value, 16);
|
||||
|
||||
if (langPtr != currentPtr)
|
||||
isPalLang = true;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> codeData;
|
||||
|
||||
|
@ -34,8 +45,18 @@ void ZText::ParseRawData()
|
|||
msgEntry.id = BitConverter::ToInt16BE(codeData, currentPtr + 0);
|
||||
msgEntry.textboxType = (codeData[currentPtr + 2] & 0xF0) >> 4;
|
||||
msgEntry.textboxYPos = (codeData[currentPtr + 2] & 0x0F);
|
||||
msgEntry.segmentId = (codeData[currentPtr + 4]);
|
||||
msgEntry.msgOffset = BitConverter::ToInt32BE(codeData, currentPtr + 4) & 0x00FFFFFF;
|
||||
|
||||
if (isPalLang)
|
||||
{
|
||||
msgEntry.segmentId = (codeData[langPtr + 0]);
|
||||
msgEntry.msgOffset = BitConverter::ToInt32BE(codeData, langPtr + 0) & 0x00FFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
msgEntry.segmentId = (codeData[langPtr + 4]);
|
||||
msgEntry.msgOffset = BitConverter::ToInt32BE(codeData, langPtr + 4) & 0x00FFFFFF;
|
||||
}
|
||||
|
||||
uint32_t msgPtr = msgEntry.msgOffset;
|
||||
|
||||
unsigned char c = rawData[msgPtr];
|
||||
|
@ -82,6 +103,11 @@ void ZText::ParseRawData()
|
|||
break;
|
||||
|
||||
currentPtr += 8;
|
||||
|
||||
if (isPalLang)
|
||||
langPtr += 4;
|
||||
else
|
||||
langPtr += 8;
|
||||
}
|
||||
|
||||
int bp2 = 0;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
class BitConverter
|
||||
{
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
for (auto& p : fs::recursive_directory_iterator(dir))
|
||||
{
|
||||
if (!p.is_directory())
|
||||
lst.push_back(p.path().string());
|
||||
lst.push_back(p.path().generic_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
#pragma optimize("2", on)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#define vsprintf_s vsprintf
|
||||
#endif
|
||||
|
||||
std::vector<std::string> StringHelper::Split(std::string s, const std::string& delimiter)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
@ -44,7 +48,7 @@ std::string StringHelper::Replace(std::string str, const std::string& from,
|
|||
|
||||
while (start_pos != std::string::npos)
|
||||
{
|
||||
str.replace(start_pos, from.length(), to);
|
||||
str.replace(start_pos, from.length(), to);
|
||||
start_pos = str.find(from);
|
||||
}
|
||||
|
||||
|
|
4
libultraship/.gitignore
vendored
4
libultraship/.gitignore
vendored
|
@ -353,4 +353,6 @@ MigrationBackup/
|
|||
.ionide/
|
||||
|
||||
!libultraship/Lib/**
|
||||
libultraship/DebugObj/*
|
||||
libultraship/DebugObj/*
|
||||
build/
|
||||
libultraship.a
|
|
@ -1,15 +1,78 @@
|
|||
# Only used for standalone compilation, usually inherits these from the main makefile
|
||||
CXXFLAGS ?= -Wall -Wextra -O2 -g -std=c++17
|
||||
|
||||
CXX := g++
|
||||
CC := gcc
|
||||
AR := ar
|
||||
FORMAT := clang-format-11
|
||||
|
||||
ASAN ?= 0
|
||||
DEBUG ?= 1
|
||||
OPTFLAGS ?= -O0
|
||||
LTO ?= 0
|
||||
|
||||
WARN := -Wall -Wextra -Werror \
|
||||
-Wno-unused-variable \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-unused-function \
|
||||
-Wno-parentheses \
|
||||
-Wno-narrowing \
|
||||
-Wno-missing-field-initializers
|
||||
|
||||
CXXFLAGS := $(WARN) -std=c++20 -D_GNU_SOURCE -DENABLE_OPENGL -DSPDLOG_ACTIVE_LEVEL=0 -m32
|
||||
CFLAGS := $(WARN) -std=c99 -D_GNU_SOURCE -DENABLE_OPENGL -DSPDLOG_ACTIVE_LEVEL=0 -m32
|
||||
CPPFLAGS := -MMD
|
||||
|
||||
ifneq ($(DEBUG),0)
|
||||
CXXFLAGS += -g -D_DEBUG
|
||||
CFLAGS += -g -D_DEBUG
|
||||
endif
|
||||
|
||||
ifneq ($(ASAN),0)
|
||||
CXXFLAGS += -fsanitize=address
|
||||
CFLAGS += -fsanitize=address
|
||||
endif
|
||||
|
||||
ifneq ($(LTO),0)
|
||||
CXXFLAGS += -flto
|
||||
CFLAGS += -flto
|
||||
endif
|
||||
|
||||
SRC_DIRS := $(shell find -type d -not -path "*build*")
|
||||
CPP_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp))
|
||||
H_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.h))
|
||||
|
||||
O_FILES := $(foreach f,$(CPP_FILES:.cpp=.o),build/$f)
|
||||
LIB := otrlib.a
|
||||
CXX_FILES := \
|
||||
$(shell find libultraship/Factories -name *.cpp) \
|
||||
$(shell find libultraship/Lib/Fast3D -name *.cpp) \
|
||||
$(shell find libultraship -maxdepth 1 -name *.cpp) \
|
||||
$(shell find libultraship/Lib/ImGui -maxdepth 1 -name *.cpp) \
|
||||
libultraship/Lib/ImGui/backends/imgui_impl_opengl3.cpp \
|
||||
libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp \
|
||||
libultraship/Lib/StrHash64.cpp \
|
||||
libultraship/Lib/tinyxml2/tinyxml2.cpp
|
||||
|
||||
C_FILES := \
|
||||
libultraship/mixer.c \
|
||||
libultraship/Lib/stb/stb_impl.c
|
||||
|
||||
FMT_FILES := $(shell find libultraship/ -type f \( -name *.cpp -o -name *.h \) -a -not -path "libultraship/Lib/*")
|
||||
|
||||
O_FILES := \
|
||||
$(CXX_FILES:%.cpp=build/%.o) \
|
||||
$(C_FILES:%.c=build/%.o)
|
||||
|
||||
D_FILES := $(O_FILES:%.o=%.d)
|
||||
|
||||
LIB := libultraship.a
|
||||
|
||||
INC_DIRS := $(addprefix -I, \
|
||||
../ZAPDTR/ZAPDUtils \
|
||||
libultraship/Lib/Fast3D/U64 \
|
||||
libultraship/Lib/spdlog \
|
||||
libultraship/Lib/spdlog/include \
|
||||
libultraship \
|
||||
)
|
||||
|
||||
# create build directories
|
||||
$(shell mkdir -p $(foreach dir,$(SRC_DIRS),build/$(dir)))
|
||||
$(shell mkdir -p $(SRC_DIRS:%=build/%))
|
||||
|
||||
all: $(LIB)
|
||||
|
||||
|
@ -17,12 +80,17 @@ clean:
|
|||
rm -rf build $(LIB)
|
||||
|
||||
format:
|
||||
clang-format-11 -i $(CPP_FILES) $(H_FILES)
|
||||
$(FORMAT) -i $(FMT_FILES)
|
||||
|
||||
.PHONY: all clean format
|
||||
|
||||
build/%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) $(OPTFLAGS) -I ./ -I ../ZAPD/ZAPD -I ../ZAPD/ZAPDUtils -I ../../ZAPD/lib/tinyxml2 -I otrlib/Lib/spdlog/include -c $(OUTPUT_OPTION) $<
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPTFLAGS) $(INC_DIRS) -c $< -o $@
|
||||
|
||||
build/%.o: %.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(OPTFLAGS) $(INC_DIRS) -c $< -o $@
|
||||
|
||||
$(LIB): $(O_FILES)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
-include $(D_FILES)
|
|
@ -21,7 +21,7 @@ void Ship::AnimationV0::ParseFileBinary(BinaryReader* reader, Resource* res)
|
|||
|
||||
uint32_t rotIndCnt = reader->ReadUInt32();
|
||||
anim->rotationIndices.reserve(rotIndCnt);
|
||||
for (int i = 0; i < rotIndCnt; i++)
|
||||
for (size_t i = 0; i < rotIndCnt; i++)
|
||||
{
|
||||
uint16_t x = reader->ReadUInt16();
|
||||
uint16_t y = reader->ReadUInt16();
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <filesystem>
|
||||
|
||||
namespace Ship {
|
||||
Archive::Archive(const std::string& MainPath, bool enableWriting) : Archive(MainPath, "", enableWriting)
|
||||
Archive::Archive(const std::string& MainPath, bool enableWriting) : Archive(MainPath, "", enableWriting)
|
||||
{
|
||||
mainMPQ = nullptr;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ namespace Ship {
|
|||
|
||||
std::shared_ptr<Archive> Archive::CreateArchive(const std::string& archivePath, int fileCapacity)
|
||||
{
|
||||
Archive* archive = new Archive(archivePath, true);
|
||||
auto archive = std::make_shared<Archive>(archivePath, true);
|
||||
|
||||
TCHAR* t_filename = new TCHAR[archivePath.size() + 1];
|
||||
t_filename[archivePath.size()] = 0;
|
||||
|
@ -37,10 +37,15 @@ namespace Ship {
|
|||
bool success = SFileCreateArchive(t_filename, MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES | MPQ_CREATE_ARCHIVE_V2, fileCapacity, &archive->mainMPQ);
|
||||
int error = GetLastError();
|
||||
|
||||
if (success) {
|
||||
delete[] t_filename;
|
||||
|
||||
if (success)
|
||||
{
|
||||
archive->mpqHandles[archivePath] = archive->mainMPQ;
|
||||
return std::make_shared<Archive>(*archive);
|
||||
} else {
|
||||
return archive;
|
||||
}
|
||||
else
|
||||
{
|
||||
SPDLOG_ERROR("({}) We tried to create an archive, but it has fallen and cannot get up.");
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -49,11 +54,16 @@ namespace Ship {
|
|||
std::shared_ptr<File> Archive::LoadFile(const std::string& filePath, bool includeParent, std::shared_ptr<File> FileToLoad) {
|
||||
HANDLE fileHandle = NULL;
|
||||
|
||||
if (FileToLoad == nullptr) {
|
||||
FileToLoad = std::make_shared<File>();
|
||||
FileToLoad->path = filePath;
|
||||
}
|
||||
|
||||
if (!SFileOpenFileEx(mainMPQ, filePath.c_str(), 0, &fileHandle)) {
|
||||
SPDLOG_ERROR("({}) Failed to open file {} from mpq archive {}", GetLastError(), filePath.c_str(), MainPath.c_str());
|
||||
std::unique_lock<std::mutex> Lock(FileToLoad->FileLoadMutex);
|
||||
FileToLoad->bHasLoadError = true;
|
||||
return nullptr;
|
||||
return FileToLoad;
|
||||
}
|
||||
|
||||
DWORD dwFileSize = SFileGetFileSize(fileHandle, 0);
|
||||
|
@ -67,18 +77,13 @@ namespace Ship {
|
|||
}
|
||||
std::unique_lock<std::mutex> Lock(FileToLoad->FileLoadMutex);
|
||||
FileToLoad->bHasLoadError = true;
|
||||
return nullptr;
|
||||
return FileToLoad;
|
||||
}
|
||||
|
||||
if (!SFileCloseFile(fileHandle)) {
|
||||
SPDLOG_ERROR("({}) Failed to close file {} from mpq archive {}", GetLastError(), filePath.c_str(), MainPath.c_str());
|
||||
}
|
||||
|
||||
if (FileToLoad == nullptr) {
|
||||
FileToLoad = std::make_shared<File>();
|
||||
FileToLoad->path = filePath;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> Lock(FileToLoad->FileLoadMutex);
|
||||
FileToLoad->parent = includeParent ? shared_from_this() : nullptr;
|
||||
FileToLoad->buffer = fileData;
|
||||
|
@ -92,6 +97,11 @@ namespace Ship {
|
|||
HANDLE fileHandle = NULL;
|
||||
HANDLE mpqHandle = NULL;
|
||||
|
||||
if (FileToLoad == nullptr) {
|
||||
FileToLoad = std::make_shared<File>();
|
||||
FileToLoad->path = filePath;
|
||||
}
|
||||
|
||||
for(auto [path, handle] : mpqHandles) {
|
||||
if (SFileOpenFileEx(mpqHandle, filePath.c_str(), 0, &fileHandle)) {
|
||||
std::unique_lock Lock(FileToLoad->FileLoadMutex);
|
||||
|
@ -116,18 +126,13 @@ namespace Ship {
|
|||
}
|
||||
std::unique_lock<std::mutex> Lock(FileToLoad->FileLoadMutex);
|
||||
FileToLoad->bHasLoadError = true;
|
||||
return nullptr;
|
||||
return FileToLoad;
|
||||
}
|
||||
|
||||
if (!SFileCloseFile(fileHandle)) {
|
||||
SPDLOG_ERROR("({}) Failed to close file {} from mpq archive {}", GetLastError(), filePath.c_str(), MainPath.c_str());
|
||||
}
|
||||
|
||||
if (FileToLoad == nullptr) {
|
||||
FileToLoad = std::make_shared<File>();
|
||||
FileToLoad->path = filePath;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> Lock(FileToLoad->FileLoadMutex);
|
||||
FileToLoad->parent = includeParent ? shared_from_this() : nullptr;
|
||||
FileToLoad->buffer = fileData;
|
||||
|
@ -139,13 +144,16 @@ namespace Ship {
|
|||
|
||||
bool Archive::AddFile(const std::string& path, uintptr_t fileData, DWORD dwFileSize) {
|
||||
HANDLE hFile;
|
||||
|
||||
#ifdef _WIN32
|
||||
SYSTEMTIME sysTime;
|
||||
GetSystemTime(&sysTime);
|
||||
FILETIME t;
|
||||
SystemTimeToFileTime(&sysTime, &t);
|
||||
ULONGLONG stupidHack = static_cast<uint64_t>(t.dwHighDateTime) << (sizeof(t.dwHighDateTime) * 8) | t.dwLowDateTime;
|
||||
|
||||
#else
|
||||
time_t stupidHack;
|
||||
time(&stupidHack);
|
||||
#endif
|
||||
if (!SFileCreateFile(mainMPQ, path.c_str(), stupidHack, dwFileSize, 0, MPQ_FILE_COMPRESS, &hFile)) {
|
||||
SPDLOG_ERROR("({}) Failed to create file of {} bytes {} in archive {}", GetLastError(), dwFileSize, path.c_str(), MainPath.c_str());
|
||||
return false;
|
||||
|
@ -181,7 +189,7 @@ namespace Ship {
|
|||
SPDLOG_ERROR("({}) Failed to remove file {} in archive {}", GetLastError(), path.c_str(), MainPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -196,12 +204,12 @@ namespace Ship {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::vector<SFILE_FIND_DATA> Archive::ListFiles(const std::string& searchMask) {
|
||||
std::vector<SFILE_FIND_DATA> Archive::ListFiles(const std::string& searchMask) const {
|
||||
auto fileList = std::vector<SFILE_FIND_DATA>();
|
||||
SFILE_FIND_DATA findContext;
|
||||
HANDLE hFind;
|
||||
|
||||
|
||||
|
||||
hFind = SFileFindFirstFile(mainMPQ, searchMask.c_str(), &findContext, nullptr);
|
||||
//if (hFind && GetLastError() != ERROR_NO_MORE_FILES) {
|
||||
if (hFind != nullptr) {
|
||||
|
@ -240,12 +248,12 @@ namespace Ship {
|
|||
return fileList;
|
||||
}
|
||||
|
||||
bool Archive::HasFile(const std::string& filename) {
|
||||
bool Archive::HasFile(const std::string& filename) const {
|
||||
bool result = false;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
auto lst = ListFiles(filename);
|
||||
|
||||
|
||||
for (const auto& item : lst) {
|
||||
if (item.cFileName == filename) {
|
||||
result = true;
|
||||
|
@ -259,15 +267,16 @@ namespace Ship {
|
|||
return result;
|
||||
}
|
||||
|
||||
std::string Archive::HashToString(uint64_t hash) {
|
||||
return hashes[hash];
|
||||
const std::string* Archive::HashToString(uint64_t hash) const {
|
||||
auto it = hashes.find(hash);
|
||||
return it != hashes.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
bool Archive::Load(bool enableWriting, bool genCRCMap) {
|
||||
return LoadMainMPQ(enableWriting, genCRCMap) && LoadPatchMPQs();
|
||||
}
|
||||
|
||||
bool Archive::Unload()
|
||||
bool Archive::Unload()
|
||||
{
|
||||
bool success = true;
|
||||
for (const auto& mpqHandle : mpqHandles) {
|
||||
|
@ -302,11 +311,16 @@ namespace Ship {
|
|||
|
||||
bool Archive::LoadMainMPQ(bool enableWriting, bool genCRCMap) {
|
||||
HANDLE mpqHandle = NULL;
|
||||
#ifdef _WIN32
|
||||
std::wstring wfullPath = std::filesystem::absolute(MainPath).wstring();
|
||||
#endif
|
||||
std::string fullPath = std::filesystem::absolute(MainPath).string();
|
||||
|
||||
std::wstring wFileName = std::filesystem::absolute(MainPath).wstring();
|
||||
|
||||
if (!SFileOpenArchive(wFileName.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle)) {
|
||||
#ifdef _WIN32
|
||||
if (!SFileOpenArchive(wfullPath.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle)) {
|
||||
#else
|
||||
if (!SFileOpenArchive(fullPath.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle)) {
|
||||
#endif
|
||||
SPDLOG_ERROR("({}) Failed to open main mpq file {}.", GetLastError(), fullPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
@ -340,12 +354,19 @@ namespace Ship {
|
|||
|
||||
std::wstring wPath = std::filesystem::absolute(path).wstring();
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!SFileOpenArchive(wPath.c_str(), 0, MPQ_OPEN_READ_ONLY, &patchHandle)) {
|
||||
#else
|
||||
if (!SFileOpenArchive(fullPath.c_str(), 0, MPQ_OPEN_READ_ONLY, &patchHandle)) {
|
||||
#endif
|
||||
SPDLOG_ERROR("({}) Failed to open patch mpq file {} while applying to {}.", GetLastError(), path.c_str(), MainPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!SFileOpenPatchArchive(mainMPQ, wPath.c_str(), "", 0)) {
|
||||
#else
|
||||
if (!SFileOpenPatchArchive(mainMPQ, fullPath.c_str(), "", 0)) {
|
||||
#endif
|
||||
SPDLOG_ERROR("({}) Failed to apply patch mpq file {} to main mpq {}.", GetLastError(), path.c_str(), MainPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -34,9 +34,9 @@ namespace Ship
|
|||
bool AddFile(const std::string& path, uintptr_t fileData, DWORD dwFileSize);
|
||||
bool RemoveFile(const std::string& path);
|
||||
bool RenameFile(const std::string& oldPath, const std::string& newPath);
|
||||
std::vector<SFILE_FIND_DATA> ListFiles(const std::string& searchMask);
|
||||
bool HasFile(const std::string& searchMask);
|
||||
std::string HashToString(uint64_t hash);
|
||||
std::vector<SFILE_FIND_DATA> ListFiles(const std::string& searchMask) const;
|
||||
bool HasFile(const std::string& searchMask) const;
|
||||
const std::string* HashToString(uint64_t hash) const;
|
||||
protected:
|
||||
bool Load(bool enableWriting, bool genCRCMap);
|
||||
bool Unload();
|
||||
|
|
|
@ -51,6 +51,8 @@ namespace Ship
|
|||
data.u16 = reader->ReadUInt16();
|
||||
break;
|
||||
// OTRTODO: IMPLEMENT OTHER TYPES!
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
arr->scalars.push_back(data);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "spdlog/spdlog.h"
|
||||
#include "GlobalCtx2.h"
|
||||
#include "Window.h"
|
||||
#include "GameSettings.h"
|
||||
|
||||
namespace Ship {
|
||||
ConfigFile::ConfigFile(std::shared_ptr<GlobalCtx2> Context, const std::string& Path) : Context(Context), Path(Path), File(Path.c_str()) {
|
||||
|
@ -71,7 +72,7 @@ namespace Ship {
|
|||
(*this)["WINDOW"]["FULLSCREEN WIDTH"] = std::to_string(1920);
|
||||
(*this)["WINDOW"]["FULLSCREEN HEIGHT"] = std::to_string(1080);
|
||||
(*this)["WINDOW"]["FULLSCREEN"] = std::to_string(false);
|
||||
(*this)["WINDOW"]["GFX BACKEND"] = "sdl";
|
||||
(*this)["WINDOW"]["GFX BACKEND"] = "";
|
||||
|
||||
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CRIGHT)] = std::to_string(0x14D);
|
||||
(*this)["KEYBOARD CONTROLLER BINDING 1"][STR(BTN_CLEFT)] = std::to_string(0x14B);
|
||||
|
@ -149,6 +150,8 @@ namespace Ship {
|
|||
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_STICKDOWN)] = std::to_string(0x01F);
|
||||
(*this)["KEYBOARD CONTROLLER BINDING 4"][STR(BTN_STICKUP)] = std::to_string(0x011);
|
||||
|
||||
(*this)["ENHANCEMENT SETTINGS"]["TEXT_SPEED"] = "1";
|
||||
|
||||
(*this)["SDL CONTROLLER 1"]["GUID"] = "";
|
||||
(*this)["SDL CONTROLLER 2"]["GUID"] = "";
|
||||
(*this)["SDL CONTROLLER 3"]["GUID"] = "";
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef CONFIG_FILE_H
|
||||
#define CONFIG_FILE_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
@ -29,9 +32,11 @@ namespace Ship {
|
|||
bool CreateDefaultConfig();
|
||||
|
||||
private:
|
||||
mINI::INIFile File;
|
||||
mINI::INIStructure Val;
|
||||
std::weak_ptr<GlobalCtx2> Context;
|
||||
std::string Path;
|
||||
mINI::INIFile File;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <memory>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include "stdint.h"
|
||||
#include "UltraController.h"
|
||||
#include "ControllerAttachment.h"
|
||||
|
@ -19,12 +20,17 @@ namespace Ship {
|
|||
void Read(OSContPad* pad);
|
||||
virtual void ReadFromSource() = 0;
|
||||
virtual void WriteToSource(ControllerCallback* controller) = 0;
|
||||
virtual bool Connected() const = 0;
|
||||
virtual bool CanRumble() const = 0;
|
||||
bool isRumbling;
|
||||
|
||||
void SetButtonMapping(const std::string& szButtonName, int32_t dwScancode);
|
||||
std::shared_ptr<ControllerAttachment> GetAttachment() { return Attachment; }
|
||||
int32_t GetControllerNumber() { return dwControllerNumber; }
|
||||
|
||||
virtual bool HasPadConf() const = 0;
|
||||
virtual std::optional<std::string> GetPadConfSection() = 0;
|
||||
|
||||
protected:
|
||||
int32_t dwPressedButtons;
|
||||
std::map<int32_t, int32_t> ButtonMapping;
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
#include "cvar.h"
|
||||
#include "Cvar.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <PR/ultra64/gbi.h>
|
||||
|
||||
std::map<std::string, CVar*> cvars;
|
||||
std::map<std::string, std::unique_ptr<CVar>, std::less<>> cvars;
|
||||
|
||||
CVar* CVar_GetVar(char* name) {
|
||||
std::string key(name);
|
||||
return cvars.contains(key) ? cvars[key] : nullptr;
|
||||
extern "C" CVar* CVar_Get(const char* name) {
|
||||
auto it = cvars.find(name);
|
||||
return (it != cvars.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
extern "C" CVar* CVar_Get(char* name) {
|
||||
return CVar_GetVar(name);
|
||||
}
|
||||
|
||||
extern "C" s32 CVar_GetS32(char* name, s32 defaultValue) {
|
||||
extern "C" s32 CVar_GetS32(const char* name, s32 defaultValue) {
|
||||
CVar* cvar = CVar_Get(name);
|
||||
|
||||
if (cvar != nullptr) {
|
||||
if (cvar) {
|
||||
if (cvar->type == CVAR_TYPE_S32)
|
||||
return cvar->value.valueS32;
|
||||
}
|
||||
|
@ -25,10 +24,10 @@ extern "C" s32 CVar_GetS32(char* name, s32 defaultValue) {
|
|||
return defaultValue;
|
||||
}
|
||||
|
||||
extern "C" float CVar_GetFloat(char* name, float defaultValue) {
|
||||
extern "C" float CVar_GetFloat(const char* name, float defaultValue) {
|
||||
CVar* cvar = CVar_Get(name);
|
||||
|
||||
if (cvar != nullptr) {
|
||||
if (cvar) {
|
||||
if (cvar->type == CVAR_TYPE_FLOAT)
|
||||
return cvar->value.valueFloat;
|
||||
}
|
||||
|
@ -36,10 +35,10 @@ extern "C" float CVar_GetFloat(char* name, float defaultValue) {
|
|||
return defaultValue;
|
||||
}
|
||||
|
||||
extern "C" char* CVar_GetString(char* name, char* defaultValue) {
|
||||
extern "C" const char* CVar_GetString(const char* name, const char* defaultValue) {
|
||||
CVar* cvar = CVar_Get(name);
|
||||
|
||||
if (cvar != nullptr) {
|
||||
if (cvar) {
|
||||
if (cvar->type == CVAR_TYPE_STRING)
|
||||
return cvar->value.valueStr;
|
||||
}
|
||||
|
@ -47,54 +46,44 @@ extern "C" char* CVar_GetString(char* name, char* defaultValue) {
|
|||
return defaultValue;
|
||||
}
|
||||
|
||||
extern "C" void CVar_SetS32(char* name, s32 value) {
|
||||
CVar* cvar = CVar_Get(name);
|
||||
extern "C" void CVar_SetS32(const char* name, s32 value) {
|
||||
auto& cvar = cvars[name];
|
||||
if (!cvar) {
|
||||
cvar = new CVar;
|
||||
cvars[std::string(name)] = cvar;
|
||||
cvar = std::make_unique<CVar>();
|
||||
}
|
||||
cvar->type = CVAR_TYPE_S32;
|
||||
cvar->value.valueS32 = value;
|
||||
}
|
||||
|
||||
void CVar_SetFloat(char* name, float value) {
|
||||
CVar* cvar = CVar_Get(name);
|
||||
void CVar_SetFloat(const char* name, float value) {
|
||||
auto& cvar = cvars[name];
|
||||
if (!cvar) {
|
||||
cvar = new CVar;
|
||||
cvars[std::string(name)] = cvar;
|
||||
cvar = std::make_unique<CVar>();
|
||||
}
|
||||
cvar->type = CVAR_TYPE_FLOAT;
|
||||
cvar->value.valueFloat = value;
|
||||
}
|
||||
|
||||
void CVar_SetString(char* name, char* value) {
|
||||
CVar* cvar = CVar_Get(name);
|
||||
void CVar_SetString(const char* name, const char* value) {
|
||||
auto& cvar = cvars[name];
|
||||
if (!cvar) {
|
||||
cvar = new CVar;
|
||||
cvars[std::string(name)] = cvar;
|
||||
cvar = std::make_unique<CVar>();
|
||||
}
|
||||
cvar->type = CVAR_TYPE_STRING;
|
||||
cvar->value.valueStr = value;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void CVar_RegisterS32(char* name, s32 defaultValue) {
|
||||
CVar* cvar = CVar_Get(name);
|
||||
|
||||
if (cvar == nullptr)
|
||||
extern "C" void CVar_RegisterS32(const char* name, s32 defaultValue) {
|
||||
if (!CVar_Get(name))
|
||||
CVar_SetS32(name, defaultValue);
|
||||
}
|
||||
|
||||
extern "C" void CVar_RegisterFloat(char* name, float defaultValue) {
|
||||
CVar* cvar = CVar_Get(name);
|
||||
|
||||
if (cvar == nullptr)
|
||||
extern "C" void CVar_RegisterFloat(const char* name, float defaultValue) {
|
||||
if (!CVar_Get(name))
|
||||
CVar_SetFloat(name, defaultValue);
|
||||
}
|
||||
|
||||
extern "C" void CVar_RegisterString(char* name, char* defaultValue) {
|
||||
CVar* cvar = CVar_Get(name);
|
||||
|
||||
if (cvar == nullptr)
|
||||
extern "C" void CVar_RegisterString(const char* name, const char* defaultValue) {
|
||||
if (!CVar_Get(name))
|
||||
CVar_SetString(name, defaultValue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
typedef enum CVarType { CVAR_TYPE_S32, CVAR_TYPE_FLOAT, CVAR_TYPE_STRING } CVarType;
|
||||
|
||||
typedef struct CVar {
|
||||
char* name;
|
||||
const char* name;
|
||||
CVarType type;
|
||||
|
||||
union {
|
||||
s32 valueS32;
|
||||
float valueFloat;
|
||||
char* valueStr;
|
||||
const char* valueStr;
|
||||
} value;
|
||||
} CVar;
|
||||
|
||||
|
@ -22,16 +22,15 @@ extern "C"
|
|||
#endif
|
||||
//#include <ultra64.h>
|
||||
|
||||
CVar* CVar_Get(const char* name);
|
||||
s32 CVar_GetS32(const char* name, s32 defaultValue);
|
||||
float CVar_GetFloat(const char* name, float defaultValue);
|
||||
const char* CVar_GetString(const char* name, const char* defaultValue);
|
||||
void CVar_SetS32(const char* name, s32 value);
|
||||
|
||||
CVar* CVar_Get(char* name);
|
||||
s32 CVar_GetS32(char* name, s32 defaultValue);
|
||||
float CVar_GetFloat(char* name, float defaultValue);
|
||||
char* CVar_GetString(char* name, char* defaultValue);
|
||||
void CVar_SetS32(char* name, s32 value);
|
||||
|
||||
void CVar_RegisterS32(char* name, s32 defaultValue);
|
||||
void CVar_RegisterFloat(char* name, float defaultValue);
|
||||
void CVar_RegisterString(char* name, char* defaultValue);
|
||||
void CVar_RegisterS32(const char* name, s32 defaultValue);
|
||||
void CVar_RegisterFloat(const char* name, float defaultValue);
|
||||
void CVar_RegisterString(const char* name, const char* defaultValue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
|
@ -40,10 +39,11 @@ void CVar_RegisterString(char* name, char* defaultValue);
|
|||
#ifdef __cplusplus
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
extern std::map<std::string, CVar*> cvars;
|
||||
CVar* CVar_GetVar(char* name);
|
||||
void CVar_SetFloat(char* name, float value);
|
||||
void CVar_SetString(char* name, char* value);
|
||||
extern std::map<std::string, std::unique_ptr<CVar>, std::less<>> cvars;
|
||||
void CVar_SetFloat(const char* name, float value);
|
||||
void CVar_SetString(const char* name, const char* value);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
|
@ -1,71 +0,0 @@
|
|||
#include "OTRResourceLoader.h"
|
||||
#include "OTRMaterialFactory.h"
|
||||
#include "OTRSceneFactory.h"
|
||||
#include "OTRCollisionHeaderFactory.h"
|
||||
#include "OTRDisplayListFactory.h"
|
||||
#include "OTRPlayerAnimationFactory.h"
|
||||
#include "OTRSkeletonFactory.h"
|
||||
#include "OTRSkeletonLimbFactory.h"
|
||||
#include "OTRAnimationFactory.h"
|
||||
#include "OTRVtxFactory.h"
|
||||
#include "OTRCutsceneFactory.h"
|
||||
#include "OTRArrayFactory.h"
|
||||
#include "OTRPathFactory.h"
|
||||
|
||||
namespace OtrLib
|
||||
{
|
||||
OTRResource* OTRResourceLoader::LoadResource(BinaryReader* reader)
|
||||
{
|
||||
Endianess endianess = (Endianess)reader->ReadByte();
|
||||
|
||||
// TODO: Setup the binaryreader to use the resource's endianess
|
||||
|
||||
ResourceType resourceType = (ResourceType)reader->ReadUInt32();
|
||||
OTRResource* result = nullptr;
|
||||
|
||||
switch (resourceType)
|
||||
{
|
||||
case ResourceType::OTRMaterial:
|
||||
result = OTRMaterialFactory::ReadMaterial(reader);
|
||||
break;
|
||||
case ResourceType::OTRRoom:
|
||||
result = OTRSceneFactory::ReadScene(reader);
|
||||
break;
|
||||
case ResourceType::OTRCollisionHeader:
|
||||
result = OTRCollisionHeaderFactory::ReadCollisionHeader(reader);
|
||||
break;
|
||||
case ResourceType::OTRDisplayList:
|
||||
result = OTRDisplayListFactory::ReadDisplayList(reader);
|
||||
break;
|
||||
case ResourceType::OTRPlayerAnimation:
|
||||
result = OTRPlayerAnimationFactory::ReadPlayerAnimation(reader);
|
||||
break;
|
||||
case ResourceType::OTRSkeleton:
|
||||
result = OTRSkeletonFactory::ReadSkeleton(reader);
|
||||
break;
|
||||
case ResourceType::OTRSkeletonLimb:
|
||||
result = OTRSkeletonLimbFactory::ReadSkeletonLimb(reader);
|
||||
break;
|
||||
case ResourceType::OTRVtx:
|
||||
result = OTRVtxFactory::ReadVtx(reader);
|
||||
break;
|
||||
case ResourceType::OTRAnimation:
|
||||
result = OTRAnimationFactory::ReadAnimation(reader);
|
||||
break;
|
||||
case ResourceType::OTRCutscene:
|
||||
result = OTRCutsceneFactory::ReadCutscene(reader);
|
||||
break;
|
||||
case ResourceType::OTRArray:
|
||||
result = OTRArrayFactory::ReadArray(reader);
|
||||
break;
|
||||
case ResourceType::OTRPath:
|
||||
result = OTRPathFactory::ReadPath(reader);
|
||||
break;
|
||||
default:
|
||||
// RESOURCE TYPE NOT SUPPORTED
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
225
libultraship/libultraship/GameOverlay.cpp
Normal file
225
libultraship/libultraship/GameOverlay.cpp
Normal file
|
@ -0,0 +1,225 @@
|
|||
#include "GameOverlay.h"
|
||||
|
||||
#include "Cvar.h"
|
||||
#include "File.h"
|
||||
#include "Archive.h"
|
||||
#include "ResourceMgr.h"
|
||||
#include "SohConsole.h"
|
||||
#include "SohImGuiImpl.h"
|
||||
#include "TextureMod.h"
|
||||
#include "Lib/ImGui/imgui_internal.h"
|
||||
#include "Utils/StringHelper.h"
|
||||
|
||||
void Ship::GameOverlay::LoadFont(const std::string& name, const std::string& path, float fontSize) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
std::shared_ptr<Archive> base = GlobalCtx2::GetInstance()->GetResourceManager()->GetArchive();
|
||||
std::shared_ptr<File> font = std::make_shared<File>();
|
||||
base->LoadFile(path, false, font);
|
||||
if (font->bIsLoaded) {
|
||||
char* font_data = new char[font->dwBufferSize];
|
||||
memcpy(font_data, font->buffer.get(), font->dwBufferSize);
|
||||
Fonts[name] = io.Fonts->AddFontFromMemoryTTF(font_data, font->dwBufferSize, fontSize);
|
||||
}
|
||||
}
|
||||
|
||||
void Ship::GameOverlay::TextDraw(float x, float y, bool shadow, ImVec4 color, const char* fmt, ...) {
|
||||
char buf[1024];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
|
||||
buf[IM_ARRAYSIZE(buf) - 1] = 0;
|
||||
va_end(args);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
ImGui::PushFont(Fonts[this->CurrentFont]);
|
||||
if (shadow) {
|
||||
ImGui::SetCursorPos(ImVec2(x + 1, y + 1));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(.0f, .0f, .0f, color.w));
|
||||
ImGui::Text(buf, args);
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SetCursorPos(ImVec2(x, y));
|
||||
ImGui::Text(buf, args);
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
void Ship::GameOverlay::TextDrawNotification(float duration, bool shadow, const char* fmt, ...) {
|
||||
char buf[1024];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
|
||||
buf[IM_ARRAYSIZE(buf) - 1] = 0;
|
||||
va_end(args);
|
||||
this->RegisteredOverlays[StringHelper::Sprintf("NotificationID:%d%d", rand(), this->RegisteredOverlays.size())] = new Overlay({ OverlayType::NOTIFICATION, ImStrdup(buf), duration, duration });
|
||||
NeedsCleanup = true;
|
||||
}
|
||||
|
||||
void Ship::GameOverlay::CleanupNotifications() {
|
||||
if(!NeedsCleanup) return;
|
||||
for (auto it = this->RegisteredOverlays.begin(); it != this->RegisteredOverlays.end(); ) {
|
||||
if (it->second->type == OverlayType::NOTIFICATION && it->second->duration <= 0.0f) {
|
||||
it = this->RegisteredOverlays.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
NeedsCleanup = false;
|
||||
}
|
||||
|
||||
float Ship::GameOverlay::GetScreenWidth() {
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
return viewport->Size.x;
|
||||
}
|
||||
|
||||
float Ship::GameOverlay::GetScreenHeight() {
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
return viewport->Size.y;
|
||||
}
|
||||
|
||||
float Ship::GameOverlay::GetStringWidth(const char* text) {
|
||||
return CalculateTextSize(text).x;
|
||||
}
|
||||
|
||||
ImVec2 Ship::GameOverlay::CalculateTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width) {
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
||||
const char* text_display_end;
|
||||
if (hide_text_after_double_hash)
|
||||
text_display_end = ImGui::FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string
|
||||
else
|
||||
text_display_end = text_end;
|
||||
|
||||
GameOverlay* overlay = SohImGui::overlay;
|
||||
|
||||
ImFont* font = overlay->CurrentFont == "Default" ? g.Font : overlay->Fonts[overlay->CurrentFont];
|
||||
const float font_size = font->FontSize;
|
||||
if (text == text_display_end)
|
||||
return ImVec2(0.0f, font_size);
|
||||
ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
|
||||
|
||||
// Round
|
||||
// FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out.
|
||||
// FIXME: Investigate using ceilf or e.g.
|
||||
// - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c
|
||||
// - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html
|
||||
text_size.x = IM_FLOOR(text_size.x + 0.99999f);
|
||||
|
||||
return text_size;
|
||||
}
|
||||
|
||||
void Ship::GameOverlay::Init() {
|
||||
this->LoadFont("Press Start 2P", "assets/ship_of_harkinian/fonts/PressStart2P-Regular.ttf", 12.0f);
|
||||
this->LoadFont("Fipps", "assets/ship_of_harkinian/fonts/Fipps-Regular.otf", 32.0f);
|
||||
const std::string DefaultFont = this->Fonts.begin()->first;
|
||||
if(!this->Fonts.empty()) {
|
||||
const std::string font = CVar_GetString("gOverlayFont", ImStrdup(DefaultFont.c_str()));
|
||||
for (auto& [name, _] : this->Fonts) {
|
||||
if (font.starts_with(name)) {
|
||||
this->CurrentFont = name;
|
||||
break;
|
||||
}
|
||||
this->CurrentFont = DefaultFont;
|
||||
}
|
||||
}
|
||||
SohImGui::console->Commands["overlay"] = { OverlayCommand, "Draw an overlay using a cvar value" };
|
||||
}
|
||||
|
||||
void Ship::GameOverlay::DrawSettings() {
|
||||
ImGui::Text("Overlays Text Font");
|
||||
if (ImGui::BeginCombo("##TextFont", this->CurrentFont.c_str())) {
|
||||
for (auto& [name, font] : this->Fonts) {
|
||||
if (ImGui::Selectable(name.c_str(), name == this->CurrentFont)) {
|
||||
this->CurrentFont = name;
|
||||
CVar_SetString("gOverlayFont", ImStrdup(name.c_str()));
|
||||
SohImGui::needs_save = true;
|
||||
}
|
||||
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Ship::GameOverlay::Draw() {
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
|
||||
ImGui::SetNextWindowPos(viewport->Pos, ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(viewport->Size, ImGuiCond_Always);
|
||||
ImGui::Begin("SoHOverlay", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground |
|
||||
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs);
|
||||
|
||||
this->CleanupNotifications();
|
||||
|
||||
float textY = 50;
|
||||
float notY = 0;
|
||||
|
||||
for (auto &[key, overlay] : this->RegisteredOverlays) {
|
||||
|
||||
if (overlay->type == OverlayType::TEXT) {
|
||||
const char* text = ImStrdup(overlay->value);
|
||||
const CVar* var = CVar_Get(text);
|
||||
ImVec4 color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
switch (var->type) {
|
||||
case CVAR_TYPE_FLOAT:
|
||||
this->TextDraw(30, textY, true, color, "%s %.2f", text, var->value.valueFloat);
|
||||
break;
|
||||
case CVAR_TYPE_S32:
|
||||
this->TextDraw(30, textY, true, color, "%s %d", text, var->value.valueS32);
|
||||
break;
|
||||
case CVAR_TYPE_STRING:
|
||||
this->TextDraw(30, textY, true, color, "%s %s", text, var->value.valueStr);
|
||||
break;
|
||||
}
|
||||
|
||||
free((void*) text);
|
||||
textY += 30;
|
||||
}
|
||||
|
||||
if (overlay->type == OverlayType::NOTIFICATION && overlay->duration > 0) {
|
||||
const char* text = overlay->value;
|
||||
const float duration = overlay->duration / overlay->fadeTime;
|
||||
|
||||
const ImVec4 color = ImVec4(1.0f, 1.0f, 1.0f, duration);
|
||||
const float textWidth = this->GetStringWidth(overlay->value);
|
||||
|
||||
this->TextDraw(GetScreenWidth() - textWidth - 40, GetScreenHeight() - 40 - notY, true, color, text);
|
||||
notY += 30;
|
||||
overlay->duration -= .05f;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
bool Ship::OverlayCommand(const std::vector<std::string>& args) {
|
||||
if (args.size() < 3) {
|
||||
return CMD_FAILED;
|
||||
}
|
||||
|
||||
if (CVar_Get(args[2].c_str()) != nullptr) {
|
||||
const char* key = args[2].c_str();
|
||||
GameOverlay* overlay = SohImGui::overlay;
|
||||
if (args[1] == "add") {
|
||||
if (!overlay->RegisteredOverlays.contains(key)) {
|
||||
overlay->RegisteredOverlays[key] = new Overlay({ OverlayType::TEXT, ImStrdup(key), -1.0f });
|
||||
INFO("Added overlay: %s ", key);
|
||||
} else {
|
||||
ERROR("Overlay already exists: %s", key);
|
||||
}
|
||||
} else if (args[1] == "remove") {
|
||||
if (overlay->RegisteredOverlays.contains(key)) {
|
||||
overlay->RegisteredOverlays.erase(key);
|
||||
INFO("Removed overlay: %s ", key);
|
||||
} else {
|
||||
ERROR("Overlay not found: %s ", key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ERROR("CVar %s does not exist", args[2].c_str());
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
42
libultraship/libultraship/GameOverlay.h
Normal file
42
libultraship/libultraship/GameOverlay.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Lib/ImGui/imgui.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
enum class OverlayType {
|
||||
TEXT, IMAGE, NOTIFICATION
|
||||
};
|
||||
|
||||
struct Overlay {
|
||||
OverlayType type;
|
||||
const char* value;
|
||||
float fadeTime;
|
||||
float duration;
|
||||
};
|
||||
|
||||
namespace Ship {
|
||||
class GameOverlay {
|
||||
public:
|
||||
std::unordered_map<std::string, Overlay*> RegisteredOverlays;
|
||||
std::unordered_map<std::string, ImFont*> Fonts;
|
||||
std::string CurrentFont = "Default";
|
||||
void Init();
|
||||
void Draw();
|
||||
void DrawSettings();
|
||||
static float GetScreenWidth();
|
||||
static float GetScreenHeight();
|
||||
static float GetStringWidth(const char* text);
|
||||
static ImVec2 CalculateTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f);
|
||||
void TextDraw(float x, float y, bool shadow, ImVec4 color, const char* text, ...);
|
||||
void TextDrawNotification(float duration, bool shadow, const char* fmt, ...);
|
||||
private:
|
||||
bool NeedsCleanup = false;
|
||||
void CleanupNotifications();
|
||||
void LoadFont(const std::string& name, const std::string& path, float fontSize);
|
||||
};
|
||||
|
||||
static bool OverlayCommand(const std::vector<std::string>& args);
|
||||
}
|
|
@ -1,19 +1,22 @@
|
|||
#include "GameSettings.h"
|
||||
|
||||
// Audio
|
||||
#include <cstddef>
|
||||
#include <PR/ultra64/types.h>
|
||||
#include <PR/ultra64/sptask.h>
|
||||
#include <PR/ultra64/pi.h>
|
||||
#include <PR/ultra64/message.h>
|
||||
#include <PR/ultra64/types.h>
|
||||
|
||||
#include "ConfigFile.h"
|
||||
#include "Cvar.h"
|
||||
#include "GlobalCtx2.h"
|
||||
#include "SohImGuiImpl.h"
|
||||
#include "stox.h"
|
||||
#include "../../soh/include/z64audio.h"
|
||||
#include <string>
|
||||
#include "SohHooks.h"
|
||||
#include "../../soh/soh/Enhancements/debugconsole.h"
|
||||
|
||||
#include "Window.h"
|
||||
#include "Lib/Fast3D/gfx_rendering_api.h"
|
||||
|
||||
#define ABS(var) var < 0 ? -(var) : var
|
||||
|
||||
|
@ -22,155 +25,46 @@ using namespace Ship;
|
|||
namespace Game {
|
||||
|
||||
bool DeSyncAudio = false;
|
||||
SoHConfigType Settings;
|
||||
const std::string ConfSection = DEBUG_SECTION;
|
||||
const std::string AudioSection = AUDIO_SECTION;
|
||||
const std::string ControllerSection = CONTROLLER_SECTION;
|
||||
const std::string EnhancementSection = ENHANCEMENTS_SECTION;
|
||||
const std::string CheatSection = CHEATS_SECTION;
|
||||
|
||||
void UpdateAudio() {
|
||||
Audio_SetGameVolume(SEQ_BGM_MAIN, Settings.audio.music_main);
|
||||
Audio_SetGameVolume(SEQ_BGM_SUB, Settings.audio.music_sub);
|
||||
Audio_SetGameVolume(SEQ_FANFARE, Settings.audio.fanfare);
|
||||
Audio_SetGameVolume(SEQ_SFX, Settings.audio.sfx);
|
||||
Audio_SetGameVolume(SEQ_BGM_MAIN, CVar_GetFloat("gMainMusicVolume", 1));
|
||||
Audio_SetGameVolume(SEQ_BGM_SUB, CVar_GetFloat("gSubMusicVolume", 1));
|
||||
Audio_SetGameVolume(SEQ_FANFARE, CVar_GetFloat("gSFXMusicVolume", 1));
|
||||
Audio_SetGameVolume(SEQ_SFX, CVar_GetFloat("gFanfareVolume", 1));
|
||||
}
|
||||
|
||||
void LoadSettings() {
|
||||
|
||||
void LoadPadSettings() {
|
||||
const std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf;
|
||||
|
||||
// Debug
|
||||
SohImGui::console->opened = stob(Conf[ConfSection]["console"]);
|
||||
Settings.debug.menu_bar = stob(Conf[ConfSection]["menu_bar"]);
|
||||
Settings.debug.soh = stob(Conf[ConfSection]["soh_debug"]);
|
||||
for (const auto& [i, controllers] : Ship::Window::Controllers) {
|
||||
for (const auto& controller : controllers) {
|
||||
if (auto padConfSection = controller->GetPadConfSection()) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Settings.debug.n64mode = stob(Conf[ConfSection]["n64_mode"]);
|
||||
|
||||
// Enhancements
|
||||
Settings.enhancements.fast_text = stob(Conf[EnhancementSection]["fast_text"]);
|
||||
CVar_SetS32(const_cast<char*>("gFastText"), Settings.enhancements.fast_text);
|
||||
|
||||
Settings.enhancements.disable_lod = stob(Conf[EnhancementSection]["disable_lod"]);
|
||||
CVar_SetS32(const_cast<char*>("gDisableLOD"), Settings.enhancements.disable_lod);
|
||||
|
||||
Settings.enhancements.animated_pause_menu = stob(Conf[EnhancementSection]["animated_pause_menu"]);
|
||||
CVar_SetS32(const_cast<char*>("gPauseLiveLink"), Settings.enhancements.animated_pause_menu);
|
||||
|
||||
Settings.enhancements.minimal_ui = stob(Conf[EnhancementSection]["minimal_ui"]);
|
||||
CVar_SetS32(const_cast<char*>("gMinimalUI"), Settings.enhancements.minimal_ui);
|
||||
|
||||
// Audio
|
||||
Settings.audio.master = Ship::stof(Conf[AudioSection]["master"]);
|
||||
CVar_SetFloat(const_cast<char*>("gGameMasterVolume"), Settings.audio.master);
|
||||
|
||||
Settings.audio.music_main = Ship::stof(Conf[AudioSection]["music_main"]);
|
||||
CVar_SetFloat(const_cast<char*>("gMainMusicVolume"), Settings.audio.music_main);
|
||||
|
||||
Settings.audio.music_sub = Ship::stof(Conf[AudioSection]["music_sub"]);
|
||||
CVar_SetFloat(const_cast<char*>("gSubMusicVolume"), Settings.audio.music_sub);
|
||||
|
||||
Settings.audio.sfx = Ship::stof(Conf[AudioSection]["sfx"]);
|
||||
CVar_SetFloat(const_cast<char*>("gSFXMusicVolume"), Settings.audio.sfx);
|
||||
|
||||
Settings.audio.fanfare = Ship::stof(Conf[AudioSection]["fanfare"]);
|
||||
CVar_SetFloat(const_cast<char*>("gFanfareVolume"), Settings.audio.fanfare);
|
||||
|
||||
// Controllers
|
||||
Settings.controller.gyro_sensitivity = Ship::stof(Conf[ControllerSection]["gyro_sensitivity"]);
|
||||
CVar_SetFloat(const_cast<char*>("gGyroSensitivity"), Settings.controller.gyro_sensitivity);
|
||||
|
||||
Settings.controller.rumble_strength = Ship::stof(Conf[ControllerSection]["rumble_strength"]);
|
||||
CVar_SetFloat(const_cast<char*>("gRumbleStrength"), Settings.controller.rumble_strength);
|
||||
|
||||
Settings.controller.input_scale = Ship::stof(Conf[ControllerSection]["input_scale"]);
|
||||
CVar_SetFloat(const_cast<char*>("gInputScale"), Settings.controller.input_scale);
|
||||
|
||||
Settings.controller.input_enabled = stob(Conf[ControllerSection]["input_enabled"]);
|
||||
CVar_SetS32(const_cast<char*>("gInputEnabled"), Settings.controller.input_enabled);
|
||||
|
||||
// Cheats
|
||||
Settings.cheats.debug_mode = stob(Conf[CheatSection]["debug_mode"]);
|
||||
CVar_SetS32(const_cast<char*>("gDebugEnabled"), Settings.cheats.debug_mode);
|
||||
|
||||
Settings.cheats.infinite_money = stob(Conf[CheatSection]["infinite_money"]);
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteMoney"), Settings.cheats.infinite_money);
|
||||
|
||||
Settings.cheats.infinite_health = stob(Conf[CheatSection]["infinite_health"]);
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteHealth"), Settings.cheats.infinite_health);
|
||||
|
||||
Settings.cheats.infinite_ammo = stob(Conf[CheatSection]["infinite_ammo"]);
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteAmmo"), Settings.cheats.infinite_ammo);
|
||||
|
||||
Settings.cheats.infinite_magic = stob(Conf[CheatSection]["infinite_magic"]);
|
||||
CVar_SetS32(const_cast<char*>("gInfiniteMagic"), Settings.cheats.infinite_magic);
|
||||
|
||||
Settings.cheats.no_clip = stob(Conf[CheatSection]["no_clip"]);
|
||||
CVar_SetS32(const_cast<char*>("gNoClip"), Settings.cheats.no_clip);
|
||||
|
||||
Settings.cheats.climb_everything = stob(Conf[CheatSection]["climb_everything"]);
|
||||
CVar_SetS32(const_cast<char*>("gClimbEverything"), Settings.cheats.climb_everything);
|
||||
|
||||
Settings.cheats.moon_jump_on_l = stob(Conf[CheatSection]["moon_jump_on_l"]);
|
||||
CVar_SetS32(const_cast<char*>("gMoonJumpOnL"), Settings.cheats.moon_jump_on_l);
|
||||
|
||||
Settings.cheats.super_tunic = stob(Conf[CheatSection]["super_tunic"]);
|
||||
CVar_SetS32(const_cast<char*>("gSuperTunic"), Settings.cheats.super_tunic);
|
||||
|
||||
UpdateAudio();
|
||||
void LoadSettings() {
|
||||
DebugConsole_LoadCVars();
|
||||
}
|
||||
|
||||
void SaveSettings() {
|
||||
const std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf;
|
||||
|
||||
// Debug
|
||||
Conf[ConfSection]["console"] = std::to_string(SohImGui::console->opened);
|
||||
Conf[ConfSection]["menu_bar"] = std::to_string(Settings.debug.menu_bar);
|
||||
Conf[ConfSection]["soh_debug"] = std::to_string(Settings.debug.soh);
|
||||
Conf[ConfSection]["n64_mode"] = std::to_string(Settings.debug.n64mode);
|
||||
|
||||
// Audio
|
||||
Conf[AudioSection]["master"] = std::to_string(Settings.audio.master);
|
||||
Conf[AudioSection]["music_main"] = std::to_string(Settings.audio.music_main);
|
||||
Conf[AudioSection]["music_sub"] = std::to_string(Settings.audio.music_sub);
|
||||
Conf[AudioSection]["sfx"] = std::to_string(Settings.audio.sfx);
|
||||
Conf[AudioSection]["fanfare"] = std::to_string(Settings.audio.fanfare);
|
||||
|
||||
// Enhancements
|
||||
Conf[EnhancementSection]["fast_text"] = std::to_string(Settings.enhancements.fast_text);
|
||||
Conf[EnhancementSection]["disable_lod"] = std::to_string(Settings.enhancements.disable_lod);
|
||||
Conf[EnhancementSection]["animated_pause_menu"] = std::to_string(Settings.enhancements.animated_pause_menu);
|
||||
Conf[EnhancementSection]["minimal_ui"] = std::to_string(Settings.enhancements.minimal_ui);
|
||||
|
||||
// Controllers
|
||||
Conf[ControllerSection]["gyro_sensitivity"] = std::to_string(Settings.controller.gyro_sensitivity);
|
||||
Conf[ControllerSection]["rumble_strength"] = std::to_string(Settings.controller.rumble_strength);
|
||||
Conf[ControllerSection]["input_scale"] = std::to_string(Settings.controller.input_scale);
|
||||
Conf[ControllerSection]["input_enabled"] = std::to_string(Settings.controller.input_enabled);
|
||||
|
||||
// Cheats
|
||||
Conf[CheatSection]["debug_mode"] = std::to_string(Settings.cheats.debug_mode);
|
||||
Conf[CheatSection]["infinite_money"] = std::to_string(Settings.cheats.infinite_money);
|
||||
Conf[CheatSection]["infinite_health"] = std::to_string(Settings.cheats.infinite_health);
|
||||
Conf[CheatSection]["infinite_ammo"] = std::to_string(Settings.cheats.infinite_ammo);
|
||||
Conf[CheatSection]["infinite_magic"] = std::to_string(Settings.cheats.infinite_magic);
|
||||
Conf[CheatSection]["no_clip"] = std::to_string(Settings.cheats.no_clip);
|
||||
Conf[CheatSection]["climb_everything"] = std::to_string(Settings.cheats.climb_everything);
|
||||
Conf[CheatSection]["moon_jump_on_l"] = std::to_string(Settings.cheats.moon_jump_on_l);
|
||||
Conf[CheatSection]["super_tunic"] = std::to_string(Settings.cheats.super_tunic);
|
||||
|
||||
Conf.Save();
|
||||
DebugConsole_SaveCVars();
|
||||
}
|
||||
|
||||
void InitSettings() {
|
||||
ModInternal::registerHookListener({ AUDIO_INIT, [](HookEvent ev) {
|
||||
UpdateAudio();
|
||||
}});
|
||||
ModInternal::registerHookListener({ GFX_INIT, [](HookEvent ev) {
|
||||
gfx_get_current_rendering_api()->set_texture_filter((FilteringMode) CVar_GetS32("gTextureFilter", THREE_POINT));
|
||||
SohImGui::console->opened = CVar_GetS32("gConsoleEnabled", 0);
|
||||
UpdateAudio();
|
||||
}});
|
||||
}
|
||||
|
||||
void SetSeqPlayerVolume(SeqPlayers playerId, float volume) {
|
||||
Audio_SetGameVolume(playerId, volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,55 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
struct SoHConfigType {
|
||||
// Debug
|
||||
struct {
|
||||
bool soh = false;
|
||||
bool n64mode = false;
|
||||
bool menu_bar = false;
|
||||
bool soh_sink = true;
|
||||
} debug;
|
||||
|
||||
// Audio
|
||||
struct {
|
||||
float master = 1.0f;
|
||||
float music_main = 1.0f;
|
||||
float fanfare = 1.0f;
|
||||
float sfx = 1.0f;
|
||||
float music_sub = 1.0f;
|
||||
} audio;
|
||||
|
||||
// Enhancements
|
||||
struct {
|
||||
bool fast_text = false;
|
||||
bool disable_lod = false;
|
||||
bool animated_pause_menu = false;
|
||||
bool minimal_ui = false;
|
||||
} enhancements;
|
||||
|
||||
// Controller
|
||||
struct {
|
||||
float gyro_sensitivity = 1.0f;
|
||||
float rumble_strength = 1.0f;
|
||||
float input_scale = 1.0f;
|
||||
float gyroDriftX = 0.0f;
|
||||
float gyroDriftY = 0.0f;
|
||||
bool input_enabled = false;
|
||||
} controller;
|
||||
|
||||
// Cheats
|
||||
struct {
|
||||
bool debug_mode = false;
|
||||
bool infinite_money = false;
|
||||
bool infinite_health = false;
|
||||
bool infinite_ammo = false;
|
||||
bool infinite_magic = false;
|
||||
bool no_clip = false;
|
||||
bool climb_everything = false;
|
||||
bool moon_jump_on_l = false;
|
||||
bool super_tunic = false;
|
||||
} cheats;
|
||||
};
|
||||
|
||||
enum SeqPlayers {
|
||||
/* 0 */ SEQ_BGM_MAIN,
|
||||
/* 1 */ SEQ_FANFARE,
|
||||
|
@ -58,16 +8,10 @@ enum SeqPlayers {
|
|||
/* 4 */ SEQ_MAX
|
||||
};
|
||||
|
||||
#define DEBUG_SECTION "DEBUG SETTINGS"
|
||||
#define AUDIO_SECTION "AUDIO SETTINGS"
|
||||
#define CONTROLLER_SECTION "CONTROLLER SECTION"
|
||||
#define ENHANCEMENTS_SECTION "ENHANCEMENT SETTINGS"
|
||||
#define CHEATS_SECTION "CHEATS SETTINGS"
|
||||
|
||||
namespace Game {
|
||||
extern SoHConfigType Settings;
|
||||
void InitSettings();
|
||||
void LoadSettings();
|
||||
void LoadPadSettings();
|
||||
void SaveSettings();
|
||||
void SetSeqPlayerVolume(SeqPlayers playerId, float volume);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef GAME_VERSION_H
|
||||
#define GAME_VERSION_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#define OOT_NTSC_10 0xEC7011B7
|
||||
|
@ -17,4 +20,6 @@
|
|||
#define OOT_PAL_GC_MQ_DBG 0x917D18F6
|
||||
#define OOT_IQUE_TW 0x3D81FB3E
|
||||
#define OOT_IQUE_CN 0xB1E1E07B
|
||||
#define OOT_UNKNOWN 0xFFFFFFFF
|
||||
#define OOT_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Ship {
|
|||
}
|
||||
|
||||
GlobalCtx2::GlobalCtx2(const std::string& Name) : Name(Name), MainPath(""), PatchesPath("") {
|
||||
|
||||
|
||||
}
|
||||
|
||||
GlobalCtx2::~GlobalCtx2() {
|
||||
|
@ -54,7 +54,11 @@ namespace Ship {
|
|||
|
||||
if (!ResMan->DidLoadSuccessfully())
|
||||
{
|
||||
#ifdef _WIN32
|
||||
MessageBox(NULL, L"Main OTR file not found!", L"Uh oh", MB_OK);
|
||||
#else
|
||||
SPDLOG_ERROR("Main OTR file not found!");
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
INSTANCE = new ModManager(ResMan);
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef GLOBAL_CTX_2
|
||||
#define GLOBAL_CTX_2
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -38,4 +41,6 @@ namespace Ship {
|
|||
std::string PatchesPath;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -53,4 +53,4 @@ namespace Ship {
|
|||
std::string KeyboardController::GetBindingConfSection() {
|
||||
return GetControllerType() + " CONTROLLER BINDING " + std::to_string(GetControllerNumber() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,16 @@ namespace Ship {
|
|||
|
||||
void ReadFromSource();
|
||||
void WriteToSource(ControllerCallback* controller);
|
||||
bool Connected() const { return true; }
|
||||
bool CanRumble() const { return false; }
|
||||
|
||||
bool PressButton(int32_t dwScancode);
|
||||
bool ReleaseButton(int32_t dwScancode);
|
||||
void ReleaseAllButtons();
|
||||
|
||||
bool HasPadConf() const { return false; }
|
||||
std::optional<std::string> GetPadConfSection() { return {}; }
|
||||
|
||||
protected:
|
||||
std::string GetControllerType();
|
||||
std::string GetConfSection();
|
||||
|
|
|
@ -170,6 +170,12 @@
|
|||
#define G_TEXRECT_WIDE 0x37
|
||||
#define G_FILLWIDERECT 0x38
|
||||
|
||||
/* GFX Effects */
|
||||
|
||||
// RDP Cmd
|
||||
#define G_SETGRAYSCALE 0x39
|
||||
#define G_SETINTENSITY 0x40
|
||||
|
||||
/*
|
||||
* The following commands are the "generated" RDP commands; the user
|
||||
* never sees them, the RSP microcode generates them.
|
||||
|
@ -998,7 +1004,7 @@
|
|||
#define G_DL_PUSH 0x00
|
||||
#define G_DL_NOPUSH 0x01
|
||||
|
||||
#if _MSC_VER
|
||||
#if defined(_MSC_VER) || defined(__GNUC__)
|
||||
#define _LANGUAGE_C
|
||||
#endif
|
||||
|
||||
|
@ -2821,6 +2827,14 @@ _DW({ \
|
|||
_g->words.w1 = 0; \
|
||||
}
|
||||
|
||||
#define gsSPGrayscale(pkt, state) \
|
||||
{ \
|
||||
Gfx *_g = (Gfx *)(pkt); \
|
||||
\
|
||||
_g->words.w0 = _SHIFTL(G_SETGRAYSCALE, 24, 8); \
|
||||
_g->words.w1 = state; \
|
||||
}
|
||||
|
||||
#ifdef F3DEX_GBI_2
|
||||
/*
|
||||
* One gSPGeometryMode(pkt,c,s) GBI is equal to these two GBIs.
|
||||
|
@ -3118,7 +3132,7 @@ _DW({ \
|
|||
#endif
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER)
|
||||
#define CALL_2(A,B) A B
|
||||
#define CALL_3(A,B,C) A B C
|
||||
|
||||
|
@ -3129,12 +3143,12 @@ _DW({ \
|
|||
#define gsDPSetCombineMode(a, b) gsDPSetCombineLERP(a, b)
|
||||
#endif
|
||||
|
||||
#if _MSC_VER
|
||||
#if defined(_MSC_VER) || defined(__GNUC__)
|
||||
#define CALL_2(A,B) A B
|
||||
#define CALL_3(A,B,C) A B C
|
||||
|
||||
#define gsDPSetCombineMode(a, b) CALL_2(gsDPSetCombineLERP, (a, b))
|
||||
//#define gsDPSetCombineMode(a, b) _SHIFTL(0, 24, 8), 0
|
||||
// #define gsDPSetCombineMode(a, b) CALL_2(gsDPSetCombineLERP, (a, b))
|
||||
// #define gsDPSetCombineMode(a, b) _SHIFTL(0, 24, 8), 0
|
||||
#else
|
||||
#define gsDPSetCombineMode(a, b) gsDPSetCombineLERP(a, b)
|
||||
#endif
|
||||
|
@ -3161,6 +3175,8 @@ _DW({ \
|
|||
(_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | \
|
||||
_SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8)))
|
||||
|
||||
#define gsDPSetGrayscaleColor(pkt, r, g, b, lerp) \
|
||||
DPRGBColor(pkt, G_SETINTENSITY, r, g, b, lerp)
|
||||
#define gDPSetEnvColor(pkt, r, g, b, a) \
|
||||
DPRGBColor(pkt, G_SETENVCOLOR, r,g,b,a)
|
||||
#define gsDPSetEnvColor(r, g, b, a) \
|
||||
|
@ -3177,7 +3193,6 @@ _DW({ \
|
|||
gDPSetColor(pkt, G_SETFILLCOLOR, (d))
|
||||
#define gsDPSetFillColor(d) \
|
||||
gsDPSetColor(G_SETFILLCOLOR, (d))
|
||||
|
||||
#define gDPSetPrimDepth(pkt, z, dz) \
|
||||
gDPSetColor(pkt, G_SETPRIMDEPTH, \
|
||||
_SHIFTL(z, 16, 16) | _SHIFTL(dz, 0, 16))
|
||||
|
@ -4560,6 +4575,20 @@ _DW({ \
|
|||
_g2->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \
|
||||
}
|
||||
|
||||
# define gsSPWideTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
|
||||
{{ \
|
||||
(_SHIFTL(G_TEXRECT_WIDE, 24, 8) | _SHIFTL((xh), 0, 24)), \
|
||||
_SHIFTL((yh), 0, 24), \
|
||||
}}, \
|
||||
{{ \
|
||||
(_SHIFTL((tile), 24, 3) | _SHIFTL((xl), 0, 24)), \
|
||||
_SHIFTL((yl), 0, 24), \
|
||||
}}, \
|
||||
{{ \
|
||||
_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16), \
|
||||
_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16) \
|
||||
}}
|
||||
|
||||
/* like gSPTextureRectangle but accepts negative position arguments */
|
||||
#define gSPScisTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \
|
||||
_DW({ \
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#define G_OFF (0)
|
||||
|
||||
#include <stdint.h>
|
||||
#include "types.h"
|
||||
#include "gbi.h"
|
||||
#include "abi.h"
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ void gfx_cc_get_features(uint64_t shader_id0, uint32_t shader_id1, struct CCFeat
|
|||
cc_features->opt_2cyc = (shader_id1 & SHADER_OPT_2CYC) != 0;
|
||||
cc_features->opt_alpha_threshold = (shader_id1 & SHADER_OPT_ALPHA_THRESHOLD) != 0;
|
||||
cc_features->opt_invisible = (shader_id1 & SHADER_OPT_INVISIBLE) != 0;
|
||||
cc_features->opt_grayscale = (shader_id1 & SHADER_OPT_GRAYSCALE) != 0;
|
||||
|
||||
cc_features->clamp[0][0] = (shader_id1 & SHADER_OPT_TEXEL0_CLAMP_S);
|
||||
cc_features->clamp[0][1] = (shader_id1 & SHADER_OPT_TEXEL0_CLAMP_T);
|
||||
|
|
|
@ -39,10 +39,11 @@ enum {
|
|||
#define SHADER_OPT_2CYC (1 << 4)
|
||||
#define SHADER_OPT_ALPHA_THRESHOLD (1 << 5)
|
||||
#define SHADER_OPT_INVISIBLE (1 << 6)
|
||||
#define SHADER_OPT_TEXEL0_CLAMP_S (1 << 7)
|
||||
#define SHADER_OPT_TEXEL0_CLAMP_T (1 << 8)
|
||||
#define SHADER_OPT_TEXEL1_CLAMP_S (1 << 9)
|
||||
#define SHADER_OPT_TEXEL1_CLAMP_T (1 << 10)
|
||||
#define SHADER_OPT_GRAYSCALE (1 << 7)
|
||||
#define SHADER_OPT_TEXEL0_CLAMP_S (1 << 8)
|
||||
#define SHADER_OPT_TEXEL0_CLAMP_T (1 << 9)
|
||||
#define SHADER_OPT_TEXEL1_CLAMP_S (1 << 10)
|
||||
#define SHADER_OPT_TEXEL1_CLAMP_T (1 << 11)
|
||||
#define CC_SHADER_OPT_POS 56
|
||||
|
||||
struct CCFeatures {
|
||||
|
@ -54,6 +55,7 @@ struct CCFeatures {
|
|||
bool opt_2cyc;
|
||||
bool opt_alpha_threshold;
|
||||
bool opt_invisible;
|
||||
bool opt_grayscale;
|
||||
bool used_textures[2];
|
||||
bool clamp[2][2];
|
||||
int num_inputs;
|
||||
|
|
|
@ -15,11 +15,9 @@
|
|||
#ifndef _LANGUAGE_C
|
||||
#define _LANGUAGE_C
|
||||
#endif
|
||||
#include <PR/ultra64/gbi.h>
|
||||
#include "PR/ultra64/gbi.h"
|
||||
|
||||
#include "gfx_cc.h"
|
||||
#include "gfx_window_manager_api.h"
|
||||
#include "gfx_rendering_api.h"
|
||||
#include "gfx_direct3d_common.h"
|
||||
|
||||
#define DECLARE_GFX_DXGI_FUNCTIONS
|
||||
|
@ -28,7 +26,9 @@
|
|||
#include "gfx_screen_config.h"
|
||||
#include "../../SohImGuiImpl.h"
|
||||
|
||||
#define THREE_POINT_FILTERING 0
|
||||
#include "gfx_cc.h"
|
||||
#include "gfx_rendering_api.h"
|
||||
#include "gfx_pc.h"
|
||||
#define DEBUG_D3D 0
|
||||
|
||||
using namespace Microsoft::WRL; // For ComPtr
|
||||
|
@ -37,9 +37,8 @@ namespace {
|
|||
|
||||
struct PerFrameCB {
|
||||
uint32_t noise_frame;
|
||||
float noise_scale_x;
|
||||
float noise_scale_y;
|
||||
uint32_t padding;
|
||||
float noise_scale;
|
||||
uint32_t padding[2]; // constant buffers must be multiples of 16 bytes in size
|
||||
};
|
||||
|
||||
struct PerDrawCB {
|
||||
|
@ -51,12 +50,12 @@ struct PerDrawCB {
|
|||
} textures[2];
|
||||
};
|
||||
|
||||
struct CoordCB {
|
||||
float x, y;
|
||||
float padding[2]; // structure size must be multiple of 16
|
||||
struct Coord {
|
||||
int x, y;
|
||||
};
|
||||
|
||||
struct TextureData {
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
ComPtr<ID3D11ShaderResourceView> resource_view;
|
||||
ComPtr<ID3D11SamplerState> sampler_state;
|
||||
uint32_t width;
|
||||
|
@ -64,10 +63,13 @@ struct TextureData {
|
|||
bool linear_filtering;
|
||||
};
|
||||
|
||||
struct FramebufferData {
|
||||
struct Framebuffer {
|
||||
ComPtr<ID3D11RenderTargetView> render_target_view;
|
||||
ComPtr<ID3D11DepthStencilView> depth_stencil_view;
|
||||
ComPtr<ID3D11ShaderResourceView> depth_stencil_srv;
|
||||
uint32_t texture_id;
|
||||
bool has_depth_buffer;
|
||||
uint32_t msaa_level;
|
||||
};
|
||||
|
||||
struct ShaderProgramD3D11 {
|
||||
|
@ -86,39 +88,35 @@ struct ShaderProgramD3D11 {
|
|||
static struct {
|
||||
HMODULE d3d11_module;
|
||||
PFN_D3D11_CREATE_DEVICE D3D11CreateDevice;
|
||||
|
||||
|
||||
HMODULE d3dcompiler_module;
|
||||
pD3DCompile D3DCompile;
|
||||
|
||||
|
||||
D3D_FEATURE_LEVEL feature_level;
|
||||
|
||||
uint32_t msaa_num_quality_levels[D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT];
|
||||
|
||||
ComPtr<ID3D11Device> device;
|
||||
ComPtr<IDXGISwapChain1> swap_chain;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
ComPtr<ID3D11RenderTargetView> backbuffer_view;
|
||||
ComPtr<ID3D11DepthStencilView> depth_stencil_view;
|
||||
ComPtr<ID3D11ShaderResourceView> depth_stencil_srv;
|
||||
ComPtr<ID3D11RasterizerState> rasterizer_state;
|
||||
ComPtr<ID3D11DepthStencilState> depth_stencil_state;
|
||||
ComPtr<ID3D11Buffer> vertex_buffer;
|
||||
ComPtr<ID3D11Buffer> per_frame_cb;
|
||||
ComPtr<ID3D11Buffer> per_draw_cb;
|
||||
ComPtr<ID3D11Texture2D> depth_stencil_texture;
|
||||
ComPtr<ID3D11Texture2D> depth_stencil_copy_texture;
|
||||
ComPtr<ID3D11Buffer> coord_buffer;
|
||||
ComPtr<ID3D11ShaderResourceView> coord_buffer_srv;
|
||||
ComPtr<ID3D11Buffer> depth_value_output_buffer;
|
||||
ComPtr<ID3D11Buffer> depth_value_output_buffer_copy;
|
||||
ComPtr<ID3D11UnorderedAccessView> depth_value_output_uav;
|
||||
ComPtr<ID3D11SamplerState> depth_value_sampler;
|
||||
ComPtr<ID3D11ComputeShader> compute_shader;
|
||||
bool copied_depth_buffer;
|
||||
ComPtr<ID3D11ComputeShader> compute_shader_msaa;
|
||||
ComPtr<ID3DBlob> compute_shader_msaa_blob;
|
||||
size_t coord_buffer_size;
|
||||
|
||||
#if DEBUG_D3D
|
||||
ComPtr<ID3D11Debug> debug;
|
||||
#endif
|
||||
|
||||
DXGI_SAMPLE_DESC sample_description;
|
||||
|
||||
PerFrameCB per_frame_cb_data;
|
||||
PerDrawCB per_draw_cb_data;
|
||||
|
||||
|
@ -128,14 +126,16 @@ static struct {
|
|||
int current_tile;
|
||||
uint32_t current_texture_ids[2];
|
||||
|
||||
std::vector<FramebufferData> framebuffers;
|
||||
std::vector<Framebuffer> framebuffers;
|
||||
|
||||
// Current state
|
||||
|
||||
struct ShaderProgramD3D11 *shader_program;
|
||||
|
||||
uint32_t current_width, current_height;
|
||||
//uint32_t current_width, current_height;
|
||||
uint32_t render_target_height;
|
||||
int current_framebuffer;
|
||||
FilteringMode current_filter_mode = NONE;
|
||||
|
||||
int8_t depth_test;
|
||||
int8_t depth_mask;
|
||||
|
@ -156,7 +156,9 @@ static struct {
|
|||
|
||||
static LARGE_INTEGER last_time, accumulated_time, frequency;
|
||||
|
||||
void create_depth_stencil_objects(uint32_t width, uint32_t height, ID3D11Texture2D **texture, ID3D11DepthStencilView **view, ID3D11ShaderResourceView **srv) {
|
||||
int gfx_d3d11_create_framebuffer(void);
|
||||
|
||||
static void create_depth_stencil_objects(uint32_t width, uint32_t height, uint32_t msaa_count, ID3D11DepthStencilView **view, ID3D11ShaderResourceView **srv) {
|
||||
D3D11_TEXTURE2D_DESC texture_desc;
|
||||
texture_desc.Width = width;
|
||||
texture_desc.Height = height;
|
||||
|
@ -164,93 +166,42 @@ void create_depth_stencil_objects(uint32_t width, uint32_t height, ID3D11Texture
|
|||
texture_desc.ArraySize = 1;
|
||||
texture_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ?
|
||||
DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R24G8_TYPELESS;
|
||||
texture_desc.SampleDesc.Count = 1;
|
||||
texture_desc.SampleDesc.Count = msaa_count;
|
||||
texture_desc.SampleDesc.Quality = 0;
|
||||
texture_desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
texture_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | (srv != nullptr ? D3D11_BIND_SHADER_RESOURCE : 0);
|
||||
texture_desc.CPUAccessFlags = 0;
|
||||
texture_desc.MiscFlags = 0;
|
||||
|
||||
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, nullptr, texture));
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, nullptr, texture.GetAddressOf()));
|
||||
|
||||
D3D11_DEPTH_STENCIL_VIEW_DESC view_desc;
|
||||
view_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ?
|
||||
DXGI_FORMAT_D32_FLOAT : DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
view_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
||||
view_desc.Flags = 0;
|
||||
view_desc.Texture2D.MipSlice = 0;
|
||||
if (msaa_count > 1) {
|
||||
view_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
|
||||
view_desc.Texture2DMS.UnusedField_NothingToDefine = 0;
|
||||
} else {
|
||||
view_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
||||
view_desc.Texture2D.MipSlice = 0;
|
||||
}
|
||||
|
||||
ThrowIfFailed(d3d.device->CreateDepthStencilView(*texture, &view_desc, view));
|
||||
ThrowIfFailed(d3d.device->CreateDepthStencilView(texture.Get(), &view_desc, view));
|
||||
|
||||
if (srv != nullptr) {
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
||||
srv_desc.Format = d3d.feature_level >= D3D_FEATURE_LEVEL_10_0 ?
|
||||
DXGI_FORMAT_R32_FLOAT : DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
|
||||
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srv_desc.ViewDimension = msaa_count > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srv_desc.Texture2D.MostDetailedMip = 0;
|
||||
srv_desc.Texture2D.MipLevels = -1;
|
||||
|
||||
ThrowIfFailed(d3d.device->CreateShaderResourceView(*texture, &srv_desc, srv));
|
||||
ThrowIfFailed(d3d.device->CreateShaderResourceView(texture.Get(), &srv_desc, srv));
|
||||
}
|
||||
}
|
||||
|
||||
static void create_render_target_views(bool is_resize) {
|
||||
DXGI_SWAP_CHAIN_DESC1 desc1;
|
||||
|
||||
if (is_resize) {
|
||||
// Release previous stuff (if any)
|
||||
|
||||
d3d.backbuffer_view.Reset();
|
||||
d3d.depth_stencil_texture.Reset();
|
||||
d3d.depth_stencil_view.Reset();
|
||||
d3d.depth_stencil_srv.Reset();
|
||||
d3d.depth_stencil_copy_texture.Reset();
|
||||
|
||||
// Resize swap chain buffers
|
||||
|
||||
ThrowIfFailed(d3d.swap_chain->GetDesc1(&desc1));
|
||||
ThrowIfFailed(d3d.swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, desc1.Flags),
|
||||
gfx_dxgi_get_h_wnd(), "Failed to resize IDXGISwapChain buffers.");
|
||||
}
|
||||
|
||||
// Get new size
|
||||
|
||||
ThrowIfFailed(d3d.swap_chain->GetDesc1(&desc1));
|
||||
|
||||
// Create back buffer
|
||||
|
||||
ComPtr<ID3D11Texture2D> backbuffer_texture;
|
||||
ThrowIfFailed(d3d.swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID *) backbuffer_texture.GetAddressOf()),
|
||||
gfx_dxgi_get_h_wnd(), "Failed to get backbuffer from IDXGISwapChain.");
|
||||
|
||||
ThrowIfFailed(d3d.device->CreateRenderTargetView(backbuffer_texture.Get(), nullptr, d3d.backbuffer_view.GetAddressOf()),
|
||||
gfx_dxgi_get_h_wnd(), "Failed to create render target view.");
|
||||
|
||||
// Create depth buffer
|
||||
create_depth_stencil_objects(desc1.Width, desc1.Height, d3d.depth_stencil_texture.GetAddressOf(), d3d.depth_stencil_view.GetAddressOf(), d3d.depth_stencil_srv.GetAddressOf());
|
||||
|
||||
// Create texture that can be used to retrieve depth value
|
||||
|
||||
D3D11_TEXTURE2D_DESC depth_texture = {};
|
||||
depth_texture.Width = desc1.Width;
|
||||
depth_texture.Height = desc1.Height;
|
||||
depth_texture.MipLevels = 1;
|
||||
depth_texture.ArraySize = 1;
|
||||
depth_texture.Format = DXGI_FORMAT_D32_FLOAT;
|
||||
depth_texture.SampleDesc.Count = 1;
|
||||
depth_texture.SampleDesc.Quality = 0;
|
||||
depth_texture.Usage = D3D11_USAGE_STAGING;
|
||||
depth_texture.BindFlags = 0;
|
||||
depth_texture.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
depth_texture.MiscFlags = 0;
|
||||
ThrowIfFailed(d3d.device->CreateTexture2D(&depth_texture, nullptr, d3d.depth_stencil_copy_texture.GetAddressOf()));
|
||||
|
||||
// Save resolution
|
||||
|
||||
d3d.current_width = desc1.Width;
|
||||
d3d.current_height = desc1.Height;
|
||||
}
|
||||
|
||||
static void gfx_d3d11_init(void) {
|
||||
// Load d3d11.dll
|
||||
d3d.d3d11_module = LoadLibraryW(L"d3d11.dll");
|
||||
|
@ -300,11 +251,6 @@ static void gfx_d3d11_init(void) {
|
|||
}
|
||||
});
|
||||
|
||||
// Sample description to be used in back buffer and depth buffer
|
||||
|
||||
d3d.sample_description.Count = 1;
|
||||
d3d.sample_description.Quality = 0;
|
||||
|
||||
// Create the swap chain
|
||||
d3d.swap_chain = gfx_dxgi_create_swap_chain(d3d.device.Get());
|
||||
|
||||
|
@ -315,9 +261,19 @@ static void gfx_d3d11_init(void) {
|
|||
gfx_dxgi_get_h_wnd(), "Failed to get ID3D11Debug device.");
|
||||
#endif
|
||||
|
||||
// Create views
|
||||
// Create the default framebuffer which represents the window
|
||||
Framebuffer& fb = d3d.framebuffers[gfx_d3d11_create_framebuffer()];
|
||||
|
||||
create_render_target_views(false);
|
||||
// Check the size of the window
|
||||
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc;
|
||||
ThrowIfFailed(d3d.swap_chain->GetDesc1(&swap_chain_desc));
|
||||
d3d.textures[fb.texture_id].width = swap_chain_desc.Width;
|
||||
d3d.textures[fb.texture_id].height = swap_chain_desc.Height;
|
||||
fb.msaa_level = 1;
|
||||
|
||||
for (uint32_t sample_count = 1; sample_count <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; sample_count++) {
|
||||
ThrowIfFailed(d3d.device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, sample_count, &d3d.msaa_num_quality_levels[sample_count - 1]));
|
||||
}
|
||||
|
||||
// Create main vertex buffer
|
||||
|
||||
|
@ -364,61 +320,30 @@ static void gfx_d3d11_init(void) {
|
|||
|
||||
// Create compute shader that can be used to retrieve depth buffer values
|
||||
|
||||
D3D11_BUFFER_DESC coord_cb_desc;
|
||||
coord_cb_desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
coord_cb_desc.ByteWidth = sizeof(CoordCB);
|
||||
coord_cb_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
coord_cb_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
coord_cb_desc.MiscFlags = 0;
|
||||
coord_cb_desc.StructureByteStride = 0;
|
||||
|
||||
ThrowIfFailed(d3d.device->CreateBuffer(&coord_cb_desc, nullptr, d3d.coord_buffer.GetAddressOf()));
|
||||
|
||||
D3D11_SAMPLER_DESC sampler_desc = {};
|
||||
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
sampler_desc.MinLOD = 0;
|
||||
sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
ThrowIfFailed(d3d.device->CreateSamplerState(&sampler_desc, d3d.depth_value_sampler.GetAddressOf()));
|
||||
|
||||
D3D11_BUFFER_DESC output_buffer_desc;
|
||||
output_buffer_desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
output_buffer_desc.ByteWidth = sizeof(float);
|
||||
output_buffer_desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
|
||||
output_buffer_desc.CPUAccessFlags = 0;
|
||||
output_buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
|
||||
output_buffer_desc.StructureByteStride = sizeof(float);
|
||||
ThrowIfFailed(d3d.device->CreateBuffer(&output_buffer_desc, nullptr, d3d.depth_value_output_buffer.GetAddressOf()));
|
||||
|
||||
D3D11_UNORDERED_ACCESS_VIEW_DESC output_buffer_uav_desc;
|
||||
output_buffer_uav_desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
output_buffer_uav_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
|
||||
output_buffer_uav_desc.Buffer.FirstElement = 0;
|
||||
output_buffer_uav_desc.Buffer.NumElements = 1;
|
||||
output_buffer_uav_desc.Buffer.Flags = 0;
|
||||
ThrowIfFailed(d3d.device->CreateUnorderedAccessView(d3d.depth_value_output_buffer.Get(), &output_buffer_uav_desc, d3d.depth_value_output_uav.GetAddressOf()));
|
||||
|
||||
output_buffer_desc.Usage = D3D11_USAGE_STAGING;
|
||||
output_buffer_desc.BindFlags = 0;
|
||||
output_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
ThrowIfFailed(d3d.device->CreateBuffer(&output_buffer_desc, nullptr, d3d.depth_value_output_buffer_copy.GetAddressOf()));
|
||||
|
||||
const char* shader_source = R"(
|
||||
sampler my_sampler : register(s0);
|
||||
Texture2D<float> tex : register(t0);
|
||||
cbuffer coordCB : register(b0) {
|
||||
float2 coord;
|
||||
}
|
||||
|
||||
StructuredBuffer<int2> coord : register(t1);
|
||||
RWStructuredBuffer<float> output : register(u0);
|
||||
|
||||
[numthreads(1, 1, 1)]
|
||||
void CSMain(uint3 DTid : SV_DispatchThreadID) {
|
||||
output[0] = tex.SampleLevel(my_sampler, coord, 0);
|
||||
output[DTid.x] = tex.Load(int3(coord[DTid.x], 0));
|
||||
}
|
||||
)";
|
||||
|
||||
const char* shader_source_msaa = R"(
|
||||
sampler my_sampler : register(s0);
|
||||
Texture2DMS<float, 2> tex : register(t0);
|
||||
StructuredBuffer<int2> coord : register(t1);
|
||||
RWStructuredBuffer<float> output : register(u0);
|
||||
|
||||
[numthreads(1, 1, 1)]
|
||||
void CSMain(uint3 DTid : SV_DispatchThreadID) {
|
||||
output[DTid.x] = tex.Load(coord[DTid.x], 0);
|
||||
}
|
||||
)";
|
||||
|
||||
#if DEBUG_D3D
|
||||
UINT compile_flags = D3DCOMPILE_DEBUG;
|
||||
#else
|
||||
|
@ -426,7 +351,9 @@ void CSMain(uint3 DTid : SV_DispatchThreadID) {
|
|||
#endif
|
||||
|
||||
ComPtr<ID3DBlob> cs, error_blob;
|
||||
HRESULT hr = d3d.D3DCompile(shader_source, strlen(shader_source), nullptr, nullptr, nullptr, "CSMain", "cs_4_0", compile_flags, 0, cs.GetAddressOf(), error_blob.GetAddressOf());
|
||||
HRESULT hr;
|
||||
|
||||
hr = d3d.D3DCompile(shader_source, strlen(shader_source), nullptr, nullptr, nullptr, "CSMain", "cs_4_0", compile_flags, 0, cs.GetAddressOf(), error_blob.GetAddressOf());
|
||||
|
||||
if (FAILED(hr)) {
|
||||
char* err = (char*)error_blob->GetBufferPointer();
|
||||
|
@ -436,6 +363,14 @@ void CSMain(uint3 DTid : SV_DispatchThreadID) {
|
|||
|
||||
ThrowIfFailed(d3d.device->CreateComputeShader(cs->GetBufferPointer(), cs->GetBufferSize(), nullptr, d3d.compute_shader.GetAddressOf()));
|
||||
|
||||
hr = d3d.D3DCompile(shader_source_msaa, strlen(shader_source_msaa), nullptr, nullptr, nullptr, "CSMain", "cs_4_1", compile_flags, 0, d3d.compute_shader_msaa_blob.GetAddressOf(), error_blob.ReleaseAndGetAddressOf());
|
||||
|
||||
if (FAILED(hr)) {
|
||||
char* err = (char*)error_blob->GetBufferPointer();
|
||||
MessageBoxA(gfx_dxgi_get_h_wnd(), err, "Error", MB_OK | MB_ICONERROR);
|
||||
throw hr;
|
||||
}
|
||||
|
||||
// Create ImGui
|
||||
|
||||
SohImGui::WindowImpl window_impl;
|
||||
|
@ -445,8 +380,8 @@ void CSMain(uint3 DTid : SV_DispatchThreadID) {
|
|||
}
|
||||
|
||||
|
||||
static bool gfx_d3d11_z_is_from_0_to_1(void) {
|
||||
return true;
|
||||
static struct GfxClipParameters gfx_d3d11_get_clip_parameters(void) {
|
||||
return { true, false };
|
||||
}
|
||||
|
||||
static void gfx_d3d11_unload_shader(struct ShaderProgram *old_prg) {
|
||||
|
@ -463,7 +398,7 @@ static struct ShaderProgram *gfx_d3d11_create_and_load_new_shader(uint64_t shade
|
|||
char buf[4096];
|
||||
size_t len, num_floats;
|
||||
|
||||
gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, THREE_POINT_FILTERING);
|
||||
gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, d3d.current_filter_mode == THREE_POINT);
|
||||
|
||||
ComPtr<ID3DBlob> vs, ps;
|
||||
ComPtr<ID3DBlob> error_blob;
|
||||
|
@ -514,6 +449,9 @@ static struct ShaderProgram *gfx_d3d11_create_and_load_new_shader(uint64_t shade
|
|||
if (cc_features.opt_fog) {
|
||||
ied[ied_index++] = { "FOG", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 };
|
||||
}
|
||||
if (cc_features.opt_grayscale) {
|
||||
ied[ied_index++] = { "GRAYSCALE", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 };
|
||||
}
|
||||
for (unsigned int i = 0; i < cc_features.num_inputs; i++) {
|
||||
DXGI_FORMAT format = cc_features.opt_alpha ? DXGI_FORMAT_R32G32B32A32_FLOAT : DXGI_FORMAT_R32G32B32_FLOAT;
|
||||
ied[ied_index++] = { "INPUT", i, format, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 };
|
||||
|
@ -531,8 +469,8 @@ static struct ShaderProgram *gfx_d3d11_create_and_load_new_shader(uint64_t shade
|
|||
blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||
blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||
blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
|
||||
blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; // We initially clear alpha to 1.0f and want to keep it at 1.0f
|
||||
blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
} else {
|
||||
|
@ -592,6 +530,10 @@ static D3D11_TEXTURE_ADDRESS_MODE gfx_cm_to_d3d11(uint32_t val) {
|
|||
static void gfx_d3d11_upload_texture(const uint8_t *rgba32_buf, uint32_t width, uint32_t height) {
|
||||
// Create texture
|
||||
|
||||
TextureData *texture_data = &d3d.textures[d3d.current_texture_ids[d3d.current_tile]];
|
||||
texture_data->width = width;
|
||||
texture_data->height = height;
|
||||
|
||||
D3D11_TEXTURE2D_DESC texture_desc;
|
||||
ZeroMemory(&texture_desc, sizeof(D3D11_TEXTURE2D_DESC));
|
||||
|
||||
|
@ -612,32 +554,19 @@ static void gfx_d3d11_upload_texture(const uint8_t *rgba32_buf, uint32_t width,
|
|||
resource_data.SysMemPitch = width * 4;
|
||||
resource_data.SysMemSlicePitch = resource_data.SysMemPitch * height;
|
||||
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, &resource_data, texture.GetAddressOf()));
|
||||
|
||||
TextureData *texture_data = &d3d.textures[d3d.current_texture_ids[d3d.current_tile]];
|
||||
texture_data->width = width;
|
||||
texture_data->height = height;
|
||||
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, &resource_data, texture_data->texture.ReleaseAndGetAddressOf()));
|
||||
|
||||
// Create shader resource view from texture
|
||||
|
||||
if (texture_data->resource_view.Get() != nullptr) {
|
||||
// Free the previous texture in this slot
|
||||
texture_data->resource_view.Reset();
|
||||
}
|
||||
|
||||
ThrowIfFailed(d3d.device->CreateShaderResourceView(texture.Get(), nullptr, texture_data->resource_view.GetAddressOf()));
|
||||
ThrowIfFailed(d3d.device->CreateShaderResourceView(texture_data->texture.Get(), nullptr, texture_data->resource_view.ReleaseAndGetAddressOf()));
|
||||
}
|
||||
|
||||
static void gfx_d3d11_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) {
|
||||
D3D11_SAMPLER_DESC sampler_desc;
|
||||
ZeroMemory(&sampler_desc, sizeof(D3D11_SAMPLER_DESC));
|
||||
|
||||
#if THREE_POINT_FILTERING
|
||||
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
#else
|
||||
sampler_desc.Filter = linear_filter ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
#endif
|
||||
sampler_desc.Filter = linear_filter && d3d.current_filter_mode == LINEAR ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
|
||||
sampler_desc.AddressU = gfx_cm_to_d3d11(cms);
|
||||
sampler_desc.AddressV = gfx_cm_to_d3d11(cmt);
|
||||
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
|
@ -741,12 +670,12 @@ static void gfx_d3d11_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t
|
|||
d3d.last_resource_views[i] = d3d.textures[d3d.current_texture_ids[i]].resource_view.Get();
|
||||
d3d.context->PSSetShaderResources(i, 1, d3d.textures[d3d.current_texture_ids[i]].resource_view.GetAddressOf());
|
||||
|
||||
#if THREE_POINT_FILTERING
|
||||
d3d.per_draw_cb_data.textures[i].width = d3d.textures[d3d.current_texture_ids[i]].width;
|
||||
d3d.per_draw_cb_data.textures[i].height = d3d.textures[d3d.current_texture_ids[i]].height;
|
||||
d3d.per_draw_cb_data.textures[i].linear_filtering = d3d.textures[d3d.current_texture_ids[i]].linear_filtering;
|
||||
textures_changed = true;
|
||||
#endif
|
||||
if (d3d.current_filter_mode == THREE_POINT) {
|
||||
d3d.per_draw_cb_data.textures[i].width = d3d.textures[d3d.current_texture_ids[i]].width;
|
||||
d3d.per_draw_cb_data.textures[i].height = d3d.textures[d3d.current_texture_ids[i]].height;
|
||||
d3d.per_draw_cb_data.textures[i].linear_filtering = d3d.textures[d3d.current_texture_ids[i]].linear_filtering;
|
||||
textures_changed = true;
|
||||
}
|
||||
|
||||
if (d3d.last_sampler_states[i].Get() != d3d.textures[d3d.current_texture_ids[i]].sampler_state.Get()) {
|
||||
d3d.last_sampler_states[i] = d3d.textures[d3d.current_texture_ids[i]].sampler_state.Get();
|
||||
|
@ -803,20 +732,10 @@ static void gfx_d3d11_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t
|
|||
}
|
||||
|
||||
static void gfx_d3d11_on_resize(void) {
|
||||
create_render_target_views(true);
|
||||
//create_render_target_views(true);
|
||||
}
|
||||
|
||||
static void gfx_d3d11_start_frame(void) {
|
||||
// Set render targets
|
||||
|
||||
d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), d3d.depth_stencil_view.Get());
|
||||
|
||||
// Clear render targets
|
||||
|
||||
const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
d3d.context->ClearRenderTargetView(d3d.backbuffer_view.Get(), clearColor);
|
||||
d3d.context->ClearDepthStencilView(d3d.depth_stencil_view.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
|
||||
|
||||
// Set per-frame constant buffer
|
||||
|
||||
d3d.per_frame_cb_data.noise_frame++;
|
||||
|
@ -824,22 +743,9 @@ static void gfx_d3d11_start_frame(void) {
|
|||
// No high values, as noise starts to look ugly
|
||||
d3d.per_frame_cb_data.noise_frame = 0;
|
||||
}
|
||||
float aspect_ratio = (float) d3d.current_width / (float) d3d.current_height;
|
||||
d3d.render_target_height = d3d.current_height;
|
||||
d3d.per_frame_cb_data.noise_scale_x = 120 * aspect_ratio; // 120 = N64 height resolution (240) / 2
|
||||
d3d.per_frame_cb_data.noise_scale_y = 120;
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE ms;
|
||||
ZeroMemory(&ms, sizeof(D3D11_MAPPED_SUBRESOURCE));
|
||||
d3d.context->Map(d3d.per_frame_cb.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
|
||||
memcpy(ms.pData, &d3d.per_frame_cb_data, sizeof(PerFrameCB));
|
||||
d3d.context->Unmap(d3d.per_frame_cb.Get(), 0);
|
||||
|
||||
d3d.copied_depth_buffer = false;
|
||||
}
|
||||
|
||||
static void gfx_d3d11_end_frame(void) {
|
||||
SohImGui::Draw();
|
||||
d3d.context->Flush();
|
||||
}
|
||||
|
||||
|
@ -847,43 +753,13 @@ static void gfx_d3d11_finish_render(void) {
|
|||
d3d.context->Flush();
|
||||
}
|
||||
|
||||
void gfx_d3d11_resize_framebuffer(int fb, uint32_t width, uint32_t height) {
|
||||
FramebufferData& fd = d3d.framebuffers[fb];
|
||||
TextureData& td = d3d.textures[fd.texture_id];
|
||||
|
||||
ComPtr<ID3D11Texture2D> texture, depth_stencil_texture;
|
||||
|
||||
D3D11_TEXTURE2D_DESC texture_desc;
|
||||
texture_desc.Width = width;
|
||||
texture_desc.Height = height;
|
||||
texture_desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
|
||||
texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
texture_desc.CPUAccessFlags = 0;
|
||||
texture_desc.MiscFlags = 0;
|
||||
texture_desc.ArraySize = 1;
|
||||
texture_desc.MipLevels = 1;
|
||||
texture_desc.SampleDesc.Count = 1;
|
||||
texture_desc.SampleDesc.Quality = 0;
|
||||
|
||||
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, nullptr, texture.GetAddressOf()));
|
||||
create_depth_stencil_objects(width, height, depth_stencil_texture.GetAddressOf(), fd.depth_stencil_view.ReleaseAndGetAddressOf(), nullptr);
|
||||
ThrowIfFailed(d3d.device->CreateRenderTargetView(texture.Get(), nullptr, fd.render_target_view.ReleaseAndGetAddressOf()));
|
||||
ThrowIfFailed(d3d.device->CreateShaderResourceView(texture.Get(), nullptr, td.resource_view.ReleaseAndGetAddressOf()));
|
||||
|
||||
td.width = width;
|
||||
td.height = height;
|
||||
}
|
||||
|
||||
int gfx_d3d11_create_framebuffer(uint32_t width, uint32_t height) {
|
||||
int gfx_d3d11_create_framebuffer(void) {
|
||||
uint32_t texture_id = gfx_d3d11_new_texture();
|
||||
TextureData& t = d3d.textures[texture_id];
|
||||
t.width = width;
|
||||
t.height = height;
|
||||
|
||||
size_t index = d3d.framebuffers.size();
|
||||
d3d.framebuffers.resize(d3d.framebuffers.size() + 1);
|
||||
FramebufferData& data = d3d.framebuffers.back();
|
||||
Framebuffer& data = d3d.framebuffers.back();
|
||||
data.texture_id = texture_id;
|
||||
|
||||
uint32_t tile = 0;
|
||||
|
@ -892,24 +768,109 @@ int gfx_d3d11_create_framebuffer(uint32_t width, uint32_t height) {
|
|||
gfx_d3d11_set_sampler_parameters(0, true, G_TX_WRAP, G_TX_WRAP);
|
||||
d3d.current_texture_ids[tile] = saved;
|
||||
|
||||
gfx_d3d11_resize_framebuffer(index, width, height);
|
||||
|
||||
return (int)index;
|
||||
}
|
||||
|
||||
void gfx_d3d11_set_framebuffer(int fb) {
|
||||
d3d.render_target_height = d3d.textures[d3d.framebuffers[fb].texture_id].height;
|
||||
static void gfx_d3d11_update_framebuffer_parameters(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, bool opengl_invert_y, bool render_target, bool has_depth_buffer, bool can_extract_depth) {
|
||||
Framebuffer& fb = d3d.framebuffers[fb_id];
|
||||
TextureData& tex = d3d.textures[fb.texture_id];
|
||||
|
||||
d3d.context->OMSetRenderTargets(1, d3d.framebuffers[fb].render_target_view.GetAddressOf(), d3d.framebuffers[fb].depth_stencil_view.Get());
|
||||
width = max(width, 1U);
|
||||
height = max(height, 1U);
|
||||
while (msaa_level > 1 && d3d.msaa_num_quality_levels[msaa_level - 1] == 0) {
|
||||
--msaa_level;
|
||||
}
|
||||
|
||||
const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
d3d.context->ClearRenderTargetView(d3d.framebuffers[fb].render_target_view.Get(), clearColor);
|
||||
d3d.context->ClearDepthStencilView(d3d.framebuffers[fb].depth_stencil_view.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
|
||||
bool diff = tex.width != width || tex.height != height || fb.msaa_level != msaa_level;
|
||||
|
||||
if (diff || (fb.render_target_view.Get() != nullptr) != render_target) {
|
||||
if (fb_id != 0) {
|
||||
D3D11_TEXTURE2D_DESC texture_desc;
|
||||
texture_desc.Width = width;
|
||||
texture_desc.Height = height;
|
||||
texture_desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
texture_desc.BindFlags = (msaa_level <= 1 ? D3D11_BIND_SHADER_RESOURCE : 0) | (render_target ? D3D11_BIND_RENDER_TARGET : 0);
|
||||
texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
texture_desc.CPUAccessFlags = 0;
|
||||
texture_desc.MiscFlags = 0;
|
||||
texture_desc.ArraySize = 1;
|
||||
texture_desc.MipLevels = 1;
|
||||
texture_desc.SampleDesc.Count = msaa_level;
|
||||
texture_desc.SampleDesc.Quality = 0;
|
||||
|
||||
ThrowIfFailed(d3d.device->CreateTexture2D(&texture_desc, nullptr, tex.texture.ReleaseAndGetAddressOf()));
|
||||
|
||||
if (msaa_level <= 1) {
|
||||
ThrowIfFailed(d3d.device->CreateShaderResourceView(tex.texture.Get(), nullptr, tex.resource_view.ReleaseAndGetAddressOf()));
|
||||
}
|
||||
} else if (diff) {
|
||||
DXGI_SWAP_CHAIN_DESC1 desc1;
|
||||
ThrowIfFailed(d3d.swap_chain->GetDesc1(&desc1));
|
||||
if (desc1.Width != width || desc1.Height != height) {
|
||||
fb.render_target_view.Reset();
|
||||
tex.texture.Reset();
|
||||
ThrowIfFailed(d3d.swap_chain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, desc1.Flags));
|
||||
}
|
||||
ThrowIfFailed(d3d.swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID *)tex.texture.ReleaseAndGetAddressOf()));
|
||||
}
|
||||
if (render_target) {
|
||||
ThrowIfFailed(d3d.device->CreateRenderTargetView(tex.texture.Get(), nullptr, fb.render_target_view.ReleaseAndGetAddressOf()));
|
||||
}
|
||||
|
||||
tex.width = width;
|
||||
tex.height = height;
|
||||
}
|
||||
|
||||
if (has_depth_buffer && (diff || !fb.has_depth_buffer || (fb.depth_stencil_srv.Get() != nullptr) != can_extract_depth)) {
|
||||
fb.depth_stencil_srv.Reset();
|
||||
create_depth_stencil_objects(width, height, msaa_level, fb.depth_stencil_view.ReleaseAndGetAddressOf(), can_extract_depth ? fb.depth_stencil_srv.GetAddressOf() : nullptr);
|
||||
}
|
||||
if (!has_depth_buffer) {
|
||||
fb.depth_stencil_view.Reset();
|
||||
fb.depth_stencil_srv.Reset();
|
||||
}
|
||||
|
||||
fb.has_depth_buffer = has_depth_buffer;
|
||||
fb.msaa_level = msaa_level;
|
||||
}
|
||||
|
||||
void gfx_d3d11_reset_framebuffer(void) {
|
||||
d3d.render_target_height = d3d.current_height;
|
||||
d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), d3d.depth_stencil_view.Get());
|
||||
void gfx_d3d11_start_draw_to_framebuffer(int fb_id, float noise_scale) {
|
||||
Framebuffer& fb = d3d.framebuffers[fb_id];
|
||||
d3d.render_target_height = d3d.textures[fb.texture_id].height;
|
||||
|
||||
d3d.context->OMSetRenderTargets(1, fb.render_target_view.GetAddressOf(), fb.has_depth_buffer ? fb.depth_stencil_view.Get() : nullptr);
|
||||
|
||||
d3d.current_framebuffer = fb_id;
|
||||
|
||||
if (noise_scale != 0.0f) {
|
||||
d3d.per_frame_cb_data.noise_scale = 1.0f / noise_scale;
|
||||
}
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE ms;
|
||||
ZeroMemory(&ms, sizeof(D3D11_MAPPED_SUBRESOURCE));
|
||||
d3d.context->Map(d3d.per_frame_cb.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
|
||||
memcpy(ms.pData, &d3d.per_frame_cb_data, sizeof(PerFrameCB));
|
||||
d3d.context->Unmap(d3d.per_frame_cb.Get(), 0);
|
||||
}
|
||||
|
||||
void gfx_d3d11_clear_framebuffer(void) {
|
||||
Framebuffer& fb = d3d.framebuffers[d3d.current_framebuffer];
|
||||
const float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
d3d.context->ClearRenderTargetView(fb.render_target_view.Get(), clearColor);
|
||||
if (fb.has_depth_buffer) {
|
||||
d3d.context->ClearDepthStencilView(fb.depth_stencil_view.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_d3d11_resolve_msaa_color_buffer(int fb_id_target, int fb_id_source) {
|
||||
Framebuffer& fb_dst = d3d.framebuffers[fb_id_target];
|
||||
Framebuffer& fb_src = d3d.framebuffers[fb_id_source];
|
||||
|
||||
d3d.context->ResolveSubresource(d3d.textures[fb_dst.texture_id].texture.Get(), 0, d3d.textures[fb_src.texture_id].texture.Get(), 0, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
}
|
||||
|
||||
void *gfx_d3d11_get_framebuffer_texture_id(int fb_id) {
|
||||
return (void *)d3d.textures[d3d.framebuffers[fb_id].texture_id].resource_view.Get();
|
||||
}
|
||||
|
||||
void gfx_d3d11_select_texture_fb(int fbID) {
|
||||
|
@ -917,72 +878,126 @@ void gfx_d3d11_select_texture_fb(int fbID) {
|
|||
gfx_d3d11_select_texture(tile, d3d.framebuffers[fbID].texture_id);
|
||||
}
|
||||
|
||||
uint16_t gfx_d3d11_get_pixel_depth(float x, float y) {
|
||||
void gfx_d3d11_set_texture_filter(FilteringMode mode) {
|
||||
d3d.current_filter_mode = mode;
|
||||
gfx_texture_cache_clear();
|
||||
}
|
||||
|
||||
FilteringMode gfx_d3d11_get_texture_filter(void) {
|
||||
return d3d.current_filter_mode;
|
||||
}
|
||||
|
||||
std::map<std::pair<float, float>, uint16_t> gfx_d3d11_get_pixel_depth(int fb_id, const std::set<std::pair<float, float>>& coordinates) {
|
||||
Framebuffer& fb = d3d.framebuffers[fb_id];
|
||||
TextureData& td = d3d.textures[fb.texture_id];
|
||||
|
||||
if (coordinates.size() > d3d.coord_buffer_size) {
|
||||
d3d.coord_buffer.Reset();
|
||||
d3d.coord_buffer_srv.Reset();
|
||||
d3d.depth_value_output_buffer.Reset();
|
||||
d3d.depth_value_output_uav.Reset();
|
||||
d3d.depth_value_output_buffer_copy.Reset();
|
||||
|
||||
D3D11_BUFFER_DESC coord_buf_desc;
|
||||
coord_buf_desc.Usage = D3D11_USAGE_DYNAMIC;
|
||||
coord_buf_desc.ByteWidth = sizeof(Coord) * coordinates.size();
|
||||
coord_buf_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
coord_buf_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
coord_buf_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
|
||||
coord_buf_desc.StructureByteStride = sizeof(Coord);
|
||||
|
||||
ThrowIfFailed(d3d.device->CreateBuffer(&coord_buf_desc, nullptr, d3d.coord_buffer.GetAddressOf()));
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC coord_buf_srv_desc;
|
||||
coord_buf_srv_desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
coord_buf_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
|
||||
coord_buf_srv_desc.Buffer.FirstElement = 0;
|
||||
coord_buf_srv_desc.Buffer.NumElements = coordinates.size();
|
||||
|
||||
ThrowIfFailed(d3d.device->CreateShaderResourceView(d3d.coord_buffer.Get(), &coord_buf_srv_desc, d3d.coord_buffer_srv.GetAddressOf()));
|
||||
|
||||
D3D11_BUFFER_DESC output_buffer_desc;
|
||||
output_buffer_desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
output_buffer_desc.ByteWidth = sizeof(float) * coordinates.size();
|
||||
output_buffer_desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
|
||||
output_buffer_desc.CPUAccessFlags = 0;
|
||||
output_buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
|
||||
output_buffer_desc.StructureByteStride = sizeof(float);
|
||||
ThrowIfFailed(d3d.device->CreateBuffer(&output_buffer_desc, nullptr, d3d.depth_value_output_buffer.GetAddressOf()));
|
||||
|
||||
D3D11_UNORDERED_ACCESS_VIEW_DESC output_buffer_uav_desc;
|
||||
output_buffer_uav_desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
output_buffer_uav_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
|
||||
output_buffer_uav_desc.Buffer.FirstElement = 0;
|
||||
output_buffer_uav_desc.Buffer.NumElements = coordinates.size();
|
||||
output_buffer_uav_desc.Buffer.Flags = 0;
|
||||
ThrowIfFailed(d3d.device->CreateUnorderedAccessView(d3d.depth_value_output_buffer.Get(), &output_buffer_uav_desc, d3d.depth_value_output_uav.GetAddressOf()));
|
||||
|
||||
output_buffer_desc.Usage = D3D11_USAGE_STAGING;
|
||||
output_buffer_desc.BindFlags = 0;
|
||||
output_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
ThrowIfFailed(d3d.device->CreateBuffer(&output_buffer_desc, nullptr, d3d.depth_value_output_buffer_copy.GetAddressOf()));
|
||||
|
||||
d3d.coord_buffer_size = coordinates.size();
|
||||
}
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE ms;
|
||||
|
||||
if (fb.msaa_level > 1 && d3d.compute_shader_msaa.Get() == nullptr) {
|
||||
ThrowIfFailed(d3d.device->CreateComputeShader(d3d.compute_shader_msaa_blob->GetBufferPointer(), d3d.compute_shader_msaa_blob->GetBufferSize(), nullptr, d3d.compute_shader_msaa.GetAddressOf()));
|
||||
}
|
||||
|
||||
// ImGui overwrites these values, so we cannot set them once at init
|
||||
d3d.context->CSSetShader(d3d.compute_shader.Get(), nullptr, 0);
|
||||
d3d.context->CSSetConstantBuffers(0, 1, d3d.coord_buffer.GetAddressOf());
|
||||
d3d.context->CSSetSamplers(0, 1, d3d.depth_value_sampler.GetAddressOf());
|
||||
d3d.context->CSSetShader(fb.msaa_level > 1 ? d3d.compute_shader_msaa.Get() : d3d.compute_shader.Get(), nullptr, 0);
|
||||
d3d.context->CSSetUnorderedAccessViews(0, 1, d3d.depth_value_output_uav.GetAddressOf(), nullptr);
|
||||
|
||||
ThrowIfFailed(d3d.context->Map(d3d.coord_buffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &ms));
|
||||
CoordCB* coord_cb = (CoordCB*)ms.pData;
|
||||
coord_cb->x = x / d3d.current_width;
|
||||
// We invert y because the game assumes OpenGL coordinates (bottom-left corner is origin), while DX's origin is top-left corner
|
||||
coord_cb->y = 1 - y / d3d.current_height;
|
||||
Coord *coord_cb = (Coord *)ms.pData;
|
||||
{
|
||||
size_t i = 0;
|
||||
for (const auto& coord : coordinates) {
|
||||
coord_cb[i].x = coord.first;
|
||||
// We invert y because the gfx_pc assumes OpenGL coordinates (bottom-left corner is origin), while DX's origin is top-left corner
|
||||
coord_cb[i].y = td.height - 1 - coord.second;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
d3d.context->Unmap(d3d.coord_buffer.Get(), 0);
|
||||
|
||||
// The depth stencil texture can only have one mapping at a time, so temporarily unbind from the OM
|
||||
d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), nullptr);
|
||||
d3d.context->CSSetShaderResources(0, 1, d3d.depth_stencil_srv.GetAddressOf());
|
||||
// The depth stencil texture can only have one mapping at a time, so unbind from the OM
|
||||
ID3D11RenderTargetView* null_arr1[1] = { nullptr };
|
||||
d3d.context->OMSetRenderTargets(1, null_arr1, nullptr);
|
||||
|
||||
d3d.context->Dispatch(1, 1, 1);
|
||||
ID3D11ShaderResourceView *srvs[] = { fb.depth_stencil_srv.Get(), d3d.coord_buffer_srv.Get() };
|
||||
d3d.context->CSSetShaderResources(0, 2, srvs);
|
||||
|
||||
d3d.context->Dispatch(coordinates.size(), 1, 1);
|
||||
|
||||
d3d.context->CopyResource(d3d.depth_value_output_buffer_copy.Get(), d3d.depth_value_output_buffer.Get());
|
||||
ThrowIfFailed(d3d.context->Map(d3d.depth_value_output_buffer_copy.Get(), 0, D3D11_MAP_READ, 0, &ms));
|
||||
float res = *(float *)ms.pData;
|
||||
d3d.context->Unmap(d3d.depth_value_output_buffer_copy.Get(), 0);
|
||||
|
||||
ID3D11ShaderResourceView *null_arr[1] = { nullptr };
|
||||
d3d.context->CSSetShaderResources(0, 1, null_arr);
|
||||
d3d.context->OMSetRenderTargets(1, d3d.backbuffer_view.GetAddressOf(), d3d.depth_stencil_view.Get());
|
||||
|
||||
return res * 65532.0f;
|
||||
}
|
||||
|
||||
uint16_t gfx_d3d11_get_pixel_depth_old(float x, float y) {
|
||||
// This approach, compared to using a compute shader, might have better performance on nvidia cards
|
||||
|
||||
if (!d3d.copied_depth_buffer) {
|
||||
d3d.context->CopyResource(d3d.depth_stencil_copy_texture.Get(), d3d.depth_stencil_texture.Get());
|
||||
d3d.copied_depth_buffer = true;
|
||||
}
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mapping_desc;
|
||||
d3d.context->Map(d3d.depth_stencil_copy_texture.Get(), 0, D3D11_MAP_READ, 0, &mapping_desc);
|
||||
float res = 0;
|
||||
if (mapping_desc.pData != nullptr) {
|
||||
float *addr = (float *)mapping_desc.pData;
|
||||
uint32_t num_pixels = mapping_desc.DepthPitch / sizeof(float);
|
||||
uint32_t width = mapping_desc.RowPitch / sizeof(float);
|
||||
uint32_t height = width == 0 ? 0 : num_pixels / width;
|
||||
if (x >= 0 && x < width && y >= 0 && y < height) {
|
||||
res = addr[width * (height - 1 - (int)y) + (int)x];
|
||||
std::map<std::pair<float, float>, uint16_t> res;
|
||||
{
|
||||
size_t i = 0;
|
||||
for (const auto& coord : coordinates) {
|
||||
res.emplace(coord, ((float *)ms.pData)[i++] * 65532.0f);
|
||||
}
|
||||
}
|
||||
d3d.context->Unmap(d3d.depth_stencil_copy_texture.Get(), 0);
|
||||
return res * 65532.0f;
|
||||
d3d.context->Unmap(d3d.depth_value_output_buffer_copy.Get(), 0);
|
||||
|
||||
ID3D11ShaderResourceView *null_arr[2] = { nullptr, nullptr };
|
||||
d3d.context->CSSetShaderResources(0, 2, null_arr);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void* SohImGui::GetTextureByID(int id) {
|
||||
ImTextureID gfx_d3d11_get_texture_by_id(int id) {
|
||||
return d3d.textures[id].resource_view.Get();
|
||||
}
|
||||
|
||||
struct GfxRenderingAPI gfx_direct3d11_api = {
|
||||
gfx_d3d11_z_is_from_0_to_1,
|
||||
gfx_d3d11_get_clip_parameters,
|
||||
gfx_d3d11_unload_shader,
|
||||
gfx_d3d11_load_shader,
|
||||
gfx_d3d11_create_and_load_new_shader,
|
||||
|
@ -993,7 +1008,6 @@ struct GfxRenderingAPI gfx_direct3d11_api = {
|
|||
gfx_d3d11_upload_texture,
|
||||
gfx_d3d11_set_sampler_parameters,
|
||||
gfx_d3d11_set_depth_test_and_mask,
|
||||
gfx_d3d11_get_pixel_depth,
|
||||
gfx_d3d11_set_zmode_decal,
|
||||
gfx_d3d11_set_viewport,
|
||||
gfx_d3d11_set_scissor,
|
||||
|
@ -1005,11 +1019,16 @@ struct GfxRenderingAPI gfx_direct3d11_api = {
|
|||
gfx_d3d11_end_frame,
|
||||
gfx_d3d11_finish_render,
|
||||
gfx_d3d11_create_framebuffer,
|
||||
gfx_d3d11_resize_framebuffer,
|
||||
gfx_d3d11_set_framebuffer,
|
||||
gfx_d3d11_reset_framebuffer,
|
||||
gfx_d3d11_update_framebuffer_parameters,
|
||||
gfx_d3d11_start_draw_to_framebuffer,
|
||||
gfx_d3d11_clear_framebuffer,
|
||||
gfx_d3d11_resolve_msaa_color_buffer,
|
||||
gfx_d3d11_get_pixel_depth,
|
||||
gfx_d3d11_get_framebuffer_texture_id,
|
||||
gfx_d3d11_select_texture_fb,
|
||||
gfx_d3d11_delete_texture
|
||||
gfx_d3d11_delete_texture,
|
||||
gfx_d3d11_set_texture_filter,
|
||||
gfx_d3d11_get_texture_filter
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -134,13 +134,14 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
|
|||
}
|
||||
}
|
||||
}
|
||||
if (cc_features.opt_alpha && cc_features.opt_noise) {
|
||||
append_line(buf, &len, " float4 screenPos : TEXCOORD2;");
|
||||
}
|
||||
if (cc_features.opt_fog) {
|
||||
append_line(buf, &len, " float4 fog : FOG;");
|
||||
num_floats += 4;
|
||||
}
|
||||
if (cc_features.opt_grayscale) {
|
||||
append_line(buf, &len, " float4 grayscale : GRAYSCALE;");
|
||||
num_floats += 4;
|
||||
}
|
||||
for (int i = 0; i < cc_features.num_inputs; i++) {
|
||||
len += sprintf(buf + len, " float%d input%d : INPUT%d;\r\n", cc_features.opt_alpha ? 4 : 3, i + 1, i);
|
||||
num_floats += cc_features.opt_alpha ? 4 : 3;
|
||||
|
@ -163,7 +164,7 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
|
|||
if (cc_features.opt_alpha && cc_features.opt_noise) {
|
||||
append_line(buf, &len, "cbuffer PerFrameCB : register(b0) {");
|
||||
append_line(buf, &len, " uint noise_frame;");
|
||||
append_line(buf, &len, " float2 noise_scale;");
|
||||
append_line(buf, &len, " float noise_scale;");
|
||||
append_line(buf, &len, "}");
|
||||
|
||||
append_line(buf, &len, "float random(in float3 value) {");
|
||||
|
@ -211,15 +212,15 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
|
|||
if (cc_features.opt_fog) {
|
||||
append_str(buf, &len, ", float4 fog : FOG");
|
||||
}
|
||||
if (cc_features.opt_grayscale) {
|
||||
append_str(buf, &len, ", float4 grayscale : GRAYSCALE");
|
||||
}
|
||||
for (int i = 0; i < cc_features.num_inputs; i++) {
|
||||
len += sprintf(buf + len, ", float%d input%d : INPUT%d", cc_features.opt_alpha ? 4 : 3, i + 1, i);
|
||||
}
|
||||
append_line(buf, &len, ") {");
|
||||
append_line(buf, &len, " PSInput result;");
|
||||
append_line(buf, &len, " result.position = position;");
|
||||
if (cc_features.opt_alpha && cc_features.opt_noise) {
|
||||
append_line(buf, &len, " result.screenPos = position;");
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (cc_features.used_textures[i]) {
|
||||
len += sprintf(buf + len, " result.uv%d = uv%d;\r\n", i, i);
|
||||
|
@ -234,6 +235,9 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
|
|||
if (cc_features.opt_fog) {
|
||||
append_line(buf, &len, " result.fog = fog;");
|
||||
}
|
||||
if (cc_features.opt_grayscale) {
|
||||
append_line(buf, &len, " result.grayscale = grayscale;");
|
||||
}
|
||||
for (int i = 0; i < cc_features.num_inputs; i++) {
|
||||
len += sprintf(buf + len, " result.input%d = input%d;\r\n", i + 1, i + 1);
|
||||
}
|
||||
|
@ -244,7 +248,11 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
|
|||
if (include_root_signature) {
|
||||
append_line(buf, &len, "[RootSignature(RS)]");
|
||||
}
|
||||
append_line(buf, &len, "float4 PSMain(PSInput input) : SV_TARGET {");
|
||||
if (cc_features.opt_alpha && cc_features.opt_noise) {
|
||||
append_line(buf, &len, "float4 PSMain(PSInput input, float4 screenSpace : SV_Position) : SV_TARGET {");
|
||||
} else {
|
||||
append_line(buf, &len, "float4 PSMain(PSInput input) : SV_TARGET {");
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (cc_features.used_textures[i]) {
|
||||
len += sprintf(buf + len, " float2 tc%d = input.uv%d;\r\n", i, i);
|
||||
|
@ -300,8 +308,14 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
|
|||
}
|
||||
}
|
||||
|
||||
if (cc_features.opt_grayscale) {
|
||||
append_line(buf, &len, "float intensity = (texel.r + texel.g + texel.b) / 3.0;");
|
||||
append_line(buf, &len, "float3 new_texel = input.grayscale.rgb * intensity;");
|
||||
append_line(buf, &len, "texel.rgb = lerp(texel.rgb, new_texel, input.grayscale.a);");
|
||||
}
|
||||
|
||||
if (cc_features.opt_alpha && cc_features.opt_noise) {
|
||||
append_line(buf, &len, " float2 coords = (input.screenPos.xy / input.screenPos.w) * noise_scale;");
|
||||
append_line(buf, &len, " float2 coords = screenSpace.xy * noise_scale;");
|
||||
append_line(buf, &len, " texel.a *= round(saturate(random(float3(floor(coords), noise_frame)) + texel.a - 0.5));");
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <windows.h>
|
||||
#include <wrl/client.h>
|
||||
#include <dxgi1_3.h>
|
||||
#include <dxgi1_4.h>
|
||||
#include <versionhelpers.h>
|
||||
|
||||
#include <shellscalingapi.h>
|
||||
|
@ -61,6 +62,7 @@ static struct {
|
|||
RECT last_window_rect;
|
||||
bool is_full_screen, last_maximized_state;
|
||||
|
||||
bool dxgi1_4;
|
||||
ComPtr<IDXGIFactory2> factory;
|
||||
ComPtr<IDXGISwapChain1> swap_chain;
|
||||
HANDLE waitable_object;
|
||||
|
@ -197,17 +199,6 @@ static void toggle_borderless_window_full_screen(bool enable, bool call_callback
|
|||
}
|
||||
}
|
||||
|
||||
static void gfx_dxgi_on_resize(void) {
|
||||
if (dxgi.swap_chain.Get() != nullptr) {
|
||||
gfx_get_current_rendering_api()->on_resize();
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 desc1;
|
||||
ThrowIfFailed(dxgi.swap_chain->GetDesc1(&desc1));
|
||||
dxgi.current_width = desc1.Width;
|
||||
dxgi.current_height = desc1.Height;
|
||||
}
|
||||
}
|
||||
|
||||
static void onkeydown(WPARAM w_param, LPARAM l_param) {
|
||||
int key = ((l_param >> 16) & 0x1ff);
|
||||
if (dxgi.on_key_down != nullptr) {
|
||||
|
@ -227,7 +218,8 @@ static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_par
|
|||
SohImGui::Update(event_impl);
|
||||
switch (message) {
|
||||
case WM_SIZE:
|
||||
gfx_dxgi_on_resize();
|
||||
dxgi.current_width = (uint32_t)(l_param & 0xffff);
|
||||
dxgi.current_height = (uint32_t)(l_param >> 16);
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
exit(0);
|
||||
|
@ -573,6 +565,13 @@ void gfx_dxgi_create_factory_and_device(bool debug, int d3d_version, bool (*crea
|
|||
ThrowIfFailed(dxgi.CreateDXGIFactory1(__uuidof(IDXGIFactory2), &dxgi.factory));
|
||||
}
|
||||
|
||||
{
|
||||
ComPtr<IDXGIFactory4> factory4;
|
||||
if (dxgi.factory->QueryInterface(__uuidof(IDXGIFactory4), &factory4) == S_OK) {
|
||||
dxgi.dxgi1_4 = true;
|
||||
}
|
||||
}
|
||||
|
||||
ComPtr<IDXGIAdapter1> adapter;
|
||||
for (UINT i = 0; dxgi.factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND; i++) {
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
|
@ -604,7 +603,9 @@ ComPtr<IDXGISwapChain1> gfx_dxgi_create_swap_chain(IUnknown *device) {
|
|||
swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swap_chain_desc.Scaling = win8 ? DXGI_SCALING_NONE : DXGI_SCALING_STRETCH;
|
||||
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // Apparently this was backported to Win 7 Platform Update
|
||||
swap_chain_desc.SwapEffect = dxgi.dxgi1_4 ?
|
||||
DXGI_SWAP_EFFECT_FLIP_DISCARD : // Introduced in DXGI 1.4 and Windows 10
|
||||
DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // Apparently flip sequential was also backported to Win 7 Platform Update
|
||||
swap_chain_desc.Flags = dxgi_13 ? DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT : 0;
|
||||
swap_chain_desc.SampleDesc.Count = 1;
|
||||
|
||||
|
|
|
@ -150,29 +150,29 @@ static struct {
|
|||
Display *dpy;
|
||||
Window root;
|
||||
Window win;
|
||||
|
||||
|
||||
Atom atom_wm_state;
|
||||
Atom atom_wm_state_fullscreen;
|
||||
Atom atom_wm_delete_window;
|
||||
|
||||
|
||||
bool is_fullscreen;
|
||||
void (*on_fullscreen_changed)(bool is_now_fullscreen);
|
||||
|
||||
|
||||
int keymap[256];
|
||||
bool (*on_key_down)(int scancode);
|
||||
bool (*on_key_up)(int scancode);
|
||||
void (*on_all_keys_up)(void);
|
||||
|
||||
|
||||
PFNGLXGETSYNCVALUESOMLPROC glXGetSyncValuesOML;
|
||||
PFNGLXSWAPBUFFERSMSCOMLPROC glXSwapBuffersMscOML;
|
||||
PFNGLXWAITFORSBCOMLPROC glXWaitForSbcOML;
|
||||
|
||||
|
||||
PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT;
|
||||
PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI;
|
||||
|
||||
|
||||
PFNGLXGETVIDEOSYNCSGIPROC glXGetVideoSyncSGI;
|
||||
PFNGLXWAITVIDEOSYNCSGIPROC glXWaitVideoSyncSGI;
|
||||
|
||||
|
||||
bool has_oml_sync_control;
|
||||
uint64_t ust0;
|
||||
int64_t last_msc;
|
||||
|
@ -181,7 +181,7 @@ static struct {
|
|||
uint64_t last_ust;
|
||||
int64_t target_msc;
|
||||
bool dropped_frame;
|
||||
|
||||
|
||||
bool has_sgi_video_sync;
|
||||
uint64_t last_sync_counter;
|
||||
int64_t this_msc;
|
||||
|
@ -220,7 +220,7 @@ static int64_t glXGetVideoSyncSGI_wrapper(void) {
|
|||
static void init_keymap(void) {
|
||||
XkbDescPtr desc = XkbGetMap(glx.dpy, 0, XkbUseCoreKbd);
|
||||
XkbGetNames(glx.dpy, XkbKeyNamesMask, desc);
|
||||
|
||||
|
||||
for (int i = desc->min_key_code; i <= desc->max_key_code && i < 256; i++) {
|
||||
char name[XkbKeyNameLength + 1];
|
||||
memcpy(name, desc->names->keys[i].name, XkbKeyNameLength);
|
||||
|
@ -232,7 +232,7 @@ static void init_keymap(void) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
XkbFreeNames(desc, XkbKeyNamesMask, True);
|
||||
XkbFreeKeyboard(desc, 0, True);
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ static void gfx_glx_set_fullscreen_state(bool on, bool call_callback) {
|
|||
return;
|
||||
}
|
||||
glx.is_fullscreen = on;
|
||||
|
||||
|
||||
XEvent xev;
|
||||
xev.xany.type = ClientMessage;
|
||||
xev.xclient.message_type = glx.atom_wm_state;
|
||||
|
@ -276,8 +276,8 @@ static void gfx_glx_set_fullscreen_state(bool on, bool call_callback) {
|
|||
xev.xclient.data.l[2] = 0;
|
||||
xev.xclient.data.l[3] = 0;
|
||||
XSendEvent(glx.dpy, glx.root, 0, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
|
||||
gfx_glx_ShowHideMouse(on);
|
||||
|
||||
gfx_glx_show_cursor(on);
|
||||
|
||||
if (glx.on_fullscreen_changed != NULL && call_callback) {
|
||||
glx.on_fullscreen_changed(on);
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ static void gfx_glx_init(const char *game_name, bool start_in_fullscreen) {
|
|||
// which means that glXSwapBuffers should be non-blocking,
|
||||
// if we are sure to wait at least one vsync interval between calls.
|
||||
setenv("__GL_MaxFramesAllowed", "2", true);
|
||||
|
||||
|
||||
glx.dpy = XOpenDisplay(NULL);
|
||||
if (glx.dpy == NULL) {
|
||||
fprintf(stderr, "Cannot connect to X server\n");
|
||||
|
@ -311,7 +311,7 @@ static void gfx_glx_init(const char *game_name, bool start_in_fullscreen) {
|
|||
}
|
||||
int screen = DefaultScreen(glx.dpy);
|
||||
glx.root = RootWindow(glx.dpy, screen);
|
||||
|
||||
|
||||
GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None };
|
||||
XVisualInfo *vi = glXChooseVisual(glx.dpy, 0, att);
|
||||
if (vi == NULL) {
|
||||
|
@ -323,7 +323,7 @@ static void gfx_glx_init(const char *game_name, bool start_in_fullscreen) {
|
|||
swa.colormap = cmap;
|
||||
swa.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | FocusChangeMask;
|
||||
glx.win = XCreateWindow(glx.dpy, glx.root, 0, 0, DESIRED_SCREEN_WIDTH, DESIRED_SCREEN_HEIGHT, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
|
||||
|
||||
|
||||
glx.atom_wm_state = XInternAtom(glx.dpy, "_NET_WM_STATE", False);
|
||||
glx.atom_wm_state_fullscreen = XInternAtom(glx.dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
||||
glx.atom_wm_delete_window = XInternAtom(glx.dpy, "WM_DELETE_WINDOW", False);
|
||||
|
@ -340,11 +340,11 @@ static void gfx_glx_init(const char *game_name, bool start_in_fullscreen) {
|
|||
XStoreName(glx.dpy, glx.win, title);
|
||||
GLXContext glc = glXCreateContext(glx.dpy, vi, NULL, GL_TRUE);
|
||||
glXMakeCurrent(glx.dpy, glx.win, glc);
|
||||
|
||||
|
||||
init_keymap();
|
||||
|
||||
|
||||
const char *extensions = glXQueryExtensionsString(glx.dpy, screen);
|
||||
|
||||
|
||||
if (gfx_glx_check_extension(extensions, "GLX_OML_sync_control")) {
|
||||
glx.glXGetSyncValuesOML = (PFNGLXGETSYNCVALUESOMLPROC)glXGetProcAddressARB((const GLubyte *)"glXGetSyncValuesOML");
|
||||
glx.glXSwapBuffersMscOML = (PFNGLXSWAPBUFFERSMSCOMLPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapBuffersMscOML");
|
||||
|
@ -360,7 +360,7 @@ static void gfx_glx_init(const char *game_name, bool start_in_fullscreen) {
|
|||
glx.glXGetVideoSyncSGI = (PFNGLXGETVIDEOSYNCSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXGetVideoSyncSGI");
|
||||
glx.glXWaitVideoSyncSGI = (PFNGLXWAITVIDEOSYNCSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXWaitVideoSyncSGI");
|
||||
}
|
||||
|
||||
|
||||
int64_t ust, msc, sbc;
|
||||
if (glx.glXGetSyncValuesOML != NULL && glx.glXGetSyncValuesOML(glx.dpy, glx.win, &ust, &msc, &sbc)) {
|
||||
glx.has_oml_sync_control = true;
|
||||
|
@ -439,7 +439,7 @@ static void gfx_glx_handle_events(void) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (xev.type == ClientMessage && xev.xclient.data.l[0] == glx.atom_wm_delete_window) {
|
||||
if (xev.type == ClientMessage && (Atom)xev.xclient.data.l[0] == glx.atom_wm_delete_window) {
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
@ -451,19 +451,19 @@ static bool gfx_glx_start_frame(void) {
|
|||
|
||||
static void gfx_glx_swap_buffers_begin(void) {
|
||||
glx.wanted_ust += FRAME_INTERVAL_US_NUMERATOR; // advance 1/30 seconds on JP/US or 1/25 seconds on EU
|
||||
|
||||
|
||||
if (!glx.has_oml_sync_control && !glx.has_sgi_video_sync) {
|
||||
glFlush();
|
||||
|
||||
|
||||
uint64_t target = glx.wanted_ust / FRAME_INTERVAL_US_DENOMINATOR;
|
||||
uint64_t now;
|
||||
while (target > (now = (uint64_t)get_time() - glx.ust0)) {
|
||||
struct timespec ts = {(target - now) / 1000000, ((target - now) % 1000000) * 1000};
|
||||
struct timespec ts = {(time_t)((target - now) / 1000000), (time_t)(((target - now) % 1000000) * 1000)};
|
||||
if (nanosleep(&ts, NULL) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (target + 2 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR < now) {
|
||||
if (target + 32 * FRAME_INTERVAL_US_NUMERATOR / FRAME_INTERVAL_US_DENOMINATOR >= now) {
|
||||
printf("Dropping frame\n");
|
||||
|
@ -476,10 +476,10 @@ static void gfx_glx_swap_buffers_begin(void) {
|
|||
}
|
||||
glXSwapBuffers(glx.dpy, glx.win);
|
||||
glx.dropped_frame = false;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
double vsyncs_to_wait = (int64_t)(glx.wanted_ust / FRAME_INTERVAL_US_DENOMINATOR - glx.last_ust) / (double)glx.vsync_interval;
|
||||
if (vsyncs_to_wait <= 0) {
|
||||
printf("Dropping frame\n");
|
||||
|
@ -519,17 +519,17 @@ static void gfx_glx_swap_buffers_begin(void) {
|
|||
vsyncs_to_wait = 2;
|
||||
}
|
||||
glx.target_msc = glx.last_msc + vsyncs_to_wait;
|
||||
|
||||
|
||||
if (glx.has_oml_sync_control) {
|
||||
glx.glXSwapBuffersMscOML(glx.dpy, glx.win, glx.target_msc, 0, 0);
|
||||
} else if (glx.has_sgi_video_sync) {
|
||||
glFlush(); // Try to submit pending work. Don't use glFinish since that busy loops on NVIDIA proprietary driver.
|
||||
|
||||
|
||||
//uint64_t counter0;
|
||||
uint64_t counter1, counter2;
|
||||
|
||||
|
||||
//uint64_t before_wait = get_time();
|
||||
|
||||
|
||||
counter1 = glXGetVideoSyncSGI_wrapper();
|
||||
//counter0 = counter1;
|
||||
//int waits = 0;
|
||||
|
@ -537,17 +537,17 @@ static void gfx_glx_swap_buffers_begin(void) {
|
|||
counter1 = glXWaitVideoSyncSGI_wrapper();
|
||||
//++waits;
|
||||
}
|
||||
|
||||
|
||||
//uint64_t before = get_time();
|
||||
glXSwapBuffers(glx.dpy, glx.win);
|
||||
|
||||
|
||||
|
||||
|
||||
counter2 = glXGetVideoSyncSGI_wrapper();
|
||||
while (counter2 < (uint64_t)glx.target_msc) {
|
||||
counter2 = glXWaitVideoSyncSGI_wrapper();
|
||||
}
|
||||
uint64_t after = get_time();
|
||||
|
||||
|
||||
//printf("%.3f %.3f %.3f\t%.3f\t%u %d %.2f %u %d\n", before_wait * 0.000060, before * 0.000060, after * 0.000060, (after - before) * 0.000060, counter0, counter2 - counter0, vsyncs_to_wait, (unsigned int)glx.target_msc, waits);
|
||||
glx.this_msc = counter2;
|
||||
glx.this_ust = after;
|
||||
|
@ -558,7 +558,7 @@ static void gfx_glx_swap_buffers_end(void) {
|
|||
if (glx.dropped_frame || (!glx.has_oml_sync_control && !glx.has_sgi_video_sync)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int64_t ust, msc, sbc;
|
||||
if (glx.has_oml_sync_control) {
|
||||
if (!glx.glXWaitForSbcOML(glx.dpy, glx.win, 0, &ust, &msc, &sbc)) {
|
||||
|
@ -600,6 +600,10 @@ static double gfx_glx_get_time(void) {
|
|||
return 0.0;
|
||||
}
|
||||
|
||||
static void gfx_glx_set_frame_divisor(int divisor) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
struct GfxWindowManagerAPI gfx_glx = {
|
||||
gfx_glx_init,
|
||||
gfx_glx_set_keyboard_callbacks,
|
||||
|
@ -612,7 +616,8 @@ struct GfxWindowManagerAPI gfx_glx = {
|
|||
gfx_glx_start_frame,
|
||||
gfx_glx_swap_buffers_begin,
|
||||
gfx_glx_swap_buffers_end,
|
||||
gfx_glx_get_time
|
||||
gfx_glx_get_time,
|
||||
gfx_glx_set_frame_divisor,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
|
||||
#include "gfx_window_manager_api.h"
|
||||
|
||||
struct GfxWindowManagerAPI gfx_glx;
|
||||
extern struct GfxWindowManagerAPI gfx_glx;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,8 +29,9 @@
|
|||
#include "SDL_opengl.h"
|
||||
#else
|
||||
#include <SDL2/SDL.h>
|
||||
#include <GL/glew.h>
|
||||
#define GL_GLEXT_PROTOTYPES 1
|
||||
#include <SDL2/SDL_opengles2.h>
|
||||
// #include <SDL2/SDL_opengles2.h>
|
||||
#endif
|
||||
|
||||
#include "gfx_cc.h"
|
||||
|
@ -52,19 +53,34 @@ struct ShaderProgram {
|
|||
uint8_t num_attribs;
|
||||
bool used_noise;
|
||||
GLint frame_count_location;
|
||||
GLint window_height_location;
|
||||
GLint noise_scale_location;
|
||||
};
|
||||
|
||||
struct Framebuffer {
|
||||
uint32_t width, height;
|
||||
bool has_depth_buffer;
|
||||
uint32_t msaa_level;
|
||||
bool invert_y;
|
||||
|
||||
GLuint fbo, clrbuf, clrbuf_msaa, rbo;
|
||||
};
|
||||
|
||||
static map<pair<uint64_t, uint32_t>, struct ShaderProgram> shader_program_pool;
|
||||
static GLuint opengl_vbo;
|
||||
|
||||
static uint32_t frame_count;
|
||||
static uint32_t current_height;
|
||||
static map<int, pair<GLuint, GLuint>> fb2tex;
|
||||
static bool current_depth_mask;
|
||||
|
||||
static bool gfx_opengl_z_is_from_0_to_1(void) {
|
||||
return false;
|
||||
static uint32_t frame_count;
|
||||
|
||||
static vector<Framebuffer> framebuffers;
|
||||
static size_t current_framebuffer;
|
||||
static float current_noise_scale;
|
||||
static FilteringMode current_filter_mode = THREE_POINT;
|
||||
|
||||
GLuint pixel_depth_rb, pixel_depth_fb;
|
||||
size_t pixel_depth_rb_size;
|
||||
|
||||
static struct GfxClipParameters gfx_opengl_get_clip_parameters(void) {
|
||||
return { false, framebuffers[current_framebuffer].invert_y };
|
||||
}
|
||||
|
||||
static void gfx_opengl_vertex_array_set_attribs(struct ShaderProgram *prg) {
|
||||
|
@ -81,7 +97,7 @@ static void gfx_opengl_vertex_array_set_attribs(struct ShaderProgram *prg) {
|
|||
static void gfx_opengl_set_uniforms(struct ShaderProgram *prg) {
|
||||
if (prg->used_noise) {
|
||||
glUniform1i(prg->frame_count_location, frame_count);
|
||||
glUniform1i(prg->window_height_location, current_height);
|
||||
glUniform1f(prg->noise_scale_location, current_noise_scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,6 +179,7 @@ static const char *shader_item_to_str(uint32_t item, bool with_alpha, bool only_
|
|||
return "texel.a";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static void append_formula(char *buf, size_t *len, uint8_t c[2][4], bool do_single, bool do_multiply, bool do_mix, bool with_alpha, bool only_alpha, bool opt_alpha) {
|
||||
|
@ -197,7 +214,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
|||
gfx_cc_get_features(shader_id0, shader_id1, &cc_features);
|
||||
|
||||
char vs_buf[1024];
|
||||
char fs_buf[1024];
|
||||
char fs_buf[3000];
|
||||
size_t vs_len = 0;
|
||||
size_t fs_len = 0;
|
||||
size_t num_floats = 4;
|
||||
|
@ -224,6 +241,13 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
|||
append_line(vs_buf, &vs_len, "varying vec4 vFog;");
|
||||
num_floats += 4;
|
||||
}
|
||||
|
||||
if (cc_features.opt_grayscale) {
|
||||
append_line(vs_buf, &vs_len, "attribute vec4 aGrayscaleColor;");
|
||||
append_line(vs_buf, &vs_len, "varying vec4 vGrayscaleColor;");
|
||||
num_floats += 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cc_features.num_inputs; i++) {
|
||||
vs_len += sprintf(vs_buf + vs_len, "attribute vec%d aInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
vs_len += sprintf(vs_buf + vs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
|
@ -243,6 +267,9 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
|||
if (cc_features.opt_fog) {
|
||||
append_line(vs_buf, &vs_len, "vFog = aFog;");
|
||||
}
|
||||
if (cc_features.opt_grayscale) {
|
||||
append_line(vs_buf, &vs_len, "vGrayscaleColor = aGrayscaleColor;");
|
||||
}
|
||||
for (int i = 0; i < cc_features.num_inputs; i++) {
|
||||
vs_len += sprintf(vs_buf + vs_len, "vInput%d = aInput%d;\n", i + 1, i + 1);
|
||||
}
|
||||
|
@ -265,6 +292,9 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
|||
if (cc_features.opt_fog) {
|
||||
append_line(fs_buf, &fs_len, "varying vec4 vFog;");
|
||||
}
|
||||
if (cc_features.opt_grayscale) {
|
||||
append_line(fs_buf, &fs_len, "varying vec4 vGrayscaleColor;");
|
||||
}
|
||||
for (int i = 0; i < cc_features.num_inputs; i++) {
|
||||
fs_len += sprintf(fs_buf + fs_len, "varying vec%d vInput%d;\n", cc_features.opt_alpha ? 4 : 3, i + 1);
|
||||
}
|
||||
|
@ -277,7 +307,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
|||
|
||||
if (cc_features.opt_alpha && cc_features.opt_noise) {
|
||||
append_line(fs_buf, &fs_len, "uniform int frame_count;");
|
||||
append_line(fs_buf, &fs_len, "uniform int window_height;");
|
||||
append_line(fs_buf, &fs_len, "uniform float noise_scale;");
|
||||
|
||||
append_line(fs_buf, &fs_len, "float random(in vec3 value) {");
|
||||
append_line(fs_buf, &fs_len, " float random = dot(sin(value), vec3(12.9898, 78.233, 37.719));");
|
||||
|
@ -285,21 +315,42 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
|||
append_line(fs_buf, &fs_len, "}");
|
||||
}
|
||||
|
||||
if (current_filter_mode == THREE_POINT) {
|
||||
append_line(fs_buf, &fs_len, "#define TEX_OFFSET(off) texture2D(tex, texCoord - (off)/texSize)");
|
||||
append_line(fs_buf, &fs_len, "vec4 filter3point(in sampler2D tex, in vec2 texCoord, in vec2 texSize) {");
|
||||
append_line(fs_buf, &fs_len, " vec2 offset = fract(texCoord*texSize - vec2(0.5));");
|
||||
append_line(fs_buf, &fs_len, " offset -= step(1.0, offset.x + offset.y);");
|
||||
append_line(fs_buf, &fs_len, " vec4 c0 = TEX_OFFSET(offset);");
|
||||
append_line(fs_buf, &fs_len, " vec4 c1 = TEX_OFFSET(vec2(offset.x - sign(offset.x), offset.y));");
|
||||
append_line(fs_buf, &fs_len, " vec4 c2 = TEX_OFFSET(vec2(offset.x, offset.y - sign(offset.y)));");
|
||||
append_line(fs_buf, &fs_len, " return c0 + abs(offset.x)*(c1-c0) + abs(offset.y)*(c2-c0);");
|
||||
append_line(fs_buf, &fs_len, "}");
|
||||
append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {");
|
||||
append_line(fs_buf, &fs_len, " return filter3point(tex, uv, texSize);");
|
||||
append_line(fs_buf, &fs_len, "}");
|
||||
} else {
|
||||
append_line(fs_buf, &fs_len, "vec4 hookTexture2D(in sampler2D tex, in vec2 uv, in vec2 texSize) {");
|
||||
append_line(fs_buf, &fs_len, " return texture2D(tex, uv);");
|
||||
append_line(fs_buf, &fs_len, "}");
|
||||
}
|
||||
|
||||
append_line(fs_buf, &fs_len, "void main() {");
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (cc_features.used_textures[i]) {
|
||||
bool s = cc_features.clamp[i][0], t = cc_features.clamp[i][1];
|
||||
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec2 texSize%d = textureSize(uTex%d, 0);\n", i, i);
|
||||
|
||||
if (!s && !t) {
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = texture2D(uTex%d, vTexCoord%d);\n", i, i, i);
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vTexCoord%d, texSize%d);\n", i, i, i, i);
|
||||
} else {
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec2 texSize%d = textureSize(uTex%d, 0);\n", i, i);
|
||||
if (s && t) {
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = texture2D(uTex%d, clamp(vTexCoord%d, 0.5 / texSize%d, vec2(vTexClampS%d, vTexClampT%d)));\n", i, i, i, i, i, i);
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, clamp(vTexCoord%d, 0.5 / texSize%d, vec2(vTexClampS%d, vTexClampT%d)), texSize%d);\n", i, i, i, i, i, i, i);
|
||||
} else if (s) {
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = texture2D(uTex%d, vec2(clamp(vTexCoord%d.s, 0.5 / texSize%d.s, vTexClampS%d), vTexCoord%d.t));\n", i, i, i, i, i, i);
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vec2(clamp(vTexCoord%d.s, 0.5 / texSize%d.s, vTexClampS%d), vTexCoord%d.t), texSize%d);\n", i, i, i, i, i, i, i);
|
||||
} else {
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = texture2D(uTex%d, vec2(vTexCoord%d.s, clamp(vTexCoord%d.t, 0.5 / texSize%d.t, vTexClampT%d)));\n", i, i, i, i, i, i);
|
||||
fs_len += sprintf(fs_buf + fs_len, "vec4 texVal%d = hookTexture2D(uTex%d, vec2(vTexCoord%d.s, clamp(vTexCoord%d.t, 0.5 / texSize%d.t, vTexClampT%d)), texSize%d);\n", i, i, i, i, i, i, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +389,13 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
|||
}
|
||||
|
||||
if (cc_features.opt_alpha && cc_features.opt_noise) {
|
||||
append_line(fs_buf, &fs_len, "texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * (240.0 / float(window_height))), float(frame_count))) + texel.a, 0.0, 1.0));");
|
||||
append_line(fs_buf, &fs_len, "texel.a *= floor(clamp(random(vec3(floor(gl_FragCoord.xy * noise_scale), float(frame_count))) + texel.a, 0.0, 1.0));");
|
||||
}
|
||||
|
||||
if (cc_features.opt_grayscale) {
|
||||
append_line(fs_buf, &fs_len, "float intensity = (texel.r + texel.g + texel.b) / 3.0;");
|
||||
append_line(fs_buf, &fs_len, "vec3 new_texel = vGrayscaleColor.rgb * intensity;");
|
||||
append_line(fs_buf, &fs_len, "texel.rgb = mix(texel.rgb, new_texel, vGrayscaleColor.a);");
|
||||
}
|
||||
|
||||
if (cc_features.opt_alpha) {
|
||||
|
@ -389,9 +446,9 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
|||
GLint max_length = 0;
|
||||
glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &max_length);
|
||||
char error_log[1024];
|
||||
//fprintf(stderr, "Fragment shader compilation failed\n");
|
||||
fprintf(stderr, "Fragment shader compilation failed\n");
|
||||
glGetShaderInfoLog(fragment_shader, max_length, &max_length, &error_log[0]);
|
||||
//fprintf(stderr, "%s\n", &error_log[0]);
|
||||
fprintf(stderr, "%s\n", &error_log[0]);
|
||||
abort();
|
||||
}
|
||||
|
||||
|
@ -432,6 +489,12 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
|||
++cnt;
|
||||
}
|
||||
|
||||
if (cc_features.opt_grayscale) {
|
||||
prg->attrib_locations[cnt] = glGetAttribLocation(shader_program, "aGrayscaleColor");
|
||||
prg->attrib_sizes[cnt] = 4;
|
||||
++cnt;
|
||||
}
|
||||
|
||||
for (int i = 0; i < cc_features.num_inputs; i++) {
|
||||
char name[16];
|
||||
sprintf(name, "aInput%d", i + 1);
|
||||
|
@ -460,7 +523,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
|
|||
|
||||
if (cc_features.opt_alpha && cc_features.opt_noise) {
|
||||
prg->frame_count_location = glGetUniformLocation(shader_program, "frame_count");
|
||||
prg->window_height_location = glGetUniformLocation(shader_program, "window_height");
|
||||
prg->noise_scale_location = glGetUniformLocation(shader_program, "noise_scale");
|
||||
prg->used_noise = true;
|
||||
} else {
|
||||
prg->used_noise = false;
|
||||
|
@ -496,7 +559,7 @@ static void gfx_opengl_select_texture(int tile, GLuint texture_id) {
|
|||
}
|
||||
|
||||
static void gfx_opengl_upload_texture(const uint8_t *rgba32_buf, uint32_t width, uint32_t height) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf);
|
||||
}
|
||||
|
||||
static uint32_t gfx_cm_to_opengl(uint32_t val) {
|
||||
|
@ -510,12 +573,14 @@ static uint32_t gfx_cm_to_opengl(uint32_t val) {
|
|||
case G_TX_NOMIRROR | G_TX_WRAP:
|
||||
return GL_REPEAT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) {
|
||||
const GLint filter = linear_filter && current_filter_mode == LINEAR ? GL_LINEAR : GL_NEAREST;
|
||||
glActiveTexture(GL_TEXTURE0 + tile);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gfx_cm_to_opengl(cms));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gfx_cm_to_opengl(cmt));
|
||||
}
|
||||
|
@ -543,7 +608,6 @@ static void gfx_opengl_set_zmode_decal(bool zmode_decal) {
|
|||
|
||||
static void gfx_opengl_set_viewport(int x, int y, int width, int height) {
|
||||
glViewport(x, y, width, height);
|
||||
current_height = height;
|
||||
}
|
||||
|
||||
static void gfx_opengl_set_scissor(int x, int y, int width, int height) {
|
||||
|
@ -564,10 +628,6 @@ static void gfx_opengl_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_
|
|||
glDrawArrays(GL_TRIANGLES, 0, 3 * buf_vbo_num_tris);
|
||||
}
|
||||
|
||||
static unsigned int framebuffer;
|
||||
static unsigned int textureColorbuffer;
|
||||
static unsigned int rbo;
|
||||
|
||||
static void gfx_opengl_init(void) {
|
||||
//#if FOR_WINDOWS
|
||||
glewInit();
|
||||
|
@ -576,143 +636,230 @@ static void gfx_opengl_init(void) {
|
|||
glGenBuffers(1, &opengl_vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, opengl_vbo);
|
||||
|
||||
glGenFramebuffers(1, &framebuffer);
|
||||
glGenTextures(1, &textureColorbuffer);
|
||||
glGenRenderbuffers(1, &rbo);
|
||||
|
||||
SohUtils::saveEnvironmentVar("framebuffer", std::to_string(textureColorbuffer));
|
||||
glEnable(GL_DEPTH_CLAMP);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
framebuffers.resize(1); // for the default screen buffer
|
||||
|
||||
glGenRenderbuffers(1, &pixel_depth_rb);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, pixel_depth_rb);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 1, 1);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
glGenFramebuffers(1, &pixel_depth_fb);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, pixel_depth_fb);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, pixel_depth_rb);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
pixel_depth_rb_size = 1;
|
||||
}
|
||||
|
||||
static void gfx_opengl_on_resize(void) {
|
||||
}
|
||||
|
||||
static void gfx_opengl_start_frame(void) {
|
||||
GLsizei framebuffer_width = gfx_current_dimensions.width;
|
||||
GLsizei framebuffer_height = gfx_current_dimensions.height;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
std::shared_ptr<Ship::Window> wnd = Ship::GlobalCtx2::GetInstance()->GetWindow();
|
||||
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, framebuffer_width, framebuffer_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, framebuffer_width, framebuffer_height); // use a single renderbuffer object for both a depth AND stencil buffer.
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); // now actually attach it
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
|
||||
frame_count++;
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glEnable(GL_DEPTH_CLAMP);
|
||||
current_depth_mask = true;
|
||||
}
|
||||
|
||||
static void gfx_opengl_end_frame(void) {
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
GLint last_program;
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
|
||||
glUseProgram(0);
|
||||
SohImGui::Draw();
|
||||
glUseProgram(last_program);
|
||||
glFlush();
|
||||
}
|
||||
|
||||
static void gfx_opengl_finish_render(void) {
|
||||
}
|
||||
|
||||
static int gfx_opengl_create_framebuffer(uint32_t width, uint32_t height) {
|
||||
GLuint textureColorbuffer;
|
||||
|
||||
glGenTextures(1, &textureColorbuffer);
|
||||
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
static int gfx_opengl_create_framebuffer() {
|
||||
GLuint clrbuf;
|
||||
glGenTextures(1, &clrbuf);
|
||||
glBindTexture(GL_TEXTURE_2D, clrbuf);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
GLuint clrbuf_msaa;
|
||||
glGenRenderbuffers(1, &clrbuf_msaa);
|
||||
|
||||
GLuint rbo;
|
||||
glGenRenderbuffers(1, &rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 1, 1);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
GLuint fbo;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
size_t i = framebuffers.size();
|
||||
framebuffers.resize(i + 1);
|
||||
|
||||
fb2tex[fbo] = make_pair(textureColorbuffer, rbo);
|
||||
framebuffers[i].fbo = fbo;
|
||||
framebuffers[i].clrbuf = clrbuf;
|
||||
framebuffers[i].clrbuf_msaa = clrbuf_msaa;
|
||||
framebuffers[i].rbo = rbo;
|
||||
|
||||
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
return fbo;
|
||||
return i;
|
||||
}
|
||||
|
||||
static void gfx_opengl_resize_framebuffer(int fb, uint32_t width, uint32_t height) {
|
||||
glBindTexture(GL_TEXTURE_2D, fb2tex[fb].first);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
static void gfx_opengl_update_framebuffer_parameters(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, bool opengl_invert_y, bool render_target, bool has_depth_buffer, bool can_extract_depth) {
|
||||
Framebuffer& fb = framebuffers[fb_id];
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fb2tex[fb].second);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
width = max(width, 1U);
|
||||
height = max(height, 1U);
|
||||
|
||||
void gfx_opengl_set_framebuffer(int fb)
|
||||
{
|
||||
if (GLEW_ARB_clip_control || GLEW_VERSION_4_5) {
|
||||
// Set origin to upper left corner, to match N64 and DX11
|
||||
// If this function is not supported, the texture will be upside down :(
|
||||
glClipControl(GL_UPPER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb.fbo);
|
||||
|
||||
if (fb_id != 0) {
|
||||
if (fb.width != width || fb.height != height || fb.msaa_level != msaa_level) {
|
||||
if (msaa_level <= 1) {
|
||||
glBindTexture(GL_TEXTURE_2D, fb.clrbuf);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.clrbuf, 0);
|
||||
} else {
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fb.clrbuf_msaa);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_level, GL_RGB8, width, height);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fb.clrbuf_msaa);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_depth_buffer && (fb.width != width || fb.height != height || fb.msaa_level != msaa_level || !fb.has_depth_buffer)) {
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fb.rbo);
|
||||
if (msaa_level <= 1) {
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
||||
} else {
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa_level, GL_DEPTH24_STENCIL8, width, height);
|
||||
}
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
|
||||
if (!fb.has_depth_buffer && has_depth_buffer) {
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.rbo);
|
||||
} else if (fb.has_depth_buffer && !has_depth_buffer) {
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
|
||||
}
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER_EXT, fb);
|
||||
|
||||
fb.width = width;
|
||||
fb.height = height;
|
||||
fb.has_depth_buffer = has_depth_buffer;
|
||||
fb.msaa_level = msaa_level;
|
||||
fb.invert_y = opengl_invert_y;
|
||||
}
|
||||
|
||||
void gfx_opengl_start_draw_to_framebuffer(int fb_id, float noise_scale) {
|
||||
Framebuffer& fb = framebuffers[fb_id];
|
||||
|
||||
if (noise_scale != 0.0f) {
|
||||
current_noise_scale = 1.0f / noise_scale;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb.fbo);
|
||||
|
||||
current_framebuffer = fb_id;
|
||||
}
|
||||
|
||||
void gfx_opengl_clear_framebuffer() {
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glDepthMask(current_depth_mask ? GL_TRUE : GL_FALSE);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void gfx_opengl_reset_framebuffer(void)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER_EXT, framebuffer);
|
||||
if (GLEW_ARB_clip_control || GLEW_VERSION_4_5) {
|
||||
glClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
|
||||
}
|
||||
void gfx_opengl_resolve_msaa_color_buffer(int fb_id_target, int fb_id_source) {
|
||||
Framebuffer& fb_dst = framebuffers[fb_id_target];
|
||||
Framebuffer& fb_src = framebuffers[fb_id_source];
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_dst.fbo);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_src.fbo);
|
||||
glBlitFramebuffer(0, 0, fb_src.width, fb_src.height, 0, 0, fb_dst.width, fb_dst.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_framebuffer);
|
||||
}
|
||||
|
||||
void gfx_opengl_select_texture_fb(int fbID)
|
||||
{
|
||||
void *gfx_opengl_get_framebuffer_texture_id(int fb_id) {
|
||||
return (void *)(uintptr_t)framebuffers[fb_id].clrbuf;
|
||||
}
|
||||
|
||||
void gfx_opengl_select_texture_fb(int fb_id) {
|
||||
//glDisable(GL_DEPTH_TEST);
|
||||
glActiveTexture(GL_TEXTURE0 + 0);
|
||||
glBindTexture(GL_TEXTURE_2D, fb2tex[fbID].first);
|
||||
glBindTexture(GL_TEXTURE_2D, framebuffers[fb_id].clrbuf);
|
||||
}
|
||||
|
||||
static uint16_t gfx_opengl_get_pixel_depth(float x, float y) {
|
||||
float depth;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
return depth * 65532.0f;
|
||||
static std::map<std::pair<float, float>, uint16_t> gfx_opengl_get_pixel_depth(int fb_id, const std::set<std::pair<float, float>>& coordinates) {
|
||||
std::map<std::pair<float, float>, uint16_t> res;
|
||||
|
||||
Framebuffer& fb = framebuffers[fb_id];
|
||||
|
||||
if (coordinates.size() == 1) {
|
||||
uint32_t depth_stencil_value;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb.fbo);
|
||||
int x = coordinates.begin()->first;
|
||||
int y = coordinates.begin()->second;
|
||||
glReadPixels(x, fb.invert_y ? fb.height - y : y, 1, 1, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, &depth_stencil_value);
|
||||
res.emplace(*coordinates.begin(), (depth_stencil_value >> 18) << 2);
|
||||
} else {
|
||||
if (pixel_depth_rb_size < coordinates.size()) {
|
||||
// Resizing a renderbuffer seems broken with Intel's driver, so recreate one instead.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, pixel_depth_fb);
|
||||
glDeleteRenderbuffers(1, &pixel_depth_rb);
|
||||
glGenRenderbuffers(1, &pixel_depth_rb);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, pixel_depth_rb);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, coordinates.size(), 1);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, pixel_depth_rb);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
pixel_depth_rb_size = coordinates.size();
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb.fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, pixel_depth_fb);
|
||||
|
||||
glDisable(GL_SCISSOR_TEST); // needed for the blit operation
|
||||
|
||||
{
|
||||
size_t i = 0;
|
||||
for (const auto& coord : coordinates) {
|
||||
int x = coord.first;
|
||||
int y = coord.second;
|
||||
if (fb.invert_y) {
|
||||
y = fb.height - y;
|
||||
}
|
||||
glBlitFramebuffer(x, y, x + 1, y + 1, i, 0, i + 1, 1, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, pixel_depth_fb);
|
||||
vector<uint32_t> depth_stencil_values(coordinates.size());
|
||||
glReadPixels(0, 0, coordinates.size(), 1, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, depth_stencil_values.data());
|
||||
|
||||
{
|
||||
size_t i = 0;
|
||||
for (const auto& coord : coordinates) {
|
||||
res.emplace(coord, (depth_stencil_values[i++] >> 18) << 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, current_framebuffer);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void gfx_opengl_set_texture_filter(FilteringMode mode) {
|
||||
current_filter_mode = mode;
|
||||
gfx_texture_cache_clear();
|
||||
}
|
||||
|
||||
FilteringMode gfx_opengl_get_texture_filter(void) {
|
||||
return current_filter_mode;
|
||||
}
|
||||
|
||||
struct GfxRenderingAPI gfx_opengl_api = {
|
||||
gfx_opengl_z_is_from_0_to_1,
|
||||
gfx_opengl_get_clip_parameters,
|
||||
gfx_opengl_unload_shader,
|
||||
gfx_opengl_load_shader,
|
||||
gfx_opengl_create_and_load_new_shader,
|
||||
|
@ -723,7 +870,6 @@ struct GfxRenderingAPI gfx_opengl_api = {
|
|||
gfx_opengl_upload_texture,
|
||||
gfx_opengl_set_sampler_parameters,
|
||||
gfx_opengl_set_depth_test_and_mask,
|
||||
gfx_opengl_get_pixel_depth,
|
||||
gfx_opengl_set_zmode_decal,
|
||||
gfx_opengl_set_viewport,
|
||||
gfx_opengl_set_scissor,
|
||||
|
@ -735,11 +881,16 @@ struct GfxRenderingAPI gfx_opengl_api = {
|
|||
gfx_opengl_end_frame,
|
||||
gfx_opengl_finish_render,
|
||||
gfx_opengl_create_framebuffer,
|
||||
gfx_opengl_resize_framebuffer,
|
||||
gfx_opengl_set_framebuffer,
|
||||
gfx_opengl_reset_framebuffer,
|
||||
gfx_opengl_update_framebuffer_parameters,
|
||||
gfx_opengl_start_draw_to_framebuffer,
|
||||
gfx_opengl_clear_framebuffer,
|
||||
gfx_opengl_resolve_msaa_color_buffer,
|
||||
gfx_opengl_get_pixel_depth,
|
||||
gfx_opengl_get_framebuffer_texture_id,
|
||||
gfx_opengl_select_texture_fb,
|
||||
gfx_opengl_delete_texture
|
||||
gfx_opengl_delete_texture,
|
||||
gfx_opengl_set_texture_filter,
|
||||
gfx_opengl_get_texture_filter
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
#ifndef _LANGUAGE_C
|
||||
#define _LANGUAGE_C
|
||||
|
@ -27,10 +29,14 @@
|
|||
|
||||
#include "../../luslog.h"
|
||||
#include "../StrHash64.h"
|
||||
#include "../../SohImGuiImpl.h"
|
||||
#include "../../Environment.h"
|
||||
#include "../../GameVersions.h"
|
||||
#include "../../ResourceMgr.h"
|
||||
|
||||
// OTRTODO: fix header files for these
|
||||
extern "C" {
|
||||
char* ResourceMgr_GetNameByCRC(uint64_t crc, char* alloc);
|
||||
const char* ResourceMgr_GetNameByCRC(uint64_t crc);
|
||||
int32_t* ResourceMgr_LoadMtxByCRC(uint64_t crc);
|
||||
Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc);
|
||||
Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc);
|
||||
|
@ -42,6 +48,8 @@ extern "C" {
|
|||
|
||||
using namespace std;
|
||||
|
||||
#define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1)
|
||||
|
||||
#define SUPPORT_CHECK(x) assert(x)
|
||||
|
||||
// SCALE_M_N: upscale/downscale M-bit integer to N-bit
|
||||
|
@ -71,10 +79,6 @@ struct RGBA {
|
|||
uint8_t r, g, b, a;
|
||||
};
|
||||
|
||||
struct XYWidthHeight {
|
||||
uint16_t x, y, width, height;
|
||||
};
|
||||
|
||||
struct LoadedVertex {
|
||||
float x, y, z, w;
|
||||
float u, v;
|
||||
|
@ -84,7 +88,7 @@ struct LoadedVertex {
|
|||
|
||||
static struct {
|
||||
TextureCacheMap map;
|
||||
list<TextureCacheMap::iterator> lru;
|
||||
list<TextureCacheMapIter> lru;
|
||||
vector<uint32_t> free_texture_ids;
|
||||
} gfx_texture_cache;
|
||||
|
||||
|
@ -130,14 +134,14 @@ static struct RDP {
|
|||
const uint8_t *addr;
|
||||
uint8_t siz;
|
||||
uint32_t width;
|
||||
char* otr_path;
|
||||
const char* otr_path;
|
||||
} texture_to_load;
|
||||
struct {
|
||||
const uint8_t *addr;
|
||||
uint32_t size_bytes;
|
||||
uint32_t full_image_line_size_bytes;
|
||||
uint32_t line_size_bytes;
|
||||
char* otr_path;
|
||||
const char* otr_path;
|
||||
} loaded_texture[2];
|
||||
struct {
|
||||
uint8_t fmt;
|
||||
|
@ -156,9 +160,10 @@ static struct RDP {
|
|||
|
||||
uint32_t other_mode_l, other_mode_h;
|
||||
uint64_t combine_mode;
|
||||
bool grayscale;
|
||||
|
||||
uint8_t prim_lod_fraction;
|
||||
struct RGBA env_color, prim_color, fog_color, fill_color;
|
||||
struct RGBA env_color, prim_color, fog_color, fill_color, grayscale_color;
|
||||
struct XYWidthHeight viewport, scissor;
|
||||
bool viewport_or_scissor_changed;
|
||||
void *z_buf_address;
|
||||
|
@ -174,11 +179,23 @@ static struct RenderingState {
|
|||
TextureCacheNode *textures[2];
|
||||
} rendering_state;
|
||||
|
||||
struct GfxDimensions gfx_current_window_dimensions;
|
||||
struct GfxDimensions gfx_current_dimensions;
|
||||
static struct GfxDimensions gfx_prev_dimensions;
|
||||
struct XYWidthHeight gfx_current_game_window_viewport;
|
||||
|
||||
static bool game_renders_to_framebuffer;
|
||||
static int game_framebuffer;
|
||||
static int game_framebuffer_msaa_resolved;
|
||||
|
||||
uint32_t gfx_msaa_level = 1;
|
||||
|
||||
static bool has_drawn_imgui_menu;
|
||||
|
||||
static bool dropped_frame;
|
||||
|
||||
static const std::unordered_map<Mtx *, MtxF> *current_mtx_replacements;
|
||||
|
||||
static float buf_vbo[MAX_BUFFERED * (32 * 3)]; // 3 vertices in a triangle and 32 floats per vtx
|
||||
static size_t buf_vbo_len;
|
||||
static size_t buf_vbo_num_tris;
|
||||
|
@ -198,7 +215,10 @@ static bool fbActive = 0;
|
|||
static map<int, FBInfo>::iterator active_fb;
|
||||
static map<int, FBInfo> framebuffers;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
static set<pair<float, float>> get_pixel_depth_pending;
|
||||
static map<pair<float, float>, uint16_t> get_pixel_depth_cached;
|
||||
|
||||
#ifdef _WIN32
|
||||
// TODO: Properly implement for MSVC
|
||||
static unsigned long get_time(void)
|
||||
{
|
||||
|
@ -436,15 +456,15 @@ static void gfx_generate_cc(struct ColorCombiner *comb, uint64_t cc_id) {
|
|||
val = SHADER_COMBINED;
|
||||
break;
|
||||
}
|
||||
// fallthrough for G_ACMUX_LOD_FRACTION
|
||||
c[i][1][j] = G_CCMUX_LOD_FRACTION;
|
||||
[[fallthrough]]; // for G_ACMUX_LOD_FRACTION
|
||||
case G_ACMUX_1:
|
||||
//case G_ACMUX_PRIM_LOD_FRAC: same numerical value
|
||||
if (j != 2) {
|
||||
val = SHADER_1;
|
||||
break;
|
||||
}
|
||||
// fallthrough for G_ACMUX_PRIM_LOD_FRAC
|
||||
[[fallthrough]]; // for G_ACMUX_PRIM_LOD_FRAC
|
||||
case G_ACMUX_PRIMITIVE:
|
||||
case G_ACMUX_SHADE:
|
||||
case G_ACMUX_ENVIRONMENT:
|
||||
|
@ -507,18 +527,18 @@ static bool gfx_texture_cache_lookup(int i, int tile) {
|
|||
key = { orig_addr, { }, fmt, siz, palette_index };
|
||||
}
|
||||
|
||||
auto it = gfx_texture_cache.map.find(key);
|
||||
TextureCacheMap::iterator it = gfx_texture_cache.map.find(key);
|
||||
|
||||
if (it != gfx_texture_cache.map.end()) {
|
||||
gfx_rapi->select_texture(i, it->second.texture_id);
|
||||
*n = &*it;
|
||||
gfx_texture_cache.lru.splice(gfx_texture_cache.lru.end(), gfx_texture_cache.lru, *(list<TextureCacheMap::iterator>::iterator*)&it->second.lru_location); // move to back
|
||||
gfx_texture_cache.lru.splice(gfx_texture_cache.lru.end(), gfx_texture_cache.lru, it->second.lru_location); // move to back
|
||||
return true;
|
||||
}
|
||||
|
||||
if (gfx_texture_cache.map.size() >= TEXTURE_CACHE_MAX_SIZE) {
|
||||
// Remove the texture that was least recently used
|
||||
it = gfx_texture_cache.lru.front();
|
||||
it = gfx_texture_cache.lru.front().it;
|
||||
gfx_texture_cache.free_texture_ids.push_back(it->second.texture_id);
|
||||
gfx_texture_cache.map.erase(it);
|
||||
gfx_texture_cache.lru.pop_front();
|
||||
|
@ -535,7 +555,7 @@ static bool gfx_texture_cache_lookup(int i, int tile) {
|
|||
it = gfx_texture_cache.map.insert(make_pair(key, TextureCacheValue())).first;
|
||||
TextureCacheNode* node = &*it;
|
||||
node->second.texture_id = texture_id;
|
||||
*(list<TextureCacheMap::iterator>::iterator*)&node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), it);
|
||||
node->second.lru_location = gfx_texture_cache.lru.insert(gfx_texture_cache.lru.end(), { it });
|
||||
|
||||
gfx_rapi->select_texture(i, texture_id);
|
||||
gfx_rapi->set_sampler_parameters(i, false, 0, 0);
|
||||
|
@ -551,9 +571,9 @@ static void gfx_texture_cache_delete(const uint8_t* orig_addr)
|
|||
bool again = false;
|
||||
for (auto it = gfx_texture_cache.map.begin(bucket); it != gfx_texture_cache.map.end(bucket); ++it) {
|
||||
if (it->first.texture_addr == orig_addr) {
|
||||
gfx_texture_cache.lru.erase(*(list<TextureCacheMap::iterator>::iterator*)&it->second.lru_location);
|
||||
gfx_texture_cache.lru.erase(it->second.lru_location);
|
||||
gfx_texture_cache.free_texture_ids.push_back(it->second.texture_id);
|
||||
gfx_texture_cache.map.erase(it);
|
||||
gfx_texture_cache.map.erase(it->first);
|
||||
again = true;
|
||||
break;
|
||||
}
|
||||
|
@ -815,22 +835,6 @@ static void import_texture(int i, int tile) {
|
|||
uint8_t siz = rdp.texture_tile[tile].siz;
|
||||
uint32_t tmem_index = rdp.texture_tile[tile].tmem_index;
|
||||
|
||||
// OTRTODO: Move it to a function to be faster
|
||||
// ModInternal::bindHook(LOOKUP_TEXTURE);
|
||||
// ModInternal::initBindHook(8,
|
||||
// HOOK_PARAMETER("gfx_api", gfx_get_current_rendering_api()),
|
||||
// HOOK_PARAMETER("path", rdp.loaded_texture[tmem_index].otr_path),
|
||||
// HOOK_PARAMETER("node", &rendering_state.textures[i]),
|
||||
// HOOK_PARAMETER("fmt", &fmt),
|
||||
// HOOK_PARAMETER("siz", &siz),
|
||||
// HOOK_PARAMETER("tile", &i),
|
||||
// HOOK_PARAMETER("palette", &rdp.texture_tile[tile].palette),
|
||||
// HOOK_PARAMETER("addr", const_cast<uint8_t*>(rdp.loaded_texture[tmem_index].addr))
|
||||
// );
|
||||
//
|
||||
// if (ModInternal::callBindHook(0))
|
||||
// return;
|
||||
|
||||
if (gfx_texture_cache_lookup(i, tile))
|
||||
{
|
||||
return;
|
||||
|
@ -916,20 +920,31 @@ static void gfx_matrix_mul(float res[4][4], const float a[4][4], const float b[4
|
|||
|
||||
static void gfx_sp_matrix(uint8_t parameters, const int32_t *addr) {
|
||||
float matrix[4][4];
|
||||
#ifndef GBI_FLOATS
|
||||
// Original GBI where fixed point matrices are used
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j += 2) {
|
||||
int32_t int_part = addr[i * 2 + j / 2];
|
||||
uint32_t frac_part = addr[8 + i * 2 + j / 2];
|
||||
matrix[i][j] = (int32_t)((int_part & 0xffff0000) | (frac_part >> 16)) / 65536.0f;
|
||||
matrix[i][j + 1] = (int32_t)((int_part << 16) | (frac_part & 0xffff)) / 65536.0f;
|
||||
|
||||
if (auto it = current_mtx_replacements->find((Mtx *)addr); it != current_mtx_replacements->end()) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
float v = it->second.mf[i][j];
|
||||
int as_int = (int)(v * 65536.0f);
|
||||
matrix[i][j] = as_int * (1.0f / 65536.0f);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#ifndef GBI_FLOATS
|
||||
// Original GBI where fixed point matrices are used
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j += 2) {
|
||||
int32_t int_part = addr[i * 2 + j / 2];
|
||||
uint32_t frac_part = addr[8 + i * 2 + j / 2];
|
||||
matrix[i][j] = (int32_t)((int_part & 0xffff0000) | (frac_part >> 16)) / 65536.0f;
|
||||
matrix[i][j + 1] = (int32_t)((int_part << 16) | (frac_part & 0xffff)) / 65536.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
// For a modified GBI where fixed point values are replaced with floats
|
||||
memcpy(matrix, addr, sizeof(matrix));
|
||||
// For a modified GBI where fixed point values are replaced with floats
|
||||
memcpy(matrix, addr, sizeof(matrix));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (parameters & G_MTX_PROJECTION) {
|
||||
if (parameters & G_MTX_LOAD) {
|
||||
|
@ -1210,7 +1225,6 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
|||
|
||||
uint64_t cc_id = rdp.combine_mode;
|
||||
|
||||
//bool use_alpha = (rdp.other_mode_l & (3 << 18)) == G_BL_1MA || (rdp.other_mode_l & (3 << 16)) == G_BL_1MA;
|
||||
bool use_alpha = (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20) && (rdp.other_mode_l & (3 << 16)) == (G_BL_1MA << 16);
|
||||
bool use_fog = (rdp.other_mode_l >> 30) == G_BL_CLR_FOG;
|
||||
bool texture_edge = (rdp.other_mode_l & CVG_X_ALPHA) == CVG_X_ALPHA;
|
||||
|
@ -1218,6 +1232,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
|||
bool use_2cyc = (rdp.other_mode_h & (3U << G_MDSFT_CYCLETYPE)) == G_CYC_2CYCLE;
|
||||
bool alpha_threshold = (rdp.other_mode_l & (3U << G_MDSFT_ALPHACOMPARE)) == G_AC_THRESHOLD;
|
||||
bool invisible = (rdp.other_mode_l & (3 << 24)) == (G_BL_0 << 24) && (rdp.other_mode_l & (3 << 20)) == (G_BL_CLR_MEM << 20);
|
||||
bool use_grayscale = rdp.grayscale;
|
||||
|
||||
if (texture_edge) {
|
||||
use_alpha = true;
|
||||
|
@ -1230,12 +1245,13 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
|||
if (use_2cyc) cc_id |= (uint64_t)SHADER_OPT_2CYC << CC_SHADER_OPT_POS;
|
||||
if (alpha_threshold) cc_id |= (uint64_t)SHADER_OPT_ALPHA_THRESHOLD << CC_SHADER_OPT_POS;
|
||||
if (invisible) cc_id |= (uint64_t)SHADER_OPT_INVISIBLE << CC_SHADER_OPT_POS;
|
||||
if (use_grayscale) cc_id |= (uint64_t)SHADER_OPT_GRAYSCALE << CC_SHADER_OPT_POS;
|
||||
|
||||
if (!use_alpha) {
|
||||
cc_id &= ~((0xfff << 16) | ((uint64_t)0xfff << 44));
|
||||
}
|
||||
|
||||
struct ColorCombiner* comb = gfx_lookup_or_create_color_combiner(cc_id);
|
||||
ColorCombiner* comb = gfx_lookup_or_create_color_combiner(cc_id);
|
||||
|
||||
uint32_t tm = 0;
|
||||
uint32_t tex_width[2], tex_height[2], tex_width2[2], tex_height2[2];
|
||||
|
@ -1326,11 +1342,11 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
|||
|
||||
gfx_rapi->shader_get_info(prg, &num_inputs, used_textures);
|
||||
|
||||
bool z_is_from_0_to_1 = gfx_rapi->z_is_from_0_to_1();
|
||||
struct GfxClipParameters clip_parameters = gfx_rapi->get_clip_parameters();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float z = v_arr[i]->z, w = v_arr[i]->w;
|
||||
if (z_is_from_0_to_1) {
|
||||
if (clip_parameters.z_is_from_0_to_1) {
|
||||
z = (z + w) / 2.0f;
|
||||
}
|
||||
|
||||
|
@ -1340,7 +1356,7 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
|||
}
|
||||
|
||||
buf_vbo[buf_vbo_len++] = v_arr[i]->x;
|
||||
buf_vbo[buf_vbo_len++] = v_arr[i]->y;
|
||||
buf_vbo[buf_vbo_len++] = clip_parameters.invert_y ? -v_arr[i]->y : v_arr[i]->y;
|
||||
buf_vbo[buf_vbo_len++] = z;
|
||||
buf_vbo[buf_vbo_len++] = w;
|
||||
|
||||
|
@ -1397,6 +1413,13 @@ static void gfx_sp_tri1(uint8_t vtx1_idx, uint8_t vtx2_idx, uint8_t vtx3_idx, bo
|
|||
buf_vbo[buf_vbo_len++] = v_arr[i]->color.a / 255.0f; // fog factor (not alpha)
|
||||
}
|
||||
|
||||
if (use_grayscale) {
|
||||
buf_vbo[buf_vbo_len++] = rdp.grayscale_color.r / 255.0f;
|
||||
buf_vbo[buf_vbo_len++] = rdp.grayscale_color.g / 255.0f;
|
||||
buf_vbo[buf_vbo_len++] = rdp.grayscale_color.b / 255.0f;
|
||||
buf_vbo[buf_vbo_len++] = rdp.grayscale_color.a / 255.0f; // lerp interpolation factor (not alpha)
|
||||
}
|
||||
|
||||
for (int j = 0; j < num_inputs; j++) {
|
||||
struct RGBA* color = 0;
|
||||
struct RGBA tmp;
|
||||
|
@ -1491,6 +1514,27 @@ static void gfx_sp_geometry_mode(uint32_t clear, uint32_t set) {
|
|||
rsp.geometry_mode |= set;
|
||||
}
|
||||
|
||||
static void gfx_adjust_viewport_or_scissor(XYWidthHeight *area) {
|
||||
if (!fbActive) {
|
||||
area->width *= RATIO_X;
|
||||
area->height *= RATIO_Y;
|
||||
area->x *= RATIO_X;
|
||||
area->y = SCREEN_HEIGHT - area->y;
|
||||
area->y *= RATIO_Y;
|
||||
|
||||
if (!game_renders_to_framebuffer || (gfx_msaa_level > 1 && gfx_current_dimensions.width == gfx_current_game_window_viewport.width && gfx_current_dimensions.height == gfx_current_game_window_viewport.height)) {
|
||||
area->x += gfx_current_game_window_viewport.x;
|
||||
area->y += gfx_current_window_dimensions.height - (gfx_current_game_window_viewport.y + gfx_current_game_window_viewport.height);
|
||||
}
|
||||
} else {
|
||||
area->width *= RATIO_Y;
|
||||
area->height *= RATIO_Y;
|
||||
area->x *= RATIO_Y;
|
||||
area->y = active_fb->second.orig_height - area->y;
|
||||
area->y *= RATIO_Y;
|
||||
}
|
||||
}
|
||||
|
||||
static void gfx_calc_and_set_viewport(const Vp_t *viewport) {
|
||||
// 2 bits fraction
|
||||
float width = 2.0f * viewport->vscale[0] / 4.0f;
|
||||
|
@ -1498,25 +1542,13 @@ static void gfx_calc_and_set_viewport(const Vp_t *viewport) {
|
|||
float x = (viewport->vtrans[0] / 4.0f) - width / 2.0f;
|
||||
float y = ((viewport->vtrans[1] / 4.0f) + height / 2.0f);
|
||||
|
||||
if (!fbActive) {
|
||||
width *= RATIO_X;
|
||||
height *= RATIO_Y;
|
||||
x *= RATIO_X;
|
||||
y = SCREEN_HEIGHT - y;
|
||||
y *= RATIO_Y;
|
||||
} else {
|
||||
width *= RATIO_Y;
|
||||
height *= RATIO_Y;
|
||||
x *= RATIO_Y;
|
||||
y = active_fb->second.orig_height - y;
|
||||
y *= RATIO_Y;
|
||||
}
|
||||
|
||||
rdp.viewport.x = x;
|
||||
rdp.viewport.y = y;
|
||||
rdp.viewport.width = width;
|
||||
rdp.viewport.height = height;
|
||||
|
||||
gfx_adjust_viewport_or_scissor(&rdp.viewport);
|
||||
|
||||
rdp.viewport_or_scissor_changed = true;
|
||||
}
|
||||
|
||||
|
@ -1585,11 +1617,6 @@ static void gfx_sp_texture(uint16_t sc, uint16_t tc, uint8_t level, uint8_t tile
|
|||
rdp.textures_changed[1] = true;
|
||||
}
|
||||
|
||||
if (tile > 8)
|
||||
{
|
||||
int bp = 0;
|
||||
}
|
||||
|
||||
rdp.first_tile_index = tile;
|
||||
}
|
||||
|
||||
|
@ -1599,33 +1626,21 @@ static void gfx_dp_set_scissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32
|
|||
float width = (lrx - ulx) / 4.0f;
|
||||
float height = (lry - uly) / 4.0f;
|
||||
|
||||
if (!fbActive) {
|
||||
x *= RATIO_X;
|
||||
y = SCREEN_HEIGHT - y;
|
||||
y *= RATIO_Y;
|
||||
width *= RATIO_X;
|
||||
height *= RATIO_Y;
|
||||
} else {
|
||||
width *= RATIO_Y;
|
||||
height *= RATIO_Y;
|
||||
x *= RATIO_Y;
|
||||
y = active_fb->second.orig_height - y;
|
||||
y *= RATIO_Y;
|
||||
}
|
||||
|
||||
rdp.scissor.x = x;
|
||||
rdp.scissor.y = y;
|
||||
rdp.scissor.width = width;
|
||||
rdp.scissor.height = height;
|
||||
|
||||
gfx_adjust_viewport_or_scissor(&rdp.scissor);
|
||||
|
||||
rdp.viewport_or_scissor_changed = true;
|
||||
}
|
||||
|
||||
static void gfx_dp_set_texture_image(uint32_t format, uint32_t size, uint32_t width, const void* addr, char* otr_path) {
|
||||
static void gfx_dp_set_texture_image(uint32_t format, uint32_t size, uint32_t width, const void* addr, const char* otr_path) {
|
||||
rdp.texture_to_load.addr = (const uint8_t*)addr;
|
||||
rdp.texture_to_load.siz = size;
|
||||
rdp.texture_to_load.width = width;
|
||||
if ( otr_path != nullptr && !strncmp(otr_path, "__OTR__", 7)) otr_path = otr_path + 7;
|
||||
if (otr_path != nullptr && !strncmp(otr_path, "__OTR__", 7)) otr_path = otr_path + 7;
|
||||
rdp.texture_to_load.otr_path = otr_path;
|
||||
}
|
||||
|
||||
|
@ -1697,7 +1712,7 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t
|
|||
SUPPORT_CHECK(ult == 0);
|
||||
|
||||
// The lrs field rather seems to be number of pixels to load
|
||||
uint32_t word_size_shift;
|
||||
uint32_t word_size_shift = 0;
|
||||
switch (rdp.texture_to_load.siz) {
|
||||
case G_IM_SIZ_4b:
|
||||
word_size_shift = 0; // Or -1? It's unused in SM64 anyway.
|
||||
|
@ -1725,7 +1740,7 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t
|
|||
static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t lrt) {
|
||||
SUPPORT_CHECK(tile == G_TX_LOADTILE);
|
||||
|
||||
uint32_t word_size_shift;
|
||||
uint32_t word_size_shift = 0;
|
||||
switch (rdp.texture_to_load.siz) {
|
||||
case G_IM_SIZ_4b:
|
||||
word_size_shift = 0;
|
||||
|
@ -1805,6 +1820,13 @@ static inline uint32_t alpha_comb(uint32_t a, uint32_t b, uint32_t c, uint32_t d
|
|||
return (a & 7) | ((b & 7) << 3) | ((c & 7) << 6) | ((d & 7) << 9);
|
||||
}
|
||||
|
||||
static void gfx_dp_set_grayscale_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
rdp.grayscale_color.r = r;
|
||||
rdp.grayscale_color.g = g;
|
||||
rdp.grayscale_color.b = b;
|
||||
rdp.grayscale_color.a = a;
|
||||
}
|
||||
|
||||
static void gfx_dp_set_env_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
rdp.env_color.r = r;
|
||||
rdp.env_color.g = g;
|
||||
|
@ -1887,10 +1909,12 @@ static void gfx_draw_rectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lr
|
|||
ur->w = 1.0f;
|
||||
|
||||
// The coordinates for texture rectangle shall bypass the viewport setting
|
||||
struct XYWidthHeight default_viewport = { 0, 0, gfx_current_dimensions.width, gfx_current_dimensions.height };
|
||||
struct XYWidthHeight default_viewport = { 0, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT };
|
||||
struct XYWidthHeight viewport_saved = rdp.viewport;
|
||||
uint32_t geometry_mode_saved = rsp.geometry_mode;
|
||||
|
||||
gfx_adjust_viewport_or_scissor(&default_viewport);
|
||||
|
||||
rdp.viewport = default_viewport;
|
||||
rdp.viewport_or_scissor_changed = true;
|
||||
rsp.geometry_mode = 0;
|
||||
|
@ -2056,12 +2080,11 @@ static void gfx_s2dex_bg_copy(const uObjBg* bg) {
|
|||
static inline void* seg_addr(uintptr_t w1)
|
||||
{
|
||||
// Segmented?
|
||||
if (w1 >= 0xF0000000)
|
||||
if (w1 & 1)
|
||||
{
|
||||
uint32_t segNum = (w1 >> 24);
|
||||
segNum -= 0xF0;
|
||||
|
||||
uint32_t offset = w1 & 0x00FFFFFF;
|
||||
uint32_t offset = w1 & 0x00FFFFFE;
|
||||
//offset = 0; // Cursed Malon bug
|
||||
|
||||
if (segmentPointers[segNum] != 0)
|
||||
|
@ -2078,7 +2101,7 @@ static inline void* seg_addr(uintptr_t w1)
|
|||
#define C0(pos, width) ((cmd->words.w0 >> (pos)) & ((1U << width) - 1))
|
||||
#define C1(pos, width) ((cmd->words.w1 >> (pos)) & ((1U << width) - 1))
|
||||
|
||||
int dListBP;
|
||||
unsigned int dListBP;
|
||||
int matrixBP;
|
||||
uintptr_t clearMtx;
|
||||
|
||||
|
@ -2091,7 +2114,7 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
//puts("dl");
|
||||
int dummy = 0;
|
||||
char dlName[128];
|
||||
char fileName[128];
|
||||
const char* fileName;
|
||||
|
||||
Gfx* dListStart = cmd;
|
||||
uint64_t ourHash = -1;
|
||||
|
@ -2145,8 +2168,16 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
uintptr_t mtxAddr = cmd->words.w1;
|
||||
|
||||
// OTRTODO: Temp way of dealing with gMtxClear. Need something more elegant in the future...
|
||||
if (mtxAddr == 0xF012DB20 || mtxAddr == 0xF012DB40)
|
||||
mtxAddr = clearMtx;
|
||||
uint32_t gameVersion = Ship::GlobalCtx2::GetInstance()->GetResourceManager()->GetGameVersion();
|
||||
if (gameVersion == OOT_PAL_GC) {
|
||||
if (mtxAddr == SEG_ADDR(0, 0x0FBC20)) {
|
||||
mtxAddr = clearMtx;
|
||||
}
|
||||
} else {
|
||||
if (mtxAddr == SEG_ADDR(0, 0x12DB20) || mtxAddr == SEG_ADDR(0, 0x12DB40)) {
|
||||
mtxAddr = clearMtx;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef F3DEX_GBI_2
|
||||
gfx_sp_matrix(C0(0, 8) ^ G_MTX_PUSH, (const int32_t *) seg_addr(mtxAddr));
|
||||
|
@ -2246,7 +2277,7 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
|
||||
cmd--;
|
||||
|
||||
if (ourHash != -1)
|
||||
if (ourHash != (uint64_t)-1)
|
||||
ResourceMgr_RegisterResourcePatch(ourHash, cmd - dListStart, cmd->words.w1);
|
||||
|
||||
cmd->words.w1 = (uintptr_t)vtx;
|
||||
|
@ -2364,7 +2395,7 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
case G_QUAD:
|
||||
{
|
||||
int bp = 0;
|
||||
// fallthrough
|
||||
[[fallthrough]];
|
||||
}
|
||||
#endif
|
||||
#if defined(F3DEX_GBI) || defined(F3DLP_GBI)
|
||||
|
@ -2394,11 +2425,11 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
|
||||
char* imgData = (char*)i;
|
||||
|
||||
if ((i & 0xF0000000) != 0xF0000000)
|
||||
if ((i & 1) != 1)
|
||||
if (ResourceMgr_OTRSigCheck(imgData) == 1)
|
||||
i = (uintptr_t)ResourceMgr_LoadTexByName(imgData);
|
||||
|
||||
gfx_dp_set_texture_image(C0(21, 3), C0(19, 2), C0(0, 10), (void*) i, imgData);
|
||||
gfx_dp_set_texture_image(C0(21, 3), C0(19, 2), C0(0, 10), (void*) i, imgData);
|
||||
break;
|
||||
}
|
||||
case G_SETTIMG_OTR:
|
||||
|
@ -2406,9 +2437,7 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
uintptr_t addr = cmd->words.w1;
|
||||
cmd++;
|
||||
uint64_t hash = ((uint64_t)cmd->words.w0 << 32) + (uint64_t)cmd->words.w1;
|
||||
ResourceMgr_GetNameByCRC(hash, fileName);
|
||||
|
||||
|
||||
fileName = ResourceMgr_GetNameByCRC(hash);
|
||||
#if _DEBUG && 0
|
||||
char* tex = ResourceMgr_LoadTexByCRC(hash);
|
||||
ResourceMgr_GetNameByCRC(hash, fileName);
|
||||
|
@ -2417,7 +2446,7 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
char* tex = NULL;
|
||||
#endif
|
||||
|
||||
if (addr != NULL)
|
||||
if (addr != 0)
|
||||
{
|
||||
tex = (char*)addr;
|
||||
}
|
||||
|
@ -2431,7 +2460,7 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
uintptr_t oldData = cmd->words.w1;
|
||||
cmd->words.w1 = (uintptr_t)tex;
|
||||
|
||||
if (ourHash != -1)
|
||||
if (ourHash != (uint64_t)-1)
|
||||
ResourceMgr_RegisterResourcePatch(ourHash, cmd - dListStart, oldData);
|
||||
|
||||
cmd++;
|
||||
|
@ -2449,24 +2478,24 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
gfx_dp_set_texture_image(fmt, size, width, tex, fileName);
|
||||
|
||||
cmd++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case G_SETFB:
|
||||
{
|
||||
gfx_flush();
|
||||
fbActive = 1;
|
||||
active_fb = framebuffers.find(cmd->words.w1);
|
||||
gfx_rapi->set_framebuffer(active_fb->first);
|
||||
}
|
||||
gfx_rapi->start_draw_to_framebuffer(active_fb->first, (float)active_fb->second.applied_height / active_fb->second.orig_height);
|
||||
gfx_rapi->clear_framebuffer();
|
||||
break;
|
||||
}
|
||||
case G_RESETFB:
|
||||
{
|
||||
gfx_flush();
|
||||
fbActive = 0;
|
||||
gfx_rapi->reset_framebuffer();
|
||||
gfx_rapi->start_draw_to_framebuffer(game_renders_to_framebuffer ? game_framebuffer : 0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case G_SETTIMG_FB:
|
||||
{
|
||||
gfx_flush();
|
||||
|
@ -2476,8 +2505,13 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
|
||||
//if (texPtr != NULL)
|
||||
//gfx_dp_set_texture_image(C0(21, 3), C0(19, 2), C0(0, 10), texPtr);
|
||||
break;
|
||||
}
|
||||
case G_SETGRAYSCALE:
|
||||
{
|
||||
rdp.grayscale = cmd->words.w1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case G_LOADBLOCK:
|
||||
gfx_dp_load_block(C1(24, 3), C0(12, 12), C0(0, 12), C1(12, 12), C1(0, 12));
|
||||
break;
|
||||
|
@ -2505,6 +2539,9 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
case G_SETFILLCOLOR:
|
||||
gfx_dp_set_fill_color(cmd->words.w1);
|
||||
break;
|
||||
case G_SETINTENSITY:
|
||||
gfx_dp_set_grayscale_color(C1(24, 8), C1(16, 8), C1(8, 8), C1(0, 8));
|
||||
break;
|
||||
case G_SETCOMBINE:
|
||||
gfx_dp_set_combine_mode(
|
||||
color_comb(C0(20, 4), C1(28, 4), C0(15, 5), C1(15, 3)),
|
||||
|
@ -2547,7 +2584,7 @@ static void gfx_run_dl(Gfx* cmd) {
|
|||
gfx_dp_texture_rectangle(ulx, uly, lrx, lry, tile, uls, ult, dsdx, dtdy, opcode == G_TEXRECTFLIP);
|
||||
break;
|
||||
}
|
||||
case G_TEXRECT_WIDE:
|
||||
case G_TEXRECT_WIDE:
|
||||
{
|
||||
int32_t lrx, lry, tile, ulx, uly;
|
||||
uint32_t uls, ult, dsdx, dtdy;
|
||||
|
@ -2630,12 +2667,15 @@ void gfx_init(struct GfxWindowManagerAPI *wapi, struct GfxRenderingAPI *rapi, co
|
|||
gfx_rapi = rapi;
|
||||
gfx_wapi->init(game_name, start_in_fullscreen);
|
||||
gfx_rapi->init();
|
||||
gfx_rapi->update_framebuffer_parameters(0, SCREEN_WIDTH, SCREEN_HEIGHT, 1, false, true, true, true);
|
||||
gfx_current_dimensions.internal_mul = 1;
|
||||
gfx_current_dimensions.width = SCREEN_WIDTH;
|
||||
gfx_current_dimensions.height = SCREEN_HEIGHT;
|
||||
game_framebuffer = gfx_rapi->create_framebuffer();
|
||||
game_framebuffer_msaa_resolved = gfx_rapi->create_framebuffer();
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
segmentPointers[i] = NULL;
|
||||
segmentPointers[i] = 0;
|
||||
|
||||
// Used in the 120 star TAS
|
||||
static uint32_t precomp_shaders[] = {
|
||||
|
@ -2681,7 +2721,9 @@ struct GfxRenderingAPI *gfx_get_current_rendering_api(void) {
|
|||
|
||||
void gfx_start_frame(void) {
|
||||
gfx_wapi->handle_events();
|
||||
// gfx_wapi->get_dimensions(&gfx_current_dimensions.width, &gfx_current_dimensions.height);
|
||||
gfx_wapi->get_dimensions(&gfx_current_window_dimensions.width, &gfx_current_window_dimensions.height);
|
||||
SohImGui::DrawMainMenuAndCalculateGameSize();
|
||||
has_drawn_imgui_menu = true;
|
||||
if (gfx_current_dimensions.height == 0) {
|
||||
// Avoid division by zero
|
||||
gfx_current_dimensions.height = 1;
|
||||
|
@ -2693,7 +2735,7 @@ void gfx_start_frame(void) {
|
|||
uint32_t width = fb.second.orig_width, height = fb.second.orig_height;
|
||||
gfx_adjust_width_height_for_scale(width, height);
|
||||
if (width != fb.second.applied_width || height != fb.second.applied_height) {
|
||||
gfx_rapi->resize_framebuffer(fb.first, width, height);
|
||||
gfx_rapi->update_framebuffer_parameters(fb.first, width, height, 1, true, true, true, true);
|
||||
fb.second.applied_width = width;
|
||||
fb.second.applied_height = height;
|
||||
}
|
||||
|
@ -2701,28 +2743,81 @@ void gfx_start_frame(void) {
|
|||
}
|
||||
gfx_prev_dimensions = gfx_current_dimensions;
|
||||
|
||||
bool different_size = gfx_current_dimensions.width != gfx_current_game_window_viewport.width || gfx_current_dimensions.height != gfx_current_game_window_viewport.height;
|
||||
if (different_size || gfx_msaa_level > 1) {
|
||||
game_renders_to_framebuffer = true;
|
||||
if (different_size) {
|
||||
gfx_rapi->update_framebuffer_parameters(game_framebuffer, gfx_current_dimensions.width, gfx_current_dimensions.height, gfx_msaa_level, true, true, true, true);
|
||||
} else {
|
||||
// MSAA framebuffer needs to be resolved to an equally sized target when complete, which must therefore match the window size
|
||||
gfx_rapi->update_framebuffer_parameters(game_framebuffer, gfx_current_window_dimensions.width, gfx_current_window_dimensions.height, gfx_msaa_level, false, true, true, true);
|
||||
}
|
||||
if (gfx_msaa_level > 1 && different_size) {
|
||||
gfx_rapi->update_framebuffer_parameters(game_framebuffer_msaa_resolved, gfx_current_dimensions.width, gfx_current_dimensions.height, 1, false, false, false, false);
|
||||
}
|
||||
} else {
|
||||
game_renders_to_framebuffer = false;
|
||||
}
|
||||
|
||||
fbActive = 0;
|
||||
}
|
||||
|
||||
void gfx_run(Gfx *commands) {
|
||||
void gfx_run(Gfx *commands, const std::unordered_map<Mtx *, MtxF>& mtx_replacements) {
|
||||
gfx_sp_reset();
|
||||
|
||||
//puts("New frame");
|
||||
get_pixel_depth_pending.clear();
|
||||
get_pixel_depth_cached.clear();
|
||||
|
||||
if (!gfx_wapi->start_frame()) {
|
||||
dropped_frame = true;
|
||||
if (has_drawn_imgui_menu) {
|
||||
SohImGui::DrawFramebufferAndGameInput();
|
||||
SohImGui::CancelFrame();
|
||||
has_drawn_imgui_menu = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
dropped_frame = false;
|
||||
|
||||
if (!has_drawn_imgui_menu) {
|
||||
SohImGui::DrawMainMenuAndCalculateGameSize();
|
||||
}
|
||||
|
||||
current_mtx_replacements = &mtx_replacements;
|
||||
|
||||
double t0 = gfx_wapi->get_time();
|
||||
gfx_rapi->update_framebuffer_parameters(0, gfx_current_window_dimensions.width, gfx_current_window_dimensions.height, 1, false, true, true, !game_renders_to_framebuffer);
|
||||
gfx_rapi->start_frame();
|
||||
gfx_rapi->start_draw_to_framebuffer(game_renders_to_framebuffer ? game_framebuffer : 0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT);
|
||||
gfx_rapi->clear_framebuffer();
|
||||
gfx_run_dl(commands);
|
||||
gfx_flush();
|
||||
SohUtils::saveEnvironmentVar("framebuffer", string());
|
||||
if (game_renders_to_framebuffer) {
|
||||
gfx_rapi->start_draw_to_framebuffer(0, 1);
|
||||
gfx_rapi->clear_framebuffer();
|
||||
|
||||
if (gfx_msaa_level > 1) {
|
||||
bool different_size = gfx_current_dimensions.width != gfx_current_game_window_viewport.width || gfx_current_dimensions.height != gfx_current_game_window_viewport.height;
|
||||
|
||||
if (different_size) {
|
||||
gfx_rapi->resolve_msaa_color_buffer(game_framebuffer_msaa_resolved, game_framebuffer);
|
||||
SohUtils::saveEnvironmentVar("framebuffer", std::to_string((uintptr_t)gfx_rapi->get_framebuffer_texture_id(game_framebuffer_msaa_resolved)));
|
||||
} else {
|
||||
gfx_rapi->resolve_msaa_color_buffer(0, game_framebuffer);
|
||||
}
|
||||
} else {
|
||||
SohUtils::saveEnvironmentVar("framebuffer", std::to_string((uintptr_t)gfx_rapi->get_framebuffer_texture_id(game_framebuffer)));
|
||||
}
|
||||
}
|
||||
SohImGui::DrawFramebufferAndGameInput();
|
||||
SohImGui::Render();
|
||||
double t1 = gfx_wapi->get_time();
|
||||
//printf("Process %f %f\n", t1, t1 - t0);
|
||||
gfx_rapi->end_frame();
|
||||
gfx_wapi->swap_buffers_begin();
|
||||
has_drawn_imgui_menu = false;
|
||||
}
|
||||
|
||||
void gfx_end_frame(void) {
|
||||
|
@ -2739,21 +2834,47 @@ void gfx_set_framedivisor(int divisor) {
|
|||
int gfx_create_framebuffer(uint32_t width, uint32_t height) {
|
||||
uint32_t orig_width = width, orig_height = height;
|
||||
gfx_adjust_width_height_for_scale(width, height);
|
||||
int fb = gfx_rapi->create_framebuffer(width, height);
|
||||
int fb = gfx_rapi->create_framebuffer();
|
||||
gfx_rapi->update_framebuffer_parameters(fb, width, height, 1, true, true, true, true);
|
||||
framebuffers[fb] = { orig_width, orig_height, width, height };
|
||||
return fb;
|
||||
}
|
||||
|
||||
void gfx_set_framebuffer(int fb)
|
||||
{
|
||||
gfx_rapi->set_framebuffer(fb);
|
||||
void gfx_set_framebuffer(int fb, float noise_scale) {
|
||||
gfx_rapi->start_draw_to_framebuffer(fb, noise_scale);
|
||||
gfx_rapi->clear_framebuffer();
|
||||
}
|
||||
|
||||
void gfx_reset_framebuffer()
|
||||
{
|
||||
gfx_rapi->reset_framebuffer();
|
||||
void gfx_reset_framebuffer() {
|
||||
gfx_rapi->start_draw_to_framebuffer(0, (float)gfx_current_dimensions.height / SCREEN_HEIGHT);
|
||||
}
|
||||
|
||||
static void adjust_pixel_depth_coordinates(float& x, float& y) {
|
||||
x = x * RATIO_Y - (SCREEN_WIDTH * RATIO_Y - gfx_current_dimensions.width) / 2;
|
||||
y *= RATIO_Y;
|
||||
if (!game_renders_to_framebuffer || (gfx_msaa_level > 1 && gfx_current_dimensions.width == gfx_current_game_window_viewport.width && gfx_current_dimensions.height == gfx_current_game_window_viewport.height)) {
|
||||
x += gfx_current_game_window_viewport.x;
|
||||
y += gfx_current_window_dimensions.height - (gfx_current_game_window_viewport.y + gfx_current_game_window_viewport.height);
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_get_pixel_depth_prepare(float x, float y) {
|
||||
adjust_pixel_depth_coordinates(x, y);
|
||||
get_pixel_depth_pending.emplace(x, y);
|
||||
}
|
||||
|
||||
uint16_t gfx_get_pixel_depth(float x, float y) {
|
||||
return gfx_rapi->get_pixel_depth(x * RATIO_Y - (SCREEN_WIDTH * RATIO_Y - gfx_current_dimensions.width) / 2, y * RATIO_Y);
|
||||
adjust_pixel_depth_coordinates(x, y);
|
||||
|
||||
if (auto it = get_pixel_depth_cached.find(make_pair(x, y)); it != get_pixel_depth_cached.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
get_pixel_depth_pending.emplace(x, y);
|
||||
|
||||
map<pair<float, float>, uint16_t> res = gfx_rapi->get_pixel_depth(game_renders_to_framebuffer ? game_framebuffer : 0, get_pixel_depth_pending);
|
||||
get_pixel_depth_cached.merge(res);
|
||||
get_pixel_depth_pending.clear();
|
||||
|
||||
return get_pixel_depth_cached.find(make_pair(x, y))->second;
|
||||
}
|
|
@ -4,12 +4,19 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
|
||||
#include "U64/PR/ultra64/types.h"
|
||||
|
||||
struct GfxRenderingAPI;
|
||||
struct GfxWindowManagerAPI;
|
||||
|
||||
struct GfxDimensions
|
||||
{
|
||||
struct XYWidthHeight {
|
||||
int16_t x, y;
|
||||
uint32_t width, height;
|
||||
};
|
||||
|
||||
struct GfxDimensions {
|
||||
uint32_t internal_mul;
|
||||
uint32_t width, height;
|
||||
float aspect_ratio;
|
||||
|
@ -22,7 +29,7 @@ struct TextureCacheKey {
|
|||
uint8_t palette_index;
|
||||
|
||||
bool operator==(const TextureCacheKey&) const noexcept = default;
|
||||
|
||||
|
||||
struct Hasher {
|
||||
size_t operator()(const TextureCacheKey& key) const noexcept {
|
||||
uintptr_t addr = (uintptr_t)key.texture_addr;
|
||||
|
@ -39,30 +46,31 @@ struct TextureCacheValue {
|
|||
uint8_t cms, cmt;
|
||||
bool linear_filter;
|
||||
|
||||
// Old versions of libstdc++ fail to compile this
|
||||
#ifdef _MSC_VER
|
||||
std::list<TextureCacheMap::iterator>::iterator lru_location;
|
||||
#else
|
||||
std::list<int>::iterator lru_location;
|
||||
#endif
|
||||
std::list<struct TextureCacheMapIter>::iterator lru_location;
|
||||
};
|
||||
|
||||
struct TextureCacheMapIter {
|
||||
TextureCacheMap::iterator it;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern struct GfxDimensions gfx_current_dimensions;
|
||||
|
||||
extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window
|
||||
extern struct GfxDimensions gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable)
|
||||
extern struct XYWidthHeight gfx_current_game_window_viewport; // The area of the window the game is drawn to, (0, 0) is top-left corner
|
||||
extern uint32_t gfx_msaa_level;
|
||||
|
||||
}
|
||||
|
||||
void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, bool start_in_fullscreen);
|
||||
struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
|
||||
void gfx_start_frame(void);
|
||||
void gfx_run(Gfx* commands);
|
||||
void gfx_run(Gfx* commands, const std::unordered_map<Mtx*, MtxF>& mtx_replacements);
|
||||
void gfx_end_frame(void);
|
||||
void gfx_set_framedivisor(int);
|
||||
void gfx_texture_cache_clear();
|
||||
int gfx_create_framebuffer(uint32_t width, uint32_t height);
|
||||
extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height);
|
||||
void gfx_get_pixel_depth_prepare(float x, float y);
|
||||
uint16_t gfx_get_pixel_depth(float x, float y);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -5,10 +5,24 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
struct ShaderProgram;
|
||||
|
||||
struct GfxClipParameters {
|
||||
bool z_is_from_0_to_1;
|
||||
bool invert_y;
|
||||
};
|
||||
|
||||
enum FilteringMode {
|
||||
THREE_POINT,
|
||||
LINEAR,
|
||||
NONE
|
||||
};
|
||||
|
||||
struct GfxRenderingAPI {
|
||||
bool (*z_is_from_0_to_1)(void);
|
||||
struct GfxClipParameters (*get_clip_parameters)(void);
|
||||
void (*unload_shader)(struct ShaderProgram *old_prg);
|
||||
void (*load_shader)(struct ShaderProgram *new_prg);
|
||||
struct ShaderProgram *(*create_and_load_new_shader)(uint64_t shader_id0, uint32_t shader_id1);
|
||||
|
@ -19,7 +33,6 @@ struct GfxRenderingAPI {
|
|||
void (*upload_texture)(const uint8_t *rgba32_buf, uint32_t width, uint32_t height);
|
||||
void (*set_sampler_parameters)(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt);
|
||||
void (*set_depth_test_and_mask)(bool depth_test, bool z_upd);
|
||||
uint16_t (*get_pixel_depth)(float x, float y);
|
||||
void (*set_zmode_decal)(bool zmode_decal);
|
||||
void (*set_viewport)(int x, int y, int width, int height);
|
||||
void (*set_scissor)(int x, int y, int width, int height);
|
||||
|
@ -30,12 +43,17 @@ struct GfxRenderingAPI {
|
|||
void (*start_frame)(void);
|
||||
void (*end_frame)(void);
|
||||
void (*finish_render)(void);
|
||||
int (*create_framebuffer)(uint32_t width, uint32_t height);
|
||||
void (*resize_framebuffer)(int fb, uint32_t width, uint32_t height);
|
||||
void (*set_framebuffer)(int fb);
|
||||
void (*reset_framebuffer)();
|
||||
void (*select_texture_fb)(int fbID);
|
||||
int (*create_framebuffer)();
|
||||
void (*update_framebuffer_parameters)(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, bool opengl_invert_y, bool render_target, bool has_depth_buffer, bool can_extract_depth);
|
||||
void (*start_draw_to_framebuffer)(int fb_id, float noise_scale);
|
||||
void (*clear_framebuffer)(void);
|
||||
void (*resolve_msaa_color_buffer)(int fb_id_target, int fb_id_source);
|
||||
std::map<std::pair<float, float>, uint16_t> (*get_pixel_depth)(int fb_id, const std::set<std::pair<float, float>>& coordinates);
|
||||
void *(*get_framebuffer_texture_id)(int fb_id);
|
||||
void (*select_texture_fb)(int fb_id);
|
||||
void (*delete_texture)(uint32_t texID);
|
||||
void (*set_texture_filter)(FilteringMode mode);
|
||||
FilteringMode(*get_texture_filter)(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#if !defined(__linux__) && defined(ENABLE_OPENGL)
|
||||
#if defined(ENABLE_OPENGL)
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#define FOR_WINDOWS 1
|
||||
|
@ -23,7 +23,9 @@
|
|||
|
||||
#include "gfx_window_manager_api.h"
|
||||
#include "gfx_screen_config.h"
|
||||
#ifdef _WIN32
|
||||
#include <WTypesbase.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#define GFX_API_NAME "SDL2 - OpenGL"
|
||||
|
@ -41,7 +43,7 @@ static bool (*on_key_up_callback)(int scancode);
|
|||
static void (*on_all_keys_up_callback)(void);
|
||||
|
||||
const SDL_Scancode windows_scancode_table[] =
|
||||
{
|
||||
{
|
||||
/* 0 1 2 3 4 5 6 7 */
|
||||
/* 8 9 A B C D E F */
|
||||
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_ESCAPE, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6, /* 0 */
|
||||
|
@ -117,7 +119,9 @@ static void set_fullscreen(bool on, bool call_callback) {
|
|||
}
|
||||
|
||||
static uint64_t previous_time;
|
||||
#ifndef __linux__
|
||||
static HANDLE timer;
|
||||
#endif
|
||||
|
||||
static int frameDivisor = 1;
|
||||
|
||||
|
@ -131,7 +135,9 @@ static void gfx_sdl_init(const char *game_name, bool start_in_fullscreen) {
|
|||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
|
||||
#ifndef __linux
|
||||
timer = CreateWaitableTimer(nullptr, false, nullptr);
|
||||
#endif
|
||||
|
||||
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
|
||||
|
@ -188,7 +194,7 @@ static void gfx_sdl_set_keyboard_callbacks(bool (*on_key_down)(int scancode), bo
|
|||
}
|
||||
|
||||
static void gfx_sdl_main_loop(void (*run_one_game_iter)(void)) {
|
||||
while (1)
|
||||
while (1)
|
||||
{
|
||||
run_one_game_iter();
|
||||
}
|
||||
|
|
|
@ -502,7 +502,6 @@ namespace ImGui
|
|||
IMGUI_API bool SmallButton(const char* label); // button with FramePadding=(0,0) to easily embed within text
|
||||
IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size, ImGuiButtonFlags flags = 0); // flexible button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.)
|
||||
IMGUI_API bool ArrowButton(const char* str_id, ImGuiDir dir); // square button with an arrow shape
|
||||
IMGUI_API void ImageRotated(ImTextureID tex_id, ImVec2 center, ImVec2 size, float angle);
|
||||
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0));
|
||||
IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding
|
||||
IMGUI_API bool Checkbox(const char* label, bool* v);
|
||||
|
|
|
@ -1007,33 +1007,6 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6
|
|||
return held;
|
||||
}
|
||||
|
||||
void ImGui::ImageRotated(ImTextureID tex_id, ImVec2 center, ImVec2 size, float angle) {
|
||||
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return;
|
||||
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImRect bb(window->DC.CursorPos + ImVec2(size.x / 2, size.y / 2), window->DC.CursorPos + size);
|
||||
|
||||
ImVec2 pos[4] =
|
||||
{
|
||||
center + bb.Min + ImVec2(-size.x * 0.5f, -size.y * 0.5f),
|
||||
center + bb.Min + ImVec2(+size.x * 0.5f, -size.y * 0.5f),
|
||||
center + bb.Min + ImVec2(+size.x * 0.5f, +size.y * 0.5f),
|
||||
center + bb.Min + ImVec2(-size.x * 0.5f, +size.y * 0.5f)
|
||||
};
|
||||
ImVec2 uvs[4] =
|
||||
{
|
||||
ImVec2(0.0f, 1.0f),
|
||||
ImVec2(1.0f, 1.0f),
|
||||
ImVec2(1.0f, 0.0f),
|
||||
ImVec2(0.0f, 0.0f)
|
||||
};
|
||||
|
||||
draw_list->AddImageQuad(tex_id, pos[0], pos[1], pos[2], pos[3], uvs[0], uvs[1], uvs[2], uvs[3], IM_COL32_WHITE);
|
||||
}
|
||||
|
||||
void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
|
|
|
@ -86,14 +86,8 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#define u8 uint8_t
|
||||
#define u16 uint16_t
|
||||
#define u32 uint32_t
|
||||
#define u64 uint64_t
|
||||
#define unint uint32_t
|
||||
|
||||
#define INITIAL_CRC64 0xffffffffffffffffULL
|
||||
|
||||
extern uint64_t update_crc64(const void* buf, unint len, u64 crc);
|
||||
extern u64 crc64(const void* buf, unint len);
|
||||
extern u64 CRC64(const char* t);
|
||||
extern uint64_t update_crc64(const void* buf, uint32_t len, uint64_t crc);
|
||||
extern uint64_t crc64(const void* buf, uint32_t len);
|
||||
extern uint64_t CRC64(const char* t);
|
|
@ -10,6 +10,7 @@
|
|||
#include <spdlog/details/synchronous_factory.h>
|
||||
#include "SohImGuiImpl.h"
|
||||
#include "GameSettings.h"
|
||||
#include "Cvar.h"
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
@ -45,8 +46,8 @@ protected:
|
|||
}
|
||||
formatted.push_back('\0');
|
||||
const char *msg_output = formatted.data();
|
||||
if (Game::Settings.debug.soh_sink && SohImGui::console->opened)
|
||||
SohImGui::console->Append("SoH Logging", priority, msg_output);
|
||||
if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->opened)
|
||||
SohImGui::console->Append("SoH Logging", priority, "%s", msg_output);
|
||||
}
|
||||
|
||||
void flush_() override {}
|
||||
|
@ -66,6 +67,8 @@ private:
|
|||
return Priority::ERROR_LVL;
|
||||
case spdlog::level::critical:
|
||||
return Priority::ERROR_LVL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Priority::LOG_LVL;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace Ship
|
|||
Vertex* vtxData = new Vertex[numVerts];
|
||||
uint32_t* indicesData = new uint32_t[numPolys];
|
||||
|
||||
if (vertices != NULL)
|
||||
if (vertices != 0)
|
||||
{
|
||||
reader->Seek(headerStart + vertices, SeekOffsetType::Start);
|
||||
|
||||
|
@ -47,7 +47,7 @@ namespace Ship
|
|||
vtxData[i].pos = reader->ReadVec3f();
|
||||
}
|
||||
|
||||
if (normals != NULL)
|
||||
if (normals != 0)
|
||||
{
|
||||
reader->Seek(headerStart + normals, SeekOffsetType::Start);
|
||||
|
||||
|
@ -55,7 +55,7 @@ namespace Ship
|
|||
vtxData[i].normal = reader->ReadVec3f();
|
||||
}
|
||||
|
||||
if (vertexColors != NULL)
|
||||
if (vertexColors != 0)
|
||||
{
|
||||
reader->Seek(headerStart + vertexColors, SeekOffsetType::Start);
|
||||
|
||||
|
@ -63,7 +63,7 @@ namespace Ship
|
|||
vtxData[i].color = reader->ReadColor3b();
|
||||
}
|
||||
|
||||
if (uvCoords != NULL)
|
||||
if (uvCoords != 0)
|
||||
{
|
||||
reader->Seek(headerStart + uvCoords, SeekOffsetType::Start);
|
||||
|
||||
|
@ -71,7 +71,7 @@ namespace Ship
|
|||
vtxData[i].uv = reader->ReadVec2f();
|
||||
}
|
||||
|
||||
if (boneWeights != NULL)
|
||||
if (boneWeights != 0)
|
||||
{
|
||||
reader->Seek(headerStart + boneWeights, SeekOffsetType::Start);
|
||||
|
||||
|
@ -81,7 +81,7 @@ namespace Ship
|
|||
mdl->boneWeights[i] = reader->ReadVec2f();
|
||||
}
|
||||
|
||||
if (faces != NULL)
|
||||
if (faces != 0)
|
||||
{
|
||||
reader->Seek(headerStart + faces, SeekOffsetType::Start);
|
||||
reader->Read((char*)indicesData, numPolys * sizeof(uint32_t));
|
||||
|
|
173
libultraship/libultraship/PulseAudioPlayer.cpp
Normal file
173
libultraship/libultraship/PulseAudioPlayer.cpp
Normal file
|
@ -0,0 +1,173 @@
|
|||
#if defined(__linux__) || defined(__BSD__)
|
||||
|
||||
#include "PulseAudioPlayer.h"
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace Ship
|
||||
{
|
||||
static void pas_context_state_cb(pa_context *c, void *userdata) {
|
||||
switch (pa_context_get_state(c)) {
|
||||
case PA_CONTEXT_READY:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
case PA_CONTEXT_FAILED:
|
||||
*(bool*)userdata = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void pas_stream_state_cb(pa_stream *s, void *userdata) {
|
||||
switch (pa_stream_get_state(s)) {
|
||||
case PA_STREAM_READY:
|
||||
case PA_STREAM_FAILED:
|
||||
case PA_STREAM_TERMINATED:
|
||||
*(bool*)userdata = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void pas_stream_write_cb(pa_stream* s, size_t length, void* userdata) {
|
||||
}
|
||||
|
||||
static void pas_update_complete(pa_stream* stream, int success, void* userdata) {
|
||||
*(bool*)userdata = true;
|
||||
}
|
||||
|
||||
static void pas_write_complete(void* userdata) {
|
||||
*(bool*)userdata = true;
|
||||
}
|
||||
|
||||
bool PulseAudioPlayer::Init()
|
||||
{
|
||||
bool done = false;
|
||||
const pa_buffer_attr* applied_attr = nullptr;
|
||||
|
||||
// Create mainloop
|
||||
m_MainLoop = pa_mainloop_new();
|
||||
if (m_MainLoop == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create context and connect
|
||||
m_Context = pa_context_new(pa_mainloop_get_api(m_MainLoop), "Ocarina of Time");
|
||||
if (m_Context == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pa_context_set_state_callback(m_Context, pas_context_state_cb, &done);
|
||||
|
||||
if (pa_context_connect(m_Context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
while (!done) {
|
||||
pa_mainloop_iterate(m_MainLoop, true, NULL);
|
||||
}
|
||||
pa_context_set_state_callback(m_Context, NULL, NULL);
|
||||
if (pa_context_get_state(m_Context) != PA_CONTEXT_READY) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// Create stream
|
||||
pa_sample_spec ss;
|
||||
ss.format = PA_SAMPLE_S16LE;
|
||||
ss.rate = 32000;
|
||||
ss.channels = 2;
|
||||
|
||||
pa_buffer_attr attr;
|
||||
attr.maxlength = (1600 + 544 + 528 + 1600) * 4;
|
||||
attr.tlength = (528*2 + 544) * 4;
|
||||
attr.prebuf = 1500 * 4;
|
||||
attr.minreq = 161 * 4;
|
||||
attr.fragsize = (uint32_t)-1;
|
||||
|
||||
m_Stream = pa_stream_new(m_Context, "zelda", &ss, NULL);
|
||||
if (m_Stream == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
done = false;
|
||||
pa_stream_set_state_callback(m_Stream, pas_stream_state_cb, &done);
|
||||
pa_stream_set_write_callback(m_Stream, pas_stream_write_cb, NULL);
|
||||
if (pa_stream_connect_playback(m_Stream, NULL, &attr, PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
while (!done) {
|
||||
pa_mainloop_iterate(m_MainLoop, true, NULL);
|
||||
}
|
||||
pa_stream_set_state_callback(m_Stream, NULL, NULL);
|
||||
if (pa_stream_get_state(m_Stream) != PA_STREAM_READY) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
applied_attr = pa_stream_get_buffer_attr(m_Stream);
|
||||
SPDLOG_TRACE("maxlength: {}\ntlength: {}\nprebuf: {}\nminreq: {}\nfragsize: {}\n",
|
||||
applied_attr->maxlength, applied_attr->tlength, applied_attr->prebuf, applied_attr->minreq, applied_attr->fragsize);
|
||||
m_Attr = *applied_attr;
|
||||
|
||||
return true;
|
||||
|
||||
fail:
|
||||
if (m_Stream != NULL) {
|
||||
pa_stream_unref(m_Stream);
|
||||
m_Stream = NULL;
|
||||
}
|
||||
if (m_Context != NULL) {
|
||||
pa_context_disconnect(m_Context);
|
||||
pa_context_unref(m_Context);
|
||||
m_Context = NULL;
|
||||
}
|
||||
if (m_MainLoop != NULL) {
|
||||
pa_mainloop_free(m_MainLoop);
|
||||
m_MainLoop = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int PulseAudioPlayer::Buffered()
|
||||
{
|
||||
if (m_Stream == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool done = false;
|
||||
pa_stream_update_timing_info(m_Stream, pas_update_complete, &done);
|
||||
while (!done) {
|
||||
pa_mainloop_iterate(m_MainLoop, true, NULL);
|
||||
}
|
||||
|
||||
const pa_timing_info *info = pa_stream_get_timing_info(m_Stream);
|
||||
if (info == NULL) {
|
||||
SPDLOG_ERROR("pa_stream_get_timing_info failed, state is %d\n", pa_stream_get_state(m_Stream));
|
||||
}
|
||||
return (info->write_index - info->read_index) / 4;
|
||||
}
|
||||
|
||||
int PulseAudioPlayer::GetDesiredBuffered()
|
||||
{
|
||||
// return 1100;
|
||||
return 1680;
|
||||
}
|
||||
|
||||
void PulseAudioPlayer::Play(const uint8_t* buff, uint32_t len)
|
||||
{
|
||||
size_t ws = m_Attr.maxlength - Buffered() * 4;
|
||||
if (ws < len) {
|
||||
len = ws;
|
||||
}
|
||||
if (pa_stream_write_ext_free(m_Stream, buff, len, pas_write_complete, &m_WriteComplete, 0LL, PA_SEEK_RELATIVE) < 0) {
|
||||
SPDLOG_ERROR("pa_stream_write failed");
|
||||
return;
|
||||
}
|
||||
while (!m_WriteComplete) {
|
||||
pa_mainloop_iterate(m_MainLoop, true, NULL);
|
||||
}
|
||||
m_WriteComplete = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
26
libultraship/libultraship/PulseAudioPlayer.h
Normal file
26
libultraship/libultraship/PulseAudioPlayer.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(__linux__) || defined(__BSD__)
|
||||
|
||||
#include "AudioPlayer.h"
|
||||
#include <pulse/pulseaudio.h>
|
||||
|
||||
namespace Ship {
|
||||
class PulseAudioPlayer : public AudioPlayer {
|
||||
public:
|
||||
PulseAudioPlayer() {}
|
||||
|
||||
bool Init() override;
|
||||
int Buffered() override;
|
||||
int GetDesiredBuffered() override;
|
||||
void Play(const uint8_t* buff, uint32_t len) override;
|
||||
|
||||
private:
|
||||
pa_context* m_Context = nullptr;
|
||||
pa_stream* m_Stream = nullptr;
|
||||
pa_mainloop* m_MainLoop = nullptr;
|
||||
bool m_WriteComplete = false;
|
||||
pa_buffer_attr m_Attr = {0};
|
||||
};
|
||||
}
|
||||
#endif
|
|
@ -2,8 +2,8 @@
|
|||
#include "DisplayList.h"
|
||||
#include "ResourceMgr.h"
|
||||
#include "Utils/BinaryReader.h"
|
||||
#include "lib/tinyxml2/tinyxml2.h"
|
||||
#include "lib/Fast3D/U64/PR/ultra64/gbi.h"
|
||||
#include "Lib/tinyxml2/tinyxml2.h"
|
||||
#include "Lib/Fast3D/U64/PR/ultra64/gbi.h"
|
||||
|
||||
namespace Ship
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ namespace Ship
|
|||
|
||||
void ResourceFile::WriteFileBinary(BinaryWriter* writer, Resource* res)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ResourceFile::WriteFileXML(tinyxml2::XMLElement* writer, Resource* res)
|
||||
|
@ -35,17 +35,20 @@ namespace Ship
|
|||
|
||||
Resource::~Resource()
|
||||
{
|
||||
free(cachedGameAsset);
|
||||
free(cachedGameAsset);
|
||||
cachedGameAsset = nullptr;
|
||||
|
||||
for (int i = 0; i < patches.size(); i++)
|
||||
for (size_t i = 0; i < patches.size(); i++)
|
||||
{
|
||||
std::string hashStr = resMgr->HashToString(patches[i].crc);
|
||||
auto resShared = resMgr->GetCachedFile(hashStr);
|
||||
const std::string* hashStr = resMgr->HashToString(patches[i].crc);
|
||||
if (hashStr == nullptr)
|
||||
continue;
|
||||
|
||||
auto resShared = resMgr->GetCachedFile(hashStr->c_str());
|
||||
if (resShared != nullptr)
|
||||
{
|
||||
auto res = (Ship::DisplayList*)resShared.get();
|
||||
|
||||
|
||||
Gfx* gfx = (Gfx*)&res->instructions[patches[i].index];
|
||||
gfx->words.w1 = patches[i].origData;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "GlobalCtx2.h"
|
||||
#include "StrHash.h"
|
||||
#include "File.h"
|
||||
#include "lib/tinyxml2/tinyxml2.h"
|
||||
#include "Lib/tinyxml2/tinyxml2.h"
|
||||
|
||||
namespace Ship
|
||||
{
|
||||
|
@ -101,10 +101,10 @@ namespace Ship
|
|||
|
||||
class ResourcePromise {
|
||||
public:
|
||||
std::shared_ptr<Resource> Resource;
|
||||
std::shared_ptr<File> File;
|
||||
std::condition_variable ResourceLoadNotifier;
|
||||
std::mutex ResourceLoadMutex;
|
||||
std::shared_ptr<Resource> resource;
|
||||
std::shared_ptr<File> file;
|
||||
std::condition_variable resourceLoadNotifier;
|
||||
std::mutex resourceLoadMutex;
|
||||
bool bHasResourceLoaded = false;
|
||||
};
|
||||
}
|
|
@ -43,7 +43,7 @@ namespace Ship {
|
|||
const std::lock_guard<std::mutex> ResLock(ResourceLoadMutex);
|
||||
bIsRunning = false;
|
||||
}
|
||||
|
||||
|
||||
FileLoadNotifier.notify_all();
|
||||
ResourceLoadNotifier.notify_all();
|
||||
FileLoadThread->join();
|
||||
|
@ -89,7 +89,7 @@ namespace Ship {
|
|||
|
||||
OTR->LoadFile(ToLoad->path, true, ToLoad);
|
||||
//Lock.lock();
|
||||
|
||||
|
||||
if (!ToLoad->bHasLoadError)
|
||||
FileCache[ToLoad->path] = ToLoad->bIsLoaded && !ToLoad->bHasLoadError ? ToLoad : nullptr;
|
||||
|
||||
|
@ -124,15 +124,15 @@ namespace Ship {
|
|||
|
||||
// Wait for the underlying File to complete loading
|
||||
{
|
||||
std::unique_lock<std::mutex> FileLock(ToLoad->File->FileLoadMutex);
|
||||
while (!ToLoad->File->bIsLoaded && !ToLoad->File->bHasLoadError) {
|
||||
ToLoad->File->FileLoadNotifier.wait(FileLock);
|
||||
std::unique_lock<std::mutex> FileLock(ToLoad->file->FileLoadMutex);
|
||||
while (!ToLoad->file->bIsLoaded && !ToLoad->file->bHasLoadError) {
|
||||
ToLoad->file->FileLoadNotifier.wait(FileLock);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ToLoad->File->bHasLoadError)
|
||||
if (!ToLoad->file->bHasLoadError)
|
||||
{
|
||||
auto UnmanagedRes = ResourceLoader::LoadResource(ToLoad->File);
|
||||
auto UnmanagedRes = ResourceLoader::LoadResource(ToLoad->file);
|
||||
|
||||
if (UnmanagedRes != nullptr)
|
||||
{
|
||||
|
@ -140,13 +140,13 @@ namespace Ship {
|
|||
auto Res = std::shared_ptr<Resource>(UnmanagedRes);
|
||||
|
||||
if (Res != nullptr) {
|
||||
std::unique_lock<std::mutex> Lock(ToLoad->ResourceLoadMutex);
|
||||
std::unique_lock<std::mutex> Lock(ToLoad->resourceLoadMutex);
|
||||
|
||||
ToLoad->bHasResourceLoaded = true;
|
||||
ToLoad->Resource = Res;
|
||||
ToLoad->resource = Res;
|
||||
ResourceCache[Res->file->path] = Res;
|
||||
|
||||
SPDLOG_DEBUG("Loaded Resource {} on ResourceMgr thread", ToLoad->File->path);
|
||||
SPDLOG_DEBUG("Loaded Resource {} on ResourceMgr thread", ToLoad->file->path);
|
||||
|
||||
// Disabled for now because it can cause random crashes
|
||||
//FileCache[Res->File->path] = nullptr;
|
||||
|
@ -155,9 +155,9 @@ namespace Ship {
|
|||
}
|
||||
else {
|
||||
ToLoad->bHasResourceLoaded = false;
|
||||
ToLoad->Resource = nullptr;
|
||||
ToLoad->resource = nullptr;
|
||||
|
||||
SPDLOG_ERROR("Resource load FAILED {} on ResourceMgr thread", ToLoad->File->path);
|
||||
SPDLOG_ERROR("Resource load FAILED {} on ResourceMgr thread", ToLoad->file->path);
|
||||
}
|
||||
|
||||
//ResLock.lock();
|
||||
|
@ -167,10 +167,10 @@ namespace Ship {
|
|||
else
|
||||
{
|
||||
ToLoad->bHasResourceLoaded = false;
|
||||
ToLoad->Resource = nullptr;
|
||||
ToLoad->resource = nullptr;
|
||||
}
|
||||
|
||||
ToLoad->ResourceLoadNotifier.notify_all();
|
||||
ToLoad->resourceLoadNotifier.notify_all();
|
||||
}
|
||||
|
||||
SPDLOG_INFO("Resource Manager LoadResourceThread ended");
|
||||
|
@ -215,48 +215,53 @@ namespace Ship {
|
|||
return ToLoad;
|
||||
}
|
||||
|
||||
std::shared_ptr<Ship::Resource> ResourceMgr::GetCachedFile(std::string FilePath) {
|
||||
std::shared_ptr<Ship::Resource> ResourceMgr::GetCachedFile(const char* FilePath) const {
|
||||
auto resCacheFind = ResourceCache.find(FilePath);
|
||||
|
||||
if (resCacheFind != ResourceCache.end())
|
||||
|
||||
if (resCacheFind != ResourceCache.end() &&
|
||||
resCacheFind->second.use_count() > 0)
|
||||
{
|
||||
return resCacheFind->second;
|
||||
}
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Resource> ResourceMgr::LoadResource(std::string FilePath) {
|
||||
auto Promise = LoadResourceAsync(FilePath);
|
||||
std::shared_ptr<Resource> ResourceMgr::LoadResource(const char* FilePath) {
|
||||
auto Res = LoadResourceAsync(FilePath);
|
||||
|
||||
if (std::holds_alternative<std::shared_ptr<Resource>>(Res))
|
||||
return std::get<std::shared_ptr<Resource>>(Res);
|
||||
|
||||
auto& Promise = std::get<std::shared_ptr<ResourcePromise>>(Res);
|
||||
|
||||
if (!Promise->bHasResourceLoaded)
|
||||
{
|
||||
std::unique_lock<std::mutex> Lock(Promise->ResourceLoadMutex);
|
||||
std::unique_lock<std::mutex> Lock(Promise->resourceLoadMutex);
|
||||
while (!Promise->bHasResourceLoaded) {
|
||||
Promise->ResourceLoadNotifier.wait(Lock);
|
||||
Promise->resourceLoadNotifier.wait(Lock);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise->Resource;
|
||||
return Promise->resource;
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourcePromise> ResourceMgr::LoadResourceAsync(std::string FilePath) {
|
||||
StringHelper::ReplaceOriginal(FilePath, "/", "\\");
|
||||
|
||||
if (StringHelper::StartsWith(FilePath, "__OTR__"))
|
||||
FilePath = StringHelper::Split(FilePath, "__OTR__")[1];
|
||||
|
||||
std::shared_ptr<ResourcePromise> Promise = std::make_shared<ResourcePromise>();
|
||||
std::variant<std::shared_ptr<Resource>, std::shared_ptr<ResourcePromise>> ResourceMgr::LoadResourceAsync(const char* FilePath) {
|
||||
if (FilePath[0] == '_' && FilePath[1] == '_' && FilePath[2] == 'O' && FilePath[3] == 'T' && FilePath[4] == 'R' && FilePath[5] == '_' && FilePath[6] == '_')
|
||||
FilePath += 7;
|
||||
|
||||
const std::lock_guard<std::mutex> ResLock(ResourceLoadMutex);
|
||||
auto resCacheFind = ResourceCache.find(FilePath);
|
||||
if (resCacheFind == ResourceCache.end() || resCacheFind->second->isDirty/* || !FileData->bIsLoaded*/) {
|
||||
if (resCacheFind == ResourceCache.end()) {
|
||||
SPDLOG_TRACE("Cache miss on Resource load: {}", FilePath.c_str());
|
||||
SPDLOG_TRACE("Cache miss on Resource load: {}", FilePath);
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourcePromise> Promise = std::make_shared<ResourcePromise>();
|
||||
std::shared_ptr<File> FileData = LoadFile(FilePath);
|
||||
Promise->File = FileData;
|
||||
Promise->file = FileData;
|
||||
|
||||
if (Promise->File->bHasLoadError)
|
||||
if (Promise->file->bHasLoadError)
|
||||
{
|
||||
Promise->bHasResourceLoaded = true;
|
||||
}
|
||||
|
@ -266,12 +271,13 @@ namespace Ship {
|
|||
ResourceLoadQueue.push(Promise);
|
||||
ResourceLoadNotifier.notify_all();
|
||||
}
|
||||
} else {
|
||||
Promise->bHasResourceLoaded = true;
|
||||
Promise->Resource = resCacheFind->second;
|
||||
}
|
||||
|
||||
return Promise;
|
||||
return Promise;
|
||||
}
|
||||
else
|
||||
{
|
||||
return resCacheFind->second;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<std::vector<std::shared_ptr<ResourcePromise>>> ResourceMgr::CacheDirectoryAsync(std::string SearchMask) {
|
||||
|
@ -279,10 +285,15 @@ namespace Ship {
|
|||
auto fileList = OTR->ListFiles(SearchMask);
|
||||
|
||||
for (DWORD i = 0; i < fileList.size(); i++) {
|
||||
auto file = LoadResourceAsync(fileList.operator[](i).cFileName);
|
||||
if (file != nullptr) {
|
||||
loadedList->push_back(file);
|
||||
auto resource = LoadResourceAsync(fileList.operator[](i).cFileName);
|
||||
if (std::holds_alternative<std::shared_ptr<Resource>>(resource))
|
||||
{
|
||||
auto promise = std::make_shared<ResourcePromise>();
|
||||
promise->bHasResourceLoaded = true;
|
||||
promise->resource = std::get<std::shared_ptr<Resource>>(resource);
|
||||
resource = promise;
|
||||
}
|
||||
loadedList->push_back(std::get<std::shared_ptr<ResourcePromise>>(resource));
|
||||
}
|
||||
|
||||
return loadedList;
|
||||
|
@ -292,37 +303,37 @@ namespace Ship {
|
|||
auto PromiseList = CacheDirectoryAsync(SearchMask);
|
||||
auto LoadedList = std::make_shared<std::vector<std::shared_ptr<Resource>>>();
|
||||
|
||||
for (int32_t i = 0; i < PromiseList->size(); i++) {
|
||||
for (size_t i = 0; i < PromiseList->size(); i++) {
|
||||
auto Promise = PromiseList->at(i);
|
||||
|
||||
std::unique_lock<std::mutex> Lock(Promise->ResourceLoadMutex);
|
||||
std::unique_lock<std::mutex> Lock(Promise->resourceLoadMutex);
|
||||
while (!Promise->bHasResourceLoaded) {
|
||||
Promise->ResourceLoadNotifier.wait(Lock);
|
||||
Promise->resourceLoadNotifier.wait(Lock);
|
||||
}
|
||||
|
||||
LoadedList->push_back(Promise->Resource);
|
||||
LoadedList->push_back(Promise->resource);
|
||||
}
|
||||
|
||||
return LoadedList;
|
||||
}
|
||||
|
||||
std::shared_ptr<std::vector<std::shared_ptr<Resource>>> ResourceMgr::DirtyDirectory(std::string SearchMask)
|
||||
std::shared_ptr<std::vector<std::shared_ptr<Resource>>> ResourceMgr::DirtyDirectory(std::string SearchMask)
|
||||
{
|
||||
auto PromiseList = CacheDirectoryAsync(SearchMask);
|
||||
auto LoadedList = std::make_shared<std::vector<std::shared_ptr<Resource>>>();
|
||||
|
||||
for (int32_t i = 0; i < PromiseList->size(); i++) {
|
||||
for (size_t i = 0; i < PromiseList->size(); i++) {
|
||||
auto Promise = PromiseList->at(i);
|
||||
|
||||
std::unique_lock<std::mutex> Lock(Promise->ResourceLoadMutex);
|
||||
std::unique_lock<std::mutex> Lock(Promise->resourceLoadMutex);
|
||||
while (!Promise->bHasResourceLoaded) {
|
||||
Promise->ResourceLoadNotifier.wait(Lock);
|
||||
Promise->resourceLoadNotifier.wait(Lock);
|
||||
}
|
||||
|
||||
if (Promise->Resource != nullptr)
|
||||
Promise->Resource->isDirty = true;
|
||||
if (Promise->resource != nullptr)
|
||||
Promise->resource->isDirty = true;
|
||||
|
||||
LoadedList->push_back(Promise->Resource);
|
||||
LoadedList->push_back(Promise->resource);
|
||||
}
|
||||
|
||||
return LoadedList;
|
||||
|
@ -332,7 +343,7 @@ namespace Ship {
|
|||
ResourceCache.clear();
|
||||
}
|
||||
|
||||
std::string ResourceMgr::HashToString(uint64_t Hash) {
|
||||
const std::string* ResourceMgr::HashToString(uint64_t Hash) const {
|
||||
return OTR->HashToString(Hash);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
#include <string>
|
||||
#include <thread>
|
||||
#include <queue>
|
||||
#include <variant>
|
||||
#include "Resource.h"
|
||||
#include "GlobalCtx2.h"
|
||||
|
||||
|
@ -25,17 +26,18 @@ namespace Ship
|
|||
std::shared_ptr<Archive> GetArchive() { return OTR; }
|
||||
std::shared_ptr<GlobalCtx2> GetContext() { return Context.lock(); }
|
||||
|
||||
std::string HashToString(uint64_t Hash);
|
||||
const std::string* HashToString(uint64_t Hash) const;
|
||||
|
||||
void InvalidateResourceCache();
|
||||
|
||||
|
||||
uint32_t GetGameVersion();
|
||||
void SetGameVersion(uint32_t newGameVersion);
|
||||
std::shared_ptr<File> LoadFileAsync(std::string FilePath);
|
||||
std::shared_ptr<File> LoadFile(std::string FilePath);
|
||||
std::shared_ptr<Ship::Resource> GetCachedFile(std::string FilePath);
|
||||
std::shared_ptr<Resource> LoadResource(std::string FilePath);
|
||||
std::shared_ptr<ResourcePromise> LoadResourceAsync(std::string FilePath);
|
||||
std::shared_ptr<Ship::Resource> GetCachedFile(const char* FilePath) const;
|
||||
std::shared_ptr<Resource> LoadResource(const char* FilePath);
|
||||
std::shared_ptr<Resource> LoadResource(const std::string& FilePath) { return LoadResource(FilePath.c_str()); }
|
||||
std::variant<std::shared_ptr<Resource>, std::shared_ptr<ResourcePromise>> LoadResourceAsync(const char* FilePath);
|
||||
std::shared_ptr<std::vector<std::shared_ptr<Resource>>> CacheDirectory(std::string SearchMask);
|
||||
std::shared_ptr<std::vector<std::shared_ptr<ResourcePromise>>> CacheDirectoryAsync(std::string SearchMask);
|
||||
std::shared_ptr<std::vector<std::shared_ptr<Resource>>> DirtyDirectory(std::string SearchMask);
|
||||
|
@ -48,8 +50,9 @@ namespace Ship
|
|||
|
||||
private:
|
||||
std::weak_ptr<GlobalCtx2> Context;
|
||||
volatile bool bIsRunning;
|
||||
std::map<std::string, std::shared_ptr<File>> FileCache;
|
||||
std::map<std::string, std::shared_ptr<Resource>> ResourceCache;
|
||||
std::map<std::string, std::shared_ptr<Resource>, std::less<>> ResourceCache;
|
||||
std::queue<std::shared_ptr<File>> FileLoadQueue;
|
||||
std::queue<std::shared_ptr<ResourcePromise>> ResourceLoadQueue;
|
||||
std::shared_ptr<Archive> OTR;
|
||||
|
@ -59,7 +62,6 @@ namespace Ship
|
|||
std::mutex ResourceLoadMutex;
|
||||
std::condition_variable FileLoadNotifier;
|
||||
std::condition_variable ResourceLoadNotifier;
|
||||
volatile bool bIsRunning;
|
||||
uint32_t gameVersion;
|
||||
};
|
||||
}
|
|
@ -5,6 +5,8 @@
|
|||
#include "spdlog/spdlog.h"
|
||||
#include "stox.h"
|
||||
#include "Window.h"
|
||||
#include "Cvar.h"
|
||||
#include <Utils/StringHelper.h>
|
||||
|
||||
extern "C" uint8_t __osMaxControllers;
|
||||
|
||||
|
@ -59,30 +61,36 @@ namespace Ship {
|
|||
if (Conf[ConfSection]["GUID"].compare("") == 0 || Conf[ConfSection]["GUID"].compare(INVALID_SDL_CONTROLLER_GUID) == 0 || Conf[ConfSection]["GUID"].compare(NewGuid) == 0) {
|
||||
auto NewCont = SDL_GameControllerOpen(i);
|
||||
|
||||
if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO))
|
||||
{
|
||||
SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE);
|
||||
}
|
||||
|
||||
// We failed to load the controller. Go to next.
|
||||
if (NewCont == nullptr) {
|
||||
SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO))
|
||||
{
|
||||
SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE);
|
||||
}
|
||||
|
||||
guid = NewGuid;
|
||||
Cont = NewCont;
|
||||
|
||||
std::string BindingConfSection = GetBindingConfSection();
|
||||
std::shared_ptr<ConfigFile> pBindingConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& BindingConf = *pBindingConf.get();
|
||||
std::string PadConfSection = *GetPadConfSection();
|
||||
std::shared_ptr<ConfigFile> config = GlobalCtx2::GetInstance()->GetConfig();
|
||||
|
||||
if (!BindingConf.has(BindingConfSection)) {
|
||||
if (!config->has(BindingConfSection)) {
|
||||
CreateDefaultBinding();
|
||||
}
|
||||
|
||||
if (!config->has(PadConfSection)) {
|
||||
CreateDefaultPadConf();
|
||||
}
|
||||
|
||||
LoadBinding();
|
||||
LoadAxisThresholds();
|
||||
// Update per-controller settings in ImGui menu after opening controller.
|
||||
Game::LoadPadSettings();
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -93,6 +101,9 @@ namespace Ship {
|
|||
}
|
||||
|
||||
bool SDLController::Close() {
|
||||
if (CanRumble()) {
|
||||
SDL_GameControllerRumble(Cont, 0, 0, 0);
|
||||
}
|
||||
if (Cont != nullptr) {
|
||||
SDL_GameControllerClose(Cont);
|
||||
}
|
||||
|
@ -178,37 +189,44 @@ namespace Ship {
|
|||
|
||||
if (SDL_GameControllerHasSensor(Cont, SDL_SENSOR_GYRO))
|
||||
{
|
||||
size_t contNumber = GetControllerNumber();
|
||||
|
||||
float gyroData[3];
|
||||
SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3);
|
||||
|
||||
const char* contName = SDL_GameControllerName(Cont);
|
||||
const int isSpecialController = !strcmp("PS5 Controller", contName);
|
||||
const float gyroSensitivity = Game::Settings.controller.gyro_sensitivity;
|
||||
float gyro_drift_x = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", contNumber).c_str(), 0.0f);
|
||||
float gyro_drift_y = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", contNumber).c_str(), 0.0f);
|
||||
const float gyro_sensitivity = CVar_GetFloat(StringHelper::Sprintf("gCont%i_GyroSensitivity", contNumber).c_str(), 1.0f);
|
||||
|
||||
if (Game::Settings.controller.gyroDriftX == 0) {
|
||||
Game::Settings.controller.gyroDriftX = gyroData[0];
|
||||
if (gyro_drift_x == 0) {
|
||||
gyro_drift_x = gyroData[0];
|
||||
}
|
||||
|
||||
if (Game::Settings.controller.gyroDriftY == 0) {
|
||||
if (gyro_drift_y == 0) {
|
||||
if (isSpecialController == 1) {
|
||||
Game::Settings.controller.gyroDriftY = gyroData[2];
|
||||
gyro_drift_y = gyroData[2];
|
||||
}
|
||||
else {
|
||||
Game::Settings.controller.gyroDriftY = gyroData[1];
|
||||
gyro_drift_y = gyroData[1];
|
||||
}
|
||||
}
|
||||
|
||||
CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftX", contNumber).c_str(), gyro_drift_x);
|
||||
CVar_SetFloat(StringHelper::Sprintf("gCont%i_GyroDriftY", contNumber).c_str(), gyro_drift_y);
|
||||
|
||||
if (isSpecialController == 1) {
|
||||
wGyroX = gyroData[0] - Game::Settings.controller.gyroDriftX;
|
||||
wGyroY = -gyroData[2] - Game::Settings.controller.gyroDriftY;
|
||||
wGyroX = gyroData[0] - gyro_drift_x;
|
||||
wGyroY = -gyroData[2] - gyro_drift_y;
|
||||
}
|
||||
else {
|
||||
wGyroX = gyroData[0] - Game::Settings.controller.gyroDriftX;
|
||||
wGyroY = gyroData[1] - Game::Settings.controller.gyroDriftY;
|
||||
wGyroX = gyroData[0] - gyro_drift_x;
|
||||
wGyroY = gyroData[1] - gyro_drift_y;
|
||||
}
|
||||
|
||||
wGyroX *= gyroSensitivity;
|
||||
wGyroY *= gyroSensitivity;
|
||||
wGyroX *= gyro_sensitivity;
|
||||
wGyroY *= gyro_sensitivity;
|
||||
}
|
||||
|
||||
for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
|
||||
|
@ -329,9 +347,12 @@ namespace Ship {
|
|||
|
||||
void SDLController::WriteToSource(ControllerCallback* controller)
|
||||
{
|
||||
if (SDL_GameControllerHasRumble(Cont)) {
|
||||
if (CanRumble()) {
|
||||
if (controller->rumble > 0) {
|
||||
SDL_GameControllerRumble(Cont, 0xFFFF * Game::Settings.controller.rumble_strength, 0xFFFF * Game::Settings.controller.rumble_strength, 1);
|
||||
float rumble_strength = CVar_GetFloat(StringHelper::Sprintf("gCont%i_RumbleStrength", GetControllerNumber()).c_str(), 1.0f);
|
||||
SDL_GameControllerRumble(Cont, 0xFFFF * rumble_strength, 0xFFFF * rumble_strength, 0);
|
||||
} else {
|
||||
SDL_GameControllerRumble(Cont, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,6 +412,14 @@ namespace Ship {
|
|||
Conf.Save();
|
||||
}
|
||||
|
||||
void SDLController::CreateDefaultPadConf() {
|
||||
std::string ConfSection = *GetPadConfSection();
|
||||
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf.get();
|
||||
|
||||
Conf.Save();
|
||||
}
|
||||
|
||||
void SDLController::SetButtonMapping(const std::string& szButtonName, int32_t dwScancode) {
|
||||
if (guid.compare(INVALID_SDL_CONTROLLER_GUID)) {
|
||||
return;
|
||||
|
@ -410,4 +439,8 @@ namespace Ship {
|
|||
std::string SDLController::GetBindingConfSection() {
|
||||
return GetControllerType() + " CONTROLLER BINDING " + guid;
|
||||
}
|
||||
|
||||
std::optional<std::string> SDLController::GetPadConfSection() {
|
||||
return GetControllerType() + " CONTROLLER PAD " + guid;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,20 +12,31 @@ namespace Ship {
|
|||
|
||||
void ReadFromSource();
|
||||
void WriteToSource(ControllerCallback* controller);
|
||||
bool Connected() const { return Cont != nullptr; }
|
||||
bool CanRumble() const {
|
||||
#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18)
|
||||
return SDL_GameControllerHasRumble(Cont);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GetGuid() { return guid; };
|
||||
|
||||
bool HasPadConf() const { return true; }
|
||||
std::optional<std::string> GetPadConfSection();
|
||||
|
||||
protected:
|
||||
std::string GetControllerType();
|
||||
void SetButtonMapping(const std::string& szButtonName, int32_t dwScancode);
|
||||
std::string GetConfSection();
|
||||
std::string GetBindingConfSection();
|
||||
void CreateDefaultBinding();
|
||||
void CreateDefaultPadConf();
|
||||
static bool IsGuidInUse(const std::string& guid);
|
||||
|
||||
private:
|
||||
std::string guid;
|
||||
SDL_GameController* Cont;
|
||||
std::string guid;
|
||||
std::map<int32_t, int16_t> ThresholdMapping;
|
||||
|
||||
void LoadAxisThresholds();
|
||||
|
|
|
@ -137,8 +137,8 @@ namespace Ship
|
|||
y = 0;
|
||||
z = 0;
|
||||
unk_06 = 0;
|
||||
opa;
|
||||
xlu;
|
||||
// opa;
|
||||
// xlu;
|
||||
}
|
||||
|
||||
SetMesh::SetMesh(BinaryReader* reader) : SceneCommand(reader)
|
||||
|
@ -398,18 +398,18 @@ namespace Ship
|
|||
LightInfo light = LightInfo();
|
||||
|
||||
light.type = reader->ReadUByte();
|
||||
|
||||
|
||||
light.x = reader->ReadInt16();
|
||||
light.y = reader->ReadInt16();
|
||||
light.y = reader->ReadInt16();
|
||||
light.z = reader->ReadInt16();
|
||||
|
||||
light.r = reader->ReadUByte();
|
||||
light.g = reader->ReadUByte();
|
||||
light.b = reader->ReadUByte();
|
||||
|
||||
|
||||
light.drawGlow = reader->ReadUByte();
|
||||
light.radius = reader->ReadInt16();
|
||||
|
||||
|
||||
lights.push_back(light);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Ship
|
|||
limb->skinVtxCnt = reader->ReadUInt16();
|
||||
uint32_t skinCnt = reader->ReadUInt32();
|
||||
|
||||
for (int i = 0; i < skinCnt; i++)
|
||||
for (size_t i = 0; i < skinCnt; i++)
|
||||
{
|
||||
Struct_800A598C struc;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ std::map<ImGuiKey, std::string> BindingToggle;
|
|||
static bool HelpCommand(const std::vector<std::string>&) {
|
||||
INFO("SoH Commands:");
|
||||
for(const auto& cmd : SohImGui::console->Commands) {
|
||||
INFO((" - " + cmd.first).c_str());
|
||||
INFO("%s", (" - " + cmd.first).c_str());
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ std::string toLowerCase(std::string in) {
|
|||
static bool BindCommand(const std::vector<std::string>& args) {
|
||||
if(args.size() > 2) {
|
||||
const ImGuiIO* io = &ImGui::GetIO();;
|
||||
for (int k = 0; k < std::size(io->KeysData); k++) {
|
||||
for (size_t k = 0; k < std::size(io->KeysData); k++) {
|
||||
std::string key(ImGui::GetKeyName(k));
|
||||
|
||||
if(toLowerCase(args[1]) == toLowerCase(key)) {
|
||||
|
@ -55,7 +55,7 @@ static bool BindCommand(const std::vector<std::string>& args) {
|
|||
static bool BindToggleCommand(const std::vector<std::string>& args) {
|
||||
if (args.size() > 2) {
|
||||
const ImGuiIO* io = &ImGui::GetIO();;
|
||||
for (int k = 0; k < std::size(io->KeysData); k++) {
|
||||
for (size_t k = 0; k < std::size(io->KeysData); k++) {
|
||||
std::string key(ImGui::GetKeyName(k));
|
||||
|
||||
if (toLowerCase(args[1]) == toLowerCase(key)) {
|
||||
|
@ -92,7 +92,7 @@ void Console::Update() {
|
|||
}
|
||||
for (auto [key, var] : BindingToggle) {
|
||||
if (ImGui::IsKeyPressed(key)) {
|
||||
CVar* cvar = CVar_GetVar(const_cast<char*>(var.c_str()));
|
||||
CVar* cvar = CVar_Get(var.c_str());
|
||||
Dispatch("set " + var + " " + std::to_string(cvar == nullptr ? 0 : !static_cast<bool>(cvar->value.valueS32)));
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ void Console::Draw() {
|
|||
if (!this->opened) return;
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("Console", &this->opened);
|
||||
ImGui::Begin("Console", nullptr, ImGuiWindowFlags_NoFocusOnAppearing);
|
||||
const ImVec2 pos = ImGui::GetWindowPos();
|
||||
const ImVec2 size = ImGui::GetWindowSize();
|
||||
|
||||
|
@ -177,8 +177,10 @@ void Console::Draw() {
|
|||
for (const auto& filter : priority_filters) {
|
||||
const bool is_selected = (filter == std::string(this->level_filter));
|
||||
if (ImGui::Selectable(filter.c_str(), is_selected))
|
||||
{
|
||||
this->level_filter = filter;
|
||||
if (is_selected) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
@ -194,7 +196,7 @@ void Console::Draw() {
|
|||
if (ImGui::BeginTable("History", 1)) {
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)))
|
||||
if (this->selectedId < this->Log.size() - 1) ++this->selectedId;
|
||||
if (this->selectedId < (int)this->Log.size() - 1) ++this->selectedId;
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
|
||||
if (this->selectedId > 0) --this->selectedId;
|
||||
|
||||
|
@ -226,7 +228,7 @@ void Console::Draw() {
|
|||
ImGui::EndChild();
|
||||
|
||||
// Renders input textfield
|
||||
constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit |
|
||||
constexpr ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackEdit |
|
||||
ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
|
||||
ImGui::PushItemWidth(-1);
|
||||
if(ImGui::InputTextWithHint("CMDInput", ">", this->InputBuffer, MAX_BUFFER_SIZE, flags, &Console::CallbackStub, this)) {
|
||||
|
@ -317,7 +319,7 @@ int Console::CallbackStub(ImGuiInputTextCallbackData* data) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Console::Append(const std::string& channel, Priority priority, const char* fmt, ...) IM_FMTARGS(4) {
|
||||
void Console::Append(const std::string& channel, Priority priority, const char* fmt, ...) {
|
||||
char buf[1024];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
#include "Lib/ImGui/imgui.h"
|
||||
|
||||
#define LOG(msg, ...) SohImGui::console->Append("Main", Priority::LOG_LVL, msg, __VA_ARGS__)
|
||||
#define INFO(msg, ...) SohImGui::console->Append("Main", Priority::INFO_LVL, msg, __VA_ARGS__)
|
||||
#define WARNING(msg, ...) SohImGui::console->Append("Main", Priority::WARNING_LVL, msg, __VA_ARGS__)
|
||||
#define ERROR(msg, ...) SohImGui::console->Append("Main", Priority::ERROR_LVL, msg, __VA_ARGS__)
|
||||
#define LOG(msg, ...) SohImGui::console->Append("Main", Priority::LOG_LVL, msg, ##__VA_ARGS__)
|
||||
#define INFO(msg, ...) SohImGui::console->Append("Main", Priority::INFO_LVL, msg, ##__VA_ARGS__)
|
||||
#define WARNING(msg, ...) SohImGui::console->Append("Main", Priority::WARNING_LVL, msg, ##__VA_ARGS__)
|
||||
#define ERROR(msg, ...) SohImGui::console->Append("Main", Priority::ERROR_LVL, msg, ##__VA_ARGS__)
|
||||
#define CMD_SUCCESS true
|
||||
#define CMD_FAILED false
|
||||
#define MAX_BUFFER_SIZE 255
|
||||
|
@ -75,7 +75,7 @@ public:
|
|||
void Init();
|
||||
void Update();
|
||||
void Draw();
|
||||
void Append(const std::string& channel, Priority priority, const char* fmt, ...);
|
||||
void Append(const std::string& channel, Priority priority, const char* fmt, ...) IM_FMTARGS(4);
|
||||
void Dispatch(const std::string& line);
|
||||
static int CallbackStub(ImGuiInputTextCallbackData* data);
|
||||
};
|
|
@ -24,7 +24,7 @@ namespace ModInternal {
|
|||
|
||||
bool handleHook(std::shared_ptr<HookCall> call) {
|
||||
std::string hookName = std::string(call->name);
|
||||
for (int l = 0; l < listeners[hookName].size(); l++) {
|
||||
for (size_t l = 0; l < listeners[hookName].size(); l++) {
|
||||
(listeners[hookName][l])(call);
|
||||
}
|
||||
return call->cancelled;
|
||||
|
|
|
@ -47,6 +47,7 @@ struct HookParameter {
|
|||
#include <functional>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
struct HookCall {
|
||||
std::string name;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "GameOverlay.h"
|
||||
#include "Lib/ImGui/imgui.h"
|
||||
#include "SohConsole.h"
|
||||
|
||||
struct GameAsset {
|
||||
|
@ -47,11 +49,35 @@ namespace SohImGui {
|
|||
} sdl;
|
||||
} EventImpl;
|
||||
|
||||
extern WindowImpl impl;
|
||||
|
||||
using WindowDrawFunc = void(*)(bool& enabled);
|
||||
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
WindowDrawFunc drawFunc;
|
||||
} CustomWindow;
|
||||
|
||||
extern Console* console;
|
||||
extern Ship::GameOverlay* overlay;
|
||||
extern bool needs_save;
|
||||
void Init(WindowImpl window_impl);
|
||||
void Update(EventImpl event);
|
||||
void Draw(void);
|
||||
|
||||
void EnhancementRadioButton(std::string text, std::string cvarName, int value);
|
||||
void EnhancementCheckbox(std::string text, std::string cvarName);
|
||||
void EnhancementSliderInt(std::string text, std::string id, std::string cvarName, int min, int max, std::string format);
|
||||
void EnhancementSliderFloat(std::string text, std::string id, std::string cvarName, float min, float max, std::string format, float defaultValue);
|
||||
|
||||
void DrawMainMenuAndCalculateGameSize(void);
|
||||
|
||||
void DrawFramebufferAndGameInput(void);
|
||||
void Render(void);
|
||||
void CancelFrame(void);
|
||||
void ShowCursor(bool hide, Dialogues w);
|
||||
void BindCmd(const std::string& cmd, CommandEntry entry);
|
||||
void* GetTextureByID(int id);
|
||||
void AddWindow(const std::string& category, const std::string& name, WindowDrawFunc drawFunc);
|
||||
void LoadResource(const std::string& name, const std::string& path, const ImVec4& tint = ImVec4(1, 1, 1, 1));
|
||||
ImTextureID GetTextureByID(int id);
|
||||
ImTextureID GetTextureByName(const std::string& name);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Ship {
|
|||
if (raw_path == nullptr) return;
|
||||
|
||||
const auto api = BIND_PTR("gfx_api", GfxRenderingAPI*);
|
||||
const auto path = normalize(raw_path) + ".png";
|
||||
const auto path = std::string(raw_path) + ".png";
|
||||
const auto node = BIND_PTR("node", TextureCacheNode**);
|
||||
const auto fmt = BIND_VAR("fmt", uint32_t*);
|
||||
const auto siz = BIND_VAR("siz", uint32_t*);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue