Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
2,121 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
# webassembly-webgl-shaders | ||
Demo project for using WebGL shaders in WebAssembly | ||
WebAssembly WebGL demo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
#include "Context.h" | ||
|
||
// Shaders | ||
std::string vertex_source = | ||
"attribute vec4 position; \n" | ||
"attribute vec2 texCoord; \n" | ||
"varying vec2 v_texCoord; \n" | ||
"void main() \n" | ||
"{ \n" | ||
" gl_Position = position; \n" | ||
" v_texCoord = texCoord; \n" | ||
"} \n"; | ||
|
||
std::string texture_load_fragment_source = | ||
"precision mediump float; \n" | ||
"varying vec2 v_texCoord; \n" | ||
"uniform sampler2D texture; \n" | ||
"void main() \n" | ||
"{ \n" | ||
" gl_FragColor = texture2D( texture, v_texCoord ); \n" | ||
"} \n"; | ||
|
||
|
||
std::string edge_detect_fragment_source = | ||
"precision mediump float; \n" | ||
"varying vec2 v_texCoord; \n" | ||
"uniform sampler2D texture; \n" | ||
"uniform float width; \n" | ||
"uniform float height; \n" | ||
"void main() \n" | ||
"{ \n" | ||
" vec4 pixel = texture2D(texture, v_texCoord); \n" | ||
" vec4 n[9];\n" | ||
|
||
" float w = 1.0 / width;\n" | ||
" float h = 1.0 / height;\n" | ||
|
||
" n[0] = texture2D(texture, v_texCoord + vec2(0.0, 0.0) );\n" | ||
" n[1] = texture2D(texture, v_texCoord + vec2(w, 0.0) );\n" | ||
" n[2] = texture2D(texture, v_texCoord + vec2(2.0*w, 0.0) );\n" | ||
" n[3] = texture2D(texture, v_texCoord + vec2(0.0*w, h) );\n" | ||
" n[4] = texture2D(texture, v_texCoord + vec2(w, h) );\n" | ||
" n[5] = texture2D(texture, v_texCoord + vec2(2.0*w, h) );\n" | ||
" n[6] = texture2D(texture, v_texCoord + vec2(0.0, 2.0*h) );\n" | ||
" n[7] = texture2D(texture, v_texCoord + vec2(w, 2.0*h) );\n" | ||
" n[8] = texture2D(texture, v_texCoord + vec2(2.0*w, 2.0*h) );\n" | ||
|
||
" vec4 sobel_x = n[2] + (2.0*n[5]) + n[8] - (n[0] + (2.0*n[3]) + n[6]);\n" | ||
" vec4 sobel_y = n[0] + (2.0*n[1]) + n[2] - (n[6] + (2.0*n[7]) + n[8]);\n" | ||
|
||
" float avg_x = (sobel_x.r + sobel_x.g + sobel_x.b) / 3.0;\n" | ||
" float avg_y = (sobel_y.r + sobel_y.g + sobel_y.b) / 3.0;\n" | ||
|
||
" sobel_x.r = avg_x;\n" | ||
" sobel_x.g = avg_x;\n" | ||
" sobel_x.b = avg_x;\n" | ||
" sobel_y.r = avg_y;\n" | ||
" sobel_y.g = avg_y;\n" | ||
" sobel_y.b = avg_y;\n" | ||
|
||
" vec3 sobel = vec3(sqrt((sobel_x.rgb * sobel_x.rgb) + (sobel_y.rgb * sobel_y.rgb)));\n" | ||
" gl_FragColor = vec4( sobel, 1.0 ); \n" | ||
"} \n"; | ||
|
||
|
||
|
||
GLuint CompileShader (GLenum type, std::string *source) { | ||
|
||
// Create shader object | ||
const GLchar* sourceString[1]; | ||
GLint sourceStringLengths[1]; | ||
|
||
sourceString[0] = source->c_str(); | ||
sourceStringLengths[0] = source->length(); | ||
GLuint shader = glCreateShader(type); | ||
|
||
if (shader == 0) { | ||
return 0; | ||
} | ||
|
||
// Assign and compile the source to the shader object | ||
glShaderSource(shader, 1, sourceString, sourceStringLengths); | ||
glCompileShader(shader); | ||
|
||
// Check if there were errors | ||
int infoLen = 0; | ||
glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &infoLen ); | ||
|
||
if (infoLen > 1) { | ||
|
||
char infoLog[infoLen]; | ||
|
||
// And print them out | ||
glGetShaderInfoLog( shader, infoLen, NULL, infoLog ); | ||
printf("%s\n", infoLog); | ||
|
||
free ( infoLog ); | ||
} | ||
|
||
return shader; | ||
} | ||
|
||
|
||
Context::Context (int w, int h, char * id) { | ||
|
||
width = w; | ||
height = h; | ||
|
||
// Context configurations | ||
EmscriptenWebGLContextAttributes attrs; | ||
attrs.explicitSwapControl = 0; | ||
attrs.depth = 1; | ||
attrs.stencil = 1; | ||
attrs.antialias = 1; | ||
attrs.majorVersion = 2; | ||
attrs.minorVersion = 0; | ||
|
||
context = emscripten_webgl_create_context(id, &attrs); | ||
emscripten_webgl_make_context_current(context); | ||
|
||
// Compile shaders | ||
if (std::string(id) == "textureLoad") { | ||
fragmentShader = CompileShader(GL_FRAGMENT_SHADER, &texture_load_fragment_source); | ||
vertexShader = CompileShader(GL_VERTEX_SHADER, &vertex_source); | ||
|
||
} else if (std::string(id) == "edgeDetect") { | ||
fragmentShader = CompileShader(GL_FRAGMENT_SHADER, &edge_detect_fragment_source); | ||
vertexShader = CompileShader(GL_VERTEX_SHADER, &vertex_source); | ||
} | ||
|
||
// Build program | ||
programObject = glCreateProgram(); | ||
|
||
glAttachShader(programObject, vertexShader); | ||
glAttachShader(programObject, fragmentShader); | ||
|
||
glBindAttribLocation(programObject, 0, "position"); | ||
|
||
glLinkProgram(programObject); | ||
glValidateProgram(programObject); | ||
} | ||
|
||
Context::~Context (void) { | ||
emscripten_webgl_destroy_context(context); | ||
} | ||
|
||
|
||
void Context::run (uint8_t* buffer) { | ||
|
||
// Make the context current and use the program | ||
emscripten_webgl_make_context_current(context); | ||
glUseProgram( programObject ); | ||
|
||
GLuint texId; | ||
GLuint vertexObject; | ||
GLuint indexObject; | ||
|
||
// Get the attribute/sampler locations | ||
GLint positionLoc = glGetAttribLocation(programObject, "position"); | ||
GLint texCoordLoc = glGetAttribLocation(programObject, "texCoord"); | ||
GLint textureLoc = glGetUniformLocation(programObject, "texture"); | ||
|
||
// For "ERROR :GL_INVALID_OPERATION : glUniform1i: wrong uniform function for type" | ||
// https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glUniform.xhtml | ||
float widthUniform = glGetUniformLocation(programObject, "width"); | ||
float heightUniform = glGetUniformLocation(programObject, "height"); | ||
glUniform1f(widthUniform, (float) width); | ||
glUniform1f(heightUniform, (float) height); | ||
|
||
|
||
// Generate a texture object | ||
glGenTextures(1, &texId); | ||
glUniform1i(textureLoc, 0); | ||
|
||
// Bind it | ||
glActiveTexture(GL_TEXTURE0); | ||
glBindTexture(GL_TEXTURE_2D, texId); | ||
|
||
// Load the texture from the image buffer | ||
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); | ||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
|
||
// Vertex data of texture bounds | ||
GLfloat vVertices[] = { -1.0, 1.0, 0.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0, 1.0, | ||
1.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0}; | ||
GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; | ||
|
||
glGenBuffers(1, &vertexObject); | ||
glBindBuffer(GL_ARRAY_BUFFER, vertexObject); | ||
glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices), vVertices, GL_STATIC_DRAW); | ||
|
||
glGenBuffers(1, &indexObject); | ||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexObject); | ||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); | ||
|
||
// Set the viewport | ||
glViewport(0, 0, width, height); | ||
glClear(GL_COLOR_BUFFER_BIT); | ||
|
||
// Load and enable the vertex position and texture coordinates | ||
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0); | ||
glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*) (3 * sizeof(GLfloat))); | ||
|
||
glEnableVertexAttribArray(positionLoc); | ||
glEnableVertexAttribArray(texCoordLoc); | ||
|
||
// Draw | ||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
|
||
|
||
class Context { | ||
public: | ||
Context (int width, int height, char * id); | ||
|
||
~Context (void); | ||
|
||
void run (uint8_t* buffer); | ||
|
||
private: | ||
int width; | ||
int height; | ||
|
||
GLuint programObject; | ||
GLuint vertexShader; | ||
GLuint fragmentShader; | ||
|
||
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context; | ||
|
||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#include <emscripten.h> | ||
#include <string> | ||
#include <GLES2/gl2.h> | ||
#include <EGL/egl.h> | ||
extern "C" { | ||
#include "html5.h" | ||
} | ||
#include "Context.cpp" | ||
|
||
Context* contexts[2]; | ||
|
||
int main(int argc, char const *argv[]) { | ||
printf("[WASM] Loaded\n"); | ||
|
||
EM_ASM( | ||
if (typeof window!="undefined") { | ||
window.dispatchEvent(new CustomEvent("wasmLoaded")) | ||
} else { | ||
global.onWASMLoaded && global.onWASMLoaded() | ||
} | ||
); | ||
|
||
return 0; | ||
} | ||
|
||
|
||
extern "C" { | ||
|
||
EMSCRIPTEN_KEEPALIVE | ||
void clearContexts (void) { | ||
if (contexts[0]) delete contexts[0]; | ||
if (contexts[1]) delete contexts[1]; | ||
} | ||
|
||
EMSCRIPTEN_KEEPALIVE | ||
void createContext (int width, int height, char * id, int index) { | ||
contexts[index] = new Context(width, height, id); | ||
free(id); | ||
} | ||
|
||
EMSCRIPTEN_KEEPALIVE | ||
void loadTexture (uint8_t *buf, int bufSize) { | ||
printf("[WASM] Loading Texture \n"); | ||
|
||
contexts[0]->run(buf); | ||
free(buf); | ||
} | ||
|
||
EMSCRIPTEN_KEEPALIVE | ||
void detectEdges (uint8_t *buf, int bufSize) { | ||
printf("[WASM] Detecting edges \n"); | ||
|
||
contexts[1]->run(buf); | ||
free(buf); | ||
} | ||
|
||
} |
Oops, something went wrong.