Home | History | Annotate | Download | only in flock
      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