example: add lighted cube

This also copy-pastes all of the math headers I originally wrote in
saturn-examples.
This commit is contained in:
Zack Buhman 2023-12-24 16:24:27 +08:00
parent 59f2819df3
commit befedb9d38
12 changed files with 969 additions and 12 deletions

View File

@ -2,7 +2,7 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
DIR := $(dir $(MAKEFILE_PATH)) DIR := $(dir $(MAKEFILE_PATH))
LIB ?= . LIB ?= .
OPT ?= -O3 OPT ?= -O1
DEBUG ?= -g -gdwarf-4 DEBUG ?= -g -gdwarf-4
GENERATED ?= GENERATED ?=

208
example/cube.cpp Normal file
View File

@ -0,0 +1,208 @@
#include <cstdint>
#include "align.hpp"
#include "vga.hpp"
#include "holly.hpp"
#include "holly/core.hpp"
#include "holly/core_bits.hpp"
#include "holly/ta_fifo_polygon_converter.hpp"
#include "holly/ta_parameter.hpp"
#include "holly/ta_bits.hpp"
#include "holly/region_array.hpp"
#include "holly/background.hpp"
#include "holly/texture_memory_alloc.hpp"
#include "memorymap.hpp"
#include "serial.hpp"
#include "geometry/cube.hpp"
#include "math/vec4.hpp"
using vec4 = vec<4, float>;
constexpr float half_degree = 0.01745329f / 2;
vec3 rotate(const vec3& vertex, float theta)
{
float x = vertex.x;
float y = vertex.y;
float z = vertex.z;
float t;
t = y * cos(theta) - z * sin(theta);
z = y * sin(theta) + z * cos(theta);
y = t;
float theta2 = 3.14 * sin(theta / 2);
t = x * cos(theta2) - z * sin(theta2);
z = x * sin(theta2) + z * cos(theta2);
x = t;
return vec3(x, y, z);
}
void transform(ta_parameter_writer& parameter,
const uint32_t face_ix,
const float theta,
const vec3 lights[2])
{
const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume
| para_control::list_type::opaque
| obj_control::col_type::floating_color
| obj_control::gouraud;
const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::cull_if_positive;
const uint32_t tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog;
parameter.append<global_polygon_type_0>() = global_polygon_type_0(parameter_control_word,
isp_tsp_instruction_word,
tsp_instruction_word,
0);
auto& face = cube::faces[face_ix];
constexpr uint32_t strip_length = 3;
for (uint32_t i = 0; i < strip_length; i++) {
bool end_of_strip = i == strip_length - 1;
// world transform
uint32_t vertex_ix = face[i].vertex - 1;
auto& vertex = cube::vertices[vertex_ix];
auto point = rotate(vertex, theta);
// lighting transform
uint32_t normal_ix = face[i].normal - 1;
auto& normal = cube::normals[normal_ix];
auto n = rotate(normal, theta);
vec4 color = {0.3, 0.3, 0.3, 1.0};
// intensity calculation
{
auto l = lights[0] - point;
auto n_dot_l = dot(n, l);
if (n_dot_l > 0) {
color.x += 0.35 * n_dot_l / (length(n) * length(l));
}
}
{
auto l = lights[1] - point;
auto n_dot_l = dot(n, l);
if (n_dot_l > 0) {
color.y += 0.35 * n_dot_l / (length(n) * length(l));
}
}
float x = point.x;
float y = point.y;
float z = point.z;
// camera transform
z += 3;
// perspective
x = x / z;
y = y / z;
// screen space transform
x *= 240.f;
y *= 240.f;
x += 320.f;
y += 240.f;
z = 1 / z;
parameter.append<vertex_polygon_type_1>() =
vertex_polygon_type_1(x, y, z,
color.w, // alpha
color.x, // r
color.y, // g
color.z, // b
end_of_strip);
}
}
void init_texture_memory(const struct opb_size& opb_size)
{
auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory32);
background_parameter(mem->background, 0xff220000);
region_array2(mem->region_array,
(offsetof (struct texture_memory_alloc, object_list)),
640 / 32, // width
480 / 32, // height
opb_size
);
}
uint32_t _ta_parameter_buf[((32 * (5 * 6 + 1)) + 32) / 4];
void main()
{
vga();
// The address of `ta_parameter_buf` must be a multiple of 32 bytes.
// This is mandatory for ch2-dma to the ta fifo polygon converter.
uint32_t * ta_parameter_buf = align_32byte(_ta_parameter_buf);
constexpr uint32_t ta_alloc = ta_alloc_ctrl::pt_opb::no_list
| ta_alloc_ctrl::tm_opb::no_list
| ta_alloc_ctrl::t_opb::no_list
| ta_alloc_ctrl::om_opb::no_list
| ta_alloc_ctrl::o_opb::_16x4byte;
constexpr struct opb_size opb_size = { .opaque = 16 * 4
, .opaque_modifier = 0
, .translucent = 0
, .translucent_modifier = 0
, .punch_through = 0
};
constexpr uint32_t tiles = (640 / 32) * (320 / 32);
holly.SOFTRESET = softreset::pipeline_soft_reset
| softreset::ta_soft_reset;
holly.SOFTRESET = 0;
core_init();
init_texture_memory(opb_size);
uint32_t frame_ix = 0;
constexpr uint32_t num_frames = 1;
float theta = 0;
vec3 lights[2] = {
{0.f, 0.f, -4.f},
{0.f, 0.f, 0.f},
};
while (1) {
ta_polygon_converter_init(opb_size.total() * tiles, ta_alloc,
640, 480);
//lights[0].x = cos(theta) * 10;
//lights[0].z = sin(theta) * 10;
//lights[1].x = cos(theta + half_degree * 90.f) * 10;
//lights[1].z = sin(theta + half_degree * 90.f) * 10;
auto parameter = ta_parameter_writer(ta_parameter_buf);
for (uint32_t i = 0; i < 12; i++) {
transform(parameter, i, theta, lights);
}
parameter.append<global_end_of_list>() = global_end_of_list();
ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset);
ta_wait_opaque_list();
core_start_render(frame_ix, num_frames);
v_sync_in();
core_wait_end_of_render_video(frame_ix, num_frames);
theta += half_degree;
frame_ix += 1;
}
}

View File

@ -96,6 +96,17 @@ TRANSLUCENCY_OBJ = \
example/translucency.elf: LDSCRIPT = $(LIB)/alt.lds example/translucency.elf: LDSCRIPT = $(LIB)/alt.lds
example/translucency.elf: $(START_OBJ) $(TRANSLUCENCY_OBJ) example/translucency.elf: $(START_OBJ) $(TRANSLUCENCY_OBJ)
CUBE_OBJ = \
example/cube.o \
vga.o \
holly/core.o \
holly/region_array.o \
holly/background.o \
holly/ta_fifo_polygon_converter.o
example/cube.elf: LDSCRIPT = $(LIB)/alt.lds
example/cube.elf: $(START_OBJ) $(CUBE_OBJ)
MACAW_CUBE_OBJ = \ MACAW_CUBE_OBJ = \
example/macaw_cube.o \ example/macaw_cube.o \
vga.o \ vga.o \

View File

@ -54,7 +54,7 @@ vertex cube_faces[][4] = {
}; };
constexpr uint32_t num_faces = (sizeof (cube_faces)) / (sizeof (cube_faces[0])); constexpr uint32_t num_faces = (sizeof (cube_faces)) / (sizeof (cube_faces[0]));
constexpr uint32_t color = 0xffff00ff; constexpr uint32_t color = 0xff0000ff;
static float theta = 0; static float theta = 0;
constexpr float half_degree = 0.01745329f / 2.f; constexpr float half_degree = 0.01745329f / 2.f;
@ -64,7 +64,7 @@ void transform(ta_parameter_writer& parameter,
const uint32_t strip_length) const uint32_t strip_length)
{ {
uint32_t texture_address = (offsetof (struct texture_memory_alloc, texture)); uint32_t texture_address = (offsetof (struct texture_memory_alloc, texture));
parameter.append<global_polygon_type_0>() = global_polygon_type_0(texture_address); parameter.append<global_polygon_type_0>() = global_polygon_type_0();
for (uint32_t i = 0; i < strip_length; i++) { for (uint32_t i = 0; i < strip_length; i++) {
bool end_of_strip = i == strip_length - 1; bool end_of_strip = i == strip_length - 1;
@ -98,10 +98,10 @@ void transform(ta_parameter_writer& parameter,
z = 1 / z; z = 1 / z;
parameter.append<vertex_polygon_type_3>() = parameter.append<vertex_polygon_type_0>() =
vertex_polygon_type_3(x, y, z, vertex_polygon_type_0(x, y, z,
strip_vertices[i].u, //strip_vertices[i].u,
strip_vertices[i].v, //strip_vertices[i].v,
color, color,
end_of_strip); end_of_strip);
} }
@ -111,7 +111,7 @@ void init_texture_memory(const struct opb_size& opb_size)
{ {
auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory32); auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory32);
background_parameter(mem->background); background_parameter(mem->background, 0xffff00ff);
region_array2(mem->region_array, region_array2(mem->region_array,
(offsetof (struct texture_memory_alloc, object_list)), (offsetof (struct texture_memory_alloc, object_list)),
@ -173,7 +173,7 @@ void main()
constexpr uint32_t num_frames = 1; constexpr uint32_t num_frames = 1;
while (1) { while (1) {
ta_polygon_converter_init(opb_size.total() * tiles, ta_alloc); ta_polygon_converter_init(opb_size.total() * tiles, ta_alloc, 640, 480);
auto parameter = ta_parameter_writer(ta_parameter_buf); auto parameter = ta_parameter_writer(ta_parameter_buf);
for (uint32_t i = 0; i < num_faces; i++) { for (uint32_t i = 0; i < num_faces; i++) {
transform(parameter, cube_faces[i], 4); transform(parameter, cube_faces[i], 4);

54
geometry/cube.hpp Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include <cstdint>
#include "math/vec3.hpp"
using vec3 = vec<3, float>;
struct vertex__normal {
uint8_t vertex;
uint8_t normal;
};
using face = vertex__normal[3];
namespace cube {
constexpr vec3 vertices[] = {
{ 1.f, 1.f, -1.f},
{ 1.f, -1.f, -1.f},
{ 1.f, 1.f, 1.f},
{ 1.f, -1.f, 1.f},
{-1.f, 1.f, -1.f},
{-1.f, -1.f, -1.f},
{-1.f, 1.f, 1.f},
{-1.f, -1.f, 1.f},
};
constexpr vec3 normals[] = {
{-0.f, 1.f, -0.f},
{-0.f, -0.f, 1.f},
{-1.f, -0.f, -0.f},
{-0.f, -1.f, -0.f},
{ 1.f, -0.f, -0.f},
{-0.f, -0.f, -1.f},
};
constexpr face faces[] = {
{{5, 1}, {3, 1}, {1, 1}},
{{3, 2}, {8, 2}, {4, 2}},
{{7, 3}, {6, 3}, {8, 3}},
{{2, 4}, {8, 4}, {6, 4}},
{{1, 5}, {4, 5}, {2, 5}},
{{5, 6}, {2, 6}, {6, 6}},
{{5, 1}, {7, 1}, {3, 1}},
{{3, 2}, {7, 2}, {8, 2}},
{{7, 3}, {5, 3}, {6, 3}},
{{2, 4}, {4, 4}, {8, 4}},
{{1, 5}, {3, 5}, {4, 5}},
{{5, 6}, {1, 6}, {2, 6}},
};
constexpr int num_faces = (sizeof (faces)) / (sizeof (face));
}

View File

@ -90,6 +90,67 @@ struct vertex_polygon_type_0 {
{ } { }
}; };
struct vertex_polygon_type_1 {
uint32_t parameter_control_word;
float x;
float y;
float z;
float base_color_alpha;
float base_color_r;
float base_color_g;
float base_color_b;
vertex_polygon_type_1(const float x,
const float y,
const float z,
const float base_color_alpha,
const float base_color_r,
const float base_color_g,
const float base_color_b,
const bool end_of_strip
)
: parameter_control_word( para_control::para_type::vertex_parameter
| (end_of_strip ? para_control::end_of_strip : 0)
)
, x(x)
, y(y)
, z(z)
, base_color_alpha(base_color_alpha)
, base_color_r(base_color_r)
, base_color_g(base_color_g)
, base_color_b(base_color_b)
{ }
};
struct vertex_polygon_type_2 {
uint32_t parameter_control_word;
float x;
float y;
float z;
uint32_t _res0;
uint32_t _res1;
float base_intensity;
uint32_t _res2;
vertex_polygon_type_2(const float x,
const float y,
const float z,
const float base_intensity,
const bool end_of_strip
)
: parameter_control_word( para_control::para_type::vertex_parameter
| (end_of_strip ? para_control::end_of_strip : 0)
)
, x(x)
, y(y)
, z(z)
, _res0(0)
, _res1(0)
, base_intensity(base_intensity)
, _res2(0)
{ }
};
struct vertex_polygon_type_3 { struct vertex_polygon_type_3 {
uint32_t parameter_control_word; uint32_t parameter_control_word;
float x; float x;
@ -171,17 +232,31 @@ struct global_polygon_type_0 {
uint32_t data_size_for_sort_dma; uint32_t data_size_for_sort_dma;
uint32_t next_address_for_sort_dma; uint32_t next_address_for_sort_dma;
global_polygon_type_0(const uint32_t parameter_control_word,
const uint32_t isp_tsp_instruction_word,
const uint32_t tsp_instruction_word,
const uint32_t texture_control_word)
: parameter_control_word(parameter_control_word)
, isp_tsp_instruction_word(isp_tsp_instruction_word)
, tsp_instruction_word(tsp_instruction_word)
, texture_control_word(texture_control_word)
, _res0(0)
, _res1(0)
, data_size_for_sort_dma(0)
, next_address_for_sort_dma(0)
{ }
// untextured // untextured
global_polygon_type_0() global_polygon_type_0()
: parameter_control_word( para_control::para_type::polygon_or_modifier_volume : parameter_control_word( para_control::para_type::polygon_or_modifier_volume
| para_control::list_type::opaque | para_control::list_type::opaque
| obj_control::col_type::packed_color ) | obj_control::col_type::packed_color )
, isp_tsp_instruction_word( isp_tsp_instruction_word::depth_compare_mode::always , isp_tsp_instruction_word( isp_tsp_instruction_word::depth_compare_mode::greater
| isp_tsp_instruction_word::culling_mode::no_culling ) | isp_tsp_instruction_word::culling_mode::no_culling )
, tsp_instruction_word( tsp_instruction_word::src_alpha_instr::src_alpha , tsp_instruction_word( tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::inverse_src_alpha | tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog ) | tsp_instruction_word::fog_control::no_fog )
, texture_control_word( 0 ) , texture_control_word( 0 )
@ -234,6 +309,35 @@ static_assert((offsetof (struct global_polygon_type_0, _res1))
static_assert((offsetof (struct global_polygon_type_0, data_size_for_sort_dma)) == 0x18); static_assert((offsetof (struct global_polygon_type_0, data_size_for_sort_dma)) == 0x18);
static_assert((offsetof (struct global_polygon_type_0, next_address_for_sort_dma)) == 0x1c); static_assert((offsetof (struct global_polygon_type_0, next_address_for_sort_dma)) == 0x1c);
struct global_polygon_type_1 {
uint32_t parameter_control_word;
uint32_t isp_tsp_instruction_word;
uint32_t tsp_instruction_word;
uint32_t texture_control_word;
float face_color_alpha;
float face_color_r;
float face_color_g;
float face_color_b;
global_polygon_type_1(const uint32_t parameter_control_word,
const uint32_t isp_tsp_instruction_word,
const uint32_t tsp_instruction_word,
const uint32_t texture_control_word,
const float face_color_alpha,
const float face_color_r,
const float face_color_g,
const float face_color_b)
: parameter_control_word(parameter_control_word)
, isp_tsp_instruction_word(isp_tsp_instruction_word)
, tsp_instruction_word(tsp_instruction_word)
, texture_control_word(texture_control_word)
, face_color_alpha(face_color_alpha)
, face_color_r(face_color_r)
, face_color_g(face_color_g)
, face_color_b(face_color_b)
{ }
};
struct global_sprite { struct global_sprite {
uint32_t parameter_control_word; uint32_t parameter_control_word;
uint32_t isp_tsp_instruction_word; uint32_t isp_tsp_instruction_word;

120
math/div.hpp Normal file
View File

@ -0,0 +1,120 @@
#pragma once
#include <stdint.h>
#ifndef USE_SH2_DVSR
inline constexpr uint32_t
__udiv32(uint32_t n, uint32_t d)
{
uint32_t q = 0;
uint32_t r = 0;
for (int i = 31; i >= 0; --i) {
q = q << 1;
r = r << 1;
r |= (n >> 31) & 1;
n = n << 1;
if (d <= r) {
r = r - d;
q = q | 1;
}
}
return q;
}
inline constexpr uint32_t
__udiv64_32(uint64_t n, uint32_t base)
{
uint64_t rem = n;
uint64_t b = base;
uint64_t res = 0, d = 1;
uint32_t high = rem >> 32;
if (high >= base) {
high = __udiv32(high, base);
res = (uint64_t)high << 32;
rem -= (uint64_t)(high*base) << 32;
}
while ((int64_t)b > 0 && b < rem) {
b = b+b;
d = d+d;
}
do {
if (rem >= b) {
rem -= b;
res += d;
}
b >>= 1;
d >>= 1;
} while (d);
return res;
}
#else
#include "sh2.h"
inline uint32_t
__udiv64_32(uint64_t n, uint32_t d)
{
sh2.reg.DVSR = d;
sh2.reg.DVDNTH = (uint32_t)(n >> 32);
sh2.reg.DVDNTL = (uint32_t)(n);
// 39 cycles
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
return sh2.reg.DVDNTL;
}
#endif
inline int32_t
__div64_32(int64_t n, int32_t d)
{
uint64_t n_abs = n >= 0 ? (uint64_t)n : -(uint64_t)n;
uint32_t d_abs = d >= 0 ? (uint32_t)d : -(uint32_t)d;
uint32_t q_abs = __udiv64_32(n_abs, d_abs);
return (n < 0) == (d < 0) ? (int32_t)q_abs : -(int32_t)q_abs;
}

124
math/mat4x4.hpp Normal file
View File

@ -0,0 +1,124 @@
#pragma once
#include <utility>
template <int R, int C, typename T>
struct mat;
//
// mat4x4
//
template <typename T>
struct mat<4, 4, T>
{
typedef vec<4, T> row_type;
typedef vec<4, T> col_type;
private:
row_type value[4];
public:
inline constexpr mat();
inline constexpr mat
(
T const& a00, T const& a01, T const& a02, T const& a03,
T const& a10, T const& a11, T const& a12, T const& a13,
T const& a20, T const& a21, T const& a22, T const& a23,
T const& a30, T const& a31, T const& a32, T const& a33
);
inline static constexpr int length() { return 4; }
inline constexpr typename mat<4, 4, T>::row_type const &
operator[](int i) const;
void operator=(const mat<4, 4, T>&) = delete;
};
template<typename T>
inline constexpr mat<4, 4, T>::mat()
: value{std::move(row_type(1, 0, 0, 0)),
std::move(row_type(0, 1, 0, 0)),
std::move(row_type(0, 0, 1, 0)),
std::move(row_type(0, 0, 0, 1))}
{ }
template<typename T>
inline constexpr mat<4, 4, T>::mat
(
T const& a00, T const& a01, T const& a02, T const& a03,
T const& a10, T const& a11, T const& a12, T const& a13,
T const& a20, T const& a21, T const& a22, T const& a23,
T const& a30, T const& a31, T const& a32, T const& a33
)
: value{std::move(row_type(a00, a01, a02, a03)),
std::move(row_type(a10, a11, a12, a13)),
std::move(row_type(a20, a21, a22, a23)),
std::move(row_type(a30, a31, a32, a33))}
{ }
template <typename T>
inline constexpr typename mat<4, 4, T>::row_type const &
mat<4, 4, T>::operator[](int i) const
{
switch (i)
{
default: [[fallthrough]];
case 0:
return value[0];
case 1:
return value[1];
case 2:
return value[2];
case 3:
return value[3];
}
}
template<typename T>
inline constexpr mat<4, 4, T> operator*(mat<4, 4, T> const& m1, mat<4, 4, T> const& m2)
{
#define c(i, j) ( \
m1[i][0] * m2[0][j] \
+ m1[i][1] * m2[1][j] \
+ m1[i][2] * m2[2][j] \
+ m1[i][3] * m2[3][j] )
return mat<4, 4, T>(c(0,0), c(0,1), c(0,2), c(0,3),
c(1,0), c(1,1), c(1,2), c(1,3),
c(2,0), c(2,1), c(2,2), c(2,3),
c(3,0), c(3,1), c(3,2), c(3,3));
#undef c
}
template<typename T>
inline constexpr typename mat<4, 4, T>::row_type operator*
(
mat<4, 4, T> const& m,
typename mat<4, 4, T>::col_type const& v
)
{
#define c(i) ( \
m[i][0] * v[0] \
+ m[i][1] * v[1] \
+ m[i][2] * v[2] \
+ m[i][3] * v[3] )
return typename mat<4, 4, T>::row_type(c(0), c(1), c(2), c(3));
#undef c
}
template<typename T>
inline constexpr mat<4, 4, T> transpose(mat<4, 4, T> const& m)
{
return mat<4, 4, T>(
m[0][0], m[1][0], m[2][0], m[3][0],
m[0][1], m[1][1], m[2][1], m[3][1],
m[0][2], m[1][2], m[2][2], m[3][2],
m[0][3], m[1][3], m[2][3], m[3][3]
);
}

28
math/math.hpp Normal file
View File

@ -0,0 +1,28 @@
#pragma once
template <typename T>
constexpr T sqrt(const T n) noexcept;
template <>
constexpr float sqrt(const float n) noexcept
{
return __builtin_sqrtf(n);
}
template <typename T>
constexpr T cos(const T n) noexcept;
template <>
constexpr float cos(const float n) noexcept
{
return __builtin_cosf(n);
}
template <typename T>
constexpr T sin(const T n) noexcept;
template <>
constexpr float sin(const float n) noexcept
{
return __builtin_sinf(n);
}

4
math/vec.hpp Normal file
View File

@ -0,0 +1,4 @@
#pragma once
template <int L, typename T>
struct vec;

149
math/vec3.hpp Normal file
View File

@ -0,0 +1,149 @@
#pragma once
#include "math.hpp"
#include "vec.hpp"
//
// vec3
//
template <typename T>
struct vec<3, T>
{
T x, y, z;
inline constexpr vec();
inline constexpr vec(T scalar);
inline constexpr vec(T _x, T _y, T _z);
constexpr inline vec<3, T> operator-() const;
inline constexpr T const& operator[](int i) const;
inline constexpr vec<3, T>& operator=(vec<3, T> const& v);
inline constexpr vec<3, T>& operator+=(vec<3, T> const& v);
inline constexpr vec<3, T>& operator-=(vec<3, T> const& v);
};
template <typename T>
inline constexpr vec<3, T>::vec()
: x(0), y(0), z(0)
{}
template <typename T>
inline constexpr vec<3, T>::vec(T scalar)
: x(scalar), y(scalar), z(scalar)
{}
template <typename T>
inline constexpr vec<3, T>::vec(T _x, T _y, T _z)
: x(_x), y(_y), z(_z)
{}
template <typename T>
constexpr inline vec<3, T> vec<3, T>::operator-() const
{
return vec<3, T>(-x, -y, -z);
}
template <typename T>
inline constexpr T const& vec<3, T>::operator[](int i) const
{
switch(i)
{
default: [[fallthrough]];
case 0: return x;
case 1: return y;
case 2: return z;
}
}
template <typename T>
inline constexpr vec<3, T>& vec<3, T>::operator=(vec<3, T> const& v)
{
this->x = static_cast<T>(v.x);
this->y = static_cast<T>(v.y);
this->z = static_cast<T>(v.z);
return *this;
}
template <typename T>
inline constexpr vec<3, T>& vec<3, T>::operator+=(vec<3, T> const& v)
{
*this = *this + vec<3, T>(v);
return *this;
}
template <typename T>
inline constexpr vec<3, T>& vec<3, T>::operator-=(vec<3, T> const& v)
{
*this = *this - vec<3, T>(v);
return *this;
}
template <typename T>
inline constexpr vec<3, T> operator+(vec<3, T> const& v1, vec<3, T> const& v2)
{
return vec<3, T>(v1.x + v2.x,
v1.y + v2.y,
v1.z + v2.z);
}
template <typename T>
inline constexpr vec<3, T> operator-(vec<3, T> const& v1, vec<3, T> const& v2)
{
return vec<3, T>(v1.x - v2.x,
v1.y - v2.y,
v1.z - v2.z);
}
template <typename T>
inline constexpr vec<3, T> operator*(vec<3, T> const& v1, vec<3, T> const& v2)
{
return vec<3, T>(v1.x * v2.x,
v1.y * v2.y,
v1.z * v2.z);
}
template <typename T>
inline constexpr vec<3, T> operator*(vec<3, T> const& v1, T const& scalar)
{
return v1 * vec<3, T>(scalar);
}
template <typename T>
inline constexpr vec<3, T> operator/(vec<3, T> const& v1, vec<3, T> const& v2)
{
return vec<3, T>(v1.x / v2.x,
v1.y / v2.y,
v1.z / v2.z);
}
template <typename T>
inline constexpr vec<3, T> operator/(vec<3, T> const& v1, T const& scalar)
{
return v1 / vec<3, T>(scalar);
}
template <typename T>
inline constexpr T dot(vec<3, T> const& v1, vec<3, T> const& v2)
{
vec<3, T> tmp(v1 * v2);
return tmp.x + tmp.y + tmp.z;
}
template <typename T>
inline constexpr vec<3, T> functor1(T (&func) (T const& x), vec<3, T> const& v)
{
return vec<3, T>(func(v.x), func(v.y), func(v.z));
}
template <typename T, typename U>
inline constexpr vec<3, U> functor1(U (&func) (T const& x), vec<3, T> const& v)
{
return vec<3, U>(func(v.x), func(v.y), func(v.z));
}
template <typename T>
inline constexpr T length(vec<3, T> const& v)
{
return sqrt(dot(v, v));
}

155
math/vec4.hpp Normal file
View File

@ -0,0 +1,155 @@
#pragma once
#include "math.hpp"
#include "vec.hpp"
//
// vec4
//
template <typename T>
struct vec<4, T>
{
T x, y, z, w;
inline constexpr vec();
inline constexpr vec(T scalar);
inline constexpr vec(T _x, T _y, T _z, T _w);
constexpr inline vec<4, T> operator-() const;
inline constexpr T const& operator[](int i) const;
inline constexpr vec<4, T>& operator=(vec<4, T> const& v);
inline constexpr vec<4, T>& operator+=(vec<4, T> const& v);
inline constexpr vec<4, T>& operator-=(vec<4, T> const& v);
};
template <typename T>
inline constexpr vec<4, T>::vec()
: x(0), y(0), z(0), w(0)
{}
template <typename T>
inline constexpr vec<4, T>::vec(T scalar)
: x(scalar), y(scalar), z(scalar), w(scalar)
{}
template <typename T>
inline constexpr vec<4, T>::vec(T _x, T _y, T _z, T _w)
: x(_x), y(_y), z(_z), w(_w)
{}
template <typename T>
constexpr inline vec<4, T> vec<4, T>::operator-() const
{
return vec<4, T>(-x, -y, -z, -w);
}
template <typename T>
inline constexpr T const& vec<4, T>::operator[](int i) const
{
switch(i)
{
default: [[fallthrough]];
case 0: return x;
case 1: return y;
case 2: return z;
case 3: return w;
}
}
template <typename T>
inline constexpr vec<4, T>& vec<4, T>::operator=(vec<4, T> const& v)
{
this->x = static_cast<T>(v.x);
this->y = static_cast<T>(v.y);
this->z = static_cast<T>(v.z);
this->w = static_cast<T>(v.w);
return *this;
}
template <typename T>
inline constexpr vec<4, T>& vec<4, T>::operator+=(vec<4, T> const& v)
{
*this = *this + vec<4, T>(v);
return *this;
}
template <typename T>
inline constexpr vec<4, T>& vec<4, T>::operator-=(vec<4, T> const& v)
{
*this = *this - vec<4, T>(v);
return *this;
}
template <typename T>
inline constexpr vec<4, T> operator+(vec<4, T> const& v1, vec<4, T> const& v2)
{
return vec<4, T>(v1.x + v2.x,
v1.y + v2.y,
v1.z + v2.z,
v1.w + v2.w);
}
template <typename T>
inline constexpr vec<4, T> operator-(vec<4, T> const& v1, vec<4, T> const& v2)
{
return vec<4, T>(v1.x - v2.x,
v1.y - v2.y,
v1.z - v2.z,
v1.w - v2.w);
}
template <typename T>
inline constexpr vec<4, T> operator*(vec<4, T> const& v1, vec<4, T> const& v2)
{
return vec<4, T>(v1.x * v2.x,
v1.y * v2.y,
v1.z * v2.z,
v1.w * v2.w);
}
template <typename T>
inline constexpr vec<4, T> operator*(vec<4, T> const& v1, T const& scalar)
{
return v1 * vec<4, T>(scalar);
}
template <typename T>
inline constexpr vec<4, T> operator/(vec<4, T> const& v1, vec<4, T> const& v2)
{
return vec<4, T>(v1.x / v2.x,
v1.y / v2.y,
v1.z / v2.z,
v1.w / v2.w);
}
template <typename T>
inline constexpr vec<4, T> operator/(vec<4, T> const& v1, T const& scalar)
{
return v1 / vec<4, T>(scalar);
}
template <typename T>
inline constexpr T dot(vec<4, T> const& v1, vec<4, T> const& v2)
{
vec<4, T> tmp(v1 * v2);
return tmp.x + tmp.y + tmp.z + tmp.w;
}
template <typename T>
inline constexpr vec<4, T> functor1(T (&func) (T const& x), vec<4, T> const& v)
{
return vec<4, T>(func(v.x), func(v.y), func(v.z), func(v.w));
}
template <typename T, typename U>
inline constexpr vec<4, U> functor1(U (&func) (T const& x), vec<4, T> const& v)
{
return vec<4, U>(func(v.x), func(v.y), func(v.z), func(v.w));
}
template <typename T>
inline constexpr T length(vec<4, T> const& v)
{
return sqrt(dot(v, v));
}