1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sys/mount.h> 9 10 #include <algorithm> 11 #include <sstream> 12 #include <string> 13 #include <vector> 14 15 #include "ppapi/c/pp_rect.h" 16 #include "ppapi/c/pp_size.h" 17 18 #include "ppapi_simple/ps_context_2d.h" 19 #include "ppapi_simple/ps_main.h" 20 21 #include "goose.h" 22 #include "sprite.h" 23 #include "vector2.h" 24 25 26 namespace { 27 // The goose sprites rotate in increments of 5 degrees. 28 const double kGooseHeadingIncrement = (5.0 * M_PI) / 180.0; 29 } // namespace 30 31 struct ImageFormat { 32 int width; 33 int height; 34 int channels; 35 }; 36 37 Sprite* g_goose_sprite; 38 std::vector<Goose> g_geese; 39 std::vector<Vector2> g_attractors; 40 41 42 void ResetFlock(PSContext2D_t* ctx, size_t count) { 43 Vector2 center(0.5 * ctx->width, 0.5 * ctx->height); 44 45 g_geese.resize(count); 46 for (size_t i = 0; i < count; i++) { 47 double dx = (double) rand() / (double) RAND_MAX; 48 double dy = (double) rand() / (double) RAND_MAX; 49 g_geese[i] = Goose(center, Vector2(dx, dy)); 50 } 51 } 52 53 void Render(PSContext2D_t* ctx) { 54 PSContext2DGetBuffer(ctx); 55 const size_t num_geese = g_geese.size(); 56 57 if (NULL == g_goose_sprite) return; 58 if (NULL == ctx->data) return; 59 60 // Clear to WHITE 61 memset(ctx->data, 0xFF, ctx->stride * ctx->height); 62 63 int32_t sprite_side_length = g_goose_sprite->size().height(); 64 pp::Rect sprite_src_rect(0, 0, sprite_side_length, sprite_side_length); 65 pp::Rect canvas_bounds(pp::Size(ctx->width, ctx->height)); 66 67 68 // Run the simulation for each goose. 69 for (size_t i = 0; i < num_geese; i++) { 70 Goose& goose = g_geese[i]; 71 72 // Update position and orientation 73 goose.SimulationTick(g_geese, g_attractors, canvas_bounds); 74 pp::Point dest_point(goose.location().x() - sprite_side_length / 2, 75 goose.location().y() - sprite_side_length / 2); 76 77 // Compute image to use 78 double heading = goose.velocity().Heading(); 79 if (heading < 0.0) 80 heading = M_PI * 2.0 + heading; 81 82 int32_t sprite_index = 83 static_cast<int32_t>(heading / kGooseHeadingIncrement); 84 85 sprite_src_rect.set_x(sprite_index * sprite_side_length); 86 g_goose_sprite->CompositeFromRectToPoint( 87 sprite_src_rect, 88 ctx->data, canvas_bounds, 0, 89 dest_point); 90 } 91 92 PSContext2DSwapBuffer(ctx); 93 } 94 95 /* 96 * Starting point for the module. We do not use main since it would 97 * collide with main in libppapi_cpp. 98 */ 99 int example_main(int argc, char *argv[]) { 100 ImageFormat fmt; 101 uint32_t* buffer; 102 size_t len; 103 104 PSEventSetFilter(PSE_ALL); 105 106 // Mount the images directory as an HTTP resource. 107 mount("images", "/images", "httpfs", 0, ""); 108 109 FILE* fp = fopen("/images/flock_green.raw", "rb"); 110 fread(&fmt, sizeof(fmt), 1, fp); 111 112 len = fmt.width * fmt.height * fmt.channels; 113 buffer = new uint32_t[len]; 114 fread(buffer, 1, len, fp); 115 fclose(fp); 116 117 g_goose_sprite = new Sprite(buffer, pp::Size(fmt.width, fmt.height), 0); 118 119 PSContext2D_t* ctx = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL); 120 ResetFlock(ctx, 50); 121 while (1) { 122 PSEvent* event; 123 124 // Consume all available events 125 while ((event = PSEventTryAcquire()) != NULL) { 126 PSContext2DHandleEvent(ctx, event); 127 PSEventRelease(event); 128 } 129 130 if (ctx->bound) { 131 Render(ctx); 132 } else { 133 // If not bound, wait for an event which may signal a context becoming 134 // available, instead of spinning. 135 event = PSEventWaitAcquire(); 136 if (PSContext2DHandleEvent(ctx, event)) 137 ResetFlock(ctx, 50); 138 PSEventRelease(event); 139 } 140 } 141 142 return 0; 143 } 144 145 /* 146 * Register the function to call once the Instance Object is initialized. 147 * see: pappi_simple/ps_main.h 148 */ 149 PPAPI_SIMPLE_REGISTER_MAIN(example_main); 150