joeylib3d/j3d/j3d.h

215 lines
7.6 KiB
C

/*
* JoeyLib 3D
* Copyright (C) 2019 Scott Duensing <scott@kangaroopunch.com>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef H_J3D_
#define H_J3D_
#include "joey.h"
typedef float j3Matrix4x4T[4][4];
typedef struct {
jint16 x;
jint16 y;
jint16 z;
} j3FacingT;
typedef struct {
float x;
float y;
float z;
} j3VertexT, j3Vector3DT;
typedef struct {
j3VertexT local; // Original vertex positions
j3VertexT world; // After rotation, scale, translation (in that order)
j3VertexT camera; // Camera space
} j3CoordinatesT;
typedef struct {
jint16 color; // Assigned color of this face
jint16 shade; // Color of this face after lighting
bool lit; // Do we care about lighting?
bool visible; // Can we see this triangle?
bool twoSided; // Are both sides visible?
float normalLength; // Magnatude of surface normal
float averageDepth; // Average Z depth of this triangle
juint16 index[3]; // We do this instead of just a typedef so it works with stretch_buffer
} j3TriangleT;
typedef struct {
juint16 vertexCount; // How many verticies are in the list
juint16 triangleCount; // How many triangles are in the list
j3CoordinatesT *verticies; // List of verticies as loaded from disk (more v1, v2, v3 than x, y, z)
j3TriangleT *triangles; // Triangles built from vertex list
j3VertexT position; // Position of object in world
j3VertexT rotation; // Rotation of object in world
j3VertexT scale; // Scale of object in world
bool positionDirty; // Did the position change?
bool rotationDirty; // Did the rotation change?
bool scaleDirty; // Did the scale change?
} j3ObjectT;
typedef struct {
j3ObjectT *object;
juint16 triangleNumber;
} j3PolyListT;
typedef struct {
juint16 objectCount;
j3ObjectT *objects;
} j3WorldT;
extern jint16 _j3VarClipMinX;
extern jint16 _j3VarClipMinY;
extern jint16 _j3VarClipMinZ;
extern jint16 _j3VarClipMaxX;
extern jint16 _j3VarClipMaxY;
extern jint16 _j3VarClipMaxZ;
extern jint16 _j3VarViewDistance;
extern float _j3VarAmbientLight;
extern j3Matrix4x4T _j3VarCameraMatrix;
extern j3VertexT _j3VarCameraLocation;
extern j3FacingT _j3VarCameraAngle;
extern bool _j3VarCameraLocationDirty;
extern bool _j3VarCameraAngleDirty;
extern j3VertexT _j3VarSunLocation;
extern j3PolyListT *_j3Polygons;
extern juint16 _j3PolygonCount;
extern juint16 _j3TriangleCount;
#define j3CameraMove(ob, px, py, pz) \
_j3VarCameraLocation.x += (px); \
_j3VarCameraLocation.y += (py); \
_j3VarCameraLocation.z += (pz); \
_j3VarCameraLocationDirty = true
#define j3CameraMoveTo(ob, px, py, pz) \
_j3VarCameraLocation.x = (px); \
_j3VarCameraLocation.y = (py); \
_j3VarCameraLocation.z = (pz); \
_j3VarCameraLocationDirty = true
#define j3CameraRotate(ob, px, py, pz) \
_j3VarCameraAngle.x += (px); j3MathWrapBounds(_j3VarCameraAngle.x, 0, 360); \
_j3VarCameraAngle.y += (py); j3MathWrapBounds(_j3VarCameraAngle.y, 0, 360); \
_j3VarCameraAngle.z += (pz); j3MathWrapBounds(_j3VarCameraAngle.z, 0, 360); \
_j3VarCameraAngleDirty = true
#define j3CameraRotateTo(ob, px, py, pz) \
_j3VarCameraAngle.x = (px); j3MathWrapBounds(_j3VarCameraAngle.x, 0, 360); \
_j3VarCameraAngle.y = (py); j3MathWrapBounds(_j3VarCameraAngle.y, 0, 360); \
_j3VarCameraAngle.z = (pz); j3MathWrapBounds(_j3VarCameraAngle.z, 0, 360); \
_j3VarCameraAngleDirty = true
#define j3CameraSetClippingBounds(x1, y1, x2, y2) \
_j3VarClipMinX = (x1); j3MathCheckBounds(_j3VarClipMinX, 0, 319); \
_j3VarClipMinY = (y1); j3MathCheckBounds(_j3VarClipMiny, 0, 199); \
_j3VarClipMaxX = (x2); j3MathCheckBounds(_j3VarClipMaxX, 0, 319); \
_j3VarClipMaxY = (y2); j3MathCheckBounds(_j3VarClipMaxy, 0, 199)
#define j3MathCheckBounds(value, min, max) \
if (value < (min)) value = (min); \
if (value > (max)) value = (max)
#define j3MathWrapBounds(value, min, max) \
if (value < (min)) value += (max); \
if (value > (max)) value -= (max)
#define j3ObjectMove(ob, px, py, pz) \
ob.position.x += (px); \
ob.position.y += (py); \
ob.position.z += (pz); \
ob.positionDirty = true
#define j3ObjectMoveTo(ob, px, py, pz) \
ob.position.x = (px); \
ob.position.y = (py); \
ob.position.z = (pz); \
ob.positionDirty = true
#define j3ObjectRotate(ob, px, py, pz) \
ob.rotation.x += (px); j3MathWrapBounds(ob.rotation.x, 0, 360); \
ob.rotation.y += (py); j3MathWrapBounds(ob.rotation.y, 0, 360); \
ob.rotation.z += (pz); j3MathWrapBounds(ob.rotation.z, 0, 360); \
ob.rotationDirty = true
#define j3ObjectRotateTo(ob, px, py, pz) \
ob.rotation.x = (px); j3MathWrapBounds(ob.rotation.x, 0, 360); \
ob.rotation.y = (py); j3MathWrapBounds(ob.rotation.y, 0, 360); \
ob.rotation.z = (pz); j3MathWrapBounds(ob.rotation.z, 0, 360); \
ob.rotationDirty = true
#define j3ObjectScale(ob, px, py, pz) \
ob.scale.x += (px); \
ob.scale.y += (py); \
ob.scale.z += (pz); \
ob.scaleDirty = true
#define j3ObjectScaleTo(ob, px, py, pz) \
ob.scale.x = (px); \
ob.scale.y = (py); \
ob.scale.z = (pz); \
ob.scaleDirty = true
// Syntatic sugar
#define j3DrawSolid(o) _j3DrawSolid(&(o))
#define j3DrawWireframe(o) _j3DrawWireframe(&(o))
#define j3ObjectReset(o) _j3ObjectReset(&(o))
#define j3ObjectUpdate(o) _j3ObjectUpdate(&(o))
#define j3WorldFree(w) _j3WorldFree((j3WorldT **)&(w))
#define j3WorldLoad(w, f) _j3WorldLoad((j3WorldT **)&(w), (f))
// Prototypes
void j3DrawTriangle2D(jint16 x1, jint16 y1, jint16 x2,jint16 y2, jint16 x3, jint16 y3, jint16 color);
void j3DrawWorld(j3WorldT *w);
void j3MathCrossProduct3D(j3Vector3DT *u, j3Vector3DT *v, j3Vector3DT *normal);
float j3MathDotProduct3D(j3Vector3DT *u, j3Vector3DT *v);
void j3MathMatrix4x4Identity(j3Matrix4x4T result);
void j3MathMatrix4x4Mult(j3Matrix4x4T a, j3Matrix4x4T b, j3Matrix4x4T result);
void j3MathMakeVector3D(j3VertexT *init, j3VertexT *term, j3Vector3DT *result);
float j3MathVectorMagnatude3D(j3Vector3DT *v);
void j3UtilShutdown(void);
void j3UtilStartup(void);
// Private Prototypes
void _j3DrawSolid(j3ObjectT *o);
void _j3DrawTriangleBottom(jint16 x1, jint16 y1, jint16 x2,jint16 y2, jint16 x3, jint16 y3);
void _j3DrawTriangleTop(jint16 x1, jint16 y1, jint16 x2,jint16 y2, jint16 x3, jint16 y3);
void _j3DrawWireframePair(j3ObjectT *o, juint16 v1, juint16 v2);
void _j3DrawWireframe(j3ObjectT *o);
void _j3ObjectReset(j3ObjectT *o);
void _j3ObjectUpdateNormalLength(j3ObjectT *object, juint16 triangle);
void _j3ObjectUpdate(j3ObjectT *o);
bool _j3UtilClipLine(jint16 *x1, jint16 *y1, jint16 *x2, jint16 *y2);
void _j3WorldFree(j3WorldT **world);
bool _j3WorldLoad(j3WorldT **world, char *file);
#endif // H_J3D_