Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / examples / demo / life / life.c
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.
4  */
5
6 #include <assert.h>
7 #include <math.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "ppapi/c/pp_resource.h"
13 #include "ppapi/c/ppb_core.h"
14 #include "ppapi/c/ppb_fullscreen.h"
15 #include "ppapi/c/ppb_graphics_2d.h"
16 #include "ppapi/c/ppb_image_data.h"
17 #include "ppapi/c/ppb_input_event.h"
18 #include "ppapi/c/ppb_instance.h"
19 #include "ppapi/c/ppb_view.h"
20
21 #include "ppapi_simple/ps_event.h"
22 #include "ppapi_simple/ps_main.h"
23
24 PPB_Core* g_pCore;
25 PPB_Fullscreen* g_pFullscreen;
26 PPB_Graphics2D* g_pGraphics2D;
27 PPB_ImageData* g_pImageData;
28 PPB_Instance* g_pInstance;
29 PPB_View* g_pView;
30 PPB_InputEvent* g_pInputEvent;
31 PPB_KeyboardInputEvent* g_pKeyboardInput;
32 PPB_MouseInputEvent* g_pMouseInput;
33 PPB_TouchInputEvent* g_pTouchInput;
34
35 struct {
36   PP_Resource ctx;
37   struct PP_Size size;
38   int bound;
39   uint8_t* cell_in;
40   uint8_t* cell_out;
41 } g_Context;
42
43
44 const unsigned int kInitialRandSeed = 0xC0DE533D;
45
46 /* BGRA helper macro, for constructing a pixel for a BGRA buffer. */
47 #define MakeBGRA(b, g, r, a)  \
48   (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
49
50
51 /*
52  * Convert a count value into a live (green) or dead color value.
53  */
54 const uint32_t kNeighborColors[] = {
55     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
56     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
57     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
58     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
59     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
60     MakeBGRA(0x00, 0xFF, 0x00, 0xFF),
61     MakeBGRA(0x00, 0xFF, 0x00, 0xFF),
62     MakeBGRA(0x00, 0xFF, 0x00, 0xFF),
63     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
64     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
65     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
66     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
67     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
68     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
69     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
70     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
71     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
72     MakeBGRA(0x00, 0x00, 0x00, 0xFF),
73 };
74
75 /*
76  * These represent the new health value of a cell based on its neighboring
77  * values.  The health is binary: either alive or dead.
78  */
79 const uint8_t kIsAlive[] = {
80       0, 0, 0, 0, 0, 1, 1, 1, 0,
81       0, 0, 0, 0, 0, 0, 0, 0, 0
82 };
83
84 void UpdateContext(uint32_t width, uint32_t height) {
85   if (width != g_Context.size.width || height != g_Context.size.height) {
86     size_t size = width * height;
87     size_t index;
88
89     free(g_Context.cell_in);
90     free(g_Context.cell_out);
91
92     /* Create a new context */
93     g_Context.cell_in = (uint8_t*) malloc(size);
94     g_Context.cell_out = (uint8_t*) malloc(size);
95
96     memset(g_Context.cell_out, 0, size);
97     for (index = 0; index < size; index++) {
98       g_Context.cell_in[index] = rand() & 1;
99     }
100   }
101
102   /* Recreate the graphics context on a view change */
103   g_pCore->ReleaseResource(g_Context.ctx);
104   g_Context.size.width = width;
105   g_Context.size.height = height;
106   g_Context.ctx =
107       g_pGraphics2D->Create(PSGetInstanceId(), &g_Context.size, PP_TRUE);
108   g_Context.bound =
109       g_pInstance->BindGraphics(PSGetInstanceId(), g_Context.ctx);
110 }
111
112 void DrawCell(int32_t x, int32_t y) {
113   int32_t width = g_Context.size.width;
114   int32_t height = g_Context.size.height;
115
116   if (!g_Context.cell_in) return;
117
118   if (x > 0 && x < width - 1 && y > 0 && y < height - 1) {
119     g_Context.cell_in[x - 1 + y * width] = 1;
120     g_Context.cell_in[x + 1 + y * width] = 1;
121     g_Context.cell_in[x + (y - 1) * width] = 1;
122     g_Context.cell_in[x + (y + 1) * width] = 1;
123   }
124 }
125
126 void ProcessTouchEvent(PSEvent* event) {
127   uint32_t count = g_pTouchInput->GetTouchCount(event->as_resource,
128       PP_TOUCHLIST_TYPE_TOUCHES);
129   uint32_t i, j;
130   for (i = 0; i < count; i++) {
131     struct PP_TouchPoint touch = g_pTouchInput->GetTouchByIndex(
132         event->as_resource, PP_TOUCHLIST_TYPE_TOUCHES, i);
133     int radius = (int)touch.radius.x;
134     int x = (int)touch.position.x;
135     int y = (int)touch.position.y;
136     /* num = 1/100th the area of touch point */
137     int num = (int)(M_PI * radius * radius / 100.0f);
138     for (j = 0; j < num; j++) {
139       int dx = rand() % (radius * 2) - radius;
140       int dy = rand() % (radius * 2) - radius;
141       /* only plot random cells within the touch area */
142       if (dx * dx + dy * dy <= radius * radius)
143         DrawCell(x + dx, y + dy);
144     }
145   }
146 }
147
148 void ProcessEvent(PSEvent* event) {
149   switch(event->type) {
150     /* If the view updates, build a new Graphics 2D Context */
151     case PSE_INSTANCE_DIDCHANGEVIEW: {
152       struct PP_Rect rect;
153
154       g_pView->GetRect(event->as_resource, &rect);
155       UpdateContext(rect.size.width, rect.size.height);
156       break;
157     }
158
159     case PSE_INSTANCE_HANDLEINPUT: {
160       PP_InputEvent_Type type = g_pInputEvent->GetType(event->as_resource);
161       PP_InputEvent_Modifier modifiers =
162           g_pInputEvent->GetModifiers(event->as_resource);
163
164       switch(type) {
165         case PP_INPUTEVENT_TYPE_MOUSEDOWN:
166         case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
167           struct PP_Point location =
168               g_pMouseInput->GetPosition(event->as_resource);
169           /* If the button is down, draw */
170           if (modifiers & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) {
171             DrawCell(location.x, location.y);
172           }
173           break;
174         }
175
176         case PP_INPUTEVENT_TYPE_TOUCHSTART:
177         case PP_INPUTEVENT_TYPE_TOUCHMOVE:
178           ProcessTouchEvent(event);
179           break;
180
181         case PP_INPUTEVENT_TYPE_KEYDOWN: {
182           PP_Bool fullscreen = g_pFullscreen->IsFullscreen(PSGetInstanceId());
183           g_pFullscreen->SetFullscreen(PSGetInstanceId(),
184                                        fullscreen ? PP_FALSE : PP_TRUE);
185           break;
186         }
187
188         default:
189           break;
190       }
191       /* case PSE_INSTANCE_HANDLEINPUT */
192       break;
193     }
194
195     default:
196       break;
197   }
198 }
199
200
201 void Stir(uint32_t width, uint32_t height) {
202   int i;
203   if (g_Context.cell_in == NULL || g_Context.cell_out == NULL)
204     return;
205
206   for (i = 0; i < width; ++i) {
207     g_Context.cell_in[i] = rand() & 1;
208     g_Context.cell_in[i + (height - 1) * width] = rand() & 1;
209   }
210   for (i = 0; i < height; ++i) {
211     g_Context.cell_in[i * width] = rand() & 1;
212     g_Context.cell_in[i * width + (width - 1)] = rand() & 1;
213   }
214 }
215
216 void Render() {
217   struct PP_Size* psize = &g_Context.size;
218   PP_ImageDataFormat format = PP_IMAGEDATAFORMAT_BGRA_PREMUL;
219
220   /*
221    * Create a buffer to draw into.  Since we are waiting until the next flush
222    * chrome has an opportunity to cache this buffer see ppb_graphics_2d.h.
223    */
224   PP_Resource image =
225       g_pImageData->Create(PSGetInstanceId(), format, psize, PP_FALSE);
226   uint8_t* pixels = g_pImageData->Map(image);
227
228   struct PP_ImageDataDesc desc;
229   uint8_t* cell_temp;
230   uint32_t x, y;
231
232   /* If we somehow have not allocated these pointers yet, skip this frame. */
233   if (!g_Context.cell_in || !g_Context.cell_out) return;
234
235   /* Get the stride. */
236   g_pImageData->Describe(image, &desc);
237
238   /* Stir up the edges to prevent the simulation from reaching steady state. */
239   Stir(desc.size.width, desc.size.height);
240
241   /* Do neighbor summation; apply rules, output pixel color. */
242   for (y = 1; y < desc.size.height - 1; ++y) {
243     uint8_t *src0 = (g_Context.cell_in + (y - 1) * desc.size.width) + 1;
244     uint8_t *src1 = src0 + desc.size.width;
245     uint8_t *src2 = src1 + desc.size.width;
246     int count;
247     uint32_t color;
248     uint8_t *dst = (g_Context.cell_out + y * desc.size.width) + 1;
249     uint32_t *pixel_line =  (uint32_t*) (pixels + y * desc.stride);
250
251     for (x = 1; x < (desc.size.width - 1); ++x) {
252       /* Jitter and sum neighbors. */
253       count = src0[-1] + src0[0] + src0[1] +
254               src1[-1] +         + src1[1] +
255               src2[-1] + src2[0] + src2[1];
256       /* Include center cell. */
257       count = count + count + src1[0];
258       /* Use table lookup indexed by count to determine pixel & alive state. */
259       color = kNeighborColors[count];
260       *pixel_line++ = color;
261       *dst++ = kIsAlive[count];
262       ++src0;
263       ++src1;
264       ++src2;
265     }
266   }
267
268   cell_temp = g_Context.cell_in;
269   g_Context.cell_in = g_Context.cell_out;
270   g_Context.cell_out = cell_temp;
271
272   /* Unmap the range, we no longer need it. */
273   g_pImageData->Unmap(image);
274
275   /* Replace the contexts, and block until it's on the screen. */
276   g_pGraphics2D->ReplaceContents(g_Context.ctx, image);
277   g_pGraphics2D->Flush(g_Context.ctx, PP_BlockUntilComplete());
278
279   /* Release the image data, we no longer need it. */
280   g_pCore->ReleaseResource(image);
281 }
282
283 /*
284  * Starting point for the module.  We do not use main since it would
285  * collide with main in libppapi_cpp.
286  */
287 int example_main(int argc, char *argv[]) {
288   fprintf(stdout,"Started main.\n");
289   g_pCore = (PPB_Core*)PSGetInterface(PPB_CORE_INTERFACE);
290   g_pFullscreen = (PPB_Fullscreen*)PSGetInterface(PPB_FULLSCREEN_INTERFACE);
291   g_pGraphics2D = (PPB_Graphics2D*)PSGetInterface(PPB_GRAPHICS_2D_INTERFACE);
292   g_pInstance = (PPB_Instance*)PSGetInterface(PPB_INSTANCE_INTERFACE);
293   g_pImageData = (PPB_ImageData*)PSGetInterface(PPB_IMAGEDATA_INTERFACE);
294   g_pView = (PPB_View*)PSGetInterface(PPB_VIEW_INTERFACE);
295
296   g_pInputEvent =
297       (PPB_InputEvent*) PSGetInterface(PPB_INPUT_EVENT_INTERFACE);
298   g_pKeyboardInput = (PPB_KeyboardInputEvent*)
299       PSGetInterface(PPB_KEYBOARD_INPUT_EVENT_INTERFACE);
300   g_pMouseInput =
301       (PPB_MouseInputEvent*) PSGetInterface(PPB_MOUSE_INPUT_EVENT_INTERFACE);
302   g_pTouchInput =
303       (PPB_TouchInputEvent*) PSGetInterface(PPB_TOUCH_INPUT_EVENT_INTERFACE);
304
305   PSEventSetFilter(PSE_ALL);
306   while (1) {
307     /* Process all waiting events without blocking */
308     PSEvent* event;
309     while ((event = PSEventTryAcquire()) != NULL) {
310       ProcessEvent(event);
311       PSEventRelease(event);
312     }
313
314     /* Render a frame, blocking until complete. */
315     if (g_Context.bound) {
316       Render();
317     }
318   }
319   return 0;
320 }
321
322 /*
323  * Register the function to call once the Instance Object is initialized.
324  * see: pappi_simple/ps_main.h
325  */
326 PPAPI_SIMPLE_REGISTER_MAIN(example_main);