blob: 3790d5f1126480f20863acfd210489b04385ea26 [file] [log] [blame]
/*
* Copyright 2020 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <webgl/webgl2_ext.h>
#include <GLES3/gl3.h>
GLuint compile_shader(GLenum shaderType, const char *src)
{
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &src, NULL);
glCompileShader(shader);
GLint isCompiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
if (!isCompiled)
{
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
char *buf = (char*)malloc(maxLength);
glGetShaderInfoLog(shader, maxLength, NULL, buf);
printf("%s\n", buf);
free(buf);
return 0;
}
return shader;
}
GLuint create_program(GLuint vertexShader, GLuint fragmentShader)
{
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glBindAttribLocation(program, 0, "apos");
glBindAttribLocation(program, 1, "acolor");
glLinkProgram(program);
return program;
}
#ifndef WEBGL_CONTEXT_VERSION
#define WEBGL_CONTEXT_VERSION 2
#endif
int main()
{
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
EMSCRIPTEN_RESULT res;
EmscriptenWebGLContextAttributes attrs;
emscripten_webgl_init_context_attributes(&attrs);
attrs.majorVersion = WEBGL_CONTEXT_VERSION;
ctx = emscripten_webgl_create_context("#canvas", &attrs);
assert(ctx > 0); // Must have received a valid context.
res = emscripten_webgl_make_context_current(ctx);
assert(res == EMSCRIPTEN_RESULT_SUCCESS);
#ifdef EXPLICIT_SWAP
attrs.explicitSwapControl = 1;
#endif
GLboolean extAvailable = emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(ctx);
extAvailable &= emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(ctx);
if (!extAvailable) {
EM_ASM({
xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8888/report_result?skipped:%20WEBGL_draw_instanced_base_vertex_base_instance%20is%20not%20supported!');
xhr.send();
setTimeout(function() { window.close() }, 2000);
});
return 0;
}
static const char vertex_shader[] =
"#version 300 es\n"
"layout(location=0) in vec4 apos;"
"layout(location=1) in vec4 acolor;"
"layout(location=2) in float icolor;"
"out vec4 color;"
"void main() {"
"color = acolor;"
"color.b = icolor;"
"gl_Position = apos;"
"}";
GLuint vs = compile_shader(GL_VERTEX_SHADER, vertex_shader);
static const char fragment_shader[] =
"#version 300 es\n"
"precision lowp float;"
"in vec4 color;"
"out vec4 o_color;"
"void main() {"
"o_color = color;"
"}";
GLuint fs = compile_shader(GL_FRAGMENT_SHADER, fragment_shader);
GLuint program = create_program(vs, fs);
glUseProgram(program);
static const float pos_and_color[] = {
// x, y, r, g, b
-0.5f, -0.5f, 1, 1, 0,
0.5f, -0.5f, 1, 0, 0,
-0.5f, 0.5f, 0, 1, 0,
0.5f, 0.5f, 0, 0, 0,
-0.5f, 0.5f, 0, 1, 0,
0.5f, -0.5f, 1, 0, 0
};
// 2 -- 3
// | \ |
// | \ |
// 0 -- 1
static const GLushort indices[] = {
0, 1, 2,
2, 1, 0
};
static const float instance_color[] = {
0, 1
};
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(pos_and_color), pos_and_color, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 20, 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 20, (void*)8);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
GLuint ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ARRAY_BUFFER, ibo);
glBufferData(GL_ARRAY_BUFFER, sizeof(instance_color), instance_color, GL_STATIC_DRAW);
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribDivisor(2, 1);
glEnableVertexAttribArray(2);
// use element array buffer
GLuint elementBuffer;
glGenBuffers(1, &elementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glClearColor(0.3f,0.3f,0.3f,1);
GLint firsts[] = {0, 3};
GLsizei counts[] = {3, 3};
GLsizei instanceCounts[] = {1, 1};
const GLvoid* const offsets[] = {(GLvoid*)0, (GLvoid*)(3 * sizeof(GLushort))};
GLint baseVertices[] = {0, 1};
GLuint baseInstances[] = {0, 1};
GLsizei drawcount = 2;
glClear(GL_COLOR_BUFFER_BIT);
#if MULTI_DRAW
#if DRAW_ELEMENTS
glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(GL_TRIANGLES, counts, GL_UNSIGNED_SHORT, offsets, instanceCounts, baseVertices, baseInstances, drawcount);
#else
glMultiDrawArraysInstancedBaseInstanceWEBGL(GL_TRIANGLES, firsts, counts, instanceCounts, baseInstances, drawcount);
#endif
#else
#if DRAW_ELEMENTS
for (GLsizei i = 0; i < drawcount; i++) {
glDrawElementsInstancedBaseVertexBaseInstanceWEBGL(GL_TRIANGLES, counts[i], GL_UNSIGNED_SHORT, offsets[i], instanceCounts[i], baseVertices[i], baseInstances[i]);
}
#else
for (GLsizei i = 0; i < drawcount; i++) {
glDrawArraysInstancedBaseInstanceWEBGL(GL_TRIANGLES, firsts[i], counts[i], instanceCounts[i], baseInstances[i]);
}
#endif
#endif
#ifdef EXPLICIT_SWAP
emscripten_webgl_commit_frame();
#endif
}