Better car movement, optimizations and clipping

This commit is contained in:
duarteapcoelho 2022-08-19 23:41:59 +01:00
parent e1e4f77685
commit 040c4ae81c
8 changed files with 505 additions and 111 deletions

View file

@ -19,11 +19,17 @@ struct Color {
#ifdef PRIZM
unsigned short color;
char textColor;
bool operator != (Color o){
return color != o.color;
}
#endif
#ifdef SDL
int r;
int g;
int b;
bool operator != (Color o){
return r != o.r || g != o.g || b != o.b;
}
#endif
};

View file

@ -4,10 +4,10 @@
#include "vector.h"
#include "display.h"
#define NEAR_PLANE 0.5
#define NEAR_PLANE 0.1
#define FAR_PLANE 100
#define PIXEL_SIZE 2
#define PIXEL_SIZE 4
#define RENDER_WIDTH (DISPLAY_WIDTH/PIXEL_SIZE)
#define RENDER_HEIGHT (DISPLAY_HEIGHT/PIXEL_SIZE)
@ -35,6 +35,7 @@ struct Model {
};
namespace Rasterizer {
void init();
void reset();
extern fp *depthBuffer;

View file

@ -16,3 +16,6 @@ fp _fp_sin(fp x);
fp fp_sin(fp x);
fp fp_cos(fp x);
fp fp_atan2(fp y, fp x);
float isqrt(float x);
fp fp_isqrt(fp x);

View file

@ -29,10 +29,36 @@ struct vec3d {
vec3d operator / (fp o){
return {x / o, y / o, z / o};
}
bool operator == (vec3d o){
return x == o.x && y == o.y && z == o.z;
}
};
struct vec3f {
float x;
float y;
float z;
vec3f operator + (vec3f o){
return {x + o.x, y + o.y, z + o.z};
}
vec3f operator - (vec3f o){
return {x - o.x, y - o.y, z - o.z};
}
vec3f operator * (vec3f o){
return {x * o.x, y * o.y, z * o.z};
}
vec3f operator / (vec3f o){
return {x / o.x, y / o.y, z / o.z};
}
vec3f operator * (float o){
return {x * o, y * o, z * o};
}
vec3f operator / (float o){
return {x / o, y / o, z / o};
}
bool operator == (vec3f o){
return x == o.x && y == o.y && z == o.z;
}
};

View file

@ -12,8 +12,10 @@ Color newColor(int r, int g, int b){
namespace Display {
int textHeight = 10;
unsigned short *VRAMAddress;
void init(){
VRAMAddress = (unsigned short*)GetVRAMAddress();
}
void clear(Color color){
@ -27,7 +29,7 @@ namespace Display {
}
void destroy(){}
void fillRect(int x, int y, int w, int h, Color color){
unsigned short*s=(unsigned short*)GetVRAMAddress();
unsigned short*s=VRAMAddress;
s+=(y*384)+x;
while(h--){
unsigned w2=w;
@ -37,7 +39,8 @@ namespace Display {
}
}
void drawPoint(int x, int y, Color color){
Bdisp_SetPoint_VRAM(x, y, color.color);
// Bdisp_SetPoint_VRAM(x, y, color.color);
*(VRAMAddress + x + y * DISPLAY_WIDTH) = color.color;
}
int textWidth(const char *text){
return strlen(text)*6;

View file

@ -7,15 +7,14 @@
#include "rmath.h"
#include "math.h"
#define NUM_CUBES 20
mat4 view;
vec3d carPos = {0, 0, 0};
vec3d carSpeed = {0, 0, 0};
fp carDirection = 0;
fp carAngle = 0;
fp cameraAngle = 0;
fp wheelSpeed = 0;
vec3f carPos = {0, 0, 0};
vec3f cameraPos = {0, 0, 0};
vec3f carSpeed = {0, 0, 0};
float carDirection = 0;
float carAngle = 0;
float cameraAngle = 0;
float wheelSpeed = 0;
vec3d vertexShader(vec3d i, void *uniforms){
if(uniforms == nullptr)
@ -724,35 +723,122 @@ int main(){
srand(0);
Triangle trackTriangles[100*2];
// Triangle treeTriangles[10*10];
// for(int x = 0; x < 10; x++){
// for(int y = 0; y < 10; y++){
// // int treeX = (x-50)*10;
// // int treeY = (y-50)*10;
// int treeX = ((rand()%100) - 50)*10;
// int treeY = ((rand()%100) - 50)*10;
// treeTriangles[x+y*10] = {
// {treeX-1, 0, treeY},
// {treeX, -1, treeY},
// {treeX+1, 0, treeY},
// newColor(0, 255, 0)
// };
// }
// }
// Mesh treeMesh = {
// 10*10,
// treeTriangles
// };
for(int i = 0; i < 100; i++){
fp angle = fp(i) * fp(2*PI) / fp(100);
fp nextAngle = fp(i+1) * fp(2*PI) / fp(100);
printf("%.3f\n", (float)fp_sin(angle));
trackTriangles[i] = {
{fp_cos(angle)*fp(4), 0, fp_sin(angle)*fp(4)},
{fp_cos(angle)*fp(5), 0, fp_sin(angle)*fp(5)},
{fp_cos(nextAngle)*fp(4), 0, fp_sin(nextAngle)*fp(4)},
newColor(0, 0, 0)
};
trackTriangles[i].p0 = trackTriangles[i].p0 * fp(10);
trackTriangles[i].p1 = trackTriangles[i].p1 * fp(10);
trackTriangles[i].p2 = trackTriangles[i].p2 * fp(10);
trackTriangles[i+100] = {
{fp_cos(angle)*fp(5), 0, fp_sin(angle)*fp(5)},
{fp_cos(nextAngle)*fp(4), 0, fp_sin(nextAngle)*fp(4)},
{fp_cos(nextAngle)*fp(5), 0, fp_sin(nextAngle)*fp(5)},
newColor(255, 255, 255)
};
trackTriangles[i+100].p0 = trackTriangles[i+100].p0 * fp(10);
trackTriangles[i+100].p1 = trackTriangles[i+100].p1 * fp(10);
trackTriangles[i+100].p2 = trackTriangles[i+100].p2 * fp(10);
#define TRACK_SEGMENTS 25
#define TRACK_WIDTH 10
vec3d trackPoints[TRACK_SEGMENTS+1] = {
{0, 0, 0},
{2, 0, 0},
{4, 0, 0},
{6, 0, 0},
{8, 0, 0},
{10, 0, 0},
{12, 0, 1},
{13, 0, 3},
{13, 0, 5},
{12, 0, 7},
{10, 0, 9},
{8, 0, 10},
{6, 0, 10},
{4, 0, 10},
{2, 0, 10},
{0, 0, 10},
{-2, 0, 10},
{-4, 0, 10},
{-6, 0, 10},
{-8, 0, 10},
{-10, 0, 10},
{-12, 0, 10},
{-14, 0, 10},
{-16, 0, 10},
{-18, 0, 10},
{-20, 0, 10},
};
for(int i = 0; i < TRACK_SEGMENTS+1; i++){
trackPoints[i] = trackPoints[i] * 0.5;
}
Triangle trackTriangles[TRACK_SEGMENTS*2];
for(int i = 0; i < TRACK_SEGMENTS; i++){
vec3d pos = trackPoints[i] * fp(10);
vec3d nextPos = trackPoints[i+1] * fp(10);
vec3d direction = nextPos - pos;
vec3d perpendicular = {direction.z, 0, fp(0)-direction.x};
direction = direction * TRACK_WIDTH;
perpendicular = perpendicular * fp_isqrt(perpendicular.x*perpendicular.x + perpendicular.y*perpendicular.y + perpendicular.z*perpendicular.z);
perpendicular = perpendicular * fp(TRACK_WIDTH);
trackTriangles[i] = {
pos - perpendicular,
nextPos - perpendicular,
nextPos + perpendicular,
newColor(50, 50, 50)
};
trackTriangles[TRACK_SEGMENTS+i] = {
pos + perpendicular,
nextPos + perpendicular,
pos - perpendicular,
newColor(50, 50, 50)
};
}
// for(int i = 0; i < TRACK_SEGMENTS; i++){
// fp angle = fp(i) * fp(2*PI) / fp(TRACK_SEGMENTS);
// fp nextAngle = fp(i+1) * fp(2*PI) / fp(TRACK_SEGMENTS);
// trackTriangles[i] = {
// {fp_cos(angle)*fp(4), 0, fp_sin(angle)*fp(4)},
// {fp_cos(angle)*fp(5), 0, fp_sin(angle)*fp(5)},
// {fp_cos(nextAngle)*fp(4), 0, fp_sin(nextAngle)*fp(4)},
// newColor(0, 0, 0)
// };
// trackTriangles[i].p0 = trackTriangles[i].p0 * fp(10);
// trackTriangles[i].p1 = trackTriangles[i].p1 * fp(10);
// trackTriangles[i].p2 = trackTriangles[i].p2 * fp(10);
// trackTriangles[i+TRACK_SEGMENTS] = {
// {fp_cos(angle)*fp(5), 0, fp_sin(angle)*fp(5)},
// {fp_cos(nextAngle)*fp(4), 0, fp_sin(nextAngle)*fp(4)},
// {fp_cos(nextAngle)*fp(5), 0, fp_sin(nextAngle)*fp(5)},
// newColor(255, 255, 255)
// };
// trackTriangles[i+TRACK_SEGMENTS].p0 = trackTriangles[i+TRACK_SEGMENTS].p0 * fp(10);
// trackTriangles[i+TRACK_SEGMENTS].p1 = trackTriangles[i+TRACK_SEGMENTS].p1 * fp(10);
// trackTriangles[i+TRACK_SEGMENTS].p2 = trackTriangles[i+TRACK_SEGMENTS].p2 * fp(10);
// }
// Model trees = {
// .mesh = treeMesh,
// .shader = {
// .vertexShader = vertexShader,
// .fragmentShader = fragmentShader,
// .uniforms = nullptr
// }
// };
Model track = {
.mesh = {
100 * 2,
TRACK_SEGMENTS*2,
trackTriangles
},
.shader = {
@ -773,6 +859,7 @@ int main(){
}
};
Rasterizer::init();
while(true){
Rasterizer::reset();
@ -783,31 +870,39 @@ int main(){
return 0;
}
const fp speed = 0.02 * Time::delta;
const fp acceleration = fp(1);
if(Input::keyDown(KEY_RIGHT)){
carAngle = carAngle + speed;
if(Input::keyDown(KEY_RIGHT) || Input::keyDown(KEY_6)){
carDirection = carDirection + Time::delta / 40.0f;
}
if(Input::keyDown(KEY_LEFT)){
carAngle = carAngle - speed;
if(Input::keyDown(KEY_LEFT) || Input::keyDown(KEY_4)){
carDirection = carDirection - Time::delta / 40.0f;
}
wheelSpeed = 0;
if(Input::keyDown(KEY_UP)){
wheelSpeed = wheelSpeed + fp(2);
if(Input::keyDown(KEY_UP) || Input::keyDown(KEY_8)){
wheelSpeed = wheelSpeed + Time::delta / 200.0f;
}
if(Input::keyDown(KEY_DOWN)){
wheelSpeed = wheelSpeed - fp(2);
if(Input::keyDown(KEY_DOWN) || Input::keyDown(KEY_5)){
wheelSpeed = wheelSpeed - Time::delta / 200.0f;
}
// wheelSpeed = wheelSpeed / (fp(1000) * fp(Time::delta));
// if(wheelSpeed < 0)
// wheelSpeed = 0;
// wheelSpeed = wheelSpeed * fp(0.7);
carSpeed.x = carSpeed.x + wheelSpeed * fp(Time::delta) * fp_cos(carAngle) / fp(500);
carSpeed.z = carSpeed.z + wheelSpeed * fp(Time::delta) * fp_sin(fp(0)-(carAngle)) / fp(500);
// cameraAngle = fp(0) - fp_atan2(carSpeed.z, carSpeed.x);
cameraAngle = carAngle;
carPos.x = carPos.x + carSpeed.x * fp(Time::delta);
carPos.z = carPos.z + carSpeed.z * fp(Time::delta);
wheelSpeed = wheelSpeed - (wheelSpeed * 0.001f) * Time::delta;
if(wheelSpeed > 1)
wheelSpeed = 1;
if(wheelSpeed < 0)
wheelSpeed = 0;
carSpeed.x = carSpeed.x + wheelSpeed * float(fp_cos(fp(carAngle))) * Time::delta / 150.0f;
carSpeed.z = carSpeed.z + wheelSpeed * float(fp_sin(fp(0)-fp(carAngle))) * Time::delta / 150.0f;
carSpeed.x = carSpeed.x - (carSpeed.x * 0.01f) * Time::delta;
carSpeed.z = carSpeed.z - (carSpeed.z * 0.01f) * Time::delta;
cameraAngle = cameraAngle + (-cameraAngle * 0.02 + 0.02 * carDirection) * Time::delta;
carAngle = carAngle + (-carAngle * 0.05 + 0.05 * carDirection) * Time::delta;
// carAngle = carDirection;
carPos.x = carPos.x + carSpeed.x * Time::delta;
carPos.z = carPos.z + carSpeed.z * Time::delta;
// vec3f zero = {0,0,0};
// cameraPos = cameraPos + (zero - cameraPos * 0.2f + carPos * 0.2f) * Time::delta;
cameraPos = carPos;
Display::clear(newColor(70, 180, 220));
@ -818,9 +913,11 @@ int main(){
view = mat4();
view = mat4::rotateX(view, HALF_PI*0.1);
view = mat4::translate(view, 0, 2, 6);
view = mat4::rotateY(view, fp(0) - cameraAngle - fp(HALF_PI));
view = mat4::translate(view, fp(0)-carPos.x, 0, fp(0)-carPos.z);
view = mat4::rotateY(view, -cameraAngle - HALF_PI);
view = mat4::translate(view, -cameraPos.x, 0, -cameraPos.z);
// Rasterizer::drawModel(trees, false);
// Rasterizer::drawTriangle(trees.mesh.triangles[51+51*100], trees.shader, false);
Rasterizer::drawModel(track, false);
Rasterizer::drawModel(car, true);

View file

@ -1,6 +1,12 @@
#include "rasterizer.h"
#include "display.h"
#include "rmath.h"
#include "time.h"
struct Plane {
vec3d n;
fp d;
};
int min(int a, int b){
if(a < b)
@ -24,8 +30,8 @@ float abs(float v){
}
#endif
float dot(vec3f a, vec3f b){
return a.x*b.x + a.y*b.y;
fp dot3(vec3d a, vec3d b){
return a.x*b.x + a.y*b.y + a.z*b.z;
}
fp cross(vec3d a, vec3d b){
@ -33,8 +39,20 @@ fp cross(vec3d a, vec3d b){
}
namespace Rasterizer {
Plane clippingPlanes[5];
fp *depthBuffer;
void init(){
#define I_SQRT_2 0.707106
clippingPlanes[0] = {{0, 0, 1}, fp(0)-fp(NEAR_PLANE)}; // near
// clippingPlanes[1] = {{0, 0, 1}, fp(0)-fp(FAR_PLANE)}; // far
clippingPlanes[1] = {{fp(I_SQRT_2), 0, fp(I_SQRT_2)}, 0}; // left
clippingPlanes[2] = {{fp(-I_SQRT_2), 0, fp(I_SQRT_2)}, 0}; // right
clippingPlanes[3] = {{0, fp(I_SQRT_2), fp(I_SQRT_2)}, 0}; // bottom
clippingPlanes[4] = {{0, fp(-I_SQRT_2), fp(I_SQRT_2)}, 0}; // top
}
int edge(vec3i p, vec3i e1, vec3i e2){
return (p.x - e2.x) * (e1.y - e2.y) - (p.y - e2.y) * (e1.x - e2.x);
}
@ -46,8 +64,6 @@ namespace Rasterizer {
}
vec3d toDevice(vec3d p){
if(p.z == 0)
p.z = -0.1;
return {
p.x / p.z,
p.y / p.z,
@ -63,31 +79,11 @@ namespace Rasterizer {
};
}
void drawTriangle(Triangle triangle, Shader shader, bool useDepth){
// reset();
// SDL_SetRenderDrawColor(renderer, triangle.c.r, triangle.c.g, triangle.c.b, 255);
//
triangle.p0 = shader.vertexShader(triangle.p0, shader.uniforms);
triangle.p1 = shader.vertexShader(triangle.p1, shader.uniforms);
triangle.p2 = shader.vertexShader(triangle.p2, shader.uniforms);
if(useDepth && (triangle.p0.z == 0 || triangle.p1.z == 0 || triangle.p2.z == 0))
return;
void _drawTriangle(Triangle triangle, Shader shader, bool useDepth){
vec3d p0_d = toDevice(triangle.p0);
vec3d p1_d = toDevice(triangle.p1);
vec3d p2_d = toDevice(triangle.p2);
if((p0_d.z < NEAR_PLANE || p1_d.z < NEAR_PLANE || p2_d.z < NEAR_PLANE)
|| (p0_d.x < -0.5 && p1_d.x < -0.5 && p2_d.x < -0.5)
|| (p0_d.y < -0.5 && p1_d.y < -0.5 && p2_d.y < -0.5)
|| (p0_d.x > 0.5 && p1_d.x > 0.5 && p2_d.x > 0.5)
|| (p0_d.y > 0.5 && p1_d.y > 0.5 && p2_d.y > 0.5)
){
return;
}
fp winding = cross({p1_d.x - p0_d.x, p1_d.y - p0_d.y, 0}, {p2_d.x - p0_d.x, p2_d.y - p0_d.y, 0});
vec3i p0, p1, p2;
@ -106,36 +102,39 @@ namespace Rasterizer {
int maxX = min(max(max(p0.x, p1.x), p2.x), RENDER_WIDTH);
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);
if(minX == maxX || minY == maxY)
return;
int e1 = edge({minX, minY, 0}, p0, p1);
int e2 = edge({minX, minY, 0}, p1, p2);
int e3 = edge({minX, minY, 0}, p2, p0);
const vec3i bary_v0 = {(p1.x - p0.x), (p1.y - p0.y), 0};
const vec3i bary_v1 = {(p2.x - p0.x), (p2.y - p0.y), 0};
fp bary_denom = (bary_v0.x * bary_v1.y - bary_v1.x * bary_v0.y);
if(bary_denom == 0)
return;
const fp i_bary_denom = fp(1000) / fp(bary_v0.x * bary_v1.y - bary_v1.x * bary_v0.y);
fp bary_v, bary_w, bary_u;
fp i_p0z, i_p1z, i_p2z;
fp bary_v_per_x, bary_w_per_x, bary_u_per_x, bary_v_per_y, bary_w_per_y, bary_u_per_y;
if(useDepth){
const vec3i bary_v0 = {(p1.x - p0.x), (p1.y - p0.y), 0};
const vec3i bary_v1 = {(p2.x - p0.x), (p2.y - p0.y), 0};
fp bary_denom = (bary_v0.x * bary_v1.y - bary_v1.x * bary_v0.y);
if(bary_denom == 0)
return;
const fp i_bary_denom = fp(1000) / fp(bary_v0.x * bary_v1.y - bary_v1.x * bary_v0.y);
const vec3i bary_v2 = {minX - p0.x, minY - p0.y, 0};
const fp bary_v_per_x = fp(bary_v1.y) * fp(i_bary_denom) / fp(1000);
const fp bary_w_per_x = fp(0) - fp(bary_v0.y) * fp(i_bary_denom) / fp(1000);
const fp bary_u_per_x = fp(0) - bary_v_per_x - bary_w_per_x;
const vec3i bary_v2 = {minX - p0.x, minY - p0.y, 0};
bary_v_per_x = fp(bary_v1.y) * fp(i_bary_denom) / fp(1000);
bary_w_per_x = fp(0) - fp(bary_v0.y) * fp(i_bary_denom) / fp(1000);
bary_u_per_x = fp(0) - bary_v_per_x - bary_w_per_x;
const fp bary_v_per_y = fp(0) - fp(bary_v1.x) * fp(i_bary_denom) / fp(1000);
const fp bary_w_per_y = fp(bary_v0.x) * fp(i_bary_denom) / fp(1000);
const fp bary_u_per_y = fp(0) -bary_v_per_y - bary_w_per_y;
bary_v_per_y = fp(0) - fp(bary_v1.x) * fp(i_bary_denom) / fp(1000);
bary_w_per_y = fp(bary_v0.x) * fp(i_bary_denom) / fp(1000);
bary_u_per_y = fp(0) -bary_v_per_y - bary_w_per_y;
fp bary_v = fp(bary_v2.x * bary_v1.y - bary_v1.x * bary_v2.y) / fp(1000) * fp(i_bary_denom);
fp bary_w = fp(bary_v0.x * bary_v2.y - bary_v2.x * bary_v0.y) / fp(1000) * fp(i_bary_denom);
fp bary_u = fp(1) - bary_v - bary_w;
bary_v = fp(bary_v2.x * bary_v1.y - bary_v1.x * bary_v2.y) / fp(1000) * fp(i_bary_denom);
bary_w = fp(bary_v0.x * bary_v2.y - bary_v2.x * bary_v0.y) / fp(1000) * fp(i_bary_denom);
bary_u = fp(1) - bary_v - bary_w;
fp i_p0z = fp(1)/fp(p0.z);
fp i_p1z = fp(1)/fp(p1.z);
fp i_p2z = fp(1)/fp(p2.z);
i_p0z = fp(1)/fp(p0.z);
i_p1z = fp(1)/fp(p1.z);
i_p2z = fp(1)/fp(p2.z);
}
for(int y = minY; y < maxY; y++){
bool hasEntered = false;
@ -153,18 +152,28 @@ namespace Rasterizer {
fp i_z;
if(useDepth){
vec3d b = {i_bary_u, i_bary_v, i_bary_w};
// fp i_z = (b.x * i_p0z + b.y * i_p1z + b.z * i_p2z);
i_z.i = ((b.x.i * i_p0z.i) + (b.y.i * i_p1z.i) + (b.z.i * i_p2z.i)) / FP_RIGHT;
// i_z = (b.x * i_p0z + b.y * i_p1z + b.z * i_p2z);
i_z.i = ((b.x.i * i_p0z.i) + (b.y.i * i_p1z.i) + (b.z.i * i_p2z.i));
visible = visible && (i_z > depthBuffer[x+y*RENDER_WIDTH] || depthBuffer[x+y*RENDER_WIDTH] == -1);
}
if(visible){
if(useDepth)
// Color c = shader.fragmentShader(triangle.c, shader.uniforms);
// if((ie1 >= -2 && ie1 <= 2)
// || (ie2 >= -2 && ie2 <= 2)
// || (ie3 >= -2 && ie3 <= 2))
// c = {255 - c.r, 255 - c.g, 255 - c.b};
if(useDepth){
depthBuffer[x+y*RENDER_WIDTH] = i_z;
Color c = shader.fragmentShader(triangle.c, shader.uniforms);
// if(!(i_z == 0)){
// c.r = (int)(fp(c.r) * i_z * fp(100));
// c.g = (int)(fp(c.g) * i_z * fp(100));
// c.b = (int)(fp(c.b) * i_z * fp(100));
// }
}
#if PIXEL_SIZE == 1
Display::drawPoint(x, y, c);
Display::drawPoint(x, y, triangle.c);
#else
Display::fillRect(x*PIXEL_SIZE, y*PIXEL_SIZE, PIXEL_SIZE, PIXEL_SIZE, c);
Display::fillRect(x*PIXEL_SIZE, y*PIXEL_SIZE, PIXEL_SIZE, PIXEL_SIZE, triangle.c);
#endif
}
hasEntered = true;
@ -194,6 +203,242 @@ namespace Rasterizer {
}
}
// void drawTriangle(Triangle triangle, Shader shader, bool useDepth){
// triangle.p0 = shader.vertexShader(triangle.p0, shader.uniforms);
// triangle.p1 = shader.vertexShader(triangle.p1, shader.uniforms);
// triangle.p2 = shader.vertexShader(triangle.p2, shader.uniforms);
//
// if(triangle.p0 == triangle.p1 || triangle.p1 == triangle.p2 || triangle.p2 == triangle.p0){
// return;
// }
//
// bool clippedP0 = false;
// bool clippedP1 = false;
// bool clippedP2 = false;
//
// for(int i = 0; i < 5; i++){
// int numClipped = 0;
// if(dot3(clippingPlanes[i].n, triangle.p0) + clippingPlanes[i].d < 0){
// numClipped++;
// clippedP0 = true;
// return;
// }
// if(dot3(clippingPlanes[i].n, triangle.p1) + clippingPlanes[i].d < 0){
// numClipped++;
// clippedP1 = true;
// return;
// }
// if(dot3(clippingPlanes[i].n, triangle.p2) + clippingPlanes[i].d < 0){
// numClipped++;
// clippedP2 = true;
// return;
// }
// if(numClipped == 0){
// _drawTriangle(triangle, shader, useDepth);
// } else if(numClipped == 1){
// vec3d clipped;
// vec3d notClipped[2];
// if(clippedP0){
// clipped = triangle.p0;
// notClipped[0] = triangle.p1;
// notClipped[1] = triangle.p2;
// }
//
// if(clippedP1){
// clipped = triangle.p1;
// notClipped[0] = triangle.p0;
// notClipped[1] = triangle.p2;
// }
//
// if(clippedP2){
// clipped = triangle.p2;
// notClipped[0] = triangle.p0;
// notClipped[1] = triangle.p1;
// }
//
// fp d0 = dot3(clippingPlanes[i].n, clipped - notClipped[0]);
// fp d1 = dot3(clippingPlanes[i].n, clipped - notClipped[1]);
// if(d0 == 0 || d1 == 0)
// return;
//
// vec3d A = notClipped[0] + (clipped - notClipped[0]) * ((fp(0) - clippingPlanes[i].d - dot3(clippingPlanes[i].n, notClipped[0]))/d0);
// vec3d B = notClipped[1] + (clipped - notClipped[1]) * ((fp(0) - clippingPlanes[i].d - dot3(clippingPlanes[i].n, notClipped[1]))/d1);
//
// _drawTriangle({notClipped[0], A, notClipped[1], triangle.c}, shader, useDepth);
// _drawTriangle({notClipped[1], A, B, triangle.c}, shader, useDepth);
// } else if(numClipped == 2){
// vec3d clipped[2];
// vec3d notClipped;
// if(!clippedP0){
// notClipped = triangle.p0;
// clipped[0] = triangle.p1;
// clipped[1] = triangle.p2;
// } else if(!clippedP1){
// notClipped = triangle.p1;
// clipped[0] = triangle.p0;
// clipped[1] = triangle.p2;
// } else {
// notClipped = triangle.p2;
// clipped[0] = triangle.p0;
// clipped[1] = triangle.p1;
// }
//
// fp d0 = dot3(clippingPlanes[i].n, clipped[0] - notClipped);
// fp d1 = dot3(clippingPlanes[i].n, clipped[1] - notClipped);
// if(d0 == 0 || d1 == 0)
// return;
//
// vec3d B = notClipped + (clipped[0] - notClipped) * ((fp(0) - clippingPlanes[i].d - dot3(clippingPlanes[i].n, notClipped))/d0);
// vec3d C = notClipped + (clipped[0] - notClipped) * ((fp(0) - clippingPlanes[i].d - dot3(clippingPlanes[i].n, notClipped))/d1);
//
// _drawTriangle({notClipped, B, C, triangle.c}, shader, useDepth);
// }
// }
// }
Mesh clipTriangleAgainstPlane(Triangle triangle, Plane plane){
int numClipped = 0;
bool clippedP0 = false;
bool clippedP1 = false;
bool clippedP2 = false;
if(dot3(plane.n, triangle.p0) + plane.d < 0){
numClipped++;
clippedP0 = true;
}
if(dot3(plane.n, triangle.p1) + plane.d < 0){
numClipped++;
clippedP1 = true;
}
if(dot3(plane.n, triangle.p2) + plane.d < 0){
numClipped++;
clippedP2 = true;
}
if(numClipped == 0){
Mesh m = {1, (Triangle*)malloc(sizeof(Triangle))};
m.triangles[0] = triangle;
return m;
} else if(numClipped == 3){
return {0, nullptr};
} else if(numClipped == 2){
vec3d clipped[2];
vec3d notClipped;
if(!clippedP0){
notClipped = triangle.p0;
clipped[0] = triangle.p1;
clipped[1] = triangle.p2;
} else if(!clippedP1){
notClipped = triangle.p1;
clipped[0] = triangle.p0;
clipped[1] = triangle.p2;
} else {
notClipped = triangle.p2;
clipped[0] = triangle.p0;
clipped[1] = triangle.p1;
}
fp d0 = dot3(plane.n, clipped[0] - notClipped);
fp d1 = dot3(plane.n, clipped[1] - notClipped);
if(d0 == 0 || d1 == 0)
return {0, nullptr};
vec3d B = notClipped + (clipped[0] - notClipped) * ((fp(0) - plane.d - dot3(plane.n, notClipped))/d0);
vec3d C = notClipped + (clipped[1] - notClipped) * ((fp(0) - plane.d - dot3(plane.n, notClipped))/d1);
Mesh m = {1, (Triangle*)malloc(sizeof(Triangle))};
m.triangles[0] = {notClipped, B, C, triangle.c};
return m;
} else if(numClipped == 1){
vec3d clipped;
vec3d notClipped[2];
if(clippedP0){
clipped = triangle.p0;
notClipped[0] = triangle.p1;
notClipped[1] = triangle.p2;
}
if(clippedP1){
clipped = triangle.p1;
notClipped[0] = triangle.p0;
notClipped[1] = triangle.p2;
}
if(clippedP2){
clipped = triangle.p2;
notClipped[0] = triangle.p0;
notClipped[1] = triangle.p1;
}
fp d0 = dot3(plane.n, clipped - notClipped[0]);
fp d1 = dot3(plane.n, clipped - notClipped[1]);
if(d0 == 0 || d1 == 0)
return {0, nullptr};
vec3d A = notClipped[0] + (clipped - notClipped[0]) * ((fp(0) - plane.d - dot3(plane.n, notClipped[0]))/d0);
vec3d B = notClipped[1] + (clipped - notClipped[1]) * ((fp(0) - plane.d - dot3(plane.n, notClipped[1]))/d1);
Mesh m = {2, (Triangle*)malloc(2*sizeof(Triangle))};
m.triangles[0] = {notClipped[0], A, notClipped[1], triangle.c};
m.triangles[1] = {notClipped[1], A, B, triangle.c};
return m;
}
return {0, nullptr};
}
Mesh clipMeshAgainstPlane(Mesh mesh, Plane plane){
Mesh r = {0, nullptr};
for(int i = 0; i < mesh.numTriangles; i++){
Mesh m = clipTriangleAgainstPlane(mesh.triangles[i], plane);
r.numTriangles += m.numTriangles;
if(r.triangles == nullptr)
r.triangles = (Triangle*) malloc(r.numTriangles*sizeof(Triangle));
else
r.triangles = (Triangle*) realloc(r.triangles, r.numTriangles*sizeof(Triangle));
for(int i = r.numTriangles - m.numTriangles; i < r.numTriangles; i++){
r.triangles[i] = m.triangles[i - (r.numTriangles - m.numTriangles)];
}
free(m.triangles);
}
free(mesh.triangles);
return r;
}
Mesh clipMesh(Mesh mesh){
for(int i = 0; i < 5; i++){
mesh = clipMeshAgainstPlane(mesh, clippingPlanes[i]);
}
return mesh;
}
Mesh clipTriangle(Triangle triangle){
Mesh m = {1, (Triangle*)malloc(sizeof(Triangle))};
m.triangles[0] = triangle;
m = clipMesh(m);
return m;
}
void drawTriangle(Triangle triangle, Shader shader, bool useDepth){
triangle.p0 = shader.vertexShader(triangle.p0, shader.uniforms);
triangle.p1 = shader.vertexShader(triangle.p1, shader.uniforms);
triangle.p2 = shader.vertexShader(triangle.p2, shader.uniforms);
if(triangle.p0 == triangle.p1 || triangle.p1 == triangle.p2 || triangle.p2 == triangle.p0){
return;
}
Mesh mesh = clipTriangle(triangle);
for(int i = 0; i < mesh.numTriangles; i++){
_drawTriangle(mesh.triangles[i], shader, useDepth);
}
free(mesh.triangles);
}
void drawModel(Model model, bool useDepth){
for(int i = 0; i < model.mesh.numTriangles; i++){
drawTriangle(model.mesh.triangles[i], model.shader, useDepth);

View file

@ -117,3 +117,16 @@ fp fp_atan2(fp y, fp 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
x = *(float*)&i; // convert new bits into float
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)));
}