Browse Source

Native Plugins

JoshEngebretson 10 years ago
parent
commit
00585307f0

+ 1 - 0
.gitignore

@@ -4,6 +4,7 @@
 Bin/Atomic.d.ts
 Bin/Atomic.js
 Bin/*.pak
+Bin/NativeSDK/*
 Source/Atomic/Javascript/Modules/*
 Data/AtomicPlayer/Resources/CoreData/Shaders/HLSL/Cache
 Artifacts/*

+ 1 - 1
CMake/Modules/AtomicWindows.cmake

@@ -2,7 +2,7 @@
 
 include(AtomicDesktop)
 
-set (CMAKE_DEBUG_POSTFIX _d)
+#set (CMAKE_DEBUG_POSTFIX _d)
 
 set (D3DCOMPILER_47_DLL ${CMAKE_SOURCE_DIR}/Build/Windows/Binaries/x64/D3DCompiler_47.dll)
 

+ 2 - 0
Source/AtomicJS/CMakeLists.txt

@@ -28,6 +28,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}
 
 file (GLOB JAVASCRIPT_SOURCE Javascript/*.cpp Javascript/*.h)
 
+GroupSources("Javascript")
+
 if (NOT MSVC)
     # for kNet
     add_definitions (-DUNIX)

+ 2 - 0
Source/AtomicJS/JSBind/CMakeLists.txt

@@ -7,6 +7,8 @@ add_definitions(-DCPLUSPLUS_WITHOUT_QT)
 # Define source files
 file (GLOB SOURCE_FILES *.cpp cplusplus/*.cpp *.h cplusplus/*.h )
 
+GroupSources("cplusplus")
+
 add_executable(JSBind ${SOURCE_FILES})
 
 target_link_libraries(JSBind ${ATOMIC_LINK_LIBRARIES})

+ 166 - 0
Source/AtomicJS/Javascript/JSRequire.cpp

@@ -0,0 +1,166 @@
+
+#include <assert.h>
+
+#include <Atomic/IO/FileSystem.h>
+#include <Atomic/Resource/ResourceCache.h>
+
+#include "JSVM.h"
+#include "JSRequire.h"
+
+namespace Atomic
+{
+    static bool js_init_native_module(duk_context* ctx, const String& pluginLibrary)
+    {
+#ifdef ATOMIC_PLATFORM_WINDOWS
+
+        LOGINFOF("Loading Native Plugin: %s", pluginLibrary.CString());
+
+        HMODULE hmodule = ::LoadLibrary(pluginLibrary.CString());
+
+        if (hmodule == NULL)
+        {
+            LOGERRORF("Native Plugin: Unable to load %s", pluginLibrary.CString());
+            return false;
+        }
+        
+        duk_c_function func = (duk_c_function) ::GetProcAddress(hmodule, "atomic_plugin_init");
+
+        if (!func)
+        {
+            LOGERRORF("Native Plugin: Unable to get atomic_plugin_init entry point in %s", pluginLibrary.CString());
+            return false;
+        }
+
+        // just to verify that we're not doing anything funky with the stack
+        int top = duk_get_top(ctx);
+
+        // the import function is a standard duktape c function, neat
+        duk_push_c_function(ctx, func, 1);
+        
+        // requires exports to be at index 2
+        duk_dup(ctx, 2);
+
+        bool success = true;
+        if (duk_pcall(ctx, 1) != DUK_EXEC_SUCCESS)
+        {
+            success = false;
+            LOGERRORF("Native Plugin: error calling atomic_plugin_init %s", pluginLibrary.CString());
+        }
+        else
+        {
+            if (!duk_is_boolean(ctx, -1) || !duk_to_boolean(ctx, -1))
+            {
+                success = false;
+                LOGERRORF("Native Plugin: error calling atomic_plugin_init, didn't return true %s", pluginLibrary.CString());
+            }
+        }
+
+        duk_pop(ctx);
+        assert(top == duk_get_top(ctx));
+
+        return success;
+        
+#else
+        return false;
+#endif
+
+    }
+
+    // see http://duktape.org/guide.html#modules   
+    static int js_module_search(duk_context* ctx)
+    {       
+        JSVM* vm = JSVM::GetJSVM(ctx);
+        FileSystem* fs = vm->GetSubsystem<FileSystem>();
+        ResourceCache* cache = vm->GetSubsystem<ResourceCache>();
+
+        int top = duk_get_top(ctx);
+
+        assert(top ==  4);
+
+        String moduleID = duk_to_string(ctx, 0);
+
+        if (top > 1)
+        {
+            // require function
+            assert(duk_is_function(ctx, 1));
+        }
+        
+        if (top > 2)
+        {
+            // exports
+            assert(duk_is_object(ctx, 2));
+        }
+
+        if (top > 3)        
+        {
+            // module (module.id == a resolved absolute identifier for the module being loaded)
+            assert(duk_is_object(ctx, 3));
+        }
+
+        String pathName, fileName, extension;
+        SplitPath(moduleID, pathName, fileName, extension);
+        String path = moduleID;
+
+        // Do we really want this?  It is nice to not have to specify the Atomic path
+        if (fileName.StartsWith("Atomic"))
+        {
+            path = "AtomicModules/" + path + ".js";
+        }
+        else
+        {
+            path += ".js";
+ 
+        }
+
+        SharedPtr<File> jsfile(cache->GetFile(path, false));
+
+        if (!jsfile)
+        {
+            // we're not a JS file, so check if we're a native module
+            const Vector<String>& resourceDirs = cache->GetResourceDirs();
+
+            for (unsigned i = 0; i < resourceDirs.Size(); i++)
+            {
+
+#ifdef ATOMIC_PLATFORM_WINDOWS
+
+                // TODO: proper platform folder detection
+
+                String pluginLibrary = resourceDirs.At(i) + "Plugins/Windows/x64/" + moduleID + ".dll";
+
+                if (fs->FileExists(pluginLibrary))
+                {
+                    // let duktape know we loaded a native module
+                    if (js_init_native_module(ctx, pluginLibrary))
+                    {
+                        duk_push_undefined(ctx);
+                        return 1;
+                    }
+                }
+
+            }
+
+#endif
+        }
+        else
+        {
+            vm->SetLastModuleSearchFile(jsfile->GetFullPath());
+            String source;
+            jsfile->ReadText(source);
+            duk_push_string(ctx, source.CString());
+        }
+
+        return 1;
+
+    }
+
+    void js_init_require(JSVM* vm)
+    {
+        duk_context* ctx = vm->GetJSContext();
+        duk_get_global_string(ctx, "Duktape");
+        duk_push_c_function(ctx, js_module_search, 4);
+        duk_put_prop_string(ctx, -2, "modSearch");
+        duk_pop(ctx);
+    }
+
+}

+ 11 - 0
Source/AtomicJS/Javascript/JSRequire.h

@@ -0,0 +1,11 @@
+
+#pragma once
+
+namespace Atomic
+{
+
+class JSVM;
+
+void js_init_require(JSVM* vm);
+
+}

+ 2 - 63
Source/AtomicJS/Javascript/JSVM.cpp

@@ -14,6 +14,7 @@
 
 #include <Atomic/Resource/ResourceCache.h>
 
+#include "JSRequire.h"
 #include "JSEvents.h"
 #include "JSVM.h"
 #include "JSAtomic.h"
@@ -58,11 +59,7 @@ void JSVM::InitJSContext()
     duk_put_prop_index(ctx_, -2, JS_GLOBALSTASH_INDEX_COMPONENTS);
     duk_pop(ctx_);
 
-    duk_get_global_string(ctx_, "Duktape");
-    duk_push_c_function(ctx_, js_module_search, 1);
-    duk_put_prop_string(ctx_, -2, "modSearch");
-    duk_pop(ctx_);
-
+    js_init_require(this);
     jsapi_init_atomic(this);
 
     InitComponents();
@@ -313,64 +310,6 @@ void JSVM::InitComponents()
 
 }
 
-int JSVM::js_module_search(duk_context* ctx)
-{
-    JSVM* vm = GetJSVM(ctx);
-
-    FileSystem* fs = vm->GetSubsystem<FileSystem>();
-    ResourceCache* cache = vm->GetSubsystem<ResourceCache>();
-
-    String path = duk_to_string(ctx, 0);
-
-    // first check if this is an AtomicModule
-    // attempting to avoid module search paths
-    // so have AtomicEditor, Atomic, and the projects "Modules"
-    String pathName, fileName, extension;
-    SplitPath(path, pathName, fileName, extension);
-
-    if (fileName.StartsWith("AtomicEditor"))
-    {
-        path =  "AtomicEditor/Modules/" + path + ".js";
-    }
-    else if (fileName.StartsWith("Atomic"))
-    {
-        path =  "AtomicModules/" + path + ".js";
-    }
-    else
-    {
-        // a module can exist in the Modules path or reside in a project directory
-        // prefer modules path
-        String modulePath = vm->moduleSearchPath_ + "/" + path + ".js";
-
-        if (fs->FileExists(modulePath))
-        {
-            // unless the file doesn't exist and then use project path
-            path = modulePath;
-        }
-        else
-        {
-            path += ".js";
-        }
-
-    }
-
-    SharedPtr<File> jsfile(cache->GetFile(path));    
-
-    if (!jsfile)
-    {
-        duk_push_null(ctx);
-    }
-    else
-    {
-        vm->SetLastModuleSearchFile(jsfile->GetFullPath());
-        String source;
-        jsfile->ReadText(source);
-        duk_push_string(ctx, source.CString());
-    }
-
-    return 1;
-}
-
 void JSVM::SendJSErrorEvent(const String& filename)
 {
     duk_context* ctx = GetJSContext();

+ 1 - 3
Source/AtomicJS/Javascript/JSVM.h

@@ -156,9 +156,7 @@ private:
 
     void SubscribeToEvents();
     void HandleUpdate(StringHash eventType, VariantMap& eventData);
-
-    static int js_module_search(duk_context* ctx);
-
+    
     duk_context* ctx_;
 
     HashMap<void*, RefCounted*> heapToObject_;

+ 12 - 1
Source/ThirdParty/Duktape/CMakeLists.txt

@@ -6,4 +6,15 @@ file (GLOB CPP_FILES *.c)
 file (GLOB H_FILES *.h)
 set (SOURCE_FILES ${CPP_FILES} ${H_FILES})
 
-add_library(Duktape ${SOURCE_FILES})
+add_library(Duktape ${SOURCE_FILES})
+
+if (MSVC)
+    # technically, we could reuse the Duktape lib, but we'll compile it directly
+    # for instance, if we want to change settings slightly for native plugins
+	add_library(AtomicPlugin ${SOURCE_FILES})
+	add_custom_command (TARGET AtomicPlugin POST_BUILD
+    COMMAND ${CMAKE_COMMAND}
+    ARGS -E copy_if_different \"${CMAKE_CURRENT_SOURCE_DIR}/duktape.h\" \"${CMAKE_SOURCE_DIR}/Bin/NativeSDK/Windows/AtomicPlugin.h\"
+    COMMAND ${CMAKE_COMMAND}
+    ARGS -E copy \"$<TARGET_LINKER_FILE:AtomicPlugin>\" \"${CMAKE_SOURCE_DIR}/Bin/NativeSDK/Windows/x64/$<TARGET_LINKER_FILE_NAME:AtomicPlugin>\")
+endif()