Compare commits

..

14 Commits

12 changed files with 194 additions and 161 deletions

1
.gitmodules vendored
View File

@ -1,3 +1,4 @@
[submodule "engine"]
path = engine
url = https://code.rozk.net/RK/rk_engine.git
branch = master

Binary file not shown.

Before

Width:  |  Height:  |  Size: 800 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

2
engine

Submodule engine updated: beca8798bf...7384a014ff

View File

@ -13,43 +13,72 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from ctypes import c_ubyte, c_uint, c_void_p, addressof
from ctypes import c_ubyte, c_ushort, c_void_p, POINTER, addressof
from engine import (vec3, mat3, buffer,
INSTANCE_FLAG_SPAWNED, BATCH_MAX_SIZE, param_type, params_format, create_batch, draw_batch, destroy_batch)
from engine import (
buffer, INSTANCE_FLAG_SPAWNED, BATCH_MAX_SIZE, vertex_type, vertex_format,
create_batch, fill_batch, draw_batch, destroy_batch)
_flags_t = c_ubyte
_flags_p = POINTER(_flags_t)
_mesh_t = c_ushort
_mesh_p = POINTER(_mesh_t)
class Batch:
__slots__ = '_batch', '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):
def __init__(self, vertices, max_size, **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))
if nparams:
self._batch = create_batch(vertices._vertices, max_size, vertex_format(*params_decls.values()))
else:
self._batch = create_batch(vertices._vertices, max_size, None)
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))
self._params = (c_void_p * nparams)(*map(addressof, self.params))
for name, value in zip(names, self.params):
setattr(self, name, value)
self.size = 0
self.flags = buffer(_flags_t, max_size)
self._flags = _flags_p(self.flags)
self.mesh = buffer(_mesh_t, max_size)
self._meshes = _mesh_p(self.mesh)
if nparams:
self.param = tuple(map(lambda f: buffer(vertex_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
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 freeze(self, flags = None, mesh = None, **params):
if flags is not None:
self._flags = None if flags else _flags_p(self.flags)
if mesh is not None:
self._meshes = None if mesh else _mesh_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):
draw_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)

View File

@ -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)

View File

@ -33,7 +33,7 @@ from game.environment import Environment
from game.inputs import InputFloat
from game.batch import Batch
from game.entity import Entity
from game.scene import Node, SceneNode, TextureNode, ShaderNode, InputNode, DrawNode, FuncNode
from game.scene import Group, SceneGroup, TextureGroup, ShaderGroup, InputNode, DrawNode, FuncNode
from game import sea
proj_hfov = pi * 0.25
@ -44,11 +44,11 @@ proj_far_z = 3000.0
sun_direction = math.vec3_normalize((1.0, 0.0, 0.5))
sun_power = 1.0
class PerfNode(Node):
class PerfGroup(Group):
__slots__ = '_count', '_min', '_max', '_total', '_name'
def __init__(self, name, *subnodes):
Node.__init__(self, *subnodes)
Group.__init__(self, *subnodes)
self._count = None
self._min = 10000.0
self._max = 0.0
@ -56,13 +56,14 @@ class PerfNode(Node):
self._name = name
def __del__(self):
avg = round(self._total / self._count, 2)
print(self._name, "*", self._count,
": min =", round(self._min, 2), ", max =", round(self._max, 2), ", avg =", avg, "(ms)")
if self._count:
avg = round(self._total / self._count, 2)
print(self._name, "*", self._count,
": min =", round(self._min, 2), ", max =", round(self._max, 2), ", avg =", avg, "(ms)")
def draw(self, time):
begin = thread_time()
Node.draw(self, time)
Group.draw(self, time)
elapsed = (thread_time() - begin) * 1000.0
if self._count is None:
self._count = 0
@ -75,8 +76,10 @@ class PerfNode(Node):
class TestEntity(Entity):
__slots__ = 'translation', 'orientation', 'spawn_translation', 'spawn_orientation'
def __init__(self, batch, model, translation, orientation):
Entity.__init__(self, batch, model, translation, orientation)
def __init__(self, batch, mesh, translation, orientation):
Entity.__init__(self, batch, INSTANCE_FLAG_VISIBLE, mesh,
translation = translation,
orientation = orientation)
self.translation = batch.translation[self.index]
self.orientation = batch.orientation[self.index]
self.spawn_translation = translation
@ -126,15 +129,15 @@ def create_scene(keyboard, mouse):
print("Building tiles...")
tiles_texture = Texture(*archive.get_texture('tiles'))
tiles_vertices = Vertices(*archive.get_vertices('tiles'))
water_model = archive.get_model('water')
sand_model = archive.get_model('sand')
grass_model = archive.get_model('grass')
forest_model = archive.get_model('forest')
rock_model = archive.get_model('rock')
mud_model = archive.get_model('mud')
lava_model = archive.get_model('lava')
tiles_batch = Batch(tiles_vertices, generated.size ** 2, 8, translation = PARAM_FORMAT_VEC3_SHORT)
tiles_vertices = archive.get_vertices('tiles')
water_mesh = tiles_vertices.get_mesh('water')
sand_mesh = tiles_vertices.get_mesh('sand')
grass_mesh = tiles_vertices.get_mesh('grass')
forest_mesh = tiles_vertices.get_mesh('forest')
rock_mesh = tiles_vertices.get_mesh('rock')
mud_mesh = tiles_vertices.get_mesh('mud')
lava_mesh = tiles_vertices.get_mesh('lava')
tiles_batch = Batch(Vertices(*tiles_vertices), generated.size ** 2, translation = VERTEX_FORMAT_VEC3_SHORT)
#TODO: generator & for real
vc = generated.volcano_c
@ -146,66 +149,74 @@ def create_scene(keyboard, mouse):
if h == 0.0:
continue
if r > 0.0:
model = water_model
mesh = water_mesh
elif h < 2.0:
model = sand_model
mesh = sand_mesh
elif h < 180:
if nz > 0.9:
if ny < -0.01 and nz > 0.93:
model = forest_model
mesh = forest_mesh
else:
model = grass_model
mesh = grass_mesh
else:
model = rock_model
mesh = rock_mesh
elif vd < vr - 3.0 and nz > 0.999:
model = lava_model
mesh = lava_mesh
elif vd < vr + 2.0:
model = mud_model
mesh = mud_mesh
elif vd < vr + 6.0 and nz < 0.67:
model = mud_model
mesh = mud_mesh
else:
model = rock_model
tiles_batch.spawn(model, vec3(float(((mx - 128) * 8) + 4), float(((127 - my) * 8) + 4), 0.0))
mesh = rock_mesh
tiles_batch.spawn(INSTANCE_FLAG_VISIBLE, 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'))
blob_model = archive.get_model('blob')
cube_model = archive.get_model('cube')
clouds_model = archive.get_model('clouds')
tests_batch = Batch(tests_vertices, 3, 3,
translation = PARAM_FORMAT_VEC3_FLOAT,
orientation = PARAM_FORMAT_MAT3_INT10 | PARAM_FORMAT_NORMALIZE)
tests_vertices = archive.get_vertices('tests')
blob_mesh = tests_vertices.get_mesh('blob')
cube_mesh = tests_vertices.get_mesh('cube')
clouds_mesh = tests_vertices.get_mesh('clouds')
tests_batch = Batch(Vertices(*tests_vertices), 3,
translation = VERTEX_FORMAT_VEC3_FLOAT,
orientation = VERTEX_FORMAT_MAT3_INT10 | VERTEX_FORMAT_NORMALIZE)
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_mesh, translation = vec3(-100.0, -500.0, 0.0), orientation = blob_orientation)
cube = TestEntity(tests_batch, cube_mesh, translation = vec3(100.0, -500.0, 0.0), orientation = mat3_identity)
clouds = TestEntity(tests_batch, clouds_mesh, 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')
sea_polar = sea.load_polar_textures(('data/sea_bump1.png', 'data/sea_bump2.png'))
sea_detail = sea.load_detail_texture('data/sea_bump.png')
sea_triangles = sea.sea_triangles(64, proj_far_z - 0.1, proj_ratio)
return SceneNode(
PerfNode('frame',
TextureNode({1: heightmap, 2: normalmap},
assert tiles_shader.u_height_sampler == tests_shader.u_height_sampler
assert tiles_shader.u_normal_sampler == tests_shader.u_normal_sampler
return SceneGroup(
PerfGroup('frame',
TextureGroup({tiles_shader.u_height_sampler: heightmap, tiles_shader.u_normal_sampler: normalmap},
FuncNode(update_camera, (mouse, camera, environment)),
TextureNode({0: tiles_texture},
ShaderNode(tiles_shader,
TextureGroup({tiles_shader.u_texture_sampler: tiles_texture},
ShaderGroup(tiles_shader,
InputNode(tiles_shader, camera, environment),
PerfNode('tiles_batch',
PerfGroup('tiles_batch',
DrawNode(tiles_batch)))),
FuncNode(update_tests, (blob, cube, clouds)),
TextureNode({0: tests_texture},
ShaderNode(tests_shader,
TextureGroup({tests_shader.u_texture_sampler: tests_texture},
ShaderGroup(tests_shader,
InputNode(tests_shader, camera, environment),
PerfNode('tests_batch',
PerfGroup('tests_batch',
DrawNode(tests_batch))))),
FuncNode(update_sea, (camera, sea_phase)),
TextureNode({0: sea_polar_textures, 1: sea_detail_texture},
ShaderNode(sea_shader,
TextureGroup({sea_shader.u_polar_sampler: sea_polar, sea_shader.u_detail_sampler: sea_detail},
ShaderGroup(sea_shader,
InputNode(sea_shader, camera, environment, sea_phase),
PerfNode('sea_triangles',
PerfGroup('sea_triangles',
DrawNode(sea_triangles))))))
def loop(display):
@ -214,14 +225,14 @@ def loop(display):
mouse = Mouse(events, wheel = 60, wheel_min = 20)
scene = create_scene(keyboard, mouse)
print("Running... Ctrl+c to quit")
time = Time()
try:
time = Time()
while not keyboard.quit:
events.update()
time.update()
clear_buffer(True, True, True)
scene.draw(time)
swap_buffers(display)
time.update()
except KeyboardInterrupt:
pass

View File

@ -22,7 +22,7 @@ from itertools import starmap, chain, repeat
from engine import *
from game.math import float_s8, vec3_srgb8a8
from game.resources import load_png, TextureData, VerticesData, ModelData, Archive
from game.resources import load_png, TextureData, VerticesData, Archive
_texture_flags = TEXTURE_FLAG_MIPMAPS | TEXTURE_FLAG_MIN_LINEAR | TEXTURE_FLAG_MAG_NEAREST
@ -195,7 +195,7 @@ class ObjArchive(Archive):
vertices = []
indices = []
models = {}
meshes = {}
for name, mesh in sorted(objects.items()):
offset = len(indices)
assert offset < 65536
@ -213,28 +213,26 @@ class ObjArchive(Archive):
assert count < 65536
vertices.extend(mesh_vertices)
indices.extend(mesh_indices)
models[name] = (offset, count)
meshes[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
assert _x >= -1.0 and _x <= 1.0
return round(_x * 511.0) & 1023
# return ((round(_x * 1023.0) - 1) // 2) & 1023
def pack_u10(_x):
return round(_x * 1023.0) & 1023
assert _x >= 0.0 and _x <= 1.0
return round(_x * 1023.0)
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))
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, offset | count << 16)
array('H', indices),
meshes)
if __name__ == '__main__':
if len(sys.argv) < 3:

View File

@ -13,6 +13,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from itertools import chain
import struct
from array import array
from pathlib import Path
@ -48,7 +49,7 @@ def _read_struct(file, format):
_read_magic(file, b'RK')
return struct.unpack(format, data)
def _write_struct(file, format, elems):
def _write_struct(file, format, *elems):
assert format
data = struct.pack(format, *elems)
size = file.write(data)
@ -56,7 +57,7 @@ def _write_struct(file, format, elems):
_write_magic(file, b'RK')
def _read_string(file):
length, = _read_struct(file, 'B')
length, = _read_struct(file, 'I')
assert length
data = file.read(length)
assert len(data) == length
@ -66,7 +67,7 @@ def _read_string(file):
def _write_string(file, string):
data = bytes(string, encoding='ascii')
assert data and len(data) < 256
_write_struct(file, 'B', (len(data),))
_write_struct(file, 'I', len(data))
size = file.write(data)
assert size == len(data)
_write_magic(file, b'RK')
@ -96,7 +97,7 @@ def _read_blob(file):
def _write_blob(file, array):
assert array
_write_struct(file, 'II', (ord(array.typecode), len(array)))
_write_struct(file, 'II', ord(array.typecode), len(array))
array.tofile(file)
_write_magic(file, b'RK')
@ -124,7 +125,7 @@ class TextureData:
@classmethod
def from_archive(cls, file):
_read_magic(file, b'TX')
_read_magic(file, b'TXTR')
name = _read_string(file)
format, width, height, nlevels, flags = _read_struct(file, 'IIIII')
pixels = _read_blob(file)
@ -133,70 +134,61 @@ class TextureData:
return cls(name, format, width, height, nlevels, flags, pixels)
def to_archive(self, file):
_write_magic(file, b'TX')
_write_magic(file, b'TXTR')
_write_string(file, self.name)
_write_struct(file, 'IIIII', (self.format, self.width, self.height, self.nlevels, self.flags))
_write_struct(file, 'IIIII', self.format, self.width, self.height, self.nlevels, self.flags)
_write_blob(file, self.pixels)
class VerticesData:
__slots__ = 'name', 'vertices', 'indices'
__slots__ = 'name', 'vertices', 'indices', 'meshes', 'meshes_db'
def __init__(self, name, vertices, indices):
def __init__(self, name, vertices, indices, meshes):
if len(vertices) % VERTEX_SIZE != 0:
raise RuntimeError("Vertex format mismatch!")
self.name = name
self.vertices = vertices
self.indices = indices
self.meshes = meshes.values()
self.meshes_db = dict(zip(meshes.keys(), range(len(meshes))))
def __iter__(self):
yield VERTEX_FORMAT
yield len(self.vertices) // VERTEX_SIZE
yield self.vertices
yield self.indices
yield array('I', chain.from_iterable(self.meshes))
def get_mesh(self, name):
return self.meshes_db[name]
@classmethod
def from_archive(cls, file):
_read_magic(file, b'VT')
_read_magic(file, b'VERT')
name = _read_string(file)
nvertices, nindices = _read_struct(file, 'II')
nvertices, nindices, nmeshes = _read_struct(file, 'III')
vertices = _read_array(file, 'B', nvertices * VERTEX_SIZE)
indices = _read_array(file, 'H', nindices)
return cls(name, vertices, indices)
names = [_read_string(file) for _ in range(nmeshes)]
meshes = [_read_struct(file, 'II') for _ in range(nmeshes)]
return cls(name, vertices, indices, dict(zip(names, meshes)))
def to_archive(self, file):
_write_magic(file, b'VT')
_write_magic(file, b'VERT')
_write_string(file, self.name)
_write_struct(file, 'II', (len(self.vertices) // VERTEX_SIZE, len(self.indices)))
_write_struct(file, 'III', len(self.vertices) // VERTEX_SIZE, len(self.indices), len(self.meshes_db))
_write_array(file, self.vertices)
_write_array(file, self.indices)
class ModelData:
__slots__ = 'name', 'flags', 'mesh'
def __init__(self, name, flags, mesh):
self.name = name
self.flags = flags
self.mesh = mesh
@classmethod
def from_archive(cls, file):
_read_magic(file, b'MD')
name = _read_string(file)
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, 'II', (self.flags, self.mesh))
for name in self.meshes_db.keys():
_write_string(file, name)
for mesh in self.meshes:
_write_struct(file, 'II', *mesh)
class Archive:
__slots__ = 'textures_db', 'vertices_db', 'models_db'
__slots__ = 'textures_db', 'vertices_db'
def __init__(self, textures_db = None, vertices_db = None, models_db = None):
def __init__(self, textures_db = None, vertices_db = None):
self.textures_db = textures_db or {}
self.vertices_db = vertices_db or {}
self.models_db = models_db or {}
def get_texture(self, name):
return self.textures_db[name]
@ -204,36 +196,27 @@ class Archive:
def get_vertices(self, name):
return self.vertices_db[name]
def get_model(self, name):
return self.models_db[name]
@classmethod
def from_archive(cls, file):
textures_db = {}
vertices_db = {}
models_db = {}
_read_magic(file, b'RKAR')
ntextures, nvertices, nmodels = _read_struct(file, 'III')
ntextures, nvertices = _read_struct(file, 'II')
for _ in range(ntextures):
data = TextureData.from_archive(file)
textures_db[data.name] = data
for _ in range(nvertices):
data = VerticesData.from_archive(file)
vertices_db[data.name] = data
for _ in range(nmodels):
data = ModelData.from_archive(file)
models_db[data.name] = data
return cls(textures_db, vertices_db, models_db)
return cls(textures_db, vertices_db)
def to_archive(self, file):
_write_magic(file, b'RKAR')
_write_struct(file, 'III', (len(self.textures_db), len(self.vertices_db), len(self.models_db)))
_write_struct(file, 'II', len(self.textures_db), len(self.vertices_db))
for _, data in self.textures_db.items():
data.to_archive(file)
for _, data in self.vertices_db.items():
data.to_archive(file)
for _, data in self.models_db.items():
data.to_archive(file)
@classmethod
def load(cls, filename):

View File

@ -13,7 +13,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class Node:
class Group:
__slots__ = '_subnodes'
def __init__(self, *subnodes):
@ -23,34 +23,34 @@ class Node:
for subnode in self._subnodes:
subnode.draw(time)
class SceneNode(Node):
class SceneGroup(Group):
pass
class TextureNode(Node):
class TextureGroup(Group):
__slots__ = '_textures'
def __init__(self, textures, *subnodes):
Node.__init__(self, *subnodes)
Group.__init__(self, *subnodes)
self._textures = textures
def draw(self, time):
items = self._textures.items()
for slot, texture in items:
texture.select(slot)
Node.draw(self, time)
Group.draw(self, time)
for slot, texture in items:
texture.unselect(slot)
class ShaderNode(Node):
class ShaderGroup(Group):
__slots__ = '_shader'
def __init__(self, shader, *subnodes):
Node.__init__(self, *subnodes)
Group.__init__(self, *subnodes)
self._shader = shader
def draw(self, time):
self._shader.select()
Node.draw(self, time)
Group.draw(self, time)
self._shader.unselect()
class InputNode:

View File

@ -24,7 +24,7 @@ def _filter(line):
return line
def _subst(line):
if line.startswith('#include '):
if line.startswith('#include'):
path = Path('.') / 'game' / 'shaders'
lines = []
for name in line.split()[1:]:
@ -45,16 +45,27 @@ def _convert(line):
def _parse(shader, vert_lines, frag_lines):
uniforms = []
for line in vert_lines:
if line.startswith('uniform '):
uniforms.append(line.split()[-1].strip(';'))
for line in frag_lines:
if line.startswith('uniform '):
bindings = {}
def collect(line):
if line.startswith('uniform'):
name = line.split()[-1].strip(';')
if name not in uniforms:
uniforms.append(name)
elif line.startswith('layout(binding='):
name = line.split()[-1].strip(';')
value = int(line[line.index('=') + 1 : line.index(')')].strip())
if name in bindings:
assert value == bindings[name]
else:
bindings[name] = value
for line in vert_lines:
collect(line)
for line in frag_lines:
collect(line)
for name in uniforms:
setattr(shader, name, resolve_input(shader._shader, bytes(name, 'utf-8')))
for name, value in bindings.items():
setattr(shader, name, value)
class Shader:
__slots__ = '_shader', '__dict__'

View File

@ -28,8 +28,8 @@ uniform float u_sea_phase;
#define u_up u_view[2].xyz
#define u_origin u_view[3].xyz
layout(binding=0) uniform highp sampler2DArray u_sea_polar_sampler;
layout(binding=1) uniform highp sampler2D u_sea_detail_sampler;
layout(binding=0) uniform highp sampler2DArray u_polar_sampler;
layout(binding=1) uniform highp sampler2D u_detail_sampler;
const float c_sea_radius = 637.1;
const float c_sea_radius_sq = c_sea_radius * c_sea_radius;
@ -68,13 +68,13 @@ void main(void) {
}
float t = sqrt(length(sea_position)); //TODO: more accurate
vec3 sea_polar1 = normalize(
c_normal_shift + texture(u_sea_polar_sampler, vec3(s, t + u_sea_phase, 0.0)).xyz * c_normal_scale);
c_normal_shift + texture(u_polar_sampler, vec3(s, t + u_sea_phase, 0.0)).xyz * c_normal_scale);
vec3 sea_polar2 = normalize(
c_normal_shift + texture(u_sea_polar_sampler, vec3(s, t - u_sea_phase, 1.0)).xyz * c_normal_scale);
c_normal_shift + texture(u_polar_sampler, vec3(s, t - u_sea_phase, 1.0)).xyz * c_normal_scale);
//TODO: vec2
s = (u_sea_phase + dot(sea_position, u_right)) * c_detail_scale;
t = (u_sea_phase + dot(sea_position, u_forward)) * c_detail_scale;
vec3 sea_detail = normalize(c_normal_shift + texture(u_sea_detail_sampler, vec2(s, t)).xyz * c_normal_scale);
vec3 sea_detail = normalize(c_normal_shift + texture(u_detail_sampler, vec2(s, t)).xyz * c_normal_scale);
//TODO: better blending, with earth normal
vec4 normal = u_view * vec4(normalize(sea_polar1 + sea_polar2 + sea_detail), 0.0);
float d = max(0.0, dot(normal.xyz, u_light_direction));

View File

@ -18,8 +18,8 @@ from engine import create_vertices, destroy_vertices
class Vertices:
__slots__ = '_vertices'
def __init__(self, format, nvertices, vertices, indices):
self._vertices = create_vertices(format, nvertices, vertices, indices)
def __init__(self, format, nvertices, vertices, indices, meshes):
self._vertices = create_vertices(format, nvertices, vertices, indices, meshes)
def __del__(self):
destroy_vertices(self._vertices)