Last active
March 20, 2020 20:18
-
-
Save YakoYakoYokuYoku/4b1005042c950f82fd8676a7b6fb906a to your computer and use it in GitHub Desktop.
An OpenGL example with support for Linux/Unix/BSD and Emscripten.
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
/* | |
Build instructions: | |
To compile and run the application with G++ or Clang++ use: | |
$ CXX -o application.o -c opengl_emscripten_example.cpp | |
$ CXX -o application application.o -lGLEW -lGLU -lGL -lglfw | |
$ ./application | |
To compile and with Emscripten use: | |
$ em++ -o application.o -c opengl_emscripten_example.cpp -s MAX_WEBGL_VERSION=2 | |
$ em++ -o application.html application.o -lGLEW -lGL -lglfw -s USE_GLFW=3 | |
$ emrun --no_browser application.html | |
*/ | |
#include <GL/glew.h> | |
#include <GLFW/glfw3.h> | |
#include <iostream> | |
#ifdef __EMSCRIPTEN__ | |
#include <emscripten.h> | |
GLFWwindow *glfwMainWindow; | |
GLuint mainShaderProgram; | |
GLuint globVertArrObj; | |
GLuint scalarID; | |
float scalar = 0.5f; | |
float scalarFactor = 0.00390625f; | |
#endif | |
const char *vertexShaderSource = | |
#ifndef __EMSCRIPTEN__ | |
"#version 330\n" | |
"layout (location = 0) in vec3 aPos;\n" | |
"uniform float scalar;\n" | |
"void main()\n" | |
"{\n" | |
" gl_Position = vec4(scalar * aPos, 1.0f);\n" | |
"}\0"; | |
#else | |
"attribute vec3 aPos;\n" | |
"uniform float scalar;\n" | |
"void main()\n" | |
"{\n" | |
" gl_Position = vec4(scalar * aPos, 1.0);\n" | |
"}\0"; | |
#endif | |
const char *fragmentShaderSource = | |
#ifndef __EMSCRIPTEN__ | |
"#version 330\n" | |
"out vec4 FragColor;\n" | |
"void main()\n" | |
"{\n" | |
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" | |
"}\0"; | |
#else | |
"void main()\n" | |
"{\n" | |
" gl_FragColor = vec4(1.0, 0.5, 0.2, 1.0);\n" | |
"}\0"; | |
#endif | |
void framebuffer_size_callback(GLFWwindow *window, int width, int height); | |
void processInput(GLFWwindow *window); | |
// settings | |
const unsigned int SCR_WIDTH = 800; | |
const unsigned int SCR_HEIGHT = 600; | |
#ifdef __EMSCRIPTEN__ | |
void glfwIter() | |
{ | |
// scale the triangle | |
if (scalar == 1.0f) | |
{ | |
scalarFactor = -0.00390625f; | |
} | |
if (scalar == 0.5f) | |
{ | |
scalarFactor = 0.00390625f; | |
} | |
scalar += scalarFactor; | |
glUniform1f(scalarID, scalar); | |
// input | |
// ----- | |
processInput(glfwMainWindow); | |
// render | |
// ------ | |
glClear(GL_COLOR_BUFFER_BIT); | |
glUseProgram(mainShaderProgram); | |
glBindVertexArray(globVertArrObj); | |
glDrawArrays(GL_TRIANGLES, 0, 3); | |
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) | |
// ------------------------------------------------------------------------------- | |
glfwSwapBuffers(glfwMainWindow); | |
glfwPollEvents(); | |
} | |
#endif | |
int main() | |
{ | |
// glfw: initialize and configure | |
// ------------------------------ | |
if (!glfwInit()) | |
{ | |
std::cerr << "Failed to initialize GLFW" << std::endl; | |
return -1; | |
} | |
// glfwWindowHint(GLFW_SAMPLES, 4); | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); | |
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |
// glfw window creation | |
// -------------------- | |
GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "OpenGL Example", NULL, NULL); | |
if (window == NULL) | |
{ | |
std::cout << "Failed to create GLFW window" << std::endl; | |
glfwTerminate(); | |
return -1; | |
} | |
glfwMakeContextCurrent(window); | |
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); | |
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); | |
// initialise GLEW | |
glewExperimental = true; | |
if (glewInit() != GLEW_OK) | |
{ | |
std::cerr << "Failed to initialize GLEW" << std::endl; | |
glfwTerminate(); | |
return -1; | |
} | |
// vertex array object | |
GLuint vertArrObj; | |
glGenVertexArrays(1, &vertArrObj); | |
glBindVertexArray(vertArrObj); | |
// triangle vertices | |
float triangleVertices[] = { | |
-0.5f, -0.5f, 0.0f, // | |
0.5f, -0.5f, 0.0f, // | |
0.0f, 0.5f, 0.0f // | |
}; | |
GLuint triangleVertBuf; | |
glGenBuffers(1, &triangleVertBuf); | |
glBindBuffer(GL_ARRAY_BUFFER, triangleVertBuf); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices, GL_STATIC_DRAW); | |
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); | |
glEnableVertexAttribArray(0); | |
// triangle shaders | |
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); | |
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); | |
glCompileShader(vertexShader); | |
int success; | |
char info_log[512]; | |
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); | |
if (!success) | |
{ | |
glGetShaderInfoLog(vertexShader, 512, NULL, info_log); | |
std::cout << "Error while compiling vertex shader: " << info_log << std::endl; | |
return -1; | |
} | |
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); | |
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); | |
glCompileShader(fragmentShader); | |
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); | |
if (!success) | |
{ | |
glGetShaderInfoLog(fragmentShader, 512, NULL, info_log); | |
std::cout << "Error while compiling fragment shader: " << info_log << std::endl; | |
return -1; | |
} | |
GLuint shaderProgram = glCreateProgram(); | |
glAttachShader(shaderProgram, vertexShader); | |
glAttachShader(shaderProgram, fragmentShader); | |
glLinkProgram(shaderProgram); | |
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); | |
if (!success) | |
{ | |
glGetProgramInfoLog(shaderProgram, 512, NULL, info_log); | |
std::cout << "Error while linking shader: " << info_log << std::endl; | |
return -1; | |
} | |
glDeleteShader(vertexShader); | |
glDeleteShader(fragmentShader); | |
// render loop | |
// ----------- | |
#ifndef __EMSCRIPTEN__ | |
float scalar = 0.5f; | |
float scalarFactor; | |
GLuint scalarID = glGetUniformLocation(shaderProgram, "scalar"); | |
while (!glfwWindowShouldClose(window)) | |
{ | |
// scale the triangle | |
if (scalar == 1.0f) | |
{ | |
scalarFactor = -0.00390625f; | |
} | |
if (scalar == 0.5f) | |
{ | |
scalarFactor = 0.00390625f; | |
} | |
scalar += scalarFactor; | |
glUniform1f(scalarID, scalar); | |
// input | |
// ----- | |
processInput(window); | |
// render | |
// ------ | |
glClear(GL_COLOR_BUFFER_BIT); | |
glUseProgram(shaderProgram); | |
glBindVertexArray(vertArrObj); | |
glDrawArrays(GL_TRIANGLES, 0, 3); | |
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) | |
// ------------------------------------------------------------------------------- | |
glfwSwapBuffers(window); | |
glfwPollEvents(); | |
} | |
#else | |
glfwMainWindow = window; | |
mainShaderProgram = shaderProgram; | |
globVertArrObj = vertArrObj; | |
scalarID = glGetUniformLocation(shaderProgram, "scalar"); | |
emscripten_set_main_loop(glfwIter, 60, 1); | |
#endif | |
// glfw: terminate, clearing all previously allocated GLFW resources. | |
// ------------------------------------------------------------------ | |
glfwTerminate(); | |
return 0; | |
} | |
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly | |
// --------------------------------------------------------------------------------------------------------- | |
void processInput(GLFWwindow *window) | |
{ | |
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) | |
glfwSetWindowShouldClose(window, true); | |
} | |
// glfw: whenever the window size changed (by OS or user resize) this callback function executes | |
// --------------------------------------------------------------------------------------------- | |
void framebuffer_size_callback(GLFWwindow *window, int width, int height) | |
{ | |
// make sure the viewport matches the new window dimensions; note that width and | |
// height will be significantly larger than specified on retina displays. | |
glViewport(0, 0, width, height); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment