1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file.
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <assert.h>
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <math.h>
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <ppapi/c/ppb_input_event.h>
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <ppapi/cpp/input_event.h>
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <ppapi/cpp/var.h>
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <ppapi/cpp/var_array.h>
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <ppapi/cpp/var_array_buffer.h>
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <ppapi/cpp/var_dictionary.h>
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <pthread.h>
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <stdio.h>
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <stdlib.h>
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <string.h>
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <sys/time.h>
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <unistd.h>
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <algorithm>
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <string>
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
233240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ppapi_simple/ps.h"
243240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ppapi_simple/ps_context_2d.h"
253240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ppapi_simple/ps_event.h"
263240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ppapi_simple/ps_interface.h"
273240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "ppapi_simple/ps_main.h"
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "sdk_util/macros.h"
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "sdk_util/thread_pool.h"
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
31ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochusing namespace sdk_util;  // For sdk_util::ThreadPool
32ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Global properties used to setup Earth demo.
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace {
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kPI = M_PI;
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kTwoPI = kPI * 2.0f;
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kOneOverPI = 1.0f / kPI;
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kOneOver2PI = 1.0f / kTwoPI;
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kOneOver255 = 1.0f / 255.0f;
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kArcCosineTableSize = 4096;
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kFramesToBenchmark = 100;
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kZoomMin = 1.0f;
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kZoomMax = 50.0f;
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kWheelSpeed = 2.0f;
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kLightMin = 0.0f;
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kLightMax = 2.0f;
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Timer helper for benchmarking.  Returns seconds elapsed since program start,
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// as a double.
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochtimeval start_tv;
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint start_tv_retv = gettimeofday(&start_tv, NULL);
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline double getseconds() {
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const double usec_to_sec = 0.000001;
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  timeval tv;
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if ((0 == start_tv_retv) && (0 == gettimeofday(&tv, NULL)))
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return (tv.tv_sec - start_tv.tv_sec) + tv.tv_usec * usec_to_sec;
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return 0.0;
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// RGBA helper functions, used for extracting color from RGBA source image.
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline float ExtractR(uint32_t c) {
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return static_cast<float>(c & 0xFF) * kOneOver255;
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline float ExtractG(uint32_t c) {
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return static_cast<float>((c & 0xFF00) >> 8) * kOneOver255;
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline float ExtractB(uint32_t c) {
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return static_cast<float>((c & 0xFF0000) >> 16) * kOneOver255;
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// BGRA helper function, for constructing a pixel for a BGRA buffer.
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)inline uint32_t MakeBGRA(uint32_t b, uint32_t g, uint32_t r, uint32_t a) {
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// simple container for earth texture
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct Texture {
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int width, height;
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  uint32_t* pixels;
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Texture(int w, int h) : width(w), height(h) {
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    pixels = new uint32_t[w * h];
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    memset(pixels, 0, sizeof(uint32_t) * w * h);
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  explicit Texture(int w, int h, uint32_t* p) : width(w), height(h) {
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    pixels = new uint32_t[w * h];
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    memcpy(pixels, p, sizeof(uint32_t) * w * h);
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ~Texture() { delete[] pixels; }
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DISALLOW_COPY_AND_ASSIGN(Texture);
94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct ArcCosine {
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // slightly larger table so we can interpolate beyond table size
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float table[kArcCosineTableSize + 2];
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float TableLerp(float x);
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ArcCosine();
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochArcCosine::ArcCosine() {
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // build a slightly larger table to allow for numeric imprecision
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (int i = 0; i < (kArcCosineTableSize + 2); ++i) {
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float f = static_cast<float>(i) / kArcCosineTableSize;
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    f = f * 2.0f - 1.0f;
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    table[i] = acos(f);
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// looks up acos(f) using a table and lerping between entries
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// (it is expected that input f is between -1 and 1)
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochfloat ArcCosine::TableLerp(float f) {
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float x = (f + 1.0f) * 0.5f;
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  x = x * kArcCosineTableSize;
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int ix = static_cast<int>(x);
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float fx = static_cast<float>(ix);
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float dx = x - fx;
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float af = table[ix];
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float af2 = table[ix + 1];
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return af + (af2 - af) * dx;
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Helper functions for quick but approximate sqrt.
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochunion Convert {
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float f;
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int i;
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Convert(int x) { i = x; }
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Convert(float x) { f = x; }
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int AsInt() { return i; }
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float AsFloat() { return f; }
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline const int AsInteger(const float f) {
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Convert u(f);
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return u.AsInt();
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline const float AsFloat(const int i) {
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Convert u(i);
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return u.AsFloat();
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst long int kOneAsInteger = AsInteger(1.0f);
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline float inline_quick_sqrt(float x) {
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int i;
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  i = (AsInteger(x) >> 1) + (kOneAsInteger >> 1);
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return AsFloat(i);
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline float inline_sqrt(float x) {
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float y;
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  y = inline_quick_sqrt(x);
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  y = (y * y + x) / (2.0f * y);
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  y = (y * y + x) / (2.0f * y);
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return y;
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// takes a -0..1+ color, clamps it to 0..1 and maps it to 0..255 integer
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline uint32_t Clamp255(float x) {
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (x < 0.0f) {
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    x = 0.0f;
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else if (x > 1.0f) {
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    x = 1.0f;
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return static_cast<uint32_t>(x * 255.0f);
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// The main object that runs the Earth demo.
1763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochclass Planet {
177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public:
1783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  Planet();
179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual ~Planet();
1803240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Runs a tick of the simulations, update 2D output.
1813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  void Update();
1823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Handle event from user, or message from JS.
1833240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  void HandleEvent(PSEvent* ps_event);
184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private:
186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Methods prefixed with 'w' are run on worker threads.
187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  uint32_t* wGetAddr(int x, int y);
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void wRenderPixelSpan(int x0, int x1, int y);
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void wMakeRect(int r, int *x, int *y, int *w, int *h);
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void wRenderRect(int x0, int y0, int x1, int y1);
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void wRenderRegion(int region);
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  static void wRenderRegionEntry(int region, void *thiz);
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // These methods are only called by the main thread.
195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void CacheCalcs();
196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetPlanetXYZR(float x, float y, float z, float r);
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetPlanetPole(float x, float y, float z);
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetPlanetEquator(float x, float y, float z);
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetPlanetSpin(float x, float y);
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetEyeXYZ(float x, float y, float z);
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetLightXYZ(float x, float y, float z);
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetAmbientRGB(float r, float g, float b);
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetDiffuseRGB(float r, float g, float b);
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetZoom(float zoom);
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetLight(float zoom);
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void SetTexture(const std::string& name, int width, int height,
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      uint32_t* pixels);
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void SpinPlanet(pp::Point new_point, pp::Point last_point);
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void Reset();
2113240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  void RequestTextures();
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void UpdateSim();
213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void Render();
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void Draw();
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void StartBenchmark();
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void EndBenchmark();
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Post a small key-value message to update JS.
218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void PostUpdateMessage(const char* message_name, double value);
219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // User Interface settings.  These settings are controlled via html
221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // controls or via user input.
222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float ui_light_;
223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float ui_zoom_;
224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float ui_spin_x_;
225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float ui_spin_y_;
2264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::Point ui_last_point_;
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Various settings for position & orientation of planet.  Do not change
229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // these variables, instead use SetPlanet*() functions.
230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_radius_;
231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_spin_x_;
232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_spin_y_;
233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_x_, planet_y_, planet_z_;
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_pole_x_, planet_pole_y_, planet_pole_z_;
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_equator_x_, planet_equator_y_, planet_equator_z_;
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Observer's eye.  Do not change these variables, instead use SetEyeXYZ().
238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float eye_x_, eye_y_, eye_z_;
239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Light position, ambient and diffuse settings.  Do not change these
241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // variables, instead use SetLightXYZ(), SetAmbientRGB() and SetDiffuseRGB().
242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float light_x_, light_y_, light_z_;
243eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float diffuse_r_, diffuse_g_, diffuse_b_;
244eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float ambient_r_, ambient_g_, ambient_b_;
245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
246eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Cached calculations.  Do not change these variables - they are updated by
247eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // CacheCalcs() function.
248eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_xyz_;
249eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_pole_x_equator_x_;
250eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_pole_x_equator_y_;
251eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_pole_x_equator_z_;
252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_radius2_;
253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_one_over_radius_;
254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float eye_xyz_;
255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Source texture (earth map).
257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Texture* base_tex_;
258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Texture* night_tex_;
259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int width_for_tex_;
260eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int height_for_tex_;
261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Quick ArcCos helper.
263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ArcCosine acos_;
264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Misc.
2663240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  PSContext2D_t* ps_context_;
267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int num_threads_;
268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ThreadPool* workers_;
269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool benchmarking_;
2703240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  int benchmark_frame_counter_;
271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  double benchmark_start_time_;
272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  double benchmark_end_time_;
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid Planet::RequestTextures() {
277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Request a set of images from JS.  After images are loaded by JS, a
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // message from JS -> NaCl will arrive containing the pixel data.  See
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // HandleMessage() method in this file.
280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  pp::VarDictionary message;
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  message.Set("message", "request_textures");
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  pp::VarArray names;
283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  names.Set(0, "earth.jpg");
284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  names.Set(1, "earthnight.jpg");
285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  message.Set("names", names);
2863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var());
287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::Reset() {
290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Reset has to first fill in all variables with valid floats, so
291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // CacheCalcs() doesn't potentially propagate NaNs when calling Set*()
292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // functions further below.
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_radius_ = 1.0f;
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_spin_x_ = 0.0f;
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_spin_y_ = 0.0f;
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_x_ = 0.0f;
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_y_ = 0.0f;
298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_z_ = 0.0f;
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_x_ = 0.0f;
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_y_ = 0.0f;
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_z_ = 0.0f;
302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_equator_x_ = 0.0f;
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_equator_y_ = 0.0f;
304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_equator_z_ = 0.0f;
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  eye_x_ = 0.0f;
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  eye_y_ = 0.0f;
307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  eye_z_ = 0.0f;
308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  light_x_ = 0.0f;
309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  light_y_ = 0.0f;
310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  light_z_ = 0.0f;
311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  diffuse_r_ = 0.0f;
312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  diffuse_g_ = 0.0f;
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  diffuse_b_ = 0.0f;
314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ambient_r_ = 0.0f;
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ambient_g_ = 0.0f;
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ambient_b_ = 0.0f;
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_xyz_ = 0.0f;
318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_x_equator_x_ = 0.0f;
319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_x_equator_y_ = 0.0f;
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_x_equator_z_ = 0.0f;
321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_radius2_ = 0.0f;
322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_one_over_radius_ = 0.0f;
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  eye_xyz_ = 0.0f;
324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ui_zoom_ = 14.0f;
325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ui_light_ = 1.0f;
326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ui_spin_x_ = 0.01f;
327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ui_spin_y_ = 0.0f;
3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ui_last_point_ = pp::Point(0, 0);
329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Set up reasonable default values.
331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetPlanetXYZR(0.0f, 0.0f, 48.0f, 4.0f);
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetEyeXYZ(0.0f, 0.0f, -ui_zoom_);
333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetLightXYZ(-60.0f, -30.0f, 0.0f);
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetAmbientRGB(0.05f, 0.05f, 0.05f);
335eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetDiffuseRGB(0.8f, 0.8f, 0.8f);
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetPlanetPole(0.0f, 1.0f, 0.0f);
337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetPlanetEquator(1.0f, 0.0f, 0.0f);
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetPlanetSpin(kPI / 2.0f, kPI / 2.0f);
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetZoom(ui_zoom_);
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetLight(ui_light_);
341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Send UI values to JS to reset html sliders.
343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PostUpdateMessage("set_zoom", ui_zoom_);
344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PostUpdateMessage("set_light", ui_light_);
345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
346eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben MurdochPlanet::Planet() : base_tex_(NULL), night_tex_(NULL), num_threads_(0),
3493240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    benchmarking_(false), benchmark_frame_counter_(0) {
350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Reset();
3523240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  RequestTextures();
353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // By default, render from the dispatch thread.
354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  workers_ = new ThreadPool(num_threads_);
3553240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  PSEventSetFilter(PSE_ALL);
3563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
358eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
359eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochPlanet::~Planet() {
360eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  delete workers_;
3613240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  PSContext2DFree(ps_context_);
362eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
363eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Given a region r, derive a rectangle.
365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// This rectangle shouldn't overlap with work being done by other workers.
366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// If multithreading, this function is only called by the worker threads.
367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::wMakeRect(int r, int *x, int *y, int *w, int *h) {
368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  *x = 0;
3693240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  *w = ps_context_->width;
3703240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  *y = r;
3713240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  *h = 1;
372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline uint32_t* Planet::wGetAddr(int x, int y) {
3763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  return ps_context_->data + x + y * ps_context_->stride / sizeof(uint32_t);
377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// This is the meat of the ray tracer.  Given a pixel span (x0, x1) on
380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// scanline y, shoot rays into the scene and render what they hit.  Use
381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// scanline coherence to do a few optimizations
382eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::wRenderPixelSpan(int x0, int x1, int y) {
383eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!base_tex_ || !night_tex_)
384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
3853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const int kColorBlack = MakeBGRA(0, 0, 0, 0xFF);
386ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  float width = ps_context_->width;
387ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  float height = ps_context_->height;
388ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  float min_dim = width < height ? width : height;
389ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  float offset_x = width < height ? 0 : (width - min_dim) * 0.5f;
390ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  float offset_y = width < height ? (height - min_dim) * 0.5f : 0;
391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float y0 = eye_y_;
392eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float z0 = eye_z_;
393ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  float y1 = (static_cast<float>(y - offset_y) / min_dim) * 2.0f - 1.0f;
394eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float z1 = 0.0f;
395eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float dy = (y1 - y0);
396eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float dz = (z1 - z0);
397eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float dy_dy_dz_dz = dy * dy + dz * dz;
398eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float two_dy_y0_y_two_dz_z0_z = 2.0f * dy * (y0 - planet_y_) +
399eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                  2.0f * dz * (z0 - planet_z_);
400eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float planet_xyz_eye_xyz = planet_xyz_ + eye_xyz_;
401eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float y_y0_z_z0 = planet_y_ * y0 + planet_z_ * z0;
402ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  float oowidth = 1.0f / min_dim;
403eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  uint32_t* pixels = this->wGetAddr(x0, y);
404eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (int x = x0; x <= x1; ++x) {
405eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // scan normalized screen -1..1
406ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    float x1 = (static_cast<float>(x - offset_x) * oowidth) * 2.0f - 1.0f;
407eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // eye
408eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float x0 = eye_x_;
409eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // delta from screen to eye
410eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float dx = (x1 - x0);
411eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // build a, b, c
412eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float a = dx * dx + dy_dy_dz_dz;
413eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float b = 2.0f * dx * (x0 - planet_x_) + two_dy_y0_y_two_dz_z0_z;
414eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float c = planet_xyz_eye_xyz +
415eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch              -2.0f * (planet_x_ * x0 + y_y0_z_z0) - (planet_radius2_);
416eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // calculate discriminant
417eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float disc = b * b - 4.0f * a * c;
418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
419eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Did ray hit the sphere?
420eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (disc < 0.0f) {
421eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      *pixels = kColorBlack;
422eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      ++pixels;
423eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      continue;
424eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
425eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
426eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // calc parametric t value
427eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float t = (-b - inline_sqrt(disc)) / (2.0f * a);
428eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float px = x0 + t * dx;
429eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float py = y0 + t * dy;
430eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float pz = z0 + t * dz;
431eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float nx = (px - planet_x_) * planet_one_over_radius_;
432eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float ny = (py - planet_y_) * planet_one_over_radius_;
433eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float nz = (pz - planet_z_) * planet_one_over_radius_;
434eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
435eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Misc raytrace calculations.
436eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float Lx = (light_x_ - px);
437eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float Ly = (light_y_ - py);
438eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float Lz = (light_z_ - pz);
439eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float Lq = 1.0f / inline_quick_sqrt(Lx * Lx + Ly * Ly + Lz * Lz);
440eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Lx *= Lq;
441eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Ly *= Lq;
442eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Lz *= Lq;
443eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float d = (Lx * nx + Ly * ny + Lz * nz);
444eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float pr = (diffuse_r_ * d) + ambient_r_;
445eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float pg = (diffuse_g_ * d) + ambient_g_;
446eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float pb = (diffuse_b_ * d) + ambient_b_;
447eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float ds = -(nx * planet_pole_x_ +
448eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 ny * planet_pole_y_ +
449eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 nz * planet_pole_z_);
450eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float ang = acos_.TableLerp(ds);
451eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float v = ang * kOneOverPI;
452eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float dp = planet_equator_x_ * nx +
453eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch               planet_equator_y_ * ny +
454eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch               planet_equator_z_ * nz;
455cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    float w = dp / sinf(ang);
456eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (w > 1.0f) w = 1.0f;
457eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (w < -1.0f) w = -1.0f;
458eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float th = acos_.TableLerp(w) * kOneOver2PI;
459eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float dps = planet_pole_x_equator_x_ * nx +
460eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                planet_pole_x_equator_y_ * ny +
461eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                planet_pole_x_equator_z_ * nz;
462eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float u;
463eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (dps < 0.0f)
464eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      u = th;
465eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    else
466eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      u = 1.0f - th;
467eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
468eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Look up daylight texel.
469eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int tx = static_cast<int>(u * base_tex_->width);
470eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int ty = static_cast<int>(v * base_tex_->height);
471eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int offset = tx + ty * base_tex_->width;
472eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    uint32_t base_texel = base_tex_->pixels[offset];
473eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float tr = ExtractR(base_texel);
474eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float tg = ExtractG(base_texel);
475eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float tb = ExtractB(base_texel);
476eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
477eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float ipr = 1.0f - pr;
478eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (ipr < 0.0f) ipr = 0.0f;
479eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float ipg = 1.0f - pg;
480eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (ipg < 0.0f) ipg = 0.0f;
481eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float ipb = 1.0f - pb;
482eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (ipb < 0.0f) ipb = 0.0f;
483eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
484eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Look up night texel.
485eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int nix = static_cast<int>(u * night_tex_->width);
486eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int niy = static_cast<int>(v * night_tex_->height);
487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int noffset = nix + niy * night_tex_->width;
488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    uint32_t night_texel = night_tex_->pixels[noffset];
489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float nr = ExtractR(night_texel);
490eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float ng = ExtractG(night_texel);
491eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    float nb = ExtractB(night_texel);
492eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Final color value is lerp between day and night texels.
494eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    unsigned int ir = Clamp255(pr * tr + nr * ipr);
495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    unsigned int ig = Clamp255(pg * tg + ng * ipg);
496eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    unsigned int ib = Clamp255(pb * tb + nb * ipb);
497eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
4983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    unsigned int color = MakeBGRA(ib, ig, ir, 0xFF);
499eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
500eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    *pixels = color;
501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ++pixels;
502eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
504eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
505eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Renders a rectangular area of the screen, scan line at a time
506eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::wRenderRect(int x, int y, int w, int h) {
507eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (int j = y; j < (y + h); ++j) {
508eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    this->wRenderPixelSpan(x, x + w - 1, j);
509eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
510eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
511eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
512eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// If multithreading, this function is only called by the worker threads.
513eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::wRenderRegion(int region) {
514eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // convert region # into x0, y0, x1, y1 rectangle
515eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int x, y, w, h;
516eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  wMakeRect(region, &x, &y, &w, &h);
517eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // render this rectangle
518eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  wRenderRect(x, y, w, h);
519eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
520eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
521eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Entry point for worker thread.  Can't pass a member function around, so we
522eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// have to do this little round-about.
523eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::wRenderRegionEntry(int region, void* thiz) {
524eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  static_cast<Planet*>(thiz)->wRenderRegion(region);
525eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
526eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
527eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Renders the planet, dispatching the work to multiple threads.
528eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::Render() {
5293240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  workers_->Dispatch(ps_context_->height, wRenderRegionEntry, this);
530eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
531eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
532eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Pre-calculations to make inner loops faster.
533eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::CacheCalcs() {
534eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_xyz_ = planet_x_ * planet_x_ +
535eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                planet_y_ * planet_y_ +
536eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                planet_z_ * planet_z_;
537eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_radius2_ = planet_radius_ * planet_radius_;
538eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_one_over_radius_ = 1.0f / planet_radius_;
539eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  eye_xyz_ = eye_x_ * eye_x_ + eye_y_ * eye_y_ + eye_z_ * eye_z_;
540eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // spin vector from center->equator
541eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_equator_x_ = cos(planet_spin_x_);
542eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_equator_y_ = 0.0f;
543eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_equator_z_ = sin(planet_spin_x_);
544eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
545eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // cache cross product of pole & equator
546eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_x_equator_x_ = planet_pole_y_ * planet_equator_z_ -
547eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                             planet_pole_z_ * planet_equator_y_;
548eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_x_equator_y_ = planet_pole_z_ * planet_equator_x_ -
549eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                             planet_pole_x_ * planet_equator_z_;
550eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_x_equator_z_ = planet_pole_x_ * planet_equator_y_ -
551eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                             planet_pole_y_ * planet_equator_x_;
552eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
553eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
554eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetPlanetXYZR(float x, float y, float z, float r) {
555eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_x_ = x;
556eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_y_ = y;
557eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_z_ = z;
558eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_radius_ = r;
559eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CacheCalcs();
560eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
561eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
562eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetEyeXYZ(float x, float y, float z) {
563eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  eye_x_ = x;
564eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  eye_y_ = y;
565eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  eye_z_ = z;
566eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CacheCalcs();
567eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
568eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
569eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetLightXYZ(float x, float y, float z) {
570eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  light_x_ = x;
571eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  light_y_ = y;
572eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  light_z_ = z;
573eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CacheCalcs();
574eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
575eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
576eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetAmbientRGB(float r, float g, float b) {
577eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ambient_r_ = r;
578eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ambient_g_ = g;
579eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ambient_b_ = b;
580eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CacheCalcs();
581eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
582eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
583eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetDiffuseRGB(float r, float g, float b) {
584eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  diffuse_r_ = r;
585eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  diffuse_g_ = g;
586eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  diffuse_b_ = b;
587eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CacheCalcs();
588eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
589eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
590eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetPlanetPole(float x, float y, float z) {
591eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_x_ = x;
592eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_y_ = y;
593eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_pole_z_ = z;
594eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CacheCalcs();
595eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
596eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
597eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetPlanetEquator(float x, float y, float z) {
598eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // This is really over-ridden by spin at the momenent.
599eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_equator_x_ = x;
600eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_equator_y_ = y;
601eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_equator_z_ = z;
602eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CacheCalcs();
603eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
604eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
605eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetPlanetSpin(float x, float y) {
606eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_spin_x_ = x;
607eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  planet_spin_y_ = y;
608eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  CacheCalcs();
609eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
610eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
611eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Run a simple sim to spin the planet.  Update loop is run once per frame.
612eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Called from the main thread only and only when the worker threads are idle.
613eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::UpdateSim() {
614eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float x = planet_spin_x_ + ui_spin_x_;
615eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  float y = planet_spin_y_ + ui_spin_y_;
616eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // keep in nice range
617eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (x > (kPI * 2.0f))
618eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    x = x - kPI * 2.0f;
619eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  else if (x < (-kPI * 2.0f))
620eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    x = x + kPI * 2.0f;
621eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (y > (kPI * 2.0f))
622eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    y = y - kPI * 2.0f;
623eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  else if (y < (-kPI * 2.0f))
624eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    y = y + kPI * 2.0f;
625eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetPlanetSpin(x, y);
626eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
627eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
628eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::StartBenchmark() {
629eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // For more consistent benchmark numbers, reset to default state.
630eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Reset();
631eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  printf("Benchmark started...\n");
632eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  benchmark_frame_counter_ = kFramesToBenchmark;
633eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  benchmarking_ = true;
634eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  benchmark_start_time_ = getseconds();
635eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
636eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
637eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::EndBenchmark() {
638eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  benchmark_end_time_ = getseconds();
639eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  printf("Benchmark ended... time: %2.5f\n",
640eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      benchmark_end_time_ - benchmark_start_time_);
641eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  benchmarking_ = false;
642eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  benchmark_frame_counter_ = 0;
643eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  double total_time = benchmark_end_time_ - benchmark_start_time_;
644eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Send benchmark result to JS.
645eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  PostUpdateMessage("benchmark_result", total_time);
646eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
647eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
648eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetZoom(float zoom) {
649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ui_zoom_ = std::min(kZoomMax, std::max(kZoomMin, zoom));
650eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetEyeXYZ(0.0f, 0.0f, -ui_zoom_);
651eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
653eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetLight(float light) {
654eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ui_light_ = std::min(kLightMax, std::max(kLightMin, light));
655eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetDiffuseRGB(0.8f * ui_light_, 0.8f * ui_light_, 0.8f * ui_light_);
656eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SetAmbientRGB(0.4f * ui_light_, 0.4f * ui_light_, 0.4f * ui_light_);
657eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
658eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
659eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetTexture(const std::string& name, int width, int height,
660eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                        uint32_t* pixels) {
661eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (pixels) {
662eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (name == "earth.jpg") {
663eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      delete base_tex_;
664eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      base_tex_ = new Texture(width, height, pixels);
665eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    } else if (name == "earthnight.jpg") {
666eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      delete night_tex_;
667eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      night_tex_ = new Texture(width, height, pixels);
668eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
669eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
670eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
671eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
6724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void Planet::SpinPlanet(pp::Point new_point, pp::Point last_point) {
6734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  float delta_x = static_cast<float>(new_point.x() - last_point.x());
6744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  float delta_y = static_cast<float>(new_point.y() - last_point.y());
6754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  float spin_x = std::min(10.0f, std::max(-10.0f, delta_x * 0.5f));
6764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  float spin_y = std::min(10.0f, std::max(-10.0f, delta_y * 0.5f));
6774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ui_spin_x_ = spin_x / 100.0f;
6784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ui_spin_y_ = spin_y / 100.0f;
6794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ui_last_point_ = new_point;
6804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
6814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Handle input events from the user and messages from JS.
6833240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid Planet::HandleEvent(PSEvent* ps_event) {
6843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // Give the 2D context a chance to process the event.
6853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (0 != PSContext2DHandleEvent(ps_context_, ps_event))
6863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    return;
6873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) {
6883240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    // Convert Pepper Simple event to a PPAPI C++ event
6893240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    pp::InputEvent event(ps_event->as_resource);
6903240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    switch (event.GetType()) {
6913240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      case PP_INPUTEVENT_TYPE_KEYDOWN: {
6923240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        pp::KeyboardInputEvent key(event);
6933240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        uint32_t key_code = key.GetKeyCode();
6943240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        if (key_code == 84)  // 't' key
6953240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          if (!benchmarking_)
6963240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch            StartBenchmark();
6973240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        break;
698eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
6994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case PP_INPUTEVENT_TYPE_MOUSEDOWN:
7004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
7013240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        pp::MouseInputEvent mouse = pp::MouseInputEvent(event);
7023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        if (mouse.GetModifiers() & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) {
7034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          if (event.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN)
7044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            SpinPlanet(mouse.GetPosition(), mouse.GetPosition());
7054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          else
7064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            SpinPlanet(mouse.GetPosition(), ui_last_point_);
7073240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        }
7083240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        break;
7093240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      }
7103240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      case PP_INPUTEVENT_TYPE_WHEEL: {
7113240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        pp::WheelInputEvent wheel = pp::WheelInputEvent(event);
7123240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        PP_FloatPoint ticks = wheel.GetTicks();
7133240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        SetZoom(ui_zoom_ + (ticks.x + ticks.y) * kWheelSpeed);
7143240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        // Update html slider by sending update message to JS.
7153240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        PostUpdateMessage("set_zoom", ui_zoom_);
7163240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        break;
7173240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      }
7184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case PP_INPUTEVENT_TYPE_TOUCHSTART:
7194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      case PP_INPUTEVENT_TYPE_TOUCHMOVE: {
7204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        pp::TouchInputEvent touches = pp::TouchInputEvent(event);
7214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        uint32_t count = touches.GetTouchCount(PP_TOUCHLIST_TYPE_TOUCHES);
7224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (count > 0) {
7234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          // Use first touch point to spin planet.
7244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          pp::TouchPoint touch =
7254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)              touches.GetTouchByIndex(PP_TOUCHLIST_TYPE_TOUCHES, 0);
7264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          pp::Point screen_point(touch.position().x(),
7274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 touch.position().y());
7284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          if (event.GetType() == PP_INPUTEVENT_TYPE_TOUCHSTART)
7294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            SpinPlanet(screen_point, screen_point);
7304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          else
7314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            SpinPlanet(screen_point, ui_last_point_);
7324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }
7334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        break;
7344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
7353240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      default:
7363240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        break;
737eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
7383240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  } else if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) {
7393240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    // Convert Pepper Simple message to PPAPI C++ vars
7403240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    pp::Var var(ps_event->as_var);
7413240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    if (var.is_dictionary()) {
7423240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      pp::VarDictionary dictionary(var);
7433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      std::string message = dictionary.Get("message").AsString();
7443240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      if (message == "run benchmark" && !benchmarking_) {
7453240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        StartBenchmark();
7463240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      } else if (message == "set_light") {
7473240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        SetLight(static_cast<float>(dictionary.Get("value").AsDouble()));
7483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      } else if (message == "set_zoom") {
7493240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        SetZoom(static_cast<float>(dictionary.Get("value").AsDouble()));
7503240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      } else if (message == "set_threads") {
7513240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        int threads = dictionary.Get("value").AsInt();
7523240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        delete workers_;
7533240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        workers_ = new ThreadPool(threads);
7543240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      } else if (message == "texture") {
7553240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        std::string name = dictionary.Get("name").AsString();
7563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        int width = dictionary.Get("width").AsInt();
7573240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        int height = dictionary.Get("height").AsInt();
7583240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        pp::VarArrayBuffer array_buffer(dictionary.Get("data"));
7593240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        if (!name.empty() && !array_buffer.is_null()) {
7603240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          if (width > 0 && height > 0) {
7613240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch            uint32_t* pixels = static_cast<uint32_t*>(array_buffer.Map());
7623240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch            SetTexture(name, width, height, pixels);
7633240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch            array_buffer.Unmap();
7643240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch          }
7653240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        }
7663240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      }
7673240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    } else {
7683240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      printf("Handle message unknown type: %s\n", var.DebugString().c_str());
769eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
770eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
771eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
772eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
773eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// PostUpdateMessage() helper function for sending small messages to JS.
774eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::PostUpdateMessage(const char* message_name, double value) {
775eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  pp::VarDictionary message;
776eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  message.Set("message", message_name);
777eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  message.Set("value", value);
7783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var());
779eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
780eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
781eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::Update() {
7823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // When benchmarking is running, don't update display via
7833240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // PSContext2DSwapBuffer() - vsync is enabled by default, and will throttle
7843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  // the benchmark results.
7853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  PSContext2DGetBuffer(ps_context_);
7863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  if (NULL == ps_context_->data)
7873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    return;
7883240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
789eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  do {
790eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    UpdateSim();
791eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Render();
792eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!benchmarking_) break;
793eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    --benchmark_frame_counter_;
794eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } while (benchmark_frame_counter_ > 0);
795eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (benchmarking_)
796eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    EndBenchmark();
797eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7983240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  PSContext2DSwapBuffer(ps_context_);
7993240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch}
8003240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch
801eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
8023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Starting point for the module.  We do not use main since it would
8033240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// collide with main in libppapi_cpp.
8043240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochint example_main(int argc, char* argv[]) {
8053240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  Planet earth;
8063240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  while (true) {
8073240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    PSEvent* ps_event;
8083240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    // Consume all available events
8093240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    while ((ps_event = PSEventTryAcquire()) != NULL) {
8103240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      earth.HandleEvent(ps_event);
8113240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      PSEventRelease(ps_event);
8123240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    }
8133240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    // Do simulation, render and present.
8143240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    earth.Update();
815eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
816eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
8173240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  return 0;
818eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
819eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
8203240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Register the function to call once the Instance Object is initialized.
8213240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// see: pappi_simple/ps_main.h
8223240926e260ce088908e02ac07a6cf7b0c0cbf44Ben MurdochPPAPI_SIMPLE_REGISTER_MAIN(example_main);
823