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