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.
13 #include "ppapi/cpp/graphics_3d.h"
14 #include "ppapi/cpp/instance.h"
15 #include "ppapi/cpp/module.h"
16 #include "ppapi/cpp/var.h"
17 #include "ppapi/cpp/var_array.h"
18 #include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
19 #include "ppapi/utility/completion_callback_factory.h"
23 // Allow 'this' in initializer list
24 #pragma warning(disable : 4355)
27 extern const uint8_t kRLETextureData
[];
28 extern const size_t kRLETextureDataLength
;
32 const float kFovY
= 45.0f
;
33 const float kZNear
= 1.0f
;
34 const float kZFar
= 10.0f
;
35 const float kCameraZ
= -4.0f
;
36 const float kXAngleDelta
= 2.0f
;
37 const float kYAngleDelta
= 0.5f
;
39 const size_t kTextureDataLength
= 128 * 128 * 3; // 128x128, 3 Bytes/pixel.
41 // The decompressed data is written here.
42 uint8_t g_texture_data
[kTextureDataLength
];
44 void DecompressTexture() {
45 // The image is first encoded with a very simple RLE scheme:
46 // <value0> <count0> <value1> <count1> ...
47 // Because a <count> of 0 is useless, we use it to represent 256.
49 // It is then Base64 encoded to make it use only printable characters (it
50 // stores more easily in a source file that way).
52 // To decompress, we have to reverse the process.
53 static const uint8_t kBase64Decode
[256] = {
54 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
57 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0,
58 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
59 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
60 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
61 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
63 const uint8_t* input
= &kRLETextureData
[0];
64 const uint8_t* const input_end
= &kRLETextureData
[kRLETextureDataLength
];
65 uint8_t* output
= &g_texture_data
[0];
67 const uint8_t* const output_end
= &g_texture_data
[kTextureDataLength
];
71 int decoded_count
= 0;
73 while (input
< input_end
|| decoded_count
> 0) {
74 if (decoded_count
< 2) {
75 assert(input
+ 4 <= input_end
);
76 // Grab four base-64 encoded (6-bit) bytes.
78 data
|= (kBase64Decode
[*input
++] << 18);
79 data
|= (kBase64Decode
[*input
++] << 12);
80 data
|= (kBase64Decode
[*input
++] << 6);
81 data
|= (kBase64Decode
[*input
++] );
82 // And decode it to 3 (8-bit) bytes.
83 decoded
[decoded_count
++] = (data
>> 16) & 0xff;
84 decoded
[decoded_count
++] = (data
>> 8) & 0xff;
85 decoded
[decoded_count
++] = (data
) & 0xff;
87 // = is the base64 end marker. Remove decoded bytes if we see any.
88 if (input
[-1] == '=') decoded_count
--;
89 if (input
[-2] == '=') decoded_count
--;
92 int value
= decoded
[0];
93 int count
= decoded
[1];
95 // Move the other decoded bytes (if any) down.
96 decoded
[0] = decoded
[2];
97 decoded
[1] = decoded
[3];
99 // Expand the RLE data.
102 assert(output
<= output_end
);
103 memset(output
, value
, count
);
106 assert(output
== output_end
);
109 GLuint
CompileShader(GLenum type
, const char* data
) {
110 GLuint shader
= glCreateShader(type
);
111 glShaderSource(shader
, 1, &data
, NULL
);
112 glCompileShader(shader
);
114 GLint compile_status
;
115 glGetShaderiv(shader
, GL_COMPILE_STATUS
, &compile_status
);
116 if (compile_status
!= GL_TRUE
) {
117 // Shader failed to compile, let's see what the error is.
120 glGetShaderInfoLog(shader
, sizeof(buffer
), &length
, &buffer
[0]);
121 fprintf(stderr
, "Shader failed to compile: %s\n", buffer
);
128 GLuint
LinkProgram(GLuint frag_shader
, GLuint vert_shader
) {
129 GLuint program
= glCreateProgram();
130 glAttachShader(program
, frag_shader
);
131 glAttachShader(program
, vert_shader
);
132 glLinkProgram(program
);
135 glGetProgramiv(program
, GL_LINK_STATUS
, &link_status
);
136 if (link_status
!= GL_TRUE
) {
137 // Program failed to link, let's see what the error is.
140 glGetProgramInfoLog(program
, sizeof(buffer
), &length
, &buffer
[0]);
141 fprintf(stderr
, "Program failed to link: %s\n", buffer
);
148 const char kFragShaderSource
[] =
149 "precision mediump float;\n"
150 "varying vec3 v_color;\n"
151 "varying vec2 v_texcoord;\n"
152 "uniform sampler2D u_texture;\n"
154 " gl_FragColor = texture2D(u_texture, v_texcoord);\n"
155 " gl_FragColor += vec4(v_color, 1);\n"
158 const char kVertexShaderSource
[] =
159 "uniform mat4 u_mvp;\n"
160 "attribute vec2 a_texcoord;\n"
161 "attribute vec3 a_color;\n"
162 "attribute vec4 a_position;\n"
163 "varying vec3 v_color;\n"
164 "varying vec2 v_texcoord;\n"
166 " gl_Position = u_mvp * a_position;\n"
167 " v_color = a_color;\n"
168 " v_texcoord = a_texcoord;\n"
177 const Vertex kCubeVerts
[24] = {
178 // +Z (red arrow, black tip)
179 {{-1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {1.0, 0.0}},
180 {{+1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0}},
181 {{+1.0, +1.0, +1.0}, {0.5, 0.0, 0.0}, {0.0, 1.0}},
182 {{-1.0, +1.0, +1.0}, {0.5, 0.0, 0.0}, {1.0, 1.0}},
184 // +X (green arrow, black tip)
185 {{+1.0, -1.0, -1.0}, {0.0, 0.0, 0.0}, {1.0, 0.0}},
186 {{+1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0}},
187 {{+1.0, +1.0, +1.0}, {0.0, 0.5, 0.0}, {0.0, 1.0}},
188 {{+1.0, -1.0, +1.0}, {0.0, 0.5, 0.0}, {1.0, 1.0}},
190 // +Y (blue arrow, black tip)
191 {{-1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {1.0, 0.0}},
192 {{-1.0, +1.0, +1.0}, {0.0, 0.0, 0.0}, {0.0, 0.0}},
193 {{+1.0, +1.0, +1.0}, {0.0, 0.0, 0.5}, {0.0, 1.0}},
194 {{+1.0, +1.0, -1.0}, {0.0, 0.0, 0.5}, {1.0, 1.0}},
196 // -Z (red arrow, red tip)
197 {{+1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {1.0, 1.0}},
198 {{-1.0, +1.0, -1.0}, {0.0, 0.0, 0.0}, {0.0, 1.0}},
199 {{-1.0, -1.0, -1.0}, {1.0, 0.0, 0.0}, {0.0, 0.0}},
200 {{+1.0, -1.0, -1.0}, {1.0, 0.0, 0.0}, {1.0, 0.0}},
202 // -X (green arrow, green tip)
203 {{-1.0, +1.0, +1.0}, {0.0, 0.0, 0.0}, {1.0, 1.0}},
204 {{-1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {0.0, 1.0}},
205 {{-1.0, -1.0, -1.0}, {0.0, 1.0, 0.0}, {0.0, 0.0}},
206 {{-1.0, +1.0, -1.0}, {0.0, 1.0, 0.0}, {1.0, 0.0}},
208 // -Y (blue arrow, blue tip)
209 {{+1.0, -1.0, +1.0}, {0.0, 0.0, 0.0}, {1.0, 1.0}},
210 {{+1.0, -1.0, -1.0}, {0.0, 0.0, 0.0}, {0.0, 1.0}},
211 {{-1.0, -1.0, -1.0}, {0.0, 0.0, 1.0}, {0.0, 0.0}},
212 {{-1.0, -1.0, +1.0}, {0.0, 0.0, 1.0}, {1.0, 0.0}},
215 const GLubyte kCubeIndexes
[36] = {
219 14, 13, 12, 15, 14, 12,
220 18, 17, 16, 19, 18, 16,
221 22, 21, 20, 23, 22, 20,
227 class Graphics3DInstance
: public pp::Instance
{
229 explicit Graphics3DInstance(PP_Instance instance
)
230 : pp::Instance(instance
),
231 callback_factory_(this),
245 virtual bool Init(uint32_t argc
, const char* argn
[], const char* argv
[]) {
249 virtual void DidChangeView(const pp::View
& view
) {
250 // Pepper specifies dimensions in DIPs (device-independent pixels). To
251 // generate a context that is at device-pixel resolution on HiDPI devices,
252 // scale the dimensions by view.GetDeviceScale().
253 int32_t new_width
= view
.GetRect().width() * view
.GetDeviceScale();
254 int32_t new_height
= view
.GetRect().height() * view
.GetDeviceScale();
256 if (context_
.is_null()) {
257 if (!InitGL(new_width
, new_height
)) {
267 // Resize the buffers to the new size of the module.
268 int32_t result
= context_
.ResizeBuffers(new_width
, new_height
);
271 "Unable to resize buffers to %d x %d!\n",
279 height_
= new_height
;
280 glViewport(0, 0, width_
, height_
);
283 virtual void HandleMessage(const pp::Var
& message
) {
284 // A bool message sets whether the cube is animating or not.
285 if (message
.is_bool()) {
286 animating_
= message
.AsBool();
290 // An array message sets the current x and y rotation.
291 if (!message
.is_array()) {
292 fprintf(stderr
, "Expected array message.\n");
296 pp::VarArray
array(message
);
297 if (array
.GetLength() != 2) {
298 fprintf(stderr
, "Expected array of length 2.\n");
302 pp::Var x_angle_var
= array
.Get(0);
303 if (x_angle_var
.is_int()) {
304 x_angle_
= x_angle_var
.AsInt();
305 } else if (x_angle_var
.is_double()) {
306 x_angle_
= x_angle_var
.AsDouble();
308 fprintf(stderr
, "Expected value to be an int or double.\n");
311 pp::Var y_angle_var
= array
.Get(1);
312 if (y_angle_var
.is_int()) {
313 y_angle_
= y_angle_var
.AsInt();
314 } else if (y_angle_var
.is_double()) {
315 y_angle_
= y_angle_var
.AsDouble();
317 fprintf(stderr
, "Expected value to be an int or double.\n");
322 bool InitGL(int32_t new_width
, int32_t new_height
) {
323 if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) {
324 fprintf(stderr
, "Unable to initialize GL PPAPI!\n");
328 const int32_t attrib_list
[] = {
329 PP_GRAPHICS3DATTRIB_ALPHA_SIZE
, 8,
330 PP_GRAPHICS3DATTRIB_DEPTH_SIZE
, 24,
331 PP_GRAPHICS3DATTRIB_WIDTH
, new_width
,
332 PP_GRAPHICS3DATTRIB_HEIGHT
, new_height
,
333 PP_GRAPHICS3DATTRIB_NONE
336 context_
= pp::Graphics3D(this, attrib_list
);
337 if (!BindGraphics(context_
)) {
338 fprintf(stderr
, "Unable to bind 3d context!\n");
339 context_
= pp::Graphics3D();
340 glSetCurrentContextPPAPI(0);
344 glSetCurrentContextPPAPI(context_
.pp_resource());
349 frag_shader_
= CompileShader(GL_FRAGMENT_SHADER
, kFragShaderSource
);
353 vertex_shader_
= CompileShader(GL_VERTEX_SHADER
, kVertexShaderSource
);
357 program_
= LinkProgram(frag_shader_
, vertex_shader_
);
361 texture_loc_
= glGetUniformLocation(program_
, "u_texture");
362 position_loc_
= glGetAttribLocation(program_
, "a_position");
363 texcoord_loc_
= glGetAttribLocation(program_
, "a_texcoord");
364 color_loc_
= glGetAttribLocation(program_
, "a_color");
365 mvp_loc_
= glGetUniformLocation(program_
, "u_mvp");
369 glGenBuffers(1, &vertex_buffer_
);
370 glBindBuffer(GL_ARRAY_BUFFER
, vertex_buffer_
);
371 glBufferData(GL_ARRAY_BUFFER
, sizeof(kCubeVerts
), &kCubeVerts
[0],
374 glGenBuffers(1, &index_buffer_
);
375 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, index_buffer_
);
376 glBufferData(GL_ELEMENT_ARRAY_BUFFER
, sizeof(kCubeIndexes
),
377 &kCubeIndexes
[0], GL_STATIC_DRAW
);
382 glGenTextures(1, &texture_
);
383 glBindTexture(GL_TEXTURE_2D
, texture_
);
384 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
385 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
386 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
387 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
388 glTexImage2D(GL_TEXTURE_2D
,
401 x_angle_
= fmod(360.0f
+ x_angle_
+ kXAngleDelta
, 360.0f
);
402 y_angle_
= fmod(360.0f
+ y_angle_
+ kYAngleDelta
, 360.0f
);
404 // Send new values to JavaScript.
407 array
.Set(0, x_angle_
);
408 array
.Set(1, y_angle_
);
414 glClearColor(0.5, 0.5, 0.5, 1);
416 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
417 glEnable(GL_DEPTH_TEST
);
419 //set what program to use
420 glUseProgram(program_
);
421 glActiveTexture(GL_TEXTURE0
);
422 glBindTexture(GL_TEXTURE_2D
, texture_
);
423 glUniform1i(texture_loc_
, 0);
425 //create our perspective matrix
430 identity_matrix(mvp
);
431 const float aspect_ratio
= static_cast<float>(width_
) / height_
;
432 glhPerspectivef2(&mvp
[0], kFovY
, aspect_ratio
, kZNear
, kZFar
);
434 translate_matrix(0, 0, kCameraZ
, trs
);
435 rotate_matrix(x_angle_
, y_angle_
, 0.0f
, rot
);
436 multiply_matrix(trs
, rot
, trs
);
437 multiply_matrix(mvp
, trs
, mvp
);
438 glUniformMatrix4fv(mvp_loc_
, 1, GL_FALSE
, mvp
);
440 //define the attributes of the vertex
441 glBindBuffer(GL_ARRAY_BUFFER
, vertex_buffer_
);
442 glVertexAttribPointer(position_loc_
,
447 reinterpret_cast<void*>(offsetof(Vertex
, loc
)));
448 glEnableVertexAttribArray(position_loc_
);
449 glVertexAttribPointer(color_loc_
,
454 reinterpret_cast<void*>(offsetof(Vertex
, color
)));
455 glEnableVertexAttribArray(color_loc_
);
456 glVertexAttribPointer(texcoord_loc_
,
461 reinterpret_cast<void*>(offsetof(Vertex
, tex
)));
462 glEnableVertexAttribArray(texcoord_loc_
);
464 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, index_buffer_
);
465 glDrawElements(GL_TRIANGLES
, 36, GL_UNSIGNED_BYTE
, 0);
468 void MainLoop(int32_t) {
471 context_
.SwapBuffers(
472 callback_factory_
.NewCallback(&Graphics3DInstance::MainLoop
));
475 pp::CompletionCallbackFactory
<Graphics3DInstance
> callback_factory_
;
476 pp::Graphics3D context_
;
480 GLuint vertex_shader_
;
482 GLuint vertex_buffer_
;
483 GLuint index_buffer_
;
487 GLuint position_loc_
;
488 GLuint texcoord_loc_
;
497 class Graphics3DModule
: public pp::Module
{
499 Graphics3DModule() : pp::Module() {}
500 virtual ~Graphics3DModule() {}
502 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
503 return new Graphics3DInstance(instance
);
508 Module
* CreateModule() { return new Graphics3DModule(); }