HYPER MIKAN BOX
検索
最近の変更
メディアマネージャー
サイトマップ
文書の表示
以前のリビジョン
バックリンク
ログイン
トレース:
この文書は読取専用です。文書のソースを閲覧することは可能ですが、変更はできません。もし変更したい場合は管理者に連絡してください。
====== OpenGLの修行 #4 - ビルド環境の見直し ====== [[https://www.youtube.com/watch?v=NCKH1Hma55E|YouTubeの動画ページ]] * 第3回からおよそ1年半の期間を経て再開する。 * 環境の準備を実演するために、Windows(Vista、VirtualBox)でやってきた。 * 次回からはLinuxでやっていく。 * その前に、現在の雑なビルド環境に改善を加えておく。 ===== メイン目標 ===== CMakeLists.txtに、GLFWのインクルードパスとライブラリパスがベタ書きされているのを直したい。 ===== メニュー ===== * (おまけ) GLFWと動的にリンクする (DLLを利用する) * GLFWをソースからビルドしてインストールする * システムの任意の場所にインストールされたGLFWを利用する * (おまけ) GLADをアプリケーションのソースから分離する ===== (おまけ) GLFWと動的にリンクする (DLLを利用する) ===== GLFWのWindows向けコンパイル済みバイナリには、DLLも含まれている。 ===== GLFWをソースからビルドしてインストールする ===== インストール場所は''CMAKE_INSTALL_PREFIX''で指定する。 例: $ cmake -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=C:/somewhere .. ===== システムの任意の場所にインストールされたGLFWを利用する ===== [[https://cmake.org/cmake/help/latest/command/find_package.html|find_package]]の検索パスは[[https://cmake.org/cmake/help/latest/variable/CMAKE_PREFIX_PATH.html|CMAKE_PREFIX_PATH]]で指定する。 例: $ cmake -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH=C:/somewhere .. ===== (おまけ) GLADをアプリケーションのソースから分離する ===== [[https://cmake.org/cmake/help/latest/command/add_subdirectory.html|add_subdirectory]] ====== ソースコード ====== {{ :youtube:hellotriangle_2.zip |ダウンロード}} ===== プロジェクトレイアウト ===== HelloTriangle_2 ├── CMakeLists.txt ├── glad │ ├── CMakeLists.txt │ ├── include │ │ ├── KHR │ │ │ └── khrplatform.h │ │ └── glad │ │ └── glad.h │ └── src │ └── glad.c ├── shaders │ ├── hello_triangle.frag │ └── hello_triangle.vert └── src └── main.cpp ===== CMakeLists.txt ===== <file cmake> cmake_minimum_required(VERSION 3.13 FATAL_ERROR) project(HelloTriangle VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) find_package(glfw3 REQUIRED) add_subdirectory(glad) add_executable(${PROJECT_NAME} src/main.cpp) target_link_libraries(${PROJECT_NAME} glad glfw) </file> ===== glad/CMakeLists.txt ===== <file cmake> enable_language(C) add_library(glad OBJECT src/glad.c) target_include_directories( glad PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ) </file> ===== glad/* ===== [[https://glad.dav1d.de/#language=c&specification=gl&api=gl%3D4.1&api=gles1%3Dnone&api=gles2%3Dnone&api=glsc2%3Dnone&profile=compatibility&loader=on|gladの入手]] ===== shaders/hello_triangle.frag ===== <file glsl> #version 410 core out vec4 vert_color; void main(void) { const vec4 positions[3] = vec4[3](vec4(-0.5, -0.5, 1.0, 1.0), vec4( 0.5, -0.5, 1.0, 1.0), vec4( 0.5, 0.5, 1.0, 1.0)); gl_Position = positions[gl_VertexID]; const vec4 colors[3] = vec4[3](vec4(1.0, 0.0, 0.0, 1.0), vec4(0.0, 1.0, 0.0, 1.0), vec4(0.0, 0.0, 1.0, 1.0)); vert_color = colors[gl_VertexID]; } </file> ===== shaders/hello_triangle.vert ===== <file glsl> #version 410 core in vec4 vert_color; out vec4 color; void main(void) { // color = vec4(1.0, 0.0, 0.0, 1.0); color = vert_color; } </file> ===== src/main.cpp ===== <file cpp> #include <glad/glad.h> // glad.h must be included before glfw3.h #include <GLFW/glfw3.h> #include <iostream> #include <string> #include <filesystem> #include <fstream> #include <iterator> #include <optional> #include <vector> namespace fs = std::filesystem; std::optional<std::string> read_to_string(fs::path const &path) { if (std::ifstream ifs{path}; ifs) { return std::string(std::istreambuf_iterator<char>{ifs}, {}); } else { return std::nullopt; } } void print_shader_compilation_errors(GLuint shader, fs::path const &path) { GLint log_length; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); if (log_length > 0) { std::vector<GLchar> log(log_length); glGetShaderInfoLog(shader, log.size(), &log_length, log.data()); std::cerr << path.string() << ':' << log.data() << '\n'; } } std::optional<GLuint> compile_shader(fs::path const &path, GLenum type) { if (auto shader_source = read_to_string(path); shader_source) { GLuint shader = glCreateShader(type); GLchar const *srcs[] = { shader_source->c_str() }; glShaderSource(shader, 1, srcs, nullptr); glCompileShader(shader); GLint success; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (success) { return shader; } else { print_shader_compilation_errors(shader, path); return std::nullopt; } } else { std::cerr << "failed read file: " << path << '\n'; return std::nullopt; } } std::optional<GLuint> link_shaders(GLuint vert, GLuint frag) { GLuint program = glCreateProgram(); glAttachShader(program, vert); glAttachShader(program, frag); glLinkProgram(program); GLint success; glGetProgramiv(program, GL_LINK_STATUS, &success); if (success) { return program; } else { return std::nullopt; } } std::optional<GLuint> shader_program_setup() { auto vert = compile_shader("shaders/hello_triangle.vert", GL_VERTEX_SHADER); auto frag = compile_shader("shaders/hello_triangle.frag", GL_FRAGMENT_SHADER); auto program = vert && frag ? link_shaders(*vert, *frag) : std::nullopt; if (vert) { glDeleteShader(*vert); } if (frag) { glDeleteShader(*frag); } return program; } int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); GLFWwindow *window = glfwCreateWindow(800, 600, "Hello Triangle!", nullptr, nullptr); if (!window) { std::cerr << "GLFW failed to create window\n" << std::endl; return 1; } glfwMakeContextCurrent(window); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cerr << "glad failed to initialize OpenGL context\n"; return 1; } auto *ver_gl = glGetString(GL_VERSION); std::cout << "OpenGL version: " << ver_gl << '\n'; auto shader_program = shader_program_setup(); if (!shader_program) { std::cerr << "failed to setup shader program\n"; return 1; } GLuint VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); while (!glfwWindowShouldClose(window)) { glClearColor(0.0, 0.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(*shader_program); glDrawArrays(GL_TRIANGLES, 0, 3); glfwSwapBuffers(window); glfwPollEvents(); } std::cerr << "Program finished successfully\n"; } </file>
文書の先頭へ