minecraft: non-global world data model

This commit is contained in:
Zack Buhman 2026-03-17 23:52:16 -05:00
parent 2b379aa27c
commit 527d4f5472
58 changed files with 1311753 additions and 380 deletions

View File

@ -17,6 +17,12 @@ CFLAGS += -fno-strict-aliasing
LDFLAGS += -lm LDFLAGS += -lm
LDFLAGS += $(shell pkg-config --libs glfw3) LDFLAGS += $(shell pkg-config --libs glfw3)
MINECRAFT_OBJS = \
minecraft/love2dworld/inthash.o \
src/minecraft.o \
src/world/world.o \
src/world/entry_table.o
OBJS = \ OBJS = \
src/gl.o \ src/gl.o \
src/opengl.o \ src/opengl.o \
@ -25,11 +31,8 @@ OBJS = \
src/window.o \ src/window.o \
src/bresenham.o \ src/bresenham.o \
src/file.o \ src/file.o \
src/world.o \
src/inthash.o \
src/non_block.o \ src/non_block.o \
src/view.o \ src/view.o \
src/minecraft.o \
src/hud.o \ src/hud.o \
src/lighting.o \ src/lighting.o \
src/collision_scene.o \ src/collision_scene.o \
@ -44,7 +47,8 @@ OBJS = \
data/scenes/ship20/ship20.o \ data/scenes/ship20/ship20.o \
data/scenes/noodle/noodle.o \ data/scenes/noodle/noodle.o \
data/scenes/shadow_test/shadow_test.o \ data/scenes/shadow_test/shadow_test.o \
data/scenes/book/book.o data/scenes/book/book.o \
$(MINECRAFT_OBJS)
all: test.so all: test.so

View File

@ -1,6 +1,10 @@
#pragma once #pragma once
#include "world/world.h"
namespace minecraft { namespace minecraft {
extern world::state * current_world;
void load(); void load();
void draw(); void draw();
} }

View File

@ -1,23 +0,0 @@
#pragma once
#include <stdint.h>
#include <assert.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct global_entry {
int global_index;
uint8_t block_id;
uint8_t block_data;
uint16_t _padding;
} global_entry_t;
static_assert((sizeof (global_entry_t)) == 8);
void load_world();
global_entry_t * const world_lookup(int x, int y, int z);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,27 @@
#pragma once
#include <stdint.h>
#include <assert.h>
namespace world::entry_table {
typedef struct global_entry {
int global_index;
uint8_t block_id;
uint8_t block_data;
uint16_t _padding;
} global_entry_t;
static_assert((sizeof (global_entry_t)) == 8);
typedef uint32_t (hash_func_t)(const int32_t key);
void load_entry_table(char const * const path,
global_entry_t ** out_entry_table,
int * out_entry_table_length,
hash_func_t * hash_func);
global_entry_t * const world_lookup(hash_func_t * hash_func,
global_entry_t * entry_table,
int entry_table_length,
int x, int y, int z);
}

View File

@ -6,8 +6,8 @@
extern "C" { extern "C" {
#endif #endif
uint32_t uint32_t love2dworld_hash(const int32_t key);
inthash(const int32_t key); uint32_t grandlecturn_hash(const int32_t key);
#ifdef __cplusplus #ifdef __cplusplus
} }

51
include/world/world.h Normal file
View File

@ -0,0 +1,51 @@
#pragma once
#include <stdint.h>
#include "world/entry_table.h"
namespace world {
struct vtx_cfg {
const char * vtx;
const char * cfg;
};
struct descriptor {
int const region_count;
vtx_cfg const * const vertex_paths;
char const * const entry_table_path;
char const * const lights_path;
entry_table::hash_func_t * hash_func;
};
struct world_id {
enum {
LOVE2DWORLD = 0,
};
};
// also update index_buffer_custom_offsets in data.inc
const int custom_block_types = 5;
const int instance_cfg_length = 64 + custom_block_types;
struct instance_cfg_entry {
int count;
int offset;
};
struct region {
unsigned int per_instance_vertex_buffer;
instance_cfg_entry instance_cfg[instance_cfg_length];
};
struct state {
world::descriptor const * descriptor;
world::region * region; // malloc region_count
unsigned int light_uniform_buffer;
entry_table::global_entry_t * entry_table;
int entry_table_length;
};
extern descriptor const descriptors[];
extern int const descriptors_length;
}

View File

@ -0,0 +1,20 @@
set -eux
#cd ./minecraft/gen
PYTHON=pypy3.11
cat <<EOF > ../grandlecturn/all_regions.txt
$HOME/GrandLecturn/region/r.0.0.mcr
$HOME/GrandLecturn/region/r.-1.-1.mcr
$HOME/GrandLecturn/region/r.0.-1.mcr
$HOME/GrandLecturn/region/r.-1.0.mcr
EOF
$PYTHON mc.py $HOME/GrandLecturn/region/r.0.0.mcr ../grandlecturn/region.0.0 ../grandlecturn/all_regions.txt &
$PYTHON mc.py $HOME/GrandLecturn/region/r.-1.-1.mcr ../grandlecturn/region.-1.-1 ../grandlecturn/all_regions.txt &
$PYTHON mc.py $HOME/GrandLecturn/region/r.0.-1.mcr ../grandlecturn/region.0.-1 ../grandlecturn/all_regions.txt &
$PYTHON mc.py $HOME/GrandLecturn/region/r.-1.0.mcr ../grandlecturn/region.-1.0 ../grandlecturn/all_regions.txt &
wait
cat ../grandlecturn/region*.lights.vtx > ../grandlecturn/global.lights.vtx
cat ../grandlecturn/region*.dump > ../grandlecturn/global.dump
$PYTHON intkeys.py ../grandlecturn/global.dump | $HOME/nbperf/nbperf -n grandlecturn_hash -I -a bpz -c 1.26 -m ../love2dworld/map.txt > ../grandlecturn/inthash.c

View File

@ -0,0 +1,20 @@
set -eux
#cd ./minecraft/gen
PYTHON=pypy3.11
cat <<EOF > ../love2dworld/all_regions.txt
$HOME/Love2DWorld/region/r.0.0.mcr
$HOME/Love2DWorld/region/r.-1.-1.mcr
$HOME/Love2DWorld/region/r.0.-1.mcr
$HOME/Love2DWorld/region/r.-1.0.mcr
EOF
$PYTHON mc.py $HOME/Love2DWorld/region/r.0.0.mcr ../love2dworld/region.0.0 ../love2dworld/all_regions.txt &
$PYTHON mc.py $HOME/Love2DWorld/region/r.-1.-1.mcr ../love2dworld/region.-1.-1 ../love2dworld/all_regions.txt &
$PYTHON mc.py $HOME/Love2DWorld/region/r.0.-1.mcr ../love2dworld/region.0.-1 ../love2dworld/all_regions.txt &
$PYTHON mc.py $HOME/Love2DWorld/region/r.-1.0.mcr ../love2dworld/region.-1.0 ../love2dworld/all_regions.txt &
wait
cat ../love2dworld/region*.lights.vtx > ../love2dworld/global.lights.vtx
cat ../love2dworld/region*.dump > ../love2dworld/global.dump
$PYTHON intkeys.py ../love2dworld/global.dump | $HOME/nbperf/nbperf -n love2dworld_hash -I -a bpz -c 1.24 -m ../love2dworld/map.txt > ../love2dworld/inthash.c

View File

@ -101,7 +101,7 @@ def build_level_table(level_table, mem, locations):
for location in locations: for location in locations:
try: try:
level = mcregion.parse_location(mem, location) level = mcregion.parse_location(mem, location)
except CountZeroException: except mcregion.CountZeroException:
continue continue
x, z = level.x_pos, level.z_pos x, z = level.x_pos, level.z_pos
level_table[(x, z)] = level level_table[(x, z)] = level
@ -209,13 +209,6 @@ def level_table_from_path(level_table, path):
build_level_table(level_table, mem, locations) build_level_table(level_table, mem, locations)
all_paths = [
"/home/bilbo/Love2DWorld/region/r.0.0.mcr",
"/home/bilbo/Love2DWorld/region/r.-1.-1.mcr",
"/home/bilbo/Love2DWorld/region/r.0.-1.mcr",
"/home/bilbo/Love2DWorld/region/r.-1.0.mcr",
]
g_stride = 512 * 2 g_stride = 512 * 2
def from_global_index(i): def from_global_index(i):
x, y, z = i % g_stride, i // (g_stride * g_stride), (i // g_stride) % g_stride x, y, z = i % g_stride, i // (g_stride * g_stride), (i // g_stride) % g_stride
@ -256,7 +249,13 @@ def main2(level_table, level_table_keys):
build_block_instances(blocks) build_block_instances(blocks)
print("blocks_length:", len(blocks)) print("blocks_length:", len(blocks))
def main(mcr_path, data_path): def parse_all_paths(path):
with open(path, 'r') as f:
buf = f.read()
return set(l.strip() for l in buf.split('\n') if l.strip())
def main(mcr_path, data_path, all_paths_path):
all_paths = parse_all_paths(all_paths_path)
assert mcr_path in all_paths assert mcr_path in all_paths
level_table = {} level_table = {}
level_table_from_path(level_table, mcr_path) level_table_from_path(level_table, mcr_path)
@ -273,4 +272,5 @@ def main(mcr_path, data_path):
mcr_path = sys.argv[1] mcr_path = sys.argv[1]
data_path = sys.argv[2] data_path = sys.argv[2]
main(mcr_path, data_path) all_paths_path = sys.argv[3]
main(mcr_path, data_path, all_paths_path)

View File

@ -1,14 +0,0 @@
set -eux
cd ./minecraft/gen
PYTHON=pypy3.11
$PYTHON mc.py ~/Love2DWorld/region/r.0.0.mcr ../region.0.0 &
$PYTHON mc.py ~/Love2DWorld/region/r.-1.-1.mcr ../region.-1.-1 &
$PYTHON mc.py ~/Love2DWorld/region/r.0.-1.mcr ../region.0.-1 &
$PYTHON mc.py ~/Love2DWorld/region/r.-1.0.mcr ../region.-1.0 &
wait
cat ../region*.lights.vtx > ../global.lights.vtx
cat ../region*.dump > ../global.dump
$PYTHON intkeys.py ../global.dump | ~/nbperf/nbperf -I -a bpz -c 1.24 -m map.txt > ../../src/inthash.c

View File

@ -0,0 +1,4 @@
/home/bilbo/Love2DWorld/region/r.0.0.mcr
/home/bilbo/Love2DWorld/region/r.-1.-1.mcr
/home/bilbo/Love2DWorld/region/r.0.-1.mcr
/home/bilbo/Love2DWorld/region/r.-1.0.mcr

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,4 @@
/home/bilbo/Love2DWorld/region/r.0.0.mcr
/home/bilbo/Love2DWorld/region/r.-1.-1.mcr
/home/bilbo/Love2DWorld/region/r.0.-1.mcr
/home/bilbo/Love2DWorld/region/r.-1.0.mcr

View File

@ -11,7 +11,7 @@
#define HAVE_POPCOUNT64 #define HAVE_POPCOUNT64
#define popcount64 __builtin_popcountll #define popcount64 __builtin_popcountll
#else #else
static const uint8_t inthash_bits_per_byte[256] = { static const uint8_t love2dworld_hash_bits_per_byte[256] = {
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
@ -41,7 +41,7 @@ static inline void _inthash4(const int32_t key, uint64_t *h)
#define GETI2(g, i) ((uint8_t)((g[i >> 2] >> ((i & 3) << 1U)) & 3)) #define GETI2(g, i) ((uint8_t)((g[i >> 2] >> ((i & 3) << 1U)) & 3))
uint32_t uint32_t
inthash(const int32_t key) love2dworld_hash(const int32_t key)
{ {
static const uint8_t g[560736] = { static const uint8_t g[560736] = {
0x81, 0x43, 0xa9, 0xba, 0xf7, 0x18, 0xa3, 0xbf, 0x45, 0x80, 0x81, 0x43, 0xa9, 0xba, 0xf7, 0x18, 0xa3, 0xbf, 0x45, 0x80,
@ -59645,7 +59645,7 @@ inthash(const int32_t key)
idx_b = idx_v >> 2; idx_b = idx_v >> 2;
end_idx_b = vertex >> 2; end_idx_b = vertex >> 2;
while (idx_b < end_idx_b) while (idx_b < end_idx_b)
base_rank += inthash_bits_per_byte[*(g + idx_b++)]; base_rank += love2dworld_hash_bits_per_byte[*(g + idx_b++)];
idx_v = idx_b << 2; idx_v = idx_b << 2;
while (idx_v < vertex) while (idx_v < vertex)
{ {

1268856
minecraft/love2dworld/map.txt Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -38,8 +38,6 @@ namespace lighting {
static unsigned int program; static unsigned int program;
static location location; static location location;
static unsigned int light_uniform_buffer;
void load_program() void load_program()
{ {
program = compile_from_files("shader/quad.vert", program = compile_from_files("shader/quad.vert",
@ -65,11 +63,6 @@ namespace lighting {
glUniformBlockBinding(program, location.uniform.lights, location.binding.lights); glUniformBlockBinding(program, location.uniform.lights, location.binding.lights);
} }
void load_light_uniform_buffer()
{
light_uniform_buffer = load_uniform_buffer("minecraft/global.lights.vtx");
}
static inline bool near_zero(float a) static inline bool near_zero(float a)
{ {
return (fabsf(a) < 0.00001f); return (fabsf(a) < 0.00001f);
@ -101,7 +94,7 @@ namespace lighting {
XMStoreFloat3(&eye, view::state.eye); XMStoreFloat3(&eye, view::state.eye);
glUniform3fv(location.uniform.eye, 1, (float*)&eye); glUniform3fv(location.uniform.eye, 1, (float*)&eye);
glBindBufferBase(GL_UNIFORM_BUFFER, location.binding.lights, light_uniform_buffer); //glBindBufferBase(GL_UNIFORM_BUFFER, location.binding.lights, light_uniform_buffer);
glBindVertexArray(empty_vertex_array_object); glBindVertexArray(empty_vertex_array_object);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_index_buffer);

View File

@ -10,6 +10,8 @@
#include "view.h" #include "view.h"
#include "minecraft.h" #include "minecraft.h"
#include "minecraft_data.inc" #include "minecraft_data.inc"
#include "new.h"
#include "world/world.h"
namespace minecraft { namespace minecraft {
struct location { struct location {
@ -35,21 +37,7 @@ namespace minecraft {
static unsigned int program; static unsigned int program;
static location location; static location location;
struct char_tpl {
const char * vtx;
const char * cfg;
};
static const int region_count = 4;
static const char_tpl vertex_paths[] = {
{ "minecraft/region.0.0.instance.vtx", "minecraft/region.0.0.instance.cfg" },
{ "minecraft/region.-1.0.instance.vtx", "minecraft/region.-1.0.instance.cfg" },
{ "minecraft/region.0.-1.instance.vtx", "minecraft/region.0.-1.instance.cfg" },
{ "minecraft/region.-1.-1.instance.vtx", "minecraft/region.-1.-1.instance.cfg" },
};
static unsigned int vertex_array_object; static unsigned int vertex_array_object;
static unsigned int per_instance_vertex_buffers[region_count];
static unsigned int per_vertex_buffer; static unsigned int per_vertex_buffer;
static const int per_instance_size = 4 + (1 * 4); static const int per_instance_size = 4 + (1 * 4);
@ -57,23 +45,14 @@ namespace minecraft {
static unsigned int index_buffer; static unsigned int index_buffer;
// also update index_buffer_custom_offsets in data.inc
static const int custom_block_types = 5;
static const int instance_cfg_length = 64 + custom_block_types;
struct instance_cfg {
struct region_instance {
int instance_count;
int offset;
} cfg[instance_cfg_length];
};
static instance_cfg instance_cfg[region_count];
static unsigned int texture; static unsigned int texture;
static unsigned int texture_id_uniform_buffer; static unsigned int texture_id_uniform_buffer;
static const int world_count = 1;
static world::state world_state[world_count];
world::state * current_world;
void load_program() void load_program()
{ {
program = compile_from_files("shader/minecraft.vert", program = compile_from_files("shader/minecraft.vert",
@ -143,19 +122,6 @@ namespace minecraft {
glBindVertexArray(0); glBindVertexArray(0);
} }
void load_per_instance_vertex_buffer(int i)
{
int vertex_buffer_data_size;
void * vertex_buffer_data = read_file(vertex_paths[i].vtx, &vertex_buffer_data_size);
glBindBuffer(GL_ARRAY_BUFFER, per_instance_vertex_buffers[i]);
glBufferData(GL_ARRAY_BUFFER, vertex_buffer_data_size, vertex_buffer_data, GL_STATIC_DRAW);
free(vertex_buffer_data);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void load_per_vertex_buffer() void load_per_vertex_buffer()
{ {
glGenBuffers(1, &per_vertex_buffer); glGenBuffers(1, &per_vertex_buffer);
@ -186,15 +152,6 @@ namespace minecraft {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
} }
void load_instance_cfg(int i)
{
int data_size;
void * data = read_file(vertex_paths[i].cfg, &data_size);
assert(data_size == (sizeof (struct instance_cfg)));
memcpy(&instance_cfg[i], data, data_size);
}
void load_texture() void load_texture()
{ {
glGenTextures(1, &texture); glGenTextures(1, &texture);
@ -223,6 +180,61 @@ namespace minecraft {
texture_id_uniform_buffer = load_uniform_buffer("minecraft/block_id_to_texture_id.data"); texture_id_uniform_buffer = load_uniform_buffer("minecraft/block_id_to_texture_id.data");
} }
//////////////////////////////////////////////////////////////////////
// per-world load
//////////////////////////////////////////////////////////////////////
namespace per_world {
static void load_instance_cfg(char const * path, world::instance_cfg_entry * entries)
{
int data_size;
void * data = read_file(path, &data_size);
assert(data_size == (sizeof (struct world::instance_cfg_entry)) * world::instance_cfg_length);
memcpy(entries, data, data_size);
}
static void load_per_instance_vertex_buffer(char const * path, unsigned int vertex_buffer)
{
int vertex_buffer_data_size;
void * vertex_buffer_data = read_file(path, &vertex_buffer_data_size); // vertex_paths[i].vtx
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); //per_instance_vertex_buffers[i]
glBufferData(GL_ARRAY_BUFFER, vertex_buffer_data_size, vertex_buffer_data, GL_STATIC_DRAW);
free(vertex_buffer_data);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
static void load_regions(world::descriptor const * const descriptor, world::region * region)
{
unsigned int per_instance_vertex_buffers[descriptor->region_count];
glGenBuffers(descriptor->region_count, per_instance_vertex_buffers);
for (int i = 0; i < descriptor->region_count; i++) {
// vtx
load_per_instance_vertex_buffer(descriptor->vertex_paths[i].vtx, per_instance_vertex_buffers[i]);
region[i].per_instance_vertex_buffer = per_instance_vertex_buffers[i];
// cfg
load_instance_cfg(descriptor->vertex_paths[i].cfg, region[i].instance_cfg);
}
}
void load_world(world::descriptor const * const descriptor, world::state & state)
{
state.descriptor = descriptor;
state.region = New<world::region>(descriptor->region_count);
load_regions(descriptor, state.region);
state.light_uniform_buffer = load_uniform_buffer(descriptor->lights_path);
// collision data
world::entry_table::load_entry_table(descriptor->entry_table_path,
&state.entry_table,
&state.entry_table_length,
descriptor->hash_func);
}
}
void load() void load()
{ {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -239,13 +251,6 @@ namespace minecraft {
// per-vertex buffer // per-vertex buffer
load_per_vertex_buffer(); load_per_vertex_buffer();
// per-instance buffer
glGenBuffers(region_count, per_instance_vertex_buffers);
for (int i = 0; i < region_count; i++) {
load_per_instance_vertex_buffer(i);
load_instance_cfg(i);
}
// index buffer // index buffer
load_index_buffer(); load_index_buffer();
@ -260,6 +265,15 @@ namespace minecraft {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
load_texture_id_uniform_buffer(); load_texture_id_uniform_buffer();
//////////////////////////////////////////////////////////////////////
// worlds
//////////////////////////////////////////////////////////////////////
for (int i = 0; i < world_count; i++) {
per_world::load_world(&world::descriptors[i], world_state[i]);
}
current_world = &world_state[world::world_id::LOVE2DWORLD];
} }
static inline int popcount(int x) static inline int popcount(int x)
@ -291,8 +305,8 @@ namespace minecraft {
glBindVertexBuffer(0, per_vertex_buffer, 0, per_vertex_size); glBindVertexBuffer(0, per_vertex_buffer, 0, per_vertex_size);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
for (int region_index = 0; region_index < region_count; region_index++) { for (int region_index = 0; region_index < current_world->descriptor->region_count; region_index++) {
glBindVertexBuffer(1, per_instance_vertex_buffers[region_index], 0, per_instance_size); glBindVertexBuffer(1, current_world->region[region_index].per_instance_vertex_buffer, 0, per_instance_size);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// cube blocks // cube blocks
@ -301,8 +315,8 @@ namespace minecraft {
int element_count = 6 * popcount(configuration); int element_count = 6 * popcount(configuration);
const void * indices = (void *)(2 * (ptrdiff_t)index_buffer_configuration_offsets[configuration]); // index into configuration.idx const void * indices = (void *)(2 * (ptrdiff_t)index_buffer_configuration_offsets[configuration]); // index into configuration.idx
int instance_count = instance_cfg[region_index].cfg[configuration].instance_count; int instance_count = current_world->region[region_index].instance_cfg[configuration].count;
int base_instance = instance_cfg[region_index].cfg[configuration].offset / per_instance_size; // index into region.0.0.instance.vtx int base_instance = current_world->region[region_index].instance_cfg[configuration].offset / per_instance_size; // index into region.0.0.instance.vtx
if (instance_count == 0) if (instance_count == 0)
continue; continue;
@ -313,11 +327,11 @@ namespace minecraft {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// custom blocks // custom blocks
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
for (int i = 0; i < custom_block_types; i++) { for (int i = 0; i < world::custom_block_types; i++) {
int element_count = index_buffer_custom_offsets[i].count; int element_count = index_buffer_custom_offsets[i].count;
const void * indices = (void *)(2 * (ptrdiff_t)index_buffer_custom_offsets[i].offset); const void * indices = (void *)(2 * (ptrdiff_t)index_buffer_custom_offsets[i].offset);
int instance_count = instance_cfg[region_index].cfg[64 + i].instance_count; int instance_count = current_world->region[region_index].instance_cfg[64 + i].count;
int base_instance = instance_cfg[region_index].cfg[64 + i].offset / per_instance_size; // index into region.0.0.instance.vtx int base_instance = current_world->region[region_index].instance_cfg[64 + i].offset / per_instance_size; // index into region.0.0.instance.vtx
if (instance_count == 0) if (instance_count == 0)
continue; continue;
glDrawElementsInstancedBaseInstance(GL_TRIANGLES, element_count, GL_UNSIGNED_SHORT, indices, instance_count, base_instance); glDrawElementsInstancedBaseInstance(GL_TRIANGLES, element_count, GL_UNSIGNED_SHORT, indices, instance_count, base_instance);

View File

@ -11,7 +11,6 @@
#include "window.h" #include "window.h"
#include "bresenham.h" #include "bresenham.h"
#include "file.h" #include "file.h"
#include "world.h"
#include "view.h" #include "view.h"
#include "non_block.h" #include "non_block.h"
#include "minecraft.h" #include "minecraft.h"
@ -26,6 +25,9 @@
#include "collada/types.h" #include "collada/types.h"
#include "collada/instance_types.h" #include "collada/instance_types.h"
#include "world/entry_table.h"
#include "world/world.h"
#include "data/scenes/ship20.h" #include "data/scenes/ship20.h"
#include "data/scenes/noodle.h" #include "data/scenes/noodle.h"
#include "data/scenes/shadow_test.h" #include "data/scenes/shadow_test.h"
@ -111,123 +113,6 @@ extern "C" {
void * SDL_GL_GetProcAddress(const char *proc); void * SDL_GL_GetProcAddress(const char *proc);
} }
struct short_point {
short x;
short y;
short z;
};
static_assert((sizeof (short_point)) == 6);
short_point line_points[128];
static int line_point_ix = 0;
void append_line_point(int x, int y, int z)
{
if (line_point_ix == 1)
return;
global_entry * const entry = world_lookup(x, y, z);
if (entry != NULL) {
line_points[line_point_ix].x = x;
line_points[line_point_ix].y = y;
line_points[line_point_ix].z = z;
line_point_ix += 1;
}
}
void load_line_program()
{
unsigned int program = compile_from_files("shader/line.vert",
NULL,
"shader/line.frag");
line_location.attrib.position = glGetAttribLocation(program, "Position");
line_location.attrib.normal = glGetAttribLocation(program, "Normal");
line_location.attrib.texture = glGetAttribLocation(program, "Texture");
line_location.attrib.block_position = glGetAttribLocation(program, "BlockPosition");
printf("line program:\n");
printf(" attributes:\n position %u\n normal %u\n texture %u\n block_position %u\n",
line_location.attrib.position,
line_location.attrib.normal,
line_location.attrib.texture,
line_location.attrib.block_position);
line_location.uniform.transform = glGetUniformLocation(program, "Transform");
printf(" uniforms:\n transform %u\n\n",
line_location.uniform.transform);
line_program = program;
}
void load_line_vertex_attributes()
{
glGenVertexArrays(1, &line_vertex_array_object);
glBindVertexArray(line_vertex_array_object);
glVertexBindingDivisor(0, 0);
glVertexBindingDivisor(1, 1);
glEnableVertexAttribArray(line_location.attrib.position);
glVertexAttribFormat(line_location.attrib.position, 3, GL_HALF_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(line_location.attrib.position, 0);
glEnableVertexAttribArray(line_location.attrib.normal);
glVertexAttribFormat(line_location.attrib.normal, 3, GL_HALF_FLOAT, GL_FALSE, 6);
glVertexAttribBinding(line_location.attrib.normal, 0);
glEnableVertexAttribArray(line_location.attrib.texture);
glVertexAttribFormat(line_location.attrib.texture, 2, GL_HALF_FLOAT, GL_FALSE, 12);
glVertexAttribBinding(line_location.attrib.texture, 0);
glEnableVertexAttribArray(line_location.attrib.block_position);
glVertexAttribFormat(line_location.attrib.block_position, 3, GL_SHORT, GL_FALSE, 0);
glVertexAttribBinding(line_location.attrib.block_position, 1);
glBindVertexArray(0);
}
void load_line_instance_buffer()
{
glBindBuffer(GL_ARRAY_BUFFER, line_instance_buffer);
glBufferData(GL_ARRAY_BUFFER, (sizeof (short_point)) * line_point_ix, line_points, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
struct line_state {
struct {
int x;
int y;
int z;
} point[2];
};
static line_state line_state = {};
void load_line()
{
line_point_ix = 0;
bresenham(line_state.point[0].x, line_state.point[0].y, line_state.point[0].z,
line_state.point[1].x, line_state.point[1].y, line_state.point[1].z,
append_line_point);
load_line_instance_buffer();
}
void load_line_point_from_eye(int point_ix)
{
int x = XMVectorGetX(view::state.eye);
int y = XMVectorGetY(view::state.eye);
int z = XMVectorGetZ(view::state.eye);
line_state.point[point_ix].x = x;
line_state.point[point_ix].y = z;
line_state.point[point_ix].z = y;
load_line();
}
void load(const char * source_path) void load(const char * source_path)
{ {
g_source_path_length = strlen(source_path); g_source_path_length = strlen(source_path);
@ -243,12 +128,6 @@ void load(const char * source_path)
minecraft::load(); minecraft::load();
//////////////////////////////////////////////////////////////////////
// world (collision data)
//////////////////////////////////////////////////////////////////////
load_world();
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// view // view
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -277,16 +156,6 @@ void load(const char * source_path)
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
lighting::load_program(); lighting::load_program();
lighting::load_light_uniform_buffer();
//////////////////////////////////////////////////////////////////////
// line
//////////////////////////////////////////////////////////////////////
load_line_program();
load_line_vertex_attributes();
glGenBuffers(1, &line_instance_buffer);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// non_block // non_block
@ -360,7 +229,10 @@ void check_collisions(collision::Sphere const & sphere, XMVECTOR const & directi
for (int x = min_x; x <= max_x; x++) { for (int x = min_x; x <= max_x; x++) {
for (int y = min_y; y <= max_y; y++) { for (int y = min_y; y <= max_y; y++) {
for (int z = min_z; z <= max_z; z++) { for (int z = min_z; z <= max_z; z++) {
global_entry * const entry = world_lookup(x, y, z); world::entry_table::global_entry * const entry = world_lookup(minecraft::current_world->descriptor->hash_func,
minecraft::current_world->entry_table,
minecraft::current_world->entry_table_length,
x, y, z);
if (entry == NULL) if (entry == NULL)
continue; continue;
@ -377,24 +249,8 @@ void check_collisions(collision::Sphere const & sphere, XMVECTOR const & directi
const int max_joysticks = 8; const int max_joysticks = 8;
void update_joystick(int joystick_index, void minecraft_view_update(XMVECTOR direction)
float lx, float ly, float rx, float ry, float tl, float tr,
int up, int down, int left, int right,
int a, int b, int x, int y,
int leftshoulder, int rightshoulder,
int start)
{ {
float forward = -ly * 0.5;
float strafe = lx * 0.5;
float elevation = (tl - tr) * 0.5;
float delta_yaw = rx * -0.035;
float delta_pitch = ry * -0.035;
XMVECTOR direction = view::third_person::apply_transform(forward, strafe, elevation,
delta_yaw, delta_pitch);
view::apply_fov(0.01 * up + -0.01 * down);
/*
XMVECTOR sphere_position = view::state.at; XMVECTOR sphere_position = view::state.at;
float sphere_radius = 0.48; float sphere_radius = 0.48;
@ -426,9 +282,31 @@ void update_joystick(int joystick_index,
// apply the last direction impulse // apply the last direction impulse
view::state.at = sphere.center + direction; view::state.at = sphere.center + direction;
} }
*/ view::state.eye = view::state.at - view::state.direction * view::at_distance;
}
view::state.eye = view::state.eye + direction; void update_joystick(int joystick_index,
float lx, float ly, float rx, float ry, float tl, float tr,
int up, int down, int left, int right,
int a, int b, int x, int y,
int leftshoulder, int rightshoulder,
int start)
{
float forward = -ly * 0.5;
float strafe = lx * 0.5;
float elevation = (tl - tr) * 0.5;
float delta_yaw = rx * -0.035;
float delta_pitch = ry * -0.035;
XMVECTOR direction = view::third_person::apply_transform(forward, strafe, elevation,
delta_yaw, delta_pitch);
view::apply_fov(0.01 * up + -0.01 * down);
if (true) {
minecraft_view_update(direction);
}
//view::state.eye = view::state.eye + direction;
//view::state.at = view::state.at - view::state.direction * view::at_distance; //view::state.at = view::state.at - view::state.direction * view::at_distance;
//view::state.at = view::state.at + direction; //view::state.at = view::state.at + direction;
@ -442,13 +320,6 @@ void update_joystick(int joystick_index,
if (lighting.linear < 0.0f) if (lighting.linear < 0.0f)
lighting.linear = 0.0f; lighting.linear = 0.0f;
*/ */
if (leftshoulder) {
load_line_point_from_eye(0);
}
if (rightshoulder) {
load_line_point_from_eye(1);
}
} }
void update(float time) void update(float time)
@ -548,48 +419,13 @@ void update_mouse(int x, int y)
GL_FLOAT, GL_FLOAT,
(void*)&mouse_position); (void*)&mouse_position);
*/ */
{
float mx = (2.0f * (float)x) / geometry_buffer_pnc.width - 1.0f;
float my = 1.0f - (2.0f * (float)y) / geometry_buffer_pnc.height;
/*
XMVECTOR mouse_world = XMVector3Transform(mouse_clip, inverse);
XMVECTOR ray = XMVector3Normalize(mouse_world - view::state.eye);
mouse_ray_position = ray;
XMVECTOR ray_start = view::state.eye;
XMVECTOR ray_end = ray_start + ray * 20.0f;
*/
XMVECTOR mouse_clip = XMVectorSet(mx, my, -1, 0);
XMMATRIX projection_inverse = XMMatrixInverse(NULL, view::state.projection_transform);
XMMATRIX view_inverse = XMMatrixInverse(NULL, view::state.view_transform);
XMVECTOR mouse_view = XMVector3Transform(mouse_clip, projection_inverse);
mouse_view = XMVectorSetZ(mouse_view, -1);
XMVECTOR ray = XMVector3Normalize(XMVector3TransformNormal(mouse_view, view_inverse));
XMVECTOR ray_start = view::state.eye;
XMVECTOR ray_end = ray_start + ray * 20.0f;
line_state.point[0].x = roundf(XMVectorGetX(ray_start));
line_state.point[0].z = roundf(XMVectorGetY(ray_start));
line_state.point[0].y = roundf(XMVectorGetZ(ray_start));
line_state.point[1].x = roundf(XMVectorGetX(ray_end));
line_state.point[1].z = roundf(XMVectorGetY(ray_end));
line_state.point[1].y = roundf(XMVectorGetZ(ray_end));
load_line();
}
} }
void draw() void draw()
{ {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(-1.0f); glClearDepth(-1.0f);
if (false) { if (true) {
// possibly re-initialize geometry buffer if window width/height changes // possibly re-initialize geometry buffer if window width/height changes
init_geometry_buffer(geometry_buffer_pnc, geometry_buffer_pnc_types); init_geometry_buffer(geometry_buffer_pnc, geometry_buffer_pnc_types);

View File

@ -104,9 +104,9 @@ namespace view {
state.direction = get_direction(); // on forward/normal/pitch change state.direction = get_direction(); // on forward/normal/pitch change
// position // position
//state.eye = XMVectorSet(-45.5f, 43.25f, 63.0f, 1); state.eye = XMVectorSet(-45.5f, 43.25f, 63.0f, 1);
//state.at = state.eye + state.direction * at_distance; state.at = state.eye + state.direction * at_distance;
state.at = XMVectorSet(0, 0, 0, 1); //state.at = XMVectorSet(0, 0, 0, 1);
state.eye = XMVectorSet(0, -100, 0, 1); //state.eye = XMVectorSet(0, -100, 0, 1);
} }
} }

View File

@ -1,52 +0,0 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "inthash.h"
#include "file.h"
#include "world.h"
static global_entry_t * global_entry_table = NULL;
static int global_entry_table_length = 0;
void load_world()
{
int global_size;
global_entry_t * entry = (global_entry_t *)read_file("minecraft/global.dump", &global_size);
assert(entry != NULL);
global_entry_table_length = global_size / (sizeof (global_entry_t));
global_entry_table = calloc(global_entry_table_length, (sizeof (global_entry_t)));
for (int i = 0; i < global_entry_table_length; i++) {
uint32_t ix = inthash(entry[i].global_index);
assert(global_entry_table[ix].global_index == 0);
memcpy(&global_entry_table[ix], &entry[i], (sizeof (global_entry_t)));
}
free(entry);
}
static inline int global_index_from_xyz(int x, int y, int z)
{
const int g_stride = 512 * 2;
if (x < 0)
x = -(x - 511);
if (z < 0)
z = -(z - 511);
return x + z * g_stride + y * g_stride * g_stride;
}
global_entry_t * const world_lookup(int x, int y, int z)
{
int global_index = global_index_from_xyz(x, y, z);
int table_index = inthash(global_index);
if (table_index < 0 || table_index >= global_entry_table_length)
return NULL;
global_entry_t * const entry = &global_entry_table[table_index];
if (entry->global_index != global_index)
return NULL;
return entry;
}

62
src/world/entry_table.cpp Normal file
View File

@ -0,0 +1,62 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "file.h"
#include "new.h"
#include "world/entry_table.h"
namespace world::entry_table {
void load_entry_table(char const * const path,
global_entry_t ** out_entry_table,
int * out_entry_table_length,
hash_func_t * hash_func)
{
int global_size;
global_entry_t * entry = (global_entry_t *)read_file(path, &global_size);
assert(entry != NULL);
int entry_table_length = global_size / (sizeof (global_entry_t));
global_entry_t * entry_table = New<global_entry_t>(entry_table_length);
memset(entry_table, 0, global_size);
for (int i = 0; i < entry_table_length; i++) {
uint32_t ix = hash_func(entry[i].global_index);
assert(entry_table[ix].global_index == 0);
memcpy(&entry_table[ix], &entry[i], (sizeof (global_entry_t)));
}
free(entry);
*out_entry_table = entry_table;
*out_entry_table_length = entry_table_length;
}
static inline int global_index_from_xyz(int x, int y, int z)
{
const int g_stride = 512 * 2;
if (x < 0)
x = -(x - 511);
if (z < 0)
z = -(z - 511);
return x + z * g_stride + y * g_stride * g_stride;
}
global_entry_t * const world_lookup(hash_func_t * hash_func,
global_entry_t * entry_table,
int entry_table_length,
int x, int y, int z)
{
int global_index = global_index_from_xyz(x, y, z);
int table_index = hash_func(global_index);
if (table_index < 0 || table_index >= entry_table_length)
return NULL;
global_entry_t * const entry = &entry_table[table_index];
if (entry->global_index != global_index)
return NULL;
return entry;
}
}

22
src/world/world.cpp Normal file
View File

@ -0,0 +1,22 @@
#include "world/world.h"
#include "world/inthash.h"
namespace world {
static vtx_cfg const love2dworld_vertex_paths[] = {
{ "minecraft/love2dworld/region.0.0.instance.vtx", "minecraft/love2dworld/region.0.0.instance.cfg" },
{ "minecraft/love2dworld/region.-1.0.instance.vtx", "minecraft/love2dworld/region.-1.0.instance.cfg" },
{ "minecraft/love2dworld/region.0.-1.instance.vtx", "minecraft/love2dworld/region.0.-1.instance.cfg" },
{ "minecraft/love2dworld/region.-1.-1.instance.vtx", "minecraft/love2dworld/region.-1.-1.instance.cfg" },
};
descriptor const descriptors[] = {
[world_id::LOVE2DWORLD] = {
.region_count = 4,
.vertex_paths = love2dworld_vertex_paths,
.entry_table_path = "minecraft/love2dworld/global.dump",
.lights_path = "minecraft/love2dworld/global.lights.vtx",
.hash_func = love2dworld_hash,
},
};
int const descriptors_length = (sizeof (descriptors)) / (sizeof (descriptors[0]));
}