basic framework OK

This commit is contained in:
VisualGMQ 2022-01-30 21:24:16 +08:00
commit 96bb3c3611
25 changed files with 12160 additions and 0 deletions

18
Makefile Normal file
View File

@ -0,0 +1,18 @@
GLFW_DEP = -L./libs/glfw/ -lglfw
GLAD_DEP = -I./libs/glad/include
STB_IMAGE_DEP = -I./libs/stb_image
SRC = $(wildcard ./*.cpp) ./libs/glad/src/gl.c ./libs/stb_image/stbi_image.cpp
CPP_FLAGS = -std=c++17
game.out: $(SRC)
$(CXX) $^ ${GLFW_DEP} -o $@ ${GLAD_DEP} ${STB_IMAGE_DEP} ${CPP_FLAGS}
.PHONY:clean pack
clean:
-rm *.o
-rm *.out
pack:
-rm -r output
-mkdir output
-mv game.out output/
-cp libs/glfw/libglfw.3.dylib output/

57
engine.cpp Normal file
View File

@ -0,0 +1,57 @@
#include "engine.hpp"
#include "event.hpp"
void error_callback(int error, const char* description) {
fprintf(stderr, "Error: %s\n", description);
}
void Engine::Init(const std::string& title, const Size& size) {
if (!glfwInit()) {
throw std::runtime_error("glfw init failed");
}
glfwSetErrorCallback(error_callback);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// only for MacOS
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
window_ = glfwCreateWindow(size.x, size.y,
title.c_str(),
NULL, NULL);
if (!window_) {
glfwTerminate();
throw std::runtime_error("glfw window create failed");
}
glfwMakeContextCurrent(window_);
glfwSetFramebufferSizeCallback(engine.GetWindow(), OnWindowResize);
Renderer::Init();
Renderer::SetViewport(0, 0, size.x, size.y);
}
void Engine::SwapContext() {
glfwSwapBuffers(window_);
}
void Engine::PollEvent() {
glfwPollEvents();
}
void Engine::Shutdown() {
glfwDestroyWindow(window_);
glfwTerminate();
}
void Engine::Update() {
}
void Engine::Render() {
}
Engine engine;

33
engine.hpp Normal file
View File

@ -0,0 +1,33 @@
#pragma once
#include "pch.hpp"
#include "libmath.hpp"
#include "renderer.hpp"
#include <string>
#include <exception>
class Engine final {
public:
void Init(const std::string& title, const Size& size);
void Shutdown();
void Exit() { shouldExit_ = true; }
bool ShouldExit() const { return glfwWindowShouldClose(window_); }
// TODO implement your logic here
void Update();
// TODO implement your render here
void Render();
GLFWwindow* GetWindow() { return window_; }
void SwapContext();
void PollEvent();
private:
bool shouldExit_ = false;
// window
GLFWwindow* window_;
};
extern Engine engine;

5
event.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "event.hpp"
void OnWindowResize(GLFWwindow* window, int width, int height) {
Renderer::SetViewport(0, 0, width, height);
}

5
event.hpp Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include "renderer.hpp"
void OnWindowResize(GLFWwindow* window, int width, int height);
void OnKeyDown(GLFWwindow* window, int key, int scancode, int action, int mods);

19
glhelpfunc.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "glhelpfunc.hpp"
#define CASE(e) case e: return #e;
const char* GLGetErrorString(GLenum err) {
switch (err) {
CASE(GL_NO_ERROR)
CASE(GL_INVALID_ENUM)
CASE(GL_INVALID_VALUE)
CASE(GL_INVALID_OPERATION)
CASE(GL_OUT_OF_MEMORY)
CASE(GL_INVALID_FRAMEBUFFER_OPERATION)
default:
return "Unknown OpenGL Error";
}
return "Unknown Error";
}
#undef CASE

15
glhelpfunc.hpp Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include "pch.hpp"
#include "log.hpp"
const char* GLGetErrorString(GLenum);
inline void GLClearError() {
while (glGetError() != GL_NO_ERROR) {}
}
#define GL_CALL(statement) do { \
GLClearError(); \
statement; \
GLenum ___err_inner_use = glGetError(); \
if (___err_inner_use != GL_NO_ERROR) Log("OpenGL Error: %s", GLGetErrorString(___err_inner_use)); \
} while(0)

41
libmath.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "libmath.hpp"
Point operator+(const Point& p1, const Point& p2) {
return Point{p1.x + p2.x, p1.y + p2.y};
}
Point operator-(const Point& p1, const Point& p2) {
return Point{p1.x - p2.x, p1.y - p2.y};
}
Point operator*(const Point& p1, const Point& p2) {
return Point{p1.x * p2.x, p1.y * p2.y};
}
Point operator/(const Point& p1, const Point& p2) {
return Point{p1.x / p2.x, p1.y / p2.y};
}
Point& operator+=(Point& p1, const Point& p2) {
p1.x += p2.x;
p1.y += p2.y;
return p1;
}
Point& operator-=(Point& p1, const Point& p2) {
p1.x -= p2.x;
p1.y -= p2.y;
return p1;
}
Point& operator*=(Point& p1, const Point& p2) {
p1.x *= p2.x;
p1.y *= p2.y;
return p1;
}
Point& operator/=(Point& p1, const Point& p2) {
p1.x /= p2.x;
p1.y /= p2.y;
return p1;
}

32
libmath.hpp Normal file
View File

@ -0,0 +1,32 @@
#pragma once
struct Point {
float x;
float y;
};
struct Rect {
float x;
float y;
float w;
float h;
};
struct Color {
float r;
float g;
float b;
float a;
};
using Size = Point;
using Rect = Rect;
Point operator+(const Point& p1, const Point& p2);
Point operator-(const Point& p1, const Point& p2);
Point operator*(const Point& p1, const Point& p2);
Point operator/(const Point& p1, const Point& p2);
Point& operator+=(Point& p1, const Point& p2);
Point& operator-=(Point& p1, const Point& p2);
Point& operator*=(Point& p1, const Point& p2);
Point& operator/=(Point& p1, const Point& p2);

View File

@ -0,0 +1,311 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* The master copy of khrplatform.h is maintained in the Khronos EGL
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
* The last semantic modification to khrplatform.h was at commit ID:
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by filing pull requests or issues on
* the EGL Registry repository linked above.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */

2139
libs/glad/include/glad/gl.h Normal file

File diff suppressed because it is too large Load Diff

1127
libs/glad/src/gl.c Normal file

File diff suppressed because it is too large Load Diff

BIN
libs/glfw/libglfw.3.dylib Executable file

Binary file not shown.

BIN
libs/glfw/libglfw3.a Normal file

Binary file not shown.

7873
libs/stb_image/stb_image.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

5
log.hpp Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include "pch.hpp"
#define Log(msg, ...) printf("[%s: %d] " msg, __func__, __LINE__, ## __VA_ARGS__)

19
main.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "engine.hpp"
#include "event.hpp"
int main(int argc, char** argv) {
engine.Init("sandbox", Size{720, 480});
Color color{0.1, 0.1, 0.1, 1};
Renderer::SetClearColor(color);
while (!engine.ShouldExit()) {
Renderer::Clear();
engine.PollEvent();
engine.Update();
engine.Render();
engine.SwapContext();
}
engine.Shutdown();
return 0;
}

11
pch.hpp Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "glad/gl.h"
#include "GLFW/glfw3.h"
#include "stb_image.h"
#include <string>
#include <exception>
#include <vector>
#include <iostream>
#include <memory>
#include <fstream>

41
renderer.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "renderer.hpp"
struct RenderContext {
};
void Renderer::Init() {
if (!gladLoadGL(glfwGetProcAddress)) {
glfwTerminate();
throw std::runtime_error("glad load failed");
}
GL_CALL(glEnable(GL_DEPTH_TEST));
GL_CALL(glEnable(GL_STENCIL_TEST));
}
void Renderer::SetClearColor(const Color& color) {
GL_CALL(glClearColor(color.r, color.g, color.b, color.a));
}
void Renderer::DrawLine(const Point& p1, const Point& p2) {
}
void Renderer::DrawRect(const Rect& rect) {
}
void Renderer::FillRect(const Rect& rect) {
}
void Renderer::SetDrawColor(const Color& color) {
}
void Renderer::Clear() {
GL_CALL(glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT));
}
void Renderer::SetViewport(int x, int y, int w, int h) {
GL_CALL(glViewport(x, y, w, h));
}
void Renderer::Shutdown() {}

18
renderer.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include "libmath.hpp"
#include "texture.hpp"
#include "pch.hpp"
#include "glhelpfunc.hpp"
class Renderer final {
public:
static void Init();
static void Shutdown();
static void SetClearColor(const Color& color);
static void SetDrawColor(const Color& color);
static void Clear();
static void DrawLine(const Point& p1, const Point& p2);
static void DrawRect(const Rect& rect);
static void FillRect(const Rect& rect);
static void SetViewport(int x, int y, int w, int h);
};

277
shader.cpp Normal file
View File

@ -0,0 +1,277 @@
#include "shader.hpp"
SourceCode::SourceCode(const std::string& code)
: code_(code) {}
Shader::ShaderStruct::ShaderStruct(const SourceCode& code, Shader::ShaderStruct::Type type) {
if (code.Empty()) { return; }
switch (type) {
case ShaderStruct::Vertex:
Log("compiling vertex shader ...");
GL_CALL(shader_ = glCreateShader(GL_VERTEX_SHADER));
break;
case Fragment:
Log("compiling fragment shader ...");
GL_CALL(shader_ = glCreateShader(GL_FRAGMENT_SHADER));
break;
case Geometry:
Log("compiling geometry shader ...");
GL_CALL(shader_ = glCreateShader(GL_GEOMETRY_SHADER));
break;
}
if (shader_ == 0) {
Log("create shader failed");
} else {
const GLchar* const sources[] = {code.GetCode().c_str()};
GL_CALL(glShaderSource(shader_, 1, sources, nullptr));
GL_CALL(glCompileShader(shader_));
GLint err;
GL_CALL(glGetShaderiv(shader_, GL_COMPILE_STATUS, &err));
if (err == GL_FALSE) {
char buf[1024] = {0};
GL_CALL(glGetShaderInfoLog(shader_, sizeof(buf), nullptr, buf));
Log("shader compile failed:\n%s", buf);
}
}
}
Shader::ShaderStruct::~ShaderStruct() {
GL_CALL(glDeleteShader(shader_));
}
Shader::Shader(const SourceCode* vertex,
const SourceCode* fragment,
const SourceCode* geometry) {
if (vertex) {
shaders_[0].reset(new ShaderStruct(*vertex, ShaderStruct::Vertex));
}
if (fragment) {
shaders_[1].reset(new ShaderStruct(*fragment, ShaderStruct::Fragment));
}
if (geometry) {
shaders_[2].reset(new ShaderStruct(*geometry, ShaderStruct::Geometry));
}
GL_CALL(program_ = glCreateProgram());
if (program_ == 0) {
Log("create shader program failed");
} else {
for (const auto& shader : shaders_) {
if (shader) {
GL_CALL(glAttachShader(program_, shader->Get()));
}
}
GL_CALL(glLinkProgram(program_));
GLint err;
GL_CALL(glGetProgramiv(program_, GL_LINK_STATUS, &err));
if (err == GL_FALSE) {
char buf[1024] = {0};
GL_CALL(glGetProgramInfoLog(program_, sizeof(buf), nullptr, buf));
Log("link shader program failed:\n%s", buf);
}
}
}
Shader::~Shader() {
for (auto& shader : shaders_)
shader.reset();
GL_CALL(glDeleteProgram(program_));
}
void Shader::SetInt(const std::string& name, int i) {
GLint loc;
GL_CALL(loc = glGetUniformLocation(program_, name.c_str()));
if (loc == -1) {
Log("uniform variable %s is not found", name.c_str());
} else {
Use();
GL_CALL(glUniform1i(loc, i));
}
}
void Shader::SetInt2(const std::string& name, int i1, int i2) {
GLint loc;
GL_CALL(loc = glGetUniformLocation(program_, name.c_str()));
if (loc == -1) {
Log("uniform variable %s is not found", name.c_str());
} else {
Use();
GL_CALL(glUniform2i(loc, i1, i2));
}
}
void Shader::SetInt3(const std::string& name, int i1, int i2, int i3) {
GLint loc;
GL_CALL(loc = glGetUniformLocation(program_, name.c_str()));
if (loc == -1) {
Log("uniform variable %s is not found", name.c_str());
} else {
Use();
GL_CALL(glUniform3i(loc, i1, i2, i3));
}
}
void Shader::SetInt4(const std::string& name, int i1, int i2, int i3, int i4) {
GLint loc;
GL_CALL(loc = glGetUniformLocation(program_, name.c_str()));
if (loc == -1) {
Log("uniform variable %s is not found", name.c_str());
} else {
Use();
GL_CALL(glUniform4i(loc, i1, i2, i3, i4));
}
}
void Shader::SetFloat(const std::string& name, float f) {
GLint loc;
GL_CALL(loc = glGetUniformLocation(program_, name.c_str()));
if (loc == -1) {
Log("uniform variable %s is not found", name.c_str());
} else {
Use();
GL_CALL(glUniform1f(loc, f));
}
}
void Shader::SetFloat2(const std::string& name, float f1, float f2) {
GLint loc;
GL_CALL(loc = glGetUniformLocation(program_, name.c_str()));
if (loc == -1) {
Log("uniform variable %s is not found", name.c_str());
} else {
Use();
GL_CALL(glUniform2f(loc, f1, f2));
}
}
void Shader::SetFloat3(const std::string& name, float f1, float f2, float f3) {
GLint loc;
GL_CALL(loc = glGetUniformLocation(program_, name.c_str()));
if (loc == -1) {
Log("uniform variable %s is not found", name.c_str());
} else {
Use();
GL_CALL(glUniform3f(loc, f1, f2, f3));
}
}
void Shader::SetFloat4(const std::string& name, float f1, float f2, float f3, float f4) {
GLint loc;
GL_CALL(loc = glGetUniformLocation(program_, name.c_str()));
if (loc == -1) {
Log("uniform variable %s is not found", name.c_str());
} else {
Use();
GL_CALL(glUniform4f(loc, f1, f2, f3, f4));
}
}
// void Shader::SetMat4(const std::string& name, const glm::mat4& mat, bool transpose) {
// GLint loc;
// GL_CALL(loc = glGetUniformLocation(program_, name.c_str()));
// if (loc == -1) {
// Log("uniform variable %s is not found", name.c_str());
// } else {
// Use();
// GL_CALL(glUniformMatrix4fv(loc, 1, transpose ? GL_TRUE : GL_FALSE, glm::value_ptr(mat)));
// }
// }
// void Shader::SetFloatVec3(const std::string& name, const glm::vec3& data) {
// GLint loc;
// GL_CALL(loc = glGetUniformLocation(program_, name.c_str()));
// if (loc == -1) {
// Log("uniform variable %s is not found", name.c_str());
// } else {
// Use();
// GL_CALL(glUniform3fv(loc, 1, glm::value_ptr(data)));
// }
// }
SourceCodePtr CreateSourceCodeFromFile(const std::string& filename) {
std::ifstream file(filename);
if (file.fail()) {
Log("SourceCodeRes %s load failed", filename.c_str());
return nullptr;
}
std::string code((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
return CreateSourceCode(code);
}
void parseShaderFile(const std::string& code,
std::string& vertexCode,
std::string& geometryCode,
std::string& fragmentCode) {
std::string::size_type pos[3] = {code.find("#type vertex"),
code.find("#type geometry"),
code.find("#type fragment")};
/* 1 - vertex shader code
2 - tessellation shader code
3 - fragment shader code */
std::string* codes[3] = {&vertexCode,
&geometryCode,
&fragmentCode};
// sort three code by their position
if (pos[0] > pos[1]) {
std::swap(pos[0], pos[1]);
std::swap(codes[0], codes[1]);
}
if (pos[1] > pos[2]) {
std::swap(pos[1], pos[2]);
std::swap(codes[1], codes[2]);
}
if (pos[0] > pos[1]) {
std::swap(pos[0], pos[1]);
std::swap(codes[0], codes[1]);
}
// split file in codes
if (pos[0] != std::string::npos) {
if (pos[1] != std::string::npos) {
std::copy_n(code.begin() + pos[0], pos[1] - pos[0], std::back_inserter(*codes[0]));
} else {
std::copy(code.begin() + pos[0], code.end(), std::back_inserter(*codes[0]));
}
}
if (pos[1] != std::string::npos) {
if (pos[2] != std::string::npos) {
std::copy_n(code.begin() + pos[1], pos[2] - pos[1], std::back_inserter(*codes[1]));
} else {
std::copy(code.begin() + pos[1], code.end(), std::back_inserter(*codes[1]));
}
}
if (pos[2] != std::string::npos) {
std::copy(code.begin() + pos[2], code.end(), std::back_inserter(*codes[2]));
}
for (auto& c : codes) {
c->erase(0, c->find_first_of('\n'));
}
}
SourceCodeGroup CreateSourceCodeFromGroup(const std::string& code) {
std::string vertex, geometry, fragment;
parseShaderFile(code, vertex, geometry, fragment);
SourceCodeGroup group;
if (!vertex.empty())
group.vertexCode = CreateSourceCode(vertex);
if (!geometry.empty())
group.geometryCode = CreateSourceCode(geometry);
if (!fragment.empty())
group.fragmentCode = CreateSourceCode(fragment);
return group;
}
SourceCodeGroup CreateSourceCodeFromGroupFile(const std::string& filename) {
std::ifstream file(filename);
if (file.fail()) {
Log("SourceCodeRes %s load failed", filename.c_str());
return {nullptr, nullptr, nullptr};
}
std::string code((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
return CreateSourceCodeFromGroup(code);
}

99
shader.hpp Normal file
View File

@ -0,0 +1,99 @@
#pragma once
#include "pch.hpp"
#include "glhelpfunc.hpp"
#include "log.hpp"
#include "tool.hpp"
class SourceCode {
public:
SourceCode(const std::string& code);
inline bool Empty() const { return code_.empty(); }
inline std::string& GetCode() { return code_; }
inline const std::string& GetCode() const { return code_;}
inline bool HasCode() const { return !code_.empty(); }
private:
std::string code_;
};
inline std::ostream& operator<<(std::ostream& o, const SourceCode& res) {
o << res.GetCode();
return o;
}
class Shader final {
public:
Shader(const SourceCode* vertex,
const SourceCode* fragment,
const SourceCode* geometry = nullptr);
Shader(const Shader&) = delete;
~Shader();
Shader& operator=(const Shader&) = delete;
inline bool Valid() const { return program_ != 0; }
GLuint Get() const { return program_; }
void SetInt(const std::string& name, int i);
void SetInt2(const std::string& name, int i1, int i2);
void SetInt3(const std::string& name, int i1, int i2, int i3);
void SetInt4(const std::string& name, int i1, int i2, int i3, int i4);
void SetFloat(const std::string& name, float f);
void SetFloat2(const std::string& name, float f1, float f2);
void SetFloat3(const std::string& name, float f1, float f2, float f3);
void SetFloat4(const std::string& name, float f1, float f2, float f3, float f4);
// void SetMat4(const std::string& name, const glm::mat4& mat, bool transpose = false);
// void SetFloatVec3(const std::string& name, const glm::vec3&);
inline void Use() const { GL_CALL(glUseProgram(program_)); }
private:
class ShaderStruct final {
public:
enum Type {
Vertex,
Fragment,
Geometry,
};
ShaderStruct(const SourceCode& code, Type type);
~ShaderStruct();
ShaderStruct(const Shader&) = delete;
Shader& operator=(const Shader&) = delete;
inline bool Valid() const { return shader_ != 0; }
GLuint Get() const { return shader_; }
private:
GLuint shader_;
};
GLuint program_;
Unique<ShaderStruct> shaders_[3];
};
using SourceCodePtr = Ref<SourceCode>;
using ShaderPtr = Ref<Shader>;
struct SourceCodeGroup {
SourceCodePtr vertexCode = nullptr;
SourceCodePtr geometryCode = nullptr;
SourceCodePtr fragmentCode = nullptr;
};
inline SourceCodePtr CreateSourceCode(const std::string& code) {
if (code.empty()) {
Log("source code is empty");
return nullptr;
}
return SourceCodePtr(new SourceCode(code));
}
SourceCodePtr CreateSourceCodeFromFile(const std::string& filename);
SourceCodeGroup CreateSourceCodeFromGroup(const std::string& code);
SourceCodeGroup CreateSourceCodeFromGroupFile(const std::string& filename);
inline ShaderPtr CreateShader(const SourceCode* vertex,
const SourceCode* fragment,
const SourceCode* geometry = nullptr) {
return ShaderPtr(new Shader(vertex, fragment, geometry));
}

5
texture.hpp Normal file
View File

@ -0,0 +1,5 @@
#pragma once
class Texture {
// TODO implement your own texture
};

8
tool.hpp Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include "pch.hpp"
template <typename T>
using Unique = std::unique_ptr<T>;
template <typename T>
using Ref = std::shared_ptr<T>;