Use templates for vectors

This commit is contained in:
duarteapcoelho 2022-09-11 11:39:40 +01:00
parent 795db01fd7
commit cf62bb7f87
10 changed files with 113 additions and 157 deletions

View File

@ -7,8 +7,8 @@ class Car {
public:
static Model model;
vec3f position = {0, 0, 0};
vec3f speed = {0, 0, 0};
vec3<float> position = {0, 0, 0};
vec3<float> speed = {0, 0, 0};
float wheelSpeed = 0;
float targetDirection = 0, direction = 0;
Car();

View File

@ -12,7 +12,7 @@ public:
m[0][1] = fp(0);
m[0][2] = fp(0);
m[0][3] = fp(0);
m[1][0] = fp(0);
m[1][1] = fp(1);
m[1][2] = fp(0);
@ -127,7 +127,7 @@ public:
return r;
}
vec3d operator * (vec3d o){
vec3<fp> operator * (vec3<fp> o){
return {
m[0][0] * o.x + m[1][0] * o.y + m[2][0] * o.z + m[3][0],
m[0][1] * o.x + m[1][1] * o.y + m[2][1] * o.z + m[3][1],
@ -135,7 +135,7 @@ public:
};
}
static mat4 translate(mat4 matrix, vec3d p){
static mat4 translate(mat4 matrix, vec3<fp> p){
mat4 t;
t.m[3][0] = p.x;
t.m[3][1] = p.y;

View File

@ -13,10 +13,10 @@
#define RENDER_HEIGHT (DISPLAY_HEIGHT/PIXEL_SIZE)
struct Triangle {
vec3d p0;
vec3d p1;
vec3d p2;
vec3d normal;
vec3<fp> p0;
vec3<fp> p1;
vec3<fp> p2;
vec3<fp> normal;
Color c;
};
@ -25,12 +25,6 @@ struct Mesh {
Triangle *triangles;
};
struct Shader {
vec3d (*vertexShader)(vec3d, void*);
Color (*fragmentShader)(Color, void*);
void *uniforms;
};
class Model {
public:
Mesh mesh;
@ -48,8 +42,7 @@ namespace Rasterizer {
void setFOV(int fov);
vec3d toDevice(vec3d p);
vec3i toScreen(vec3d p);
void drawLine(vec3d p0, vec3d p1);
void drawTriangle(Model *model, Triangle triangle, Shader shader, bool useDepth, bool isShaded, bool clipTriangles);
vec3<fp> toDevice(vec3<fp> p);
vec3<int> toScreen(vec3<fp> p);
void drawLine(vec3<fp> p0, vec3<fp> p1);
};

View File

@ -30,5 +30,9 @@ fp fp_tan(fp x);
fp fp_atan(fp x);
fp fp_atan2(fp y, fp x);
float isqrt(float x);
fp fp_isqrt(fp x);
float _isqrt(float x);
template <typename T>
T isqrt(T x){
return T(_isqrt(float(x)));
}

View File

@ -7,7 +7,7 @@ class Track {
float width, tolerance;
int numPoints;
vec3f *points;
vec3<float> *points;
Triangle *triangles;
Model *cones;
Model model;
@ -15,7 +15,7 @@ public:
static Mesh coneMesh;
static Mesh simpleConeMesh;
Track(int numPoints, vec3f *points, float width = 10.0f, float tolerance = 1.2f);
void render(mat4 viewMatrix, vec3f carPos);
bool isInside(vec3f p);
Track(int numPoints, vec3<float> *points, float width = 10.0f, float tolerance = 1.2f);
void render(mat4 viewMatrix, vec3<float> carPos);
bool isInside(vec3<float> p);
};

View File

@ -2,120 +2,89 @@
#include "fp.h"
#include "rmath.h"
struct vec3i {
int x;
int y;
int z;
};
struct vec3d {
fp x;
fp y;
fp z;
inline vec3d operator + (vec3d o){
template <typename T>
struct vec3 {
T x;
T y;
T z;
inline vec3(){
x = 0;
y = 0;
z = 0;
}
inline vec3(T x, T y, T z){
this->x = x;
this->y = y;
this->z = z;
}
inline vec3<T> operator + (vec3<T> o){
return {x + o.x, y + o.y, z + o.z};
}
inline vec3d operator - (vec3d o){
inline vec3<T> operator - (vec3<T> o){
return {x - o.x, y - o.y, z - o.z};
}
inline vec3d operator * (vec3d o){
inline vec3<T> operator * (vec3<T> o){
return {x * o.x, y * o.y, z * o.z};
}
inline vec3d operator / (vec3d o){
inline vec3<T> operator / (vec3<T> o){
return {x / o.x, y / o.y, z / o.z};
}
inline vec3d operator * (fp o){
inline vec3<T> operator * (T o){
return {x * o, y * o, z * o};
}
inline vec3d operator / (fp o){
inline vec3<T> operator / (T o){
return {x / o, y / o, z / o};
}
inline bool operator == (vec3d o){
inline bool operator == (vec3<T> o){
return x == o.x && y == o.y && z == o.z;
}
inline vec3d normalized(){
fp i_d = fp_isqrt(x*x + y*y + z*z);
inline vec3<T> normalized(){
T i_d = isqrt<T>(x*x + y*y + z*z);
return (*this) * i_d;
}
inline fp i_length(){
return fp_isqrt(x*x + y*y + z*z);
inline T i_length(){
return isqrt<T>(x*x + y*y + z*z);
}
inline fp length2(){
inline T length2(){
return x*x + y*y + z*z;
}
template <typename U>
inline operator vec3<U>(){
return {x, y, z};
}
};
struct vec3f {
float x;
float y;
float z;
inline vec3f operator + (vec3f o){
return {x + o.x, y + o.y, z + o.z};
}
inline vec3f operator - (vec3f o){
return {x - o.x, y - o.y, z - o.z};
}
inline vec3f operator * (vec3f o){
return {x * o.x, y * o.y, z * o.z};
}
inline vec3f operator / (vec3f o){
return {x / o.x, y / o.y, z / o.z};
}
inline vec3f operator * (float o){
return {x * o, y * o, z * o};
}
inline vec3f operator / (float o){
return {x / o, y / o, z / o};
}
inline bool operator == (vec3f o){
return x == o.x && y == o.y && z == o.z;
}
inline operator vec3d(){
return {.x = x, .y = y, .z = z};
}
inline vec3f normalized(){
fp i_d = fp_isqrt(x*x + y*y + z*z);
return (*this) * i_d;
}
inline float i_length(){
return isqrt(x*x + y*y + z*z);
}
inline float length2(){
return x*x + y*y + z*z;
}
};
inline vec3f smoothDamp(vec3f current, vec3f target, vec3f *currentVelocity, float smoothTime, float deltaTime, float maxSpeed){
template <typename T>
inline vec3<T> smoothDamp(vec3<T> current, vec3<T> target, vec3<T> *currentVelocity, T smoothTime, T deltaTime, T maxSpeed){
if(smoothTime < 0.0001f) smoothTime = 0.0001f;
float omega = 2.0f / smoothTime;
T omega = 2.0f / smoothTime;
float x = omega * deltaTime;
float exp = 1.0f / (1.0f + x + 0.48f * x * x + 0.235f * x * x * x);
T x = omega * deltaTime;
T exp = 1.0f / (1.0f + x + 0.48f * x * x + 0.235f * x * x * x);
vec3f change = current - target;
vec3f originalTo = target;
vec3<T> change = current - target;
vec3<T> originalTo = target;
float maxChange = maxSpeed * smoothTime;
float maxChangeSq = maxChange * maxChange;
float sqDist = change.x * change.x + change.y * change.y + change.z * change.z;
T maxChange = maxSpeed * smoothTime;
T maxChangeSq = maxChange * maxChange;
T sqDist = change.x * change.x + change.y * change.y + change.z * change.z;
if(sqDist > maxChangeSq){
float mag = 1.0f/isqrt(sqDist);
T mag = 1.0f/isqrt(sqDist);
change = change / mag * maxChange;
}
target = current - change;
vec3f temp = ((*currentVelocity) + change * omega) * deltaTime;
vec3<T> temp = ((*currentVelocity) + change * omega) * deltaTime;
(*currentVelocity) = ((*currentVelocity) - temp * omega) * exp;
vec3f output = target + (change + temp) * exp;
vec3<T> output = target + (change + temp) * exp;
vec3f origMinusCurrent = originalTo - current;
vec3f outMinusOrig = output - originalTo;
vec3<T> origMinusCurrent = originalTo - current;
vec3<T> outMinusOrig = output - originalTo;
if(origMinusCurrent.x * outMinusOrig.x + origMinusCurrent.y * outMinusOrig.y > 0){
output = originalTo;
@ -125,18 +94,12 @@ inline vec3f smoothDamp(vec3f current, vec3f target, vec3f *currentVelocity, flo
return output;
}
inline fp dot(vec3d a, vec3d b){
template <typename T>
inline T dot(vec3<T> a, vec3<T> b){
return a.x*b.x + a.y*b.y + a.z*b.z;
}
inline fp cross(vec3d a, vec3d b){
return (a.x*b.y) - (a.y*b.x);
}
inline float dot(vec3f a, vec3f b){
return a.x*b.x + a.y*b.y + a.z*b.z;
}
inline float cross(vec3f a, vec3f b){
template <typename T>
inline T cross(vec3<T> a, vec3<T> b){
return (a.x*b.y) - (a.y*b.x);
}

View File

@ -11,8 +11,8 @@
#include "track.h"
mat4 view;
vec3f cameraPos = {0, 0, 0};
vec3f cameraSpeed = {0, 0, 0};
vec3<float> cameraPos = {0, 0, 0};
vec3<float> cameraSpeed = {0, 0, 0};
float cameraAngle = 0;
int main(){
@ -1608,7 +1608,7 @@ int main(){
Model sun({2, sunTriangles});
vec3f trackPoints[] = {
vec3<float> trackPoints[] = {
{0, 0, 0},
{2, 0, 0},
{2+I_SQRT_2, 0, 1-I_SQRT_2},
@ -1665,8 +1665,8 @@ int main(){
cameraAngle = cameraAngle + (-cameraAngle * 0.02 + 0.02 * car.direction) * Time::delta;
vec3f lc = cameraPos;
vec3f ls = cameraSpeed;
vec3<float> lc = cameraPos;
vec3<float> ls = cameraSpeed;
cameraPos = smoothDamp(cameraPos, car.position, &cameraSpeed, 5.0f, Time::delta, 1000.0f);
if(cameraPos == car.position){
cameraPos = lc;

View File

@ -4,7 +4,7 @@
#include "time.h"
struct Plane {
vec3d n;
vec3<fp> n;
fp d;
};
@ -60,7 +60,7 @@ namespace Rasterizer {
clippingPlanes[4] = {{0, fp(0)-d, c}, 0}; // top
}
inline vec3d toDevice(vec3d p){
inline vec3<fp> toDevice(vec3<fp> p){
return {
p.x / p.z / fov_d,
p.y / p.z / fov_d,
@ -68,7 +68,7 @@ namespace Rasterizer {
};
}
inline vec3i toScreen(vec3d p){
inline vec3<int> toScreen(vec3<fp> p){
return {
p.x * fp(RENDER_WIDTH) + fp(RENDER_WIDTH / 2.0f),
p.y * fp(RENDER_WIDTH) + fp(RENDER_HEIGHT / 2.0f),
@ -83,7 +83,7 @@ namespace Rasterizer {
fp m;
Edge *next;
};
inline Edge newEdge(vec3i p0, vec3i p1){
inline Edge newEdge(vec3<int> p0, vec3<int> p1){
if(p0.y > p1.y){
return {
p1.y,
@ -106,20 +106,20 @@ namespace Rasterizer {
}
inline void _drawTriangle(Model *model, Triangle triangle, bool useDepth, bool isShaded){
vec3d p0_d = toDevice(triangle.p0);
vec3d p1_d = toDevice(triangle.p1);
vec3d p2_d = toDevice(triangle.p2);
vec3<fp> p0_d = toDevice(triangle.p0);
vec3<fp> p1_d = toDevice(triangle.p1);
vec3<fp> p2_d = toDevice(triangle.p2);
vec3i p0 = toScreen(p0_d);
vec3i p1 = toScreen(p1_d);
vec3i p2 = toScreen(p2_d);
vec3<int> p0 = toScreen(p0_d);
vec3<int> p1 = toScreen(p1_d);
vec3<int> p2 = toScreen(p2_d);
int minY = max(min(min(p0.y, p1.y), p2.y), 0);
int maxY = min(max(max(p0.y, p1.y), p2.y), RENDER_HEIGHT);
fp z = (p0.z + p1.z + p2.z) / 3;
if(isShaded){
fp brightness = dot(mat4::toMat3(model->modelMatrix) * triangle.normal, {I_SQRT_3, -I_SQRT_3, -I_SQRT_3}) * fp(0.6) + fp(0.4);
fp brightness = dot(mat4::toMat3(model->modelMatrix) * triangle.normal, vec3<fp>(I_SQRT_3, -I_SQRT_3, -I_SQRT_3)) * fp(0.6) + fp(0.4);
if(brightness > 1)
brightness = 1;
if(brightness < 0)
@ -245,8 +245,8 @@ namespace Rasterizer {
} else if(numClipped == 3){
return {0, nullptr};
} else if(numClipped == 2){
vec3d clipped[2];
vec3d notClipped;
vec3<fp> clipped[2];
vec3<fp> notClipped;
if(!clippedP0){
notClipped = triangle.p0;
clipped[0] = triangle.p1;
@ -266,15 +266,15 @@ namespace Rasterizer {
if(d0 == 0 || d1 == 0)
return {0, nullptr};
vec3d B = notClipped + (clipped[0] - notClipped) * ((fp(0) - plane.d - dot(plane.n, notClipped))/d0);
vec3d C = notClipped + (clipped[1] - notClipped) * ((fp(0) - plane.d - dot(plane.n, notClipped))/d1);
vec3<fp> B = notClipped + (clipped[0] - notClipped) * ((fp(0) - plane.d - dot(plane.n, notClipped))/d0);
vec3<fp> C = notClipped + (clipped[1] - notClipped) * ((fp(0) - plane.d - dot(plane.n, notClipped))/d1);
Mesh m = {1, (Triangle*)malloc(sizeof(Triangle))};
m.triangles[0] = {notClipped, B, C, triangle.normal, triangle.c};
return m;
} else if(numClipped == 1){
vec3d clipped;
vec3d notClipped[2];
vec3<fp> clipped;
vec3<fp> notClipped[2];
if(clippedP0){
clipped = triangle.p0;
notClipped[0] = triangle.p1;
@ -298,8 +298,8 @@ namespace Rasterizer {
if(d0 == 0 || d1 == 0)
return {0, nullptr};
vec3d A = notClipped[0] + (clipped - notClipped[0]) * ((fp(0) - plane.d - dot(plane.n, notClipped[0]))/d0);
vec3d B = notClipped[1] + (clipped - notClipped[1]) * ((fp(0) - plane.d - dot(plane.n, notClipped[1]))/d1);
vec3<fp> A = notClipped[0] + (clipped - notClipped[0]) * ((fp(0) - plane.d - dot(plane.n, notClipped[0]))/d0);
vec3<fp> B = notClipped[1] + (clipped - notClipped[1]) * ((fp(0) - plane.d - dot(plane.n, notClipped[1]))/d1);
Mesh m = {2, (Triangle*)malloc(2*sizeof(Triangle))};
m.triangles[0] = {notClipped[0], A, notClipped[1], triangle.normal, triangle.c};

View File

@ -115,7 +115,7 @@ fp fp_atan2(fp y, fp x){
}
}
float isqrt(float x){
float _isqrt(float x){
float xhalf = 0.5f * x;
int i = *(int*)&x; // store floating-point bits in integer
i = 0x5f3759df - (i >> 1); // initial guess for Newton's method
@ -123,7 +123,3 @@ float isqrt(float x){
x = x*(1.5f - xhalf*x*x); // One round of Newton's method
return x;
}
fp fp_isqrt(fp x){
return fp(isqrt(float(x)));
}

View File

@ -1,6 +1,6 @@
#include "track.h"
Track::Track(int numPoints, vec3f *points, float width, float tolerance){
Track::Track(int numPoints, vec3<float> *points, float width, float tolerance){
this->numPoints = numPoints;
this->points = points;
this->width = width;
@ -10,25 +10,25 @@ Track::Track(int numPoints, vec3f *points, float width, float tolerance){
cones = (Model*)malloc(numPoints*2 * sizeof(Model));
for(int i = 0; i < numPoints; i++){
vec3f pos = points[i];
vec3f direction = points[(i+1)%numPoints] - points[i];
vec3f nextDirection = points[(i+2)%numPoints] - points[(i+1)%numPoints];
vec3f perpendicular = {direction.z, direction.y, -direction.x};
vec3<float> pos = points[i];
vec3<float> direction = points[(i+1)%numPoints] - points[i];
vec3<float> nextDirection = points[(i+2)%numPoints] - points[(i+1)%numPoints];
vec3<float> perpendicular = {direction.z, direction.y, -direction.x};
perpendicular = perpendicular * width * perpendicular.i_length();
vec3f nextPerpendicular = {nextDirection.z, nextDirection.y, -nextDirection.x};
vec3<float> nextPerpendicular = {nextDirection.z, nextDirection.y, -nextDirection.x};
nextPerpendicular = nextPerpendicular * width * nextPerpendicular.i_length();
triangles[i*2] = {
vec3d(pos - perpendicular),
vec3d(pos + perpendicular),
vec3d(pos - nextPerpendicular + direction),
vec3<fp>(pos - perpendicular),
vec3<fp>(pos + perpendicular),
vec3<fp>(pos - nextPerpendicular + direction),
{0, -1, 0},
newColor(50, 50, 50)
};
triangles[i*2+1] = {
vec3d(pos + perpendicular),
vec3d(pos - nextPerpendicular + direction),
vec3d(pos + nextPerpendicular + direction),
vec3<fp>(pos + perpendicular),
vec3<fp>(pos - nextPerpendicular + direction),
vec3<fp>(pos + nextPerpendicular + direction),
{0, -1, 0},
newColor(50, 50, 50)
};
@ -41,7 +41,7 @@ Track::Track(int numPoints, vec3f *points, float width, float tolerance){
model = Model({numPoints * 2, triangles});
}
void Track::render(mat4 viewMatrix, vec3f carPos){
void Track::render(mat4 viewMatrix, vec3<float> carPos){
model.viewMatrix = viewMatrix;
model.draw(false, false, true);
@ -63,7 +63,7 @@ void Track::render(mat4 viewMatrix, vec3f carPos){
}
}
float distanceToLine2(vec3f p, vec3f p1, vec3f p2){
float distanceToLine2(vec3<float> p, vec3<float> p1, vec3<float> p2){
float l2 = (p1-p2).length2();
if(l2 == 0) return (p1 - p).length2();
@ -71,11 +71,11 @@ float distanceToLine2(vec3f p, vec3f p1, vec3f p2){
float t = dot(p - p1, p2 - p1) / l2;
if(t < 0) t = 0;
if(t > 1) t = 1;
vec3f projection = p1 + (p2 - p1) * t;
vec3<float> projection = p1 + (p2 - p1) * t;
return (p - projection).length2();
}
bool Track::isInside(vec3f p){
bool Track::isInside(vec3<float> p){
float minDistance2 = -1;
for(int i = 0; i < numPoints; i++){
float d = distanceToLine2(p, points[i], points[(i+1)%numPoints]);