Compare commits

...

9 Commits

17 changed files with 1204 additions and 30 deletions

View File

@ -2,7 +2,7 @@
CC=$(PREFIX)gcc
CXX=$(PREFIX)g++
OPT = -O0 -march=x86-64-v3
OPT = -O2 -march=x86-64-v3
CSTD = -std=gnu23
CXXSTD = -std=gnu++23
@ -12,6 +12,7 @@ CFLAGS += -I./include
CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -Wno-error=unused-but-set-variable
CFLAGS += -Wno-error=unknown-pragmas -Wno-unknown-pragmas
CFLAGS += $(shell pkg-config --cflags glfw3)
CFLAGS += -fno-strict-aliasing
LDFLAGS += -lm
LDFLAGS += $(shell pkg-config --libs glfw3)
@ -30,7 +31,8 @@ OBJS = \
src/view.o \
src/minecraft.o \
src/hud.o \
src/lighting.o
src/lighting.o \
src/collision_scene.o
all: test.so

253
include/collision.h Normal file
View File

@ -0,0 +1,253 @@
#pragma once
#include <float.h>
#include <stdio.h>
#include "directxmath/directxmath.h"
namespace collision {
struct AABB {
XMVECTOR min;
XMVECTOR max;
};
struct Sphere {
XMVECTOR center;
float radius;
};
struct Capsule {
XMVECTOR a;
XMVECTOR b;
float radius;
};
static inline AABB cube_aabb(XMVECTOR const & center, float half)
{
half = fabsf(half);
XMVECTOR min = center + XMVectorReplicate(-half);
XMVECTOR max = center + XMVectorReplicate( half);
return AABB(min, max);
}
static inline XMVECTOR closest_point_point_aabb(XMVECTOR const & p, AABB const & aabb)
{
return XMVectorClamp(p, aabb.min, aabb.max);
}
static inline bool test_sphere_aabb(Sphere const & sphere, AABB const & aabb, XMVECTOR & point)
{
point = closest_point_point_aabb(sphere.center, aabb);
XMVECTOR v = point - sphere.center;
return XMVectorGetX(XMVector3Dot(v, v)) <= sphere.radius * sphere.radius;
}
static inline void vector_swap_control(XMVECTOR & a, XMVECTOR & b, XMVECTOR const & control)
{
XMVECTOR tmp = XMVectorSelect(a, b, control);
b = XMVectorSelect(b, a, control);
a = tmp;
}
static inline bool intersect_ray_aabb(XMVECTOR const & point, XMVECTOR const & direction, AABB const & aabb, float & t_result, XMVECTOR & v_result)
{
// check parallel
XMVECTOR parallel = XMVectorLess(XMVectorAbs(direction), XMVectorSplatEpsilon());
XMVECTOR point_lt_aabb = XMVectorLess(point, aabb.min);
XMVECTOR point_gt_aabb = XMVectorGreater(point, aabb.max);
if (XMVectorGetX(parallel) != 0) // if (x < epsilon)
if (XMVectorGetX(point_lt_aabb) != 0 || XMVectorGetX(point_gt_aabb) != 0)
return false; // direction x is parallel and point x outside aabb
if (XMVectorGetY(parallel) != 0) // if (y < epsilon)
if (XMVectorGetY(point_lt_aabb) != 0 || XMVectorGetY(point_gt_aabb) != 0)
return false; // direction y is parallel and point y outside aabb
if (XMVectorGetZ(parallel) != 0) // if (z < epsilon)
if (XMVectorGetZ(point_lt_aabb) != 0 || XMVectorGetZ(point_gt_aabb) != 0)
return false; // direction z is parallel and point z outside aabb
XMVECTOR direction_reciprocal = XMVectorReciprocalEst(direction);
XMVECTOR t1 = (aabb.min - point) * direction_reciprocal;
XMVECTOR t2 = (aabb.max - point) * direction_reciprocal;
vector_swap_control(t2, t1, XMVectorGreater(t1, t2));
float tmin = XMVectorGetX(t1);
if (XMVectorGetY(t1) > tmin) tmin = XMVectorGetY(t1);
if (XMVectorGetZ(t1) > tmin) tmin = XMVectorGetZ(t1);
float tmax = XMVectorGetX(t2);
if (XMVectorGetY(t2) < tmax) tmax = XMVectorGetY(t2);
if (XMVectorGetZ(t2) < tmax) tmax = XMVectorGetZ(t2);
if (tmin > tmax) return false; // no intersection
t_result = tmin;
v_result = point + direction * tmin;
return true;
}
static inline float clamp(float f, float min, float max)
{
if (f < min) return min;
if (f > max) return max;
return f;
}
static inline void closest_point_segment_segment(XMVECTOR const & a1, XMVECTOR const & b1, // segment 1
XMVECTOR const & a2, XMVECTOR const & b2, // segment 2
float & t1, // (s)
float & t2, // (t)
XMVECTOR & c1, // closest point to segment 1
XMVECTOR & c2) // closest point to segment 2
{
const float epsilon = 1.192092896e-7f;
XMVECTOR d1 = b1 - a1;
XMVECTOR d2 = b2 - a2;
XMVECTOR r = a1 - a2;
float l1 = XMVectorGetX(XMVector3Dot(d1, d1)); // squared length of segment 1 (a)
float l2 = XMVectorGetX(XMVector3Dot(d2, d2)); // squared length of segment 2 (e)
float d1r = XMVectorGetX(XMVector3Dot(d1, r)); // (c)
float d2r = XMVectorGetX(XMVector3Dot(d2, r)); // (f)
if (l1 <= epsilon && l2 <= epsilon) {
// both segments are points
t1 = 0.0f;
t2 = 0.0f;
c1 = a1;
c2 = a2;
return;
}
if (l1 <= epsilon) {
// segment 1 is a point
t1 = 0.0f;
t2 = clamp(d2r / l2, 0.0f, 1.0f);
} else if (l2 <= epsilon) {
// segment 2 is a point
t1 = clamp(-d1r / l1, 0.0, 1.0f);
t2 = 0.0f;
} else {
float b = XMVectorGetX(XMVector3Dot(d1, d2));
float denom = l1 * l2 - b * b;
if (denom != 0.0f) {
// segments are not parallel
t1 = clamp((b * d2r - d1r * l2) / denom, 0.0f, 1.0f);
} else {
t1 = 0.0f;
}
t2 = (b * t1 + d2r) / l2;
if (t2 < 0.0f) {
t2 = 0.0f;
t1 = clamp(-d1r / l1, 0.0f, 1.0f);
} else if (t2 > 1.0f) {
t2 = 1.0f;
t1 = clamp((b - d1r) / l1, 0.0f, 1.0f);
}
}
c1 = a1 + d1 * t1;
c2 = a2 + d2 * t2;
}
static inline bool intersect_capsule_capsule(Capsule const & capsule1, Capsule const & capsule2,
XMVECTOR & p1, XMVECTOR & p2)
{
float t1;
float t2;
XMVECTOR c1; // closest point in capsule1
XMVECTOR c2; // closest point in capsule2
closest_point_segment_segment(capsule1.a, capsule1.b,
capsule2.a, capsule2.b,
t1, t2,
c1, c2);
float distance2 = XMVectorGetX(XMVector3Dot(c1 - c2, c1 - c2));
float radius = capsule1.radius + capsule2.radius;
if (distance2 >= radius * radius)
return false;
float length = XMVectorGetX(XMVector3Length(c1 - c2));
XMVECTOR normal = XMVector3NormalizeEst(c2 - c1);
printf("length2 %f\n", capsule1.radius - length);
p1 = c1 + normal * capsule1.radius;
p2 = c2 + normal;
return true;
}
static const float interval_epsilon = 0.001f;
static inline bool intersect_moving_sphere_aabb(Sphere const & sphere, XMVECTOR const & direction,
float t0, float t1, AABB const & aabb,
float & t, XMVECTOR & point)
{
float mid = (t0 + t1) * 0.5f;
XMVECTOR center = sphere.center + direction * mid;
float radius = (mid - t0) * XMVectorGetX(XMVector3Length(direction)) + sphere.radius;
Sphere bound(center, radius);
if (!test_sphere_aabb(bound, aabb, point))
return false;
if (t1 - t0 < interval_epsilon) {
t = t0;
return true;
}
if (intersect_moving_sphere_aabb(sphere, direction, t0, mid, aabb, t, point))
return true;
return intersect_moving_sphere_aabb(sphere, direction, mid, t1, aabb, t, point);
}
static inline AABB moving_sphere_aabb(Sphere const & sphere, XMVECTOR const & direction)
{
XMVECTOR min = sphere.center + XMVectorReplicate(-sphere.radius);
XMVECTOR max = sphere.center + XMVectorReplicate( sphere.radius);
min = XMVectorMin(min, min + direction);
max = XMVectorMax(max, max + direction);
return AABB(min, max);
}
struct state {
float t;
bool intersected;
XMVECTOR intersection_point;
XMVECTOR intersection_position;
};
static inline void check_collision(collision::Sphere const & sphere, XMVECTOR const & direction,
XMVECTOR const & cube_center, float cube_half,
state & state)
{
collision::AABB aabb = collision::cube_aabb(cube_center, cube_half);
float t;
XMVECTOR intersection_point;
bool intersected = collision::intersect_moving_sphere_aabb(sphere, direction,
0, 1, aabb,
t, intersection_point);
XMVECTOR intersection_position = sphere.center + direction * t;
if (intersected && t < state.t) {
state.t = t;
state.intersected = true;
state.intersection_point = intersection_point;
state.intersection_position = intersection_position;
}
}
static inline XMVECTOR sphere_collision_response(Sphere const & sphere, XMVECTOR const & direction,
XMVECTOR const & intersection_point,
XMVECTOR const & intersection_position,
XMVECTOR & intersection_normal)
{
XMVECTOR origin = intersection_point;
XMVECTOR normal = XMVector3Normalize(intersection_position - intersection_point);
XMVECTOR destination = sphere.center + direction;
XMVECTOR distance = XMVector3Dot(destination, normal) - XMVector3Dot(normal, origin);
XMVECTOR new_destination = (destination - normal * distance) + normal * sphere.radius;
XMVECTOR new_direction = new_destination - intersection_position;
intersection_normal = normal;
return new_direction;
}
}

10
include/collision_scene.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
namespace collision_scene {
void load();
void draw();
void update(int up, int down, int left, int right,
int w, int s, int a, int d,
int t, int g, int f, int h,
int i, int k, int j, int l);
}

View File

@ -6,7 +6,10 @@ extern "C" {
void load(const char * source_path);
void draw();
void update_keyboard(int up, int down, int left, int right);
void update_keyboard(int up, int down, int left, int right,
int w, int s, int a, int d,
int t, int g, int f, int h,
int i, int k, int j, int l);
void update_mouse(int x, int y);
void update_joystick(int joystick_index,
float lx, float ly, float rx, float ry, float tl, float tr,

View File

@ -33,11 +33,13 @@ namespace view {
}
namespace third_person {
void apply_transform(float forward, float strafe, float elevation,
XMVECTOR apply_transform(float forward, float strafe, float elevation,
float delta_yaw, float delta_pitch);
}
void apply_fov(float delta);
void update_transforms();
void load();
const float at_distance = 10;
}

View File

@ -11,7 +11,10 @@ function init()
void load(const char * source_path);
void update_window(int width, int height);
void draw();
void update_keyboard(int kbup, int kbdown, int kbleft, int kbright);
void update_keyboard(int up, int down, int left, int right,
int w, int s, int a, int d,
int t, int g, int f, int h,
int i, int k, int j, int l);
void update_mouse(int x, int y);
void update_joystick(int joystick_index,
float lx, float ly, float rx, float ry, float tl, float tr,
@ -61,7 +64,22 @@ local update = function(time)
local down = love.keyboard.isDown("down")
local left = love.keyboard.isDown("left")
local right = love.keyboard.isDown("right")
test.update_keyboard(up, down, left, right);
local w = love.keyboard.isDown("w")
local s = love.keyboard.isDown("s")
local a = love.keyboard.isDown("a")
local d = love.keyboard.isDown("d")
local t = love.keyboard.isDown("t")
local g = love.keyboard.isDown("g")
local f = love.keyboard.isDown("f")
local h = love.keyboard.isDown("h")
local i = love.keyboard.isDown("i")
local k = love.keyboard.isDown("k")
local j = love.keyboard.isDown("j")
local l = love.keyboard.isDown("l")
test.update_keyboard(up, down, left, right,
w, s, a, d,
t, g, f, h,
i, k, j, l);
test.update(time)
end

269
minecraft/gen/icosphere.obj Normal file
View File

@ -0,0 +1,269 @@
# Blender 5.0.0
# www.blender.org
o Icosphere
v 0.000000 -1.000000 0.000000
v 0.723607 -0.447220 0.525725
v -0.276388 -0.447220 0.850649
v -0.894426 -0.447216 0.000000
v -0.276388 -0.447220 -0.850649
v 0.723607 -0.447220 -0.525725
v 0.276388 0.447220 0.850649
v -0.723607 0.447220 0.525725
v -0.723607 0.447220 -0.525725
v 0.276388 0.447220 -0.850649
v 0.894426 0.447216 0.000000
v 0.000000 1.000000 0.000000
v -0.162456 -0.850654 0.499995
v 0.425323 -0.850654 0.309011
v 0.262869 -0.525738 0.809012
v 0.850648 -0.525736 0.000000
v 0.425323 -0.850654 -0.309011
v -0.525730 -0.850652 0.000000
v -0.688189 -0.525736 0.499997
v -0.162456 -0.850654 -0.499995
v -0.688189 -0.525736 -0.499997
v 0.262869 -0.525738 -0.809012
v 0.951058 0.000000 0.309013
v 0.951058 0.000000 -0.309013
v 0.000000 0.000000 1.000000
v 0.587786 0.000000 0.809017
v -0.951058 0.000000 0.309013
v -0.587786 0.000000 0.809017
v -0.587786 0.000000 -0.809017
v -0.951058 0.000000 -0.309013
v 0.587786 0.000000 -0.809017
v 0.000000 0.000000 -1.000000
v 0.688189 0.525736 0.499997
v -0.262869 0.525738 0.809012
v -0.850648 0.525736 0.000000
v -0.262869 0.525738 -0.809012
v 0.688189 0.525736 -0.499997
v 0.162456 0.850654 0.499995
v 0.525730 0.850652 0.000000
v -0.425323 0.850654 0.309011
v -0.425323 0.850654 -0.309011
v 0.162456 0.850654 -0.499995
vn 0.1024 -0.9435 0.3151
vn 0.7002 -0.6617 0.2680
vn -0.2680 -0.9435 0.1947
vn -0.2680 -0.9435 -0.1947
vn 0.1024 -0.9435 -0.3151
vn 0.9050 -0.3304 0.2680
vn 0.0247 -0.3304 0.9435
vn -0.8897 -0.3304 0.3151
vn -0.5746 -0.3304 -0.7488
vn 0.5346 -0.3304 -0.7779
vn 0.8026 -0.1256 0.5831
vn -0.3066 -0.1256 0.9435
vn -0.9921 -0.1256 -0.0000
vn -0.3066 -0.1256 -0.9435
vn 0.8026 -0.1256 -0.5831
vn 0.4089 0.6617 0.6284
vn -0.4713 0.6617 0.5831
vn -0.7002 0.6617 -0.2680
vn 0.0385 0.6617 -0.7488
vn 0.7240 0.6617 -0.1947
vn 0.2680 0.9435 -0.1947
vn 0.4911 0.7947 -0.3568
vn 0.4089 0.6617 -0.6284
vn -0.1024 0.9435 -0.3151
vn -0.1876 0.7947 -0.5773
vn -0.4713 0.6617 -0.5831
vn -0.3313 0.9435 -0.0000
vn -0.6071 0.7947 -0.0000
vn -0.7002 0.6617 0.2680
vn -0.1024 0.9435 0.3151
vn -0.1876 0.7947 0.5773
vn 0.0385 0.6617 0.7488
vn 0.2680 0.9435 0.1947
vn 0.4911 0.7947 0.3568
vn 0.7240 0.6617 0.1947
vn 0.8897 0.3304 -0.3151
vn 0.7947 0.1876 -0.5773
vn 0.5746 0.3304 -0.7488
vn -0.0247 0.3304 -0.9435
vn -0.3035 0.1876 -0.9342
vn -0.5346 0.3304 -0.7779
vn -0.9050 0.3304 -0.2680
vn -0.9822 0.1876 -0.0000
vn -0.9050 0.3304 0.2680
vn -0.5346 0.3304 0.7779
vn -0.3035 0.1876 0.9342
vn -0.0247 0.3304 0.9435
vn 0.5746 0.3304 0.7488
vn 0.7947 0.1876 0.5773
vn 0.8897 0.3304 0.3151
vn 0.3066 0.1256 -0.9435
vn 0.3035 -0.1876 -0.9342
vn 0.0247 -0.3304 -0.9435
vn -0.8026 0.1256 -0.5831
vn -0.7947 -0.1876 -0.5773
vn -0.8897 -0.3304 -0.3151
vn -0.8026 0.1256 0.5831
vn -0.7947 -0.1876 0.5773
vn -0.5746 -0.3304 0.7488
vn 0.3066 0.1256 0.9435
vn 0.3035 -0.1876 0.9342
vn 0.5346 -0.3304 0.7779
vn 0.9921 0.1256 -0.0000
vn 0.9822 -0.1876 -0.0000
vn 0.9050 -0.3304 -0.2680
vn 0.4713 -0.6617 -0.5831
vn 0.1876 -0.7947 -0.5773
vn -0.0385 -0.6617 -0.7488
vn -0.4089 -0.6617 -0.6284
vn -0.4911 -0.7947 -0.3568
vn -0.7240 -0.6617 -0.1947
vn -0.7240 -0.6617 0.1947
vn -0.4911 -0.7947 0.3568
vn -0.4089 -0.6617 0.6284
vn 0.7002 -0.6617 -0.2680
vn 0.6071 -0.7947 -0.0000
vn 0.3313 -0.9435 -0.0000
vn -0.0385 -0.6617 0.7488
vn 0.1876 -0.7947 0.5773
vn 0.4713 -0.6617 0.5831
vt 0.181819 0.000000
vt 0.227273 0.078731
vt 0.136365 0.078731
vt 0.272728 0.157461
vt 0.318182 0.078731
vt 0.363637 0.157461
vt 0.909091 0.000000
vt 0.954545 0.078731
vt 0.863636 0.078731
vt 0.727273 0.000000
vt 0.772727 0.078731
vt 0.681818 0.078731
vt 0.545455 0.000000
vt 0.590909 0.078731
vt 0.500000 0.078731
vt 0.318182 0.236191
vt 0.090910 0.157461
vt 0.181819 0.157461
vt 0.136365 0.236191
vt 0.818182 0.157461
vt 0.909091 0.157461
vt 0.863636 0.236191
vt 0.636364 0.157461
vt 0.727273 0.157461
vt 0.681818 0.236191
vt 0.454546 0.157461
vt 0.545455 0.157461
vt 0.500000 0.236191
vt 0.227273 0.236191
vt 0.045455 0.236191
vt 0.772727 0.236191
vt 0.590909 0.236191
vt 0.409092 0.236191
vt 0.181819 0.314921
vt 0.272728 0.314921
vt 0.227273 0.393651
vt 0.000000 0.314921
vt 0.090910 0.314921
vt 0.045455 0.393651
vt 0.727273 0.314921
vt 0.818182 0.314921
vt 0.772727 0.393651
vt 0.545455 0.314921
vt 0.636364 0.314921
vt 0.590909 0.393651
vt 0.363637 0.314921
vt 0.454546 0.314921
vt 0.409092 0.393651
vt 0.500000 0.393651
vt 0.454546 0.472382
vt 0.681818 0.393651
vt 0.636364 0.472382
vt 0.863636 0.393651
vt 0.818182 0.472382
vt 0.909091 0.314921
vt 0.136365 0.393651
vt 0.090910 0.472382
vt 0.318182 0.393651
vt 0.272728 0.472382
vt 0.954545 0.236191
vt 1.000000 0.157461
vt 0.409092 0.078731
vt 0.363637 0.000000
s 0
f 1/1/1 14/2/1 13/3/1
f 2/4/2 14/5/2 16/6/2
f 1/7/3 13/8/3 18/9/3
f 1/10/4 18/11/4 20/12/4
f 1/13/5 20/14/5 17/15/5
f 2/4/6 16/6/6 23/16/6
f 3/17/7 15/18/7 25/19/7
f 4/20/8 19/21/8 27/22/8
f 5/23/9 21/24/9 29/25/9
f 6/26/10 22/27/10 31/28/10
f 2/4/11 23/16/11 26/29/11
f 3/17/12 25/19/12 28/30/12
f 4/20/13 27/22/13 30/31/13
f 5/23/14 29/25/14 32/32/14
f 6/26/15 31/28/15 24/33/15
f 7/34/16 33/35/16 38/36/16
f 8/37/17 34/38/17 40/39/17
f 9/40/18 35/41/18 41/42/18
f 10/43/19 36/44/19 42/45/19
f 11/46/20 37/47/20 39/48/20
f 39/48/21 42/49/21 12/50/21
f 39/48/22 37/47/22 42/49/22
f 37/47/23 10/43/23 42/49/23
f 42/45/24 41/51/24 12/52/24
f 42/45/25 36/44/25 41/51/25
f 36/44/26 9/40/26 41/51/26
f 41/42/27 40/53/27 12/54/27
f 41/42/28 35/41/28 40/53/28
f 35/41/29 8/55/29 40/53/29
f 40/39/30 38/56/30 12/57/30
f 40/39/31 34/38/31 38/56/31
f 34/38/32 7/34/32 38/56/32
f 38/36/33 39/58/33 12/59/33
f 38/36/34 33/35/34 39/58/34
f 33/35/35 11/46/35 39/58/35
f 24/33/36 37/47/36 11/46/36
f 24/33/37 31/28/37 37/47/37
f 31/28/38 10/43/38 37/47/38
f 32/32/39 36/44/39 10/43/39
f 32/32/40 29/25/40 36/44/40
f 29/25/41 9/40/41 36/44/41
f 30/31/42 35/41/42 9/40/42
f 30/31/43 27/22/43 35/41/43
f 27/22/44 8/55/44 35/41/44
f 28/30/45 34/38/45 8/37/45
f 28/30/46 25/19/46 34/38/46
f 25/19/47 7/34/47 34/38/47
f 26/29/48 33/35/48 7/34/48
f 26/29/49 23/16/49 33/35/49
f 23/16/50 11/46/50 33/35/50
f 31/28/51 32/32/51 10/43/51
f 31/28/52 22/27/52 32/32/52
f 22/27/53 5/23/53 32/32/53
f 29/25/54 30/31/54 9/40/54
f 29/25/55 21/24/55 30/31/55
f 21/24/56 4/20/56 30/31/56
f 27/22/57 28/60/57 8/55/57
f 27/22/58 19/21/58 28/60/58
f 19/21/59 3/61/59 28/60/59
f 25/19/60 26/29/60 7/34/60
f 25/19/61 15/18/61 26/29/61
f 15/18/62 2/4/62 26/29/62
f 23/16/63 24/33/63 11/46/63
f 23/16/64 16/6/64 24/33/64
f 16/6/65 6/26/65 24/33/65
f 17/15/66 22/27/66 6/26/66
f 17/15/67 20/14/67 22/27/67
f 20/14/68 5/23/68 22/27/68
f 20/12/69 21/24/69 5/23/69
f 20/12/70 18/11/70 21/24/70
f 18/11/71 4/20/71 21/24/71
f 18/9/72 19/21/72 4/20/72
f 18/9/73 13/8/73 19/21/73
f 13/8/74 3/61/74 19/21/74
f 16/6/75 17/62/75 6/26/75
f 16/6/76 14/5/76 17/62/76
f 14/5/77 1/63/77 17/62/77
f 13/3/78 15/18/78 3/17/78
f 13/3/79 14/2/79 15/18/79
f 14/2/80 2/4/80 15/18/80

View File

@ -5,7 +5,7 @@ def main():
index_buffer = []
index_lookup = {}
obj_write.write_obj(vertex_buffer, index_buffer, index_lookup, "rounded-rectangle.obj")
obj_write.write_obj(vertex_buffer, index_buffer, index_lookup, "icosphere.obj")
with open("../non_block.idx", "wb") as f:
obj_write.write_indices(f, "<H", index_buffer)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 600 B

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

View File

@ -0,0 +1,14 @@
#version 330 core
out vec4 Color;
flat in int InstanceID;
uniform vec3 BaseColor;
void main()
{
float intensity = (InstanceID == 0) ? 0.7 : 0.3;
Color = vec4(BaseColor * intensity, 1);
}

View File

@ -0,0 +1,39 @@
#version 330 core
// per-vertex
in vec2 Position;
flat out int InstanceID;
uniform mat4 Transform;
uniform bool UseGridTransform;
vec2 world_translation()
{
if (gl_InstanceID == 0)
return vec2(0, 0);
int instance = gl_InstanceID + 1;
float negative = ((instance % 2) == 0) ? -1.0 : 1.0;
vec2 translation = (Position.x == 0) ? vec2(1, 0) : vec2(0, 1);
return translation * negative * (instance >> 1);
}
vec2 grid_transform(vec2 position)
{
return position * 4 + world_translation();
}
void main()
{
InstanceID = gl_InstanceID;
vec2 position;
if (UseGridTransform)
position = grid_transform(Position);
else
position = Position;
gl_Position = Transform * vec4(position, 0, 1);
}

View File

@ -1,11 +0,0 @@
#include "directxmath/directxmath.h"
struct AABB {
XMVECTOR min;
XMVECTOR max;
};
XMVECTOR closest_point_point_aabb(XMVECTOR const &p, AABB const& aabb)
{
return XMVectorClamp(p, aabb.min, aabb.max);
}

481
src/collision_scene.cpp Normal file
View File

@ -0,0 +1,481 @@
#include "glad/gl.h"
#include "directxmath/directxmath.h"
#include "opengl.h"
#include "collision.h"
#include "collision_scene.h"
namespace collision_scene {
struct location {
struct {
unsigned int position;
} attrib;
struct {
unsigned int transform;
unsigned int use_grid_transform;
unsigned int base_color;
} uniform;
};
static unsigned int program;
static location location;
static unsigned int vertex_array_object;
static unsigned int per_vertex_buffer;
static unsigned int index_buffer;
static XMVECTOR point_position[4];
static unsigned int ray_vertex_buffer;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnarrowing"
const _Float16 vertex_data[] = {
// 0: lines
-1.0, 0.0, 1.0, 0.0, // horizontal, left to right
0.0, 1.0, 0.0, -1.0, // vertical, top to bottom
// 4: "cube"
-1.0, 1.0, // tl
1.0, 1.0, // tr
1.0, -1.0, // br
-1.0, -1.0, // bl
// 8: "circle"
0.000000, -1.000000,
-0.195090, -0.980785,
-0.382683, -0.923880,
-0.555570, -0.831470,
-0.707107, -0.707107,
-0.831470, -0.555570,
-0.923880, -0.382683,
-0.980785, -0.195090,
-1.000000, 0.000000,
-0.980785, 0.195090,
-0.923880, 0.382683,
-0.831470, 0.555570,
-0.707107, 0.707107,
-0.555570, 0.831470,
-0.382683, 0.923880,
-0.195090, 0.980785,
0.000000, 1.000000,
0.195090, 0.980785,
0.382683, 0.923880,
0.555570, 0.831470,
0.707107, 0.707107,
0.831470, 0.555570,
0.923880, 0.382683,
0.980785, 0.195090,
1.000000, 0.000000,
0.980785, -0.195090,
0.923880, -0.382683,
0.831470, -0.555570,
0.707107, -0.707107,
0.555570, -0.831470,
0.382683, -0.923880,
0.195090, -0.980785,
};
#pragma GCC diagnostic pop
const int vertex_data_size = (sizeof (vertex_data));
const int per_vertex_size = (sizeof (_Float16)) * 2;
const unsigned short index_data[] = {
// "cube" (line strip)
0, 1, 2, 3, 0,
// "circle" (line strip)
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
0,
};
const int index_data_size = (sizeof (index_data));
void load_program()
{
program = compile_from_files("shader/collision_scene.vert",
nullptr,
"shader/collision_scene.frag");
location.attrib.position = glGetAttribLocation(program, "Position");
location.uniform.transform = glGetUniformLocation(program, "Transform");
location.uniform.use_grid_transform = glGetUniformLocation(program, "UseGridTransform");
location.uniform.base_color = glGetUniformLocation(program, "BaseColor");
}
void load_vertex_attributes()
{
glGenVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
glVertexBindingDivisor(0, 0);
glEnableVertexAttribArray(location.attrib.position);
glVertexAttribFormat(location.attrib.position, 2, GL_HALF_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(location.attrib.position, 0);
glBindVertexArray(0);
}
void load_per_vertex_buffer()
{
glGenBuffers(1, &per_vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, per_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, vertex_data_size, vertex_data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void load_index_buffer()
{
glGenBuffers(1, &index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_data_size, index_data, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void load()
{
load_program();
load_vertex_attributes();
load_per_vertex_buffer();
load_index_buffer();
for (int i = 0; i < 4; i++)
point_position[i] = XMVectorSet(-1, -1, 0, 1);
// ray buffer
glGenBuffers(1, &ray_vertex_buffer);
}
void load_ray_vertex_buffer(XMVECTOR const & a, XMVECTOR const & b)
{
_Float16 data[] = {
(_Float16)XMVectorGetX(a), (_Float16)XMVectorGetY(a),
(_Float16)XMVectorGetX(b), (_Float16)XMVectorGetY(b),
};
glBindBuffer(GL_ARRAY_BUFFER, ray_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, 2 * 4, data, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
static inline XMMATRIX view()
{
XMVECTOR eye = XMVectorSet(0, 0, 1, 0);
XMVECTOR at = XMVectorSet(0, 0, 0, 0);
XMVECTOR up = XMVectorSet(0, 1, 0, 0);
return XMMatrixLookAtRH(eye, at, up);
}
static inline XMMATRIX projection()
{
return XMMatrixOrthographicRH(10, 10, 0, 10);
}
const float point_radius = 0.05f;
void update(int up, int down, int left, int right,
int w, int s, int a, int d,
int t, int g, int f, int h,
int i, int k, int j, int l)
{
float rate = 0.05f;
float forward[4];
float strafe[4];
forward[0] = (rate * up + -rate * down);
strafe[0] = (-rate * left + rate * right);
forward[1] = (rate * w + -rate * s);
strafe[1] = (-rate * a + rate * d);
forward[2] = (rate * t + -rate * g);
strafe[2] = (-rate * f + rate * h);
forward[3] = (rate * i + -rate * k);
strafe[3] = (-rate * j + rate * l);
for (int i = 0; i < 4; i++)
point_position[i] = XMVector3Transform(point_position[i], XMMatrixTranslation(strafe[i], forward[i], 0));
}
static inline void set_transform(XMMATRIX const & transform)
{
XMFLOAT4X4 float_transform;
XMStoreFloat4x4(&float_transform, transform);
glUniformMatrix4fv(location.uniform.transform, 1, false, (float *)&float_transform);
}
const int circle_base_vertex = 8;
const int circle_base_index = 5 * (sizeof (unsigned short));
void draw_line(XMMATRIX const & transform, XMVECTOR const & a, XMVECTOR const & b)
{
load_ray_vertex_buffer(a, b);
set_transform(transform);
glBindVertexBuffer(0, ray_vertex_buffer, 0, per_vertex_size);
glDrawArrays(GL_LINES, 0, 4);
}
void draw_sphere(XMMATRIX const & transform, XMVECTOR const & center, float radius)
{
XMMATRIX sphere_transform
= XMMatrixScaling(radius, radius, radius)
* XMMatrixTranslationFromVector(center)
* transform;
set_transform(sphere_transform);
glBindVertexBuffer(0, per_vertex_buffer, 0, per_vertex_size);
glDrawElementsBaseVertex(GL_LINE_STRIP, 33, GL_UNSIGNED_SHORT, (void*)(circle_base_index), circle_base_vertex);
}
void draw_capsule(XMMATRIX const & transform, XMVECTOR a, XMVECTOR b, float radius)
{
draw_sphere(transform, a, radius);
draw_sphere(transform, b, radius);
XMVECTOR abn = XMVector3Normalize(a - b);
XMVECTOR p = XMVectorSet(0, 0, 1, 0);
XMVECTOR pxabn = XMVector3Cross(abn, p);
draw_line(transform, a + pxabn * radius, b + pxabn * radius);
draw_line(transform, a - pxabn * radius, b - pxabn * radius);
}
void draw_cube(XMMATRIX const & transform, XMVECTOR const & position)
{
float cube_half = 0.5;
XMMATRIX cube_transform
= XMMatrixScaling(cube_half, cube_half, cube_half)
* XMMatrixTranslationFromVector(position)
* transform;
set_transform(cube_transform);
const int cube_base_vertex = 4;
const int cube_base_index = 0;
glDrawElementsBaseVertex(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, (void*)(cube_base_index), cube_base_vertex);
}
static const XMVECTOR cubes[] = {
XMVectorSet(1, 1, 0, 1),
XMVectorSet(-1, 1, 0, 1),
XMVectorSet(-2, 1, 0, 1),
XMVectorSet(-2, -2, 0, 1),
XMVectorSet(-2, -3, 0, 1),
};
static const int cubes_length = (sizeof (cubes)) / (sizeof (cubes[0]));
void check_collisions(collision::Sphere const & sphere, XMVECTOR const & direction,
collision::state & state)
{
state.t = FLT_MAX;
state.intersected = false;
collision::AABB sphere_aabb = collision::moving_sphere_aabb(sphere, direction);
XMVECTOR min_floor = XMVectorFloor(sphere_aabb.min);
XMVECTOR max_ceiling = XMVectorCeiling(sphere_aabb.max);
for (int i = 0; i < cubes_length; i++) {
XMVECTOR cube_center = cubes[i];
// coarse filter
XMVECTOR le = XMVectorLessOrEqual(min_floor, cube_center);
XMVECTOR ge = XMVectorGreaterOrEqual(max_ceiling, cube_center);
if (XMVectorGetX(le) == 0 || XMVectorGetY(le) == 0 || XMVectorGetZ(le) == 0 ||
XMVectorGetX(ge) == 0 || XMVectorGetY(ge) == 0 || XMVectorGetZ(ge) == 0) {
continue;
}
float cube_half = 0.5;
collision::check_collision(sphere, direction, cube_center, cube_half, state);
}
}
void draw()
{
glUseProgram(program);
glBlendFunc(GL_ONE, GL_ZERO);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glBindVertexArray(vertex_array_object);
glBindVertexBuffer(0, per_vertex_buffer, 0, per_vertex_size);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
XMMATRIX transform = view() * projection();
// grid
glLineWidth(1.0f);
set_transform(transform);
glUniform3f(location.uniform.base_color, 0, 1, 0);
glUniform1i(location.uniform.use_grid_transform, 1);
glDrawArraysInstanced(GL_LINES, 0, 4, 7);
glUniform1i(location.uniform.use_grid_transform, 0);
collision::Sphere sphere(point_position[0], 0.48);
XMVECTOR direction = point_position[1] - point_position[0];
//////////////////////////////////////////////////////////////////////
// reset intersections
//////////////////////////////////////////////////////////////////////
glLineWidth(3.0f);
for (int i = 0; i < cubes_length; i++) {
XMVECTOR center = cubes[i];
draw_cube(transform, center);
}
//////////////////////////////////////////////////////////////////////
// collision response
//////////////////////////////////////////////////////////////////////
glUniform3f(location.uniform.base_color, 0, 0.0, 1.0);
draw_sphere(transform, sphere.center, sphere.radius);
glUniform3f(location.uniform.base_color, 0, 0.5, 1.0);
draw_sphere(transform, sphere.center + direction, point_radius);
draw_line(transform, sphere.center, sphere.center + direction);
int intersections = 0;
while (intersections < 10) {
collision::state state;
check_collisions(sphere, direction, state);
if (!state.intersected)
break;
XMVECTOR intersection_normal;
XMVECTOR new_direction = collision::sphere_collision_response(sphere, direction,
state.intersection_point,
state.intersection_position,
intersection_normal);
glUniform3f(location.uniform.base_color, 1.0, 0.5, 1.0);
draw_line(transform, state.intersection_position, state.intersection_position + new_direction);
glUniform3f(location.uniform.base_color, 1.0, 0.5, 0.0);
draw_sphere(transform, state.intersection_position, sphere.radius);
glUniform3f(location.uniform.base_color, 1.0, 0.0, 0.0);
draw_sphere(transform, state.intersection_point, point_radius);
// collide again
sphere.center = state.intersection_position;
direction = new_direction;
printf("intersection %d\n", intersections);
intersections += 1;
}
if (intersections == 10) {
//direction == XMVectorZero();
} else {
glUniform3f(location.uniform.base_color, 1.0, 1.0, 0.0);
draw_sphere(transform, sphere.center + direction, sphere.radius);
}
/*
XMVECTOR pa = XMVectorSelect(sphere_aabb.min, sphere_aabb.max, g_XMSelect1000);
XMVECTOR pb = XMVectorSelect(sphere_aabb.min, sphere_aabb.max, g_XMSelect0101);
draw_line(transform, sphere_aabb.min, pa);
draw_line(transform, pa, sphere_aabb.max);
draw_line(transform, sphere_aabb.max, pb);
draw_line(transform, pb, sphere_aabb.min);
*/
//sphere_aabb.max,
/*
// segments
glUniform3f(location.uniform.base_color, 0, 0.5, 1.0);
draw_line(transform, point_position[0], point_position[1]);
glUniform3f(location.uniform.base_color, 0, 1.0, 0.5);
draw_line(transform, point_position[2], point_position[3]);
// points
glUniform3f(location.uniform.base_color, 0, 0.5, 1.0);
draw_sphere(transform, point_position[0], point_radius);
draw_sphere(transform, point_position[1], point_radius);
glUniform3f(location.uniform.base_color, 0, 1.0, 0.5);
draw_sphere(transform, point_position[2], point_radius);
draw_sphere(transform, point_position[3], point_radius);
float t1, t2;
XMVECTOR c1, c2;
collision::closest_point_segment_segment(point_position[0], point_position[1],
point_position[2], point_position[3],
t1, t2, c1, c2);
glUniform3f(location.uniform.base_color, 0.0, 0.5, 1.0);
draw_sphere(transform, c1, point_radius);
glUniform3f(location.uniform.base_color, 0.0, 1.0, 0.5);
draw_sphere(transform, c2, point_radius);
collision::Capsule capsule1(point_position[0], point_position[1], 0.5);
collision::Capsule capsule2(point_position[2], point_position[3], 0.0);
glUniform3f(location.uniform.base_color, 0, 0.5, 1.0);
draw_capsule(transform, capsule1.a, capsule1.b, capsule1.radius);
glUniform3f(location.uniform.base_color, 0, 1.0, 0.5);
//draw_capsule(transform, capsule2.a, capsule2.b, capsule2.radius);
XMVECTOR c1_point;
XMVECTOR c2_point;
bool collided = collision::intersect_capsule_capsule(capsule1, capsule2, c1_point, c2_point);
if (collided) {
glUniform3f(location.uniform.base_color, 1.0, 0.0, 0.0);
draw_sphere(transform, c1_point, point_radius);
glUniform3f(location.uniform.base_color, 1.0, 0.5, 0.0);
draw_sphere(transform, c2_point, point_radius);
}
*/
// cube
/*
float cube_half = 0.5;
XMVECTOR cube_position = XMVectorSet(1, 0, 0, 0);
XMMATRIX cube_transform
= XMMatrixScaling(cube_half, cube_half, cube_half)
* XMMatrixTranslationFromVector(cube_position)
* transform;
set_transform(cube_transform);
glUniform3f(location.uniform.base_color, 0, 0.5, 1.0);
glUniform1i(location.uniform.use_grid_transform, 0);
const int cube_base_vertex = 4;
const int cube_base_index = 0;
glDrawElementsBaseVertex(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, (void*)(cube_base_index), cube_base_vertex);
// circle
glUniform3f(location.uniform.base_color, 1.0, 0.5, 0.0);
draw_sphere(transform, point_position, point_radius);
draw_sphere(transform, point_1_position, point_radius);
XMVECTOR direction = XMVector3Normalize(point_1_position - point_position);
collision::AABB cube_aabb = collision::cube_aabb(cube_position, cube_half);
XMVECTOR intersection_point;
float t;
bool intersection = intersect_ray_aabb(point_position, direction, cube_aabb, t, intersection_point);
if (intersection && t > 0.0f) {
glUniform3f(location.uniform.base_color, 0.9, 0.0, 0.0);
draw_line(transform, point_position, intersection_point);
draw_sphere(transform, intersection_point, point_radius);
} else {
glUniform3f(location.uniform.base_color, 0.5, 0.5, 0.5);
draw_line(transform, point_position, point_position + direction * 20.0f);
}
glUniform3f(location.uniform.base_color, 0.5, 0.0, 0.5);
XMVECTOR ca = XMVectorSet(1, 2.5, 0, 0);
XMVECTOR cb = XMVectorSet(-1, 2, 0, 0);
draw_capsule(transform, ca, cb, 0.5);
*/
}
}

View File

@ -127,7 +127,8 @@ namespace non_block {
glBindVertexBuffer(0, per_vertex_buffer, 0, per_vertex_size);
void const * indices = (void *)(0);
int element_count = 300;
// element_count from vertex_buffer_non_block.py stdout
int element_count = 240;
glDrawElements(GL_TRIANGLES, element_count, GL_UNSIGNED_SHORT, indices);
}
}

View File

@ -17,6 +17,8 @@
#include "minecraft.h"
#include "hud.h"
#include "lighting.h"
#include "collision_scene.h"
#include "collision.h"
struct line_location {
struct {
@ -278,13 +280,62 @@ void load(const char * source_path)
non_block::load_index_buffer();
non_block::load_per_vertex_buffer();
non_block::load_vertex_attributes();
//////////////////////////////////////////////////////////////////////
// collision_scene
//////////////////////////////////////////////////////////////////////
collision_scene::load();
}
void update_keyboard(int up, int down, int left, int right)
void update_keyboard(int up, int down, int left, int right,
int w, int s, int a, int d,
int t, int g, int f, int h,
int i, int k, int j, int l)
{
//float forward = (0.1f * up + -0.1f * down);
//float strafe = (-0.1f * left + 0.1f * right);
//view::third_person::apply_translation(forward, strafe, 0);
collision_scene::update(up, down, left, right,
w, s, a, d,
t, g, f, h,
i, k, j, l);
}
void check_collisions(collision::Sphere const & sphere, XMVECTOR const & direction,
collision::state & state)
{
state.t = FLT_MAX;
state.intersected = false;
collision::AABB sphere_aabb = collision::moving_sphere_aabb(sphere, direction);
XMVECTOR min_floor = XMVectorFloor(sphere_aabb.min);
XMVECTOR max_ceiling = XMVectorCeiling(sphere_aabb.max);
int min_x = XMVectorGetX(min_floor);
int min_y = XMVectorGetZ(min_floor); // swizzle
int min_z = XMVectorGetY(min_floor); // swizzle
int max_x = XMVectorGetX(max_ceiling);
int max_y = XMVectorGetZ(max_ceiling); // swizzle
int max_z = XMVectorGetY(max_ceiling); // swizzle
for (int x = min_x; x <= max_x; x++) {
for (int y = min_y; y <= max_y; y++) {
for (int z = min_z; z <= max_z; z++) {
global_entry * const entry = world_lookup(x, y, z);
if (entry == NULL)
continue;
// there is a block at x, y, z
XMVECTOR cube_center = XMVectorSet(x, z, y, 1); // swizzle
float cube_half = 0.5f;
collision::check_collision(sphere, direction,
cube_center, cube_half,
state);
}
}
}
}
const int max_joysticks = 8;
@ -301,10 +352,45 @@ void update_joystick(int joystick_index,
float elevation = (tl - tr) * 0.5;
float delta_yaw = rx * -0.035;
float delta_pitch = ry * -0.035;
view::third_person::apply_transform(forward, strafe, elevation,
XMVECTOR direction = view::third_person::apply_transform(forward, strafe, elevation,
delta_yaw, delta_pitch);
view::apply_fov(0.01 * up + -0.01 * down);
XMVECTOR sphere_position = view::state.at;
float sphere_radius = 0.48;
collision::Sphere sphere(sphere_position, sphere_radius);
int intersections = 0;
collision::state state;
while (intersections < 500) {
check_collisions(sphere, direction, state);
if (!state.intersected)
break;
XMVECTOR intersection_normal;
XMVECTOR new_direction = collision::sphere_collision_response(sphere, direction,
state.intersection_point,
state.intersection_position,
intersection_normal);
// collide again
sphere.center = state.intersection_position + intersection_normal * 0.01f;
direction = new_direction * 0.9f;
if (XMVectorGetX(XMVector3Length(direction)) < 0.001f) {
direction = XMVectorZero();
break;
}
intersections += 1;
}
if (intersections == 500) { // too many recursive collisions
printf("too many recursive collisions\n");
} else {
// apply the last direction impulse
view::state.at = sphere.center + direction;
}
view::state.eye = view::state.at - view::state.direction * view::at_distance;
/*
lighting.quadratic += 0.01 * a + -0.01 * b;
if (lighting.quadratic < 0.0f)
@ -469,5 +555,11 @@ void draw()
//draw_quad();
hud::draw();
/*
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
collision_scene::draw();
*/
last_frame_time = current_time;
}

View File

@ -8,8 +8,6 @@ constexpr bool third_person = false;
namespace view {
view_state state = {};
const float at_distance = 10;
static inline XMMATRIX current_projection()
{
float fov_angle_y = XMConvertToRadians(45 * state.fov);
@ -61,7 +59,7 @@ namespace view {
}
namespace third_person {
void apply_transform(float forward, float strafe, float elevation,
XMVECTOR apply_transform(float forward, float strafe, float elevation,
float delta_yaw, float delta_pitch)
{
state.pitch = clamp_pitch(delta_pitch);
@ -70,8 +68,11 @@ namespace view {
state.normal = get_normal(); // on forward change
state.direction = get_direction(); // on forward/normal/pitch change
/*
state.at += state.forward * forward + state.normal * strafe + state.up * elevation;
state.eye = state.at - state.direction * at_distance;
*/
return state.forward * forward + state.normal * strafe + state.up * elevation;
}
}
@ -96,14 +97,14 @@ namespace view {
state.up = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
state.fov = 1.5;
state.pitch = 0;
state.pitch = -0.7;
state.forward = XMVector3Normalize(XMVectorSet(-0.63, 0.78, 0, 0));
state.forward = XMVector3Normalize(XMVectorSet(-0.64, 0.77, 0, 0));
state.normal = get_normal(); // on forward change
state.direction = get_direction(); // on forward/normal/pitch change
// position
state.eye = XMVectorSet(-55.5f, 48.25f, 50.0f, 1);
state.eye = XMVectorSet(-45.5f, 43.25f, 63.0f, 1);
state.at = state.eye + state.direction * at_distance;
}
}