Bump engine submodule and move texlevels from instance params to texcoords.
This commit is contained in:
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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'
|
||||
|
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user