|
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 The Native Client SDK Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can | |
3 // be found in the LICENSE file. | |
4 | |
5 #include <assert.h> | |
6 #include <math.h> | |
7 #include <ppapi/cpp/completion_callback.h> | |
8 #include <ppapi/cpp/graphics_2d.h> | |
9 #include <ppapi/cpp/image_data.h> | |
10 #include <ppapi/cpp/input_event.h> | |
11 #include <ppapi/cpp/instance.h> | |
12 #include <ppapi/cpp/module.h> | |
13 #include <ppapi/cpp/rect.h> | |
14 #include <ppapi/cpp/size.h> | |
15 #include <ppapi/cpp/var.h> | |
16 #include <pthread.h> | |
17 #include <stdio.h> | |
18 #include <stdlib.h> | |
19 #include <string.h> | |
20 #include <sys/time.h> | |
21 #include <unistd.h> | |
22 | |
23 #include <string> | |
24 | |
25 #include "threadpool.h" | |
26 | |
27 // Global properties used to setup Voronoi demo. | |
28 namespace { | |
29 const int kMinRectSize = 4; | |
30 const int kStartRecurseSize = 32; | |
binji
2013/05/24 21:47:55
must be power of 2
nfullagar1
2013/05/28 23:11:50
comment added
| |
31 const float kHugeZ = 1.0e38f; | |
32 const float kPI = M_PI; | |
33 const float kTwoPI = kPI * 2.0f; | |
34 const int kFramesToBenchmark = 100; | |
35 const unsigned int kRandomStartSeed = 0xC0DE533D; | |
36 const int kMaxPointCount = 1024; | |
37 const int kStartPointCount = 256; | |
38 | |
39 unsigned int g_rand_state = kRandomStartSeed; | |
40 | |
41 // random number helper | |
42 inline unsigned char rand255() { | |
43 return static_cast<unsigned char>(rand_r(&g_rand_state) & 255); | |
44 } | |
45 | |
46 // random number helper | |
47 inline float frand() { | |
48 return (static_cast<float>(rand_r(&g_rand_state)) / | |
49 static_cast<float>(RAND_MAX)); | |
50 } | |
51 | |
52 // reset random seed | |
53 inline void rand_reset(unsigned int seed) { | |
54 g_rand_state = seed; | |
55 } | |
56 | |
57 inline double getseconds() { | |
58 const double usec_to_sec = 0.000001; | |
59 timeval tv; | |
60 if (0 == gettimeofday(&tv, NULL)) | |
61 return tv.tv_sec + tv.tv_usec * usec_to_sec; | |
62 return 0.0; | |
63 } | |
64 | |
65 inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) { | |
66 return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)); | |
67 } | |
68 } // namespace | |
69 | |
70 // Vec2, simple 2D vector | |
71 struct Vec2 { | |
72 float x, y; | |
73 Vec2() { ; } | |
binji
2013/05/24 21:47:55
init to 0?
noelallen1
2013/05/25 00:21:11
We typically use {} not {;}
nfullagar1
2013/05/28 23:11:50
This struct is closer to an int or a float (in my
nfullagar1
2013/05/28 23:11:50
Done.
| |
74 Vec2(float px, float py) { | |
75 x = px; | |
76 y = py; | |
77 } | |
78 void Set(float px, float py) { | |
79 x = px; | |
80 y = py; | |
81 } | |
82 }; | |
83 | |
84 // The main object that runs Voronoi simulation. | |
85 class Voronoi : public pp::Instance { | |
86 public: | |
87 explicit Voronoi(PP_Instance instance); | |
88 virtual ~Voronoi(); | |
89 | |
90 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { | |
91 return true; | |
92 } | |
93 | |
94 virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip); | |
95 | |
96 // Catch events. | |
97 virtual bool HandleInputEvent(const pp::InputEvent& event); | |
98 | |
99 // Catch messages posted from Javascript. | |
100 virtual void HandleMessage(const pp::Var& message); | |
101 | |
102 private: | |
103 // Methods prefixed with 'w' are run on worker threads. | |
104 int wCell(float x, float y); | |
105 inline void wFillSpan(uint32_t *pixels, uint32_t color, int width); | |
106 void wRenderTile(int x, int y, int w, int h); | |
107 void wProcessTile(int x, int y, int w, int h); | |
108 void wSubdivide(int x, int y, int w, int h); | |
109 void wMakeRect(int region, int *x, int *y, int *w, int *h); | |
110 bool wTestRect(int *m, int x, int y, int w, int h); | |
111 void wFillRect(int x, int y, int w, int h, uint32_t color); | |
112 void wRenderRect(int x0, int y0, int x1, int y1); | |
113 void wRenderRegion(int region); | |
114 static void wRenderRegionEntry(int region, void *thiz); | |
115 | |
116 // These methods are only called by the main thread. | |
117 void Reset(); | |
118 void UpdateSim(); | |
119 void RenderDot(float x, float y, uint32_t color1, uint32_t color2); | |
120 void SuperimposePositions(); | |
121 void Render(); | |
122 void Draw(); | |
123 void StartBenchmark(); | |
124 void EndBenchmark(); | |
125 | |
126 // Runs a tick of the simulations, updating all buffers. Flushes the | |
127 // contents of |image_data_| to the 2D graphics context. | |
128 void Update(); | |
129 | |
130 // Create and initialize the 2D context used for drawing. | |
131 void CreateContext(const pp::Size& size); | |
132 // Destroy the 2D drawing context. | |
133 void DestroyContext(); | |
134 // Push the pixels to the browser, then attempt to flush the 2D context. | |
135 void FlushPixelBuffer(); | |
136 static void FlushCallback(void* data, int32_t result); | |
137 | |
138 | |
139 pp::Graphics2D* graphics_2d_context_; | |
140 pp::ImageData* image_data_; | |
141 Vec2 positions_[kMaxPointCount]; | |
142 Vec2 screen_positions_[kMaxPointCount]; | |
143 Vec2 velocities_[kMaxPointCount]; | |
144 uint32_t colors_[kMaxPointCount]; | |
145 float ang_; | |
146 int point_count_; | |
147 int num_threads_; | |
148 int num_regions_; | |
149 bool draw_points_; | |
150 bool draw_interiors_; | |
151 ThreadPool *workers_; | |
152 int width_; | |
153 int height_; | |
154 uint32_t stride_in_pixels_; | |
155 uint32_t *pixel_buffer_; | |
156 int benchmark_frame_counter_; | |
157 bool benchmarking_; | |
158 double benchmark_start_time_; | |
159 double benchmark_end_time_; | |
160 }; | |
161 | |
162 | |
163 | |
164 void Voronoi::Reset() { | |
165 rand_reset(kRandomStartSeed); | |
166 ang_ = 0.0f; | |
167 for (int i = 0; i < kMaxPointCount; i++) { | |
168 // random initial start position | |
169 const float x = frand(); | |
170 const float y = frand(); | |
171 positions_[i].Set(x, y); | |
172 // random directional velocity ( -1..1, -1..1 ) | |
173 const float speed = 0.0005f; | |
174 const float u = (frand() * 2.0f - 1.0f) * speed; | |
175 const float v = (frand() * 2.0f - 1.0f) * speed; | |
176 velocities_[i].Set(u, v); | |
177 // 'unique' color (well... unique enough for our purposes) | |
178 colors_[i] = MakeRGBA(rand255(), rand255(), rand255(), 255); | |
179 } | |
180 } | |
181 | |
182 Voronoi::Voronoi(PP_Instance instance) : pp::Instance(instance), | |
183 graphics_2d_context_(NULL), | |
184 image_data_(NULL) { | |
185 draw_points_ = true; | |
186 draw_interiors_ = true; | |
187 width_ = 0; | |
188 height_ = 0; | |
189 stride_in_pixels_ = 0; | |
190 pixel_buffer_ = NULL; | |
191 benchmark_frame_counter_ = 0; | |
192 benchmarking_ = false; | |
193 | |
194 point_count_ = kStartPointCount; | |
195 Reset(); | |
196 | |
197 // By default, do single threaded rendering. | |
198 num_regions_ = 256; | |
199 num_threads_ = 1; | |
200 workers_ = new ThreadPool(num_threads_); | |
201 | |
202 // Request PPAPI input events for mouse & keyboard. | |
203 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE); | |
noelallen1
2013/05/25 00:21:11
You aren't looking at mouse events.
nfullagar1
2013/05/28 23:11:50
Not now. The thought being if a user makes local
| |
204 RequestInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); | |
205 } | |
206 | |
207 Voronoi::~Voronoi() { | |
208 delete workers_; | |
209 DestroyContext(); | |
210 } | |
211 | |
212 // This is the core of the Voronoi calculation. At a given point on the | |
213 // screen, iterate through all voronoi positions and render them as 3D cones. | |
214 // We're looking for the voronoi cell that generates the closest z value. | |
215 // (not really cones - since it is all realative, we avoid doing the | |
binji
2013/05/24 21:47:55
sp: relative
nfullagar1
2013/05/28 23:11:50
Done.
| |
216 // expensive sqrt and test against z*z instead) | |
217 // If multithreading, this function is only called by the worker threads. | |
218 int Voronoi::wCell(float x, float y) { | |
219 int n = 0; | |
binji
2013/05/24 21:47:55
maybe a better var name here... closest_index?
nfullagar1
2013/05/28 23:11:50
s/n/closest_cell, removed comment on return statem
| |
220 float zz = kHugeZ; | |
binji
2013/05/24 21:47:55
maybe minz?
nfullagar1
2013/05/28 23:11:50
Is comment above sufficient?
| |
221 Vec2 *pos = screen_positions_; | |
222 for (int i = 0; i < point_count_; ++i) { | |
223 // measured 5.18 cycles per iteration on a core2 | |
224 float dx = x - pos[i].x; | |
225 float dy = y - pos[i].y; | |
226 float dd = (dx * dx + dy * dy); | |
227 if (dd < zz) { | |
228 zz = dd; | |
229 n = i; | |
230 } | |
231 } | |
232 // Return the closest cell to point x,y. | |
233 return n; | |
234 } | |
235 | |
236 // Given a region r, derive a non-overlapping rectangle for a thread to | |
237 // work on. | |
238 // If multithreading, this function is only called by the worker threads. | |
239 void Voronoi::wMakeRect(int r, int *x, int *y, int *w, int *h) { | |
240 const int parts = 16; | |
241 assert(parts * parts == num_regions_); | |
binji
2013/05/24 21:47:55
num_regions should be const too, I think.
nfullagar1
2013/05/28 23:11:50
Done.
binji
2013/05/28 23:37:50
Ah, I just meant it seemed strange to have parts d
| |
242 *w = width_ / parts; | |
243 *h = height_ / parts; | |
244 *x = *w * (r % parts); | |
245 *y = *h * ((r / parts) % parts); | |
246 } | |
247 | |
248 // Test 4 corners of a rectangle to see if they all belong to the same | |
249 // voronoi cell. Each test is expensive so bail asap. Returns true | |
250 // if all 4 corners match. | |
251 // If multithreading, this function is only called by the worker threads. | |
252 bool Voronoi::wTestRect(int *m, int x, int y, int w, int h) { | |
253 // each test is expensive, so exit ASAP | |
254 const int m0 = wCell(x, y); | |
255 const int m1 = wCell(x + w - 1, y); | |
256 if (m0 != m1) return false; | |
257 const int m2 = wCell(x, y + h - 1); | |
258 if (m0 != m2) return false; | |
259 const int m3 = wCell(x + w - 1, y + h - 1); | |
260 if (m0 != m3) return false; | |
261 // all 4 corners belong to the same cell | |
262 *m = m0; | |
263 return true; | |
264 } | |
265 | |
266 // Quickly fill a span of pixels with a solid color. Assumes | |
267 // span width is divisible by 4. | |
268 // If multithreading, this function is only called by the worker threads. | |
269 inline void Voronoi::wFillSpan(uint32_t *pixels, uint32_t color, int width) { | |
270 if (!draw_interiors_) { | |
271 const uint32_t gray = MakeRGBA(128, 128, 128, 255); | |
272 color = gray; | |
273 } | |
274 for (int i = 0; i < width; i += 4) { | |
275 *pixels++ = color; | |
276 *pixels++ = color; | |
277 *pixels++ = color; | |
278 *pixels++ = color; | |
279 } | |
280 } | |
281 | |
282 // Quickly fill a rectangle with a solid color. Assumes | |
283 // the width w parameter is evenly divisible by 4. | |
284 // If multithreading, this function is only called by the worker threads. | |
285 void Voronoi::wFillRect(int x, int y, int w, int h, uint32_t color) { | |
286 const uint32_t pitch = width_; | |
287 uint32_t *pixels = pixel_buffer_ + y * pitch + x; | |
288 for (int j = 0; j < h; j++) { | |
289 wFillSpan(pixels, color, w); | |
290 pixels += pitch; | |
291 } | |
292 } | |
293 | |
294 // When recursive subdivision reaches a certain minimum without finding a | |
295 // rectangle that has four matching corners belonging to the same voronoi | |
296 // cell, this function will break the retangular 'tile' into smaller scanlines | |
297 // and look for opportunities to quick fill at the scanline level. If the | |
298 // scanline can't be quick filled, it will slow down even further and compute | |
299 // voronoi membership per pixel. | |
300 void Voronoi::wRenderTile(int x, int y, int w, int h) { | |
301 // rip through a tile | |
302 uint32_t *pixels = pixel_buffer_ + y * stride_in_pixels_ + x; | |
303 for (int j = 0; j < h; j++) { | |
304 // get start and end cell values | |
305 int ms = wCell(x + 0, y + j); | |
306 int me = wCell(x + w - 1, y + j); | |
307 // if the end points are the same, quick fill the span | |
308 if (ms == me) { | |
309 wFillSpan(pixels, colors_[ms], w); | |
310 } else { | |
311 // else compute each pixel in the span... this is the slow part! | |
312 uint32_t *p = pixels; | |
313 *p++ = colors_[ms]; | |
314 for (int i = 1; i < (w - 1); i++) { | |
315 int m = wCell(x + i, y + j); | |
316 *p++ = colors_[m]; | |
317 } | |
318 *p++ = colors_[me]; | |
319 } | |
320 pixels += stride_in_pixels_; | |
321 } | |
322 } | |
323 | |
324 // Take a rectangular region and do one of - | |
325 // If all four corners below to the same voronoi cell, stop recursion and | |
326 // quick fill the rectangle. | |
327 // If the minimum rectangle size has been reached, break out of recursion | |
328 // and process the rectangle. This small rectangle is called a tile. | |
329 // Otherwise, keep recursively subdividing the rectangle into 4 equally | |
330 // sized smaller rectangles. | |
331 // Note: at the moment, these will always be squares, not rectangles. | |
332 // If multithreading, this function is only called by the worker threads. | |
333 void Voronoi::wSubdivide(int x, int y, int w, int h) { | |
334 int m; | |
335 // if all 4 corners are equal, quick fill interior | |
336 if (wTestRect(&m, x, y, w, h)) { | |
337 wFillRect(x, y, w, h, colors_[m]); | |
338 } else { | |
339 // did we reach the minimum rectangle size? | |
340 if ((w <= kMinRectSize) || (h <= kMinRectSize)) { | |
341 wRenderTile(x, y, w, h); | |
342 } else { | |
343 // else recurse into smaller rectangles | |
344 const int half_w = w / 2; | |
345 const int half_h = h / 2; | |
346 wSubdivide(x, y, half_w, half_h); | |
347 wSubdivide(x + half_w, y, half_w, half_h); | |
348 wSubdivide(x, y + half_h, half_w, half_h); | |
349 wSubdivide(x + half_w, y + half_h, half_w, half_h); | |
350 } | |
351 } | |
352 } | |
353 | |
354 // This function cuts up the rectangle into power of 2 sized squares. It | |
355 // assumes the input rectangle w & h are evenly divisible by | |
356 // kStartRecurseSize. | |
357 // If multithreading, this function is only called by the worker threads. | |
358 void Voronoi::wRenderRect(int x, int y, int w, int h) { | |
359 for (int iy = y; iy < (y + h); iy += kStartRecurseSize) { | |
360 for (int ix = x; ix < (x + w); ix += kStartRecurseSize) { | |
361 wSubdivide(ix, iy, kStartRecurseSize, kStartRecurseSize); | |
362 } | |
363 } | |
364 } | |
365 | |
366 // If multithreading, this function is only called by the worker threads. | |
367 void Voronoi::wRenderRegion(int region) { | |
368 // convert region # into x0, y0, x1, y1 rectangle | |
369 int x, y, w, h; | |
370 wMakeRect(region, &x, &y, &w, &h); | |
371 // render this rectangle | |
372 wRenderRect(x, y, w, h); | |
binji
2013/05/24 21:47:55
assert that w, h are power of two?
nfullagar1
2013/05/28 23:11:50
done (but assert is down in CreateContext)
| |
373 } | |
374 | |
375 // Entry point for worker thread. Can't pass a member function around, so we | |
376 // have to do this little round-about. | |
377 void Voronoi::wRenderRegionEntry(int region, void *thiz) { | |
binji
2013/05/24 21:47:55
I've been calling this a "thunk"
nfullagar1
2013/05/28 23:11:50
hmm... if you don't feel strongly about this, it f
binji
2013/05/28 23:37:50
Nope, Entry is fine.
| |
378 static_cast<Voronoi*>(thiz)->wRenderRegion(region); | |
379 } | |
380 | |
381 // Function Voronoi::UpdateSim() | |
382 // Run a simple sim to move the voronoi positions. This update loop | |
383 // is run once per frame. Called from the main thread only, and only | |
384 // when the worker threads are idle. | |
385 void Voronoi::UpdateSim() { | |
386 ang_ += 0.002f; | |
387 if (ang_ > kTwoPI) { | |
388 ang_ = ang_ - kTwoPI; | |
389 } | |
390 float z = cosf(ang_) * 3.0f; | |
391 // push the points around on the screen for animation | |
392 for (int j = 0; j < kMaxPointCount; j++) { | |
393 positions_[j].x += (velocities_[j].x) * z; | |
394 positions_[j].y += (velocities_[j].y) * z; | |
395 screen_positions_[j].x = positions_[j].x * width_; | |
396 screen_positions_[j].y = positions_[j].y * height_; | |
397 } | |
398 } | |
399 | |
400 // Renders a small diamond shaped dot at x, y clipped against the window | |
401 void Voronoi::RenderDot(float x, float y, uint32_t color1, uint32_t color2) { | |
402 const int ix = static_cast<int>(x); | |
403 const int iy = static_cast<int>(y); | |
404 // clip it against window | |
405 if (ix < 1) return; | |
406 if (ix >= (width_ - 1)) return; | |
407 if (iy < 1) return; | |
408 if (iy >= (height_ - 1)) return; | |
409 uint32_t *pixel = pixel_buffer_ + iy * stride_in_pixels_ + ix; | |
410 // render dot as a small diamond | |
411 *pixel = color1; | |
412 *(pixel - 1) = color2; | |
413 *(pixel + 1) = color2; | |
414 *(pixel - stride_in_pixels_) = color2; | |
415 *(pixel + stride_in_pixels_) = color2; | |
416 } | |
417 | |
418 // Superimposes dots on the positions. | |
419 void Voronoi::SuperimposePositions() { | |
420 const uint32_t white = MakeRGBA(255, 255, 255, 255); | |
421 const uint32_t gray = MakeRGBA(192, 192, 192, 255); | |
422 for (int i = 0; i < point_count_; i++) { | |
423 RenderDot( | |
424 screen_positions_[i].x, screen_positions_[i].y, white, gray); | |
425 } | |
426 } | |
427 | |
428 // Renders the Voronoi diagram, dispatching the work to multiple threads. | |
429 // Note: This Dispatch() is from the main PPAPI thread, so care must be taken | |
430 // not to attempt PPAPI calls from the worker threads, since Dispatch() will | |
431 // block here until all work is complete. The worker threads are compute only | |
432 // and do not make any PPAPI calls. | |
433 void Voronoi::Render() { | |
434 workers_->Dispatch(num_regions_, wRenderRegionEntry, this); | |
435 if (draw_points_) | |
436 SuperimposePositions(); | |
437 } | |
438 | |
439 void Voronoi::DidChangeView(const pp::Rect& position, const pp::Rect& clip) { | |
440 if (position.size().width() == width_ && | |
441 position.size().height() == height_) | |
442 return; // Size didn't change, no need to update anything. | |
443 | |
444 // Create a new device context with the new size. | |
445 DestroyContext(); | |
446 CreateContext(position.size()); | |
447 Update(); | |
448 } | |
449 | |
450 void Voronoi::StartBenchmark() { | |
451 Reset(); | |
452 printf("Benchmark started...\n"); | |
453 benchmark_frame_counter_ = kFramesToBenchmark; | |
454 benchmarking_ = true; | |
455 benchmark_start_time_ = getseconds(); | |
456 } | |
457 | |
458 void Voronoi::EndBenchmark() { | |
459 benchmark_end_time_ = getseconds(); | |
460 printf("Benchmark ended... time: %2.5f\n", | |
461 benchmark_end_time_ - benchmark_start_time_); | |
462 benchmarking_ = false; | |
463 benchmark_frame_counter_ = 0; | |
464 pp::Var result(benchmark_end_time_ - benchmark_start_time_); | |
465 PostMessage(result); | |
466 } | |
467 | |
468 // Handle input events from the user. | |
469 bool Voronoi::HandleInputEvent(const pp::InputEvent& event) { | |
470 switch (event.GetType()) { | |
471 case PP_INPUTEVENT_TYPE_KEYDOWN: { | |
472 pp::KeyboardInputEvent key = pp::KeyboardInputEvent(event); | |
473 uint32_t key_code = key.GetKeyCode(); | |
474 if (key_code == 84) // 't' key | |
475 if (!benchmarking_) | |
476 StartBenchmark(); | |
477 break; | |
478 } | |
479 default: | |
480 return false; | |
481 } | |
482 return true; | |
483 } | |
484 | |
485 // Handle messages sent from Javascript. | |
486 void Voronoi::HandleMessage(const pp::Var& message) { | |
487 if (message.is_string()) { | |
488 std::string message_string = message.AsString(); | |
489 if (message_string == "run benchmark" && !benchmarking_) | |
490 StartBenchmark(); | |
491 else if (message_string == "with points") | |
492 draw_points_ = true; | |
493 else if (message_string == "without points") | |
494 draw_points_ = false; | |
495 else if (message_string == "with interiors") | |
496 draw_interiors_ = true; | |
497 else if (message_string == "without interiors") | |
498 draw_interiors_ = false; | |
499 else if (strstr(message_string.c_str(), "points:")) { | |
500 int num_points = atoi(strstr(message_string.c_str(), " ")); | |
501 point_count_ = num_points < kMaxPointCount ? num_points : kMaxPointCount; | |
binji
2013/05/24 21:47:55
check for negative?
nfullagar1
2013/05/28 23:11:50
Done.
| |
502 } else if (strstr(message_string.c_str(), "threads:")) { | |
503 int thread_count = atoi(strstr(message_string.c_str(), " ")); | |
504 delete workers_; | |
505 workers_ = new ThreadPool(thread_count); | |
506 } | |
507 } | |
508 } | |
509 | |
510 void Voronoi::FlushCallback(void* thiz, int32_t result) { | |
511 static_cast<Voronoi*>(thiz)->Update(); | |
512 } | |
513 | |
514 // Update the 2d region and flush to make it visible on the page. | |
515 void Voronoi::FlushPixelBuffer() { | |
516 graphics_2d_context_->PaintImageData(*image_data_, pp::Point(0, 0)); | |
517 graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this)); | |
518 } | |
519 | |
520 void Voronoi::Update() { | |
521 // Don't call FlushPixelBuffer() when benchmarking - vsync is enabled by | |
522 // default, and will throttle the benchmark results. | |
523 do { | |
524 UpdateSim(); | |
525 Render(); | |
526 if (!benchmarking_) break; | |
527 --benchmark_frame_counter_; | |
528 } while (benchmark_frame_counter_ > 0); | |
529 if (benchmarking_) | |
530 EndBenchmark(); | |
531 FlushPixelBuffer(); | |
532 } | |
533 | |
534 void Voronoi::CreateContext(const pp::Size& size) { | |
535 const size_t bytes = size.width() * size.height(); | |
binji
2013/05/24 21:47:55
unused
nfullagar1
2013/05/28 23:11:50
good catch
| |
536 graphics_2d_context_ = new pp::Graphics2D(this, size, false); | |
537 if (!BindGraphics(*graphics_2d_context_)) | |
538 printf("Couldn't bind the device context\n"); | |
539 image_data_ = new pp::ImageData(this, | |
540 PP_IMAGEDATAFORMAT_BGRA_PREMUL, | |
541 size, | |
542 false); | |
543 width_ = image_data_->size().width(); | |
544 height_ = image_data_->size().height(); | |
545 stride_in_pixels_ = static_cast<uint32_t>(image_data_->stride() / 4); | |
546 pixel_buffer_ = static_cast<uint32_t*>(image_data_->data()); | |
547 } | |
548 | |
549 void Voronoi::DestroyContext() { | |
550 delete graphics_2d_context_; | |
551 delete image_data_; | |
552 graphics_2d_context_ = NULL; | |
553 image_data_ = NULL; | |
554 width_ = 0; | |
555 height_ = 0; | |
556 stride_in_pixels_ = 0; | |
557 pixel_buffer_ = NULL; | |
558 } | |
559 | |
560 // The Module class. The browser calls the CreateInstance() method to create | |
binji
2013/05/24 21:47:55
kill comment
nfullagar1
2013/05/28 23:11:50
Done.
| |
561 // an instance of you NaCl module on the web page. The browser creates a new | |
562 // instance for each <embed> tag with type="application/x-nacl". | |
563 class VoronoiModule : public pp::Module { | |
564 public: | |
565 VoronoiModule() : pp::Module() {} | |
566 virtual ~VoronoiModule() {} | |
567 | |
568 // Create and return a Voronoi instance. | |
569 virtual pp::Instance* CreateInstance(PP_Instance instance) { | |
570 return new Voronoi(instance); | |
571 } | |
572 }; | |
573 | |
574 // Factory function called by the browser when the module is first loaded. | |
binji
2013/05/24 21:47:55
kill comment
nfullagar1
2013/05/28 23:11:50
Done.
| |
575 // The browser keeps a singleton of this module. It calls the | |
576 // CreateInstance() method on the object you return to make instances. There | |
577 // is one instance per <embed> tag on the page. This is the main binding | |
578 // point for your NaCl module with the browser. | |
579 namespace pp { | |
580 Module* CreateModule() { | |
581 return new VoronoiModule(); | |
582 } | |
583 } // namespace pp | |
584 | |
OLD | NEW |