Browse Source

Split Headless And Server Mode Code

pull/23/head
TheBrokenRail 3 months ago
parent
commit
a762654e35
  1. 4
      CMakeLists.txt
  2. 3
      docs/BUILDING.md
  3. 1
      libreborn/include/libreborn/log.h
  4. 4
      media-layer/CMakeLists.txt
  5. 2
      media-layer/core/CMakeLists.txt
  6. 42
      media-layer/core/src/media.c
  7. 56
      media-layer/core/src/screenshot.c
  8. 2
      media-layer/include/libreborn/media-layer/core.h
  9. 6
      media-layer/proxy/CMakeLists.txt
  10. 11
      media-layer/proxy/src/media-layer-core.c
  11. 6
      media-layer/stubs/CMakeLists.txt
  12. 2
      media-layer/stubs/src/EGL.c
  13. 2
      media-layer/stubs/src/X11.c
  14. 4
      mods/CMakeLists.txt
  15. 5
      mods/src/camera/camera.cpp
  16. 3
      mods/src/compat/compat.c
  17. 17
      mods/src/home/home.c

4
CMakeLists.txt

@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.13.0)
# Specify Options
option(MCPI_USE_MEDIA_LAYER_PROXY "Whether To Enable The Media Layer Proxy" FALSE)
option(MCPI_SERVER_MODE "Server Mode" FALSE)
option(MCPI_HEADLESS_MODE "Headless Mode" ${MCPI_SERVER_MODE})
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")
@ -95,6 +96,9 @@ set(CMAKE_CXX_STANDARD 11)
if(MCPI_SERVER_MODE)
add_definitions(-DMCPI_SERVER_MODE)
endif()
if(MCPI_HEADLESS_MODE)
add_definitions(-DMCPI_HEADLESS_MODE)
endif()
# Version
file(STRINGS VERSION VERSION)

3
docs/BUILDING.md

@ -8,6 +8,9 @@
* ``MCPI_SERVER_MODE``
* ``ON``: Enable Server Mode
* ``OFF`` (Default): Disable Server Mode
* ``MCPI_HEADLESS_MODE``
* ``ON`` (Default In Server Mode): Enable Headless Mode
* ``OFF`` (Default In Client Mode): Disable Headless Mode
* ``MCPI_USE_MEDIA_LAYER_PROXY``
* ``ON``: Enable The Media Layer Proxy
* ``OFF`` (Default): Disable The Media Layer Proxy

1
libreborn/include/libreborn/log.h

@ -7,3 +7,4 @@
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", __VA_ARGS__); }
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", __VA_ARGS__); }
#define ERR(format, ...) { fprintf(stderr, "[ERR]: " format "\n", __VA_ARGS__); exit(EXIT_FAILURE); }
#define IMPOSSIBLE() ERR("(%s:%i) This Should Never Be Called", __FILE__, __LINE__)

4
media-layer/CMakeLists.txt

@ -2,8 +2,8 @@ project(media-layer)
# Check Options
if(MCPI_USE_MEDIA_LAYER_PROXY)
if(MCPI_SERVER_MODE)
message(FATAL_ERROR "Server Mode With Media Layer Proxy Configuration Is Redundant")
if(MCPI_HEADLESS_MODE)
message(FATAL_ERROR "Headless Mode With Media Layer Proxy Configuration Is Redundant")
endif()
if(MCPI_BUILD_MODE STREQUAL "both")
message(FATAL_ERROR "Media Layer Proxy Is Redundant When Building ARM And Native Components In The Same Build")

2
media-layer/core/CMakeLists.txt

@ -18,7 +18,7 @@ endif()
if(TARGET media-layer-core)
# Link
target_link_libraries(media-layer-core media-layer-headers reborn-headers pthread dl)
if(NOT MCPI_SERVER_MODE)
if(NOT MCPI_HEADLESS_MODE)
# Find GLFW
find_package(glfw3 3.3 REQUIRED)
# Find FreeImage

42
media-layer/core/src/media.c

@ -3,17 +3,17 @@
#include <SDL/SDL.h>
#include <GLES/gl.h>
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#endif // #ifndef MCPI_SERVER_MODE
#endif // #ifndef MCPI_HEADLESS_MODE
#include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h>
#include <libreborn/media-layer/internal.h>
// GLFW Code Not Needed In Server Mode
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
static GLFWwindow *glfw_window;
@ -194,12 +194,12 @@ static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute_
}
}
#endif // #ifndef MCPI_SERVER_MODE
#endif // #ifndef MCPI_HEADLESS_MODE
// Init GLFW
void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *icon) {
// Don't Enable GLFW In Server Mode
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
glfwSetErrorCallback(glfw_error);
if (!glfwInit()) {
@ -229,20 +229,20 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
glfwSetScrollCallback(glfw_window, glfw_scroll);
glfwMakeContextCurrent(glfw_window);
#else // #ifndef MCPI_SERVER_MODE
#else // #ifndef MCPI_HEADLESS_MODE
(void) title; // Mark As Used
#endif // #ifndef MCPI_SERVER_MODE
#endif // #ifndef MCPI_HEADLESS_MODE
}
void media_swap_buffers() {
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
// Don't Swap Buffers In A Context-Less Window
glfwSwapBuffers(glfw_window);
#endif // #ifndef MCPI_SERVER_MODE
#endif // #ifndef MCPI_HEADLESS_MODE
}
// Fullscreen Not Needed In Server Mode
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
static int is_fullscreen = 0;
// Old Size And Position To Use When Exiting Fullscreen
@ -271,15 +271,15 @@ void media_toggle_fullscreen() {
}
is_fullscreen = !is_fullscreen;
}
#else // #ifndef MCPI_SERVER_MODE
#else // #ifndef MCPI_HEADLESS_MODE
void media_toggle_fullscreen() {
}
#endif // #ifndef MCPI_SERVER_MODE
#endif // #ifndef MCPI_HEADLESS_MODE
// Intercept SDL Events
void _media_handle_SDL_PollEvent() {
// GLFW Is Disabled In Server Mode
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
// Process GLFW Events
glfwPollEvents();
@ -290,16 +290,16 @@ void _media_handle_SDL_PollEvent() {
SDL_PushEvent(&event);
glfwSetWindowShouldClose(glfw_window, GLFW_FALSE);
}
#endif // #ifndef MCPI_SERVER_MODE
#endif // #ifndef MCPI_HEADLESS_MODE
}
// Terminate GLFW
void media_cleanup() {
// GLFW Is Disabled In Server Mode
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
glfwDestroyWindow(glfw_window);
glfwTerminate();
#endif // #ifndef MCPI_SERVER_MODE
#endif // #ifndef MCPI_HEADLESS_MODE
}
// Store Cursor State
@ -307,7 +307,7 @@ static int cursor_grabbed = 0;
static int cursor_visible = 1;
// Update GLFW Cursor State (Client Only)
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
static void update_glfw_cursor() {
// Store Old Mode
int old_mode = glfwGetInputMode(glfw_window, GLFW_CURSOR);
@ -352,7 +352,7 @@ SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode) {
cursor_grabbed = 0;
}
// Update Cursor GLFW State (Client Only)
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
update_glfw_cursor();
#endif
// Return
@ -372,7 +372,7 @@ int SDL_ShowCursor(int toggle) {
cursor_visible = 0;
}
// Update Cursor GLFW State (Client Only)
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
update_glfw_cursor();
#endif
// Return
@ -381,12 +381,12 @@ int SDL_ShowCursor(int toggle) {
// Get Framebuffer Size
void media_get_framebuffer_size(int *width, int *height) {
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
if (glfw_window != NULL) {
glfwGetFramebufferSize(glfw_window, width, height);
return;
}
#endif // #ifndef MCPI_SERVER_MODE
#endif // #ifndef MCPI_HEADLESS_MODE
*width = DEFAULT_WIDTH;
*height = DEFAULT_HEIGHT;
}

56
media-layer/core/src/screenshot.c

@ -1,5 +1,5 @@
// Screenshot Code Is Useless In Server Mode
#ifndef MCPI_SERVER_MODE
#ifndef MCPI_HEADLESS_MODE
#include <stdlib.h>
#include <stdio.h>
@ -16,22 +16,41 @@
#include <libreborn/libreborn.h>
#include <libreborn/media-layer/core.h>
// Ensure Screenshots Folder Exists
static void ensure_screenshots_folder(char *screenshots) {
// Check Screenshots Folder
struct stat obj;
if (stat(screenshots, &obj) != 0 || !S_ISDIR(obj.st_mode)) {
// Create Screenshots Folder
int ret = mkdir(screenshots, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (ret != 0) {
// Unable To Create Folder
ERR("Error Creating Directory: %s: %s", screenshots, strerror(errno));
}
}
}
// 4 (Year) + 1 (Hyphen) + 2 (Month) + 1 (Hyphen) + 2 (Day) + 1 (Underscore) + 2 (Hour) + 1 (Period) + 2 (Minute) + 1 (Period) + 2 (Second) + 1 (Null Terminator)
#define TIME_SIZE 20
// Take Screenshot
void media_take_screenshot() {
void media_take_screenshot(char *home) {
// Get Directory
char *screenshots = NULL;
safe_asprintf(&screenshots, "%s/screenshots", home);
// Get Timestamp
time_t rawtime;
struct tm *timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
char time[TIME_SIZE];
strftime(time, TIME_SIZE, "%Y-%m-%d_%H.%M.%S", timeinfo);
char *screenshots = NULL;
safe_asprintf(&screenshots, "%s/.minecraft-pi/screenshots", getenv("HOME"));
// Ensure Screenshots Folder Exists
ensure_screenshots_folder(screenshots);
// Prevent Overwriting Screenshots
int num = 1;
char *file = NULL;
safe_asprintf(&file, "%s/%s.png", screenshots, time);
@ -42,6 +61,7 @@ void media_take_screenshot() {
num++;
}
// Get Image Size
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
int x = viewport[0];
@ -49,12 +69,15 @@ void media_take_screenshot() {
int width = viewport[2];
int height = viewport[3];
// Get Line Size
int line_size = width * 3;
int size = height * line_size;
// Read Pixels
unsigned char pixels[size];
glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
// Handle Little Endian Systems
#if __BYTE_ORDER == __LITTLE_ENDIAN
// Swap Red And Blue
for (int i = 0; i < (size / 3); i++) {
@ -66,6 +89,7 @@ void media_take_screenshot() {
}
#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);
if (!FreeImage_Save(FIF_PNG, image, file, 0)) {
INFO("Screenshot Failed: %s", file);
@ -74,6 +98,7 @@ void media_take_screenshot() {
}
FreeImage_Unload(image);
// Free
free(file);
free(screenshots);
}
@ -82,27 +107,10 @@ void media_take_screenshot() {
__attribute__((constructor)) static void init() {
// Init FreeImage
FreeImage_Initialise(0);
// Screenshots Folder
char *screenshots_folder = NULL;
safe_asprintf(&screenshots_folder, "%s/.minecraft-pi/screenshots", getenv("HOME"));
{
// Check Screenshots Folder
struct stat obj;
if (stat(screenshots_folder, &obj) != 0 || !S_ISDIR(obj.st_mode)) {
// Create Screenshots Folder
int ret = mkdir(screenshots_folder, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (ret != 0) {
// Unable To Create Folder
ERR("Error Creating Directory: %s: %s", screenshots_folder, strerror(errno));
}
}
}
free(screenshots_folder);
}
#else // #ifndef MCPI_SERVER_MODE
#else // #ifndef MCPI_HEADLESS_MODE
void media_take_screenshot() {
// NOP
}
#endif // #ifndef MCPI_SERVER_MODE
#endif // #ifndef MCPI_HEADLESS_MODE

2
media-layer/include/libreborn/media-layer/core.h

@ -8,7 +8,7 @@ extern "C" {
#define DEFAULT_WIDTH 840
#define DEFAULT_HEIGHT 480
void media_take_screenshot();
void media_take_screenshot(char *home);
void media_toggle_fullscreen();
void media_swap_buffers();
void media_cleanup();

6
media-layer/proxy/CMakeLists.txt

@ -1,9 +1,3 @@
# Component Details:
# Media Layer Proxy
#
# This components proxies multi-media calls from the ARM
# MCPI to the native architecture by using a UNIX socket.
project(media-layer-proxy)
# Configuration

11
media-layer/proxy/src/media-layer-core.c

@ -284,15 +284,22 @@ CALL(6, SDL_ShowCursor, int, (int32_t toggle)) {
#endif
}
CALL(7, media_take_screenshot, void, ()) {
CALL(7, media_take_screenshot, void, (char *home)) {
#if defined(MEDIA_LAYER_PROXY_SERVER)
// Lock Proxy
start_proxy_call();
// Arguments
write_string(home);
// Release Proxy
end_proxy_call();
#else
char *home = read_string();
// Run
media_take_screenshot();
media_take_screenshot(home);
// Free
free(home);
#endif
}

6
media-layer/stubs/CMakeLists.txt

@ -21,21 +21,21 @@ if(BUILD_ARM_COMPONENTS)
target_link_libraries(X11 reborn-headers media-layer-headers)
set_target_properties(X11 PROPERTIES SOVERSION "6")
# Install
if(MCPI_SERVER_MODE OR MCPI_USE_MEDIA_LAYER_PROXY)
if(MCPI_HEADLESS_MODE OR MCPI_USE_MEDIA_LAYER_PROXY)
install(TARGETS EGL X11 DESTINATION "${MCPI_LIB_DIR}")
else()
install(TARGETS EGL X11 DESTINATION "${MCPI_FALLBACK_LIB_DIR}") # Place At The End Of LD_LIBRARY_PATH
endif()
# Install GLESv1_CM Stubs In Server Mode
if(MCPI_SERVER_MODE)
if(MCPI_HEADLESS_MODE)
install(TARGETS GLESv1_CM DESTINATION "${MCPI_LIB_DIR}")
endif()
# MCPI Depends On GLESv2, But Uses GLESv1_CM
install_symlink("libGLESv1_CM.so.1" "${MCPI_LIB_DIR}/libGLESv2.so")
# Prevent MCPI From Linking To The Legacy GL Driver When Directly Linking To GL
if(NOT MCPI_SERVER_MODE AND NOT MCPI_USE_MEDIA_LAYER_PROXY)
if(NOT MCPI_HEADLESS_MODE AND NOT MCPI_USE_MEDIA_LAYER_PROXY)
# Symlinks
install_symlink("/usr/lib/arm-linux-gnueabihf/libEGL.so.1" "${MCPI_LIB_DIR}/libEGL.so")
install_symlink("/usr/lib/arm-linux-gnueabihf/libGLESv1_CM.so.1" "${MCPI_LIB_DIR}/libGLESv1_CM.so.1")

2
media-layer/stubs/src/EGL.c

@ -2,8 +2,6 @@
#include <libreborn/libreborn.h>
#define IMPOSSIBLE() ERR("(%s:%i) This Should Never Be Called", __FILE__, __LINE__)
// EGL Is Replaced With GLFW
EGLDisplay eglGetDisplay(__attribute__((unused)) NativeDisplayType native_display) {

2
media-layer/stubs/src/X11.c

@ -2,8 +2,6 @@
#include <libreborn/libreborn.h>
#define IMPOSSIBLE() ERR("(%s:%i) This Should Never Be Called", __FILE__, __LINE__)
// Raw X11 Is Replaced With GLFW
int XTranslateCoordinates(__attribute__((unused)) void *display, __attribute__((unused)) XID src_w, __attribute__((unused)) XID dest_w, __attribute__((unused)) int src_x, __attribute__((unused)) int src_y, __attribute__((unused)) int *dest_x_return, __attribute__((unused)) int *dest_y_return, __attribute__((unused)) XID *child_return) {

4
mods/CMakeLists.txt

@ -8,7 +8,7 @@ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
## Mods
add_library(compat SHARED src/compat/compat.c src/compat/egl.c src/compat/x11.c)
target_link_libraries(compat feature input chat sign media-layer-core dl)
target_link_libraries(compat feature input chat sign media-layer-core home dl)
add_library(readdir SHARED src/readdir/readdir.c)
@ -27,7 +27,7 @@ else()
endif()
add_library(camera SHARED src/camera/camera.cpp)
target_link_libraries(camera reborn media-layer-core feature)
target_link_libraries(camera reborn media-layer-core feature home)
add_library(game-mode SHARED src/game-mode/game-mode.c src/game-mode/game-mode.cpp)
target_link_libraries(game-mode reborn feature)

5
mods/src/camera/camera.cpp

@ -2,12 +2,13 @@
#include <libreborn/media-layer/core.h>
#include <libreborn/minecraft.h>
#include "../init/init.h"
#include "../feature/feature.h"
#include "../home/home.h"
#include "../init/init.h"
// Take Screenshot Using TripodCamera
static void AppPlatform_linux_saveScreenshot_injection(__attribute__((unused)) unsigned char *app_platform, __attribute__((unused)) std::string const& path, __attribute__((unused)) int32_t width, __attribute__((unused)) int32_t height) {
media_take_screenshot();
media_take_screenshot(home_get());
}
// Enable TripodCameraRenderer

3
mods/src/compat/compat.c

@ -9,6 +9,7 @@
#include "../input/input.h"
#include "../sign/sign.h"
#include "../chat/chat.h"
#include "../home/home.h"
#include "../init/init.h"
#include "compat.h"
@ -53,7 +54,7 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
media_toggle_fullscreen();
handled = 1;
} else if (event->key.keysym.sym == SDLK_F2) {
media_take_screenshot();
media_take_screenshot(home_get());
handled = 1;
} else if (event->key.keysym.sym == SDLK_F1) {
input_hide_gui();

17
mods/src/home/home.c

@ -13,15 +13,24 @@
#define NEW_PATH ""
// Store Launch Directory
static char *launch_directory = NULL;
static char *get_launch_directory() {
static char *launch_directory = NULL;
if (launch_directory == NULL) {
launch_directory = getcwd(NULL, 0);
}
return launch_directory;
}
__attribute__((constructor)) static void init_launch_directory() {
launch_directory = getcwd(NULL, 0);
get_launch_directory();
}
__attribute__((destructor)) static void free_launch_directory() {
free(get_launch_directory());
}
// Pretend $HOME Is Launch Directory
HOOK(getenv, char *, (const char *name)) {
if (strcmp(name, "HOME") == 0) {
return launch_directory;
return get_launch_directory();
} else {
ensure_getenv();
return (*real_getenv)(name);
@ -34,7 +43,7 @@ char *home_get() {
static char *dir = NULL;
// Load
if (dir == NULL) {
safe_asprintf(&dir, "%s/" NEW_PATH, getenv("HOME"));
safe_asprintf(&dir, "%s" NEW_PATH, getenv("HOME"));
}
// Return
return dir;

Loading…
Cancel
Save