# OpenGL 建置
## Step 0. 前置下載
- [CMake (如果已經安裝過就不用了)](https://github.com/Kitware/CMake/releases/download/v3.28.0-rc2/cmake-3.28.0-rc2-windows-x86_64.msi)
- [glfw](https://www.glfw.org/download)

- 64-bit Windows binaries
- [glad](https://glad.dav1d.de)


- API "gl" 選最新的,其他為 None
- Profile: Core
- 選完後按 Generate
- [linmath.h(可選,但這個教學一定需要)](https://github.com/glfw/glfw/blob/master/deps/linmath.h)
- [Visual studio 2022](https://visualstudio.microsoft.com/zh-hant/thank-you-downloading-visual-studio/?sku=Community&channel=Release&version=VS2022&source=VSLandingPage&cid=2030&workload=dotnet-dotnetwebcloud&passive=false#dotnet)
- 至少需要能建立 C++ 空白專案

## Step 1. 建立 C++ Project
1. 建立新專案
2. C++ 空白專案

3. 專案基礎設定

4. 建立
### 專案目前的檔案結構
```
OpenGL-Tutorial
│ OpenGL-Tutorial.sln
│
└─OpenGL-Tutorial
OpenGL-Tutorial.vcxproj
OpenGL-Tutorial.vcxproj.filters
OpenGL-Tutorial.vcxproj.user
```
## Step 2. 建立基本檔案與資料夾
1. 把 "方案總管" 切換成 "顯示所有檔案" 模式

2. 在 Visual Studio 內,右鍵 "專案名稱(在這個範例為OpenGL-Tutorial)" -> "加入" -> "新增項目" -> "C++檔(.cpp)" -> 命名為 `main.cpp`



3. 把下面的程式碼貼到 `main.cpp`
```cpp=
#include "config.h"
#include "linmath.h"
static const struct
{
float x, y;
float r, g, b;
} vertices[3] =
{
{ -0.6f, -0.4f, 1.f, 0.f, 0.f },
{ 0.6f, -0.4f, 0.f, 1.f, 0.f },
{ 0.f, 0.6f, 0.f, 0.f, 1.f }
};
static const char* vertex_shader_text =
"#version 110\n"
"uniform mat4 MVP;\n"
"attribute vec3 vCol;\n"
"attribute vec2 vPos;\n"
"varying vec3 color;\n"
"void main()\n"
"{\n"
" gl_Position = MVP * vec4(vPos, 0.0, 1.0);\n"
" color = vCol;\n"
"}\n";
static const char* fragment_shader_text =
"#version 110\n"
"varying vec3 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(color, 1.0);\n"
"}\n";
static void error_callback(int error, const char* description)
{
fprintf(stderr, "Error: %s\n", description);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
int main(void)
{
GLFWwindow* window;
GLuint vertex_buffer, vertex_shader, fragment_shader, program;
GLint mvp_location, vpos_location, vcol_location;
glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(EXIT_FAILURE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetKeyCallback(window, key_callback);
glfwMakeContextCurrent(window);
gladLoadGL();
glfwSwapInterval(1);
// NOTE: OpenGL error checks have been omitted for brevity
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
glCompileShader(vertex_shader);
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
glCompileShader(fragment_shader);
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
mvp_location = glGetUniformLocation(program, "MVP");
vpos_location = glGetAttribLocation(program, "vPos");
vcol_location = glGetAttribLocation(program, "vCol");
glEnableVertexAttribArray(vpos_location);
glVertexAttribPointer(vpos_location, 2, GL_FLOAT, GL_FALSE,
sizeof(vertices[0]), (void*)0);
glEnableVertexAttribArray(vcol_location);
glVertexAttribPointer(vcol_location, 3, GL_FLOAT, GL_FALSE,
sizeof(vertices[0]), (void*)(sizeof(float) * 2));
while (!glfwWindowShouldClose(window))
{
float ratio;
int width, height;
mat4x4 m, p, mvp;
glfwGetFramebufferSize(window, &width, &height);
ratio = width / (float)height;
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
mat4x4_identity(m);
mat4x4_rotate_Z(m, m, (float)glfwGetTime());
mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);
mat4x4_mul(mvp, p, m);
glUseProgram(program);
glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*)mvp);
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
```
4. 用同樣的方法新增一個 "標頭檔(.h)" -> 命名為 `config.h`

5. 把下面的程式碼貼到 `config.h`
```h=
#include <glad/glad.h> // 這行一定要在最上面
#include <GLFW/glfw3.h>
#include <iostream>
```
6. 到電腦的檔案總管 -> 進入與 `main.cpp` 同層的資料夾 建立 `deps` 資料夾
### 專案目前的檔案結構
```
OpenGL-Tutorial
│ OpenGL-Tutorial.sln
│
└─OpenGL-Tutorial
│ config.h
│ main.cpp
│ OpenGL-Tutorial.vcxproj
│ OpenGL-Tutorial.vcxproj.filters
│ OpenGL-Tutorial.vcxproj.user
│
└─deps
```
## Step 3. 複製 glfw、glad、linmath.h
1. 把下載的 glfw、glad 解壓縮,並跟 `linmath.h` 丟到同一個資料夾(隨便建一個在任意地方)
```
OpenGL-Tools
│ linmath.h
│
├─glad
│ ├─include
│ │ ├─glad
│ │ │ glad.h
│ │ │
│ │ └─KHR
│ │ khrplatform.h
│ │
│ └─src
│ glad.c
│
└─glfw-3.3.8.bin.WIN64
│ LICENSE.md
│ README.md
│
├─docs
│ └─html
│ ...
│
├─include
│ └─GLFW
│ glfw3.h
│ glfw3native.h
│
├─lib-mingw-w64
│ ...
│
├─lib-static-ucrt
│ ...
│
├─lib-vc2012
│ ⁝
└─lib-vc2022
glfw3.dll
glfw3.lib
glfw3dll.lib
glfw3_mt.lib
```
2. 將 `linmath.h` 複製到 `專案資料夾`
3. 將 `glfw-3.3.8.bin.WIN64/lib-vc2022` 複製到 `專案資料夾/deps`,並刪除除了 `glfw3.lib` 以外的檔案
4. 將 `glfw-3.3.8.bin.WIN64/include/GLFW` 複製到 `專案資料夾/deps`
5. 將 `glad/include/glad`、`glad/include/KHR` 複製到 `專案資料夾/deps`
6. 將 `glad/src/glad.c` 複製到 `專案資料夾`
### 專案目前的檔案結構
```
OpenGL-Tutorial
│ OpenGL-Tutorial.sln
│
└─OpenGL-Tutorial
│ config.h
│ glad.c
│ linmath.h
│ main.cpp
│ OpenGL-Tutorial.vcxproj
│ OpenGL-Tutorial.vcxproj.filters
│ OpenGL-Tutorial.vcxproj.user
│
└─deps
├─glad
│ glad.h
│
├─GLFW
│ glfw3.h
│ glfw3native.h
│
├─KHR
│ khrplatform.h
│
└─lib-vc2022
glfw3.lib
```
## Step 4. 專案設定
1. 2. 右鍵 `linmath.h` -> "加入至專案"
- 加入前:

- 加入後:

2. 右鍵 `glad.c` -> "加入至專案"
- 加入前:

- 加入後:

2. 右鍵 "專案名稱" -> "屬性" -> "VC++目錄" -> "包含目錄" -> "∨" -> "編輯..." -> 右上角的 "新增一行" 圖示 -> "..." -> 選擇專案內的 `deps` 資料夾 -> "確定"





3. 右鍵 "專案名稱" -> "屬性" -> "連結器" -> "輸入" -> "其他相依性" -> "∨" -> "編輯..." -> 輸入 `./deps/libs-vc2022/glfw3.lib` -> "確定" -> "套用" -> "確定"


## Step 5. 執行
1. 開啟 `main.cpp`
2. "本機 Windows 偵錯工具" 或按下 `F5`
3. 如果跳出以下視窗就代表你成功了
