mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 13:41:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			332 lines
		
	
	
	
		
			9.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			332 lines
		
	
	
	
		
			9.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*************************************************************************/
 | |
| /*  godot_module.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.                */
 | |
| /*************************************************************************/
 | |
| #include "opengl_context.h"
 | |
| 
 | |
| #include <cstdlib>
 | |
| #include <cstring>
 | |
| #include <string>
 | |
| #include <vector>
 | |
| 
 | |
| #include "ppapi/cpp/instance.h"
 | |
| #include "ppapi/cpp/module.h"
 | |
| #include "ppapi/gles2/gl2ext_ppapi.h"
 | |
| 
 | |
| #include "ppapi/cpp/rect.h"
 | |
| #include "ppapi/cpp/size.h"
 | |
| #include "ppapi/cpp/var.h"
 | |
| #include "geturl_handler.h"
 | |
| 
 | |
| #include "core/variant.h"
 | |
| #include "os_nacl.h"
 | |
| 
 | |
| extern int nacl_main(int argc, const char** argn, const char** argv);
 | |
| extern void nacl_cleanup();
 | |
| 
 | |
| static String pkg_url;
 | |
| 
 | |
| pp::Instance* godot_instance = NULL;
 | |
| 
 | |
| struct StateData {
 | |
| 	int arg_count;
 | |
| 	Array args;
 | |
| 	String method;
 | |
| };
 | |
| 
 | |
| extern OSNacl* os_nacl;
 | |
| 
 | |
| class GodotInstance : public pp::Instance {
 | |
| 
 | |
| 	enum State {
 | |
| 		STATE_METHOD,
 | |
| 		STATE_PARAM_COUNT,
 | |
| 		STATE_PARAMS,
 | |
| 		STATE_CALL,
 | |
| 	};
 | |
| 
 | |
| 	State state;
 | |
| 	StateData* sd;
 | |
| 	SharedOpenGLContext opengl_context_;
 | |
| 	int width;
 | |
| 	int height;
 | |
| 
 | |
| 	#define MAX_ARGS 64
 | |
| 	uint32_t init_argc;
 | |
| 	char* init_argn[MAX_ARGS];
 | |
| 	char* init_argv[MAX_ARGS];
 | |
| 
 | |
| 	bool package_loaded;
 | |
| 	GetURLHandler* package_pending;
 | |
| 
 | |
| public:
 | |
| 	explicit GodotInstance(PP_Instance instance) : pp::Instance(instance) {
 | |
| 		printf("GodotInstance!\n");
 | |
| 		state = STATE_METHOD;
 | |
| 		RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_KEYBOARD | PP_INPUTEVENT_CLASS_WHEEL | PP_INPUTEVENT_CLASS_TOUCH);
 | |
| 		sd = NULL;
 | |
| 		package_pending = NULL;
 | |
| 		package_loaded = false;
 | |
| 		godot_instance = this;
 | |
| 	}
 | |
| 	virtual ~GodotInstance() {
 | |
| 
 | |
| 		nacl_cleanup();
 | |
| 	}
 | |
| 
 | |
| 	/// Called by the browser to handle the postMessage() call in Javascript.
 | |
| 	/// Detects which method is being called from the message contents, and
 | |
| 	/// calls the appropriate function.  Posts the result back to the browser
 | |
| 	/// asynchronously.
 | |
| 	/// @param[in] var_message The message posted by the browser.  The possible
 | |
| 	///     messages are 'fortyTwo' and 'reverseText:Hello World'.  Note that
 | |
| 	///     the 'reverseText' form contains the string to reverse following a ':'
 | |
| 	///     separator.
 | |
| 	virtual void HandleMessage(const pp::Var& var_message);
 | |
| 
 | |
| 	bool HandleInputEvent(const pp::InputEvent& event);
 | |
| 
 | |
| 	bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
 | |
| 
 | |
| 		printf("******* init! %i, %p, %p\n", argc, argn, argv);
 | |
| 		fflush(stdout);
 | |
| 		if (opengl_context_ == NULL) {
 | |
| 			opengl_context_.reset(new OpenGLContext(this));
 | |
| 		};
 | |
| 		opengl_context_->InvalidateContext(this);
 | |
| 		opengl_context_->ResizeContext(pp::Size(0, 0));
 | |
| 		int current = opengl_context_->MakeContextCurrent(this);
 | |
| 		printf("current is %i\n", current);
 | |
| 
 | |
| 		os_nacl = new OSNacl;
 | |
| 
 | |
| 		pkg_url = "";
 | |
| 		for (uint32_t i=0; i<argc; i++) {
 | |
| 			if (strcmp(argn[i], "package") == 0) {
 | |
| 				pkg_url = argv[i];
 | |
| 			};
 | |
| 		};
 | |
| 
 | |
| 		sd = memnew(StateData);
 | |
| 
 | |
| 		if (pkg_url == "") {
 | |
| 			nacl_main(argc, argn, argv);
 | |
| 		} else {
 | |
| 			printf("starting package %ls\n", pkg_url.c_str());
 | |
| 			init_argc = MIN(argc, MAX_ARGS-1);
 | |
| 			for (uint32_t i=0; i<argc; i++) {
 | |
| 
 | |
| 				int nlen = strlen(argn[i]);
 | |
| 				init_argn[i] = (char*)memalloc(nlen+1);
 | |
| 				strcpy(init_argn[i], argn[i]);
 | |
| 				init_argn[i+1] = NULL;
 | |
| 
 | |
| 				int len = strlen(argv[i]);
 | |
| 				init_argv[i] = (char*)memalloc(len+1);
 | |
| 				strcpy(init_argv[i], argv[i]);
 | |
| 				init_argv[i+1] = NULL;
 | |
| 			};
 | |
| 			package_pending = memnew(GetURLHandler(this, pkg_url));
 | |
| 			package_pending->Start();
 | |
| 		};
 | |
| 		return true;
 | |
| 	};
 | |
| 
 | |
| 	// Called whenever the in-browser window changes size.
 | |
| 	virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
 | |
| 
 | |
| 		if (position.size().width() == width &&
 | |
| 			position.size().height() == height)
 | |
| 			return;  // Size didn't change, no need to update anything.
 | |
| 
 | |
| 		if (opengl_context_ == NULL) {
 | |
| 			opengl_context_.reset(new OpenGLContext(this));
 | |
| 		};
 | |
| 		opengl_context_->InvalidateContext(this);
 | |
| 		opengl_context_->ResizeContext(position.size());
 | |
| 		if (!opengl_context_->MakeContextCurrent(this))
 | |
| 			return;
 | |
| 
 | |
| 		width = position.size().width();
 | |
| 		height = position.size().height();
 | |
| 		// init gl here?
 | |
| 		OS::VideoMode vm;
 | |
| 		vm.width = width;
 | |
| 		vm.height = height;
 | |
| 		vm.resizable = false;
 | |
| 		vm.fullscreen = true;
 | |
| 		OS::get_singleton()->set_video_mode(vm, 0);
 | |
| 
 | |
| 		DrawSelf();
 | |
| 	};
 | |
| 
 | |
| 	// Called to draw the contents of the module's browser area.
 | |
| 	void DrawSelf() {
 | |
| 
 | |
| 		if (opengl_context_ == NULL)
 | |
| 			return;
 | |
| 
 | |
| 		opengl_context_->FlushContext();
 | |
| 	};
 | |
| };
 | |
| 
 | |
| static Variant to_variant(const pp::Var& p_var) {
 | |
| 
 | |
| 	if (p_var.is_undefined() || p_var.is_null())
 | |
| 		return Variant();
 | |
| 	if (p_var.is_bool())
 | |
| 		return Variant(p_var.AsBool());
 | |
| 	if (p_var.is_double())
 | |
| 		return Variant(p_var.AsDouble());
 | |
| 	if (p_var.is_int())
 | |
| 		return Variant((int64_t)p_var.AsInt());
 | |
| 	if (p_var.is_string())
 | |
| 		return Variant(String::utf8(p_var.AsString().c_str()));
 | |
| 
 | |
| 	return Variant();
 | |
| };
 | |
| 
 | |
| void GodotInstance::HandleMessage(const pp::Var& var_message) {
 | |
| 
 | |
| 	switch (state) {
 | |
| 
 | |
| 		case STATE_METHOD: {
 | |
| 
 | |
| 			ERR_FAIL_COND(!var_message.is_string());
 | |
| 			sd->method = var_message.AsString().c_str();
 | |
| 			state = STATE_PARAM_COUNT;
 | |
| 		} break;
 | |
| 		case STATE_PARAM_COUNT: {
 | |
| 
 | |
| 			ERR_FAIL_COND(!var_message.is_number());
 | |
| 			sd->arg_count = var_message.AsInt();
 | |
| 			state = sd->arg_count>0?STATE_PARAMS:STATE_CALL;
 | |
| 
 | |
| 		} break;
 | |
| 		case STATE_PARAMS: {
 | |
| 
 | |
| 			Variant p = to_variant(var_message);
 | |
| 			sd->args.push_back(p);
 | |
| 			if (sd->args.size() >= sd->arg_count)
 | |
| 				state = STATE_CALL;
 | |
| 		} break;
 | |
| 		default:
 | |
| 			break;
 | |
| 	};
 | |
| 
 | |
| 	if (state == STATE_CALL) {
 | |
| 
 | |
| 		// call
 | |
| 		state = STATE_METHOD;
 | |
| 
 | |
| 
 | |
| 		if (sd->method == "package_finished") {
 | |
| 
 | |
| 			GetURLHandler::Status status = package_pending->get_status();
 | |
| 			printf("status is %i, %i, %i\n", status, GetURLHandler::STATUS_ERROR, GetURLHandler::STATUS_COMPLETED);
 | |
| 			if (status == GetURLHandler::STATUS_ERROR) {
 | |
| 				printf("Error fetching package!\n");
 | |
| 			};
 | |
|             if (status == GetURLHandler::STATUS_COMPLETED) {
 | |
| 
 | |
| 				OSNacl* os = (OSNacl*)OS::get_singleton();
 | |
| 				os->add_package(pkg_url, package_pending->get_data());
 | |
| 			};
 | |
|             memdelete(package_pending);
 | |
| 			package_pending = NULL;
 | |
| 
 | |
|             package_loaded = true;
 | |
| 
 | |
|             opengl_context_->MakeContextCurrent(this);
 | |
|             nacl_main(init_argc, (const char**)init_argn, (const char**)init_argv);
 | |
|             for (uint32_t i=0; i<init_argc; i++) {
 | |
| 				memfree(init_argn[i]);
 | |
| 				memfree(init_argv[i]);
 | |
| 			};
 | |
| 		};
 | |
| 
 | |
| 		if (sd->method == "get_package_status") {
 | |
| 
 | |
| 			if (package_loaded) {
 | |
| 				// post "loaded"
 | |
| 				PostMessage("loaded");
 | |
| 			} else if (package_pending == NULL) {
 | |
| 				// post "none"
 | |
| 				PostMessage("none");
 | |
| 			} else {
 | |
| 				// post package_pending->get_bytes_read();
 | |
| 				PostMessage(package_pending->get_bytes_read());
 | |
| 			};
 | |
| 		};
 | |
| 	};
 | |
| }
 | |
| 
 | |
| bool GodotInstance::HandleInputEvent(const pp::InputEvent& event) {
 | |
| 
 | |
| 	OSNacl* os = (OSNacl*)OS::get_singleton();
 | |
| 	os->handle_event(event);
 | |
| 	return true;
 | |
| };
 | |
| 
 | |
| class GodotModule : public pp::Module {
 | |
|  public:
 | |
|   GodotModule() : pp::Module() {}
 | |
|   virtual ~GodotModule() {
 | |
| 	  glTerminatePPAPI();
 | |
|   }
 | |
| 
 | |
|   /// Create and return a GodotInstance object.
 | |
|   /// @param[in] instance a handle to a plug-in instance.
 | |
|   /// @return a newly created GodotInstance.
 | |
|   /// @note The browser is responsible for calling @a delete when done.
 | |
|   virtual pp::Instance* CreateInstance(PP_Instance instance) {
 | |
| 	printf("CreateInstance! %x\n", instance);
 | |
| 	return new GodotInstance(instance);
 | |
|   }
 | |
| 
 | |
|   /// Called by the browser when the module is first loaded and ready to run.
 | |
|   /// This is called once per module, not once per instance of the module on
 | |
|   /// the page.
 | |
|   virtual bool Init() {
 | |
| 	printf("GodotModule::init!\n");
 | |
| 	return glInitializePPAPI(get_browser_interface());
 | |
|   }
 | |
| };
 | |
| 
 | |
| namespace pp {
 | |
| /// Factory function called by the browser when the module is first loaded.
 | |
| /// The browser keeps a singleton of this module.  It calls the
 | |
| /// CreateInstance() method on the object you return to make instances.  There
 | |
| /// is one instance per <embed> tag on the page.  This is the main binding
 | |
| /// point for your NaCl module with the browser.
 | |
| /// @return new GodotModule.
 | |
| /// @note The browser is responsible for deleting returned @a Module.
 | |
| Module* CreateModule() {
 | |
|   printf("CreateModule!\n");
 | |
|   return new GodotModule();
 | |
| }
 | |
| }  // namespace pp
 | 
