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; 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const int kStartPointCount = 256; 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) 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// returns true if input is power of two. 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)inline bool is_pow2(int x) { 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return (x & (x - 1)) == 0; 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)inline double getseconds() { 69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const double usec_to_sec = 0.000001; 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) timeval tv; 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (0 == gettimeofday(&tv, NULL)) 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return tv.tv_sec + tv.tv_usec * usec_to_sec; 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return 0.0; 74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 76f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)// BGRA helper function, for constructing a pixel for a BGRA buffer. 77f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles)inline uint32_t MakeBGRA(uint32_t b, uint32_t g, uint32_t r, uint32_t a) { 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)); 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace 81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Vec2, simple 2D vector 83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)struct Vec2 { 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float x, y; 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2() {} 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2(float px, float py) { 87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) x = px; 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) y = py; 89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void Set(float px, float py) { 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) x = px; 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) y = py; 93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}; 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// The main object that runs Voronoi simulation. 973240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochclass Voronoi { 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public: 993240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch Voronoi(); 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) virtual ~Voronoi(); 1013240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Runs a tick of the simulations, update 2D output. 1023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch void Update(); 1033240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Handle event from user, or message from JS. 1043240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch void HandleEvent(PSEvent* ps_event); 105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private: 107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Methods prefixed with 'w' are run on worker threads. 1083240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t* wGetAddr(int x, int y); 109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int wCell(float x, float y); 110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) inline void wFillSpan(uint32_t *pixels, uint32_t color, int width); 111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wRenderTile(int x, int y, int w, int h); 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wProcessTile(int x, int y, int w, int h); 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wSubdivide(int x, int y, int w, int h); 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wMakeRect(int region, int *x, int *y, int *w, int *h); 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool wTestRect(int *m, int x, int y, int w, int h); 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wFillRect(int x, int y, int w, int h, uint32_t color); 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wRenderRect(int x0, int y0, int x1, int y1); 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void wRenderRegion(int region); 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static void wRenderRegionEntry(int region, void *thiz); 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // These methods are only called by the main thread. 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void Reset(); 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void UpdateSim(); 124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void RenderDot(float x, float y, uint32_t color1, uint32_t color2); 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void SuperimposePositions(); 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void Render(); 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void Draw(); 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void StartBenchmark(); 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void EndBenchmark(); 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Helper to post small update messages to JS. 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void PostUpdateMessage(const char* message_name, double value); 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 1333240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSContext2D_t* ps_context_; 134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2 positions_[kMaxPointCount]; 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2 screen_positions_[kMaxPointCount]; 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2 velocities_[kMaxPointCount]; 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) uint32_t colors_[kMaxPointCount]; 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float ang_; 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int num_regions_; 1403240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int num_threads_; 1413240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int point_count_; 142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool draw_points_; 143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool draw_interiors_; 144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ThreadPool* workers_; 145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int benchmark_frame_counter_; 146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool benchmarking_; 147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) double benchmark_start_time_; 148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) double benchmark_end_time_; 149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}; 150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::Reset() { 153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rand_reset(kRandomStartSeed); 154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ang_ = 0.0f; 155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 0; i < kMaxPointCount; i++) { 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // random initial start position 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const float x = frand(); 158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const float y = frand(); 159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) positions_[i].Set(x, y); 160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // random directional velocity ( -1..1, -1..1 ) 161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const float speed = 0.0005f; 162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const float u = (frand() * 2.0f - 1.0f) * speed; 163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const float v = (frand() * 2.0f - 1.0f) * speed; 164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) velocities_[i].Set(u, v); 165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // 'unique' color (well... unique enough for our purposes) 166f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles) colors_[i] = MakeBGRA(rand255(), rand255(), rand255(), 255); 167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 1703240926e260ce088908e02ac07a6cf7b0c0cbf44Ben MurdochVoronoi::Voronoi() : num_regions_(kDefaultNumRegions), num_threads_(0), 1713240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch point_count_(kStartPointCount), draw_points_(true), draw_interiors_(true), 1723240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch benchmark_frame_counter_(0), benchmarking_(false) { 173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Reset(); 174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // By default, render from the dispatch thread. 175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) workers_ = new ThreadPool(num_threads_); 1763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSEventSetFilter(PSE_ALL); 177f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles) ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL); 178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)Voronoi::~Voronoi() { 181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) delete workers_; 1823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSContext2DFree(ps_context_); 1833240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch} 1843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 1853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochinline uint32_t* Voronoi::wGetAddr(int x, int y) { 1863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return ps_context_->data + x + y * ps_context_->stride / sizeof(uint32_t); 187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// This is the core of the Voronoi calculation. At a given point on the 190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// screen, iterate through all voronoi positions and render them as 3D cones. 191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// We're looking for the voronoi cell that generates the closest z value. 192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// (not really cones - since it is all relative, we avoid doing the 193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// expensive sqrt and test against z*z instead) 194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)int Voronoi::wCell(float x, float y) { 196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int closest_cell = 0; 197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float zz = kHugeZ; 198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Vec2* pos = screen_positions_; 199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 0; i < point_count_; ++i) { 200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // measured 5.18 cycles per iteration on a core2 201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float dx = x - pos[i].x; 202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float dy = y - pos[i].y; 203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float dd = (dx * dx + dy * dy); 204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (dd < zz) { 205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) zz = dd; 206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) closest_cell = i; 207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return closest_cell; 210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Given a region r, derive a non-overlapping rectangle for a thread to 213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// work on. 214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wMakeRect(int r, int* x, int* y, int* w, int* h) { 216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int parts = 16; 217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) assert(parts * parts == num_regions_); 2183240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch *w = ps_context_->width / parts; 2193240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch *h = ps_context_->height / parts; 220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *x = *w * (r % parts); 221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *y = *h * ((r / parts) % parts); 222868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Test 4 corners of a rectangle to see if they all belong to the same 225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// voronoi cell. Each test is expensive so bail asap. Returns true 226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// if all 4 corners match. 227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 228868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool Voronoi::wTestRect(int* m, int x, int y, int w, int h) { 229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // each test is expensive, so exit ASAP 230868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int m0 = wCell(x, y); 231868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int m1 = wCell(x + w - 1, y); 232868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (m0 != m1) return false; 233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int m2 = wCell(x, y + h - 1); 234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (m0 != m2) return false; 235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int m3 = wCell(x + w - 1, y + h - 1); 236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (m0 != m3) return false; 237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // all 4 corners belong to the same cell 238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *m = m0; 239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 242868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Quickly fill a span of pixels with a solid color. Assumes 243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// span width is divisible by 4. 244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)inline void Voronoi::wFillSpan(uint32_t* pixels, uint32_t color, int width) { 246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!draw_interiors_) { 247f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles) const uint32_t gray = MakeBGRA(128, 128, 128, 255); 248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) color = gray; 249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 0; i < width; i += 4) { 251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *pixels++ = color; 252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *pixels++ = color; 253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *pixels++ = color; 254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *pixels++ = color; 255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Quickly fill a rectangle with a solid color. Assumes 259868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// the width w parameter is evenly divisible by 4. 260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wFillRect(int x, int y, int w, int h, uint32_t color) { 2623240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t); 2633240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t* pixels = wGetAddr(x, y); 264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int j = 0; j < h; j++) { 265868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wFillSpan(pixels, color, w); 2663240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pixels += stride_in_pixels; 267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// When recursive subdivision reaches a certain minimum without finding a 271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// rectangle that has four matching corners belonging to the same voronoi 272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// cell, this function will break the retangular 'tile' into smaller scanlines 273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// and look for opportunities to quick fill at the scanline level. If the 274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// scanline can't be quick filled, it will slow down even further and compute 275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// voronoi membership per pixel. 276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wRenderTile(int x, int y, int w, int h) { 277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // rip through a tile 2783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t); 2793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t* pixels = wGetAddr(x, y); 280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int j = 0; j < h; j++) { 281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // get start and end cell values 282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int ms = wCell(x + 0, y + j); 283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int me = wCell(x + w - 1, y + j); 284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // if the end points are the same, quick fill the span 285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (ms == me) { 286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wFillSpan(pixels, colors_[ms], w); 287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // else compute each pixel in the span... this is the slow part! 289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) uint32_t* p = pixels; 290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *p++ = colors_[ms]; 291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 1; i < (w - 1); i++) { 292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int m = wCell(x + i, y + j); 293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *p++ = colors_[m]; 294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *p++ = colors_[me]; 296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 2973240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pixels += stride_in_pixels; 298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Take a rectangular region and do one of - 302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If all four corners below to the same voronoi cell, stop recursion and 303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// quick fill the rectangle. 304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If the minimum rectangle size has been reached, break out of recursion 305868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// and process the rectangle. This small rectangle is called a tile. 306868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Otherwise, keep recursively subdividing the rectangle into 4 equally 307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// sized smaller rectangles. 308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Note: at the moment, these will always be squares, not rectangles. 309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wSubdivide(int x, int y, int w, int h) { 311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int m; 312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // if all 4 corners are equal, quick fill interior 313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (wTestRect(&m, x, y, w, h)) { 314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wFillRect(x, y, w, h, colors_[m]); 315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // did we reach the minimum rectangle size? 317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if ((w <= kMinRectSize) || (h <= kMinRectSize)) { 318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wRenderTile(x, y, w, h); 319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // else recurse into smaller rectangles 321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int half_w = w / 2; 322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int half_h = h / 2; 323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wSubdivide(x, y, half_w, half_h); 324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wSubdivide(x + half_w, y, half_w, half_h); 325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wSubdivide(x, y + half_h, half_w, half_h); 326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wSubdivide(x + half_w, y + half_h, half_w, half_h); 327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// This function cuts up the rectangle into power of 2 sized squares. It 332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// assumes the input rectangle w & h are evenly divisible by 333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// kStartRecurseSize. 334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 335868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wRenderRect(int x, int y, int w, int h) { 336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int iy = y; iy < (y + h); iy += kStartRecurseSize) { 337868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int ix = x; ix < (x + w); ix += kStartRecurseSize) { 338868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wSubdivide(ix, iy, kStartRecurseSize, kStartRecurseSize); 339868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 342868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 344868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wRenderRegion(int region) { 345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // convert region # into x0, y0, x1, y1 rectangle 346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int x, y, w, h; 347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wMakeRect(region, &x, &y, &w, &h); 348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // render this rectangle 349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wRenderRect(x, y, w, h); 350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Entry point for worker thread. Can't pass a member function around, so we 353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// have to do this little round-about. 354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::wRenderRegionEntry(int region, void* thiz) { 355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) static_cast<Voronoi*>(thiz)->wRenderRegion(region); 356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Function Voronoi::UpdateSim() 359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Run a simple sim to move the voronoi positions. This update loop 360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// is run once per frame. Called from the main thread only, and only 361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// when the worker threads are idle. 362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::UpdateSim() { 363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ang_ += 0.002f; 364868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (ang_ > kTwoPI) { 365868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ang_ = ang_ - kTwoPI; 366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) float z = cosf(ang_) * 3.0f; 368868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // push the points around on the screen for animation 369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int j = 0; j < kMaxPointCount; j++) { 370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) positions_[j].x += (velocities_[j].x) * z; 371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) positions_[j].y += (velocities_[j].y) * z; 3723240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch screen_positions_[j].x = positions_[j].x * ps_context_->width; 3733240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch screen_positions_[j].y = positions_[j].y * ps_context_->height; 374868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 375868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 376868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 377868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Renders a small diamond shaped dot at x, y clipped against the window 378868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::RenderDot(float x, float y, uint32_t color1, uint32_t color2) { 379868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int ix = static_cast<int>(x); 380868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const int iy = static_cast<int>(y); 3813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t); 382868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // clip it against window 383868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (ix < 1) return; 3843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (ix >= (ps_context_->width - 1)) return; 385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (iy < 1) return; 3863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (iy >= (ps_context_->height - 1)) return; 3873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t* pixel = wGetAddr(ix, iy); 388868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // render dot as a small diamond 389868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *pixel = color1; 390868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *(pixel - 1) = color2; 391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *(pixel + 1) = color2; 3923240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch *(pixel - stride_in_pixels) = color2; 3933240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch *(pixel + stride_in_pixels) = color2; 394868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 395868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 396868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Superimposes dots on the positions. 397868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::SuperimposePositions() { 398f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles) const uint32_t white = MakeBGRA(255, 255, 255, 255); 399f3ce491c3623b9924dccab3703a43e03157e988aTorne (Richard Coles) const uint32_t gray = MakeBGRA(192, 192, 192, 255); 400868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (int i = 0; i < point_count_; i++) { 401868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) RenderDot( 402868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) screen_positions_[i].x, screen_positions_[i].y, white, gray); 403868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 404868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 405868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 406868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Renders the Voronoi diagram, dispatching the work to multiple threads. 407868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::Render() { 408868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) workers_->Dispatch(num_regions_, wRenderRegionEntry, this); 409868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (draw_points_) 410868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) SuperimposePositions(); 411868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 412868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 413868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::StartBenchmark() { 414868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Reset(); 415868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) printf("Benchmark started...\n"); 416868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmark_frame_counter_ = kFramesToBenchmark; 417868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmarking_ = true; 418868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmark_start_time_ = getseconds(); 419868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 420868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 421868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::EndBenchmark() { 422868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmark_end_time_ = getseconds(); 423868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) printf("Benchmark ended... time: %2.5f\n", 424868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmark_end_time_ - benchmark_start_time_); 425868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmarking_ = false; 426868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) benchmark_frame_counter_ = 0; 427eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch double result = benchmark_end_time_ - benchmark_start_time_; 428eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PostUpdateMessage("benchmark_result", result); 429868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 430868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 4313240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Handle input events from the user and messages from JS. 4323240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid Voronoi::HandleEvent(PSEvent* ps_event) { 4333240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Give the 2D context a chance to process the event. 4343240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (0 != PSContext2DHandleEvent(ps_context_, ps_event)) 4353240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return; 4363240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) { 4373240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Convert Pepper Simple event to a PPAPI C++ event 4383240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::InputEvent event(ps_event->as_resource); 4393240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch switch (event.GetType()) { 4403240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch case PP_INPUTEVENT_TYPE_KEYDOWN: { 4413240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event); 4423240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t key_code = key.GetKeyCode(); 4433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (key_code == 84) // 't' key 4443240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (!benchmarking_) 4453240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch StartBenchmark(); 4463240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch break; 4473240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 4483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch default: 4493240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch break; 450868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 4513240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } else if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) { 4523240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Convert Pepper Simple message to PPAPI C++ var 4533240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::Var var(ps_event->as_var); 4543240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (var.is_dictionary()) { 4553240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::VarDictionary dictionary(var); 4563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch std::string message = dictionary.Get("message").AsString(); 4573240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (message == "run_benchmark" && !benchmarking_) 4583240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch StartBenchmark(); 4593240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch else if (message == "draw_points") 4603240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch draw_points_ = dictionary.Get("value").AsBool(); 4613240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch else if (message == "draw_interiors") 4623240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch draw_interiors_ = dictionary.Get("value").AsBool(); 4633240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch else if (message == "set_points") { 4643240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int num_points = dictionary.Get("value").AsInt(); 4653240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch point_count_ = std::min(kMaxPointCount, std::max(0, num_points)); 4663240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } else if (message == "set_threads") { 4673240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int thread_count = dictionary.Get("value").AsInt(); 4683240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch delete workers_; 4693240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch workers_ = new ThreadPool(thread_count); 4703240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 471868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 472868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 473868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 474868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 475eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// PostUpdateMessage() helper function for sendimg small messages to JS. 476eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Voronoi::PostUpdateMessage(const char* message_name, double value) { 477eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pp::VarDictionary message; 478eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch message.Set("message", message_name); 479eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch message.Set("value", value); 4803240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var()); 481868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 482868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 483868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Voronoi::Update() { 4843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSContext2DGetBuffer(ps_context_); 4853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (NULL == ps_context_->data) 4863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return; 4873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch assert(is_pow2(ps_context_->width)); 4883240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch assert(is_pow2(ps_context_->height)); 4893240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 4903240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // When benchmarking is running, don't update display via 4913240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // PSContext2DSwapBuffer() - vsync is enabled by default, and will throttle 4923240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // the benchmark results. 493868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) do { 494868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) UpdateSim(); 495868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Render(); 496868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!benchmarking_) break; 497868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) --benchmark_frame_counter_; 498868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } while (benchmark_frame_counter_ > 0); 499868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (benchmarking_) 500868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) EndBenchmark(); 501868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSContext2DSwapBuffer(ps_context_); 503868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 504868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5053240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Starting point for the module. We do not use main since it would 5063240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// collide with main in libppapi_cpp. 5073240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochint example_main(int argc, char* argv[]) { 5083240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch Voronoi voronoi; 5093240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch while (true) { 5103240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSEvent* ps_event; 5113240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Consume all available events. 5123240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch while ((ps_event = PSEventTryAcquire()) != NULL) { 5133240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch voronoi.HandleEvent(ps_event); 5143240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSEventRelease(ps_event); 5153240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 5163240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Do simulation, render and present. 5173240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch voronoi.Update(); 518868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 519868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5203240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return 0; 521868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 522868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5233240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Register the function to call once the Instance Object is initialized. 5243240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// see: pappi_simple/ps_main.h 5253240926e260ce088908e02ac07a6cf7b0c0cbf44Ben MurdochPPAPI_SIMPLE_REGISTER_MAIN(example_main); 526