1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <assert.h>
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <math.h>
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <ppapi/c/ppb_input_event.h>
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <ppapi/cpp/input_event.h>
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <ppapi/cpp/var.h>
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <ppapi/cpp/var_array.h>
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <ppapi/cpp/var_array_buffer.h>
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <ppapi/cpp/var_dictionary.h>
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <pthread.h>
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <stdio.h>
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <stdlib.h>
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <string.h>
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <sys/time.h>
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <unistd.h>
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <algorithm>
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <string>
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ppapi_simple/ps.h"
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ppapi_simple/ps_context_2d.h"
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ppapi_simple/ps_event.h"
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ppapi_simple/ps_interface.h"
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ppapi_simple/ps_main.h"
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "sdk_util/macros.h"
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "sdk_util/thread_pool.h"
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using namespace sdk_util;  // For sdk_util::ThreadPool
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#define INLINE inline __attribute__((always_inline))
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// 128 bit SIMD vector types
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)typedef uint8_t u8x16_t __attribute__ ((vector_size (16)));
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)typedef int32_t i32x4_t __attribute__ ((vector_size (16)));
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)typedef uint32_t u32x4_t __attribute__ ((vector_size (16)));
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)typedef float f32x4_t __attribute__ ((vector_size (16)));
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Global properties used to setup Earth demo.
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace {
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const float kPI = M_PI;
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const float kTwoPI = kPI * 2.0f;
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const float kOneOverPI = 1.0f / kPI;
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const float kOneOver2PI = 1.0f / kTwoPI;
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kArcCosineTableSize = 4096;
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kFramesToBenchmark = 100;
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const float kZoomMin = 1.0f;
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const float kZoomMax = 50.0f;
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const float kWheelSpeed = 2.0f;
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const float kLightMin = 0.0f;
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const float kLightMax = 2.0f;
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Timer helper for benchmarking.  Returns seconds elapsed since program start,
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// as a double.
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)timeval start_tv;
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int start_tv_retv = gettimeofday(&start_tv, NULL);
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)inline double getseconds() {
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const double usec_to_sec = 0.000001;
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  timeval tv;
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if ((0 == start_tv_retv) && (0 == gettimeofday(&tv, NULL)))
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return (tv.tv_sec - start_tv.tv_sec) + tv.tv_usec * usec_to_sec;
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return 0.0;
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// SIMD Vector helper functions.
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)//
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Note that a compare between two vectors will return a signed integer vector
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// with the same number of elements, where each element will be all bits set
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// for true (-1), and all bits clear for false (0) This integer vector can be
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// useful as a mask.
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)//
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Also note that c-style casts do not mutate the bits of a vector - only the
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// type.  Boolean operators can't operate on float vectors, but it is possible
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// to cast them temporarily to integer vector, perform the mask, and cast
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// them back to float.
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)//
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// To convert a float vector to an integer vector using trunction, or to
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// convert an integer vector to a float vector, use __builtin_convertvector().
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE f32x4_t min(f32x4_t a, f32x4_t b) {
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  i32x4_t m = a < b;
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return (f32x4_t)(((i32x4_t)a & m) | ((i32x4_t)b & ~m));
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE f32x4_t max(f32x4_t a, f32x4_t b) {
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  i32x4_t m = a > b;
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return (f32x4_t)(((i32x4_t)a & m) | ((i32x4_t)b & ~m));
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE float dot3(f32x4_t a, f32x4_t b) {
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  f32x4_t c = a * b;
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return c[0] + c[1] + c[2];
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE f32x4_t broadcast(float x) {
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  f32x4_t r = {x, x, x, x};
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return r;
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// SIMD RGBA helper functions, used for extracting color from RGBA source image.
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE f32x4_t ExtractRGBA(uint32_t c) {
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t kOneOver255 = broadcast(1.0f / 255.0f);
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const i32x4_t kZero = {0, 0, 0, 0};
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  i32x4_t v = {c, c, c, c};
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // zero extend packed color into 32x4 integer vector
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  v = (i32x4_t)__builtin_shufflevector((u8x16_t)v, (u8x16_t)kZero,
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      0, 16, 16, 16, 1, 16, 16, 16, 2, 16, 16, 16, 3, 16, 16, 16);
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // convert color values to float, range 0..1
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  f32x4_t f = __builtin_convertvector(v, f32x4_t) * kOneOver255;
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return f;
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// SIMD BGRA helper function, for constructing a pixel for a BGRA buffer.
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE uint32_t PackBGRA(f32x4_t f) {
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t kZero = broadcast(0.0f);
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t kHalf = broadcast(0.5f);
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t k255 = broadcast(255.0f);
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  f = max(f, kZero);
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Add 0.5 to perform rounding instead of truncation.
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  f = f * k255 + kHalf;
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  f = min(f, k255);
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  i32x4_t i = __builtin_convertvector(f, i32x4_t);
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  u32x4_t p = (u32x4_t)__builtin_shufflevector((u8x16_t)i, (u8x16_t)i,
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      8, 4, 0, 12, 8, 4, 0, 12, 8, 4, 0, 12, 8, 4, 0, 12);
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return p[0];
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// BGRA helper function, for constructing a pixel for a BGRA buffer.
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE uint32_t MakeBGRA(uint32_t b, uint32_t g, uint32_t r, uint32_t a) {
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// simple container for earth texture
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)struct Texture {
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int width, height;
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  uint32_t* pixels;
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Texture(int w, int h) : width(w), height(h) {
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    pixels = new uint32_t[w * h];
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    memset(pixels, 0, sizeof(uint32_t) * w * h);
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  explicit Texture(int w, int h, uint32_t* p) : width(w), height(h) {
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    pixels = new uint32_t[w * h];
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    memcpy(pixels, p, sizeof(uint32_t) * w * h);
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ~Texture() { delete[] pixels; }
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Texture);
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)struct ArcCosine {
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // slightly larger table so we can interpolate beyond table size
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float table[kArcCosineTableSize + 2];
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float TableLerp(float x);
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ArcCosine();
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ArcCosine::ArcCosine() {
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // build a slightly larger table to allow for numeric imprecision
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (int i = 0; i < (kArcCosineTableSize + 2); ++i) {
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float f = static_cast<float>(i) / kArcCosineTableSize;
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    f = f * 2.0f - 1.0f;
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    table[i] = acos(f);
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// looks up acos(f) using a table and lerping between entries
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// (it is expected that input f is between -1 and 1)
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE float ArcCosine::TableLerp(float f) {
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float x = (f + 1.0f) * 0.5f;
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  x = x * kArcCosineTableSize;
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int ix = static_cast<int>(x);
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float fx = static_cast<float>(ix);
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float dx = x - fx;
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float af = table[ix];
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float af2 = table[ix + 1];
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return af + (af2 - af) * dx;
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Helper functions for quick but approximate sqrt.
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)union Convert {
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float f;
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int i;
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Convert(int x) { i = x; }
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Convert(float x) { f = x; }
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int AsInt() { return i; }
191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float AsFloat() { return f; }
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE const int AsInteger(const float f) {
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Convert u(f);
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return u.AsInt();
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE const float AsFloat(const int i) {
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Convert u(i);
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return u.AsFloat();
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const long int kOneAsInteger = AsInteger(1.0f);
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE float inline_quick_sqrt(float x) {
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int i;
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  i = (AsInteger(x) >> 1) + (kOneAsInteger >> 1);
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return AsFloat(i);
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)INLINE float inline_sqrt(float x) {
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float y;
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  y = inline_quick_sqrt(x);
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  y = (y * y + x) / (2.0f * y);
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  y = (y * y + x) / (2.0f * y);
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return y;
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// The main object that runs the Earth demo.
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class Planet {
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public:
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Planet();
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual ~Planet();
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Runs a tick of the simulations, update 2D output.
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void Update();
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Handle event from user, or message from JS.
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void HandleEvent(PSEvent* ps_event);
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private:
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Methods prefixed with 'w' are run on worker threads.
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  uint32_t* wGetAddr(int x, int y);
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void wRenderPixelSpan(int x0, int x1, int y);
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void wMakeRect(int r, int *x, int *y, int *w, int *h);
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void wRenderRect(int x0, int y0, int x1, int y1);
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void wRenderRegion(int region);
240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static void wRenderRegionEntry(int region, void *thiz);
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // These methods are only called by the main thread.
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void CacheCalcs();
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetPlanetXYZR(float x, float y, float z, float r);
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetPlanetPole(float x, float y, float z);
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetPlanetEquator(float x, float y, float z);
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetPlanetSpin(float x, float y);
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetEyeXYZ(float x, float y, float z);
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetLightXYZ(float x, float y, float z);
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetAmbientRGB(float r, float g, float b);
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetDiffuseRGB(float r, float g, float b);
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetZoom(float zoom);
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetLight(float zoom);
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SetTexture(const std::string& name, int width, int height,
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      uint32_t* pixels);
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SpinPlanet(pp::Point new_point, pp::Point last_point);
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void Reset();
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void RequestTextures();
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void UpdateSim();
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void Render();
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void Draw();
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void StartBenchmark();
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void EndBenchmark();
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Post a small key-value message to update JS.
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void PostUpdateMessage(const char* message_name, double value);
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // User Interface settings.  These settings are controlled via html
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // controls or via user input.
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float ui_light_;
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float ui_zoom_;
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float ui_spin_x_;
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float ui_spin_y_;
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  pp::Point ui_last_point_;
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Various settings for position & orientation of planet.  Do not change
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // these variables, instead use SetPlanet*() functions.
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_radius_;
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_spin_x_;
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_spin_y_;
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_x_, planet_y_, planet_z_;
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_pole_x_, planet_pole_y_, planet_pole_z_;
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_equator_x_, planet_equator_y_, planet_equator_z_;
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Observer's eye.  Do not change these variables, instead use SetEyeXYZ().
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float eye_x_, eye_y_, eye_z_;
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Light position, ambient and diffuse settings.  Do not change these
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // variables, instead use SetLightXYZ(), SetAmbientRGB() and SetDiffuseRGB().
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float light_x_, light_y_, light_z_;
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float diffuse_r_, diffuse_g_, diffuse_b_;
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float ambient_r_, ambient_g_, ambient_b_;
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Cached calculations.  Do not change these variables - they are updated by
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // CacheCalcs() function.
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_xyz_;
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_pole_x_equator_x_;
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_pole_x_equator_y_;
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_pole_x_equator_z_;
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_radius2_;
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_one_over_radius_;
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float eye_xyz_;
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Source texture (earth map).
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Texture* base_tex_;
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Texture* night_tex_;
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int width_for_tex_;
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int height_for_tex_;
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Quick ArcCos helper.
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ArcCosine acos_;
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Misc.
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PSContext2D_t* ps_context_;
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int num_threads_;
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ThreadPool* workers_;
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool benchmarking_;
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int benchmark_frame_counter_;
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  double benchmark_start_time_;
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  double benchmark_end_time_;
321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::RequestTextures() {
325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Request a set of images from JS.  After images are loaded by JS, a
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // message from JS -> NaCl will arrive containing the pixel data.  See
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // HandleMessage() method in this file.
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  pp::VarDictionary message;
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  message.Set("message", "request_textures");
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  pp::VarArray names;
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  names.Set(0, "earth.jpg");
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  names.Set(1, "earthnight.jpg");
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  message.Set("names", names);
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var());
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::Reset() {
338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Reset has to first fill in all variables with valid floats, so
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // CacheCalcs() doesn't potentially propagate NaNs when calling Set*()
340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // functions further below.
341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_radius_ = 1.0f;
342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_spin_x_ = 0.0f;
343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_spin_y_ = 0.0f;
344cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_x_ = 0.0f;
345cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_y_ = 0.0f;
346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_z_ = 0.0f;
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_x_ = 0.0f;
348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_y_ = 0.0f;
349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_z_ = 0.0f;
350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_equator_x_ = 0.0f;
351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_equator_y_ = 0.0f;
352cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_equator_z_ = 0.0f;
353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  eye_x_ = 0.0f;
354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  eye_y_ = 0.0f;
355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  eye_z_ = 0.0f;
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  light_x_ = 0.0f;
357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  light_y_ = 0.0f;
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  light_z_ = 0.0f;
359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  diffuse_r_ = 0.0f;
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  diffuse_g_ = 0.0f;
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  diffuse_b_ = 0.0f;
362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ambient_r_ = 0.0f;
363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ambient_g_ = 0.0f;
364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ambient_b_ = 0.0f;
365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_xyz_ = 0.0f;
366cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_x_equator_x_ = 0.0f;
367cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_x_equator_y_ = 0.0f;
368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_x_equator_z_ = 0.0f;
369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_radius2_ = 0.0f;
370cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_one_over_radius_ = 0.0f;
371cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  eye_xyz_ = 0.0f;
372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui_zoom_ = 14.0f;
373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui_light_ = 1.0f;
374cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui_spin_x_ = 0.01f;
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui_spin_y_ = 0.0f;
376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui_last_point_ = pp::Point(0, 0);
377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Set up reasonable default values.
379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetPlanetXYZR(0.0f, 0.0f, 48.0f, 4.0f);
380cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetEyeXYZ(0.0f, 0.0f, -ui_zoom_);
381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetLightXYZ(-60.0f, -30.0f, 0.0f);
382cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetAmbientRGB(0.05f, 0.05f, 0.05f);
383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetDiffuseRGB(0.8f, 0.8f, 0.8f);
384cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetPlanetPole(0.0f, 1.0f, 0.0f);
385cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetPlanetEquator(1.0f, 0.0f, 0.0f);
386cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetPlanetSpin(kPI / 2.0f, kPI / 2.0f);
387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetZoom(ui_zoom_);
388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetLight(ui_light_);
389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Send UI values to JS to reset html sliders.
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PostUpdateMessage("set_zoom", ui_zoom_);
392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PostUpdateMessage("set_light", ui_light_);
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
396cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Planet::Planet() : base_tex_(NULL), night_tex_(NULL), num_threads_(0),
397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    benchmarking_(false), benchmark_frame_counter_(0) {
398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Reset();
400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  RequestTextures();
401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // By default, render from the dispatch thread.
402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  workers_ = new ThreadPool(num_threads_);
403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PSEventSetFilter(PSE_ALL);
404cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
405cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)Planet::~Planet() {
408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  delete workers_;
409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PSContext2DFree(ps_context_);
410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
411cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Given a region r, derive a rectangle.
413cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// This rectangle shouldn't overlap with work being done by other workers.
414cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// If multithreading, this function is only called by the worker threads.
415cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::wMakeRect(int r, int *x, int *y, int *w, int *h) {
416cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *x = 0;
417cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *w = ps_context_->width;
418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *y = r;
419cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *h = 1;
420cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
421cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
422cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
423cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)inline uint32_t* Planet::wGetAddr(int x, int y) {
424cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return ps_context_->data + x + y * ps_context_->stride / sizeof(uint32_t);
425cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
426cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
427cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// This is the inner loop of the ray tracer.  Given a pixel span (x0, x1) on
428cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// scanline y, shoot rays into the scene and render what they hit.  Use
429cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// scanline coherence to do a few optimizations.
430cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// This version uses portable SIMD 4 element single precision floating point
431cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// vectors to perform many of the calculations, and builds only on PNaCl.
432cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::wRenderPixelSpan(int x0, int x1, int y) {
433cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!base_tex_ || !night_tex_)
434cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
435cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const uint32_t kColorBlack = MakeBGRA(0, 0, 0, 0xFF);
436cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const uint32_t kSolidAlpha = MakeBGRA(0, 0, 0, 0xFF);
437cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t kOne = {1.0f, 1.0f, 1.0f, 1.0f};
438cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t diffuse = {diffuse_r_, diffuse_g_, diffuse_b_, 0.0f};
439cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t ambient = {ambient_r_, ambient_g_, ambient_b_, 0.0f};
440cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t light_pos = {light_x_, light_y_, light_z_, 1.0f};
441cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t planet_pos = {planet_x_, planet_y_, planet_z_, 1.0f};
442cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t planet_one_over_radius = broadcast(planet_one_over_radius_);
443cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t planet_equator = {
444cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      planet_equator_x_, planet_equator_y_, planet_equator_z_, 0.0f};
445cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t planet_pole = {
446cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      planet_pole_x_, planet_pole_y_, planet_pole_z_, 1.0f};
447cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const f32x4_t planet_pole_x_equator = {
448cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      planet_pole_x_equator_x_, planet_pole_x_equator_y_,
449cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      planet_pole_x_equator_z_, 0.0f};
450cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
451cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float width = ps_context_->width;
452cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float height = ps_context_->height;
453cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float min_dim = width < height ? width : height;
454cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float offset_x = width < height ? 0 : (width - min_dim) * 0.5f;
455cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float offset_y = width < height ? (height - min_dim) * 0.5f : 0;
456cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float y0 = eye_y_;
457cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float z0 = eye_z_;
458cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float y1 = (static_cast<float>(y - offset_y) / min_dim) * 2.0f - 1.0f;
459cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float z1 = 0.0f;
460cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float dy = (y1 - y0);
461cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float dz = (z1 - z0);
462cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float dy_dy_dz_dz = dy * dy + dz * dz;
463cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float two_dy_y0_y_two_dz_z0_z = 2.0f * dy * (y0 - planet_y_) +
464cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                  2.0f * dz * (z0 - planet_z_);
465cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float planet_xyz_eye_xyz = planet_xyz_ + eye_xyz_;
466cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float y_y0_z_z0 = planet_y_ * y0 + planet_z_ * z0;
467cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float oowidth = 1.0f / min_dim;
468cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  uint32_t* pixels = this->wGetAddr(x0, y);
469cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (int x = x0; x <= x1; ++x) {
470cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // scan normalized screen -1..1
471cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float x1 = (static_cast<float>(x - offset_x) * oowidth) * 2.0f - 1.0f;
472cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // eye
473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float x0 = eye_x_;
474cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // delta from screen to eye
475cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float dx = (x1 - x0);
476cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // build a, b, c
477cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float a = dx * dx + dy_dy_dz_dz;
478cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float b = 2.0f * dx * (x0 - planet_x_) + two_dy_y0_y_two_dz_z0_z;
479cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float c = planet_xyz_eye_xyz +
480cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              -2.0f * (planet_x_ * x0 + y_y0_z_z0) - (planet_radius2_);
481cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // calculate discriminant
482cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float disc = b * b - 4.0f * a * c;
483cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
484cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Did ray hit the sphere?
485cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (disc < 0.0f) {
486cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      *pixels = kColorBlack;
487cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ++pixels;
488cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      continue;
489cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
490cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
491cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    f32x4_t delta = {dx, dy, dz, 1.0f};
492cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    f32x4_t base = {x0, y0, z0, 1.0f};
493cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
494cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Calc parametric t value.
495cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float t = (-b - inline_sqrt(disc)) / (2.0f * a);
496cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
497cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    f32x4_t pos = base + broadcast(t) * delta;
498cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    f32x4_t normal = (pos - planet_pos) * planet_one_over_radius;
499cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
500cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Misc raytrace calculations.
501cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    f32x4_t L = light_pos - pos;
502cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float Lq = 1.0f / inline_quick_sqrt(dot3(L, L));
503cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    L = L * broadcast(Lq);
504cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float d = dot3(L, normal);
505cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    f32x4_t p = diffuse * broadcast(d) + ambient;
506cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float ds = -dot3(normal, planet_pole);
507cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float ang = acos_.TableLerp(ds);
508cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float v = ang * kOneOverPI;
509cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float dp = dot3(planet_equator, normal);
510cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float w = dp / sinf(ang);
511cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (w > 1.0f) w = 1.0f;
512cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (w < -1.0f) w = -1.0f;
513cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float th = acos_.TableLerp(w) * kOneOver2PI;
514cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float dps = dot3(planet_pole_x_equator, normal);
515cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float u;
516cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (dps < 0.0f)
517cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      u = th;
518cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    else
519cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      u = 1.0f - th;
520cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
521cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Look up daylight texel.
522cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int tx = static_cast<int>(u * base_tex_->width);
523cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int ty = static_cast<int>(v * base_tex_->height);
524cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int offset = tx + ty * base_tex_->width;
525cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    uint32_t base_texel = base_tex_->pixels[offset];
526cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    f32x4_t dc = ExtractRGBA(base_texel);
527cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
528cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Look up night texel.
529cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int nix = static_cast<int>(u * night_tex_->width);
530cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int niy = static_cast<int>(v * night_tex_->height);
531cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    int noffset = nix + niy * night_tex_->width;
532cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    uint32_t night_texel = night_tex_->pixels[noffset];
533cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    f32x4_t nc = ExtractRGBA(night_texel);
534cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
535cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Blend between daylight (dc) and nighttime (nc) color.
536cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    f32x4_t pc = min(p, kOne);
537cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    f32x4_t fc = dc * p + nc * (kOne - pc);
538cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    uint32_t color = PackBGRA(fc);
539cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
540cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    *pixels = color | kSolidAlpha;
541cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ++pixels;
542cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
543cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
544cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
545cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Renders a rectangular area of the screen, scan line at a time
546cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::wRenderRect(int x, int y, int w, int h) {
547cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (int j = y; j < (y + h); ++j) {
548cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this->wRenderPixelSpan(x, x + w - 1, j);
549cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
550cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
551cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
552cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// If multithreading, this function is only called by the worker threads.
553cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::wRenderRegion(int region) {
554cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // convert region # into x0, y0, x1, y1 rectangle
555cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int x, y, w, h;
556cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  wMakeRect(region, &x, &y, &w, &h);
557cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // render this rectangle
558cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  wRenderRect(x, y, w, h);
559cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
560cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
561cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Entry point for worker thread.  Can't pass a member function around, so we
562cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// have to do this little round-about.
563cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::wRenderRegionEntry(int region, void* thiz) {
564cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static_cast<Planet*>(thiz)->wRenderRegion(region);
565cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
566cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
567cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Renders the planet, dispatching the work to multiple threads.
568cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::Render() {
569cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  workers_->Dispatch(ps_context_->height, wRenderRegionEntry, this);
570cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
571cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
572cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Pre-calculations to make inner loops faster.
573cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::CacheCalcs() {
574cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_xyz_ = planet_x_ * planet_x_ +
575cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                planet_y_ * planet_y_ +
576cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                planet_z_ * planet_z_;
577cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_radius2_ = planet_radius_ * planet_radius_;
578cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_one_over_radius_ = 1.0f / planet_radius_;
579cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  eye_xyz_ = eye_x_ * eye_x_ + eye_y_ * eye_y_ + eye_z_ * eye_z_;
580cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // spin vector from center->equator
581cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_equator_x_ = cos(planet_spin_x_);
582cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_equator_y_ = 0.0f;
583cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_equator_z_ = sin(planet_spin_x_);
584cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
585cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // cache cross product of pole & equator
586cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_x_equator_x_ = planet_pole_y_ * planet_equator_z_ -
587cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                             planet_pole_z_ * planet_equator_y_;
588cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_x_equator_y_ = planet_pole_z_ * planet_equator_x_ -
589cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                             planet_pole_x_ * planet_equator_z_;
590cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_x_equator_z_ = planet_pole_x_ * planet_equator_y_ -
591cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                             planet_pole_y_ * planet_equator_x_;
592cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
593cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
594cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SetPlanetXYZR(float x, float y, float z, float r) {
595cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_x_ = x;
596cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_y_ = y;
597cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_z_ = z;
598cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_radius_ = r;
599cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CacheCalcs();
600cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
601cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
602cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SetEyeXYZ(float x, float y, float z) {
603cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  eye_x_ = x;
604cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  eye_y_ = y;
605cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  eye_z_ = z;
606cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CacheCalcs();
607cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
608cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
609cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SetLightXYZ(float x, float y, float z) {
610cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  light_x_ = x;
611cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  light_y_ = y;
612cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  light_z_ = z;
613cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CacheCalcs();
614cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
615cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
616cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SetAmbientRGB(float r, float g, float b) {
617cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ambient_r_ = r;
618cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ambient_g_ = g;
619cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ambient_b_ = b;
620cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CacheCalcs();
621cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
622cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
623cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SetDiffuseRGB(float r, float g, float b) {
624cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  diffuse_r_ = r;
625cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  diffuse_g_ = g;
626cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  diffuse_b_ = b;
627cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CacheCalcs();
628cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
629cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
630cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SetPlanetPole(float x, float y, float z) {
631cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_x_ = x;
632cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_y_ = y;
633cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_pole_z_ = z;
634cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CacheCalcs();
635cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
636cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
637cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SetPlanetEquator(float x, float y, float z) {
638cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // This is really over-ridden by spin at the momenent.
639cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_equator_x_ = x;
640cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_equator_y_ = y;
641cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_equator_z_ = z;
642cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CacheCalcs();
643cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
644cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
645cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SetPlanetSpin(float x, float y) {
646cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_spin_x_ = x;
647cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  planet_spin_y_ = y;
648cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CacheCalcs();
649cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
650cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
651cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Run a simple sim to spin the planet.  Update loop is run once per frame.
652cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Called from the main thread only and only when the worker threads are idle.
653cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::UpdateSim() {
654cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float x = planet_spin_x_ + ui_spin_x_;
655cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float y = planet_spin_y_ + ui_spin_y_;
656cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // keep in nice range
657cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (x > (kPI * 2.0f))
658cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    x = x - kPI * 2.0f;
659cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  else if (x < (-kPI * 2.0f))
660cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    x = x + kPI * 2.0f;
661cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (y > (kPI * 2.0f))
662cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    y = y - kPI * 2.0f;
663cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  else if (y < (-kPI * 2.0f))
664cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    y = y + kPI * 2.0f;
665cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetPlanetSpin(x, y);
666cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
667cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
668cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::StartBenchmark() {
669cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // For more consistent benchmark numbers, reset to default state.
670cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Reset();
671cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  printf("Benchmark started...\n");
672cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  benchmark_frame_counter_ = kFramesToBenchmark;
673cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  benchmarking_ = true;
674cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  benchmark_start_time_ = getseconds();
675cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
676cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
677cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::EndBenchmark() {
678cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  benchmark_end_time_ = getseconds();
679cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  printf("Benchmark ended... time: %2.5f\n",
680cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      benchmark_end_time_ - benchmark_start_time_);
681cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  benchmarking_ = false;
682cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  benchmark_frame_counter_ = 0;
683cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  double total_time = benchmark_end_time_ - benchmark_start_time_;
684cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Send benchmark result to JS.
685cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PostUpdateMessage("benchmark_result", total_time);
686cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
687cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
688cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SetZoom(float zoom) {
689cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui_zoom_ = std::min(kZoomMax, std::max(kZoomMin, zoom));
690cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetEyeXYZ(0.0f, 0.0f, -ui_zoom_);
691cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
692cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
693cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SetLight(float light) {
694cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui_light_ = std::min(kLightMax, std::max(kLightMin, light));
695cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetDiffuseRGB(0.8f * ui_light_, 0.8f * ui_light_, 0.8f * ui_light_);
696cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SetAmbientRGB(0.4f * ui_light_, 0.4f * ui_light_, 0.4f * ui_light_);
697cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
698cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
699cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SetTexture(const std::string& name, int width, int height,
700cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                        uint32_t* pixels) {
701cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (pixels) {
702cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (name == "earth.jpg") {
703cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      delete base_tex_;
704cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base_tex_ = new Texture(width, height, pixels);
705cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else if (name == "earthnight.jpg") {
706cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      delete night_tex_;
707cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      night_tex_ = new Texture(width, height, pixels);
708cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
709cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
710cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
711cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
712cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::SpinPlanet(pp::Point new_point, pp::Point last_point) {
713cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float delta_x = static_cast<float>(new_point.x() - last_point.x());
714cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float delta_y = static_cast<float>(new_point.y() - last_point.y());
715cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float spin_x = std::min(10.0f, std::max(-10.0f, delta_x * 0.5f));
716cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  float spin_y = std::min(10.0f, std::max(-10.0f, delta_y * 0.5f));
717cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui_spin_x_ = spin_x / 100.0f;
718cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui_spin_y_ = spin_y / 100.0f;
719cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui_last_point_ = new_point;
720cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
721cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
722cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Handle input events from the user and messages from JS.
723cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::HandleEvent(PSEvent* ps_event) {
724cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Give the 2D context a chance to process the event.
725cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (0 != PSContext2DHandleEvent(ps_context_, ps_event))
726cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
727cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) {
728cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Convert Pepper Simple event to a PPAPI C++ event
729cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    pp::InputEvent event(ps_event->as_resource);
730cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    switch (event.GetType()) {
731cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      case PP_INPUTEVENT_TYPE_KEYDOWN: {
732cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        pp::KeyboardInputEvent key(event);
733cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        uint32_t key_code = key.GetKeyCode();
734cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (key_code == 84)  // 't' key
735cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if (!benchmarking_)
736cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            StartBenchmark();
737cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        break;
738cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
739cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      case PP_INPUTEVENT_TYPE_MOUSEDOWN:
740cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
741cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        pp::MouseInputEvent mouse = pp::MouseInputEvent(event);
742cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (mouse.GetModifiers() & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) {
743cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if (event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN)
744cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            SpinPlanet(mouse.GetPosition(), mouse.GetPosition());
745cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          else
746cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            SpinPlanet(mouse.GetPosition(), ui_last_point_);
747cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }
748cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        break;
749cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
750cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      case PP_INPUTEVENT_TYPE_WHEEL: {
751cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        pp::WheelInputEvent wheel = pp::WheelInputEvent(event);
752cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        PP_FloatPoint ticks = wheel.GetTicks();
753cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        SetZoom(ui_zoom_ + (ticks.x + ticks.y) * kWheelSpeed);
754cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        // Update html slider by sending update message to JS.
755cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        PostUpdateMessage("set_zoom", ui_zoom_);
756cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        break;
757cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
758cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      case PP_INPUTEVENT_TYPE_TOUCHSTART:
759cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      case PP_INPUTEVENT_TYPE_TOUCHMOVE: {
760cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        pp::TouchInputEvent touches = pp::TouchInputEvent(event);
761cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        uint32_t count = touches.GetTouchCount(PP_TOUCHLIST_TYPE_TOUCHES);
762cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (count > 0) {
763cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          // Use first touch point to spin planet.
764cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          pp::TouchPoint touch =
765cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              touches.GetTouchByIndex(PP_TOUCHLIST_TYPE_TOUCHES, 0);
766cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          pp::Point screen_point(touch.position().x(),
767cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                 touch.position().y());
768cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if (event.GetType() == PP_INPUTEVENT_TYPE_TOUCHSTART)
769cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            SpinPlanet(screen_point, screen_point);
770cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          else
771cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            SpinPlanet(screen_point, ui_last_point_);
772cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }
773cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        break;
774cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
775cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      default:
776cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        break;
777cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
778cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) {
779cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Convert Pepper Simple message to PPAPI C++ vars
780cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    pp::Var var(ps_event->as_var);
781cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (var.is_dictionary()) {
782cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      pp::VarDictionary dictionary(var);
783cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      std::string message = dictionary.Get("message").AsString();
784cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (message == "run benchmark" && !benchmarking_) {
785cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        StartBenchmark();
786cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      } else if (message == "set_light") {
787cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        SetLight(static_cast<float>(dictionary.Get("value").AsDouble()));
788cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      } else if (message == "set_zoom") {
789cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        SetZoom(static_cast<float>(dictionary.Get("value").AsDouble()));
790cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      } else if (message == "set_threads") {
791cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        int threads = dictionary.Get("value").AsInt();
792cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        delete workers_;
793cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        workers_ = new ThreadPool(threads);
794cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      } else if (message == "texture") {
795cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        std::string name = dictionary.Get("name").AsString();
796cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        int width = dictionary.Get("width").AsInt();
797cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        int height = dictionary.Get("height").AsInt();
798cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        pp::VarArrayBuffer array_buffer(dictionary.Get("data"));
799cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (!name.empty() && !array_buffer.is_null()) {
800cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if (width > 0 && height > 0) {
801cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            uint32_t* pixels = static_cast<uint32_t*>(array_buffer.Map());
802cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            SetTexture(name, width, height, pixels);
803cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            array_buffer.Unmap();
804cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          }
805cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }
806cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
807cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    } else {
808cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      printf("Handle message unknown type: %s\n", var.DebugString().c_str());
809cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
810cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
811cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
812cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
813cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// PostUpdateMessage() helper function for sending small messages to JS.
814cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::PostUpdateMessage(const char* message_name, double value) {
815cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  pp::VarDictionary message;
816cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  message.Set("message", message_name);
817cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  message.Set("value", value);
818cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var());
819cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
820cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
821cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Planet::Update() {
822cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // When benchmarking is running, don't update display via
823cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // PSContext2DSwapBuffer() - vsync is enabled by default, and will throttle
824cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // the benchmark results.
825cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PSContext2DGetBuffer(ps_context_);
826cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (NULL == ps_context_->data)
827cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
828cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
829cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  do {
830cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    UpdateSim();
831cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Render();
832cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!benchmarking_) break;
833cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    --benchmark_frame_counter_;
834cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } while (benchmark_frame_counter_ > 0);
835cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (benchmarking_)
836cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    EndBenchmark();
837cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
838cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PSContext2DSwapBuffer(ps_context_);
839cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
840cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
841cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
842cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Starting point for the module.  We do not use main since it would
843cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// collide with main in libppapi_cpp.
844cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)int example_main(int argc, char* argv[]) {
845cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  Planet earth;
846cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  while (true) {
847cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PSEvent* ps_event;
848cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Consume all available events
849cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    while ((ps_event = PSEventTryAcquire()) != NULL) {
850cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      earth.HandleEvent(ps_event);
851cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      PSEventRelease(ps_event);
852cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
853cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Do simulation, render and present.
854cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    earth.Update();
855cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
856cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
857cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return 0;
858cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
859cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
860cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Register the function to call once the Instance Object is initialized.
861cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// see: pappi_simple/ps_main.h
862cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PPAPI_SIMPLE_REGISTER_MAIN(example_main);
863