summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Decals.cpp7
-rw-r--r--src/GameLoop.cpp2
-rw-r--r--src/GameTick.cpp29
-rw-r--r--src/Models.cpp29
-rw-r--r--src/Person.cpp45
-rw-r--r--src/Quaternions.cpp79
-rw-r--r--src/Quaternions.h19
-rw-r--r--src/Skeleton.cpp38
-rw-r--r--src/misc.h3
-rw-r--r--src/misc.zig50
10 files changed, 121 insertions, 180 deletions
diff --git a/src/Decals.cpp b/src/Decals.cpp
index 8a6ab5e..e5971e4 100644
--- a/src/Decals.cpp
+++ b/src/Decals.cpp
@@ -52,12 +52,11 @@ int Decals::MakeDecal(int atype, XYZ location, float size, XYZ normal, int poly,
 		else if (major == 0)
 			right = {normal.z, 0.0f, 0.0f};
 	} else {
-		CrossProduct(axis[major], normal, &right);
+		right = crossProduct(axis[major], normal);
 	}
 
-    CrossProduct(normal, right, &up);
-    Normalise(&up);
-    Normalise(&right);
+	up = normalize(crossProduct(normal, right));
+	right = normalize(right);
 
 	float count;
 	float count2;
diff --git a/src/GameLoop.cpp b/src/GameLoop.cpp
index 0cfe3ef..f9eefcc 100644
--- a/src/GameLoop.cpp
+++ b/src/GameLoop.cpp
@@ -141,7 +141,7 @@ void handleKey(Game* game, int key, int action, int mods)
 
 			XYZ towards = player.playercoords - game->bodycoords;
 			if (towards.x || towards.z) {
-				Normalise(&towards);
+				towards = normalize(towards);
 				camera.rotation = asin(towards.x) * 180.0f / M_PI;
 				if (towards.z > 0)
 					camera.rotation = 180 - camera.rotation;
diff --git a/src/GameTick.cpp b/src/GameTick.cpp
index 1193c3c..fc5305b 100644
--- a/src/GameTick.cpp
+++ b/src/GameTick.cpp
@@ -186,7 +186,7 @@ void click(Game* game, int button, int action, int mods)
 
 	XYZ flatfacing = facing;
 	flatfacing.y = 0;
-	Normalise(&flatfacing);
+	flatfacing = normalize(flatfacing);
 
 	// Gun whacking or knife slashing
 	if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS
@@ -932,7 +932,7 @@ void renderLaser(Game* game)
 		return;
 	}
 
-	Normalise(&aim);
+	aim = normalize(aim);
 	auto& coords = player.playercoords;
 	auto start = coords
 		+ DoRotation(joints[lefthand].position, 0.0f, rotation, 0.0f)
@@ -1015,7 +1015,7 @@ void Game::Tick()
 
 	XYZ flatfacing = facing;
 	flatfacing.y = 0;
-	Normalise(&flatfacing);
+	flatfacing = normalize(flatfacing);
 
 	// Check collision with buildings
 	int beginx,endx;
@@ -1449,8 +1449,7 @@ void Game::Tick()
 					}
 
 					if(person[i].targetanimation!=zombieeatanim||person[i].type!=zombietype){
-						towards=person[i].playercoords-person[i].pathtarget;
-						Normalise(&towards);
+						towards = normalize(person[i].playercoords - person[i].pathtarget);
 						person[i].playerrotation=asin(0-towards.x)*360/6.28;
 						if(towards.z>0)person[i].playerrotation=180-person[i].playerrotation;
 					}
@@ -1527,8 +1526,8 @@ void Game::Tick()
 					person[i].playercoords.y = joint.position.y;
 
 			//Find orientation
-			XYZ firsttop=person[i].skeleton.joints[neck].position-person[i].skeleton.joints[groin].position;
-			Normalise(&firsttop);
+			XYZ firsttop = normalize(person[i].skeleton.joints[neck].position
+				- person[i].skeleton.joints[groin].position);
 			person[i].playerrotation=acos(0-firsttop.z);
 			person[i].playerrotation*=360/6.28;
 			if(0>firsttop.x)person[i].playerrotation=360-person[i].playerrotation;
@@ -1626,7 +1625,7 @@ void Game::Tick()
 				aim = aimPlayer(this);
 			else
 				aim = facing;
-			Normalise(&aim);
+			aim = normalize(aim);
 
 			int aimjoint;
 			switch (person[j].whichgun) {
@@ -2000,10 +1999,8 @@ void Game::Tick()
 								joint.offset += DoRotation(aim * 200 / distance / totalarea * 10,
 									0, -person[whichhit].playerrotation, 0);
 							}
-							if (findLengthfast(joint.offset) > 36) {
-								Normalise(&joint.offset);
-								joint.offset *= 6;
-							}
+							if (findLengthfast(joint.offset) > 36)
+								joint.offset = normalize(joint.offset) * 6;
 						}
 					}
 
@@ -2232,7 +2229,7 @@ void Game::Tick()
 				if (sprites.size[i] > 1)
 					decals.MakeDecal(crater, wallhit, 9, normalrotated, whichtri, &blocks[citytype[wherex][wherey]], move, cityrotation[wherex][wherey] * 90);
 				sprites.location[i] = wallhit + normalrotated * 0.02f;
-				ReflectVector(&sprites.velocity[i], &normalrotated);
+				reflect(&sprites.velocity[i], normalrotated);
 				sprites.velocity[i] *= 0.3f;
 
 				if (sprites.type[i] == grenadesprite && sprites.size[i] <= 1) {
@@ -2341,8 +2338,7 @@ void Game::Tick()
 								joint.offset += DoRotation(sprites.velocity[i] * 0.1 * 200 / distance / totalarea * 10, 0, -person[j].playerrotation, 0);
 							}
 							if (findLengthfast(joint.offset) > 9) {
-								Normalise(&joint.offset);
-								joint.offset *= 3;
+								joint.offset = normalize(joint.offset) * 3;
 							}
 						}
 					}
@@ -2432,8 +2428,7 @@ void Game::Tick()
 
 				person[k].longdead=1;
 				for (auto& joint : person[k].skeleton.joints) {
-					relation = joint.position - sprites.location[i];
-					Normalise(&relation);
+					relation = normalize(joint.position - sprites.location[i]);
 					auto distance = findDistance(joint.position, sprites.location[i]);
 					if (distance > 1)
 						joint.velocity += relation / distance * 300;
diff --git a/src/Models.cpp b/src/Models.cpp
index ad0f357..e706ebf 100644
--- a/src/Models.cpp
+++ b/src/Models.cpp
@@ -6,14 +6,11 @@
 
 void Model::CalculateNormals()
 {
-	for (int i = 0; i < TriangleNum; ++i) {
-		CrossProduct(vertex[Triangles[i].vertex[1]]
+	for (int i = 0; i < TriangleNum; ++i)
+		normals[i] = normalize(crossProduct(vertex[Triangles[i].vertex[1]]
 			- vertex[Triangles[i].vertex[0]],
 			vertex[Triangles[i].vertex[2]]
-			- vertex[Triangles[i].vertex[0]],
-			normals + i);
-		Normalise(normals + i);
-	}
+			- vertex[Triangles[i].vertex[0]]));
 
 	for (int i = 0; i < TriangleNum; ++i) {
 		vArray[i*27+0]=vertex[Triangles[i].vertex[0]].x;
@@ -128,10 +125,7 @@ int Model::LineCheck(XYZ p1,XYZ p2, XYZ *p)
 	int intersecting=0;
 	int firstintersecting=-1;
 	XYZ point;
-	if(sphere_line_intersection(p1.x,p1.y,p1.z,
-								p2.x,p2.y,p2.z,
-								boundingspherecenter.x,boundingspherecenter.y,boundingspherecenter.z,
-								boundingsphereradius))
+	if (segmentIntersectsSphere(p1, p2, boundingspherecenter, boundingsphereradius))
 	for (j=0;j<TriangleNum;j++){
 		intersecting=LineFacetd(p1,p2,vertex[Triangles[j].vertex[0]],vertex[Triangles[j].vertex[1]],vertex[Triangles[j].vertex[2]],normals[j],&point);
 		if (intersecting == 0) continue;
@@ -153,10 +147,7 @@ int Model::LineCheck2(XYZ p1,XYZ p2, XYZ *p, XYZ move, float rotate)
 	p2=p2-move;
 	if(rotate)p1=DoRotation(p1,0,-rotate,0);
 	if(rotate)p2=DoRotation(p2,0,-rotate,0);
-	if(sphere_line_intersection(p1.x,p1.y,p1.z,
-								p2.x,p2.y,p2.z,
-								boundingspherecenter.x,boundingspherecenter.y,boundingspherecenter.z,
-								boundingsphereradius))
+	if (segmentIntersectsSphere(p1, p2, boundingspherecenter, boundingsphereradius))
 	for (j=0;j<TriangleNum;j++){
 		intersecting=LineFacetd(p1,p2,vertex[Triangles[j].vertex[0]],vertex[Triangles[j].vertex[1]],vertex[Triangles[j].vertex[2]],normals[j],&point);
 		if (intersecting == 0) continue;
@@ -181,10 +172,7 @@ int Model::LineCheck2(XYZ *p1,XYZ *p2, XYZ *p, XYZ *move, float *rotate)
 	*p2=*p2-*move;
 	if(*rotate)*p1=DoRotation(*p1,0,-*rotate,0);
 	if(*rotate)*p2=DoRotation(*p2,0,-*rotate,0);
-	if(sphere_line_intersection(p1->x,p1->y,p1->z,
-								p2->x,p2->y,p2->z,
-								boundingspherecenter.x,boundingspherecenter.y,boundingspherecenter.z,
-								boundingsphereradius))
+	if (segmentIntersectsSphere(*p1, *p2, boundingspherecenter, boundingsphereradius))
 	for (j=0;j<TriangleNum;j++){
 		intersecting = LineFacetd(*p1, *p2,
 			vertex[Triangles[j].vertex[0]],
@@ -213,10 +201,7 @@ int Model::LineCheck3(XYZ p1,XYZ p2, XYZ *p, XYZ move, float rotate, float *d)
 	p2=p2-move;
 	p1=DoRotation(p1,0,-rotate,0);
 	p2=DoRotation(p2,0,-rotate,0);
-	if(sphere_line_intersection(p1.x,p1.y,p1.z,
-								p2.x,p2.y,p2.z,
-								boundingspherecenter.x,boundingspherecenter.y,boundingspherecenter.z,
-								boundingsphereradius))
+	if (segmentIntersectsSphere(p1, p2, boundingspherecenter, boundingsphereradius))
 	for (j=0;j<TriangleNum;j++){
 		intersecting=LineFacetd(p1,p2,vertex[Triangles[j].vertex[0]],vertex[Triangles[j].vertex[1]],vertex[Triangles[j].vertex[2]],normals[j],&point);
 		if (intersecting == 0) continue;
diff --git a/src/Person.cpp b/src/Person.cpp
index 2007857..452a8bd 100644
--- a/src/Person.cpp
+++ b/src/Person.cpp
@@ -72,9 +72,7 @@ HitStruct 	Person::BulletCollideWithPlayer(int who, XYZ start, XYZ end){
 	}
 	tempbulletloc[0]=start;
 	tempbulletloc[1]=end;
-	if(sphere_line_intersection(tempbulletloc[0].x,tempbulletloc[0].y,tempbulletloc[0].z,
-								tempbulletloc[1].x,tempbulletloc[1].y,tempbulletloc[1].z,
-								average.x, average.y, average.z, distancemax)){
+	if (segmentIntersectsSphere(start, end, average, distancemax)) {
 	for (auto& joint : skeleton.joints) {
 		if (joint.hasparent && joint.visible) {
 			tempbulletloc[0] = start;
@@ -726,7 +724,7 @@ void Person::FindRotationGun(XYZ start, XYZ target)
 	tempforward=DoRotation(tempforward,0,gunrotate1-90,0);
 	tempforward=DoRotation(tempforward,0,0,gunrotate2-90);
 	tempforward.y=0;
-	Normalise(&tempforward);
+	tempforward = normalize(tempforward);
 	gunrotate3=acos(0-tempforward.z)*rad2deg;
 	if(0>tempforward.x)gunrotate3=360-gunrotate3;
 }
@@ -935,8 +933,7 @@ int Person::DrawSkeleton(int who)
 					joint.oldposition = joint.position;
 					joint.position += joint.offset;
 					if (findLengthfast(joint.offset) >= multiplier * multiplier * 25) {
-						normal = joint.offset;
-						Normalise(&normal);
+						normal = normalize(joint.offset);
 						skeleton.offset = 1;
 						joint.offset -= normal * multiplier * 5;
 					} else {
@@ -947,34 +944,30 @@ int Person::DrawSkeleton(int who)
 			}
 
 			auto& fwdjoints = skeleton.forwardjoints;
-			CrossProduct(skeleton.joints[fwdjoints[1]].position
+			skeleton.forward = normalize(crossProduct(skeleton.joints[fwdjoints[1]].position
 				- skeleton.joints[fwdjoints[0]].position,
 				skeleton.joints[fwdjoints[2]].position
-				- skeleton.joints[fwdjoints[0]].position,
-				&skeleton.forward);
-			Normalise(&skeleton.forward);
+				- skeleton.joints[fwdjoints[0]].position));
 
 			auto& lowfwd = skeleton.lowforwardjoints;
-			CrossProduct(skeleton.joints[lowfwd[1]].position
+			skeleton.lowforward = normalize(crossProduct(skeleton.joints[lowfwd[1]].position
 				- skeleton.joints[lowfwd[0]].position,
 				skeleton.joints[lowfwd[2]].position
-				- skeleton.joints[lowfwd[0]].position,
-				&skeleton.lowforward);
-			Normalise(&skeleton.lowforward);
+				- skeleton.joints[lowfwd[0]].position));
 
 			// Special forwards
 			auto specialfwd = skeleton.specialforward;
 			*specialfwd++ = skeleton.forward;
 
-			*specialfwd = skeleton.joints[rightelbow].position
+			*specialfwd = normalize(skeleton.joints[rightelbow].position
 				- skeleton.joints[rightshoulder].position / 2
-				- right_wrist / 2 + skeleton.forward * 0.2;
-			Normalise(specialfwd++);
+				- right_wrist / 2 + skeleton.forward * 0.2);
+			specialfwd++;
 
-			*specialfwd = skeleton.joints[leftelbow].position
+			*specialfwd = normalize(skeleton.joints[leftelbow].position
 				- skeleton.joints[leftshoulder].position / 2
-				- left_wrist / 2 + skeleton.forward * 0.2;
-			Normalise(specialfwd++);
+				- left_wrist / 2 + skeleton.forward * 0.2);
+			specialfwd++;
 
 			if(!who && aimamount > 0
 			   && health == 100 && whichgun != nogun) {
@@ -990,17 +983,17 @@ int Person::DrawSkeleton(int who)
 				skeleton.specialforward[2] += facingdown * aimamount;
 			}
 
-			*specialfwd = skeleton.joints[righthip].position / 2
+			*specialfwd = normalize(skeleton.joints[righthip].position / 2
 				+ skeleton.joints[rightankle].position / 2
 				- skeleton.joints[rightknee].position
-				+ skeleton.lowforward * 0.2;
-			Normalise(specialfwd++);
+				+ skeleton.lowforward * 0.2);
+			specialfwd++;
 
-			*specialfwd = skeleton.joints[lefthip].position / 2
+			*specialfwd = normalize(skeleton.joints[lefthip].position / 2
 				+ skeleton.joints[leftankle].position / 2
 				- skeleton.joints[leftknee].position
-				+ skeleton.lowforward * 0.2;
-			Normalise(specialfwd++);
+				+ skeleton.lowforward * 0.2);
+			specialfwd++;
 
 			for (int i = 0; i < max_joints; i++)
 				if (skeleton.joints[i].hasparent
diff --git a/src/Quaternions.cpp b/src/Quaternions.cpp
index 6fe85bf..9142da0 100644
--- a/src/Quaternions.cpp
+++ b/src/Quaternions.cpp
@@ -2,20 +2,6 @@
 
 #include "Quaternions.h"
 
-void CrossProduct(XYZ P, XYZ Q, XYZ *V){
-	V->x = P.y * Q.z - P.z * Q.y;
-	V->y = P.z * Q.x - P.x * Q.z;
-	V->z = P.x * Q.y - P.y * Q.x;
-}
-
-void Normalise(XYZ *vectory) {
-	float d = sqrt(vectory->x*vectory->x+vectory->y*vectory->y+vectory->z*vectory->z);
-	if(d==0){return;}
-	vectory->x /= d;
-	vectory->y /= d;
-	vectory->z /= d;
-}
-
 extern float u0, u1, u2;
 extern float v0, v1, v2;
 extern float a, b;
@@ -117,30 +103,6 @@ float LineFacetd(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc, XYZ n, XYZ *p)
    return 1;
 }
 
-void ReflectVector(XYZ *vel, XYZ *n)
-{
-   XYZ vn;
-   XYZ vt;
-   float dotprod;
-
-   dotprod=dotproduct(*n,*vel);
-   vn.x=n->x*dotprod;
-   vn.y=n->y*dotprod;
-   vn.z=n->z*dotprod;
-
-   vt.x=vel->x-vn.x;
-   vt.y=vel->y-vn.y;
-   vt.z=vel->z-vn.z;
-
-   vel->x = vt.x - vn.x;
-   vel->y = vt.y - vn.y;
-   vel->z = vt.z - vn.z;
-}
-
-float dotproduct(XYZ point1, XYZ point2){
-	return point1.x * point2.x + point1.y * point2.y + point1.z * point2.z;
-}
-
 float findDistance(XYZ point1, XYZ point2){
 	return sqrt((point1.x-point2.x)*(point1.x-point2.x)+(point1.y-point2.y)*(point1.y-point2.y)+(point1.z-point2.z)*(point1.z-point2.z));
 }
@@ -191,44 +153,3 @@ XYZ DoRotation(XYZ thePoint, float xang, float yang, float zang){
 
 	return thePoint;
 }
-
-float square( float f ) { return (f*f) ;}
-
-bool sphere_line_intersection(float x1, float y1, float z1,
-	float x2, float y2, float z2, float x3, float y3, float z3, float r)
-{
-
-	 // x1,y1,z1  P1 coordinates (point of line)
-	 // x2,y2,z2  P2 coordinates (point of line)
-	 // x3,y3,z3, r  P3 coordinates and radius (sphere)
-	 // x,y,z   intersection coordinates
-	 //
-	 // This function returns a pointer array which first index indicates
-	 // the number of intersection point, followed by coordinate pairs.
-
-	float a, b, c, i;
-
-	if(x1>x3+r&&x2>x3+r)return(0);
-	if(x1<x3-r&&x2<x3-r)return(0);
-	if(y1>y3+r&&y2>y3+r)return(0);
-	if(y1<y3-r&&y2<y3-r)return(0);
-	if(z1>z3+r&&z2>z3+r)return(0);
-	if(z1<z3-r&&z2<z3-r)return(0);
-	 a =  square(x2 - x1) + square(y2 - y1) + square(z2 - z1);
-	 b =  2* ( (x2 - x1)*(x1 - x3)
-	      + (y2 - y1)*(y1 - y3)
-	      + (z2 - z1)*(z1 - z3) ) ;
-	 c =  square(x3) + square(y3) +
-	      square(z3) + square(x1) +
-	      square(y1) + square(z1) -
-	      2* ( x3*x1 + y3*y1 + z3*z1 ) - square(r) ;
-	 i =   b * b - 4 * a * c ;
-
-	 if ( i < 0.0 )
-	 {
-	  // no intersection
-	  return(0);
-	 }
-
-	return(1);
-}
diff --git a/src/Quaternions.h b/src/Quaternions.h
index ee3e876..16ff2d9 100644
--- a/src/Quaternions.h
+++ b/src/Quaternions.h
@@ -41,23 +41,24 @@ constexpr XYZ& operator/=(XYZ& u, float k) { return u = u / k; }
 #ifdef __cplusplus
 extern "C" {
 #endif // __cplusplus
-	void CrossProduct(struct XYZ P, struct XYZ Q, struct XYZ *V);
-	void Normalise(struct XYZ *vectory);
-	bool PointInTriangle(struct XYZ *p, struct XYZ normal,
-		struct XYZ *p1, struct XYZ *p2, struct XYZ *p3);
+	float dotProduct(struct XYZ, struct XYZ);
+	struct XYZ crossProduct(struct XYZ, struct XYZ);
+	struct XYZ normalize(struct XYZ);
+	void reflect(struct XYZ*, struct XYZ);
+	bool segmentIntersectsSphere(struct XYZ, struct XYZ, struct XYZ, float);
+
 	float LineFacetd(struct XYZ p1, struct XYZ p2,
 		struct XYZ pa, struct XYZ pb, struct XYZ pc,
 		struct XYZ n, struct XYZ *p);
-	void ReflectVector(struct XYZ *vel, struct XYZ *n);
 	struct XYZ DoRotation(struct XYZ thePoint,
 		float xang, float yang, float zang);
 	float findDistance(struct XYZ point1, struct XYZ point2);
 	float findLengthfast(struct XYZ point1);
 	float findDistancefast(struct XYZ point1, struct XYZ point2);
-	float dotproduct(struct XYZ point1, struct XYZ point2);
-	bool sphere_line_intersection(float x1, float y1, float z1,
-		float x2, float y2, float z2,
-		float x3, float y3, float z3, float r);
+
+	void getFrustum(float (*)[4]);
+	int cubeInFrustum(float (*)[4], float, float, float, float);
+	int sphereInFrustum(float (*)[4], float, float, float, float);
 #ifdef __cplusplus
 } // extern "C"
 #endif // __cplusplus
diff --git a/src/Skeleton.cpp b/src/Skeleton.cpp
index dc5cdf8..6925fb6 100644
--- a/src/Skeleton.cpp
+++ b/src/Skeleton.cpp
@@ -34,10 +34,8 @@ void Joint::DoConstraint()
 	if(hasparent){
 		//Find midpoint
 		midp=(position+parent->position)/2;
-		//Find vector from midpoint to second vector
-		vel=parent->position-midp;
-		//Change to unit vector
-		Normalise(&vel);
+		// Find vector from midpoint to second vector
+		vel = normalize(parent->position - midp);
 		//Apply velocity change
 		velocity+=((midp-vel*length/2)-position);
 		parent->velocity+=((midp+vel*length/2)-parent->position);
@@ -69,10 +67,8 @@ void Muscle::DoConstraint(int broken)
 
 	//Find midpoint
 	midp=(parent1->position+parent2->position)/2;
-	//Find vector from midpoint to second vector
-	vel=parent2->position-midp;
-	//Change to unit vector
-	Normalise(&vel);
+	// Find vector from midpoint to second vector
+	vel = normalize(parent2->position - midp);
 	//Apply velocity change
 	newpoint1=midp-vel*length/2;
 	newpoint2=midp+vel*length/2;
@@ -137,7 +133,7 @@ void Skeleton::DoConstraints(Model *collide, XYZ *move, float rotation)
 				    && collide->normals[whichtri].y <= 0.8) {
 					normalrotated = DoRotation(collide->normals[whichtri], 0, rotation, 0);
 					pos = impact + normalrotated * offset;
-					ReflectVector(&joints[i].velocity, &normalrotated);
+					reflect(&joints[i].velocity, normalrotated);
 					joints[i].velocity *= 0.3;
 				}
 
@@ -284,7 +280,7 @@ void Skeleton::FindRotationJoint(int which)
 	tempforward=DoRotation(tempforward,0,joints[which].rotate1-90,0);
 	tempforward=DoRotation(tempforward,0,0,joints[which].rotate2-90);
 	tempforward.y=0;
-	Normalise(&tempforward);
+	tempforward = normalize(tempforward);
 	joints[which].rotate3=acos(0-tempforward.z)*rad2deg;
 	if(0>tempforward.x)joints[which].rotate3=360-joints[which].rotate3;
 }
@@ -313,7 +309,7 @@ void Skeleton::FindRotationMuscle(int which)
 	tempforward=DoRotation(tempforward,0,muscles[which].rotate1-90,0);
 	tempforward=DoRotation(tempforward,0,0,muscles[which].rotate2-90);
 	tempforward.y=0;
-	Normalise(&tempforward);
+	tempforward = normalize(tempforward);
 	muscles[which].rotate3=acos(0-tempforward.z)*rad2deg;
 	for (auto& joint : joints)
 		if (&joint == muscles[which].parent1) {
@@ -344,11 +340,15 @@ void Animation::load(const char* name)
 		for (int i = 0; i < max_joints; ++i)
 			testskeleton.joints[i].position = position[i][j];
 		//Find forward vectors
-		CrossProduct(testskeleton.joints[testskeleton.forwardjoints[1]].position-testskeleton.joints[testskeleton.forwardjoints[0]].position,testskeleton.joints[testskeleton.forwardjoints[2]].position-testskeleton.joints[testskeleton.forwardjoints[0]].position,&testskeleton.forward);
-		Normalise(&testskeleton.forward);
+		testskeleton.forward = normalize(crossProduct(testskeleton.joints[testskeleton.forwardjoints[1]].position
+			- testskeleton.joints[testskeleton.forwardjoints[0]].position,
+			testskeleton.joints[testskeleton.forwardjoints[2]].position
+			- testskeleton.joints[testskeleton.forwardjoints[0]].position));
 
-		CrossProduct(testskeleton.joints[testskeleton.lowforwardjoints[1]].position-testskeleton.joints[testskeleton.lowforwardjoints[0]].position,testskeleton.joints[testskeleton.lowforwardjoints[2]].position-testskeleton.joints[testskeleton.lowforwardjoints[0]].position,&testskeleton.lowforward);
-		Normalise(&testskeleton.lowforward);
+		testskeleton.lowforward = normalize(crossProduct(testskeleton.joints[testskeleton.lowforwardjoints[1]].position
+			- testskeleton.joints[testskeleton.lowforwardjoints[0]].position,
+			testskeleton.joints[testskeleton.lowforwardjoints[2]].position
+			- testskeleton.joints[testskeleton.lowforwardjoints[0]].position));
 
 		//Special forwards
 		testskeleton.specialforward[0]=testskeleton.forward;
@@ -356,20 +356,20 @@ void Animation::load(const char* name)
 		testskeleton.specialforward[1]=testskeleton.joints[rightshoulder].position+testskeleton.joints[rightwrist].position;
 		testskeleton.specialforward[1]=testskeleton.joints[rightelbow].position-testskeleton.specialforward[1]/2;
 		testskeleton.specialforward[1]+=testskeleton.forward*.2;
-		Normalise(&testskeleton.specialforward[1]);
+		testskeleton.specialforward[1] = normalize(testskeleton.specialforward[1]);
 		testskeleton.specialforward[2]=testskeleton.joints[leftshoulder].position+testskeleton.joints[leftwrist].position;
 		testskeleton.specialforward[2]=testskeleton.joints[leftelbow].position-testskeleton.specialforward[2]/2;
 		testskeleton.specialforward[2]+=testskeleton.forward*.2;
-		Normalise(&testskeleton.specialforward[2]);
+		testskeleton.specialforward[2] = normalize(testskeleton.specialforward[2]);
 
 		testskeleton.specialforward[3]=testskeleton.joints[righthip].position+testskeleton.joints[rightankle].position;
 		testskeleton.specialforward[3]=testskeleton.specialforward[3]/2-testskeleton.joints[rightknee].position;
 		testskeleton.specialforward[3]+=testskeleton.lowforward*.2;
-		Normalise(&testskeleton.specialforward[3]);
+		testskeleton.specialforward[3] = normalize(testskeleton.specialforward[3]);
 		testskeleton.specialforward[4]=testskeleton.joints[lefthip].position+testskeleton.joints[leftankle].position;
 		testskeleton.specialforward[4]=testskeleton.specialforward[4]/2-testskeleton.joints[leftknee].position;
 		testskeleton.specialforward[4]+=testskeleton.lowforward*.2;
-		Normalise(&testskeleton.specialforward[4]);
+		testskeleton.specialforward[4] = normalize(testskeleton.specialforward[4]);
 
 		//Find joint rotations
 		for (int i = 0; i < max_joints; ++i)
diff --git a/src/misc.h b/src/misc.h
index a51e2f3..148917f 100644
--- a/src/misc.h
+++ b/src/misc.h
@@ -74,9 +74,6 @@ extern "C" {
 	int32_t randInt(int32_t at_least, int32_t at_most);
 	uint32_t randUint(uint32_t less_than);
 
-	void getFrustum(float (*)[4]);
-	int cubeInFrustum(float (*)[4], float, float, float, float);
-	int sphereInFrustum(float (*)[4], float, float, float, float);
 	void setFog(struct Fog*, GLfloat, GLfloat, GLfloat,
 	            GLfloat, GLfloat, GLfloat);
 	void tempFog(struct Fog*, GLfloat, GLfloat, GLfloat);
diff --git a/src/misc.zig b/src/misc.zig
index d523827..0b1ad54 100644
--- a/src/misc.zig
+++ b/src/misc.zig
@@ -17,6 +17,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Black Shades.  If not, see <https://www.gnu.org/licenses/>.
 
+const Child = std.meta.Child;
 const Dir = std.fs.Dir;
 const TokenIterator = std.mem.TokenIterator(u8);
 const allocPrint = std.fmt.allocPrint;
@@ -377,6 +378,55 @@ pub fn saveScores(base_dir: []const u8, current: Scores) !void {
     try dir.writeFile("scores.ini", data);
 }
 
+// TODO: move graphics functions to a seperate file
+fn sqr(x: anytype) @TypeOf(x) {
+    return x * x;
+}
+
+fn dot(u: anytype, v: @TypeOf(u)) Child(@TypeOf(u)) {
+    return @reduce(.Add, u * v);
+}
+
+fn norm(v: anytype) Child(@TypeOf(v)) {
+    return @sqrt(dot(v, v));
+}
+
+const XYZ = extern struct { x: f32, y: f32, z: f32 };
+
+export fn crossProduct(u: XYZ, v: XYZ) XYZ {
+    return .{
+        .x = u.y * v.z - u.z * v.y,
+        .y = u.z * v.x - u.x * v.z,
+        .z = u.x * v.y - u.y * v.x,
+    };
+}
+
+export fn normalize(v: XYZ) XYZ {
+    const u = @bitCast(@Vector(3, f32), v);
+    const d = norm(u);
+    return if (d == 0) v else @bitCast(XYZ, u / @splat(3, d));
+}
+
+export fn reflect(v: XYZ, n: XYZ) XYZ {
+    const u = @bitCast(@Vector(3, f32), v);
+    const m = @bitCast(@Vector(3, f32), n);
+    return @bitCast(XYZ, u - m * @splat(3, dot(u, m) * 2));
+}
+
+export fn segmentIntersectsSphere(a: XYZ, b: XYZ, j: XYZ, r: f32) bool {
+    // FIXME: call directly with vectors
+    const p = @bitCast(@Vector(3, f32), a);
+    const q = @bitCast(@Vector(3, f32), b);
+    const i = @bitCast(@Vector(3, f32), j);
+
+    if (@reduce(.Or, @max(p, q) < i - @splat(3, r))) return false;
+    if (@reduce(.Or, @min(p, q) > i + @splat(3, r))) return false;
+    // https://en.wikipedia.org/wiki/Line–sphere_intersection
+    const d = q - p; // line's direction
+    const u = d / @splat(3, norm(d)); // unit vector
+    return sqr(dot(u, (p - i))) >= @reduce(.Add, sqr(p - i)) - sqr(r);
+}
+
 export fn getFrustum(frustum: [*][4]f32) void {
     var proj: [16]f32 = undefined;
     c.glGetFloatv(c.GL_PROJECTION_MATRIX, &proj);