Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa60274540 |
@@ -74,12 +74,12 @@ class Buffer : public OpenGLObject {
|
|||||||
if (!_id) {
|
if (!_id) {
|
||||||
OPENGL_CALL(glGenBuffers(1, &_id));
|
OPENGL_CALL(glGenBuffers(1, &_id));
|
||||||
}
|
}
|
||||||
bind();
|
this->bind();
|
||||||
return _id;
|
return _id;
|
||||||
}
|
}
|
||||||
virtual void remove() override {
|
virtual void remove() override {
|
||||||
if (_id) {
|
if (_id) {
|
||||||
unbind();
|
this->unbind();
|
||||||
OPENGL_CALL(glDeleteBuffers(1, &_id));
|
OPENGL_CALL(glDeleteBuffers(1, &_id));
|
||||||
_id = 0;
|
_id = 0;
|
||||||
}
|
}
|
||||||
@@ -160,6 +160,18 @@ class ArrayBuffer : public Buffer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class UniformBuffer : public Buffer {
|
||||||
|
protected:
|
||||||
|
GLuint _index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
UniformBuffer();
|
||||||
|
void bind() const override;
|
||||||
|
GLuint bufferIndex() const;
|
||||||
|
GLuint bufferIndex(GLuint);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class ElementBuffer : protected Buffer {
|
class ElementBuffer : protected Buffer {
|
||||||
protected:
|
protected:
|
||||||
GLenum _glslType;
|
GLenum _glslType;
|
||||||
|
|||||||
@@ -158,6 +158,8 @@ class Image<Pixel<T, Channels...>> {
|
|||||||
using Codes = ImageError::Codes;
|
using Codes = ImageError::Codes;
|
||||||
bool _data_managed;
|
bool _data_managed;
|
||||||
T* _data;
|
T* _data;
|
||||||
|
Image(unsigned int x, unsigned int y, T* data, bool managed)
|
||||||
|
: width(x), height(y), _data(data), _data_managed(managed) {}
|
||||||
void clear() {
|
void clear() {
|
||||||
if (_data_managed) {
|
if (_data_managed) {
|
||||||
delete[] _data;
|
delete[] _data;
|
||||||
@@ -171,19 +173,21 @@ class Image<Pixel<T, Channels...>> {
|
|||||||
static constexpr size_t NumberChannels = sizeof...(Channels);
|
static constexpr size_t NumberChannels = sizeof...(Channels);
|
||||||
const unsigned int width;
|
const unsigned int width;
|
||||||
const unsigned int height;
|
const unsigned int height;
|
||||||
static Image&& CreateImageStorage(
|
static Image CreateImageStorage(
|
||||||
unsigned int width,
|
unsigned int width,
|
||||||
unsigned int height,
|
unsigned int height,
|
||||||
T* data=nullptr
|
T* data=nullptr
|
||||||
) {
|
) {
|
||||||
unsigned int data_size = NumberChannels*width*height*sizeof(T);
|
unsigned int data_size = NumberChannels*width*height*sizeof(T);
|
||||||
T* data_ptr = new T[data_size];
|
T* data_ptr = new T[data_size];
|
||||||
auto& ret = Image(width, height, data_ptr);
|
Image ret(width, height, data_ptr, true);
|
||||||
if (data) {
|
if (data) {
|
||||||
std::memcpy(data_ptr, data, data_size);
|
std::memcpy(data_ptr, data, data_size);
|
||||||
|
} else {
|
||||||
|
std::memset(data_ptr, 0x00, data_size);
|
||||||
}
|
}
|
||||||
ret._data_managed = true;
|
ret._data_managed = true;
|
||||||
return std::move(ret);
|
return ret;
|
||||||
}
|
}
|
||||||
Image(unsigned int x, unsigned int y, T* data=nullptr)
|
Image(unsigned int x, unsigned int y, T* data=nullptr)
|
||||||
: width(x), height(y), _data(data), _data_managed(false) {}
|
: width(x), height(y), _data(data), _data_managed(false) {}
|
||||||
@@ -201,8 +205,13 @@ class Image<Pixel<T, Channels...>> {
|
|||||||
}
|
}
|
||||||
const Error<> sizeErr = sizeCompare(cpy);
|
const Error<> sizeErr = sizeCompare(cpy);
|
||||||
if (sizeErr.code!=1) { THROW(sizeErr); }
|
if (sizeErr.code!=1) { THROW(sizeErr); }
|
||||||
_data = cpy._data;
|
if (!cpy._data_managed) {
|
||||||
return this;
|
_data = cpy._data;
|
||||||
|
_data_managed = false;
|
||||||
|
} else {
|
||||||
|
*this = cpy.copy();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
Image& operator=(Image&& mv) {
|
Image& operator=(Image&& mv) {
|
||||||
if (_data_managed) {
|
if (_data_managed) {
|
||||||
@@ -213,7 +222,7 @@ class Image<Pixel<T, Channels...>> {
|
|||||||
_data = mv._data;
|
_data = mv._data;
|
||||||
_data_managed = mv._data_managed;
|
_data_managed = mv._data_managed;
|
||||||
mv._data_managed = false;
|
mv._data_managed = false;
|
||||||
return this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Image() {
|
virtual ~Image() {
|
||||||
@@ -221,7 +230,7 @@ class Image<Pixel<T, Channels...>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const T* data() const { return _data; }
|
const T* data() const { return _data; }
|
||||||
Image<PixelType>&& copy() const {
|
Image<PixelType> copy() const {
|
||||||
return CreateImageStorage(width, height, _data);
|
return CreateImageStorage(width, height, _data);
|
||||||
}
|
}
|
||||||
PixelReference<PixelType> at(unsigned int x, unsigned int y) {
|
PixelReference<PixelType> at(unsigned int x, unsigned int y) {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class OpenGLError : public Error<OpenGLError> {
|
|||||||
static const std::string type;
|
static const std::string type;
|
||||||
static const ErrorCodeMap ErrorMessages;
|
static const ErrorCodeMap ErrorMessages;
|
||||||
static OpenGLError status();
|
static OpenGLError status();
|
||||||
|
static OpenGLError status(const std::string& note);
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpenGLObjectError : public Error<OpenGLObjectError> {
|
class OpenGLObjectError : public Error<OpenGLObjectError> {
|
||||||
@@ -41,7 +42,7 @@ class OpenGLObjectError : public Error<OpenGLObjectError> {
|
|||||||
using Base::Base;
|
using Base::Base;
|
||||||
|
|
||||||
enum Codes : unsigned int {
|
enum Codes : unsigned int {
|
||||||
UNDEFINED, HANGING_OBJECT, INVALID_OBJECT
|
UNDEFINED, HANGING_OBJECT, INVALID_OBJECT, INVALID_CONTEXT
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::string type;
|
static const std::string type;
|
||||||
@@ -60,13 +61,16 @@ class OpenGLObject {
|
|||||||
virtual void unbind() const = 0;
|
virtual void unbind() const = 0;
|
||||||
GLuint id() const { return _id; }
|
GLuint id() const { return _id; }
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using Codes = OpenGLObjectError::Codes;
|
using Codes = OpenGLObjectError::Codes;
|
||||||
OpenGLObject() = default;
|
OpenGLObject();
|
||||||
|
|
||||||
|
void checkObjectContextValidity();
|
||||||
virtual GLuint declare() = 0;
|
virtual GLuint declare() = 0;
|
||||||
virtual void remove() = 0;
|
virtual void remove() = 0;
|
||||||
|
|
||||||
|
const GLFWwindow* const _arena;
|
||||||
GLuint _id = 0;
|
GLuint _id = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,21 +84,21 @@ class OpenGLObject {
|
|||||||
unsigned int line,
|
unsigned int line,
|
||||||
Fn fn
|
Fn fn
|
||||||
) {
|
) {
|
||||||
auto check_ = [file, line]() {
|
auto check_ = [file, line](const std::string& note="") {
|
||||||
const auto no_err = nb::OpenGLError::NO_ERROR;
|
const auto no_err = nb::OpenGLError::NO_ERROR;
|
||||||
auto stat = nb::OpenGLError::status();
|
auto stat = nb::OpenGLError::status(note);
|
||||||
if (stat.code != no_err) {
|
if (stat.code != no_err) {
|
||||||
THROW_W_CODE_LOC(file, line, stat);
|
THROW_W_CODE_LOC(file, line, stat);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if constexpr(std::is_same_v<std::invoke_result_t<Fn>, void>) {
|
if constexpr(std::is_same_v<std::invoke_result_t<Fn>, void>) {
|
||||||
check_();
|
check_("Pre-call state");
|
||||||
fn();
|
fn();
|
||||||
check_();
|
check_("Post-call state");
|
||||||
} else {
|
} else {
|
||||||
check_();
|
check_("Pre-call state");
|
||||||
auto ret = fn();
|
auto ret = fn();
|
||||||
check_();
|
check_("Post-call state");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <NBCore/Errors.hpp>
|
#include <NBCore/Errors.hpp>
|
||||||
#include <NBCore/Utils.hpp>
|
#include <NBCore/Utils.hpp>
|
||||||
|
|
||||||
|
#include <NBGraphics/Buffers.hpp>
|
||||||
#include <NBGraphics/OGLObjects.hpp>
|
#include <NBGraphics/OGLObjects.hpp>
|
||||||
|
|
||||||
namespace nb {
|
namespace nb {
|
||||||
@@ -112,17 +113,22 @@ class Program : public OpenGLObject {
|
|||||||
Program& operator=(Program&&) = delete;
|
Program& operator=(Program&&) = delete;
|
||||||
operator bool();
|
operator bool();
|
||||||
~Program() { remove(); }
|
~Program() { remove(); }
|
||||||
virtual void bind() const override {
|
void bind() const override {
|
||||||
OPENGL_CALL(glUseProgram(_id));
|
OPENGL_CALL(glUseProgram(_id));
|
||||||
}
|
}
|
||||||
virtual void unbind() const override { /* TODO: Some warning of some kind perhaps*/ }
|
void unbind() const override { /* TODO: Some warning of some kind perhaps*/ }
|
||||||
GLint status(GLenum) const;
|
GLint status(GLenum) const;
|
||||||
std::string log() const;
|
std::string log() const;
|
||||||
|
void setUniform(const std::string& blockname, std::shared_ptr<UniformBuffer>);
|
||||||
|
void setUniformBinding(const std::string& blockname, GLuint index);
|
||||||
|
GLuint getUniformBinding(const std::string& blockname) const;
|
||||||
|
|
||||||
friend Base;
|
friend Base;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using Base::_id;
|
using Base::_id;
|
||||||
GLint _success;
|
GLint _success;
|
||||||
|
std::unordered_map<std::string, GLuint> _uniformBindings;
|
||||||
virtual GLuint declare() override {
|
virtual GLuint declare() override {
|
||||||
if (!_id) {
|
if (!_id) {
|
||||||
_id = OPENGL_CALL(glCreateProgram());
|
_id = OPENGL_CALL(glCreateProgram());
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ class RenderTarget : public OpenGLObject {
|
|||||||
using Base = OpenGLObject;
|
using Base = OpenGLObject;
|
||||||
using Base::_id;
|
using Base::_id;
|
||||||
RenderTarget(GLenum target) : Target(target) {}
|
RenderTarget(GLenum target) : Target(target) {}
|
||||||
RenderTarget(RenderTarget&& rhs)
|
|
||||||
: Target(rhs.Target), Base(std::move(rhs)) {}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Base::id;
|
using Base::id;
|
||||||
|
RenderTarget(RenderTarget&& mv);
|
||||||
|
RenderTarget& operator=(RenderTarget&& mv);
|
||||||
const GLenum Target;
|
const GLenum Target;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -57,8 +57,10 @@ class Texture : public RenderTarget {
|
|||||||
public:
|
public:
|
||||||
using Base::id;
|
using Base::id;
|
||||||
using Base::Target;
|
using Base::Target;
|
||||||
|
Texture(Texture&& mv);
|
||||||
|
Texture& operator=(Texture&& mv);
|
||||||
|
|
||||||
virtual void bind() const override {
|
void bind() const override {
|
||||||
if (_id) {
|
if (_id) {
|
||||||
OPENGL_CALL(glBindTexture(Target, _id));
|
OPENGL_CALL(glBindTexture(Target, _id));
|
||||||
} else {
|
} else {
|
||||||
@@ -68,7 +70,7 @@ class Texture : public RenderTarget {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void unbind() const override {
|
void unbind() const override {
|
||||||
OPENGL_CALL(glBindTexture(Target, 0));
|
OPENGL_CALL(glBindTexture(Target, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,13 +121,6 @@ struct OGLPixelFormat;
|
|||||||
template<typename T, typename... Channels>
|
template<typename T, typename... Channels>
|
||||||
struct OGLPixelFormat<Pixel<T, Channels...>>;
|
struct OGLPixelFormat<Pixel<T, Channels...>>;
|
||||||
|
|
||||||
template<>
|
|
||||||
struct OGLPixelFormat<Pixel<uint8_t, Red, Green, Blue>> {
|
|
||||||
static constexpr GLenum glBase = GL_RGB;
|
|
||||||
static constexpr GLenum glFormat = GL_RGB8UI;
|
|
||||||
static constexpr GLenum glData = GL_UNSIGNED_BYTE;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct OGLPixelFormat<Pixel<uint8_t, Red, Green, Blue, Alpha>> {
|
struct OGLPixelFormat<Pixel<uint8_t, Red, Green, Blue, Alpha>> {
|
||||||
static constexpr GLenum glBase = GL_RGBA;
|
static constexpr GLenum glBase = GL_RGBA;
|
||||||
@@ -133,6 +128,27 @@ struct OGLPixelFormat<Pixel<uint8_t, Red, Green, Blue, Alpha>> {
|
|||||||
static constexpr GLenum glData = GL_UNSIGNED_BYTE;
|
static constexpr GLenum glData = GL_UNSIGNED_BYTE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct OGLPixelFormat<Pixel<float, Red, Green, Blue, Alpha>> {
|
||||||
|
static constexpr GLenum glBase = GL_RGBA;
|
||||||
|
static constexpr GLenum glFormat = GL_RGBA32F;
|
||||||
|
static constexpr GLenum glData = GL_FLOAT;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct OGLPixelFormat<Pixel<uint8_t, Red, Green, Blue>> {
|
||||||
|
static constexpr GLenum glBase = GL_RGB;
|
||||||
|
static constexpr GLenum glFormat = GL_RGB8UI;
|
||||||
|
static constexpr GLenum glData = GL_UNSIGNED_BYTE;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct OGLPixelFormat<Pixel<float, Red, Green, Blue>> {
|
||||||
|
static constexpr GLenum glBase = GL_RGB;
|
||||||
|
static constexpr GLenum glFormat = GL_RGB32F;
|
||||||
|
static constexpr GLenum glData = GL_FLOAT;
|
||||||
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct OGLPixelFormat<Pixel<float, Red, Green>> {
|
struct OGLPixelFormat<Pixel<float, Red, Green>> {
|
||||||
static constexpr GLenum glBase = GL_RG;
|
static constexpr GLenum glBase = GL_RG;
|
||||||
@@ -140,6 +156,13 @@ struct OGLPixelFormat<Pixel<float, Red, Green>> {
|
|||||||
static constexpr GLenum glData = GL_FLOAT;
|
static constexpr GLenum glData = GL_FLOAT;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct OGLPixelFormat<Pixel<float, Red>> {
|
||||||
|
static constexpr GLenum glBase = GL_RED;
|
||||||
|
static constexpr GLenum glFormat = GL_R32F;
|
||||||
|
static constexpr GLenum glData = GL_FLOAT;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class Texture2D;
|
class Texture2D;
|
||||||
|
|
||||||
@@ -226,5 +249,19 @@ class Texture1D<Pixel<T, Channels...>> : public Texture {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Texture1DArray;
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
class Texture1DArray<Pixel<T...>> : public Texture {
|
||||||
|
protected:
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Texture::generateMipmaps;
|
||||||
|
Texture1DArray() : Texture(GL_TEXTURE_1D_ARRAY) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace nb
|
} // namespace nb
|
||||||
#endif // _NB_TEXTURES
|
#endif // _NB_TEXTURES
|
||||||
@@ -7,7 +7,9 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <NBCore/Errors.hpp>
|
#include <NBCore/Errors.hpp>
|
||||||
#include <NBCore/Utils.hpp>
|
#include <NBCore/Utils.hpp>
|
||||||
@@ -21,7 +23,8 @@ class GLFWError : public Error<GLFWError> {
|
|||||||
using Base::Base;
|
using Base::Base;
|
||||||
|
|
||||||
enum Codes : unsigned int {
|
enum Codes : unsigned int {
|
||||||
UNDEFINED, INIT_FAILED, GLFW_INTIALIZED, GLAD_FAILED
|
UNDEFINED, INIT_FAILED, GLFW_INTIALIZED, GLAD_FAILED,
|
||||||
|
NOT_MAIN, WINDOW_FAILED
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::string type;
|
static const std::string type;
|
||||||
@@ -84,5 +87,69 @@ protected:
|
|||||||
int gladResponse = -1;
|
int gladResponse = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OGLObjectArena;
|
||||||
|
|
||||||
|
class OGLWindow {
|
||||||
|
using GLFWHint = std::array<int, 2>;
|
||||||
|
private:
|
||||||
|
static inline void CheckForMainThread() {
|
||||||
|
if (nb::CurrentTID != nb::MainTID) {
|
||||||
|
THROW(GLFWError(GLFWError::Codes::NOT_MAIN));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static std::atomic<unsigned int> _count;
|
||||||
|
static std::atomic<bool> _glfwInitialized;
|
||||||
|
static thread_local std::shared_ptr<OGLWindow> _currWindow;
|
||||||
|
static thread_local GLFWwindow* _currArena;
|
||||||
|
|
||||||
|
std::string _title;
|
||||||
|
GLFWwindow* _window_ptr;
|
||||||
|
GLFWwindow* _arena;
|
||||||
|
|
||||||
|
static void SetHintInteger(const std::array<int, 2>&);
|
||||||
|
static void SetHintString(const std::tuple<int, std::string>&);
|
||||||
|
|
||||||
|
OGLWindow(
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
const std::string&,
|
||||||
|
const std::vector<std::array<int, 2>>&,
|
||||||
|
const std::vector<std::tuple<int, std::string>>&
|
||||||
|
);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static inline bool IsGLFWInitialized() { return _glfwInitialized; }
|
||||||
|
static bool InitGLFW(const std::vector<GLFWHint>& hints={});
|
||||||
|
static bool TerminateGLFW();
|
||||||
|
static inline std::shared_ptr<OGLWindow> getCurrentWindow() { return _currWindow; }
|
||||||
|
static inline const GLFWwindow* getCurrentObjectArena() { return _currArena; }
|
||||||
|
static std::shared_ptr<OGLWindow> MakeCurrent(const std::shared_ptr<OGLWindow>&);
|
||||||
|
static inline std::shared_ptr<OGLWindow> DropCurrent() { return MakeCurrent(nullptr); }
|
||||||
|
static std::shared_ptr<OGLWindow> CreateWindow(
|
||||||
|
unsigned int x,
|
||||||
|
unsigned int y,
|
||||||
|
const std::string& title,
|
||||||
|
const std::vector<std::array<int, 2>>& integerHints={},
|
||||||
|
const std::vector<std::tuple<int, std::string>>& stringHints={}
|
||||||
|
);
|
||||||
|
OGLWindow(OGLWindow&&) = delete;
|
||||||
|
OGLWindow(const OGLWindow&) = delete;
|
||||||
|
~OGLWindow();
|
||||||
|
inline bool operator==(const OGLWindow& rhs) { return _window_ptr==rhs._window_ptr; }
|
||||||
|
|
||||||
|
|
||||||
|
int getWindowAttribute(int) const;
|
||||||
|
inline GLFWwindow* getWindowPtr() const { return _window_ptr; }
|
||||||
|
inline std::string getTitle() const { return _title; }
|
||||||
|
std::array<int, 2> getSize() const;
|
||||||
|
std::shared_ptr<OGLWindow> makeSharedContext();
|
||||||
|
|
||||||
|
void makeCurrent() const;
|
||||||
|
void setSize(unsigned int x, unsigned int y);
|
||||||
|
void setTitle(const std::string&);
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@@ -74,6 +74,21 @@ void Buffer::subdata(const ByteVector& data_, GLintptr offset_) {
|
|||||||
subdata(data_.data(), size_);
|
subdata(data_.data(), size_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// class UniformBuffer
|
||||||
|
UniformBuffer::UniformBuffer() : Buffer(GL_UNIFORM_BUFFER) {}
|
||||||
|
|
||||||
|
void UniformBuffer::bind() const {
|
||||||
|
Buffer::bind();
|
||||||
|
OPENGL_CALL(glBindBufferBase(GL_UNIFORM_BUFFER, _index, id()));
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint UniformBuffer::bufferIndex() const { return _index; }
|
||||||
|
|
||||||
|
GLuint UniformBuffer::bufferIndex(GLuint idx) {
|
||||||
|
return (_index = idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// class ElementBuffer
|
||||||
ElementBuffer::ElementBuffer() : Buffer(GL_ELEMENT_ARRAY_BUFFER) {}
|
ElementBuffer::ElementBuffer() : Buffer(GL_ELEMENT_ARRAY_BUFFER) {}
|
||||||
|
|
||||||
ByteVector ElementBuffer::data() const {
|
ByteVector ElementBuffer::data() const {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <NBGraphics/OGLObjects.hpp>
|
#include <NBGraphics/OGLObjects.hpp>
|
||||||
|
#include <NBGraphics/Window.hpp>
|
||||||
|
|
||||||
#ifndef GLENUMSTRPAIR
|
#ifndef GLENUMSTRPAIR
|
||||||
#define GLENUMSTRPAIR(x) {x, #x}
|
#define GLENUMSTRPAIR(x) {x, #x}
|
||||||
@@ -10,7 +11,8 @@ const std::string OpenGLObjectError::type = "nb::OpenGLObjectError";
|
|||||||
const ErrorCodeMap OpenGLObjectError::ErrorMessages = {
|
const ErrorCodeMap OpenGLObjectError::ErrorMessages = {
|
||||||
{ OpenGLObjectError::Codes::UNDEFINED, "Error" },
|
{ OpenGLObjectError::Codes::UNDEFINED, "Error" },
|
||||||
{OpenGLObjectError::Codes::HANGING_OBJECT, "Attempting to leave a hanging OpenGL object"},
|
{OpenGLObjectError::Codes::HANGING_OBJECT, "Attempting to leave a hanging OpenGL object"},
|
||||||
{OpenGLObjectError::Codes::INVALID_OBJECT, "Attempting operation with invalid object"}
|
{OpenGLObjectError::Codes::INVALID_OBJECT, "Attempting operation with invalid object"},
|
||||||
|
{OpenGLObjectError::Codes::INVALID_CONTEXT, "Object not valid with current OpengGL context"}
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string OpenGLError::type = "nb::OpenGLError";
|
const std::string OpenGLError::type = "nb::OpenGLError";
|
||||||
@@ -30,11 +32,28 @@ OpenGLError OpenGLError::status() {
|
|||||||
return OpenGLError(glGetError());
|
return OpenGLError(glGetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLObject::OpenGLObject(OpenGLObject&& rval) {
|
OpenGLError OpenGLError::status(const std::string& note) {
|
||||||
|
return OpenGLError(glGetError(), note);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// class OpenGLObject
|
||||||
|
|
||||||
|
void OpenGLObject::checkObjectContextValidity() {
|
||||||
|
if (_arena != OGLWindow::getCurrentObjectArena()) {
|
||||||
|
THROW(OpenGLObjectError(OpenGLObjectError::INVALID_CONTEXT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLObject::OpenGLObject(OpenGLObject&& rval) : _arena(rval._arena) {
|
||||||
|
checkObjectContextValidity();
|
||||||
*this = std::move(rval);
|
*this = std::move(rval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenGLObject::OpenGLObject() : _arena(OGLWindow::getCurrentObjectArena()) {}
|
||||||
|
|
||||||
OpenGLObject& OpenGLObject::operator=(OpenGLObject&& rhs) {
|
OpenGLObject& OpenGLObject::operator=(OpenGLObject&& rhs) {
|
||||||
|
rhs.checkObjectContextValidity();
|
||||||
if (_id) { THROW(OpenGLObjectError(Codes::HANGING_OBJECT)); }
|
if (_id) { THROW(OpenGLObjectError(Codes::HANGING_OBJECT)); }
|
||||||
_id = rhs._id;
|
_id = rhs._id;
|
||||||
rhs._id = 0;
|
rhs._id = 0;
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ const ErrorCodeMap ProgramError::ErrorMessages = {
|
|||||||
{ProgramErrCodes::LINKING_ERROR, "Linker error"}
|
{ProgramErrCodes::LINKING_ERROR, "Linker error"}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// class Shader
|
||||||
|
|
||||||
Shader::Shader(GLenum target_, const std::string& source_)
|
Shader::Shader(GLenum target_, const std::string& source_)
|
||||||
: Shader(target_, std::vector<std::string>({source_})) {}
|
: Shader(target_, std::vector<std::string>({source_})) {}
|
||||||
|
|
||||||
@@ -54,6 +56,8 @@ std::string Shader::log() const {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// class Program
|
||||||
|
|
||||||
Program::Program(SharedVector<Shader> shaders_) {
|
Program::Program(SharedVector<Shader> shaders_) {
|
||||||
declare();
|
declare();
|
||||||
for (auto shad_ptr : shaders_) {
|
for (auto shad_ptr : shaders_) {
|
||||||
@@ -83,6 +87,26 @@ std::string Program::log() const {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Program::setUniform(const std::string& blockname, std::shared_ptr<UniformBuffer> buffer) {
|
||||||
|
declare();
|
||||||
|
auto idx = OPENGL_CALL(glGetUniformBlockIndex(id(), blockname.data()));
|
||||||
|
if (idx == GL_INVALID_INDEX) {
|
||||||
|
THROW("something");
|
||||||
|
}
|
||||||
|
this->setUniformBinding(blockname, buffer->bufferIndex());
|
||||||
|
OPENGL_CALL(glUniformBlockBinding(
|
||||||
|
id(),
|
||||||
|
idx,
|
||||||
|
_uniformBindings[blockname]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Program::setUniformBinding(const std::string& blockname, GLuint index) {
|
||||||
|
_uniformBindings[blockname] = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint Program::getUniformBinding(const std::string& blockname) const {
|
||||||
|
return _uniformBindings.at(blockname);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,33 @@
|
|||||||
|
|
||||||
namespace nb {
|
namespace nb {
|
||||||
|
|
||||||
|
// class RenderTarget
|
||||||
|
|
||||||
|
RenderTarget::RenderTarget(RenderTarget&& mv) : Target(mv.Target) {
|
||||||
|
*this = std::move(mv);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderTarget& RenderTarget::operator=(RenderTarget&& mv) {
|
||||||
|
if (mv.Target != Target) {
|
||||||
|
THROW(OpenGLObjectError(
|
||||||
|
OpenGLObjectError::INVALID_OBJECT,
|
||||||
|
"Cannot assign RenderTarget of different types."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Base::operator=(std::move(mv));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// class Texture
|
||||||
Texture::Texture(GLenum target_) : Base(target_) {}
|
Texture::Texture(GLenum target_) : Base(target_) {}
|
||||||
|
|
||||||
|
Texture::Texture(Texture&& mv) : Base(mv.Target) {
|
||||||
|
*this = std::move(mv);
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture& Texture::operator=(Texture&& mv) {
|
||||||
|
Base::operator=(std::move(mv));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace nb
|
} // namespace nb
|
||||||
@@ -22,7 +22,9 @@ const ErrorCodeMap GLFWError::ErrorMessages = {
|
|||||||
{GLFWCodes::UNDEFINED, "Error"},
|
{GLFWCodes::UNDEFINED, "Error"},
|
||||||
{GLFWCodes::INIT_FAILED, "GLFW initialization failed"},
|
{GLFWCodes::INIT_FAILED, "GLFW initialization failed"},
|
||||||
{GLFWCodes::GLFW_INTIALIZED, "GLFW has already been initialized"},
|
{GLFWCodes::GLFW_INTIALIZED, "GLFW has already been initialized"},
|
||||||
{GLFWCodes::GLAD_FAILED, "GLAD initialization failed"}
|
{GLFWCodes::GLAD_FAILED, "GLAD initialization failed"},
|
||||||
|
{GLFWCodes::NOT_MAIN, "Action can only be done on main thread"},
|
||||||
|
{GLFWCodes::WINDOW_FAILED, "Failed to initialize window"}
|
||||||
};
|
};
|
||||||
|
|
||||||
using WindowErrorCodes = WindowError::Codes;
|
using WindowErrorCodes = WindowError::Codes;
|
||||||
@@ -34,6 +36,9 @@ const ErrorCodeMap WindowError::ErrorMessages = {
|
|||||||
{WindowErrorCodes::INIT_FAILED, "Could not intialized window"}
|
{WindowErrorCodes::INIT_FAILED, "Could not intialized window"}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// class Window
|
||||||
|
|
||||||
int Window::getGLFWHint(int hint_key) {
|
int Window::getGLFWHint(int hint_key) {
|
||||||
if (GLFWHints.find(hint_key) == GLFWHints.end()) {
|
if (GLFWHints.find(hint_key) == GLFWHints.end()) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -183,4 +188,148 @@ void Window::resize(const std::array<uint16_t, 2> newSize) {
|
|||||||
|
|
||||||
void Window::resize(const uint16_t x, const uint16_t y) { resize({x, y}); }
|
void Window::resize(const uint16_t x, const uint16_t y) { resize({x, y}); }
|
||||||
|
|
||||||
|
// class OGLWindow
|
||||||
|
|
||||||
|
std::atomic<bool> OGLWindow::_glfwInitialized = false;
|
||||||
|
thread_local std::shared_ptr<OGLWindow> OGLWindow::_currWindow = nullptr;
|
||||||
|
thread_local GLFWwindow* OGLWindow::_currArena = nullptr;
|
||||||
|
std::atomic<unsigned int> OGLWindow::_count = 0;
|
||||||
|
|
||||||
|
bool OGLWindow::InitGLFW(const std::vector<GLFWHint>& hints) {
|
||||||
|
if (nb::MainTID != GetTID()) {
|
||||||
|
THROW(GLFWError(GLFWError::NOT_MAIN));
|
||||||
|
}
|
||||||
|
if (!IsGLFWInitialized()) {
|
||||||
|
for (const auto& hint : hints) {
|
||||||
|
glfwInitHint(hint[0], hint[1]);
|
||||||
|
}
|
||||||
|
if (glfwInit()) {
|
||||||
|
OGLWindow::_glfwInitialized.store(true, std::memory_order_release);
|
||||||
|
} else {
|
||||||
|
THROW(GLFWError(GLFWError::INIT_FAILED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IsGLFWInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OGLWindow::TerminateGLFW() {
|
||||||
|
if (nb::MainTID != GetTID()) {
|
||||||
|
THROW(GLFWError(GLFWError::NOT_MAIN));
|
||||||
|
}
|
||||||
|
if (IsGLFWInitialized()) {
|
||||||
|
glfwTerminate();
|
||||||
|
OGLWindow::_glfwInitialized.store(false, std::memory_order_release);
|
||||||
|
}
|
||||||
|
return !IsGLFWInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OGLWindow::SetHintInteger(const std::array<int, 2>& hint) {
|
||||||
|
CheckForMainThread();
|
||||||
|
glfwWindowHint(hint[0], hint[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OGLWindow::SetHintString(const std::tuple<int, std::string>& hint) {
|
||||||
|
CheckForMainThread();
|
||||||
|
glfwWindowHintString(std::get<0>(hint), std::get<1>(hint).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<OGLWindow> OGLWindow::MakeCurrent(const std::shared_ptr<OGLWindow>& window) {
|
||||||
|
auto tmp = _currWindow;
|
||||||
|
_currWindow = window;
|
||||||
|
if (window) {
|
||||||
|
glfwMakeContextCurrent(_currWindow->_window_ptr);
|
||||||
|
_currArena = window->_arena;
|
||||||
|
} else {
|
||||||
|
glfwMakeContextCurrent(nullptr);
|
||||||
|
_currArena = nullptr;
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
OGLWindow::OGLWindow(
|
||||||
|
unsigned int x,
|
||||||
|
unsigned int y,
|
||||||
|
const std::string& title,
|
||||||
|
const std::vector<std::array<int, 2>>& integerHints,
|
||||||
|
const std::vector<std::tuple<int, std::string>>& stringHints
|
||||||
|
) : _title(title) {
|
||||||
|
CheckForMainThread();
|
||||||
|
InitGLFW();
|
||||||
|
for (const auto& hint : integerHints) {
|
||||||
|
SetHintInteger(hint);
|
||||||
|
}
|
||||||
|
for (const auto& hint : stringHints) {
|
||||||
|
SetHintString(hint);
|
||||||
|
}
|
||||||
|
_window_ptr = glfwCreateWindow(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
_title.c_str(),
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if (_window_ptr == NULL) {
|
||||||
|
THROW(GLFWError(GLFWError::Codes::WINDOW_FAILED));
|
||||||
|
}
|
||||||
|
_arena = _window_ptr;
|
||||||
|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
||||||
|
THROW(GLFWError(GLFWError::Codes::GLAD_FAILED));
|
||||||
|
}
|
||||||
|
OGLWindow::_count.fetch_add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<OGLWindow> OGLWindow::CreateWindow(
|
||||||
|
unsigned int x,
|
||||||
|
unsigned int y,
|
||||||
|
const std::string& title,
|
||||||
|
const std::vector<std::array<int, 2>>& integerHints,
|
||||||
|
const std::vector<std::tuple<int, std::string>>& stringHints
|
||||||
|
) {
|
||||||
|
return std::shared_ptr<OGLWindow>( new OGLWindow(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
title,
|
||||||
|
integerHints,
|
||||||
|
stringHints
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
OGLWindow::~OGLWindow() {
|
||||||
|
CheckForMainThread();
|
||||||
|
if (_window_ptr) {
|
||||||
|
if (_window_ptr == _currWindow->_window_ptr) {
|
||||||
|
_currWindow = nullptr;
|
||||||
|
_currArena = nullptr;
|
||||||
|
}
|
||||||
|
glfwDestroyWindow(_window_ptr);
|
||||||
|
_count.fetch_add(-1);
|
||||||
|
if (!_count.load()) {
|
||||||
|
TerminateGLFW();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int OGLWindow::getWindowAttribute(int attr) const {
|
||||||
|
CheckForMainThread();
|
||||||
|
return glfwGetWindowAttrib(_window_ptr, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<int, 2> OGLWindow::getSize() const {
|
||||||
|
CheckForMainThread();
|
||||||
|
int x, y;
|
||||||
|
glfwGetWindowSize(_window_ptr, &x, &y);
|
||||||
|
return {x, y};
|
||||||
|
}
|
||||||
|
|
||||||
|
void OGLWindow::setSize(unsigned int x, unsigned int y) {
|
||||||
|
CheckForMainThread();
|
||||||
|
glfwSetWindowSize(_window_ptr, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OGLWindow::setTitle(const std::string& name) {
|
||||||
|
CheckForMainThread();
|
||||||
|
_title = name;
|
||||||
|
glfwSetWindowTitle(_window_ptr, _title.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -12,10 +12,13 @@
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
LOG("Howdy!");
|
LOG("Howdy!");
|
||||||
nb::Window window(400, 400, "Hello!");
|
auto window = nb::OGLWindow::CreateWindow(
|
||||||
window.setWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
400,
|
||||||
window.setWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
400,
|
||||||
window.init();
|
"Howdy!",
|
||||||
|
{{GLFW_CONTEXT_VERSION_MAJOR, 3},
|
||||||
|
{GLFW_CONTEXT_VERSION_MINOR, 3}}
|
||||||
|
);
|
||||||
|
|
||||||
auto vert = std::make_shared<nb::Shader>(
|
auto vert = std::make_shared<nb::Shader>(
|
||||||
GL_VERTEX_SHADER,
|
GL_VERTEX_SHADER,
|
||||||
@@ -66,7 +69,7 @@ int main() {
|
|||||||
}, indxs);
|
}, indxs);
|
||||||
LOG(prog.log());
|
LOG(prog.log());
|
||||||
|
|
||||||
GLFWwindow* window_ptr = window.getWindow();
|
GLFWwindow* window_ptr = window->getWindowPtr();
|
||||||
while(!glfwWindowShouldClose(window_ptr)) {
|
while(!glfwWindowShouldClose(window_ptr)) {
|
||||||
OPENGL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
|
OPENGL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));
|
||||||
OPENGL_CALL(glClear(GL_COLOR_BUFFER_BIT));
|
OPENGL_CALL(glClear(GL_COLOR_BUFFER_BIT));
|
||||||
|
|||||||
Reference in New Issue
Block a user