11e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 21e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 31e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// found in the LICENSE file. 41e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 51e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <assert.h> 61e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <math.h> 71e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <ppapi/c/ppb_input_event.h> 81e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <ppapi/cpp/input_event.h> 91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <ppapi/cpp/var.h> 101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <ppapi/cpp/var_array.h> 111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <ppapi/cpp/var_array_buffer.h> 121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <ppapi/cpp/var_dictionary.h> 131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <pthread.h> 141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <stdio.h> 151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <stdlib.h> 161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <string.h> 171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <unistd.h> 181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <algorithm> 201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <string> 211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "common/fps.h" 231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ppapi_simple/ps.h" 241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ppapi_simple/ps_context_2d.h" 251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ppapi_simple/ps_event.h" 261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ppapi_simple/ps_interface.h" 271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ppapi_simple/ps_main.h" 281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "sdk_util/thread_pool.h" 291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)using namespace sdk_util; // For sdk_util::ThreadPool 311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Global properties used to setup Voronoi demo. 331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace { 341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const int kMinRectSize = 4; 351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const int kStartRecurseSize = 32; // must be power-of-two 361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const float kHugeZ = 1.0e38f; 371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const float kPI = M_PI; 381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const float kTwoPI = kPI * 2.0f; 391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const unsigned int kRandomStartSeed = 0xC0DE533D; 401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const int kMaxPointCount = 1024; 411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const int kStartPointCount = 48; 421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const int kDefaultNumRegions = 256; 431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)unsigned int g_rand_state = kRandomStartSeed; 451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// random number helper 471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)inline unsigned char rand255() { 481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return static_cast<unsigned char>(rand_r(&g_rand_state) & 255); 491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// random number helper 521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)inline float frand() { 531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return (static_cast<float>(rand_r(&g_rand_state)) / 541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) static_cast<float>(RAND_MAX)); 551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// reset random seed 581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)inline void rand_reset(unsigned int seed) { 591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) g_rand_state = seed; 601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)inline uint32_t next_pow2(uint32_t x) { 631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Via Hacker's Delight, section 3.2 "Rounding Up/Down to the Next Power of 2" 641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) --x; 651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) x |= (x >> 1); 661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) x |= (x >> 2); 671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) x |= (x >> 4); 681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) x |= (x >> 8); 691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) x |= (x >> 16); 701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return x + 1; 711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// BGRA helper function, for constructing a pixel for a BGRA buffer. 741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)inline uint32_t MakeBGRA(uint32_t b, uint32_t g, uint32_t r, uint32_t a) { 751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)); 761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} // namespace 781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Vec2, simple 2D vector 801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)struct Vec2 { 811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) float x, y; 821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) Vec2() {} 831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) Vec2(float px, float py) { 841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) x = px; 851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) y = py; 861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void Set(float px, float py) { 881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) x = px; 891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) y = py; 901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}; 921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// The main object that runs Voronoi simulation. 941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)class Voronoi { 951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) public: 961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) Voronoi(); 971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) virtual ~Voronoi(); 981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Runs a tick of the simulations, update 2D output. 991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void Update(); 1001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Handle event from user, or message from JS. 1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void HandleEvent(PSEvent* ps_event); 1021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) private: 1041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Methods prefixed with 'w' are run on worker threads. 1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) uint32_t* wGetAddr(int x, int y); 1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int wCell(float x, float y); 1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) inline void wFillSpan(uint32_t *pixels, uint32_t color, int width); 1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void wRenderTile(int x, int y, int w, int h); 1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void wProcessTile(int x, int y, int w, int h); 1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void wSubdivide(int x, int y, int w, int h); 1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void wMakeRect(int region, int *x, int *y, int *w, int *h); 1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) bool wTestRect(int *m, int x, int y, int w, int h); 1131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void wFillRect(int x, int y, int w, int h, uint32_t color); 1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void wRenderRect(int x0, int y0, int x1, int y1); 1151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void wRenderRegion(int region); 1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) static void wRenderRegionEntry(int region, void *thiz); 1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // These methods are only called by the main thread. 1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void Reset(); 1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void UpdateSim(); 1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void RenderDot(float x, float y, uint32_t color1, uint32_t color2); 1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void SuperimposePositions(); 1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void Render(); 1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void Draw(); 1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Helper to post small update messages to JS. 1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) void PostUpdateMessage(const char* message_name, double value); 1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) PSContext2D_t* ps_context_; 1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) Vec2 positions_[kMaxPointCount]; 1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) Vec2 screen_positions_[kMaxPointCount]; 1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) Vec2 velocities_[kMaxPointCount]; 1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) uint32_t colors_[kMaxPointCount]; 1331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) float ang_; 1341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const int num_regions_; 1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int num_threads_; 1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int point_count_; 1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) bool draw_points_; 1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) bool draw_interiors_; 1391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ThreadPool* workers_; 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) FpsState fps_state_; 1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}; 1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::Reset() { 1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) rand_reset(kRandomStartSeed); 1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ang_ = 0.0f; 1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (int i = 0; i < kMaxPointCount; i++) { 1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // random initial start position 1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const float x = frand(); 1501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const float y = frand(); 1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) positions_[i].Set(x, y); 1521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // random directional velocity ( -1..1, -1..1 ) 1531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const float speed = 0.0005f; 1541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const float u = (frand() * 2.0f - 1.0f) * speed; 1551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const float v = (frand() * 2.0f - 1.0f) * speed; 1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) velocities_[i].Set(u, v); 1571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // 'unique' color (well... unique enough for our purposes) 1581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) colors_[i] = MakeBGRA(rand255(), rand255(), rand255(), 255); 1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)Voronoi::Voronoi() : num_regions_(kDefaultNumRegions), num_threads_(0), 1631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) point_count_(kStartPointCount), draw_points_(true), draw_interiors_(true) { 1641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) Reset(); 1651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // By default, render from the dispatch thread. 1661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) workers_ = new ThreadPool(num_threads_); 1671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) PSEventSetFilter(PSE_ALL); 1681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL); 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) FpsInit(&fps_state_); 1701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)Voronoi::~Voronoi() { 1731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) delete workers_; 1741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) PSContext2DFree(ps_context_); 1751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)inline uint32_t* Voronoi::wGetAddr(int x, int y) { 1781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return ps_context_->data + x + y * ps_context_->stride / sizeof(uint32_t); 1791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 1801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 1811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// This is the core of the Voronoi calculation. At a given point on the 1821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// screen, iterate through all voronoi positions and render them as 3D cones. 1831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// We're looking for the voronoi cell that generates the closest z value. 1841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// (not really cones - since it is all relative, we avoid doing the 1851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// expensive sqrt and test against z*z instead) 1861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 1871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int Voronoi::wCell(float x, float y) { 1881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int closest_cell = 0; 1891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) float zz = kHugeZ; 1901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) Vec2* pos = screen_positions_; 1911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (int i = 0; i < point_count_; ++i) { 1921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // measured 5.18 cycles per iteration on a core2 1931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) float dx = x - pos[i].x; 1941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) float dy = y - pos[i].y; 1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) float dd = (dx * dx + dy * dy); 1961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (dd < zz) { 1971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) zz = dd; 1981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) closest_cell = i; 1991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return closest_cell; 2021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 2031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Given a region r, derive a non-overlapping rectangle for a thread to 2051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// work on. 2061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 2071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::wMakeRect(int r, int* x, int* y, int* w, int* h) { 2081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const int parts = 16; 2091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) assert(parts * parts == num_regions_); 2101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Round up to the nearest power of two so we can divide by parts cleanly. We 2111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // could round up to the nearest 16 pixels, but it runs much faster when 2121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // subdividing power-of-two squares. 2131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // 2141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Many of these squares are outside of the canvas, but they will be 2151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // trivially culled by wRenderRect. 2161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *w = static_cast<int>(next_pow2(ps_context_->width)) / parts; 2171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *h = static_cast<int>(next_pow2(ps_context_->height)) / parts; 2181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *x = *w * (r % parts); 2191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *y = *h * ((r / parts) % parts); 2201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 2211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Test 4 corners of a rectangle to see if they all belong to the same 2231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// voronoi cell. Each test is expensive so bail asap. Returns true 2241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// if all 4 corners match. 2251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 2261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool Voronoi::wTestRect(int* m, int x, int y, int w, int h) { 2271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // each test is expensive, so exit ASAP 2281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const int m0 = wCell(x, y); 2291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const int m1 = wCell(x + w - 1, y); 2301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (m0 != m1) return false; 2311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const int m2 = wCell(x, y + h - 1); 2321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (m0 != m2) return false; 2331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const int m3 = wCell(x + w - 1, y + h - 1); 2341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (m0 != m3) return false; 2351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // all 4 corners belong to the same cell 2361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *m = m0; 2371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return true; 2381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 2391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Quickly fill a span of pixels with a solid color. 2411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)inline void Voronoi::wFillSpan(uint32_t* pixels, uint32_t color, int width) { 2431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!draw_interiors_) { 2441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const uint32_t gray = MakeBGRA(128, 128, 128, 255); 2451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) color = gray; 2461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (int i = 0; i < width; ++i) 2491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *pixels++ = color; 2501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Quickly fill a rectangle with a solid color. 2531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 2541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::wFillRect(int x, int y, int w, int h, uint32_t color) { 2551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t); 2561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) uint32_t* pixels = wGetAddr(x, y); 2571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (int j = 0; j < h; j++) { 2581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) wFillSpan(pixels, color, w); 2591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) pixels += stride_in_pixels; 2601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 2621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// When recursive subdivision reaches a certain minimum without finding a 2641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// rectangle that has four matching corners belonging to the same voronoi 2651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// cell, this function will break the retangular 'tile' into smaller scanlines 2661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// and look for opportunities to quick fill at the scanline level. If the 2671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// scanline can't be quick filled, it will slow down even further and compute 2681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// voronoi membership per pixel. 2691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::wRenderTile(int x, int y, int w, int h) { 2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // rip through a tile 2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t); 2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) uint32_t* pixels = wGetAddr(x, y); 2731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (int j = 0; j < h; j++) { 2741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // get start and end cell values 2751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int ms = wCell(x + 0, y + j); 2761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int me = wCell(x + w - 1, y + j); 2771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // if the end points are the same, quick fill the span 2781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (ms == me) { 2791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) wFillSpan(pixels, colors_[ms], w); 2801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else { 2811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // else compute each pixel in the span... this is the slow part! 2821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) uint32_t* p = pixels; 2831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *p++ = colors_[ms]; 2841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (int i = 1; i < (w - 1); i++) { 2851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int m = wCell(x + i, y + j); 2861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *p++ = colors_[m]; 2871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *p++ = colors_[me]; 2891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) pixels += stride_in_pixels; 2911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 2921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 2931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 2941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Take a rectangular region and do one of - 2951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// If all four corners below to the same voronoi cell, stop recursion and 2961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// quick fill the rectangle. 2971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// If the minimum rectangle size has been reached, break out of recursion 2981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// and process the rectangle. This small rectangle is called a tile. 2991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Otherwise, keep recursively subdividing the rectangle into 4 equally 3001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// sized smaller rectangles. 3011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 3021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::wSubdivide(int x, int y, int w, int h) { 3031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int m; 3041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // if all 4 corners are equal, quick fill interior 3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (wTestRect(&m, x, y, w, h)) { 3061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) wFillRect(x, y, w, h, colors_[m]); 3071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else { 3081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // did we reach the minimum rectangle size? 3091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if ((w <= kMinRectSize) || (h <= kMinRectSize)) { 3101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) wRenderTile(x, y, w, h); 3111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else { 3121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // else recurse into smaller rectangles 3131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const int half_w = w / 2; 3141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const int half_h = h / 2; 3151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) wSubdivide(x, y, half_w, half_h); 3161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) wSubdivide(x + half_w, y, w - half_w, half_h); 3171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) wSubdivide(x, y + half_h, half_w, h - half_h); 3181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) wSubdivide(x + half_w, y + half_h, w - half_w, h - half_h); 3191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 3201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 3211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 3221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// This function cuts up the rectangle into squares (preferably power-of-two). 3241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 3251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::wRenderRect(int x, int y, int w, int h) { 3261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (int iy = y; iy < (y + h); iy += kStartRecurseSize) { 3271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (int ix = x; ix < (x + w); ix += kStartRecurseSize) { 3281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int iw = kStartRecurseSize; 3291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int ih = kStartRecurseSize; 3301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Clamp width + height. 3311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (ix + iw > ps_context_->width) 3321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) iw = ps_context_->width - ix; 3331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (iy + ih > ps_context_->height) 3341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ih = ps_context_->height - iy; 3351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (iw <= 0 || ih <= 0) 3361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) continue; 3371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) wSubdivide(ix, iy, iw, ih); 3391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 3401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 3411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 3421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// If multithreading, this function is only called by the worker threads. 3441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::wRenderRegion(int region) { 3451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // convert region # into x0, y0, x1, y1 rectangle 3461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int x, y, w, h; 3471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) wMakeRect(region, &x, &y, &w, &h); 3481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // render this rectangle 3491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) wRenderRect(x, y, w, h); 3501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 3511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Entry point for worker thread. Can't pass a member function around, so we 3531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// have to do this little round-about. 3541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::wRenderRegionEntry(int region, void* thiz) { 3551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) static_cast<Voronoi*>(thiz)->wRenderRegion(region); 3561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 3571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Function Voronoi::UpdateSim() 3591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Run a simple sim to move the voronoi positions. This update loop 3601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// is run once per frame. Called from the main thread only, and only 3611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// when the worker threads are idle. 3621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::UpdateSim() { 3631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ang_ += 0.002f; 3641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (ang_ > kTwoPI) { 3651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ang_ = ang_ - kTwoPI; 3661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 3671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) float z = cosf(ang_) * 3.0f; 3681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // push the points around on the screen for animation 3691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (int j = 0; j < kMaxPointCount; j++) { 3701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) positions_[j].x += (velocities_[j].x) * z; 3711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) positions_[j].y += (velocities_[j].y) * z; 3721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) screen_positions_[j].x = positions_[j].x * ps_context_->width; 3731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) screen_positions_[j].y = positions_[j].y * ps_context_->height; 3741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 3751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 3761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Renders a small diamond shaped dot at x, y clipped against the window 3781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::RenderDot(float x, float y, uint32_t color1, uint32_t color2) { 3791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const int ix = static_cast<int>(x); 3801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const int iy = static_cast<int>(y); 3811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const uint32_t stride_in_pixels = ps_context_->stride / sizeof(uint32_t); 3821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // clip it against window 3831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (ix < 1) return; 3841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (ix >= (ps_context_->width - 1)) return; 3851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (iy < 1) return; 3861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (iy >= (ps_context_->height - 1)) return; 3871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) uint32_t* pixel = wGetAddr(ix, iy); 3881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // render dot as a small diamond 3891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *pixel = color1; 3901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *(pixel - 1) = color2; 3911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *(pixel + 1) = color2; 3921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *(pixel - stride_in_pixels) = color2; 3931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) *(pixel + stride_in_pixels) = color2; 3941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 3951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 3961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Superimposes dots on the positions. 3971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::SuperimposePositions() { 3981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const uint32_t white = MakeBGRA(255, 255, 255, 255); 3991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const uint32_t gray = MakeBGRA(192, 192, 192, 255); 4001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (int i = 0; i < point_count_; i++) { 4011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) RenderDot( 4021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) screen_positions_[i].x, screen_positions_[i].y, white, gray); 4031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 4041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 4051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 4061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Renders the Voronoi diagram, dispatching the work to multiple threads. 4071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::Render() { 4081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) workers_->Dispatch(num_regions_, wRenderRegionEntry, this); 4091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (draw_points_) 4101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) SuperimposePositions(); 4111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 4121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 4131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Handle input events from the user and messages from JS. 4141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::HandleEvent(PSEvent* ps_event) { 4151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Give the 2D context a chance to process the event. 4161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (0 != PSContext2DHandleEvent(ps_context_, ps_event)) 4171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return; 4181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) { 4191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Convert Pepper Simple event to a PPAPI C++ event 4201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) pp::InputEvent event(ps_event->as_resource); 4211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) switch (event.GetType()) { 4221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case PP_INPUTEVENT_TYPE_TOUCHSTART: 4231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) case PP_INPUTEVENT_TYPE_TOUCHMOVE: { 4241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) pp::TouchInputEvent touches = pp::TouchInputEvent(event); 4251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) uint32_t count = touches.GetTouchCount(PP_TOUCHLIST_TYPE_TOUCHES); 4261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Touch points 0..n directly set position of points 0..n in 4271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Voronoi diagram. 4281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for (uint32_t i = 0; i < count; i++) { 4291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) pp::TouchPoint touch = 4301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) touches.GetTouchByIndex(PP_TOUCHLIST_TYPE_TOUCHES, i); 4311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) pp::FloatPoint point = touch.position(); 4321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) positions_[i].Set(point.x() / ps_context_->width, 4331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) point.y() / ps_context_->height); 4341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 4351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) break; 4361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 4371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) default: 4381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) break; 4391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 4401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) { 4411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Convert Pepper Simple message to PPAPI C++ var 4421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) pp::Var var(ps_event->as_var); 4431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (var.is_dictionary()) { 4441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) pp::VarDictionary dictionary(var); 4451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string message = dictionary.Get("message").AsString(); 4461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (message == "draw_points") 4471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) draw_points_ = dictionary.Get("value").AsBool(); 4481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) else if (message == "draw_interiors") 4491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) draw_interiors_ = dictionary.Get("value").AsBool(); 4501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) else if (message == "set_points") { 4511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int num_points = dictionary.Get("value").AsInt(); 4521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) point_count_ = std::min(kMaxPointCount, std::max(0, num_points)); 4531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else if (message == "set_threads") { 4541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) int thread_count = dictionary.Get("value").AsInt(); 4551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) delete workers_; 4561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) workers_ = new ThreadPool(thread_count); 4571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 4581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 4591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 4601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 4611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 4621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// PostUpdateMessage() helper function for sendimg small messages to JS. 4631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::PostUpdateMessage(const char* message_name, double value) { 4641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) pp::VarDictionary message; 4651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) message.Set("message", message_name); 4661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) message.Set("value", value); 4671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var()); 4681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 4691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 4701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void Voronoi::Update() { 4711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) PSContext2DGetBuffer(ps_context_); 4721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (NULL == ps_context_->data) 4731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return; 4741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 4751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) UpdateSim(); 4761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) Render(); 4771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) PSContext2DSwapBuffer(ps_context_); 478f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 479f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) double fps; 480f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (FpsStep(&fps_state_, &fps)) 481f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) PostUpdateMessage("fps", fps); 4821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 4831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 4841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Starting point for the module. We do not use main since it would 4851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// collide with main in libppapi_cpp. 4861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)int example_main(int argc, char* argv[]) { 4871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) Voronoi voronoi; 4881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) while (true) { 4891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) PSEvent* ps_event; 4901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Consume all available events. 4911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) while ((ps_event = PSEventTryAcquire()) != NULL) { 4921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) voronoi.HandleEvent(ps_event); 4931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) PSEventRelease(ps_event); 4941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 4951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Do simulation, render and present. 4961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) voronoi.Update(); 4971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 4981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 4991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return 0; 5001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)} 5011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) 5021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Register the function to call once the Instance Object is initialized. 5031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// see: pappi_simple/ps_main.h 5041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)PPAPI_SIMPLE_REGISTER_MAIN(example_main); 505