差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

次のリビジョン
前のリビジョン
youtube:opengl-training-004 [2025/11/03 23:01] – 作成 freemikanyoutube:opengl-training-004 [2025/11/04 12:57] (現在) – [glad/*] Fix wrong URL freemikan
行 1: 行 1:
-準備中…+====== 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をソースからビルドしてインストールする ===== 
 +インストール場所は[[https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html|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=core&loader=on|gladの入手]] 
 + 
 + 
 +===== shaders/hello_triangle.frag ===== 
 + 
 +<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> 
 + 
 +===== shaders/hello_triangle.vert ===== 
 + 
 +<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> 
 + 
 +===== 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> 
文書の先頭へ