1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file. 4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <assert.h> 6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <math.h> 73240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include <ppapi/c/ppb_input_event.h> 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <ppapi/cpp/input_event.h> 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <ppapi/cpp/var.h> 103240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include <ppapi/cpp/var_array.h> 113240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include <ppapi/cpp/var_array_buffer.h> 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <ppapi/cpp/var_dictionary.h> 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <pthread.h> 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <stdio.h> 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <stdlib.h> 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <string.h> 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <sys/time.h> 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <unistd.h> 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <algorithm> 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <string> 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 233240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ppapi_simple/ps.h" 243240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ppapi_simple/ps_context_2d.h" 253240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ppapi_simple/ps_event.h" 263240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ppapi_simple/ps_interface.h" 273240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ppapi_simple/ps_main.h" 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "sdk_util/thread_pool.h" 29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 30ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochusing namespace sdk_util; // For sdk_util::ThreadPool 31ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Global properties used to setup Voronoi demo. 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace { 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const int kMinRectSize = 4; 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const int kStartRecurseSize = 32; // must be power-of-two 36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const float kHugeZ = 1.0e38f; 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const float kPI = M_PI; 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const float kTwoPI = kPI * 2.0f; 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const int kFramesToBenchmark = 100; 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const unsigned int kRandomStartSeed = 0xC0DE533D; 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const int kMaxPointCount = 1024; 424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const int kStartPointCount = 48; 433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochconst int kDefaultNumRegions = 256; 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)unsigned int g_rand_state = kRandomStartSeed; 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// random number helper 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)inline unsigned char rand255() { 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return static_cast<unsigned char>(rand_r(&g_rand_state) & 255); 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// random number helper 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)inline float frand() { 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return (static_cast<float>(rand_r(&g_rand_state)) / 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<float>(RAND_MAX)); 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// reset random seed 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)inline void rand_reset(unsigned int seed) { 60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) g_rand_state = seed; 61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#ifndef NDEBUG 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// returns true if input is power of two. 6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// only used in assertions. 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)inline bool is_pow2(int x) { 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return (x & (x - 1)) == 0; 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#endif 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)inline double getseconds() { 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const double usec_to_sec = 0.000001; 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) timeval tv; 74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (0 == gettimeofday(&tv, NULL)) 75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return tv.tv_sec + tv.tv_usec * usec_to_sec; 76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return 0.0; 77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// BGRA helper function, for constructing a pixel for a BGRA buffer. 803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)inline uint32_t MakeBGRA(uint32_t b, uint32_t g, uint32_t r, uint32_t a) { 81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)); 82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Vec2, simple 2D vector 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)struct Vec2 { 87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float x, y; 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2() {} 89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2(float px, float py) { 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) x = px; 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) y = py; 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void Set(float px, float py) { 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) x = px; 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) y = py; 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}; 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// The main object that runs Voronoi simulation. 1003240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochclass Voronoi { 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public: 1023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch Voronoi(); 103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) virtual ~Voronoi(); 1043240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Runs a tick of the simulations, update 2D output. 1053240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch void Update(); 1063240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Handle event from user, or message from JS. 1073240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch void HandleEvent(PSEvent* ps_event); 108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private: 110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Methods prefixed with 'w' are run on worker threads. 1113240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t* wGetAddr(int x, int y); 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int wCell(float x, float y); 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) inline void wFillSpan(uint32_t *pixels, uint32_t color, int width); 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wRenderTile(int x, int y, int w, int h); 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wProcessTile(int x, int y, int w, int h); 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wSubdivide(int x, int y, int w, int h); 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wMakeRect(int region, int *x, int *y, int *w, int *h); 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool wTestRect(int *m, int x, int y, int w, int h); 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wFillRect(int x, int y, int w, int h, uint32_t color); 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wRenderRect(int x0, int y0, int x1, int y1); 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wRenderRegion(int region); 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static void wRenderRegionEntry(int region, void *thiz); 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // These methods are only called by the main thread. 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void Reset(); 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void UpdateSim(); 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void RenderDot(float x, float y, uint32_t color1, uint32_t color2); 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void SuperimposePositions(); 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void Render(); 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void Draw(); 131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void StartBenchmark(); 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void EndBenchmark(); 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Helper to post small update messages to JS. 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void PostUpdateMessage(const char* message_name, double value); 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 1363240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSContext2D_t* ps_context_; 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2 positions_[kMaxPointCount]; 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2 screen_positions_[kMaxPointCount]; 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2 velocities_[kMaxPointCount]; 140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) uint32_t colors_[kMaxPointCount]; 141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float ang_; 142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int num_regions_; 1433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int num_threads_; 1443240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int point_count_; 145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool draw_points_; 146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool draw_interiors_; 147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ThreadPool* workers_; 148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int benchmark_frame_counter_; 149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool benchmarking_; 150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) double benchmark_start_time_; 151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) double benchmark_end_time_; 152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}; 153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::Reset() { 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rand_reset(kRandomStartSeed); 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ang_ = 0.0f; 158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 0; i < kMaxPointCount; i++) { 159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // random initial start position 160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const float x = frand(); 161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const float y = frand(); 162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) positions_[i].Set(x, y); 163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // random directional velocity ( -1..1, -1..1 ) 164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const float speed = 0.0005f; 165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const float u = (frand() * 2.0f - 1.0f) * speed; 166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const float v = (frand() * 2.0f - 1.0f) * speed; 167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) velocities_[i].Set(u, v); 168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // 'unique' color (well... unique enough for our purposes) 1693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) colors_[i] = MakeBGRA(rand255(), rand255(), rand255(), 255); 170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 1733240926e260ce088908e02ac07a6cf7b0c0cbf44Ben MurdochVoronoi::Voronoi() : num_regions_(kDefaultNumRegions), num_threads_(0), 1743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch point_count_(kStartPointCount), draw_points_(true), draw_interiors_(true), 1753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch benchmark_frame_counter_(0), benchmarking_(false) { 176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Reset(); 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // By default, render from the dispatch thread. 178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) workers_ = new ThreadPool(num_threads_); 1793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSEventSetFilter(PSE_ALL); 1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL); 181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)Voronoi::~Voronoi() { 184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) delete workers_; 1853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSContext2DFree(ps_context_); 1863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch} 1873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1883240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochinline uint32_t* Voronoi::wGetAddr(int x, int y) { 1893240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return ps_context_->data + x + y * ps_context_->stride / sizeof(uint32_t); 190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// This is the core of the Voronoi calculation. At a given point on the 193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// screen, iterate through all voronoi positions and render them as 3D cones. 194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// We're looking for the voronoi cell that generates the closest z value. 195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// (not really cones - since it is all relative, we avoid doing the 196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// expensive sqrt and test against z*z instead) 197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)int Voronoi::wCell(float x, float y) { 199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int closest_cell = 0; 200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float zz = kHugeZ; 201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2* pos = screen_positions_; 202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 0; i < point_count_; ++i) { 203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // measured 5.18 cycles per iteration on a core2 204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float dx = x - pos[i].x; 205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float dy = y - pos[i].y; 206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float dd = (dx * dx + dy * dy); 207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (dd < zz) { 208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) zz = dd; 209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) closest_cell = i; 210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return closest_cell; 213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Given a region r, derive a non-overlapping rectangle for a thread to 216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// work on. 217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wMakeRect(int r, int* x, int* y, int* w, int* h) { 219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int parts = 16; 220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) assert(parts * parts == num_regions_); 2213240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch *w = ps_context_->width / parts; 2223240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch *h = ps_context_->height / parts; 223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *x = *w * (r % parts); 224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *y = *h * ((r / parts) % parts); 225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Test 4 corners of a rectangle to see if they all belong to the same 228868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// voronoi cell. Each test is expensive so bail asap. Returns true 229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// if all 4 corners match. 230868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 231868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool Voronoi::wTestRect(int* m, int x, int y, int w, int h) { 232868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // each test is expensive, so exit ASAP 233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int m0 = wCell(x, y); 234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int m1 = wCell(x + w - 1, y); 235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (m0 != m1) return false; 236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int m2 = wCell(x, y + h - 1); 237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (m0 != m2) return false; 238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int m3 = wCell(x + w - 1, y + h - 1); 239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (m0 != m3) return false; 240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // all 4 corners belong to the same cell 241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *m = m0; 242868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Quickly fill a span of pixels with a solid color. Assumes 246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// span width is divisible by 4. 247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)inline void Voronoi::wFillSpan(uint32_t* pixels, uint32_t color, int width) { 249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!draw_interiors_) { 2503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const uint32_t gray = MakeBGRA(128, 128, 128, 255); 251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) color = gray; 252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 0; i < width; i += 4) { 254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *pixels++ = color; 255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *pixels++ = color; 256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *pixels++ = color; 257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *pixels++ = color; 258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 259868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Quickly fill a rectangle with a solid color. Assumes 262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// the width w parameter is evenly divisible by 4. 263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wFillRect(int x, int y, int w, int h, uint32_t color) { 2653240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t); 2663240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t* pixels = wGetAddr(x, y); 267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int j = 0; j < h; j++) { 268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wFillSpan(pixels, color, w); 2693240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pixels += stride_in_pixels; 270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// When recursive subdivision reaches a certain minimum without finding a 274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// rectangle that has four matching corners belonging to the same voronoi 275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// cell, this function will break the retangular 'tile' into smaller scanlines 276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// and look for opportunities to quick fill at the scanline level. If the 277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// scanline can't be quick filled, it will slow down even further and compute 278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// voronoi membership per pixel. 279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wRenderTile(int x, int y, int w, int h) { 280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // rip through a tile 2813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t); 2823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t* pixels = wGetAddr(x, y); 283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int j = 0; j < h; j++) { 284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // get start and end cell values 285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int ms = wCell(x + 0, y + j); 286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int me = wCell(x + w - 1, y + j); 287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // if the end points are the same, quick fill the span 288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (ms == me) { 289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wFillSpan(pixels, colors_[ms], w); 290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // else compute each pixel in the span... this is the slow part! 292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) uint32_t* p = pixels; 293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *p++ = colors_[ms]; 294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 1; i < (w - 1); i++) { 295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int m = wCell(x + i, y + j); 296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *p++ = colors_[m]; 297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *p++ = colors_[me]; 299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 3003240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pixels += stride_in_pixels; 301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Take a rectangular region and do one of - 305868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If all four corners below to the same voronoi cell, stop recursion and 306868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// quick fill the rectangle. 307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If the minimum rectangle size has been reached, break out of recursion 308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// and process the rectangle. This small rectangle is called a tile. 309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Otherwise, keep recursively subdividing the rectangle into 4 equally 310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// sized smaller rectangles. 311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Note: at the moment, these will always be squares, not rectangles. 312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wSubdivide(int x, int y, int w, int h) { 314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int m; 315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // if all 4 corners are equal, quick fill interior 316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (wTestRect(&m, x, y, w, h)) { 317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wFillRect(x, y, w, h, colors_[m]); 318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // did we reach the minimum rectangle size? 320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if ((w <= kMinRectSize) || (h <= kMinRectSize)) { 321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wRenderTile(x, y, w, h); 322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // else recurse into smaller rectangles 324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int half_w = w / 2; 325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int half_h = h / 2; 326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wSubdivide(x, y, half_w, half_h); 327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wSubdivide(x + half_w, y, half_w, half_h); 328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wSubdivide(x, y + half_h, half_w, half_h); 329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wSubdivide(x + half_w, y + half_h, half_w, half_h); 330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// This function cuts up the rectangle into power of 2 sized squares. It 335868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// assumes the input rectangle w & h are evenly divisible by 336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// kStartRecurseSize. 337868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 338868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wRenderRect(int x, int y, int w, int h) { 339868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int iy = y; iy < (y + h); iy += kStartRecurseSize) { 340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int ix = x; ix < (x + w); ix += kStartRecurseSize) { 341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wSubdivide(ix, iy, kStartRecurseSize, kStartRecurseSize); 342868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 344868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wRenderRegion(int region) { 348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // convert region # into x0, y0, x1, y1 rectangle 349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int x, y, w, h; 350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wMakeRect(region, &x, &y, &w, &h); 351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // render this rectangle 352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wRenderRect(x, y, w, h); 353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Entry point for worker thread. Can't pass a member function around, so we 356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// have to do this little round-about. 357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wRenderRegionEntry(int region, void* thiz) { 358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<Voronoi*>(thiz)->wRenderRegion(region); 359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Function Voronoi::UpdateSim() 362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Run a simple sim to move the voronoi positions. This update loop 363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// is run once per frame. Called from the main thread only, and only 364868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// when the worker threads are idle. 365868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::UpdateSim() { 366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ang_ += 0.002f; 367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (ang_ > kTwoPI) { 368868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ang_ = ang_ - kTwoPI; 369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float z = cosf(ang_) * 3.0f; 371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // push the points around on the screen for animation 372868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int j = 0; j < kMaxPointCount; j++) { 373868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) positions_[j].x += (velocities_[j].x) * z; 374868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) positions_[j].y += (velocities_[j].y) * z; 3753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch screen_positions_[j].x = positions_[j].x * ps_context_->width; 3763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch screen_positions_[j].y = positions_[j].y * ps_context_->height; 377868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 378868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 379868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 380868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Renders a small diamond shaped dot at x, y clipped against the window 381868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::RenderDot(float x, float y, uint32_t color1, uint32_t color2) { 382868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int ix = static_cast<int>(x); 383868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int iy = static_cast<int>(y); 3843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t); 385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // clip it against window 386868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (ix < 1) return; 3873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (ix >= (ps_context_->width - 1)) return; 388868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (iy < 1) return; 3893240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (iy >= (ps_context_->height - 1)) return; 3903240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t* pixel = wGetAddr(ix, iy); 391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // render dot as a small diamond 392868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *pixel = color1; 393868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *(pixel - 1) = color2; 394868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *(pixel + 1) = color2; 3953240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch *(pixel - stride_in_pixels) = color2; 3963240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch *(pixel + stride_in_pixels) = color2; 397868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 398868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 399868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Superimposes dots on the positions. 400868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::SuperimposePositions() { 4013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const uint32_t white = MakeBGRA(255, 255, 255, 255); 4023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const uint32_t gray = MakeBGRA(192, 192, 192, 255); 403868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 0; i < point_count_; i++) { 404868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) RenderDot( 405868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) screen_positions_[i].x, screen_positions_[i].y, white, gray); 406868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 407868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 408868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 409868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Renders the Voronoi diagram, dispatching the work to multiple threads. 410868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::Render() { 411868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) workers_->Dispatch(num_regions_, wRenderRegionEntry, this); 412868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (draw_points_) 413868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SuperimposePositions(); 414868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 415868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 416868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::StartBenchmark() { 417868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Reset(); 418868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) printf("Benchmark started...\n"); 419868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmark_frame_counter_ = kFramesToBenchmark; 420868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmarking_ = true; 421868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmark_start_time_ = getseconds(); 422868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 423868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 424868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::EndBenchmark() { 425868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmark_end_time_ = getseconds(); 426868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) printf("Benchmark ended... time: %2.5f\n", 427868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmark_end_time_ - benchmark_start_time_); 428868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmarking_ = false; 429868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmark_frame_counter_ = 0; 430eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch double result = benchmark_end_time_ - benchmark_start_time_; 431eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PostUpdateMessage("benchmark_result", result); 432868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 433868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 4343240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Handle input events from the user and messages from JS. 4353240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid Voronoi::HandleEvent(PSEvent* ps_event) { 4363240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Give the 2D context a chance to process the event. 4373240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (0 != PSContext2DHandleEvent(ps_context_, ps_event)) 4383240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return; 4393240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) { 4403240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Convert Pepper Simple event to a PPAPI C++ event 4413240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::InputEvent event(ps_event->as_resource); 4423240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch switch (event.GetType()) { 4433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch case PP_INPUTEVENT_TYPE_KEYDOWN: { 4443240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event); 4453240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t key_code = key.GetKeyCode(); 4463240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (key_code == 84) // 't' key 4473240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (!benchmarking_) 4483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch StartBenchmark(); 4493240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch break; 4503240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 4514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case PP_INPUTEVENT_TYPE_TOUCHSTART: 4524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) case PP_INPUTEVENT_TYPE_TOUCHMOVE: { 4534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) pp::TouchInputEvent touches = pp::TouchInputEvent(event); 4544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) uint32_t count = touches.GetTouchCount(PP_TOUCHLIST_TYPE_TOUCHES); 4554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Touch points 0..n directly set position of points 0..n in 4564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Voronoi diagram. 4574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (uint32_t i = 0; i < count; i++) { 4584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) pp::TouchPoint touch = 4594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) touches.GetTouchByIndex(PP_TOUCHLIST_TYPE_TOUCHES, i); 4604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) pp::FloatPoint point = touch.position(); 4614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) positions_[i].Set(point.x() / ps_context_->width, 4624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) point.y() / ps_context_->height); 4634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 4644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) break; 4654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 4663240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch default: 4673240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch break; 468868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 4693240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } else if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) { 4703240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Convert Pepper Simple message to PPAPI C++ var 4713240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::Var var(ps_event->as_var); 4723240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (var.is_dictionary()) { 4733240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::VarDictionary dictionary(var); 4743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch std::string message = dictionary.Get("message").AsString(); 4753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (message == "run_benchmark" && !benchmarking_) 4763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch StartBenchmark(); 4773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch else if (message == "draw_points") 4783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch draw_points_ = dictionary.Get("value").AsBool(); 4793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch else if (message == "draw_interiors") 4803240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch draw_interiors_ = dictionary.Get("value").AsBool(); 4813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch else if (message == "set_points") { 4823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int num_points = dictionary.Get("value").AsInt(); 4833240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch point_count_ = std::min(kMaxPointCount, std::max(0, num_points)); 4843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } else if (message == "set_threads") { 4853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int thread_count = dictionary.Get("value").AsInt(); 4863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch delete workers_; 4873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch workers_ = new ThreadPool(thread_count); 4883240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 489868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 490868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 491868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 492868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// PostUpdateMessage() helper function for sendimg small messages to JS. 494eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Voronoi::PostUpdateMessage(const char* message_name, double value) { 495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pp::VarDictionary message; 496eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch message.Set("message", message_name); 497eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch message.Set("value", value); 4983240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var()); 499868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 500868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 501868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::Update() { 5023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSContext2DGetBuffer(ps_context_); 5033240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (NULL == ps_context_->data) 5043240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return; 5053240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch assert(is_pow2(ps_context_->width)); 5063240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch assert(is_pow2(ps_context_->height)); 5073240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 5083240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // When benchmarking is running, don't update display via 5093240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // PSContext2DSwapBuffer() - vsync is enabled by default, and will throttle 5103240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // the benchmark results. 511868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) do { 512868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UpdateSim(); 513868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Render(); 514868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!benchmarking_) break; 515868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) --benchmark_frame_counter_; 516868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } while (benchmark_frame_counter_ > 0); 517868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (benchmarking_) 518868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EndBenchmark(); 519868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5203240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSContext2DSwapBuffer(ps_context_); 521868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 522868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5233240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Starting point for the module. We do not use main since it would 5243240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// collide with main in libppapi_cpp. 5253240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochint example_main(int argc, char* argv[]) { 5263240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch Voronoi voronoi; 5273240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch while (true) { 5283240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSEvent* ps_event; 5293240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Consume all available events. 5303240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch while ((ps_event = PSEventTryAcquire()) != NULL) { 5313240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch voronoi.HandleEvent(ps_event); 5323240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSEventRelease(ps_event); 5333240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 5343240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Do simulation, render and present. 5353240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch voronoi.Update(); 536868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 537868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5383240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return 0; 539868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 540868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5413240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Register the function to call once the Instance Object is initialized. 5423240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// see: pappi_simple/ps_main.h 5433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben MurdochPPAPI_SIMPLE_REGISTER_MAIN(example_main); 544