point lighting, colored wool

This commit is contained in:
Zack Buhman 2026-03-09 18:23:46 -05:00
parent ba2247068b
commit 7428b86b9e
19 changed files with 444 additions and 124 deletions

View File

@ -7,7 +7,8 @@ extern "C" {
void load(const char * source_path); void load(const char * source_path);
void draw(); void draw();
void update(float lx, float ly, float rx, float ry, float tl, float tr, void update(float lx, float ly, float rx, float ry, float tl, float tr,
int up, int down, int left, int right); int up, int down, int left, int right,
int a, int b, int x, int y);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -9,7 +9,8 @@ void load(const char * source_path);
void update_window(int width, int height); void update_window(int width, int height);
void draw(); void draw();
void update(float lx, float ly, float rx, float ry, float tl, float tr, void update(float lx, float ly, float rx, float ry, float tl, float tr,
int up, int down, int left, int right); int up, int down, int left, int right,
int a, int b, int x, int y);
]] ]]
local source_path = love.filesystem.getSource() local source_path = love.filesystem.getSource()
test = ffi.load(source_path .. "/test.so") test = ffi.load(source_path .. "/test.so")
@ -29,7 +30,11 @@ local update = function(dt)
local down = joystick:isGamepadDown("dpdown") local down = joystick:isGamepadDown("dpdown")
local left = joystick:isGamepadDown("dpleft") local left = joystick:isGamepadDown("dpleft")
local right = joystick:isGamepadDown("dpright") local right = joystick:isGamepadDown("dpright")
test.update(lx, ly, rx, ry, tl, tr, up, down, left, right) local a = joystick:isGamepadDown("a")
local b = joystick:isGamepadDown("b")
local x = joystick:isGamepadDown("x")
local y = joystick:isGamepadDown("y")
test.update(lx, ly, rx, ry, tl, tr, up, down, left, right, a, b, x, y)
end end
end end

Binary file not shown.

View File

@ -1,15 +1,13 @@
import struct import struct
import data
import sys
unk = 185 unk = 253
lookup = { with open(sys.argv[1], "wb") as f:
k: v for k, v, _ in mapping
}
with open("block_id_to_texture_id.data", "wb") as f:
for i in range(256): for i in range(256):
value = lookup.get(i, unk) if i in data.tiles_by_id:
value = data.tiles_by_id[i].texture
else:
value = unk
f.write(struct.pack("<i", value)) f.write(struct.pack("<i", value))
print(str(value).rjust(3), end=', ')
if i % 16 == 15:
print()

4
minecraft/gen/blocks.sh Normal file
View File

@ -0,0 +1,4 @@
set -eux
cd ./minecraft/gen
PYTHON=pypy3.11
$PYTHON blocks.py ../block_id_to_texture_id.data

View File

@ -118,9 +118,9 @@ class BlockID:
CLOTH_51 = 114 CLOTH_51 = 114
CLOTH_61 = 115 CLOTH_61 = 115
INFO_UPDATEGAME1 = 248 # modded
INFO_UPDATEGAME2 = 249 YELLOW_COBBLE = 128
LEAVES_CARRIED = 254 MARBLE_YELLOW = 248
class Texture: class Texture:
GRASS_TOP = 0 GRASS_TOP = 0
@ -272,6 +272,10 @@ class Texture:
LAVA_PLACEHOLDER = 255 LAVA_PLACEHOLDER = 255
# modded
YELLOW_COBBLE = 213
MARBLE_YELLOW = 214
@dataclass @dataclass
class Tile: class Tile:
block_id: BlockID block_id: BlockID
@ -299,6 +303,7 @@ tiles = [
Tile(BlockID.ORE_LAPIS, Texture.ORE_LAPIS), Tile(BlockID.ORE_LAPIS, Texture.ORE_LAPIS),
Tile(BlockID.BLOCK_LAPIS, Texture.LAPIS), Tile(BlockID.BLOCK_LAPIS, Texture.LAPIS),
Tile(BlockID.SANDSTONE, Texture.SANDSTONE_SIDE), Tile(BlockID.SANDSTONE, Texture.SANDSTONE_SIDE),
Tile(BlockID.CLOTH, Texture.CLOTH_64), # wool, colored
Tile(BlockID.FLOWER, Texture.FLOWER), Tile(BlockID.FLOWER, Texture.FLOWER),
Tile(BlockID.ROSE, Texture.ROSE), Tile(BlockID.ROSE, Texture.ROSE),
Tile(BlockID.MUSHROOM_1, Texture.MUSHROOM_BROWN), Tile(BlockID.MUSHROOM_1, Texture.MUSHROOM_BROWN),
@ -332,7 +337,7 @@ tiles = [
Tile(BlockID.FENCE, Texture.PLANKS), Tile(BlockID.FENCE, Texture.PLANKS),
Tile(BlockID.INVISIBLE, Texture.STONE), Tile(BlockID.INVISIBLE, Texture.STONE),
Tile(BlockID.WOOD, Texture.PLANKS), Tile(BlockID.WOOD, Texture.PLANKS),
Tile(BlockID.LEAVES_CARRIED, Texture.LEAVES_TRANSPARENT), # fixme #Tile(BlockID.LEAVES_CARRIED, Texture.LEAVES_TRANSPARENT), # fixme
Tile(BlockID.FIRE, Texture.FIRE1), Tile(BlockID.FIRE, Texture.FIRE1),
Tile(BlockID.SAPLING, Texture.SAPLING), Tile(BlockID.SAPLING, Texture.SAPLING),
Tile(BlockID.SPONGE, Texture.SPONGE), Tile(BlockID.SPONGE, Texture.SPONGE),
@ -346,6 +351,10 @@ tiles = [
Tile(BlockID.COBWEB, Texture.COBWEB), Tile(BlockID.COBWEB, Texture.COBWEB),
Tile(BlockID.WORKBENCH, Texture.WORKBENCH_TOP), # fixme Tile(BlockID.WORKBENCH, Texture.WORKBENCH_TOP), # fixme
Tile(BlockID.WHEAT, Texture.WHEAT_0), Tile(BlockID.WHEAT, Texture.WHEAT_0),
# modded blocks
Tile(BlockID.YELLOW_COBBLE, Texture.YELLOW_COBBLE),
Tile(BlockID.MARBLE_YELLOW, Texture.MARBLE_YELLOW),
] ]
tiles_by_id = { tiles_by_id = {

View File

@ -62,6 +62,9 @@ def block_neighbors(level_table, chunk_x, chunk_z, block_index):
if block_id == data.BlockID.AIR: if block_id == data.BlockID.AIR:
return return
block_data = level_table[(chunk_x, chunk_z)].data[block_index // 2]
block_data = (block_data >> (1 - (block_index % 2)) * 4) & 0xf
xyz = mcregion.xyz_from_block_index(block_index) xyz = mcregion.xyz_from_block_index(block_index)
center_position = vec3.add(xyz, (chunk_x * 16, 0, chunk_z * 16)) center_position = vec3.add(xyz, (chunk_x * 16, 0, chunk_z * 16))
@ -74,7 +77,7 @@ def block_neighbors(level_table, chunk_x, chunk_z, block_index):
normal_indices = list(find_non_neighbors()) normal_indices = list(find_non_neighbors())
if block_id in non_solid_blocks or normal_indices: if block_id in non_solid_blocks or normal_indices:
yield center_position, block_id, normal_indices yield center_position, block_id, block_data, normal_indices
def devoxelize_region(level_table, level_table_keys): def devoxelize_region(level_table, level_table_keys):
for chunk_x, chunk_z in level_table_keys: for chunk_x, chunk_z in level_table_keys:
@ -107,15 +110,15 @@ def build_block_configuration_table():
indices.extend(vertex_buffer.faces_by_normal[vertex_buffer.normals[j]]) indices.extend(vertex_buffer.faces_by_normal[vertex_buffer.normals[j]])
yield indices yield indices
def pack_instance_data(position, block_id): def pack_instance_data(position, block_id, block_data):
packed = struct.pack("<hhhBB", packed = struct.pack("<hhhBB",
position[0], position[1], position[2], position[0], position[1], position[2],
block_id, block_id,
0) block_data)
return packed return packed
def pack_light_data(position, block_id): def pack_light_data(position, block_id):
packed = struct.pack("<iiii", position[0], position[1], position[2], block_id) packed = struct.pack("<ffff", position[0], position[1], position[2], block_id)
return packed return packed
def build_block_instances(blocks): def build_block_instances(blocks):
@ -125,21 +128,21 @@ def build_block_instances(blocks):
light_sources = [] light_sources = []
def is_deferred_block(position, block_id): def is_deferred_block(position, block_id, block_data):
for i, custom_block_types in enumerate(custom_blocks): for i, custom_block_types in enumerate(custom_blocks):
if block_id in custom_block_types: if block_id in custom_block_types:
deferred_blocks[i].append((position, block_id)) deferred_blocks[i].append((position, block_id, block_data))
return True return True
return False return False
for position, block_id, normal_indices in blocks: for position, block_id, block_data, normal_indices in blocks:
if block_id == data.BlockID.TORCH: if block_id == data.BlockID.TORCH:
light_sources.append((position, block_id)) light_sources.append((position, block_id))
if is_deferred_block(position, block_id): if is_deferred_block(position, block_id, block_data):
assert block_id in non_solid_blocks assert block_id in non_solid_blocks
continue continue
configuration = normal_indices_as_block_configuration(normal_indices) configuration = normal_indices_as_block_configuration(normal_indices)
by_configuration[configuration].append((position, block_id)) by_configuration[configuration].append((position, block_id, block_data))
offset = 0 offset = 0
configuration_instance_count_offset = [] configuration_instance_count_offset = []
@ -153,9 +156,9 @@ def build_block_instances(blocks):
continue continue
_blocks = by_configuration[configuration] _blocks = by_configuration[configuration]
configuration_instance_count_offset.append((len(_blocks), offset)) configuration_instance_count_offset.append((len(_blocks), offset))
for position, block_id in _blocks: for position, block_id, block_data in _blocks:
assert block_id not in non_solid_blocks, block_id assert block_id not in non_solid_blocks, block_id
packed = pack_instance_data(position, block_id) packed = pack_instance_data(position, block_id, block_data)
f.write(packed) f.write(packed)
offset += len(packed) offset += len(packed)
@ -165,9 +168,9 @@ def build_block_instances(blocks):
for custom_block_ix in range(len(custom_blocks)): for custom_block_ix in range(len(custom_blocks)):
nc_offset = offset nc_offset = offset
nc_instance_count = 0 nc_instance_count = 0
for position, block_id in deferred_blocks[custom_block_ix]: for position, block_id, block_data in deferred_blocks[custom_block_ix]:
assert block_id in non_solid_blocks, block_id assert block_id in non_solid_blocks, block_id
packed = pack_instance_data(position, block_id) packed = pack_instance_data(position, block_id, block_data)
f.write(packed) f.write(packed)
offset += len(packed) offset += len(packed)
nc_instance_count += 1 nc_instance_count += 1

View File

@ -0,0 +1,150 @@
import struct
from collections import defaultdict
import sys
import data
files = sys.argv[1:]
by_block_id = defaultdict(list)
no_tile = defaultdict(list)
block_ids = {
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
66,
67,
68,
69,
70,
71,
72,
73,
74,
75,
76,
77,
78,
79,
80,
81,
82,
83,
84,
85,
86,
87,
88,
89,
90,
91,
92,
93,
94,
95,
96,
97,
98,
99,
100,
101,
102,
103,
104,
105,
106,
107,
108,
109,
110,
111,
112,
113,
114,
115,
}
for filename in files:
with open(filename, 'rb') as f:
buf = f.read()
for i in range(len(buf) // 8):
x, y, z, block_id, block_data = struct.unpack("<hhhBB", buf[i*8:i*8+8])
if block_id == 35:
print(x, y, z, block_data)
if block_id not in block_ids and block_id not in data.tiles_by_id:
by_block_id[block_id].append((x, y, z, block_data))
elif block_id not in data.tiles_by_id:
no_tile[block_id].append((x, y, z, block_data))
print("no block id:")
for key in sorted(by_block_id.keys()):
print(" ", key, len(by_block_id[key]), by_block_id[key][0])
print("no tile:")
for key in sorted(no_tile.keys()):
print(" ", key, len(no_tile[key]), no_tile[key][0])

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.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

@ -1,58 +1,40 @@
#version 330 core #version 330 core
in VS_OUT { uniform sampler2D PositionSampler;
vec3 Normal; uniform sampler2D NormalSampler;
vec2 Texture; uniform sampler2D ColorSampler;
flat int BlockID;
} fs_in;
out vec4 FragColor; uniform float Linear;
uniform float Quadratic;
uniform vec3 Eye;
uniform sampler2D TerrainSampler; layout (location = 0) out vec4 Color;
int Textures[256] = int[256]( in vec4 PixelTexture;
185, 1, 0, 2, 16, 4, 15, 17, 205, 205, 237, 237, 18, 19, 32, 33,
34, 20, 52, 48, 49, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 39, layout (std140) uniform Lights
185, 185, 185, 64, 185, 13, 12, 29, 28, 39, 38, 5, 5, 7, 8, 35, {
36, 37, 80, 31, 65, 4, 27, 84, 50, 40, 43, 88, 87, 44, 61, 185, vec4 light[256];
81, 83, 128, 16, 185, 96, 6, 82, 6, 51, 51, 115, 99, 185, 66, 67, };
66, 70, 72, 73, 74, 4, 102, 103, 104, 105, 14, 102, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185
);
void main() void main()
{ {
vec3 light_direction = normalize(vec3(-1, -0.5, 0.5)); vec4 position = texture(PositionSampler, PixelTexture.xy);
float diffuse_intensity = max(dot(normalize(fs_in.Normal), light_direction), 0.0); vec4 normal = texture(NormalSampler, PixelTexture.xy);
vec4 color = texture(ColorSampler, PixelTexture.xy);
int terrain_ix = int(Textures[int(fs_in.BlockID)]); vec3 out_color = color.xyz * 0.1;
int terrain_x = terrain_ix % 16; for (int i = 0; i < 82; i++) {
int terrain_y = terrain_ix / 16; vec3 light_position = light[i].xzy;
ivec2 coord = ivec2(terrain_x, terrain_y) * 16; float light_distance = length(light_position - position.xyz);
coord += ivec2(fs_in.Texture.xy * 16.0); vec3 light_direction = normalize(light_position - position.xyz);
float diffuse = max(dot(normal.xyz, light_direction), 0.0);
//float attenuation = 1.0 / (1.0 + Linear * light_distance + Quadratic * light_distance * light_distance);
vec4 texture_color = texelFetch(TerrainSampler, coord, 0); float attenuation = 1.0 / (1.0 + Quadratic * light_distance * light_distance);
if (texture_color.w != 1.0) { out_color += color.xyz * attenuation * diffuse;
discard; //out_color = vec3(diffuse);
return;
} }
if (fs_in.BlockID == 18 || fs_in.BlockID == 31) // leaves Color = vec4(out_color, 1.0);
texture_color.xyz *= vec3(0.125, 0.494, 0.027);
if (diffuse_intensity < 0.1)
diffuse_intensity = 0.1;
if (fs_in.BlockID == 31 || fs_in.BlockID == 39 || fs_in.BlockID == 40 || fs_in.BlockID == 37 || fs_in.BlockID == 38 || fs_in.BlockID == 6) // tall_grass
diffuse_intensity = 1.0;
FragColor = vec4(texture_color.xyz * vec3(diffuse_intensity), 1.0);
} }

View File

@ -5,6 +5,7 @@ in VS_OUT {
vec3 Normal; vec3 Normal;
vec2 Texture; vec2 Texture;
flat int BlockID; flat int BlockID;
flat int Data;
} fs_in; } fs_in;
layout (location = 0) out vec3 Position; layout (location = 0) out vec3 Position;
@ -13,28 +14,37 @@ layout (location = 2) out vec3 Color;
uniform sampler2D TerrainSampler; uniform sampler2D TerrainSampler;
int Textures[256] = int[256]( layout (std140) uniform TextureID
185, 1, 0, 2, 16, 4, 15, 17, 205, 205, 237, 237, 18, 19, 32, 33, {
34, 20, 52, 48, 49, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 39, ivec4 block_id_to_texture_id[256 / 4];
185, 185, 185, 64, 185, 13, 12, 29, 28, 39, 38, 5, 5, 7, 8, 35, };
36, 37, 80, 31, 65, 4, 27, 84, 50, 40, 43, 88, 87, 44, 61, 185,
81, 83, 128, 16, 185, 96, 6, 82, 6, 51, 51, 115, 99, 185, 66, 67, int wool[16] = int[16]( 64, // 0 64
66, 70, 72, 73, 74, 4, 102, 103, 104, 105, 14, 102, 185, 185, 185, 185, 210, // 32 208
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 194, // 32 192
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 178, // 32 176
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 162, // 32 160
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 146, // 32 144
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 130, // 32 128
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 114, // 32 112
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 225, // 16 224
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 209, // 16 208
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 193, // 16 192
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185 177, // 16 176
); 161, // 16 160
145, // 16 144
129, // 16 128
113 // 16 112
);
void main() void main()
{ {
int terrain_ix = int(Textures[int(fs_in.BlockID)]); int terrain_ix;
if (fs_in.BlockID == 35) // cloth
terrain_ix = wool[fs_in.Data];
else
terrain_ix = block_id_to_texture_id[fs_in.BlockID / 4][fs_in.BlockID % 4];
int terrain_x = terrain_ix % 16; int terrain_x = terrain_ix % 16;
int terrain_y = terrain_ix / 16; int terrain_y = terrain_ix / 16;
ivec2 coord = ivec2(terrain_x, terrain_y) * 16; ivec2 coord = ivec2(terrain_x, terrain_y) * 16;
@ -49,7 +59,7 @@ void main()
if (fs_in.BlockID == 18 || fs_in.BlockID == 31) // leaves if (fs_in.BlockID == 18 || fs_in.BlockID == 31) // leaves
texture_color.xyz *= vec3(0.125, 0.494, 0.027); texture_color.xyz *= vec3(0.125, 0.494, 0.027);
Position = fs_in.Position; Position = fs_in.Position.xzy;
Normal = normalize(fs_in.Normal); Normal = normalize(fs_in.Normal.xzy);
Color = texture_color.xyz; Color = texture_color.xyz;
} }

View File

@ -7,12 +7,14 @@ in vec2 Texture;
// per-instance: // per-instance:
in vec3 BlockPosition; in vec3 BlockPosition;
in float BlockID; in float BlockID;
in float Data;
out VS_OUT { out VS_OUT {
vec3 Position; vec3 Position;
vec3 Normal; vec3 Normal;
vec2 Texture; vec2 Texture;
flat int BlockID; flat int BlockID;
flat int Data;
} vs_out; } vs_out;
uniform mat4 Transform; uniform mat4 Transform;
@ -22,9 +24,10 @@ void main()
vec3 position = Position + BlockPosition; // world coordinates vec3 position = Position + BlockPosition; // world coordinates
vs_out.Position = position; vs_out.Position = position;
vs_out.Normal = Normal.xzy; vs_out.Normal = Normal;
vs_out.Texture = Texture; vs_out.Texture = Texture;
vs_out.BlockID = int(BlockID); vs_out.BlockID = int(BlockID);
vs_out.Data = int(Data);
gl_Position = Transform * vec4(position.xzy, 1.0); gl_Position = Transform * vec4(position.xzy, 1.0);
} }

View File

@ -18,12 +18,17 @@ struct test_location {
unsigned int texture; unsigned int texture;
unsigned int block_position; unsigned int block_position;
unsigned int block_id; unsigned int block_id;
//unsigned int configuration; unsigned int data;
} attrib; } attrib;
struct { struct {
unsigned int transform; unsigned int transform;
unsigned int terrain_sampler; unsigned int terrain_sampler;
unsigned int texture_id;
} uniform; } uniform;
struct {
unsigned int texture_id;
} binding;
}; };
static unsigned int test_program; static unsigned int test_program;
static test_location test_location; static test_location test_location;
@ -36,6 +41,24 @@ struct quad_location {
static unsigned int quad_program; static unsigned int quad_program;
static quad_location quad_location; static quad_location quad_location;
struct lighting_location {
struct {
unsigned int position_sampler;
unsigned int normal_sampler;
unsigned int color_sampler;
unsigned int quadratic;
unsigned int linear;
unsigned int eye;
unsigned int lights;
} uniform;
struct {
unsigned int lights;
} binding;
};
static unsigned int lighting_program;
static lighting_location lighting_location;
struct char_tpl { struct char_tpl {
const char * vtx; const char * vtx;
const char * cfg; const char * cfg;
@ -100,19 +123,26 @@ void load_test_program()
test_location.attrib.block_position = glGetAttribLocation(program, "BlockPosition"); test_location.attrib.block_position = glGetAttribLocation(program, "BlockPosition");
test_location.attrib.block_id = glGetAttribLocation(program, "BlockID"); test_location.attrib.block_id = glGetAttribLocation(program, "BlockID");
test_location.attrib.data = glGetAttribLocation(program, "Data");
printf("test program:\n"); printf("test program:\n");
printf(" attributes:\n position %u\n normal %u\n texture %u\n block_position %u\n block_id %u\n", printf(" attributes:\n position %u\n normal %u\n texture %u\n block_position %u\n block_id %u\n block_id %u\n",
test_location.attrib.position, test_location.attrib.position,
test_location.attrib.normal, test_location.attrib.normal,
test_location.attrib.texture, test_location.attrib.texture,
test_location.attrib.block_position, test_location.attrib.block_position,
test_location.attrib.block_id); test_location.attrib.block_id,
test_location.attrib.data);
test_location.uniform.transform = glGetUniformLocation(program, "Transform"); test_location.uniform.transform = glGetUniformLocation(program, "Transform");
test_location.uniform.terrain_sampler = glGetUniformLocation(program, "TerrainSampler"); test_location.uniform.terrain_sampler = glGetUniformLocation(program, "TerrainSampler");
printf(" uniforms:\n transform %u\n terrain_sampler %u\n", test_location.uniform.texture_id = glGetUniformBlockIndex(program, "TextureID");
printf(" uniforms:\n transform %u\n terrain_sampler %u\n texture_id %u\n",
test_location.uniform.transform, test_location.uniform.transform,
test_location.uniform.terrain_sampler); test_location.uniform.terrain_sampler,
test_location.uniform.texture_id);
test_location.binding.texture_id = 0;
glUniformBlockBinding(program, test_location.uniform.texture_id, test_location.binding.texture_id);
test_program = program; test_program = program;
} }
@ -131,6 +161,33 @@ void load_quad_program()
quad_program = program; quad_program = program;
} }
void load_lighting_program()
{
unsigned int program = compile_from_files("shader/quad.vert",
NULL,
"shader/lighting.frag");
lighting_location.uniform.position_sampler = glGetUniformLocation(program, "PositionSampler");
lighting_location.uniform.normal_sampler = glGetUniformLocation(program, "NormalSampler");
lighting_location.uniform.color_sampler = glGetUniformLocation(program, "ColorSampler");
lighting_location.uniform.quadratic = glGetUniformLocation(program, "Quadratic");
lighting_location.uniform.linear = glGetUniformLocation(program, "Linear");
lighting_location.uniform.eye = glGetUniformLocation(program, "Eye");
lighting_location.uniform.lights = glGetUniformBlockIndex(program, "Lights");
fprintf(stderr, "lighting program:\n");
fprintf(stderr, " uniforms:\n position_sampler %u normal_sampler %u color_sampler %u lights %u\n",
lighting_location.uniform.position_sampler,
lighting_location.uniform.normal_sampler,
lighting_location.uniform.color_sampler,
lighting_location.uniform.lights);
lighting_location.binding.lights = 0;
glUniformBlockBinding(program, lighting_location.uniform.lights, lighting_location.binding.lights);
lighting_program = program;
}
void load_per_instance_vertex_buffer(int i) void load_per_instance_vertex_buffer(int i)
{ {
int vertex_buffer_data_size; int vertex_buffer_data_size;
@ -202,6 +259,10 @@ void load_test_vertex_attributes()
glVertexAttribFormat(test_location.attrib.block_id, 1, GL_UNSIGNED_BYTE, GL_FALSE, 6); glVertexAttribFormat(test_location.attrib.block_id, 1, GL_UNSIGNED_BYTE, GL_FALSE, 6);
glVertexAttribBinding(test_location.attrib.block_id, 1); glVertexAttribBinding(test_location.attrib.block_id, 1);
glEnableVertexAttribArray(test_location.attrib.data);
glVertexAttribFormat(test_location.attrib.data, 1, GL_UNSIGNED_BYTE, GL_FALSE, 7);
glVertexAttribBinding(test_location.attrib.data, 1);
glBindVertexArray(0); glBindVertexArray(0);
} }
@ -334,23 +395,34 @@ void load_textures()
} }
static unsigned int light_uniform_buffer; static unsigned int light_uniform_buffer;
static unsigned int texture_id_uniform_buffer;
void load_light_uniform_buffer() unsigned int load_uniform_buffer(char const * const path)
{ {
unsigned int buffer; unsigned int buffer;
glGenBuffers(1, &buffer); glGenBuffers(1, &buffer);
glBindBuffer(GL_UNIFORM_BUFFER, buffer); glBindBuffer(GL_UNIFORM_BUFFER, buffer);
int data_size; int data_size;
void * data = read_file("minecraft/global.lights.vtx", &data_size); void * data = read_file(path, &data_size);
assert(data != NULL); assert(data != NULL);
glBufferData(GL_UNIFORM_BUFFER, data_size, data, GL_STATIC_DRAW); glBufferData(GL_UNIFORM_BUFFER, data_size, data, GL_STATIC_DRAW);
free(data); free(data);
light_uniform_buffer = buffer;
glBindBuffer(GL_UNIFORM_BUFFER, 0); glBindBuffer(GL_UNIFORM_BUFFER, 0);
return buffer;
}
void load_light_uniform_buffer()
{
light_uniform_buffer = load_uniform_buffer("minecraft/global.lights.vtx");
}
void load_texture_id_uniform_buffer()
{
texture_id_uniform_buffer = load_uniform_buffer("minecraft/block_id_to_texture_id.data");
} }
extern "C" { extern "C" {
@ -382,21 +454,16 @@ void load(const char * source_path)
load_test_program(); load_test_program();
load_buffers(); load_buffers();
load_textures(); load_textures();
load_texture_id_uniform_buffer();
view_state.up = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); view_state.up = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
view_state.eye = XMVectorSet(0, 0, 0, 1); view_state.eye = XMVectorSet(50.5f, 40.25f, 59.0f, 1);
view_state.forward = XMVectorSet(1, 0, 0, 0); view_state.forward = XMVectorSet(0.93, -0.38, 0, 0);
view_state.direction = view_state.forward; view_state.direction = view_state.forward;
view_state.pitch = 0.0; view_state.pitch = -0.278;
view_state.fov = 1.5; view_state.fov = 1.5;
load_light_uniform_buffer();
//location.uniform.light_block = glGetUniformBlockIndex(test_program, "TexturesLayout");
//glUniformBlockBinding(ProgramName, location.uniform.light_block, bindingPoint);
//printf("textures_layout %d\n", textures_layout);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// font // font
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -412,22 +479,39 @@ void load(const char * source_path)
load_quad_program(); load_quad_program();
load_quad_index_buffer(); load_quad_index_buffer();
//////////////////////////////////////////////////////////////////////
// lighting
//////////////////////////////////////////////////////////////////////
load_lighting_program();
load_light_uniform_buffer();
} }
float _ry = 0.0; float _ry = 0.0;
struct light_parameters {
float quadratic;
float linear;
};
light_parameters lighting = {
.quadratic = 1.0,
.linear = 1.0
};
void update(float lx, float ly, float rx, float ry, float tl, float tr, void update(float lx, float ly, float rx, float ry, float tl, float tr,
int up, int down, int left, int right) int up, int down, int left, int right,
int a, int b, int x, int y)
{ {
//view_state.yaw += rx; //view_state.yaw += rx;
XMMATRIX mrz = XMMatrixRotationZ(rx * -0.035); XMMATRIX mrz = XMMatrixRotationZ(rx * -0.035);
view_state.forward = XMVector3Transform(view_state.forward, mrz); view_state.forward = XMVector3Transform(XMVector3NormalizeEst(view_state.forward), mrz);
XMVECTOR normal = XMVector3NormalizeEst(XMVector3Cross(view_state.forward, view_state.up)); XMVECTOR normal = XMVector3NormalizeEst(XMVector3Cross(view_state.forward, view_state.up));
view_state.pitch += ry * -0.035; view_state.pitch += ry * -0.035;
if (view_state.pitch > 1.5f) view_state.pitch = 1.5f; if (view_state.pitch > 1.57f) view_state.pitch = 1.57f;
if (view_state.pitch < -1.5f) view_state.pitch = -1.5f; if (view_state.pitch < -1.57f) view_state.pitch = -1.57f;
XMMATRIX mrn = XMMatrixRotationAxis(normal, view_state.pitch); XMMATRIX mrn = XMMatrixRotationAxis(normal, view_state.pitch);
view_state.direction = XMVector3Transform(view_state.forward, mrn); view_state.direction = XMVector3Transform(view_state.forward, mrn);
@ -438,6 +522,12 @@ void update(float lx, float ly, float rx, float ry, float tl, float tr,
if (new_fov > 0.00001f) { if (new_fov > 0.00001f) {
view_state.fov = new_fov; view_state.fov = new_fov;
} }
lighting.quadratic += 0.01 * a + -0.01 * b;
if (lighting.quadratic < 0.0f)
lighting.quadratic = 0.0f;
lighting.linear += 0.01 * x + -0.01 * y;
if (lighting.linear < 0.0f)
lighting.linear = 0.0f;
} }
static inline int popcount(int x) static inline int popcount(int x)
@ -454,6 +544,20 @@ void labeled_value(char * const buf, char const * const label, char const * cons
buf[label_length + len] = 0; buf[label_length + len] = 0;
} }
inline static float draw_vector(font::font const& ter_best, char * const buf, float y, char const * const label, XMVECTOR vec)
{
labeled_value<float>(buf, label, ".x: %.2f", XMVectorGetX(vec));
font::draw_string(ter_best, buf, 10, y);
y += ter_best.desc->glyph_height;
labeled_value<float>(buf, label, ".y: %.2f", XMVectorGetY(vec));
font::draw_string(ter_best, buf, 10, y);
y += ter_best.desc->glyph_height;
labeled_value<float>(buf, label, ".z: %.2f", XMVectorGetZ(vec));
font::draw_string(ter_best, buf, 10, y);
y += ter_best.desc->glyph_height;
return y;
}
void draw_hud() void draw_hud()
{ {
char buf[512]; char buf[512];
@ -469,11 +573,22 @@ void draw_hud()
font::draw_string(ter_best, buf, 10, y); font::draw_string(ter_best, buf, 10, y);
y += ter_best.desc->glyph_height; y += ter_best.desc->glyph_height;
labeled_value<float>(buf, "pitch: ", "%.9f", view_state.pitch); labeled_value<int>(buf, "font_height: ", "%d", ter_best.desc->glyph_height);
font::draw_string(ter_best, buf, 10, y); font::draw_string(ter_best, buf, 10, y);
y += ter_best.desc->glyph_height; y += ter_best.desc->glyph_height;
labeled_value<int>(buf, "font_height: ", "%d", ter_best.desc->glyph_height); labeled_value<float>(buf, "lighting.quadratic: ", "%.2f", lighting.quadratic);
font::draw_string(ter_best, buf, 10, y);
y += ter_best.desc->glyph_height;
labeled_value<float>(buf, "lighting.linear: ", "%.2f", lighting.linear);
font::draw_string(ter_best, buf, 10, y);
y += ter_best.desc->glyph_height;
y = draw_vector(ter_best, buf, y, "eye", view_state.eye);
y = draw_vector(ter_best, buf, y, "forward", view_state.forward);
labeled_value<float>(buf, "pitch: ", "%.9f", view_state.pitch);
font::draw_string(ter_best, buf, 10, y); font::draw_string(ter_best, buf, 10, y);
y += ter_best.desc->glyph_height; y += ter_best.desc->glyph_height;
} }
@ -505,7 +620,7 @@ void draw_minecraft()
glUniformMatrix4fv(test_location.uniform.transform, 1, false, (float *)&transform); glUniformMatrix4fv(test_location.uniform.transform, 1, false, (float *)&transform);
glUniform1i(test_location.uniform.terrain_sampler, 0); glUniform1i(test_location.uniform.terrain_sampler, 0);
//glBindBufferBase(GL_UNIFORM_BUFFER, location.binding.light_block, light_uniform_buffer); glBindBufferBase(GL_UNIFORM_BUFFER, test_location.binding.texture_id, texture_id_uniform_buffer);
//glEnable(GL_CULL_FACE); //glEnable(GL_CULL_FACE);
//glCullFace(GL_FRONT); //glCullFace(GL_FRONT);
@ -565,6 +680,45 @@ void draw_quad()
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, (void *)0); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, (void *)0);
} }
static inline bool near_zero(float a)
{
return (fabsf(a) < 0.00001f);
}
void draw_lighting()
{
glUseProgram(lighting_program);
glDepthFunc(GL_ALWAYS);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, geometry_buffer_pnc.target[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, geometry_buffer_pnc.target[1]);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, geometry_buffer_pnc.target[2]);
glUniform1i(lighting_location.uniform.position_sampler, 0);
glUniform1i(lighting_location.uniform.normal_sampler, 1);
glUniform1i(lighting_location.uniform.color_sampler, 2);
float quadratic = near_zero(lighting.quadratic) ? 0.0 : 1.0f / lighting.quadratic;
float linear = near_zero(lighting.linear) ? 0.0 : 1.0f / lighting.linear;
glUniform1f(lighting_location.uniform.quadratic, quadratic);
glUniform1f(lighting_location.uniform.linear, linear);
XMFLOAT3 eye;
XMStoreFloat3(&eye, view_state.eye);
glUniform3fv(lighting_location.uniform.eye, 1, (float*)&eye);
glBindBufferBase(GL_UNIFORM_BUFFER, lighting_location.binding.lights, light_uniform_buffer);
glBindVertexArray(empty_vertex_array_object);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_index_buffer);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, (void *)0);
}
void draw() void draw()
{ {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@ -578,6 +732,7 @@ void draw()
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw_quad(); draw_lighting();
//draw_hud(); //draw_quad();
draw_hud();
} }