Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4c4ff349a0 | |||
| 79ec8fb439 |
+1
-1
@@ -1,4 +1,4 @@
|
||||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
AccessModifierOffset: -4
|
||||
# SortIncludes: false # FIXME: https://github.com/4jcraft/4jcraft/issues/225
|
||||
SortIncludes: false # FIXME: https://github.com/4jcraft/4jcraft/issues/225
|
||||
@@ -1,38 +0,0 @@
|
||||
name: "Build Meson"
|
||||
description: "Builds the project using Meson"
|
||||
|
||||
inputs:
|
||||
dir_name:
|
||||
description: "The name of the directory to setup meson in"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
setup_args:
|
||||
description: "The args to additionally pass to meson"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
upload:
|
||||
description: "Upload the executable"
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Setup build-directory
|
||||
shell: nix develop --command bash -e {0}
|
||||
run: meson setup ${{ inputs.dir_name }} --wipe ${{ inputs.setup_args }}
|
||||
|
||||
- name: Compile directory
|
||||
shell: nix develop --command bash -e {0}
|
||||
run: meson compile -C ${{ inputs.dir_name }} -j $(nproc) -v Minecraft.Client
|
||||
|
||||
- name: Upload executable
|
||||
if: ${{ inputs.upload }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: minecraft-client-linux-${{ inputs.dir_name }}-${{ github.sha }}
|
||||
path: ${{ inputs.dir_name }}/Minecraft.Client/Minecraft.Client
|
||||
retention-days: 7
|
||||
@@ -1,18 +0,0 @@
|
||||
name: "Enter Nix dev-shell"
|
||||
description: "Enters a Nix dev-shell"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- name: Verify flake integrity
|
||||
shell: bash
|
||||
run: nix flake check
|
||||
|
||||
- name: Enter Nix dev-shell
|
||||
shell: bash
|
||||
run: nix develop
|
||||
@@ -1,27 +0,0 @@
|
||||
name: "Restore cache"
|
||||
description: "Restores the cache for ccache and Meson"
|
||||
|
||||
inputs:
|
||||
ccache_dir:
|
||||
description: "The directory used by ccache"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Restore ccache cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ${{ runner.os }}-ccache-${{ hashFiles('**/meson.build') }}
|
||||
|
||||
- name: Create ccache dir
|
||||
shell: bash
|
||||
run: mkdir -p {{ inputs.ccache_dir }}
|
||||
|
||||
- name: Restore meson cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/meson
|
||||
key: ${{ runner.os }}-meson-${{ hashFiles('**/meson.build') }}
|
||||
@@ -4,9 +4,9 @@ on:
|
||||
push:
|
||||
branches: ["dev"]
|
||||
paths:
|
||||
- "resources/**"
|
||||
- "Minecraft.Assets/**"
|
||||
- "Minecraft.Client/**"
|
||||
- "minecraft/**"
|
||||
- "Minecraft.World/**"
|
||||
- "docs/**"
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -1,91 +1,66 @@
|
||||
name: Build (Linux, x86-64)
|
||||
|
||||
# TODO: test with only pull-request
|
||||
on:
|
||||
push:
|
||||
paths: &workflow_paths
|
||||
- "**.cppm"
|
||||
- "**.ixx"
|
||||
- "**.inl"
|
||||
- "**.mpp"
|
||||
- "**.ipp"
|
||||
- "**.tpp"
|
||||
- "**.txx"
|
||||
- "**.inc"
|
||||
- "**.cpp"
|
||||
- "**.hpp"
|
||||
- "**.cxx"
|
||||
- "**.hxx"
|
||||
- "**.cc"
|
||||
- "**.hh"
|
||||
- "**.c"
|
||||
- "**.h"
|
||||
- ".github/workflows/build-linux.yml"
|
||||
- "**/meson.build"
|
||||
- '**.cpp'
|
||||
- '**.h'
|
||||
- '**.c'
|
||||
- '**.cc'
|
||||
- '**.cxx'
|
||||
- '**.hh'
|
||||
- '**.hpp'
|
||||
- '**.hxx'
|
||||
- '**.inl'
|
||||
- "**meson.build"
|
||||
- "flake.nix"
|
||||
- '.github/workflows/build-linux.yml'
|
||||
|
||||
pull_request:
|
||||
paths: *workflow_paths
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ !contains(github.ref, 'dev/') }}
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-linux-amalgamate:
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Cache .git folder
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential ccache python3 python3-pip ninja-build libsdl2-dev libgl-dev libglu1-mesa-dev libpthread-stubs0-dev libglm-dev
|
||||
python -m pip install meson
|
||||
|
||||
- name: Restore ccache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: .git
|
||||
key: ${{ runner.os }}-git-${{ github.sha }}
|
||||
restore-keys: ${{ runner.os }}-git-
|
||||
path: ${{ runner.temp }}/ccache
|
||||
key: ${{ runner.os }}-ccache-${{ hashFiles('**/meson.build') }}
|
||||
restore-keys: ${{ runner.os }}-ccache-
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
- name: Configure Meson
|
||||
env:
|
||||
CC: "ccache clang"
|
||||
CXX: "ccache clang++"
|
||||
CC_LD: lld
|
||||
CXX_LD: lld
|
||||
run: |
|
||||
meson setup build --wipe
|
||||
|
||||
- name: Build with Meson
|
||||
env:
|
||||
CCACHE_DIR: ${{ runner.temp }}/ccache
|
||||
run: |
|
||||
# Use all available cores for faster parallel builds
|
||||
meson compile -C build -j $(nproc) -v Minecraft.Client
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Enter dev-shell
|
||||
uses: ./.github/actions/enter-devshell
|
||||
|
||||
- name: Restore build cache
|
||||
uses: ./.github/actions/restore-cache
|
||||
with:
|
||||
ccache_dir: ${{ runner.temp }}/ccache
|
||||
|
||||
- name: Compile
|
||||
uses: ./.github/actions/build-meson
|
||||
with:
|
||||
dir_name: "build_release"
|
||||
setup_args: "-Dunity=on -Dunity_size=99999"
|
||||
|
||||
build-linux-full:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Cache .git folder
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: .git
|
||||
key: ${{ runner.os }}-git-${{ github.sha }}
|
||||
restore-keys: ${{ runner.os }}-git-
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Enter dev-shell
|
||||
uses: ./.github/actions/enter-devshell
|
||||
|
||||
- name: Restore build cache
|
||||
uses: ./.github/actions/restore-cache
|
||||
with:
|
||||
ccache_dir: ${{ runner.temp }}/ccache
|
||||
|
||||
- name: Compile
|
||||
uses: ./.github/actions/build-meson
|
||||
with:
|
||||
dir_name: "build_debug"
|
||||
setup_args: "-Dunity=off"
|
||||
name: minecraft-client-linux-${{ github.sha }}
|
||||
path: build/Minecraft.Client/Minecraft.Client
|
||||
retention-days: 7
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
name: Release Nightly (Linux, x86-64)
|
||||
|
||||
on:
|
||||
push:
|
||||
paths: &workflow_paths
|
||||
- '**.cpp'
|
||||
- '**.h'
|
||||
- '**.c'
|
||||
- '**.cc'
|
||||
- '**.cxx'
|
||||
- '**.hh'
|
||||
- '**.hpp'
|
||||
- '**.hxx'
|
||||
- '**.inl'
|
||||
- "**meson.build"
|
||||
- "flake.nix"
|
||||
- '.github/workflows/release-linux.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release-linux:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential ccache python3 python3-pip ninja-build libsdl2-dev libgl-dev libglu1-mesa-dev libpthread-stubs0-dev libglm-dev
|
||||
python -m pip install meson
|
||||
# Set a reasonable ccache size
|
||||
ccache -M 5G || true
|
||||
|
||||
- name: Install LLVM + libc++
|
||||
run: |
|
||||
wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- 20
|
||||
sudo apt-get install -y libc++-20-dev libc++abi-20-dev
|
||||
|
||||
- name: Restore ccache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ runner.temp }}/ccache
|
||||
key: ${{ runner.os }}-ccache-${{ hashFiles('**/meson.build') }}
|
||||
restore-keys: ${{ runner.os }}-ccache-
|
||||
|
||||
- name: Configure Meson
|
||||
env:
|
||||
CC: "ccache clang"
|
||||
CXX: "ccache clang++"
|
||||
CC_LD: lld
|
||||
CXX_LD: lld
|
||||
run: |
|
||||
meson setup build --native-file=scripts/llvm_native.txt --wipe
|
||||
|
||||
- name: Build with Meson
|
||||
env:
|
||||
CCACHE_DIR: ${{ runner.temp }}/ccache
|
||||
run: |
|
||||
export CCACHE_DIR="${{ runner.temp }}/ccache"
|
||||
meson compile -C build -j $(nproc)
|
||||
|
||||
- name: Install patchelf
|
||||
run: sudo apt-get install -y patchelf
|
||||
|
||||
- name: Package artifact
|
||||
run: |
|
||||
cd build/targets
|
||||
zip -r ../minecraft-client-linux.zip app --exclude "app/Minecraft.Client.p/*"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: minecraft-client-linux-${{ github.sha }}
|
||||
path: minecraft-client-linux.zip
|
||||
retention-days: 7
|
||||
|
||||
- name: Create nightly release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: nightly
|
||||
name: Nightly
|
||||
prerelease: true
|
||||
files: minecraft-client-linux.zip
|
||||
+4
-1
@@ -6,7 +6,10 @@
|
||||
!/.github/
|
||||
!/.github-assets/
|
||||
!/docs/
|
||||
!/targets/
|
||||
!/Minecraft.Assets/
|
||||
!/Minecraft.Client/
|
||||
!/Minecraft.World/
|
||||
!/4J.*/
|
||||
!/scripts/
|
||||
!/subprojects/
|
||||
/subprojects/*
|
||||
|
||||
@@ -1,74 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
// Shared value types used by platform interfaces. These are NOT interfaces
|
||||
// themselves — they are data carriers that cross the platform boundary.
|
||||
|
||||
struct ImageFileBuffer {
|
||||
enum EImageType { e_typePNG, e_typeJPG };
|
||||
EImageType m_type;
|
||||
void* m_pBuffer = nullptr;
|
||||
int m_bufferSize = 0;
|
||||
|
||||
[[nodiscard]] int GetType() const { return m_type; }
|
||||
[[nodiscard]] void* GetBufferPointer() const { return m_pBuffer; }
|
||||
[[nodiscard]] int GetBufferSize() const { return m_bufferSize; }
|
||||
[[nodiscard]] bool Allocated() const { return m_pBuffer != nullptr; }
|
||||
void Release() {
|
||||
std::free(m_pBuffer);
|
||||
m_pBuffer = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
struct D3DXIMAGE_INFO {
|
||||
int Width;
|
||||
int Height;
|
||||
};
|
||||
|
||||
struct XSOCIAL_PREVIEWIMAGE {
|
||||
std::uint8_t* pBytes;
|
||||
std::uint32_t Pitch;
|
||||
std::uint32_t Width;
|
||||
std::uint32_t Height;
|
||||
};
|
||||
using PXSOCIAL_PREVIEWIMAGE = XSOCIAL_PREVIEWIMAGE*;
|
||||
|
||||
struct STRING_VERIFY_RESPONSE {
|
||||
std::uint16_t wNumStrings;
|
||||
int* pStringResult;
|
||||
};
|
||||
|
||||
enum class EKeyboardResult {
|
||||
Pending,
|
||||
Cancelled,
|
||||
ResultAccept,
|
||||
ResultDecline,
|
||||
};
|
||||
|
||||
// Profile-related enums at file scope.
|
||||
enum class EAwardType {
|
||||
Achievement = 0,
|
||||
GamerPic,
|
||||
Theme,
|
||||
AvatarItem,
|
||||
};
|
||||
|
||||
// The extracted 4J public headers only need the generic Linux/Windows-style
|
||||
// compatibility surface. Console backends still own their platform-specific
|
||||
// identity/content definitions elsewhere.
|
||||
#if !defined(__ORBIS__) && !defined(__PS3__) && !defined(__PSVITA__) && \
|
||||
!defined(_DURANGO)
|
||||
#ifndef XUSER_INDEX_ANY
|
||||
inline constexpr int XUSER_INDEX_ANY = 255;
|
||||
inline constexpr int XUSER_MAX_COUNT = 4;
|
||||
inline constexpr int XUSER_NAME_SIZE = 32;
|
||||
inline constexpr int XUSER_INDEX_FOCUS = 254;
|
||||
#endif
|
||||
|
||||
#ifndef XUSER_MAX_COUNT
|
||||
inline constexpr int XUSER_MAX_COUNT = 4;
|
||||
#endif
|
||||
|
||||
#ifndef XUSER_NAME_SIZE
|
||||
inline constexpr int XUSER_NAME_SIZE = 32;
|
||||
#endif
|
||||
|
||||
#ifndef XUSER_INDEX_FOCUS
|
||||
inline constexpr int XUSER_INDEX_FOCUS = 254;
|
||||
#endif
|
||||
|
||||
#ifndef FOURJ_COMMON_PLAYER_UID_DEFINED
|
||||
#define FOURJ_COMMON_PLAYER_UID_DEFINED
|
||||
using PlayerUID = unsigned long long;
|
||||
using PPlayerUID = PlayerUID*;
|
||||
inline constexpr PlayerUID INVALID_XUID = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class CXuiStringTable;
|
||||
|
||||
#if !defined(__ORBIS__) && !defined(__PS3__) && !defined(__PSVITA__) && \
|
||||
!defined(_DURANGO)
|
||||
#ifndef XCONTENT_MAX_DISPLAYNAME_LENGTH
|
||||
inline constexpr int XCONTENT_MAX_DISPLAYNAME_LENGTH = 256;
|
||||
inline constexpr int XCONTENT_MAX_FILENAME_LENGTH = 256;
|
||||
#endif
|
||||
|
||||
#ifndef XCONTENT_MAX_FILENAME_LENGTH
|
||||
inline constexpr int XCONTENT_MAX_FILENAME_LENGTH = 256;
|
||||
#endif
|
||||
|
||||
#ifndef FOURJ_COMMON_XCONTENT_DATA_DEFINED
|
||||
#define FOURJ_COMMON_XCONTENT_DATA_DEFINED
|
||||
using XCONTENTDEVICEID = int;
|
||||
|
||||
struct XCONTENT_DATA {
|
||||
@@ -78,9 +53,14 @@ struct XCONTENT_DATA {
|
||||
char szFileName[XCONTENT_MAX_FILENAME_LENGTH];
|
||||
};
|
||||
using PXCONTENT_DATA = XCONTENT_DATA*;
|
||||
#endif
|
||||
|
||||
#ifndef XMARKETPLACE_CONTENT_ID_LEN
|
||||
inline constexpr int XMARKETPLACE_CONTENT_ID_LEN = 4;
|
||||
#endif
|
||||
|
||||
#ifndef FOURJ_COMMON_XMARKETPLACE_DEFINED
|
||||
#define FOURJ_COMMON_XMARKETPLACE_DEFINED
|
||||
struct XMARKETPLACE_CONTENTOFFER_INFO {
|
||||
std::uint64_t qwOfferID;
|
||||
std::uint64_t qwPreviewOfferID;
|
||||
@@ -104,13 +84,45 @@ struct XMARKETPLACE_CONTENTOFFER_INFO {
|
||||
std::uint32_t dwPointsPrice;
|
||||
};
|
||||
using PXMARKETPLACE_CONTENTOFFER_INFO = XMARKETPLACE_CONTENTOFFER_INFO*;
|
||||
#endif
|
||||
|
||||
#ifndef XMARKETPLACE_OFFERING_TYPE_CONTENT
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_CONTENT = 0x00000002;
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_GAME_DEMO = 0x00000020;
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_GAME_TRAILER = 0x00000040;
|
||||
#endif
|
||||
|
||||
#ifndef XMARKETPLACE_OFFERING_TYPE_GAME_DEMO
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_GAME_DEMO =
|
||||
0x00000020;
|
||||
#endif
|
||||
|
||||
#ifndef XMARKETPLACE_OFFERING_TYPE_GAME_TRAILER
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_GAME_TRAILER =
|
||||
0x00000040;
|
||||
#endif
|
||||
|
||||
#ifndef XMARKETPLACE_OFFERING_TYPE_THEME
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_THEME = 0x00000080;
|
||||
#endif
|
||||
|
||||
#ifndef XMARKETPLACE_OFFERING_TYPE_TILE
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_TILE = 0x00000800;
|
||||
#endif
|
||||
|
||||
#ifndef XMARKETPLACE_OFFERING_TYPE_ARCADE
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_ARCADE = 0x00002000;
|
||||
#endif
|
||||
|
||||
#ifndef XMARKETPLACE_OFFERING_TYPE_VIDEO
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_VIDEO = 0x00004000;
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_CONSUMABLE = 0x00010000;
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_AVATARITEM = 0x00100000;
|
||||
#endif
|
||||
|
||||
#ifndef XMARKETPLACE_OFFERING_TYPE_CONSUMABLE
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_CONSUMABLE =
|
||||
0x00010000;
|
||||
#endif
|
||||
|
||||
#ifndef XMARKETPLACE_OFFERING_TYPE_AVATARITEM
|
||||
inline constexpr std::uint32_t XMARKETPLACE_OFFERING_TYPE_AVATARITEM =
|
||||
0x00100000;
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,25 +1,11 @@
|
||||
#include "Input.h"
|
||||
|
||||
#include "4J_Input.h"
|
||||
#include "../4J.Common/4J_InputActions.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL2/SDL_gamecontroller.h>
|
||||
#include <SDL2/SDL_joystick.h>
|
||||
#include <SDL2/SDL_keyboard.h>
|
||||
#include <SDL2/SDL_mouse.h>
|
||||
#include <SDL2/SDL_scancode.h>
|
||||
#include <SDL2/SDL_stdinc.h>
|
||||
#include <SDL2/SDL_video.h>
|
||||
#include <SDL2/begin_code.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <functional>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "../InputActions.h"
|
||||
#include "../PlatformTypes.h"
|
||||
|
||||
C_4JInput InputManager;
|
||||
|
||||
static const int KEY_COUNT = SDL_NUM_SCANCODES;
|
||||
@@ -52,7 +38,8 @@ static bool s_scrollSnapTaken = false;
|
||||
// Text input state (non-blocking keyboard)
|
||||
static bool s_keyboardActive = false;
|
||||
static std::string s_textInputBuf;
|
||||
static std::function<int(bool)> s_keyboardCallback;
|
||||
static int (*s_keyboardCallback)(void*, const bool) = nullptr;
|
||||
static void* s_keyboardCallbackParam = nullptr;
|
||||
|
||||
// We set all the watched keys
|
||||
// I don't know if I'll need to change this if we add chat support soon.
|
||||
@@ -357,8 +344,9 @@ void C_4JInput::Tick() {
|
||||
s_keysCurrent[SDL_SCANCODE_RETURN] = false;
|
||||
s_keysCurrent[SDL_SCANCODE_KP_ENTER] = false;
|
||||
if (s_keyboardCallback) {
|
||||
s_keyboardCallback(true);
|
||||
s_keyboardCallback(s_keyboardCallbackParam, true);
|
||||
s_keyboardCallback = nullptr;
|
||||
s_keyboardCallbackParam = nullptr;
|
||||
}
|
||||
} else if (KPressed(SDL_SCANCODE_ESCAPE)) {
|
||||
s_keyboardActive = false;
|
||||
@@ -367,8 +355,9 @@ void C_4JInput::Tick() {
|
||||
// Consume the key so it doesn't also trigger ACTION_MENU_CANCEL
|
||||
s_keysCurrent[SDL_SCANCODE_ESCAPE] = false;
|
||||
if (s_keyboardCallback) {
|
||||
s_keyboardCallback(false);
|
||||
s_keyboardCallback(s_keyboardCallbackParam, false);
|
||||
s_keyboardCallback = nullptr;
|
||||
s_keyboardCallbackParam = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -640,19 +629,21 @@ void C_4JInput::SetJoypadSensitivity(int, float) {}
|
||||
void C_4JInput::SetJoypadStickAxisMap(int, unsigned int, unsigned int) {}
|
||||
void C_4JInput::SetJoypadStickTriggerMap(int, unsigned int, unsigned int) {}
|
||||
void C_4JInput::SetKeyRepeatRate(float, float) {}
|
||||
void C_4JInput::SetDebugSequence(const char*, std::function<int()>) {}
|
||||
void C_4JInput::SetDebugSequence(const char*, int (*)(void*), void*) {}
|
||||
float C_4JInput::GetIdleSeconds(int) { return 0.f; }
|
||||
bool C_4JInput::IsPadConnected(int iPad) { return iPad == 0; }
|
||||
|
||||
EKeyboardResult C_4JInput::RequestKeyboard(const wchar_t*, const wchar_t*, int,
|
||||
unsigned int,
|
||||
std::function<int(bool)> callback,
|
||||
int (*callback)(void*, const bool),
|
||||
void* scene,
|
||||
C_4JInput::EKeyboardMode) {
|
||||
s_keyboardActive = true;
|
||||
s_textInputBuf.clear();
|
||||
s_keyboardCallback = std::move(callback);
|
||||
s_keyboardCallback = callback;
|
||||
s_keyboardCallbackParam = scene;
|
||||
SDL_StartTextInput();
|
||||
return EKeyboardResult::Pending;
|
||||
return EKeyboard_Pending;
|
||||
}
|
||||
bool C_4JInput::GetMenuDisplayed(int iPad) {
|
||||
if (iPad >= 0 && iPad < 4) return s_menuDisplayed[iPad];
|
||||
@@ -660,16 +651,10 @@ bool C_4JInput::GetMenuDisplayed(int iPad) {
|
||||
}
|
||||
const char* C_4JInput::GetText() { return s_textInputBuf.c_str(); }
|
||||
bool C_4JInput::VerifyStrings(wchar_t**, int,
|
||||
std::function<int(STRING_VERIFY_RESPONSE*)>) {
|
||||
int (*)(void*, STRING_VERIFY_RESPONSE*), void*) {
|
||||
return true;
|
||||
}
|
||||
void C_4JInput::CancelQueuedVerifyStrings(
|
||||
std::function<int(STRING_VERIFY_RESPONSE*)>) {}
|
||||
void C_4JInput::CancelQueuedVerifyStrings(int (*)(void*,
|
||||
STRING_VERIFY_RESPONSE*),
|
||||
void*) {}
|
||||
void C_4JInput::CancelAllVerifyInProgress() {}
|
||||
|
||||
// Primary pad (moved from Profile)
|
||||
namespace {
|
||||
int s_inputPrimaryPad = 0;
|
||||
}
|
||||
int C_4JInput::GetPrimaryPad() { return s_inputPrimaryPad; }
|
||||
void C_4JInput::SetPrimaryPad(int iPad) { s_inputPrimaryPad = iPad; }
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "../IPlatformInput.h"
|
||||
|
||||
#define MAP_STYLE_0 0
|
||||
#define MAP_STYLE_1 1
|
||||
#define MAP_STYLE_2 2
|
||||
@@ -49,8 +47,31 @@
|
||||
#define TRIGGER_MAP_0 0
|
||||
#define TRIGGER_MAP_1 1
|
||||
|
||||
class C_4JInput : public IPlatformInput {
|
||||
enum EKeyboardResult {
|
||||
EKeyboard_Pending,
|
||||
EKeyboard_Cancelled,
|
||||
EKeyboard_ResultAccept,
|
||||
EKeyboard_ResultDecline,
|
||||
};
|
||||
|
||||
typedef struct _STRING_VERIFY_RESPONSE {
|
||||
std::uint16_t wNumStrings;
|
||||
int* pStringResult;
|
||||
} STRING_VERIFY_RESPONSE;
|
||||
|
||||
class C_4JInput {
|
||||
public:
|
||||
enum EKeyboardMode {
|
||||
EKeyboardMode_Default,
|
||||
EKeyboardMode_Numeric,
|
||||
EKeyboardMode_Password,
|
||||
EKeyboardMode_Alphabet,
|
||||
EKeyboardMode_Full,
|
||||
EKeyboardMode_Alphabet_Extended,
|
||||
EKeyboardMode_IP_Address,
|
||||
EKeyboardMode_Phone
|
||||
};
|
||||
|
||||
void Initialise(int iInputStateC, unsigned char ucMapC,
|
||||
unsigned char ucActionC, unsigned char ucMenuActionC);
|
||||
void Tick(void);
|
||||
@@ -75,8 +96,8 @@ public:
|
||||
void SetJoypadStickTriggerMap(int iPad, unsigned int uiFrom,
|
||||
unsigned int uiTo);
|
||||
void SetKeyRepeatRate(float fRepeatDelaySecs, float fRepeatRateSecs);
|
||||
void SetDebugSequence(const char* chSequenceA,
|
||||
std::function<int()> callback);
|
||||
void SetDebugSequence(const char* chSequenceA, int (*Func)(void*),
|
||||
void* lpParam);
|
||||
float GetIdleSeconds(int iPad);
|
||||
bool IsPadConnected(int iPad);
|
||||
|
||||
@@ -97,7 +118,8 @@ public:
|
||||
// live here. The remaining public API keeps the direct text/callback form.
|
||||
EKeyboardResult RequestKeyboard(const wchar_t* Title, const wchar_t* Text,
|
||||
int iPad, unsigned int uiMaxChars,
|
||||
std::function<int(bool)> callback,
|
||||
int (*Func)(void*, const bool),
|
||||
void* lpParam,
|
||||
C_4JInput::EKeyboardMode eMode);
|
||||
bool GetMenuDisplayed(int);
|
||||
const char* GetText();
|
||||
@@ -126,18 +148,15 @@ public:
|
||||
//
|
||||
// Intent Protect players from inappropriate language.
|
||||
bool VerifyStrings(wchar_t** pwStringA, int iStringC,
|
||||
std::function<int(STRING_VERIFY_RESPONSE*)> callback);
|
||||
void CancelQueuedVerifyStrings(
|
||||
std::function<int(STRING_VERIFY_RESPONSE*)> callback);
|
||||
int (*Func)(void*, STRING_VERIFY_RESPONSE*),
|
||||
void* lpParam);
|
||||
void CancelQueuedVerifyStrings(int (*Func)(void*, STRING_VERIFY_RESPONSE*),
|
||||
void* lpParam);
|
||||
void CancelAllVerifyInProgress(void);
|
||||
|
||||
int GetMouseX();
|
||||
int GetMouseY();
|
||||
|
||||
// Primary pad (moved from Profile)
|
||||
int GetPrimaryPad();
|
||||
void SetPrimaryPad(int iPad);
|
||||
|
||||
// bool InputDetected(int userIndex, wchar_t* inputText);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
input_sources = files(
|
||||
'4J_Input.cpp',
|
||||
'INP_ForceFeedback.cpp',
|
||||
'INP_Keyboard.cpp',
|
||||
'INP_Main.cpp',
|
||||
'INP_StringCheck.cpp',
|
||||
'stdafx.cpp',
|
||||
)
|
||||
|
||||
lib_input = static_library('4J_Input',
|
||||
input_sources,
|
||||
include_directories : include_directories('.'),
|
||||
cpp_args : global_cpp_args + global_cpp_defs + [
|
||||
'-include', meson.current_source_dir() / 'stdafx.h',
|
||||
],
|
||||
)
|
||||
|
||||
# We import SDL2 but not SDL3.. which is a bit sad,
|
||||
sdl_dep = dependency('sdl2', required : false)
|
||||
|
||||
input_dep = declare_dependency(
|
||||
link_with : lib_input,
|
||||
dependencies : [sdl_dep],
|
||||
include_directories : include_directories('.'),
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
#include "stdafx.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _4J_INPUT_STADAFX_H
|
||||
#define _4J_INPUT_STADAFX_H
|
||||
|
||||
#include "../4J.Common/4J_Compat.h"
|
||||
|
||||
#endif //_4J_INPUT_STADAFX_H
|
||||
@@ -0,0 +1,273 @@
|
||||
#include "4J_Profile.h"
|
||||
#include "../4J.Common/4J_ProfileConstants.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
C_4JProfile ProfileManager;
|
||||
|
||||
namespace {
|
||||
constexpr PlayerUID kFakeXuidBase = 0xe000d45248242f2eULL;
|
||||
|
||||
struct ProfileGameSettings {
|
||||
bool bSettingsChanged;
|
||||
unsigned char ucMusicVolume;
|
||||
unsigned char ucSoundFXVolume;
|
||||
unsigned char ucSensitivity;
|
||||
unsigned char ucGamma;
|
||||
unsigned char ucPad01;
|
||||
unsigned short usBitmaskValues;
|
||||
unsigned int uiDebugBitmask;
|
||||
union {
|
||||
struct {
|
||||
unsigned char ucTutorialCompletion[TUTORIAL_PROFILE_STORAGE_BYTES];
|
||||
std::uint32_t dwSelectedSkin;
|
||||
unsigned char ucMenuSensitivity;
|
||||
unsigned char ucInterfaceOpacity;
|
||||
unsigned char ucPad02;
|
||||
unsigned char usPad03;
|
||||
unsigned int uiBitmaskValues;
|
||||
unsigned int uiSpecialTutorialBitmask;
|
||||
std::uint32_t dwSelectedCape;
|
||||
unsigned int uiFavoriteSkinA[MAX_FAVORITE_SKINS];
|
||||
unsigned char ucCurrentFavoriteSkinPos;
|
||||
unsigned int uiMashUpPackWorldsDisplay;
|
||||
unsigned char ucLanguage;
|
||||
};
|
||||
|
||||
unsigned char ucReservedSpace[192];
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(ProfileGameSettings) == 204,
|
||||
"ProfileGameSettings must match GAME_SETTINGS profile storage");
|
||||
|
||||
void* s_profileData[XUSER_MAX_COUNT] = {};
|
||||
C_4JProfile::PROFILESETTINGS s_dashboardSettings[XUSER_MAX_COUNT] = {};
|
||||
char s_gamertags[XUSER_MAX_COUNT][16] = {};
|
||||
std::wstring s_displayNames[XUSER_MAX_COUNT];
|
||||
int s_primaryPad = 0;
|
||||
int s_lockedProfile = 0;
|
||||
bool s_profileIsFullVersion = true;
|
||||
int (*s_defaultOptionsCallback)(void*, C_4JProfile::PROFILESETTINGS*,
|
||||
const int iPad) = nullptr;
|
||||
void* s_defaultOptionsCallbackParam = nullptr;
|
||||
|
||||
bool isValidPad(int iPad) { return iPad >= 0 && iPad < XUSER_MAX_COUNT; }
|
||||
|
||||
void ensureFakeIdentity(int iPad) {
|
||||
if (!isValidPad(iPad) || s_gamertags[iPad][0] != '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
std::snprintf(s_gamertags[iPad], sizeof(s_gamertags[iPad]), "Player%d",
|
||||
iPad + 1);
|
||||
s_displayNames[iPad] = std::wstring(L"Player") + std::to_wstring(iPad + 1);
|
||||
}
|
||||
|
||||
void initialiseDefaultGameSettings(ProfileGameSettings* gameSettings) {
|
||||
gameSettings->ucMenuSensitivity = 100;
|
||||
gameSettings->ucInterfaceOpacity = 80;
|
||||
gameSettings->usBitmaskValues |= 0x0200;
|
||||
gameSettings->usBitmaskValues |= 0x0400;
|
||||
gameSettings->usBitmaskValues |= 0x1000;
|
||||
gameSettings->usBitmaskValues |= 0x8000;
|
||||
gameSettings->uiBitmaskValues = 0L;
|
||||
gameSettings->uiBitmaskValues |= GAMESETTING_CLOUDS;
|
||||
gameSettings->uiBitmaskValues |= GAMESETTING_ONLINE;
|
||||
gameSettings->uiBitmaskValues |= GAMESETTING_FRIENDSOFFRIENDS;
|
||||
gameSettings->uiBitmaskValues |= GAMESETTING_DISPLAYUPDATEMSG;
|
||||
gameSettings->uiBitmaskValues &= ~GAMESETTING_BEDROCKFOG;
|
||||
gameSettings->uiBitmaskValues |= GAMESETTING_DISPLAYHUD;
|
||||
gameSettings->uiBitmaskValues |= GAMESETTING_DISPLAYHAND;
|
||||
gameSettings->uiBitmaskValues |= GAMESETTING_CUSTOMSKINANIM;
|
||||
gameSettings->uiBitmaskValues |= GAMESETTING_DEATHMESSAGES;
|
||||
gameSettings->uiBitmaskValues |= (GAMESETTING_UISIZE & 0x00000800);
|
||||
gameSettings->uiBitmaskValues |=
|
||||
(GAMESETTING_UISIZE_SPLITSCREEN & 0x00004000);
|
||||
gameSettings->uiBitmaskValues |= GAMESETTING_ANIMATEDCHARACTER;
|
||||
|
||||
for (int i = 0; i < MAX_FAVORITE_SKINS; ++i) {
|
||||
gameSettings->uiFavoriteSkinA[i] = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
gameSettings->ucCurrentFavoriteSkinPos = 0;
|
||||
gameSettings->uiMashUpPackWorldsDisplay = 0xFFFFFFFF;
|
||||
gameSettings->uiBitmaskValues &= ~GAMESETTING_PS3EULAREAD;
|
||||
gameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT;
|
||||
gameSettings->uiBitmaskValues &= ~GAMESETTING_PSVITANETWORKMODEADHOC;
|
||||
gameSettings->ucTutorialCompletion[0] = 0xFF;
|
||||
gameSettings->ucTutorialCompletion[1] = 0xFF;
|
||||
gameSettings->ucTutorialCompletion[2] = 0x0F;
|
||||
gameSettings->ucTutorialCompletion[28] |= 1 << 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void C_4JProfile::Initialise(std::uint32_t dwTitleID, std::uint32_t dwOfferID,
|
||||
unsigned short usProfileVersion,
|
||||
unsigned int uiProfileValuesC,
|
||||
unsigned int uiProfileSettingsC,
|
||||
std::uint32_t* pdwProfileSettingsA,
|
||||
int iGameDefinedDataSizeX4,
|
||||
unsigned int* puiGameDefinedDataChangedBitmask) {
|
||||
s_primaryPad = 0;
|
||||
s_lockedProfile = 0;
|
||||
std::memset(s_dashboardSettings, 0, sizeof(s_dashboardSettings));
|
||||
|
||||
for (int i = 0; i < XUSER_MAX_COUNT; ++i) {
|
||||
delete[] static_cast<unsigned char*>(s_profileData[i]);
|
||||
s_profileData[i] = new unsigned char[iGameDefinedDataSizeX4 / 4];
|
||||
std::memset(s_profileData[i], 0, iGameDefinedDataSizeX4 / 4);
|
||||
initialiseDefaultGameSettings(
|
||||
static_cast<ProfileGameSettings*>(s_profileData[i]));
|
||||
ensureFakeIdentity(i);
|
||||
}
|
||||
}
|
||||
void C_4JProfile::SetTrialTextStringTable(CXuiStringTable* pStringTable,
|
||||
int iAccept, int iReject) {}
|
||||
void C_4JProfile::SetTrialAwardText(eAwardType AwardType, int iTitle,
|
||||
int iText) {}
|
||||
int C_4JProfile::GetLockedProfile() { return s_lockedProfile; }
|
||||
void C_4JProfile::SetLockedProfile(int iProf) { s_lockedProfile = iProf; }
|
||||
bool C_4JProfile::IsSignedIn(int iQuadrant) { return iQuadrant == 0; }
|
||||
bool C_4JProfile::IsSignedInLive(int iProf) { return IsSignedIn(iProf); }
|
||||
bool C_4JProfile::IsGuest(int iQuadrant) { return false; }
|
||||
unsigned int C_4JProfile::RequestSignInUI(
|
||||
bool bFromInvite, bool bLocalGame, bool bNoGuestsAllowed,
|
||||
bool bMultiplayerSignIn, bool bAddUser,
|
||||
int (*Func)(void*, const bool, const int iPad), void* lpParam,
|
||||
int iQuadrant) {
|
||||
return 0;
|
||||
}
|
||||
unsigned int C_4JProfile::DisplayOfflineProfile(int (*Func)(void*, const bool,
|
||||
const int iPad),
|
||||
void* lpParam, int iQuadrant) {
|
||||
return 0;
|
||||
}
|
||||
unsigned int C_4JProfile::RequestConvertOfflineToGuestUI(
|
||||
int (*Func)(void*, const bool, const int iPad), void* lpParam,
|
||||
int iQuadrant) {
|
||||
return 0;
|
||||
}
|
||||
void C_4JProfile::SetPrimaryPlayerChanged(bool bVal) {}
|
||||
bool C_4JProfile::QuerySigninStatus(void) { return true; }
|
||||
void C_4JProfile::GetXUID(int iPad, PlayerUID* pXuid, bool bOnlineXuid) {
|
||||
if (pXuid)
|
||||
*pXuid =
|
||||
kFakeXuidBase + static_cast<PlayerUID>(isValidPad(iPad) ? iPad : 0);
|
||||
}
|
||||
bool C_4JProfile::AreXUIDSEqual(PlayerUID xuid1, PlayerUID xuid2) {
|
||||
return xuid1 == xuid2;
|
||||
}
|
||||
bool C_4JProfile::XUIDIsGuest(PlayerUID xuid) { return false; }
|
||||
bool C_4JProfile::AllowedToPlayMultiplayer(int iProf) { return true; }
|
||||
bool C_4JProfile::GetChatAndContentRestrictions(int iPad,
|
||||
bool* pbChatRestricted,
|
||||
bool* pbContentRestricted,
|
||||
int* piAge) {
|
||||
if (pbChatRestricted) *pbChatRestricted = false;
|
||||
if (pbContentRestricted) *pbContentRestricted = false;
|
||||
if (piAge) *piAge = 18;
|
||||
return true;
|
||||
}
|
||||
void C_4JProfile::StartTrialGame() {}
|
||||
void C_4JProfile::AllowedPlayerCreatedContent(int iPad, bool thisQuadrantOnly,
|
||||
bool* allAllowed,
|
||||
bool* friendsAllowed) {
|
||||
if (allAllowed) *allAllowed = true;
|
||||
if (friendsAllowed) *friendsAllowed = true;
|
||||
}
|
||||
bool C_4JProfile::CanViewPlayerCreatedContent(int iPad, bool thisQuadrantOnly,
|
||||
PlayerUID* pXuids,
|
||||
unsigned int xuidCount) {
|
||||
return true;
|
||||
}
|
||||
void C_4JProfile::ShowProfileCard(int iPad, PlayerUID targetUid) {}
|
||||
bool C_4JProfile::GetProfileAvatar(int iPad,
|
||||
int (*Func)(void* lpParam,
|
||||
std::uint8_t* thumbnailData,
|
||||
unsigned int thumbnailBytes),
|
||||
void* lpParam) {
|
||||
return false;
|
||||
}
|
||||
void C_4JProfile::CancelProfileAvatarRequest() {}
|
||||
int C_4JProfile::GetPrimaryPad() { return s_primaryPad; }
|
||||
void C_4JProfile::SetPrimaryPad(int iPad) { s_primaryPad = iPad; }
|
||||
|
||||
char* C_4JProfile::GetGamertag(int iPad) {
|
||||
const int resolvedPad = isValidPad(iPad) ? iPad : 0;
|
||||
ensureFakeIdentity(resolvedPad);
|
||||
return s_gamertags[resolvedPad];
|
||||
}
|
||||
std::wstring C_4JProfile::GetDisplayName(int iPad) {
|
||||
const int resolvedPad = isValidPad(iPad) ? iPad : 0;
|
||||
ensureFakeIdentity(resolvedPad);
|
||||
return s_displayNames[resolvedPad];
|
||||
}
|
||||
bool C_4JProfile::IsFullVersion() { return s_profileIsFullVersion; }
|
||||
void C_4JProfile::SetSignInChangeCallback(void (*Func)(void*, bool,
|
||||
unsigned int),
|
||||
void* lpParam) {}
|
||||
void C_4JProfile::SetNotificationsCallback(void (*Func)(void*, std::uint32_t,
|
||||
unsigned int),
|
||||
void* lpParam) {}
|
||||
bool C_4JProfile::RegionIsNorthAmerica(void) { return false; }
|
||||
bool C_4JProfile::LocaleIsUSorCanada(void) { return false; }
|
||||
int C_4JProfile::GetLiveConnectionStatus() { return 0; }
|
||||
bool C_4JProfile::IsSystemUIDisplayed() { return false; }
|
||||
void C_4JProfile::SetProfileReadErrorCallback(void (*Func)(void*),
|
||||
void* lpParam) {}
|
||||
int C_4JProfile::SetDefaultOptionsCallback(int (*Func)(void*, PROFILESETTINGS*,
|
||||
const int iPad),
|
||||
void* lpParam) {
|
||||
s_defaultOptionsCallback = Func;
|
||||
s_defaultOptionsCallbackParam = lpParam;
|
||||
return 0;
|
||||
}
|
||||
int C_4JProfile::SetOldProfileVersionCallback(int (*Func)(void*, unsigned char*,
|
||||
const unsigned short,
|
||||
const int),
|
||||
void* lpParam) {
|
||||
return 0;
|
||||
}
|
||||
C_4JProfile::PROFILESETTINGS* C_4JProfile::GetDashboardProfileSettings(
|
||||
int iPad) {
|
||||
return &s_dashboardSettings[isValidPad(iPad) ? iPad : 0];
|
||||
}
|
||||
void C_4JProfile::WriteToProfile(int iQuadrant, bool bGameDefinedDataChanged,
|
||||
bool bOverride5MinuteLimitOnProfileWrites) {}
|
||||
void C_4JProfile::ForceQueuedProfileWrites(int iPad) {}
|
||||
void* C_4JProfile::GetGameDefinedProfileData(int iQuadrant) {
|
||||
return isValidPad(iQuadrant) ? s_profileData[iQuadrant] : nullptr;
|
||||
}
|
||||
void C_4JProfile::ResetProfileProcessState() {}
|
||||
void C_4JProfile::Tick(void) {}
|
||||
void C_4JProfile::RegisterAward(int iAwardNumber, int iGamerconfigID,
|
||||
eAwardType eType, bool bLeaderboardAffected,
|
||||
CXuiStringTable* pStringTable, int iTitleStr,
|
||||
int iTextStr, int iAcceptStr,
|
||||
char* pszThemeName, unsigned int uiThemeSize) {}
|
||||
int C_4JProfile::GetAwardId(int iAwardNumber) { return 0; }
|
||||
eAwardType C_4JProfile::GetAwardType(int iAwardNumber) {
|
||||
return eAwardType_Achievement;
|
||||
}
|
||||
bool C_4JProfile::CanBeAwarded(int iQuadrant, int iAwardNumber) {
|
||||
return false;
|
||||
}
|
||||
void C_4JProfile::Award(int iQuadrant, int iAwardNumber, bool bForce) {}
|
||||
bool C_4JProfile::IsAwardsFlagSet(int iQuadrant, int iAward) { return false; }
|
||||
void C_4JProfile::RichPresenceInit(int iPresenceCount, int iContextCount) {}
|
||||
void C_4JProfile::RegisterRichPresenceContext(int iGameConfigContextID) {}
|
||||
void C_4JProfile::SetRichPresenceContextValue(int iPad, int iContextID,
|
||||
int iVal) {}
|
||||
void C_4JProfile::SetCurrentGameActivity(int iPad, int iNewPresence,
|
||||
bool bSetOthersToIdle) {}
|
||||
void C_4JProfile::DisplayFullVersionPurchase(bool bRequired, int iQuadrant,
|
||||
int iUpsellParam) {}
|
||||
void C_4JProfile::SetUpsellCallback(void (*Func)(void* lpParam,
|
||||
eUpsellType type,
|
||||
eUpsellResponse response,
|
||||
int iUserData),
|
||||
void* lpParam) {}
|
||||
void C_4JProfile::SetDebugFullOverride(bool bVal) {
|
||||
s_profileIsFullVersion = bVal;
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "../4J.Common/4J_Compat.h"
|
||||
|
||||
enum eAwardType {
|
||||
eAwardType_Achievement = 0,
|
||||
eAwardType_GamerPic,
|
||||
eAwardType_Theme,
|
||||
eAwardType_AvatarItem,
|
||||
};
|
||||
|
||||
enum eUpsellType {
|
||||
eUpsellType_Custom = 0, // This is the default, and means that the upsell
|
||||
// dialog was initiated in the app code
|
||||
eUpsellType_Achievement,
|
||||
eUpsellType_GamerPic,
|
||||
eUpsellType_Theme,
|
||||
eUpsellType_AvatarItem,
|
||||
};
|
||||
|
||||
enum eUpsellResponse {
|
||||
eUpsellResponse_Declined,
|
||||
eUpsellResponse_Accepted_NoPurchase,
|
||||
eUpsellResponse_Accepted_Purchase,
|
||||
};
|
||||
|
||||
class C_4JProfile {
|
||||
public:
|
||||
struct PROFILESETTINGS {
|
||||
int iYAxisInversion;
|
||||
int iControllerSensitivity;
|
||||
int iVibration;
|
||||
bool bSwapSticks;
|
||||
};
|
||||
|
||||
// 4 players have game defined data, puiGameDefinedDataChangedBitmask needs
|
||||
// to be checked by the game side to see if there's an update needed - it'll
|
||||
// have the bits set for players to be updated
|
||||
void Initialise(std::uint32_t dwTitleID, std::uint32_t dwOfferID,
|
||||
unsigned short usProfileVersion,
|
||||
unsigned int uiProfileValuesC,
|
||||
unsigned int uiProfileSettingsC,
|
||||
std::uint32_t* pdwProfileSettingsA,
|
||||
int iGameDefinedDataSizeX4,
|
||||
unsigned int* puiGameDefinedDataChangedBitmask);
|
||||
void SetTrialTextStringTable(CXuiStringTable* pStringTable, int iAccept,
|
||||
int iReject);
|
||||
void SetTrialAwardText(eAwardType AwardType, int iTitle,
|
||||
int iText); // achievement popup in the trial game
|
||||
int GetLockedProfile();
|
||||
void SetLockedProfile(int iProf);
|
||||
bool IsSignedIn(int iQuadrant);
|
||||
bool IsSignedInLive(int iProf);
|
||||
bool IsGuest(int iQuadrant);
|
||||
unsigned int RequestSignInUI(bool bFromInvite, bool bLocalGame,
|
||||
bool bNoGuestsAllowed, bool bMultiplayerSignIn,
|
||||
bool bAddUser,
|
||||
int (*Func)(void*, const bool, const int iPad),
|
||||
void* lpParam,
|
||||
int iQuadrant = XUSER_INDEX_ANY);
|
||||
unsigned int DisplayOfflineProfile(int (*Func)(void*, const bool,
|
||||
const int iPad),
|
||||
void* lpParam,
|
||||
int iQuadrant = XUSER_INDEX_ANY);
|
||||
unsigned int RequestConvertOfflineToGuestUI(
|
||||
int (*Func)(void*, const bool, const int iPad), void* lpParam,
|
||||
int iQuadrant = XUSER_INDEX_ANY);
|
||||
void SetPrimaryPlayerChanged(bool bVal);
|
||||
bool QuerySigninStatus(void);
|
||||
void GetXUID(int iPad, PlayerUID* pXuid, bool bOnlineXuid);
|
||||
bool AreXUIDSEqual(PlayerUID xuid1, PlayerUID xuid2);
|
||||
bool XUIDIsGuest(PlayerUID xuid);
|
||||
bool AllowedToPlayMultiplayer(int iProf);
|
||||
bool GetChatAndContentRestrictions(int iPad, bool* pbChatRestricted,
|
||||
bool* pbContentRestricted, int* piAge);
|
||||
void StartTrialGame(); // disables saves and leaderboard, and change state
|
||||
// to readyforgame from pregame
|
||||
void AllowedPlayerCreatedContent(int iPad, bool thisQuadrantOnly,
|
||||
bool* allAllowed, bool* friendsAllowed);
|
||||
bool CanViewPlayerCreatedContent(int iPad, bool thisQuadrantOnly,
|
||||
PlayerUID* pXuids, unsigned int xuidCount);
|
||||
void ShowProfileCard(int iPad, PlayerUID targetUid);
|
||||
bool GetProfileAvatar(int iPad,
|
||||
int (*Func)(void* lpParam,
|
||||
std::uint8_t* thumbnailData,
|
||||
unsigned int thumbnailBytes),
|
||||
void* lpParam);
|
||||
void CancelProfileAvatarRequest();
|
||||
|
||||
// SYS
|
||||
int GetPrimaryPad();
|
||||
void SetPrimaryPad(int iPad);
|
||||
char* GetGamertag(int iPad);
|
||||
std::wstring GetDisplayName(int iPad);
|
||||
bool IsFullVersion();
|
||||
void SetSignInChangeCallback(void (*Func)(void*, bool, unsigned int),
|
||||
void* lpParam);
|
||||
void SetNotificationsCallback(void (*Func)(void*, std::uint32_t,
|
||||
unsigned int),
|
||||
void* lpParam);
|
||||
bool RegionIsNorthAmerica(void);
|
||||
bool LocaleIsUSorCanada(void);
|
||||
int GetLiveConnectionStatus();
|
||||
bool IsSystemUIDisplayed();
|
||||
void SetProfileReadErrorCallback(void (*Func)(void*), void* lpParam);
|
||||
|
||||
// PROFILE DATA
|
||||
int SetDefaultOptionsCallback(int (*Func)(void*, PROFILESETTINGS*,
|
||||
const int iPad),
|
||||
void* lpParam);
|
||||
int SetOldProfileVersionCallback(int (*Func)(void*, unsigned char*,
|
||||
const unsigned short,
|
||||
const int),
|
||||
void* lpParam);
|
||||
PROFILESETTINGS* GetDashboardProfileSettings(int iPad);
|
||||
void WriteToProfile(int iQuadrant, bool bGameDefinedDataChanged = false,
|
||||
bool bOverride5MinuteLimitOnProfileWrites = false);
|
||||
void ForceQueuedProfileWrites(int iPad = XUSER_INDEX_ANY);
|
||||
void* GetGameDefinedProfileData(int iQuadrant);
|
||||
void ResetProfileProcessState(); // after a sign out from the primary
|
||||
// player, call this
|
||||
void Tick(void);
|
||||
|
||||
// ACHIEVEMENTS & AWARDS
|
||||
|
||||
void RegisterAward(int iAwardNumber, int iGamerconfigID, eAwardType eType,
|
||||
bool bLeaderboardAffected = false,
|
||||
CXuiStringTable* pStringTable = nullptr,
|
||||
int iTitleStr = -1, int iTextStr = -1,
|
||||
int iAcceptStr = -1, char* pszThemeName = nullptr,
|
||||
unsigned int uiThemeSize = 0L);
|
||||
int GetAwardId(int iAwardNumber);
|
||||
eAwardType GetAwardType(int iAwardNumber);
|
||||
bool CanBeAwarded(int iQuadrant, int iAwardNumber);
|
||||
void Award(int iQuadrant, int iAwardNumber, bool bForce = false);
|
||||
bool IsAwardsFlagSet(int iQuadrant, int iAward);
|
||||
|
||||
// RICH PRESENCE
|
||||
|
||||
void RichPresenceInit(int iPresenceCount, int iContextCount);
|
||||
void RegisterRichPresenceContext(int iGameConfigContextID);
|
||||
void SetRichPresenceContextValue(int iPad, int iContextID, int iVal);
|
||||
void SetCurrentGameActivity(int iPad, int iNewPresence,
|
||||
bool bSetOthersToIdle = false);
|
||||
|
||||
// PURCHASE
|
||||
void DisplayFullVersionPurchase(bool bRequired, int iQuadrant,
|
||||
int iUpsellParam = -1);
|
||||
void SetUpsellCallback(void (*Func)(void* lpParam, eUpsellType type,
|
||||
eUpsellResponse response,
|
||||
int iUserData),
|
||||
void* lpParam);
|
||||
|
||||
// Debug
|
||||
void SetDebugFullOverride(
|
||||
bool bVal); // To override the license version (trail/full). Only in
|
||||
// debug/release, not ContentPackage
|
||||
};
|
||||
|
||||
// Singleton
|
||||
extern C_4JProfile ProfileManager;
|
||||
@@ -0,0 +1,22 @@
|
||||
profile_sources = files(
|
||||
'4J_Profile.cpp',
|
||||
'PRO_AwardManager.cpp',
|
||||
'PRO_Data.cpp',
|
||||
'PRO_Main.cpp',
|
||||
'PRO_RichPresence.cpp',
|
||||
'PRO_Sys.cpp',
|
||||
'stdafx.cpp',
|
||||
)
|
||||
# 4jprofile stink
|
||||
lib_profile = static_library('4J_Profile',
|
||||
profile_sources,
|
||||
include_directories : include_directories('.'),
|
||||
cpp_args : global_cpp_args + global_cpp_defs + [
|
||||
'-include', meson.current_source_dir() / 'stdafx.h',
|
||||
],
|
||||
)
|
||||
|
||||
profile_dep = declare_dependency(
|
||||
link_with : lib_profile,
|
||||
include_directories : include_directories('.'),
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
#include "stdafx.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _4J_PROFILE_STADAFX_H
|
||||
#define _4J_PROFILE_STADAFX_H
|
||||
|
||||
#include "../4J.Common/4J_Compat.h"
|
||||
|
||||
#endif //_4J_PROFILE_STADAFX_H
|
||||
@@ -1,12 +1,5 @@
|
||||
#include "Render.h"
|
||||
|
||||
#include "../PlatformTypes.h"
|
||||
#include "SDL.h"
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_events.h"
|
||||
#include "SDL_stdinc.h"
|
||||
#include "SDL_video.h"
|
||||
#include "gl3_loader.h"
|
||||
#include "4J_Render.h"
|
||||
|
||||
// undefine macros from header to avoid argument mismatch
|
||||
#undef glGenTextures
|
||||
@@ -23,33 +16,23 @@
|
||||
#undef glVertexPointer
|
||||
#undef glGenQueriesARB
|
||||
#undef glGetQueryObjectuARB
|
||||
#undef glEnable
|
||||
#undef glDisable
|
||||
#undef glBlendFunc
|
||||
#undef glDepthMask
|
||||
#undef glColorMask
|
||||
#undef glLineWidth
|
||||
#undef glFrontFace
|
||||
#undef glPolygonOffset
|
||||
#undef glStencilFunc
|
||||
#undef glStencilMask
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <pthread.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
C4JRender RenderManager;
|
||||
|
||||
@@ -59,20 +42,17 @@ C4JRender RenderManager;
|
||||
|
||||
#ifdef GLES
|
||||
static const char* VERT_SRC =
|
||||
#include "sdl2/shaders/vertex_es.vert"
|
||||
|
||||
#include "shaders/vertex_es.vert"
|
||||
;
|
||||
static const char* FRAG_SRC =
|
||||
#include "sdl2/shaders/fragment_es.frag"
|
||||
|
||||
#include "shaders/fragment_es.frag"
|
||||
;
|
||||
#else
|
||||
static const char* VERT_SRC =
|
||||
#include "sdl2/shaders/vertex.vert"
|
||||
|
||||
#include "shaders/vertex.vert"
|
||||
;
|
||||
static const char* FRAG_SRC =
|
||||
#include "sdl2/shaders/fragment.frag"
|
||||
#include "shaders/fragment.frag"
|
||||
;
|
||||
#endif
|
||||
|
||||
@@ -102,45 +82,7 @@ static pthread_mutex_t s_sharedMtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t s_glCallMtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_t s_mainThread;
|
||||
static bool s_mainThreadSet = false;
|
||||
static thread_local unsigned int s_rs_dirty_mask = 0xFFFFFFFF;
|
||||
|
||||
struct GLShadowState {
|
||||
bool blend;
|
||||
bool cull;
|
||||
bool depth;
|
||||
bool polygon;
|
||||
bool stencil;
|
||||
GLint blendSrc;
|
||||
GLint blendDst;
|
||||
GLboolean depthMask;
|
||||
GLboolean colorMask[4];
|
||||
float lineWidth;
|
||||
GLenum frontFace;
|
||||
float polySlope;
|
||||
float polyBias;
|
||||
GLenum stencilFunc;
|
||||
GLint stencilRef;
|
||||
GLuint stencilMask;
|
||||
GLuint stencilWriteMask;
|
||||
};
|
||||
|
||||
static GLShadowState s_gl_state;
|
||||
static unsigned int s_gl_shadow_mask = 0;
|
||||
|
||||
enum GLShadowBits {
|
||||
SHADOW_BLEND = 1 << 0,
|
||||
SHADOW_CULL = 1 << 1,
|
||||
SHADOW_DEPTH = 1 << 2,
|
||||
SHADOW_BLEND_FUNC = 1 << 3,
|
||||
SHADOW_DEPTH_MASK = 1 << 4,
|
||||
SHADOW_COLOR_MASK = 1 << 5,
|
||||
SHADOW_LINE_WIDTH = 1 << 6,
|
||||
SHADOW_FRONT_FACE = 1 << 7,
|
||||
SHADOW_POLY_OFFSET = 1 << 8,
|
||||
SHADOW_POLY_OFFSET_PARAMS = 1 << 9,
|
||||
SHADOW_STENCIL = 1 << 10,
|
||||
SHADOW_STENCIL_PARAMS = 1 << 11,
|
||||
};
|
||||
static thread_local bool s_rs_dirty = true;
|
||||
|
||||
static void onFramebufferResize(int w, int h) {
|
||||
if (w < 1) w = 1;
|
||||
@@ -269,9 +211,7 @@ static thread_local int s_matMode = 0; // 0=MV 1=proj 2=tex0 3=tex1
|
||||
static thread_local bool s_normalMatDirty = true;
|
||||
static thread_local glm::mat3 s_cachedNormalMat;
|
||||
static thread_local float s_cachedNormalSign = 1.0f;
|
||||
static thread_local bool s_matDirty = true;
|
||||
static inline void markNormalDirty() { s_normalMatDirty = true; }
|
||||
static inline void markMatrixDirty() { s_matDirty = true; }
|
||||
|
||||
static MatrixStack& activeStack() {
|
||||
switch (s_matMode) {
|
||||
@@ -286,23 +226,22 @@ static MatrixStack& activeStack() {
|
||||
}
|
||||
|
||||
static void flushMatrices() {
|
||||
if (s_matDirty) {
|
||||
glm::mat4 mvp = s_proj.cur() * s_mv.cur();
|
||||
glUniformMatrix4fv(s_shader.uMVP, 1, GL_FALSE, glm::value_ptr(mvp));
|
||||
glUniformMatrix4fv(s_shader.uMV, 1, GL_FALSE,
|
||||
glm::value_ptr(s_mv.cur()));
|
||||
glm::mat4 mvp = s_proj.cur() * s_mv.cur();
|
||||
glUniformMatrix4fv(s_shader.uMVP, 1, GL_FALSE, glm::value_ptr(mvp));
|
||||
glUniformMatrix4fv(s_shader.uMV, 1, GL_FALSE, glm::value_ptr(s_mv.cur()));
|
||||
|
||||
// Send the texture matrix to the depths of hell...
|
||||
glUniformMatrix4fv(s_shader.uTexMat0, 1, GL_FALSE,
|
||||
glm::value_ptr(s_tex[0].cur()));
|
||||
s_matDirty = false;
|
||||
}
|
||||
// Send the texture matrix to the depths of hell...
|
||||
glUniformMatrix4fv(s_shader.uTexMat0, 1, GL_FALSE,
|
||||
glm::value_ptr(s_tex[0].cur()));
|
||||
|
||||
if (s_shader.uNormalMatrix >= 0 && s_normalMatDirty) {
|
||||
glm::mat3 m3 = glm::mat3(s_mv.cur());
|
||||
s_cachedNormalMat = glm::transpose(glm::inverse(m3));
|
||||
s_cachedNormalSign = glm::determinant(m3) < 0.0f ? -1.0f : 1.0f;
|
||||
s_normalMatDirty = false;
|
||||
// if (s_shader.uLighting)
|
||||
if (s_shader.uNormalMatrix >= 0) {
|
||||
if (s_normalMatDirty) {
|
||||
glm::mat3 m3 = glm::mat3(s_mv.cur());
|
||||
s_cachedNormalMat = glm::transpose(glm::inverse(m3));
|
||||
s_cachedNormalSign = glm::determinant(m3) < 0.0f ? -1.0f : 1.0f;
|
||||
s_normalMatDirty = false;
|
||||
}
|
||||
glUniformMatrix3fv(s_shader.uNormalMatrix, 1, GL_FALSE,
|
||||
glm::value_ptr(s_cachedNormalMat));
|
||||
glUniform1f(s_shader.uNormalSign, s_cachedNormalSign);
|
||||
@@ -326,154 +265,27 @@ struct RenderState {
|
||||
glm::vec4 lmt = {1, 1, 0, 0};
|
||||
glm::vec2 globalLM = {240.f, 240.f}; // fullbright default
|
||||
int activeTexture = 0;
|
||||
// we MAKE sure everything is FINE.
|
||||
bool operator!=(const RenderState& o) const {
|
||||
return baseColor != o.baseColor || fogColor != o.fogColor ||
|
||||
fogStart != o.fogStart || fogEnd != o.fogEnd ||
|
||||
fogDensity != o.fogDensity || fogMode != o.fogMode ||
|
||||
fogEnable != o.fogEnable || alphaRef != o.alphaRef ||
|
||||
gamma != o.gamma || useTexture != o.useTexture ||
|
||||
useLightmap != o.useLightmap || lighting != o.lighting ||
|
||||
l0 != o.l0 || l1 != o.l1 || ldiff != o.ldiff || lamb != o.lamb ||
|
||||
lmt != o.lmt || globalLM != o.globalLM ||
|
||||
activeTexture != o.activeTexture;
|
||||
}
|
||||
};
|
||||
|
||||
enum RenderDirtyBits {
|
||||
DIRTY_BASECOLOR = 1 << 0,
|
||||
DIRTY_LIGHTING = 1 << 1,
|
||||
DIRTY_FOG = 1 << 2,
|
||||
DIRTY_ALPHA = 1 << 3,
|
||||
DIRTY_GAMMA = 1 << 4,
|
||||
DIRTY_TEXTURE = 1 << 5,
|
||||
DIRTY_LMT = 1 << 6,
|
||||
DIRTY_GLOBAL_LM = 1 << 7,
|
||||
};
|
||||
|
||||
static inline void markDirty(unsigned int bit) { s_rs_dirty_mask |= bit; }
|
||||
|
||||
static thread_local RenderState s_rs;
|
||||
static RenderState s_gpu_state;
|
||||
static bool s_gpu_state_valid = false;
|
||||
|
||||
// track currently bound program to avoid iggy shitting up
|
||||
static GLuint s_boundProgram = 0;
|
||||
|
||||
static void glShadowSetBlend(bool e) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_BLEND) || s_gl_state.blend != e) {
|
||||
if (e)
|
||||
::glEnable(GL_BLEND);
|
||||
else
|
||||
::glDisable(GL_BLEND);
|
||||
s_gl_state.blend = e;
|
||||
s_gl_shadow_mask |= SHADOW_BLEND;
|
||||
}
|
||||
}
|
||||
|
||||
static void glShadowSetCull(bool e) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_CULL) || s_gl_state.cull != e) {
|
||||
if (e)
|
||||
::glEnable(GL_CULL_FACE);
|
||||
else
|
||||
::glDisable(GL_CULL_FACE);
|
||||
s_gl_state.cull = e;
|
||||
s_gl_shadow_mask |= SHADOW_CULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void glShadowSetDepthTest(bool e) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_DEPTH) || s_gl_state.depth != e) {
|
||||
if (e)
|
||||
::glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
::glDisable(GL_DEPTH_TEST);
|
||||
s_gl_state.depth = e;
|
||||
s_gl_shadow_mask |= SHADOW_DEPTH;
|
||||
}
|
||||
}
|
||||
|
||||
static void glShadowSetBlendFunc(GLint s, GLint d) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_BLEND_FUNC) ||
|
||||
s_gl_state.blendSrc != s || s_gl_state.blendDst != d) {
|
||||
::glBlendFunc(s, d);
|
||||
s_gl_state.blendSrc = s;
|
||||
s_gl_state.blendDst = d;
|
||||
s_gl_shadow_mask |= SHADOW_BLEND_FUNC;
|
||||
}
|
||||
}
|
||||
|
||||
static void glShadowSetDepthMask(GLboolean e) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_DEPTH_MASK) ||
|
||||
s_gl_state.depthMask != e) {
|
||||
::glDepthMask(e);
|
||||
s_gl_state.depthMask = e;
|
||||
s_gl_shadow_mask |= SHADOW_DEPTH_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
static void glShadowSetColorMask(GLboolean r, GLboolean g, GLboolean b,
|
||||
GLboolean a) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_COLOR_MASK) ||
|
||||
s_gl_state.colorMask[0] != r || s_gl_state.colorMask[1] != g ||
|
||||
s_gl_state.colorMask[2] != b || s_gl_state.colorMask[3] != a) {
|
||||
::glColorMask(r, g, b, a);
|
||||
s_gl_state.colorMask[0] = r;
|
||||
s_gl_state.colorMask[1] = g;
|
||||
s_gl_state.colorMask[2] = b;
|
||||
s_gl_state.colorMask[3] = a;
|
||||
s_gl_shadow_mask |= SHADOW_COLOR_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
static void glShadowSetLineWidth(float w) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_LINE_WIDTH) || s_gl_state.lineWidth != w) {
|
||||
::glLineWidth(w);
|
||||
s_gl_state.lineWidth = w;
|
||||
s_gl_shadow_mask |= SHADOW_LINE_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
static void glShadowSetFrontFace(GLenum mode) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_FRONT_FACE) ||
|
||||
s_gl_state.frontFace != mode) {
|
||||
::glFrontFace(mode);
|
||||
s_gl_state.frontFace = mode;
|
||||
s_gl_shadow_mask |= SHADOW_FRONT_FACE;
|
||||
}
|
||||
}
|
||||
|
||||
static void glShadowSetPolygonOffset(float slope, float bias) {
|
||||
bool enable = (slope != 0.0f || bias != 0.0f);
|
||||
if (!(s_gl_shadow_mask & SHADOW_POLY_OFFSET) ||
|
||||
s_gl_state.polygon != enable) {
|
||||
if (enable)
|
||||
::glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
else
|
||||
::glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
s_gl_state.polygon = enable;
|
||||
s_gl_shadow_mask |= SHADOW_POLY_OFFSET;
|
||||
}
|
||||
if (enable) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_POLY_OFFSET_PARAMS) ||
|
||||
s_gl_state.polySlope != slope || s_gl_state.polyBias != bias) {
|
||||
::glPolygonOffset(slope, bias);
|
||||
s_gl_state.polySlope = slope;
|
||||
s_gl_state.polyBias = bias;
|
||||
s_gl_shadow_mask |= SHADOW_POLY_OFFSET_PARAMS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void glShadowSetStencil(GLenum fn, uint8_t ref, uint8_t fmask,
|
||||
uint8_t wmask) {
|
||||
if (!(s_gl_shadow_mask & SHADOW_STENCIL) || !s_gl_state.stencil) {
|
||||
::glEnable(GL_STENCIL_TEST);
|
||||
s_gl_state.stencil = true;
|
||||
s_gl_shadow_mask |= SHADOW_STENCIL;
|
||||
}
|
||||
if (!(s_gl_shadow_mask & SHADOW_STENCIL_PARAMS) ||
|
||||
s_gl_state.stencilFunc != fn || s_gl_state.stencilRef != (GLint)ref ||
|
||||
s_gl_state.stencilMask != fmask ||
|
||||
s_gl_state.stencilWriteMask != wmask) {
|
||||
::glStencilFunc(fn, ref, fmask);
|
||||
::glStencilMask(wmask);
|
||||
s_gl_state.stencilFunc = fn;
|
||||
s_gl_state.stencilRef = (GLint)ref;
|
||||
s_gl_state.stencilMask = fmask;
|
||||
s_gl_state.stencilWriteMask = wmask;
|
||||
s_gl_shadow_mask |= SHADOW_STENCIL_PARAMS;
|
||||
}
|
||||
}
|
||||
static thread_local bool s_chunkOffsetValid = false;
|
||||
static thread_local glm::vec3 s_chunkOffset;
|
||||
|
||||
static void pushRenderState() {
|
||||
if (!s_shader.prog) return;
|
||||
|
||||
@@ -481,52 +293,35 @@ static void pushRenderState() {
|
||||
if (s_boundProgram != s_shader.prog) {
|
||||
glUseProgram(s_shader.prog);
|
||||
s_boundProgram = s_shader.prog;
|
||||
s_matDirty = true;
|
||||
s_normalMatDirty = true;
|
||||
s_rs_dirty_mask = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
if (s_rs_dirty_mask) {
|
||||
if (s_rs_dirty_mask & DIRTY_BASECOLOR)
|
||||
glUniform4fv(s_shader.uBaseColor, 1,
|
||||
glm::value_ptr(s_rs.baseColor));
|
||||
if (s_rs_dirty_mask & DIRTY_LIGHTING) {
|
||||
glUniform1i(s_shader.uLighting, s_rs.lighting ? 1 : 0);
|
||||
glUniform3fv(s_shader.uLight0Dir, 1, glm::value_ptr(s_rs.l0));
|
||||
glUniform3fv(s_shader.uLight1Dir, 1, glm::value_ptr(s_rs.l1));
|
||||
glUniform3fv(s_shader.uLightDiffuse, 1, glm::value_ptr(s_rs.ldiff));
|
||||
glUniform3fv(s_shader.uLightAmbient, 1, glm::value_ptr(s_rs.lamb));
|
||||
}
|
||||
if (s_rs_dirty_mask & DIRTY_FOG) {
|
||||
glUniform1i(s_shader.uFogMode, s_rs.fogMode);
|
||||
glUniform1f(s_shader.uFogStart, s_rs.fogStart);
|
||||
glUniform1f(s_shader.uFogEnd, s_rs.fogEnd);
|
||||
glUniform1f(s_shader.uFogDensity, s_rs.fogDensity);
|
||||
glUniform4fv(s_shader.uFogColor, 1,
|
||||
glm::value_ptr(s_rs.fogColor));
|
||||
glUniform1i(s_shader.uFogEnable, s_rs.fogEnable ? 1 : 0);
|
||||
}
|
||||
if (s_rs_dirty_mask & DIRTY_TEXTURE) {
|
||||
glUniform1i(s_shader.uUseTexture, s_rs.useTexture ? 1 : 0);
|
||||
glUniform1i(s_shader.uUseLightmap, s_rs.useLightmap ? 1 : 0);
|
||||
}
|
||||
if (s_rs_dirty_mask & DIRTY_ALPHA)
|
||||
glUniform1f(s_shader.uAlphaRef, s_rs.alphaRef);
|
||||
if (s_rs_dirty_mask & DIRTY_GAMMA)
|
||||
glUniform1f(s_shader.uInvGamma, 1.0f / s_rs.gamma);
|
||||
if (s_rs_dirty_mask & DIRTY_LMT)
|
||||
glUniform4fv(s_shader.uLMTransform, 1,
|
||||
glm::value_ptr(s_rs.lmt));
|
||||
if (s_rs_dirty_mask & DIRTY_GLOBAL_LM)
|
||||
glUniform2fv(s_shader.uGlobalLM, 1,
|
||||
glm::value_ptr(s_rs.globalLM));
|
||||
s_rs_dirty_mask = 0;
|
||||
if (!s_gpu_state_valid || s_gpu_state != s_rs) {
|
||||
glUniform4fv(s_shader.uBaseColor, 1, glm::value_ptr(s_rs.baseColor));
|
||||
glUniform1i(s_shader.uLighting, s_rs.lighting ? 1 : 0);
|
||||
glUniform3fv(s_shader.uLight0Dir, 1, glm::value_ptr(s_rs.l0));
|
||||
glUniform3fv(s_shader.uLight1Dir, 1, glm::value_ptr(s_rs.l1));
|
||||
glUniform3fv(s_shader.uLightDiffuse, 1, glm::value_ptr(s_rs.ldiff));
|
||||
glUniform3fv(s_shader.uLightAmbient, 1, glm::value_ptr(s_rs.lamb));
|
||||
glUniform1i(s_shader.uFogMode, s_rs.fogMode);
|
||||
glUniform1f(s_shader.uFogStart, s_rs.fogStart);
|
||||
glUniform1f(s_shader.uFogEnd, s_rs.fogEnd);
|
||||
glUniform1f(s_shader.uFogDensity, s_rs.fogDensity);
|
||||
glUniform4fv(s_shader.uFogColor, 1, glm::value_ptr(s_rs.fogColor));
|
||||
glUniform1i(s_shader.uFogEnable, s_rs.fogEnable ? 1 : 0);
|
||||
glUniform1i(s_shader.uUseTexture, s_rs.useTexture ? 1 : 0);
|
||||
glUniform1i(s_shader.uUseLightmap, s_rs.useLightmap ? 1 : 0);
|
||||
glUniform1f(s_shader.uAlphaRef, s_rs.alphaRef);
|
||||
glUniform1f(s_shader.uInvGamma, 1.0f / s_rs.gamma);
|
||||
glUniform4fv(s_shader.uLMTransform, 1, glm::value_ptr(s_rs.lmt));
|
||||
glUniform2fv(s_shader.uGlobalLM, 1, glm::value_ptr(s_rs.globalLM));
|
||||
s_gpu_state = s_rs;
|
||||
s_gpu_state_valid = true;
|
||||
s_rs_dirty = false;
|
||||
}
|
||||
flushMatrices();
|
||||
}
|
||||
|
||||
static GLuint s_sVAO_std = 0, s_sVBO_std = 0;
|
||||
static GLsizeiptr s_streamVBOSize = 0;
|
||||
|
||||
static void bindStdAttribs() {
|
||||
glEnableVertexAttribArray(0);
|
||||
@@ -667,18 +462,18 @@ void C4JRender::Initialise() {
|
||||
int fw, fh;
|
||||
SDL_GetWindowSize(s_window, &fw, &fh);
|
||||
onFramebufferResize(fw, fh);
|
||||
glShadowSetDepthTest(true);
|
||||
::glDepthFunc(GL_LEQUAL);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
#ifdef GLES
|
||||
glClearDepthf(1.0f);
|
||||
#else
|
||||
glClearDepth(1.0);
|
||||
#endif
|
||||
glShadowSetBlend(true);
|
||||
glShadowSetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glShadowSetCull(true);
|
||||
::glCullFace(GL_BACK);
|
||||
::glClearColor(0, 0, 0, 1);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glViewport(0, 0, s_windowWidth, s_windowHeight);
|
||||
s_shader.build(VERT_SRC, FRAG_SRC);
|
||||
initStreamingVAOs();
|
||||
@@ -743,7 +538,6 @@ void C4JRender::InitialiseContext() {
|
||||
}
|
||||
|
||||
void C4JRender::StartFrame() {
|
||||
Set_matrixDirty();
|
||||
int w, h;
|
||||
SDL_GetWindowSize(s_window, &w, &h);
|
||||
s_windowWidth = w > 0 ? w : 1;
|
||||
@@ -903,10 +697,10 @@ void C4JRender::DrawVertices(ePrimitiveType ptype, int count, void* dataIn,
|
||||
glBindVertexArray(s_sVAO_std);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, s_sVBO_std);
|
||||
|
||||
// Standard orphaning
|
||||
// orphan buffer
|
||||
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)bytes, nullptr, GL_STREAM_DRAW);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, (GLsizeiptr)bytes, dataIn);
|
||||
s_streamVBOSize = (GLsizeiptr)bytes;
|
||||
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)bytes, dataIn, GL_STREAM_DRAW);
|
||||
bindStdAttribs();
|
||||
|
||||
glDrawArrays(glMode, 0, count);
|
||||
|
||||
@@ -942,16 +736,6 @@ void C4JRender::CBuffDelete(int first, int count) {
|
||||
pthread_mutex_unlock(&s_glCallMtx);
|
||||
}
|
||||
|
||||
void C4JRender::CBuffDeleteAll() {
|
||||
pthread_mutex_lock(&s_glCallMtx);
|
||||
for (auto& kv : s_chunkPool) {
|
||||
kv.second.destroy();
|
||||
}
|
||||
s_chunkPool.clear();
|
||||
s_nextListBase = 1;
|
||||
pthread_mutex_unlock(&s_glCallMtx);
|
||||
}
|
||||
|
||||
void C4JRender::CBuffStart(int index, bool) {
|
||||
s_recListId = index;
|
||||
s_recVerts.clear();
|
||||
@@ -980,10 +764,7 @@ void C4JRender::CBuffEnd() {
|
||||
void C4JRender::CBuffClear(int index) {
|
||||
pthread_mutex_lock(&s_glCallMtx);
|
||||
auto it = s_chunkPool.find(index);
|
||||
if (it != s_chunkPool.end()) {
|
||||
it->second.destroy();
|
||||
s_chunkPool.erase(it);
|
||||
}
|
||||
if (it != s_chunkPool.end()) it->second.destroy();
|
||||
pthread_mutex_unlock(&s_glCallMtx);
|
||||
}
|
||||
|
||||
@@ -1037,48 +818,39 @@ void C4JRender::MatrixMode(int t) {
|
||||
|
||||
void C4JRender::MatrixSetIdentity() {
|
||||
activeStack().load(glm::mat4(1.f));
|
||||
markMatrixDirty();
|
||||
if (s_matMode == 0) markNormalDirty();
|
||||
}
|
||||
void C4JRender::MatrixPush() {
|
||||
activeStack().push();
|
||||
// push doesn't change cur() so no dirty needed but mark anyway to be safe
|
||||
// ;w;
|
||||
markMatrixDirty();
|
||||
if (s_matMode == 0) markNormalDirty();
|
||||
}
|
||||
void C4JRender::MatrixPop() {
|
||||
activeStack().pop();
|
||||
markMatrixDirty();
|
||||
if (s_matMode == 0) markNormalDirty();
|
||||
}
|
||||
void C4JRender::MatrixTranslate(float x, float y, float z) {
|
||||
activeStack().mul(glm::translate(glm::mat4(1.f), {x, y, z}));
|
||||
markMatrixDirty();
|
||||
if (s_matMode == 0) markNormalDirty();
|
||||
}
|
||||
void C4JRender::MatrixRotate(float a, float x, float y, float z) {
|
||||
activeStack().mul(glm::rotate(glm::mat4(1.f), a, {x, y, z}));
|
||||
markMatrixDirty();
|
||||
if (s_matMode == 0) markNormalDirty();
|
||||
}
|
||||
void C4JRender::MatrixScale(float x, float y, float z) {
|
||||
activeStack().mul(glm::scale(glm::mat4(1.f), {x, y, z}));
|
||||
markMatrixDirty();
|
||||
if (s_matMode == 0) markNormalDirty();
|
||||
}
|
||||
void C4JRender::MatrixPerspective(float fovy, float asp, float zn, float zf) {
|
||||
s_proj.cur() = glm::perspective(glm::radians(fovy), asp, zn, zf);
|
||||
markMatrixDirty();
|
||||
}
|
||||
void C4JRender::MatrixOrthogonal(float l, float r, float b, float t, float zn,
|
||||
float zf) {
|
||||
s_proj.cur() = glm::ortho(l, r, b, t, zn, zf);
|
||||
markMatrixDirty();
|
||||
}
|
||||
void C4JRender::MatrixMult(float* m) {
|
||||
activeStack().mul(glm::make_mat4(m));
|
||||
markMatrixDirty();
|
||||
if (s_matMode == 0) markNormalDirty();
|
||||
}
|
||||
const float* C4JRender::MatrixGet(int t) {
|
||||
@@ -1093,11 +865,8 @@ const float* C4JRender::MatrixGet(int t) {
|
||||
void C4JRender::Set_matrixDirty() {
|
||||
// iggy wipes opengl state
|
||||
s_boundProgram = 0;
|
||||
s_rs_dirty_mask = 0xFFFFFFFF;
|
||||
s_gl_shadow_mask = 0;
|
||||
s_normalMatDirty = true; // normal matrix dirt after iggy reset
|
||||
s_matDirty = true;
|
||||
s_chunkOffsetValid = false;
|
||||
s_gpu_state_valid = false;
|
||||
s_normalMatDirty = true; // normal matrix dirt after iggy reset
|
||||
if (s_shader.prog) {
|
||||
glUseProgram(s_shader.prog);
|
||||
s_boundProgram = s_shader.prog;
|
||||
@@ -1111,61 +880,56 @@ void C4JRender::SetClearColour(const float c[4]) {
|
||||
bool C4JRender::IsWidescreen() { return true; }
|
||||
bool C4JRender::IsHiDef() { return true; }
|
||||
void C4JRender::StateSetColour(float r, float g, float b, float a) {
|
||||
glm::vec4 v = {r, g, b, a};
|
||||
if (s_rs.baseColor != v) {
|
||||
s_rs.baseColor = v;
|
||||
markDirty(DIRTY_BASECOLOR);
|
||||
}
|
||||
s_rs.baseColor = {r, g, b, a};
|
||||
}
|
||||
void C4JRender::SetChunkOffset(float x, float y, float z) {
|
||||
if (s_shader.uChunkOffset < 0) return;
|
||||
glm::vec3 v = {x, y, z};
|
||||
if (!s_chunkOffsetValid || s_chunkOffset != v) {
|
||||
s_chunkOffset = v;
|
||||
s_chunkOffsetValid = true;
|
||||
}
|
||||
if (s_boundProgram == s_shader.prog) {
|
||||
glUniform3f(s_shader.uChunkOffset, x, y, z);
|
||||
}
|
||||
if (s_shader.uChunkOffset >= 0) glUniform3f(s_shader.uChunkOffset, x, y, z);
|
||||
}
|
||||
void C4JRender::StateSetDepthMask(bool e) {
|
||||
glShadowSetDepthMask(e ? GL_TRUE : GL_FALSE);
|
||||
glDepthMask(e ? GL_TRUE : GL_FALSE);
|
||||
}
|
||||
void C4JRender::StateSetBlendEnable(bool e) { glShadowSetBlend(e); }
|
||||
void C4JRender::StateSetBlendFunc(int s, int d) {
|
||||
glShadowSetBlendFunc(s, d);
|
||||
void C4JRender::StateSetBlendEnable(bool e) {
|
||||
if (e)
|
||||
glEnable(GL_BLEND);
|
||||
else
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
void C4JRender::StateSetDepthFunc(int f) { ::glDepthFunc(f); }
|
||||
void C4JRender::StateSetFaceCull(bool e) { glShadowSetCull(e); }
|
||||
void C4JRender::StateSetFaceCullCW(bool e) {
|
||||
glShadowSetFrontFace(e ? GL_CW : GL_CCW);
|
||||
void C4JRender::StateSetBlendFunc(int s, int d) { glBlendFunc(s, d); }
|
||||
void C4JRender::StateSetDepthFunc(int f) { glDepthFunc(f); }
|
||||
void C4JRender::StateSetFaceCull(bool e) {
|
||||
if (e)
|
||||
glEnable(GL_CULL_FACE);
|
||||
else
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
void C4JRender::StateSetFaceCullCW(bool e) { glFrontFace(e ? GL_CW : GL_CCW); }
|
||||
void C4JRender::StateSetLineWidth(float w) {
|
||||
#ifndef GLES
|
||||
glShadowSetLineWidth(w);
|
||||
glLineWidth(w);
|
||||
#else
|
||||
(void)w;
|
||||
#endif
|
||||
}
|
||||
void C4JRender::StateSetWriteEnable(bool r, bool g, bool b, bool a) {
|
||||
glShadowSetColorMask(r, g, b, a);
|
||||
glColorMask(r, g, b, a);
|
||||
}
|
||||
void C4JRender::StateSetDepthTestEnable(bool e) {
|
||||
if (e)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
void C4JRender::StateSetDepthTestEnable(bool e) { glShadowSetDepthTest(e); }
|
||||
void C4JRender::StateSetAlphaTestEnable(bool e) {
|
||||
float v = e ? 0.1f : 0.f;
|
||||
if (s_rs.alphaRef != v) {
|
||||
s_rs.alphaRef = v;
|
||||
markDirty(DIRTY_ALPHA);
|
||||
}
|
||||
}
|
||||
void C4JRender::StateSetAlphaFunc(int, float p) {
|
||||
if (s_rs.alphaRef != p) {
|
||||
s_rs.alphaRef = p;
|
||||
markDirty(DIRTY_ALPHA);
|
||||
}
|
||||
s_rs.alphaRef = e ? 0.1f : 0.f;
|
||||
}
|
||||
void C4JRender::StateSetAlphaFunc(int, float p) { s_rs.alphaRef = p; }
|
||||
void C4JRender::StateSetDepthSlopeAndBias(float s, float b) {
|
||||
glShadowSetPolygonOffset(s, b);
|
||||
if (s || b) {
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(s, b);
|
||||
} else {
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
}
|
||||
}
|
||||
void C4JRender::StateSetBlendFactor(unsigned int col) {
|
||||
float a = ((col >> 24) & 0xFF) / 255.f;
|
||||
@@ -1174,96 +938,58 @@ void C4JRender::StateSetBlendFactor(unsigned int col) {
|
||||
float b = (col & 0xFF) / 255.f;
|
||||
glBlendColor(r, g, b, a);
|
||||
}
|
||||
void C4JRender::StateSetFogEnable(bool e) {
|
||||
if (s_rs.fogEnable != e) {
|
||||
s_rs.fogEnable = e;
|
||||
markDirty(DIRTY_FOG);
|
||||
}
|
||||
}
|
||||
void C4JRender::StateSetFogEnable(bool e) { s_rs.fogEnable = e; }
|
||||
void C4JRender::StateSetFogMode(int mode) {
|
||||
int v = (mode == GL_LINEAR) ? 1 : (mode == GL_EXP) ? 2 : (mode == 0x0801) ? 3 : 0;
|
||||
if (s_rs.fogMode != v) {
|
||||
s_rs.fogMode = v;
|
||||
markDirty(DIRTY_FOG);
|
||||
}
|
||||
}
|
||||
void C4JRender::StateSetFogNearDistance(float d) {
|
||||
if (s_rs.fogStart != d) {
|
||||
s_rs.fogStart = d;
|
||||
markDirty(DIRTY_FOG);
|
||||
}
|
||||
}
|
||||
void C4JRender::StateSetFogFarDistance(float d) {
|
||||
if (s_rs.fogEnd != d) {
|
||||
s_rs.fogEnd = d;
|
||||
markDirty(DIRTY_FOG);
|
||||
}
|
||||
}
|
||||
void C4JRender::StateSetFogDensity(float d) {
|
||||
if (s_rs.fogDensity != d) {
|
||||
s_rs.fogDensity = d;
|
||||
markDirty(DIRTY_FOG);
|
||||
}
|
||||
s_rs.fogMode = (mode == GL_LINEAR) ? 1
|
||||
: (mode == GL_EXP) ? 2
|
||||
: (mode == 0x0801) ? 3
|
||||
: 0;
|
||||
}
|
||||
void C4JRender::StateSetFogNearDistance(float d) { s_rs.fogStart = d; }
|
||||
void C4JRender::StateSetFogFarDistance(float d) { s_rs.fogEnd = d; }
|
||||
void C4JRender::StateSetFogDensity(float d) { s_rs.fogDensity = d; }
|
||||
void C4JRender::StateSetFogColour(float r, float g, float b) {
|
||||
glm::vec4 v = {r, g, b, 1};
|
||||
if (s_rs.fogColor != v) {
|
||||
s_rs.fogColor = v;
|
||||
markDirty(DIRTY_FOG);
|
||||
}
|
||||
s_rs.fogColor = {r, g, b, 1};
|
||||
}
|
||||
void C4JRender::StateSetLightingEnable(bool e) {
|
||||
if (s_rs.lighting != e) {
|
||||
s_rs.lighting = e;
|
||||
markDirty(DIRTY_LIGHTING);
|
||||
}
|
||||
s_rs.lighting = e;
|
||||
s_rs_dirty = true;
|
||||
}
|
||||
void C4JRender::StateSetLightColour(int, float r, float g, float b) {
|
||||
glm::vec3 v = {r, g, b};
|
||||
if (s_rs.ldiff != v) {
|
||||
s_rs.ldiff = v;
|
||||
markDirty(DIRTY_LIGHTING);
|
||||
}
|
||||
s_rs.ldiff = {r, g, b};
|
||||
s_rs_dirty = true;
|
||||
}
|
||||
void C4JRender::StateSetLightAmbientColour(float r, float g, float b) {
|
||||
glm::vec3 v = {r, g, b};
|
||||
if (s_rs.lamb != v) {
|
||||
s_rs.lamb = v;
|
||||
markDirty(DIRTY_LIGHTING);
|
||||
}
|
||||
s_rs.lamb = {r, g, b};
|
||||
s_rs_dirty = true;
|
||||
}
|
||||
void C4JRender::StateSetLightDirection(int light, float x, float y, float z) {
|
||||
glm::vec3 d = glm::normalize(glm::mat3(s_mv.cur()) * glm::vec3(x, y, z));
|
||||
if (light == 0) {
|
||||
if (s_rs.l0 != d) {
|
||||
s_rs.l0 = d;
|
||||
markDirty(DIRTY_LIGHTING);
|
||||
}
|
||||
} else {
|
||||
if (s_rs.l1 != d) {
|
||||
s_rs.l1 = d;
|
||||
markDirty(DIRTY_LIGHTING);
|
||||
}
|
||||
}
|
||||
if (light == 0)
|
||||
s_rs.l0 = d;
|
||||
else
|
||||
s_rs.l1 = d;
|
||||
}
|
||||
void C4JRender::StateSetViewport(eViewportType) {
|
||||
glViewport(0, 0, s_windowWidth, s_windowHeight);
|
||||
}
|
||||
void C4JRender::StateSetVertexTextureUV(float u, float v) {
|
||||
glm::vec2 val = {u, v};
|
||||
if (s_rs.globalLM != val) {
|
||||
s_rs.globalLM = val;
|
||||
markDirty(DIRTY_GLOBAL_LM);
|
||||
}
|
||||
s_rs.globalLM = {u, v};
|
||||
}
|
||||
void C4JRender::StateSetStencil(int fn, uint8_t ref, uint8_t fmask,
|
||||
uint8_t wmask) {
|
||||
glShadowSetStencil(fn, ref, fmask, wmask);
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilFunc(fn, ref, fmask);
|
||||
glStencilMask(wmask);
|
||||
}
|
||||
void C4JRender::StateSetTextureEnable(bool e) {
|
||||
if (s_rs.activeTexture == 0 && s_rs.useTexture != e) {
|
||||
if (s_rs.activeTexture == 0) {
|
||||
s_rs.useTexture = e;
|
||||
markDirty(DIRTY_TEXTURE);
|
||||
if (s_shader.prog) {
|
||||
glUseProgram(s_shader.prog);
|
||||
s_boundProgram = s_shader.prog;
|
||||
glUniform1i(s_shader.uUseTexture, e ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
void C4JRender::StateSetActiveTexture(int tex) {
|
||||
@@ -1285,10 +1011,7 @@ void C4JRender::TextureBind(int idx) {
|
||||
}
|
||||
void C4JRender::TextureBindVertex(int idx, bool scaleLight) {
|
||||
if (idx < 0) {
|
||||
if (s_rs.useLightmap) {
|
||||
s_rs.useLightmap = false;
|
||||
markDirty(DIRTY_TEXTURE);
|
||||
}
|
||||
s_rs.useLightmap = false;
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
return;
|
||||
}
|
||||
@@ -1299,17 +1022,9 @@ void C4JRender::TextureBindVertex(int idx, bool scaleLight) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
if (!s_rs.useLightmap) {
|
||||
s_rs.useLightmap = true;
|
||||
markDirty(DIRTY_TEXTURE);
|
||||
}
|
||||
glm::vec4 newLmt =
|
||||
scaleLight ? glm::vec4{1.f, 1.f, 8.f / 256.f, 8.f / 256.f}
|
||||
: glm::vec4{1.f, 1.f, 0.f, 0.f};
|
||||
if (s_rs.lmt != newLmt) {
|
||||
s_rs.lmt = newLmt;
|
||||
markDirty(DIRTY_LMT);
|
||||
}
|
||||
s_rs.useLightmap = true;
|
||||
s_rs.lmt = scaleLight ? glm::vec4{1.f, 1.f, 8.f / 256.f, 8.f / 256.f}
|
||||
: glm::vec4{1.f, 1.f, 0.f, 0.f};
|
||||
}
|
||||
void C4JRender::TextureSetTextureLevels(int l) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, l > 0 ? l - 1 : 0);
|
||||
@@ -1373,7 +1088,6 @@ int C4JRender::LoadTextureData(uint8_t* pb, uint32_t nb, D3DXIMAGE_INFO* i,
|
||||
return hr;
|
||||
}
|
||||
|
||||
// TODO: TO REMOVE SOON.
|
||||
void C4JRender::UpdateGamma(unsigned short usGamma) {
|
||||
constexpr unsigned short GAMMA_MAX = 32768;
|
||||
s_rs.gamma = 0.5f + ((float)(usGamma) * (1.0f / GAMMA_MAX));
|
||||
@@ -1470,4 +1184,4 @@ void glLightModelfv(GLenum pname, const GLfloat* params) {
|
||||
void glShadeModel(GLenum) {}
|
||||
void glColorMaterial(GLenum, GLenum) {}
|
||||
void glNormal3f(GLfloat, GLfloat, GLfloat) {}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "gl3_loader.h"
|
||||
// NOTE: gl3_loader.h must be included before these two
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "../IPlatformRenderer.h"
|
||||
#ifdef __linux__
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
class C4JRender : public IPlatformRenderer {
|
||||
class ImageFileBuffer {
|
||||
public:
|
||||
enum EImageType { e_typePNG, e_typeJPG };
|
||||
EImageType m_type;
|
||||
void* m_pBuffer;
|
||||
int m_bufferSize;
|
||||
int GetType() { return m_type; }
|
||||
void* GetBufferPointer() { return m_pBuffer; }
|
||||
int GetBufferSize() { return m_bufferSize; }
|
||||
void Release() {
|
||||
std::free(m_pBuffer);
|
||||
m_pBuffer = nullptr;
|
||||
}
|
||||
bool Allocated() { return m_pBuffer != nullptr; }
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int Width;
|
||||
int Height;
|
||||
} D3DXIMAGE_INFO;
|
||||
|
||||
typedef struct _XSOCIAL_PREVIEWIMAGE {
|
||||
std::uint8_t* pBytes;
|
||||
std::uint32_t Pitch;
|
||||
std::uint32_t Width;
|
||||
std::uint32_t Height;
|
||||
} XSOCIAL_PREVIEWIMAGE, *PXSOCIAL_PREVIEWIMAGE;
|
||||
|
||||
class C4JRender {
|
||||
public:
|
||||
void Tick();
|
||||
void UpdateGamma(unsigned short usGamma);
|
||||
@@ -52,14 +78,60 @@ public:
|
||||
void BeginConditionalRendering(int identifier);
|
||||
void EndConditionalRendering();
|
||||
|
||||
// Vertex data handling
|
||||
typedef enum {
|
||||
VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1, // Position 3 x float, texture 2 x
|
||||
// float, colour 4 x byte, normal 4 x
|
||||
// byte, padding 1 32-bit word
|
||||
VERTEX_TYPE_COMPRESSED, // Compressed format - see comment at top of
|
||||
// VS_PS3_TS2_CS1.hlsl for description of
|
||||
// layout
|
||||
VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_LIT, // as
|
||||
// VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1
|
||||
// with lighting applied,
|
||||
VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TEXGEN, // as
|
||||
// VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1
|
||||
// with tex gen
|
||||
VERTEX_TYPE_COUNT
|
||||
} eVertexType;
|
||||
|
||||
// Pixel shader
|
||||
typedef enum {
|
||||
PIXEL_SHADER_TYPE_STANDARD,
|
||||
PIXEL_SHADER_TYPE_PROJECTION,
|
||||
PIXEL_SHADER_TYPE_FORCELOD,
|
||||
PIXEL_SHADER_COUNT
|
||||
} ePixelShaderType;
|
||||
|
||||
typedef enum {
|
||||
VIEWPORT_TYPE_FULLSCREEN,
|
||||
VIEWPORT_TYPE_SPLIT_TOP,
|
||||
VIEWPORT_TYPE_SPLIT_BOTTOM,
|
||||
VIEWPORT_TYPE_SPLIT_LEFT,
|
||||
VIEWPORT_TYPE_SPLIT_RIGHT,
|
||||
VIEWPORT_TYPE_QUADRANT_TOP_LEFT,
|
||||
VIEWPORT_TYPE_QUADRANT_TOP_RIGHT,
|
||||
VIEWPORT_TYPE_QUADRANT_BOTTOM_LEFT,
|
||||
VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT,
|
||||
} eViewportType;
|
||||
|
||||
typedef enum {
|
||||
PRIMITIVE_TYPE_TRIANGLE_LIST,
|
||||
PRIMITIVE_TYPE_TRIANGLE_STRIP,
|
||||
PRIMITIVE_TYPE_TRIANGLE_FAN,
|
||||
PRIMITIVE_TYPE_QUAD_LIST,
|
||||
PRIMITIVE_TYPE_LINE_LIST,
|
||||
PRIMITIVE_TYPE_LINE_STRIP,
|
||||
PRIMITIVE_TYPE_COUNT
|
||||
} ePrimitiveType;
|
||||
|
||||
void DrawVertices(ePrimitiveType PrimitiveType, int count, void* dataIn,
|
||||
eVertexType vType, ePixelShaderType psType);
|
||||
eVertexType vType, C4JRender::ePixelShaderType psType);
|
||||
|
||||
// Command buffers
|
||||
void CBuffLockStaticCreations();
|
||||
int CBuffCreate(int count);
|
||||
void CBuffDelete(int first, int count);
|
||||
void CBuffDeleteAll();
|
||||
void CBuffStart(int index, bool full = false);
|
||||
void CBuffClear(int index);
|
||||
int CBuffSize(int index);
|
||||
@@ -69,6 +141,18 @@ public:
|
||||
void CBuffDeferredModeStart();
|
||||
void CBuffDeferredModeEnd();
|
||||
|
||||
typedef enum {
|
||||
TEXTURE_FORMAT_RxGyBzAw, // Normal 32-bit RGBA texture, 8 bits per
|
||||
// component
|
||||
/* Don't think these are all directly available on D3D 11 - leaving for
|
||||
now TEXTURE_FORMAT_R0G0B0Ax, // One 8-bit component mapped to
|
||||
alpha channel, R=G=B=0 TEXTURE_FORMAT_R1G1B1Ax, // One 8-bit
|
||||
component mapped to alpha channel, R=G=B=1 TEXTURE_FORMAT_RxGxBxAx,
|
||||
// One 8-bit component mapped to all channels
|
||||
*/
|
||||
MAX_TEXTURE_FORMATS
|
||||
} eTextureFormat;
|
||||
|
||||
// Textures
|
||||
int TextureCreate();
|
||||
void TextureFree(int idx);
|
||||
@@ -491,12 +575,6 @@ extern C4JRender RenderManager;
|
||||
RenderManager.StateSetAlphaTestEnable(true); \
|
||||
else if ((cap) == 0x0DE1 /*GL_TEXTURE_2D*/) \
|
||||
RenderManager.StateSetTextureEnable(true); \
|
||||
else if ((cap) == 0x0BE2 /*GL_BLEND*/) \
|
||||
RenderManager.StateSetBlendEnable(true); \
|
||||
else if ((cap) == 0x0B44 /*GL_CULL_FACE*/) \
|
||||
RenderManager.StateSetFaceCull(true); \
|
||||
else if ((cap) == 0x0B71 /*GL_DEPTH_TEST*/) \
|
||||
RenderManager.StateSetDepthTestEnable(true); \
|
||||
else if ((cap) == 0x4000 /*GL_LIGHT0*/) \
|
||||
RenderManager.StateSetLightEnable(0, true); \
|
||||
else if ((cap) == 0x4001 /*GL_LIGHT1*/) \
|
||||
@@ -523,12 +601,6 @@ extern C4JRender RenderManager;
|
||||
RenderManager.StateSetAlphaTestEnable(false); \
|
||||
else if ((cap) == 0x0DE1 /*GL_TEXTURE_2D*/) \
|
||||
RenderManager.StateSetTextureEnable(false); \
|
||||
else if ((cap) == 0x0BE2 /*GL_BLEND*/) \
|
||||
RenderManager.StateSetBlendEnable(false); \
|
||||
else if ((cap) == 0x0B44 /*GL_CULL_FACE*/) \
|
||||
RenderManager.StateSetFaceCull(false); \
|
||||
else if ((cap) == 0x0B71 /*GL_DEPTH_TEST*/) \
|
||||
RenderManager.StateSetDepthTestEnable(false); \
|
||||
else if ((cap) == 0x4000 /*GL_LIGHT0*/) \
|
||||
RenderManager.StateSetLightEnable(0, false); \
|
||||
else if ((cap) == 0x4001 /*GL_LIGHT1*/) \
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <cstdio>
|
||||
#ifndef GL_ARRAY_BUFFER
|
||||
#define GL_ARRAY_BUFFER 0x8892
|
||||
@@ -0,0 +1,37 @@
|
||||
# isolate em
|
||||
_sdl2 = dependency('sdl2')
|
||||
_threads = dependency('threads')
|
||||
_glm = dependency('glm')
|
||||
_defs = []
|
||||
|
||||
if get_option('renderer') == 'gles'
|
||||
_gl = dependency('glesv2', required: true)
|
||||
_defs += ['-DGLES']
|
||||
else
|
||||
_gl = dependency('gl', required: true)
|
||||
endif
|
||||
|
||||
render_sources = files(
|
||||
'4J_Render.cpp',
|
||||
'stdafx.cpp',
|
||||
'stubs.cpp',
|
||||
)
|
||||
|
||||
lib_render = static_library(
|
||||
'4J_Render',
|
||||
render_sources,
|
||||
include_directories: include_directories('.'),
|
||||
dependencies: [_sdl2, _gl, _threads, _glm],
|
||||
cpp_args: _defs
|
||||
+ [
|
||||
'-fpermissive',
|
||||
'-Wshift-count-overflow',
|
||||
'-pipe',
|
||||
'-include', meson.current_source_dir() / 'stdafx.h',
|
||||
],
|
||||
)
|
||||
|
||||
render_dep = declare_dependency(
|
||||
link_with: lib_render,
|
||||
include_directories: include_directories('.'),
|
||||
)
|
||||
@@ -46,7 +46,7 @@ void main() {
|
||||
|
||||
float d0 = max(dot(n, uLight0Dir), 0.0);
|
||||
float d1 = max(dot(n, uLight1Dir), 0.0);
|
||||
vColor = vec4(col.rgb * (uLightAmbient + uLightDiffuse * clamp(d0 + d1, 0.0, 1.0)), col.a);
|
||||
vColor = vec4(col.rgb * (uLightAmbient + uLightDiffuse * (d0 + d1)), col.a);
|
||||
} else {
|
||||
vColor = col;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
#include "stdafx.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _4J_RENDER_STADAFX_H
|
||||
#define _4J_RENDER_STADAFX_H
|
||||
|
||||
#include "../4J.Common/4J_Compat.h"
|
||||
|
||||
#endif //_4J_RENDER_STADAFX_H
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Render.h"
|
||||
#include "4J_Render.h"
|
||||
|
||||
// Command Buffers
|
||||
void C4JRender::CBuffLockStaticCreations() {}
|
||||
@@ -0,0 +1,224 @@
|
||||
#include "4J_Storage.h"
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
C4JStorage StorageManager;
|
||||
|
||||
static XMARKETPLACE_CONTENTOFFER_INFO s_dummyOffer = {};
|
||||
static XCONTENT_DATA s_dummyContentData = {};
|
||||
|
||||
C4JStorage::C4JStorage() : m_pStringTable(nullptr) {}
|
||||
|
||||
void C4JStorage::Tick(void) {}
|
||||
|
||||
C4JStorage::EMessageResult C4JStorage::RequestMessageBox(
|
||||
unsigned int uiTitle, unsigned int uiText, unsigned int* uiOptionA,
|
||||
unsigned int uiOptionC, unsigned int pad,
|
||||
int (*Func)(void*, int, const C4JStorage::EMessageResult), void* lpParam,
|
||||
C4JStringTable* pStringTable, wchar_t* pwchFormatString,
|
||||
unsigned int focusButton) {
|
||||
return EMessage_ResultAccept;
|
||||
}
|
||||
|
||||
C4JStorage::EMessageResult C4JStorage::GetMessageBoxResult() {
|
||||
return EMessage_Undefined;
|
||||
}
|
||||
|
||||
bool C4JStorage::SetSaveDevice(int (*Func)(void*, const bool), void* lpParam,
|
||||
bool bForceResetOfSaveDevice) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void C4JStorage::Init(unsigned int uiSaveVersion,
|
||||
const wchar_t* pwchDefaultSaveName, char* pszSavePackName,
|
||||
int iMinimumSaveSize,
|
||||
int (*Func)(void*, const ESavingMessage, int),
|
||||
void* lpParam, const char* szGroupID) {}
|
||||
void C4JStorage::ResetSaveData() {}
|
||||
void C4JStorage::SetDefaultSaveNameForKeyboardDisplay(
|
||||
const wchar_t* pwchDefaultSaveName) {}
|
||||
void C4JStorage::SetSaveTitle(const wchar_t* pwchDefaultSaveName) {}
|
||||
bool C4JStorage::GetSaveUniqueNumber(int* piVal) {
|
||||
if (piVal) *piVal = 0;
|
||||
return true;
|
||||
}
|
||||
bool C4JStorage::GetSaveUniqueFilename(char* pszName) {
|
||||
if (pszName) pszName[0] = '\0';
|
||||
return true;
|
||||
}
|
||||
void C4JStorage::SetSaveUniqueFilename(char* szFilename) {}
|
||||
void C4JStorage::SetState(ESaveGameControlState eControlState,
|
||||
int (*Func)(void*, const bool), void* lpParam) {}
|
||||
void C4JStorage::SetSaveDisabled(bool bDisable) {}
|
||||
bool C4JStorage::GetSaveDisabled(void) { return false; }
|
||||
unsigned int C4JStorage::GetSaveSize() { return 0; }
|
||||
void C4JStorage::GetSaveData(void* pvData, unsigned int* puiBytes) {
|
||||
if (puiBytes) *puiBytes = 0;
|
||||
}
|
||||
void* C4JStorage::AllocateSaveData(unsigned int uiBytes) {
|
||||
return malloc(uiBytes);
|
||||
}
|
||||
void C4JStorage::SetSaveImages(std::uint8_t* pbThumbnail,
|
||||
unsigned int thumbnailBytes,
|
||||
std::uint8_t* pbImage, unsigned int imageBytes,
|
||||
std::uint8_t* pbTextData,
|
||||
unsigned int textDataBytes) {}
|
||||
C4JStorage::ESaveGameState C4JStorage::SaveSaveData(int (*Func)(void*,
|
||||
const bool),
|
||||
void* lpParam) {
|
||||
return ESaveGame_Idle;
|
||||
}
|
||||
void C4JStorage::CopySaveDataToNewSave(std::uint8_t* pbThumbnail,
|
||||
unsigned int cbThumbnail,
|
||||
wchar_t* wchNewName,
|
||||
int (*Func)(void* lpParam, bool),
|
||||
void* lpParam) {}
|
||||
void C4JStorage::SetSaveDeviceSelected(unsigned int uiPad, bool bSelected) {}
|
||||
bool C4JStorage::GetSaveDeviceSelected(unsigned int iPad) { return true; }
|
||||
C4JStorage::ESaveGameState C4JStorage::DoesSaveExist(bool* pbExists) {
|
||||
if (pbExists) *pbExists = false;
|
||||
return ESaveGame_Idle;
|
||||
}
|
||||
bool C4JStorage::EnoughSpaceForAMinSaveGame() { return true; }
|
||||
void C4JStorage::SetSaveMessageVPosition(float fY) {}
|
||||
C4JStorage::ESaveGameState C4JStorage::GetSavesInfo(
|
||||
int iPad,
|
||||
int (*Func)(void* lpParam, SAVE_DETAILS* pSaveDetails, const bool),
|
||||
void* lpParam, char* pszSavePackName) {
|
||||
return ESaveGame_Idle;
|
||||
}
|
||||
PSAVE_DETAILS C4JStorage::ReturnSavesInfo() { return nullptr; }
|
||||
void C4JStorage::ClearSavesInfo() {}
|
||||
C4JStorage::ESaveGameState C4JStorage::LoadSaveDataThumbnail(
|
||||
PSAVE_INFO pSaveInfo,
|
||||
int (*Func)(void* lpParam, std::uint8_t* thumbnailData,
|
||||
unsigned int thumbnailBytes),
|
||||
void* lpParam) {
|
||||
return ESaveGame_Idle;
|
||||
}
|
||||
void C4JStorage::GetSaveCacheFileInfo(unsigned int fileIndex,
|
||||
XCONTENT_DATA& xContentData) {
|
||||
memset(&xContentData, 0, sizeof(xContentData));
|
||||
}
|
||||
void C4JStorage::GetSaveCacheFileInfo(unsigned int fileIndex,
|
||||
std::uint8_t** ppbImageData,
|
||||
unsigned int* pImageBytes) {
|
||||
if (ppbImageData) *ppbImageData = nullptr;
|
||||
if (pImageBytes) *pImageBytes = 0;
|
||||
}
|
||||
C4JStorage::ESaveGameState C4JStorage::LoadSaveData(
|
||||
PSAVE_INFO pSaveInfo, int (*Func)(void* lpParam, const bool, const bool),
|
||||
void* lpParam) {
|
||||
return ESaveGame_Idle;
|
||||
}
|
||||
C4JStorage::ESaveGameState C4JStorage::DeleteSaveData(PSAVE_INFO pSaveInfo,
|
||||
int (*Func)(void* lpParam,
|
||||
const bool),
|
||||
void* lpParam) {
|
||||
return ESaveGame_Idle;
|
||||
}
|
||||
void C4JStorage::RegisterMarketplaceCountsCallback(
|
||||
int (*Func)(void* lpParam, C4JStorage::DLC_TMS_DETAILS*, int),
|
||||
void* lpParam) {}
|
||||
void C4JStorage::SetDLCPackageRoot(char* pszDLCRoot) {}
|
||||
C4JStorage::EDLCStatus C4JStorage::GetDLCOffers(
|
||||
int iPad, int (*Func)(void*, int, std::uint32_t, int), void* lpParam,
|
||||
std::uint32_t dwOfferTypesBitmask) {
|
||||
return EDLC_NoOffers;
|
||||
}
|
||||
unsigned int C4JStorage::CancelGetDLCOffers() { return 0; }
|
||||
void C4JStorage::ClearDLCOffers() {}
|
||||
XMARKETPLACE_CONTENTOFFER_INFO& C4JStorage::GetOffer(unsigned int dw) {
|
||||
return s_dummyOffer;
|
||||
}
|
||||
int C4JStorage::GetOfferCount() { return 0; }
|
||||
unsigned int C4JStorage::InstallOffer(int iOfferIDC, std::uint64_t* ullOfferIDA,
|
||||
int (*Func)(void*, int, int),
|
||||
void* lpParam, bool bTrial) {
|
||||
return 0;
|
||||
}
|
||||
unsigned int C4JStorage::GetAvailableDLCCount(int iPad) { return 0; }
|
||||
C4JStorage::EDLCStatus C4JStorage::GetInstalledDLC(int iPad,
|
||||
int (*Func)(void*, int, int),
|
||||
void* lpParam) {
|
||||
if (Func) {
|
||||
Func(lpParam, 0, iPad);
|
||||
}
|
||||
return EDLC_NoInstalledDLC;
|
||||
}
|
||||
XCONTENT_DATA& C4JStorage::GetDLC(unsigned int dw) {
|
||||
return s_dummyContentData;
|
||||
}
|
||||
std::uint32_t C4JStorage::MountInstalledDLC(
|
||||
int iPad, std::uint32_t dwDLC,
|
||||
int (*Func)(void*, int, std::uint32_t, std::uint32_t), void* lpParam,
|
||||
const char* szMountDrive) {
|
||||
return 0;
|
||||
}
|
||||
unsigned int C4JStorage::UnmountInstalledDLC(const char* szMountDrive) {
|
||||
return 0;
|
||||
}
|
||||
void C4JStorage::GetMountedDLCFileList(const char* szMountDrive,
|
||||
std::vector<std::string>& fileList) {
|
||||
fileList.clear();
|
||||
}
|
||||
std::string C4JStorage::GetMountedPath(std::string szMount) { return ""; }
|
||||
C4JStorage::ETMSStatus C4JStorage::ReadTMSFile(
|
||||
int iQuadrant, eGlobalStorage eStorageFacility,
|
||||
C4JStorage::eTMS_FileType eFileType, wchar_t* pwchFilename,
|
||||
std::uint8_t** ppBuffer, unsigned int* pBufferSize,
|
||||
int (*Func)(void*, wchar_t*, int, bool, int), void* lpParam, int iAction) {
|
||||
return ETMSStatus_Fail;
|
||||
}
|
||||
bool C4JStorage::WriteTMSFile(int iQuadrant, eGlobalStorage eStorageFacility,
|
||||
wchar_t* pwchFilename, std::uint8_t* pBuffer,
|
||||
unsigned int bufferSize) {
|
||||
return false;
|
||||
}
|
||||
bool C4JStorage::DeleteTMSFile(int iQuadrant, eGlobalStorage eStorageFacility,
|
||||
wchar_t* pwchFilename) {
|
||||
return false;
|
||||
}
|
||||
void C4JStorage::StoreTMSPathName(wchar_t* pwchName) {}
|
||||
C4JStorage::ETMSStatus C4JStorage::TMSPP_ReadFile(
|
||||
int iPad, C4JStorage::eGlobalStorage eStorageFacility,
|
||||
C4JStorage::eTMS_FILETYPEVAL eFileTypeVal, const char* szFilename,
|
||||
int (*Func)(void*, int, int, PTMSPP_FILEDATA, const char*), void* lpParam,
|
||||
int iUserData) {
|
||||
return ETMSStatus_Fail;
|
||||
}
|
||||
unsigned int C4JStorage::CRC(unsigned char* buf, int len) {
|
||||
unsigned int crc = 0xFFFFFFFF;
|
||||
for (int i = 0; i < len; i++) {
|
||||
crc ^= buf[i];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
crc = (crc >> 1) ^ (0xEDB88320 & (-(crc & 1)));
|
||||
}
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
int C4JStorage::AddSubfile(int regionIndex) {
|
||||
(void)regionIndex;
|
||||
return 0;
|
||||
}
|
||||
unsigned int C4JStorage::GetSubfileCount() { return 0; }
|
||||
void C4JStorage::GetSubfileDetails(unsigned int i, int* regionIndex,
|
||||
void** data, unsigned int* size) {
|
||||
(void)i;
|
||||
if (regionIndex) *regionIndex = 0;
|
||||
if (data) *data = 0;
|
||||
if (size) *size = 0;
|
||||
}
|
||||
void C4JStorage::ResetSubfiles() {}
|
||||
void C4JStorage::UpdateSubfile(int index, void* data, unsigned int size) {
|
||||
(void)index;
|
||||
(void)data;
|
||||
(void)size;
|
||||
}
|
||||
void C4JStorage::SaveSubfiles(int (*Func)(void*, const bool), void* param) {
|
||||
if (Func) Func(param, true);
|
||||
}
|
||||
C4JStorage::ESaveGameState C4JStorage::GetSaveState() { return ESaveGame_Idle; }
|
||||
void C4JStorage::ContinueIncompleteOperation() {}
|
||||
@@ -2,13 +2,11 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
// #include <xtms.h>
|
||||
|
||||
#include "../PlatformTypes.h"
|
||||
#include "../IPlatformStorage.h"
|
||||
#include "../4J.Common/4J_Compat.h"
|
||||
|
||||
class C4JStringTable;
|
||||
|
||||
@@ -16,25 +14,23 @@ class C4JStringTable;
|
||||
#define MAX_DETAILS_LENGTH 128 // CELL_SAVEDATA_SYSP_SUBTITLE_SIZE on PS3
|
||||
#define MAX_SAVEFILENAME_LENGTH 32 // CELL_SAVEDATA_DIRNAME_SIZE
|
||||
|
||||
struct CONTAINER_METADATA {
|
||||
typedef struct {
|
||||
time_t modifiedTime;
|
||||
unsigned int dataSize;
|
||||
unsigned int thumbnailSize;
|
||||
};
|
||||
} CONTAINER_METADATA;
|
||||
|
||||
struct SAVE_INFO {
|
||||
typedef struct {
|
||||
char UTF8SaveFilename[MAX_SAVEFILENAME_LENGTH];
|
||||
char UTF8SaveTitle[MAX_DISPLAYNAME_LENGTH];
|
||||
CONTAINER_METADATA metaData;
|
||||
std::uint8_t* thumbnailData;
|
||||
};
|
||||
using PSAVE_INFO = SAVE_INFO*;
|
||||
} SAVE_INFO, *PSAVE_INFO;
|
||||
|
||||
struct SAVE_DETAILS {
|
||||
typedef struct {
|
||||
int iSaveC;
|
||||
PSAVE_INFO SaveInfoA;
|
||||
};
|
||||
using PSAVE_DETAILS = SAVE_DETAILS*;
|
||||
} SAVE_DETAILS, *PSAVE_DETAILS;
|
||||
|
||||
typedef std::vector<PXMARKETPLACE_CONTENTOFFER_INFO> OfferDataArray;
|
||||
typedef std::vector<PXCONTENT_DATA> XContentDataArray;
|
||||
@@ -43,32 +39,89 @@ typedef std::vector<PXCONTENT_DATA> XContentDataArray;
|
||||
// Current version of the dlc data creator
|
||||
#define CURRENT_DLC_VERSION_NUM 3
|
||||
|
||||
class C4JStorage : public IPlatformStorage {
|
||||
class C4JStorage {
|
||||
public:
|
||||
struct DLC_FILE_DETAILS {
|
||||
// Structs defined in the DLC_Creator, but added here to be used in the app
|
||||
typedef struct {
|
||||
unsigned int uiFileSize;
|
||||
std::uint32_t dwType;
|
||||
std::uint32_t dwWchCount;
|
||||
std::uint32_t dwWchCount; // count of wchar_t in next array
|
||||
wchar_t wchFile[1];
|
||||
};
|
||||
using PDLC_FILE_DETAILS = DLC_FILE_DETAILS*;
|
||||
} DLC_FILE_DETAILS, *PDLC_FILE_DETAILS;
|
||||
|
||||
struct DLC_FILE_PARAM {
|
||||
typedef struct {
|
||||
std::uint32_t dwType;
|
||||
std::uint32_t dwWchCount;
|
||||
wchar_t wchData[1];
|
||||
};
|
||||
using PDLC_FILE_PARAM = DLC_FILE_PARAM*;
|
||||
std::uint32_t dwWchCount; // count of wchar_t in next array;
|
||||
wchar_t wchData[1]; // will be an array of size dwBytes
|
||||
} DLC_FILE_PARAM, *PDLC_FILE_PARAM;
|
||||
// End of DLC_Creator structs
|
||||
|
||||
struct CACHEINFOSTRUCT {
|
||||
typedef struct {
|
||||
wchar_t wchDisplayName[XCONTENT_MAX_DISPLAYNAME_LENGTH];
|
||||
char szFileName[XCONTENT_MAX_FILENAME_LENGTH];
|
||||
std::uint32_t dwImageOffset;
|
||||
std::uint32_t dwImageBytes;
|
||||
};
|
||||
} CACHEINFOSTRUCT;
|
||||
|
||||
// structure to hold DLC info in TMS
|
||||
typedef struct {
|
||||
std::uint32_t dwVersion;
|
||||
std::uint32_t dwNewOffers;
|
||||
std::uint32_t dwTotalOffers;
|
||||
std::uint32_t dwInstalledTotalOffers;
|
||||
std::uint8_t bPadding[1024 - sizeof(std::uint32_t) * 4];
|
||||
// future expansion
|
||||
} DLC_TMS_DETAILS;
|
||||
|
||||
enum eGTS_FileTypes { eGTS_Type_Skin = 0, eGTS_Type_Cape, eGTS_Type_MAX };
|
||||
|
||||
enum eGlobalStorage {
|
||||
// eGlobalStorage_GameClip=0,
|
||||
eGlobalStorage_Title = 0,
|
||||
eGlobalStorage_TitleUser,
|
||||
eGlobalStorage_Max
|
||||
};
|
||||
|
||||
enum EMessageResult {
|
||||
EMessage_Undefined = 0,
|
||||
EMessage_Busy,
|
||||
EMessage_Pending,
|
||||
EMessage_Cancelled,
|
||||
EMessage_ResultAccept,
|
||||
EMessage_ResultDecline,
|
||||
EMessage_ResultThirdOption,
|
||||
EMessage_ResultFourthOption
|
||||
};
|
||||
|
||||
enum ESaveGameControlState {
|
||||
ESaveGameControl_Idle = 0,
|
||||
ESaveGameControl_Save,
|
||||
ESaveGameControl_InternalRequestingDevice,
|
||||
ESaveGameControl_InternalGetSaveName,
|
||||
ESaveGameControl_InternalSaving,
|
||||
ESaveGameControl_CopySave,
|
||||
ESaveGameControl_CopyingSave,
|
||||
};
|
||||
|
||||
enum ESaveGameState {
|
||||
ESaveGame_Idle = 0,
|
||||
ESaveGame_Save,
|
||||
ESaveGame_InternalRequestingDevice,
|
||||
ESaveGame_InternalGetSaveName,
|
||||
ESaveGame_InternalSaving,
|
||||
ESaveGame_CopySave,
|
||||
ESaveGame_CopyingSave,
|
||||
ESaveGame_Load,
|
||||
ESaveGame_GetSavesInfo,
|
||||
ESaveGame_Rename,
|
||||
ESaveGame_Delete,
|
||||
|
||||
ESaveGame_GetSaveThumbnail // Not used as an actual state in the PS4,
|
||||
// but the game expects this to be returned
|
||||
// to indicate success when getting a
|
||||
// thumbnail
|
||||
|
||||
};
|
||||
enum ELoadGameStatus {
|
||||
ELoadGame_Idle = 0,
|
||||
ELoadGame_InProgress,
|
||||
@@ -89,20 +142,60 @@ public:
|
||||
ESGIStatus_NoSaves,
|
||||
};
|
||||
|
||||
enum EDLCStatus {
|
||||
EDLC_Error = 0,
|
||||
EDLC_Idle,
|
||||
EDLC_NoOffers,
|
||||
EDLC_AlreadyEnumeratedAllOffers,
|
||||
EDLC_NoInstalledDLC,
|
||||
EDLC_Pending,
|
||||
EDLC_LoadInProgress,
|
||||
EDLC_Loaded,
|
||||
EDLC_ChangedDevice
|
||||
};
|
||||
|
||||
enum ESavingMessage {
|
||||
ESavingMessage_None = 0,
|
||||
ESavingMessage_Short,
|
||||
ESavingMessage_Long
|
||||
};
|
||||
|
||||
enum ETMSStatus {
|
||||
ETMSStatus_Idle = 0,
|
||||
ETMSStatus_Fail,
|
||||
ETMSStatus_Fail_ReadInProgress,
|
||||
ETMSStatus_Fail_WriteInProgress,
|
||||
ETMSStatus_Pending,
|
||||
};
|
||||
|
||||
enum eTMS_FileType {
|
||||
eTMS_FileType_Normal = 0,
|
||||
eTMS_FileType_Graphic,
|
||||
};
|
||||
|
||||
enum eTMS_FILETYPEVAL {
|
||||
TMS_FILETYPE_BINARY,
|
||||
TMS_FILETYPE_CONFIG,
|
||||
TMS_FILETYPE_JSON,
|
||||
TMS_FILETYPE_MAX
|
||||
};
|
||||
enum eTMS_UGCTYPE { TMS_UGCTYPE_NONE, TMS_UGCTYPE_IMAGE, TMS_UGCTYPE_MAX };
|
||||
|
||||
struct TMSPP_FILE_DETAILS {
|
||||
typedef struct {
|
||||
char szFilename[256];
|
||||
int iFileSize;
|
||||
eTMS_FILETYPEVAL eFileTypeVal;
|
||||
};
|
||||
using PTMSPP_FILE_DETAILS = TMSPP_FILE_DETAILS*;
|
||||
} TMSPP_FILE_DETAILS, *PTMSPP_FILE_DETAILS;
|
||||
|
||||
struct TMSPP_FILE_LIST {
|
||||
typedef struct {
|
||||
int iCount;
|
||||
PTMSPP_FILE_DETAILS FileDetailsA;
|
||||
};
|
||||
using PTMSPP_FILE_LIST = TMSPP_FILE_LIST*;
|
||||
} TMSPP_FILE_LIST, *PTMSPP_FILE_LIST;
|
||||
|
||||
typedef struct {
|
||||
unsigned int size;
|
||||
std::uint8_t* pbData;
|
||||
} TMSPP_FILEDATA, *PTMSPP_FILEDATA;
|
||||
|
||||
C4JStorage();
|
||||
|
||||
@@ -112,21 +205,20 @@ public:
|
||||
C4JStorage::EMessageResult RequestMessageBox(
|
||||
unsigned int uiTitle, unsigned int uiText, unsigned int* uiOptionA,
|
||||
unsigned int uiOptionC, unsigned int pad = XUSER_INDEX_ANY,
|
||||
std::function<int(int, const C4JStorage::EMessageResult)> callback =
|
||||
nullptr,
|
||||
C4JStringTable* pStringTable = nullptr,
|
||||
int (*Func)(void*, int, const C4JStorage::EMessageResult) = nullptr,
|
||||
void* lpParam = nullptr, C4JStringTable* pStringTable = nullptr,
|
||||
wchar_t* pwchFormatString = nullptr, unsigned int focusButton = 0);
|
||||
|
||||
C4JStorage::EMessageResult GetMessageBoxResult();
|
||||
|
||||
// save device
|
||||
bool SetSaveDevice(std::function<int(const bool)> callback,
|
||||
bool SetSaveDevice(int (*Func)(void*, const bool), void* lpParam,
|
||||
bool bForceResetOfSaveDevice = false);
|
||||
|
||||
// savegame
|
||||
void Init(unsigned int uiSaveVersion, const wchar_t* pwchDefaultSaveName,
|
||||
char* pszSavePackName, int iMinimumSaveSize,
|
||||
std::function<int(const ESavingMessage, int)> callback,
|
||||
int (*Func)(void*, const ESavingMessage, int), void* lpParam,
|
||||
const char* szGroupID);
|
||||
void ResetSaveData(); // Call before a new save to clear out stored save
|
||||
// file name
|
||||
@@ -137,7 +229,7 @@ public:
|
||||
bool GetSaveUniqueFilename(char* pszName);
|
||||
void SetSaveUniqueFilename(char* szFilename);
|
||||
void SetState(ESaveGameControlState eControlState,
|
||||
std::function<int(const bool)> callback);
|
||||
int (*Func)(void*, const bool), void* lpParam);
|
||||
void SetSaveDisabled(bool bDisable);
|
||||
bool GetSaveDisabled(void);
|
||||
unsigned int GetSaveSize();
|
||||
@@ -150,11 +242,11 @@ public:
|
||||
unsigned int textDataBytes); // Sets the thumbnail & image for the
|
||||
// save, optionally setting the
|
||||
// metadata in the png
|
||||
C4JStorage::ESaveGameState SaveSaveData(
|
||||
std::function<int(const bool)> callback);
|
||||
C4JStorage::ESaveGameState SaveSaveData(int (*Func)(void*, const bool),
|
||||
void* lpParam);
|
||||
void CopySaveDataToNewSave(std::uint8_t* pbThumbnail,
|
||||
unsigned int cbThumbnail, wchar_t* wchNewName,
|
||||
std::function<int(bool)> callback);
|
||||
int (*Func)(void* lpParam, bool), void* lpParam);
|
||||
void SetSaveDeviceSelected(unsigned int uiPad, bool bSelected);
|
||||
bool GetSaveDeviceSelected(unsigned int iPad);
|
||||
C4JStorage::ESaveGameState DoesSaveExist(bool* pbExists);
|
||||
@@ -166,16 +258,16 @@ public:
|
||||
// Get the info for the saves
|
||||
C4JStorage::ESaveGameState GetSavesInfo(
|
||||
int iPad,
|
||||
std::function<int(SAVE_DETAILS* pSaveDetails, const bool)> callback,
|
||||
char* pszSavePackName);
|
||||
int (*Func)(void* lpParam, SAVE_DETAILS* pSaveDetails, const bool),
|
||||
void* lpParam, char* pszSavePackName);
|
||||
PSAVE_DETAILS ReturnSavesInfo();
|
||||
void ClearSavesInfo(); // Clears results
|
||||
C4JStorage::ESaveGameState LoadSaveDataThumbnail(
|
||||
PSAVE_INFO pSaveInfo,
|
||||
std::function<int(std::uint8_t* thumbnailData,
|
||||
unsigned int thumbnailBytes)>
|
||||
callback); // Get the thumbnail for an individual save referenced
|
||||
// by pSaveInfo
|
||||
int (*Func)(void* lpParam, std::uint8_t* thumbnailData,
|
||||
unsigned int thumbnailBytes),
|
||||
void* lpParam); // Get the thumbnail for an individual save referenced
|
||||
// by pSaveInfo
|
||||
|
||||
void GetSaveCacheFileInfo(unsigned int fileIndex,
|
||||
XCONTENT_DATA& xContentData);
|
||||
@@ -184,36 +276,41 @@ public:
|
||||
unsigned int* pImageBytes);
|
||||
|
||||
// Load the save. Need to call GetSaveData once the callback is called
|
||||
C4JStorage::ESaveGameState LoadSaveData(
|
||||
PSAVE_INFO pSaveInfo,
|
||||
std::function<int(const bool, const bool)> callback);
|
||||
C4JStorage::ESaveGameState DeleteSaveData(
|
||||
PSAVE_INFO pSaveInfo,
|
||||
std::function<int(const bool)> callback);
|
||||
C4JStorage::ESaveGameState LoadSaveData(PSAVE_INFO pSaveInfo,
|
||||
int (*Func)(void* lpParam,
|
||||
const bool, const bool),
|
||||
void* lpParam);
|
||||
C4JStorage::ESaveGameState DeleteSaveData(PSAVE_INFO pSaveInfo,
|
||||
int (*Func)(void* lpParam,
|
||||
const bool),
|
||||
void* lpParam);
|
||||
|
||||
// DLC
|
||||
void RegisterMarketplaceCountsCallback(
|
||||
std::function<int(C4JStorage::DLC_TMS_DETAILS*, int)> callback);
|
||||
int (*Func)(void* lpParam, C4JStorage::DLC_TMS_DETAILS*, int),
|
||||
void* lpParam);
|
||||
void SetDLCPackageRoot(char* pszDLCRoot);
|
||||
C4JStorage::EDLCStatus GetDLCOffers(
|
||||
int iPad, std::function<int(int, std::uint32_t, int)> callback,
|
||||
int iPad, int (*Func)(void*, int, std::uint32_t, int), void* lpParam,
|
||||
std::uint32_t dwOfferTypesBitmask = XMARKETPLACE_OFFERING_TYPE_CONTENT);
|
||||
unsigned int CancelGetDLCOffers();
|
||||
void ClearDLCOffers();
|
||||
XMARKETPLACE_CONTENTOFFER_INFO& GetOffer(unsigned int dw);
|
||||
int GetOfferCount();
|
||||
unsigned int InstallOffer(int iOfferIDC, std::uint64_t* ullOfferIDA,
|
||||
std::function<int(int, int)> callback,
|
||||
int (*Func)(void*, int, int), void* lpParam,
|
||||
bool bTrial = false);
|
||||
unsigned int GetAvailableDLCCount(int iPad);
|
||||
|
||||
C4JStorage::EDLCStatus GetInstalledDLC(
|
||||
int iPad, std::function<int(int, int)> callback);
|
||||
C4JStorage::EDLCStatus GetInstalledDLC(int iPad,
|
||||
int (*Func)(void*, int, int),
|
||||
void* lpParam);
|
||||
XCONTENT_DATA& GetDLC(unsigned int dw);
|
||||
std::uint32_t MountInstalledDLC(
|
||||
int iPad, std::uint32_t dwDLC,
|
||||
std::function<int(int, std::uint32_t, std::uint32_t)> callback,
|
||||
const char* szMountDrive = nullptr);
|
||||
std::uint32_t MountInstalledDLC(int iPad, std::uint32_t dwDLC,
|
||||
int (*Func)(void*, int, std::uint32_t,
|
||||
std::uint32_t),
|
||||
void* lpParam,
|
||||
const char* szMountDrive = nullptr);
|
||||
unsigned int UnmountInstalledDLC(const char* szMountDrive = nullptr);
|
||||
void GetMountedDLCFileList(const char* szMountDrive,
|
||||
std::vector<std::string>& fileList);
|
||||
@@ -224,8 +321,8 @@ public:
|
||||
int iQuadrant, eGlobalStorage eStorageFacility,
|
||||
C4JStorage::eTMS_FileType eFileType, wchar_t* pwchFilename,
|
||||
std::uint8_t** ppBuffer, unsigned int* pBufferSize,
|
||||
std::function<int(wchar_t*, int, bool, int)> callback = nullptr,
|
||||
int iAction = 0);
|
||||
int (*Func)(void*, wchar_t*, int, bool, int) = nullptr,
|
||||
void* lpParam = nullptr, int iAction = 0);
|
||||
bool WriteTMSFile(int iQuadrant, eGlobalStorage eStorageFacility,
|
||||
wchar_t* pwchFilename, std::uint8_t* pBuffer,
|
||||
unsigned int bufferSize);
|
||||
@@ -247,9 +344,8 @@ public:
|
||||
C4JStorage::ETMSStatus TMSPP_ReadFile(
|
||||
int iPad, C4JStorage::eGlobalStorage eStorageFacility,
|
||||
C4JStorage::eTMS_FILETYPEVAL eFileTypeVal, const char* szFilename,
|
||||
std::function<int(int, int, PTMSPP_FILEDATA, const char*)> callback =
|
||||
nullptr,
|
||||
int iUserData = 0);
|
||||
int (*Func)(void*, int, int, PTMSPP_FILEDATA, const char*) = nullptr,
|
||||
void* lpParam = nullptr, int iUserData = 0);
|
||||
// Older TMS++ list/delete helpers stayed platform-specific. The shared
|
||||
// surface keeps the read path plus CRC/subfile helpers below.
|
||||
|
||||
@@ -271,7 +367,7 @@ public:
|
||||
unsigned int* size);
|
||||
void ResetSubfiles();
|
||||
void UpdateSubfile(int index, void* data, unsigned int size);
|
||||
void SaveSubfiles(std::function<int(const bool)> callback);
|
||||
void SaveSubfiles(int (*Func)(void*, const bool), void* param);
|
||||
ESaveGameState GetSaveState();
|
||||
|
||||
void ContinueIncompleteOperation();
|
||||
@@ -0,0 +1,20 @@
|
||||
storage_sources = files(
|
||||
'4J_Storage.cpp',
|
||||
'stdafx.cpp',
|
||||
'STO_DLC.cpp',
|
||||
'STO_Main.cpp',
|
||||
'STO_SaveGame.cpp',
|
||||
)
|
||||
|
||||
lib_storage = static_library('4J_Storage',
|
||||
storage_sources,
|
||||
include_directories : include_directories('.'),
|
||||
cpp_args : global_cpp_args + global_cpp_defs + [
|
||||
'-include', meson.current_source_dir() / 'stdafx.h',
|
||||
],
|
||||
)
|
||||
|
||||
storage_dep = declare_dependency(
|
||||
link_with : lib_storage,
|
||||
include_directories : include_directories('.'),
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
#include "stdafx.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _4J_STORAGE_STADAFX_H
|
||||
#define _4J_STORAGE_STADAFX_H
|
||||
|
||||
#include "../4J.Common/4J_Compat.h"
|
||||
|
||||
#endif //_4J_STORAGE_STADAFX_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user