From f79b33e8dc3dad32a9c3ed14b304bade2e1a3187 Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Thu, 6 May 2021 16:24:51 -0500 Subject: [PATCH] Begin experimental guile support --- CMakeLists.txt | 14 +++++ core/CMakeLists.txt | 11 +++- core/Scripting/Guile.cpp | 103 +++++++++++++++++++++++++++++++++ core/Scripting/Guile.h | 46 +++++++++++++++ core/couch.cpp | 43 +++++++++++--- demo/scm/exampleworld/main.scm | 5 ++ scripting/CMakeLists.txt | 15 ++++- 7 files changed, 225 insertions(+), 12 deletions(-) create mode 100644 core/Scripting/Guile.cpp create mode 100644 core/Scripting/Guile.h create mode 100644 demo/scm/exampleworld/main.scm diff --git a/CMakeLists.txt b/CMakeLists.txt index 22a151f..9b18612 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,11 +12,25 @@ if (LUA_ENABLED) find_package(Lua REQUIRED) include_directories(${LUA_INCLUDE_DIR}) endif () + +option(GUILE_ENABLED "Guile 2.0 scripting support" OFF) +if (GUILE_ENABLED) + add_compile_definitions(GUILE_SCRIPTING) + ## Find pkg-config + find_package(PkgConfig REQUIRED) + ## Use pkg-config to find Guile 2.0 + pkg_check_modules(GUILE REQUIRED guile-2.0) + include_directories(${GUILE_INCLUDE_DIRS}) +endif () + + + add_executable(couch core/couch.cpp) add_subdirectory(core) target_link_libraries(couch couchlib) target_link_libraries(couch couchlib_luascripting) +target_link_libraries(couch couchlib_guilescripting) add_subdirectory(scripting) if (LUA_ENABLED) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index fc4b42a..20a3479 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -65,12 +65,16 @@ target_sources(couchlib PUBLIC add_library(couchlib_luascripting STATIC) - target_sources(couchlib_luascripting PUBLIC Scripting/Lua.h Scripting/Lua.cpp) target_link_libraries(couchlib_luascripting couchlua) +add_library(couchlib_guilescripting STATIC) +target_sources(couchlib_guilescripting PUBLIC + Scripting/Guile.h + Scripting/Guile.cpp) +target_link_libraries(couchlib_guilescripting couchguile) target_include_directories(couchlib PUBLIC @@ -89,7 +93,10 @@ target_link_libraries(couchlib OpenGL::GL) target_link_libraries(couchlib GLEW::GLEW) if (LUA_ENABLED) target_link_libraries(couchlib_luascripting ${LUA_LIBRARIES}) -endif () +endif () +if (GUILE_ENABLED) + target_link_libraries(couchlib_guilescripting ${GUILE_LIBRARIES}) +endif () target_link_libraries(couchlib ${BULLET_LIBRARIES}) target_link_libraries(couchlib ${ASSIMP_LIBRARY}) diff --git a/core/Scripting/Guile.cpp b/core/Scripting/Guile.cpp new file mode 100644 index 0000000..e0d207f --- /dev/null +++ b/core/Scripting/Guile.cpp @@ -0,0 +1,103 @@ +#include "Guile.h" + +#include "../Util.h" + +void Guile::Initialize() { +#ifdef GUILE_SCRIPTING + language = this; + // Initialize Guile + scm_with_guile(Guile::inner_init, NULL); + + // Bind input functions + Input *input = Input::GetInstance(); + if (HasHook("onkey")) { + input->keyHandlers.push_back(GuileKeyHandler); + } + if (HasHook("onmousemotion")) { + input->mousePositionHandlers.push_back(GuileMousePositionHandler); + } +#else // GUILE_SCRIPTING + Util::Die("Guile is selected as the scripting language, but this binary was built without Guile support."); +#endif // GUILE_SCRIPTING +} + +void Guile::Update(double delta) { +#ifdef GUILE_SCRIPTING + if (HasHook("update")) { + scm_with_guile(Guile::inner_update, &delta); + } +#endif // GUILE_SCRIPTING +} + +void Guile::Close() { + // Nothing to do +} + +bool Guile::HasHook(const char *name) { + bool exists = false; +#ifdef GUILE_SCRIPTING + exists = scm_with_guile(Guile::inner_has_hook, (void *) name); +#endif // GUILE_SCRIPTING + return exists; +} + +#ifdef GUILE_SCRIPTING + +void Guile::GuileKeyHandler(int key, int code, int action, int mods) { + Guile::key_event ev {key, code, action, mods}; + scm_with_guile(Guile::inner_key_handler, &ev); +} + +void Guile::GuileMousePositionHandler(double xpos, double ypos, double relx, double rely) { + Guile::mouse_position_event ev {xpos, ypos, relx, rely}; + scm_with_guile(Guile::inner_mouse_position_handler, &ev); +} + +void *Guile::inner_init(void* empty) { + // Init swig + SWIG_init(); + // Load main file + scm_c_primitive_load("main.scm"); + // Execute the init function if it exists + if (ScriptingLanguage::language->HasHook("init")) { + scm_call_0(scm_c_eval_string("init")); + } +} + +void *Guile::inner_update(void *data) { + double delta = *(double*) data; + if (ScriptingLanguage::language->HasHook("update")) { + scm_call_1(scm_c_eval_string("update"), scm_from_double(delta)); + } +} + +void *Guile::inner_has_hook(void *data) { + const char *name = (const char *) data; + return (void *) scm_to_bool(scm_defined_p(scm_from_locale_symbol(name), SCM_UNDEFINED)); +} + +void *Guile::inner_key_handler(void *data) { + Guile::key_event *ev = (Guile::key_event*) data; + if (ScriptingLanguage::language->HasHook("onkey")) { + scm_call_4(scm_c_eval_string("onkey"), + scm_from_int(ev->key), + scm_from_int(ev->code), + scm_from_int(ev->action), + scm_from_int(ev->mods)); + } +} + +void *Guile::inner_mouse_position_handler(void *data) { + Guile::mouse_position_event *ev = (Guile::mouse_position_event *) data; + if (ScriptingLanguage::language->HasHook("onmousemotion")) { + scm_call_4(scm_c_eval_string("onmousemotion"), + scm_from_double(ev->xpos), + scm_from_double(ev->ypos), + scm_from_double(ev->relx), + scm_from_double(ev->rely)); + } +} + + +#endif // GUILE_SCRIPTING + diff --git a/core/Scripting/Guile.h b/core/Scripting/Guile.h new file mode 100644 index 0000000..a5d62cb --- /dev/null +++ b/core/Scripting/Guile.h @@ -0,0 +1,46 @@ +#ifndef GUILE_H +#define GUILE_H + +#include "../Input.h" + +#ifdef GUILE_SCRIPTING +#include + + +extern "C" void SWIG_init(); +#endif // GUILE_SCRIPTING + +#include "ScriptingLanguage.h" + +class Guile : public ScriptingLanguage { +public: + void Initialize(); + void Update(double delta); + void Close(); + bool HasHook(const char *name); +private: +#ifdef GUILE_SCRIPTING + struct key_event { + int key; + int code; + int action; + int mods; + }; + struct mouse_position_event { + double xpos; + double ypos; + double relx; + double rely; + }; + static void *inner_init(void *empty); + static void *inner_update(void *delta); + static void *inner_has_hook(void *name); + static void *inner_key_handler(void *ev); + static void *inner_mouse_position_handler(void *ev); + static void GuileKeyHandler(int key, int code, int action, int mods); + static void GuileMousePositionHandler(double xpos, double ypos, double relx, double rely); +#endif // GUILE_SCRIPTING +}; + + +#endif /* GUILE_H */ diff --git a/core/couch.cpp b/core/couch.cpp index e01f81d..903e511 100644 --- a/core/couch.cpp +++ b/core/couch.cpp @@ -30,11 +30,14 @@ #include "Rigidbody.h" #include "World.h" - #include "Scripting/Lua.h" +#include "Scripting/Guile.h" Node *root; +char script_type = 'l'; +ScriptingLanguage *sl; + void render(Node *curr, Shader *shader, Matrix model) { Spatial *spatial = dynamic_cast(curr); if (spatial) { @@ -57,11 +60,27 @@ void render(Node *curr, Shader *shader, Matrix model) { } } +void parse_args(int argc, char* argv[]) { + int curr = 1; + while (curr < argc) { + if (argv[curr][0] == '-') { + switch(argv[curr][1]) { + case 'l': + ++curr; + script_type = argv[curr][0]; + ++curr; + break; + } + } else { + chdir(argv[curr]); + ++curr; + } + } +} + int main(int argc, char *argv[]) { - if (argc == 2) { - chdir(argv[1]); - } + parse_args(argc, argv); Window window; window.Init(); @@ -84,9 +103,15 @@ int main(int argc, char *argv[]) { Matrix projection = glm::perspective(glm::radians(45.0f), 800.0f/600.0f, 0.1f, 100.0f); - // TODO Allow multiple scripting languages - Lua *lua = new Lua(); - lua->Initialize(); + switch(script_type) { + case 'l': + sl = new Lua(); + break; + case 'g': + sl = new Guile(); + break; + } + sl->Initialize(); double lastTime = glfwGetTime(); @@ -97,7 +122,7 @@ int main(int argc, char *argv[]) { world->Step(delta); // Script update - lua->Update(delta); + ScriptingLanguage::GetCurrentLanguage()->Update(delta); // Delete freed nodes root->DoFree(); @@ -158,7 +183,7 @@ int main(int argc, char *argv[]) { lastTime = curTime; } - lua->Close(); + ScriptingLanguage::GetCurrentLanguage()->Close(); window.Close(); return 0; } diff --git a/demo/scm/exampleworld/main.scm b/demo/scm/exampleworld/main.scm new file mode 100644 index 0000000..1894b71 --- /dev/null +++ b/demo/scm/exampleworld/main.scm @@ -0,0 +1,5 @@ +(define (init) + (display "Hello from init!") + (newline)) +(display "Hello from main.scm!") +(newline) diff --git a/scripting/CMakeLists.txt b/scripting/CMakeLists.txt index 56666b3..d431ed2 100644 --- a/scripting/CMakeLists.txt +++ b/scripting/CMakeLists.txt @@ -4,7 +4,6 @@ set_property(SOURCE couch.i PROPERTY CPLUSPLUS ON) set_property(SOURCE couch.i PROPERTY USE_TARGET_INCLUDE_DIRECTORIES ON) if (LUA_ENABLED) - ## Find Lua swig_add_library(couchlua TYPE STATIC LANGUAGE lua @@ -17,3 +16,17 @@ if (LUA_ENABLED) couchlib ${LUA_LIBRARIES}) endif () + +if (GUILE_ENABLED) + swig_add_library(couchguile + TYPE STATIC + LANGUAGE guile + SOURCES couch.i) + + target_include_directories(couchguile PRIVATE "${PROJECT_SOURCE_DIR}/core") + + swig_link_libraries(couchguile + PRIVATE + couchlib + ${GUILE_LIBRARIES}) +endif ()