Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
DanRuta committed Dec 17, 2017
1 parent 5786da8 commit a068b40
Show file tree
Hide file tree
Showing 16 changed files with 2,121 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
node_modules
3 changes: 1 addition & 2 deletions README.md
@@ -1,2 +1 @@
# webassembly-webgl-shaders
Demo project for using WebGL shaders in WebAssembly
WebAssembly WebGL demo
210 changes: 210 additions & 0 deletions dev/cpp/Context.cpp
@@ -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);
}
21 changes: 21 additions & 0 deletions dev/cpp/Context.h
@@ -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;

};
57 changes: 57 additions & 0 deletions dev/cpp/emscripten.cpp
@@ -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);
}

}

0 comments on commit a068b40

Please sign in to comment.