Sweeping Media Layer Changes (GL ES 2.0 Support)

This commit is contained in:
TheBrokenRail 2022-05-29 18:44:27 -04:00
parent 4ed11b67e7
commit 1743626113
44 changed files with 1181 additions and 190 deletions

2
.gitignore vendored
View File

@ -9,3 +9,5 @@ appimage-builder-cache
appimage-build appimage-build
AppDir AppDir
*.zsync *.zsync
core*
qemu_*

View File

@ -2,15 +2,15 @@ cmake_minimum_required(VERSION 3.13.0)
# Specify Options # Specify Options
option(MCPI_IS_MIXED_BUILD "Whether The Architecture-Independent And ARM Code Are Different Architecture" FALSE) 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" ${MCPI_IS_MIXED_BUILD})
option(MCPI_BUNDLE_ARMHF_SYSROOT "Whether To Include An ARMHF Sysroot" TRUE)
endif()
option(MCPI_SERVER_MODE "Server Mode" FALSE) option(MCPI_SERVER_MODE "Server Mode" FALSE)
option(MCPI_HEADLESS_MODE "Headless Mode" ${MCPI_SERVER_MODE}) option(MCPI_HEADLESS_MODE "Headless Mode" ${MCPI_SERVER_MODE})
if(NOT MCPI_HEADLESS_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_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() else()
set(MCPI_USE_MEDIA_LAYER_PROXY FALSE) set(MCPI_USE_MEDIA_LAYER_PROXY FALSE)
set(MCPI_USE_GLES1_COMPATIBILITY_LAYER FALSE)
endif() 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(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") set_property(CACHE MCPI_BUILD_MODE PROPERTY STRINGS "both" "arm" "native")
@ -118,6 +118,9 @@ endif()
if(MCPI_BUNDLE_ARMHF_SYSROOT) if(MCPI_BUNDLE_ARMHF_SYSROOT)
add_definitions(-DMCPI_BUNDLE_ARMHF_SYSROOT) add_definitions(-DMCPI_BUNDLE_ARMHF_SYSROOT)
endif() endif()
if(MCPI_USE_GLES1_COMPATIBILITY_LAYER)
add_definitions(-DMCPI_USE_GLES1_COMPATIBILITY_LAYER)
endif()
# Version # Version
set_property( set_property(

View File

@ -12,4 +12,9 @@ FetchContent_Declare(
FetchContent_Populate(minecraft-pi) FetchContent_Populate(minecraft-pi)
# Install # 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
)

View File

@ -2,8 +2,11 @@
## Command Line Arguments ## 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) ### ``--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: The feature flags are printed in the following format:
``` ```

View File

@ -149,7 +149,17 @@ static void exit_handler(__attribute__((unused)) int signal_id) {
} }
// Pre-Bootstrap // 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 // GTK Dark Mode
#ifndef MCPI_SERVER_MODE #ifndef MCPI_SERVER_MODE
set_and_print_env("GTK_THEME", "Adwaita:dark"); set_and_print_env("GTK_THEME", "Adwaita:dark");

View File

@ -6,7 +6,7 @@ extern "C" {
void set_and_print_env(const char *name, char *value); 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[]); void bootstrap(int argc, char *argv[]);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -127,7 +127,7 @@ static void run_zenity_and_set_env(const char *env_name, std::vector<std::string
#define LIST_DIALOG_SIZE "400" #define LIST_DIALOG_SIZE "400"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// Pre-Bootstrap // Pre-Bootstrap
pre_bootstrap(); pre_bootstrap(argc, argv);
// Print Features // Print Features
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {

View File

@ -6,6 +6,7 @@
#include <stdint.h> #include <stdint.h>
#include <signal.h> #include <signal.h>
#include <poll.h> #include <poll.h>
#include <sys/ioctl.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
@ -41,14 +42,16 @@ static void exit_handler(__attribute__((unused)) int signal) {
} }
// Setup // Setup
#define PIPE_READ 0
#define PIPE_WRITE 1
void setup_crash_report() { void setup_crash_report() {
// Store Output // Store Output
#ifndef MCPI_HEADLESS_MODE
int output_pipe[2]; int output_pipe[2];
safe_pipe2(output_pipe, 0); safe_pipe2(output_pipe, 0);
int error_pipe[2]; int error_pipe[2];
safe_pipe2(error_pipe, 0); safe_pipe2(error_pipe, 0);
#endif int input_pipe[2];
safe_pipe2(input_pipe, 0);
// Fork // Fork
pid_t ret = fork(); pid_t ret = fork();
@ -58,14 +61,15 @@ void setup_crash_report() {
// Child Process // Child Process
// Pipe stdio // Pipe stdio
#ifndef MCPI_HEADLESS_MODE dup2(output_pipe[PIPE_WRITE], STDOUT_FILENO);
dup2(output_pipe[1], STDOUT_FILENO); close(output_pipe[PIPE_READ]);
close(output_pipe[0]); close(output_pipe[PIPE_WRITE]);
close(output_pipe[1]); dup2(error_pipe[PIPE_WRITE], STDERR_FILENO);
dup2(error_pipe[1], STDERR_FILENO); close(error_pipe[PIPE_READ]);
close(error_pipe[0]); close(error_pipe[PIPE_WRITE]);
close(error_pipe[1]); dup2(input_pipe[PIPE_READ], STDIN_FILENO);
#endif close(input_pipe[PIPE_READ]);
close(input_pipe[PIPE_WRITE]);
// Create New Process Group // Create New Process Group
setpgid(0, 0); setpgid(0, 0);
@ -87,13 +91,12 @@ void setup_crash_report() {
act_sigterm.sa_handler = &exit_handler; act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL); sigaction(SIGTERM, &act_sigterm, NULL);
// Capture stdio
#ifndef MCPI_HEADLESS_MODE
// Close Unneeded File Descriptors // Close Unneeded File Descriptors
close(output_pipe[1]); close(output_pipe[PIPE_WRITE]);
close(error_pipe[1]); close(error_pipe[PIPE_WRITE]);
close(input_pipe[PIPE_READ]);
// Create A Buffer // Setup Logging
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024
char buf[BUFFER_SIZE]; char buf[BUFFER_SIZE];
@ -105,10 +108,11 @@ void setup_crash_report() {
} }
// Setup Polling // Setup Polling
int number_fds = 2; int number_fds = 3;
struct pollfd poll_fds[number_fds]; struct pollfd poll_fds[number_fds];
poll_fds[0].fd = output_pipe[0]; poll_fds[0].fd = output_pipe[PIPE_READ];
poll_fds[1].fd = error_pipe[0]; poll_fds[1].fd = error_pipe[PIPE_READ];
poll_fds[2].fd = STDIN_FILENO;
for (int i = 0; i < number_fds; i++) { for (int i = 0; i < number_fds; i++) {
poll_fds[i].events = POLLIN; poll_fds[i].events = POLLIN;
} }
@ -129,31 +133,51 @@ void setup_crash_report() {
for (int i = 0; i < number_fds; i++) { for (int i = 0; i < number_fds; i++) {
if (poll_fds[i].revents != 0) { if (poll_fds[i].revents != 0) {
if (poll_fds[i].revents & POLLIN) { if (poll_fds[i].revents & POLLIN) {
// Data Available if (poll_fds[i].fd == STDIN_FILENO) {
ssize_t bytes_read = read(poll_fds[i].fd, (void *) buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */); // Data Available From stdin
if (bytes_read == -1) { int bytes_available;
ERR("Unable To Read Log Data: %s", strerror(errno)); 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 // Print To Terminal
buf[bytes_read] = '\0'; buf[bytes_read] = '\0';
fprintf(i == 0 ? stdout : stderr, "%s", buf); fprintf(i == 0 ? stdout : stderr, "%s", buf);
// Write To log // Write To log
if (write(log_file_fd, (void *) buf, bytes_read) == -1) { if (write(log_file_fd, (void *) buf, bytes_read) == -1) {
ERR("Unable To Write Log Data: %s", strerror(errno)); ERR("Unable To Write Log Data: %s", strerror(errno));
}
} }
} else { } else {
// File Descriptor No Longer Accessible // 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)); ERR("Unable To Close File Descriptor: %s", strerror(errno));
} }
poll_fds[i].events = 0;
number_open_fds--; number_open_fds--;
} }
} }
} }
} }
#endif
// Close Input Pipe
close(input_pipe[PIPE_WRITE]);
// Get Return Code // Get Return Code
int status; int status;
@ -176,33 +200,30 @@ void setup_crash_report() {
fprintf(stderr, "%s", exit_code_line); fprintf(stderr, "%s", exit_code_line);
// Write Exit Code Log Line // Write Exit Code Log Line
#ifndef MCPI_HEADLESS_MODE
if (write(log_file_fd, (void *) exit_code_line, strlen(exit_code_line)) == -1) { 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)); ERR("Unable To Write Exit Code To Log: %s", strerror(errno));
} }
#endif
// Free Exit Code Log Line // Free Exit Code Log Line
free(exit_code_line); free(exit_code_line);
} }
// Show Crash Log
#ifndef MCPI_HEADLESS_MODE
// Close Log File FD // Close Log File FD
if (close(log_file_fd) == -1) { if (close(log_file_fd) == -1) {
ERR("Unable To Close Log File Descriptor: %s", strerror(errno)); ERR("Unable To Close Log File Descriptor: %s", strerror(errno));
} }
// Show Report // Show Crash Log
#ifndef MCPI_HEADLESS_MODE
if (is_crash) { if (is_crash) {
show_report(log_filename); show_report(log_filename);
} }
#endif
// Delete Log File // Delete Log File
if (unlink(log_filename) == -1) { if (unlink(log_filename) == -1) {
ERR("Unable To Delete Log File: %s", strerror(errno)); ERR("Unable To Delete Log File: %s", strerror(errno));
} }
#endif
// Exit // Exit
exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE); exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);

View File

@ -5,7 +5,7 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// Pre-Bootstrap // Pre-Bootstrap
pre_bootstrap(); pre_bootstrap(argc, argv);
// Set Home To Current Directory, So World Data Is Stored There // Set Home To Current Directory, So World Data Is Stored There
char *launch_directory = getcwd(NULL, 0); char *launch_directory = getcwd(NULL, 0);

View File

@ -25,7 +25,7 @@
dlerror(); \ dlerror(); \
real_##name = (name##_t) dlsym(RTLD_NEXT, #name); \ real_##name = (name##_t) dlsym(RTLD_NEXT, #name); \
if (!real_##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() // Safe Version Of pipe()
void safe_pipe2(int pipefd[2], int flags); 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 #ifdef __cplusplus
} }

View File

@ -6,3 +6,19 @@ void safe_pipe2(int pipefd[2], int flags) {
ERR("Unable To Create Pipe: %s", strerror(errno)); 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;
}
}

View File

@ -1,14 +1,16 @@
project(media-layer) project(media-layer)
# Check Options # Target Notes:
if(MCPI_USE_MEDIA_LAYER_PROXY AND MCPI_BUILD_MODE STREQUAL "both") # media-layer-core-real: Fully Built Media Layer Core
message(FATAL_ERROR "Media Layer Proxy Is Redundant When Building ARM And Native Components In The Same Build") # media-layer-core: Alias Target That Points To The Library MCPI Should Link To
endif()
# Add Headers # Add Headers
add_library(media-layer-headers INTERFACE) add_library(media-layer-headers INTERFACE)
target_include_directories(media-layer-headers INTERFACE include) target_include_directories(media-layer-headers INTERFACE include)
# Add GLESv1_CM Stubs Or Compatibility Layer
add_subdirectory(gles)
# Add Core # Add Core
add_subdirectory(core) add_subdirectory(core)
@ -17,8 +19,5 @@ if(MCPI_USE_MEDIA_LAYER_PROXY)
add_subdirectory(proxy) add_subdirectory(proxy)
endif() endif()
# Add Stubs
add_subdirectory(stubs)
# Add Extras # Add Extras
add_subdirectory(extras) add_subdirectory(extras)

View File

@ -8,26 +8,30 @@ endif()
# Build # Build
if(MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_NATIVE_COMPONENTS) if(MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_NATIVE_COMPONENTS)
# Building Native Components # Build Media Layer Core Natively And Use Proxy
add_library(media-layer-core OBJECT ${CORE_SRC}) # Dependencies Are Setup Later add_library(media-layer-core-real OBJECT ${CORE_SRC}) # Dependencies Are Setup Later
elseif(NOT MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_ARM_COMPONENTS) endif()
# Building ARM Components if(NOT MCPI_USE_MEDIA_LAYER_PROXY AND BUILD_ARM_COMPONENTS)
add_library(media-layer-core SHARED ${CORE_SRC}) # Dependencies Are Setup Later # 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
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() endif()
# Configure Media Layer Core If Built # Configure Media Layer Core If Built
if(TARGET media-layer-core) if(TARGET media-layer-core-real)
# Link # 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) if(NOT MCPI_HEADLESS_MODE)
# Find FreeImage # Find FreeImage
find_library(FREEIMAGE_LIBRARY NAMES freeimage libfreeimage.so.3 REQUIRED) find_library(FREEIMAGE_LIBRARY NAMES freeimage libfreeimage.so.3 REQUIRED)
# OpenAL # OpenAL
find_library(OPENAL_LIBRARY NAMES openal REQUIRED) find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
# Link # 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()
endif() endif()

View File

@ -15,6 +15,7 @@ static std::vector<ALuint> &get_sources() {
return sources; return sources;
} }
// Error Checking
#define AL_ERROR_CHECK() AL_ERROR_CHECK_MANUAL(alGetError()) #define AL_ERROR_CHECK() AL_ERROR_CHECK_MANUAL(alGetError())
#define AL_ERROR_CHECK_MANUAL(val) \ #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) { void media_audio_play(const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui) {
// Check // Check
if (_media_audio_is_loaded()) { if (_media_audio_is_loaded()) {

View File

@ -207,21 +207,18 @@ static ALuint load_sound(const char *source, const char *name) {
} }
// Store Buffers // Store Buffers
static std::unordered_map<std::string, ALuint> &get_buffers() { static std::unordered_map<std::string, ALuint> buffers;
static std::unordered_map<std::string, ALuint> buffers;
return buffers;
}
// Get Buffer For Sound // Get Buffer For Sound
ALuint _media_audio_get_buffer(const char *source, const char *name) { ALuint _media_audio_get_buffer(const char *source, const char *name) {
// Check // Check
if (_media_audio_is_loaded()) { if (_media_audio_is_loaded()) {
if (get_buffers().count(name) > 0) { if (buffers.count(name) > 0) {
// Return // Return
return get_buffers()[name]; return buffers[name];
} else { } else {
// Load And Return // Load And Return
get_buffers()[name] = load_sound(source, name); buffers[name] = load_sound(source, name);
return _media_audio_get_buffer(source, name); return _media_audio_get_buffer(source, name);
} }
} else { } else {
@ -232,11 +229,11 @@ ALuint _media_audio_get_buffer(const char *source, const char *name) {
// Delete Buffers // Delete Buffers
void _media_audio_delete_buffers() { void _media_audio_delete_buffers() {
if (_media_audio_is_loaded()) { if (_media_audio_is_loaded()) {
for (auto it : get_buffers()) { for (auto it : buffers) {
if (it.second && alIsBuffer(it.second)) { if (it.second && alIsBuffer(it.second)) {
alDeleteBuffers(1, &it.second); alDeleteBuffers(1, &it.second);
} }
} }
} }
get_buffers().clear(); buffers.clear();
} }

View File

@ -1,7 +1,6 @@
#include <unistd.h> #include <unistd.h>
#include <SDL/SDL.h> #include <SDL/SDL.h>
#include <GLES/gl.h>
#ifndef MCPI_HEADLESS_MODE #ifndef MCPI_HEADLESS_MODE
#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_NONE
@ -225,7 +224,7 @@ static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute_
#endif #endif
// Track Media Layer State // Track Media Layer State
static int is_running = 0; static volatile int is_running = 0;
// Track If Raw Mouse Motion Is Enabled // Track If Raw Mouse Motion Is Enabled
static int raw_mouse_motion_enabled = 1; static int raw_mouse_motion_enabled = 1;
@ -253,6 +252,8 @@ void media_disable_vsync() {
} }
// Init Media Layer // 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) { void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *icon) {
// Don't Enable GLFW In Headless Mode // Don't Enable GLFW In Headless Mode
#ifndef MCPI_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"); ERR("Unable To Initialize GLFW");
} }
// Create OpenGL ES 1.1 Context // Create OpenGL ES Context
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); 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_MAJOR, 1);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
#endif
// Use EGL // Use EGL
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
// Extra Settings // Extra Settings
@ -289,6 +295,10 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
// Make Window Context Current // Make Window Context Current
glfwMakeContextCurrent(glfw_window); glfwMakeContextCurrent(glfw_window);
// Debug
glGetString_t glGetString = (glGetString_t) glfwGetProcAddress("glGetString");
DEBUG("Using %s", (*glGetString)(GL_VERSION));
// Init OpenAL // Init OpenAL
_media_audio_init(); _media_audio_init();
#else #else
@ -303,6 +313,9 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
if (disable_vsync) { if (disable_vsync) {
media_disable_vsync(); media_disable_vsync();
} }
// Always Cleanup Media Layer
atexit(media_cleanup);
} }
void media_swap_buffers() { void media_swap_buffers() {
@ -384,10 +397,6 @@ void media_cleanup() {
is_running = 0; is_running = 0;
} }
} }
// Always Cleanup Media Layer
__attribute__((destructor)) static void always_cleanup() {
media_cleanup();
}
// Store Cursor State // Store Cursor State
static int cursor_grabbed = 0; static int cursor_grabbed = 0;

View File

@ -70,7 +70,7 @@ void media_take_screenshot(char *home) {
int height = viewport[3]; int height = viewport[3];
// Get Line Size // Get Line Size
int line_size = width * 3; int line_size = width * 4;
{ {
// Handle Alignment // Handle Alignment
int alignment; int alignment;
@ -85,14 +85,14 @@ void media_take_screenshot(char *home) {
// Read Pixels // Read Pixels
unsigned char pixels[size]; 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 // Handle Little Endian Systems
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
// Swap Red And Blue // Swap Red And Blue
for (int j = 0; j < width; j++) { for (int j = 0; j < width; j++) {
for (int k = 0; k < height; k++) { for (int k = 0; k < height; k++) {
int pixel = (k * line_size) + (j * 3); int pixel = (k * line_size) + (j * 4);
// Swap // Swap
int red = pixels[pixel]; int red = pixels[pixel];
int blue = pixels[pixel + 2]; int blue = pixels[pixel + 2];
@ -103,7 +103,7 @@ void media_take_screenshot(char *home) {
#endif #endif
// Save Image // 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)) { if (!FreeImage_Save(FIF_PNG, image, file, 0)) {
INFO("Screenshot Failed: %s", file); INFO("Screenshot Failed: %s", file);
} else { } else {

View File

@ -2,5 +2,10 @@ project(media-layer-extras)
if(BUILD_ARM_COMPONENTS) if(BUILD_ARM_COMPONENTS)
# Add Source To Media Core # 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() endif()

View 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")

View 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);
}
}

View 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);
}

View 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;

View 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
}

View 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; \
}

View 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;
}
}
}

View 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;

View File

@ -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 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) { 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 glDeleteTextures(GLsizei n, const GLuint *textures) {
} }
void glAlphaFunc(GLenum func, GLclampf ref) { void glAlphaFunc(GLenum func, GLclampf ref) {
} }
void glGetFloatv(GLenum pname, GLfloat *params) { 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) { void glBindTexture(GLenum target, GLuint texture) {
if (target == GL_TEXTURE_2D) {
current_texture = texture;
}
} }
void glTranslatef(GLfloat x, GLfloat y, GLfloat z) { void glTranslatef(GLfloat x, GLfloat y, GLfloat z) {
} }
@ -101,6 +135,20 @@ GLboolean glIsEnabled(GLenum cap) {
return GL_FALSE; return GL_FALSE;
} }
void glGetIntegerv(GLenum pname, GLint *data) { 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) { void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data) {
} }

View File

@ -5,10 +5,10 @@ extern "C" {
#endif #endif
#define GL_FALSE 0 #define GL_FALSE 0
#define GL_FOG_COLOR 0xb66
#define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ARRAY_BUFFER_BINDING 0x8894
#define GL_TEXTURE_BINDING_2D 0x8069 #define GL_TEXTURE_BINDING_2D 0x8069
#define GL_UNSIGNED_BYTE 0x1401 #define GL_UNSIGNED_BYTE 0x1401
#define GL_FLOAT 0x1406
#define GL_RGB 0x1907 #define GL_RGB 0x1907
#define GL_RGBA 0x1908 #define GL_RGBA 0x1908
#define GL_MODELVIEW_MATRIX 0xba6 #define GL_MODELVIEW_MATRIX 0xba6
@ -19,6 +19,25 @@ extern "C" {
#define GL_UNPACK_ALIGNMENT 0xcf5 #define GL_UNPACK_ALIGNMENT 0xcf5
#define GL_SRC_ALPHA 0x302 #define GL_SRC_ALPHA 0x302
#define GL_ONE_MINUS_SRC_ALPHA 0x303 #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 <stdio.h>
#include <stdint.h> #include <stdint.h>
@ -34,6 +53,7 @@ typedef intptr_t GLintptr;
typedef int32_t GLfixed; typedef int32_t GLfixed;
typedef unsigned int GLbitfield; typedef unsigned int GLbitfield;
typedef unsigned int GLenum; typedef unsigned int GLenum;
typedef char GLchar;
void glFogfv(GLenum pname, const GLfloat *params); void glFogfv(GLenum pname, const GLfloat *params);
void glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer); void glVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer);

View File

@ -4,8 +4,15 @@
extern "C" { extern "C" {
#endif #endif
#ifndef MCPI_HEADLESS_MODE
void media_audio_update(float volume, float x, float y, float z, float yaw); 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); 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 #ifdef __cplusplus
} }

View File

@ -2,28 +2,26 @@ project(media-layer-proxy)
# Configuration # 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_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) if(BUILD_NATIVE_COMPONENTS)
# Building Native Components
# Build Media Layer Proxy Client # Build Media Layer Proxy Client
add_executable(media-layer-proxy-client src/client/client.cpp ${MEDIA_LAYER_PROXY_SRC}) 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) target_compile_definitions(media-layer-proxy-client PRIVATE -DMEDIA_LAYER_PROXY_CLIENT)
# Install # Install
install(TARGETS media-layer-proxy-client DESTINATION "${MCPI_BIN_DIR}") install(TARGETS media-layer-proxy-client DESTINATION "${MCPI_BIN_DIR}")
endif() endif()
if(BUILD_ARM_COMPONENTS) if(BUILD_ARM_COMPONENTS)
# Building ARM Components
# Build Media Layer Proxy Server # Build Media Layer Proxy Server
add_library(media-layer-core SHARED src/server/server.cpp ${MEDIA_LAYER_PROXY_SRC}) add_library(media-layer-proxy-server SHARED src/server/server.cpp ${MEDIA_LAYER_PROXY_SRC})
target_link_libraries(media-layer-core media-layer-headers reborn-util) target_link_libraries(media-layer-proxy-server media-layer-headers reborn-util)
target_compile_definitions(media-layer-core PRIVATE -DMEDIA_LAYER_PROXY_SERVER) 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 # Symlink GLESv1_CM To Media Layer Proxy Server
install_symlink("libmedia-layer-core.so" "${MCPI_LIB_DIR}/libGLESv1_CM.so.1") install_symlink("libmedia-layer-core.so" "${MCPI_LIB_DIR}/libGLESv1_CM.so.1")
# Install # 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() endif()

View File

@ -342,7 +342,7 @@ static int get_texture_size(GLsizei width, GLsizei height, GLenum format, GLenum
break; break;
} }
default: { default: {
PROXY_ERR("Invalid Texture Format: %u", (unsigned int) format); PROXY_ERR("Unsupported Texture Format: %u", (unsigned int) format);
} }
} }
} else { } else {
@ -858,7 +858,7 @@ static int get_glGetFloatv_params_size(GLenum pname) {
return 16; return 16;
} }
default: { 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; return 1;
} }
default: { default: {
PROXY_ERR("Inavlid glGetIntegerv Property: %u", pname); PROXY_ERR("Unsupported glGetIntegerv Property: %u", pname);
} }
} }
} }

View File

@ -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()

View File

@ -54,15 +54,13 @@ else()
target_link_libraries(override reborn-patch symbols dl home) target_link_libraries(override reborn-patch symbols dl home)
add_library(textures SHARED src/textures/textures.cpp) 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) add_library(atlas SHARED src/atlas/atlas.cpp)
target_link_libraries(atlas reborn-patch symbols feature GLESv1_CM) target_link_libraries(atlas reborn-patch symbols feature GLESv1_CM)
if(NOT MCPI_HEADLESS_MODE) add_library(benchmark SHARED src/benchmark/benchmark.cpp)
add_library(benchmark SHARED src/benchmark/benchmark.cpp) target_link_libraries(benchmark reborn-patch symbols compat misc media-layer-core)
target_link_libraries(benchmark reborn-patch symbols compat misc media-layer-core)
endif()
endif() endif()
add_library(death SHARED src/death/death.cpp) 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) if(MCPI_SERVER_MODE)
target_link_libraries(init server) target_link_libraries(init server)
else() else()
target_link_libraries(init multiplayer sound camera input sign touch textures atlas) target_link_libraries(init multiplayer sound camera input sign touch textures atlas benchmark)
if(NOT MCPI_HEADLESS_MODE)
target_link_libraries(init benchmark)
endif()
endif() endif()
## Install Mods ## Install Mods
@ -96,8 +91,5 @@ install(TARGETS init compat readdir feature game-mode misc death options chat cr
if(MCPI_SERVER_MODE) if(MCPI_SERVER_MODE)
install(TARGETS server DESTINATION "${MCPI_INSTALL_DIR}/mods") install(TARGETS server DESTINATION "${MCPI_INSTALL_DIR}/mods")
else() else()
install(TARGETS multiplayer sound override camera input sign touch textures atlas DESTINATION "${MCPI_INSTALL_DIR}/mods") install(TARGETS multiplayer sound override camera input sign touch textures atlas benchmark DESTINATION "${MCPI_INSTALL_DIR}/mods")
if(NOT MCPI_HEADLESS_MODE)
install(TARGETS benchmark DESTINATION "${MCPI_INSTALL_DIR}/mods")
endif()
endif() endif()

View File

@ -28,7 +28,7 @@ __attribute__((constructor)) static void _init_active(int argc, char *argv[]) {
#define NANOSECONDS_IN_SECOND 1000000000ll #define NANOSECONDS_IN_SECOND 1000000000ll
// Config // Config
#define BENCHMARK_GAME_MODE 1 // Creative Mode #define BENCHMARK_GAME_MODE 0 // Survival Mode
#define BENCHMARK_SEED 2048 // Random Number #define BENCHMARK_SEED 2048 // Random Number
#define BENCHMARK_WORLD_NAME "_Benchmark" // Random Number #define BENCHMARK_WORLD_NAME "_Benchmark" // Random Number
#define BENCHMARK_LENGTH (180ll * NANOSECONDS_IN_SECOND) // 3 Minutes #define BENCHMARK_LENGTH (180ll * NANOSECONDS_IN_SECOND) // 3 Minutes
@ -62,12 +62,20 @@ static void start_world(unsigned char *minecraft) {
} }
// Track Frames // Track Frames
#ifndef MCPI_HEADLESS_MODE
static unsigned long long int frames = 0; static unsigned long long int frames = 0;
HOOK(media_swap_buffers, void, ()) { HOOK(media_swap_buffers, void, ()) {
ensure_media_swap_buffers(); ensure_media_swap_buffers();
(*real_media_swap_buffers)(); (*real_media_swap_buffers)();
frames++; frames++;
} }
#endif
// Track Ticks
static unsigned long long int ticks = 0;
static void Minecraft_tick_injection(__attribute__((unused)) unsigned char *minecraft) {
ticks++;
}
// Get Time // Get Time
static long long int get_time() { static long long int get_time() {
@ -81,7 +89,13 @@ static long long int get_time() {
// Store Time When World Loaded // Store Time When World Loaded
static int world_loaded = 0; static int world_loaded = 0;
static long long int world_loaded_time; static long long int world_loaded_time;
#ifndef MCPI_HEADLESS_MODE
static unsigned long long int world_loaded_frames; 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 // Runs Every Tick
static bool loaded = false; static bool loaded = false;
@ -97,14 +111,30 @@ static void Minecraft_update_injection(unsigned char *minecraft) {
if (!world_loaded && (*Minecraft_isLevelGenerated)(minecraft)) { if (!world_loaded && (*Minecraft_isLevelGenerated)(minecraft)) {
world_loaded = 1; world_loaded = 1;
world_loaded_time = get_time(); world_loaded_time = get_time();
#ifndef MCPI_HEADLESS_MODE
world_loaded_frames = frames; world_loaded_frames = frames;
#endif
world_loaded_ticks = ticks;
} }
// Run Benchmark // Run Benchmark
if (!exit_requested && world_loaded) { if (!exit_requested && world_loaded) {
// Get Time // Get Time
long long int current_time = get_time() - world_loaded_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; 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 // Rotate Player
static long long int rotate_point = BENCHMARK_ROTATION_INTERVAL; 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 // Disable Special Behavior After Requesting Exit
exit_requested = true; 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_nanosecond = ((double) current_frames) / ((double) current_time);
static double frames_per_second = frames_per_nanosecond * NANOSECONDS_IN_SECOND; 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() { void init_benchmark() {
if (active) { if (active) {
misc_run_on_update(Minecraft_update_injection); misc_run_on_update(Minecraft_update_injection);
// Track Ticks
misc_run_on_tick(Minecraft_tick_injection);
// Disable Interaction // Disable Interaction
media_set_interactable(0); media_set_interactable(0);
// Disable V-Sync // Disable V-Sync

View File

@ -107,7 +107,7 @@ static void send_queued_messages(unsigned char *minecraft) {
pthread_mutex_lock(&queue_mutex); 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 // 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(); 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 // Unlock UI
media_set_interactable(1); media_set_interactable(1);
} }

View File

@ -26,7 +26,7 @@ __attribute__((constructor)) static void init() {
init_options(); init_options();
init_chat(); init_chat();
init_home(); init_home();
#if !defined(MCPI_SERVER_MODE) && !defined(MCPI_HEADLESS_MODE) #ifndef MCPI_SERVER_MODE
init_benchmark(); init_benchmark();
#endif #endif
} }

View File

@ -26,7 +26,7 @@ void init_death();
void init_options(); void init_options();
void init_chat(); void init_chat();
void init_home(); void init_home();
#if !defined(MCPI_SERVER_MODE) && !defined(MCPI_HEADLESS_MODE) #ifndef MCPI_SERVER_MODE
void init_benchmark(); void init_benchmark();
#endif #endif

View File

@ -35,22 +35,6 @@ static void Gui_addMessage_injection(unsigned char *gui, std::string const& text
free(new_message); 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 // Print Progress Reports
static int last_progress = -1; static int last_progress = -1;
static const char *last_message = NULL; static const char *last_message = NULL;

View File

@ -25,7 +25,7 @@ static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injectio
return ret; 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> &get_misc_update_functions() {
static std::vector<misc_update_function_t> functions; static std::vector<misc_update_function_t> functions;
return 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) { void misc_run_on_update(misc_update_function_t function) {
get_misc_update_functions().push_back(function); get_misc_update_functions().push_back(function);
} }
// Handle Custom Update Behavior // Handle Custom Update Behavior
static void Minecraft_update_injection(unsigned char *minecraft) { static void Minecraft_update_injection(unsigned char *minecraft) {
// Call Original Method // Call Original Method
(*Minecraft_update)(minecraft); (*Minecraft_update)(minecraft);
// Run Input Tick Functions // Run Functions
for (misc_update_function_t function : get_misc_update_functions()) { for (misc_update_function_t function : get_misc_update_functions()) {
(*function)(minecraft); (*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 // Add Missing Buttons To Pause Menu
static void PauseScreen_init_injection(unsigned char *screen) { static void PauseScreen_init_injection(unsigned char *screen) {
// Call Original Method // Call Original Method
@ -88,6 +106,8 @@ void _init_misc_cpp() {
// Handle Custom Update Behavior // Handle Custom Update Behavior
overwrite_calls((void *) Minecraft_update, (void *) Minecraft_update_injection); 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 // Fix Pause Menu
if (feature_has("Fix Pause Menu", server_disabled)) { if (feature_has("Fix Pause Menu", server_disabled)) {

View File

@ -6,6 +6,7 @@ extern "C" {
typedef void (*misc_update_function_t)(unsigned char *minecraft); typedef void (*misc_update_function_t)(unsigned char *minecraft);
void misc_run_on_update(misc_update_function_t function); 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); void Level_saveLevelData_injection(unsigned char *level);

View File

@ -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 // Get ServerSideNetworkHandler From Minecraft
static unsigned char *get_server_side_network_handler(unsigned char *minecraft) { static unsigned char *get_server_side_network_handler(unsigned char *minecraft) {
return *(unsigned char **) (minecraft + Minecraft_network_handler_property_offset); 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 bool stdin_buffer_complete = false;
static volatile char *stdin_buffer = NULL; static volatile char *stdin_buffer = NULL;
static void *read_stdin_thread(__attribute__((unused)) void *data) { static void *read_stdin_thread(__attribute__((unused)) void *data) {
// Check If STDIN Is A TTY // Loop
if (isatty(fileno(stdin))) { while (1) {
// Loop int bytes_available;
while (1) { if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) {
int bytes_available; bytes_available = 0;
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++) { for (int i = 0; i < bytes_available; i++) {
if (!stdin_buffer_complete) { if (!stdin_buffer_complete) {
// Read Data // Read Data
int x = fgetc(stdin); char x = buffer[i];
if (x != EOF) { if (x == '\n') {
if (x == '\n') { if (stdin_buffer == NULL) {
if (stdin_buffer == NULL) { stdin_buffer = (volatile char *) malloc(1);
stdin_buffer = strdup(""); stdin_buffer[0] = '\0';
}
stdin_buffer_complete = true;
} else {
string_append((char **) &stdin_buffer, "%c", (char) x);
}
} }
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 say_command("say ");
static std::string kill_command("kill "); static std::string kill_command("kill ");
static std::string list_command("list"); static std::string list_command("list");
static std::string tps_command("tps");
static std::string stop_command("stop"); static std::string stop_command("stop");
static std::string help_command("help"); static std::string help_command("help");
if (!is_whitelist() && data.rfind(ban_command, 0) == 0) { if (!is_whitelist() && data.rfind(ban_command, 0) == 0) {
@ -301,6 +323,9 @@ static void handle_commands(unsigned char *minecraft) {
// List Players // List Players
INFO("All Players:"); INFO("All Players:");
find_players(minecraft, "", list_callback, true); find_players(minecraft, "", list_callback, true);
} else if (data == tps_command) {
// Print TPS
INFO("TPS: %f", tps);
} else if (data == stop_command) { } else if (data == stop_command) {
// Stop Server // Stop Server
compat_request_exit(); compat_request_exit();
@ -312,6 +337,7 @@ static void handle_commands(unsigned char *minecraft) {
INFO(" kill <Username> - Kill All Players With Specifed Username"); INFO(" kill <Username> - Kill All Players With Specifed Username");
INFO(" say <Message> - Print Specified Message To Chat"); INFO(" say <Message> - Print Specified Message To Chat");
INFO(" list - List All Players"); INFO(" list - List All Players");
INFO(" tps - Print TPS");
INFO(" stop - Stop Server"); INFO(" stop - Stop Server");
INFO(" help - Print This Message"); INFO(" help - Print This Message");
} else { } else {
@ -523,6 +549,9 @@ static void server_init() {
// Log IPs // Log IPs
overwrite_call((void *) 0x75e54, (void *) ServerSideNetworkHandler_onReady_ClientGeneration_ServerSideNetworkHandler_popPendingPlayer_injection); overwrite_call((void *) 0x75e54, (void *) ServerSideNetworkHandler_onReady_ClientGeneration_ServerSideNetworkHandler_popPendingPlayer_injection);
// Track TPS
misc_run_on_tick(Minecraft_tick_injection);
// Start Reading STDIN // Start Reading STDIN
pthread_t read_stdin_thread_obj; pthread_t read_stdin_thread_obj;
pthread_create(&read_stdin_thread_obj, NULL, read_stdin_thread, NULL); pthread_create(&read_stdin_thread_obj, NULL, read_stdin_thread, NULL);

View File

@ -42,13 +42,13 @@ static void TextEditScreen_updateEvents_injection(unsigned char *screen) {
(*Screen_updateEvents)(screen); (*Screen_updateEvents)(screen);
if (*(char *)(screen + 4) == '\0') { if (*(char *)(screen + 4) == '\0') {
uint32_t vtable = *((uint32_t *) screen); unsigned char *vtable = *(unsigned char **) screen;
for (char key : input) { for (char key : input) {
if (key == BACKSPACE_KEY) { if (key == BACKSPACE_KEY) {
// Handle Backspace // Handle Backspace
(*(Screen_keyPressed_t *) (vtable + Screen_keyPressed_vtable_offset))(screen, BACKSPACE_KEY); (*(Screen_keyPressed_t *) (vtable + Screen_keyPressed_vtable_offset))(screen, BACKSPACE_KEY);
} else { } else {
// Handle Nrmal Key // Handle Normal Key
(*(Screen_keyboardNewChar_t *) (vtable + Screen_keyboardNewChar_vtable_offset))(screen, key); (*(Screen_keyboardNewChar_t *) (vtable + Screen_keyboardNewChar_vtable_offset))(screen, key);
} }
} }

View File

@ -7,14 +7,12 @@
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <symbols/minecraft.h> #include <symbols/minecraft.h>
#include "../misc/misc.h"
#include "../feature/feature.h" #include "../feature/feature.h"
#include "../init/init.h" #include "../init/init.h"
// Animated Water // Animated Water
static void Minecraft_tick_injection(unsigned char *minecraft, int32_t param_1, int32_t param_2) { static void Minecraft_tick_injection(unsigned char *minecraft) {
// Call Original Method
(*Minecraft_tick)(minecraft, param_1, param_2);
// Tick Dynamic Textures // Tick Dynamic Textures
unsigned char *textures = *(unsigned char **) (minecraft + Minecraft_textures_property_offset); unsigned char *textures = *(unsigned char **) (minecraft + Minecraft_textures_property_offset);
if (textures != NULL) { if (textures != NULL) {
@ -77,7 +75,8 @@ static void get_texture_size(GLint id, GLsizei *width, GLsizei *height) {
++it; ++it;
} }
// Not Found // Not Found
ERR("Unable To Find Size Of Texture: %i", id); *width = 0;
*height = 0;
} }
// Scale Texture (Remember To Free) // Scale Texture (Remember To Free)
@ -167,7 +166,7 @@ static void Textures_tick_glTexSubImage2D_injection(GLenum target, GLint level,
void init_textures() { void init_textures() {
// Tick Dynamic Textures (Animated Water) // Tick Dynamic Textures (Animated Water)
if (feature_has("Animated Water", server_disabled)) { 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 // Scale Animated Textures

View File

@ -108,18 +108,23 @@ const afterBundle = [
'find ./AppDir/usr/bin -maxdepth 1 -name \'qemu-*\' -a ! -name \'qemu-arm\' -delete' '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 // Runtime
const runtime = { const runtime = {
env: mode === 'client' ? { env: env,
// 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,
preserve: arch !== 'armhf' ? [ preserve: arch !== 'armhf' ? [
// On non-ARM32 systems, an ARM32 linker is embedded, this // On non-ARM32 systems, an ARM32 linker is embedded, this
// prevents AppImage-Builder from modifying ARM32 binaries // prevents AppImage-Builder from modifying ARM32 binaries