1c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// found in the LICENSE file.
4c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
5c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <assert.h>
6c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <math.h>
7c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/c/pp_point.h>
8c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/c/ppb_input_event.h>
9c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/completion_callback.h>
10c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/graphics_2d.h>
11c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/image_data.h>
12c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/input_event.h>
13c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/instance.h>
14c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/module.h>
15c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/rect.h>
16c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/size.h>
17c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/var.h>
18c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/var_array.h>
19c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/var_array_buffer.h>
20c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <ppapi/cpp/var_dictionary.h>
21c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <pthread.h>
22c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <stdio.h>
23c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <stdlib.h>
24c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <string.h>
25c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <unistd.h>
26c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
27c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <algorithm>
28c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include <string>
29c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "common/fps.h"
31c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include "sdk_util/macros.h"
32c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch#include "sdk_util/thread_pool.h"
33c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Chromium presubmit prevents checking in changes with calls to printf to
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// prevent spammy output. We'll work around that for this example.
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#define logf printf
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
38c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochusing namespace sdk_util;  // For sdk_util::ThreadPool
39c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
40c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Global properties used to setup Earth demo.
41c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochnamespace {
42c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst float kPI = M_PI;
43c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst float kTwoPI = kPI * 2.0f;
44c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst float kOneOverPI = 1.0f / kPI;
45c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst float kOneOver2PI = 1.0f / kTwoPI;
46c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst float kOneOver255 = 1.0f / 255.0f;
47c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst int kArcCosineTableSize = 4096;
48c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst int kFramesToBenchmark = 100;
49c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst float kZoomMin = 1.0f;
50c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst float kZoomMax = 50.0f;
51c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst float kWheelSpeed = 2.0f;
52c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst float kLightMin = 0.0f;
53c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst float kLightMax = 2.0f;
54c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
55c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// RGBA helper functions.
56c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochinline float ExtractR(uint32_t c) {
57c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return static_cast<float>(c & 0xFF) * kOneOver255;
58c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
59c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
60c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochinline float ExtractG(uint32_t c) {
61c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return static_cast<float>((c & 0xFF00) >> 8) * kOneOver255;
62c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
63c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
64c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochinline float ExtractB(uint32_t c) {
65c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return static_cast<float>((c & 0xFF0000) >> 16) * kOneOver255;
66c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
67c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
68c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochinline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
69c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
70c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
71c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
72c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// simple container for earth texture
73c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochstruct Texture {
74c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int width, height;
75c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  uint32_t* pixels;
76c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  Texture(int w, int h) : width(w), height(h) {
77c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    pixels = new uint32_t[w * h];
78c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    memset(pixels, 0, sizeof(uint32_t) * w * h);
79c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
80c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  explicit Texture(int w, int h, uint32_t* p) : width(w), height(h) {
81c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    pixels = new uint32_t[w * h];
82c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    memcpy(pixels, p, sizeof(uint32_t) * w * h);
83c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
84c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ~Texture() { delete[] pixels; }
85c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
86c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(Texture);
87c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch};
88c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
89c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
90c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
91c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochstruct ArcCosine {
92c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // slightly larger table so we can interpolate beyond table size
93c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float table[kArcCosineTableSize + 2];
94c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float TableLerp(float x);
95c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ArcCosine();
96c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch};
97c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
98c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben MurdochArcCosine::ArcCosine() {
99c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // build a slightly larger table to allow for numeric imprecision
100c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  for (int i = 0; i < (kArcCosineTableSize + 2); ++i) {
101c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float f = static_cast<float>(i) / kArcCosineTableSize;
102c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    f = f * 2.0f - 1.0f;
103c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    table[i] = acos(f);
104c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
105c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
106c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
107c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// looks up acos(f) using a table and lerping between entries
108c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// (it is expected that input f is between -1 and 1)
109c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochfloat ArcCosine::TableLerp(float f) {
110c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float x = (f + 1.0f) * 0.5f;
111c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  x = x * kArcCosineTableSize;
112c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int ix = static_cast<int>(x);
113c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float fx = static_cast<float>(ix);
114c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float dx = x - fx;
115c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float af = table[ix];
116c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float af2 = table[ix + 1];
117c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return af + (af2 - af) * dx;
118c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
119c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
120c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Helper functions for quick but approximate sqrt.
121c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochunion Convert {
122c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float f;
123c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int i;
124c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  Convert(int x) { i = x; }
125c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  Convert(float x) { f = x; }
126c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int AsInt() { return i; }
127c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float AsFloat() { return f; }
128c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch};
129c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
130c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochinline const int AsInteger(const float f) {
131c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  Convert u(f);
132c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return u.AsInt();
133c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
134c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
135c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochinline const float AsFloat(const int i) {
136c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  Convert u(i);
137c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return u.AsFloat();
138c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
139c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
140c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochconst long int kOneAsInteger = AsInteger(1.0f);
141c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
142c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochinline float inline_quick_sqrt(float x) {
143c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int i;
144c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  i = (AsInteger(x) >> 1) + (kOneAsInteger >> 1);
145c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return AsFloat(i);
146c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
147c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
148c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochinline float inline_sqrt(float x) {
149c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float y;
150c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  y = inline_quick_sqrt(x);
151c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  y = (y * y + x) / (2.0f * y);
152c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  y = (y * y + x) / (2.0f * y);
153c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return y;
154c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
155c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
156c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// takes a -0..1+ color, clamps it to 0..1 and maps it to 0..255 integer
157c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochinline uint32_t Clamp255(float x) {
158c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (x < 0.0f) {
159c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    x = 0.0f;
160c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  } else if (x > 1.0f) {
161c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    x = 1.0f;
162c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
163c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return static_cast<uint32_t>(x * 255.0f);
164c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
165c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}  // namespace
166c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
167c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
168c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// The main object that runs the Earth demo.
169c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochclass Planet : public pp::Instance {
170c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch public:
171c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  explicit Planet(PP_Instance instance);
172c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  virtual ~Planet();
173c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
174c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
175c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual void DidChangeView(const pp::View& view);
177c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
178c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Catch events.
179c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  virtual bool HandleInputEvent(const pp::InputEvent& event);
180c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
181c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Catch messages posted from Javascript.
182c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  virtual void HandleMessage(const pp::Var& message);
183c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
184c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch private:
185c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Methods prefixed with 'w' are run on worker threads.
186c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  uint32_t* wGetAddr(int x, int y);
187c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void wRenderPixelSpan(int x0, int x1, int y);
188c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void wMakeRect(int r, int *x, int *y, int *w, int *h);
189c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void wRenderRect(int x0, int y0, int x1, int y1);
190c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void wRenderRegion(int region);
191c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  static void wRenderRegionEntry(int region, void *thiz);
192c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
193c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // These methods are only called by the main thread.
194c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void CacheCalcs();
195c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void SetPlanetXYZR(float x, float y, float z, float r);
196c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void SetPlanetPole(float x, float y, float z);
197c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void SetPlanetEquator(float x, float y, float z);
198c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void SetPlanetSpin(float x, float y);
199c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void SetEyeXYZ(float x, float y, float z);
200c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void SetLightXYZ(float x, float y, float z);
201c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void SetAmbientRGB(float r, float g, float b);
202c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void SetDiffuseRGB(float r, float g, float b);
203c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void SetZoom(float zoom);
204c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void SetLight(float zoom);
205c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void SetTexture(const std::string& name, int width, int height,
206c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      uint32_t* pixels);
207c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
208c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void Reset();
209c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void PostInit(int32_t result);
210c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void UpdateSim();
211c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void Render();
212c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void Draw();
213c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void StartBenchmark();
214c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void EndBenchmark();
215c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
216c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Runs a tick of the simulations, updating all buffers.  Flushes the
217c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // contents of |image_data_| to the 2D graphics context.
218c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void Update();
219c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
220c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Post a small key-value message to update JS.
221c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void PostUpdateMessage(const char* message_name, double value);
222c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Create and initialize the 2D context used for drawing.
223c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void CreateContext(const pp::Size& size);
224c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Destroy the 2D drawing context.
225c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void DestroyContext();
226c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Push the pixels to the browser, then attempt to flush the 2D context.
227c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  void FlushPixelBuffer();
228c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  static void FlushCallback(void* data, int32_t result);
229c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
230c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // User Interface settings.  These settings are controlled via html
231c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // controls or via user input.
232c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float ui_light_;
233c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float ui_zoom_;
234c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float ui_spin_x_;
235c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float ui_spin_y_;
236c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
237c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Various settings for position & orientation of planet.  Do not change
238c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // these variables, instead use SetPlanet*() functions.
239c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_radius_;
240c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_spin_x_;
241c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_spin_y_;
242c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_x_, planet_y_, planet_z_;
243c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_pole_x_, planet_pole_y_, planet_pole_z_;
244c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_equator_x_, planet_equator_y_, planet_equator_z_;
245c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
246c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Observer's eye.  Do not change these variables, instead use SetEyeXYZ().
247c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float eye_x_, eye_y_, eye_z_;
248c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
249c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Light position, ambient and diffuse settings.  Do not change these
250c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // variables, instead use SetLightXYZ(), SetAmbientRGB() and SetDiffuseRGB().
251c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float light_x_, light_y_, light_z_;
252c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float diffuse_r_, diffuse_g_, diffuse_b_;
253c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float ambient_r_, ambient_g_, ambient_b_;
254c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
255c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Cached calculations.  Do not change these variables - they are updated by
256c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // CacheCalcs() function.
257c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_xyz_;
258c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_pole_x_equator_x_;
259c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_pole_x_equator_y_;
260c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_pole_x_equator_z_;
261c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_radius2_;
262c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_one_over_radius_;
263c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float eye_xyz_;
264c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
265c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Source texture (earth map).
266c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  Texture* base_tex_;
267c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  Texture* night_tex_;
268c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int width_for_tex_;
269c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int height_for_tex_;
270c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  std::string name_for_tex_;
271c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
272c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Quick ArcCos helper.
273c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ArcCosine acos_;
274c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
275c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Misc.
276c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  pp::Graphics2D* graphics_2d_context_;
277c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  pp::ImageData* image_data_;
278c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  bool initial_did_change_view_;
279c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int num_threads_;
280c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int num_regions_;
281c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ThreadPool* workers_;
282c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int width_;
283c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int height_;
2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool hidden_;
2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  PP_Point last_mouse_pos_;
286c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  uint32_t stride_in_pixels_;
287c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  uint32_t* pixel_buffer_;
288c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int benchmark_frame_counter_;
289c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  bool benchmarking_;
290c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  double benchmark_start_time_;
291c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  double benchmark_end_time_;
292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  FpsState fps_state_;
293c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch};
294c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
295c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
296c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochbool Planet::Init(uint32_t argc, const char* argn[], const char* argv[]) {
297c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Request PPAPI input events for mouse & keyboard.
298c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
299c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  RequestInputEvents(PP_INPUTEVENT_CLASS_WHEEL);
300c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  RequestInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
301c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Request a set of images from JS.  After images are loaded by JS, a
302c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // message from JS -> NaCl will arrive containing the pixel data.  See
303c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // HandleMessage() method in this file.
304c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  pp::VarDictionary message;
305c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  message.Set("message", "request_textures");
306c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  pp::VarArray names;
307c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  names.Set(0, "earth.jpg");
308c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  names.Set(1, "earthnight.jpg");
309c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  message.Set("names", names);
310c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  PostMessage(message);
311c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return true;
312c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
313c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
314c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::Reset() {
315c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Reset has to first fill in all variables with valid floats, so
316c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // CacheCalcs() doesn't potentially propagate NaNs when calling Set*()
317c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // functions further below.
318c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_radius_ = 1.0f;
319c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_spin_x_ = 0.0f;
320c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_spin_y_ = 0.0f;
321c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_x_ = 0.0f;
322c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_y_ = 0.0f;
323c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_z_ = 0.0f;
324c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_x_ = 0.0f;
325c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_y_ = 0.0f;
326c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_z_ = 0.0f;
327c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_equator_x_ = 0.0f;
328c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_equator_y_ = 0.0f;
329c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_equator_z_ = 0.0f;
330c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  eye_x_ = 0.0f;
331c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  eye_y_ = 0.0f;
332c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  eye_z_ = 0.0f;
333c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  light_x_ = 0.0f;
334c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  light_y_ = 0.0f;
335c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  light_z_ = 0.0f;
336c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  diffuse_r_ = 0.0f;
337c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  diffuse_g_ = 0.0f;
338c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  diffuse_b_ = 0.0f;
339c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ambient_r_ = 0.0f;
340c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ambient_g_ = 0.0f;
341c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ambient_b_ = 0.0f;
342c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_xyz_ = 0.0f;
343c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_x_equator_x_ = 0.0f;
344c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_x_equator_y_ = 0.0f;
345c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_x_equator_z_ = 0.0f;
346c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_radius2_ = 0.0f;
347c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_one_over_radius_ = 0.0f;
348c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  eye_xyz_ = 0.0f;
349c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ui_zoom_ = 14.0f;
350c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ui_light_ = 1.0f;
351c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ui_spin_x_ = 0.01f;
352c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ui_spin_y_ = 0.0f;
353c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
354c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Set up reasonable default values.
355c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetPlanetXYZR(0.0f, 0.0f, 48.0f, 4.0f);
356c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetEyeXYZ(0.0f, 0.0f, -ui_zoom_);
357c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetLightXYZ(-60.0f, -30.0f, 0.0f);
358c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetAmbientRGB(0.05f, 0.05f, 0.05f);
359c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetDiffuseRGB(0.8f, 0.8f, 0.8f);
360c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetPlanetPole(0.0f, 1.0f, 0.0f);
361c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetPlanetEquator(1.0f, 0.0f, 0.0f);
362c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetPlanetSpin(kPI / 2.0f, kPI / 2.0f);
363c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetZoom(ui_zoom_);
364c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetLight(ui_light_);
365c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
366c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Send UI values to JS to reset html sliders.
367c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  PostUpdateMessage("set_zoom", ui_zoom_);
368c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  PostUpdateMessage("set_light", ui_light_);
369c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
370c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
371c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
372c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben MurdochPlanet::Planet(PP_Instance instance) : pp::Instance(instance),
373c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                                       graphics_2d_context_(NULL),
374c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                                       image_data_(NULL),
375c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                                       initial_did_change_view_(true),
376c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                                       num_regions_(256) {
377c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  width_ = 0;
378c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  height_ = 0;
3794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  hidden_ = false;
380c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  stride_in_pixels_ = 0;
381c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  pixel_buffer_ = NULL;
382c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  benchmark_frame_counter_ = 0;
383c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  benchmarking_ = false;
384c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  base_tex_ = NULL;
385c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  night_tex_ = NULL;
386c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  name_for_tex_ = "";
3874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  last_mouse_pos_ = PP_MakePoint(0, 0);
388f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  FpsInit(&fps_state_);
389c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
390c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  Reset();
391c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
392c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // By default, render from the dispatch thread.
393c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  num_threads_ = 0;
394c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  workers_ = new ThreadPool(num_threads_);
395c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
396c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
397c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben MurdochPlanet::~Planet() {
398c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  delete workers_;
399c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  DestroyContext();
400c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
401c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
402c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Given a region r, derive a rectangle.
403c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// This rectangle shouldn't overlap with work being done by other workers.
404c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// If multithreading, this function is only called by the worker threads.
405c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::wMakeRect(int r, int *x, int *y, int *w, int *h) {
406c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int dy = height_ / num_regions_;
407c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  *x = 0;
408c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  *w = width_;
409c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  *y = r * dy;
410c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  *h = dy;
411c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
412c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
413c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
414c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochinline uint32_t* Planet::wGetAddr(int x, int y) {
415c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  assert(pixel_buffer_);
416c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return (pixel_buffer_ + y * stride_in_pixels_) + x;
417c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
418c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
419c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// This is the meat of the ray tracer.  Given a pixel span (x0, x1) on
420c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// scanline y, shoot rays into the scene and render what they hit.  Use
421c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// scanline coherence to do a few optimizations
422c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::wRenderPixelSpan(int x0, int x1, int y) {
423c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (!base_tex_ || !night_tex_)
424c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    return;
425c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  const int kColorBlack = MakeRGBA(0, 0, 0, 0xFF);
426c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float min_dim = width_ < height_ ? width_ : height_;
427c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float offset_x = width_ < height_ ? 0 : (width_ - min_dim) * 0.5f;
428c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float offset_y = width_ < height_ ? (height_ - min_dim) * 0.5f : 0;
429c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float y0 = eye_y_;
430c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float z0 = eye_z_;
431c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float y1 = (static_cast<float>(y - offset_y) / min_dim) * 2.0f - 1.0f;
432c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float z1 = 0.0f;
433c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float dy = (y1 - y0);
434c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float dz = (z1 - z0);
435c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float dy_dy_dz_dz = dy * dy + dz * dz;
436c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float two_dy_y0_y_two_dz_z0_z = 2.0f * dy * (y0 - planet_y_) +
437c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                                  2.0f * dz * (z0 - planet_z_);
438c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float planet_xyz_eye_xyz = planet_xyz_ + eye_xyz_;
439c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float y_y0_z_z0 = planet_y_ * y0 + planet_z_ * z0;
440c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float oowidth = 1.0f / min_dim;
441c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  uint32_t* pixels = this->wGetAddr(x0, y);
442c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  for (int x = x0; x <= x1; ++x) {
443c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // scan normalized screen -1..1
444c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float x1 = (static_cast<float>(x - offset_x) * oowidth) * 2.0f - 1.0f;
445c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // eye
446c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float x0 = eye_x_;
447c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // delta from screen to eye
448c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float dx = (x1 - x0);
449c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // build a, b, c
450c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float a = dx * dx + dy_dy_dz_dz;
451c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float b = 2.0f * dx * (x0 - planet_x_) + two_dy_y0_y_two_dz_z0_z;
452c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float c = planet_xyz_eye_xyz +
453c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch              -2.0f * (planet_x_ * x0 + y_y0_z_z0) - (planet_radius2_);
454c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // calculate discriminant
455c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float disc = b * b - 4.0f * a * c;
456c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
457c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // Did ray hit the sphere?
458c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (disc < 0.0f) {
459c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      *pixels = kColorBlack;
460c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      ++pixels;
461c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      continue;
462c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    }
463c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
464c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // calc parametric t value
465c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float t = (-b - inline_sqrt(disc)) / (2.0f * a);
466c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float px = x0 + t * dx;
467c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float py = y0 + t * dy;
468c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float pz = z0 + t * dz;
469c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float nx = (px - planet_x_) * planet_one_over_radius_;
470c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float ny = (py - planet_y_) * planet_one_over_radius_;
471c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float nz = (pz - planet_z_) * planet_one_over_radius_;
472c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
473c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // Misc raytrace calculations.
474c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float Lx = (light_x_ - px);
475c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float Ly = (light_y_ - py);
476c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float Lz = (light_z_ - pz);
477c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float Lq = 1.0f / inline_quick_sqrt(Lx * Lx + Ly * Ly + Lz * Lz);
478c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    Lx *= Lq;
479c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    Ly *= Lq;
480c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    Lz *= Lq;
481c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float d = (Lx * nx + Ly * ny + Lz * nz);
482c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float pr = (diffuse_r_ * d) + ambient_r_;
483c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float pg = (diffuse_g_ * d) + ambient_g_;
484c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float pb = (diffuse_b_ * d) + ambient_b_;
485c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float ds = -(nx * planet_pole_x_ +
486c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                 ny * planet_pole_y_ +
487c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                 nz * planet_pole_z_);
488c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float ang = acos_.TableLerp(ds);
489c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float v = ang * kOneOverPI;
490c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float dp = planet_equator_x_ * nx +
491c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch               planet_equator_y_ * ny +
492c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch               planet_equator_z_ * nz;
493c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float w = dp / sin(ang);
494c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (w > 1.0f) w = 1.0f;
495c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (w < -1.0f) w = -1.0f;
496c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float th = acos_.TableLerp(w) * kOneOver2PI;
497c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float dps = planet_pole_x_equator_x_ * nx +
498c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                planet_pole_x_equator_y_ * ny +
499c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                planet_pole_x_equator_z_ * nz;
500c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float u;
501c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (dps < 0.0f)
502c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      u = th;
503c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    else
504c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      u = 1.0f - th;
505c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
506c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // Look up daylight texel.
507c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    int tx = static_cast<int>(u * base_tex_->width);
508c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    int ty = static_cast<int>(v * base_tex_->height);
509c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    int offset = tx + ty * base_tex_->width;
510c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    uint32_t base_texel = base_tex_->pixels[offset];
511c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float tr = ExtractR(base_texel);
512c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float tg = ExtractG(base_texel);
513c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float tb = ExtractB(base_texel);
514c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
515c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float ipr = 1.0f - pr;
516c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (ipr < 0.0f) ipr = 0.0f;
517c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float ipg = 1.0f - pg;
518c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (ipg < 0.0f) ipg = 0.0f;
519c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float ipb = 1.0f - pb;
520c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (ipb < 0.0f) ipb = 0.0f;
521c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
522c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // Look up night texel.
523c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    int nix = static_cast<int>(u * night_tex_->width);
524c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    int niy = static_cast<int>(v * night_tex_->height);
525c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    int noffset = nix + niy * night_tex_->width;
526c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    uint32_t night_texel = night_tex_->pixels[noffset];
527c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float nr = ExtractR(night_texel);
528c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float ng = ExtractG(night_texel);
529c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    float nb = ExtractB(night_texel);
530c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
531c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // Final color value is lerp between day and night texels.
532c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    unsigned int ir = Clamp255(pr * tr + nr * ipr);
533c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    unsigned int ig = Clamp255(pg * tg + ng * ipg);
534c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    unsigned int ib = Clamp255(pb * tb + nb * ipb);
535c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
536c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    unsigned int color = MakeRGBA(ir, ig, ib, 0xFF);
537c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
538c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    *pixels = color;
539c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    ++pixels;
540c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
541c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
542c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
543c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Renders a rectangular area of the screen, scan line at a time
544c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::wRenderRect(int x, int y, int w, int h) {
545c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  for (int j = y; j < (y + h); ++j) {
546c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    this->wRenderPixelSpan(x, x + w - 1, j);
547c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
548c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
549c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
550c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// If multithreading, this function is only called by the worker threads.
551c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::wRenderRegion(int region) {
552c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // convert region # into x0, y0, x1, y1 rectangle
553c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  int x, y, w, h;
554c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  wMakeRect(region, &x, &y, &w, &h);
555c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // render this rectangle
556c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  wRenderRect(x, y, w, h);
557c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
558c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
559c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Entry point for worker thread.  Can't pass a member function around, so we
560c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// have to do this little round-about.
561c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::wRenderRegionEntry(int region, void* thiz) {
562c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  static_cast<Planet*>(thiz)->wRenderRegion(region);
563c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
564c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
565c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Renders the planet, dispatching the work to multiple threads.
566c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Note: This Dispatch() is from the main PPAPI thread, so care must be taken
567c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// not to attempt PPAPI calls from the worker threads, since Dispatch() will
568c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// block here until all work is complete.  The worker threads are compute only
569c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// and do not make any PPAPI calls.
570c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::Render() {
571c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  workers_->Dispatch(num_regions_, wRenderRegionEntry, this);
572c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
573c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
574c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Pre-calculations to make inner loops faster.
575c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::CacheCalcs() {
576c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_xyz_ = planet_x_ * planet_x_ +
577c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                planet_y_ * planet_y_ +
578c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                planet_z_ * planet_z_;
579c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_radius2_ = planet_radius_ * planet_radius_;
580c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_one_over_radius_ = 1.0f / planet_radius_;
581c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  eye_xyz_ = eye_x_ * eye_x_ + eye_y_ * eye_y_ + eye_z_ * eye_z_;
582c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // spin vector from center->equator
583c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_equator_x_ = cos(planet_spin_x_);
584c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_equator_y_ = 0.0f;
585c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_equator_z_ = sin(planet_spin_x_);
586c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
587c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // cache cross product of pole & equator
588c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_x_equator_x_ = planet_pole_y_ * planet_equator_z_ -
589c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                             planet_pole_z_ * planet_equator_y_;
590c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_x_equator_y_ = planet_pole_z_ * planet_equator_x_ -
591c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                             planet_pole_x_ * planet_equator_z_;
592c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_x_equator_z_ = planet_pole_x_ * planet_equator_y_ -
593c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                             planet_pole_y_ * planet_equator_x_;
594c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
595c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
596c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::SetPlanetXYZR(float x, float y, float z, float r) {
597c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_x_ = x;
598c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_y_ = y;
599c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_z_ = z;
600c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_radius_ = r;
601c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  CacheCalcs();
602c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
603c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
604c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::SetEyeXYZ(float x, float y, float z) {
605c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  eye_x_ = x;
606c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  eye_y_ = y;
607c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  eye_z_ = z;
608c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  CacheCalcs();
609c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
610c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
611c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::SetLightXYZ(float x, float y, float z) {
612c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  light_x_ = x;
613c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  light_y_ = y;
614c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  light_z_ = z;
615c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  CacheCalcs();
616c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
617c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
618c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::SetAmbientRGB(float r, float g, float b) {
619c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ambient_r_ = r;
620c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ambient_g_ = g;
621c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ambient_b_ = b;
622c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  CacheCalcs();
623c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
624c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
625c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::SetDiffuseRGB(float r, float g, float b) {
626c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  diffuse_r_ = r;
627c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  diffuse_g_ = g;
628c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  diffuse_b_ = b;
629c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  CacheCalcs();
630c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
631c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
632c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::SetPlanetPole(float x, float y, float z) {
633c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_x_ = x;
634c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_y_ = y;
635c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_pole_z_ = z;
636c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  CacheCalcs();
637c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
638c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
639c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::SetPlanetEquator(float x, float y, float z) {
640c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // This is really over-ridden by spin at the momenent.
641c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_equator_x_ = x;
642c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_equator_y_ = y;
643c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_equator_z_ = z;
644c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  CacheCalcs();
645c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
646c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
647c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::SetPlanetSpin(float x, float y) {
648c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_spin_x_ = x;
649c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  planet_spin_y_ = y;
650c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  CacheCalcs();
651c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
652c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
653c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Run a simple sim to spin the planet.  Update loop is run once per frame.
654c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Called from the main thread only and only when the worker threads are idle.
655c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::UpdateSim() {
656c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float x = planet_spin_x_ + ui_spin_x_;
657c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  float y = planet_spin_y_ + ui_spin_y_;
658c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // keep in nice range
659c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (x > (kPI * 2.0f))
660c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    x = x - kPI * 2.0f;
661c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  else if (x < (-kPI * 2.0f))
662c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    x = x + kPI * 2.0f;
663c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (y > (kPI * 2.0f))
664c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    y = y - kPI * 2.0f;
665c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  else if (y < (-kPI * 2.0f))
666c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    y = y + kPI * 2.0f;
667c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetPlanetSpin(x, y);
668c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
669c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
6704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void Planet::DidChangeView(const pp::View& view) {
6714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  pp::Rect position = view.GetRect();
6724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Update hidden_ state
6734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  hidden_ = !view.IsVisible();
674c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (position.size().width() == width_ &&
675c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      position.size().height() == height_)
676c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    return;  // Size didn't change, no need to update anything.
677c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Create a new device context with the new size.
678c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  DestroyContext();
679c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  CreateContext(position.size());
680c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
681c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (initial_did_change_view_) {
682c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    initial_did_change_view_ = false;
683c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    Update();
684c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
685c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
686c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
687c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::StartBenchmark() {
688c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // For more consistent benchmark numbers, reset to default state.
689c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  Reset();
690a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  logf("Benchmark started...\n");
691c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  benchmark_frame_counter_ = kFramesToBenchmark;
692c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  benchmarking_ = true;
693c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  benchmark_start_time_ = getseconds();
694c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
695c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
696c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::EndBenchmark() {
697c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  benchmark_end_time_ = getseconds();
698a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  logf("Benchmark ended... time: %2.5f\n",
699c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      benchmark_end_time_ - benchmark_start_time_);
700c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  benchmarking_ = false;
701c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  benchmark_frame_counter_ = 0;
702c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  double total_time = benchmark_end_time_ - benchmark_start_time_;
703c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Send benchmark result to JS.
704c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  PostUpdateMessage("benchmark_result", total_time);
705c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
706c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
707c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::SetZoom(float zoom) {
708c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ui_zoom_ = std::min(kZoomMax, std::max(kZoomMin, zoom));
709c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetEyeXYZ(0.0f, 0.0f, -ui_zoom_);
710c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
711c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
712c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::SetLight(float light) {
713c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  ui_light_ = std::min(kLightMax, std::max(kLightMin, light));
714c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetDiffuseRGB(0.8f * ui_light_, 0.8f * ui_light_, 0.8f * ui_light_);
715c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  SetAmbientRGB(0.4f * ui_light_, 0.4f * ui_light_, 0.4f * ui_light_);
716c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
717c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
718c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::SetTexture(const std::string& name, int width, int height,
719c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                        uint32_t* pixels) {
720c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (pixels) {
721c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (name == "earth.jpg") {
722c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      delete base_tex_;
723c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      base_tex_ = new Texture(width, height, pixels);
724c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    } else if (name == "earthnight.jpg") {
725c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      delete night_tex_;
726c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      night_tex_ = new Texture(width, height, pixels);
727c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    }
728c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
729c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
730c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
731c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Handle input events from the user.
732c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochbool Planet::HandleInputEvent(const pp::InputEvent& event) {
733c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  switch (event.GetType()) {
734c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    case PP_INPUTEVENT_TYPE_KEYDOWN: {
735c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      pp::KeyboardInputEvent key(event);
736c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      uint32_t key_code = key.GetKeyCode();
737c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      if (key_code == 84)  // 't' key
738c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        if (!benchmarking_)
739c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch          StartBenchmark();
740c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      break;
741c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    }
742c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
743c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      pp::MouseInputEvent mouse = pp::MouseInputEvent(event);
7444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      last_mouse_pos_ = mouse.GetPosition();
7454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ui_spin_x_ = 0.0f;
7464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ui_spin_y_ = 0.0f;
7474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break;
7484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
7494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
7504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      pp::MouseInputEvent mouse = pp::MouseInputEvent(event);
751c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      if (mouse.GetModifiers() & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) {
7524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        PP_Point mouse_pos = mouse.GetPosition();
7534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        float delta_x = static_cast<float>(mouse_pos.x - last_mouse_pos_.x);
7544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        float delta_y = static_cast<float>(mouse_pos.y - last_mouse_pos_.y);
7554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        float spin_x = std::min(10.0f, std::max(-10.0f, delta_x * 0.5f));
7564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        float spin_y = std::min(10.0f, std::max(-10.0f, delta_y * 0.5f));
757c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        ui_spin_x_ = spin_x / 100.0f;
758c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        ui_spin_y_ = spin_y / 100.0f;
7594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        last_mouse_pos_ = mouse_pos;
760c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      }
761c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      break;
762c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    }
763c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    case PP_INPUTEVENT_TYPE_WHEEL: {
764c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      pp::WheelInputEvent wheel = pp::WheelInputEvent(event);
765c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      PP_FloatPoint ticks = wheel.GetTicks();
766c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      SetZoom(ui_zoom_ + (ticks.x + ticks.y) * kWheelSpeed);
767c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      // Update html slider by sending update message to JS.
768c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      PostUpdateMessage("set_zoom", ui_zoom_);
769c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      break;
770c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    }
771c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    default:
772c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      return false;
773c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
774c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return true;
775c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
776c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
777c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// PostUpdateMessage() helper function for sending small messages to JS.
778c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::PostUpdateMessage(const char* message_name, double value) {
779c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  pp::VarDictionary message;
780c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  message.Set("message", message_name);
781c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  message.Set("value", value);
782c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  PostMessage(message);
783c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
784c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
785c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Handle message sent from Javascript.
786c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::HandleMessage(const pp::Var& var) {
787c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (var.is_dictionary()) {
788c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    pp::VarDictionary dictionary(var);
789c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    std::string message = dictionary.Get("message").AsString();
790c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (message == "run benchmark" && !benchmarking_) {
791c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      StartBenchmark();
792c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    } else if (message == "set_light") {
793c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      SetLight(static_cast<float>(dictionary.Get("value").AsDouble()));
794c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    } else if (message == "set_zoom") {
795c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      SetZoom(static_cast<float>(dictionary.Get("value").AsDouble()));
796c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    } else if (message == "set_threads") {
797c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      int threads = dictionary.Get("value").AsInt();
798c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      delete workers_;
799c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      workers_ = new ThreadPool(threads);
800c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    } else if (message == "texture") {
801c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      std::string name = dictionary.Get("name").AsString();
802c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      int width = dictionary.Get("width").AsInt();
803c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      int height = dictionary.Get("height").AsInt();
804c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      pp::VarArrayBuffer array_buffer(dictionary.Get("data"));
805c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      if (!name.empty() && width > 0 && height > 0 && !array_buffer.is_null()) {
806c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        uint32_t* pixels = static_cast<uint32_t*>(array_buffer.Map());
807c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        SetTexture(name, width, height, pixels);
808c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        array_buffer.Unmap();
809c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      }
810c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    }
811c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  } else {
812a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    logf("Handle message unknown type: %s\n", var.DebugString().c_str());
813c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
814c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
815c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
816c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::FlushCallback(void* thiz, int32_t result) {
817c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  static_cast<Planet*>(thiz)->Update();
818c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
819c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
820c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch// Update the 2d region and flush to make it visible on the page.
821c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::FlushPixelBuffer() {
822c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  graphics_2d_context_->PaintImageData(*image_data_, pp::Point(0, 0));
823c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this));
824c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
825c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
826c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::Update() {
8274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If view is hidden, don't render, but periodically (every 33ms) chain w/
8284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // CallOnMainThread().
8294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (hidden_) {
8304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    pp::Module::Get()->core()->CallOnMainThread(33,
8314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        pp::CompletionCallback(&FlushCallback, this));
8324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
8334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
834c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Don't call FlushPixelBuffer() when benchmarking - vsync is enabled by
835c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // default, and will throttle the benchmark results.
836c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  do {
837c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    UpdateSim();
838c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    Render();
839c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if (!benchmarking_) break;
840c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    --benchmark_frame_counter_;
841c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  } while (benchmark_frame_counter_ > 0);
842c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (benchmarking_)
843c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    EndBenchmark();
844c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
845c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  FlushPixelBuffer();
846f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
847f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  double fps;
848f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (FpsStep(&fps_state_, &fps))
849f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    PostUpdateMessage("fps", fps);
850c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
851c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
852c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::CreateContext(const pp::Size& size) {
853c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  graphics_2d_context_ = new pp::Graphics2D(this, size, false);
854c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (graphics_2d_context_->is_null())
855a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    logf("Failed to create a 2D resource!\n");
856c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (!BindGraphics(*graphics_2d_context_))
857a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    logf("Couldn't bind the device context\n");
858c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  image_data_ = new pp::ImageData(this,
859c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                                  PP_IMAGEDATAFORMAT_BGRA_PREMUL,
860c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                                  size,
861c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch                                  false);
862c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  width_ = image_data_->size().width();
863c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  height_ = image_data_->size().height();
864c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  stride_in_pixels_ = static_cast<uint32_t>(image_data_->stride() / 4);
865c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  pixel_buffer_ = static_cast<uint32_t*>(image_data_->data());
866c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  num_regions_ = height_;
867c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
868c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
869c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochvoid Planet::DestroyContext() {
870c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  delete graphics_2d_context_;
871c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  delete image_data_;
872c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  graphics_2d_context_ = NULL;
873c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  image_data_ = NULL;
874c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  width_ = 0;
875c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  height_ = 0;
876c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  stride_in_pixels_ = 0;
877c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  pixel_buffer_ = NULL;
878c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
879c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
880c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochclass PlanetModule : public pp::Module {
881c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch public:
882c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  PlanetModule() : pp::Module() {}
883c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  virtual ~PlanetModule() {}
884c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
885c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Create and return a Planet instance.
886c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  virtual pp::Instance* CreateInstance(PP_Instance instance) {
887c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    return new Planet(instance);
888c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
889c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch};
890c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
891c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdochnamespace pp {
892c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben MurdochModule* CreateModule() {
893c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  return new PlanetModule();
894c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}
895c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch}  // namespace pp
896c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
897