1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include <ppapi/c/ppb_input_event.h>
8 #include <ppapi/cpp/input_event.h>
9 #include <ppapi/cpp/var.h>
10 #include <ppapi/cpp/var_array.h>
11 #include <ppapi/cpp/var_array_buffer.h>
12 #include <ppapi/cpp/var_dictionary.h>
23 #include "ppapi_simple/ps.h"
24 #include "ppapi_simple/ps_context_2d.h"
25 #include "ppapi_simple/ps_event.h"
26 #include "ppapi_simple/ps_interface.h"
27 #include "ppapi_simple/ps_main.h"
28 #include "sdk_util/macros.h"
29 #include "sdk_util/thread_pool.h"
31 using namespace sdk_util
; // For sdk_util::ThreadPool
33 // Global properties used to setup Earth demo.
35 const float kPI
= M_PI
;
36 const float kTwoPI
= kPI
* 2.0f
;
37 const float kOneOverPI
= 1.0f
/ kPI
;
38 const float kOneOver2PI
= 1.0f
/ kTwoPI
;
39 const float kOneOver255
= 1.0f
/ 255.0f
;
40 const int kArcCosineTableSize
= 4096;
41 const int kFramesToBenchmark
= 100;
42 const float kZoomMin
= 1.0f
;
43 const float kZoomMax
= 50.0f
;
44 const float kWheelSpeed
= 2.0f
;
45 const float kLightMin
= 0.0f
;
46 const float kLightMax
= 2.0f
;
48 // Timer helper for benchmarking. Returns seconds elapsed since program start,
51 int start_tv_retv
= gettimeofday(&start_tv
, NULL
);
53 inline double getseconds() {
54 const double usec_to_sec
= 0.000001;
56 if ((0 == start_tv_retv
) && (0 == gettimeofday(&tv
, NULL
)))
57 return (tv
.tv_sec
- start_tv
.tv_sec
) + tv
.tv_usec
* usec_to_sec
;
61 // RGBA helper functions, used for extracting color from RGBA source image.
62 inline float ExtractR(uint32_t c
) {
63 return static_cast<float>(c
& 0xFF) * kOneOver255
;
66 inline float ExtractG(uint32_t c
) {
67 return static_cast<float>((c
& 0xFF00) >> 8) * kOneOver255
;
70 inline float ExtractB(uint32_t c
) {
71 return static_cast<float>((c
& 0xFF0000) >> 16) * kOneOver255
;
74 // BGRA helper function, for constructing a pixel for a BGRA buffer.
75 inline uint32_t MakeBGRA(uint32_t b
, uint32_t g
, uint32_t r
, uint32_t a
) {
76 return (((a
) << 24) | ((r
) << 16) | ((g
) << 8) | (b
));
79 // simple container for earth texture
83 Texture(int w
, int h
) : width(w
), height(h
) {
84 pixels
= new uint32_t[w
* h
];
85 memset(pixels
, 0, sizeof(uint32_t) * w
* h
);
87 explicit Texture(int w
, int h
, uint32_t* p
) : width(w
), height(h
) {
88 pixels
= new uint32_t[w
* h
];
89 memcpy(pixels
, p
, sizeof(uint32_t) * w
* h
);
91 ~Texture() { delete[] pixels
; }
93 DISALLOW_COPY_AND_ASSIGN(Texture
);
99 // slightly larger table so we can interpolate beyond table size
100 float table
[kArcCosineTableSize
+ 2];
101 float TableLerp(float x
);
105 ArcCosine::ArcCosine() {
106 // build a slightly larger table to allow for numeric imprecision
107 for (int i
= 0; i
< (kArcCosineTableSize
+ 2); ++i
) {
108 float f
= static_cast<float>(i
) / kArcCosineTableSize
;
114 // looks up acos(f) using a table and lerping between entries
115 // (it is expected that input f is between -1 and 1)
116 float ArcCosine::TableLerp(float f
) {
117 float x
= (f
+ 1.0f
) * 0.5f
;
118 x
= x
* kArcCosineTableSize
;
119 int ix
= static_cast<int>(x
);
120 float fx
= static_cast<float>(ix
);
122 float af
= table
[ix
];
123 float af2
= table
[ix
+ 1];
124 return af
+ (af2
- af
) * dx
;
127 // Helper functions for quick but approximate sqrt.
131 Convert(int x
) { i
= x
; }
132 Convert(float x
) { f
= x
; }
133 int AsInt() { return i
; }
134 float AsFloat() { return f
; }
137 inline const int AsInteger(const float f
) {
142 inline const float AsFloat(const int i
) {
147 const long int kOneAsInteger
= AsInteger(1.0f
);
149 inline float inline_quick_sqrt(float x
) {
151 i
= (AsInteger(x
) >> 1) + (kOneAsInteger
>> 1);
155 inline float inline_sqrt(float x
) {
157 y
= inline_quick_sqrt(x
);
158 y
= (y
* y
+ x
) / (2.0f
* y
);
159 y
= (y
* y
+ x
) / (2.0f
* y
);
163 // takes a -0..1+ color, clamps it to 0..1 and maps it to 0..255 integer
164 inline uint32_t Clamp255(float x
) {
167 } else if (x
> 1.0f
) {
170 return static_cast<uint32_t>(x
* 255.0f
);
175 // The main object that runs the Earth demo.
180 // Runs a tick of the simulations, update 2D output.
182 // Handle event from user, or message from JS.
183 void HandleEvent(PSEvent
* ps_event
);
186 // Methods prefixed with 'w' are run on worker threads.
187 uint32_t* wGetAddr(int x
, int y
);
188 void wRenderPixelSpan(int x0
, int x1
, int y
);
189 void wMakeRect(int r
, int *x
, int *y
, int *w
, int *h
);
190 void wRenderRect(int x0
, int y0
, int x1
, int y1
);
191 void wRenderRegion(int region
);
192 static void wRenderRegionEntry(int region
, void *thiz
);
194 // These methods are only called by the main thread.
196 void SetPlanetXYZR(float x
, float y
, float z
, float r
);
197 void SetPlanetPole(float x
, float y
, float z
);
198 void SetPlanetEquator(float x
, float y
, float z
);
199 void SetPlanetSpin(float x
, float y
);
200 void SetEyeXYZ(float x
, float y
, float z
);
201 void SetLightXYZ(float x
, float y
, float z
);
202 void SetAmbientRGB(float r
, float g
, float b
);
203 void SetDiffuseRGB(float r
, float g
, float b
);
204 void SetZoom(float zoom
);
205 void SetLight(float zoom
);
206 void SetTexture(const std::string
& name
, int width
, int height
,
208 void SpinPlanet(pp::Point new_point
, pp::Point last_point
);
211 void RequestTextures();
215 void StartBenchmark();
217 // Post a small key-value message to update JS.
218 void PostUpdateMessage(const char* message_name
, double value
);
220 // User Interface settings. These settings are controlled via html
221 // controls or via user input.
226 pp::Point ui_last_point_
;
228 // Various settings for position & orientation of planet. Do not change
229 // these variables, instead use SetPlanet*() functions.
230 float planet_radius_
;
231 float planet_spin_x_
;
232 float planet_spin_y_
;
233 float planet_x_
, planet_y_
, planet_z_
;
234 float planet_pole_x_
, planet_pole_y_
, planet_pole_z_
;
235 float planet_equator_x_
, planet_equator_y_
, planet_equator_z_
;
237 // Observer's eye. Do not change these variables, instead use SetEyeXYZ().
238 float eye_x_
, eye_y_
, eye_z_
;
240 // Light position, ambient and diffuse settings. Do not change these
241 // variables, instead use SetLightXYZ(), SetAmbientRGB() and SetDiffuseRGB().
242 float light_x_
, light_y_
, light_z_
;
243 float diffuse_r_
, diffuse_g_
, diffuse_b_
;
244 float ambient_r_
, ambient_g_
, ambient_b_
;
246 // Cached calculations. Do not change these variables - they are updated by
247 // CacheCalcs() function.
249 float planet_pole_x_equator_x_
;
250 float planet_pole_x_equator_y_
;
251 float planet_pole_x_equator_z_
;
252 float planet_radius2_
;
253 float planet_one_over_radius_
;
256 // Source texture (earth map).
262 // Quick ArcCos helper.
266 PSContext2D_t
* ps_context_
;
268 ThreadPool
* workers_
;
270 int benchmark_frame_counter_
;
271 double benchmark_start_time_
;
272 double benchmark_end_time_
;
276 void Planet::RequestTextures() {
277 // Request a set of images from JS. After images are loaded by JS, a
278 // message from JS -> NaCl will arrive containing the pixel data. See
279 // HandleMessage() method in this file.
280 pp::VarDictionary message
;
281 message
.Set("message", "request_textures");
283 names
.Set(0, "earth.jpg");
284 names
.Set(1, "earthnight.jpg");
285 message
.Set("names", names
);
286 PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message
.pp_var());
289 void Planet::Reset() {
290 // Reset has to first fill in all variables with valid floats, so
291 // CacheCalcs() doesn't potentially propagate NaNs when calling Set*()
292 // functions further below.
293 planet_radius_
= 1.0f
;
294 planet_spin_x_
= 0.0f
;
295 planet_spin_y_
= 0.0f
;
299 planet_pole_x_
= 0.0f
;
300 planet_pole_y_
= 0.0f
;
301 planet_pole_z_
= 0.0f
;
302 planet_equator_x_
= 0.0f
;
303 planet_equator_y_
= 0.0f
;
304 planet_equator_z_
= 0.0f
;
318 planet_pole_x_equator_x_
= 0.0f
;
319 planet_pole_x_equator_y_
= 0.0f
;
320 planet_pole_x_equator_z_
= 0.0f
;
321 planet_radius2_
= 0.0f
;
322 planet_one_over_radius_
= 0.0f
;
328 ui_last_point_
= pp::Point(0, 0);
330 // Set up reasonable default values.
331 SetPlanetXYZR(0.0f
, 0.0f
, 48.0f
, 4.0f
);
332 SetEyeXYZ(0.0f
, 0.0f
, -ui_zoom_
);
333 SetLightXYZ(-60.0f
, -30.0f
, 0.0f
);
334 SetAmbientRGB(0.05f
, 0.05f
, 0.05f
);
335 SetDiffuseRGB(0.8f
, 0.8f
, 0.8f
);
336 SetPlanetPole(0.0f
, 1.0f
, 0.0f
);
337 SetPlanetEquator(1.0f
, 0.0f
, 0.0f
);
338 SetPlanetSpin(kPI
/ 2.0f
, kPI
/ 2.0f
);
342 // Send UI values to JS to reset html sliders.
343 PostUpdateMessage("set_zoom", ui_zoom_
);
344 PostUpdateMessage("set_light", ui_light_
);
348 Planet::Planet() : base_tex_(NULL
), night_tex_(NULL
), num_threads_(0),
349 benchmarking_(false), benchmark_frame_counter_(0) {
353 // By default, render from the dispatch thread.
354 workers_
= new ThreadPool(num_threads_
);
355 PSEventSetFilter(PSE_ALL
);
356 ps_context_
= PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL
);
361 PSContext2DFree(ps_context_
);
364 // Given a region r, derive a rectangle.
365 // This rectangle shouldn't overlap with work being done by other workers.
366 // If multithreading, this function is only called by the worker threads.
367 void Planet::wMakeRect(int r
, int *x
, int *y
, int *w
, int *h
) {
369 *w
= ps_context_
->width
;
375 inline uint32_t* Planet::wGetAddr(int x
, int y
) {
376 return ps_context_
->data
+ x
+ y
* ps_context_
->stride
/ sizeof(uint32_t);
379 // This is the meat of the ray tracer. Given a pixel span (x0, x1) on
380 // scanline y, shoot rays into the scene and render what they hit. Use
381 // scanline coherence to do a few optimizations
382 void Planet::wRenderPixelSpan(int x0
, int x1
, int y
) {
383 if (!base_tex_
|| !night_tex_
)
385 const int kColorBlack
= MakeBGRA(0, 0, 0, 0xFF);
386 float width
= ps_context_
->width
;
387 float height
= ps_context_
->height
;
388 float min_dim
= width
< height
? width
: height
;
389 float offset_x
= width
< height
? 0 : (width
- min_dim
) * 0.5f
;
390 float offset_y
= width
< height
? (height
- min_dim
) * 0.5f
: 0;
393 float y1
= (static_cast<float>(y
- offset_y
) / min_dim
) * 2.0f
- 1.0f
;
395 float dy
= (y1
- y0
);
396 float dz
= (z1
- z0
);
397 float dy_dy_dz_dz
= dy
* dy
+ dz
* dz
;
398 float two_dy_y0_y_two_dz_z0_z
= 2.0f
* dy
* (y0
- planet_y_
) +
399 2.0f
* dz
* (z0
- planet_z_
);
400 float planet_xyz_eye_xyz
= planet_xyz_
+ eye_xyz_
;
401 float y_y0_z_z0
= planet_y_
* y0
+ planet_z_
* z0
;
402 float oowidth
= 1.0f
/ min_dim
;
403 uint32_t* pixels
= this->wGetAddr(x0
, y
);
404 for (int x
= x0
; x
<= x1
; ++x
) {
405 // scan normalized screen -1..1
406 float x1
= (static_cast<float>(x
- offset_x
) * oowidth
) * 2.0f
- 1.0f
;
409 // delta from screen to eye
410 float dx
= (x1
- x0
);
412 float a
= dx
* dx
+ dy_dy_dz_dz
;
413 float b
= 2.0f
* dx
* (x0
- planet_x_
) + two_dy_y0_y_two_dz_z0_z
;
414 float c
= planet_xyz_eye_xyz
+
415 -2.0f
* (planet_x_
* x0
+ y_y0_z_z0
) - (planet_radius2_
);
416 // calculate discriminant
417 float disc
= b
* b
- 4.0f
* a
* c
;
419 // Did ray hit the sphere?
421 *pixels
= kColorBlack
;
426 // calc parametric t value
427 float t
= (-b
- inline_sqrt(disc
)) / (2.0f
* a
);
428 float px
= x0
+ t
* dx
;
429 float py
= y0
+ t
* dy
;
430 float pz
= z0
+ t
* dz
;
431 float nx
= (px
- planet_x_
) * planet_one_over_radius_
;
432 float ny
= (py
- planet_y_
) * planet_one_over_radius_
;
433 float nz
= (pz
- planet_z_
) * planet_one_over_radius_
;
435 // Misc raytrace calculations.
436 float Lx
= (light_x_
- px
);
437 float Ly
= (light_y_
- py
);
438 float Lz
= (light_z_
- pz
);
439 float Lq
= 1.0f
/ inline_quick_sqrt(Lx
* Lx
+ Ly
* Ly
+ Lz
* Lz
);
443 float d
= (Lx
* nx
+ Ly
* ny
+ Lz
* nz
);
444 float pr
= (diffuse_r_
* d
) + ambient_r_
;
445 float pg
= (diffuse_g_
* d
) + ambient_g_
;
446 float pb
= (diffuse_b_
* d
) + ambient_b_
;
447 float ds
= -(nx
* planet_pole_x_
+
448 ny
* planet_pole_y_
+
449 nz
* planet_pole_z_
);
450 float ang
= acos_
.TableLerp(ds
);
451 float v
= ang
* kOneOverPI
;
452 float dp
= planet_equator_x_
* nx
+
453 planet_equator_y_
* ny
+
454 planet_equator_z_
* nz
;
455 float w
= dp
/ sinf(ang
);
456 if (w
> 1.0f
) w
= 1.0f
;
457 if (w
< -1.0f
) w
= -1.0f
;
458 float th
= acos_
.TableLerp(w
) * kOneOver2PI
;
459 float dps
= planet_pole_x_equator_x_
* nx
+
460 planet_pole_x_equator_y_
* ny
+
461 planet_pole_x_equator_z_
* nz
;
468 // Look up daylight texel.
469 int tx
= static_cast<int>(u
* base_tex_
->width
);
470 int ty
= static_cast<int>(v
* base_tex_
->height
);
471 int offset
= tx
+ ty
* base_tex_
->width
;
472 uint32_t base_texel
= base_tex_
->pixels
[offset
];
473 float tr
= ExtractR(base_texel
);
474 float tg
= ExtractG(base_texel
);
475 float tb
= ExtractB(base_texel
);
477 float ipr
= 1.0f
- pr
;
478 if (ipr
< 0.0f
) ipr
= 0.0f
;
479 float ipg
= 1.0f
- pg
;
480 if (ipg
< 0.0f
) ipg
= 0.0f
;
481 float ipb
= 1.0f
- pb
;
482 if (ipb
< 0.0f
) ipb
= 0.0f
;
484 // Look up night texel.
485 int nix
= static_cast<int>(u
* night_tex_
->width
);
486 int niy
= static_cast<int>(v
* night_tex_
->height
);
487 int noffset
= nix
+ niy
* night_tex_
->width
;
488 uint32_t night_texel
= night_tex_
->pixels
[noffset
];
489 float nr
= ExtractR(night_texel
);
490 float ng
= ExtractG(night_texel
);
491 float nb
= ExtractB(night_texel
);
493 // Final color value is lerp between day and night texels.
494 unsigned int ir
= Clamp255(pr
* tr
+ nr
* ipr
);
495 unsigned int ig
= Clamp255(pg
* tg
+ ng
* ipg
);
496 unsigned int ib
= Clamp255(pb
* tb
+ nb
* ipb
);
498 unsigned int color
= MakeBGRA(ib
, ig
, ir
, 0xFF);
505 // Renders a rectangular area of the screen, scan line at a time
506 void Planet::wRenderRect(int x
, int y
, int w
, int h
) {
507 for (int j
= y
; j
< (y
+ h
); ++j
) {
508 this->wRenderPixelSpan(x
, x
+ w
- 1, j
);
512 // If multithreading, this function is only called by the worker threads.
513 void Planet::wRenderRegion(int region
) {
514 // convert region # into x0, y0, x1, y1 rectangle
516 wMakeRect(region
, &x
, &y
, &w
, &h
);
517 // render this rectangle
518 wRenderRect(x
, y
, w
, h
);
521 // Entry point for worker thread. Can't pass a member function around, so we
522 // have to do this little round-about.
523 void Planet::wRenderRegionEntry(int region
, void* thiz
) {
524 static_cast<Planet
*>(thiz
)->wRenderRegion(region
);
527 // Renders the planet, dispatching the work to multiple threads.
528 void Planet::Render() {
529 workers_
->Dispatch(ps_context_
->height
, wRenderRegionEntry
, this);
532 // Pre-calculations to make inner loops faster.
533 void Planet::CacheCalcs() {
534 planet_xyz_
= planet_x_
* planet_x_
+
535 planet_y_
* planet_y_
+
536 planet_z_
* planet_z_
;
537 planet_radius2_
= planet_radius_
* planet_radius_
;
538 planet_one_over_radius_
= 1.0f
/ planet_radius_
;
539 eye_xyz_
= eye_x_
* eye_x_
+ eye_y_
* eye_y_
+ eye_z_
* eye_z_
;
540 // spin vector from center->equator
541 planet_equator_x_
= cos(planet_spin_x_
);
542 planet_equator_y_
= 0.0f
;
543 planet_equator_z_
= sin(planet_spin_x_
);
545 // cache cross product of pole & equator
546 planet_pole_x_equator_x_
= planet_pole_y_
* planet_equator_z_
-
547 planet_pole_z_
* planet_equator_y_
;
548 planet_pole_x_equator_y_
= planet_pole_z_
* planet_equator_x_
-
549 planet_pole_x_
* planet_equator_z_
;
550 planet_pole_x_equator_z_
= planet_pole_x_
* planet_equator_y_
-
551 planet_pole_y_
* planet_equator_x_
;
554 void Planet::SetPlanetXYZR(float x
, float y
, float z
, float r
) {
562 void Planet::SetEyeXYZ(float x
, float y
, float z
) {
569 void Planet::SetLightXYZ(float x
, float y
, float z
) {
576 void Planet::SetAmbientRGB(float r
, float g
, float b
) {
583 void Planet::SetDiffuseRGB(float r
, float g
, float b
) {
590 void Planet::SetPlanetPole(float x
, float y
, float z
) {
597 void Planet::SetPlanetEquator(float x
, float y
, float z
) {
598 // This is really over-ridden by spin at the momenent.
599 planet_equator_x_
= x
;
600 planet_equator_y_
= y
;
601 planet_equator_z_
= z
;
605 void Planet::SetPlanetSpin(float x
, float y
) {
611 // Run a simple sim to spin the planet. Update loop is run once per frame.
612 // Called from the main thread only and only when the worker threads are idle.
613 void Planet::UpdateSim() {
614 float x
= planet_spin_x_
+ ui_spin_x_
;
615 float y
= planet_spin_y_
+ ui_spin_y_
;
616 // keep in nice range
617 if (x
> (kPI
* 2.0f
))
619 else if (x
< (-kPI
* 2.0f
))
621 if (y
> (kPI
* 2.0f
))
623 else if (y
< (-kPI
* 2.0f
))
628 void Planet::StartBenchmark() {
629 // For more consistent benchmark numbers, reset to default state.
631 printf("Benchmark started...\n");
632 benchmark_frame_counter_
= kFramesToBenchmark
;
633 benchmarking_
= true;
634 benchmark_start_time_
= getseconds();
637 void Planet::EndBenchmark() {
638 benchmark_end_time_
= getseconds();
639 printf("Benchmark ended... time: %2.5f\n",
640 benchmark_end_time_
- benchmark_start_time_
);
641 benchmarking_
= false;
642 benchmark_frame_counter_
= 0;
643 double total_time
= benchmark_end_time_
- benchmark_start_time_
;
644 // Send benchmark result to JS.
645 PostUpdateMessage("benchmark_result", total_time
);
648 void Planet::SetZoom(float zoom
) {
649 ui_zoom_
= std::min(kZoomMax
, std::max(kZoomMin
, zoom
));
650 SetEyeXYZ(0.0f
, 0.0f
, -ui_zoom_
);
653 void Planet::SetLight(float light
) {
654 ui_light_
= std::min(kLightMax
, std::max(kLightMin
, light
));
655 SetDiffuseRGB(0.8f
* ui_light_
, 0.8f
* ui_light_
, 0.8f
* ui_light_
);
656 SetAmbientRGB(0.4f
* ui_light_
, 0.4f
* ui_light_
, 0.4f
* ui_light_
);
659 void Planet::SetTexture(const std::string
& name
, int width
, int height
,
662 if (name
== "earth.jpg") {
664 base_tex_
= new Texture(width
, height
, pixels
);
665 } else if (name
== "earthnight.jpg") {
667 night_tex_
= new Texture(width
, height
, pixels
);
672 void Planet::SpinPlanet(pp::Point new_point
, pp::Point last_point
) {
673 float delta_x
= static_cast<float>(new_point
.x() - last_point
.x());
674 float delta_y
= static_cast<float>(new_point
.y() - last_point
.y());
675 float spin_x
= std::min(10.0f
, std::max(-10.0f
, delta_x
* 0.5f
));
676 float spin_y
= std::min(10.0f
, std::max(-10.0f
, delta_y
* 0.5f
));
677 ui_spin_x_
= spin_x
/ 100.0f
;
678 ui_spin_y_
= spin_y
/ 100.0f
;
679 ui_last_point_
= new_point
;
682 // Handle input events from the user and messages from JS.
683 void Planet::HandleEvent(PSEvent
* ps_event
) {
684 // Give the 2D context a chance to process the event.
685 if (0 != PSContext2DHandleEvent(ps_context_
, ps_event
))
687 if (ps_event
->type
== PSE_INSTANCE_HANDLEINPUT
) {
688 // Convert Pepper Simple event to a PPAPI C++ event
689 pp::InputEvent
event(ps_event
->as_resource
);
690 switch (event
.GetType()) {
691 case PP_INPUTEVENT_TYPE_KEYDOWN
: {
692 pp::KeyboardInputEvent
key(event
);
693 uint32_t key_code
= key
.GetKeyCode();
694 if (key_code
== 84) // 't' key
699 case PP_INPUTEVENT_TYPE_MOUSEDOWN
:
700 case PP_INPUTEVENT_TYPE_MOUSEMOVE
: {
701 pp::MouseInputEvent mouse
= pp::MouseInputEvent(event
);
702 if (mouse
.GetModifiers() & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN
) {
703 if (event
.GetType() == PP_INPUTEVENT_TYPE_MOUSEDOWN
)
704 SpinPlanet(mouse
.GetPosition(), mouse
.GetPosition());
706 SpinPlanet(mouse
.GetPosition(), ui_last_point_
);
710 case PP_INPUTEVENT_TYPE_WHEEL
: {
711 pp::WheelInputEvent wheel
= pp::WheelInputEvent(event
);
712 PP_FloatPoint ticks
= wheel
.GetTicks();
713 SetZoom(ui_zoom_
+ (ticks
.x
+ ticks
.y
) * kWheelSpeed
);
714 // Update html slider by sending update message to JS.
715 PostUpdateMessage("set_zoom", ui_zoom_
);
718 case PP_INPUTEVENT_TYPE_TOUCHSTART
:
719 case PP_INPUTEVENT_TYPE_TOUCHMOVE
: {
720 pp::TouchInputEvent touches
= pp::TouchInputEvent(event
);
721 uint32_t count
= touches
.GetTouchCount(PP_TOUCHLIST_TYPE_TOUCHES
);
723 // Use first touch point to spin planet.
724 pp::TouchPoint touch
=
725 touches
.GetTouchByIndex(PP_TOUCHLIST_TYPE_TOUCHES
, 0);
726 pp::Point
screen_point(touch
.position().x(),
727 touch
.position().y());
728 if (event
.GetType() == PP_INPUTEVENT_TYPE_TOUCHSTART
)
729 SpinPlanet(screen_point
, screen_point
);
731 SpinPlanet(screen_point
, ui_last_point_
);
738 } else if (ps_event
->type
== PSE_INSTANCE_HANDLEMESSAGE
) {
739 // Convert Pepper Simple message to PPAPI C++ vars
740 pp::Var
var(ps_event
->as_var
);
741 if (var
.is_dictionary()) {
742 pp::VarDictionary
dictionary(var
);
743 std::string message
= dictionary
.Get("message").AsString();
744 if (message
== "run benchmark" && !benchmarking_
) {
746 } else if (message
== "set_light") {
747 SetLight(static_cast<float>(dictionary
.Get("value").AsDouble()));
748 } else if (message
== "set_zoom") {
749 SetZoom(static_cast<float>(dictionary
.Get("value").AsDouble()));
750 } else if (message
== "set_threads") {
751 int threads
= dictionary
.Get("value").AsInt();
753 workers_
= new ThreadPool(threads
);
754 } else if (message
== "texture") {
755 std::string name
= dictionary
.Get("name").AsString();
756 int width
= dictionary
.Get("width").AsInt();
757 int height
= dictionary
.Get("height").AsInt();
758 pp::VarArrayBuffer
array_buffer(dictionary
.Get("data"));
759 if (!name
.empty() && !array_buffer
.is_null()) {
760 if (width
> 0 && height
> 0) {
761 uint32_t* pixels
= static_cast<uint32_t*>(array_buffer
.Map());
762 SetTexture(name
, width
, height
, pixels
);
763 array_buffer
.Unmap();
768 printf("Handle message unknown type: %s\n", var
.DebugString().c_str());
773 // PostUpdateMessage() helper function for sending small messages to JS.
774 void Planet::PostUpdateMessage(const char* message_name
, double value
) {
775 pp::VarDictionary message
;
776 message
.Set("message", message_name
);
777 message
.Set("value", value
);
778 PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), message
.pp_var());
781 void Planet::Update() {
782 // When benchmarking is running, don't update display via
783 // PSContext2DSwapBuffer() - vsync is enabled by default, and will throttle
784 // the benchmark results.
785 PSContext2DGetBuffer(ps_context_
);
786 if (NULL
== ps_context_
->data
)
792 if (!benchmarking_
) break;
793 --benchmark_frame_counter_
;
794 } while (benchmark_frame_counter_
> 0);
798 PSContext2DSwapBuffer(ps_context_
);
802 // Starting point for the module. We do not use main since it would
803 // collide with main in libppapi_cpp.
804 int example_main(int argc
, char* argv
[]) {
808 // Consume all available events
809 while ((ps_event
= PSEventTryAcquire()) != NULL
) {
810 earth
.HandleEvent(ps_event
);
811 PSEventRelease(ps_event
);
813 // Do simulation, render and present.
820 // Register the function to call once the Instance Object is initialized.
821 // see: pappi_simple/ps_main.h
822 PPAPI_SIMPLE_REGISTER_MAIN(example_main
);