6
#include <emscripten.h>
8
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
10
static const int WINDOWS_SIZE = 500;
12
static GLfloat vertices[] = { 0.0f, 250.f, 0.0f,
14
250.f, -250.f, 0.0f };
16
static GLfloat vertices2[] = { 0.0f, 250.f, -1.0f,
17
-250.f, -250.f, -1.0f,
18
250.f, -250.f, -1.0f };
20
static GLuint shaderProgram = 0;
21
static GLuint verticesVBO = 0;
22
static GLuint verticesVBO2 = 0;
24
static unsigned char backgroundColor[4] = {255, 255, 255, 255};
25
static unsigned char triangleColor[4] = {255, 0, 0, 255};
26
static unsigned char triangleColor2[4] = {0, 255, 0, 255};
28
static char vertexShaderSrc[] =
29
"precision highp float;"
30
"precision highp int;"
32
"uniform mat4 u_mvpMatrix;"
33
"uniform vec4 u_color;"
35
"attribute vec3 a_position;"
37
"varying vec4 v_color;"
40
" gl_Position = u_mvpMatrix * vec4(a_position, 1.0);"
45
static char fragmentShaderSrc[] =
46
"precision highp float;"
47
"precision highp int;"
49
"varying vec4 v_color;"
52
" gl_FragColor = v_color;"
56
static GLuint createShader(const char *source, int type) {
57
GLuint shader = glCreateShader(type);
58
glShaderSource(shader, 1, (const GLchar**)(&source), NULL);
59
glCompileShader(shader);
63
static GLuint createShaderProgram(const char *vertexShaderSrc, const char *fragmentShaderSrc) {
64
GLuint program = glCreateProgram();
65
glAttachShader(program, createShader(vertexShaderSrc, GL_VERTEX_SHADER));
66
glAttachShader(program, createShader(fragmentShaderSrc, GL_FRAGMENT_SHADER));
67
glLinkProgram(program);
71
void ortho(float left, float right, float bottom, float top, float nearVal, float farVal, GLfloat *projMatrix) {
72
float tx = -(right+left)/(right-left);
73
float ty = -(top+bottom)/(top-bottom);
74
float tz = -(farVal+nearVal)/(farVal-nearVal);
75
memset(projMatrix, 0, 16 * sizeof(GLfloat));
76
projMatrix[0] = 2.0f / (right-left);
78
projMatrix[1*4+1] = 2.0f / (top-bottom);
79
projMatrix[1*4+3] = ty;
80
projMatrix[2*4+2] = -2.0f / (farVal-nearVal);
81
projMatrix[2*4+3] = tz;
82
projMatrix[3*4+3] = 1.0f;
85
static void initGlObjects() {
86
glGenBuffers(1, &verticesVBO);
87
glBindBuffer(GL_ARRAY_BUFFER, verticesVBO);
88
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), vertices, GL_STATIC_DRAW);
89
glBindBuffer(GL_ARRAY_BUFFER, 0);
91
glGenBuffers(1, &verticesVBO2);
92
glBindBuffer(GL_ARRAY_BUFFER, verticesVBO2);
93
glBufferData(GL_ARRAY_BUFFER, 9*sizeof(float), vertices2, GL_STATIC_DRAW);
94
glBindBuffer(GL_ARRAY_BUFFER, 0);
96
shaderProgram = createShaderProgram(vertexShaderSrc, fragmentShaderSrc);
99
static void drawTriangle(GLuint verticesVBO, unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
100
glUseProgram(shaderProgram);
101
GLuint posLoc = glGetAttribLocation(shaderProgram, "a_position");
102
GLuint mvpLoc = glGetUniformLocation(shaderProgram, "u_mvpMatrix");
103
GLuint colorLoc = glGetUniformLocation(shaderProgram, "u_color");
106
ortho(-WINDOWS_SIZE/2, WINDOWS_SIZE/2, -WINDOWS_SIZE/2, WINDOWS_SIZE/2, -100, 100, mvpMat);
108
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, mvpMat);
109
glUniform4f(colorLoc, r/255.f, g/255.f, b/255.f, a/255.f);
111
glBindBuffer(GL_ARRAY_BUFFER, verticesVBO);
112
glEnableVertexAttribArray(posLoc);
113
glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), BUFFER_OFFSET(0));
115
glDrawArrays(GL_TRIANGLES, 0, 3);
117
glBindBuffer(GL_ARRAY_BUFFER, 0);
121
// Draw a red triangle on a white background. If antialiasing is disabled, resulting pixels
122
// will only have white and red colors. If antialiasing is enabled, there will be pixels
123
// whose color is different from red and white.
124
static int testAntiAliasing(bool activated) {
125
glViewport(0, 0, WINDOWS_SIZE, WINDOWS_SIZE);
126
glClearColor(backgroundColor[0]/255.f, backgroundColor[1]/255.f, backgroundColor[2]/255.f, backgroundColor[3]/255.f);
127
glClear(GL_COLOR_BUFFER_BIT);
129
drawTriangle(verticesVBO, triangleColor[0], triangleColor[1], triangleColor[2], triangleColor[3]);
131
bool antialiased = false;
133
unsigned char buffer[(WINDOWS_SIZE*WINDOWS_SIZE)*4];
134
glReadPixels(0, 0, WINDOWS_SIZE, WINDOWS_SIZE, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
136
for (unsigned int i = 0 ; i < WINDOWS_SIZE ; ++i) {
137
for (unsigned int j = 0 ; j < WINDOWS_SIZE ; ++j) {
138
unsigned char r = buffer[4*(i*WINDOWS_SIZE+j)];
139
unsigned char g = buffer[4*(i*WINDOWS_SIZE+j)+1];
140
unsigned char b = buffer[4*(i*WINDOWS_SIZE+j)+2];
141
unsigned char a = buffer[4*(i*WINDOWS_SIZE+j)+3];
142
if ((r == backgroundColor[0] && g == backgroundColor[1] && b == backgroundColor[2] && a == backgroundColor[3]) ||
143
(r == triangleColor[0] && g == triangleColor[1] && b == triangleColor[2] && a == triangleColor[3])) {
152
return (activated && antialiased) || (!activated && !antialiased);
155
// Draw a red triangle with depth equals to 0 then a green triangle whose depth equals -1.
156
// If there is an attached depth buffer, the resulting image will be a red triangle. If not,
157
// the resulting image will be a green triangle.
158
static int testDepth(bool activated) {
159
glViewport(0, 0, WINDOWS_SIZE, WINDOWS_SIZE);
160
glClearColor(backgroundColor[0]/255.f, backgroundColor[1]/255.f, backgroundColor[2]/255.f, backgroundColor[3]/255.f);
161
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
163
glEnable(GL_DEPTH_TEST);
164
glDepthFunc(GL_LEQUAL);
166
drawTriangle(verticesVBO, triangleColor[0], triangleColor[1], triangleColor[2], triangleColor[3]);
167
drawTriangle(verticesVBO2, triangleColor2[0], triangleColor2[1], triangleColor2[2], triangleColor2[3]);
169
glDisable(GL_DEPTH_TEST);
171
// read the pixel at the center of the resulting image.
172
unsigned char buffer[4];
173
glReadPixels(WINDOWS_SIZE/2, WINDOWS_SIZE/2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
175
bool frontTriangleColor = (buffer[0] == triangleColor[0] && buffer[1] == triangleColor[1] &&
176
buffer[2] == triangleColor[2] && buffer[3] == triangleColor[3]);
178
bool backTriangleColor = (buffer[0] == triangleColor2[0] && buffer[1] == triangleColor2[1] &&
179
buffer[2] == triangleColor2[2] && buffer[3] == triangleColor2[3]);
181
return (activated && frontTriangleColor) || (!activated && backTriangleColor);
184
// The stencil function is set to GL_LEQUAL so fragments will be written to the
185
// back buffer only if the ref value is less or equal than the one in the stencil buffer.
186
// The content of the stencil buffer is initialized to 0xFF.
187
// First draw a red triangle whose stencil ref value is 0x1.
188
// Then draw a green triangle whose stencil ref value is 0xFF.
189
// If there is an attached stencil buffer, the resulting image will be a red triangle. If not,
190
// the resulting image will be a green triangle.
191
static int testStencil(bool activated) {
192
glViewport(0, 0, WINDOWS_SIZE, WINDOWS_SIZE);
193
glClearColor(backgroundColor[0]/255.f, backgroundColor[1]/255.f, backgroundColor[2]/255.f, backgroundColor[3]/255.f);
194
glClearStencil(0xFF);
195
glStencilOp(GL_KEEP,GL_KEEP,GL_REPLACE);
196
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
198
glEnable(GL_STENCIL_TEST);
200
glStencilFunc(GL_LEQUAL, 0x1, 0xFF);
201
drawTriangle(verticesVBO, triangleColor[0], triangleColor[1], triangleColor[2], triangleColor[3]);
203
glStencilFunc(GL_LEQUAL, 0xFF, 0xFF);
204
drawTriangle(verticesVBO, triangleColor2[0], triangleColor2[1], triangleColor2[2], triangleColor2[3]);
206
glDisable(GL_STENCIL_TEST);
208
unsigned char buffer[4];
209
glReadPixels(WINDOWS_SIZE/2, WINDOWS_SIZE/2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
211
bool firstTriangleColor = (buffer[0] == triangleColor[0] && buffer[1] == triangleColor[1] &&
212
buffer[2] == triangleColor[2] && buffer[3] == triangleColor[3]);
214
bool secondTriangleColor = (buffer[0] == triangleColor2[0] && buffer[1] == triangleColor2[1] &&
215
buffer[2] == triangleColor2[2] && buffer[3] == triangleColor2[3]);
217
return (activated && firstTriangleColor) || (!activated && secondTriangleColor);
220
static bool antiAliasingActivated = false;
221
static bool depthActivated = false;
222
static bool stencilActivated = false;
224
static int result = 0;
225
static int resultAA = 0;
226
static int resultDepth = 0;
227
static int resultStencil = 0;
231
if (!resultAA) resultAA = testAntiAliasing(antiAliasingActivated);
233
if (!resultDepth) resultDepth = testDepth(depthActivated);
235
if (!resultStencil) resultStencil = testStencil(stencilActivated);
237
result = resultAA && resultDepth && resultStencil;
241
extern int webglAntialiasSupported(void);
242
extern int webglDepthSupported(void);
243
extern int webglStencilSupported(void);
245
// Check attributes support in the WebGL implementation (see test_webgl_context_attributes function in test_browser.py)
246
// Tests will succeed if they are not.
247
static void checkContextAttributesSupport() {
248
if (!webglAntialiasSupported()) {
250
EM_ASM(alert('warning: no antialiasing\n'));
252
if (!webglDepthSupported()) {
254
EM_ASM(alert('warning: no depth\n'));
256
if (!webglStencilSupported()) {
258
EM_ASM(alert('warning: no stencil\n'));