00001
00002
00003
00004
00005 #include <pthread.h>
00006 #include <stdio.h>
00007 #include <stdlib.h>
00008
00009 #include <ppapi/cpp/instance.h>
00010 #include <ppapi/cpp/module.h>
00011 #include <ppapi/cpp/rect.h>
00012 #include <ppapi/cpp/size.h>
00013 #include <ppapi/cpp/file_system.h>
00014
00015 #include <SDL_video.h>
00016 extern int wesnoth_main(int argc, char **argv);
00017 #include <SDL.h>
00018 #include <SDL_nacl.h>
00019
00020 #include <nacl-mounts/base/KernelProxy.h>
00021 #include <nacl-mounts/base/MainThreadRunner.h>
00022 #include <nacl-mounts/http2/HTTP2Mount.h>
00023 #include <nacl-mounts/pepper/PepperMount.h>
00024
00025
00026 const char* http_dirs[] = {
00027 #include <dir_list.h>
00028 };
00029
00030 struct http_file_info {
00031 const char* path;
00032 size_t size;
00033 } http_files[] = {
00034 #include <file_list.h>
00035 };
00036
00037 struct http_pack_info {
00038 const char* path;
00039 const char* pack_path;
00040 off_t offset;
00041 } http_packs[] = {
00042 #include <pack_list.h>
00043 };
00044
00045
00046 class PluginInstance : public pp::Instance {
00047 public:
00048 explicit PluginInstance(PP_Instance instance) : pp::Instance(instance),
00049 sdl_main_thread_(0),
00050 width_(0),
00051 height_(0),
00052 progress_handler_(this),
00053 directory_reader_(this) {
00054 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
00055 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
00056
00057 proxy_ = KernelProxy::KPInstance();
00058 runner_ = new MainThreadRunner(this);
00059
00060 fprintf(stderr, "Requesting an HTML5 local persistent filesystem.\n");
00061 fflush(stderr);
00062 fs_ = new pp::FileSystem(this, PP_FILESYSTEMTYPE_LOCALPERSISTENT);
00063 }
00064
00065 ~PluginInstance() {
00066 if (sdl_main_thread_) {
00067 pthread_join(sdl_main_thread_, NULL);
00068 }
00069 }
00070
00071 virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
00072 fprintf(stderr, "did change view, new %dx%d, old %dx%d\n",
00073 position.size().width(), position.size().height(),
00074 width_, height_);
00075 fflush(stderr);
00076
00077 width_ = position.size().width();
00078 height_ = position.size().height();
00079
00080 SDL_NACL_SetInstance(pp_instance(), width_, height_);
00081
00082 if (sdl_thread_started_ == false) {
00083
00084
00085
00086 int lval = SDL_Init(SDL_INIT_AUDIO);
00087 assert(lval >= 0);
00088 if (0 == pthread_create(&sdl_main_thread_, NULL, sdl_thread_static, this)) {
00089 sdl_thread_started_ = true;
00090 }
00091 }
00092 }
00093
00094 bool HandleInputEvent(const pp::InputEvent& event) {
00095 SDL_NACL_PushEvent(event);
00096 return true;
00097 }
00098
00099 void HandleMessage(const pp::Var& message) {
00100 std::string s = message.AsString();
00101 directory_reader_.HandleResponse(s);
00102 }
00103
00104 bool Init(int argc, const char* argn[], const char* argv[]) {
00105 return true;
00106 }
00107
00108 private:
00109 bool sdl_thread_started_;
00110 pthread_t sdl_main_thread_;
00111 int width_;
00112 int height_;
00113 KernelProxy* proxy_;
00114 MainThreadRunner* runner_;
00115 pp::FileSystem* fs_;
00116
00117 static void* sdl_thread_static(void* param) {
00118 return reinterpret_cast<PluginInstance*>(param)->sdl_thread();
00119 }
00120
00121 void* sdl_thread() {
00122 fprintf(stderr, "Initializing nacl-mounts.\n");
00123 fflush(stderr);
00124
00125
00126 PepperMount* pepper_mount = new PepperMount(runner_, fs_, 20 * 1024 * 1024);
00127 pepper_mount->SetDirectoryReader(&directory_reader_);
00128 pepper_mount->SetPathPrefix("/wesnoth-userdata");
00129
00130 proxy_->mkdir("/wesnoth-userdata", 0777);
00131 int res = proxy_->mount("/wesnoth-userdata", pepper_mount);
00132
00133
00134 proxy_->mkdir("/wesnoth-userdata/saves", 0777);
00135
00136
00137 HTTP2Mount* http2_mount = new HTTP2Mount(runner_, "./usr/local/share/wesnoth");
00138 http2_mount->SetLocalCache(fs_, 350*1024*1024, "/wesnoth0", true);
00139 http2_mount->SetProgressHandler(&progress_handler_);
00140
00141 fprintf(stderr, "Registering known files.\n");
00142 fflush(stderr);
00143 for (int i = 0; i < sizeof(http_dirs) / sizeof(*http_dirs); ++i) {
00144 char* path = (char*)http_dirs[i];
00145 if (path && *path)
00146 http2_mount->AddDir(path);
00147 }
00148
00149 for (int i = 0; i < sizeof(http_files) / sizeof(*http_files); ++i) {
00150 char* path = (char*)http_files[i].path;
00151 size_t size = http_files[i].size;
00152 if (path && *path)
00153 http2_mount->AddFile(path, size);
00154 }
00155
00156 for (int i = 0; i < sizeof(http_packs) / sizeof(*http_packs); ++i) {
00157 char* path = (char*)http_packs[i].path;
00158 char* pack_path = (char*)http_packs[i].pack_path;
00159 off_t offset = http_packs[i].offset;
00160 if (path && *path) {
00161 http2_mount->SetInPack(path, pack_path, offset);
00162 }
00163 }
00164
00165 http2_mount->SetInMemory("/fonts/Andagii.ttf", true);
00166 http2_mount->SetInMemory("/fonts/DejaVuSans.ttf", true);
00167 http2_mount->SetInMemory("/fonts/wqy-zenhei.ttc", true);
00168
00169 fprintf(stderr, "Mounting the filesystem.\n");
00170 fflush(stderr);
00171 proxy_->mkdir("/usr", 0777);
00172 proxy_->mkdir("/usr/local", 0777);
00173 proxy_->mkdir("/usr/local/share", 0777);
00174 res = proxy_->mount("/usr/local/share/wesnoth", http2_mount);
00175 if (!res) {
00176 fprintf(stderr, "FS initialization success.\n");
00177 } else {
00178 fprintf(stderr, "FS initialization failure.\n");
00179 }
00180 fflush(stderr);
00181
00182
00183 char res_s[100];
00184 snprintf(res_s, sizeof(res_s), "%dx%d", width_, height_);
00185 static char const * argv[] = {"wesnoth", "-r", res_s, NULL};
00186 printf("starting game thread: %s\n", res_s);
00187 wesnoth_main(sizeof(argv) / sizeof(*argv) - 1, (char**)argv);
00188 return NULL;
00189 }
00190
00191 class ProgressHandler : public HTTP2ProgressHandler {
00192 public:
00193 pp::Instance* instance_;
00194
00195 ProgressHandler(pp::Instance* instance) : instance_(instance) {}
00196
00197 void HandleProgress(std::string& path, int64_t bytes, int64_t size) {
00198 char buf[100];
00199 snprintf(buf, sizeof(buf), "%llu,%llu", (unsigned long long)bytes,
00200 (unsigned long long)size);
00201 std::string message = "[\"" + path + "\"," + buf + "]";
00202 instance_->PostMessage(message);
00203 }
00204 };
00205
00206 ProgressHandler progress_handler_;
00207
00208 class JSDirectoryReader: public DirectoryReader {
00209 public:
00210 pp::Instance* instance_;
00211 pp::CompletionCallback cc_;
00212 std::set<std::string>* entries_;
00213
00214 JSDirectoryReader(pp::Instance* instance) : instance_(instance) {}
00215
00216 int ReadDirectory(const std::string& path, std::set<std::string>* entries, const pp::CompletionCallback& cc) {
00217 cc_ = cc;
00218 entries_ = entries;
00219 std::string message = "[\"ReadDirectory\",\"" + path + "\"]";
00220 instance_->PostMessage(message);
00221 }
00222
00223 void HandleResponse(const std::string& response) {
00224 fprintf(stderr, "response: %s\n", response.c_str());
00225 std::string::const_iterator ind = response.begin();
00226 std::string::const_iterator next = response.begin();
00227 while (ind != response.end() && next != response.end()) {
00228 if (*next == '\n' && ind != next) {
00229 if (*ind == '\n') {
00230 ++ind;
00231 }
00232 if (ind != next) {
00233 entries_->insert(std::string(ind, next));
00234 }
00235 ind = next;
00236 }
00237 ++next;
00238 }
00239 if (ind != next) {
00240 std::string last(ind, next-1);
00241 if (!last.empty()) {
00242 entries_->insert(last);
00243 }
00244 }
00245 cc_.Run(PP_OK);
00246 }
00247 };
00248
00249 JSDirectoryReader directory_reader_;
00250 };
00251
00252 class PepperModule : public pp::Module {
00253 public:
00254
00255 virtual pp::Instance* CreateInstance(PP_Instance instance) {
00256 return new PluginInstance(instance);
00257 }
00258 };
00259
00260 namespace pp {
00261 Module* CreateModule() {
00262 return new PepperModule();
00263 }
00264 }