added args and input, played around with raylib as static lib but reverted to dynamic, tried to fix objective-c runtime duplicate sumbol warning but failed, should be fine, added cmake option for raylib release

This commit is contained in:
Harvey Fong 2025-04-16 19:12:58 -06:00
parent fae5d540f6
commit 80dce65014
3 changed files with 130 additions and 42 deletions

View File

@ -31,13 +31,15 @@ apt install libx11-dev
apt install xorg-dev apt install xorg-dev
``` ```
cmake -DBUILD_SHARED_LIBS=OFF -DUSE_EXTERNAL_GLFW=OFF ..
``` ```
cd workdir cd workdir
git clone https://github.com/raysan5/raylib.git git clone https://github.com/raysan5/raylib.git
cd raylib/src mkdir -p raylib/build
make cd raylib/build
cd ../examples /Applications/CMake.app/Contents/bin/cmake -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release ..
make make -j4
cd ../.. cd ../..
git clone https://github.com/raysan5/raygui.git git clone https://github.com/raysan5/raygui.git
git clone https://github.com/oomer/poomer-raylib-bella_onimage.git git clone https://github.com/oomer/poomer-raylib-bella_onimage.git

View File

@ -8,6 +8,8 @@ BUILD_TYPE ?= release# Default to release build if not specified
BELLA_SDK_PATH = ../bella_engine_sdk BELLA_SDK_PATH = ../bella_engine_sdk
RAYGUI_PATH = ../raygui RAYGUI_PATH = ../raygui
RAYLIB_PATH = ../raylib RAYLIB_PATH = ../raylib
# Path to dynamic raylib library
RAYLIB_DYLIB_PATH = ../raylib/build/raylib
OBJ_DIR = obj/$(PLATFORM)/$(BUILD_TYPE) OBJ_DIR = obj/$(PLATFORM)/$(BUILD_TYPE)
BIN_DIR = bin/$(PLATFORM)/$(BUILD_TYPE) BIN_DIR = bin/$(PLATFORM)/$(BUILD_TYPE)
OUTPUT_FILE = $(BIN_DIR)/$(EXECUTABLE_NAME) OUTPUT_FILE = $(BIN_DIR)/$(EXECUTABLE_NAME)
@ -17,6 +19,7 @@ ifeq ($(PLATFORM), Darwin)
# macOS configuration # macOS configuration
SDK_LIB_EXT = dylib SDK_LIB_EXT = dylib
SDK_LIB_FILE = lib$(BELLA_SDK_NAME).$(SDK_LIB_EXT) SDK_LIB_FILE = lib$(BELLA_SDK_NAME).$(SDK_LIB_EXT)
# Dynamic raylib library
RAYLIB_LIB_NAME = libraylib.$(SDK_LIB_EXT) RAYLIB_LIB_NAME = libraylib.$(SDK_LIB_EXT)
MACOS_SDK_PATH = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk MACOS_SDK_PATH = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
@ -25,7 +28,7 @@ ifeq ($(PLATFORM), Darwin)
CXX = clang++ CXX = clang++
# Architecture flags # Architecture flags
ARCH_FLAGS = -arch x86_64 -arch arm64 -mmacosx-version-min=11.0 -isysroot $(MACOS_SDK_PATH) ARCH_FLAGS = -arch x86_64 -arch arm64 -mmacosx-version-min=15.0 -isysroot $(MACOS_SDK_PATH)
# Include paths # Include paths
INCLUDE_PATHS = -I$(BELLA_SDK_PATH)/src \ INCLUDE_PATHS = -I$(BELLA_SDK_PATH)/src \
@ -34,10 +37,12 @@ ifeq ($(PLATFORM), Darwin)
# Library paths # Library paths
SDK_LIB_PATH = $(BELLA_SDK_PATH)/lib SDK_LIB_PATH = $(BELLA_SDK_PATH)/lib
RAYLIB_LIB_PATH = $(RAYLIB_PATH)/src # Updated path to dynamic raylib library
RAYLIB_LIB_PATH = $(RAYLIB_DYLIB_PATH)
LIB_PATHS = -L$(SDK_LIB_PATH) -L$(RAYLIB_LIB_PATH) LIB_PATHS = -L$(SDK_LIB_PATH) -L$(RAYLIB_LIB_PATH)
# Platform-specific libraries # Platform-specific libraries
# For dynamic library, we don't need to explicitly link all of raylib's dependencies
LIBRARIES = -l$(BELLA_SDK_NAME) \ LIBRARIES = -l$(BELLA_SDK_NAME) \
-lraylib \ -lraylib \
-lm \ -lm \
@ -47,10 +52,11 @@ ifeq ($(PLATFORM), Darwin)
-framework AppKit \ -framework AppKit \
-framework IOKit \ -framework IOKit \
-framework CoreGraphics \ -framework CoreGraphics \
-framework CoreVideo \
-framework Foundation -framework Foundation
# Linking flags # Linking flags
LINKER_FLAGS = -mmacosx-version-min=11.0 \ LINKER_FLAGS = -mmacosx-version-min=15.0 \
-isysroot $(MACOS_SDK_PATH) \ -isysroot $(MACOS_SDK_PATH) \
-framework Cocoa \ -framework Cocoa \
-framework IOKit \ -framework IOKit \
@ -60,11 +66,13 @@ ifeq ($(PLATFORM), Darwin)
-fvisibility=hidden \ -fvisibility=hidden \
-O5 \ -O5 \
-rpath @executable_path \ -rpath @executable_path \
-rpath @loader_path \
-weak_library $(SDK_LIB_PATH)/libvulkan.dylib -weak_library $(SDK_LIB_PATH)/libvulkan.dylib
else else
# Linux configuration # Linux configuration
SDK_LIB_EXT = so SDK_LIB_EXT = so
SDK_LIB_FILE = lib$(BELLA_SDK_NAME).$(SDK_LIB_EXT) SDK_LIB_FILE = lib$(BELLA_SDK_NAME).$(SDK_LIB_EXT)
# Dynamic raylib library
RAYLIB_LIB_NAME = libraylib.$(SDK_LIB_EXT) RAYLIB_LIB_NAME = libraylib.$(SDK_LIB_EXT)
# Compiler settings # Compiler settings
@ -81,11 +89,13 @@ else
# Library paths # Library paths
SDK_LIB_PATH = $(BELLA_SDK_PATH)/lib SDK_LIB_PATH = $(BELLA_SDK_PATH)/lib
RAYLIB_LIB_PATH = $(RAYLIB_PATH)/src # Updated path to dynamic raylib library
RAYLIB_LIB_PATH = $(RAYLIB_DYLIB_PATH)
SYSTEM_LIB_PATH = /usr/lib/x86_64-linux-gnu/ SYSTEM_LIB_PATH = /usr/lib/x86_64-linux-gnu/
LIB_PATHS = -L$(SDK_LIB_PATH) -L$(RAYLIB_LIB_PATH) LIB_PATHS = -L$(SDK_LIB_PATH) -L$(RAYLIB_LIB_PATH)
# Platform-specific libraries # Platform-specific libraries
# For dynamic library, we don't need to explicitly link all dependencies of raylib
LIBRARIES = -l$(BELLA_SDK_NAME) \ LIBRARIES = -l$(BELLA_SDK_NAME) \
-lraylib \ -lraylib \
-lm \ -lm \
@ -106,16 +116,24 @@ endif
# Build type specific flags # Build type specific flags
ifeq ($(BUILD_TYPE), debug) ifeq ($(BUILD_TYPE), debug)
ifeq ($(PLATFORM), Darwin)
CPP_DEFINES = -D_DEBUG -DDL_USE_SHARED CPP_DEFINES = -D_DEBUG -DDL_USE_SHARED
else
CPP_DEFINES = -D_DEBUG -DDL_USE_SHARED
endif
COMMON_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -g -O0 $(INCLUDE_PATHS) COMMON_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -g -O0 $(INCLUDE_PATHS)
else else
ifeq ($(PLATFORM), Darwin)
CPP_DEFINES = -DNDEBUG=1 -DDL_USE_SHARED CPP_DEFINES = -DNDEBUG=1 -DDL_USE_SHARED
else
CPP_DEFINES = -DNDEBUG=1 -DDL_USE_SHARED
endif
COMMON_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -O3 $(INCLUDE_PATHS) COMMON_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -O3 $(INCLUDE_PATHS)
endif endif
# Language-specific flags # Language-specific flags
C_FLAGS = $(COMMON_FLAGS) -std=c11 C_FLAGS = $(COMMON_FLAGS) -std=c11
CXX_FLAGS = $(COMMON_FLAGS) -std=c++11 CXX_FLAGS = $(COMMON_FLAGS) -std=c++17
# Objects # Objects
OBJECTS = $(EXECUTABLE_NAME).o OBJECTS = $(EXECUTABLE_NAME).o
@ -131,6 +149,14 @@ $(OUTPUT_FILE): $(OBJECT_FILES)
$(CXX) -o $@ $^ $(LINKER_FLAGS) $(LIB_PATHS) $(LIBRARIES) $(CXX) -o $@ $^ $(LINKER_FLAGS) $(LIB_PATHS) $(LIBRARIES)
@echo "Copying libraries to $(BIN_DIR)..." @echo "Copying libraries to $(BIN_DIR)..."
@cp $(SDK_LIB_PATH)/$(SDK_LIB_FILE) $(BIN_DIR)/$(SDK_LIB_FILE) @cp $(SDK_LIB_PATH)/$(SDK_LIB_FILE) $(BIN_DIR)/$(SDK_LIB_FILE)
ifeq ($(PLATFORM), Darwin)
@# Copy raylib dylib files preserving symbolic links
@cp -P $(RAYLIB_LIB_PATH)/libraylib.5.5.0.dylib $(BIN_DIR)/
@cp -P $(RAYLIB_LIB_PATH)/libraylib.550.dylib $(BIN_DIR)/
@cp -P $(RAYLIB_LIB_PATH)/libraylib.dylib $(BIN_DIR)/
else
@cp $(RAYLIB_LIB_PATH)/$(RAYLIB_LIB_NAME) $(BIN_DIR)/$(RAYLIB_LIB_NAME)
endif
@echo "Build complete: $(OUTPUT_FILE)" @echo "Build complete: $(OUTPUT_FILE)"
# Add default target # Add default target
@ -141,7 +167,11 @@ clean:
rm -f $(OBJ_DIR)/*.o rm -f $(OBJ_DIR)/*.o
rm -f $(OUTPUT_FILE) rm -f $(OUTPUT_FILE)
rm -f $(BIN_DIR)/$(SDK_LIB_FILE) rm -f $(BIN_DIR)/$(SDK_LIB_FILE)
ifeq ($(PLATFORM), Darwin)
rm -f $(BIN_DIR)/libraylib*.dylib
else
rm -f $(BIN_DIR)/$(RAYLIB_LIB_NAME) rm -f $(BIN_DIR)/$(RAYLIB_LIB_NAME)
endif
rmdir $(OBJ_DIR) 2>/dev/null || true rmdir $(OBJ_DIR) 2>/dev/null || true
rmdir $(BIN_DIR) 2>/dev/null || true rmdir $(BIN_DIR) 2>/dev/null || true

View File

@ -1,3 +1,14 @@
#ifdef __APPLE__
#include <stdlib.h>
#include <stdio.h>
// Force the environment variable using putenv which is more reliable
// This must be set before any Objective-C classes are loaded
static const char* objc_disable_warning = "OBJC_DISABLE_CLASS_DUP_WARNING=YES";
static bool _init_env = (putenv((char*)objc_disable_warning), true);
#endif
#include <chrono>
// Add these definitions before any includes to prevent Windows API conflicts // Add these definitions before any includes to prevent Windows API conflicts
#define NOMINMAX #define NOMINMAX
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
@ -13,6 +24,8 @@
#include <string> #include <string>
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
// Include our fix header first
#include "raylib_objc_fix.h"
// Include raylib directly but don't use its namespace // Include raylib directly but don't use its namespace
#include <raylib.h> #include <raylib.h>
#include <mutex> // For thread synchronization #include <mutex> // For thread synchronization
@ -24,7 +37,8 @@
#include "../bella_engine_sdk/src/bella_sdk/bella_engine.h" // For rendering and scene creation in Bella #include "../bella_engine_sdk/src/bella_sdk/bella_engine.h" // For rendering and scene creation in Bella
#include "../bella_engine_sdk/src/dl_core/dl_main.inl" // Core functionality from the Diffuse Logic engine #include "../bella_engine_sdk/src/dl_core/dl_main.inl" // Core functionality from the Diffuse Logic engine
#include "../oom/oom_license.h" // common misc code #include "../oom/oom_license.h" // common misc code
#include "../oom/oom_bella_long.h" // common misc code #include "../oom/oom_dl_misc.h" // common misc code
#include "../oom/oom_misc.h" // common misc code
#include "../oom/oom_bella_engine.h" // common misc code #include "../oom/oom_bella_engine.h" // common misc code
// Create namespace aliases for raylib types that conflict with bella_sdk // Create namespace aliases for raylib types that conflict with bella_sdk
@ -62,6 +76,10 @@ namespace rl {
} }
// Define a callback type for receiving image data from the path tracer // Define a callback type for receiving image data from the path tracer
// This creates a type alias called 'OnImageCallback' that represents a function that:
// 1. Takes image data (pointer to pixels), width, height, and number of color channels as parameters
// 2. Returns void (nothing)
// std::function is a flexible wrapper that can store any callable object (functions, lambdas, etc.)
using OnImageCallback = std::function<void(const unsigned char* data, int width, int height, int channels)>; using OnImageCallback = std::function<void(const unsigned char* data, int width, int height, int channels)>;
// Structure to hold image data in the queue // Structure to hold image data in the queue
@ -95,7 +113,8 @@ private:
// This is crucial because OpenGL operations (like texture creation) must happen on the main thread // This is crucial because OpenGL operations (like texture creation) must happen on the main thread
std::queue<ImageData> imageQueue; std::queue<ImageData> imageQueue;
// Callback for receiving image data // This member variable stores a function that will be called when new image data arrives
// It will be set to a lambda function in the constructor
OnImageCallback onImageCallback; OnImageCallback onImageCallback;
// Mouse interaction properties // Mouse interaction properties
@ -132,8 +151,10 @@ public:
rl::SetTargetFPS(60); rl::SetTargetFPS(60);
// THREAD SAFETY: Set up the callback that will be called by the path tracer // THREAD SAFETY: Set up the callback that will be called by the path tracer
// Instead of directly updating the image (which would create textures in a non-main thread), // This creates a lambda function (an anonymous function) that captures 'this' pointer
// we queue the image data for later processing by the main thread // so it can access the current instance's methods.
// When this callback is invoked later with image data, it will call queueImageData
// to safely pass the data between threads.
onImageCallback = [this](const unsigned char* data, int width, int height, int channels) { onImageCallback = [this](const unsigned char* data, int width, int height, int channels) {
this->queueImageData(data, width, height, channels); this->queueImageData(data, width, height, channels);
}; };
@ -163,7 +184,9 @@ public:
rl::CloseWindow(); rl::CloseWindow();
} }
// Get the callback that the path tracer should call when new image data is available // This method returns the callback function so other components can use it
// The 'const' means this method doesn't modify the class state
// It returns a copy of the callback function
OnImageCallback getCallback() const { OnImageCallback getCallback() const {
return onImageCallback; return onImageCallback;
} }
@ -486,7 +509,9 @@ public:
// Load an image from file - use raylib's Image type // Load an image from file - use raylib's Image type
rl::Image image = rl::LoadImage(filename); rl::Image image = rl::LoadImage(filename);
if (image.data != NULL) { if (image.data != NULL) {
// Call our callback with the image data // Call our callback function with the image data to process it
// This simulates what would happen when the path tracer produces an image
// It determines the number of channels based on the image format
onImageCallback( onImageCallback(
static_cast<const unsigned char*>(image.data), static_cast<const unsigned char*>(image.data),
image.width, image.width,
@ -503,7 +528,7 @@ public:
// Forward declaration // Forward declaration
class PathTracerPreview; class PathTracerPreview;
// Custom engine observer that connects bsdk's Image to our PathTracerPreview // Custom override engine observer that connects bsdk's Image to our PathTracerPreview
struct BellaEngineObserver : public dl::bella_sdk::EngineObserver { struct BellaEngineObserver : public dl::bella_sdk::EngineObserver {
private: private:
PathTracerPreview* preview; PathTracerPreview* preview;
@ -512,21 +537,21 @@ public:
BellaEngineObserver(PathTracerPreview* preview) : preview(preview) {} BellaEngineObserver(PathTracerPreview* preview) : preview(preview) {}
void onStarted(dl::String pass) override { void onStarted(dl::String pass) override {
//logInfo("Started pass %s", pass.buf()); dl::logInfo("Started pass %s", pass.buf());
} }
void onStatus(dl::String pass, dl::String status) override { void onStatus(dl::String pass, dl::String status) override {
//logInfo("%s [%s]", status.buf(), pass.buf()); dl::logInfo("%s [%s]", status.buf(), pass.buf());
} }
void onProgress(dl::String pass, dl::bella_sdk::Progress progress) override { void onProgress(dl::String pass, dl::bella_sdk::Progress progress) override {
//logInfo("%s [%s]", progress.toString().buf(), pass.buf()); dl::logInfo("%s [%s]", progress.toString().buf(), pass.buf());
} }
// This is the key method that receives images from the bella engine // This is the key method that receives images from the bella engine
// IMPORTANT: This method is called from the bella engine's thread, NOT the main thread // IMPORTANT: This method is called from the bella engine's thread, NOT the main thread
void onImage(dl::String pass, dl::bella_sdk::Image image) override { void onImage(dl::String pass, dl::bella_sdk::Image image) override {
//logInfo("Received image from bella: %d x %d", (int)image.width(), (int)image.height()); dl::logInfo("Received image from bella: %d x %d", (int)image.width(), (int)image.height());
// Get the dimensions of the image // Get the dimensions of the image
int width = (int)image.width(); int width = (int)image.width();
@ -554,11 +579,12 @@ public:
// Direct memory copy for optimal performance // Direct memory copy for optimal performance
std::memcpy(buffer, rgba_data, width * height * 4); std::memcpy(buffer, rgba_data, width * height * 4);
// THREAD SAFETY: Instead of directly calling updateImage (which would create textures in the wrong thread), // THREAD SAFETY: Use the callback to queue data for processing by the main thread
// use the callback which will queue the data for processing by the main thread
try { try {
if (preview->getCallback()) { if (preview->getCallback()) {
// This will queue the data for later processing in the main thread // Get the callback function from the preview object and invoke it
// This passes the image data to the main thread via the callback
// When called, this executes the lambda we defined in the constructor
preview->getCallback()(buffer, width, height, 4); preview->getCallback()(buffer, width, height, 4);
//std::cout << "Image data queued successfully" << std::endl; //std::cout << "Image data queued successfully" << std::endl;
} else { } else {
@ -580,21 +606,55 @@ public:
} }
void onError(dl::String pass, dl::String msg) override { void onError(dl::String pass, dl::String msg) override {
//logError("%s [%s]", msg.buf(), pass.buf()); dl::logError("%s [%s]", msg.buf(), pass.buf());
} }
void onStopped(dl::String pass) override { void onStopped(dl::String pass) override {
//logInfo("Stopped %s", pass.buf()); dl::logInfo("Stopped %s", pass.buf());
} }
}; };
//#include "dl_core/dl_main.inl"
int DL_main(dl::Args& args) int DL_main(dl::Args& args)
{ {
int s_oomBellaLogContext = 0;
dl::subscribeLog(&s_oomBellaLogContext, oom::bella::log);
dl::flushStartupMessages();
args.add("wd", "watchdir", "", "watch directory for changes");
args.add("tp", "thirdparty", "", "prints third party licenses");
args.add("li", "licenseinfo", "", "prints license info");
args.add("i", "input", "", "prints license info");
if (args.helpRequested()) {
std::cout << args.help("poomer-efsw © 2025 Harvey Fong","", "1.0") << std::endl;
return 0;
}
if (args.have("--licenseinfo")) {
std::cout << "poomer-raylib-bella_onimage © 2025 Harvey Fong" << std::endl;
std::cout << oom::license::printLicense() << std::endl;
return 0;
}
if (args.have("--thirdparty")) {
std::cout << oom::license::printBellaSDK() << "\n====\n" << std::endl;
return 0;
}
auto belPath = dl::bella_sdk::previewPath();
if (args.have("--input")) {
belPath = args.value("--input");
if (!dl::fs::exists(belPath)) {
dl::logError("Input file %s does not exist", belPath.buf());
return 1;
}
}
try { try {
SetTraceLogLevel(LOG_ERROR); SetTraceLogLevel(LOG_ERROR);
// Set raylib configuration flags before creating the window // Set raylib configuration flags before creating the window
rl::SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_WINDOW_RESIZABLE); rl::SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_WINDOW_RESIZABLE);
PathTracerPreview preview(400, 400, "poomer-raylib-bella_onimage"); PathTracerPreview preview(400, 400, "poomer-raylib-bella_onimage");
if (!rl::IsWindowReady()) { if (!rl::IsWindowReady()) {
std::cerr << "ERROR: Window initialization failed" << std::endl; std::cerr << "ERROR: Window initialization failed" << std::endl;
@ -611,6 +671,8 @@ int DL_main(dl::Args& args)
} }
//std::cout << "OpenGL context initialized" << std::endl; //std::cout << "OpenGL context initialized" << std::endl;
oom::misc::saveHDRI();
// Initialize the bella engine // Initialize the bella engine
dl::bella_sdk::Engine engine; dl::bella_sdk::Engine engine;
engine.scene().loadDefs(); engine.scene().loadDefs();
@ -625,20 +687,15 @@ int DL_main(dl::Args& args)
engine.subscribe(&engineObserver); engine.subscribe(&engineObserver);
// Get the preview scene with material sphere // Get the preview scene with material sphere
auto path = dl::bella_sdk::previewPath(); if (belPath != "") {
if (path != "") {
//std::cout << "Loading scene: " << path.buf() << std::endl;
//logInfo("Loading scene: %s", path.buf());
// Use the read method to load the scene // Use the read method to load the scene, load left some cruft
if (!engine.scene().read(path)) { if (!engine.scene().read(belPath)) {
std::cerr << "ERROR: Failed to read " << path.buf() << " from " << dl::fs::currentDir().buf() << std::endl; dl::logError("Failed to read %s from %s", belPath.buf(), dl::fs::currentDir().buf());
dl::logError("Failed to read %s from %s", path.buf(), dl::fs::currentDir().buf());
return 1; return 1;
} }
if (!engine.start()) { if (!engine.start()) {
std::cerr << "ERROR: Engine failed to start" << std::endl;
dl::logError("Engine failed to start."); dl::logError("Engine failed to start.");
return 1; return 1;
} }
@ -646,10 +703,9 @@ int DL_main(dl::Args& args)
// Store the initial camera state after the scene is loaded and engine started // Store the initial camera state after the scene is loaded and engine started
//preview.storeInitialCameraTransform(); //preview.storeInitialCameraTransform();
//std::cout << "Engine started successfully" << std::endl;
} else { } else {
// For testing, load a sample image // For testing, load a sample image, seems to have broke
preview.simulateDataFromPathTracer("oomer.png"); preview.simulateDataFromPathTracer("res/DayEnvironmentHDRI019_1K-TONEMAPPED.jpg");
} }
// Run the preview window - this will block until the window is closed // Run the preview window - this will block until the window is closed