Compare commits
5 Commits
3bdd356ed6
...
a61e07bd54
Author | SHA1 | Date |
---|---|---|
Lephenixnoir | a61e07bd54 | |
Lephenixnoir | 17e50fc79e | |
Lephenixnoir | 7f104395e0 | |
Lephenixnoir | 7e64004de2 | |
Lephenixnoir | ea6cfa2eb0 |
|
@ -53,6 +53,9 @@ GLuint compileShaderFile(GLenum type, char const *path);
|
|||
Returns the shader ID, 0 in case of error. Errors are logged. */
|
||||
GLuint compileShaderSource(GLenum type, char const *code, ssize_t size);
|
||||
|
||||
/* Link a program. This function takes an array of shader IDs. */
|
||||
GLuint link(GLuint *shaders, int count);
|
||||
|
||||
/* Link a program. This function takes a 0-terminated list of shaders IDs and
|
||||
links them into a new program. Returns the new program's ID, or 0 in case
|
||||
of error. Errors are logged. */
|
||||
|
|
|
@ -0,0 +1,330 @@
|
|||
//---------------------------------------------------------------------------//
|
||||
// ," /\ ", Azur: A game engine for CASIO fx-CG and PC //
|
||||
// | _/__\_ | Designed by Lephe' and the Planète Casio community. //
|
||||
// "._`\/'_." License: MIT <https://opensource.org/licenses/MIT> //
|
||||
//---------------------------------------------------------------------------//
|
||||
// azur.gl.shaders: Abstraction of OpenGL 3.3 program objects
|
||||
//
|
||||
// This header provides the ShaderProgram class as an abstraction for OpenGL
|
||||
// shaders. Each shader comes with its own uniform parameters, vertex
|
||||
// attributes, textures, and potentially other settings; ie., it encapsulates
|
||||
// all of the OpenGL state needed to properly run the program.
|
||||
//
|
||||
// ShaderProgram provides the generic mechanisms for using a shader (ie. it has
|
||||
// all the downwards-facing interfaces), but it only exposes a low-level vertex
|
||||
// buffer for describing draw commands. Hence, the intended way to use it is to
|
||||
// subclass it for each shader, and add shader-specific high-level drawing
|
||||
// functions to the derived class.
|
||||
// TODO: Mention how drawing functions add new vertices to the VAO
|
||||
// Access to low-level OpenGL components is provided in case advanced GL things
|
||||
// are needed, but that shouldn't be the case for basic use.
|
||||
//
|
||||
// The initialization of a ShaderProgram goes as follows:
|
||||
// 1. Create a ShaderProgram object (directly or through a derived class);
|
||||
// 2. Load code with one or more calls to addSourceFile(), addSourceText();
|
||||
// 3. Compile the program with compile().
|
||||
//
|
||||
// At this stage, if no error occurred the shader has source code and its
|
||||
// static configuration can be set:
|
||||
// 4. Specify the attribute format (see below).
|
||||
// 5. Load relevant textures or state that are the same for all frames.
|
||||
//
|
||||
// Once that's done, the shader can be used in rendering frames:
|
||||
// 6. Set up frame-specific uniforms, resources, etc.
|
||||
// 7. Queue draw calls.
|
||||
//
|
||||
// TODO: Provide a ShaderPipeline for automatically switching between programs
|
||||
// and checking whether the flow is correct.
|
||||
//
|
||||
// The attribute format describes per-vertex data in the form of a structure
|
||||
// layout, and is basically a meta-level reflection of the structure type used
|
||||
// for VertexAttr. It tells OpenGL how to read the raw vertex data buffer.
|
||||
//---
|
||||
|
||||
#pragma once
|
||||
#include <azur/gl/gl.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace azur::gl {
|
||||
|
||||
template<typename VertexAttr>
|
||||
class ShaderProgram
|
||||
{
|
||||
public:
|
||||
/* Create an empty shader program with no code and no settings. This is an
|
||||
inert call which does nothing, and especially no OpenGL calls. */
|
||||
ShaderProgram() = default;
|
||||
~ShaderProgram();
|
||||
|
||||
/* OpenGL objects cannot be copied, and we don't care about moving yet. */
|
||||
ShaderProgram(ShaderProgram const &) = delete;
|
||||
ShaderProgram(ShaderProgram &&) = delete;
|
||||
|
||||
/*** Initialization ***/
|
||||
|
||||
/* Initialize the shader by allocating some OpenGL objects. */
|
||||
void init();
|
||||
|
||||
/* Add a piece of source code taken from a file. */
|
||||
bool addSourceFile(GLuint type, std::string const &file);
|
||||
/* Add a piece of source given directly as a string. */
|
||||
void addSourceText(GLuint type, std::string const &code)
|
||||
{
|
||||
m_code[type] += code;
|
||||
}
|
||||
void addSourceText(GLuint type, char const *code, ssize_t size = -1)
|
||||
{
|
||||
m_code[type] += std::string {code, size >= 0 ? size : strlen(code)};
|
||||
}
|
||||
|
||||
/* Compile all provided code. */
|
||||
bool compile();
|
||||
|
||||
/* Check whether the program has been compiled successfully. */
|
||||
bool isCompiled() const
|
||||
{
|
||||
return (m_prog != 0);
|
||||
}
|
||||
|
||||
/*** Configuration ***/
|
||||
|
||||
/* Set uniforms. */
|
||||
void setUniform(char const *name, float f);
|
||||
void setUniform(char const *name, float f1, float f2);
|
||||
void setUniform(char const *name, float f1, float f2, float f3);
|
||||
void setUniform(char const *name, glm::vec2 const &v2);
|
||||
void setUniform(char const *name, glm::vec3 const &v3);
|
||||
void setUniform(char const *name, glm::vec4 const &v4);
|
||||
void setUniform(char const *name, glm::mat2 const &m2);
|
||||
void setUniform(char const *name, glm::mat3 const &m3);
|
||||
void setUniform(char const *name, glm::mat4 const &m4);
|
||||
|
||||
/*** Generating draw commands ***/
|
||||
|
||||
/* Add a vertex to the list of vertices for this frame. */
|
||||
void addVertex(VertexAttr &&attr)
|
||||
{
|
||||
m_vertices.push_pack(std::move(attr));
|
||||
}
|
||||
|
||||
/* Add three new vertices (makes a triangle in GL_TRIANGLES mode). */
|
||||
void addVertexTriangle(
|
||||
VertexAttr const &a1, VertexAttr const &a2, VertexAttr const &a3)
|
||||
{
|
||||
m_vertices.push_back(a1);
|
||||
m_vertices.push_back(a2);
|
||||
m_vertices.push_back(a3);
|
||||
}
|
||||
|
||||
/* Add two side-sharing triangles (makes a quad in GL_TRIANGLES mode).
|
||||
VertexAttr must be copyable. */
|
||||
void addVertexQuad(VertexAttr const &a1, VertexAttr const &a2,
|
||||
VertexAttr const &a3, VertexAttr const &a4)
|
||||
{
|
||||
m_vertices.push_back(a1);
|
||||
m_vertices.push_back(a2);
|
||||
m_vertices.push_back(a3);
|
||||
m_vertices.push_back(a2);
|
||||
m_vertices.push_back(a3);
|
||||
m_vertices.push_back(a4);
|
||||
}
|
||||
|
||||
/* Direct access to vertex list, to facilitate faster methods of building a
|
||||
vertex list for any given frame. */
|
||||
std::vector<VertexAttr> &vertices()
|
||||
{
|
||||
return m_vertices;
|
||||
}
|
||||
|
||||
/* Queue a draw call. Indices should be within the range of vertices pushed
|
||||
to the VAO at the time of the call. Info for this call is kept in memory
|
||||
until the rendering phase, so the VAO and the order should be valid
|
||||
until the end of the frame.
|
||||
|
||||
With queueDrawArrays, the vertices at positions [first .. first+count)
|
||||
of the VBO are used to render. With queueDrawElements, the vertices at
|
||||
positions ind[0], .., ind[count-1] are used. Depending on mode, these
|
||||
are combined in pairs, triples, or other ways to render primitives. */
|
||||
void queueDrawArrays(GLenum mode, GLint first, GLsizei count);
|
||||
void queueDrawElements(GLenum mode, GLsizei count, uint8_t const *ind);
|
||||
void queueDrawElements(GLenum mode, GLsizei count, uint16_t const *ind);
|
||||
void queueDrawElements(GLenum mode, GLsizei count, uint32_t const *ind);
|
||||
|
||||
/*** Executing commands ***/
|
||||
|
||||
/* Load buffer data; this is usually executed once at the beginning of the
|
||||
frame. (This is normally called by ShaderPipeline::render().) */
|
||||
void loadBuffer();
|
||||
|
||||
/* Switch to this shader program. This should be called before executing a
|
||||
draw command if the previous shader to run was different. (This is
|
||||
normally called by ShaderPipeline::render().) */
|
||||
void useProgram();
|
||||
|
||||
|
||||
protected:
|
||||
/* Program ID */
|
||||
GLuint m_prog = 0;
|
||||
/* Vertex Array Object and Vertex Buffer Object with parameters */
|
||||
GLuint m_vao = 0, m_vbo = 0;
|
||||
/* Size of the VBO on the GPU */
|
||||
size_t m_vboSize = 0;
|
||||
|
||||
private:
|
||||
/* Map from program type (vertex/etc/fragment shader) to code during the
|
||||
construction phase. */
|
||||
std::map<GLuint, std::string> m_code;
|
||||
/* List of vertices during rendering. */
|
||||
std::vector<VertexAttr> m_vertices;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::init()
|
||||
{
|
||||
glGenVertexArrays(1, &m_vao);
|
||||
glGenBuffers(1, &m_vbo);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ShaderProgram<T>::~ShaderProgram()
|
||||
{
|
||||
glDeleteProgram(m_prog);
|
||||
glDeleteBuffers(1, &m_vbo);
|
||||
glDeleteVertexArrays(1, &m_vao);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool ShaderProgram<T>::addSourceFile(
|
||||
GLuint type, std::string const &file)
|
||||
{
|
||||
extern char *load_file(char const *, size_t *);
|
||||
char *data = load_file(file.c_str(), nullptr);
|
||||
if(!data)
|
||||
return false;
|
||||
|
||||
m_code[type] += data;
|
||||
delete[] data;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool ShaderProgram<T>::compile()
|
||||
{
|
||||
/* List of shader descriptors obtained from OpenGL. */
|
||||
std::vector<GLuint> m_shaders;
|
||||
bool success = true;
|
||||
|
||||
for(auto const &[type, code]: m_code) {
|
||||
GLuint id = compileShaderSource(type, code.c_str(), -1);
|
||||
if(id != 0)
|
||||
m_shaders.push_back(id);
|
||||
else
|
||||
success = false;
|
||||
}
|
||||
|
||||
// TODO: No link error detection?
|
||||
m_prog = success ? link(m_shaders.data(), m_shaders.size()) : 0;
|
||||
|
||||
for(auto id: m_shaders)
|
||||
glDeleteShader(id);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/* TODO: Complete state associated with each program:
|
||||
1. Uniforms (glUniform*)
|
||||
2. Vertex array (glBindVertexArray)
|
||||
3. Textures (glActiveTexture, glBindTexture)
|
||||
4. Other state (glEnable, glDisable, glBlendFunc)
|
||||
Render with glDrawArrays or glDrawElements.
|
||||
|
||||
TODO: Can we minimize switching (eg. texture switching)? */
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::setUniform(char const *name, float f)
|
||||
{
|
||||
glUniform1f(glGetUniformLocation(m_prog, name), f);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::setUniform(char const *name, float f1, float f2)
|
||||
{
|
||||
glUniform2f(glGetUniformLocation(m_prog, name), f1, f2);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::setUniform(
|
||||
char const *name, float f1, float f2, float f3)
|
||||
{
|
||||
glUniform3f(glGetUniformLocation(m_prog, name), f1, f2, f3);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::setUniform(char const *name, glm::vec2 const &v2)
|
||||
{
|
||||
glUniform2fv(glGetUniformLocation(m_prog, name), 1, &v2[0]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::setUniform(char const *name, glm::vec3 const &v3)
|
||||
{
|
||||
glUniform3fv(glGetUniformLocation(m_prog, name), 1, &v3[0]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::setUniform(char const *name, glm::vec4 const &v4)
|
||||
{
|
||||
glUniform4fv(glGetUniformLocation(m_prog, name), 1, &v4[0]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::setUniform(char const *name, glm::mat2 const &m2)
|
||||
{
|
||||
glUniformMatrix2fv(
|
||||
glGetUniformLocation(m_prog, name), 1, GL_FALSE, &m2[0][0]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::setUniform(char const *name, glm::mat3 const &m3)
|
||||
{
|
||||
glUniformMatrix3fv(
|
||||
glGetUniformLocation(m_prog, name), 1, GL_FALSE, &m3[0][0]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::setUniform(char const *name, glm::mat4 const &m4)
|
||||
{
|
||||
glUniformMatrix4fv(
|
||||
glGetUniformLocation(m_prog, name), 1, GL_FALSE, &m4[0][0]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::loadBuffer()
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||
|
||||
/* If the size of the VBO is too small or much larger than needed, resize
|
||||
it; otherwise, simply swap the data without reallocating */
|
||||
if(m_vboSize < m_vertices.size() || m_vboSize > m_vertices.size() * 4) {
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(T) * m_vertices.size(),
|
||||
m_vertices.data(), GL_DYNAMIC_DRAW);
|
||||
m_vboSize = m_vertices.size();
|
||||
}
|
||||
else {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(T) * m_vertices.size(),
|
||||
m_vertices.data());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ShaderProgram<T>::useProgram()
|
||||
{
|
||||
glUseProgram(m_prog);
|
||||
glBindVertexArray(m_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||
}
|
||||
|
||||
} /* namespace azur::gl */
|
|
@ -13,10 +13,17 @@
|
|||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
extern char const *azur_glsl__vs_prelude_gles2;
|
||||
extern char const *azur_glsl__vs_prelude_gl3;
|
||||
extern char const *azur_glsl__fs_prelude_gles2;
|
||||
extern char const *azur_glsl__fs_prelude_gl3;
|
||||
|
||||
namespace azur::gl {
|
||||
|
||||
/* Read the full contents of a file into the heap. Returns an malloc'd pointer
|
||||
on success, NULL if an error occurs. */
|
||||
// TODO: Move the load_file() function to a more convenient fs util header
|
||||
static char *load_file(char const *path, size_t *out_size)
|
||||
char *load_file(char const *path, size_t *out_size)
|
||||
{
|
||||
char *contents = NULL;
|
||||
long size = 0;
|
||||
|
@ -40,13 +47,6 @@ load_file_end:
|
|||
return contents;
|
||||
}
|
||||
|
||||
extern char const *azur_glsl__vs_prelude_gles2;
|
||||
extern char const *azur_glsl__vs_prelude_gl3;
|
||||
extern char const *azur_glsl__fs_prelude_gles2;
|
||||
extern char const *azur_glsl__fs_prelude_gl3;
|
||||
|
||||
namespace azur::gl {
|
||||
|
||||
char const *errorString(GLenum ec)
|
||||
{
|
||||
static char str[32];
|
||||
|
@ -157,7 +157,7 @@ GLuint compileShaderSource(GLenum type, char const *code, ssize_t size)
|
|||
return compileShader(type, code, size, "<inline>");
|
||||
}
|
||||
|
||||
static GLuint link(GLuint *shaders, int count)
|
||||
GLuint link(GLuint *shaders, int count)
|
||||
{
|
||||
GLuint prog = glCreateProgram();
|
||||
if(prog == 0) {
|
||||
|
|
|
@ -116,24 +116,27 @@ struct num8
|
|||
v %= other.v;
|
||||
return *this;
|
||||
}
|
||||
inline constexpr num8 ifloor() {
|
||||
inline constexpr num8 ifloor() const {
|
||||
return 0;
|
||||
}
|
||||
inline constexpr num8 floor() {
|
||||
inline constexpr num8 floor() const {
|
||||
return num8(0);
|
||||
}
|
||||
inline constexpr num8 iceil() {
|
||||
inline constexpr num8 iceil() const {
|
||||
return v != 0;
|
||||
}
|
||||
/* Warning: num8::ceil() always overflows! */
|
||||
inline constexpr num8 ceil() {
|
||||
inline constexpr num8 ceil() const {
|
||||
return num8(0);
|
||||
}
|
||||
inline constexpr num8 frac() {
|
||||
inline constexpr num8 frac() const {
|
||||
num8 x;
|
||||
x.v = v;
|
||||
return x;
|
||||
}
|
||||
inline constexpr num8 abs() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Comparisons with int */
|
||||
|
||||
|
@ -226,27 +229,32 @@ struct num16
|
|||
v %= other.v;
|
||||
return *this;
|
||||
}
|
||||
inline constexpr int ifloor() {
|
||||
inline constexpr int ifloor() const {
|
||||
return v >> 8;
|
||||
}
|
||||
inline constexpr num16 floor() {
|
||||
inline constexpr num16 floor() const {
|
||||
num16 x;
|
||||
x.v = v & 0xff00;
|
||||
return x;
|
||||
}
|
||||
inline constexpr int iceil() {
|
||||
inline constexpr int iceil() const {
|
||||
return (v + 0xff) >> 8;
|
||||
}
|
||||
inline constexpr num16 ceil() {
|
||||
inline constexpr num16 ceil() const {
|
||||
num16 x;
|
||||
x.v = ((v - 1) | 0xff) + 1;
|
||||
return x;
|
||||
}
|
||||
inline constexpr num16 frac() {
|
||||
inline constexpr num16 frac() const {
|
||||
num16 x;
|
||||
x.v = v & 0xff;
|
||||
return x;
|
||||
}
|
||||
inline constexpr num16 abs() const {
|
||||
num16 x;
|
||||
x.v = (v < 0) ? -v : v;
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Comparisons with int */
|
||||
|
||||
|
@ -344,27 +352,32 @@ struct num32
|
|||
v %= other.v;
|
||||
return *this;
|
||||
}
|
||||
inline constexpr int ifloor() {
|
||||
inline constexpr int ifloor() const {
|
||||
return v >> 16;
|
||||
}
|
||||
inline constexpr num32 floor() {
|
||||
inline constexpr num32 floor() const {
|
||||
num32 x;
|
||||
x.v = v & 0xffff0000;
|
||||
return x;
|
||||
}
|
||||
inline constexpr int iceil() {
|
||||
inline constexpr int iceil() const {
|
||||
return (v + 0xffff) >> 16;
|
||||
}
|
||||
inline constexpr num32 ceil() {
|
||||
inline constexpr num32 ceil() const {
|
||||
num32 x;
|
||||
x.v = ((v - 1) | 0xffff) + 1;
|
||||
return x;
|
||||
}
|
||||
inline constexpr num32 frac() {
|
||||
inline constexpr num32 frac() const {
|
||||
num32 x;
|
||||
x.v = v & 0xffff;
|
||||
return x;
|
||||
}
|
||||
inline constexpr num32 abs() const {
|
||||
num32 x;
|
||||
x.v = (v < 0) ? -v : v;
|
||||
return x;
|
||||
}
|
||||
num32 sqrt() const;
|
||||
|
||||
/* Comparisons with int */
|
||||
|
@ -450,27 +463,32 @@ struct num64
|
|||
v %= other.v;
|
||||
return *this;
|
||||
}
|
||||
inline constexpr int ifloor() {
|
||||
inline constexpr int ifloor() const {
|
||||
return v >> 32;
|
||||
}
|
||||
inline constexpr num64 floor() {
|
||||
inline constexpr num64 floor() const {
|
||||
num64 x;
|
||||
x.v = v & 0xffffffff00000000ull;
|
||||
return x;
|
||||
}
|
||||
inline constexpr int iceil() {
|
||||
inline constexpr int iceil() const {
|
||||
return (v >> 32) + ((uint32_t)v != 0);
|
||||
}
|
||||
inline constexpr num64 ceil() {
|
||||
inline constexpr num64 ceil() const {
|
||||
num64 x;
|
||||
x.v = ((v - 1) | 0xffffffffull) + 1;
|
||||
return x;
|
||||
}
|
||||
inline constexpr num64 frac() {
|
||||
inline constexpr num64 frac() const {
|
||||
num64 x;
|
||||
x.v = v & 0xffffffffull;
|
||||
return x;
|
||||
}
|
||||
inline constexpr num64 abs() const {
|
||||
num64 x;
|
||||
x.v = (v < 0) ? -v : v;
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Limits as int */
|
||||
static constexpr int minInt = 0;
|
||||
|
@ -621,6 +639,28 @@ inline constexpr T operator/(T const &x, int n) {
|
|||
return r;
|
||||
}
|
||||
|
||||
/* Comparison with double */
|
||||
|
||||
template<typename T> requires(is_num<T>)
|
||||
inline constexpr bool operator<(T const &x, double const &y) {
|
||||
return x < T(y);
|
||||
}
|
||||
|
||||
template<typename T> requires(is_num<T>)
|
||||
inline constexpr bool operator>=(T const &x, double const &y) {
|
||||
return x >= T(y);
|
||||
}
|
||||
|
||||
template<typename T> requires(is_num<T>)
|
||||
inline constexpr bool operator<=(T const &x, double const &y) {
|
||||
return x <= T(y);
|
||||
}
|
||||
|
||||
template<typename T> requires(is_num<T>)
|
||||
inline constexpr bool operator>(T const &x, double const &y) {
|
||||
return x > T(y);
|
||||
}
|
||||
|
||||
/* Other specific operations */
|
||||
|
||||
inline constexpr num32 num16::dmul(num16 const &x, num16 const &y)
|
||||
|
|
|
@ -22,42 +22,77 @@
|
|||
|
||||
namespace libnum {
|
||||
|
||||
template<typename T, int N> requires(N > 0)
|
||||
struct vec
|
||||
/* _vec_mixin: CRTP support type with common methods
|
||||
This structure type is inherited by all vec<T,N> types. It assumes that the
|
||||
vector type is isomorphic to T[N] and implements all the methods that can be
|
||||
derived from that. */
|
||||
template<typename Vector, typename T, int N> requires(N > 0)
|
||||
struct _vec_mixin
|
||||
{
|
||||
T coords[N];
|
||||
|
||||
inline constexpr int size() const { return N; }
|
||||
/* Number of components in the vector. */
|
||||
inline constexpr int size() const {
|
||||
return N;
|
||||
}
|
||||
|
||||
/* Access to the i-th component as an lvalue. */
|
||||
inline constexpr T &operator[](int i) {
|
||||
return ((T *)this)[i];
|
||||
}
|
||||
inline constexpr T const &operator[](int i) const {
|
||||
return ((T *)this)[i];
|
||||
}
|
||||
|
||||
/* Dot product with another vector of the same size. */
|
||||
constexpr T dot(Vector const &other) const {
|
||||
T r(0);
|
||||
for(int i = 0; i < N; ++i)
|
||||
r += (*this)[i] * other[i];
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Vector norm, squared. */
|
||||
constexpr T norm2() const {
|
||||
T r(0);
|
||||
for(int i = 0; i < N; ++i)
|
||||
r += (*this)[i] * (*this)[i];
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Vector norm. */
|
||||
// TODO: _vec_mixin<T,N>::norm() only works for num (uses .sqrt() method)
|
||||
constexpr T norm() const {
|
||||
return norm2().sqrt();
|
||||
}
|
||||
|
||||
/* Normalized */
|
||||
constexpr Vector normalize() const {
|
||||
return *static_cast<const Vector *>(this) / norm();
|
||||
}
|
||||
};
|
||||
|
||||
/* Vector type implementations. The generic type vec<T,N> uses an array and no
|
||||
specific facilities. The specialized types vec<T,2> through vec<T,4> provide
|
||||
access to members as .x, .y, .z, .w in addition to operator[]. They also
|
||||
provide swizzling-style constructors and methods. */
|
||||
|
||||
template<typename T, int N> requires(N > 0)
|
||||
struct vec: _vec_mixin<vec<T,N>, T, N>
|
||||
{
|
||||
T coords[N];
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct vec<T,2>
|
||||
struct vec<T,2>: _vec_mixin<vec<T,2>, T, 2>
|
||||
{
|
||||
T x, y;
|
||||
|
||||
vec(): x {0}, y {0} {}
|
||||
vec(T _x, T _y): x {_x}, y {_y} {}
|
||||
|
||||
inline constexpr int size() const { return 2; }
|
||||
|
||||
inline constexpr T &operator[](int i) {
|
||||
return ((T *)this)[i];
|
||||
}
|
||||
inline constexpr T const &operator[](int i) const {
|
||||
return ((T *)this)[i];
|
||||
}
|
||||
};
|
||||
using vec2 = vec<num,2>;
|
||||
|
||||
template<typename T>
|
||||
struct vec<T,3>
|
||||
struct vec<T,3>: _vec_mixin<vec<T,3>, T, 3>
|
||||
{
|
||||
T x, y, z;
|
||||
|
||||
|
@ -67,15 +102,6 @@ struct vec<T,3>
|
|||
vec(vec<T,2> v): x {v.x}, y {v.y}, z {0} {}
|
||||
vec(vec<T,2> v, T _z): x {v.x}, y {v.y}, z {_z} {}
|
||||
|
||||
inline constexpr int size() const { return 3; }
|
||||
|
||||
inline constexpr T &operator[](int i) {
|
||||
return ((T *)this)[i];
|
||||
}
|
||||
inline constexpr T const &operator[](int i) const {
|
||||
return ((T *)this)[i];
|
||||
}
|
||||
|
||||
inline constexpr vec<T,2> xy() const {
|
||||
return vec<T,2>(x, y);
|
||||
}
|
||||
|
@ -89,7 +115,7 @@ struct vec<T,3>
|
|||
using vec3 = vec<num,3>;
|
||||
|
||||
template<typename T>
|
||||
struct vec<T,4>
|
||||
struct vec<T,4>: _vec_mixin<vec<T,4>, T, 4>
|
||||
{
|
||||
T x, y, z, w;
|
||||
|
||||
|
@ -101,15 +127,6 @@ struct vec<T,4>
|
|||
vec(vec<T,3> v): x {v.x}, y {v.y}, z {v.z}, w {0} {}
|
||||
vec(vec<T,3> v, T _w): x {v.x}, y {v.y}, z {v.z}, w {_w} {}
|
||||
|
||||
inline constexpr int size() const { return 4; }
|
||||
|
||||
inline constexpr T &operator[](int i) {
|
||||
return ((T *)this)[i];
|
||||
}
|
||||
inline constexpr T const &operator[](int i) const {
|
||||
return ((T *)this)[i];
|
||||
}
|
||||
|
||||
inline constexpr vec<T,3> xyz() const {
|
||||
return vec<T,3>(x, y, z);
|
||||
}
|
||||
|
@ -148,11 +165,10 @@ inline constexpr vec<T,N> &operator*=(vec<T,N> &lhs, T const &rhs) {
|
|||
return lhs;
|
||||
}
|
||||
template<typename T, int N>
|
||||
inline constexpr vec<T,N> &operator*=(vec<T,N> &lhs, vec<T,N> const &rhs) {
|
||||
T r = T(0);
|
||||
inline constexpr vec<T,N> &operator*=(vec<T,N> &lhs, int rhs) {
|
||||
for(int i = 0; i < N; i++)
|
||||
r += lhs[i] * rhs[i];
|
||||
return r;
|
||||
lhs[i] *= rhs;
|
||||
return lhs;
|
||||
}
|
||||
template<typename T, int N>
|
||||
inline constexpr vec<T,N> &operator/=(vec<T,N> &lhs, T const &rhs) {
|
||||
|
@ -160,6 +176,12 @@ inline constexpr vec<T,N> &operator/=(vec<T,N> &lhs, T const &rhs) {
|
|||
lhs[i] /= rhs;
|
||||
return lhs;
|
||||
}
|
||||
template<typename T, int N>
|
||||
inline constexpr vec<T,N> &operator/=(vec<T,N> &lhs, int rhs) {
|
||||
for(int i = 0; i < N; i++)
|
||||
lhs[i] /= rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename T, int N>
|
||||
inline constexpr vec<T,N> operator+(vec<T,N> const &lhs) {
|
||||
|
@ -190,9 +212,17 @@ inline constexpr vec<T,N> operator*(T const &lhs, vec<T,N> rhs) {
|
|||
return rhs;
|
||||
}
|
||||
template<typename T, int N>
|
||||
inline constexpr vec<T,N> operator*(vec<T,N> lhs, int rhs) {
|
||||
return lhs *= rhs;
|
||||
}
|
||||
template<typename T, int N>
|
||||
inline constexpr vec<T,N> operator/(vec<T,N> lhs, T const &rhs) {
|
||||
return lhs /= rhs;
|
||||
}
|
||||
template<typename T, int N>
|
||||
inline constexpr vec<T,N> operator/(vec<T,N> lhs, int rhs) {
|
||||
return lhs /= rhs;
|
||||
}
|
||||
|
||||
/* Comparisons */
|
||||
|
||||
|
|
Loading…
Reference in New Issue