blob: d8e8f62fe239371d211d4167ab506c86d229dadf [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include "ppapi/c/pp_rect.h"
#include "ppapi/c/pp_size.h"
#include "ppapi_simple/ps_context_2d.h"
#include "goose.h"
#include "sprite.h"
#include "vector2.h"
namespace {
// The goose sprites rotate in increments of 5 degrees.
const double kGooseHeadingIncrement = (5.0 * M_PI) / 180.0;
} // namespace
struct ImageFormat {
int width;
int height;
int channels;
};
Sprite* g_goose_sprite;
std::vector<Goose> g_geese;
std::vector<Vector2> g_attractors;
void ResetFlock(PSContext2D_t* ctx, size_t count) {
Vector2 center(0.5 * ctx->width, 0.5 * ctx->height);
g_geese.resize(count);
for (size_t i = 0; i < count; i++) {
double dx = (double) rand() / (double) RAND_MAX;
double dy = (double) rand() / (double) RAND_MAX;
g_geese[i] = Goose(center, Vector2(dx, dy));
}
}
void Render(PSContext2D_t* ctx) {
PSContext2DGetBuffer(ctx);
const size_t num_geese = g_geese.size();
if (NULL == g_goose_sprite) return;
if (NULL == ctx->data) return;
// Clear to WHITE
memset(ctx->data, 0xFF, ctx->stride * ctx->height);
int32_t sprite_side_length = g_goose_sprite->size().height();
pp::Rect sprite_src_rect(0, 0, sprite_side_length, sprite_side_length);
pp::Rect canvas_bounds(pp::Size(ctx->width, ctx->height));
// Run the simulation for each goose.
for (size_t i = 0; i < num_geese; i++) {
Goose& goose = g_geese[i];
// Update position and orientation
goose.SimulationTick(g_geese, g_attractors, canvas_bounds);
pp::Point dest_point(goose.location().x() - sprite_side_length / 2,
goose.location().y() - sprite_side_length / 2);
// Compute image to use
double heading = goose.velocity().Heading();
if (heading < 0.0)
heading = M_PI * 2.0 + heading;
int32_t sprite_index =
static_cast<int32_t>(heading / kGooseHeadingIncrement);
sprite_src_rect.set_x(sprite_index * sprite_side_length);
g_goose_sprite->CompositeFromRectToPoint(
sprite_src_rect,
ctx->data, canvas_bounds, 0,
dest_point);
}
PSContext2DSwapBuffer(ctx);
}
/*
* Starting point for the module. We do not use main since it would
* collide with main in libppapi_cpp.
*/
int main(int argc, char *argv[]) {
ImageFormat fmt;
uint32_t* buffer;
size_t len;
PSEventSetFilter(PSE_ALL);
// Mount the images directory as an HTTP resource.
mount("images", "/images", "httpfs", 0, "");
FILE* fp = fopen("/images/flock_green.raw", "rb");
fread(&fmt, sizeof(fmt), 1, fp);
len = fmt.width * fmt.height * fmt.channels;
buffer = new uint32_t[len];
fread(buffer, 1, len, fp);
fclose(fp);
g_goose_sprite = new Sprite(buffer, pp::Size(fmt.width, fmt.height), 0);
PSContext2D_t* ctx = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
ResetFlock(ctx, 50);
while (1) {
PSEvent* event;
// Consume all available events
while ((event = PSEventTryAcquire()) != NULL) {
PSContext2DHandleEvent(ctx, event);
PSEventRelease(event);
}
if (ctx->bound) {
Render(ctx);
} else {
// If not bound, wait for an event which may signal a context becoming
// available, instead of spinning.
event = PSEventWaitAcquire();
if (PSContext2DHandleEvent(ctx, event))
ResetFlock(ctx, 50);
PSEventRelease(event);
}
}
return 0;
}