├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── Makefile ├── README.md ├── native └── CMakeLists.txt └── src └── demo.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | build-native 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(demo) 3 | 4 | add_definitions(-std=c++14) 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(DEMO_SOURCE src/demo.cpp) 7 | 8 | message(STATUS "WebAssembly build enabled") 9 | message(STATUS "CMAKE_TOOLCHAIN_FILE='${CMAKE_TOOLCHAIN_FILE}'") 10 | if(DEFINED ENV{EMSCRIPTEN}) 11 | message(STATUS "emscripten environment is loaded") 12 | else() 13 | message(FATAL_ERROR "emscripten environment is NOT loaded") 14 | endif() 15 | 16 | add_executable(wasm ${DEMO_SOURCE}) 17 | set_target_properties(wasm 18 | PROPERTIES SUFFIX ".html" 19 | LINK_FLAGS "-Os -s USE_WEBGL2=1 -s FULL_ES3=1 -s USE_GLFW=3 -s WASM=1") 20 | em_link_js_library(wasm ${libraryJsFiles}) 21 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2018 Brad Erickson 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 20 | OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Make as a task manager to run cmake to run make. 2 | SRC=src/demo.cpp 3 | WASM=build/wasm.html 4 | NATIVE=build-native/native 5 | 6 | .PHONY: all 7 | all: $(WASM) $(NATIVE) 8 | 9 | # Build WebAssembly and load in Python Webserver 10 | .PHONY: wasm 11 | wasm: $(WASM) 12 | cd build && python -m SimpleHTTPServer 8080 13 | 14 | # Build Native and execute 15 | .PHONY: native 16 | native: $(NATIVE) 17 | $(NATIVE) 18 | 19 | $(WASM): $(SRC) 20 | mkdir -p build 21 | cd build && cmake .. -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake 22 | cd build && make 23 | 24 | $(NATIVE): $(SRC) 25 | mkdir -p build-native 26 | cd build-native && cmake ../native 27 | cd build-native && make 28 | 29 | .PHONY: clean 30 | clean: 31 | cd build && make clean 32 | cd build-native && make clean 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly/WebGL and Native/OpenGL 3D project StarterKit 2 | 3 | A starting point for a new web and native cross-platform 3D project. 4 | 5 | Builds with CMake. Supports [GLFW](http://www.glfw.org/). 6 | 7 | ## Details 8 | 9 | * Requires `Make` and `CMake` installed. 10 | * `CMake` configures `Make` to build for both environments. 11 | * The `Makefile` in the root is only a task runner. 12 | * [Libraries available in emscripten][emsdklib]. 13 | * Displays an empty off-white window. Nothing else. 14 | 15 | [emsdklib]:https://github.com/kripken/emscripten/tree/incoming/system/include 16 | 17 | ## Building 18 | 19 | ### WebAssembly 20 | 21 | * [Download or Compile the WASM Toolchain][wasm-toolchain]. 22 | * Setup the WASM toolchain 23 | * `cd emsdk` 24 | * `./emsdk install latest` 25 | * `./emsdk activate latest` 26 | * `source ./emsdk_env.sh` 27 | * Build/Run the example 28 | * `cd starter-wasm-webgl-opengl` 29 | * `make wasm` 30 | * Available at: http://localhost:8080/wasm.html 31 | 32 | [wasm-toolchain]:http://webassembly.org/getting-started/developers-guide/ 33 | 34 | ### Native Linux 35 | 36 | Tested on Ubuntu 16.04. 37 | 38 | * Install development tools X11 and OpenGL: `sudo apt install xorg-dev libgl1-mesa-dev` 39 | * Install GLFW: http://www.glfw.org/download.html 40 | * `wget https://github.com/glfw/glfw/releases/download/3.2.1/glfw-3.2.1.zip` 41 | * `unzip glfw-3.2.1.zip` 42 | * `cd glfw-3.2.1` 43 | * `cmake .` 44 | * `sudo make install` 45 | * Build/Run the example 46 | * `cd starter-wasm-webgl-opengl` 47 | * `make native` 48 | 49 | [glfw-dl]:http://www.glfw.org/download.html 50 | 51 | ## Notes 52 | 53 | I was hoping to build both in the same CMake tree, but the `CMAKE_TOOLCHAIN_FILE` change 54 | for emscripten breaks the native build. 55 | 56 | Thanks to: 57 | 58 | * https://cmake.org/cmake/help/v3.0/ 59 | * http://www.glfw.org/docs/latest/quick.html 60 | * https://github.com/HarryLovesCode/WebAssembly-WebGL-2 61 | * https://github.com/daminetreg/emscripten-example/ 62 | 63 | ## Todo 64 | 65 | * Test/debug on a fresh Ubuntu install 66 | * Native MacOS 67 | * Native Windows 68 | * More polish 69 | -------------------------------------------------------------------------------- /native/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(demo) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | set(DEMO_SOURCE ../src/demo.cpp) 6 | 7 | message(STATUS ${CMAKE_MODULE_PATH}) 8 | 9 | message(STATUS "Native build enabled") 10 | 11 | find_package(OpenGL REQUIRED) 12 | find_package(glfw3 REQUIRED) 13 | 14 | include_directories(${OPENGL_INCLUDE_DIR}) 15 | 16 | add_executable(native ${DEMO_SOURCE}) 17 | target_link_libraries(native ${OPENGL_gl_LIBRARY} glfw) 18 | -------------------------------------------------------------------------------- /src/demo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Include the Emscripten library only if targetting WebAssembly 5 | #ifdef __EMSCRIPTEN__ 6 | #include 7 | #define GLFW_INCLUDE_ES3 8 | #endif 9 | 10 | #include 11 | 12 | GLFWwindow* window; 13 | 14 | // Handle GLFW Errors 15 | static void error_callback(int error, const char* description) { 16 | fprintf(stderr, "Error: %s\n", description); 17 | } 18 | 19 | // Handle key presses 20 | static void key_callback(GLFWwindow* window, int key, int scancode, int action, 21 | int mods) { 22 | if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) 23 | glfwSetWindowShouldClose(window, GLFW_TRUE); 24 | } 25 | 26 | static void force_exit() { 27 | #ifdef __EMSCRIPTEN__ 28 | emscripten_force_exit(EXIT_FAILURE); 29 | #else 30 | exit(EXIT_FAILURE); 31 | #endif 32 | } 33 | 34 | // Generate the frame data. 35 | static void generate_frame() { 36 | // Clear the window with the background color 37 | glClear(GL_COLOR_BUFFER_BIT); 38 | // Flip the double buffer 39 | glfwSwapBuffers(window); 40 | // Handle any events 41 | glfwPollEvents(); 42 | } 43 | 44 | int main() { 45 | // Setup the Error handler 46 | glfwSetErrorCallback(error_callback); 47 | 48 | // Start GLFW 49 | if (!glfwInit()) { 50 | fprintf(stderr, "Error: GLFW Initialization failed."); 51 | force_exit(); 52 | } 53 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 54 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); 55 | 56 | // Create the display window 57 | window = glfwCreateWindow(640, 480, "Demo", NULL, NULL); 58 | if (!window) { 59 | fprintf(stderr, "Error: GLFW Window Creation Failed"); 60 | glfwTerminate(); 61 | force_exit(); 62 | } 63 | // Setup the Key Press handler 64 | glfwSetKeyCallback(window, key_callback); 65 | // Select the window as the drawing destination 66 | glfwMakeContextCurrent(window); 67 | 68 | // Near white background 69 | glClearColor(0.9f, 0.9f, 0.9f, 0.0f); 70 | 71 | // Run the loop correctly for the target environment 72 | #ifdef __EMSCRIPTEN__ 73 | emscripten_set_main_loop(generate_frame, 0, false); 74 | #else 75 | // Display the window until ESC is pressed 76 | while (!glfwWindowShouldClose(window)) { 77 | generate_frame(); 78 | } 79 | // Clean up 80 | glfwDestroyWindow(window); 81 | glfwTerminate(); 82 | exit(EXIT_SUCCESS); 83 | #endif 84 | } 85 | --------------------------------------------------------------------------------