Bump engine submodule and move texlevels from instance params to texcoords.

This commit is contained in:
2022-12-05 05:53:23 +01:00
parent a145a4bea3
commit e361a68b7c
9 changed files with 360 additions and 246 deletions

View File

@ -19,14 +19,13 @@ from engine import (
INSTANCE_FLAG_SPAWNED, BATCH_MAX_SIZE, BATCH_ORIENTATION_FORMAT_NONE, create_batch, draw_batch, destroy_batch)
class Batch:
__slots__ = '_batch', 'max_size', 'flags', 'texlevels', 'meshes', 'translations', 'orientations'
__slots__ = '_batch', 'max_size', 'flags', 'meshes', 'translations', 'orientations'
def __init__(self, max_size, translation_format, orientation_format):
assert max_size <= BATCH_MAX_SIZE
self._batch = create_batch(max_size, translation_format, orientation_format)
self.max_size = max_size
self.flags = array('B')
self.texlevels = array('H')
self.meshes = array('I')
self.translations = array('f')
if orientation_format != BATCH_ORIENTATION_FORMAT_NONE:
@ -37,13 +36,12 @@ class Batch:
def __del__(self):
destroy_batch(self._batch)
def append(self, flags, texlevel, mesh, translation, orientation):
def append(self, flags, mesh, translation, orientation):
assert len(translation) == 3
assert orientation is None or len(orientation) == 3
index = len(self.flags)
assert index < self.max_size
self.flags.append(flags | INSTANCE_FLAG_SPAWNED)
self.texlevels.append(texlevel)
self.meshes.append(mesh)
self.translations.extend(translation)
if self.orientations is not None:
@ -57,4 +55,4 @@ class Batch:
self.orientations[index * 3 : index * 3 + 3] = orientation
def draw(self):
draw_batch(self._batch, self.flags, self.texlevels, self.meshes, self.translations, self.orientations)
draw_batch(self._batch, self.flags, self.meshes, self.translations, self.orientations)

View File

@ -30,23 +30,6 @@ class ObjArchive(Archive):
def __init__(self):
super().__init__()
def import_hacks(self, path):
print("Importing hacks", path)
hacks = {}
for line in open(path):
data = line.split()
if not data:
continue
name = data.pop(0)
if name == '#':
continue
assert len(data) == 4 and data[0] == '=' and data[2] == 'mesh'
alias = data[1]
mesh = data[3]
assert name not in hacks.keys()
hacks[name] = (alias, mesh)
return hacks
def import_mtl(self, mtlpath):
def load_value(x):
x = round(float(x), 6)
@ -178,12 +161,10 @@ class ObjArchive(Archive):
elif code == 'o':
if name:
assert mesh
objects[name] = (texlevel, mesh)
objects[name] = mesh
name = data[0]
print("Importing object", name)
mesh = []
elif code == 'usemtl':
texlevel = texlevels[data[0]]
elif code == 'v':
position = tuple(map(load_coord, data))
assert len(position) == 3
@ -196,66 +177,57 @@ class ObjArchive(Archive):
texcoord = tuple(map(load_coord, data))
assert len(texcoord) == 2
texcoords.append((texcoord[0], 1.0 - texcoord[1]))
elif code == 'usemtl':
texlevel = texlevels[data[0]]
elif code == 'f':
indices = tuple(map(lambda x: tuple(map(load_index, x.split('/'))), data))
assert len(indices) == 3
assert len(indices[0]) == 3
assert len(indices[1]) == 3
assert len(indices[2]) == 3
triangle = tuple(map(lambda x: positions[x[0]] + normals[x[2]] + texcoords[x[1]], indices))
triangle = tuple(map(
lambda x: positions[x[0]] + normals[x[2]] + texcoords[x[1]] + (texlevel,), indices))
assert len(triangle) == 3 and len(set(triangle)) == 3
mesh.append(triangle)
if name:
assert mesh
objects[name] = (texlevel, mesh)
objects[name] = mesh
vertices = set()
for _, mesh in objects.values():
for mesh in objects.values():
vertices |= frozenset(chain.from_iterable(mesh))
vertices = tuple(vertices)
indices = []
models = {}
for name, (texlevel, mesh) in sorted(objects.items()):
if name[0] == '_':
print(name, ": texlevel =", texlevel)
models[name] = (texlevel, -1, -1)
else:
offset = len(indices)
assert offset < 65536
indices.extend(map(vertices.index, chain.from_iterable(mesh)))
count = len(indices) - offset
assert count % 3 == 0
count //= 3
assert count < 65536
print(name, ": texlevel =", texlevel, "offset =", offset, "count =", count)
models[name] = (texlevel, offset, count)
for name, mesh in sorted(objects.items()):
offset = len(indices)
assert offset < 65536
indices.extend(map(vertices.index, chain.from_iterable(mesh)))
count = len(indices) - offset
assert count % 3 == 0
count //= 3
assert count < 65536
print(name, ": offset =", offset, "triangles =", count)
models[name] = (offset, count)
name = str(objpath.stem)
assert name not in self.vertices_db.keys()
#TODO: move to math
def pack_10(_x):
return round(_x * (512.0 if _x < 0.0 else 511.0)) & 1023
def pack_vertex(_px, _py, _pz, _nx, _ny, _nz, _s, _t):
n = (pack_10(_nx) << 20) | (pack_10(_ny) << 10) | (pack_10(_nz) << 0)
s = max(0, min(65535, round(_s * 65535.0)))
t = max(0, min(65535, round(_t * 65535.0)))
return struct.pack('fffIHH', _px, _py, _pz, n, s, t)
def pack_u10(_x):
return round(_x * 1023.0) & 1023
def pack_vertex(_px, _py, _pz, _nx, _ny, _nz, _s, _t, _tl):
n = (pack_10(_nz) << 20) | (pack_10(_ny) << 10) | pack_10(_nx)
t = ((_tl & 1023) << 20) | (pack_u10(_t) << 10) | pack_u10(_s)
return struct.pack('fffII', _px, _py, _pz, n, t)
self.vertices_db[name] = VerticesData(name,
array('B', b''.join(starmap(pack_vertex, vertices))),
array('H', indices))
path = objpath.parent / (objpath.stem + '.hacks')
if path.exists():
hacks = self.import_hacks(path)
for name, (alias, mesh) in hacks.items():
print("Hacking", name, "from", alias, "with mesh", mesh)
assert name not in models.keys() and alias in models.keys() and mesh in models.keys()
texlevel, _, _ = models[alias]
_, offset, count = models[mesh]
models[name] = (texlevel, offset, count)
for name, (texlevel, offset, count) in sorted(models.items()):
for name, (offset, count) in sorted(models.items()):
if name[0] != '_':
print("Storing", name)
assert name not in self.models_db.keys()
self.models_db[name] = ModelData(
name, INSTANCE_FLAG_VISIBLE, texlevel, offset | count << 16)
name, INSTANCE_FLAG_VISIBLE, offset | count << 16)
if __name__ == '__main__':
if len(sys.argv) < 3:

View File

@ -23,9 +23,9 @@ import engine
VERTEX_SIZE = 20
VERTEX_FORMAT = engine.vertex_format(
engine.VERTEX_FORMAT_VEC3_FLOAT,
engine.VERTEX_FORMAT_VEC3_INT10,
engine.VERTEX_FORMAT_VEC2_USHORT)
engine.VERTEX_FORMAT_VEC3_FLOAT, # position
engine.VERTEX_FORMAT_VEC3_INT10 | engine.VERTEX_FORMAT_NORMALIZE, # normal
engine.VERTEX_FORMAT_VEC3_UINT10) # texcoords
def load_png(path):
width, height, data, _ = png.Reader(filename = path).read_flat()
@ -166,39 +166,37 @@ def create_vertices(data):
return engine.create_vertices(VERTEX_FORMAT, len(data.vertices) // VERTEX_SIZE, data.vertices, data.indices)
class ModelData:
__slots__ = 'name', 'flags', 'texlevel', 'mesh'
__slots__ = 'name', 'flags', 'mesh'
def __init__(self, name, flags, texlevel, mesh):
def __init__(self, name, flags, mesh):
self.name = name
self.flags = flags
self.texlevel = texlevel
self.mesh = mesh
@classmethod
def from_archive(cls, file):
_read_magic(file, b'MD')
name = _read_string(file)
flags, texlevel, mesh = _read_struct(file, 'BHI')
return ModelData(name, flags, texlevel, mesh)
flags, mesh = _read_struct(file, 'II')
return ModelData(name, flags, mesh)
def to_archive(self, file):
_write_magic(file, b'MD')
_write_string(file, self.name)
_write_struct(file, 'BHI', (self.flags, self.texlevel, self.mesh))
_write_struct(file, 'II', (self.flags, self.mesh))
class Model:
__slots__ = 'flags', 'texlevel', 'mesh'
__slots__ = 'flags', 'mesh'
def __init__(self, flags, texlevel, mesh):
def __init__(self, flags, mesh):
self.flags = flags
self.texlevel = texlevel
self.mesh = mesh
def spawn(self, batch, translation = engine.vec3_zero, orientation = engine.vec3_forward):
return batch.append(self.flags, self.texlevel, self.mesh, translation, orientation)
return batch.append(self.flags, self.mesh, translation, orientation)
def create_model(data):
return Model(data.flags, data.texlevel, data.mesh)
return Model(data.flags, data.mesh)
class Archive:
__slots__ = 'textures_db', 'vertices_db', 'models_db'

View File

@ -18,13 +18,11 @@ precision highp float;
layout(location = 0) in vec3 a_position; // model space
layout(location = 1) in vec3 a_normal; // model space
layout(location = 2) in vec2 a_texcoord; // texture space
layout(location = 2) in vec3 a_texcoord; // texture space
layout(location = 3) in vec4 i_translation; // per mesh, model space -> world space (x, y, z, texlevel)
layout(location = 3) in vec3 i_translation; // per mesh, model space -> world space
layout(location = 4) in vec3 i_orientation; // per mesh, model space -> world space
#define i_texlevel i_translation.w
uniform mat4 u_view; // world space -> view space
uniform mat4 u_projection; // view space -> screen space
@ -33,6 +31,7 @@ uniform highp sampler2D u_normal_sampler;
const vec3 c_normal_scale = vec3(2.0, 2.0, 1.0);
const vec3 c_normal_shift = vec3(-1.0, -1.0, 0.0);
const vec2 c_st_scale = vec2(1.0 / 1023.0, 1.0 / 1023.0);
const vec2 c_terrain_scale = vec2(1.0 / 2048.0, -1.0 / 2048.0);
const vec2 c_terrain_shift = vec2(0.5, 0.5);
const float c_weight_scale = 1.0 / 64.f;
@ -58,6 +57,6 @@ void main(void) {
v_position = view_position.xyz;
v_normal = (u_view * vec4(world_normal, 0.0)).xyz;
v_terrain_normal = vec4((u_view * vec4(terrain_normal, 0.0)).xyz, weight);
v_texcoord = vec4(a_texcoord, i_texlevel, i_texlevel + 1.0);
v_texcoord = vec4(a_texcoord.st * c_st_scale, a_texcoord.p, a_texcoord.p + 1.0);
gl_Position = u_projection * view_position;
}