diff --git a/engine b/engine index ed87f29..baac333 160000 --- a/engine +++ b/engine @@ -1 +1 @@ -Subproject commit ed87f292ffa3cf89903cddcdec396115893f7d66 +Subproject commit baac333b44118e17e46f85fc8637aa5ff7f519fc diff --git a/game/batch.py b/game/batch.py index b3612fc..527d7a2 100644 --- a/game/batch.py +++ b/game/batch.py @@ -13,54 +13,70 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from ctypes import c_ubyte, c_uint, c_void_p, addressof +from ctypes import c_ubyte, c_uint, c_void_p, POINTER, addressof from engine import ( buffer, INSTANCE_FLAG_SPAWNED, BATCH_MAX_SIZE, param_type, params_format, create_batch, fill_batch, draw_batch, destroy_batch) +_c_ubyte_p = POINTER(c_ubyte) +_c_uint_p = POINTER(c_uint) + class Batch: - __slots__ = '_batch', '_static', 'vertices', 'size', 'max_size', 'flags', 'meshes', 'params', '_params', '__dict__' + __slots__ = ('_batch', 'vertices', 'max_size', 'size', + 'flags', '_flags', 'mesh', '_meshes', 'param', '_params', '_name', '__dict__') def __init__(self, vertices, max_size, max_meshes, **params_decls): assert max_size <= BATCH_MAX_SIZE nparams = len(params_decls) - names = params_decls.keys() - formats = params_decls.values() - self._batch = create_batch(vertices._vertices, max_size, max_meshes, params_format(*formats)) - self._static = False - self.vertices = vertices - self.size = 0 - self.max_size = max_size - self.flags = buffer(c_ubyte, max_size) - self.meshes = buffer(c_uint, max_size) - self.params = tuple(map(lambda f: buffer(param_type(f), max_size), formats)) if nparams: - self._params = (c_void_p * nparams)(*map(addressof, self.params)) + self._batch = create_batch(vertices._vertices, max_size, max_meshes, params_format(*params_decls.values())) else: + self._batch = create_batch(vertices._vertices, max_size, max_meshes, None) + self.vertices = vertices + self.max_size = max_size + self.size = 0 + self.flags = buffer(c_ubyte, max_size) + self._flags = _c_ubyte_p(self.flags) + self.mesh = buffer(c_uint, max_size) + self._meshes = _c_uint_p(self.mesh) + if nparams: + self.param = tuple(map(lambda f: buffer(param_type(f), max_size), params_decls.values())) + self._params = (c_void_p * nparams)(*map(addressof, self.param)) + self._name = dict(zip(params_decls.keys(), range(nparams))) + for name, value in zip(params_decls.keys(), self.param): + setattr(self, name, value) + else: + self.param = None self._params = None - for name, value in zip(names, self.params): - setattr(self, name, value) + self._name = None def __del__(self): destroy_batch(self._batch) - def spawn(self, model, *params): - assert len(params) == len(self.params) + def spawn(self, flags, mesh, **params): index = self.size assert index < self.max_size - self.flags[index] = model.flags | INSTANCE_FLAG_SPAWNED - self.meshes[index] = model.mesh - for self_params, param in zip(self.params, params): - self_params[index] = param + self.flags[index] = flags | INSTANCE_FLAG_SPAWNED + self.mesh[index] = mesh + for name, value in params.items(): + getattr(self, name)[index] = value self.size += 1 return index - def make_static(self): - fill_batch(self._batch, self.size, self.flags, self.meshes, self._params) - self._static = True + def freeze(self, flags = None, mesh = None, **params): + if flags is not None: + self._flags = None if flags else _c_ubyte_p(self.flags) + if mesh is not None: + self._meshes = None if mesh else _c_uint_p(self.mesh) + for name, value in params.items(): + if value is not None: + index = self._name[name] + self._params[index] = None if value else addressof(self.param[index]) + + def fill(self): + fill_batch(self._batch, self.size, self._flags, self._meshes, self._params) def draw(self): - if not self._static: - fill_batch(self._batch, self.size, self.flags, self.meshes, self._params) + fill_batch(self._batch, self.size, self._flags, self._meshes, self._params) draw_batch(self._batch) diff --git a/game/entity.py b/game/entity.py index dcf49c4..e7604a0 100644 --- a/game/entity.py +++ b/game/entity.py @@ -16,5 +16,5 @@ class Entity: __slots__ = 'index' - def __init__(self, batch, model, *params): - self.index = batch.spawn(model, *params) + def __init__(self, batch, flags, mesh, **params): + self.index = batch.spawn(flags, mesh, **params) diff --git a/game/game.py b/game/game.py index cfca321..82a1e2a 100644 --- a/game/game.py +++ b/game/game.py @@ -76,7 +76,7 @@ class TestEntity(Entity): __slots__ = 'translation', 'orientation', 'spawn_translation', 'spawn_orientation' def __init__(self, batch, model, translation, orientation): - Entity.__init__(self, batch, model, translation, orientation) + Entity.__init__(self, batch, model.flags, model.mesh, translation = translation, orientation = orientation) self.translation = batch.translation[self.index] self.orientation = batch.orientation[self.index] self.spawn_translation = translation @@ -165,8 +165,10 @@ def create_scene(keyboard, mouse): model = mud_model else: model = rock_model - tiles_batch.spawn(model, vec3(float(((mx - 128) * 8) + 4), float(((127 - my) * 8) + 4), 0.0)) - tiles_batch.make_static() + tiles_batch.spawn(model.flags, model.mesh, + translation = vec3(float(((mx - 128) * 8) + 4), float(((127 - my) * 8) + 4), 0.0)) + tiles_batch.fill() + tiles_batch.freeze(flags = True, mesh = True, translation = True) tests_texture = Texture(*archive.get_texture('tests')) tests_vertices = Vertices(*archive.get_vertices('tests')) @@ -179,9 +181,11 @@ def create_scene(keyboard, mouse): blob_forward = math.vec3_normalize((sun_direction[0], sun_direction[1], 0.0)) blob_right = math.vec3_cross(blob_forward, math.vec3_up) blob_orientation = mat3(vec3(*blob_right), vec3(*blob_forward), vec3_up) - blob = TestEntity(tests_batch, blob_model, vec3(-100.0, -500.0, 0.0), blob_orientation) - cube = TestEntity(tests_batch, cube_model, vec3(100.0, -500.0, 0.0), mat3_identity) - clouds = TestEntity(tests_batch, clouds_model, vec3(0.0, 0.0, 32.0), mat3_identity) + blob = TestEntity(tests_batch, blob_model, translation = vec3(-100.0, -500.0, 0.0), orientation = blob_orientation) + cube = TestEntity(tests_batch, cube_model, translation = vec3(100.0, -500.0, 0.0), orientation = mat3_identity) + clouds = TestEntity(tests_batch, clouds_model, translation = vec3(0.0, 0.0, 32.0), orientation = mat3_identity) + tests_batch.fill() + tests_batch.freeze(flags = True, mesh = True) sea_polar_textures = sea.load_polar_textures(('data/sea_bump1.png', 'data/sea_bump2.png')) sea_detail_texture = sea.load_detail_texture('data/sea_bump.png')