Compare commits

...

32 Commits

Author SHA1 Message Date
mid
b32671567e Switch to strncasecmp
All checks were successful
k4 Build Test / do_the_build (push) Successful in 52s
2025-07-13 10:15:02 +03:00
mid
f4cf597a95 _DEFAULT_SOURCE and _GNU_SOURCE
Some checks failed
k4 Build Test / do_the_build (push) Failing after 30s
2025-07-13 09:57:52 +03:00
mid
5f2e84d8cf Support LOOPPOINT metadata field for ogg files
Some checks failed
k4 Build Test / do_the_build (push) Failing after 30s
2025-07-12 23:27:33 +03:00
mid
7754e410fd EVEN MORE STABLIER
All checks were successful
k4 Build Test / do_the_build (push) Successful in 56s
2025-07-05 14:06:07 +03:00
mid
5a3a524cb3 add libgomp
All checks were successful
k4 Build Test / do_the_build (push) Successful in 50s
2025-07-05 11:26:59 +03:00
mid
55b8e827c2 Strip
All checks were successful
k4 Build Test / do_the_build (push) Successful in 50s
2025-07-05 10:39:43 +03:00
mid
368664d246 Bug fixes
All checks were successful
k4 Build Test / do_the_build (push) Successful in 56s
2025-06-29 22:22:13 +03:00
mid
90f0e2dd42 Physics stability 2025-06-29 20:47:24 +03:00
mid
355df2ee44 Extend network traversal to local addresses 2025-06-29 20:47:14 +03:00
mid
e126db573a Change top-level dir name
All checks were successful
k4 Build Test / do_the_build (push) Successful in 58s
2025-06-28 14:01:32 +03:00
mid
ceb8ccb7d4 README.md 2025-06-28 13:20:38 +03:00
mid
e81750300d Abstract shader parameters (to make them modifiable later) 2025-06-28 13:18:58 +03:00
mid
446ff24fcf Make time per-scene 2025-06-28 13:18:24 +03:00
mid
309af8f59e stopsmooth 2025-06-28 13:17:58 +03:00
mid
7b6ce73fa5 Improve ray-based character controller 2025-06-28 13:17:20 +03:00
mid
ce465ef449 Fix ray origin 2025-06-12 12:00:16 +03:00
mid
9478bca2ad Raycasting character controller 2025-06-11 10:14:56 +03:00
mid
da59158fd1 fix 2?
All checks were successful
k4 Build Test / do_the_build (push) Successful in 53s
2025-05-11 16:22:45 +03:00
mid
ff2924a0b7 fix?
Some checks failed
k4 Build Test / do_the_build (push) Failing after 4s
2025-05-11 16:21:05 +03:00
mid
24ddb047aa Updated runner to Debian 12
All checks were successful
k4 Build Test / do_the_build (push) Successful in 1m3s
2025-05-11 15:32:58 +03:00
mid
0ba2cdee1c Remove __in6_u usage
Some checks failed
k4 Build Test / do_the_build (push) Failing after 59s
2025-05-11 15:26:25 +03:00
mid
ae4a62f584 fix k3 submodule
Some checks failed
k4 Build Test / do_the_build (push) Failing after 26s
2025-05-11 11:41:17 +03:00
mid
e43391caa3 update workflow
Some checks failed
k4 Build Test / do_the_build (push) Failing after 6s
2025-05-10 19:20:19 +03:00
mid
eb17923448 Add noise1234 source 2025-05-10 19:19:32 +03:00
mid
9cd4aee87a bugfix 2025-05-10 19:19:13 +03:00
mid
310889bd2c things 2025-05-10 19:18:58 +03:00
mid
0629b042ad Many API additions 2 2025-05-10 19:18:09 +03:00
mid
3c780c7290 Clamping texture sizes 2025-05-10 19:17:23 +03:00
mid
943a8cd1d9 Do not tanh the final audio 2025-05-10 19:16:59 +03:00
mid
2c1ee84791 Update GLAD file 2025-05-10 19:16:45 +03:00
mid
8990e415d3 Many API additions 2025-05-10 19:16:20 +03:00
mid
85d5f4f019 Makefile changes 2025-05-10 19:13:01 +03:00
23 changed files with 1726 additions and 411 deletions

View File

@@ -13,12 +13,13 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
submodules: 'true' submodules: 'true'
- run: mkdir build build/k3 bin bin/assets - run: mkdir build build/k3 build/k3/compr bin bin/assets
- run: CC="i686-w64-mingw32-gcc" CFLAGS="-I/usr/i686-w64-mingw32/include -I/usr/i686-w64-mingw32/include/lua5.3 -L/usr/i686-w64-mingw32/lib -Wno-error" make -B - run: CC="i686-w64-mingw32-gcc" CFLAGS="-I/usr/i686-w64-mingw32/include -I/usr/i686-w64-mingw32/include/lua5.3 -L/usr/i686-w64-mingw32/lib -Wno-error" make -B
- run: CC="i686-linux-gnu-gcc" CFLAGS="-I/usr/i686-linux-gnu/include -I/usr/i686-linux-gnu/include/lua5.3 -L/usr/i686-linux-gnu/lib -Wno-error" make -B - run: CC="i686-linux-gnu-gcc" CFLAGS="-I/usr/i686-linux-gnu/include -I/usr/i686-linux-gnu/include/lua5.3 -L/usr/i686-linux-gnu/lib -Wno-error -include /home/git/force_link_glibc_2.20.h" make -B
- run: cp /usr/lib/gcc/i686-w64-mingw32/10-win32/libgcc_s_dw2-1.dll /usr/lib/gcc/i686-w64-mingw32/10-win32/libstdc++-6.dll /usr/i686-w64-mingw32/lib/libportaudio-2.dll /usr/i686-w64-mingw32/lib/libwinpthread-1.dll bin/ - run: cp /usr/lib/gcc/i686-w64-mingw32/12-win32/libgcc_s_dw2-1.dll /usr/lib/gcc/i686-w64-mingw32/12-win32/libstdc++-6.dll /usr/i686-w64-mingw32/lib/libportaudio-2.dll /usr/i686-w64-mingw32/lib/libwinpthread-1.dll /usr/lib/gcc/i686-w64-mingw32/12-win32/libgomp-1.dll bin/
- run: cp -r /home/git/k4templateassets/* bin/assets/ - run: cp -r /home/git/k4templateassets/* bin/assets/
- run: zip -9r "k4${{ github.ref_name }}.zip" bin/ - run: mv bin k4
- run: zip -9r "k4${{ github.ref_name }}.zip" k4/
- name: Create package - name: Create package
uses: akkuman/gitea-release-action@v1 uses: akkuman/gitea-release-action@v1
with: with:

View File

@@ -1,24 +1,26 @@
k4_SRCS := $(wildcard src/*.c) rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))
k4_HDRS := $(wildcard src/*.h)
k4_SRCS := $(call rwildcard,src,*.c)
k4_HDRS := $(call rwildcard,src,*.h)
k4_OBJS := $(patsubst src/%.c, build/%.o, $(k4_SRCS)) k4_OBJS := $(patsubst src/%.c, build/%.o, $(k4_SRCS))
k4_DEPS := $(patsubst src/%.c, build/%.d, $(k4_SRCS)) k4_DEPS := $(patsubst src/%.c, build/%.d, $(k4_SRCS))
k3_SRCS = $(wildcard k3/src/*.c) k3_SRCS := $(call rwildcard,k3/src,*.c)
k3_HDRS = $(wildcard k3/src/*.h) k3_HDRS := $(call rwildcard,k3/src,*.h)
k3_OBJS := $(patsubst k3/src/%.c, build/k3/%.o, $(k3_SRCS)) k3_OBJS := $(patsubst k3/src/%.c, build/k3/%.o, $(k3_SRCS))
k3_DEPS := $(patsubst k3/src/%.c, build/k3/%.d, $(k3_SRCS)) k3_DEPS := $(patsubst k3/src/%.c, build/k3/%.d, $(k3_SRCS))
CFLAGS := $(CFLAGS) -Ik3/src CFLAGS := $(CFLAGS) -D_GNU_SOURCE -D_DEFAULT_SOURCE -Ik3/src -O2 -fopenmp -flto -s
ifneq (,$(findstring mingw,$(CC))) ifneq (,$(findstring mingw,$(CC)))
CFLAGS := -static-libgcc -static-libstdc++ -std=gnu99 -march=pentium4 -D_WIN32_WINNT=0x600 -DENET_FEATURE_ADDRESS_MAPPING -fno-pic -no-pie -fms-extensions -fno-pie -O0 -g -gdwarf-2 -Isrc $(CFLAGS) CFLAGS := -static-libgcc -static-libstdc++ -std=gnu99 -march=pentium4 -D_WIN32_WINNT=0x600 -DENET_FEATURE_ADDRESS_MAPPING -fno-pic -no-pie -fms-extensions -fno-pie -Isrc $(CFLAGS)
LIBS := -l:libglfw3.a -lopengl32 -pthread -lm -l:libode.a -l:libvorbisfile.a -l:libvorbis.a -l:libogg.a -lportaudio -lgdi32 -lws2_32 -lwinmm -lstdc++ -lole32 -lsetupapi -lhid -l:liblua5.3.a $(LIBS) LIBS := -l:libglfw3.a -lopengl32 -pthread -lm -l:libode.a -l:libvorbisfile.a -l:libvorbis.a -l:libogg.a -lportaudio -lgdi32 -lws2_32 -lwinmm -lstdc++ -lole32 -lsetupapi -lhid -l:liblua5.3.a -liphlpapi $(LIBS)
else else
CFLAGS := -march=opteron $(SAN) -std=gnu99 -DENET_FEATURE_ADDRESS_MAPPING -fms-extensions -fno-pic -no-pie -fno-pie -O0 -g -Isrc $(CFLAGS) CFLAGS := -march=opteron $(SAN) -std=gnu99 -DENET_FEATURE_ADDRESS_MAPPING -fms-extensions -fno-pic -no-pie -fno-pie -Isrc $(CFLAGS)
LIBS := -lglfw3 -pthread -ldl -lm -lode -lstdc++ -llua5.3 -lvorbis -lvorbisfile -lportaudio $(LIBS) LIBS := -lglfw3 -pthread -ldl -lm -lode -lstdc++ -llua5.3 -lvorbis -lvorbisfile -lportaudio $(LIBS)
endif endif
CFLAGS := $(CFLAGS) -DLOCALHOST_ONLY -Dk3_IRREGULAR_SHADOWS CFLAGS := $(CFLAGS) -DLOCALHOST_ONLY
build/k3/%.o: k3/src/%.c build/k3/%.o: k3/src/%.c
$(CC) $(CFLAGS) -MMD -o $@ -c $< $(CC) $(CFLAGS) -MMD -o $@ -c $<

1
README.md Normal file
View File

@@ -0,0 +1 @@
Homepage: https://mid.net.ua/k4.html

View File

@@ -216,7 +216,7 @@ for input_filename in sys.argv[1:]:
k3result["meshes"].append(mehs) k3result["meshes"].append(mehs)
if len(skin.joints) > 255: if skin and len(skin.joints) > 255:
err("Bone maximum is 255") err("Bone maximum is 255")
err_barrier() err_barrier()

1
k3 Submodule

Submodule k3 added at 4d74b5e3e9

View File

@@ -5,6 +5,8 @@
#include"resman.h" #include"resman.h"
#include<cglm/vec3.h> #include<cglm/vec3.h>
#define SUBFEET(cp) (cp->capsule.radius)
struct Game Game; struct Game Game;
void game_init() { void game_init() {
@@ -29,8 +31,8 @@ void game_init() {
} }
struct CollisionPair { struct CollisionPair {
dGeomID g1; // greater uint16_t e1; // greater
dGeomID g2; // lesser uint16_t e2; // lesser
uint8_t x; uint8_t x;
} __attribute__((packed)); } __attribute__((packed));
static size_t activeCollisionCount, activeCollisionCapacity; static size_t activeCollisionCount, activeCollisionCapacity;
@@ -38,22 +40,22 @@ static struct CollisionPair *activeCollisions;
int pair_comparator(const void *a_, const void *b_) { int pair_comparator(const void *a_, const void *b_) {
const struct CollisionPair *a = a_; const struct CollisionPair *a = a_;
const struct CollisionPair *b = b_; const struct CollisionPair *b = b_;
if(a->g1 == b->g1) { if(a->e1 == b->e1) {
return (uintptr_t) a->g2 - (uintptr_t) b->g2; return (intmax_t) a->e2 - (intmax_t) b->e2;
} else { } else {
return (uintptr_t) a->g1 - (uintptr_t) b->g1; return (intmax_t) a->e1 - (intmax_t) b->e1;
} }
} }
static int activate_pair(dGeomID g1, dGeomID g2) { static int activate_pair(uint16_t e1, uint16_t e2) {
struct CollisionPair p = { struct CollisionPair p = {
.g1 = g1 > g2 ? g1 : g2, .e1 = e1 > e2 ? e1 : e2,
.g2 = g1 > g2 ? g2 : g1, .e2 = e1 > e2 ? e2 : e1,
}; };
struct CollisionPair *peepee = bsearch(&p, activeCollisions, activeCollisionCount, sizeof(struct CollisionPair), pair_comparator); struct CollisionPair *peepee = bsearch(&p, activeCollisions, activeCollisionCount, sizeof(struct CollisionPair), pair_comparator);
if(peepee) { if(peepee) {
peepee->x++; peepee->x = 2;
return TRIGGER_EV_CONTINUOUS; return TRIGGER_EV_CONTINUOUS;
} }
@@ -72,8 +74,8 @@ static int activate_pair(dGeomID g1, dGeomID g2) {
static void tick_pairs() { static void tick_pairs() {
for(size_t i = 0; i < activeCollisionCount;) { for(size_t i = 0; i < activeCollisionCount;) {
if(--activeCollisions[i].x == 0) { if(--activeCollisions[i].x == 0) {
uint16_t e1 = (uintptr_t) dGeomGetData(activeCollisions[i].g1); uint16_t e1 = activeCollisions[i].e1;
uint16_t e2 = (uintptr_t) dGeomGetData(activeCollisions[i].g2); uint16_t e2 = activeCollisions[i].e2;
if(e1 != ENT_ID_INVALID) { if(e1 != ENT_ID_INVALID) {
struct CPhysics *p1 = game_getcomponent(e1, physics); struct CPhysics *p1 = game_getcomponent(e1, physics);
@@ -97,10 +99,21 @@ static void tick_pairs() {
} }
} }
static void vec3_project_to_plane(vec3 v, vec3 n, vec3 ret) {
float scale = glm_vec3_dot(v, n) / glm_vec3_dot(n, n);
vec3 n2;
glm_vec3_scale(n, scale, n2);
glm_vec3_sub(v, n2, ret);
}
static void contact_callback(void *data, dGeomID g1, dGeomID g2) { static void contact_callback(void *data, dGeomID g1, dGeomID g2) {
uint16_t e1 = (uintptr_t) dGeomGetData(g1); uint16_t e1 = (uintptr_t) dGeomGetData(g1);
uint16_t e2 = (uintptr_t) dGeomGetData(g2); uint16_t e2 = (uintptr_t) dGeomGetData(g2);
if(e1 != ENT_ID_INVALID && e1 == e2) return;
dBodyID b1 = dGeomGetBody(g1); dBodyID b1 = dGeomGetBody(g1);
dBodyID b2 = dGeomGetBody(g2); dBodyID b2 = dGeomGetBody(g2);
@@ -124,8 +137,6 @@ static void contact_callback(void *data, dGeomID g1, dGeomID g2) {
if(movingPlatform) { if(movingPlatform) {
const dReal *platvel = dBodyGetLinearVel(movingPlatform == 1 ? b1 : b2); const dReal *platvel = dBodyGetLinearVel(movingPlatform == 1 ? b1 : b2);
//if(i == 0)printf("get %f %f %f\n", platvel[0], platvel[1], platvel[2]);
contact[i].surface.mode |= dContactMotion1 | dContactMotion2 | dContactMotionN | dContactFDir1; contact[i].surface.mode |= dContactMotion1 | dContactMotion2 | dContactMotionN | dContactFDir1;
contact[i].surface.mode |= dContactSoftERP; contact[i].surface.mode |= dContactSoftERP;
contact[i].surface.soft_erp = 0.9; contact[i].surface.soft_erp = 0.9;
@@ -146,17 +157,42 @@ static void contact_callback(void *data, dGeomID g1, dGeomID g2) {
int ghost = 0; int ghost = 0;
if(dGeomGetCategoryBits(g1) & CATEGORY_GHOST) ghost = 1;
if(dGeomGetCategoryBits(g2) & CATEGORY_GHOST) ghost = 1;
if(numc) { if(numc) {
int triggerType = activate_pair(g1, g2); int triggerType = activate_pair(e1, e2);
if(e1 != ENT_ID_INVALID) { if(e1 != ENT_ID_INVALID) {
if(game_getcomponent(e1, physics)->dynamics & CPHYSICS_GHOST) { struct CPhysics *cp = game_getcomponent(e1, physics);
if(!cp) {
// Entity being killed maybe
return;
}
if(cp->dynamics & CPHYSICS_GHOST) {
ghost = 1;
}
struct CMovement *cm = game_getcomponent(e1, movement);
if(cm && cm->holding != ENT_ID_INVALID && cm->holding == e2) {
ghost = 1; ghost = 1;
} }
} }
if(e2 != ENT_ID_INVALID) { if(e2 != ENT_ID_INVALID) {
if(game_getcomponent(e2, physics)->dynamics & CPHYSICS_GHOST) { struct CPhysics *cp = game_getcomponent(e2, physics);
if(!cp) {
// Entity being killed maybe
return;
}
if(cp->dynamics & CPHYSICS_GHOST) {
ghost = 1;
}
struct CMovement *cm = game_getcomponent(e2, movement);
if(cm && cm->holding != ENT_ID_INVALID && cm->holding == e1) {
ghost = 1; ghost = 1;
} }
} }
@@ -168,37 +204,6 @@ static void contact_callback(void *data, dGeomID g1, dGeomID g2) {
friction *= c->friction; friction *= c->friction;
vec4 q;
if(b1) {
memcpy(q, dBodyGetQuaternion(b1), sizeof(q));
} else {
dGeomGetQuaternion(c->geom, q);
}
{
float temp = q[0];
q[0] = q[1];
q[1] = q[2];
q[2] = q[3];
q[3] = temp;
}
vec3 n = {0, 1, 0};
glm_quat_rotatev(q, n, n);
if(!ghost) for(int i = 0; i < numc; i++) {
if(glm_vec3_dot(contact[i].geom.normal, n) >= 0.7) {
struct CMovement *m = game_getcomponent(e1, movement);
if(m) {
if(m->holding != ENT_ID_INVALID && m->holding == e2) {
ghost = 1;
}
m->canJump = 1;
break;
}
}
}
if(c->trigger != TRIGGER_INVALID) { if(c->trigger != TRIGGER_INVALID) {
Game.triggers[c->trigger - 1](c->trigger, e1, e2, triggerType); Game.triggers[c->trigger - 1](c->trigger, e1, e2, triggerType);
} }
@@ -209,37 +214,6 @@ static void contact_callback(void *data, dGeomID g1, dGeomID g2) {
friction *= c->friction; friction *= c->friction;
vec4 q;
if(b2) {
memcpy(q, dBodyGetQuaternion(b2), sizeof(q));
} else {
dGeomGetQuaternion(c->geom, q);
}
{
float temp = q[0];
q[0] = q[1];
q[1] = q[2];
q[2] = q[3];
q[3] = temp;
}
vec3 n = {0, -1, 0};
glm_quat_rotatev(q, n, n);
if(!ghost) for(int i = 0; i < numc; i++) {
if(glm_vec3_dot(contact[i].geom.normal, n) >= 0.7) {
struct CMovement *m = game_getcomponent(e2, movement);
if(m) {
if(m->holding != ENT_ID_INVALID && m->holding == e1) {
ghost = 1;
}
m->canJump = 1;
break;
}
}
}
if(c->trigger != TRIGGER_INVALID) { if(c->trigger != TRIGGER_INVALID) {
Game.triggers[c->trigger - 1](c->trigger, e2, e1, triggerType); Game.triggers[c->trigger - 1](c->trigger, e2, e1, triggerType);
} }
@@ -337,7 +311,102 @@ void game_raycast(struct LocalRay *rays, size_t count) {
} }
} }
static void game_character_controller_raycast_handler(void *data, dGeomID g1, dGeomID g2) {
if(dGeomGetClass(g1) != dRayClass && dGeomGetClass(g2) != dRayClass) {
return;
}
uint16_t e1 = (uintptr_t) dGeomGetData(g1);
uint16_t e2 = (uintptr_t) dGeomGetData(g2);
if(e1 == e2) {
// This means the ray is hitting the entity casting it.
return;
}
dContact contact[1];
memset(contact, 0, sizeof(contact));
int numc = dCollide(g1, g2, 1, &contact[0].geom, sizeof(dContact));
if(numc) {
vec3 n = {0, -1, 0};
struct CPhysics *cp1 = game_getcomponent(e1, physics);
struct CPhysics *cp2 = game_getcomponent(e2, physics);
if((cp2 && (cp2->dynamics & CPHYSICS_GHOST)) || (cp1 && (cp1->dynamics & CPHYSICS_GHOST))) {
return;
}
if(dGeomGetClass(g1) == dRayClass) {
dBodyID bid = dGeomGetBody(cp1->geom);
struct CMovement *cm = game_getcomponent(e1, movement);
cm->groundDepth = dGeomRayGetLength(g1) - contact[0].geom.depth;
if(glm_vec3_dot(contact[0].geom.normal, n) <= -0.7 && cm->groundDepth > SUBFEET(cp1)) {
cm->canJump = 1;
glm_vec3_scale(contact[0].geom.normal, -1, cm->groundNormal);
}
} else if(dGeomGetClass(g2) == dRayClass) {
dBodyID bid = dGeomGetBody(cp2->geom);
struct CMovement *cm = game_getcomponent(e2, movement);
cm->groundDepth = dGeomRayGetLength(g2) - contact[0].geom.depth;
if(glm_vec3_dot(contact[0].geom.normal, n) >= +0.7 && cm->groundDepth > SUBFEET(cp2)) {
cm->canJump = 1;
glm_vec3_scale(contact[0].geom.normal, +1, cm->groundNormal);
}
}
}
}
void game_character_controller_raycast() {
dGeomID rayGeoms[Game.entities.movementCount];
for(size_t i = 0; i < Game.entities.movementCount; i++) {
Game.entities.movement[i].canJump = 0;
}
for(int i = 0; i < Game.entities.movementCount; i++) {
struct CPhysics *cp = game_getcomponent(Game.entities.movement[i].entity, physics);
if(!cp || !cp->geom || cp->type != CPHYSICS_CAPSULE) {
rayGeoms[i] = NULL;
continue;
}
rayGeoms[i] = dCreateRay(Game.space, cp->capsule.length / 2 + cp->capsule.radius + SUBFEET(cp));
dGeomSetData(rayGeoms[i], (void*) (uintptr_t) Game.entities.movement[i].entity);
dGeomSetCategoryBits(rayGeoms[i], CATEGORY_RAY);
dGeomSetCollideBits(rayGeoms[i], CATEGORY_STATIC | CATEGORY_ENTITY);
dBodyID bid = dGeomGetBody(cp->geom);
const float *position = dBodyGetPosition(bid);
dGeomRaySet(rayGeoms[i], position[0], position[1], position[2], 0, -1, 0);
}
dSpaceCollide(Game.space, NULL, game_character_controller_raycast_handler);
for(int i = 0; i < Game.entities.movementCount; i++) {
if(rayGeoms[i]) {
dGeomDestroy(rayGeoms[i]);
}
}
}
void game_update() { void game_update() {
game_character_controller_raycast();
for(size_t i = 0; i < Game.entities.playerctrlCount; i++) { for(size_t i = 0; i < Game.entities.playerctrlCount; i++) {
struct CPlayerCtrl *cc = &Game.entities.playerctrl[i]; struct CPlayerCtrl *cc = &Game.entities.playerctrl[i];
@@ -383,9 +452,18 @@ void game_update() {
if(cp && cp->geom) { if(cp && cp->geom) {
dBodyID bid = dGeomGetBody(cp->geom); dBodyID bid = dGeomGetBody(cp->geom);
if(Game.entities.movement[i].canJump) { if(Game.entities.movement[i].canJump) {
if(dBodyGetLinearVel(bid)[1] <= 0) {
Game.entities.movement[i].isJumping = false;
}
if(!Game.entities.movement[i].isJumping) {
const float *pos = dBodyGetPosition(bid);
dBodySetPosition(bid, pos[0], pos[1] + Game.entities.movement[i].groundDepth - cp->capsule.radius / 2 - SUBFEET(cp), pos[2]);
dBodySetLinearVel(bid, 0, 0, 0); dBodySetLinearVel(bid, 0, 0, 0);
} }
dBodySetGravityMode(bid, !Game.entities.movement[i].canJump); }
dBodySetGravityMode(bid, Game.entities.movement[i].canJump && !Game.entities.movement[i].isJumping ? 0 : 1);
} }
} }
@@ -421,14 +499,21 @@ void game_update() {
Game.entities.physics[i].box.l); Game.entities.physics[i].box.l);
break; break;
case CPHYSICS_CAPSULE: case CPHYSICS_CAPSULE: {
Game.entities.physics[i].geom = dCreateCapsule(Game.space, dGeomID top = dCreateCapsule(Game.space,
Game.entities.physics[i].capsule.radius, Game.entities.physics[i].capsule.radius,
Game.entities.physics[i].capsule.length); Game.entities.physics[i].capsule.length - Game.entities.physics[i].capsule.radius);
dGeomID feet = dCreateSphere(Game.space,
Game.entities.physics[i].capsule.radius);
Game.entities.physics[i].geom = top;
Game.entities.physics[i].geom2 = feet;
dMassSetCapsuleTotal(&mass, Game.entities.physics[i].mass, 2, Game.entities.physics[i].capsule.radius, Game.entities.physics[i].capsule.length); dMassSetCapsuleTotal(&mass, Game.entities.physics[i].mass, 2, Game.entities.physics[i].capsule.radius, Game.entities.physics[i].capsule.length);
break; break;
}
case CPHYSICS_SPHERE: case CPHYSICS_SPHERE:
Game.entities.physics[i].geom = dCreateSphere(Game.space, Game.entities.physics[i].geom = dCreateSphere(Game.space,
Game.entities.physics[i].sphere.radius); Game.entities.physics[i].sphere.radius);
@@ -442,6 +527,12 @@ void game_update() {
dGeomSetCollideBits(Game.entities.physics[i].geom, Game.entities.physics[i].collide); dGeomSetCollideBits(Game.entities.physics[i].geom, Game.entities.physics[i].collide);
dGeomSetData(Game.entities.physics[i].geom, (void*) Game.entities.physics[i].entity); dGeomSetData(Game.entities.physics[i].geom, (void*) Game.entities.physics[i].entity);
if(Game.entities.physics[i].type == CPHYSICS_CAPSULE) {
dGeomSetCategoryBits(Game.entities.physics[i].geom2, CATEGORY_ENTITY | CATEGORY_GHOST);
dGeomSetCollideBits(Game.entities.physics[i].geom2, Game.entities.physics[i].collide);
dGeomSetData(Game.entities.physics[i].geom2, (void*) Game.entities.physics[i].entity);
}
if((Game.entities.physics[i].dynamics & ~CPHYSICS_GHOST) != CPHYSICS_STATIC) { if((Game.entities.physics[i].dynamics & ~CPHYSICS_GHOST) != CPHYSICS_STATIC) {
dBodyID body = dBodyCreate(Game.phys); dBodyID body = dBodyCreate(Game.phys);
@@ -452,10 +543,16 @@ void game_update() {
} }
dGeomSetBody(Game.entities.physics[i].geom, body); dGeomSetBody(Game.entities.physics[i].geom, body);
if(Game.entities.physics[i].geom2) {
dGeomSetBody(Game.entities.physics[i].geom2, body);
}
if(Game.entities.physics[i].type == CPHYSICS_CAPSULE) { if(Game.entities.physics[i].type == CPHYSICS_CAPSULE) {
dBodySetMaxAngularSpeed(body, 0); dBodySetMaxAngularSpeed(body, 0);
dGeomSetOffsetPosition(Game.entities.physics[i].geom, 0, Game.entities.physics[i].capsule.radius / 2, 0);
dGeomSetOffsetPosition(Game.entities.physics[i].geom2, 0, -Game.entities.physics[i].capsule.length / 2, 0);
// Rotate to Y-up // Rotate to Y-up
dQuaternion q; dQuaternion q;
dQFromAxisAndAngle(q, 1, 0, 0, M_PI * 0.5); dQFromAxisAndAngle(q, 1, 0, 0, M_PI * 0.5);
@@ -516,6 +613,10 @@ void game_update() {
if(glm_vec3_norm(wishvel) > 3) { if(glm_vec3_norm(wishvel) > 3) {
glm_vec3_scale_as(wishvel, 3, wishvel); glm_vec3_scale_as(wishvel, 3, wishvel);
} }
} else {
// We project the movement vector onto the ground plane (set by game_character_controller_raycast_handler)
// to "slide" along the ground with minimal bouncing
vec3_project_to_plane(wishvel, Game.entities.movement[mi].groundNormal, wishvel);
} }
float currentspeed = glm_vec3_dot(wishvel, dBodyGetLinearVel(bid)); float currentspeed = glm_vec3_dot(wishvel, dBodyGetLinearVel(bid));
@@ -538,21 +639,17 @@ void game_update() {
dQFromAxisAndAngle(q, 0, 1, 0, Game.entities.movement[mi].pointing + M_PI); dQFromAxisAndAngle(q, 0, 1, 0, Game.entities.movement[mi].pointing + M_PI);
dBodySetQuaternion(bid, q); dBodySetQuaternion(bid, q);
if(Game.entities.movement[mi].jump && (0||Game.entities.movement[mi].canJump)) { if(Game.entities.movement[mi].jump && Game.entities.movement[mi].canJump) {
Game.entities.movement[mi].canJump = 0; dVector3 force = {};
dWorldImpulseToForce(Game.phys, 1.f / GAME_TPS, 0, 6.5, 0, force);
dVector3 force;
dWorldImpulseToForce(Game.phys, 1.f / GAME_TPS, 0, 5, 0, force);
if(bid) { if(bid) {
dBodyAddForce(bid, force[0], force[1], force[2]); dBodyAddForce(bid, force[0], force[1], force[2]);
} }
}
}
}
for(size_t i = 0; i < Game.entities.movementCount; i++) { Game.entities.movement[mi].isJumping = true;
Game.entities.movement[i].canJump = 0; }
}
} }
dSpaceCollide(Game.space, 0, &contact_callback); dSpaceCollide(Game.space, 0, &contact_callback);
@@ -889,10 +986,46 @@ void game_cleanup() {
Game.phys = dWorldCreate(); Game.phys = dWorldCreate();
dWorldSetGravity(Game.phys, 0, -15, 0); dWorldSetGravity(Game.phys, 0, -15, 0);
dWorldSetCFM(Game.phys, 0.0001); dWorldSetCFM(Game.phys, 0.00002);
dWorldSetERP(Game.phys, 0.5); dWorldSetERP(Game.phys, 0.1);
Game.space = dHashSpaceCreate(NULL); Game.space = dHashSpaceCreate(NULL);
Game.contactgroup = dJointGroupCreate(0); Game.contactgroup = dJointGroupCreate(0);
} }
void game_killentity(uint16_t eid) {
// XXX: Go over ALL component types!
struct CPhysics *cp = game_getcomponent(eid, physics);
if(cp) {
dBodyID bid = dGeomGetBody(cp->geom);
if(bid) {
for(dGeomID gid = dBodyGetFirstGeom(bid); gid; gid = dBodyGetNextGeom(gid)) {
dGeomDestroy(gid);
}
dBodyDestroy(bid);
} else {
dGeomDestroy(cp->geom);
}
game_killcomponent_ptr(cp, physics);
}
struct CRender *cr = game_getcomponent(eid, render);
if(cr) {
if(cr->cache) {
if(resman_rev(cr->cache)) {
resman_unref(RESMAN_MODEL, cr->cache);
}
}
game_killcomponent_ptr(cr, render);
}
game_killcomponent(eid, movement);
game_killcomponent(eid, playerctrl);
game_killcomponent(eid, boned);
}

View File

@@ -13,6 +13,7 @@
#define CATEGORY_STATIC 1 #define CATEGORY_STATIC 1
#define CATEGORY_RAY 2 #define CATEGORY_RAY 2
#define CATEGORY_ENTITY 4 #define CATEGORY_ENTITY 4
#define CATEGORY_GHOST 8
#define TRIGGER_INVALID 0 #define TRIGGER_INVALID 0
@@ -47,7 +48,7 @@ struct TrimeshData {
#define CPHYSICS_GHOST 128 #define CPHYSICS_GHOST 128
struct CPhysics { struct CPhysics {
uint16_t entity; uint16_t entity;
dGeomID geom; dGeomID geom, geom2;
uint16_t trigger; uint16_t trigger;
uint8_t type; uint8_t type;
@@ -87,7 +88,9 @@ struct CMovement {
uint16_t entity; uint16_t entity;
vec3 dir; vec3 dir;
float pointing; float pointing;
char jump, canJump; char jump, canJump, isJumping;
vec3 groundNormal;
float groundDepth;
uint16_t holding; uint16_t holding;
}; };
@@ -248,7 +251,22 @@ static inline void *game_ensurecomponent_(uint16_t eid, void *array, size_t comp
return ptr; return ptr;
} }
#define game_killcomponent_ptr(c, arr) do { \
size_t idx = c - Game.entities.arr; \
memmove(c, c + 1, sizeof(*c) * (Game.entities.arr##Count - idx - 1)); \
Game.entities.arr##Count--; \
} while(0);
#define game_killcomponent(eid, arr) do { \
typeof(&Game.entities.arr[0]) c = game_getcomponent(eid, arr); \
if(c) { \
game_killcomponent_ptr(c, arr); \
} \
} while(0);
// An artifact of using a third-party physics engine // An artifact of using a third-party physics engine
void game_synccphysics(); void game_synccphysics();
void game_cleanup(); void game_cleanup();
void game_killentity(uint16_t eid);

View File

@@ -1,11 +1,11 @@
/** /**
* Loader generated by glad 2.0.8 on Sun Nov 17 08:36:10 2024 * Loader generated by glad 2.0.8 on Fri May 9 09:20:04 2025
* *
* SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
* *
* Generator: C/C++ * Generator: C/C++
* Specification: gl * Specification: gl
* Extensions: 31 * Extensions: 37
* *
* APIs: * APIs:
* - gl:compatibility=4.6 * - gl:compatibility=4.6
@@ -19,10 +19,10 @@
* - ON_DEMAND = False * - ON_DEMAND = False
* *
* Commandline: * Commandline:
* --api='gl:compatibility=4.6' --extensions='GL_ARB_compatibility,GL_ARB_debug_output,GL_ARB_fragment_program,GL_ARB_fragment_shader,GL_ARB_framebuffer_sRGB,GL_ARB_shader_image_load_store,GL_ARB_shader_image_size,GL_ARB_shader_objects,GL_ARB_shader_storage_buffer_object,GL_ARB_shading_language_100,GL_ARB_texture_float,GL_ARB_texture_rg,GL_ARB_texture_rgb10_a2ui,GL_ARB_vertex_buffer_object,GL_ARB_vertex_program,GL_ARB_vertex_shader,GL_ARB_vertex_type_2_10_10_10_rev,GL_EXT_direct_state_access,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_object,GL_EXT_framebuffer_sRGB,GL_EXT_geometry_shader4,GL_EXT_gpu_shader4,GL_EXT_shader_image_load_store,GL_EXT_texture_array,GL_EXT_texture_compression_s3tc,GL_EXT_texture_integer,GL_EXT_texture_sRGB,GL_EXT_transform_feedback,GL_INTEL_conservative_rasterization,GL_NV_conservative_raster' c --header-only * --api='gl:compatibility=4.6' --extensions='GL_ARB_compatibility,GL_ARB_debug_output,GL_ARB_fragment_program,GL_ARB_fragment_shader,GL_ARB_framebuffer_sRGB,GL_ARB_shader_image_load_store,GL_ARB_shader_image_size,GL_ARB_shader_objects,GL_ARB_shader_storage_buffer_object,GL_ARB_shading_language_100,GL_ARB_texture_compression_bptc,GL_ARB_texture_float,GL_ARB_texture_rg,GL_ARB_texture_rgb10_a2ui,GL_ARB_vertex_buffer_object,GL_ARB_vertex_program,GL_ARB_vertex_shader,GL_ARB_vertex_type_2_10_10_10_rev,GL_EXT_direct_state_access,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_multisample_blit_scaled,GL_EXT_framebuffer_object,GL_EXT_framebuffer_sRGB,GL_EXT_geometry_shader4,GL_EXT_gpu_shader4,GL_EXT_shader_image_load_store,GL_EXT_texture_array,GL_EXT_texture_compression_rgtc,GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_integer,GL_EXT_texture_sRGB,GL_EXT_transform_feedback,GL_INTEL_conservative_rasterization,GL_KHR_texture_compression_astc_ldr,GL_NV_conservative_raster' c --header-only
* *
* Online: * Online:
* http://glad.sh/#api=gl%3Acompatibility%3D4.6&extensions=GL_ARB_compatibility%2CGL_ARB_debug_output%2CGL_ARB_fragment_program%2CGL_ARB_fragment_shader%2CGL_ARB_framebuffer_sRGB%2CGL_ARB_shader_image_load_store%2CGL_ARB_shader_image_size%2CGL_ARB_shader_objects%2CGL_ARB_shader_storage_buffer_object%2CGL_ARB_shading_language_100%2CGL_ARB_texture_float%2CGL_ARB_texture_rg%2CGL_ARB_texture_rgb10_a2ui%2CGL_ARB_vertex_buffer_object%2CGL_ARB_vertex_program%2CGL_ARB_vertex_shader%2CGL_ARB_vertex_type_2_10_10_10_rev%2CGL_EXT_direct_state_access%2CGL_EXT_framebuffer_blit%2CGL_EXT_framebuffer_object%2CGL_EXT_framebuffer_sRGB%2CGL_EXT_geometry_shader4%2CGL_EXT_gpu_shader4%2CGL_EXT_shader_image_load_store%2CGL_EXT_texture_array%2CGL_EXT_texture_compression_s3tc%2CGL_EXT_texture_integer%2CGL_EXT_texture_sRGB%2CGL_EXT_transform_feedback%2CGL_INTEL_conservative_rasterization%2CGL_NV_conservative_raster&generator=c&options=HEADER_ONLY * http://glad.sh/#api=gl%3Acompatibility%3D4.6&extensions=GL_ARB_compatibility%2CGL_ARB_debug_output%2CGL_ARB_fragment_program%2CGL_ARB_fragment_shader%2CGL_ARB_framebuffer_sRGB%2CGL_ARB_shader_image_load_store%2CGL_ARB_shader_image_size%2CGL_ARB_shader_objects%2CGL_ARB_shader_storage_buffer_object%2CGL_ARB_shading_language_100%2CGL_ARB_texture_compression_bptc%2CGL_ARB_texture_float%2CGL_ARB_texture_rg%2CGL_ARB_texture_rgb10_a2ui%2CGL_ARB_vertex_buffer_object%2CGL_ARB_vertex_program%2CGL_ARB_vertex_shader%2CGL_ARB_vertex_type_2_10_10_10_rev%2CGL_EXT_direct_state_access%2CGL_EXT_framebuffer_blit%2CGL_EXT_framebuffer_multisample%2CGL_EXT_framebuffer_multisample_blit_scaled%2CGL_EXT_framebuffer_object%2CGL_EXT_framebuffer_sRGB%2CGL_EXT_geometry_shader4%2CGL_EXT_gpu_shader4%2CGL_EXT_shader_image_load_store%2CGL_EXT_texture_array%2CGL_EXT_texture_compression_rgtc%2CGL_EXT_texture_compression_s3tc%2CGL_EXT_texture_filter_anisotropic%2CGL_EXT_texture_integer%2CGL_EXT_texture_sRGB%2CGL_EXT_transform_feedback%2CGL_INTEL_conservative_rasterization%2CGL_KHR_texture_compression_astc_ldr%2CGL_NV_conservative_raster&generator=c&options=HEADER_ONLY
* *
*/ */
@@ -465,7 +465,9 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB #define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB
#define GL_COMPRESSED_R11_EAC 0x9270 #define GL_COMPRESSED_R11_EAC 0x9270
#define GL_COMPRESSED_RED 0x8225 #define GL_COMPRESSED_RED 0x8225
#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD
#define GL_COMPRESSED_RED_RGTC1 0x8DBB #define GL_COMPRESSED_RED_RGTC1 0x8DBB
#define GL_COMPRESSED_RED_RGTC1_EXT 0x8DBB
#define GL_COMPRESSED_RG 0x8226 #define GL_COMPRESSED_RG 0x8226
#define GL_COMPRESSED_RG11_EAC 0x9272 #define GL_COMPRESSED_RG11_EAC 0x9272
#define GL_COMPRESSED_RGB 0x84ED #define GL_COMPRESSED_RGB 0x84ED
@@ -473,16 +475,35 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
#define GL_COMPRESSED_RGBA 0x84EE #define GL_COMPRESSED_RGBA 0x84EE
#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB
#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8
#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9
#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA
#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC
#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD
#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0
#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1
#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2
#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3
#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4
#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5
#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6
#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7
#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C #define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F
#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
#define GL_COMPRESSED_RG_RGTC2 0x8DBD #define GL_COMPRESSED_RG_RGTC2 0x8DBD
#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE
#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC
#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE #define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
#define GL_COMPRESSED_SLUMINANCE 0x8C4A #define GL_COMPRESSED_SLUMINANCE 0x8C4A
@@ -490,11 +511,26 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B #define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B
#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A #define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A
#define GL_COMPRESSED_SRGB 0x8C48 #define GL_COMPRESSED_SRGB 0x8C48
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7
#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
#define GL_COMPRESSED_SRGB8_ETC2 0x9275 #define GL_COMPRESSED_SRGB8_ETC2 0x9275
#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 #define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
#define GL_COMPRESSED_SRGB_ALPHA 0x8C49 #define GL_COMPRESSED_SRGB_ALPHA 0x8C49
#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D #define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D
#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49 #define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
@@ -833,6 +869,7 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
#define GL_FRAMEBUFFER_RENDERABLE 0x8289 #define GL_FRAMEBUFFER_RENDERABLE 0x8289
@@ -1335,6 +1372,7 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_MAX_RENDERBUFFER_SIZE 0x84E8
#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8 #define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8
#define GL_MAX_SAMPLES 0x8D57 #define GL_MAX_SAMPLES 0x8D57
#define GL_MAX_SAMPLES_EXT 0x8D57
#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 #define GL_MAX_SAMPLE_MASK_WORDS 0x8E59
#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 #define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE #define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE
@@ -1370,6 +1408,7 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872 #define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872
#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF #define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
#define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_MAX_TEXTURE_SIZE 0x0D33
#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 #define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39
#define GL_MAX_TEXTURE_UNITS 0x84E2 #define GL_MAX_TEXTURE_UNITS 0x84E2
@@ -1730,6 +1769,7 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_RED_SIZE 0x8D50
#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50 #define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50
#define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_RENDERBUFFER_SAMPLES 0x8CAB
#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55 #define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
#define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERBUFFER_WIDTH 0x8D42
@@ -1864,6 +1904,8 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define GL_SAMPLE_MASK_VALUE 0x8E52 #define GL_SAMPLE_MASK_VALUE 0x8E52
#define GL_SAMPLE_POSITION 0x8E50 #define GL_SAMPLE_POSITION 0x8E50
#define GL_SAMPLE_SHADING 0x8C36 #define GL_SAMPLE_SHADING 0x8C36
#define GL_SCALED_RESOLVE_FASTEST_EXT 0x90BA
#define GL_SCALED_RESOLVE_NICEST_EXT 0x90BB
#define GL_SCISSOR_BIT 0x00080000 #define GL_SCISSOR_BIT 0x00080000
#define GL_SCISSOR_BOX 0x0C10 #define GL_SCISSOR_BOX 0x0C10
#define GL_SCISSOR_TEST 0x0C11 #define GL_SCISSOR_TEST 0x0C11
@@ -2174,6 +2216,7 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MAG_FILTER 0x2800
#define GL_TEXTURE_MATRIX 0x0BA8 #define GL_TEXTURE_MATRIX 0x0BA8
#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE #define GL_TEXTURE_MAX_ANISOTROPY 0x84FE
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
#define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_TEXTURE_MAX_LEVEL 0x813D
#define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_MAX_LOD 0x813B
#define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_MIN_FILTER 0x2801
@@ -2889,6 +2932,8 @@ GLAD_API_CALL int GLAD_GL_ARB_shader_objects;
GLAD_API_CALL int GLAD_GL_ARB_shader_storage_buffer_object; GLAD_API_CALL int GLAD_GL_ARB_shader_storage_buffer_object;
#define GL_ARB_shading_language_100 1 #define GL_ARB_shading_language_100 1
GLAD_API_CALL int GLAD_GL_ARB_shading_language_100; GLAD_API_CALL int GLAD_GL_ARB_shading_language_100;
#define GL_ARB_texture_compression_bptc 1
GLAD_API_CALL int GLAD_GL_ARB_texture_compression_bptc;
#define GL_ARB_texture_float 1 #define GL_ARB_texture_float 1
GLAD_API_CALL int GLAD_GL_ARB_texture_float; GLAD_API_CALL int GLAD_GL_ARB_texture_float;
#define GL_ARB_texture_rg 1 #define GL_ARB_texture_rg 1
@@ -2907,6 +2952,10 @@ GLAD_API_CALL int GLAD_GL_ARB_vertex_type_2_10_10_10_rev;
GLAD_API_CALL int GLAD_GL_EXT_direct_state_access; GLAD_API_CALL int GLAD_GL_EXT_direct_state_access;
#define GL_EXT_framebuffer_blit 1 #define GL_EXT_framebuffer_blit 1
GLAD_API_CALL int GLAD_GL_EXT_framebuffer_blit; GLAD_API_CALL int GLAD_GL_EXT_framebuffer_blit;
#define GL_EXT_framebuffer_multisample 1
GLAD_API_CALL int GLAD_GL_EXT_framebuffer_multisample;
#define GL_EXT_framebuffer_multisample_blit_scaled 1
GLAD_API_CALL int GLAD_GL_EXT_framebuffer_multisample_blit_scaled;
#define GL_EXT_framebuffer_object 1 #define GL_EXT_framebuffer_object 1
GLAD_API_CALL int GLAD_GL_EXT_framebuffer_object; GLAD_API_CALL int GLAD_GL_EXT_framebuffer_object;
#define GL_EXT_framebuffer_sRGB 1 #define GL_EXT_framebuffer_sRGB 1
@@ -2919,8 +2968,12 @@ GLAD_API_CALL int GLAD_GL_EXT_gpu_shader4;
GLAD_API_CALL int GLAD_GL_EXT_shader_image_load_store; GLAD_API_CALL int GLAD_GL_EXT_shader_image_load_store;
#define GL_EXT_texture_array 1 #define GL_EXT_texture_array 1
GLAD_API_CALL int GLAD_GL_EXT_texture_array; GLAD_API_CALL int GLAD_GL_EXT_texture_array;
#define GL_EXT_texture_compression_rgtc 1
GLAD_API_CALL int GLAD_GL_EXT_texture_compression_rgtc;
#define GL_EXT_texture_compression_s3tc 1 #define GL_EXT_texture_compression_s3tc 1
GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc; GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc;
#define GL_EXT_texture_filter_anisotropic 1
GLAD_API_CALL int GLAD_GL_EXT_texture_filter_anisotropic;
#define GL_EXT_texture_integer 1 #define GL_EXT_texture_integer 1
GLAD_API_CALL int GLAD_GL_EXT_texture_integer; GLAD_API_CALL int GLAD_GL_EXT_texture_integer;
#define GL_EXT_texture_sRGB 1 #define GL_EXT_texture_sRGB 1
@@ -2929,6 +2982,8 @@ GLAD_API_CALL int GLAD_GL_EXT_texture_sRGB;
GLAD_API_CALL int GLAD_GL_EXT_transform_feedback; GLAD_API_CALL int GLAD_GL_EXT_transform_feedback;
#define GL_INTEL_conservative_rasterization 1 #define GL_INTEL_conservative_rasterization 1
GLAD_API_CALL int GLAD_GL_INTEL_conservative_rasterization; GLAD_API_CALL int GLAD_GL_INTEL_conservative_rasterization;
#define GL_KHR_texture_compression_astc_ldr 1
GLAD_API_CALL int GLAD_GL_KHR_texture_compression_astc_ldr;
#define GL_NV_conservative_raster 1 #define GL_NV_conservative_raster 1
GLAD_API_CALL int GLAD_GL_NV_conservative_raster; GLAD_API_CALL int GLAD_GL_NV_conservative_raster;
@@ -3949,6 +4004,7 @@ typedef GLint (GLAD_API_PTR *PFNGLRENDERMODEPROC)(GLenum mode);
typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEEXTPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEEXTPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GLAD_API_PTR *PFNGLRESUMETRANSFORMFEEDBACKPROC)(void); typedef void (GLAD_API_PTR *PFNGLRESUMETRANSFORMFEEDBACKPROC)(void);
typedef void (GLAD_API_PTR *PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); typedef void (GLAD_API_PTR *PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);
typedef void (GLAD_API_PTR *PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); typedef void (GLAD_API_PTR *PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
@@ -6458,6 +6514,8 @@ GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT;
#define glRenderbufferStorageEXT glad_glRenderbufferStorageEXT #define glRenderbufferStorageEXT glad_glRenderbufferStorageEXT
GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;
#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample #define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample
GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT;
#define glRenderbufferStorageMultisampleEXT glad_glRenderbufferStorageMultisampleEXT
GLAD_API_CALL PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback; GLAD_API_CALL PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback;
#define glResumeTransformFeedback glad_glResumeTransformFeedback #define glResumeTransformFeedback glad_glResumeTransformFeedback
GLAD_API_CALL PFNGLROTATEDPROC glad_glRotated; GLAD_API_CALL PFNGLROTATEDPROC glad_glRotated;
@@ -7480,6 +7538,7 @@ int GLAD_GL_ARB_shader_image_size = 0;
int GLAD_GL_ARB_shader_objects = 0; int GLAD_GL_ARB_shader_objects = 0;
int GLAD_GL_ARB_shader_storage_buffer_object = 0; int GLAD_GL_ARB_shader_storage_buffer_object = 0;
int GLAD_GL_ARB_shading_language_100 = 0; int GLAD_GL_ARB_shading_language_100 = 0;
int GLAD_GL_ARB_texture_compression_bptc = 0;
int GLAD_GL_ARB_texture_float = 0; int GLAD_GL_ARB_texture_float = 0;
int GLAD_GL_ARB_texture_rg = 0; int GLAD_GL_ARB_texture_rg = 0;
int GLAD_GL_ARB_texture_rgb10_a2ui = 0; int GLAD_GL_ARB_texture_rgb10_a2ui = 0;
@@ -7489,17 +7548,22 @@ int GLAD_GL_ARB_vertex_shader = 0;
int GLAD_GL_ARB_vertex_type_2_10_10_10_rev = 0; int GLAD_GL_ARB_vertex_type_2_10_10_10_rev = 0;
int GLAD_GL_EXT_direct_state_access = 0; int GLAD_GL_EXT_direct_state_access = 0;
int GLAD_GL_EXT_framebuffer_blit = 0; int GLAD_GL_EXT_framebuffer_blit = 0;
int GLAD_GL_EXT_framebuffer_multisample = 0;
int GLAD_GL_EXT_framebuffer_multisample_blit_scaled = 0;
int GLAD_GL_EXT_framebuffer_object = 0; int GLAD_GL_EXT_framebuffer_object = 0;
int GLAD_GL_EXT_framebuffer_sRGB = 0; int GLAD_GL_EXT_framebuffer_sRGB = 0;
int GLAD_GL_EXT_geometry_shader4 = 0; int GLAD_GL_EXT_geometry_shader4 = 0;
int GLAD_GL_EXT_gpu_shader4 = 0; int GLAD_GL_EXT_gpu_shader4 = 0;
int GLAD_GL_EXT_shader_image_load_store = 0; int GLAD_GL_EXT_shader_image_load_store = 0;
int GLAD_GL_EXT_texture_array = 0; int GLAD_GL_EXT_texture_array = 0;
int GLAD_GL_EXT_texture_compression_rgtc = 0;
int GLAD_GL_EXT_texture_compression_s3tc = 0; int GLAD_GL_EXT_texture_compression_s3tc = 0;
int GLAD_GL_EXT_texture_filter_anisotropic = 0;
int GLAD_GL_EXT_texture_integer = 0; int GLAD_GL_EXT_texture_integer = 0;
int GLAD_GL_EXT_texture_sRGB = 0; int GLAD_GL_EXT_texture_sRGB = 0;
int GLAD_GL_EXT_transform_feedback = 0; int GLAD_GL_EXT_transform_feedback = 0;
int GLAD_GL_INTEL_conservative_rasterization = 0; int GLAD_GL_INTEL_conservative_rasterization = 0;
int GLAD_GL_KHR_texture_compression_astc_ldr = 0;
int GLAD_GL_NV_conservative_raster = 0; int GLAD_GL_NV_conservative_raster = 0;
@@ -8520,6 +8584,7 @@ PFNGLRENDERMODEPROC glad_glRenderMode = NULL;
PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT = NULL; PFNGLRENDERBUFFERSTORAGEEXTPROC glad_glRenderbufferStorageEXT = NULL;
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glad_glRenderbufferStorageMultisampleEXT = NULL;
PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL; PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL;
PFNGLROTATEDPROC glad_glRotated = NULL; PFNGLROTATEDPROC glad_glRotated = NULL;
PFNGLROTATEFPROC glad_glRotatef = NULL; PFNGLROTATEFPROC glad_glRotatef = NULL;
@@ -10618,6 +10683,10 @@ static void glad_gl_load_GL_EXT_framebuffer_blit( GLADuserptrloadfunc load, void
if(!GLAD_GL_EXT_framebuffer_blit) return; if(!GLAD_GL_EXT_framebuffer_blit) return;
glad_glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC) load(userptr, "glBlitFramebufferEXT"); glad_glBlitFramebufferEXT = (PFNGLBLITFRAMEBUFFEREXTPROC) load(userptr, "glBlitFramebufferEXT");
} }
static void glad_gl_load_GL_EXT_framebuffer_multisample( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GL_EXT_framebuffer_multisample) return;
glad_glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) load(userptr, "glRenderbufferStorageMultisampleEXT");
}
static void glad_gl_load_GL_EXT_framebuffer_object( GLADuserptrloadfunc load, void* userptr) { static void glad_gl_load_GL_EXT_framebuffer_object( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GL_EXT_framebuffer_object) return; if(!GLAD_GL_EXT_framebuffer_object) return;
glad_glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) load(userptr, "glBindFramebufferEXT"); glad_glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) load(userptr, "glBindFramebufferEXT");
@@ -10816,6 +10885,7 @@ static int glad_gl_find_extensions_gl(void) {
GLAD_GL_ARB_shader_objects = glad_gl_has_extension(exts, exts_i, "GL_ARB_shader_objects"); GLAD_GL_ARB_shader_objects = glad_gl_has_extension(exts, exts_i, "GL_ARB_shader_objects");
GLAD_GL_ARB_shader_storage_buffer_object = glad_gl_has_extension(exts, exts_i, "GL_ARB_shader_storage_buffer_object"); GLAD_GL_ARB_shader_storage_buffer_object = glad_gl_has_extension(exts, exts_i, "GL_ARB_shader_storage_buffer_object");
GLAD_GL_ARB_shading_language_100 = glad_gl_has_extension(exts, exts_i, "GL_ARB_shading_language_100"); GLAD_GL_ARB_shading_language_100 = glad_gl_has_extension(exts, exts_i, "GL_ARB_shading_language_100");
GLAD_GL_ARB_texture_compression_bptc = glad_gl_has_extension(exts, exts_i, "GL_ARB_texture_compression_bptc");
GLAD_GL_ARB_texture_float = glad_gl_has_extension(exts, exts_i, "GL_ARB_texture_float"); GLAD_GL_ARB_texture_float = glad_gl_has_extension(exts, exts_i, "GL_ARB_texture_float");
GLAD_GL_ARB_texture_rg = glad_gl_has_extension(exts, exts_i, "GL_ARB_texture_rg"); GLAD_GL_ARB_texture_rg = glad_gl_has_extension(exts, exts_i, "GL_ARB_texture_rg");
GLAD_GL_ARB_texture_rgb10_a2ui = glad_gl_has_extension(exts, exts_i, "GL_ARB_texture_rgb10_a2ui"); GLAD_GL_ARB_texture_rgb10_a2ui = glad_gl_has_extension(exts, exts_i, "GL_ARB_texture_rgb10_a2ui");
@@ -10825,17 +10895,22 @@ static int glad_gl_find_extensions_gl(void) {
GLAD_GL_ARB_vertex_type_2_10_10_10_rev = glad_gl_has_extension(exts, exts_i, "GL_ARB_vertex_type_2_10_10_10_rev"); GLAD_GL_ARB_vertex_type_2_10_10_10_rev = glad_gl_has_extension(exts, exts_i, "GL_ARB_vertex_type_2_10_10_10_rev");
GLAD_GL_EXT_direct_state_access = glad_gl_has_extension(exts, exts_i, "GL_EXT_direct_state_access"); GLAD_GL_EXT_direct_state_access = glad_gl_has_extension(exts, exts_i, "GL_EXT_direct_state_access");
GLAD_GL_EXT_framebuffer_blit = glad_gl_has_extension(exts, exts_i, "GL_EXT_framebuffer_blit"); GLAD_GL_EXT_framebuffer_blit = glad_gl_has_extension(exts, exts_i, "GL_EXT_framebuffer_blit");
GLAD_GL_EXT_framebuffer_multisample = glad_gl_has_extension(exts, exts_i, "GL_EXT_framebuffer_multisample");
GLAD_GL_EXT_framebuffer_multisample_blit_scaled = glad_gl_has_extension(exts, exts_i, "GL_EXT_framebuffer_multisample_blit_scaled");
GLAD_GL_EXT_framebuffer_object = glad_gl_has_extension(exts, exts_i, "GL_EXT_framebuffer_object"); GLAD_GL_EXT_framebuffer_object = glad_gl_has_extension(exts, exts_i, "GL_EXT_framebuffer_object");
GLAD_GL_EXT_framebuffer_sRGB = glad_gl_has_extension(exts, exts_i, "GL_EXT_framebuffer_sRGB"); GLAD_GL_EXT_framebuffer_sRGB = glad_gl_has_extension(exts, exts_i, "GL_EXT_framebuffer_sRGB");
GLAD_GL_EXT_geometry_shader4 = glad_gl_has_extension(exts, exts_i, "GL_EXT_geometry_shader4"); GLAD_GL_EXT_geometry_shader4 = glad_gl_has_extension(exts, exts_i, "GL_EXT_geometry_shader4");
GLAD_GL_EXT_gpu_shader4 = glad_gl_has_extension(exts, exts_i, "GL_EXT_gpu_shader4"); GLAD_GL_EXT_gpu_shader4 = glad_gl_has_extension(exts, exts_i, "GL_EXT_gpu_shader4");
GLAD_GL_EXT_shader_image_load_store = glad_gl_has_extension(exts, exts_i, "GL_EXT_shader_image_load_store"); GLAD_GL_EXT_shader_image_load_store = glad_gl_has_extension(exts, exts_i, "GL_EXT_shader_image_load_store");
GLAD_GL_EXT_texture_array = glad_gl_has_extension(exts, exts_i, "GL_EXT_texture_array"); GLAD_GL_EXT_texture_array = glad_gl_has_extension(exts, exts_i, "GL_EXT_texture_array");
GLAD_GL_EXT_texture_compression_rgtc = glad_gl_has_extension(exts, exts_i, "GL_EXT_texture_compression_rgtc");
GLAD_GL_EXT_texture_compression_s3tc = glad_gl_has_extension(exts, exts_i, "GL_EXT_texture_compression_s3tc"); GLAD_GL_EXT_texture_compression_s3tc = glad_gl_has_extension(exts, exts_i, "GL_EXT_texture_compression_s3tc");
GLAD_GL_EXT_texture_filter_anisotropic = glad_gl_has_extension(exts, exts_i, "GL_EXT_texture_filter_anisotropic");
GLAD_GL_EXT_texture_integer = glad_gl_has_extension(exts, exts_i, "GL_EXT_texture_integer"); GLAD_GL_EXT_texture_integer = glad_gl_has_extension(exts, exts_i, "GL_EXT_texture_integer");
GLAD_GL_EXT_texture_sRGB = glad_gl_has_extension(exts, exts_i, "GL_EXT_texture_sRGB"); GLAD_GL_EXT_texture_sRGB = glad_gl_has_extension(exts, exts_i, "GL_EXT_texture_sRGB");
GLAD_GL_EXT_transform_feedback = glad_gl_has_extension(exts, exts_i, "GL_EXT_transform_feedback"); GLAD_GL_EXT_transform_feedback = glad_gl_has_extension(exts, exts_i, "GL_EXT_transform_feedback");
GLAD_GL_INTEL_conservative_rasterization = glad_gl_has_extension(exts, exts_i, "GL_INTEL_conservative_rasterization"); GLAD_GL_INTEL_conservative_rasterization = glad_gl_has_extension(exts, exts_i, "GL_INTEL_conservative_rasterization");
GLAD_GL_KHR_texture_compression_astc_ldr = glad_gl_has_extension(exts, exts_i, "GL_KHR_texture_compression_astc_ldr");
GLAD_GL_NV_conservative_raster = glad_gl_has_extension(exts, exts_i, "GL_NV_conservative_raster"); GLAD_GL_NV_conservative_raster = glad_gl_has_extension(exts, exts_i, "GL_NV_conservative_raster");
glad_gl_free_extensions(exts_i); glad_gl_free_extensions(exts_i);
@@ -10929,6 +11004,7 @@ int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) {
glad_gl_load_GL_ARB_vertex_type_2_10_10_10_rev(load, userptr); glad_gl_load_GL_ARB_vertex_type_2_10_10_10_rev(load, userptr);
glad_gl_load_GL_EXT_direct_state_access(load, userptr); glad_gl_load_GL_EXT_direct_state_access(load, userptr);
glad_gl_load_GL_EXT_framebuffer_blit(load, userptr); glad_gl_load_GL_EXT_framebuffer_blit(load, userptr);
glad_gl_load_GL_EXT_framebuffer_multisample(load, userptr);
glad_gl_load_GL_EXT_framebuffer_object(load, userptr); glad_gl_load_GL_EXT_framebuffer_object(load, userptr);
glad_gl_load_GL_EXT_geometry_shader4(load, userptr); glad_gl_load_GL_EXT_geometry_shader4(load, userptr);
glad_gl_load_GL_EXT_gpu_shader4(load, userptr); glad_gl_load_GL_EXT_gpu_shader4(load, userptr);

View File

@@ -6,6 +6,11 @@
#include<math.h> #include<math.h>
#include<pthread.h> #include<pthread.h>
#include<assert.h> #include<assert.h>
#include"k3.h"
#ifdef _WIN32
#define strncasecmp _strnicmp
#endif
static uint32_t FinalSampleRate; static uint32_t FinalSampleRate;
static uint8_t FinalChannels; static uint8_t FinalChannels;
@@ -19,12 +24,22 @@ struct k3MixSource {
char *filepath; char *filepath;
OggVorbis_File vf; OggVorbis_File vf;
int bitstream; int bitstream;
size_t looppoint;
}; };
struct k3MixSource *k3MixSourceFile(const char *path) { struct k3MixSource *k3MixSourceFile(const char *path) {
struct k3MixSource *ret = calloc(1, sizeof(*ret)); struct k3MixSource *ret = calloc(1, sizeof(*ret));
ret->filepath = strdup(path); ret->filepath = strdup(path);
ov_fopen(path, &ret->vf); ov_fopen(path, &ret->vf);
ret->bitstream = 0; ret->bitstream = 0;
ret->looppoint = 0;
for(size_t ci = 0; ci < ret->vf.vc->comments; ci++) {
if(strncasecmp(ret->vf.vc->user_comments[ci], "looppoint=", 10) == 0) {
ret->looppoint = strtol(ret->vf.vc->user_comments[ci] + 10, NULL, 0);
k3Log(k3_DEBUG, "%s has loop point %lu", path, ret->looppoint);
}
}
return ret; return ret;
} }
void k3MixSourceClose(struct k3MixSource *src) { void k3MixSourceClose(struct k3MixSource *src) {
@@ -42,7 +57,7 @@ __attribute__((optimize("Ofast"))) static intmax_t ogg_read(struct k3MixWave *th
long lastRead = ov_read_float(&od->vf, &ni, sampleCount, &od->bitstream); long lastRead = ov_read_float(&od->vf, &ni, sampleCount, &od->bitstream);
if(this->loop && lastRead == 0) { if(this->loop && lastRead == 0) {
ov_pcm_seek(&od->vf, 0); ov_pcm_seek(&od->vf, od->looppoint);
continue; continue;
} else if(lastRead <= 0) { } else if(lastRead <= 0) {
this->end = true; this->end = true;
@@ -161,12 +176,13 @@ static void queue_clone(struct k3MixWave *this, struct k3MixWave *new) {
new->clone = queue_clone; new->clone = queue_clone;
new->close = queue_close; new->close = queue_close;
new->end = this->end;
new->loop = this->loop; new->loop = this->loop;
new->dam = this->dam; new->dam = this->dam;
new->volume = this->volume; new->volume = this->volume;
} }
struct k3MixWave *k3MixQueue() { struct k3MixWave *k3MixQueue() {
struct k3MixWave *ret = malloc(sizeof(*ret)); struct k3MixWave *ret = calloc(1, sizeof(*ret));
ret->refs = 1; ret->refs = 1;
ret->sampleRate = FinalSampleRate; ret->sampleRate = FinalSampleRate;
ret->channels = FinalChannels; ret->channels = FinalChannels;
@@ -182,6 +198,7 @@ struct k3MixWave *k3MixQueue() {
ret->loop = 0; ret->loop = 0;
ret->dam = 0; ret->dam = 0;
ret->volume = 1; ret->volume = 1;
ret->end = false;
return ret; return ret;
} }
@@ -260,6 +277,7 @@ static void power_measurement_clone(struct k3MixWave *this, struct k3MixWave *ne
new->clone = power_measurement_clone; new->clone = power_measurement_clone;
new->close = power_measurement_close; new->close = power_measurement_close;
new->end = this->end;
new->loop = this->loop; new->loop = this->loop;
new->dam = this->dam; new->dam = this->dam;
new->volume = this->volume; new->volume = this->volume;
@@ -308,6 +326,10 @@ struct k3MixWave *k3MixPowerMeasurement(struct k3MixWave *child) {
static size_t playingCount, playingCapacity; static size_t playingCount, playingCapacity;
static struct k3MixWave **playings; static struct k3MixWave **playings;
void k3MixStopSmooth(struct k3MixWave *wav) {
wav->fade = -0.01;
}
void k3MixStop(struct k3MixWave *wav) { void k3MixStop(struct k3MixWave *wav) {
for(size_t i = 0; i < playingCount; i++) { for(size_t i = 0; i < playingCount; i++) {
if(playings[i] == wav) { if(playings[i] == wav) {
@@ -346,12 +368,22 @@ __attribute__((optimize("Ofast"))) static void k3MixDoYourThang(size_t sampleCou
for(size_t i = 0; i < playingCount;) { for(size_t i = 0; i < playingCount;) {
intmax_t read = playings[i]->read(playings[i], sampleCount, FinalData); intmax_t read = playings[i]->read(playings[i], sampleCount, FinalData);
if(playings[i]->fade) {
playings[i]->volume += playings[i]->fade;
if(playings[i]->volume > 1) {
playings[i]->volume = 1;
playings[i]->fade = 0;
} else if(playings[i]->volume < 0) {
playings[i]->end = true;
}
}
if(playings[i]->end) { if(playings[i]->end) {
k3MixStop(playings[i]); k3MixStop(playings[i]);
} else i++; } else i++;
} }
for(size_t i = 0; i < sampleCount * FinalChannels; i += 4) { /*for(size_t i = 0; i < sampleCount * FinalChannels; i += 4) {
// Compute tanh approximation x*(27+x*x)/(27+9*x*x) // Compute tanh approximation x*(27+x*x)/(27+9*x*x)
float *ptr = FinalData + i; float *ptr = FinalData + i;
@@ -363,7 +395,7 @@ __attribute__((optimize("Ofast"))) static void k3MixDoYourThang(size_t sampleCou
__m128 denom = _mm_add_ps(_mm_set1_ps(27), _mm_mul_ps(_mm_set1_ps(9), xx)); __m128 denom = _mm_add_ps(_mm_set1_ps(27), _mm_mul_ps(_mm_set1_ps(9), xx));
_mm_storeu_ps(ptr, _mm_div_ps(numer, denom)); _mm_storeu_ps(ptr, _mm_div_ps(numer, denom));
} }*/
// The accuracy isn't worth the function call per sample // The accuracy isn't worth the function call per sample
/*for(size_t i = 0; i < sampleCount * FinalChannels; i++) { /*for(size_t i = 0; i < sampleCount * FinalChannels; i++) {

View File

@@ -29,6 +29,7 @@ struct k3MixWave {
bool end; bool end;
uint16_t dam; uint16_t dam;
float volume; float volume;
float fade;
}; };
void k3MixInit(uint32_t sampleRate, uint8_t channels); void k3MixInit(uint32_t sampleRate, uint8_t channels);
@@ -44,6 +45,7 @@ struct k3MixWave *k3MixPowerMeasurement(struct k3MixWave *child);
float k3MixPowerMeasurementGetRMS(struct k3MixWave*); float k3MixPowerMeasurementGetRMS(struct k3MixWave*);
void k3MixStop(struct k3MixWave*); void k3MixStop(struct k3MixWave*);
void k3MixStopSmooth(struct k3MixWave*);
struct k3MixWave *k3MixPlay(struct k3MixWave*); struct k3MixWave *k3MixPlay(struct k3MixWave*);
void k3MixPlayDirect(struct k3MixWave*); void k3MixPlayDirect(struct k3MixWave*);

View File

@@ -253,15 +253,27 @@ static int refresh_texture(struct ResManRes *res) {
int w, h, origN; int w, h, origN;
unsigned char *data = stbi_load(namebuf, &w, &h, &origN, n); unsigned char *data = stbi_load(namebuf, &w, &h, &origN, n);
int stbifree = 1;
if(TextureResolutionReduction && data) { int newW = w, newH = h;
int newW = w >> TextureResolutionReduction;
int newH = h >> TextureResolutionReduction;
if(newW <= 4) newW = 4; if(TextureResolutionReduction) {
if(newH <= 4) newH = 4; newW = newW >> TextureResolutionReduction;
newH = newH >> TextureResolutionReduction;
}
if(newW > k3TexSzMax()) {
newW = k3TexSzMax();
}
if(newH > k3TexSzMax()) {
newH = k3TexSzMax();
}
if(newW < 4) {
newW = 4;
}
if(newH < 4) {
newH = 4;
}
if(newW != w || newH != h) {
unsigned char *data2 = malloc(newW * newH * n); unsigned char *data2 = malloc(newW * newH * n);
int success = stbir_resize_uint8_generic(data, w, h, 0, data2, newW, newH, 0, n, n == 4 ? 3 : -1, 0, STBIR_EDGE_WRAP, STBIR_FILTER_DEFAULT, gamma ? STBIR_COLORSPACE_SRGB : STBIR_COLORSPACE_LINEAR, NULL); int success = stbir_resize_uint8_generic(data, w, h, 0, data2, newW, newH, 0, n, n == 4 ? 3 : -1, 0, STBIR_EDGE_WRAP, STBIR_FILTER_DEFAULT, gamma ? STBIR_COLORSPACE_SRGB : STBIR_COLORSPACE_LINEAR, NULL);
@@ -271,7 +283,6 @@ static int refresh_texture(struct ResManRes *res) {
w = newW; w = newW;
h = newH; h = newH;
data = data2; data = data2;
stbifree = 0;
} else { } else {
free(data2); free(data2);
} }
@@ -283,14 +294,9 @@ static int refresh_texture(struct ResManRes *res) {
if(data) { if(data) {
k3TexUpdate(res->thing, type, 0, w, h, data); k3TexUpdate(res->thing, type, 0, w, h, data);
if(stbifree) {
stbi_image_free(data);
} else {
free(data); free(data);
} }
} }
}
return 1; return 1;
} }

View File

@@ -15,6 +15,10 @@
#include"k3menu.h" #include"k3menu.h"
#include<assert.h> #include<assert.h>
#include"net_hi.h" #include"net_hi.h"
#include"k3particles.h"
#include<GLFW/glfw3.h>
#include"ssort.h"
#include<ctype.h>
/* /*
* This is by far the least clean or well-maintained source in the * This is by far the least clean or well-maintained source in the
@@ -170,6 +174,24 @@ error:
return 0; return 0;
} }
struct mixitem {
void *thing;
#define MIXITEM_SOURCE 0
#define MIXITEM_SOUND 1
#define MIXITEM_QUEUE 2
#define MIXITEM_POWER 3
int type;
};
struct Animator {
struct k3Mdl *mdl;
struct k3Animator animator;
struct k3AnimationBone *bones;
bool playing;
double playStartTime;
};
static int game_addentity(lua_State *L) { static int game_addentity(lua_State *L) {
lua_Integer li; lua_Integer li;
int i; int i;
@@ -666,15 +688,6 @@ static int game_water_disturb(lua_State *L) {
return 0; return 0;
} }
struct mixitem {
void *thing;
#define MIXITEM_SOURCE 0
#define MIXITEM_SOUND 1
#define MIXITEM_QUEUE 2
#define MIXITEM_POWER 3
int type;
};
static int dagame_mixsound(lua_State *L) { static int dagame_mixsound(lua_State *L) {
struct mixitem *i = lua_touserdata(L, 1); struct mixitem *i = lua_touserdata(L, 1);
@@ -711,6 +724,17 @@ static int dagame_mixstop(lua_State *L) {
return 1; return 1;
} }
static int dagame_mixstopsmooth(lua_State *L) {
struct mixitem *i = lua_touserdata(L, 1);
assert(i->type != MIXITEM_SOURCE);
k3MixStopSmooth(i->thing);
lua_pushvalue(L, 1);
return 1;
}
static int dagame_mixpower(lua_State *L) { static int dagame_mixpower(lua_State *L) {
struct mixitem *i = lua_touserdata(L, 1); struct mixitem *i = lua_touserdata(L, 1);
@@ -866,13 +890,15 @@ static int game_ref(lua_State *L) {
} }
static int game_batch(lua_State *L) { static int game_batch(lua_State *L) {
void **r = lua_touserdata(L, 1); void *r = lua_touserdata(L, 1);
struct k3Mdl *mdl; struct k3Mdl *mdl;
if(luaL_testudata(L, 1, "k3water")) { if(luaL_testudata(L, 1, "k3water")) {
mdl = ((struct k3Water*) *r)->mdl; mdl = (*(struct k3Water**) r)->mdl;
} else if(luaL_testudata(L, 1, "k3cpuparticles")) {
mdl = (*(struct k3CPUQuadParticles**) r)->mdl;
} else if(luaL_testudata(L, 1, "k3mdl")) { } else if(luaL_testudata(L, 1, "k3mdl")) {
mdl = *r; mdl = *(struct k3Mdl**) r;
} else return 0; } else return 0;
lua_rawgeti(L, 2, 1); lua_rawgeti(L, 2, 1);
@@ -884,7 +910,28 @@ static int game_batch(lua_State *L) {
lua_pop(L, 3); lua_pop(L, 3);
if(lua_gettop(L) == 3) { struct k3AnimationBone *bones = NULL;
if(lua_gettop(L) >= 4) {
struct Animator *anim = lua_touserdata(L, 4);
if(anim->playing) {
k3AnimatorSet(&anim->animator, glfwGetTime() - anim->playStartTime);
}
bones = anim->bones;
size_t boneCount = k3MdlGetBoneCount(anim->mdl);
for(size_t m = 0; m < boneCount; m++) {
vec3 scaleignore;
mat4 rot;
glm_decompose(anim->animator.inter[m], bones[m].translation, rot, scaleignore);
glm_mat4_quat(anim->animator.inter[m], bones[m].rotation);
}
}
if(lua_gettop(L) >= 3) {
mat4 anchor; mat4 anchor;
for(int i = 0; i < 16; i++) { for(int i = 0; i < 16; i++) {
lua_rawgeti(L, 3, i + 1); lua_rawgeti(L, 3, i + 1);
@@ -895,7 +942,7 @@ static int game_batch(lua_State *L) {
glm_mat4_mul(anchor, m, m); glm_mat4_mul(anchor, m, m);
} }
k3Batch(mdl, m, NULL); k3Batch(mdl, m, bones);
return 0; return 0;
} }
@@ -986,6 +1033,22 @@ static int game_submissive_send(lua_State *L) {
return 0; return 0;
} }
static int dagame_cphysics_add_force(lua_State *L) {
struct CPhysics *c = *(struct CPhysics**) lua_touserdata(L, 1);
dBodyID bid = dGeomGetBody(c->geom);
if(!bid) {
lua_pushboolean(L, false);
return 1;
}
dBodyAddForce(bid, lua_tonumber(L, 2), lua_tonumber(L, 3), lua_tonumber(L, 4));
lua_pushboolean(L, true);
return 1;
}
static int game_cphysics_get(lua_State *L) { static int game_cphysics_get(lua_State *L) {
struct CPhysics *c = *(struct CPhysics**) lua_touserdata(L, 1); struct CPhysics *c = *(struct CPhysics**) lua_touserdata(L, 1);
@@ -1052,7 +1115,7 @@ static int game_cphysics_get(lua_State *L) {
lua_pushnumber(L, c->speed); lua_pushnumber(L, c->speed);
return 1; return 1;
} else if(!strcmp(k, "add_force")) { } else if(!strcmp(k, "add_force")) {
//lua_pushcfunction(L, ); lua_pushcfunction(L, dagame_cphysics_add_force);
return 1; return 1;
} }
@@ -1083,7 +1146,9 @@ static int game_cphysics_set(lua_State *L) {
lua_rawgeti(L, 3, 3); lua_rawgeti(L, 3, 3);
lua_rawgeti(L, 3, 4); lua_rawgeti(L, 3, 4);
dGeomSetQuaternion(c->geom, (dQuaternion) {lua_tonumber(L, -1), lua_tonumber(L, -4), lua_tonumber(L, -3), lua_tonumber(L, -2)}); dQuaternion q = {lua_tonumber(L, -1), lua_tonumber(L, -4), lua_tonumber(L, -3), lua_tonumber(L, -2)};
dGeomSetQuaternion(c->geom, q);
lua_pop(L, 4); lua_pop(L, 4);
} else if(!strcmp(k, "vel")) { } else if(!strcmp(k, "vel")) {
@@ -1280,7 +1345,11 @@ static int game_get(lua_State *L) {
} else if(!strcmp(i, "authority")) { } else if(!strcmp(i, "authority")) {
lua_pushboolean(L, Game.isAuthority); lua_pushboolean(L, Game.isAuthority);
} else if(!strcmp(i, "spectated")) { } else if(!strcmp(i, "spectated")) {
if(Game.spectated == ENT_ID_INVALID) {
lua_pushnil(L);
} else {
lua_pushinteger(L, Game.spectated); lua_pushinteger(L, Game.spectated);
}
} else if(!strcmp(i, "fov")) { } else if(!strcmp(i, "fov")) {
lua_pushnumber(L, LuaapiFov); lua_pushnumber(L, LuaapiFov);
} else if(!strcmp(i, "rate")) { } else if(!strcmp(i, "rate")) {
@@ -1491,7 +1560,6 @@ static int game_load(lua_State *L) {
static int dagame_cleanup(lua_State *L) { static int dagame_cleanup(lua_State *L) {
luaapi_cleanup(); luaapi_cleanup();
LuaapiCamFocus = false;
return 0; return 0;
} }
@@ -1597,7 +1665,7 @@ static int dagame_mdl(lua_State *L) {
vertexCount = lua_tointeger(L, -1) / 3; vertexCount = lua_tointeger(L, -1) / 3;
lua_pop(L, 1); lua_pop(L, 1);
positions = malloc(sizeof(*positions) * vertexCount); positions = calloc(vertexCount, sizeof(*positions));
for(size_t i = 0; i < vertexCount; i++) { for(size_t i = 0; i < vertexCount; i++) {
lua_geti(L, -1, i * 3 + 1); lua_geti(L, -1, i * 3 + 1);
@@ -1615,7 +1683,7 @@ static int dagame_mdl(lua_State *L) {
indexCount = lua_tointeger(L, -1); indexCount = lua_tointeger(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
indices = malloc(sizeof(*indices) * indexCount); indices = calloc(indexCount, sizeof(*indices));
for(size_t i = 0; i < indexCount; i++) { for(size_t i = 0; i < indexCount; i++) {
lua_geti(L, -1, i + 1); lua_geti(L, -1, i + 1);
@@ -1637,7 +1705,7 @@ static int dagame_mdl(lua_State *L) {
return 0; return 0;
} }
normals = malloc(sizeof(*normals) * 3 * vertexCount); normals = calloc(vertexCount, sizeof(*normals) * 3);
for(size_t i = 0; i < vertexCount; i++) { for(size_t i = 0; i < vertexCount; i++) {
lua_geti(L, -1, i * 3 + 1); lua_geti(L, -1, i * 3 + 1);
@@ -1660,7 +1728,7 @@ static int dagame_mdl(lua_State *L) {
return 0; return 0;
} }
uvs = malloc(sizeof(*uvs) * vertexCount); uvs = calloc(vertexCount, sizeof(*uvs));
for(size_t i = 0; i < vertexCount; i++) { for(size_t i = 0; i < vertexCount; i++) {
lua_geti(L, -1, i * 2 + 1); lua_geti(L, -1, i * 2 + 1);
@@ -1858,7 +1926,7 @@ static int dagame_draw(lua_State *L) {
float b = lua_type(L, -2) == LUA_TNUMBER ? lua_tonumber(L, -2) : 1; float b = lua_type(L, -2) == LUA_TNUMBER ? lua_tonumber(L, -2) : 1;
float a = lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : 1; float a = lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : 1;
k3BatchAdd(tex, (struct k3RectF) {.x = sx, .y = sy, .w = sw, .h = sh}, (struct k3RectF) {.x = x, .y = y, .w = w, .h = h}, 0, (vec4) {r, g, b, a}); k3BatchAdd(tex, (struct k3RectF) {.x = sx, .y = sy, .w = sw, .h = sh}, (struct k3RectF) {.x = x, .y = y, .w = w, .h = h}, 0, (vec4) {r, g, b, a}, 0);
lua_pop(L, 13); lua_pop(L, 13);
} else { } else {
@@ -2156,9 +2224,9 @@ static int dagame_set_texture_reduction(lua_State *L) {
} }
int PeercodeHandler = LUA_NOREF; int PeercodeHandler = LUA_NOREF;
static void get_peercode_callback(void *ud, const char *peercode_bin) { static void get_peercode_callback(void *ud, struct StoonPeercode *peercode_bin) {
char peercode[STOON_CONN_INFO_SIZE * 2 + 1] = {}; char peercode[sizeof(*peercode_bin) * 2 + 1] = {};
for(int i = 0; i < STOON_CONN_INFO_SIZE; i++) { for(int i = 0; i < sizeof(*peercode_bin); i++) {
snprintf(peercode + i * 2, 3, "%02x", ((uint8_t*) peercode_bin)[i]); snprintf(peercode + i * 2, 3, "%02x", ((uint8_t*) peercode_bin)[i]);
} }
@@ -2228,11 +2296,11 @@ static int get_peercode_bin(const char *peercode, char *peercode_bin) {
if(!peercode) return 0; if(!peercode) return 0;
if(!peercode_bin) return 0; if(!peercode_bin) return 0;
if(strlen(peercode) < 2 * STOON_CONN_INFO_SIZE) { if(strlen(peercode) < 2 * sizeof(struct StoonPeercode)) {
return 0; return 0;
} }
for(int i = 0; i < STOON_CONN_INFO_SIZE; i++) { for(int i = 0; i < sizeof(struct StoonPeercode); i++) {
int b = 0; int b = 0;
if(peercode[i * 2 + 0] >= '0' && peercode[i * 2 + 0] <= '9') { if(peercode[i * 2 + 0] >= '0' && peercode[i * 2 + 0] <= '9') {
@@ -2260,8 +2328,8 @@ static int dagame_net_host(lua_State *L) {
} }
static int dagame_net_join(lua_State *L) { static int dagame_net_join(lua_State *L) {
char peercode[STOON_CONN_INFO_SIZE]; struct StoonPeercode peercode;
if(!get_peercode_bin(lua_tostring(L, 1), peercode)) { if(!get_peercode_bin(lua_tostring(L, 1), &peercode)) {
lua_pushliteral(L, "Invalid peercode"); lua_pushliteral(L, "Invalid peercode");
lua_error(L); lua_error(L);
return 0; return 0;
@@ -2269,20 +2337,20 @@ static int dagame_net_join(lua_State *L) {
net_hi_setup(false); net_hi_setup(false);
lua_pushboolean(L, net_hi_connect(peercode)); lua_pushboolean(L, net_hi_connect(&peercode));
return 1; return 1;
} }
static int dagame_net_punch(lua_State *L) { static int dagame_net_punch(lua_State *L) {
char peercode[STOON_CONN_INFO_SIZE]; struct StoonPeercode peercode;
if(!get_peercode_bin(lua_tostring(L, 1), peercode)) { if(!get_peercode_bin(lua_tostring(L, 1), &peercode)) {
lua_pushliteral(L, "Invalid peercode"); lua_pushliteral(L, "Invalid peercode");
lua_error(L); lua_error(L);
return 0; return 0;
} }
net_hi_add_punch(peercode); net_hi_add_punch(&peercode);
return 0; return 0;
} }
@@ -2348,12 +2416,277 @@ static int dagame_mdl_desc_append(lua_State *L) {
return 0; return 0;
} }
#include<GLFW/glfw3.h>
static int os_time(lua_State *L) { static int os_time(lua_State *L) {
lua_pushnumber(L, glfwGetTime() - LuaapiStartTime); lua_pushnumber(L, isnan(LuaapiStartTime) ? 0 : glfwGetTime() - LuaapiStartTime);
return 1; return 1;
} }
static int dagame_particle_system(lua_State *L) {
struct k3CPUQuadParticles *qp = calloc(1, sizeof(*qp));
qp->capacity = lua_tointeger(L, 1);
qp->origin[0] = 0;
qp->origin[1] = 0;
qp->origin[2] = 0;
qp->emissionEnabled = true;
qp->emissionRate = 100;
qp->emissionConeDirection[0] = 0;
qp->emissionConeDirection[1] = 1;
qp->emissionConeDirection[2] = 0;
qp->emissionConeAngle = M_PI / 2;
qp->gravity[0] = 0;
qp->gravity[1] = 0.03;
qp->gravity[2] = 0;
qp->particleLifetime = 4;
qp->colorStart[0] = 1;
qp->colorStart[1] = 1;
qp->colorStart[2] = 1;
qp->colorStart[3] = 1;
qp->colorEnd[0] = 1;
qp->colorEnd[1] = 1;
qp->colorEnd[2] = 1;
qp->colorEnd[3] = 0;
struct k3Mat *mat = *(struct k3Mat**) lua_touserdata(L, 2);
/*struct k3Mat mat = {
.primitive = {
.diffuse = {1, 1, 1, 1},
.specular = {0, 0, 0, 0},
.emission = {0, 0, 0, 0},
.shininess = 16,
},
.passes = {
{
.unitsUsed = 0,
.aabb = NAN,
.transparent = true,
.nocull = false,
.alphatest = false,
.depthwrite = false,
}
},
};*/
k3CPUQuadParticlesInit(qp, mat);
void **z = lua_newuserdata(L, sizeof(*z));
*z = qp;
luaL_setmetatable(L, "k3cpuparticles");
return 1;
}
static int dagame_k3cpuparticles_update(lua_State *L) {
struct k3CPUQuadParticles *qp = *(void**) lua_touserdata(L, 1);
k3CPUQuadParticlesUpdate(qp, lua_tonumber(L, 2), &LuaapiCamMatrix[0], &LuaapiCamMatrix[1], &LuaapiCamMatrix[2]);
lua_pushvalue(L, 1);
return 1;
}
static int dagame_k3cpuparticles_set(lua_State *L) {
struct k3CPUQuadParticles *qp = *(void**) lua_touserdata(L, 1);
const char *key = lua_tostring(L, 2);
if(!strcmp(key, "origin")) {
lua_geti(L, 3, 1);
lua_geti(L, 3, 2);
lua_geti(L, 3, 3);
qp->origin[0] = lua_tonumber(L, -3);
qp->origin[1] = lua_tonumber(L, -2);
qp->origin[2] = lua_tonumber(L, -1);
lua_pop(L, 3);
} else if(!strcmp(key, "enabled")) {
qp->emissionEnabled = lua_toboolean(L, 3);
} else if(!strcmp(key, "rate")) {
qp->emissionRate = lua_tonumber(L, 3);
} else if(!strcmp(key, "cone_direction")) {
lua_geti(L, 3, 1);
lua_geti(L, 3, 2);
lua_geti(L, 3, 3);
qp->emissionConeDirection[0] = lua_tonumber(L, -3);
qp->emissionConeDirection[1] = lua_tonumber(L, -2);
qp->emissionConeDirection[2] = lua_tonumber(L, -1);
lua_pop(L, 3);
} else if(!strcmp(key, "cone_angle")) {
qp->emissionConeAngle = lua_tonumber(L, 3);
} else if(!strcmp(key, "gravity")) {
lua_geti(L, 3, 1);
lua_geti(L, 3, 2);
lua_geti(L, 3, 3);
qp->gravity[0] = lua_tonumber(L, -3);
qp->gravity[1] = lua_tonumber(L, -2);
qp->gravity[2] = lua_tonumber(L, -1);
lua_pop(L, 3);
} else if(!strcmp(key, "lifetime")) {
qp->particleLifetime = lua_tonumber(L, 3);
} else if(!strcmp(key, "remaining")) {
qp->emissionLifetime = lua_tonumber(L, 3);
} else if(!strcmp(key, "color_start")) {
lua_geti(L, 3, 1);
lua_geti(L, 3, 2);
lua_geti(L, 3, 3);
lua_geti(L, 3, 4);
qp->colorStart[0] = lua_tonumber(L, -4);
qp->colorStart[1] = lua_tonumber(L, -3);
qp->colorStart[2] = lua_tonumber(L, -2);
qp->colorStart[3] = lua_tonumber(L, -1);
lua_pop(L, 4);
} else if(!strcmp(key, "color_end")) {
lua_geti(L, 3, 1);
lua_geti(L, 3, 2);
lua_geti(L, 3, 3);
lua_geti(L, 3, 4);
qp->colorEnd[0] = lua_tonumber(L, -4);
qp->colorEnd[1] = lua_tonumber(L, -3);
qp->colorEnd[2] = lua_tonumber(L, -2);
qp->colorEnd[3] = lua_tonumber(L, -1);
lua_pop(L, 4);
}
return 0;
}
static int dagame_k3cpuparticles_get(lua_State *L) {
struct k3CPUQuadParticles *qp = *(void**) lua_touserdata(L, 1);
const char *key = lua_tostring(L, 2);
if(!strcmp(key, "update")) {
lua_pushcfunction(L, dagame_k3cpuparticles_update);
return 1;
} else if(!strcmp(key, "remaining")) {
lua_pushnumber(L, qp->emissionLifetime);
return 1;
} else if(!strcmp(key, "count")) {
lua_pushinteger(L, qp->count);
return 1;
}
return 0;
}
#include"noise1234.h"
static int dagame_perlin3(lua_State *L) {
lua_pushnumber(L, noise3(lua_tonumber(L, 1), lua_tonumber(L, 2), lua_tonumber(L, 3)));
return 1;
}
static int dagame_fbm(lua_State *L) {
float x = lua_tonumber(L, 1);
float y = lua_tonumber(L, 2);
float z = lua_tonumber(L, 3);
int octaves = lua_type(L, 4) == LUA_TNIL ? 8 : lua_tointeger(L, 4);
float lacunarity = lua_type(L, 5) == LUA_TNIL ? 2 : lua_tonumber(L, 5);
float gain = lua_type(L, 6) == LUA_TNIL ? 0.5 : lua_tonumber(L, 6);
float sum = 0;
float freq = 1;
float amp = 1;
for(int o = 0; o < octaves; o++) {
sum += amp * noise3(x * freq, y * freq, z * freq);
amp *= gain;
freq *= lacunarity;
}
lua_pushnumber(L, sum);
return 1;
}
static int dagame_kill(lua_State *L) {
if(lua_type(L, 1) != LUA_TNUMBER) {
return luaL_error(L, "Invalid entity ID");
}
game_killentity(lua_tointeger(L, 1));
}
static int dagame_animator(lua_State *L) {
struct Animator *this = lua_newuserdata(L, sizeof(*this));
this->mdl = *(struct k3Mdl**) lua_touserdata(L, 1);
memset(&this->animator, 0, sizeof(this->animator));
size_t boneCount = k3MdlGetBoneCount(this->mdl);
this->bones = _mm_malloc(boneCount * sizeof(*this->bones), 16);
for(size_t b = 0; b < boneCount; b++) {
this->bones[b].translation[0] = 0;
this->bones[b].translation[1] = 0;
this->bones[b].translation[2] = 0;
this->bones[b].translation[3] = 1;
this->bones[b].rotation[0] = 0;
this->bones[b].rotation[1] = 0;
this->bones[b].rotation[2] = 0;
this->bones[b].rotation[3] = 1;
}
luaL_setmetatable(L, "k4animator");
return 1;
}
static int dagame_animator_set(lua_State *L) {
struct Animator *this = lua_touserdata(L, 1);
size_t animIdx = lua_tointeger(L, 2);
this->animator.base = k3MdlGetAnim(this->mdl, animIdx);
this->animator.loop = false;
this->playStartTime = glfwGetTime();
k3AnimatorSet(&this->animator, 0);
lua_pushvalue(L, 1);
return 1;
}
static int dagame_animator_play(lua_State *L) {
struct Animator *this = lua_touserdata(L, 1);
this->playing = true;
this->playStartTime = glfwGetTime();
}
static int dagame_animator_index(lua_State *L) {
struct Animator *this = lua_touserdata(L, 1);
const char *key = lua_tostring(L, 2);
if(!strcmp(key, "set")) {
lua_pushcfunction(L, dagame_animator_set);
return 1;
} else if(!strcmp(key, "play")) {
lua_pushcfunction(L, dagame_animator_play);
return 1;
} else if(!strcmp(key, "time")) {
lua_pushnumber(L, this->animator.time);
return 1;
} else if(!strcmp(key, "loop")) {
lua_pushboolean(L, this->animator.loop);
return 1;
}
return 0;
}
static int dagame_animator_newindex(lua_State *L) {
struct Animator *this = lua_touserdata(L, 1);
const char *key = lua_tostring(L, 2);
if(!strcmp(key, "time")) {
k3AnimatorSet(&this->animator, lua_tonumber(L, 3));
} else if(!strcmp(key, "loop")) {
this->animator.loop = lua_toboolean(L, 3);
}
return 0;
}
void luaapi_init() { void luaapi_init() {
k3Log(k3_DEBUG, "Creating Lua environment"); k3Log(k3_DEBUG, "Creating Lua environment");
@@ -2435,6 +2768,9 @@ void luaapi_init() {
lua_pushcfunction(L, dagame_mixstop); lua_pushcfunction(L, dagame_mixstop);
lua_setfield(L, -2, "stop"); lua_setfield(L, -2, "stop");
lua_pushcfunction(L, dagame_mixstopsmooth);
lua_setfield(L, -2, "stopsmooth");
lua_pushcfunction(L, game_mixqueue); lua_pushcfunction(L, game_mixqueue);
lua_setfield(L, -2, "queue"); lua_setfield(L, -2, "queue");
@@ -2496,6 +2832,21 @@ void luaapi_init() {
lua_pushcfunction(L, dagame_set_texture_reduction); lua_pushcfunction(L, dagame_set_texture_reduction);
lua_setfield(L, -2, "set_texture_reduction"); lua_setfield(L, -2, "set_texture_reduction");
lua_pushcfunction(L, dagame_particle_system);
lua_setfield(L, -2, "particle_system");
lua_pushcfunction(L, dagame_perlin3);
lua_setfield(L, -2, "perlin3");
lua_pushcfunction(L, dagame_fbm);
lua_setfield(L, -2, "fbm3");
lua_pushcfunction(L, dagame_kill);
lua_setfield(L, -2, "kill");
lua_pushcfunction(L, dagame_animator);
lua_setfield(L, -2, "animator");
k3Log(k3_DEBUG, "Creating table game.ui"); k3Log(k3_DEBUG, "Creating table game.ui");
lua_newtable(L); lua_newtable(L);
lua_pushcfunction(L, dagame_ui_screen); lua_pushcfunction(L, dagame_ui_screen);
@@ -2753,9 +3104,33 @@ void luaapi_init() {
lua_pushcfunction(L, os_time); lua_pushcfunction(L, os_time);
lua_setfield(L, -2, "time"); lua_setfield(L, -2, "time");
lua_setglobal(L, "os"); lua_setglobal(L, "os");
luaL_newmetatable(L, "k3cpuparticles");
lua_pushcfunction(L, dagame_k3cpuparticles_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, dagame_k3cpuparticles_get);
lua_setfield(L, -2, "__index");
lua_pushboolean(L, 0);
lua_setfield(L, -2, "__metatable");
lua_pop(L, 1);
luaL_newmetatable(L, "k4animator");
lua_pushcfunction(L, dagame_animator_index);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, dagame_animator_newindex);
lua_setfield(L, -2, "__newindex");
lua_pushboolean(L, 0);
lua_setfield(L, -2, "__metatable");
lua_pop(L, 1);
} }
void luaapi_load(const char *name) { void luaapi_load(const char *name) {
LuaapiStartTime = NAN;
lua_getglobal(L, "require"); lua_getglobal(L, "require");
lua_pushstring(L, name); lua_pushstring(L, name);
if(lua_pcall(L, 1, 1, 0) != LUA_OK) { if(lua_pcall(L, 1, 1, 0) != LUA_OK) {
@@ -2766,7 +3141,7 @@ void luaapi_load(const char *name) {
lua_getfield(L, -1, "load"); lua_getfield(L, -1, "load");
if(lua_pcall(L, 0, 0, 0) != LUA_OK) { if(lua_pcall(L, 0, 0, 0) != LUA_OK) {
puts(lua_tostring(L, -1)); k3Log(k3_ERR, "%s", lua_tostring(L, -1));
lua_pop(L, 1); lua_pop(L, 1);
return; return;
} }
@@ -2774,6 +3149,8 @@ void luaapi_load(const char *name) {
if(Game.isAuthority) { if(Game.isAuthority) {
luaapi_join(NULL, 0); luaapi_join(NULL, 0);
} }
LuaapiStartTime = glfwGetTime();
} }
void luaapi_render(double dt, double alpha) { void luaapi_render(double dt, double alpha) {
@@ -2908,26 +3285,99 @@ static const char *k3glslloader(const char *fn) {
return data; return data;
} }
#define KV_STORE_SIZE 128
struct KVPair {
char *key;
char *value;
};
typedef struct KVPair KVStore[KV_STORE_SIZE];
static intmax_t kvpair_compare(const void *a_, const void *b_) {
const struct KVPair *a = a_;
const struct KVPair *b = b_;
if(!a->key) {
return 1;
} else if(!b->key) {
return -1;
}
return strcmp(a->key, b->key);
}
static char *kvstore_tostring(KVStore store) {
ssort(store, KV_STORE_SIZE, sizeof(struct KVPair), kvpair_compare);
const size_t sz = 2048;
char *ret = calloc(1, sz);
for(size_t i = 0; i < KV_STORE_SIZE; i++) {
if(store[i].key == NULL) {
break;
}
char def[256];
snprintf(def, sizeof(def), "%s\x1F%s\x1E", store[i].key, store[i].value);
strncat(ret, def, sz - strlen(ret) - 1);
}
return ret;
}
static bool kvstore_add(KVStore store, char *key, char *value) {
for(size_t i = 0; i < KV_STORE_SIZE; i++) {
if(store[i].key == NULL) {
store[i].key = key;
store[i].value = value;
return true;
}
}
return false;
}
static bool kvstore_add_fmt(KVStore store, char *key, const char *format, ...) {
va_list vl;
va_start(vl, format);
va_list vl2;
va_copy(vl2, vl);
size_t len = vsnprintf(NULL, 0, format, vl2);
char *def = malloc(len);
vsnprintf(def, len, format, vl);
va_end(vl);
va_end(vl2);
return kvstore_add(store, key, def);
}
static void kvstore_free(KVStore store) {
for(size_t i = 0; i < KV_STORE_SIZE; i++) {
free(store[i].key);
free(store[i].value);
}
}
// The glsl field of a material table is cached and stored // The glsl field of a material table is cached and stored
// in the resource manager. This function generates its name. // in the resource manager. This function generates its name.
static char *glsl_table_fullname() { static char *glsl_table_fullname() {
KVStore store = {};
lua_getfield(L, -1, "vs"); lua_getfield(L, -1, "vs");
lua_geti(L, -1, 1); // Version lua_geti(L, -1, 1); // Version
size_t vsVer = lua_tointeger(L, -1); size_t vsVer = lua_tointeger(L, -1);
lua_geti(L, -2, 2); // Filename lua_geti(L, -2, 2); // Filename
char *vsFile = strdup(lua_tostring(L, -1)); kvstore_add(store, strdup("vs"), strdup(lua_tostring(L, -1)));
kvstore_add_fmt(store, strdup("vsv"), "%lu", vsVer);
lua_pop(L, 3); lua_pop(L, 3);
lua_getfield(L, -1, "fs"); lua_getfield(L, -1, "fs");
lua_geti(L, -1, 1); // Version lua_geti(L, -1, 1); // Version
size_t fsVer = lua_tointeger(L, -1); size_t fsVer = lua_tointeger(L, -1);
lua_geti(L, -2, 2); // Filename lua_geti(L, -2, 2); // Filename
char *fsFile = strdup(lua_tostring(L, -1)); kvstore_add(store, strdup("fs"), strdup(lua_tostring(L, -1)));
kvstore_add_fmt(store, strdup("fsv"), "%lu", fsVer);
lua_pop(L, 3); lua_pop(L, 3);
char ret[1024];
snprintf(ret, sizeof(ret), "\x1E%u\x1E%s\x1E%u\x1E%s\x1E", vsVer, vsFile, fsVer, fsFile);
lua_getfield(L, -1, "defs"); lua_getfield(L, -1, "defs");
lua_pushnil(L); lua_pushnil(L);
while(lua_next(L, -2)) { while(lua_next(L, -2)) {
@@ -2937,19 +3387,17 @@ static char *glsl_table_fullname() {
continue; continue;
} }
char def[128]; kvstore_add(store, strdup(lua_tostring(L, -2)), strdup(lua_tostring(L, -1)));
snprintf(def, sizeof(def), "%s\x1F%s\x1E", lua_tostring(L, -2), lua_tostring(L, -1));
strncat(ret, def, sizeof(ret) - strlen(ret) - 1);
lua_pop(L, 1); lua_pop(L, 1);
} }
lua_pop(L, 1); lua_pop(L, 1);
free(vsFile); char *fullname = kvstore_tostring(store);
free(fsFile);
return strdup(ret); kvstore_free(store);
return fullname;
} }
static int parse_glsl_table(struct k3Mat *mat) { static int parse_glsl_table(struct k3Mat *mat) {
@@ -3211,6 +3659,10 @@ void luaapi_fillmaterial_direct(struct k3Mat *mat) {
mat->passes[0].alphatest = lua_toboolean(L, -1); mat->passes[0].alphatest = lua_toboolean(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, -1, "depthwrite");
mat->passes[0].depthwrite = lua_isnil(L, -1) ? true : lua_toboolean(L, -1);
lua_pop(L, 1);
lua_getfield(L, -1, "aabb"); lua_getfield(L, -1, "aabb");
mat->passes[0].aabb = lua_isnil(L, -1) ? NAN : lua_tonumber(L, -1); mat->passes[0].aabb = lua_isnil(L, -1) ? NAN : lua_tonumber(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
@@ -3417,6 +3869,9 @@ struct k3Light *luaapi_getlights(size_t *count) {
ret[i].dir.direction[3] = lua_tonumber(L, -1); ret[i].dir.direction[3] = lua_tonumber(L, -1);
glm_vec3_normalize(ret[i].dir.direction); glm_vec3_normalize(ret[i].dir.direction);
lua_pop(L, 5); lua_pop(L, 5);
lua_getfield(L, -1, "cascades");
ret[i].dir.cascadeCount = lua_tointeger(L, -1);
lua_pop(L, 1);
} }
lua_pop(L, 1); lua_pop(L, 1);
} }
@@ -3428,6 +3883,8 @@ struct k3Light *luaapi_getlights(size_t *count) {
} }
void luaapi_cleanup() { void luaapi_cleanup() {
LuaapiCamFocus = false;
game_cleanup(); game_cleanup();
lua_getglobal(L, "game"); lua_getglobal(L, "game");

View File

@@ -46,6 +46,7 @@ static int TextureResolutionReduction = 0;
static int IrregularShadows = 0; static int IrregularShadows = 0;
static int InstantCamShift = 5;
static float CamPitch, CamYaw; static float CamPitch, CamYaw;
static vec3 CamPos; static vec3 CamPos;
static int ThirdPerson = 1; static int ThirdPerson = 1;
@@ -169,8 +170,10 @@ static void charcallback(GLFWwindow *window, unsigned int codepoint) {
} }
} }
static void fix_resol();
static void resizecallback(GLFWwindow *window, int width, int height) { static void resizecallback(GLFWwindow *window, int width, int height) {
k3Resize(width, height); k3Resize(width, height);
fix_resol();
} }
static int argc; static int argc;
@@ -184,86 +187,6 @@ const char *k4_get_arg(const char *name) {
return NULL; return NULL;
} }
/*static void netwrap_step() {
if(NetWrap.stage && CurrentTime >= NetWrap.timeout) {
if(NetWrap.stage == 1) {
if(stoon_req(&NetWrap.stoon)) {
if(stoon_listen(&NetWrap.stoon)) {
uint8_t conndata[STOON_CONN_INFO_SIZE] = {};
stoon_serialize(&NetWrap.stoon, conndata);
char str[STOON_CONN_INFO_SIZE * 2 + 1] = {};
for(int i = 0; i < sizeof(conndata); i++) {
snprintf(str + i * 2, 3, "%02x", conndata[i]);
}
luaapi_peercode_found(str);
NetWrap.stage = 2;
} else {
k3Log(k3_INFO, "Stoon listen timeout.");
NetWrap.timeout = CurrentTime + 0.5;
}
} else {
k3Log(k3_INFO, "Stoon request failed.");
NetWrap.timeout = CurrentTime + 0.5;
}
} else if(NetWrap.stage == 2) {
stoon_keepalive(&NetWrap.stoon);
NetWrap.timeout = CurrentTime + 1;
} else if(NetWrap.stage == 3) {
if(NetWrap.isHost) {
stoon_kill(&NetWrap.stoon);
net_server_init();
NetWrap.stage = 4;
}
} else if(NetWrap.stage == 4) {
if(NetWrap.isHost) {
ENetBuffer buf = {.data = "Punch!", .dataLength = 6};
ENetHost *h = net_server_get_enethost();
for(size_t i = 0; i < NETWRAP_BACKLOG; i++) {
if(NetWrap.otherpeersActive[i]) {
ENetAddress v4 = {}, v6 = {};
stoonpeer_to_enets(NetWrap.otherpeers[i], &v4, &v6);
enet_socket_send(h->socket, &v4, &buf, 1);
enet_socket_send(h->socket, &v6, &buf, 1);
}
}
} else {
stoon_keepalive(&NetWrap.stoon);
}
NetWrap.timeout = CurrentTime + 1;
} else if(NetWrap.stage == 5) {
if(!NetWrap.isHost) {
char ip[64];
int port;
if(*(uint16_t*) (NetWrap.otherpeer + 22) == 0) {
inet_ntop(AF_INET, NetWrap.otherpeer, ip, sizeof(ip));
port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 4));
} else {
inet_ntop(AF_INET6, NetWrap.otherpeer + 6, ip, sizeof(ip));
port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 22));
}
printf("Trying [%s]:%u\n", ip, port);
net_client_init();
if(net_client_connect(ip, port)) {
NetWrap.stage = 5;
}
}
NetWrap.timeout = CurrentTime + 0.5;
} else {
NetWrap.timeout = CurrentTime + 1;
}
}
}*/
#include<signal.h> #include<signal.h>
void k4k3LogCallback(enum k3LogLevel lvl, const char *str, size_t len) { void k4k3LogCallback(enum k3LogLevel lvl, const char *str, size_t len) {
static const char *prefixes[] = { static const char *prefixes[] = {
@@ -304,6 +227,7 @@ static int eng_init() {
GameWnd = glfwCreateWindow(START_WIDTH, START_HEIGHT, START_TITLE, NULL, NULL); GameWnd = glfwCreateWindow(START_WIDTH, START_HEIGHT, START_TITLE, NULL, NULL);
} }
// Attempt compatibility
if(!GameWnd) { if(!GameWnd) {
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE);
@@ -376,7 +300,7 @@ static void fix_resol() {
} }
static void eng_ui_init() { static void eng_ui_init() {
set_ui_mode(1); set_ui_mode(!!UiActive);
} }
static void fps_counter_step(double newDT) { static void fps_counter_step(double newDT) {
@@ -415,6 +339,7 @@ static int gr_shadowmap_init() {
"!!ARBfp1.0\n" "!!ARBfp1.0\n"
"TEMP col;\n" "TEMP col;\n"
"TEX col, fragment.texcoord, texture[0], 2D;\n" "TEX col, fragment.texcoord, texture[0], 2D;\n"
"MOV result.color, col;\n"
"MAD col.xyz, -col, 29.9, 30.1;\n" "MAD col.xyz, -col, 29.9, 30.1;\n"
"RCP col.x, col.x;\n" "RCP col.x, col.x;\n"
"RCP col.y, col.y;\n" "RCP col.y, col.y;\n"
@@ -459,32 +384,17 @@ static int gr_lowres(int newW, int newH) {
} }
k3TexUpdate(lowresDepth, k3_DEPTH, 0, newW, newH, NULL); k3TexUpdate(lowresDepth, k3_DEPTH, 0, newW, newH, NULL);
lowresOffscreen = k3OffscreenCreate(lowres, lowresDepth); lowresOffscreen = k3OffscreenCreateMultisampled(lowres, lowresDepth, 4);
} }
return !!lowresOffscreen; return !!lowresOffscreen;
} }
#define MAX_RAYS 64
static struct LocalRay RaysToCast[MAX_RAYS];
static size_t RaysToCastCount = 0;
struct LocalRay *request_ray(struct LocalRay *lr) {
if(RaysToCastCount == MAX_RAYS) {
return NULL;
}
memcpy(RaysToCast + RaysToCastCount, lr, sizeof(*lr));
return &RaysToCast[RaysToCastCount++];
}
int main(int argc_, char **argv_) { int main(int argc_, char **argv_) {
argc = argc_; argc = argc_;
argv = argv_; argv = argv_;
eng_init(); eng_init();
eng_ui_init();
gr_shadowmap_init(); gr_shadowmap_init();
gr_bloom_init(); gr_bloom_init();
@@ -504,7 +414,7 @@ int main(int argc_, char **argv_) {
luaapi_load(k4_get_arg("script") ? k4_get_arg("script") : "init"); luaapi_load(k4_get_arg("script") ? k4_get_arg("script") : "init");
// //
LuaapiStartTime = glfwGetTime(); eng_ui_init();
LastTime = glfwGetTime(); LastTime = glfwGetTime();
@@ -557,9 +467,6 @@ int main(int argc_, char **argv_) {
} }
} }
game_raycast(RaysToCast, RaysToCastCount);
RaysToCastCount = 0;
while(accumulator >= 1. / GAME_TPS) { while(accumulator >= 1. / GAME_TPS) {
for(size_t i = 0; i < Game.entities.renderCount; i++) { for(size_t i = 0; i < Game.entities.renderCount; i++) {
glm_vec4_copy(Game.entities.render[i].pos, Game.entities.render[i].posLast); glm_vec4_copy(Game.entities.render[i].pos, Game.entities.render[i].posLast);
@@ -586,10 +493,10 @@ int main(int argc_, char **argv_) {
glfwGetFramebufferSize(GameWnd, &width, &height); glfwGetFramebufferSize(GameWnd, &width, &height);
mat4 proj; mat4 proj;
glm_perspective(glm_rad(LuaapiFov), (float) width / height, 0.01f, 100.f, proj); glm_perspective(glm_rad(LuaapiFov), (float) width / height, 0.1f, 80.f, proj);
/* Third-person camera movement */ /* Third-person camera movement */
struct LocalRay camray; struct LocalRay camray = {};
if(Game.spectated != ENT_ID_INVALID) { if(Game.spectated != ENT_ID_INVALID) {
struct CRender *c = game_getcomponent(Game.spectated, render); struct CRender *c = game_getcomponent(Game.spectated, render);
if(c) { if(c) {
@@ -610,12 +517,20 @@ int main(int argc_, char **argv_) {
} }
mat4 cam; mat4 cam;
if(InstantCamShift) {
InstantCamShift--;
}
if(LuaapiFirstPerson) { if(LuaapiFirstPerson) {
struct CRender *c = game_getcomponent(Game.spectated, render); struct CRender *cr = game_getcomponent(Game.spectated, render);
struct CPhysics *cp = game_getcomponent(Game.spectated, physics);
if(c) { if(cr) {
vec3 p; vec3 p;
glm_vec3_lerp(c->posLast, c->pos, alpha, p); glm_vec3_lerp(cr->posLast, cr->pos, alpha, p);
if(cp && cp->type == CPHYSICS_CAPSULE) {
p[1] += cp->capsule.length / 2;
}
mat4 view; mat4 view;
glm_look(p, cameraForwardDir, (vec3) {0, 1, 0}, view); glm_look(p, cameraForwardDir, (vec3) {0, 1, 0}, view);
@@ -628,10 +543,15 @@ int main(int argc_, char **argv_) {
vec3 almostThere; vec3 almostThere;
if(LuaapiCamFocus) { if(LuaapiCamFocus) {
float lerpa = InstantCamShift ? 1 : 0.1;
glm_vec3_copy(LuaapiCamFocusPos, almostThere); glm_vec3_copy(LuaapiCamFocusPos, almostThere);
glm_vec3_lerp(CamPos, almostThere, 0.1, CamPos); glm_vec3_lerp(CamPos, almostThere, 0.1, CamPos);
glm_vec3_copy(LuaapiCamFocusPos, CamPos);
glm_look(CamPos, LuaapiCamFocusDir, (vec3) {0, 1, 0}, cam); glm_look(CamPos, LuaapiCamFocusDir, (vec3) {0, 1, 0}, cam);
} else { } else {
float lerpa = InstantCamShift ? 1 : 0.2;
vec3 dirneg; vec3 dirneg;
glm_vec3_negate_to(camray.dir, dirneg); glm_vec3_negate_to(camray.dir, dirneg);
@@ -745,7 +665,7 @@ int main(int argc_, char **argv_) {
// Shadowmap debugging // Shadowmap debugging
if(glfwGetKey(GameWnd, GLFW_KEY_F5) == GLFW_PRESS) { if(glfwGetKey(GameWnd, GLFW_KEY_F5) == GLFW_PRESS) {
k3BlitToScreen(shadowmapOffscreen, 0); k3BlitToScreenEffect(shadowmapOffscreen, 0, k3_ARBFRAG, shadowmapDebugThing, NULL);
} }
glfwSwapBuffers(GameWnd); glfwSwapBuffers(GameWnd);

View File

@@ -26,11 +26,7 @@ void net_client_init() {
Game.isAuthority = 0; Game.isAuthority = 0;
} }
bool net_client_connect(const char *addr, uint16_t port) { bool net_client_connect(ENetAddress eaddr) {
ENetAddress eaddr;
enet_address_set_host(&eaddr, addr);
eaddr.port = port;
peer = enet_host_connect(host, &eaddr, 1, 0); peer = enet_host_connect(host, &eaddr, 1, 0);
ENetEvent ev; ENetEvent ev;

View File

@@ -1,7 +1,9 @@
#pragma once #pragma once
#include"enet.h"
void net_client_init(); void net_client_init();
bool net_client_connect(const char *addr, uint16_t port); bool net_client_connect(ENetAddress addr);
void net_client_receive(); void net_client_receive();
void net_client_update(); void net_client_update();
void net_client_dejitter(); void net_client_dejitter();

View File

@@ -7,9 +7,15 @@
#include"net_server.h" #include"net_server.h"
#include"net_client.h" #include"net_client.h"
#include<math.h> #include<math.h>
#include"k3.h"
/*
* Handles networking on a higher-level, combining hole punching with
* basic client & server interface
* */
static void *ReqPeercodeUD; static void *ReqPeercodeUD;
static void(*ReqPeercodeCB)(void*, const char *peercode); static void(*ReqPeercodeCB)(void*, struct StoonPeercode *peercode);
static struct Stoon stoon; static struct Stoon stoon;
@@ -17,11 +23,11 @@ static bool inited = false;
static bool isHost; static bool isHost;
typedef struct { typedef struct {
#define MASK_IPv4 1 ENetAddress pv4;
#define MASK_IPv6 2 ENetAddress pv6;
int mask;
ENetAddress v4; ENetAddress lv4;
ENetAddress v6; ENetAddress lv6;
} ToPunch; } ToPunch;
static ToPunch *topunch = NULL; static ToPunch *topunch = NULL;
static size_t topunchCount = 0; static size_t topunchCount = 0;
@@ -30,13 +36,22 @@ static double Timeout = 0;
static bool connected = false; static bool connected = false;
bool net_hi_request_peercode(void *ud, void(*callback)(void*, const char *peercode)) { static uint16_t servport = 0;
bool net_hi_request_peercode(void *ud, void(*callback)(void*, struct StoonPeercode *peercode)) {
if(inited) return false; if(inited) return false;
ReqPeercodeUD = ud; ReqPeercodeUD = ud;
ReqPeercodeCB = callback; ReqPeercodeCB = callback;
stoon = stoon_init("stun.easybell.de", 3478, 26656); for(size_t port = 25000; port <= 26656; port++) {
stoon = stoon_init("stun.easybell.de", 3478, port);
if(stoon.fd4 >= 0 || stoon.fd6 >= 0) {
servport = port;
break;
}
}
Timeout = 0; Timeout = 0;
@@ -52,7 +67,7 @@ bool net_hi_setup(bool host) {
isHost = host; isHost = host;
if(host) { if(host) {
net_server_init(); net_server_init(servport);
} else { } else {
net_client_init(); net_client_init();
} }
@@ -67,16 +82,17 @@ void net_hi_update(double now) {
if(stoon_req(&stoon)) { if(stoon_req(&stoon)) {
if(stoon_listen(&stoon)) { if(stoon_listen(&stoon)) {
uint8_t peercode[STOON_CONN_INFO_SIZE] = {}; ReqPeercodeCB(ReqPeercodeUD, &stoon.peercode);
stoon_serialize(&stoon, peercode);
ReqPeercodeCB(ReqPeercodeUD, peercode);
ReqPeercodeCB = NULL; ReqPeercodeCB = NULL;
} else { } else {
k3Log(k3_INFO, "stoon_listen failure");
Timeout = now + 1; Timeout = now + 1;
} }
} else { } else {
k3Log(k3_INFO, "stoon_req failure");
Timeout = now + 1; Timeout = now + 1;
} }
@@ -97,11 +113,11 @@ void net_hi_update(double now) {
for(size_t tpi = 0; tpi < topunchCount; tpi++) { for(size_t tpi = 0; tpi < topunchCount; tpi++) {
ToPunch *tp = &topunch[tpi]; ToPunch *tp = &topunch[tpi];
if(tp->mask & MASK_IPv4) { if(tp->lv6.port) enet_socket_send(h->socket, &tp->lv6, &buf, 1);
enet_socket_send(h->socket, &tp->v4, &buf, 1); if(tp->lv4.port) enet_socket_send(h->socket, &tp->lv4, &buf, 1);
} else if(tp->mask & MASK_IPv6) {
enet_socket_send(h->socket, &tp->v6, &buf, 1); if(tp->pv6.port) enet_socket_send(h->socket, &tp->pv6, &buf, 1);
} if(tp->pv4.port) enet_socket_send(h->socket, &tp->pv4, &buf, 1);
} }
} }
@@ -111,55 +127,85 @@ void net_hi_update(double now) {
} }
} }
static void stoonpeer_to_enets(const char *peercode, ENetAddress *v4, ENetAddress *v6, int *mask) { static bool stoonpeer_to_enet4(uint8_t *publicV4, uint8_t *publicP4, ENetAddress *enet) {
memset(v4->host.__in6_u.__u6_addr8, 0, 16); memset(enet, 0, sizeof(*enet));
v4->host.__in6_u.__u6_addr8[10] = 0xFF;
v4->host.__in6_u.__u6_addr8[11] = 0xFF;
v4->host.__in6_u.__u6_addr8[12] = peercode[0];
v4->host.__in6_u.__u6_addr8[13] = peercode[1];
v4->host.__in6_u.__u6_addr8[14] = peercode[2];
v4->host.__in6_u.__u6_addr8[15] = peercode[3];
v4->port = ntohs(*(uint16_t*) &peercode[4]);
memcpy(v6->host.__in6_u.__u6_addr8, peercode + 6, 16); if(*(uint32_t*) publicV4 == 0 || *(uint16_t*) publicP4 == 0) {
v6->port = ntohs(*(uint16_t*) &peercode[22]); return false;
*mask = 0;
if(v4->port) {
*mask |= MASK_IPv4;
}
if(v6->port) {
*mask |= MASK_IPv6;
}
} }
void net_hi_add_punch(const char *peercode) { uint8_t *addr8 = (uint8_t*) &enet->host;
int mask;
ENetAddress v4 = {}, v6 = {};
stoonpeer_to_enets(peercode, &v4, &v6, &mask);
memset(addr8, 0, 16);
addr8[10] = 0xFF;
addr8[11] = 0xFF;
addr8[12] = publicV4[0];
addr8[13] = publicV4[1];
addr8[14] = publicV4[2];
addr8[15] = publicV4[3];
enet->port = *(uint16_t*) publicP4;
return true;
}
static bool stoonpeer_to_enet6(uint8_t *publicV6, uint8_t *publicP6, ENetAddress *enet) {
memset(enet, 0, sizeof(*enet));
if(*(uint32_t*) publicV6 == 0 || *(uint16_t*) publicP6 == 0) {
return false;
}
uint8_t *addr8 = (uint8_t*) &enet->host;
memcpy(addr8, publicV6, 16);
enet->port = *(uint16_t*) publicP6;
return true;
}
void net_hi_add_punch(struct StoonPeercode *peercode) {
topunch = realloc(topunch, sizeof(*topunch) * (++topunchCount)); topunch = realloc(topunch, sizeof(*topunch) * (++topunchCount));
topunch[topunchCount - 1] = (ToPunch) { ToPunch *tp = &topunch[topunchCount - 1];
.v4 = v4,
.v6 = v6, stoonpeer_to_enet4(peercode->publicV4, peercode->publicP4, &tp->pv4);
.mask = mask, stoonpeer_to_enet6(peercode->publicV6, peercode->publicP6, &tp->pv6);
};
stoonpeer_to_enet4(peercode->localV4, peercode->localP4, &tp->lv4);
stoonpeer_to_enet6(peercode->localV6, peercode->localP6, &tp->lv6);
} }
bool net_hi_connect(const char *peercode) { bool net_hi_connect(struct StoonPeercode *peercode) {
if(!inited) return false; if(!inited) return false;
if(connected) return false; if(connected) return false;
char ip[64]; ENetAddress pv4, pv6;
int port; stoonpeer_to_enet4(peercode->publicV4, peercode->publicP4, &pv4);
if(*(uint16_t*) (peercode + 22) == 0) { stoonpeer_to_enet6(peercode->publicV6, peercode->publicP6, &pv6);
inet_ntop(AF_INET, peercode, ip, sizeof(ip));
port = ntohs(*(uint16_t*) (peercode + 4)); ENetAddress lv4, lv6;
} else { stoonpeer_to_enet4(peercode->localV4, peercode->localP4, &lv4);
inet_ntop(AF_INET6, peercode + 6, ip, sizeof(ip)); stoonpeer_to_enet6(peercode->localV6, peercode->localP6, &lv6);
port = ntohs(*(uint16_t*) (peercode + 22));
if(lv6.port && net_client_connect(lv6)) {
k3Log(k3_INFO, "Found local IPv6");
return true;
}
if(lv4.port && net_client_connect(lv4)) {
k3Log(k3_INFO, "Found local IPv4");
return true;
} }
return net_client_connect(ip, port); if(pv6.port && net_client_connect(pv6)) {
k3Log(k3_INFO, "Found remote IPv6");
return true;
}
if(pv4.port && net_client_connect(pv4)) {
k3Log(k3_INFO, "Found remote IPv4");
return true;
}
k3Log(k3_INFO, "Failed to establish connection");
return false;
} }

View File

@@ -2,10 +2,12 @@
#include<stdbool.h> #include<stdbool.h>
bool net_hi_request_peercode(void *ud, void(*callback)(void*, const char *peercode)); struct StoonPeercode;
bool net_hi_request_peercode(void *ud, void(*callback)(void*, struct StoonPeercode *peercode));
bool net_hi_setup(bool host); bool net_hi_setup(bool host);
void net_hi_update(double now); void net_hi_update(double now);
void net_hi_add_punch(const char *peercode); void net_hi_add_punch(struct StoonPeercode *peercode);
bool net_hi_connect(const char *peercode); bool net_hi_connect(struct StoonPeercode *peercode);

View File

@@ -18,8 +18,8 @@ struct Conn {
#define MAX_PLAYERS 64 #define MAX_PLAYERS 64
static struct Conn conns[MAX_PLAYERS]; static struct Conn conns[MAX_PLAYERS];
void net_server_init() { void net_server_init(uint16_t port) {
host = enet_host_create(&(ENetAddress) {.host = ENET_HOST_ANY, .port = 26656}, 16, 1, 0, 0); host = enet_host_create(&(ENetAddress) {.host = ENET_HOST_ANY, .port = port}, 16, 1, 0, 0);
Game.isMultiplayer = 1; Game.isMultiplayer = 1;
Game.isAuthority = 1; Game.isAuthority = 1;

View File

@@ -5,7 +5,7 @@
struct _ENetPeer; struct _ENetPeer;
struct bstr; struct bstr;
void net_server_init(); void net_server_init(uint16_t port);
void net_server_receive(); void net_server_receive();
void net_server_update(); void net_server_update();

524
src/noise1234.c Normal file
View File

@@ -0,0 +1,524 @@
// noise1234
//
// Author: Stefan Gustavson, 2003-2005
// Contact: stefan.gustavson@liu.se
//
// This code was GPL licensed until February 2011.
// As the original author of this code, I hereby
// release it into the public domain.
// Please feel free to use it for whatever you want.
// Credit is appreciated where appropriate, and I also
// appreciate being told where this code finds any use,
// but you may do as you like.
/*
* This implementation is "Improved Noise" as presented by
* Ken Perlin at Siggraph 2002. The 3D function is a direct port
* of his Java reference code which was once publicly available
* on www.noisemachine.com (although I cleaned it up, made it
* faster and made the code more readable), but the 1D, 2D and
* 4D functions were implemented from scratch by me.
*
* This is a backport to C of my improved noise class in C++
* which was included in the Aqsis renderer project.
* It is highly reusable without source code modifications.
*
*/
#include "noise1234.h"
// This is the new and improved, C(2) continuous interpolant
#define FADE(t) ( t * t * t * ( t * ( t * 6 - 15 ) + 10 ) )
#define FASTFLOOR(x) ( ((int)(x)<(x)) ? ((int)x) : ((int)x-1 ) )
#define LERP(t, a, b) ((a) + (t)*((b)-(a)))
//---------------------------------------------------------------------
// Static data
/*
* Permutation table. This is just a random jumble of all numbers 0-255,
* repeated twice to avoid wrapping the index at 255 for each lookup.
* This needs to be exactly the same for all instances on all platforms,
* so it's easiest to just keep it as static explicit data.
* This also removes the need for any initialisation of this class.
*
* Note that making this an int[] instead of a char[] might make the
* code run faster on platforms with a high penalty for unaligned single
* byte addressing. Intel x86 is generally single-byte-friendly, but
* some other CPUs are faster with 4-aligned reads.
* However, a char[] is smaller, which avoids cache trashing, and that
* is probably the most important aspect on most architectures.
* This array is accessed a *lot* by the noise functions.
* A vector-valued noise over 3D accesses it 96 times, and a
* float-valued 4D noise 64 times. We want this to fit in the cache!
*/
unsigned char perm[] = {151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};
//---------------------------------------------------------------------
/*
* Helper functions to compute gradients-dot-residualvectors (1D to 4D)
* Note that these generate gradients of more than unit length. To make
* a close match with the value range of classic Perlin noise, the final
* noise values need to be rescaled. To match the RenderMan noise in a
* statistical sense, the approximate scaling values (empirically
* determined from test renderings) are:
* 1D noise needs rescaling with 0.188
* 2D noise needs rescaling with 0.507
* 3D noise needs rescaling with 0.936
* 4D noise needs rescaling with 0.87
* Note that these noise functions are the most practical and useful
* signed version of Perlin noise. To return values according to the
* RenderMan specification from the SL noise() and pnoise() functions,
* the noise values need to be scaled and offset to [0,1], like this:
* float SLnoise = (noise3(x,y,z) + 1.0) * 0.5;
*/
float grad1( int hash, float x ) {
int h = hash & 15;
float grad = 1.0 + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0
if (h&8) grad = -grad; // and a random sign for the gradient
return ( grad * x ); // Multiply the gradient with the distance
}
float grad2( int hash, float x, float y ) {
int h = hash & 7; // Convert low 3 bits of hash code
float u = h<4 ? x : y; // into 8 simple gradient directions,
float v = h<4 ? y : x; // and compute the dot product with (x,y).
return ((h&1)? -u : u) + ((h&2)? -2.0*v : 2.0*v);
}
float grad3( int hash, float x, float y , float z ) {
int h = hash & 15; // Convert low 4 bits of hash code into 12 simple
float u = h<8 ? x : y; // gradient directions, and compute dot product.
float v = h<4 ? y : h==12||h==14 ? x : z; // Fix repeats at h = 12 to 15
return ((h&1)? -u : u) + ((h&2)? -v : v);
}
float grad4( int hash, float x, float y, float z, float t ) {
int h = hash & 31; // Convert low 5 bits of hash code into 32 simple
float u = h<24 ? x : y; // gradient directions, and compute dot product.
float v = h<16 ? y : z;
float w = h<8 ? z : t;
return ((h&1)? -u : u) + ((h&2)? -v : v) + ((h&4)? -w : w);
}
//---------------------------------------------------------------------
/** 1D float Perlin noise, SL "noise()"
*/
float noise1( float x )
{
int ix0, ix1;
float fx0, fx1;
float s, n0, n1;
ix0 = FASTFLOOR( x ); // Integer part of x
fx0 = x - ix0; // Fractional part of x
fx1 = fx0 - 1.0f;
ix1 = ( ix0+1 ) & 0xff;
ix0 = ix0 & 0xff; // Wrap to 0..255
s = FADE( fx0 );
n0 = grad1( perm[ ix0 ], fx0 );
n1 = grad1( perm[ ix1 ], fx1 );
return 0.188f * ( LERP( s, n0, n1 ) );
}
//---------------------------------------------------------------------
/** 1D float Perlin periodic noise, SL "pnoise()"
*/
float pnoise1( float x, int px )
{
int ix0, ix1;
float fx0, fx1;
float s, n0, n1;
ix0 = FASTFLOOR( x ); // Integer part of x
fx0 = x - ix0; // Fractional part of x
fx1 = fx0 - 1.0f;
ix1 = (( ix0 + 1 ) % px) & 0xff; // Wrap to 0..px-1 *and* wrap to 0..255
ix0 = ( ix0 % px ) & 0xff; // (because px might be greater than 256)
s = FADE( fx0 );
n0 = grad1( perm[ ix0 ], fx0 );
n1 = grad1( perm[ ix1 ], fx1 );
return 0.188f * ( LERP( s, n0, n1 ) );
}
//---------------------------------------------------------------------
/** 2D float Perlin noise.
*/
float noise2( float x, float y )
{
int ix0, iy0, ix1, iy1;
float fx0, fy0, fx1, fy1;
float s, t, nx0, nx1, n0, n1;
ix0 = FASTFLOOR( x ); // Integer part of x
iy0 = FASTFLOOR( y ); // Integer part of y
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
ix1 = (ix0 + 1) & 0xff; // Wrap to 0..255
iy1 = (iy0 + 1) & 0xff;
ix0 = ix0 & 0xff;
iy0 = iy0 & 0xff;
t = FADE( fy0 );
s = FADE( fx0 );
nx0 = grad2(perm[ix0 + perm[iy0]], fx0, fy0);
nx1 = grad2(perm[ix0 + perm[iy1]], fx0, fy1);
n0 = LERP( t, nx0, nx1 );
nx0 = grad2(perm[ix1 + perm[iy0]], fx1, fy0);
nx1 = grad2(perm[ix1 + perm[iy1]], fx1, fy1);
n1 = LERP(t, nx0, nx1);
return 0.507f * ( LERP( s, n0, n1 ) );
}
//---------------------------------------------------------------------
/** 2D float Perlin periodic noise.
*/
float pnoise2( float x, float y, int px, int py )
{
int ix0, iy0, ix1, iy1;
float fx0, fy0, fx1, fy1;
float s, t, nx0, nx1, n0, n1;
ix0 = FASTFLOOR( x ); // Integer part of x
iy0 = FASTFLOOR( y ); // Integer part of y
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
ix1 = (( ix0 + 1 ) % px) & 0xff; // Wrap to 0..px-1 and wrap to 0..255
iy1 = (( iy0 + 1 ) % py) & 0xff; // Wrap to 0..py-1 and wrap to 0..255
ix0 = ( ix0 % px ) & 0xff;
iy0 = ( iy0 % py ) & 0xff;
t = FADE( fy0 );
s = FADE( fx0 );
nx0 = grad2(perm[ix0 + perm[iy0]], fx0, fy0);
nx1 = grad2(perm[ix0 + perm[iy1]], fx0, fy1);
n0 = LERP( t, nx0, nx1 );
nx0 = grad2(perm[ix1 + perm[iy0]], fx1, fy0);
nx1 = grad2(perm[ix1 + perm[iy1]], fx1, fy1);
n1 = LERP(t, nx0, nx1);
return 0.507f * ( LERP( s, n0, n1 ) );
}
//---------------------------------------------------------------------
/** 3D float Perlin noise.
*/
float noise3( float x, float y, float z )
{
int ix0, iy0, ix1, iy1, iz0, iz1;
float fx0, fy0, fz0, fx1, fy1, fz1;
float s, t, r;
float nxy0, nxy1, nx0, nx1, n0, n1;
ix0 = FASTFLOOR( x ); // Integer part of x
iy0 = FASTFLOOR( y ); // Integer part of y
iz0 = FASTFLOOR( z ); // Integer part of z
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fz0 = z - iz0; // Fractional part of z
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
fz1 = fz0 - 1.0f;
ix1 = ( ix0 + 1 ) & 0xff; // Wrap to 0..255
iy1 = ( iy0 + 1 ) & 0xff;
iz1 = ( iz0 + 1 ) & 0xff;
ix0 = ix0 & 0xff;
iy0 = iy0 & 0xff;
iz0 = iz0 & 0xff;
r = FADE( fz0 );
t = FADE( fy0 );
s = FADE( fx0 );
nxy0 = grad3(perm[ix0 + perm[iy0 + perm[iz0]]], fx0, fy0, fz0);
nxy1 = grad3(perm[ix0 + perm[iy0 + perm[iz1]]], fx0, fy0, fz1);
nx0 = LERP( r, nxy0, nxy1 );
nxy0 = grad3(perm[ix0 + perm[iy1 + perm[iz0]]], fx0, fy1, fz0);
nxy1 = grad3(perm[ix0 + perm[iy1 + perm[iz1]]], fx0, fy1, fz1);
nx1 = LERP( r, nxy0, nxy1 );
n0 = LERP( t, nx0, nx1 );
nxy0 = grad3(perm[ix1 + perm[iy0 + perm[iz0]]], fx1, fy0, fz0);
nxy1 = grad3(perm[ix1 + perm[iy0 + perm[iz1]]], fx1, fy0, fz1);
nx0 = LERP( r, nxy0, nxy1 );
nxy0 = grad3(perm[ix1 + perm[iy1 + perm[iz0]]], fx1, fy1, fz0);
nxy1 = grad3(perm[ix1 + perm[iy1 + perm[iz1]]], fx1, fy1, fz1);
nx1 = LERP( r, nxy0, nxy1 );
n1 = LERP( t, nx0, nx1 );
return 0.936f * ( LERP( s, n0, n1 ) );
}
//---------------------------------------------------------------------
/** 3D float Perlin periodic noise.
*/
float pnoise3( float x, float y, float z, int px, int py, int pz )
{
int ix0, iy0, ix1, iy1, iz0, iz1;
float fx0, fy0, fz0, fx1, fy1, fz1;
float s, t, r;
float nxy0, nxy1, nx0, nx1, n0, n1;
ix0 = FASTFLOOR( x ); // Integer part of x
iy0 = FASTFLOOR( y ); // Integer part of y
iz0 = FASTFLOOR( z ); // Integer part of z
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fz0 = z - iz0; // Fractional part of z
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
fz1 = fz0 - 1.0f;
ix1 = (( ix0 + 1 ) % px ) & 0xff; // Wrap to 0..px-1 and wrap to 0..255
iy1 = (( iy0 + 1 ) % py ) & 0xff; // Wrap to 0..py-1 and wrap to 0..255
iz1 = (( iz0 + 1 ) % pz ) & 0xff; // Wrap to 0..pz-1 and wrap to 0..255
ix0 = ( ix0 % px ) & 0xff;
iy0 = ( iy0 % py ) & 0xff;
iz0 = ( iz0 % pz ) & 0xff;
r = FADE( fz0 );
t = FADE( fy0 );
s = FADE( fx0 );
nxy0 = grad3(perm[ix0 + perm[iy0 + perm[iz0]]], fx0, fy0, fz0);
nxy1 = grad3(perm[ix0 + perm[iy0 + perm[iz1]]], fx0, fy0, fz1);
nx0 = LERP( r, nxy0, nxy1 );
nxy0 = grad3(perm[ix0 + perm[iy1 + perm[iz0]]], fx0, fy1, fz0);
nxy1 = grad3(perm[ix0 + perm[iy1 + perm[iz1]]], fx0, fy1, fz1);
nx1 = LERP( r, nxy0, nxy1 );
n0 = LERP( t, nx0, nx1 );
nxy0 = grad3(perm[ix1 + perm[iy0 + perm[iz0]]], fx1, fy0, fz0);
nxy1 = grad3(perm[ix1 + perm[iy0 + perm[iz1]]], fx1, fy0, fz1);
nx0 = LERP( r, nxy0, nxy1 );
nxy0 = grad3(perm[ix1 + perm[iy1 + perm[iz0]]], fx1, fy1, fz0);
nxy1 = grad3(perm[ix1 + perm[iy1 + perm[iz1]]], fx1, fy1, fz1);
nx1 = LERP( r, nxy0, nxy1 );
n1 = LERP( t, nx0, nx1 );
return 0.936f * ( LERP( s, n0, n1 ) );
}
//---------------------------------------------------------------------
/** 4D float Perlin noise.
*/
float noise4( float x, float y, float z, float w )
{
int ix0, iy0, iz0, iw0, ix1, iy1, iz1, iw1;
float fx0, fy0, fz0, fw0, fx1, fy1, fz1, fw1;
float s, t, r, q;
float nxyz0, nxyz1, nxy0, nxy1, nx0, nx1, n0, n1;
ix0 = FASTFLOOR( x ); // Integer part of x
iy0 = FASTFLOOR( y ); // Integer part of y
iz0 = FASTFLOOR( z ); // Integer part of y
iw0 = FASTFLOOR( w ); // Integer part of w
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fz0 = z - iz0; // Fractional part of z
fw0 = w - iw0; // Fractional part of w
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
fz1 = fz0 - 1.0f;
fw1 = fw0 - 1.0f;
ix1 = ( ix0 + 1 ) & 0xff; // Wrap to 0..255
iy1 = ( iy0 + 1 ) & 0xff;
iz1 = ( iz0 + 1 ) & 0xff;
iw1 = ( iw0 + 1 ) & 0xff;
ix0 = ix0 & 0xff;
iy0 = iy0 & 0xff;
iz0 = iz0 & 0xff;
iw0 = iw0 & 0xff;
q = FADE( fw0 );
r = FADE( fz0 );
t = FADE( fy0 );
s = FADE( fx0 );
nxyz0 = grad4(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx0, fy0, fz0, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx0, fy0, fz0, fw1);
nxy0 = LERP( q, nxyz0, nxyz1 );
nxyz0 = grad4(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx0, fy0, fz1, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx0, fy0, fz1, fw1);
nxy1 = LERP( q, nxyz0, nxyz1 );
nx0 = LERP ( r, nxy0, nxy1 );
nxyz0 = grad4(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx0, fy1, fz0, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx0, fy1, fz0, fw1);
nxy0 = LERP( q, nxyz0, nxyz1 );
nxyz0 = grad4(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx0, fy1, fz1, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx0, fy1, fz1, fw1);
nxy1 = LERP( q, nxyz0, nxyz1 );
nx1 = LERP ( r, nxy0, nxy1 );
n0 = LERP( t, nx0, nx1 );
nxyz0 = grad4(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx1, fy0, fz0, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx1, fy0, fz0, fw1);
nxy0 = LERP( q, nxyz0, nxyz1 );
nxyz0 = grad4(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx1, fy0, fz1, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx1, fy0, fz1, fw1);
nxy1 = LERP( q, nxyz0, nxyz1 );
nx0 = LERP ( r, nxy0, nxy1 );
nxyz0 = grad4(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx1, fy1, fz0, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx1, fy1, fz0, fw1);
nxy0 = LERP( q, nxyz0, nxyz1 );
nxyz0 = grad4(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx1, fy1, fz1, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx1, fy1, fz1, fw1);
nxy1 = LERP( q, nxyz0, nxyz1 );
nx1 = LERP ( r, nxy0, nxy1 );
n1 = LERP( t, nx0, nx1 );
return 0.87f * ( LERP( s, n0, n1 ) );
}
//---------------------------------------------------------------------
/** 4D float Perlin periodic noise.
*/
float pnoise4( float x, float y, float z, float w,
int px, int py, int pz, int pw )
{
int ix0, iy0, iz0, iw0, ix1, iy1, iz1, iw1;
float fx0, fy0, fz0, fw0, fx1, fy1, fz1, fw1;
float s, t, r, q;
float nxyz0, nxyz1, nxy0, nxy1, nx0, nx1, n0, n1;
ix0 = FASTFLOOR( x ); // Integer part of x
iy0 = FASTFLOOR( y ); // Integer part of y
iz0 = FASTFLOOR( z ); // Integer part of y
iw0 = FASTFLOOR( w ); // Integer part of w
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fz0 = z - iz0; // Fractional part of z
fw0 = w - iw0; // Fractional part of w
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
fz1 = fz0 - 1.0f;
fw1 = fw0 - 1.0f;
ix1 = (( ix0 + 1 ) % px ) & 0xff; // Wrap to 0..px-1 and wrap to 0..255
iy1 = (( iy0 + 1 ) % py ) & 0xff; // Wrap to 0..py-1 and wrap to 0..255
iz1 = (( iz0 + 1 ) % pz ) & 0xff; // Wrap to 0..pz-1 and wrap to 0..255
iw1 = (( iw0 + 1 ) % pw ) & 0xff; // Wrap to 0..pw-1 and wrap to 0..255
ix0 = ( ix0 % px ) & 0xff;
iy0 = ( iy0 % py ) & 0xff;
iz0 = ( iz0 % pz ) & 0xff;
iw0 = ( iw0 % pw ) & 0xff;
q = FADE( fw0 );
r = FADE( fz0 );
t = FADE( fy0 );
s = FADE( fx0 );
nxyz0 = grad4(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx0, fy0, fz0, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx0, fy0, fz0, fw1);
nxy0 = LERP( q, nxyz0, nxyz1 );
nxyz0 = grad4(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx0, fy0, fz1, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx0, fy0, fz1, fw1);
nxy1 = LERP( q, nxyz0, nxyz1 );
nx0 = LERP ( r, nxy0, nxy1 );
nxyz0 = grad4(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx0, fy1, fz0, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx0, fy1, fz0, fw1);
nxy0 = LERP( q, nxyz0, nxyz1 );
nxyz0 = grad4(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx0, fy1, fz1, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx0, fy1, fz1, fw1);
nxy1 = LERP( q, nxyz0, nxyz1 );
nx1 = LERP ( r, nxy0, nxy1 );
n0 = LERP( t, nx0, nx1 );
nxyz0 = grad4(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx1, fy0, fz0, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx1, fy0, fz0, fw1);
nxy0 = LERP( q, nxyz0, nxyz1 );
nxyz0 = grad4(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx1, fy0, fz1, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx1, fy0, fz1, fw1);
nxy1 = LERP( q, nxyz0, nxyz1 );
nx0 = LERP ( r, nxy0, nxy1 );
nxyz0 = grad4(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx1, fy1, fz0, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx1, fy1, fz0, fw1);
nxy0 = LERP( q, nxyz0, nxyz1 );
nxyz0 = grad4(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx1, fy1, fz1, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx1, fy1, fz1, fw1);
nxy1 = LERP( q, nxyz0, nxyz1 );
nx1 = LERP ( r, nxy0, nxy1 );
n1 = LERP( t, nx0, nx1 );
return 0.87f * ( LERP( s, n0, n1 ) );
}
//---------------------------------------------------------------------

41
src/noise1234.h Normal file
View File

@@ -0,0 +1,41 @@
// noise1234
//
// Author: Stefan Gustavson, 2003-2005
// Contact: stefan.gustavson@liu.se
//
// This code was GPL licensed until February 2011.
// As the original author of this code, I hereby
// release it into the public domain.
// Please feel free to use it for whatever you want.
// Credit is appreciated where appropriate, and I also
// appreciate being told where this code finds any use,
// but you may do as you like.
/*
* This implementation is "Improved Noise" as presented by
* Ken Perlin at Siggraph 2002. The 3D function is a direct port
* of his Java reference code which was once publicly available
* on www.noisemachine.com (although I cleaned it up, made it
* faster and made the code more readable), but the 1D, 2D and
* 4D functions were implemented from scratch by me.
*
* This is a backport to C of my improved noise class in C++
* which was included in the Aqsis renderer project.
* It is highly reusable without source code modifications.
*
*/
/** 1D, 2D, 3D and 4D float Perlin noise
*/
extern float noise1( float x );
extern float noise2( float x, float y );
extern float noise3( float x, float y, float z );
extern float noise4( float x, float y, float z, float w );
/** 1D, 2D, 3D and 4D float Perlin periodic noise
*/
extern float pnoise1( float x, int px );
extern float pnoise2( float x, float y, int px, int py );
extern float pnoise3( float x, float y, float z, int px, int py, int pz );
extern float pnoise4( float x, float y, float z, float w,
int px, int py, int pz, int pw );

View File

@@ -4,11 +4,13 @@
#include<winsock2.h> #include<winsock2.h>
#include<ws2tcpip.h> #include<ws2tcpip.h>
#include<ntsecapi.h> #include<ntsecapi.h>
#include<iphlpapi.h>
#else #else
#include<netdb.h> #include<netdb.h>
#include<sys/socket.h> #include<sys/socket.h>
#include<sys/random.h> #include<sys/random.h>
#include<arpa/inet.h> #include<arpa/inet.h>
#include<ifaddrs.h>
#endif #endif
#include<unistd.h> #include<unistd.h>
#include<sys/types.h> #include<sys/types.h>
@@ -43,7 +45,7 @@ struct StunMsg {
uint8_t id[12]; uint8_t id[12];
}; };
static int stoon_init_mini(struct addrinfo *serv, uint16_t myport) { static int stoon_init_mini(struct Stoon *this, struct addrinfo *serv, uint16_t myport) {
#ifdef _WIN32 #ifdef _WIN32
errno = 0; errno = 0;
int fd = socket(serv->ai_family, serv->ai_socktype, serv->ai_protocol); int fd = socket(serv->ai_family, serv->ai_socktype, serv->ai_protocol);
@@ -59,16 +61,79 @@ static int stoon_init_mini(struct addrinfo *serv, uint16_t myport) {
char p[6]; char p[6];
sprintf(p, "%u", myport); sprintf(p, "%u", myport);
struct addrinfo *myaddr; struct addrinfo *myaddrinfo;
if(getaddrinfo(NULL, p, &(struct addrinfo) {.ai_family = serv->ai_family, .ai_socktype = SOCK_DGRAM, .ai_protocol = IPPROTO_UDP, .ai_flags = AI_PASSIVE}, &myaddr)) { if(getaddrinfo(NULL, p, &(struct addrinfo) {.ai_family = serv->ai_family, .ai_socktype = SOCK_DGRAM, .ai_protocol = IPPROTO_UDP, .ai_flags = AI_PASSIVE}, &myaddrinfo)) {
close(fd); close(fd);
return -1; return -1;
} }
if(bind(fd, myaddr->ai_addr, myaddr->ai_addrlen)) { if(bind(fd, myaddrinfo->ai_addr, myaddrinfo->ai_addrlen)) {
close(fd); close(fd);
return -2; return -2;
} }
freeaddrinfo(myaddr);
freeaddrinfo(myaddrinfo);
#ifdef _WIN32
size_t sz = 1024 * 64;
IP_ADAPTER_ADDRESSES *addrs = malloc(sz);
if(GetAdaptersAddresses(serv->ai_family, GAA_FLAG_SKIP_MULTICAST, NULL, addrs, &sz) == NO_ERROR) {
for(IP_ADAPTER_ADDRESSES *ifa = addrs; ifa; ifa = ifa->Next) {
if(!ifa->FirstUnicastAddress) {
continue;
}
if(serv->ai_family == AF_INET6) {
uint8_t *addr = (void*) &((struct sockaddr_in6*) ifa->FirstUnicastAddress->Address.lpSockaddr)->sin6_addr;
if(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0 && addr[4] == 0 && addr[5] == 0 && addr[6] == 0 && addr[7] == 0 && addr[8] == 0 && addr[9] == 0 && addr[10] == 0 && addr[11] == 0 && addr[12] == 0 && addr[13] == 0 && addr[14] == 0 && (addr[15] == 0 || addr[15] == 1)) {
continue;
}
memcpy(this->peercode.localV6, addr, 16);
memcpy(this->peercode.localP6, &myport, 2);
} else {
uint8_t *addr = (void*) &((struct sockaddr_in*) ifa->FirstUnicastAddress->Address.lpSockaddr)->sin_addr;
if(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0 || addr[0] == 127 && addr[1] == 0 && addr[2] == 0 && addr[3] == 1) {
continue;
}
memcpy(this->peercode.localV4, addr, 4);
memcpy(this->peercode.localP4, &myport, 2);
}
}
}
free(addrs);
#else
struct ifaddrs *ifaddr;
if(getifaddrs(&ifaddr) >= 0) {
for(struct ifaddrs *ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
if(!ifa->ifa_addr || ifa->ifa_addr->sa_family != serv->ai_family) {
continue;
}
if(serv->ai_family == AF_INET6) {
uint8_t *addr = (void*) &((struct sockaddr_in6*) ifa->ifa_addr)->sin6_addr;
if(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0 && addr[4] == 0 && addr[5] == 0 && addr[6] == 0 && addr[7] == 0 && addr[8] == 0 && addr[9] == 0 && addr[10] == 0 && addr[11] == 0 && addr[12] == 0 && addr[13] == 0 && addr[14] == 0 && (addr[15] == 0 || addr[15] == 1)) {
continue;
}
memcpy(this->peercode.localV6, addr, 16);
memcpy(this->peercode.localP6, &myport, 2);
} else {
uint8_t *addr = (void*) &((struct sockaddr_in*) ifa->ifa_addr)->sin_addr;
if(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0 || addr[0] == 127 && addr[1] == 0 && addr[2] == 0 && addr[3] == 1) {
continue;
}
memcpy(this->peercode.localV4, addr, 4);
memcpy(this->peercode.localP4, &myport, 2);
}
break;
}
freeifaddrs(ifaddr);
}
#endif
return fd; return fd;
} }
@@ -92,18 +157,16 @@ struct Stoon stoon_init(const char *stunhost, uint16_t stunport, uint16_t myport
} }
} }
struct Stoon ret; struct Stoon ret = {};
memset(&ret.my4, 0, sizeof(ret.my4));
if(v4) { if(v4) {
memcpy(&ret.stu4, v4->ai_addr, v4->ai_addrlen); memcpy(&ret.stu4, v4->ai_addr, v4->ai_addrlen);
ret.fd4 = stoon_init_mini(v4, myport); ret.fd4 = stoon_init_mini(&ret, v4, myport);
} else ret.fd4 = -1; } else ret.fd4 = -1;
memset(&ret.my6, 0, sizeof(ret.my6));
if(v6) { if(v6) {
memcpy(&ret.stu6, v6->ai_addr, v6->ai_addrlen); memcpy(&ret.stu6, v6->ai_addr, v6->ai_addrlen);
ret.fd6 = stoon_init_mini(v6, myport); ret.fd6 = stoon_init_mini(&ret, v6, myport);
} else ret.fd6 = -1; } else ret.fd6 = -1;
ret.poonchstage = 0; ret.poonchstage = 0;
@@ -121,12 +184,21 @@ static int stoon_req_mini(struct Stoon *this, int *fd, struct sockaddr *serv, in
if(errno == ENETUNREACH) { if(errno == ENETUNREACH) {
close(*fd); close(*fd);
*fd = -1; *fd = -1;
return false;
} }
} }
return true;
} }
int stoon_req(struct Stoon *this) { int stoon_req(struct Stoon *this) {
if(this->fd4 >= 0) stoon_req_mini(this, &this->fd4, (struct sockaddr*) &this->stu4, sizeof(struct sockaddr_in)); if(this->fd4 >= 0) stoon_req_mini(this, &this->fd4, (struct sockaddr*) &this->stu4, sizeof(struct sockaddr_in));
if(this->fd6 >= 0) stoon_req_mini(this, &this->fd6, (struct sockaddr*) &this->stu6, sizeof(struct sockaddr_in6)); if(this->fd6 >= 0) stoon_req_mini(this, &this->fd6, (struct sockaddr*) &this->stu6, sizeof(struct sockaddr_in6));
if(this->fd4 < 0 && this->fd6 < 0) {
return false;
}
return true;
} }
static int stoon_listen_mini(struct Stoon *this, int fd, struct sockaddr *serv, int servlen) { static int stoon_listen_mini(struct Stoon *this, int fd, struct sockaddr *serv, int servlen) {
@@ -161,11 +233,10 @@ static int stoon_listen_mini(struct Stoon *this, int fd, struct sockaddr *serv,
uint16_t netfam = ntohs(((uint16_t*) d)[2]); uint16_t netfam = ntohs(((uint16_t*) d)[2]);
uint16_t publicPort = ntohs(((uint16_t*) d)[3]) ^ (STUN_MAGIC >> 16); uint16_t publicPort = ntohs(((uint16_t*) d)[3]) ^ (STUN_MAGIC >> 16);
if(netfam == STUN_NETFAM_IPV4) { if(netfam == STUN_NETFAM_IPV4) {
uint32_t publicIp = ntohl(((uint32_t*) d)[2]) ^ STUN_MAGIC; uint32_t publicIp = htonl(ntohl(((uint32_t*) d)[2]) ^ STUN_MAGIC);
this->my4.sin_family = AF_INET; memcpy(this->peercode.publicV4, &publicIp, 4);
memcpy(&this->my4.sin_addr, &publicIp, 4); memcpy(this->peercode.publicP4, &publicPort, 2);
this->my4.sin_port = htons(publicPort);
return 1; return 1;
} else if(netfam == STUN_NETFAM_IPV6) { } else if(netfam == STUN_NETFAM_IPV6) {
@@ -175,9 +246,8 @@ static int stoon_listen_mini(struct Stoon *this, int fd, struct sockaddr *serv,
publicIp[2] = ((uint32_t*) d)[4] ^ ((uint32_t*) res.base.id)[1]; publicIp[2] = ((uint32_t*) d)[4] ^ ((uint32_t*) res.base.id)[1];
publicIp[3] = ((uint32_t*) d)[5] ^ ((uint32_t*) res.base.id)[2]; publicIp[3] = ((uint32_t*) d)[5] ^ ((uint32_t*) res.base.id)[2];
this->my6.sin6_family = AF_INET6; memcpy(this->peercode.publicV6, &publicIp, 16);
memcpy(&this->my6.sin6_addr, &publicIp, 16); memcpy(this->peercode.publicP6, &publicPort, 2);
this->my6.sin6_port = htons(publicPort);
return 1; return 1;
} else { } else {
@@ -188,12 +258,12 @@ static int stoon_listen_mini(struct Stoon *this, int fd, struct sockaddr *serv,
d += 4 + attribLen; d += 4 + attribLen;
} }
return 0; return false;
} }
int stoon_listen(struct Stoon *this) { int stoon_listen(struct Stoon *this) {
if(this->fd4 >= 0) if(stoon_listen_mini(this, this->fd4, (struct sockaddr*) &this->stu4, sizeof(struct sockaddr_in)) < 0) return 0; if(this->fd4 >= 0) if(stoon_listen_mini(this, this->fd4, (struct sockaddr*) &this->stu4, sizeof(struct sockaddr_in)) < 0) return 0;
if(this->fd6 >= 0) if(stoon_listen_mini(this, this->fd6, (struct sockaddr*) &this->stu6, sizeof(struct sockaddr_in6)) < 0) return 0; if(this->fd6 >= 0) if(stoon_listen_mini(this, this->fd6, (struct sockaddr*) &this->stu6, sizeof(struct sockaddr_in6)) < 0) return 0;
return 1; return true;
} }
void stoon_keepalive(struct Stoon *this) { void stoon_keepalive(struct Stoon *this) {
@@ -217,31 +287,7 @@ void stoon_kill(struct Stoon *this) {
this->fd6 = -1; this->fd6 = -1;
} }
int stoon_v4_available(struct Stoon *this) { /*int stoon_poonch(struct Stoon *this, const uint8_t peerdata[static STOON_CONN_INFO_SIZE]) {
return this->fd4 >= 0;
}
int stoon_v6_available(struct Stoon *this) {
return this->fd6 >= 0;
}
void stoon_serialize(struct Stoon *this, uint8_t ret[static STOON_CONN_INFO_SIZE]) {
if(this->fd4 >= 0) {
memcpy(ret + 0, &this->my4.sin_addr, 4);
memcpy(ret + 4, &this->my4.sin_port, 2);
} else {
memset(ret, 0, 6);
}
if(this->fd6 >= 0) {
memcpy(ret + 6, &this->my6.sin6_addr, 16);
memcpy(ret + 22, &this->my6.sin6_port, 2);
} else {
memset(ret + 6, 0, 18);
}
}
int stoon_poonch(struct Stoon *this, const uint8_t peerdata[static STOON_CONN_INFO_SIZE]) {
struct { struct {
uint32_t addr4; uint32_t addr4;
uint16_t port4; uint16_t port4;
@@ -303,7 +349,7 @@ int stoon_poonch(struct Stoon *this, const uint8_t peerdata[static STOON_CONN_IN
} }
return STOON_POONCH_NO_KNOCK; return STOON_POONCH_NO_KNOCK;
} }*/
#ifdef STOON_STANDALONE #ifdef STOON_STANDALONE
int main() { int main() {

View File

@@ -6,6 +6,7 @@
#include<stddef.h> #include<stddef.h>
#include<stdint.h> #include<stdint.h>
#include<stdbool.h>
#ifdef _WIN32 #ifdef _WIN32
#include<winsock2.h> #include<winsock2.h>
@@ -16,8 +17,6 @@
/* Standalone hole punching libary (IPv4 & IPv6 compatible) */ /* Standalone hole punching libary (IPv4 & IPv6 compatible) */
#define STOON_CONN_INFO_SIZE (4 + 2 + 16 + 2)
#define POONCH_MAGIC 0x504F4348 #define POONCH_MAGIC 0x504F4348
#define POONCH_STAGE_KNOCKING 0 #define POONCH_STAGE_KNOCKING 0
#define POONCH_STAGE_ACK 1 #define POONCH_STAGE_ACK 1
@@ -26,16 +25,30 @@ struct Poonch {
uint32_t stage; uint32_t stage;
}; };
struct StoonPeercode {
uint8_t publicV4[4];
uint8_t publicP4[2];
uint8_t publicV6[16];
uint8_t publicP6[2];
uint8_t localV4[4];
uint8_t localP4[2];
uint8_t localV6[16];
uint8_t localP6[2];
};
struct Stoon { struct Stoon {
struct sockaddr_in stu4; struct sockaddr_in stu4;
struct sockaddr_in my4;
int fd4; int fd4;
struct sockaddr_in6 stu6; struct sockaddr_in6 stu6;
struct sockaddr_in6 my6;
int fd6; int fd6;
uint8_t poonchstage; uint8_t poonchstage;
struct StoonPeercode peercode;
}; };
// stunhost: Self-explanatory // stunhost: Self-explanatory
@@ -53,12 +66,8 @@ void stoon_keepalive(struct Stoon*);
void stoon_kill(struct Stoon*); void stoon_kill(struct Stoon*);
int stoon_v4_available(struct Stoon*); /*#define STOON_POONCH_INCOMPATIBLE_NETFAMS (-1)
int stoon_v6_available(struct Stoon*);
void stoon_serialize(struct Stoon*, uint8_t ret[static STOON_CONN_INFO_SIZE]);
#define STOON_POONCH_INCOMPATIBLE_NETFAMS (-1)
#define STOON_POONCH_NO_KNOCK 0 #define STOON_POONCH_NO_KNOCK 0
#define STOON_POONCH_ACKED 1 #define STOON_POONCH_ACKED 1
int stoon_poonch(struct Stoon*, const uint8_t peerdata[static STOON_CONN_INFO_SIZE]); int stoon_poonch(struct Stoon*, const uint8_t peerdata[static STOON_CONN_INFO_SIZE]);
*/