earth.cc revision 3240926e260ce088908e02ac07a6cf7b0c0cbf44
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 kHugeZ = 1.0e38f; 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kPI = M_PI; 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kTwoPI = kPI * 2.0f; 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kOneOverPI = 1.0f / kPI; 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kOneOver2PI = 1.0f / kTwoPI; 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kOneOver255 = 1.0f / 255.0f; 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kArcCosineTableSize = 4096; 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kFramesToBenchmark = 100; 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kZoomMin = 1.0f; 44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kZoomMax = 50.0f; 45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kWheelSpeed = 2.0f; 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kLightMin = 0.0f; 47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kLightMax = 2.0f; 48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int kFrameTimeBufferSize = 512; 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Timer helper for benchmarking. Returns seconds elapsed since program start, 51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// as a double. 52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochtimeval start_tv; 53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint start_tv_retv = gettimeofday(&start_tv, NULL); 54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline double getseconds() { 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double usec_to_sec = 0.000001; 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch timeval tv; 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if ((0 == start_tv_retv) && (0 == gettimeofday(&tv, NULL))) 59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return (tv.tv_sec - start_tv.tv_sec) + tv.tv_usec * usec_to_sec; 60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return 0.0; 61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// RGBA helper functions. 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline float ExtractR(uint32_t c) { 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return static_cast<float>(c & 0xFF) * kOneOver255; 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline float ExtractG(uint32_t c) { 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return static_cast<float>((c & 0xFF00) >> 8) * kOneOver255; 70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline float ExtractB(uint32_t c) { 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return static_cast<float>((c & 0xFF0000) >> 16) * kOneOver255; 74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) { 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)); 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// simple container for earth texture 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct Texture { 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int width, height; 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32_t* pixels; 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Texture(int w, int h) : width(w), height(h) { 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pixels = new uint32_t[w * h]; 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch memset(pixels, 0, sizeof(uint32_t) * w * h); 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch explicit Texture(int w, int h, uint32_t* p) : width(w), height(h) { 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pixels = new uint32_t[w * h]; 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch memcpy(pixels, p, sizeof(uint32_t) * w * h); 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ~Texture() { delete[] pixels; } 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DISALLOW_COPY_AND_ASSIGN(Texture); 95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct ArcCosine { 100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // slightly larger table so we can interpolate beyond table size 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float table[kArcCosineTableSize + 2]; 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float TableLerp(float x); 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ArcCosine(); 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochArcCosine::ArcCosine() { 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // build a slightly larger table to allow for numeric imprecision 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (int i = 0; i < (kArcCosineTableSize + 2); ++i) { 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float f = static_cast<float>(i) / kArcCosineTableSize; 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch f = f * 2.0f - 1.0f; 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch table[i] = acos(f); 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// looks up acos(f) using a table and lerping between entries 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// (it is expected that input f is between -1 and 1) 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochfloat ArcCosine::TableLerp(float f) { 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float x = (f + 1.0f) * 0.5f; 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch x = x * kArcCosineTableSize; 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int ix = static_cast<int>(x); 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float fx = static_cast<float>(ix); 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float dx = x - fx; 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float af = table[ix]; 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float af2 = table[ix + 1]; 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return af + (af2 - af) * dx; 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Helper functions for quick but approximate sqrt. 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochunion Convert { 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float f; 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int i; 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Convert(int x) { i = x; } 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Convert(float x) { f = x; } 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int AsInt() { return i; } 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float AsFloat() { return f; } 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline const int AsInteger(const float f) { 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Convert u(f); 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return u.AsInt(); 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline const float AsFloat(const int i) { 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Convert u(i); 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return u.AsFloat(); 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst long int kOneAsInteger = AsInteger(1.0f); 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kScaleUp = float(0x00800000); 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst float kScaleDown = 1.0f / kScaleUp; 151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline float inline_quick_sqrt(float x) { 153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int i; 154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch i = (AsInteger(x) >> 1) + (kOneAsInteger >> 1); 155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return AsFloat(i); 156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline float inline_sqrt(float x) { 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float y; 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch y = inline_quick_sqrt(x); 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch y = (y * y + x) / (2.0f * y); 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch y = (y * y + x) / (2.0f * y); 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return y; 164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// takes a -0..1+ color, clamps it to 0..1 and maps it to 0..255 integer 167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochinline uint32_t Clamp255(float x) { 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (x < 0.0f) { 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch x = 0.0f; 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else if (x > 1.0f) { 171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch x = 1.0f; 172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return static_cast<uint32_t>(x * 255.0f); 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// The main object that runs the Earth demo. 1793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochclass Planet { 180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public: 1813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch Planet(); 182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual ~Planet(); 1833240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Runs a tick of the simulations, update 2D output. 1843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch void Update(); 1853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Handle event from user, or message from JS. 1863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch void HandleEvent(PSEvent* ps_event); 187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private: 189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Methods prefixed with 'w' are run on worker threads. 190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32_t* wGetAddr(int x, int y); 191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void wRenderPixelSpan(int x0, int x1, int y); 192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void wMakeRect(int r, int *x, int *y, int *w, int *h); 193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void wRenderRect(int x0, int y0, int x1, int y1); 194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void wRenderRegion(int region); 195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch static void wRenderRegionEntry(int region, void *thiz); 196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // These methods are only called by the main thread. 198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void CacheCalcs(); 199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SetPlanetXYZR(float x, float y, float z, float r); 200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SetPlanetPole(float x, float y, float z); 201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SetPlanetEquator(float x, float y, float z); 202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SetPlanetSpin(float x, float y); 203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SetEyeXYZ(float x, float y, float z); 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SetLightXYZ(float x, float y, float z); 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SetAmbientRGB(float r, float g, float b); 206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SetDiffuseRGB(float r, float g, float b); 207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SetZoom(float zoom); 208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SetLight(float zoom); 209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void SetTexture(const std::string& name, int width, int height, 210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32_t* pixels); 211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void Reset(); 2133240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch void RequestTextures(); 214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void UpdateSim(); 215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void Render(); 216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void Draw(); 217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void StartBenchmark(); 218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void EndBenchmark(); 219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Post a small key-value message to update JS. 220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void PostUpdateMessage(const char* message_name, double value); 221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // User Interface settings. These settings are controlled via html 223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // controls or via user input. 224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ui_light_; 225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ui_zoom_; 226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ui_spin_x_; 227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ui_spin_y_; 228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Various settings for position & orientation of planet. Do not change 230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // these variables, instead use SetPlanet*() functions. 231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_radius_; 232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_spin_x_; 233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_spin_y_; 234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_x_, planet_y_, planet_z_; 235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_pole_x_, planet_pole_y_, planet_pole_z_; 236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_equator_x_, planet_equator_y_, planet_equator_z_; 237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Observer's eye. Do not change these variables, instead use SetEyeXYZ(). 239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float eye_x_, eye_y_, eye_z_; 240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Light position, ambient and diffuse settings. Do not change these 242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // variables, instead use SetLightXYZ(), SetAmbientRGB() and SetDiffuseRGB(). 243eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float light_x_, light_y_, light_z_; 244eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float diffuse_r_, diffuse_g_, diffuse_b_; 245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ambient_r_, ambient_g_, ambient_b_; 246eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 247eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Cached calculations. Do not change these variables - they are updated by 248eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // CacheCalcs() function. 249eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_xyz_; 250eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_pole_x_equator_x_; 251eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_pole_x_equator_y_; 252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_pole_x_equator_z_; 253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_radius2_; 254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_one_over_radius_; 255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float eye_xyz_; 256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Source texture (earth map). 258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Texture* base_tex_; 259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Texture* night_tex_; 260eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int width_for_tex_; 261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int height_for_tex_; 262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Quick ArcCos helper. 264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ArcCosine acos_; 265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Misc. 2673240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSContext2D_t* ps_context_; 268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int num_threads_; 269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ThreadPool* workers_; 270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool benchmarking_; 2713240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int benchmark_frame_counter_; 272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch double benchmark_start_time_; 273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch double benchmark_end_time_; 274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid Planet::RequestTextures() { 278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Request a set of images from JS. After images are loaded by JS, a 279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // message from JS -> NaCl will arrive containing the pixel data. See 280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // HandleMessage() method in this file. 281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pp::VarDictionary message; 282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch message.Set("message", "request_textures"); 283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pp::VarArray names; 284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch names.Set(0, "earth.jpg"); 285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch names.Set(1, "earthnight.jpg"); 286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch message.Set("names", names); 2873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var()); 288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::Reset() { 291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Reset has to first fill in all variables with valid floats, so 292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // CacheCalcs() doesn't potentially propagate NaNs when calling Set*() 293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // functions further below. 294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_radius_ = 1.0f; 295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_spin_x_ = 0.0f; 296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_spin_y_ = 0.0f; 297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_x_ = 0.0f; 298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_y_ = 0.0f; 299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_z_ = 0.0f; 300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_x_ = 0.0f; 301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_y_ = 0.0f; 302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_z_ = 0.0f; 303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_equator_x_ = 0.0f; 304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_equator_y_ = 0.0f; 305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_equator_z_ = 0.0f; 306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch eye_x_ = 0.0f; 307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch eye_y_ = 0.0f; 308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch eye_z_ = 0.0f; 309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch light_x_ = 0.0f; 310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch light_y_ = 0.0f; 311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch light_z_ = 0.0f; 312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch diffuse_r_ = 0.0f; 313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch diffuse_g_ = 0.0f; 314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch diffuse_b_ = 0.0f; 315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ambient_r_ = 0.0f; 316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ambient_g_ = 0.0f; 317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ambient_b_ = 0.0f; 318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_xyz_ = 0.0f; 319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_x_equator_x_ = 0.0f; 320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_x_equator_y_ = 0.0f; 321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_x_equator_z_ = 0.0f; 322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_radius2_ = 0.0f; 323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_one_over_radius_ = 0.0f; 324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch eye_xyz_ = 0.0f; 325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ui_zoom_ = 14.0f; 326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ui_light_ = 1.0f; 327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ui_spin_x_ = 0.01f; 328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ui_spin_y_ = 0.0f; 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); 3563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ps_context_ = PSContext2DAllocate(); 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; 385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const int kColorBlack = MakeRGBA(0, 0, 0, 0xFF); 386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float y0 = eye_y_; 387eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float z0 = eye_z_; 3883240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch float y1 = (static_cast<float>(y) / ps_context_->height) * 2.0f - 1.0f; 389eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float z1 = 0.0f; 390eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float dy = (y1 - y0); 391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float dz = (z1 - z0); 392eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float dy_dy_dz_dz = dy * dy + dz * dz; 393eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float two_dy_y0_y_two_dz_z0_z = 2.0f * dy * (y0 - planet_y_) + 394eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2.0f * dz * (z0 - planet_z_); 395eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float planet_xyz_eye_xyz = planet_xyz_ + eye_xyz_; 396eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float y_y0_z_z0 = planet_y_ * y0 + planet_z_ * z0; 3973240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch float oowidth = 1.0f / ps_context_->width; 398eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32_t* pixels = this->wGetAddr(x0, y); 399eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (int x = x0; x <= x1; ++x) { 400eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // scan normalized screen -1..1 401eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float x1 = (static_cast<float>(x) * oowidth) * 2.0f - 1.0f; 402eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // eye 403eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float x0 = eye_x_; 404eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // delta from screen to eye 405eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float dx = (x1 - x0); 406eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // build a, b, c 407eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float a = dx * dx + dy_dy_dz_dz; 408eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float b = 2.0f * dx * (x0 - planet_x_) + two_dy_y0_y_two_dz_z0_z; 409eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float c = planet_xyz_eye_xyz + 410eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch -2.0f * (planet_x_ * x0 + y_y0_z_z0) - (planet_radius2_); 411eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // calculate discriminant 412eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float disc = b * b - 4.0f * a * c; 413eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 414eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Did ray hit the sphere? 415eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (disc < 0.0f) { 416eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *pixels = kColorBlack; 417eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ++pixels; 418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch continue; 419eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 420eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 421eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // calc parametric t value 422eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float t = (-b - inline_sqrt(disc)) / (2.0f * a); 423eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float px = x0 + t * dx; 424eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float py = y0 + t * dy; 425eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float pz = z0 + t * dz; 426eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float nx = (px - planet_x_) * planet_one_over_radius_; 427eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ny = (py - planet_y_) * planet_one_over_radius_; 428eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float nz = (pz - planet_z_) * planet_one_over_radius_; 429eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 430eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Misc raytrace calculations. 431eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float Lx = (light_x_ - px); 432eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float Ly = (light_y_ - py); 433eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float Lz = (light_z_ - pz); 434eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float Lq = 1.0f / inline_quick_sqrt(Lx * Lx + Ly * Ly + Lz * Lz); 435eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Lx *= Lq; 436eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Ly *= Lq; 437eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Lz *= Lq; 438eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float d = (Lx * nx + Ly * ny + Lz * nz); 439eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float pr = (diffuse_r_ * d) + ambient_r_; 440eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float pg = (diffuse_g_ * d) + ambient_g_; 441eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float pb = (diffuse_b_ * d) + ambient_b_; 442eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ds = -(nx * planet_pole_x_ + 443eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ny * planet_pole_y_ + 444eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch nz * planet_pole_z_); 445eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ang = acos_.TableLerp(ds); 446eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float v = ang * kOneOverPI; 447eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float dp = planet_equator_x_ * nx + 448eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_equator_y_ * ny + 449eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_equator_z_ * nz; 450eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float w = dp / sin(ang); 451eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (w > 1.0f) w = 1.0f; 452eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (w < -1.0f) w = -1.0f; 453eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float th = acos_.TableLerp(w) * kOneOver2PI; 454eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float dps = planet_pole_x_equator_x_ * nx + 455eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_x_equator_y_ * ny + 456eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_x_equator_z_ * nz; 457eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float u; 458eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (dps < 0.0f) 459eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch u = th; 460eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch else 461eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch u = 1.0f - th; 462eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 463eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Look up daylight texel. 464eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int tx = static_cast<int>(u * base_tex_->width); 465eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int ty = static_cast<int>(v * base_tex_->height); 466eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int offset = tx + ty * base_tex_->width; 467eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32_t base_texel = base_tex_->pixels[offset]; 468eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float tr = ExtractR(base_texel); 469eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float tg = ExtractG(base_texel); 470eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float tb = ExtractB(base_texel); 471eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 472eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ipr = 1.0f - pr; 473eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (ipr < 0.0f) ipr = 0.0f; 474eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ipg = 1.0f - pg; 475eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (ipg < 0.0f) ipg = 0.0f; 476eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ipb = 1.0f - pb; 477eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (ipb < 0.0f) ipb = 0.0f; 478eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 479eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Look up night texel. 480eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int nix = static_cast<int>(u * night_tex_->width); 481eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int niy = static_cast<int>(v * night_tex_->height); 482eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int noffset = nix + niy * night_tex_->width; 483eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32_t night_texel = night_tex_->pixels[noffset]; 484eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float nr = ExtractR(night_texel); 485eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float ng = ExtractG(night_texel); 486eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float nb = ExtractB(night_texel); 487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Final color value is lerp between day and night texels. 489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned int ir = Clamp255(pr * tr + nr * ipr); 490eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned int ig = Clamp255(pg * tg + ng * ipg); 491eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned int ib = Clamp255(pb * tb + nb * ipb); 492eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned int color = MakeRGBA(ir, ig, ib, 0xFF); 494eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *pixels = color; 496eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ++pixels; 497eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 498eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 499eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 500eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Renders a rectangular area of the screen, scan line at a time 501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::wRenderRect(int x, int y, int w, int h) { 502eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (int j = y; j < (y + h); ++j) { 503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch this->wRenderPixelSpan(x, x + w - 1, j); 504eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 505eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 506eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 507eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// If multithreading, this function is only called by the worker threads. 508eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::wRenderRegion(int region) { 509eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // convert region # into x0, y0, x1, y1 rectangle 510eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int x, y, w, h; 511eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch wMakeRect(region, &x, &y, &w, &h); 512eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // render this rectangle 513eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch wRenderRect(x, y, w, h); 514eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 515eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 516eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Entry point for worker thread. Can't pass a member function around, so we 517eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// have to do this little round-about. 518eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::wRenderRegionEntry(int region, void* thiz) { 519eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch static_cast<Planet*>(thiz)->wRenderRegion(region); 520eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 521eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 522eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Renders the planet, dispatching the work to multiple threads. 523eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::Render() { 5243240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch workers_->Dispatch(ps_context_->height, wRenderRegionEntry, this); 525eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 526eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 527eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Pre-calculations to make inner loops faster. 528eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::CacheCalcs() { 529eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_xyz_ = planet_x_ * planet_x_ + 530eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_y_ * planet_y_ + 531eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_z_ * planet_z_; 532eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_radius2_ = planet_radius_ * planet_radius_; 533eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_one_over_radius_ = 1.0f / planet_radius_; 534eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch eye_xyz_ = eye_x_ * eye_x_ + eye_y_ * eye_y_ + eye_z_ * eye_z_; 535eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // spin vector from center->equator 536eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_equator_x_ = cos(planet_spin_x_); 537eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_equator_y_ = 0.0f; 538eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_equator_z_ = sin(planet_spin_x_); 539eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 540eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // cache cross product of pole & equator 541eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_x_equator_x_ = planet_pole_y_ * planet_equator_z_ - 542eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_z_ * planet_equator_y_; 543eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_x_equator_y_ = planet_pole_z_ * planet_equator_x_ - 544eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_x_ * planet_equator_z_; 545eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_x_equator_z_ = planet_pole_x_ * planet_equator_y_ - 546eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_y_ * planet_equator_x_; 547eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 548eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 549eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetPlanetXYZR(float x, float y, float z, float r) { 550eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_x_ = x; 551eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_y_ = y; 552eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_z_ = z; 553eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_radius_ = r; 554eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CacheCalcs(); 555eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 556eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 557eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetEyeXYZ(float x, float y, float z) { 558eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch eye_x_ = x; 559eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch eye_y_ = y; 560eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch eye_z_ = z; 561eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CacheCalcs(); 562eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 563eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 564eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetLightXYZ(float x, float y, float z) { 565eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch light_x_ = x; 566eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch light_y_ = y; 567eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch light_z_ = z; 568eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CacheCalcs(); 569eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 570eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 571eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetAmbientRGB(float r, float g, float b) { 572eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ambient_r_ = r; 573eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ambient_g_ = g; 574eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ambient_b_ = b; 575eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CacheCalcs(); 576eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 577eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 578eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetDiffuseRGB(float r, float g, float b) { 579eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch diffuse_r_ = r; 580eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch diffuse_g_ = g; 581eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch diffuse_b_ = b; 582eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CacheCalcs(); 583eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 584eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 585eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetPlanetPole(float x, float y, float z) { 586eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_x_ = x; 587eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_y_ = y; 588eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_pole_z_ = z; 589eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CacheCalcs(); 590eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 591eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 592eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetPlanetEquator(float x, float y, float z) { 593eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // This is really over-ridden by spin at the momenent. 594eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_equator_x_ = x; 595eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_equator_y_ = y; 596eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_equator_z_ = z; 597eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CacheCalcs(); 598eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 599eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 600eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetPlanetSpin(float x, float y) { 601eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_spin_x_ = x; 602eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch planet_spin_y_ = y; 603eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CacheCalcs(); 604eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 605eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 606eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Run a simple sim to spin the planet. Update loop is run once per frame. 607eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Called from the main thread only and only when the worker threads are idle. 608eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::UpdateSim() { 609eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float x = planet_spin_x_ + ui_spin_x_; 610eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch float y = planet_spin_y_ + ui_spin_y_; 611eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // keep in nice range 612eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (x > (kPI * 2.0f)) 613eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch x = x - kPI * 2.0f; 614eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch else if (x < (-kPI * 2.0f)) 615eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch x = x + kPI * 2.0f; 616eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (y > (kPI * 2.0f)) 617eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch y = y - kPI * 2.0f; 618eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch else if (y < (-kPI * 2.0f)) 619eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch y = y + kPI * 2.0f; 620eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SetPlanetSpin(x, y); 621eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 622eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 623eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::StartBenchmark() { 624eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // For more consistent benchmark numbers, reset to default state. 625eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Reset(); 626eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch printf("Benchmark started...\n"); 627eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch benchmark_frame_counter_ = kFramesToBenchmark; 628eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch benchmarking_ = true; 629eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch benchmark_start_time_ = getseconds(); 630eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 631eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 632eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::EndBenchmark() { 633eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch benchmark_end_time_ = getseconds(); 634eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch printf("Benchmark ended... time: %2.5f\n", 635eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch benchmark_end_time_ - benchmark_start_time_); 636eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch benchmarking_ = false; 637eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch benchmark_frame_counter_ = 0; 638eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch double total_time = benchmark_end_time_ - benchmark_start_time_; 639eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Send benchmark result to JS. 640eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch PostUpdateMessage("benchmark_result", total_time); 641eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 642eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 643eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetZoom(float zoom) { 644eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ui_zoom_ = std::min(kZoomMax, std::max(kZoomMin, zoom)); 645eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SetEyeXYZ(0.0f, 0.0f, -ui_zoom_); 646eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 647eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 648eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetLight(float light) { 649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ui_light_ = std::min(kLightMax, std::max(kLightMin, light)); 650eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SetDiffuseRGB(0.8f * ui_light_, 0.8f * ui_light_, 0.8f * ui_light_); 651eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SetAmbientRGB(0.4f * ui_light_, 0.4f * ui_light_, 0.4f * ui_light_); 652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 653eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 654eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::SetTexture(const std::string& name, int width, int height, 655eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32_t* pixels) { 656eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (pixels) { 657eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (name == "earth.jpg") { 658eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch delete base_tex_; 659eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base_tex_ = new Texture(width, height, pixels); 660eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else if (name == "earthnight.jpg") { 661eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch delete night_tex_; 662eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch night_tex_ = new Texture(width, height, pixels); 663eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 664eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 665eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 666eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 6673240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Handle input events from the user and messages from JS. 6683240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochvoid Planet::HandleEvent(PSEvent* ps_event) { 6693240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Give the 2D context a chance to process the event. 6703240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (0 != PSContext2DHandleEvent(ps_context_, ps_event)) 6713240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return; 6723240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (ps_event->type == PSE_INSTANCE_HANDLEINPUT) { 6733240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Convert Pepper Simple event to a PPAPI C++ event 6743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::InputEvent event(ps_event->as_resource); 6753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch switch (event.GetType()) { 6763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch case PP_INPUTEVENT_TYPE_KEYDOWN: { 6773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::KeyboardInputEvent key(event); 6783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t key_code = key.GetKeyCode(); 6793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (key_code == 84) // 't' key 6803240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (!benchmarking_) 6813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch StartBenchmark(); 6823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch break; 683eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 6843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch case PP_INPUTEVENT_TYPE_MOUSEMOVE: 6853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch case PP_INPUTEVENT_TYPE_MOUSEDOWN: { 6863240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::MouseInputEvent mouse = pp::MouseInputEvent(event); 6873240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (mouse.GetModifiers() & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) { 6883240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PP_Point delta = mouse.GetMovement(); 6893240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch float delta_x = static_cast<float>(delta.x); 6903240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch float delta_y = static_cast<float>(delta.y); 6913240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch float spin_x = std::min(4.0f, std::max(-4.0f, delta_x * 0.5f)); 6923240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch float spin_y = std::min(4.0f, std::max(-4.0f, delta_y * 0.5f)); 6933240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ui_spin_x_ = spin_x / 100.0f; 6943240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch ui_spin_y_ = spin_y / 100.0f; 6953240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 6963240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch break; 6973240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 6983240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch case PP_INPUTEVENT_TYPE_WHEEL: { 6993240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::WheelInputEvent wheel = pp::WheelInputEvent(event); 7003240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PP_FloatPoint ticks = wheel.GetTicks(); 7013240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch SetZoom(ui_zoom_ + (ticks.x + ticks.y) * kWheelSpeed); 7023240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Update html slider by sending update message to JS. 7033240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PostUpdateMessage("set_zoom", ui_zoom_); 7043240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch break; 7053240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 7063240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch default: 7073240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch break; 708eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 7093240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } else if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) { 7103240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Convert Pepper Simple message to PPAPI C++ vars 7113240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::Var var(ps_event->as_var); 7123240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (var.is_dictionary()) { 7133240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::VarDictionary dictionary(var); 7143240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch std::string message = dictionary.Get("message").AsString(); 7153240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (message == "run benchmark" && !benchmarking_) { 7163240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch StartBenchmark(); 7173240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } else if (message == "set_light") { 7183240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch SetLight(static_cast<float>(dictionary.Get("value").AsDouble())); 7193240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } else if (message == "set_zoom") { 7203240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch SetZoom(static_cast<float>(dictionary.Get("value").AsDouble())); 7213240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } else if (message == "set_threads") { 7223240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int threads = dictionary.Get("value").AsInt(); 7233240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch delete workers_; 7243240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch workers_ = new ThreadPool(threads); 7253240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } else if (message == "texture") { 7263240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch std::string name = dictionary.Get("name").AsString(); 7273240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int width = dictionary.Get("width").AsInt(); 7283240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch int height = dictionary.Get("height").AsInt(); 7293240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch pp::VarArrayBuffer array_buffer(dictionary.Get("data")); 7303240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (!name.empty() && !array_buffer.is_null()) { 7313240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (width > 0 && height > 0) { 7323240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch uint32_t* pixels = static_cast<uint32_t*>(array_buffer.Map()); 7333240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch SetTexture(name, width, height, pixels); 7343240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch array_buffer.Unmap(); 7353240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 7363240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 7373240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 7383240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } else { 7393240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch printf("Handle message unknown type: %s\n", var.DebugString().c_str()); 740eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 741eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 742eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 743eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 744eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// PostUpdateMessage() helper function for sending small messages to JS. 745eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::PostUpdateMessage(const char* message_name, double value) { 746eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch pp::VarDictionary message; 747eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch message.Set("message", message_name); 748eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch message.Set("value", value); 7493240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message.pp_var()); 750eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 751eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 752eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Planet::Update() { 7533240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // When benchmarking is running, don't update display via 7543240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // PSContext2DSwapBuffer() - vsync is enabled by default, and will throttle 7553240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // the benchmark results. 7563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSContext2DGetBuffer(ps_context_); 7573240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch if (NULL == ps_context_->data) 7583240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return; 7593240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 760eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch do { 761eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch UpdateSim(); 762eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Render(); 763eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!benchmarking_) break; 764eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch --benchmark_frame_counter_; 765eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } while (benchmark_frame_counter_ > 0); 766eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (benchmarking_) 767eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch EndBenchmark(); 768eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 7693240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSContext2DSwapBuffer(ps_context_); 7703240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch} 7713240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch 772eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 7733240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Starting point for the module. We do not use main since it would 7743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// collide with main in libppapi_cpp. 7753240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdochint example_main(int argc, char* argv[]) { 7763240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch Planet earth; 7773240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch while (true) { 7783240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSEvent* ps_event; 7793240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Consume all available events 7803240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch while ((ps_event = PSEventTryAcquire()) != NULL) { 7813240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch earth.HandleEvent(ps_event); 7823240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch PSEventRelease(ps_event); 7833240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch } 7843240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch // Do simulation, render and present. 7853240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch earth.Update(); 786eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 787eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 7883240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch return 0; 789eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 790eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 7913240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// Register the function to call once the Instance Object is initialized. 7923240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch// see: pappi_simple/ps_main.h 7933240926e260ce088908e02ac07a6cf7b0c0cbf44Ben MurdochPPAPI_SIMPLE_REGISTER_MAIN(example_main); 794