542 lines
16 KiB
C++
542 lines
16 KiB
C++
|
/*************************************************************************/
|
||
|
/* pepper_main.cpp */
|
||
|
/*************************************************************************/
|
||
|
/* This file is part of: */
|
||
|
/* GODOT ENGINE */
|
||
|
/* http://www.godotengine.org */
|
||
|
/*************************************************************************/
|
||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||
|
/* */
|
||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||
|
/* a copy of this software and associated documentation files (the */
|
||
|
/* "Software"), to deal in the Software without restriction, including */
|
||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||
|
/* the following conditions: */
|
||
|
/* */
|
||
|
/* The above copyright notice and this permission notice shall be */
|
||
|
/* included in all copies or substantial portions of the Software. */
|
||
|
/* */
|
||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||
|
/*************************************************************************/
|
||
|
IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
|
||
|
("Apple") in consideration of your agreement to the following terms, and
|
||
|
your use, installation, modification or redistribution of this Apple software
|
||
|
constitutes acceptance of these terms. If you do not agree with these terms,
|
||
|
please do not use, install, modify or redistribute this Apple software.
|
||
|
|
||
|
In consideration of your agreement to abide by the following terms, and
|
||
|
subject to these terms, Apple grants you a personal, non-exclusive license,
|
||
|
under Apple's copyrights in this original Apple software
|
||
|
(the "Apple Software"), to use, reproduce, modify and redistribute the Apple
|
||
|
Software, with or without modifications, in source and/or binary forms;
|
||
|
provided that if you redistribute the Apple Software in its entirety and
|
||
|
without modifications, you must retain this notice and the following text and
|
||
|
disclaimers in all such redistributions of the Apple Software. Neither the
|
||
|
name, trademarks, service marks or logos of Apple Computer, Inc. may be used
|
||
|
to endorse or promote products derived from the Apple Software without
|
||
|
specific prior written permission from Apple. Except as expressly stated in
|
||
|
this notice, no other rights or licenses, express or implied, are granted by
|
||
|
Apple herein, including but not limited to any patent rights that may be
|
||
|
infringed by your derivative works or by other works in which the Apple
|
||
|
Software may be incorporated.
|
||
|
|
||
|
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||
|
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||
|
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||
|
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||
|
COMBINATION WITH YOUR PRODUCTS.
|
||
|
|
||
|
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||
|
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
|
||
|
AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER
|
||
|
THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
|
||
|
OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include "os_nacl.h"
|
||
|
#include <GLES2/gl2.h>
|
||
|
|
||
|
#include <nacl/npupp.h>
|
||
|
#include <pgl/pgl.h>
|
||
|
#include <string.h>
|
||
|
#include <stdint.h>
|
||
|
|
||
|
static NPNetscapeFuncs kBrowserFuncs = { 0 };
|
||
|
static NPNetscapeFuncs* browser = &kBrowserFuncs;
|
||
|
|
||
|
static NPDevice* device3d_ = NULL;
|
||
|
static PGLContext pgl_context_;
|
||
|
static NPDeviceContext3D context3d_;
|
||
|
static int width_;
|
||
|
static int height_;
|
||
|
|
||
|
extern int nacl_main(int argc, char** argn, char** argv);
|
||
|
extern void nacl_cleanup();
|
||
|
|
||
|
NPExtensions* extensions = NULL;
|
||
|
static NPP npp_;
|
||
|
|
||
|
const int32_t kCommandBufferSize = 1024 * 1024;
|
||
|
|
||
|
// Plugin entry points
|
||
|
extern "C" {
|
||
|
|
||
|
// Plugin entry points
|
||
|
|
||
|
// Entrypoints -----------------------------------------------------------------
|
||
|
|
||
|
NPError NP_GetEntryPoints(NPPluginFuncs* plugin_funcs) {
|
||
|
plugin_funcs->version = 11;
|
||
|
plugin_funcs->size = sizeof(plugin_funcs);
|
||
|
plugin_funcs->newp = NPP_New;
|
||
|
plugin_funcs->destroy = NPP_Destroy;
|
||
|
plugin_funcs->setwindow = NPP_SetWindow;
|
||
|
plugin_funcs->newstream = NPP_NewStream;
|
||
|
plugin_funcs->destroystream = NPP_DestroyStream;
|
||
|
plugin_funcs->asfile = NPP_StreamAsFile;
|
||
|
plugin_funcs->writeready = NPP_WriteReady;
|
||
|
plugin_funcs->write = (NPP_WriteUPP)NPP_Write;
|
||
|
plugin_funcs->print = NPP_Print;
|
||
|
plugin_funcs->event = NPP_HandleEvent;
|
||
|
plugin_funcs->urlnotify = NPP_URLNotify;
|
||
|
plugin_funcs->getvalue = NPP_GetValue;
|
||
|
plugin_funcs->setvalue = NPP_SetValue;
|
||
|
|
||
|
return NPERR_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
NPError NP_Shutdown() {
|
||
|
pglTerminate();
|
||
|
return NPERR_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
NPError NP_GetValue(void* instance, NPPVariable variable, void* value);
|
||
|
char* NP_GetMIMEDescription();
|
||
|
|
||
|
NPError NP_Initialize(NPNetscapeFuncs* browser_funcs,
|
||
|
NPPluginFuncs* plugin_funcs) {
|
||
|
printf("NPP_Initialize\n");
|
||
|
memcpy(&kBrowserFuncs, browser_funcs, sizeof(kBrowserFuncs));
|
||
|
pglInitialize();
|
||
|
return NP_GetEntryPoints(plugin_funcs);
|
||
|
}
|
||
|
|
||
|
|
||
|
} // extern "C"
|
||
|
|
||
|
void Initialize3D() {
|
||
|
// Initialize a 3D context.
|
||
|
NPDeviceContext3DConfig config;
|
||
|
config.commandBufferSize = kCommandBufferSize;
|
||
|
NPError err = device3d_->initializeContext(npp_, &config, &context3d_);
|
||
|
if (err != NPERR_NO_ERROR) {
|
||
|
printf("Failed to initialize 3D context\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
// Create a PGL context.
|
||
|
pgl_context_ = pglCreateContext(npp_, device3d_, &context3d_);
|
||
|
|
||
|
// Initialize the demo GL state.
|
||
|
//pglMakeCurrent(pgl_context_);
|
||
|
//GLFromCPPInit();
|
||
|
//pglMakeCurrent(NULL);
|
||
|
}
|
||
|
|
||
|
NPError NPP_New(NPMIMEType pluginType,
|
||
|
NPP instance,
|
||
|
uint16_t mode,
|
||
|
int16_t argc, char* argn[], char* argv[],
|
||
|
NPSavedData* saved) {
|
||
|
printf("NPP_New\n");
|
||
|
if (browser->version >= 14) {
|
||
|
|
||
|
npp_ = instance;
|
||
|
if (!extensions) {
|
||
|
browser->getvalue(npp_, NPNVPepperExtensions,
|
||
|
reinterpret_cast<void*>(&extensions));
|
||
|
// CHECK(extensions);
|
||
|
}
|
||
|
|
||
|
printf("%s: %i\n", __FUNCTION__, __LINE__);
|
||
|
|
||
|
device3d_ = extensions->acquireDevice(npp_, NPPepper3DDevice);
|
||
|
if (device3d_ == NULL) {
|
||
|
printf("Failed to acquire 3DDevice\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
printf("%s: %i\n", __FUNCTION__, __LINE__);
|
||
|
|
||
|
/*
|
||
|
deviceaudio_ = extensions->acquireDevice(npp_, NPPepperAudioDevice);
|
||
|
if (deviceaudio_ == NULL) {
|
||
|
printf("Failed to acquire AudioDevice\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
*/
|
||
|
Initialize3D();
|
||
|
pglMakeCurrent(pgl_context_);
|
||
|
nacl_main(argc, argn, argv);
|
||
|
pglMakeCurrent(NULL);
|
||
|
};
|
||
|
|
||
|
return NPERR_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
NPError NPP_Destroy(NPP instance, NPSavedData** save) {
|
||
|
|
||
|
nacl_cleanup();
|
||
|
|
||
|
return NPERR_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
void Destroy3D() {
|
||
|
printf("destroy 3d\n");
|
||
|
// Destroy the PGL context.
|
||
|
pglDestroyContext(pgl_context_);
|
||
|
pgl_context_ = NULL;
|
||
|
|
||
|
// Destroy the Device3D context.
|
||
|
device3d_->destroyContext(npp_, &context3d_);
|
||
|
}
|
||
|
|
||
|
static void iteration(void* data) {
|
||
|
|
||
|
(void)data;
|
||
|
OSNacl* os = (OSNacl*)OS::get_singleton();
|
||
|
|
||
|
if (!pglMakeCurrent(pgl_context_) && pglGetError() == PGL_CONTEXT_LOST) {
|
||
|
printf("******* Lost context! :O\n");
|
||
|
Destroy3D();
|
||
|
Initialize3D();
|
||
|
pglMakeCurrent(pgl_context_);
|
||
|
}
|
||
|
|
||
|
glViewport(0, 0, width_, height_);
|
||
|
|
||
|
os->iterate();
|
||
|
|
||
|
pglSwapBuffers();
|
||
|
pglMakeCurrent(NULL);
|
||
|
|
||
|
browser->pluginthreadasynccall(npp_, iteration, NULL);
|
||
|
};
|
||
|
|
||
|
NPError NPP_SetWindow(NPP instance, NPWindow* window) {
|
||
|
|
||
|
width_ = window->width;
|
||
|
height_ = window->height;
|
||
|
|
||
|
if (!pgl_context_)
|
||
|
Initialize3D();
|
||
|
|
||
|
// Schedule the first call to Draw.
|
||
|
OSNacl* os = (OSNacl*)OS::get_singleton();
|
||
|
OS::VideoMode vm;
|
||
|
vm.width = width_;
|
||
|
vm.height = height_;
|
||
|
vm.resizable = false;
|
||
|
vm.fullscreen = false;
|
||
|
os->set_video_mode(vm);
|
||
|
|
||
|
browser->pluginthreadasynccall(npp_, iteration, NULL);
|
||
|
|
||
|
return NPERR_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
NPError NPP_NewStream(NPP instance,
|
||
|
NPMIMEType type,
|
||
|
NPStream* stream,
|
||
|
NPBool seekable,
|
||
|
uint16_t* stype) {
|
||
|
*stype = NP_ASFILEONLY;
|
||
|
return NPERR_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) {
|
||
|
return NPERR_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) {
|
||
|
}
|
||
|
|
||
|
int32_t NPP_Write(NPP instance,
|
||
|
NPStream* stream,
|
||
|
int32_t offset,
|
||
|
int32_t len,
|
||
|
void* buffer) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int32_t NPP_WriteReady(NPP instance, NPStream* stream) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void NPP_Print(NPP instance, NPPrint* platformPrint) {
|
||
|
}
|
||
|
|
||
|
int16_t NPP_HandleEvent(NPP instance, void* event) {
|
||
|
|
||
|
OSNacl* os = (OSNacl*)OS::get_singleton();
|
||
|
os->handle_event(event);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void NPP_URLNotify(NPP instance,
|
||
|
const char* url,
|
||
|
NPReason reason,
|
||
|
void* notify_data) {
|
||
|
// PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
|
||
|
}
|
||
|
|
||
|
static NPObject* Allocate(NPP npp, NPClass* npclass) {
|
||
|
return new NPObject;
|
||
|
}
|
||
|
|
||
|
static void Deallocate(NPObject* object) {
|
||
|
delete object;
|
||
|
}
|
||
|
|
||
|
// Return |true| if |method_name| is a recognized method.
|
||
|
static bool HasMethod(NPObject* obj, NPIdentifier method_name) {
|
||
|
|
||
|
char *name = NPN_UTF8FromIdentifier(method_name);
|
||
|
bool is_method = false;
|
||
|
if (strcmp((const char *)name, "start_package") == 0) {
|
||
|
is_method = true;
|
||
|
} else if (strcmp((const char*)name, "add_package_chunk") == 0) {
|
||
|
is_method = true;
|
||
|
} else if (strcmp((const char*)name, "end_package") == 0) {
|
||
|
is_method = true;
|
||
|
} else if (strcmp((const char*)name, "start_scene") == 0) {
|
||
|
is_method = true;
|
||
|
}
|
||
|
NPN_MemFree(name);
|
||
|
return is_method;
|
||
|
}
|
||
|
|
||
|
// I don't know what this is
|
||
|
static bool InvokeDefault(NPObject *obj, const NPVariant *args,
|
||
|
uint32_t argCount, NPVariant *result) {
|
||
|
if (result) {
|
||
|
NULL_TO_NPVARIANT(*result);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static uint8_t* mem = NULL;
|
||
|
static int pkg_size = 0;
|
||
|
static String pkgname;
|
||
|
|
||
|
static bool variant_is_number(const NPVariant& v) {
|
||
|
|
||
|
switch (v.type) {
|
||
|
|
||
|
case NPVariantType_Int32:
|
||
|
case NPVariantType_Double:
|
||
|
return true;
|
||
|
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
static double variant_as_number(const NPVariant& v) {
|
||
|
|
||
|
switch (v.type) {
|
||
|
|
||
|
case NPVariantType_Int32:
|
||
|
return (double)v.value.intValue;
|
||
|
case NPVariantType_Double:
|
||
|
return (double)v.value.doubleValue;
|
||
|
default:
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
};
|
||
|
|
||
|
// Invoke() is called by the browser to invoke a function object whose name
|
||
|
// is |method_name|.
|
||
|
static bool Invoke(NPObject* obj,
|
||
|
NPIdentifier method_name,
|
||
|
const NPVariant *args,
|
||
|
uint32_t arg_count,
|
||
|
NPVariant *result) {
|
||
|
NULL_TO_NPVARIANT(*result);
|
||
|
char *name = NPN_UTF8FromIdentifier(method_name);
|
||
|
if (name == NULL)
|
||
|
return false;
|
||
|
bool rval = false;
|
||
|
|
||
|
OSNacl* os = (OSNacl*)OS::get_singleton();
|
||
|
|
||
|
if (strcmp(name, "start_package") == 0) {
|
||
|
|
||
|
printf("arg count is %i\n", arg_count);
|
||
|
for (int i=0; i<arg_count; i++) {
|
||
|
printf("type for %i is %i\n", i, args[i].type);
|
||
|
}
|
||
|
if (arg_count != 2) {
|
||
|
return false; // assuming "false" means error
|
||
|
};
|
||
|
|
||
|
if (args[0].type != NPVariantType_String) {
|
||
|
printf("arg 0 not string type %i\n", args[1].type);
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
if (!variant_is_number(args[1])) {
|
||
|
|
||
|
printf("arg 1 not number, type %i\n", args[1].type);
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
pkgname = String::utf8(args[0].value.stringValue.UTF8Characters, args[0].value.stringValue.UTF8Length);
|
||
|
pkg_size = (int)variant_as_number(args[1]);
|
||
|
mem = (uint8_t*)malloc(pkg_size);
|
||
|
|
||
|
printf("args %ls, %lf\n", pkgname.c_str(), variant_as_number(args[1]));
|
||
|
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
if (strcmp(name, "add_package_chunk") == 0) {
|
||
|
|
||
|
if (arg_count != 3) { // assuming arg_count starts from 1
|
||
|
return false; // assuming "false" means error
|
||
|
};
|
||
|
|
||
|
if (!variant_is_number(args[0])) return false;
|
||
|
if (args[1].type != NPVariantType_String) return false;
|
||
|
if (!variant_is_number(args[2])) return false;
|
||
|
|
||
|
if (!mem)
|
||
|
return false;
|
||
|
|
||
|
int ofs = variant_as_number(args[0]);
|
||
|
int len = variant_as_number(args[2]);
|
||
|
|
||
|
String s;
|
||
|
if (s.parse_utf8(args[1].value.stringValue.UTF8Characters, args[1].value.stringValue.UTF8Length)) {
|
||
|
printf("error parsing?\n");
|
||
|
};
|
||
|
uint8_t* dst = mem + ofs;
|
||
|
for (int i=0; i<len; i++) {
|
||
|
|
||
|
dst[i] = s[i];
|
||
|
};
|
||
|
|
||
|
//memcpy(mem + ofs, args[1].value.stringValue.UTF8Characters, len);
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
if (strcmp(name, "end_package") == 0) {
|
||
|
|
||
|
os->add_package(pkgname, mem, pkg_size);
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
|
||
|
if (strcmp(name, "start_scene") == 0) {
|
||
|
printf("start_scene!\n");
|
||
|
if (arg_count != 1) {
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
if (args[0].type != NPVariantType_String) return false;
|
||
|
printf("calling with param %s\n", args[0].value.stringValue.UTF8Characters);
|
||
|
|
||
|
printf("pepper iteration\n");
|
||
|
if (!pglMakeCurrent(pgl_context_) && pglGetError() == PGL_CONTEXT_LOST) {
|
||
|
printf("******* Lost context! :O\n");
|
||
|
Destroy3D();
|
||
|
Initialize3D();
|
||
|
pglMakeCurrent(pgl_context_);
|
||
|
}
|
||
|
os->start_scene(String::utf8(args[0].value.stringValue.UTF8Characters));
|
||
|
pglSwapBuffers();
|
||
|
pglMakeCurrent(NULL);
|
||
|
|
||
|
printf("returning true\n");
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
NPN_MemFree(name);
|
||
|
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
|
||
|
static NPClass GodotClass = {
|
||
|
NP_CLASS_STRUCT_VERSION,
|
||
|
Allocate,
|
||
|
Deallocate,
|
||
|
NULL, // Invalidate is not implemented
|
||
|
HasMethod,
|
||
|
Invoke,
|
||
|
InvokeDefault,
|
||
|
NULL, // HasProperty is not implemented
|
||
|
NULL, // GetProperty is not implemented
|
||
|
NULL, // SetProperty is not implemented
|
||
|
};
|
||
|
|
||
|
static NPObject* npobject = NULL;
|
||
|
|
||
|
NPError NPP_GetValue(NPP instance, NPPVariable variable, void* value) {
|
||
|
NPError err = NPERR_NO_ERROR;
|
||
|
|
||
|
switch (variable) {
|
||
|
case NPPVpluginNameString:
|
||
|
*(reinterpret_cast<const char**>(value)) = "Pepper Test PlugIn";
|
||
|
break;
|
||
|
case NPPVpluginDescriptionString:
|
||
|
*(reinterpret_cast<const char**>(value)) =
|
||
|
"Simple Pepper plug-in for manual testing.";
|
||
|
break;
|
||
|
case NPPVpluginNeedsXEmbed:
|
||
|
*(reinterpret_cast<NPBool*>(value)) = 1;
|
||
|
break;
|
||
|
case NPPVpluginScriptableNPObject: {
|
||
|
if (npobject == NULL) {
|
||
|
npobject = NPN_CreateObject(instance, &GodotClass);
|
||
|
} else {
|
||
|
NPN_RetainObject(npobject);
|
||
|
};
|
||
|
void** v = reinterpret_cast<void**>(value);
|
||
|
*v = npobject;
|
||
|
} break;
|
||
|
default:
|
||
|
fprintf(stderr, "Unhandled variable to NPP_GetValue\n");
|
||
|
err = NPERR_GENERIC_ERROR;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
NPError NPP_SetValue(NPP instance, NPNVariable variable, void* value) {
|
||
|
return NPERR_GENERIC_ERROR;
|
||
|
}
|
||
|
|
||
|
NPError NP_GetValue(void* instance, NPPVariable variable, void* value) {
|
||
|
return NPP_GetValue(reinterpret_cast<NPP>(instance), variable, value);
|
||
|
}
|
||
|
|
||
|
char* NP_GetMIMEDescription() {
|
||
|
return const_cast<char*>("pepper-application/x-pepper-test-plugin;");
|
||
|
}
|