summaryrefslogtreecommitdiff
path: root/lib/glArrays.h
blob: 1cf2fbf9d7f3eacdeb276534c9af4647f9740439 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#pragma once

#include <algorithm> // IWYU pragma: keep
#include <array>
#include <cstddef>
#include <glad/gl.h>
#include <special_members.h>
#include <utility>

namespace Detail {
	// NOLINTNEXTLINE(readability-identifier-naming)
	class glNamed;

	template<typename Named>
	concept IsglNamed = sizeof(Named) == sizeof(GLuint) && std::is_base_of_v<Detail::glNamed, Named>;
}

template<Detail::IsglNamed, size_t, auto, auto>
// NOLINTNEXTLINE(readability-identifier-naming)
struct glManagedArray;

namespace Detail {
	// NOLINTNEXTLINE(readability-identifier-naming)
	class glNamed {
	public:
		glNamed() = default;
		~glNamed() = default;
		DEFAULT_MOVE_NO_COPY(glNamed);

		GLuint
		operator*() const noexcept
		{
			return name;
		}

		// NOLINTNEXTLINE(hicpp-explicit-conversions)
		operator GLuint() const noexcept
		{
			return name;
		}

	protected:
		GLuint name {};
		template<Detail::IsglNamed, size_t, auto, auto> friend struct ::glManagedArray;
	};
}

// NOLINTNEXTLINE(readability-identifier-naming)
template<Detail::IsglNamed Named, auto Gen, auto Del> struct glManagedSingle : public Named {
	glManagedSingle() noexcept
	{
		(*Gen)(1, &this->name);
	}

	glManagedSingle(glManagedSingle && src) noexcept
	{
		this->name = std::exchange(src.name, 0);
	}

	~glManagedSingle() noexcept
	{
		if (this->name) {
			(*Del)(1, &this->name);
		}
	}

	NO_COPY(glManagedSingle);

	glManagedSingle &
	operator=(glManagedSingle && src) noexcept
	{
		if (this->name) {
			(*Del)(1, &this->name);
		}
		this->name = std::exchange(src.name, 0);
		return *this;
	}
};

template<Detail::IsglNamed Named, size_t N, auto Gen, auto Del>
// NOLINTNEXTLINE(readability-identifier-naming)
struct glManagedArray : public std::array<Named, N> {
	using Arr = std::array<Named, N>;

	glManagedArray() noexcept
	{
		(*Gen)(N, &Arr::front().name);
	}

	glManagedArray(glManagedArray && src) noexcept
	{
		Arr::operator=(std::exchange(static_cast<Arr &>(src), {}));
	}

	~glManagedArray() noexcept
	{
		if (Arr::front().name) {
			(*Del)(N, &Arr::front().name);
		}
	}

	NO_COPY(glManagedArray);

	glManagedArray &
	operator=(glManagedArray && src) noexcept
	{
		if (Arr::front().name) {
			(*Del)(N, &Arr::front().name);
		}
		Arr::operator=(std::exchange(static_cast<Arr &>(src), {}));
		return *this;
	}

	[[nodiscard]] static constexpr size_t
	size() noexcept
	{
		return N;
	}
};

// NOLINTBEGIN(readability-identifier-naming)
template<size_t N> using glFrameBuffers = glManagedArray<Detail::glNamed, N, &glGenFramebuffers, &glDeleteFramebuffers>;
using glFrameBuffer = glManagedSingle<Detail::glNamed, &glGenFramebuffers, &glDeleteFramebuffers>;
template<size_t N>
using glRenderBuffers = glManagedArray<Detail::glNamed, N, &glGenRenderbuffers, &glDeleteRenderbuffers>;
using glRenderBuffer = glManagedSingle<Detail::glNamed, &glGenRenderbuffers, &glDeleteRenderbuffers>;
// NOLINTEND(readability-identifier-naming)