Skip to content

Instantly share code, notes, and snippets.

@neguse
Last active June 7, 2020 13:29
Show Gist options
  • Save neguse/dc5d04ec65bec7d82d47f0a2a9745637 to your computer and use it in GitHub Desktop.
Save neguse/dc5d04ec65bec7d82d47f0a2a9745637 to your computer and use it in GitHub Desktop.
SDL2+WebGL2でEmscriptenビルド
# SDL2+WebGL2でEmscriptenビルドしてみる
## ビルド方法
### 今回用意した環境
* Visual Studio 2019 Community
* cmake
* Emscripten
### vcpkgでSDL2をインストール
```
vcpkg install --triplet wasm32-emscripten sdl2
```
### プロジェクトの設定
Visual Studioでリポジトリのディレクトリを開くとCMakeSettings.jsonというファイルができる
CMakeSettings.jsonを以下のように編集
```
{
// See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.
"configurations": [
{
"name": "x64-Debug",
// 元からあるやつはそのまま
},
{
"name": "wasm32-Debug",
"generator": "Ninja",
"configurationType": "Debug",
// "inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"cmakeToolchain": "path/to/Microsoft/vcpkg/scripts/buildsystems/vcpkg.cmake",
"variables": [
{
"name": "VCPKG_CHAINLOAD_TOOLCHAIN_FILE",
"value": "path/to/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake"
},
{
"name": "CMAKE_CROSSCOMPILING_EMULATOR",
"value": "path/to/emsdk/node/12.9.1_64bit/bin/node.exe"
},
{
"name": "VCPKG_TARGET_TRIPLET",
"value": "wasm32-emscripten"
}
]
}
```
### ビルドと起動
Visual Studio上のConfigurationを`wasm32-Debug`に切り替えてビルドする。
`out\build\wasm32-Debug`にhtmlファイルができるので、このディレクトリ上で`python -m http.server`のような適当なWebサーバを立ち上げてブラウザからアクセスする。
cmake_minimum_required(VERSION 3.0.0)
project(sdl2webgl2 VERSION 0.1.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(SDL2 CONFIG REQUIRED)
file(GLOB_RECURSE sources "*.cpp")
add_executable(sdl2webgl2 ${sources})
if (EMSCRIPTEN)
set(CMAKE_EXECUTABLE_SUFFIX ".html")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2")
endif()
target_include_directories(sdl2webgl2 PUBLIC ".")
target_link_libraries(sdl2webgl2 PRIVATE SDL2::SDL2main SDL2::SDL2-static)
#include <stdio.h>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
#include <GL/glew.h>
#include <stdlib.h>
#include <string.h>
#include "shader.hpp"
GLuint LoadShaders(const char* vertex_file, const char* fragment_file) {
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
printf("Compiling shader : %s\n", vertex_file);
char const* VertexSourcePointer = vertex_file;
glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL,
&VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);
}
// Compile Fragment Shader
printf("Compiling shader : %s\n", fragment_file);
char const* FragmentSourcePointer = fragment_file;
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
glCompileShader(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL,
&FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);
}
// Link the program
printf("Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL,
&ProgramErrorMessage[0]);
printf("%s\n", &ProgramErrorMessage[0]);
}
glDetachShader(ProgramID, VertexShaderID);
glDetachShader(ProgramID, FragmentShaderID);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}
#pragma once
#include <GLES3/gl3.h>
GLuint LoadShaders(const char* vertex_file, const char* fragment_file);
#include <SDL2/SDL.h>
#include <emscripten.h>
#include <stdio.h>
#include <stdlib.h>
#include <functional>
SDL_Window* window;
// Include GLM
#include <glm/glm.hpp>
using namespace glm;
#include <shader.hpp>
std::function<void(void)> updater;
void main_func() { updater(); }
int main(void) {
if (SDL_Init(SDL_INIT_VIDEO)) {
fprintf(stderr, "Failed to initialize SDL\n");
getchar();
return -1;
}
// SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
// Open a window and create its OpenGL context
window = SDL_CreateWindow(nullptr, SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, 1024, 768,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE |
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI);
if (window == NULL) {
fprintf(stderr,
"Failed to open SDL window. If you have an Intel GPU, they are "
"not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
getchar();
return -1;
}
SDL_GLContext ctx = SDL_GL_CreateContext(window);
if (ctx == nullptr) {
fprintf(stderr, "Failed to create GL context.\n");
getchar();
return -1;
}
SDL_GL_MakeCurrent(window, ctx);
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
const char* vertex_shader = R"(#version 300 es
precision mediump float;
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
void main(){
gl_Position.xyz = vertexPosition_modelspace;
gl_Position.w = 1.0;
})";
const char* fragment_shader = R"(#version 300 es
precision mediump float;
// Ouput data
out vec3 color;
void main()
{
// Output color = red
color = vec3(1, 0, 0);
})";
// Create and compile our GLSL program from the shaders
GLuint programID = LoadShaders(vertex_shader, fragment_shader);
static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
};
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data),
g_vertex_buffer_data, GL_STATIC_DRAW);
emscripten_set_main_loop(main_func, 0, 0);
updater = [&]() {
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0, // attribute 0. No particular reason for 0,
// but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangle !
glDrawArrays(GL_TRIANGLES, 0,
3); // 3 indices starting at 0 -> 1 triangle
glDisableVertexAttribArray(0);
// Swap buffers
SDL_GL_SwapWindow(window);
};
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment