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