commit 415ec3ecd38334e30919964c60741fd96706bda8 Author: blankhex Date: Sat Apr 18 11:05:46 2026 +0300 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f765426 --- /dev/null +++ b/.gitignore @@ -0,0 +1,68 @@ +# ---> C +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# ---> CMake +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +CMakeUserPresets.json + diff --git a/Box2f.c b/Box2f.c new file mode 100644 index 0000000..78ea4e5 --- /dev/null +++ b/Box2f.c @@ -0,0 +1,56 @@ +#include "CgeMath.h" +#include + +#define EPSILON 0.00001f +#define PI 3.14159265358979323846f + +void CgeBox2fUnion(const float aMin[2], const float aMax[2], + const float bMin[2], const float bMax[2], + float outMin[2], float outMax[2]) { + CgeVec2fMin(aMin, bMin, outMin); + CgeVec2fMax(aMax, bMax, outMax); +} + +int CgeBox2fIntersect(const float aMin[2], const float aMax[2], + const float bMin[2], const float bMax[2], + float outMin[2], float outMax[2]) { + CgeVec2fMax(aMin, bMin, outMin); + CgeVec2fMin(aMax, bMax, outMax); + + if (outMin[0] >= outMax[0] || outMin[1] >= outMax[1]) + return 0; + + return 1; +} + +int CgeBox2fContains(const float aMin[2], const float aMax[2], + const float point[2]) { + if (point[0] < aMin[0] || point[1] < aMin[1]) + return 0; + + if (point[0] > aMax[0] || point[1] > aMax[1]) + return 0; + + return 1; +} + +int CgeBox2fEnclose(const float *points, size_t size, float outMin[2], + float outMax[2]) { + float tmp1[2], tmp2[2]; + size_t i; + + if (!size) + return 0; + + memcpy(tmp1, points, sizeof(tmp1)); + memcpy(tmp2, points, sizeof(tmp2)); + + for (i = 1; i < size; i++) { + CgeVec2fMin(tmp1, points + i * 2, tmp1); + CgeVec2fMax(tmp2, points + i * 2, tmp2); + } + + memcpy(outMin, tmp1, sizeof(tmp1)); + memcpy(outMax, tmp2, sizeof(tmp2)); + return 1; +} diff --git a/Box3f.c b/Box3f.c new file mode 100644 index 0000000..d33d49f --- /dev/null +++ b/Box3f.c @@ -0,0 +1,56 @@ +#include "CgeMath.h" +#include + +#define EPSILON 0.00001f +#define PI 3.14159265358979323846f + +void CgeBox3fUnion(const float aMin[3], const float aMax[3], + const float bMin[3], const float bMax[3], + float outMin[3], float outMax[3]) { + CgeVec3fMin(aMin, bMin, outMin); + CgeVec3fMax(aMax, bMax, outMax); +} + +int CgeBox3fIntersect(const float aMin[3], const float aMax[3], + const float bMin[3], const float bMax[3], + float outMin[3], float outMax[3]) { + CgeVec3fMax(aMin, bMin, outMin); + CgeVec3fMin(aMax, bMax, outMax); + + if (outMin[0] >= outMax[0] || outMin[1] >= outMax[1] || outMin[2] >= outMax[2]) + return 0; + + return 1; +} + +int CgeBox3fContains(const float aMin[3], const float aMax[3], + const float point[3]) { + if (point[0] < aMin[0] || point[1] < aMin[1] || point[2] < aMin[2]) + return 0; + + if (point[0] > aMax[0] || point[1] > aMax[1] || point[2] > aMax[2]) + return 0; + + return 1; +} + +int CgeBox3fEnclose(const float *points, size_t size, float outMin[3], + float outMax[3]) { + float tmp1[3], tmp2[3]; + size_t i; + + if (!size) + return 0; + + memcpy(tmp1, points, sizeof(tmp1)); + memcpy(tmp2, points, sizeof(tmp2)); + + for (i = 1; i < size; i++) { + CgeVec3fMin(tmp1, points + i * 3, tmp1); + CgeVec3fMax(tmp2, points + i * 3, tmp2); + } + + memcpy(outMin, tmp1, sizeof(tmp1)); + memcpy(outMax, tmp2, sizeof(tmp2)); + return 1; +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..656f6cb --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.10) +project(CgeMath LANGUAGES C) + +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED ON) + +set(SOURCES + Box2f.c + Box3f.c + Line.c + Mat3f.c + Mat4f.c + Misc.c + Plane.c + Quat4f.c + Ray2f.c + Ray3f.c + Vec2f.c + Vec2i.c + Vec3f.c + Vec3i.c + Vec4f.c + Vec4i.c +) + +set(HEADERS + CgeMath.h +) + +add_library(CgeMath STATIC ${SOURCES} ${HEADERS}) + +target_include_directories(CgeMath PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +install(TARGETS CgeMath + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) + +install(FILES ${HEADERS} DESTINATION include) diff --git a/CgeMath.h b/CgeMath.h new file mode 100644 index 0000000..66a4b68 --- /dev/null +++ b/CgeMath.h @@ -0,0 +1,230 @@ +#ifndef CGE_MATH_H +#define CGE_MATH_H + +#include + +void CgeBox2fUnion(const float aMin[2], const float aMax[2], + const float bMin[2], const float bMax[2], + float outMin[2], float outMax[2]); +int CgeBox2fIntersect(const float aMin[2], const float aMax[2], + const float bMin[2], const float bMax[2], + float outMin[2], float outMax[2]); +int CgeBox2fContains(const float aMin[2], const float aMax[2], + const float point[2]); +int CgeBox2fEnclose(const float *points, size_t size, float outMin[2], + float outMax[2]); + +void CgeBox3fUnion(const float aMin[3], const float aMax[3], + const float bMin[3], const float bMax[3], + float outMin[3], float outMax[3]); +int CgeBox3fIntersect(const float aMin[3], const float aMax[3], + const float bMin[3], const float bMax[3], + float outMin[3], float outMax[3]); +int CgeBox3fContains(const float aMin[3], const float aMax[3], + const float point[3]); +int CgeBox3fEnclose(const float *points, size_t size, float outMin[3], + float outMax[3]); + +int CgeLineFromPoints(const float a[2], const float b[2], float out[3]); +float CgeLineDistance(const float line[3], const float point[2]); +void CgeLineClosestPoint(const float line[3], const float point[2], + float out[2]); + +void CgeMat3fIdentity(float out[9]); +void CgeMat3fAdd(const float a[9], const float b[9], float out[9]); +void CgeMat3fSub(const float a[9], const float b[9], float out[9]); +void CgeMat3fMul(const float a[9], const float b[9], float out[9]); +void CgeMat3fScale(const float a[9], float b, float out[9]); +void CgeMat3fTranspose(const float in[9], float out[9]); +float CgeMat3fTrace(const float in[9]); +float CgeMat3fDet(const float in[9]); +int CgeMat3fInverse(const float in[9], float out[9]); +void CgeMat3fFromScale(float x, float y, float out[9]); +void CgeMat3fFromTranslation(float x, float y, float out[9]); +void CgeMat3fFromRotation(float angle, float out[9]); +void CgeMat3fApplyVec3f(float a[9], float b[3], float out[3]); +void CgeMat3fApplyVec2f(float a[9], float b[2], float out[2]); + +void CgeMat4fIdentity(float out[16]); +void CgeMat4fAdd(const float a[16], const float b[16], float out[16]); +void CgeMat4fSub(const float a[16], const float b[16], float out[16]); +void CgeMat4fMul(const float a[16], const float b[16], float out[16]); +void CgeMat4fScale(const float a[16], float b, float out[16]); +void CgeMat4fTranspose(const float in[16], float out[16]); +float CgeMat4fTrace(const float in[16]); +float CgeMat4fDet(const float in[16]); +int CgeMat4fInverse(const float in[16], float out[16]); +void CgeMat4fFromScale(float x, float y, float z, float out[16]); +void CgeMat4fFromTranslation(float x, float y, float z, float out[16]); +void CgeMat4fFromRotationX(float angle, float out[16]); +void CgeMat4fFromRotationY(float angle, float out[16]); +void CgeMat4fFromRotationZ(float angle, float out[16]); +void CgeMat4fFromAxis(const float axis[3], float angle, float out[16]); +void CgeMat4fFromEuler(float roll, float pitch, float yaw, float out[16]); +void CgeMat4fFromQuat4f(const float in[4], float out[16]); +void CgeMat4fFromOrtho(float xMin, float xMax, float yMin, float yMax, + float zMin, float zMax, float out[16]); +void CgeMat4fFromFrustum(float fov, float aspect, float zMin, float zMax, + float out[16]); +void CgeMat4fFromLookAt(const float position[3], const float at[3], + const float up[3], float out[16]); +void CgeMat4fApplyVec4f(const float a[16], const float b[4], float out[4]); +void CgeMat4fApplyVec3f(const float a[16], const float b[3], float out[3]); + +float CgeLerpf(float a, float b, float t); + +void CgeTriangle3fBarycentric(const float a[3], const float b[3], + const float c[3], const float point[3], + float out[3]); + +int CgePlaneFromPoints(const float a[3], const float b[3], const float c[3], + float out[4]); +float CgePlaneDistance(const float plane[4], const float point[3]); + +void CgePlaneClosestPoint(const float plane[4], const float point[3], + float out[3]); + +#define CgeQuat4fAdd(a, b, out) CgeVec4fAdd(a, b, out) +#define CgeQuat4fSub(a, b, out) CgeVec4fSub(a, b, out) +#define CgeQuat4fScale(a, b, out) CgeVec4fScale(a, b, out) +#define CgeQuat4fNegate(in, out) CgeVec4fNegate(in, out) +#define CgeQuat4fDot(a, b) CgeVec4fDot(a, b) +#define CgeQuat4fLength(in) CgeVec4fLength(in) +#define CgeQuat4fNormal(in, out) CgeVec4fNormal(in, out) +#define CgeQuat4fLerp(a, b, t, out) CgeVec4fLerp(a, b, t, out) + +void CgeQuat4fIdentity(float out[4]); +void CgeQuat4fConjugate(const float in[4],float out[4]); +void CgeQuat4fInverse(const float in[4], float out[4]); +void CgeQuat4fMul(const float a[4], const float b[4], float out[4]); +void CgeQuat4fSlerp(const float a[4], const float b[4], float t, float out[4]); +void CgeQuat4fFromEuler(float roll, float pitch, float yaw, float out[4]); +void CgeQuat4fFromAxis(const float axis[3], float angle, float out[4]); +void CgeQuat4fToEuler(const float in[4], float *roll, float *pitch, float *yaw); +void CgeQuat4fToAxis(const float in[4], float axis[3], float *angle); +void CgeQuat4fToMat4f(const float in[4], float out[16]); + +int CgeRay2fIntersectLine(const float start[2], const float direction[2], + const float line[3], float *t, float out[2]); +int CgeRay2fIntersectTime(const float aStart[2], const float aDirection[2], + const float bStart[2], const float bDirection[2], + float *time1, float *time2); +int CgeRay2fIntersectRay(const float aStart[2], const float aDirection[2], + const float bStart[2], const float bDirection[2], + float *t, float out[2]); +int CgeRay2fIntersectSegment(const float aStart[2], const float aDirection[2], + const float bStart[2], const float bEnd[2], + float *t, float out[2]); +int CgeSegment2fIntersectLine(const float start[2], const float end[2], + const float line[3], float *t, float out[2]); +int CgeSegment2fIntersectSegment(const float aStart[2], const float aEnd[2], + const float bStart[2], const float bEnd[2], + float *t, float out[2]); +int CgeRay2fIntersectBox2f(const float aStart[2], const float aDirection[2], + const float bMin[2], const float bMax[2], + float *t, float out[2]); +int CgeSegment2fIntersectBox2f(const float aStart[2], const float aEnd[2], + const float bMin[2], const float bMax[2], + float *t, float out[2]); + +int CgeRay3fIntersectPlane(const float start[3], const float direction[3], + const float plane[4], float *t, float out[3]); +int CgeRay3fIntersectTriangle(const float start[3], const float direction[3], + const float a[3], const float b[3], + const float c[3], float *t, float out[3]); +int CgeSegment3fIntersectPlane(const float start[3], const float end[3], + const float plane[4], float *t, float out[3]); +int CgeSegment3fIntersectTriangle(const float start[3], const float end[3], + const float a[3], const float b[3], + const float c[3], float *t, float out[3]); +int CgeRay3fIntersectBox3f(const float aStart[3], const float aDirection[3], + const float bMin[3], const float bMax[3], + float *t, float out[3]); +int CgeSegment3fIntersectBox3f(const float aStart[3], const float aEnd[3], + const float bMin[3], const float bMax[3], + float *t, float out[3]); + +void CgeVec2fAdd(const float a[2], const float b[2], float out[2]); +void CgeVec2fSub(const float a[2], const float b[2], float out[2]); +void CgeVec2fMul(const float a[2], const float b[2], float out[2]); +void CgeVec2fScale(const float a[2], float b, float out[2]); +void CgeVec2fMulAdd(const float a[2], const float b[2], const float c[2], + float out[2]); +void CgeVec2fNegate(const float in[2], float out[2]); +float CgeVec2fDot(const float a[2], const float b[2]); +float CgeVec2fCross(const float a[2], const float b[2]); +float CgeVec2fLength(const float in[2]); +void CgeVec2fNormal(const float in[2], float out[2]); +float CgeVec2fNormalEx(const float in[2], float out[2]); +void CgeVec2fMin(const float a[2], const float b[2], float out[2]); +void CgeVec2fMax(const float a[2], const float b[2], float out[2]); +void CgeVec2fLerp(const float a[2], const float b[2], float t, float out[2]); +void CgeVec2fProject(const float a[2], const float b[2], float out[2]); +void CgeVec2fBarycentric(const float a[2], const float b[2], const float c[2], + float v, float w, float out[2]); + +void CgeVec2iAdd(const int a[2], const int b[2], int out[2]); +void CgeVec2iSub(const int a[2], const int b[2], int out[2]); +void CgeVec2iMul(const int a[2], const int b[2], int out[2]); +void CgeVec2iScale(const int a[2], int b, int out[2]); +void CgeVec2iMulAdd(const int a[2], const int b[2], const int c[2], int out[2]); +void CgeVec2iNegate(const int in[2], int out[2]); +void CgeVec2iMin(const int a[2], const int b[2], int out[2]); +void CgeVec2iMax(const int a[2], const int b[2], int out[2]); + +void CgeVec3fAdd(const float a[3], const float b[3], float out[3]); +void CgeVec3fSub(const float a[3], const float b[3], float out[3]); +void CgeVec3fMul(const float a[3], const float b[3], float out[3]); +void CgeVec3fScale(const float a[3], float b, float out[3]); +void CgeVec3fMulAdd(const float a[3], const float b[3], const float c[3], + float out[3]); +void CgeVec3fNegate(const float in[3], float out[3]); +float CgeVec3fDot(const float a[3], const float b[3]); +void CgeVec3fCross(const float a[3], const float b[3], float out[3]); +float CgeVec3fLength(const float in[3]); +void CgeVec3fNormal(const float in[3], float out[3]); +float CgeVec3fNormalEx(const float in[3], float out[3]); +void CgeVec3fMin(const float a[3], const float b[3], float out[3]); +void CgeVec3fMax(const float a[3], const float b[3], float out[3]); +void CgeVec3fLerp(const float a[3], const float b[3], float t, float out[3]); +void CgeVec3fProject(const float a[3], const float b[3], float out[3]); +void CgeVec3fBarycentric(const float a[3], const float b[3], const float c[3], + float v, float w, float out[3]); + +void CgeVec3iAdd(const int a[3], const int b[3], int out[3]); +void CgeVec3iSub(const int a[3], const int b[3], int out[3]); +void CgeVec3iMul(const int a[3], const int b[3], int out[3]); +void CgeVec3iScale(const int a[3], int b, int out[3]); +void CgeVec3iMulAdd(const int a[3], const int b[3], const int c[3], int out[3]); +void CgeVec3iNegate(const int in[3], int out[3]); +void CgeVec3iMin(const int a[3], const int b[3], int out[3]); +void CgeVec3iMax(const int a[3], const int b[3], int out[3]); + +void CgeVec4fAdd(const float a[4], const float b[4], float out[4]); +void CgeVec4fSub(const float a[4], const float b[4], float out[4]); +void CgeVec4fMul(const float a[4], const float b[4], float out[4]); +void CgeVec4fScale(const float a[4], float b, float out[4]); +void CgeVec4fMulAdd(const float a[4], const float b[4], const float c[4], + float out[4]); +void CgeVec4fNegate(const float in[4], float out[4]); +float CgeVec4fDot(const float a[4], const float b[4]); +float CgeVec4fLength(const float in[4]); +void CgeVec4fNormal(const float in[4], float out[4]); +float CgeVec4fNormalEx(const float in[4], float out[4]); +void CgeVec4fMin(const float a[4], const float b[4], float out[4]); +void CgeVec4fMax(const float a[4], const float b[4], float out[4]); +void CgeVec4fLerp(const float a[4], const float b[4], float t, float out[4]); +void CgeVec4fProject(const float a[4], const float b[4], float out[4]); +void CgeVec4fBarycentric(const float a[4], const float b[4], const float c[4], + float v, float w, float out[4]); + +void CgeVec4iAdd(const int a[4], const int b[4], int out[4]); +void CgeVec4iSub(const int a[4], const int b[4], int out[4]); +void CgeVec4iMul(const int a[4], const int b[4], int out[4]); +void CgeVec4iScale(const int a[4], int b, int out[4]); +void CgeVec4iMulAdd(const int a[4], const int b[4], const int c[4], int out[4]); +void CgeVec4iNegate(const int in[4], int out[4]); +void CgeVec4iMin(const int a[4], const int b[4], int out[4]); +void CgeVec4iMax(const int a[4], const int b[4], int out[4]); + +#endif /* CGE_MATH_H */ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3d44ffd --- /dev/null +++ b/LICENSE @@ -0,0 +1,12 @@ +Copyright (C) 2026 by blankhex me@blankhex.com + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/Line.c b/Line.c new file mode 100644 index 0000000..9c9e445 --- /dev/null +++ b/Line.c @@ -0,0 +1,30 @@ +#include "CgeMath.h" +#include + +#define EPSILON 0.00001f +#define PI 3.14159265358979323846f + +int CgeLineFromPoints(const float a[2], const float b[2], float out[3]) { + float tmp[2]; + + tmp[0] = a[1] - b[1]; + tmp[1] = b[0] - a[0]; + if (CgeVec2fNormalEx(tmp, tmp) < EPSILON) + return 0; + + out[2] = CgeVec2fDot(tmp, a); + memcpy(out, tmp, sizeof(tmp)); + return 1; +} + +float CgeLineDistance(const float line[3], const float point[2]) { + return CgeVec2fDot(line, point) - line[2]; +} + +void CgeLineClosestPoint(const float line[3], const float point[2], + float out[2]) { + float tmp[2]; + + CgeVec2fScale(line, CgeLineDistance(line, point), tmp); + CgeVec2fSub(point, tmp, out); +} diff --git a/Makefile.mingw b/Makefile.mingw new file mode 100644 index 0000000..04d54f5 --- /dev/null +++ b/Makefile.mingw @@ -0,0 +1,24 @@ +# MinGW Makefile for CgeMath + +CC = gcc +AR = ar +CFLAGS = -std=c99 -O2 -Wall -Wextra +ARFLAGS = rcs +TARGET = libCgeMath.a + +SOURCES = Box2f.c Box3f.c Line.c Mat3f.c Mat4f.c Misc.c Plane.c Quat4f.c \ + Ray2f.c Ray3f.c Vec2f.c Vec2i.c Vec3f.c Vec3i.c Vec4f.c Vec4i.c +OBJECTS = $(SOURCES:.c=.o) + +.PHONY: all clean + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(AR) $(ARFLAGS) $@ $^ + +%.o: %.c CgeMath.h + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + del $(OBJECTS) $(TARGET) 2>nul || exit 0 diff --git a/Makefile.posix b/Makefile.posix new file mode 100644 index 0000000..3325cd8 --- /dev/null +++ b/Makefile.posix @@ -0,0 +1,34 @@ +# POSIX Makefile for CgeMath + +CC = gcc +AR = ar +CFLAGS = -std=c99 -O2 -Wall -Wextra -fPIC +ARFLAGS = rcs +TARGET = libCgeMath.a + +SOURCES = Box2f.c Box3f.c Line.c Mat3f.c Mat4f.c Misc.c Plane.c Quat4f.c \ + Ray2f.c Ray3f.c Vec2f.c Vec2i.c Vec3f.c Vec3i.c Vec4f.c Vec4i.c +OBJECTS = $(SOURCES:.c=.o) + +.PHONY: all clean install + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(AR) $(ARFLAGS) $@ $^ + +%.o: %.c CgeMath.h + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJECTS) $(TARGET) + +install: $(TARGET) + cp $(TARGET) /usr/local/lib/ + cp CgeMath.h /usr/local/include/ + ldconfig || echo "Run ldconfig manually if needed" + +uninstall: + rm -f /usr/local/lib/libCgeMath.a + rm -f /usr/local/include/CgeMath.h + ldconfig || true diff --git a/Makefile.win32 b/Makefile.win32 new file mode 100644 index 0000000..13fff97 --- /dev/null +++ b/Makefile.win32 @@ -0,0 +1,24 @@ +# Makefile.win32 for MSVC (NMake) +# Usage: Open "x86 Native Tools Command Prompt", then: +# nmake -f Makefile.win32 + +CC = cl +LIB = lib +CFLAGS = /c /nologo /W3 /O2 +LIBFLAGS = /nologo +TARGET = CgeMath.lib + +SOURCES = Box2f.c Box3f.c Line.c Mat3f.c Mat4f.c Misc.c Plane.c Quat4f.c \ + Ray2f.c Ray3f.c Vec2f.c Vec2i.c Vec3f.c Vec3i.c Vec4f.c Vec4i.c +OBJECTS = $(SOURCES:.c=.obj) + +$(TARGET): $(OBJECTS) + $(LIB) $(LIBFLAGS) /OUT:$(TARGET) $(OBJECTS) + +{.}.c{}.obj: + $(CC) $(CFLAGS) /Fo$@ $< + +clean: + del $(OBJECTS) $(TARGET) 2>nul + +.PHONY: clean diff --git a/Mat3f.c b/Mat3f.c new file mode 100644 index 0000000..8f97501 --- /dev/null +++ b/Mat3f.c @@ -0,0 +1,167 @@ +#include "CgeMath.h" +#include +#include + +#define EPSILON 0.00001f +#define PI 3.14159265358979323846f +#define SET_ROW(row, val) row[0] = row[1] = row[2] = val + +void CgeMat3fIdentity(float out[9]) { + static const float ident[9] = { + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f + }; + + memcpy(out, ident, sizeof(ident)); +} + +void CgeMat3fAdd(const float a[9], const float b[9], float out[9]) { + CgeVec3fAdd(&a[0], &b[0], &out[0]); + CgeVec3fAdd(&a[3], &b[3], &out[3]); + CgeVec3fAdd(&a[6], &b[6], &out[6]); +} + +void CgeMat3fSub(const float a[9], const float b[9], float out[9]) { + CgeVec3fSub(&a[0], &b[0], &out[0]); + CgeVec3fSub(&a[3], &b[3], &out[3]); + CgeVec3fSub(&a[6], &b[6], &out[6]); +} + +void CgeMat3fMul(const float a[9], const float b[9], float out[9]) { + float tmp[9], row[3]; + + SET_ROW(row, b[0]); CgeVec3fMul(&a[0], row, &tmp[0]); + SET_ROW(row, b[1]); CgeVec3fMulAdd(&a[3], row, &tmp[0], &tmp[0]); + SET_ROW(row, b[2]); CgeVec3fMulAdd(&a[6], row, &tmp[0], &tmp[0]); + + SET_ROW(row, b[3]); CgeVec3fMul(&a[0], row, &tmp[3]); + SET_ROW(row, b[4]); CgeVec3fMulAdd(&a[3], row, &tmp[3], &tmp[3]); + SET_ROW(row, b[5]); CgeVec3fMulAdd(&a[6], row, &tmp[3], &tmp[3]); + + SET_ROW(row, b[6]); CgeVec3fMul(&a[0], row, &tmp[6]); + SET_ROW(row, b[7]); CgeVec3fMulAdd(&a[3], row, &tmp[6], &tmp[6]); + SET_ROW(row, b[8]); CgeVec3fMulAdd(&a[6], row, &tmp[6], &tmp[6]); + + memcpy(out, tmp, sizeof(tmp)); +} + +void CgeMat3fScale(const float a[9], float b, float out[9]) { + CgeVec3fScale(&a[0], b, &out[0]); + CgeVec3fScale(&a[3], b, &out[3]); + CgeVec3fScale(&a[6], b, &out[6]); +} + +void CgeMat3fTranspose(const float in[9], float out[9]) { + float tmp[9]; + + tmp[0] = in[0]; tmp[3] = in[1]; tmp[6] = in[2]; + tmp[1] = in[3]; tmp[4] = in[4]; tmp[7] = in[5]; + tmp[2] = in[6]; tmp[5] = in[7]; tmp[8] = in[8]; + + memcpy(out, tmp, sizeof(tmp)); +} + +float CgeMat3fTrace(const float in[9]) { + return in[0] + in[4] + in[8]; +} + +float CgeMat3fDet(const float in[9]) { + float a, b, c, result; + + a = in[4] * in[8] - in[7] * in[5]; + b = in[1] * in[8] - in[7] * in[2]; + c = in[1] * in[5] - in[4] * in[2]; + + result = 0.0f; + result += in[0] * a; + result -= in[3] * b; + result += in[6] * c; + + return result; +} + +int CgeMat3fInverse(const float in[9], float out[9]) { + float a, b, c, det; + float tmp[16]; + + a = in[4] * in[8] - in[7] * in[5]; + b = in[1] * in[8] - in[7] * in[2]; + c = in[1] * in[5] - in[4] * in[2]; + + tmp[0] = a; + tmp[1] = -b; + tmp[2] = c; + + det = 0.0f; + det += in[0] * tmp[0]; + det += in[3] * tmp[1]; + det += in[6] * tmp[2]; + + if (fabsf(det) < EPSILON) + return 0; + + a = in[3] * in[8] - in[6] * in[5]; + b = in[0] * in[8] - in[6] * in[2]; + c = in[0] * in[5] - in[3] * in[2]; + + tmp[3] = -a; + tmp[4] = b; + tmp[5] = -c; + + a = in[3] * in[7] - in[6] * in[4]; + b = in[0] * in[7] - in[6] * in[1]; + c = in[0] * in[4] - in[3] * in[1]; + + tmp[6] = a; + tmp[7] = -b; + tmp[8] = c; + + CgeMat3fScale(tmp, 1.0f / det, out); + return 1; +} + +void CgeMat3fFromScale(float x, float y, float out[9]) { + CgeMat3fIdentity(out); + out[0] = x; + out[4] = y; +} + +void CgeMat3fFromTranslation(float x, float y, float out[9]) { + CgeMat3fIdentity(out); + out[6] = x; + out[7] = y; +} + +void CgeMat3fFromRotation(float angle, float out[9]) { + float c, s; + + c = cosf(angle); + s = sinf(angle); + + CgeMat3fIdentity(out); + out[0] = c; + out[1] = s; + out[3] = -s; + out[4] = c; +} + +void CgeMat3fApplyVec3f(float a[9], float b[3], float out[3]) { + float tmp[3], row[3]; + + SET_ROW(row, b[0]); CgeVec3fMul(&a[0], row, tmp); + SET_ROW(row, b[1]); CgeVec3fMulAdd(&a[3], row, tmp, tmp); + SET_ROW(row, b[2]); CgeVec3fMulAdd(&a[6], row, tmp, tmp); + + memcpy(out, tmp, sizeof(tmp)); +} + +void CgeMat3fApplyVec2f(float a[9], float b[2], float out[2]) { + float tmp[3], row[3]; + + SET_ROW(row, b[0]); CgeVec3fMul(&a[0], row, tmp); + SET_ROW(row, b[1]); CgeVec3fMulAdd(&a[3], row, tmp, tmp); + SET_ROW(row, 1.0f); CgeVec3fMulAdd(&a[6], row, tmp, tmp); + + memcpy(out, tmp, sizeof(float) * 2); +} diff --git a/Mat4f.c b/Mat4f.c new file mode 100644 index 0000000..01324b6 --- /dev/null +++ b/Mat4f.c @@ -0,0 +1,362 @@ +#include "CgeMath.h" +#include +#include + +#define EPSILON 0.00001f +#define PI 3.14159265358979323846f +#define SET_ROW(row, val) row[0] = row[1] = row[2] = row[3] = val + +void CgeMat4fIdentity(float out[16]) { + const float ident[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + memcpy(out, ident, sizeof(ident)); +} + +void CgeMat4fAdd(const float a[16], const float b[16], float out[16]) { + CgeVec4fAdd(&a[0], &b[0], &out[0]); + CgeVec4fAdd(&a[4], &b[4], &out[4]); + CgeVec4fAdd(&a[8], &b[8], &out[8]); + CgeVec4fAdd(&a[12], &b[12], &out[12]); +} + +void CgeMat4fSub(const float a[16], const float b[16], float out[16]) { + CgeVec4fSub(&a[0], &b[0], &out[0]); + CgeVec4fSub(&a[4], &b[4], &out[4]); + CgeVec4fSub(&a[8], &b[8], &out[8]); + CgeVec4fSub(&a[12], &b[12], &out[12]); +} + +void CgeMat4fMul(const float a[16], const float b[16], float out[16]) { + float tmp[16], row[4]; + + SET_ROW(row, b[0]); CgeVec4fMul(&a[0], row, &tmp[0]); + SET_ROW(row, b[1]); CgeVec4fMulAdd(&a[4], row, &tmp[0], &tmp[0]); + SET_ROW(row, b[2]); CgeVec4fMulAdd(&a[8], row, &tmp[0], &tmp[0]); + SET_ROW(row, b[3]); CgeVec4fMulAdd(&a[12], row, &tmp[0], &tmp[0]); + + SET_ROW(row, b[4]); CgeVec4fMul(&a[0], row, &tmp[4]); + SET_ROW(row, b[5]); CgeVec4fMulAdd(&a[4], row, &tmp[4], &tmp[4]); + SET_ROW(row, b[6]); CgeVec4fMulAdd(&a[8], row, &tmp[4], &tmp[4]); + SET_ROW(row, b[7]); CgeVec4fMulAdd(&a[12], row, &tmp[4], &tmp[4]); + + SET_ROW(row, b[8]); CgeVec4fMul(&a[0], row, &tmp[8]); + SET_ROW(row, b[9]); CgeVec4fMulAdd(&a[4], row, &tmp[8], &tmp[8]); + SET_ROW(row, b[10]); CgeVec4fMulAdd(&a[8], row, &tmp[8], &tmp[8]); + SET_ROW(row, b[11]); CgeVec4fMulAdd(&a[12], row, &tmp[8], &tmp[8]); + + SET_ROW(row, b[12]); CgeVec4fMul(&a[0], row, &tmp[12]); + SET_ROW(row, b[13]); CgeVec4fMulAdd(&a[4], row, &tmp[12], &tmp[12]); + SET_ROW(row, b[14]); CgeVec4fMulAdd(&a[8], row, &tmp[12], &tmp[12]); + SET_ROW(row, b[15]); CgeVec4fMulAdd(&a[12], row, &tmp[12], &tmp[12]); + + memcpy(out, tmp, sizeof(tmp)); +} + +void CgeMat4fScale(const float a[16], float b, float out[16]) { + CgeVec4fScale(&a[0], b, &out[0]); + CgeVec4fScale(&a[4], b, &out[4]); + CgeVec4fScale(&a[8], b, &out[8]); + CgeVec4fScale(&a[12], b, &out[12]); +} + +void CgeMat4fTranspose(const float in[16], float out[16]) { + float tmp[16]; + + tmp[0] = in[0]; tmp[4] = in[1]; tmp[8] = in[2]; tmp[12] = in[3]; + tmp[1] = in[4]; tmp[5] = in[5]; tmp[9] = in[6]; tmp[13] = in[7]; + tmp[2] = in[8]; tmp[6] = in[9]; tmp[10] = in[10]; tmp[14] = in[11]; + tmp[3] = in[12]; tmp[7] = in[13]; tmp[11] = in[14]; tmp[15] = in[15]; + + memcpy(out, tmp, sizeof(tmp)); +} + +float CgeMat4fTrace(const float in[16]) { + return in[0] + in[5] + in[10] + in[15]; +} + +float CgeMat4fDet(const float in[16]) { + float a, b, c, d, e, f, result; + + a = in[2] * in[7] - in[3] * in[6]; + b = in[2] * in[11] - in[3] * in[10]; + c = in[2] * in[15] - in[3] * in[14]; + d = in[6] * in[11] - in[7] * in[10]; + e = in[6] * in[15] - in[7] * in[14]; + f = in[10] * in[15] - in[11] * in[14]; + + result = 0.0f; + result += in[0] * (in[5] * f - in[9] * e + in[13] * d); + result -= in[4] * (in[1] * f - in[9] * c + in[13] * b); + result += in[8] * (in[1] * e - in[5] * c + in[13] * a); + result -= in[12] * (in[1] * d - in[5] * b + in[9] * a); + + return result; +} + +int CgeMat4fInverse(const float in[16], float out[16]) { + float a, b, c, d, e, f, det; + float tmp[16]; + + a = in[2] * in[7] - in[3] * in[6]; + b = in[2] * in[11] - in[3] * in[10]; + c = in[2] * in[15] - in[3] * in[14]; + d = in[6] * in[11] - in[7] * in[10]; + e = in[6] * in[15] - in[7] * in[14]; + f = in[10] * in[15] - in[11] * in[14]; + + tmp[0] = (in[5] * f - in[9] * e + in[13] * d); + tmp[1] = -(in[1] * f - in[9] * c + in[13] * b); + tmp[2] = (in[1] * e - in[5] * c + in[13] * a); + tmp[3] = -(in[1] * d - in[5] * b + in[9] * a); + + det = 0.0f; + det += in[0] * tmp[0]; + det += in[4] * tmp[1]; + det += in[8] * tmp[2]; + det += in[12] * tmp[3]; + + if (fabsf(det) < EPSILON) + return 0; + + tmp[4] = -(in[4] * f - in[8] * e + in[12] * d); + tmp[5] = (in[0] * f - in[8] * c + in[12] * b); + tmp[6] = -(in[0] * e - in[4] * c + in[12] * a); + tmp[7] = (in[0] * d - in[4] * b + in[8] * a); + + a = in[1] * in[7] - in[3] * in[5]; + b = in[1] * in[11] - in[3] * in[9]; + c = in[1] * in[15] - in[3] * in[13]; + d = in[5] * in[11] - in[7] * in[9]; + e = in[5] * in[15] - in[7] * in[13]; + f = in[9] * in[15] - in[11] * in[13]; + + tmp[8] = (in[4] * f - in[8] * e + in[12] * d); + tmp[9] = -(in[0] * f - in[8] * c + in[12] * b); + tmp[10] = (in[0] * e - in[4] * c + in[12] * a); + tmp[11] = -(in[0] * d - in[4] * b + in[8] * a); + + a = in[1] * in[6] - in[2] * in[5]; + b = in[1] * in[10] - in[2] * in[9]; + c = in[1] * in[14] - in[2] * in[13]; + d = in[5] * in[10] - in[6] * in[9]; + e = in[5] * in[14] - in[6] * in[13]; + f = in[9] * in[14] - in[10] * in[13]; + + tmp[12] = -(in[4] * f - in[8] * e + in[12] * d); + tmp[13] = (in[0] * f - in[8] * c + in[12] * b); + tmp[14] = -(in[0] * e - in[4] * c + in[12] * a); + tmp[15] = (in[0] * d - in[4] * b + in[8] * a); + + CgeMat4fScale(tmp, 1.0f / det, out); + return 1; +} + +void CgeMat4fFromScale(float x, float y, float z, float out[16]) { + CgeMat4fIdentity(out); + out[0] = x; + out[5] = y; + out[10] = z; +} + +void CgeMat4fFromTranslation(float x, float y, float z, float out[16]) { + CgeMat4fIdentity(out); + out[12] = x; + out[13] = y; + out[14] = z; +} + +void CgeMat4fFromRotationX(float angle, float out[16]) { + float c, s; + + c = cosf(angle); + s = sinf(angle); + + CgeMat4fIdentity(out); + out[5] = c; + out[6] = s; + out[9] = -s; + out[10] = c; +} + +void CgeMat4fFromRotationY(float angle, float out[16]) { + float c, s; + + c = cosf(angle); + s = sinf(angle); + + CgeMat4fIdentity(out); + out[0] = c; + out[2] = -s; + out[8] = s; + out[10] = c; +} + +void CgeMat4fFromRotationZ(float angle, float out[16]) { + float c, s; + + c = cosf(angle); + s = sinf(angle); + + CgeMat4fIdentity(out); + out[0] = c; + out[1] = s; + out[4] = -s; + out[5] = c; +} + +void CgeMat4fFromAxis(const float axis[3], float angle, float out[16]) { + float x, y, z, length; + float c, s, moc, xx, xy, xz, yy, yz, zz; + + length = CgeVec3fLength(axis); + CgeMat4fIdentity(out); + + if (fabsf(length) < EPSILON) + return; + + x = axis[0] / length; + y = axis[1] / length; + z = axis[2] / length; + + c = cosf(angle); + s = sinf(angle); + moc = 1.0f - c; + + xx = x * x; + xy = x * y; + xz = x * z; + yy = y * y; + yz = y * z; + zz = z * z; + + out[0] = c + xx * moc; + out[1] = xy * moc + z * s; + out[2] = xz * moc - y * s; + + out[4] = xy * moc - z * s; + out[5] = c + yy * moc; + out[6] = yz * moc + x * s; + + out[8] = xz * moc + y * s; + out[9] = yz * moc - x * s; + out[10] = c + zz * moc; +} + +void CgeMat4fFromEuler(float roll, float pitch, float yaw, float out[16]) { + float rs, rc, ys, yc, ps, pc; + + rs = sinf(roll); + rc = cosf(roll); + ps = sinf(pitch); + pc = cosf(pitch); + ys = sinf(yaw); + yc = cosf(yaw); + + CgeMat4fIdentity(out); + out[0] = pc * yc; + out[1] = pc * ys; + out[2] = -ps; + out[4] = ps * rs * yc - rc * ys; + out[5] = ps * rs * ys + rc * yc; + out[6] = pc * rs; + out[8] = rs * ys + ps * rc * yc; + out[9] = ps * rc * ys - rs * yc; + out[10] = pc * rc; +} + +void CgeMat4fFromQuat4f(const float in[4], float out[16]) { + CgeQuat4fToMat4f(in, out); +} + +void CgeMat4fFromOrtho(float xMin, float xMax, float yMin, float yMax, + float zMin, float zMax, float out[16]) { + float dx, dy, dz; + + dx = xMax - xMin; + dy = yMax - yMin; + dz = zMax - zMin; + + CgeMat4fIdentity(out); + + out[0] = 2.0f / dx; + out[5] = 2.0f / dy; + out[10] = -2.0f / dz; + out[12] = -(xMax + xMin) / dx; + out[13] = -(yMax + yMin) / dy; + out[14] = -(zMax + zMin) / dz; +} + +void CgeMat4fFromFrustum(float fov, float aspect, float zMin, float zMax, + float out[16]) { + float t, dz; + + dz = zMax - zMin; + t = tanf(fov / 2.0f); + + CgeMat4fIdentity(out); + + out[0] = 1.0f / (aspect * t); + out[5] = 1.0f / t; + out[10] = -(zMax + zMin) / dz; + out[11] = -1.0f; + out[14] = -(2.0f * zMax * zMin) / dz; + out[15] = 0.0f; +} + +void CgeMat4fFromLookAt(const float position[3], const float at[3], + const float up[3], float out[16]) { + float cameraDir[3], cameraRight[3], cameraUp[3]; + + CgeVec3fSub(position, at, cameraDir); + CgeVec3fNormal(cameraDir, cameraDir); + CgeVec3fCross(up, cameraDir, cameraRight); + CgeVec3fNormal(cameraRight, cameraRight); + CgeVec3fCross(cameraDir, cameraRight, cameraUp); + + out[0] = cameraRight[0]; + out[1] = cameraUp[0]; + out[2] = cameraDir[0]; + out[3] = 0.0f; + + out[4] = cameraRight[1]; + out[5] = cameraUp[1]; + out[6] = cameraDir[1]; + out[7] = 0.0f; + + out[8] = cameraRight[2]; + out[9] = cameraUp[2]; + out[10] = cameraDir[2]; + out[11] = 0.0f; + + out[12] = -CgeVec3fDot(cameraRight, position); + out[13] = -CgeVec3fDot(cameraUp, position); + out[14] = -CgeVec3fDot(cameraDir, position); + out[15] = 1.0f; +} + +void CgeMat4fApplyVec4f(const float a[16], const float b[4], float out[4]) { + float tmp[4], row[4]; + + SET_ROW(row, b[0]); CgeVec4fMul(&a[0], row, tmp); + SET_ROW(row, b[1]); CgeVec4fMulAdd(&a[4], row, tmp, tmp); + SET_ROW(row, b[2]); CgeVec4fMulAdd(&a[8], row, tmp, tmp); + SET_ROW(row, b[3]); CgeVec4fMulAdd(&a[12], row, tmp, tmp); + + memcpy(out, tmp, sizeof(tmp)); +} + +void CgeMat4fApplyVec3f(const float a[16], const float b[3], float out[3]) { + float tmp[4], row[4]; + + SET_ROW(row, b[0]); CgeVec4fMul(&a[0], row, tmp); + SET_ROW(row, b[1]); CgeVec4fMulAdd(&a[4], row, tmp, tmp); + SET_ROW(row, b[2]); CgeVec4fMulAdd(&a[8], row, tmp, tmp); + SET_ROW(row, 1.0f); CgeVec4fMulAdd(&a[12], row, tmp, tmp); + + memcpy(out, tmp, sizeof(float) * 3); +} diff --git a/Misc.c b/Misc.c new file mode 100644 index 0000000..0b4a1f5 --- /dev/null +++ b/Misc.c @@ -0,0 +1,27 @@ +#include "CgeMath.h" + +float CgeLerpf(float a, float b, float t) { + return a + (b - a) * t; +} + +void CgeTriangle3fBarycentric(const float a[3], const float b[3], + const float c[3], const float point[3], + float out[3]) { + float tmp1[3], tmp2[3], tmp3[3]; + float t11, t12, t22, t31, t32, denom; + + CgeVec3fSub(b, a, tmp1); + CgeVec3fSub(c, a, tmp2); + CgeVec3fSub(point, a, tmp3); + + t11 = CgeVec3fDot(tmp1, tmp1); + t12 = CgeVec3fDot(tmp1, tmp2); + t22 = CgeVec3fDot(tmp2, tmp2); + t31 = CgeVec3fDot(tmp3, tmp1); + t32 = CgeVec3fDot(tmp3, tmp2); + denom = 1.0f / (t11 * t22 - t12 * t12); + + out[1] = (t22 * t31 - t12 * t32) * denom; + out[2] = (t11 * t32 - t12 * t31) * denom; + out[0] = 1.0f - out[1] - out[2]; +} diff --git a/Plane.c b/Plane.c new file mode 100644 index 0000000..2e45970 --- /dev/null +++ b/Plane.c @@ -0,0 +1,32 @@ +#include "CgeMath.h" +#include + +#define EPSILON 0.00001f +#define PI 3.14159265358979323846f + +int CgePlaneFromPoints(const float a[3], const float b[3], const float c[3], + float out[4]) { + float tmp1[3], tmp2[3]; + + CgeVec3fSub(b, a, tmp1); + CgeVec3fSub(c, a, tmp2); + CgeVec3fCross(tmp2, tmp1, tmp1); + if (CgeVec3fNormalEx(tmp1, tmp1) < EPSILON) + return 0; + + out[3] = CgeVec3fDot(a, tmp1); + memcpy(out, tmp1, sizeof(tmp1)); + return 1; +} + +float CgePlaneDistance(const float plane[4], const float point[3]) { + return CgeVec3fDot(plane, point) - plane[3]; +} + +void CgePlaneClosestPoint(const float plane[4], const float point[3], + float out[3]) { + float tmp[3]; + + CgeVec3fScale(plane, CgePlaneDistance(plane, point), tmp); + CgeVec3fSub(point, tmp, out); +} diff --git a/Quat4f.c b/Quat4f.c new file mode 100644 index 0000000..d86100e --- /dev/null +++ b/Quat4f.c @@ -0,0 +1,160 @@ +#include "CgeMath.h" +#include +#include + +#define EPSILON 0.00001f +#define PI 3.14159265358979323846f + +void CgeQuat4fIdentity(float out[4]) { + static const float ident[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + memcpy(out, ident, sizeof(ident)); +} + +void CgeQuat4fConjugate(const float in[4], float out[4]) { + out[0] = -in[0]; + out[1] = -in[1]; + out[2] = -in[2]; + out[3] = in[3]; +} + +void CgeQuat4fInverse(const float in[4], float out[4]) { + float dot; + + dot = CgeVec4fDot(in, in); + CgeQuat4fConjugate(in, out); + CgeQuat4fScale(out, 1.0f / dot, out); +} + +void CgeQuat4fMul(const float a[4], const float b[4], float out[4]) { + float tmp1[4], tmp2[4], tmp3[4]; + float w; + + w = a[3] * b[3] - CgeVec3fDot(a, b); + CgeVec4fScale(a, b[3], tmp1); + CgeVec4fScale(b, a[3], tmp2); + CgeVec3fCross(a, b, tmp3); + CgeVec4fAdd(tmp1, tmp2, out); + CgeVec4fAdd(tmp3, out, out); + out[3] = w; +} + +void CgeQuat4fSlerp(const float a[4], const float b[4], float t, float out[4]) { + float angle, denom; + float from[4], to[4]; + + angle = acosf(CgeVec4fDot(a, b)); + if (fabsf(angle) < EPSILON) { + CgeVec4fLerp(a, b, t, out); + return; + } + + denom = 1.0f / sinf(angle); + CgeVec4fScale(a, sinf((1 - t) * angle) * denom, from); + CgeVec4fScale(b, sinf(t * angle) * denom, to); + CgeVec4fAdd(from, to, out); +} + +void CgeQuat4fFromEuler(float roll, float pitch, float yaw, float out[4]) { + float cr, cp, cy, sr, sp, sy; + + cr = cosf(roll / 2.0f); + cp = cosf(pitch / 2.0f); + cy = cosf(yaw / 2.0f); + sr = sinf(roll / 2.0f); + sp = sinf(pitch / 2.0f); + sy = sinf(yaw / 2.0f); + + out[0] = sr * cp * cy - cr * sp * sy; + out[1] = cr * sp * cy + sr * cp * sy; + out[2] = cr * cp * sy - sr * sp * cy; + out[3] = cr * cp * cy + sr * sp * sy; +} + +void CgeQuat4fFromAxis(const float axis[3], float angle, float out[4]) { + float c, s; + + c = cosf(angle / 2.0f); + s = sinf(angle / 2.0f); + + out[0] = axis[0] * s; + out[1] = axis[1] * s; + out[2] = axis[2] * s; + out[3] = c; +} + +void CgeQuat4fToEuler(const float in[4], float *roll, float *pitch, + float *yaw) { + float ww, xw, yw, zw, xx, xy, xz, yy, yz, zz, angle; + + xx = in[0] * in[0]; + xy = in[0] * in[1]; + xz = in[0] * in[2]; + xw = in[0] * in[3]; + yy = in[1] * in[1]; + yz = in[1] * in[2]; + yw = in[1] * in[3]; + zz = in[2] * in[2]; + zw = in[2] * in[3]; + ww = in[3] * in[3]; + + angle = 2.0f * (yw - xz); + if (angle > 1.0f) + angle = 1.0f; + if (angle < -1.0f) + angle = -1.0f; + + *pitch = asinf(angle); + + if (fabsf(*pitch - (PI / 2.0f)) < EPSILON) { + *roll = 0.0f; + *yaw = -2.0f * atan2f(in[0], in[3]); + } else if (fabsf(*pitch - (PI / -2.0f)) < EPSILON) { + *roll = 0.0f; + *yaw = 2.0f * atan2f(in[0], in[3]); + } else { + *roll = atan2f(2.0f * (xw + yz), ww - xx - yy + zz); + *yaw = atan2f(2.0f * (zw + xy), ww + xx - yy - zz); + } +} + +void CgeQuat4fToAxis(const float in[4], float axis[3], float *angle) { + *angle = 2.0f * acosf(in[3]); + + if (fabsf(*angle) < EPSILON) { + axis[0] = 1.0f; + axis[1] = 0.0f; + axis[2] = 0.0f; + } else { + float tmp; + + tmp = sqrtf(1.0f - in[3] * in[3]); + axis[0] = in[0] / tmp; + axis[1] = in[1] / tmp; + axis[2] = in[2] / tmp; + } +} + +void CgeQuat4fToMat4f(const float in[4], float out[16]) { + float xx, xy, xz, xw, yy, yz, yw, zz, zw; + + xx = in[0] * in[0]; + xy = in[0] * in[1]; + xz = in[0] * in[2]; + xw = in[0] * in[3]; + yy = in[1] * in[1]; + yz = in[1] * in[2]; + yw = in[1] * in[3]; + zz = in[2] * in[2]; + zw = in[2] * in[3]; + + CgeMat4fIdentity(out); + out[0] = 1.0f - 2.0f * (yy + zz); + out[1] = 2.0f * (xy + zw); + out[2] = 2.0f * (xz - yw); + out[4] = 2.0f * (xy - zw); + out[5] = 1.0f - 2.0f * (xx + zz); + out[6] = 2.0f * (yz + xw); + out[8] = 2.0f * (xz + yw); + out[9] = 2.0f * (yz - xw); + out[10] = 1.0f - 2.0f * (xx + yy); +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ef02c9 --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# CgeMath - Lightweight Math Library for C + +A compact, dependency-free C library for 2D/3D math, linear algebra, and +computational geometry operations. + +## Features + +- 2D/3D vector operations: addition, subtraction, scaling, dot product, cross product +- Vector normalization, length computation, linear interpolation (lerp) +- 3x3 and 4x4 matrix operations: multiplication, addition, transpose, inverse, determinant +- Matrix utilities: identity, scaling, translation, rotation (axis and Euler) +- Projection matrices: orthographic, frustum, perspective from FOV +- View matrix from position, target, and up vector +- Quaternion operations: multiplication, conjugate, inverse, slerp, lerp +- Quaternion to/from rotation matrix and Euler angles +- Axis-aligned bounding box (AABB) operations in 2D and 3D: union, intersection, containment +- Point enclosure: compute bounding box from point set +- Line and plane geometry: construction from points, distance to point, closest point +- Ray, segment, and line intersection tests in 2D and 3D +- Ray-triangle and segment-triangle intersection +- Barycentric coordinate computation for 2D and 3D triangles +- Integer vector operations for 2D, 3D, 4D: add, subtract, min, max + +## Build Systems + +- CMake - supports Linux, macOS, Windows (MSVC, MinGW) +- Makefile.posix - for GCC/Clang on POSIX systems +- Makefile.mingw - for MinGW on Windows +- Makefile.win32 - for MSVC with NMake + +Builds a static library. No shared library or external dependencies. + +## Usage Example + +```c +#include "CgeMath.h" +#include + +int main() { + float pos[] = {1.0f, 0.0f, 0.0f}; + float scale[] = {2.0f, 2.0f, 2.0f}; + float mat[16], result[3]; + + CgeMat4fIdentity(mat); + CgeMat4fFromScale(scale[0], scale[1], scale[2], mat); + CgeMat4fApplyVec3f(mat, pos, result); + + printf("Transformed: (%f, %f, %f)\n", + result[0], result[1], result[2]); + return 0; +} +``` + +## Portability + +- Written in C89 + stdint.h +- No dynamic memory allocation +- No external dependencies + +## License + +0BSD - a permissive license with no attribution required. diff --git a/Ray2f.c b/Ray2f.c new file mode 100644 index 0000000..a731c95 --- /dev/null +++ b/Ray2f.c @@ -0,0 +1,193 @@ +#include "CgeMath.h" +#include +#include + +#define EPSILON 0.00001f +#define PI 3.14159265358979323846f + +int CgeRay2fIntersectLine(const float start[2], const float direction[2], + const float line[3], float *t, float out[2]) { + float tmp1[2]; + float denom, time; + + /* Calculate intersection time */ + denom = CgeVec2fDot(direction, line); + time = (line[2] - CgeVec2fDot(line, start)) / denom; + + /* Check for ray/plane parallel to each other or point is behing the ray. */ + if (fabsf(denom) < EPSILON || time < 0.0f) + return 0; + + /* Compute intersection point */ + CgeVec2fScale(direction, time, tmp1); + CgeVec2fAdd(start, tmp1, out); + *t = time; + return 1; +} + +int CgeRay2fIntersectTime(const float aStart[2], const float aDirection[2], + const float bStart[2], const float bDirection[2], + float *time1, float *time2) { + float tmp1[2], tmp2[2], tmp3[2]; + float denom; + + /* Rotate directions by 90 degrees and caluclate denom */ + tmp1[0] = -aDirection[1]; tmp1[1] = aDirection[0]; + tmp2[0] = -bDirection[1]; tmp2[1] = bDirection[0]; + denom = CgeVec2fDot(tmp1, bDirection); + + if (fabsf(denom) < EPSILON) + return 0; + + /* Calculate segments offset and intersection times */ + CgeVec2fSub(aStart, bStart, tmp3); + *time1 = CgeVec2fDot(tmp3, tmp2) / denom; + *time2 = CgeVec2fDot(tmp3, tmp1) / denom; + + return 1; +} + +int CgeRay2fIntersectRay(const float aStart[2], const float aDirection[2], + const float bStart[2], const float bDirection[2], + float *t, float out[2]) { + float tmp[2]; + float time1, time2; + + if (CgeRay2fIntersectTime(aStart, aDirection, bStart, bDirection, &time1, &time2)) + return 0; + + if (time1 < 0.0f || time2 < 0.0f) + return 0; + + CgeVec2fScale(aDirection, time1, tmp); + CgeVec2fAdd(aStart, tmp, out); + *t = time1; + return 1; +} + +int CgeRay2fIntersectSegment(const float aStart[2], const float aDirection[2], + const float bStart[2], const float bEnd[2], + float *t, float out[2]) { + float tmp[2]; + float time1, time2; + + CgeVec2fSub(bEnd, bStart, tmp); + if (CgeRay2fIntersectTime(aStart, aDirection, bStart, tmp, &time1, &time2)) + return 0; + + if (time1 < 0.0f || time2 < 0.0f || time2 > 1.0f) + return 0; + + CgeVec2fScale(aDirection, time1, tmp); + CgeVec2fAdd(aStart, tmp, out); + *t = time1; + return 1; +} + +int CgeSegment2fIntersectLine(const float start[2], const float end[2], + const float line[3], float *t, float out[2]) { + float tmp[2]; + float denom, time; + + /* Calculate intersection time */ + CgeVec2fSub(end, start, tmp); + denom = CgeVec2fDot(tmp, line); + time = (line[2] - CgeVec2fDot(line, start)) / denom; + + /* Check for ray/plane parallel to each other or point is behing the ray. */ + if (fabsf(denom) < EPSILON || time < 0.0f || time > 1.0f) + return 0; + + /* Compute intersection point */ + CgeVec2fScale(tmp, time, tmp); + CgeVec2fAdd(start, tmp, out); + *t = time; + return 1; +} + +int CgeSegment2fIntersectSegment(const float aStart[2], const float aEnd[2], + const float bStart[2], const float bEnd[2], + float *t, float out[2]) { + float tmp1[2], tmp2[2]; + float time1, time2; + + CgeVec2fSub(aEnd, aStart, tmp1); + CgeVec2fSub(bEnd, bStart, tmp2); + if (CgeRay2fIntersectTime(aStart, tmp1, bStart, tmp2, &time1, &time2)) + return 0; + + if (time1 < 0.0f || time1 > 1.0f || time2 < 0.0f || time2 > 1.0f) + return 0; + + CgeVec2fLerp(aStart, aEnd, time1, out); + *t = time1; + + return 1; +} + +int CgeRay2fIntersectBox2f(const float aStart[2], const float aDirection[2], + const float bMin[2], const float bMax[2], + float *t, float out[2]) { + float timeNear, timeFar, hitNear, hitFar, denom, tmp; + int i; + + timeNear = -1.0f / 0.0f; + timeFar = 1.0f / 0.0f; + + /* Check if origin inside box */ + if (!CgeBox2fContains(bMin, bMax, aStart)) { + memcpy(out, aStart, sizeof(float) * 2); + *t = 0.0f; + return 1; + } + + /* Check each axis for the minimal and maximum intersection time */ + for (i = 0; i < 2; i++) { + if (fabsf(aDirection[i]) < EPSILON) { + if (aStart[i] < bMin[i] || aStart[i] > bMax[i]) + return 0; + continue; + } + + denom = 1.0f / aDirection[i]; + hitNear = (bMin[i] - aStart[i]) * denom; + hitFar = (bMax[i] - aStart[i]) * denom; + + if (hitNear > hitFar) { + tmp = hitNear; + hitNear = hitFar; + hitFar = tmp; + } + + if (hitNear > timeNear) + timeNear = hitNear; + if (hitFar < timeFar) + timeFar = hitFar; + + if (timeNear > timeFar || timeFar < 0.0f) + return 0; + } + + out[0] = aStart[0] + aDirection[0] * timeNear; + out[1] = aStart[1] + aDirection[1] * timeNear; + *t = timeNear; + + return 1; +} + +int CgeSegment2fIntersectBox2f(const float aStart[2], const float aEnd[2], + const float bMin[2], const float bMax[2], + float *t, float out[2]) { + float tmp[3]; + float time; + + CgeVec2fSub(aEnd, aStart, tmp); + if (CgeRay2fIntersectBox2f(aStart, tmp, bMin, bMax, &time, out)) + return 0; + + if (time > 1.0f) + return 0; + + *t = time; + return 1; +} diff --git a/Ray3f.c b/Ray3f.c new file mode 100644 index 0000000..c683569 --- /dev/null +++ b/Ray3f.c @@ -0,0 +1,195 @@ +#include "CgeMath.h" +#include +#include + +#define EPSILON 0.00001f +#define PI 3.14159265358979323846f + +int CgeRay3fIntersectPlane(const float start[3], const float direction[3], + const float plane[4], float *t, float out[3]) { + float tmp1[3]; + float denom, time; + + /* Calculate intersection time */ + denom = CgeVec3fDot(direction, plane); + time = (plane[3] - CgeVec3fDot(plane, start)) / denom; + + /* Check for ray/plane parallel to each other or point is behing the ray. */ + if (fabsf(denom) < EPSILON || time < 0.0f) + return 0; + + /* Compute intersection point */ + CgeVec3fScale(direction, time, tmp1); + CgeVec3fAdd(start, tmp1, out); + *t = time; + return 1; +} + +int CgeRay3fIntersectTriangle(const float start[3], const float direction[3], + const float a[3], const float b[3], + const float c[3], float *t, float out[3]) { + float plane[4]; + float tmp1[3], tmp2[3], tmp3[3]; + float time; + + /* Compute plane */ + if (CgePlaneFromPoints(a, b, c, plane)) + return 0; + + /* Compute intersection point in ray against plane */ + if (CgeRay3fIntersectPlane(start, direction, plane, &time, tmp3)) + return 0; + + /* Check if point inside rectangle */ + CgeVec3fSub(b, a, tmp1); + CgeVec3fSub(tmp3, a, tmp2); + CgeVec3fCross(tmp2, tmp1, tmp1); + if (CgeVec3fDot(tmp1, plane) < 0.0f) + return 0; + + CgeVec3fSub(c, b, tmp1); + CgeVec3fSub(tmp3, b, tmp2); + CgeVec3fCross(tmp2, tmp1, tmp1); + if (CgeVec3fDot(tmp1, plane) < 0.0f) + return 0; + + CgeVec3fSub(a, c, tmp1); + CgeVec3fSub(tmp3, c, tmp2); + CgeVec3fCross(tmp2, tmp1, tmp1); + if (CgeVec3fDot(tmp1, plane) < 0.0f) + return 0; + + /* Copy intersection point */ + memcpy(out, tmp3, sizeof(tmp3)); + *t = time; + return 1; +} + +int CgeSegment3fIntersectPlane(const float start[3], const float end[3], + const float plane[4], float *t, float out[3]) { + float tmp[3]; + float denom, time; + + /* Calculate intersection time */ + CgeVec3fSub(end, start, tmp); + denom = CgeVec3fDot(tmp, plane); + time = (plane[3] - CgeVec3fDot(plane, start)) / denom; + + /* Check for ray/plane parallel to each other or point is behing the ray. */ + if (fabsf(denom) < EPSILON || time < 0.0f || time > 1.0f) + return 0; + + /* Compute intersection point */ + CgeVec3fScale(tmp, time, tmp); + CgeVec3fAdd(start, tmp, out); + *t = time; + return 1; +} + +int CgeSegment3fIntersectTriangle(const float start[3], const float end[3], + const float a[3], const float b[3], + const float c[3], float *t, float out[3]) { + float plane[4]; + float tmp1[3], tmp2[3], tmp3[3]; + float time; + + /* Compute plane */ + if (CgePlaneFromPoints(a, b, c, plane)) + return 0; + + /* Compute intersection point in ray against plane */ + if (CgeSegment3fIntersectPlane(start, end, plane, &time, tmp3)) + return 0; + + /* Check if point inside rectangle */ + CgeVec3fSub(b, a, tmp1); + CgeVec3fSub(tmp3, a, tmp2); + CgeVec3fCross(tmp2, tmp1, tmp1); + if (CgeVec3fDot(tmp1, plane) < 0.0f) + return 0; + + CgeVec3fSub(c, b, tmp1); + CgeVec3fSub(tmp3, b, tmp2); + CgeVec3fCross(tmp2, tmp1, tmp1); + if (CgeVec3fDot(tmp1, plane) < 0.0f) + return 0; + + CgeVec3fSub(a, c, tmp1); + CgeVec3fSub(tmp3, c, tmp2); + CgeVec3fCross(tmp2, tmp1, tmp1); + if (CgeVec3fDot(tmp1, plane) < 0.0f) + return 0; + + /* Copy intersection point */ + memcpy(out, tmp3, sizeof(tmp3)); + *t = time; + return 1; +} + +int CgeRay3fIntersectBox3f(const float aStart[3], const float aDirection[3], + const float bMin[3], const float bMax[3], float *t, + float out[3]) { + float timeNear, timeFar, hitNear, hitFar, denom, tmp; + int i; + + timeNear = -1.0f / 0.0f; + timeFar = 1.0f / 0.0f; + + /* Check if origin inside box */ + if (!CgeBox3fContains(bMin, bMax, aStart)) { + memcpy(out, aStart, sizeof(float) * 3); + *t = 0.0f; + return 1; + } + + /* Check each axis for the minimal and maximum intersection time */ + for (i = 0; i < 3; i++) { + if (fabsf(aDirection[i]) < EPSILON) { + if (aStart[i] < bMin[i] || aStart[i] > bMax[i]) + return 0; + continue; + } + + denom = 1.0f / aDirection[i]; + hitNear = (bMin[i] - aStart[i]) * denom; + hitFar = (bMax[i] - aStart[i]) * denom; + + if (hitNear > hitFar) { + tmp = hitNear; + hitNear = hitFar; + hitFar = tmp; + } + + if (hitNear > timeNear) + timeNear = hitNear; + if (hitFar < timeFar) + timeFar = hitFar; + + if (timeNear > timeFar || timeFar < 0.0f) + return 0; + } + + out[0] = aStart[0] + aDirection[0] * timeNear; + out[1] = aStart[1] + aDirection[1] * timeNear; + out[2] = aStart[2] + aDirection[2] * timeNear; + *t = timeNear; + + return 1; +} + +int CgeSegment3fIntersectBox3f(const float aStart[3], const float aEnd[3], + const float bMin[3], const float bMax[3], + float *t, float out[3]) { + float tmp[3]; + float time; + + CgeVec3fSub(aEnd, aStart, tmp); + if (CgeRay3fIntersectBox3f(aStart, tmp, bMin, bMax, &time, out)) + return 0; + + if (time > 1.0f) + return 0; + + *t = time; + return 1; +} diff --git a/Vec2f.c b/Vec2f.c new file mode 100644 index 0000000..4f67b55 --- /dev/null +++ b/Vec2f.c @@ -0,0 +1,95 @@ +#include "CgeMath.h" +#include + +#define SET_ROW(row, val) row[0] = row[1] = val + +void CgeVec2fAdd(const float a[2], const float b[2], float out[2]) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; +} + +void CgeVec2fSub(const float a[2], const float b[2], float out[2]) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; +} + +void CgeVec2fMul(const float a[2], const float b[2], float out[2]) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; +} + +void CgeVec2fScale(const float a[2], float b, float out[2]) { + out[0] = a[0] * b; + out[1] = a[1] * b; +} + +void CgeVec2fMulAdd(const float a[2], const float b[2], const float c[2], + float out[2]) { + out[0] = a[0] * b[0] + c[0]; + out[1] = a[1] * b[1] + c[1]; +} + +void CgeVec2fNegate(const float in[2], float out[2]) { + out[0] = -in[0]; + out[1] = -in[1]; +} + +float CgeVec2fDot(const float a[2], const float b[2]) { + return a[0] * b[0] + a[1] * b[1]; +} + +float CgeVec2fCross(const float a[2], const float b[2]) { + return a[0] * b[1] - a[1] * b[0]; +} + +float CgeVec2fLength(const float in[2]) { + return sqrtf(CgeVec2fDot(in, in)); +} + +void CgeVec2fNormal(const float in[2], float out[2]) { + CgeVec2fScale(in, 1.0f / CgeVec2fLength(in), out); +} + +float CgeVec2fNormalEx(const float in[2], float out[2]) { + float length; + + length = CgeVec2fLength(in); + CgeVec2fScale(in, 1.0f / length, out); + return length; +} + +void CgeVec2fMin(const float a[2], const float b[2], float out[2]) { + if (a[0] < b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] < b[1]) out[1] = a[1]; else out[1] = b[1]; +} + +void CgeVec2fMax(const float a[2], const float b[2], float out[2]) { + if (a[0] > b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] > b[1]) out[1] = a[1]; else out[1] = b[1]; +} + +void CgeVec2fLerp(const float a[2], const float b[2], float t, float out[2]) { + float tmp[2]; + + CgeVec2fSub(b, a, tmp); + CgeVec2fScale(tmp, t, tmp); + CgeVec2fAdd(a, tmp, out); +} + +void CgeVec2fProject(const float a[2], const float b[2], float out[2]) { + float amount; + + amount = CgeVec2fDot(a, b) / CgeVec2fDot(b, b); + CgeVec2fScale(b, amount, out); +} + +void CgeVec2fBarycentric(const float a[2], const float b[2], const float c[2], + float v, float w, float out[2]) { + float tmp1[2], tmp2[2]; + float u; + + u = 1.0f - v - w; + SET_ROW(tmp1, u); CgeVec2fMul(a, tmp1, tmp2); + SET_ROW(tmp1, v); CgeVec2fMulAdd(b, tmp1, tmp2, tmp2); + SET_ROW(tmp1, w); CgeVec2fMulAdd(c, tmp1, tmp2, out); +} diff --git a/Vec2i.c b/Vec2i.c new file mode 100644 index 0000000..6cad67f --- /dev/null +++ b/Vec2i.c @@ -0,0 +1,42 @@ +#include "CgeMath.h" + +void CgeVec2iAdd(const int a[2], const int b[2], int out[2]) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; +} + +void CgeVec2iSub(const int a[2], const int b[2], int out[2]) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; +} + +void CgeVec2iMul(const int a[2], const int b[2], int out[2]) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; +} + +void CgeVec2iScale(const int a[2], int b, int out[2]) { + out[0] = a[0] * b; + out[1] = a[1] * b; +} + +void CgeVec2iMulAdd(const int a[2], const int b[2], const int c[2], + int out[2]) { + out[0] = a[0] * b[0] + c[0]; + out[1] = a[1] * b[1] + c[1]; +} + +void CgeVec2iNegate(const int in[2], int out[2]) { + out[0] = -in[0]; + out[1] = -in[1]; +} + +void CgeVec2iMin(const int a[2], const int b[2], int out[2]) { + if (a[0] < b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] < b[1]) out[1] = a[1]; else out[1] = b[1]; +} + +void CgeVec2iMax(const int a[2], const int b[2], int out[2]) { + if (a[0] > b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] > b[1]) out[1] = a[1]; else out[1] = b[1]; +} diff --git a/Vec3f.c b/Vec3f.c new file mode 100644 index 0000000..34d8767 --- /dev/null +++ b/Vec3f.c @@ -0,0 +1,109 @@ +#include "CgeMath.h" +#include +#include + +#define SET_ROW(row, val) row[0] = row[1] = row[2] = val + +void CgeVec3fAdd(const float a[3], const float b[3], float out[3]) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; +} + +void CgeVec3fSub(const float a[3], const float b[3], float out[3]) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; +} + +void CgeVec3fMul(const float a[3], const float b[3], float out[3]) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; +} + +void CgeVec3fScale(const float a[3], float b, float out[3]) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; +} + +void CgeVec3fMulAdd(const float a[3], const float b[3], const float c[3], + float out[3]) { + out[0] = a[0] * b[0] + c[0]; + out[1] = a[1] * b[1] + c[1]; + out[2] = a[2] * b[2] + c[2]; +} + +void CgeVec3fNegate(const float in[3], float out[3]) { + out[0] = -in[0]; + out[1] = -in[1]; + out[2] = -in[2]; +} + +float CgeVec3fDot(const float a[3], const float b[3]) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +void CgeVec3fCross(const float a[3], const float b[3], float out[3]) { + float tmp[3]; + + tmp[0] = a[1] * b[2] - a[2] * b[1]; + tmp[1] = a[2] * b[0] - a[0] * b[2]; + tmp[2] = a[0] * b[1] - a[1] * b[0]; + memcpy(out, tmp, sizeof(tmp)); +} + +float CgeVec3fLength(const float in[3]) { + return sqrtf(CgeVec3fDot(in, in)); +} + +void CgeVec3fNormal(const float in[3], float out[3]) { + CgeVec3fScale(in, 1.0f / CgeVec3fLength(in), out); +} + +float CgeVec3fNormalEx(const float in[3], float out[3]) { + float length; + + length = CgeVec3fLength(in); + CgeVec3fScale(in, 1.0f / length, out); + return length; +} + +void CgeVec3fMin(const float a[3], const float b[3], float out[3]) { + if (a[0] < b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] < b[1]) out[1] = a[1]; else out[1] = b[1]; + if (a[2] < b[2]) out[2] = a[2]; else out[2] = b[2]; +} + +void CgeVec3fMax(const float a[3], const float b[3], float out[3]) { + if (a[0] > b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] > b[1]) out[1] = a[1]; else out[1] = b[1]; + if (a[2] > b[2]) out[2] = a[2]; else out[2] = b[2]; +} + +void CgeVec3fLerp(const float a[3], const float b[3], float t, float out[3]) { + float tmp[3]; + + CgeVec3fSub(b, a, tmp); + CgeVec3fScale(tmp, t, tmp); + CgeVec3fAdd(a, tmp, out); +} + +void CgeVec3fProject(const float a[3], const float b[3], float out[3]) { + float amount; + + amount = CgeVec3fDot(a, b) / CgeVec3fDot(b, b); + CgeVec3fScale(b, amount, out); +} + +void CgeVec3fBarycentric(const float a[3], const float b[3], const float c[3], + float v, float w, float out[3]) { + float tmp1[3], tmp2[3]; + float u; + + u = 1.0f - v - w; + SET_ROW(tmp1, u); CgeVec3fMul(a, tmp1, tmp2); + SET_ROW(tmp1, v); CgeVec3fMulAdd(b, tmp1, tmp2, tmp2); + SET_ROW(tmp1, w); CgeVec3fMulAdd(c, tmp1, tmp2, out); +} diff --git a/Vec3i.c b/Vec3i.c new file mode 100644 index 0000000..52532de --- /dev/null +++ b/Vec3i.c @@ -0,0 +1,50 @@ +#include "CgeMath.h" + +void CgeVec3iAdd(const int a[3], const int b[3], int out[3]) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; +} + +void CgeVec3iSub(const int a[3], const int b[3], int out[3]) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; +} + +void CgeVec3iMul(const int a[3], const int b[3], int out[3]) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; +} + +void CgeVec3iScale(const int a[3], int b, int out[3]) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; +} + +void CgeVec3iMulAdd(const int a[3], const int b[3], const int c[3], + int out[3]) { + out[0] = a[0] * b[0] + c[0]; + out[1] = a[1] * b[1] + c[1]; + out[2] = a[2] * b[2] + c[2]; +} + +void CgeVec3iNegate(const int in[3], int out[3]) { + out[0] = -in[0]; + out[1] = -in[1]; + out[2] = -in[2]; +} + +void CgeVec3iMin(const int a[3], const int b[3], int out[3]) { + if (a[0] < b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] < b[1]) out[1] = a[1]; else out[1] = b[1]; + if (a[2] < b[2]) out[2] = a[2]; else out[2] = b[2]; +} + +void CgeVec3iMax(const int a[3], const int b[3], int out[3]) { + if (a[0] > b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] > b[1]) out[1] = a[1]; else out[1] = b[1]; + if (a[2] > b[2]) out[2] = a[2]; else out[2] = b[2]; +} diff --git a/Vec4f.c b/Vec4f.c new file mode 100644 index 0000000..2d542e8 --- /dev/null +++ b/Vec4f.c @@ -0,0 +1,108 @@ +#include "CgeMath.h" +#include + +#define SET_ROW(row, val) row[0] = row[1] = row[2] = row[3] = val + +void CgeVec4fAdd(const float a[4], const float b[4], float out[4]) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; +} + +void CgeVec4fSub(const float a[4], const float b[4], float out[4]) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; +} + +void CgeVec4fMul(const float a[4], const float b[4], float out[4]) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + out[3] = a[3] * b[3]; +} + +void CgeVec4fScale(const float a[4], float b, float out[4]) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; +} + +void CgeVec4fMulAdd(const float a[4], const float b[4], const float c[4], + float out[4]) { + out[0] = a[0] * b[0] + c[0]; + out[1] = a[1] * b[1] + c[1]; + out[2] = a[2] * b[2] + c[2]; + out[3] = a[3] * b[3] + c[3]; +} + +void CgeVec4fNegate(const float in[4], float out[4]) { + out[0] = -in[0]; + out[1] = -in[1]; + out[2] = -in[2]; + out[3] = -in[3]; +} + +float CgeVec4fDot(const float a[4], const float b[4]) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; +} + +float CgeVec4fLength(const float in[4]) { + return sqrtf(CgeVec4fDot(in, in)); +} + +void CgeVec4fNormal(const float in[4], + float out[4]) { + CgeVec4fScale(in, 1.0f / CgeVec4fLength(in), out); +} + +float CgeVec4fNormalEx(const float in[4], float out[4]) { + float length; + + length = CgeVec4fLength(in); + CgeVec4fScale(in, 1.0f / length, out); + return length; +} + +void CgeVec4fMin(const float a[4], const float b[4], float out[4]) { + if (a[0] < b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] < b[1]) out[1] = a[1]; else out[1] = b[1]; + if (a[2] < b[2]) out[2] = a[2]; else out[2] = b[2]; + if (a[3] < b[3]) out[3] = a[3]; else out[3] = b[3]; +} + +void CgeVec4fMax(const float a[4], const float b[4], float out[4]) { + if (a[0] > b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] > b[1]) out[1] = a[1]; else out[1] = b[1]; + if (a[2] > b[2]) out[2] = a[2]; else out[2] = b[2]; + if (a[3] > b[3]) out[3] = a[3]; else out[3] = b[3]; +} + +void CgeVec4fLerp(const float a[4], const float b[4], float t, float out[4]) { + float tmp[4]; + + CgeVec4fSub(b, a, tmp); + CgeVec4fScale(tmp, t, tmp); + CgeVec4fAdd(a, tmp, out); +} + +void CgeVec4fProject(const float a[4], const float b[4], float out[4]) { + float amount; + + amount = CgeVec4fDot(a, b) / CgeVec4fDot(b, b); + CgeVec4fScale(b, amount, out); +} + +void CgeVec4fBarycentric(const float a[4], const float b[4], const float c[4], + float v, float w, float out[4]) { + float tmp1[4], tmp2[4]; + float u; + + u = 1.0f - v - w; + SET_ROW(tmp1, u); CgeVec4fMul(a, tmp1, tmp2); + SET_ROW(tmp1, v); CgeVec4fMulAdd(b, tmp1, tmp2, tmp2); + SET_ROW(tmp1, w); CgeVec4fMulAdd(c, tmp1, tmp2, out); +} diff --git a/Vec4i.c b/Vec4i.c new file mode 100644 index 0000000..fa9d51a --- /dev/null +++ b/Vec4i.c @@ -0,0 +1,58 @@ +#include "CgeMath.h" + +void CgeVec4iAdd(const int a[4], const int b[4], int out[4]) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; +} + +void CgeVec4iSub(const int a[4], const int b[4], int out[4]) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; +} + +void CgeVec4iMul(const int a[4], const int b[4], int out[4]) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + out[3] = a[3] * b[3]; +} + +void CgeVec4iScale(const int a[4], int b, int out[4]) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; +} + +void CgeVec4iMulAdd(const int a[4], const int b[4], const int c[4], + int out[4]) { + out[0] = a[0] * b[0] + c[0]; + out[1] = a[1] * b[1] + c[1]; + out[2] = a[2] * b[2] + c[2]; + out[3] = a[3] * b[3] + c[3]; +} + +void CgeVec4iNegate(const int in[4], int out[4]) { + out[0] = -in[0]; + out[1] = -in[1]; + out[2] = -in[2]; + out[3] = -in[3]; +} + +void CgeVec4iMin(const int a[4], const int b[4], int out[4]) { + if (a[0] < b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] < b[1]) out[1] = a[1]; else out[1] = b[1]; + if (a[2] < b[2]) out[2] = a[2]; else out[2] = b[2]; + if (a[3] < b[3]) out[3] = a[3]; else out[3] = b[3]; +} + +void CgeVec4iMax(const int a[4], const int b[4], int out[4]) { + if (a[0] > b[0]) out[0] = a[0]; else out[0] = b[0]; + if (a[1] > b[1]) out[1] = a[1]; else out[1] = b[1]; + if (a[2] > b[2]) out[2] = a[2]; else out[2] = b[2]; + if (a[3] > b[3]) out[3] = a[3]; else out[3] = b[3]; +}