Compare commits
2 commits
62d39c522f
...
fc862a279f
| Author | SHA1 | Date | |
|---|---|---|---|
| fc862a279f | |||
| fc2b17a3f5 |
2 changed files with 301 additions and 15 deletions
39
examples/1-window.md
Normal file
39
examples/1-window.md
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
# Empty window
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <cglm/cglm.h>
|
||||||
|
|
||||||
|
#define SKR_BACKEND_API 0 // opengl
|
||||||
|
#define SKR_BACKEND_WINDOW 0 // glfw
|
||||||
|
#include <skr/skr.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
SkrState state = SkrInit(&(SkrWindow){
|
||||||
|
.Title = "Hello SKR",
|
||||||
|
.Width = 800,
|
||||||
|
.Height = 600,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!SKR_OK) {
|
||||||
|
fprintf(stderr, "Failed to init window: %s\n", SKR_LAST_ERROR);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glewInit() != GLEW_OK) {
|
||||||
|
fprintf(stderr, "Failed to init GLEW\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SkrTriangle(&state);
|
||||||
|
|
||||||
|
while (!SkrWindowShouldClose(state.Window)) {
|
||||||
|
SkrRendererRender(&state);
|
||||||
|
}
|
||||||
|
|
||||||
|
SkrFinalize(&state);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
277
skr/skr.h
277
skr/skr.h
|
|
@ -67,6 +67,13 @@ typedef enum SkrApiBackendType {
|
||||||
/* Default API if none was specified: GL */
|
/* Default API if none was specified: GL */
|
||||||
#define SKR_BACKEND_API SKR_BACKEND_API_GL
|
#define SKR_BACKEND_API SKR_BACKEND_API_GL
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#if !defined(VULKAN_H_)
|
||||||
|
typedef struct VkPipeline_T* VkPipeline;
|
||||||
|
typedef struct VkPipelineLayout_T* VkPipelineLayout;
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -190,6 +197,22 @@ typedef struct SkrShader {
|
||||||
const char* Path;
|
const char* Path;
|
||||||
} SkrShader;
|
} SkrShader;
|
||||||
|
|
||||||
|
static SkrShader skr_fps_camera_vert = {
|
||||||
|
GL_VERTEX_SHADER,
|
||||||
|
(char*){"#version 330 core\n"
|
||||||
|
"layout (location = 0) in vec3 aPos;\n"
|
||||||
|
"layout (location = 1) in vec2 aTexCoord;\n"
|
||||||
|
"out vec2 TexCoord;\n"
|
||||||
|
"uniform mat4 model;\n"
|
||||||
|
"uniform mat4 view;\n"
|
||||||
|
"uniform mat4 projection;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
"gl_Position = projection * view * model * vec4(aPos, "
|
||||||
|
"1.0f);\n"
|
||||||
|
"TexCoord = vec2(aTexCoord.x, aTexCoord.y);\n"
|
||||||
|
"}\n"},
|
||||||
|
NULL};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Vertex structure used by the rendering engine.
|
* @brief Vertex structure used by the rendering engine.
|
||||||
*
|
*
|
||||||
|
|
@ -367,6 +390,24 @@ typedef struct SkrMesh {
|
||||||
*/
|
*/
|
||||||
SkrTexture* Textures;
|
SkrTexture* Textures;
|
||||||
unsigned int TextureCount;
|
unsigned int TextureCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Backend-specific rendering data.
|
||||||
|
*
|
||||||
|
* Tagged union that stores handles or objects specific to the graphics
|
||||||
|
* API backend in use. Only the member corresponding to the current
|
||||||
|
* backend type is valid.
|
||||||
|
*/
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
GLuint Program;
|
||||||
|
} GL;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
VkPipeline Pipeline;
|
||||||
|
VkPipelineLayout Layout;
|
||||||
|
} VK;
|
||||||
|
} Backend;
|
||||||
} SkrMesh;
|
} SkrMesh;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -424,13 +465,64 @@ typedef struct SkrWindow {
|
||||||
SkrWindowBackend Backend; /*!< Backend type and handle. */
|
SkrWindowBackend Backend; /*!< Backend type and handle. */
|
||||||
} SkrWindow;
|
} SkrWindow;
|
||||||
|
|
||||||
|
typedef struct SkrShaderProgram {
|
||||||
|
GLuint ID;
|
||||||
|
char* Name;
|
||||||
|
SkrShader* Shaders;
|
||||||
|
unsigned int ShaderCount;
|
||||||
|
} SkrShaderProgram;
|
||||||
|
|
||||||
typedef struct SkrState {
|
typedef struct SkrState {
|
||||||
SkrWindow* Window;
|
SkrWindow* Window;
|
||||||
|
|
||||||
SkrModel* Models;
|
SkrModel* Models;
|
||||||
unsigned int ModelCount;
|
unsigned int ModelCount;
|
||||||
|
|
||||||
|
SkrShaderProgram* Programs;
|
||||||
|
unsigned int ProgramCount;
|
||||||
} SkrState;
|
} SkrState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief First-person camera structure.
|
||||||
|
*
|
||||||
|
* Stores position, orientation, and field-of-view.
|
||||||
|
* Can be controlled by mouse and keyboard input.
|
||||||
|
*/
|
||||||
|
typedef struct SkrCamera {
|
||||||
|
vec3 Position; /*!< Camera position in world space. */
|
||||||
|
vec3 Front; /*!< Normalized forward vector. */
|
||||||
|
vec3 Up; /*!< Normalized up vector. */
|
||||||
|
vec3 Right; /*!< Normalized right vector. */
|
||||||
|
vec3 WorldUp; /*!< Global up direction, usually {0, 1, 0}. */
|
||||||
|
|
||||||
|
float Yaw;
|
||||||
|
float Pitch;
|
||||||
|
float FOV;
|
||||||
|
|
||||||
|
float Sensitivity;
|
||||||
|
float LastX; /*!< Last cursor X position. */
|
||||||
|
float LastY; /*!< Last cursor Y position. */
|
||||||
|
bool FirstMouse; /*!< Whether the first mouse movement has been
|
||||||
|
captured. */
|
||||||
|
bool Initialized;
|
||||||
|
} SkrCamera;
|
||||||
|
|
||||||
|
#define SkrDefaultFPSCamera \
|
||||||
|
(&(SkrCamera){ \
|
||||||
|
.Position = {0.0f, 0.0f, 3.0f}, \
|
||||||
|
.Front = {0.0f, 0.0f, -1.0f}, \
|
||||||
|
.Up = {0.0f, 1.0f, 0.0f}, \
|
||||||
|
.Yaw = -90.0f, \
|
||||||
|
.Pitch = 0.0f, \
|
||||||
|
.FOV = 70.0f, \
|
||||||
|
.Sensitivity = 0.1f, \
|
||||||
|
.LastX = 400.0f, \
|
||||||
|
.LastY = 300.0f, \
|
||||||
|
.FirstMouse = true, \
|
||||||
|
})
|
||||||
|
|
||||||
|
extern SkrCamera* g_skr_camera;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* @brief Set the last error message with source metadata.
|
* @brief Set the last error message with source metadata.
|
||||||
|
|
@ -586,10 +678,54 @@ static inline void m_skr_gl_framebuffer_size_callback(const int width,
|
||||||
static inline void m_skr_gl_glfw_framebuffer_size_callback(GLFWwindow* window,
|
static inline void m_skr_gl_glfw_framebuffer_size_callback(GLFWwindow* window,
|
||||||
const int width,
|
const int width,
|
||||||
const int height) {
|
const int height) {
|
||||||
|
(void)window;
|
||||||
m_skr_gl_framebuffer_size_callback(width, height);
|
m_skr_gl_framebuffer_size_callback(width, height);
|
||||||
m_skr_last_error_clear();
|
m_skr_last_error_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void m_skr_gl_glfw_mouse_callback(GLFWwindow* window,
|
||||||
|
double xposIn, double yposIn) {
|
||||||
|
float xpos = xposIn;
|
||||||
|
float ypos = yposIn;
|
||||||
|
|
||||||
|
if (g_skr_camera->FirstMouse) {
|
||||||
|
g_skr_camera->LastX = xpos;
|
||||||
|
g_skr_camera->LastY = ypos;
|
||||||
|
g_skr_camera->FirstMouse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float xoffset = xpos - g_skr_camera->LastX;
|
||||||
|
float yoffset =
|
||||||
|
g_skr_camera->LastY -
|
||||||
|
ypos; // reversed since y-coordinates go from bottom to top
|
||||||
|
g_skr_camera->LastX = xpos;
|
||||||
|
g_skr_camera->LastY = ypos;
|
||||||
|
|
||||||
|
float sensitivity = g_skr_camera->Sensitivity;
|
||||||
|
xoffset *= sensitivity;
|
||||||
|
yoffset *= sensitivity;
|
||||||
|
|
||||||
|
g_skr_camera->Yaw += xoffset;
|
||||||
|
g_skr_camera->Pitch += yoffset;
|
||||||
|
|
||||||
|
// make sure that when pitch is out of bounds, screen doesn't get
|
||||||
|
// flipped
|
||||||
|
if (g_skr_camera->Pitch > 89.0f)
|
||||||
|
g_skr_camera->Pitch = 89.0f;
|
||||||
|
if (g_skr_camera->Pitch < -89.0f)
|
||||||
|
g_skr_camera->Pitch = -89.0f;
|
||||||
|
|
||||||
|
vec3 front = {0.0f, 0.0f, 0.0f};
|
||||||
|
|
||||||
|
front[0] = cosf(glm_rad(g_skr_camera->Yaw)) *
|
||||||
|
cosf(glm_rad(g_skr_camera->Pitch));
|
||||||
|
front[1] = sinf(glm_rad(g_skr_camera->Pitch));
|
||||||
|
front[2] = sinf(glm_rad(g_skr_camera->Yaw)) *
|
||||||
|
cosf(glm_rad(g_skr_camera->Pitch));
|
||||||
|
|
||||||
|
glm_vec3_normalize_to(front, g_skr_camera->Front);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
* @brief Initialize a GLFW window for OpenGL rendering.
|
* @brief Initialize a GLFW window for OpenGL rendering.
|
||||||
|
|
@ -626,6 +762,11 @@ static inline int m_skr_gl_glfw_init(SkrWindow* w) {
|
||||||
m_skr_gl_glfw_framebuffer_size_callback);
|
m_skr_gl_glfw_framebuffer_size_callback);
|
||||||
glfwMakeContextCurrent(w->Backend.Handler.GLFW);
|
glfwMakeContextCurrent(w->Backend.Handler.GLFW);
|
||||||
|
|
||||||
|
if (g_skr_camera) {
|
||||||
|
glfwSetCursorPosCallback(w->Backend.Handler.GLFW,
|
||||||
|
m_skr_gl_glfw_mouse_callback);
|
||||||
|
}
|
||||||
|
|
||||||
m_skr_last_error_clear();
|
m_skr_last_error_clear();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -922,8 +1063,27 @@ static inline void m_skr_gl_renderer_init() {}
|
||||||
* @internal
|
* @internal
|
||||||
* @brief GL clear screen (color + depth).
|
* @brief GL clear screen (color + depth).
|
||||||
*/
|
*/
|
||||||
static inline void m_skr_gl_renderer_render(void) {
|
static inline void m_skr_gl_renderer_render(SkrState* s) {
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < s->ModelCount; ++i) {
|
||||||
|
SkrModel* model = &s->Models[i];
|
||||||
|
if (!model->Meshes)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < model->MeshCount; ++j) {
|
||||||
|
SkrMesh* mesh = &model->Meshes[j];
|
||||||
|
|
||||||
|
if (mesh->VAO == 0 || mesh->VertexCount == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
glUseProgram(mesh->Backend.GL.Program);
|
||||||
|
glBindVertexArray(mesh->VAO);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, mesh->VertexCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -944,6 +1104,14 @@ static inline void m_skr_gl_renderer_finalize(SkrState* s) {
|
||||||
for (unsigned int j = 0; j < model->MeshCount; ++j) {
|
for (unsigned int j = 0; j < model->MeshCount; ++j) {
|
||||||
SkrMesh* mesh = &model->Meshes[j];
|
SkrMesh* mesh = &model->Meshes[j];
|
||||||
|
|
||||||
|
if (mesh->Textures && mesh->TextureCount > 0) {
|
||||||
|
for (unsigned int t = 0; t < mesh->TextureCount;
|
||||||
|
++t) {
|
||||||
|
glDeleteTextures(1,
|
||||||
|
&mesh->Textures[t].ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mesh->VAO)
|
if (mesh->VAO)
|
||||||
glDeleteVertexArrays(1, &mesh->VAO);
|
glDeleteVertexArrays(1, &mesh->VAO);
|
||||||
if (mesh->VBO)
|
if (mesh->VBO)
|
||||||
|
|
@ -952,8 +1120,14 @@ static inline void m_skr_gl_renderer_finalize(SkrState* s) {
|
||||||
glDeleteBuffers(1, &mesh->EBO);
|
glDeleteBuffers(1, &mesh->EBO);
|
||||||
|
|
||||||
mesh->VAO = mesh->VBO = mesh->EBO = 0;
|
mesh->VAO = mesh->VBO = mesh->EBO = 0;
|
||||||
|
mesh->Backend.GL.Program = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
glUseProgram(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -975,24 +1149,14 @@ static inline void m_skr_gl_glfw_renderer_render(SkrState* s) {
|
||||||
s->Window->InputHandler(s->Window);
|
s->Window->InputHandler(s->Window);
|
||||||
}
|
}
|
||||||
|
|
||||||
glfwPollEvents();
|
|
||||||
|
|
||||||
glfwGetFramebufferSize(s->Window->Backend.Handler.GLFW,
|
glfwGetFramebufferSize(s->Window->Backend.Handler.GLFW,
|
||||||
&s->Window->Width, &s->Window->Height);
|
&s->Window->Width, &s->Window->Height);
|
||||||
|
|
||||||
m_skr_gl_renderer_render();
|
m_skr_gl_renderer_render(s);
|
||||||
|
|
||||||
glfwSwapBuffers(s->Window->Backend.Handler.GLFW);
|
glfwSwapBuffers(s->Window->Backend.Handler.GLFW);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
glfwPollEvents();
|
||||||
* @internal
|
|
||||||
* @brief GLFW Shutdown OpenGL renderer and GLFW.
|
|
||||||
*/
|
|
||||||
static inline void m_skr_gl_glfw_renderer_finalize(SkrState* s) {
|
|
||||||
m_skr_gl_renderer_finalize(s);
|
|
||||||
|
|
||||||
glfwTerminate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1102,6 +1266,9 @@ static inline int SkrWindowShouldClose(SkrWindow* w) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void SkrRendererRender(SkrState* s) {
|
static inline void SkrRendererRender(SkrState* s) {
|
||||||
|
if (!s || !s->Window)
|
||||||
|
return;
|
||||||
|
|
||||||
if (SKR_BACKEND_API == SKR_BACKEND_API_GL) {
|
if (SKR_BACKEND_API == SKR_BACKEND_API_GL) {
|
||||||
if (SKR_BACKEND_WINDOW == SKR_BACKEND_WINDOW_GLFW) {
|
if (SKR_BACKEND_WINDOW == SKR_BACKEND_WINDOW_GLFW) {
|
||||||
m_skr_gl_glfw_renderer_render(s);
|
m_skr_gl_glfw_renderer_render(s);
|
||||||
|
|
@ -1111,10 +1278,90 @@ static inline void SkrRendererRender(SkrState* s) {
|
||||||
|
|
||||||
static inline void SkrFinalize(SkrState* s) {
|
static inline void SkrFinalize(SkrState* s) {
|
||||||
if (SKR_BACKEND_API == SKR_BACKEND_API_GL) {
|
if (SKR_BACKEND_API == SKR_BACKEND_API_GL) {
|
||||||
if (SKR_BACKEND_WINDOW == SKR_BACKEND_WINDOW_GLFW) {
|
m_skr_gl_renderer_finalize(s);
|
||||||
m_skr_gl_glfw_renderer_finalize(s);
|
|
||||||
|
if (s->Window->Backend.Type == SKR_BACKEND_WINDOW_GLFW) {
|
||||||
|
glfwTerminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->Models = NULL;
|
||||||
|
s->ModelCount = 0;
|
||||||
|
s->Window = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline GLuint m_skr_gl_triangle(SkrState* s) {
|
||||||
|
static SkrMesh mesh = {0};
|
||||||
|
static SkrModel model = {0};
|
||||||
|
|
||||||
|
const char* triangle_vert = "#version 330 core\n"
|
||||||
|
"layout (location = 0) in vec3 aPos;\n"
|
||||||
|
"layout (location = 1) in vec3 aColor;\n"
|
||||||
|
"out vec3 ourColor;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" gl_Position = vec4(aPos, 1.0);\n"
|
||||||
|
" ourColor = aColor;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const char* triangle_frag = "#version 330 core\n"
|
||||||
|
"out vec4 FragColor;\n"
|
||||||
|
"in vec3 ourColor;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" FragColor = vec4(ourColor, 1.0f);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
SkrShader shaders[] = {
|
||||||
|
{GL_VERTEX_SHADER, triangle_vert, NULL},
|
||||||
|
{GL_FRAGMENT_SHADER, triangle_frag, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
mesh.Backend.GL.Program =
|
||||||
|
m_skr_gl_create_program_from_shaders(shaders, 2);
|
||||||
|
glUseProgram(mesh.Backend.GL.Program);
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &mesh.VAO);
|
||||||
|
glGenBuffers(1, &mesh.VBO);
|
||||||
|
glBindVertexArray(mesh.VAO);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, mesh.VBO);
|
||||||
|
|
||||||
|
float vertices[] = {0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
|
||||||
|
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,
|
||||||
|
GL_STATIC_DRAW);
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float),
|
||||||
|
(void*)0);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float),
|
||||||
|
(void*)(3 * sizeof(float)));
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
mesh.VertexCount = 3;
|
||||||
|
model.Meshes = &mesh;
|
||||||
|
model.MeshCount = 1;
|
||||||
|
|
||||||
|
s->Models = &model;
|
||||||
|
s->ModelCount = 1;
|
||||||
|
|
||||||
|
return mesh.Backend.GL.Program;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void SkrTriangle(SkrState* s) {
|
||||||
|
if (SKR_BACKEND_API == SKR_BACKEND_API_GL) {
|
||||||
|
m_skr_gl_triangle(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void SkrInitCamera(SkrState* s, SkrShader vert) {}
|
||||||
|
|
||||||
|
static inline void SkrCaptureCursor(SkrState* s) {
|
||||||
|
if (s->Window->Backend.Type == SKR_BACKEND_WINDOW_GLFW) {
|
||||||
|
glfwSetInputMode(s->Window->Backend.Handler.GLFW, GLFW_CURSOR,
|
||||||
|
GLFW_CURSOR_DISABLED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue