| /* |
| * Copyright 2014 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. |
| */ |
| |
| // Built from glbook/hello triange and sdl_ogl, see details there |
| |
| #include "SDL/SDL.h" |
| #include "SDL/SDL_image.h" |
| #include "SDL/SDL_opengl.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <assert.h> |
| #include <string.h> |
| |
| GLuint programObject; |
| int width = 512; |
| int height = 256; |
| |
| GLuint LoadShader ( GLenum type, const char *shaderSrc ) |
| { |
| GLuint shader; |
| GLint compiled; |
| |
| shader = glCreateShader ( type ); |
| if ( shader == 0 ) |
| return 0; |
| |
| glShaderSource ( shader, 1, &shaderSrc, NULL ); |
| glCompileShader ( shader ); |
| glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled ); |
| if ( !compiled ) |
| { |
| GLint infoLen = 0; |
| glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen ); |
| if ( infoLen > 1 ) |
| { |
| char* infoLog = malloc (sizeof(char) * infoLen ); |
| glGetShaderInfoLog ( shader, infoLen, NULL, infoLog ); |
| printf ( "Error compiling shader:\n%s\n", infoLog ); |
| free ( infoLog ); |
| } |
| glDeleteShader ( shader ); |
| return 0; |
| } |
| return shader; |
| } |
| |
| int Init () |
| { |
| GLbyte vShaderStr[] = |
| "attribute vec4 vPosition; \n" |
| "void main() \n" |
| "{ \n" |
| " gl_Position = vPosition; \n" |
| "} \n"; |
| |
| GLbyte fShaderStr[] = |
| "precision mediump float;\n"\ |
| "void main() \n" |
| "{ \n" |
| " gl_FragColor = vec4 ( 0.0, 0.0, 1.0, 1.0 );\n" |
| "} \n"; |
| |
| GLuint vertexShader; |
| GLuint fragmentShader; |
| GLint linked; |
| |
| vertexShader = LoadShader ( GL_VERTEX_SHADER, (const char *)vShaderStr ); |
| fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, (const char *)fShaderStr ); |
| |
| programObject = glCreateProgram ( ); |
| if ( programObject == 0 ) |
| return 0; |
| |
| glAttachShader ( programObject, vertexShader ); |
| glAttachShader ( programObject, fragmentShader ); |
| glBindAttribLocation ( programObject, 0, "vPosition" ); |
| glLinkProgram ( programObject ); |
| glGetProgramiv ( programObject, GL_LINK_STATUS, &linked ); |
| if ( !linked ) |
| { |
| GLint infoLen = 0; |
| glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen ); |
| if ( infoLen > 1 ) |
| { |
| char* infoLog = malloc (sizeof(char) * infoLen ); |
| glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog ); |
| printf ( "Error linking program:\n%s\n", infoLog ); |
| free ( infoLog ); |
| } |
| glDeleteProgram ( programObject ); |
| return GL_FALSE; |
| } |
| |
| glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f ); |
| return GL_TRUE; |
| } |
| |
| /// |
| // Draw a triangle using the shader pair created in Init() |
| // |
| void Draw () |
| { |
| void *buffer; |
| GLfloat vVertices[] = { 0.0f, 0.5f, 0.0f, |
| -0.5f, -0.5f, 0.0f, |
| 0.5f, -0.5f, 0.0f }; |
| |
| // No clientside arrays, so do this in a webgl-friendly manner |
| GLuint vertexPosObject; |
| glGenBuffers(1, &vertexPosObject); |
| glBindBuffer(GL_ARRAY_BUFFER, vertexPosObject); |
| glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices), NULL, GL_STATIC_DRAW); |
| buffer = glMapBufferRange( |
| GL_ARRAY_BUFFER, |
| 0, |
| sizeof(vVertices), |
| GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_WRITE_BIT |
| ); |
| if (buffer == NULL) { |
| fprintf(stderr, "Could not map buffer: %x\n", glGetError()); |
| exit(1); |
| } |
| memcpy(buffer, vVertices, sizeof(vVertices)); |
| glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, sizeof(vVertices)); |
| glUnmapBuffer(GL_ARRAY_BUFFER); |
| |
| glViewport ( 0, 0, width, height ); |
| glClear ( GL_COLOR_BUFFER_BIT ); |
| glUseProgram ( programObject ); |
| |
| glBindBuffer(GL_ARRAY_BUFFER, vertexPosObject); |
| glVertexAttribPointer(0 /* ? */, 3, GL_FLOAT, 0, 0, 0); |
| glEnableVertexAttribArray(0); |
| |
| glDrawArrays ( GL_TRIANGLES, 0, 3 ); |
| } |
| |
| void Verify() { |
| unsigned char *data = malloc(width*height*4 + 16); |
| int *last = (int*)(data + width*height*4 - 4); |
| int *after = (int*)(data + width*height*4); |
| *last = 0xdeadbeef; |
| *after = 0x12345678; |
| glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); |
| assert(*last != 0xdeadbeef); // should overwrite the buffer to the end |
| assert(*after == 0x12345678); // nothing should be written afterwards! |
| // Should see some blue, and nothing else |
| int seen = 0; |
| int ok = 1; |
| for (int x = 0; x < width*height; x++) { |
| seen = seen || data[x*4+2] != 0; |
| ok = ok && (data[x*4+0] == 0); |
| ok = ok && (data[x*4+1] == 0); |
| } |
| int result = seen && ok; |
| REPORT_RESULT(result); |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| SDL_Surface *screen; |
| if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) { |
| printf("Unable to initialize SDL: %s\n", SDL_GetError()); |
| return 1; |
| } |
| |
| screen = SDL_SetVideoMode(width, height, 32, SDL_OPENGL); |
| if (!screen) { |
| printf("Unable to set video mode: %s\n", SDL_GetError()); |
| return 1; |
| } |
| |
| Init(); |
| Draw(); |
| Verify(); |
| |
| return 0; |
| } |
| |