Compare commits
3 Commits
365e238c29
...
0dd0706f52
Author | SHA1 | Date | |
---|---|---|---|
0dd0706f52 | |||
1743626113 | |||
4ed11b67e7 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -9,3 +9,5 @@ appimage-builder-cache
|
||||
appimage-build
|
||||
AppDir
|
||||
*.zsync
|
||||
core*
|
||||
qemu_*
|
||||
|
@ -2,15 +2,15 @@ cmake_minimum_required(VERSION 3.13.0)
|
||||
|
||||
# Specify Options
|
||||
option(MCPI_IS_MIXED_BUILD "Whether The Architecture-Independent And ARM Code Are Different Architecture" FALSE)
|
||||
if(MCPI_IS_MIXED_BUILD)
|
||||
option(MCPI_BUNDLE_ARMHF_SYSROOT "Whether To Include An ARMHF Sysroot" TRUE)
|
||||
endif()
|
||||
option(MCPI_BUNDLE_ARMHF_SYSROOT "Whether To Include An ARMHF Sysroot" ${MCPI_IS_MIXED_BUILD})
|
||||
option(MCPI_SERVER_MODE "Server Mode" FALSE)
|
||||
option(MCPI_HEADLESS_MODE "Headless Mode" ${MCPI_SERVER_MODE})
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
option(MCPI_USE_MEDIA_LAYER_PROXY "Whether To Enable The Media Layer Proxy" ${MCPI_IS_MIXED_BUILD})
|
||||
option(MCPI_USE_GLES1_COMPATIBILITY_LAYER "Whether To Enable The GLESv1_CM Compatibility Layer" TRUE)
|
||||
else()
|
||||
set(MCPI_USE_MEDIA_LAYER_PROXY FALSE)
|
||||
set(MCPI_USE_GLES1_COMPATIBILITY_LAYER FALSE)
|
||||
endif()
|
||||
set(MCPI_BUILD_MODE "both" CACHE STRING "\"arm\" = Build Only Code That Must Be ARM; \"native\" = Build Architecture-Independent Code; \"both\" = Build All Code As ARM")
|
||||
set_property(CACHE MCPI_BUILD_MODE PROPERTY STRINGS "both" "arm" "native")
|
||||
@ -118,6 +118,9 @@ endif()
|
||||
if(MCPI_BUNDLE_ARMHF_SYSROOT)
|
||||
add_definitions(-DMCPI_BUNDLE_ARMHF_SYSROOT)
|
||||
endif()
|
||||
if(MCPI_USE_GLES1_COMPATIBILITY_LAYER)
|
||||
add_definitions(-DMCPI_USE_GLES1_COMPATIBILITY_LAYER)
|
||||
endif()
|
||||
|
||||
# Version
|
||||
set_property(
|
||||
|
7
dependencies/minecraft-pi/CMakeLists.txt
vendored
7
dependencies/minecraft-pi/CMakeLists.txt
vendored
@ -12,4 +12,9 @@ FetchContent_Declare(
|
||||
FetchContent_Populate(minecraft-pi)
|
||||
|
||||
# Install
|
||||
install(DIRECTORY "${minecraft-pi_SOURCE_DIR}/" DESTINATION "${MCPI_INSTALL_DIR}" USE_SOURCE_PERMISSIONS)
|
||||
install(
|
||||
DIRECTORY "${minecraft-pi_SOURCE_DIR}/"
|
||||
DESTINATION "${MCPI_INSTALL_DIR}"
|
||||
USE_SOURCE_PERMISSIONS
|
||||
REGEX "api" EXCLUDE
|
||||
)
|
||||
|
@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
**2.3.11**
|
||||
* ``--version`` Command Line Option
|
||||
* TPS Measured In Benchmark & Server
|
||||
* Front-Facing Third-Person
|
||||
* GLESv1 Comparability Layer
|
||||
* Miscellaneous Bug Fixes
|
||||
|
||||
**2.3.10**
|
||||
* Add Crash Report Dialog
|
||||
* Disable V-Sync By Default
|
||||
|
@ -2,8 +2,11 @@
|
||||
|
||||
## Command Line Arguments
|
||||
|
||||
### ``--version`` (Or ``-v``)
|
||||
If you run MCPI-Reborn with ``--version`` it will print its version to ``stdout``.
|
||||
|
||||
### ``--print-available-feature-flags`` (Client Mode Only)
|
||||
If you run MCPI-Reborn with ``--print-available-feature-flags``, it will print the available feature flags and then immediately exit.
|
||||
If you run MCPI-Reborn with ``--print-available-feature-flags``, it will print the available feature flags to ``stdout`` and then immediately exit.
|
||||
|
||||
The feature flags are printed in the following format:
|
||||
```
|
||||
|
BIN
images/start.png
BIN
images/start.png
Binary file not shown.
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
@ -149,7 +149,17 @@ static void exit_handler(__attribute__((unused)) int signal_id) {
|
||||
}
|
||||
|
||||
// Pre-Bootstrap
|
||||
void pre_bootstrap() {
|
||||
void pre_bootstrap(int argc, char *argv[]) {
|
||||
// Print Version
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
|
||||
// Print
|
||||
printf("Reborn v%s\n", VERSION);
|
||||
fflush(stdout);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
// GTK Dark Mode
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
set_and_print_env("GTK_THEME", "Adwaita:dark");
|
||||
@ -219,30 +229,6 @@ void bootstrap(int argc, char *argv[]) {
|
||||
// Get Binary Directory
|
||||
char *binary_directory = get_binary_directory();
|
||||
|
||||
// Resolve Binary Path & Set MCPI_DIRECTORY
|
||||
{
|
||||
// Log
|
||||
DEBUG("Resolving File Paths...");
|
||||
|
||||
// Resolve Full Binary Path
|
||||
char *full_path = NULL;
|
||||
safe_asprintf(&full_path, "%s/" MCPI_BINARY, binary_directory);
|
||||
char *resolved_path = realpath(full_path, NULL);
|
||||
ALLOC_CHECK(resolved_path);
|
||||
free(full_path);
|
||||
|
||||
// Set MCPI_EXECUTABLE_PATH
|
||||
set_and_print_env("MCPI_EXECUTABLE_PATH", resolved_path);
|
||||
|
||||
// Set MCPI_VANILLA_ASSETS_PATH
|
||||
{
|
||||
chop_last_component(&resolved_path);
|
||||
string_append(&resolved_path, "/data");
|
||||
set_and_print_env("MCPI_VANILLA_ASSETS_PATH", resolved_path);
|
||||
free(resolved_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Set MCPI_REBORN_ASSETS_PATH
|
||||
{
|
||||
char *assets_path = realpath("/proc/self/exe", NULL);
|
||||
@ -253,6 +239,20 @@ void bootstrap(int argc, char *argv[]) {
|
||||
free(assets_path);
|
||||
}
|
||||
|
||||
// Resolve Binary Path & Set MCPI_DIRECTORY
|
||||
char *resolved_path = NULL;
|
||||
{
|
||||
// Log
|
||||
DEBUG("Resolving File Paths...");
|
||||
|
||||
// Resolve Full Binary Path
|
||||
char *full_path = NULL;
|
||||
safe_asprintf(&full_path, "%s/" MCPI_BINARY, binary_directory);
|
||||
resolved_path = realpath(full_path, NULL);
|
||||
ALLOC_CHECK(resolved_path);
|
||||
free(full_path);
|
||||
}
|
||||
|
||||
// Fix MCPI Dependencies
|
||||
{
|
||||
// Log
|
||||
@ -273,7 +273,7 @@ void bootstrap(int argc, char *argv[]) {
|
||||
#endif
|
||||
|
||||
// Patch
|
||||
patch_mcpi_elf_dependencies(linker);
|
||||
patch_mcpi_elf_dependencies(resolved_path, linker);
|
||||
|
||||
// Free Linker Path
|
||||
if (linker != NULL) {
|
||||
@ -286,6 +286,19 @@ void bootstrap(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
// Set MCPI_VANILLA_ASSETS_PATH
|
||||
{
|
||||
char *assets_path = strdup(resolved_path);
|
||||
ALLOC_CHECK(assets_path);
|
||||
chop_last_component(&assets_path);
|
||||
string_append(&assets_path, "/data");
|
||||
set_and_print_env("MCPI_VANILLA_ASSETS_PATH", assets_path);
|
||||
free(assets_path);
|
||||
}
|
||||
|
||||
// Free Resolved Path
|
||||
free(resolved_path);
|
||||
|
||||
// Configure LD_LIBRARY_PATH
|
||||
{
|
||||
// Log
|
||||
|
@ -6,7 +6,7 @@ extern "C" {
|
||||
|
||||
void set_and_print_env(const char *name, char *value);
|
||||
|
||||
void pre_bootstrap();
|
||||
void pre_bootstrap(int argc, char *argv[]);
|
||||
void bootstrap(int argc, char *argv[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -127,7 +127,7 @@ static void run_zenity_and_set_env(const char *env_name, std::vector<std::string
|
||||
#define LIST_DIALOG_SIZE "400"
|
||||
int main(int argc, char *argv[]) {
|
||||
// Pre-Bootstrap
|
||||
pre_bootstrap();
|
||||
pre_bootstrap(argc, argv);
|
||||
|
||||
// Print Features
|
||||
for (int i = 1; i < argc; i++) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
@ -41,14 +42,16 @@ static void exit_handler(__attribute__((unused)) int signal) {
|
||||
}
|
||||
|
||||
// Setup
|
||||
#define PIPE_READ 0
|
||||
#define PIPE_WRITE 1
|
||||
void setup_crash_report() {
|
||||
// Store Output
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
int output_pipe[2];
|
||||
safe_pipe2(output_pipe, 0);
|
||||
int error_pipe[2];
|
||||
safe_pipe2(error_pipe, 0);
|
||||
#endif
|
||||
int input_pipe[2];
|
||||
safe_pipe2(input_pipe, 0);
|
||||
|
||||
// Fork
|
||||
pid_t ret = fork();
|
||||
@ -58,14 +61,15 @@ void setup_crash_report() {
|
||||
// Child Process
|
||||
|
||||
// Pipe stdio
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
dup2(output_pipe[1], STDOUT_FILENO);
|
||||
close(output_pipe[0]);
|
||||
close(output_pipe[1]);
|
||||
dup2(error_pipe[1], STDERR_FILENO);
|
||||
close(error_pipe[0]);
|
||||
close(error_pipe[1]);
|
||||
#endif
|
||||
dup2(output_pipe[PIPE_WRITE], STDOUT_FILENO);
|
||||
close(output_pipe[PIPE_READ]);
|
||||
close(output_pipe[PIPE_WRITE]);
|
||||
dup2(error_pipe[PIPE_WRITE], STDERR_FILENO);
|
||||
close(error_pipe[PIPE_READ]);
|
||||
close(error_pipe[PIPE_WRITE]);
|
||||
dup2(input_pipe[PIPE_READ], STDIN_FILENO);
|
||||
close(input_pipe[PIPE_READ]);
|
||||
close(input_pipe[PIPE_WRITE]);
|
||||
|
||||
// Create New Process Group
|
||||
setpgid(0, 0);
|
||||
@ -87,13 +91,12 @@ void setup_crash_report() {
|
||||
act_sigterm.sa_handler = &exit_handler;
|
||||
sigaction(SIGTERM, &act_sigterm, NULL);
|
||||
|
||||
// Capture stdio
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
// Close Unneeded File Descriptors
|
||||
close(output_pipe[1]);
|
||||
close(error_pipe[1]);
|
||||
close(output_pipe[PIPE_WRITE]);
|
||||
close(error_pipe[PIPE_WRITE]);
|
||||
close(input_pipe[PIPE_READ]);
|
||||
|
||||
// Create A Buffer
|
||||
// Setup Logging
|
||||
#define BUFFER_SIZE 1024
|
||||
char buf[BUFFER_SIZE];
|
||||
|
||||
@ -105,10 +108,11 @@ void setup_crash_report() {
|
||||
}
|
||||
|
||||
// Setup Polling
|
||||
int number_fds = 2;
|
||||
int number_fds = 3;
|
||||
struct pollfd poll_fds[number_fds];
|
||||
poll_fds[0].fd = output_pipe[0];
|
||||
poll_fds[1].fd = error_pipe[0];
|
||||
poll_fds[0].fd = output_pipe[PIPE_READ];
|
||||
poll_fds[1].fd = error_pipe[PIPE_READ];
|
||||
poll_fds[2].fd = STDIN_FILENO;
|
||||
for (int i = 0; i < number_fds; i++) {
|
||||
poll_fds[i].events = POLLIN;
|
||||
}
|
||||
@ -129,31 +133,51 @@ void setup_crash_report() {
|
||||
for (int i = 0; i < number_fds; i++) {
|
||||
if (poll_fds[i].revents != 0) {
|
||||
if (poll_fds[i].revents & POLLIN) {
|
||||
// Data Available
|
||||
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */);
|
||||
if (bytes_read == -1) {
|
||||
ERR("Unable To Read Log Data: %s", strerror(errno));
|
||||
}
|
||||
if (poll_fds[i].fd == STDIN_FILENO) {
|
||||
// Data Available From stdin
|
||||
int bytes_available;
|
||||
if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) {
|
||||
bytes_available = 0;
|
||||
}
|
||||
// Read
|
||||
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE);
|
||||
if (bytes_read == -1) {
|
||||
ERR("Unable To Read Log Data: %s", strerror(errno));
|
||||
}
|
||||
// Write To Child
|
||||
if (write(input_pipe[PIPE_WRITE], (void *) buf, bytes_read) == -1) {
|
||||
ERR("Unable To Write Input To Child: %s", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
// Data Available From Child's stdout/stderr
|
||||
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */);
|
||||
if (bytes_read == -1) {
|
||||
ERR("Unable To Read Log Data: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Print To Terminal
|
||||
buf[bytes_read] = '\0';
|
||||
fprintf(i == 0 ? stdout : stderr, "%s", buf);
|
||||
// Print To Terminal
|
||||
buf[bytes_read] = '\0';
|
||||
fprintf(i == 0 ? stdout : stderr, "%s", buf);
|
||||
|
||||
// Write To log
|
||||
if (write(log_file_fd, (void *) buf, bytes_read) == -1) {
|
||||
ERR("Unable To Write Log Data: %s", strerror(errno));
|
||||
// Write To log
|
||||
if (write(log_file_fd, (void *) buf, bytes_read) == -1) {
|
||||
ERR("Unable To Write Log Data: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// File Descriptor No Longer Accessible
|
||||
if (close(poll_fds[i].fd) == -1) {
|
||||
if (poll_fds[i].events != 0 && close(poll_fds[i].fd) == -1) {
|
||||
ERR("Unable To Close File Descriptor: %s", strerror(errno));
|
||||
}
|
||||
poll_fds[i].events = 0;
|
||||
number_open_fds--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Close Input Pipe
|
||||
close(input_pipe[PIPE_WRITE]);
|
||||
|
||||
// Get Return Code
|
||||
int status;
|
||||
@ -176,33 +200,30 @@ void setup_crash_report() {
|
||||
fprintf(stderr, "%s", exit_code_line);
|
||||
|
||||
// Write Exit Code Log Line
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
if (write(log_file_fd, (void *) exit_code_line, strlen(exit_code_line)) == -1) {
|
||||
ERR("Unable To Write Exit Code To Log: %s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Free Exit Code Log Line
|
||||
free(exit_code_line);
|
||||
}
|
||||
|
||||
// Show Crash Log
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
// Close Log File FD
|
||||
if (close(log_file_fd) == -1) {
|
||||
ERR("Unable To Close Log File Descriptor: %s", strerror(errno));
|
||||
}
|
||||
|
||||
// Show Report
|
||||
// Show Crash Log
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
if (is_crash) {
|
||||
show_report(log_filename);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Delete Log File
|
||||
if (unlink(log_filename) == -1) {
|
||||
ERR("Unable To Delete Log File: %s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Exit
|
||||
exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
|
||||
|
@ -9,10 +9,7 @@
|
||||
|
||||
// Duplicate MCPI Executable Into /tmp
|
||||
#define TMP_DIR "/tmp/.minecraft-pi-patched"
|
||||
static void duplicate_mcpi_executable() {
|
||||
// Get Original Path
|
||||
const char *original_path = getenv("MCPI_EXECUTABLE_PATH");
|
||||
|
||||
static void duplicate_mcpi_executable(const char *original_path) {
|
||||
// Ensure Temporary Directory
|
||||
{
|
||||
// Check If It Exists
|
||||
@ -89,9 +86,9 @@ static void duplicate_mcpi_executable() {
|
||||
} \
|
||||
_macro_return_code; \
|
||||
})
|
||||
void patch_mcpi_elf_dependencies(const char *linker) {
|
||||
void patch_mcpi_elf_dependencies(const char *original_path, const char *linker) {
|
||||
// Duplicate MCPI executable into /tmp so it can be modified.
|
||||
duplicate_mcpi_executable();
|
||||
duplicate_mcpi_executable(original_path);
|
||||
|
||||
// Get Path
|
||||
char *exe = getenv("MCPI_EXECUTABLE_PATH");
|
||||
|
@ -4,7 +4,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void patch_mcpi_elf_dependencies(const char *linker);
|
||||
void patch_mcpi_elf_dependencies(const char *original_path, const char *linker);
|
||||
char *patch_get_interpreter(const char *file);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// Pre-Bootstrap
|
||||
pre_bootstrap();
|
||||
pre_bootstrap(argc, argv);
|
||||
|
||||
// Set Home To Current Directory, So World Data Is Stored There
|
||||
char *launch_directory = getcwd(NULL, 0);
|
||||
|
@ -13,9 +13,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Find And Iterate Over All .text Sections In Current Binary
|
||||
typedef void (*text_section_callback_t)(ElfW(Addr) section, ElfW(Word) size, void *data);
|
||||
void iterate_text_sections(const char *exe, text_section_callback_t callback, void *data);
|
||||
// Find And Iterate Over All Segments In Current Binary
|
||||
typedef void (*segment_callback_t)(ElfW(Addr) section, ElfW(Word) size, void *data);
|
||||
void iterate_segments(segment_callback_t callback, void *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
dlerror(); \
|
||||
real_##name = (name##_t) dlsym(RTLD_NEXT, #name); \
|
||||
if (!real_##name) { \
|
||||
ERR("Error Resolving Symbol: "#name": %s", dlerror()); \
|
||||
ERR("Error Resolving Symbol: " #name ": %s", dlerror()); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
@ -49,6 +49,8 @@ extern "C" {
|
||||
|
||||
// Safe Version Of pipe()
|
||||
void safe_pipe2(int pipefd[2], int flags);
|
||||
// Check If Two Percentages Are Different Enough To Be Logged
|
||||
int is_progress_difference_significant(int32_t new_val, int32_t old_val);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ void _overwrite_calls(const char *file, int line, void *start, void *target) {
|
||||
data.replacement = code_block;
|
||||
data.found = 0;
|
||||
|
||||
iterate_text_sections(getenv("MCPI_EXECUTABLE_PATH"), overwrite_calls_callback, &data);
|
||||
iterate_segments(overwrite_calls_callback, &data);
|
||||
|
||||
// Increment Code Block Position
|
||||
increment_code_block();
|
||||
|
@ -1,53 +1,28 @@
|
||||
#include <libreborn/elf.h>
|
||||
|
||||
// Find And Iterate Over All .text Sections In Current Binary
|
||||
void iterate_text_sections(const char *exe, text_section_callback_t callback, void *data) {
|
||||
// Load Main Binary
|
||||
FILE *file_obj = fopen(exe, "rb");
|
||||
|
||||
// Verify Binary
|
||||
if (!file_obj) {
|
||||
ERR("Unable To Open Binary");
|
||||
}
|
||||
|
||||
// Get File Size
|
||||
fseek(file_obj, 0L, SEEK_END);
|
||||
long int file_size = ftell(file_obj);
|
||||
fseek(file_obj, 0L, SEEK_SET);
|
||||
|
||||
// Map File To Pointer
|
||||
unsigned char *file_map = (unsigned char *) mmap(0, file_size, PROT_READ, MAP_PRIVATE, fileno(file_obj), 0);
|
||||
|
||||
// Parse ELF
|
||||
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_map;
|
||||
ElfW(Shdr) *elf_section_headers = (ElfW(Shdr) *) (file_map + elf_header->e_shoff);
|
||||
int elf_section_header_count = elf_header->e_shnum;
|
||||
|
||||
// Locate Section Names
|
||||
ElfW(Shdr) elf_shstrtab = elf_section_headers[elf_header->e_shstrndx];
|
||||
unsigned char *elf_shstrtab_p = file_map + elf_shstrtab.sh_offset;
|
||||
|
||||
// Track .text Sections
|
||||
int text_sections = 0;
|
||||
|
||||
// Iterate Sections
|
||||
for (int i = 0; i < elf_section_header_count; ++i) {
|
||||
ElfW(Shdr) header = elf_section_headers[i];
|
||||
char *name = (char *) (elf_shstrtab_p + header.sh_name);
|
||||
// Check Section Type
|
||||
if (strcmp(name, ".text") == 0) {
|
||||
// .text Section
|
||||
(*callback)(header.sh_addr, header.sh_size, data);
|
||||
text_sections++;
|
||||
// Find And Iterate Over All Segments In Current Binary
|
||||
typedef struct {
|
||||
segment_callback_t callback;
|
||||
void *data;
|
||||
} dl_iterate_callback_data;
|
||||
static int dl_iterate_callback(struct dl_phdr_info *info, __attribute__((unused)) size_t size, void *data) {
|
||||
dl_iterate_callback_data *callback_data = (dl_iterate_callback_data *) data;
|
||||
// Only Search Current Program
|
||||
if (strcmp(info->dlpi_name, "") == 0) {
|
||||
for (int i = 0; i < info->dlpi_phnum; i++) {
|
||||
// Only Executable Segemnts
|
||||
if (info->dlpi_phdr[i].p_type == PT_LOAD && (info->dlpi_phdr[i].p_flags & PF_X) != 0) {
|
||||
// Callback
|
||||
(*callback_data->callback)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_memsz, callback_data->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure At Least .text Section Was Scanned
|
||||
if (text_sections < 1) {
|
||||
ERR("Unable To Find .text Sectons");
|
||||
}
|
||||
|
||||
// Unmap And Close File
|
||||
munmap(file_map, file_size);
|
||||
fclose(file_obj);
|
||||
return 0;
|
||||
}
|
||||
void iterate_segments(segment_callback_t callback, void *data) {
|
||||
dl_iterate_callback_data callback_data = {
|
||||
.callback = callback,
|
||||
.data = data
|
||||
};
|
||||
dl_iterate_phdr(dl_iterate_callback, (void *) &callback_data);
|
||||
}
|
||||
|
@ -6,3 +6,19 @@ void safe_pipe2(int pipefd[2], int flags) {
|
||||
ERR("Unable To Create Pipe: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
// Check If Two Percentages Are Different Enough To Be Logged
|
||||
#define SIGNIFICANT_PROGRESS 5
|
||||
int is_progress_difference_significant(int32_t new_val, int32_t old_val) {
|
||||
if (new_val != old_val) {
|
||||
if (new_val == -1 || old_val == -1) {
|
||||
return 1;
|
||||
} else if (new_val == 0 || new_val == 100) {
|
||||
return 1;
|
||||
} else {
|
||||
return new_val - old_val >= SIGNIFICANT_PROGRESS;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
project(media-layer)
|
||||
|
||||
# Check Options
|
||||
if(MCPI_USE_MEDIA_LAYER_PROXY AND MCPI_BUILD_MODE STREQUAL "both")
|
||||
message(FATAL_ERROR "Media Layer Proxy Is Redundant When Building ARM And Native Components In The Same Build")
|
||||
endif()
|
||||
# Target Notes:
|
||||
# media-layer-core-real: Fully Built Media Layer Core
|
||||
# media-layer-core: Alias Target That Points To The Library MCPI Should Link To
|
||||
|
||||
# Add Headers
|
||||
add_library(media-layer-headers INTERFACE)
|
||||
target_include_directories(media-layer-headers INTERFACE include)
|
||||
|
||||
# Add GLESv1_CM Stubs Or Compatibility Layer
|
||||
add_subdirectory(gles)
|
||||
|
||||
# Add Core
|
||||
add_subdirectory(core)
|
||||
|
||||
@ -17,8 +19,5 @@ if(MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
add_subdirectory(proxy)
|
||||
endif()
|
||||
|
||||
# Add Stubs
|
||||
add_subdirectory(stubs)
|
||||
|
||||
# Add Extras
|
||||
add_subdirectory(extras)
|
||||
|
@ -8,26 +8,30 @@ endif()
|
||||
|
||||
# Build
|
||||
if(MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_NATIVE_COMPONENTS)
|
||||
# Building Native Components
|
||||
add_library(media-layer-core OBJECT ${CORE_SRC}) # Dependencies Are Setup Later
|
||||
elseif(NOT MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_ARM_COMPONENTS)
|
||||
# Building ARM Components
|
||||
add_library(media-layer-core SHARED ${CORE_SRC}) # Dependencies Are Setup Later
|
||||
# Build Media Layer Core Natively And Use Proxy
|
||||
add_library(media-layer-core-real OBJECT ${CORE_SRC}) # Dependencies Are Setup Later
|
||||
endif()
|
||||
if(NOT MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_ARM_COMPONENTS)
|
||||
# Directly Link Media Layer Core To MCPI
|
||||
add_library(media-layer-core-real SHARED ${CORE_SRC}) # Dependencies Are Setup Later
|
||||
set_target_properties(media-layer-core-real PROPERTIES OUTPUT_NAME "media-layer-core")
|
||||
# Install
|
||||
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
|
||||
install(TARGETS media-layer-core-real DESTINATION "${MCPI_LIB_DIR}")
|
||||
# Create Alias Target For Linking
|
||||
add_library(media-layer-core ALIAS media-layer-core-real)
|
||||
endif()
|
||||
|
||||
# Configure Media Layer Core If Built
|
||||
if(TARGET media-layer-core)
|
||||
if(TARGET media-layer-core-real)
|
||||
# Link
|
||||
target_link_libraries(media-layer-core media-layer-headers reborn-util pthread dl)
|
||||
target_link_libraries(media-layer-core-real media-layer-headers reborn-util pthread dl)
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
# Find FreeImage
|
||||
find_library(FREEIMAGE_LIBRARY NAMES freeimage libfreeimage.so.3 REQUIRED)
|
||||
# OpenAL
|
||||
find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
|
||||
# Link
|
||||
target_link_libraries(media-layer-core "${FREEIMAGE_LIBRARY}" "${OPENAL_LIBRARY}" m GLESv1_CM glfw)
|
||||
target_link_libraries(media-layer-core-real "${FREEIMAGE_LIBRARY}" "${OPENAL_LIBRARY}" m GLESv1_CM glfw)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -15,6 +15,7 @@ static std::vector<ALuint> &get_sources() {
|
||||
return sources;
|
||||
}
|
||||
|
||||
// Error Checking
|
||||
#define AL_ERROR_CHECK() AL_ERROR_CHECK_MANUAL(alGetError())
|
||||
#define AL_ERROR_CHECK_MANUAL(val) \
|
||||
{ \
|
||||
@ -73,6 +74,7 @@ void media_audio_update(float volume, float x, float y, float z, float yaw) {
|
||||
}
|
||||
}
|
||||
|
||||
// Play
|
||||
void media_audio_play(const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui) {
|
||||
// Check
|
||||
if (_media_audio_is_loaded()) {
|
||||
|
@ -207,21 +207,18 @@ static ALuint load_sound(const char *source, const char *name) {
|
||||
}
|
||||
|
||||
// Store Buffers
|
||||
static std::unordered_map<std::string, ALuint> &get_buffers() {
|
||||
static std::unordered_map<std::string, ALuint> buffers;
|
||||
return buffers;
|
||||
}
|
||||
static std::unordered_map<std::string, ALuint> buffers;
|
||||
|
||||
// Get Buffer For Sound
|
||||
ALuint _media_audio_get_buffer(const char *source, const char *name) {
|
||||
// Check
|
||||
if (_media_audio_is_loaded()) {
|
||||
if (get_buffers().count(name) > 0) {
|
||||
if (buffers.count(name) > 0) {
|
||||
// Return
|
||||
return get_buffers()[name];
|
||||
return buffers[name];
|
||||
} else {
|
||||
// Load And Return
|
||||
get_buffers()[name] = load_sound(source, name);
|
||||
buffers[name] = load_sound(source, name);
|
||||
return _media_audio_get_buffer(source, name);
|
||||
}
|
||||
} else {
|
||||
@ -232,11 +229,11 @@ ALuint _media_audio_get_buffer(const char *source, const char *name) {
|
||||
// Delete Buffers
|
||||
void _media_audio_delete_buffers() {
|
||||
if (_media_audio_is_loaded()) {
|
||||
for (auto it : get_buffers()) {
|
||||
for (auto it : buffers) {
|
||||
if (it.second && alIsBuffer(it.second)) {
|
||||
alDeleteBuffers(1, &it.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
get_buffers().clear();
|
||||
buffers.clear();
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
#define GLFW_INCLUDE_NONE
|
||||
@ -225,7 +224,7 @@ static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute_
|
||||
#endif
|
||||
|
||||
// Track Media Layer State
|
||||
static int is_running = 0;
|
||||
static volatile int is_running = 0;
|
||||
|
||||
// Track If Raw Mouse Motion Is Enabled
|
||||
static int raw_mouse_motion_enabled = 1;
|
||||
@ -253,6 +252,8 @@ void media_disable_vsync() {
|
||||
}
|
||||
|
||||
// Init Media Layer
|
||||
#define GL_VERSION 0x1f02
|
||||
typedef const unsigned char *(*glGetString_t)(unsigned int name);
|
||||
void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *icon) {
|
||||
// Don't Enable GLFW In Headless Mode
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
@ -263,10 +264,15 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
|
||||
ERR("Unable To Initialize GLFW");
|
||||
}
|
||||
|
||||
// Create OpenGL ES 1.1 Context
|
||||
// Create OpenGL ES Context
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
|
||||
#ifdef MCPI_USE_GLES1_COMPATIBILITY_LAYER
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||
#else
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
||||
#endif
|
||||
// Use EGL
|
||||
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
|
||||
// Extra Settings
|
||||
@ -289,6 +295,10 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
|
||||
// Make Window Context Current
|
||||
glfwMakeContextCurrent(glfw_window);
|
||||
|
||||
// Debug
|
||||
glGetString_t glGetString = (glGetString_t) glfwGetProcAddress("glGetString");
|
||||
DEBUG("Using %s", (*glGetString)(GL_VERSION));
|
||||
|
||||
// Init OpenAL
|
||||
_media_audio_init();
|
||||
#else
|
||||
@ -303,6 +313,9 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
|
||||
if (disable_vsync) {
|
||||
media_disable_vsync();
|
||||
}
|
||||
|
||||
// Always Cleanup Media Layer
|
||||
atexit(media_cleanup);
|
||||
}
|
||||
|
||||
void media_swap_buffers() {
|
||||
@ -384,10 +397,6 @@ void media_cleanup() {
|
||||
is_running = 0;
|
||||
}
|
||||
}
|
||||
// Always Cleanup Media Layer
|
||||
__attribute__((destructor)) static void always_cleanup() {
|
||||
media_cleanup();
|
||||
}
|
||||
|
||||
// Store Cursor State
|
||||
static int cursor_grabbed = 0;
|
||||
|
@ -70,7 +70,7 @@ void media_take_screenshot(char *home) {
|
||||
int height = viewport[3];
|
||||
|
||||
// Get Line Size
|
||||
int line_size = width * 3;
|
||||
int line_size = width * 4;
|
||||
{
|
||||
// Handle Alignment
|
||||
int alignment;
|
||||
@ -85,14 +85,14 @@ void media_take_screenshot(char *home) {
|
||||
|
||||
// Read Pixels
|
||||
unsigned char pixels[size];
|
||||
glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
|
||||
glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Handle Little Endian Systems
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
// Swap Red And Blue
|
||||
for (int j = 0; j < width; j++) {
|
||||
for (int k = 0; k < height; k++) {
|
||||
int pixel = (k * line_size) + (j * 3);
|
||||
int pixel = (k * line_size) + (j * 4);
|
||||
// Swap
|
||||
int red = pixels[pixel];
|
||||
int blue = pixels[pixel + 2];
|
||||
@ -103,7 +103,7 @@ void media_take_screenshot(char *home) {
|
||||
#endif
|
||||
|
||||
// Save Image
|
||||
FIBITMAP *image = FreeImage_ConvertFromRawBits(pixels, width, height, line_size, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, 0);
|
||||
FIBITMAP *image = FreeImage_ConvertFromRawBits(pixels, width, height, line_size, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, 0);
|
||||
if (!FreeImage_Save(FIF_PNG, image, file, 0)) {
|
||||
INFO("Screenshot Failed: %s", file);
|
||||
} else {
|
||||
|
@ -2,5 +2,10 @@ project(media-layer-extras)
|
||||
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
# Add Source To Media Core
|
||||
target_sources(media-layer-core PRIVATE src/SDL.c)
|
||||
if(TARGET media-layer-core-real)
|
||||
set(TARGET media-layer-core-real)
|
||||
elseif(TARGET media-layer-proxy-server)
|
||||
set(TARGET media-layer-proxy-server)
|
||||
endif()
|
||||
target_sources("${TARGET}" PRIVATE src/SDL.c)
|
||||
endif()
|
||||
|
29
media-layer/gles/CMakeLists.txt
Normal file
29
media-layer/gles/CMakeLists.txt
Normal file
@ -0,0 +1,29 @@
|
||||
project(media-layer-stubs)
|
||||
|
||||
# Stubs Only Needed For ARM
|
||||
if(MCPI_USE_GLES1_COMPATIBILITY_LAYER AND BUILD_NATIVE_COMPONENTS AND NOT MCPI_HEADLESS_MODE)
|
||||
# GLESv1_CM Compatibility Layer
|
||||
set(GLES1_LINK_MODE "SHARED")
|
||||
if(MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
# Link To Media Layer Proxy Client Statically
|
||||
# (This is so it doesn't interfere with the Media Layer Proxy Server's libGLESv1_CM.so.1 symlink.)
|
||||
set(GLES1_LINK_MODE "OBJECT")
|
||||
endif()
|
||||
add_library(GLESv1_CM "${GLES1_LINK_MODE}" src/compatibility-layer/state.c src/compatibility-layer/passthrough.c src/compatibility-layer/matrix.c src/compatibility-layer/draw.c)
|
||||
target_link_libraries(GLESv1_CM glfw reborn-util dl m)
|
||||
# Install
|
||||
if(NOT MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
install(TARGETS GLESv1_CM DESTINATION "${MCPI_LIB_DIR}")
|
||||
endif()
|
||||
else()
|
||||
# Add GLESv1_CM Stubs For Linking
|
||||
add_library(GLESv1_CM SHARED src/stubs.c)
|
||||
# Install Fake GLESv1_CM Stubs In Server Mode
|
||||
if(MCPI_HEADLESS_MODE AND BUILD_ARM_COMPONENTS)
|
||||
install(TARGETS GLESv1_CM DESTINATION "${MCPI_LIB_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Common
|
||||
target_link_libraries(GLESv1_CM media-layer-headers)
|
||||
set_target_properties(GLESv1_CM PROPERTIES SOVERSION "1")
|
255
media-layer/gles/src/compatibility-layer/draw.c
Normal file
255
media-layer/gles/src/compatibility-layer/draw.c
Normal file
@ -0,0 +1,255 @@
|
||||
#include "state.h"
|
||||
#include "passthrough.h"
|
||||
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
// Shaders
|
||||
#define REAL_GL_FRAGMENT_SHADER 0x8b30
|
||||
#define REAL_GL_VERTEX_SHADER 0x8b31
|
||||
#define REAL_GL_INFO_LOG_LENGTH 0x8b84
|
||||
#define REAL_GL_COMPILE_STATUS 0x8b81
|
||||
GL_FUNC(glUseProgram, void, (GLuint program));
|
||||
GL_FUNC(glGetUniformLocation, GLint, (GLuint program, const GLchar *name));
|
||||
GL_FUNC(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value));
|
||||
GL_FUNC(glUniform1i, void, (GLint location, GLint v0));
|
||||
GL_FUNC(glUniform1f, void, (GLint location, GLfloat v0));
|
||||
GL_FUNC(glUniform4f, void, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3));
|
||||
GL_FUNC(glGetAttribLocation, GLint, (GLuint program, const GLchar *name));
|
||||
GL_FUNC(glEnableVertexAttribArray, void, (GLuint index));
|
||||
GL_FUNC(glDisableVertexAttribArray, void, (GLuint index));
|
||||
GL_FUNC(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer));
|
||||
GL_FUNC(glVertexAttrib3f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2));
|
||||
GL_FUNC(glVertexAttrib4f, void, (GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3));
|
||||
GL_FUNC(glCreateShader, GLuint, (GLenum type));
|
||||
GL_FUNC(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length));
|
||||
GL_FUNC(glCompileShader, void, (GLuint shader));
|
||||
GL_FUNC(glCreateProgram, GLuint, ());
|
||||
GL_FUNC(glAttachShader, void, (GLuint program, GLuint shader));
|
||||
GL_FUNC(glLinkProgram, void, (GLuint program));
|
||||
GL_FUNC(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint *params));
|
||||
GL_FUNC(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog));
|
||||
|
||||
// Compile Shader
|
||||
static void log_shader(GLuint shader, const char *name) {
|
||||
// Log
|
||||
GLint log_length = 0;
|
||||
real_glGetShaderiv()(shader, REAL_GL_INFO_LOG_LENGTH, &log_length);
|
||||
GLchar *log = malloc(log_length * sizeof (GLchar));
|
||||
ALLOC_CHECK(log);
|
||||
real_glGetShaderInfoLog()(shader, log_length, &log_length, log);
|
||||
if (log_length > 0) {
|
||||
if (log_length > 1 && log[log_length - 1] == '\n') {
|
||||
log[log_length - 1] = '\0';
|
||||
}
|
||||
DEBUG("%s Shader Compile Log: %s", name, log);
|
||||
}
|
||||
free(log);
|
||||
|
||||
// Check Status
|
||||
GLint is_compiled = 0;
|
||||
real_glGetShaderiv()(shader, REAL_GL_COMPILE_STATUS, &is_compiled);
|
||||
if (!is_compiled) {
|
||||
ERR("Failed To Compile %s Shader", name);
|
||||
}
|
||||
}
|
||||
static GLuint compile_shader(const char *vertex_shader_text, const char *fragment_shader_text) {
|
||||
// Vertex Shader
|
||||
const GLuint vertex_shader = real_glCreateShader()(REAL_GL_VERTEX_SHADER);
|
||||
real_glShaderSource()(vertex_shader, 1, &vertex_shader_text, NULL);
|
||||
real_glCompileShader()(vertex_shader);
|
||||
log_shader(vertex_shader, "Vertex");
|
||||
|
||||
// Fragment Shader
|
||||
const GLuint fragment_shader = real_glCreateShader()(REAL_GL_FRAGMENT_SHADER);
|
||||
real_glShaderSource()(fragment_shader, 1, &fragment_shader_text, NULL);
|
||||
real_glCompileShader()(fragment_shader);
|
||||
log_shader(fragment_shader, "Fragment");
|
||||
|
||||
// Link
|
||||
GLuint program = real_glCreateProgram()();
|
||||
real_glAttachShader()(program, vertex_shader);
|
||||
real_glAttachShader()(program, fragment_shader);
|
||||
real_glLinkProgram()(program);
|
||||
|
||||
// Return
|
||||
return program;
|
||||
}
|
||||
|
||||
// Shader
|
||||
static GLuint get_shader() {
|
||||
static GLuint program = 0;
|
||||
if (program == 0) {
|
||||
static const char *vertex_shader_text =
|
||||
"#version 100\n"
|
||||
"precision mediump float;\n"
|
||||
// Matrices
|
||||
"uniform mat4 u_projection;\n"
|
||||
"uniform mat4 u_model_view;\n"
|
||||
"uniform mat4 u_texture;\n"
|
||||
// Texture
|
||||
"attribute vec3 a_vertex_coords;\n"
|
||||
"attribute vec2 a_texture_coords;\n"
|
||||
"varying vec4 v_texture_pos;\n"
|
||||
// Color
|
||||
"attribute vec4 a_color;\n"
|
||||
"varying vec4 v_color;\n"
|
||||
// Fog
|
||||
"varying vec4 v_fog_eye_position;\n"
|
||||
// Main
|
||||
"void main() {\n"
|
||||
" v_texture_pos = u_texture * vec4(a_texture_coords.xy, 0.0, 1.0);\n"
|
||||
" gl_Position = u_projection * u_model_view * vec4(a_vertex_coords.xyz, 1.0);\n"
|
||||
" v_color = a_color;\n"
|
||||
" v_fog_eye_position = u_model_view * vec4(a_vertex_coords.xyz, 1.0);\n"
|
||||
"}";
|
||||
static const char *fragment_shader_text =
|
||||
"#version 100\n"
|
||||
"precision mediump float;\n"
|
||||
// Texture
|
||||
"uniform bool u_has_texture;"
|
||||
"uniform sampler2D u_texture_unit;\n"
|
||||
// Color
|
||||
"varying vec4 v_color;\n"
|
||||
"varying vec4 v_texture_pos;\n"
|
||||
// Alpha Test
|
||||
"uniform bool u_alpha_test;\n"
|
||||
// Fog
|
||||
"uniform bool u_fog;\n"
|
||||
"uniform vec4 u_fog_color;\n"
|
||||
"uniform bool u_fog_is_linear;\n"
|
||||
"uniform float u_fog_start;\n"
|
||||
"uniform float u_fog_end;\n"
|
||||
"varying vec4 v_fog_eye_position;\n"
|
||||
// Main
|
||||
"void main(void) {\n"
|
||||
" gl_FragColor = v_color;\n"
|
||||
" if (u_has_texture) {\n"
|
||||
" gl_FragColor *= texture2D(u_texture_unit, v_texture_pos.xy);\n"
|
||||
" }\n"
|
||||
" if (u_alpha_test && gl_FragColor.a <= 0.1) {\n"
|
||||
" discard;\n"
|
||||
" }\n"
|
||||
" if (u_fog) {\n"
|
||||
" float fog_factor;\n"
|
||||
" if (u_fog_is_linear) {\n"
|
||||
" fog_factor = (u_fog_end - length(v_fog_eye_position)) / (u_fog_end - u_fog_start);\n"
|
||||
" } else {\n"
|
||||
" fog_factor = exp(-u_fog_start * length(v_fog_eye_position));\n"
|
||||
" }\n"
|
||||
" gl_FragColor = mix(gl_FragColor, u_fog_color, 1.0 - clamp(fog_factor, 0.0, 1.0));\n"
|
||||
" }\n"
|
||||
"}";
|
||||
program = compile_shader(vertex_shader_text, fragment_shader_text);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
// Shader Switching
|
||||
static void use_shader(GLuint program) {
|
||||
static GLuint current_program = 0;
|
||||
if (current_program != program) {
|
||||
real_glUseProgram()(program);
|
||||
current_program = program;
|
||||
}
|
||||
}
|
||||
|
||||
// Array Pointer Drawing
|
||||
GL_FUNC(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count));
|
||||
void glDrawArrays(GLenum mode, GLint first, GLsizei count) {
|
||||
// Verify
|
||||
if (gl_state.array_pointers.vertex.size != 3 || !gl_state.array_pointers.vertex.enabled || gl_state.array_pointers.vertex.type != GL_FLOAT) {
|
||||
ERR("Unsupported Vertex Conifguration");
|
||||
}
|
||||
|
||||
// Check Mode
|
||||
int use_color_pointer = gl_state.array_pointers.color.enabled;
|
||||
if (use_color_pointer && (gl_state.array_pointers.color.size != 4 || gl_state.array_pointers.color.type != GL_UNSIGNED_BYTE)) {
|
||||
ERR("Unsupported Color Conifguration");
|
||||
}
|
||||
int use_texture = gl_state.texture_2d && gl_state.array_pointers.tex_coord.enabled;
|
||||
if (use_texture && (gl_state.array_pointers.tex_coord.size != 2 || gl_state.array_pointers.tex_coord.type != GL_FLOAT)) {
|
||||
ERR("Unsupported Texture Conifguration");
|
||||
}
|
||||
|
||||
// Load Shader
|
||||
GLuint program = get_shader();
|
||||
use_shader(program);
|
||||
|
||||
// Projection Matrix
|
||||
GLint u_projection_handle = real_glGetUniformLocation()(program, "u_projection");
|
||||
matrix_t *p = &gl_state.matrix_stacks.projection.stack[gl_state.matrix_stacks.projection.i];
|
||||
real_glUniformMatrix4fv()(u_projection_handle, 1, 0, (GLfloat *) &p->data[0][0]);
|
||||
|
||||
// Model View Matrix
|
||||
GLint u_model_view_handle = real_glGetUniformLocation()(program, "u_model_view");
|
||||
p = &gl_state.matrix_stacks.model_view.stack[gl_state.matrix_stacks.model_view.i];
|
||||
real_glUniformMatrix4fv()(u_model_view_handle, 1, 0, (GLfloat *) &p->data[0][0]);
|
||||
|
||||
// Has Texture
|
||||
GLint u_has_texture_handle = real_glGetUniformLocation()(program, "u_has_texture"); \
|
||||
real_glUniform1i()(u_has_texture_handle, use_texture); \
|
||||
|
||||
// Texture Matrix
|
||||
GLint u_texture_handle = real_glGetUniformLocation()(program, "u_texture");
|
||||
p = &gl_state.matrix_stacks.texture.stack[gl_state.matrix_stacks.texture.i];
|
||||
real_glUniformMatrix4fv()(u_texture_handle, 1, 0, (GLfloat *) &p->data[0][0]);
|
||||
|
||||
// Texture Unit
|
||||
GLint u_texture_unit_handle = real_glGetUniformLocation()(program, "u_texture_unit");
|
||||
real_glUniform1i()(u_texture_unit_handle, 0);
|
||||
|
||||
// Alpha Test
|
||||
GLint u_alpha_test_handle = real_glGetUniformLocation()(program, "u_alpha_test");
|
||||
real_glUniform1i()(u_alpha_test_handle, gl_state.alpha_test);
|
||||
|
||||
// Color
|
||||
GLint a_color_handle = real_glGetAttribLocation()(program, "a_color");
|
||||
if (use_color_pointer) {
|
||||
real_glVertexAttribPointer()(a_color_handle, gl_state.array_pointers.color.size, gl_state.array_pointers.color.type, 1, gl_state.array_pointers.color.stride, gl_state.array_pointers.color.pointer);
|
||||
real_glEnableVertexAttribArray()(a_color_handle);
|
||||
} else {
|
||||
real_glVertexAttrib4f()(a_color_handle, gl_state.color.red, gl_state.color.green, gl_state.color.blue, gl_state.color.alpha);
|
||||
}
|
||||
|
||||
// Fog
|
||||
GLint u_fog_handle = real_glGetUniformLocation()(program, "u_fog");
|
||||
real_glUniform1i()(u_fog_handle, gl_state.fog.enabled);
|
||||
if (gl_state.fog.enabled) {
|
||||
GLint u_fog_color_handle = real_glGetUniformLocation()(program, "u_fog_color");
|
||||
real_glUniform4f()(u_fog_color_handle, gl_state.fog.color[0], gl_state.fog.color[1], gl_state.fog.color[2], gl_state.fog.color[3]);
|
||||
GLint u_fog_is_linear_handle = real_glGetUniformLocation()(program, "u_fog_is_linear");
|
||||
real_glUniform1i()(u_fog_is_linear_handle, gl_state.fog.mode == GL_LINEAR);
|
||||
GLint u_fog_start_handle = real_glGetUniformLocation()(program, "u_fog_start");
|
||||
real_glUniform1f()(u_fog_start_handle, gl_state.fog.start);
|
||||
GLint u_fog_end_handle = real_glGetUniformLocation()(program, "u_fog_end");
|
||||
real_glUniform1f()(u_fog_end_handle, gl_state.fog.end);
|
||||
}
|
||||
|
||||
// Vertices
|
||||
GLint a_vertex_coords_handle = real_glGetAttribLocation()(program, "a_vertex_coords");
|
||||
real_glVertexAttribPointer()(a_vertex_coords_handle, gl_state.array_pointers.vertex.size, gl_state.array_pointers.vertex.type, 0, gl_state.array_pointers.vertex.stride, gl_state.array_pointers.vertex.pointer);
|
||||
real_glEnableVertexAttribArray()(a_vertex_coords_handle);
|
||||
|
||||
// Texture Coordinates
|
||||
GLint a_texture_coords_handle = real_glGetAttribLocation()(program, "a_texture_coords");
|
||||
if (use_texture) {
|
||||
real_glVertexAttribPointer()(a_texture_coords_handle, gl_state.array_pointers.tex_coord.size, gl_state.array_pointers.tex_coord.type, 0, gl_state.array_pointers.tex_coord.stride, gl_state.array_pointers.tex_coord.pointer);
|
||||
real_glEnableVertexAttribArray()(a_texture_coords_handle);
|
||||
} else {
|
||||
real_glVertexAttrib3f()(a_texture_coords_handle, 0, 0, 0);
|
||||
}
|
||||
|
||||
// Draw
|
||||
real_glDrawArrays()(mode, first, count);
|
||||
|
||||
// Cleanup
|
||||
if (use_color_pointer) {
|
||||
real_glDisableVertexAttribArray()(a_color_handle);
|
||||
}
|
||||
real_glDisableVertexAttribArray()(a_vertex_coords_handle);
|
||||
if (use_texture) {
|
||||
real_glDisableVertexAttribArray()(a_texture_coords_handle);
|
||||
}
|
||||
}
|
132
media-layer/gles/src/compatibility-layer/matrix.c
Normal file
132
media-layer/gles/src/compatibility-layer/matrix.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "state.h"
|
||||
#include "passthrough.h"
|
||||
|
||||
// Matrix Common
|
||||
static void matrix_copy(matrix_t *src, matrix_t *dst) {
|
||||
memcpy((void *) dst->data, (void *) src->data, MATRIX_DATA_SIZE);
|
||||
}
|
||||
|
||||
// Identity Matrix
|
||||
static matrix_t identity_matrix = {
|
||||
.data = {
|
||||
{1, 0, 0, 0},
|
||||
{0, 1, 0, 0},
|
||||
{0, 0, 1, 0},
|
||||
{0, 0, 0, 1}
|
||||
}
|
||||
};
|
||||
static void init_matrix_stack(matrix_stack_t *stack) {
|
||||
matrix_copy(&identity_matrix, &stack->stack[0]);
|
||||
}
|
||||
__attribute__((constructor)) static void init_matrix_stacks() {
|
||||
init_matrix_stack(&gl_state.matrix_stacks.model_view);
|
||||
init_matrix_stack(&gl_state.matrix_stacks.projection);
|
||||
init_matrix_stack(&gl_state.matrix_stacks.texture);
|
||||
}
|
||||
|
||||
// Matrix Mode
|
||||
static matrix_stack_t *get_matrix_stack() {
|
||||
switch (gl_state.matrix_stacks.mode) {
|
||||
case GL_MODELVIEW: {
|
||||
return &gl_state.matrix_stacks.model_view;
|
||||
}
|
||||
case GL_PROJECTION: {
|
||||
return &gl_state.matrix_stacks.projection;
|
||||
}
|
||||
case GL_TEXTURE: {
|
||||
return &gl_state.matrix_stacks.texture;
|
||||
}
|
||||
default: {
|
||||
ERR("Unsupported Matrix Mode: %i", gl_state.matrix_stacks.mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Matrix Functions
|
||||
void glMatrixMode(GLenum mode) {
|
||||
gl_state.matrix_stacks.mode = mode;
|
||||
}
|
||||
void glPopMatrix() {
|
||||
get_matrix_stack()->i--;
|
||||
}
|
||||
void glLoadIdentity() {
|
||||
matrix_stack_t *stack = get_matrix_stack();
|
||||
matrix_copy(&identity_matrix, &stack->stack[stack->i]);
|
||||
}
|
||||
void glPushMatrix() {
|
||||
matrix_stack_t *stack = get_matrix_stack();
|
||||
matrix_copy(&stack->stack[stack->i], &stack->stack[stack->i + 1]);
|
||||
stack->i++;
|
||||
}
|
||||
void glMultMatrixf(const GLfloat *m) {
|
||||
matrix_t new_matrix;
|
||||
matrix_stack_t *stack = get_matrix_stack();
|
||||
matrix_t *current_matrix = &stack->stack[stack->i];
|
||||
for (int x = 0; x < MATRIX_SIZE; x++) {
|
||||
for (int y = 0; y < MATRIX_SIZE; y++) {
|
||||
GLfloat result = 0;
|
||||
for (int i = 0; i < MATRIX_SIZE; i++) {
|
||||
result += (current_matrix->data[i][y] * m[(x * MATRIX_SIZE) + i]);
|
||||
}
|
||||
new_matrix.data[x][y] = result;
|
||||
}
|
||||
}
|
||||
matrix_copy(&new_matrix, current_matrix);
|
||||
}
|
||||
void glScalef(GLfloat x, GLfloat y, GLfloat z) {
|
||||
GLfloat m[] = {
|
||||
x, 0, 0, 0,
|
||||
0, y, 0, 0,
|
||||
0, 0, z, 0,
|
||||
0, 0, 0, 1
|
||||
};
|
||||
glMultMatrixf(m);
|
||||
}
|
||||
void glTranslatef(GLfloat x, GLfloat y, GLfloat z) {
|
||||
GLfloat m[] = {
|
||||
1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
x, y, z, 1
|
||||
};
|
||||
glMultMatrixf(m);
|
||||
}
|
||||
void glOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far) {
|
||||
GLfloat m[] = {
|
||||
(2.f / (right - left)), 0, 0, 0,
|
||||
0, (2.f / (top - bottom)), 0, 0,
|
||||
0, 0, (-2.f / (far - near)), 0,
|
||||
-((right + left) / (right - left)), -((top + bottom) / (top - bottom)), -((far + near) / (far - near)), 1
|
||||
};
|
||||
glMultMatrixf(m);
|
||||
}
|
||||
#define DEG2RAD (M_PI / 180.f)
|
||||
void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {
|
||||
// Normalize
|
||||
GLfloat length = sqrtf((x * x) + (y * y) + (z * z));
|
||||
x /= length;
|
||||
y /= length;
|
||||
z /= length;
|
||||
|
||||
// Values
|
||||
GLfloat angle_radians = angle * DEG2RAD;
|
||||
GLfloat c = cosf(angle_radians);
|
||||
GLfloat s = sinf(angle_radians);
|
||||
GLfloat x2 = x * x;
|
||||
GLfloat y2 = y * y;
|
||||
GLfloat z2 = z * z;
|
||||
|
||||
// Multiply
|
||||
GLfloat m[] = {
|
||||
x2 * (1.f - c) + c, (x * y) * (1.f - c) + (z * s), (x * z) * (1.f - c) - (y * s), 0,
|
||||
(x * y) * (1.f - c) - (z * s), y2 * (1.f - c) + c, (y * z) * (1.f - c) + (x * s), 0,
|
||||
(x * z) * (1.f - c) + (y * s), (y * z) * (1.f - c) - (x * s), z2 * (1.f - c) + c, 0,
|
||||
0, 0, 0, 1.f
|
||||
};
|
||||
glMultMatrixf(m);
|
||||
}
|
9
media-layer/gles/src/compatibility-layer/matrix.h
Normal file
9
media-layer/gles/src/compatibility-layer/matrix.h
Normal file
@ -0,0 +1,9 @@
|
||||
#include <GLES/gl.h>
|
||||
|
||||
// Matrix Common
|
||||
#define MATRIX_SIZE 4
|
||||
#define MATRIX_DATA_SIZE (sizeof (float) * MATRIX_SIZE * MATRIX_SIZE)
|
||||
// OpenGL Matricies Are Column-Major
|
||||
typedef struct {
|
||||
GLfloat data[MATRIX_SIZE][MATRIX_SIZE];
|
||||
} matrix_t;
|
113
media-layer/gles/src/compatibility-layer/passthrough.c
Normal file
113
media-layer/gles/src/compatibility-layer/passthrough.c
Normal file
@ -0,0 +1,113 @@
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#include "passthrough.h"
|
||||
|
||||
// Simple v1.1 -> v2.0 Passthrough Functions
|
||||
GL_FUNC(glLineWidth, void, (GLfloat width));
|
||||
void glLineWidth(GLfloat width) {
|
||||
real_glLineWidth()(width);
|
||||
}
|
||||
GL_FUNC(glBlendFunc, void, (GLenum sfactor, GLenum dfactor));
|
||||
void glBlendFunc(GLenum sfactor, GLenum dfactor) {
|
||||
real_glBlendFunc()(sfactor, dfactor);
|
||||
}
|
||||
GL_FUNC(glClear, void, (GLbitfield mask));
|
||||
void glClear(GLbitfield mask) {
|
||||
real_glClear()(mask);
|
||||
}
|
||||
GL_FUNC(glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage));
|
||||
void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {
|
||||
real_glBufferData()(target, size, data, usage);
|
||||
}
|
||||
GL_FUNC(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height));
|
||||
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
real_glScissor()(x, y, width, height);
|
||||
}
|
||||
GL_FUNC(glTexParameteri, void, (GLenum target, GLenum pname, GLint param));
|
||||
void glTexParameteri(GLenum target, GLenum pname, GLint param) {
|
||||
real_glTexParameteri()(target, pname, param);
|
||||
}
|
||||
GL_FUNC(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels));
|
||||
void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {
|
||||
real_glTexImage2D()(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
}
|
||||
GL_FUNC(glPolygonOffset, void, (GLfloat factor, GLfloat units));
|
||||
void glPolygonOffset(GLfloat factor, GLfloat units) {
|
||||
real_glPolygonOffset()(factor, units);
|
||||
}
|
||||
GL_FUNC(glDepthRangef, void, (GLclampf near, GLclampf far));
|
||||
void glDepthRangef(GLclampf near, GLclampf far) {
|
||||
real_glDepthRangef()(near, far);
|
||||
}
|
||||
GL_FUNC(glDepthFunc, void, (GLenum func));
|
||||
void glDepthFunc(GLenum func) {
|
||||
real_glDepthFunc()(func);
|
||||
}
|
||||
GL_FUNC(glBindBuffer, void, (GLenum target, GLuint buffer));
|
||||
void glBindBuffer(GLenum target, GLuint buffer) {
|
||||
real_glBindBuffer()(target, buffer);
|
||||
}
|
||||
GL_FUNC(glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha));
|
||||
void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
|
||||
real_glClearColor()(red, green, blue, alpha);
|
||||
}
|
||||
GL_FUNC(glDepthMask, void, (GLboolean flag));
|
||||
void glDepthMask(GLboolean flag) {
|
||||
real_glDepthMask()(flag);
|
||||
}
|
||||
GL_FUNC(glHint, void, (GLenum target, GLenum mode));
|
||||
void glHint(GLenum target, GLenum mode) {
|
||||
if (target != GL_PERSPECTIVE_CORRECTION_HINT) {
|
||||
real_glHint()(target, mode);
|
||||
}
|
||||
}
|
||||
GL_FUNC(glDeleteBuffers, void, (GLsizei n, const GLuint *buffers));
|
||||
void glDeleteBuffers(GLsizei n, const GLuint *buffers) {
|
||||
real_glDeleteBuffers()(n, buffers);
|
||||
}
|
||||
GL_FUNC(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha));
|
||||
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
||||
real_glColorMask()(red, green, blue, alpha);
|
||||
}
|
||||
GL_FUNC(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels));
|
||||
void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {
|
||||
real_glTexSubImage2D()(target, level, xoffset, yoffset, width, height, format, type, pixels);
|
||||
}
|
||||
GL_FUNC(glGenTextures, void, (GLsizei n, GLuint *textures));
|
||||
void glGenTextures(GLsizei n, GLuint *textures) {
|
||||
real_glGenTextures()(n, textures);
|
||||
}
|
||||
GL_FUNC(glDeleteTextures, void, (GLsizei n, const GLuint *textures));
|
||||
void glDeleteTextures(GLsizei n, const GLuint *textures) {
|
||||
real_glDeleteTextures()(n, textures);
|
||||
}
|
||||
GL_FUNC(glBindTexture, void, (GLenum target, GLuint texture));
|
||||
void glBindTexture(GLenum target, GLuint texture) {
|
||||
real_glBindTexture()(target, texture);
|
||||
}
|
||||
GL_FUNC(glCullFace, void, (GLenum mode));
|
||||
void glCullFace(GLenum mode) {
|
||||
real_glCullFace()(mode);
|
||||
}
|
||||
GL_FUNC(glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height));
|
||||
void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
|
||||
real_glViewport()(x, y, width, height);
|
||||
}
|
||||
GL_FUNC(glIsEnabled, GLboolean, (GLenum cap));
|
||||
GLboolean glIsEnabled(GLenum cap) {
|
||||
return real_glIsEnabled()(cap);
|
||||
}
|
||||
GL_FUNC(glGetIntegerv, void, (GLenum pname, GLint *data));
|
||||
void glGetIntegerv(GLenum pname, GLint *data) {
|
||||
real_glGetIntegerv()(pname, data);
|
||||
}
|
||||
GL_FUNC(glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data));
|
||||
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data) {
|
||||
real_glReadPixels()(x, y, width, height, format, type, data);
|
||||
}
|
||||
void glShadeModel(__attribute__((unused)) GLenum mode) {
|
||||
// Do Nothing
|
||||
}
|
||||
void glNormal3f(__attribute__((unused)) GLfloat nx, __attribute__((unused)) GLfloat ny, __attribute__((unused)) GLfloat nz) {
|
||||
// Do Nothing
|
||||
}
|
19
media-layer/gles/src/compatibility-layer/passthrough.h
Normal file
19
media-layer/gles/src/compatibility-layer/passthrough.h
Normal file
@ -0,0 +1,19 @@
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
// Load GL Function
|
||||
#define GL_FUNC(name, return_type, args) \
|
||||
typedef return_type (*real_##name##_t)args; \
|
||||
\
|
||||
__attribute__((__unused__)) static real_##name##_t real_##name() { \
|
||||
static real_##name##_t func = NULL; \
|
||||
if (!func) { \
|
||||
func = (real_##name##_t) glfwGetProcAddress(#name); \
|
||||
if (!func) { \
|
||||
ERR("Error Resolving GL Symbol: " #name ": %s", dlerror()); \
|
||||
} \
|
||||
} \
|
||||
return func; \
|
||||
}
|
178
media-layer/gles/src/compatibility-layer/state.c
Normal file
178
media-layer/gles/src/compatibility-layer/state.c
Normal file
@ -0,0 +1,178 @@
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "state.h"
|
||||
#include "passthrough.h"
|
||||
|
||||
// GL State
|
||||
gl_state_t gl_state = {
|
||||
.color = {
|
||||
.red = 1,
|
||||
.green = 1,
|
||||
.blue = 1,
|
||||
.alpha = 1
|
||||
},
|
||||
.matrix_stacks = {
|
||||
.mode = GL_MODELVIEW
|
||||
},
|
||||
.alpha_test = 0,
|
||||
.texture_2d = 0,
|
||||
.fog = {
|
||||
.enabled = 0,
|
||||
.mode = GL_LINEAR,
|
||||
.color = {0, 0, 0, 0},
|
||||
.start = 0,
|
||||
.end = 1
|
||||
}
|
||||
};
|
||||
|
||||
// Change Color
|
||||
void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
gl_state.color.red = red;
|
||||
gl_state.color.green = green;
|
||||
gl_state.color.blue = blue;
|
||||
gl_state.color.alpha = alpha;
|
||||
}
|
||||
|
||||
// Array Pointer Storage
|
||||
#define ARRAY_POINTER_FUNC(func, name) \
|
||||
void func(GLint size, GLenum type, GLsizei stride, const void *pointer) { \
|
||||
gl_state.array_pointers.name.size = size; \
|
||||
gl_state.array_pointers.name.type = type; \
|
||||
gl_state.array_pointers.name.stride = stride; \
|
||||
gl_state.array_pointers.name.pointer = pointer; \
|
||||
}
|
||||
ARRAY_POINTER_FUNC(glVertexPointer, vertex)
|
||||
ARRAY_POINTER_FUNC(glColorPointer, color)
|
||||
ARRAY_POINTER_FUNC(glTexCoordPointer, tex_coord)
|
||||
static array_pointer_t *get_array_pointer(GLenum array) {
|
||||
switch (array) {
|
||||
case GL_VERTEX_ARRAY: {
|
||||
return &gl_state.array_pointers.vertex;
|
||||
}
|
||||
case GL_COLOR_ARRAY: {
|
||||
return &gl_state.array_pointers.color;
|
||||
}
|
||||
case GL_TEXTURE_COORD_ARRAY: {
|
||||
return &gl_state.array_pointers.tex_coord;
|
||||
}
|
||||
default: {
|
||||
ERR("Unsupported Array Pointer: %i", array);
|
||||
}
|
||||
}
|
||||
}
|
||||
void glEnableClientState(GLenum array) {
|
||||
get_array_pointer(array)->enabled = 1;
|
||||
}
|
||||
void glDisableClientState(GLenum array) {
|
||||
get_array_pointer(array)->enabled = 0;
|
||||
}
|
||||
|
||||
// Enable/Disable State
|
||||
GL_FUNC(glEnable, void, (GLenum cap));
|
||||
void glEnable(GLenum cap) {
|
||||
switch (cap) {
|
||||
case GL_ALPHA_TEST: {
|
||||
gl_state.alpha_test = 1;
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_2D: {
|
||||
gl_state.texture_2d = 1;
|
||||
break;
|
||||
}
|
||||
case GL_COLOR_MATERIAL: {
|
||||
// Ignore
|
||||
break;
|
||||
}
|
||||
case GL_FOG: {
|
||||
gl_state.fog.enabled = 1;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
real_glEnable()(cap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
GL_FUNC(glDisable, void, (GLenum cap));
|
||||
void glDisable(GLenum cap) {
|
||||
switch (cap) {
|
||||
case GL_ALPHA_TEST: {
|
||||
gl_state.alpha_test = 0;
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_2D: {
|
||||
gl_state.texture_2d = 0;
|
||||
break;
|
||||
}
|
||||
case GL_COLOR_MATERIAL: {
|
||||
// Ignore
|
||||
break;
|
||||
}
|
||||
case GL_FOG: {
|
||||
gl_state.fog.enabled = 0;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
real_glDisable()(cap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void glAlphaFunc(GLenum func, GLclampf ref) {
|
||||
if (func != GL_GREATER && ref != 0.1f) {
|
||||
ERR("Unsupported Alpha Function");
|
||||
}
|
||||
}
|
||||
|
||||
// Fog
|
||||
#define UNSUPPORTED_FOG() ERR("Unsupported Fog Configuration")
|
||||
void glFogfv(GLenum pname, const GLfloat *params) {
|
||||
if (pname == GL_FOG_COLOR) {
|
||||
memcpy((void *) gl_state.fog.color, params, sizeof (gl_state.fog.color));
|
||||
} else {
|
||||
UNSUPPORTED_FOG();
|
||||
}
|
||||
}
|
||||
void glFogx(GLenum pname, GLfixed param) {
|
||||
if (pname == GL_FOG_MODE && (param == GL_LINEAR || param == GL_EXP)) {
|
||||
gl_state.fog.mode = param;
|
||||
} else {
|
||||
UNSUPPORTED_FOG();
|
||||
}
|
||||
}
|
||||
void glFogf(GLenum pname, GLfloat param) {
|
||||
switch (pname) {
|
||||
case GL_FOG_DENSITY:
|
||||
case GL_FOG_START: {
|
||||
gl_state.fog.start = param;
|
||||
break;
|
||||
}
|
||||
case GL_FOG_END: {
|
||||
gl_state.fog.end = param;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNSUPPORTED_FOG();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get Matrix Data
|
||||
GL_FUNC(glGetFloatv, void, (GLenum pname, GLfloat *params));
|
||||
void glGetFloatv(GLenum pname, GLfloat *params) {
|
||||
switch (pname) {
|
||||
case GL_MODELVIEW_MATRIX: {
|
||||
memcpy((void *) params, gl_state.matrix_stacks.model_view.stack[gl_state.matrix_stacks.model_view.i].data, MATRIX_DATA_SIZE);
|
||||
break;
|
||||
}
|
||||
case GL_PROJECTION_MATRIX: {
|
||||
memcpy((void *) params, gl_state.matrix_stacks.projection.stack[gl_state.matrix_stacks.projection.i].data, MATRIX_DATA_SIZE);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
real_glGetFloatv()(pname, params);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
50
media-layer/gles/src/compatibility-layer/state.h
Normal file
50
media-layer/gles/src/compatibility-layer/state.h
Normal file
@ -0,0 +1,50 @@
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#include "matrix.h"
|
||||
|
||||
// Matrix Data
|
||||
#define MATRIX_STACK_DEPTH 256
|
||||
typedef struct {
|
||||
matrix_t stack[MATRIX_STACK_DEPTH];
|
||||
unsigned int i;
|
||||
} matrix_stack_t;
|
||||
|
||||
// Array Pointer Storage
|
||||
typedef struct {
|
||||
GLboolean enabled;
|
||||
GLint size;
|
||||
GLenum type;
|
||||
GLsizei stride;
|
||||
const void *pointer;
|
||||
} array_pointer_t;
|
||||
|
||||
// GL State
|
||||
typedef struct {
|
||||
struct {
|
||||
GLfloat red;
|
||||
GLfloat green;
|
||||
GLfloat blue;
|
||||
GLfloat alpha;
|
||||
} color;
|
||||
struct {
|
||||
GLenum mode;
|
||||
matrix_stack_t model_view;
|
||||
matrix_stack_t projection;
|
||||
matrix_stack_t texture;
|
||||
} matrix_stacks;
|
||||
struct {
|
||||
array_pointer_t vertex;
|
||||
array_pointer_t color;
|
||||
array_pointer_t tex_coord;
|
||||
} array_pointers;
|
||||
GLboolean alpha_test;
|
||||
GLboolean texture_2d;
|
||||
struct {
|
||||
GLboolean enabled;
|
||||
GLfixed mode;
|
||||
GLfloat color[4];
|
||||
GLfloat start;
|
||||
GLfloat end;
|
||||
} fog;
|
||||
} gl_state_t;
|
||||
extern gl_state_t gl_state;
|
@ -72,14 +72,48 @@ void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha
|
||||
void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {
|
||||
}
|
||||
void glGenTextures(GLsizei n, GLuint *textures) {
|
||||
static int i = 0;
|
||||
for (int j = 0; j < n; j++) {
|
||||
textures[j] = i++;
|
||||
}
|
||||
}
|
||||
void glDeleteTextures(GLsizei n, const GLuint *textures) {
|
||||
}
|
||||
void glAlphaFunc(GLenum func, GLclampf ref) {
|
||||
}
|
||||
void glGetFloatv(GLenum pname, GLfloat *params) {
|
||||
switch (pname) {
|
||||
case GL_MODELVIEW_MATRIX:
|
||||
case GL_PROJECTION_MATRIX: {
|
||||
params[0] = 1;
|
||||
params[1] = 0;
|
||||
params[2] = 0;
|
||||
params[3] = 0;
|
||||
params[4] = 0;
|
||||
params[5] = 1;
|
||||
params[6] = 0;
|
||||
params[7] = 0;
|
||||
params[8] = 0;
|
||||
params[9] = 0;
|
||||
params[10] = 1;
|
||||
params[11] = 0;
|
||||
params[12] = 0;
|
||||
params[13] = 0;
|
||||
params[14] = 0;
|
||||
params[15] = 1;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
params[0] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static GLuint current_texture = 0;
|
||||
void glBindTexture(GLenum target, GLuint texture) {
|
||||
if (target == GL_TEXTURE_2D) {
|
||||
current_texture = texture;
|
||||
}
|
||||
}
|
||||
void glTranslatef(GLfloat x, GLfloat y, GLfloat z) {
|
||||
}
|
||||
@ -101,6 +135,20 @@ GLboolean glIsEnabled(GLenum cap) {
|
||||
return GL_FALSE;
|
||||
}
|
||||
void glGetIntegerv(GLenum pname, GLint *data) {
|
||||
switch (pname) {
|
||||
case GL_TEXTURE_BINDING_2D: {
|
||||
data[0] = current_texture;
|
||||
break;
|
||||
}
|
||||
case GL_UNPACK_ALIGNMENT: {
|
||||
data[0] = 1;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
data[0] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data) {
|
||||
}
|
@ -5,10 +5,10 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define GL_FALSE 0
|
||||
#define GL_FOG_COLOR 0xb66
|
||||
#define GL_ARRAY_BUFFER_BINDING 0x8894
|
||||
#define GL_TEXTURE_BINDING_2D 0x8069
|
||||
#define GL_UNSIGNED_BYTE 0x1401
|
||||
#define GL_FLOAT 0x1406
|
||||
#define GL_RGB 0x1907
|
||||
#define GL_RGBA 0x1908
|
||||
#define GL_MODELVIEW_MATRIX 0xba6
|
||||
@ -19,6 +19,25 @@ extern "C" {
|
||||
#define GL_UNPACK_ALIGNMENT 0xcf5
|
||||
#define GL_SRC_ALPHA 0x302
|
||||
#define GL_ONE_MINUS_SRC_ALPHA 0x303
|
||||
#define GL_MODELVIEW 0x1700
|
||||
#define GL_PROJECTION 0x1701
|
||||
#define GL_TEXTURE 0x1702
|
||||
#define GL_VERTEX_ARRAY 0x8074
|
||||
#define GL_COLOR_ARRAY 0x8076
|
||||
#define GL_TEXTURE_COORD_ARRAY 0x8078
|
||||
#define GL_GREATER 0x204
|
||||
#define GL_ALPHA_TEST 0xbc0
|
||||
#define GL_TEXTURE_2D 0xde1
|
||||
#define GL_COLOR_MATERIAL 0xb57
|
||||
#define GL_PERSPECTIVE_CORRECTION_HINT 0xc50
|
||||
#define GL_FOG 0xb60
|
||||
#define GL_LINEAR 0x2601
|
||||
#define GL_EXP 0x800
|
||||
#define GL_FOG_DENSITY 0xb62
|
||||
#define GL_FOG_START 0xb63
|
||||
#define GL_FOG_END 0xb64
|
||||
#define GL_FOG_MODE 0xb65
|
||||
#define GL_FOG_COLOR 0xb66
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
@ -34,6 +53,7 @@ typedef intptr_t GLintptr;
|
||||
typedef int32_t GLfixed;
|
||||
typedef unsigned int GLbitfield;
|
||||
typedef unsigned int GLenum;
|
||||
typedef char GLchar;
|
||||
|
||||
void glFogfv(GLenum pname, const GLfloat *params);
|
||||
void glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer);
|
||||
|
@ -4,8 +4,15 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
void media_audio_update(float volume, float x, float y, float z, float yaw);
|
||||
void media_audio_play(const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui);
|
||||
#else
|
||||
static inline void media_audio_update(__attribute__((unused)) float volume, __attribute__((unused)) float x, __attribute__((unused)) float y, __attribute__((unused)) float z, __attribute__((unused)) float yaw) {
|
||||
}
|
||||
static inline void media_audio_play(__attribute__((unused)) const char *source, __attribute__((unused)) const char *name, __attribute__((unused)) float x, __attribute__((unused)) float y, __attribute__((unused)) float z, __attribute__((unused)) float pitch, __attribute__((unused)) float volume, __attribute__((unused)) int is_ui) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -2,28 +2,26 @@ project(media-layer-proxy)
|
||||
|
||||
# Configuration
|
||||
set(MEDIA_LAYER_PROXY_SRC src/common/common.c src/media-layer-core.c src/GLESv1_CM.c) # Media Layer Proxy Source
|
||||
set(MEDIA_LAYER_PROXY_LIBS media-layer-core GLESv1_CM) # Media Layer Proxy Client Dependencies
|
||||
|
||||
# Build
|
||||
if(BUILD_NATIVE_COMPONENTS)
|
||||
# Building Native Components
|
||||
|
||||
# Build Media Layer Proxy Client
|
||||
add_executable(media-layer-proxy-client src/client/client.cpp ${MEDIA_LAYER_PROXY_SRC})
|
||||
target_link_libraries(media-layer-proxy-client media-layer-headers reborn-util ${MEDIA_LAYER_PROXY_LIBS})
|
||||
target_link_libraries(media-layer-proxy-client media-layer-headers reborn-util media-layer-core-real GLESv1_CM)
|
||||
target_compile_definitions(media-layer-proxy-client PRIVATE -DMEDIA_LAYER_PROXY_CLIENT)
|
||||
# Install
|
||||
install(TARGETS media-layer-proxy-client DESTINATION "${MCPI_BIN_DIR}")
|
||||
endif()
|
||||
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
# Building ARM Components
|
||||
|
||||
# Build Media Layer Proxy Server
|
||||
add_library(media-layer-core SHARED src/server/server.cpp ${MEDIA_LAYER_PROXY_SRC})
|
||||
target_link_libraries(media-layer-core media-layer-headers reborn-util)
|
||||
target_compile_definitions(media-layer-core PRIVATE -DMEDIA_LAYER_PROXY_SERVER)
|
||||
add_library(media-layer-proxy-server SHARED src/server/server.cpp ${MEDIA_LAYER_PROXY_SRC})
|
||||
target_link_libraries(media-layer-proxy-server media-layer-headers reborn-util)
|
||||
target_compile_definitions(media-layer-proxy-server PRIVATE -DMEDIA_LAYER_PROXY_SERVER)
|
||||
set_target_properties(media-layer-proxy-server PROPERTIES OUTPUT_NAME "media-layer-core")
|
||||
# Symlink GLESv1_CM To Media Layer Proxy Server
|
||||
install_symlink("libmedia-layer-core.so" "${MCPI_LIB_DIR}/libGLESv1_CM.so.1")
|
||||
# Install
|
||||
install(TARGETS media-layer-core DESTINATION "${MCPI_LIB_DIR}")
|
||||
install(TARGETS media-layer-proxy-server DESTINATION "${MCPI_LIB_DIR}")
|
||||
# Create Alias Target For Linking
|
||||
add_library(media-layer-core ALIAS media-layer-proxy-server)
|
||||
endif()
|
||||
|
@ -342,7 +342,7 @@ static int get_texture_size(GLsizei width, GLsizei height, GLenum format, GLenum
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
PROXY_ERR("Invalid Texture Format: %u", (unsigned int) format);
|
||||
PROXY_ERR("Unsupported Texture Format: %u", (unsigned int) format);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -858,7 +858,7 @@ static int get_glGetFloatv_params_size(GLenum pname) {
|
||||
return 16;
|
||||
}
|
||||
default: {
|
||||
PROXY_ERR("Inavlid glGetFloatv Property: %u", pname);
|
||||
PROXY_ERR("Unsupported glGetFloatv Property: %u", pname);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1104,7 +1104,7 @@ static int get_glGetIntegerv_params_size(GLenum pname) {
|
||||
return 1;
|
||||
}
|
||||
default: {
|
||||
PROXY_ERR("Inavlid glGetIntegerv Property: %u", pname);
|
||||
PROXY_ERR("Unsupported glGetIntegerv Property: %u", pname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
project(media-layer-stubs)
|
||||
|
||||
# Add GLES1 Stubs For Linking
|
||||
add_library(GLESv1_CM SHARED src/GLESv1_CM.c)
|
||||
target_link_libraries(GLESv1_CM media-layer-headers)
|
||||
set_target_properties(GLESv1_CM PROPERTIES SOVERSION "1")
|
||||
|
||||
# Stubs Only Needed For ARM
|
||||
if(BUILD_ARM_COMPONENTS)
|
||||
# Install Fake GLESv1_CM Stubs In Server Mode
|
||||
if(MCPI_HEADLESS_MODE)
|
||||
install(TARGETS GLESv1_CM DESTINATION "${MCPI_LIB_DIR}")
|
||||
endif()
|
||||
endif()
|
@ -54,15 +54,13 @@ else()
|
||||
target_link_libraries(override reborn-patch symbols dl home)
|
||||
|
||||
add_library(textures SHARED src/textures/textures.cpp)
|
||||
target_link_libraries(textures reborn-patch symbols media-layer-core feature)
|
||||
target_link_libraries(textures reborn-patch symbols media-layer-core feature misc)
|
||||
|
||||
add_library(atlas SHARED src/atlas/atlas.cpp)
|
||||
target_link_libraries(atlas reborn-patch symbols feature GLESv1_CM)
|
||||
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
add_library(benchmark SHARED src/benchmark/benchmark.cpp)
|
||||
target_link_libraries(benchmark reborn-patch symbols compat misc media-layer-core)
|
||||
endif()
|
||||
add_library(benchmark SHARED src/benchmark/benchmark.cpp)
|
||||
target_link_libraries(benchmark reborn-patch symbols compat misc media-layer-core)
|
||||
endif()
|
||||
|
||||
add_library(death SHARED src/death/death.cpp)
|
||||
@ -85,10 +83,7 @@ target_link_libraries(init compat game-mode misc death options chat creative hom
|
||||
if(MCPI_SERVER_MODE)
|
||||
target_link_libraries(init server)
|
||||
else()
|
||||
target_link_libraries(init multiplayer sound camera input sign touch textures atlas)
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
target_link_libraries(init benchmark)
|
||||
endif()
|
||||
target_link_libraries(init multiplayer sound camera input sign touch textures atlas benchmark)
|
||||
endif()
|
||||
|
||||
## Install Mods
|
||||
@ -96,8 +91,5 @@ install(TARGETS init compat readdir feature game-mode misc death options chat cr
|
||||
if(MCPI_SERVER_MODE)
|
||||
install(TARGETS server DESTINATION "${MCPI_INSTALL_DIR}/mods")
|
||||
else()
|
||||
install(TARGETS multiplayer sound override camera input sign touch textures atlas DESTINATION "${MCPI_INSTALL_DIR}/mods")
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
install(TARGETS benchmark DESTINATION "${MCPI_INSTALL_DIR}/mods")
|
||||
endif()
|
||||
install(TARGETS multiplayer sound override camera input sign touch textures atlas benchmark DESTINATION "${MCPI_INSTALL_DIR}/mods")
|
||||
endif()
|
||||
|
@ -28,7 +28,7 @@ __attribute__((constructor)) static void _init_active(int argc, char *argv[]) {
|
||||
#define NANOSECONDS_IN_SECOND 1000000000ll
|
||||
|
||||
// Config
|
||||
#define BENCHMARK_GAME_MODE 1 // Creative Mode
|
||||
#define BENCHMARK_GAME_MODE 0 // Survival Mode
|
||||
#define BENCHMARK_SEED 2048 // Random Number
|
||||
#define BENCHMARK_WORLD_NAME "_Benchmark" // Random Number
|
||||
#define BENCHMARK_LENGTH (180ll * NANOSECONDS_IN_SECOND) // 3 Minutes
|
||||
@ -62,12 +62,20 @@ static void start_world(unsigned char *minecraft) {
|
||||
}
|
||||
|
||||
// Track Frames
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
static unsigned long long int frames = 0;
|
||||
HOOK(media_swap_buffers, void, ()) {
|
||||
ensure_media_swap_buffers();
|
||||
(*real_media_swap_buffers)();
|
||||
frames++;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Track Ticks
|
||||
static unsigned long long int ticks = 0;
|
||||
static void Minecraft_tick_injection(__attribute__((unused)) unsigned char *minecraft) {
|
||||
ticks++;
|
||||
}
|
||||
|
||||
// Get Time
|
||||
static long long int get_time() {
|
||||
@ -81,7 +89,13 @@ static long long int get_time() {
|
||||
// Store Time When World Loaded
|
||||
static int world_loaded = 0;
|
||||
static long long int world_loaded_time;
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
static unsigned long long int world_loaded_frames;
|
||||
#endif
|
||||
static unsigned long long int world_loaded_ticks;
|
||||
|
||||
// Last Logged Status Update
|
||||
static int32_t last_logged_status = -1;
|
||||
|
||||
// Runs Every Tick
|
||||
static bool loaded = false;
|
||||
@ -97,14 +111,30 @@ static void Minecraft_update_injection(unsigned char *minecraft) {
|
||||
if (!world_loaded && (*Minecraft_isLevelGenerated)(minecraft)) {
|
||||
world_loaded = 1;
|
||||
world_loaded_time = get_time();
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
world_loaded_frames = frames;
|
||||
#endif
|
||||
world_loaded_ticks = ticks;
|
||||
}
|
||||
|
||||
// Run Benchmark
|
||||
if (!exit_requested && world_loaded) {
|
||||
// Get Time
|
||||
long long int current_time = get_time() - world_loaded_time;
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
unsigned long long int current_frames = frames - world_loaded_frames;
|
||||
#endif
|
||||
unsigned long long int current_ticks = ticks - world_loaded_ticks;
|
||||
|
||||
// Log
|
||||
int32_t status = (((double) current_time) / ((double) BENCHMARK_LENGTH)) * 100;
|
||||
if (status > 100) {
|
||||
status = 100;
|
||||
}
|
||||
if (is_progress_difference_significant(status, last_logged_status)) {
|
||||
INFO("Benchmark Status: %i%%", status);
|
||||
last_logged_status = status;
|
||||
}
|
||||
|
||||
// Rotate Player
|
||||
static long long int rotate_point = BENCHMARK_ROTATION_INTERVAL;
|
||||
@ -127,10 +157,17 @@ static void Minecraft_update_injection(unsigned char *minecraft) {
|
||||
// Disable Special Behavior After Requesting Exit
|
||||
exit_requested = true;
|
||||
|
||||
// Calculate FPS
|
||||
// Calculate FPS & TPS
|
||||
INFO("Benchmark Completed");
|
||||
INFO(" Total Time: %lld Nanoseconds", current_time);
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
static double frames_per_nanosecond = ((double) current_frames) / ((double) current_time);
|
||||
static double frames_per_second = frames_per_nanosecond * NANOSECONDS_IN_SECOND;
|
||||
INFO("Benchmark Completed After %llu Frames In %lld Nanoseconds, Average FPS: %f", current_frames, current_time, frames_per_second);
|
||||
INFO(" FPS: %f (%llu Total Frames)", frames_per_second, current_frames);
|
||||
#endif
|
||||
static double ticks_per_nanosecond = ((double) current_ticks) / ((double) current_time);
|
||||
static double ticks_per_second = ticks_per_nanosecond * NANOSECONDS_IN_SECOND;
|
||||
INFO(" TPS: %f (%llu Total Ticks)", ticks_per_second, current_ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,6 +176,8 @@ static void Minecraft_update_injection(unsigned char *minecraft) {
|
||||
void init_benchmark() {
|
||||
if (active) {
|
||||
misc_run_on_update(Minecraft_update_injection);
|
||||
// Track Ticks
|
||||
misc_run_on_tick(Minecraft_tick_injection);
|
||||
// Disable Interaction
|
||||
media_set_interactable(0);
|
||||
// Disable V-Sync
|
||||
|
@ -107,7 +107,7 @@ static void send_queued_messages(unsigned char *minecraft) {
|
||||
pthread_mutex_lock(&queue_mutex);
|
||||
// If Message Was Submitted, No Other Chat Windows Are Open, And The Game Is Not Paused, Then Re-Lock Cursor
|
||||
unsigned int new_chat_counter = chat_get_counter();
|
||||
if (old_chat_counter > new_chat_counter && new_chat_counter == 0 && (*(unsigned char **) (minecraft + Minecraft_screen_property_offset)) == NULL) {
|
||||
if (old_chat_counter > new_chat_counter && new_chat_counter == 0) {
|
||||
// Unlock UI
|
||||
media_set_interactable(1);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ __attribute__((constructor)) static void init() {
|
||||
init_options();
|
||||
init_chat();
|
||||
init_home();
|
||||
#if !defined(MCPI_SERVER_MODE) && !defined(MCPI_HEADLESS_MODE)
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
init_benchmark();
|
||||
#endif
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ void init_death();
|
||||
void init_options();
|
||||
void init_chat();
|
||||
void init_home();
|
||||
#if !defined(MCPI_SERVER_MODE) && !defined(MCPI_HEADLESS_MODE)
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
void init_benchmark();
|
||||
#endif
|
||||
|
||||
|
@ -29,9 +29,44 @@ static void _handle_toggle_options(unsigned char *minecraft) {
|
||||
hide_gui_toggle = 0;
|
||||
if (third_person_toggle % 2 != 0) {
|
||||
// Toggle Third Person
|
||||
*(options + Options_third_person_property_offset) = *(options + Options_third_person_property_offset) ^ 1;
|
||||
*(options + Options_third_person_property_offset) = (*(options + Options_third_person_property_offset) + 1) % 3;
|
||||
}
|
||||
third_person_toggle = 0;
|
||||
// Fix Broken Value From Third-Person OptionsButton Toggle
|
||||
// (Because Front-Facing Code Repurposes A Boolean As A Ternary)
|
||||
if (*(options + Options_third_person_property_offset) == 3) {
|
||||
*(options + Options_third_person_property_offset) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Font-Facing View
|
||||
static void GameRenderer_setupCamera_injection(unsigned char *game_renderer, float param_1, int param_2) {
|
||||
// Get Objects
|
||||
unsigned char *minecraft = *(unsigned char **) (game_renderer + GameRenderer_minecraft_property_offset);
|
||||
unsigned char *player = *(unsigned char **) (minecraft + Minecraft_player_property_offset);
|
||||
|
||||
// Check If In Third-Person
|
||||
unsigned char *options = minecraft + Minecraft_options_property_offset;
|
||||
int is_font_facing = (*(options + Options_third_person_property_offset) == 2);
|
||||
|
||||
// Invert Rotation
|
||||
if (is_font_facing && player != NULL) {
|
||||
*(float *) (player + Entity_yaw_property_offset) = 180.f + (*(float *) (player + Entity_yaw_property_offset));
|
||||
*(float *) (player + Entity_old_yaw_property_offset) = 180.f + (*(float *) (player + Entity_old_yaw_property_offset));
|
||||
*(float *) (player + Entity_pitch_property_offset) = -(*(float *) (player + Entity_pitch_property_offset));
|
||||
*(float *) (player + Entity_old_pitch_property_offset) = -(*(float *) (player + Entity_old_pitch_property_offset));
|
||||
}
|
||||
|
||||
// Call Original Method
|
||||
(*GameRenderer_setupCamera)(game_renderer, param_1, param_2);
|
||||
|
||||
// Revert
|
||||
if (is_font_facing && player != NULL) {
|
||||
*(float *) (player + Entity_yaw_property_offset) = -180.f + (*(float *) (player + Entity_yaw_property_offset));
|
||||
*(float *) (player + Entity_old_yaw_property_offset) = -180.f + (*(float *) (player + Entity_old_yaw_property_offset));
|
||||
*(float *) (player + Entity_pitch_property_offset) = -(*(float *) (player + Entity_pitch_property_offset));
|
||||
*(float *) (player + Entity_old_pitch_property_offset) = -(*(float *) (player + Entity_old_pitch_property_offset));
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,4 +74,9 @@ static void _handle_toggle_options(unsigned char *minecraft) {
|
||||
void _init_toggle() {
|
||||
enable_toggles = feature_has("Bind Common Toggleable Options To Function Keys", server_disabled);
|
||||
input_run_on_tick(_handle_toggle_options);
|
||||
|
||||
// Font-Facing View
|
||||
if (enable_toggles) {
|
||||
overwrite_calls((void *) GameRenderer_setupCamera, (void *) GameRenderer_setupCamera_injection);
|
||||
}
|
||||
}
|
||||
|
@ -35,22 +35,6 @@ static void Gui_addMessage_injection(unsigned char *gui, std::string const& text
|
||||
free(new_message);
|
||||
}
|
||||
|
||||
// Check If Two Percentages Are Different Enough To Be Logged
|
||||
#define SIGNIFICANT_PROGRESS 5
|
||||
static bool is_progress_difference_significant(int32_t new_val, int32_t old_val) {
|
||||
if (new_val != old_val) {
|
||||
if (new_val == -1 || old_val == -1) {
|
||||
return true;
|
||||
} else if (new_val == 0 || new_val == 100) {
|
||||
return true;
|
||||
} else {
|
||||
return new_val - old_val >= SIGNIFICANT_PROGRESS;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Print Progress Reports
|
||||
static int last_progress = -1;
|
||||
static const char *last_message = NULL;
|
||||
|
@ -25,7 +25,7 @@ static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injectio
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Run Functions On Input Tick
|
||||
// Run Functions On Update
|
||||
static std::vector<misc_update_function_t> &get_misc_update_functions() {
|
||||
static std::vector<misc_update_function_t> functions;
|
||||
return functions;
|
||||
@ -33,18 +33,36 @@ static std::vector<misc_update_function_t> &get_misc_update_functions() {
|
||||
void misc_run_on_update(misc_update_function_t function) {
|
||||
get_misc_update_functions().push_back(function);
|
||||
}
|
||||
|
||||
// Handle Custom Update Behavior
|
||||
static void Minecraft_update_injection(unsigned char *minecraft) {
|
||||
// Call Original Method
|
||||
(*Minecraft_update)(minecraft);
|
||||
|
||||
// Run Input Tick Functions
|
||||
// Run Functions
|
||||
for (misc_update_function_t function : get_misc_update_functions()) {
|
||||
(*function)(minecraft);
|
||||
}
|
||||
}
|
||||
|
||||
// Run Functions On Update
|
||||
static std::vector<misc_update_function_t> &get_misc_tick_functions() {
|
||||
static std::vector<misc_update_function_t> functions;
|
||||
return functions;
|
||||
}
|
||||
void misc_run_on_tick(misc_update_function_t function) {
|
||||
get_misc_tick_functions().push_back(function);
|
||||
}
|
||||
// Handle Custom Tick Behavior
|
||||
static void Minecraft_tick_injection(unsigned char *minecraft, int32_t param_1, int32_t param_2) {
|
||||
// Call Original Method
|
||||
(*Minecraft_tick)(minecraft, param_1, param_2);
|
||||
|
||||
// Run Functions
|
||||
for (misc_update_function_t function : get_misc_tick_functions()) {
|
||||
(*function)(minecraft);
|
||||
}
|
||||
}
|
||||
|
||||
// Add Missing Buttons To Pause Menu
|
||||
static void PauseScreen_init_injection(unsigned char *screen) {
|
||||
// Call Original Method
|
||||
@ -88,6 +106,8 @@ void _init_misc_cpp() {
|
||||
|
||||
// Handle Custom Update Behavior
|
||||
overwrite_calls((void *) Minecraft_update, (void *) Minecraft_update_injection);
|
||||
// Handle Custom Tick Behavior
|
||||
overwrite_calls((void *) Minecraft_tick, (void *) Minecraft_tick_injection);
|
||||
|
||||
// Fix Pause Menu
|
||||
if (feature_has("Fix Pause Menu", server_disabled)) {
|
||||
|
@ -6,6 +6,7 @@ extern "C" {
|
||||
|
||||
typedef void (*misc_update_function_t)(unsigned char *minecraft);
|
||||
void misc_run_on_update(misc_update_function_t function);
|
||||
void misc_run_on_tick(misc_update_function_t function);
|
||||
|
||||
void Level_saveLevelData_injection(unsigned char *level);
|
||||
|
||||
|
@ -224,6 +224,29 @@ static void handle_server_stop(unsigned char *minecraft) {
|
||||
}
|
||||
}
|
||||
|
||||
// Track TPS
|
||||
#define NANOSECONDS_IN_SECOND 1000000000ll
|
||||
static long long int get_time() {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
long long int a = (long long int) ts.tv_nsec;
|
||||
long long int b = ((long long int) ts.tv_sec) * NANOSECONDS_IN_SECOND;
|
||||
return a + b;
|
||||
}
|
||||
static bool is_last_tick_time_set = false;
|
||||
static long long int last_tick_time;
|
||||
static double tps = 0;
|
||||
static void Minecraft_tick_injection(__attribute__((unused)) unsigned char *minecraft) {
|
||||
long long int time = get_time();
|
||||
if (is_last_tick_time_set) {
|
||||
long long int tick_time = time - last_tick_time;
|
||||
tps = ((double) NANOSECONDS_IN_SECOND) / ((double) tick_time);
|
||||
} else {
|
||||
is_last_tick_time_set = true;
|
||||
}
|
||||
last_tick_time = time;
|
||||
}
|
||||
|
||||
// Get ServerSideNetworkHandler From Minecraft
|
||||
static unsigned char *get_server_side_network_handler(unsigned char *minecraft) {
|
||||
return *(unsigned char **) (minecraft + Minecraft_network_handler_property_offset);
|
||||
@ -233,28 +256,26 @@ static unsigned char *get_server_side_network_handler(unsigned char *minecraft)
|
||||
static volatile bool stdin_buffer_complete = false;
|
||||
static volatile char *stdin_buffer = NULL;
|
||||
static void *read_stdin_thread(__attribute__((unused)) void *data) {
|
||||
// Check If STDIN Is A TTY
|
||||
if (isatty(fileno(stdin))) {
|
||||
// Loop
|
||||
while (1) {
|
||||
int bytes_available;
|
||||
if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) {
|
||||
bytes_available = 0;
|
||||
}
|
||||
for (int i = 0; i < bytes_available; i++) {
|
||||
if (!stdin_buffer_complete) {
|
||||
// Read Data
|
||||
int x = fgetc(stdin);
|
||||
if (x != EOF) {
|
||||
if (x == '\n') {
|
||||
if (stdin_buffer == NULL) {
|
||||
stdin_buffer = strdup("");
|
||||
}
|
||||
stdin_buffer_complete = true;
|
||||
} else {
|
||||
string_append((char **) &stdin_buffer, "%c", (char) x);
|
||||
}
|
||||
// Loop
|
||||
while (1) {
|
||||
int bytes_available;
|
||||
if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) {
|
||||
bytes_available = 0;
|
||||
}
|
||||
char buffer[bytes_available];
|
||||
bytes_available = read(fileno(stdin), (void *) buffer, bytes_available);
|
||||
for (int i = 0; i < bytes_available; i++) {
|
||||
if (!stdin_buffer_complete) {
|
||||
// Read Data
|
||||
char x = buffer[i];
|
||||
if (x == '\n') {
|
||||
if (stdin_buffer == NULL) {
|
||||
stdin_buffer = (volatile char *) malloc(1);
|
||||
stdin_buffer[0] = '\0';
|
||||
}
|
||||
stdin_buffer_complete = true;
|
||||
} else {
|
||||
string_append((char **) &stdin_buffer, "%c", (char) x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -282,6 +303,7 @@ static void handle_commands(unsigned char *minecraft) {
|
||||
static std::string say_command("say ");
|
||||
static std::string kill_command("kill ");
|
||||
static std::string list_command("list");
|
||||
static std::string tps_command("tps");
|
||||
static std::string stop_command("stop");
|
||||
static std::string help_command("help");
|
||||
if (!is_whitelist() && data.rfind(ban_command, 0) == 0) {
|
||||
@ -301,6 +323,9 @@ static void handle_commands(unsigned char *minecraft) {
|
||||
// List Players
|
||||
INFO("All Players:");
|
||||
find_players(minecraft, "", list_callback, true);
|
||||
} else if (data == tps_command) {
|
||||
// Print TPS
|
||||
INFO("TPS: %f", tps);
|
||||
} else if (data == stop_command) {
|
||||
// Stop Server
|
||||
compat_request_exit();
|
||||
@ -312,6 +337,7 @@ static void handle_commands(unsigned char *minecraft) {
|
||||
INFO(" kill <Username> - Kill All Players With Specifed Username");
|
||||
INFO(" say <Message> - Print Specified Message To Chat");
|
||||
INFO(" list - List All Players");
|
||||
INFO(" tps - Print TPS");
|
||||
INFO(" stop - Stop Server");
|
||||
INFO(" help - Print This Message");
|
||||
} else {
|
||||
@ -523,6 +549,9 @@ static void server_init() {
|
||||
// Log IPs
|
||||
overwrite_call((void *) 0x75e54, (void *) ServerSideNetworkHandler_onReady_ClientGeneration_ServerSideNetworkHandler_popPendingPlayer_injection);
|
||||
|
||||
// Track TPS
|
||||
misc_run_on_tick(Minecraft_tick_injection);
|
||||
|
||||
// Start Reading STDIN
|
||||
pthread_t read_stdin_thread_obj;
|
||||
pthread_create(&read_stdin_thread_obj, NULL, read_stdin_thread, NULL);
|
||||
|
@ -42,13 +42,13 @@ static void TextEditScreen_updateEvents_injection(unsigned char *screen) {
|
||||
(*Screen_updateEvents)(screen);
|
||||
|
||||
if (*(char *)(screen + 4) == '\0') {
|
||||
uint32_t vtable = *((uint32_t *) screen);
|
||||
unsigned char *vtable = *(unsigned char **) screen;
|
||||
for (char key : input) {
|
||||
if (key == BACKSPACE_KEY) {
|
||||
// Handle Backspace
|
||||
(*(Screen_keyPressed_t *) (vtable + Screen_keyPressed_vtable_offset))(screen, BACKSPACE_KEY);
|
||||
} else {
|
||||
// Handle Nrmal Key
|
||||
// Handle Normal Key
|
||||
(*(Screen_keyboardNewChar_t *) (vtable + Screen_keyboardNewChar_vtable_offset))(screen, key);
|
||||
}
|
||||
}
|
||||
|
@ -7,14 +7,12 @@
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include "../misc/misc.h"
|
||||
#include "../feature/feature.h"
|
||||
#include "../init/init.h"
|
||||
|
||||
// Animated Water
|
||||
static void Minecraft_tick_injection(unsigned char *minecraft, int32_t param_1, int32_t param_2) {
|
||||
// Call Original Method
|
||||
(*Minecraft_tick)(minecraft, param_1, param_2);
|
||||
|
||||
static void Minecraft_tick_injection(unsigned char *minecraft) {
|
||||
// Tick Dynamic Textures
|
||||
unsigned char *textures = *(unsigned char **) (minecraft + Minecraft_textures_property_offset);
|
||||
if (textures != NULL) {
|
||||
@ -77,7 +75,8 @@ static void get_texture_size(GLint id, GLsizei *width, GLsizei *height) {
|
||||
++it;
|
||||
}
|
||||
// Not Found
|
||||
ERR("Unable To Find Size Of Texture: %i", id);
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
}
|
||||
|
||||
// Scale Texture (Remember To Free)
|
||||
@ -167,7 +166,7 @@ static void Textures_tick_glTexSubImage2D_injection(GLenum target, GLint level,
|
||||
void init_textures() {
|
||||
// Tick Dynamic Textures (Animated Water)
|
||||
if (feature_has("Animated Water", server_disabled)) {
|
||||
overwrite_calls((void *) Minecraft_tick, (void *) Minecraft_tick_injection);
|
||||
misc_run_on_tick(Minecraft_tick_injection);
|
||||
}
|
||||
|
||||
// Scale Animated Textures
|
||||
|
@ -108,18 +108,23 @@ const afterBundle = [
|
||||
'find ./AppDir/usr/bin -maxdepth 1 -name \'qemu-*\' -a ! -name \'qemu-arm\' -delete'
|
||||
];
|
||||
|
||||
// Environment
|
||||
const env = {
|
||||
APPDIR_MODULE_DIR: '/tmp/.minecraft-pi-patched'
|
||||
};
|
||||
if (mode === 'client') {
|
||||
// Make GTK Work (Zenity Uses GTK)
|
||||
env.GTK_EXE_PREFIX = '${APPDIR}/usr';
|
||||
env.GTK_PATH = `\${APPDIR}/usr/lib/${triplet}/gtk-3.0`;
|
||||
env.GTK_DATA_PREFIX = '${APPDIR}';
|
||||
env.GTK_THEME = 'Default';
|
||||
env.XDG_DATA_DIRS = '${APPDIR}/share:${APPDIR}/usr/share:/share:/usr/share';
|
||||
env.APPDIR_LIBRARY_PATH = `\${APPDIR}/usr/lib/${triplet}:\${APPDIR}/usr/${triplet}/lib:\${APPDIR}/lib/${triplet}:\${APPDIR}/usr/lib:\${APPDIR}/usr/lib/${triplet}/gdk-pixbuf-2.0/2.10.0/loaders`;
|
||||
}
|
||||
|
||||
// Runtime
|
||||
const runtime = {
|
||||
env: mode === 'client' ? {
|
||||
// Make GTK Work (Zenity Uses GTK)
|
||||
GTK_EXE_PREFIX: '${APPDIR}/usr',
|
||||
GTK_PATH: `\${APPDIR}/usr/lib/${triplet}/gtk-3.0`,
|
||||
GTK_DATA_PREFIX: '${APPDIR}',
|
||||
GTK_THEME: 'Default',
|
||||
XDG_DATA_DIRS: '${APPDIR}/share:${APPDIR}/usr/share:/share:/usr/share',
|
||||
APPDIR_LIBRARY_PATH: `\${APPDIR}/usr/lib/${triplet}:\${APPDIR}/usr/${triplet}/lib:\${APPDIR}/lib/${triplet}:\${APPDIR}/usr/lib:\${APPDIR}/usr/lib/${triplet}/gdk-pixbuf-2.0/2.10.0/loaders`,
|
||||
APPDIR_MODULE_DIR: '/tmp/.minecraft-pi-patched'
|
||||
} : undefined,
|
||||
env: env,
|
||||
preserve: arch !== 'armhf' ? [
|
||||
// On non-ARM32 systems, an ARM32 linker is embedded, this
|
||||
// prevents AppImage-Builder from modifying ARM32 binaries
|
||||
|
@ -202,6 +202,9 @@ static uint32_t Minecraft_perf_renderer_property_offset = 0xcbc; // PerfRenderer
|
||||
typedef void (*GameRenderer_render_t)(unsigned char *game_renderer, float param_1);
|
||||
static GameRenderer_render_t GameRenderer_render = (GameRenderer_render_t) 0x4a338;
|
||||
|
||||
typedef void (*GameRenderer_setupCamera_t)(unsigned char *game_renderer, float param_1, int param_2);
|
||||
static GameRenderer_setupCamera_t GameRenderer_setupCamera = (GameRenderer_setupCamera_t) 0x489f8;
|
||||
|
||||
static uint32_t GameRenderer_minecraft_property_offset = 0x4; // Minecraft *
|
||||
|
||||
// Mouse
|
||||
@ -326,10 +329,12 @@ static uint32_t Entity_x_property_offset = 0x4; // float
|
||||
static uint32_t Entity_y_property_offset = 0x8; // float
|
||||
static uint32_t Entity_z_property_offset = 0xc; // float
|
||||
static uint32_t Entity_yaw_property_offset = 0x40; // float
|
||||
static uint32_t Entity_pitch_property_offset = 0x44; // float
|
||||
static uint32_t Entity_old_x_property_offset = 0x28; // float
|
||||
static uint32_t Entity_old_y_property_offset = 0x2c; // float
|
||||
static uint32_t Entity_old_z_property_offset = 0x30; // float
|
||||
static uint32_t Entity_old_yaw_property_offset = 0x48; // float
|
||||
static uint32_t Entity_old_pitch_property_offset = 0x4c; // float
|
||||
|
||||
// Mob
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user