void UpdateContext(uint32_t width, uint32_t height) { if (width != g_Context.size.width || height != g_Context.size.height) { size_t size = width * height; size_t index; free(g_Context.cell_in); free(g_Context.cell_out); /* Create a new context */ g_Context.cell_in = (uint8_t*) malloc(size); g_Context.cell_out = (uint8_t*) malloc(size); memset(g_Context.cell_out, 0, size); for (index = 0; index < size; index++) { g_Context.cell_in[index] = rand() & 1; } } /* Recreate the graphics context on a view change */ g_pCore->ReleaseResource(g_Context.ctx); g_Context.size.width = width; g_Context.size.height = height; g_Context.ctx = g_pGraphics2D->Create(PSGetInstanceId(), &g_Context.size, PP_TRUE); g_Context.bound = g_pInstance->BindGraphics(PSGetInstanceId(), g_Context.ctx); }
void ProcessEvent(PSEvent* event) { switch(event->type) { /* If the view updates, build a new Graphics 2D Context */ case PSE_INSTANCE_DIDCHANGEVIEW: { struct PP_Rect rect; g_pView->GetRect(event->as_resource, &rect); UpdateContext(rect.size.width, rect.size.height); break; } case PSE_INSTANCE_HANDLEINPUT: { PP_InputEvent_Type type = g_pInputEvent->GetType(event->as_resource); PP_InputEvent_Modifier modifiers = g_pInputEvent->GetModifiers(event->as_resource); switch(type) { case PP_INPUTEVENT_TYPE_MOUSEDOWN: { struct PP_Point location = g_pMouseInput->GetPosition(event->as_resource); DrawCell(location.x, location.y); break; } case PP_INPUTEVENT_TYPE_MOUSEMOVE: { struct PP_Point location = g_pMouseInput->GetPosition(event->as_resource); /* If the button is down, draw */ if (modifiers & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) { DrawCell(location.x, location.y); } break; } case PP_INPUTEVENT_TYPE_KEYDOWN: { PP_Bool fullscreen = g_pFullscreen->IsFullscreen(PSGetInstanceId()); g_pFullscreen->SetFullscreen(PSGetInstanceId(), fullscreen ? PP_FALSE : PP_TRUE); break; } default: break; } /* case PSE_INSTANCE_HANDLEINPUT */ break; } default: break; } }
/** @internal @This allocates an nacl audio pipe. * * @param mgr common management structure * @param uprobe structure used to raise events * @param signature signature of the pipe allocator * @param args optional arguments * @return pointer to upipe or NULL in case of allocation error */ static struct upipe *upipe_nacl_audio_alloc(struct upipe_mgr *mgr, struct uprobe *uprobe, uint32_t signature, va_list args) { if (signature != UPIPE_VOID_SIGNATURE) return NULL; struct upipe_nacl_audio *upipe_nacl_audio = malloc(sizeof(struct upipe_nacl_audio) + uqueue_sizeof(MAX_QUEUE_LENGTH)); if (unlikely(upipe_nacl_audio == NULL)) return NULL; if(unlikely(!uqueue_init(&upipe_nacl_audio->uqueue, MAX_QUEUE_LENGTH, upipe_nacl_audio->uqueue_extra))) { free(upipe_nacl_audio); return NULL; } struct upipe *upipe = upipe_nacl_audio_to_upipe(upipe_nacl_audio); upipe_init(upipe, mgr, uprobe); upipe_nacl_audio_init_urefcount(upipe); upipe_nacl_audio_init_input(upipe); upipe_nacl_audio_init_upump_mgr(upipe); upipe_nacl_audio_init_upump(upipe); upipe_nacl_audio_init_uclock(upipe); upipe_nacl_audio->started = false; PPB_AudioConfig *audio_config_interface = (PPB_AudioConfig *)PSGetInterface(PPB_AUDIO_CONFIG_INTERFACE); upipe_nacl_audio->nb_samples = audio_config_interface->RecommendSampleFrameCount(PSGetInstanceId(), SAMPLE_RATE, NB_SAMPLES); upipe_nacl_audio->audio_config = audio_config_interface->CreateStereo16Bit(PSGetInstanceId(), SAMPLE_RATE, upipe_nacl_audio->nb_samples); upipe_nacl_audio->core_interface = (PPB_Core *)PSGetInterface(PPB_CORE_INTERFACE); upipe_nacl_audio->audio_interface = (PPB_Audio *)PSGetInterface(PPB_AUDIO_INTERFACE); upipe_nacl_audio->audio = upipe_nacl_audio->audio_interface->Create(PSGetInstanceId(), upipe_nacl_audio->audio_config, upipe_nacl_audio_worker, upipe); upipe_throw_ready(upipe); return upipe; }
static int NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { PP_Instance instance = PSGetInstanceId(); const PPB_Audio *ppb_audio = PSInterfaceAudio(); const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig(); private = (SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *private));
void Render() { struct PP_Size* psize = &g_Context.size; PP_ImageDataFormat format = PP_IMAGEDATAFORMAT_BGRA_PREMUL; PP_Resource image = g_pImageData->Create(PSGetInstanceId(), format, psize, PP_FALSE); uint8_t* pixels = g_pImageData->Map(image); struct PP_ImageDataDesc desc; uint8_t* cell_temp; uint32_t x, y; if (!g_Context.cell_in || !g_Context.cell_out) return; g_pImageData->Describe(image, &desc); Stir(desc.size.width, desc.size.height); for (y = 1; y < desc.size.height - 1; ++y) { uint8_t *src0 = (g_Context.cell_in + (y - 1) * desc.size.width) + 1; uint8_t *src1 = src0 + desc.size.width; uint8_t *src2 = src1 + desc.size.width; int count; uint32_t color; uint8_t *dst = (g_Context.cell_out + y * desc.size.width) + 1; uint32_t *pixel_line = (uint32_t*) (pixels + y * desc.stride); for (x = 1; x < (desc.size.width - 1); ++x) { count = src0[-1] + src0[0] + src0[1] + src1[-1] + src1[0] * 9 + src1[1] + src2[-1] + src2[0] + src2[1]; color = kNeighborColors[count]; *pixel_line++ = color; *dst++ = kIsAlive[count]; ++src0; ++src1; ++src2; } } cell_temp = g_Context.cell_in; g_Context.cell_in = g_Context.cell_out; g_Context.cell_out = cell_temp; g_pImageData->Unmap(image); g_pGraphics2D->ReplaceContents(g_Context.ctx, image); g_pGraphics2D->Flush(g_Context.ctx, PP_BlockUntilComplete()); g_pCore->ReleaseResource(image); }
void network_error() { Json::Value writerRoot; writerRoot["result"] = 1; writerRoot["type"] = "network error"; Json::StyledWriter writer; std::string msg(writer.write(writerRoot)); struct PP_Var var = PSInterfaceVar()->VarFromUtf8(msg.data(), msg.length()); PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), var); PSInterfaceVar()->Release(var); }
struct PP_Var nspawn_send_request(struct PP_Var req_var) { /* * naclprocess.js is required in order send requests to JavaScript. * If NACL_PROCESS is not set in the environment then we assume it is * not present and exit early. Without this check we would block forever * waiting for a response for the JavaScript side. * * Only check this once per process, as some programs (emacs) * engage in manipulation of the environment that may not be safely * read at all times. */ static int checked_for_nacl_process = 0; if (!checked_for_nacl_process) { const char* naclprocess = getenv("NACL_PROCESS"); if (naclprocess == NULL) { fprintf(stderr, "nspawn_send_request called without NACL_PROCESS set\n"); return PP_MakeNull(); } checked_for_nacl_process = 1; } int64_t id = get_request_id(); char req_id[64]; sprintf(req_id, "%lld", id); nspawn_dict_setstring(req_var, "id", req_id); struct NaClSpawnReply reply; pthread_mutex_init(&reply.mu, NULL); pthread_cond_init(&reply.cond, NULL); PSEventRegisterMessageHandler(req_id, &handle_reply, &reply); PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), req_var); nspawn_var_release(req_var); pthread_mutex_lock(&reply.mu); /* * Wait for response for JavaScript. This can block for an unbounded amount * of time (e.g. waiting for a response to waitpid). */ int error = pthread_cond_wait(&reply.cond, &reply.mu); pthread_mutex_unlock(&reply.mu); pthread_cond_destroy(&reply.cond); pthread_mutex_destroy(&reply.mu); PSEventRegisterMessageHandler(req_id, NULL, &reply); if (error != 0) { fprintf(stderr, "nspawn_send_request: pthread_cond_timedwait: %s\n", strerror(error)); return PP_MakeNull(); } return reply.result_var; }
int nacl_main(int argc, char *argv[]) { int status; PSEvent* ps_event; PP_Resource event; struct PP_Rect rect; int ready = 0; const PPB_View *ppb_view = PSInterfaceView(); /* This is started in a worker thread by ppapi_simple! */ /* Wait for the first PSE_INSTANCE_DIDCHANGEVIEW event before starting the app */ PSEventSetFilter(PSE_INSTANCE_DIDCHANGEVIEW); while (!ready) { /* Process all waiting events without blocking */ while (!ready && (ps_event = PSEventWaitAcquire()) != NULL) { event = ps_event->as_resource; switch(ps_event->type) { /* From DidChangeView, contains a view resource */ case PSE_INSTANCE_DIDCHANGEVIEW: ppb_view->GetRect(event, &rect); NACL_SetScreenResolution(rect.size.width, rect.size.height, 0); ready = 1; break; default: break; } PSEventRelease(ps_event); } } /* Do a default httpfs mount on /, * apps can override this by unmounting / * and remounting with the desired configuration */ nacl_io_init_ppapi(PSGetInstanceId(), PSGetInterface); umount("/"); mount( "", /* source */ "/", /* target */ "httpfs", /* filesystemtype */ 0, /* mountflags */ ""); /* data specific to the html5fs type */ /* Everything is ready, start the user main function */ SDL_SetMainReady(); status = SDL_main(argc, argv); return 0; }
int NACL_VideoInit(_THIS) { SDL_VideoData *driverdata = (SDL_VideoData *) _this->driverdata; SDL_DisplayMode mode; SDL_zero(mode); mode.format = driverdata->format; mode.w = driverdata->w; mode.h = driverdata->h; mode.refresh_rate = 0; mode.driverdata = NULL; if (SDL_AddBasicVideoDisplay(&mode) < 0) { return -1; } SDL_AddDisplayMode(&_this->displays[0], &mode); PSInterfaceInit(); driverdata->instance = PSGetInstanceId(); driverdata->ppb_graphics = PSInterfaceGraphics3D(); driverdata->ppb_message_loop = PSInterfaceMessageLoop(); driverdata->ppb_core = PSInterfaceCore(); driverdata->ppb_fullscreen = PSInterfaceFullscreen(); driverdata->ppb_instance = PSInterfaceInstance(); driverdata->ppb_image_data = PSInterfaceImageData(); driverdata->ppb_view = PSInterfaceView(); driverdata->ppb_var = PSInterfaceVar(); driverdata->ppb_input_event = (PPB_InputEvent*) PSGetInterface(PPB_INPUT_EVENT_INTERFACE); driverdata->ppb_keyboard_input_event = (PPB_KeyboardInputEvent*) PSGetInterface(PPB_KEYBOARD_INPUT_EVENT_INTERFACE); driverdata->ppb_mouse_input_event = (PPB_MouseInputEvent*) PSGetInterface(PPB_MOUSE_INPUT_EVENT_INTERFACE); driverdata->ppb_wheel_input_event = (PPB_WheelInputEvent*) PSGetInterface(PPB_WHEEL_INPUT_EVENT_INTERFACE); driverdata->ppb_touch_input_event = (PPB_TouchInputEvent*) PSGetInterface(PPB_TOUCH_INPUT_EVENT_INTERFACE); driverdata->message_loop = driverdata->ppb_message_loop->Create(driverdata->instance); PSEventSetFilter(PSE_ALL); /* We're done! */ return 0; }
void Render() { struct PP_Size* psize = &g_Context.size; PP_ImageDataFormat format = PP_IMAGEDATAFORMAT_BGRA_PREMUL; /* * Create a buffer to draw into. Since we are waiting until the next flush * chrome has an opportunity to cache this buffer see ppb_graphics_2d.h. */ PP_Resource image = g_pImageData->Create(PSGetInstanceId(), format, psize, PP_FALSE); uint8_t* pixels = g_pImageData->Map(image); struct PP_ImageDataDesc desc; uint8_t* cell_temp; uint32_t x, y; /* If we somehow have not allocated these pointers yet, skip this frame. */ if (!g_Context.cell_in || !g_Context.cell_out) return; /* Get the stride. */ g_pImageData->Describe(image, &desc); /* Stir up the edges to prevent the simulation from reaching steady state. */ Stir(desc.size.width, desc.size.height); /* Do neighbor summation; apply rules, output pixel color. */ for (y = 1; y < desc.size.height - 1; ++y) { uint8_t *src0 = (g_Context.cell_in + (y - 1) * desc.size.width) + 1; uint8_t *src1 = src0 + desc.size.width; uint8_t *src2 = src1 + desc.size.width; int count; uint32_t color; uint8_t *dst = (g_Context.cell_out + y * desc.size.width) + 1; uint32_t *pixel_line = (uint32_t*) (pixels + y * desc.stride); for (x = 1; x < (desc.size.width - 1); ++x) { /* Jitter and sum neighbors. */ count = src0[-1] + src0[0] + src0[1] + src1[-1] + + src1[1] + src2[-1] + src2[0] + src2[1]; /* Include center cell. */ count = count + count + src1[0]; /* Use table lookup indexed by count to determine pixel & alive state. */ color = kNeighborColors[count]; *pixel_line++ = color; *dst++ = kIsAlive[count]; ++src0; ++src1; ++src2; } } cell_temp = g_Context.cell_in; g_Context.cell_in = g_Context.cell_out; g_Context.cell_out = cell_temp; /* Unmap the range, we no longer need it. */ g_pImageData->Unmap(image); /* Replace the contexts, and block until it's on the screen. */ g_pGraphics2D->ReplaceContents(g_Context.ctx, image); g_pGraphics2D->Flush(g_Context.ctx, PP_BlockUntilComplete()); /* Release the image data, we no longer need it. */ g_pCore->ReleaseResource(image); }
static int NACL_Available(void) { return PSGetInstanceId() != 0; }
int ProcessProperties(void) { /* Reset verbosity if passed in */ const char* verbosity = getenv("PS_VERBOSITY"); if (verbosity) PSInstanceSetVerbosity(atoi(verbosity)); /* Enable NaCl IO to map STDIN, STDOUT, and STDERR */ nacl_io_init_ppapi(PSGetInstanceId(), PSGetInterface); s_tty_prefix = getenv("PS_TTY_PREFIX"); if (s_tty_prefix) { s_tty_fd = open("/dev/tty", O_WRONLY); if (s_tty_fd >= 0) { PSEventRegisterMessageHandler(s_tty_prefix, MessageHandlerInput, NULL); const char* tty_resize = getenv("PS_TTY_RESIZE"); if (tty_resize) PSEventRegisterMessageHandler(tty_resize, MessageHandlerResize, NULL); char* tty_rows = getenv("PS_TTY_ROWS"); char* tty_cols = getenv("PS_TTY_COLS"); if (tty_rows && tty_cols) { char* end = tty_rows; int rows = strtol(tty_rows, &end, 10); if (*end != '\0' || rows < 0) { PSInstanceError("Invalid value for PS_TTY_ROWS: %s\n", tty_rows); } else { end = tty_cols; int cols = strtol(tty_cols, &end, 10); if (*end != '\0' || cols < 0) PSInstanceError("Invalid value for PS_TTY_COLS: %s\n", tty_cols); else HandleResize(cols, rows); } } else if (tty_rows || tty_cols) { PSInstanceError("PS_TTY_ROWS and PS_TTY_COLS must be set together\n"); } struct tioc_nacl_output handler; handler.handler = TtyOutputHandler; handler.user_data = NULL; ioctl(s_tty_fd, TIOCNACLOUTPUT, &handler); } else { PSInstanceError("Failed to open /dev/tty.\n"); } } /* Set default values */ setenv("PS_STDIN", "/dev/stdin", 0); setenv("PS_STDOUT", "/dev/stdout", 0); setenv("PS_STDERR", "/dev/console3", 0); int fd0 = open(getenv("PS_STDIN"), O_RDONLY); dup2(fd0, 0); int fd1 = open(getenv("PS_STDOUT"), O_WRONLY); dup2(fd1, 1); int fd2 = open(getenv("PS_STDERR"), O_WRONLY); dup2(fd2, 2); PSEventRegisterMessageHandler("jspipe1", MessageHandlerInput, NULL); PSEventRegisterMessageHandler("jspipe2", MessageHandlerInput, NULL); PSEventRegisterMessageHandler("jspipe3", MessageHandlerInput, NULL); s_exit_message = getenv("PS_EXIT_MESSAGE"); /* If PS_EXIT_MESSAGE is set in the environment then we perform a handshake * with JavaScript when program exits. */ if (s_exit_message != NULL) nacl_io_set_exit_callback(ExitHandshake, NULL); /* Set line buffering on stdout and stderr */ #if !defined(WIN32) setvbuf(stderr, NULL, _IOLBF, 0); setvbuf(stdout, NULL, _IOLBF, 0); #endif return 1; }
int my_main(int argc, char *argv[]) { SDL_NACL_SetInstance(PSGetInstanceId(), 640, 480); umount("/"); mount("", "/", "memfs", 0, NULL); mount("", "/http", "httpfs", 0, "manifest=/manifest.txt"); mount("", "/save", "html5fs", 0, "type=PERSISTENT"); CopyFile("/http/font.ttf", "/font.ttf"); CopyFile("/http/sprites.sif", "/sprites.sif"); CopyFile("/http/tilekey.dat", "/tilekey.dat"); ExtractGameZip("/save/cavestoryen.zip"); mkdir("/pxt", 0666); PSEventSetFilter(PSE_INSTANCE_HANDLEINPUT | PSE_INSTANCE_DIDCHANGEFOCUS); #else int main(int argc, char *argv[]) { #endif bool inhibit_loadfade = false; bool error = false; bool freshstart; //SetLogFilename("debug.txt"); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { staterr("ack, sdl_init failed: %s.", SDL_GetError()); return 1; } atexit(SDL_Quit); // start up inputs first thing because settings_load may remap them input_init(); // load settings, or at least get the defaults, // so we know the initial screen resolution. settings_load(); if (Graphics::init(settings->resolution)) { staterr("Failed to initilize graphics."); return 1; } if (font_init()) { staterr("Failed to load font."); return 1; } //speed_test(); //return 1; #ifdef CONFIG_DATA_EXTRACTOR if (!settings->files_extracted) { if (extract_main()) { Graphics::close(); font_close(); return 0; } else { settings->files_extracted = true; settings_save(); } } #endif if (check_data_exists()) { return 1; } //Graphics::ShowLoadingScreen(); if (sound_init()) { fatal("Failed to initilize sound."); return 1; } if (trig_init()) { fatal("Failed trig module init."); return 1; } if (tsc_init()) { fatal("Failed to initilize script engine."); return 1; } if (textbox.Init()) { fatal("Failed to initialize textboxes."); return 1; } if (Carets::init()) { fatal("Failed to initialize carets."); return 1; } if (game.init()) return 1; game.setmode(GM_NORMAL); // set null stage just to have something to do while we go to intro game.switchstage.mapno = 0; //#define REPLAY #ifdef REPLAY game.switchstage.mapno = START_REPLAY; //Replay::set_ffwd(6000); //Replay::set_stopat(3500); game.switchstage.param = 1; #else //game.switchstage.mapno = LOAD_GAME; //game.pause(GP_OPTIONS); if (settings->skip_intro && file_exists(GetProfileName(settings->last_save_slot))) game.switchstage.mapno = LOAD_GAME; else game.setmode(GM_INTRO); #endif // for debug if (game.paused) { game.switchstage.mapno = 0; game.switchstage.eventonentry = 0; } if (game.switchstage.mapno == LOAD_GAME) inhibit_loadfade = true; game.running = true; freshstart = true; stat("Entering main loop..."); #ifdef __SDLSHIM__ set_console_visible(false); #endif //speed_test(); //return 1; while(game.running) { // SSS/SPS persists across stage transitions until explicitly // stopped, or you die & reload. It seems a bit risky to me, // but that's the spec. if (game.switchstage.mapno >= MAPNO_SPECIALS) { StopLoopSounds(); } // enter next stage, whatever it may be if (game.switchstage.mapno == LOAD_GAME || \ game.switchstage.mapno == LOAD_GAME_FROM_MENU) { if (game.switchstage.mapno == LOAD_GAME_FROM_MENU) freshstart = true; stat("= Loading game ="); if (game_load(settings->last_save_slot)) { fatal("savefile error"); goto ingame_error; } Replay::OnGameStarting(); if (!inhibit_loadfade) fade.Start(FADE_IN, FADE_CENTER); else inhibit_loadfade = false; } else if (game.switchstage.mapno == START_REPLAY) { stat(">> beginning replay '%s'", GetReplayName(game.switchstage.param)); StopScripts(); if (Replay::begin_playback(GetReplayName(game.switchstage.param))) { fatal("error starting playback"); goto ingame_error; } } else { if (game.switchstage.mapno == NEW_GAME || \ game.switchstage.mapno == NEW_GAME_FROM_MENU) { bool show_intro = (game.switchstage.mapno == NEW_GAME_FROM_MENU); InitNewGame(show_intro); } // slide weapon bar on first intro to Start Point if (game.switchstage.mapno == STAGE_START_POINT && \ game.switchstage.eventonentry == 91) { freshstart = true; } // switch maps if (load_stage(game.switchstage.mapno)) goto ingame_error; player->x = (game.switchstage.playerx * TILE_W) << CSF; player->y = (game.switchstage.playery * TILE_H) << CSF; } // start the level if (game.initlevel()) return 1; if (freshstart) weapon_introslide(); gameloop(); game.stageboss.OnMapExit(); freshstart = false; } shutdown: ; Replay::close(); game.close(); Carets::close(); Graphics::close(); input_close(); font_close(); sound_close(); tsc_close(); textbox.Deinit(); #ifdef __native_client__ pp::Instance(PSGetInstanceId()).PostMessage(pp::Var("quit")); while(1); #endif return error; ingame_error: ; stat(""); stat(" ************************************************"); stat(" * An in-game error occurred. Game shutting down."); stat(" ************************************************"); error = true; goto shutdown; }
// PostUpdateMessage() helper function for sendimg small messages to JS. void SimpleTemplate::PostUpdateMessage(const char* message_name, double value) { pp::VarDictionary message; message.Set("message", message_name); message.Set("value", value); PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var()); }