Compare commits

..

No commits in common. "a96ea8bb6b93ff2a370df809982cf2442b6da857" and "9131523ae7ac3a3875de5c9ab0261da5b61b3859" have entirely different histories.

6 changed files with 41 additions and 68 deletions

2
engine

@ -1 +1 @@
Subproject commit ed87f292ffa3cf89903cddcdec396115893f7d66 Subproject commit beca8798bf91edba954d31eb4e1a619ec2140c83

View File

@ -15,12 +15,11 @@
from ctypes import c_ubyte, c_uint, c_void_p, addressof from ctypes import c_ubyte, c_uint, c_void_p, addressof
from engine import ( from engine import (vec3, mat3, buffer,
buffer, INSTANCE_FLAG_SPAWNED, BATCH_MAX_SIZE, param_type, params_format, INSTANCE_FLAG_SPAWNED, BATCH_MAX_SIZE, param_type, params_format, create_batch, draw_batch, destroy_batch)
create_batch, fill_batch, draw_batch, destroy_batch)
class Batch: class Batch:
__slots__ = '_batch', '_static', 'vertices', 'size', 'max_size', 'flags', 'meshes', 'params', '_params', '__dict__' __slots__ = '_batch', 'vertices', 'size', 'max_size', 'flags', 'meshes', 'params', '_params', '__dict__'
def __init__(self, vertices, max_size, max_meshes, **params_decls): def __init__(self, vertices, max_size, max_meshes, **params_decls):
assert max_size <= BATCH_MAX_SIZE assert max_size <= BATCH_MAX_SIZE
@ -28,17 +27,13 @@ class Batch:
names = params_decls.keys() names = params_decls.keys()
formats = params_decls.values() formats = params_decls.values()
self._batch = create_batch(vertices._vertices, max_size, max_meshes, params_format(*formats)) self._batch = create_batch(vertices._vertices, max_size, max_meshes, params_format(*formats))
self._static = False
self.vertices = vertices self.vertices = vertices
self.size = 0 self.size = 0
self.max_size = max_size self.max_size = max_size
self.flags = buffer(c_ubyte, max_size) self.flags = buffer(c_ubyte, max_size)
self.meshes = buffer(c_uint, max_size) self.meshes = buffer(c_uint, max_size)
self.params = tuple(map(lambda f: buffer(param_type(f), max_size), formats)) 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._params = (c_void_p * nparams)(*map(addressof, self.params))
else:
self._params = None
for name, value in zip(names, self.params): for name, value in zip(names, self.params):
setattr(self, name, value) setattr(self, name, value)
@ -56,11 +51,5 @@ class Batch:
self.size += 1 self.size += 1
return index return index
def make_static(self):
fill_batch(self._batch, self.size, self.flags, self.meshes, self._params)
self._static = True
def draw(self): def draw(self):
if not self._static: 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

@ -33,7 +33,7 @@ from game.environment import Environment
from game.inputs import InputFloat from game.inputs import InputFloat
from game.batch import Batch from game.batch import Batch
from game.entity import Entity from game.entity import Entity
from game.scene import Group, SceneGroup, TextureGroup, ShaderGroup, InputNode, DrawNode, FuncNode from game.scene import Node, SceneNode, TextureNode, ShaderNode, InputNode, DrawNode, FuncNode
from game import sea from game import sea
proj_hfov = pi * 0.25 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_direction = math.vec3_normalize((1.0, 0.0, 0.5))
sun_power = 1.0 sun_power = 1.0
class PerfGroup(Group): class PerfNode(Node):
__slots__ = '_count', '_min', '_max', '_total', '_name' __slots__ = '_count', '_min', '_max', '_total', '_name'
def __init__(self, name, *subnodes): def __init__(self, name, *subnodes):
Group.__init__(self, *subnodes) Node.__init__(self, *subnodes)
self._count = None self._count = None
self._min = 10000.0 self._min = 10000.0
self._max = 0.0 self._max = 0.0
@ -62,7 +62,7 @@ class PerfGroup(Group):
def draw(self, time): def draw(self, time):
begin = thread_time() begin = thread_time()
Group.draw(self, time) Node.draw(self, time)
elapsed = (thread_time() - begin) * 1000.0 elapsed = (thread_time() - begin) * 1000.0
if self._count is None: if self._count is None:
self._count = 0 self._count = 0
@ -166,7 +166,6 @@ def create_scene(keyboard, mouse):
else: else:
model = rock_model model = rock_model
tiles_batch.spawn(model, vec3(float(((mx - 128) * 8) + 4), float(((127 - my) * 8) + 4), 0.0)) tiles_batch.spawn(model, vec3(float(((mx - 128) * 8) + 4), float(((127 - my) * 8) + 4), 0.0))
tiles_batch.make_static()
tests_texture = Texture(*archive.get_texture('tests')) tests_texture = Texture(*archive.get_texture('tests'))
tests_vertices = Vertices(*archive.get_vertices('tests')) tests_vertices = Vertices(*archive.get_vertices('tests'))
@ -187,30 +186,26 @@ def create_scene(keyboard, mouse):
sea_detail_texture = sea.load_detail_texture('data/sea_bump.png') sea_detail_texture = sea.load_detail_texture('data/sea_bump.png')
sea_triangles = sea.sea_triangles(64, proj_far_z - 0.1, proj_ratio) sea_triangles = sea.sea_triangles(64, proj_far_z - 0.1, proj_ratio)
assert tiles_shader.u_height_sampler == tests_shader.u_height_sampler return SceneNode(
assert tiles_shader.u_normal_sampler == tests_shader.u_normal_sampler PerfNode('frame',
TextureNode({1: heightmap, 2: normalmap},
return SceneGroup(
PerfGroup('frame',
TextureGroup({tiles_shader.u_height_sampler: heightmap, tiles_shader.u_normal_sampler: normalmap},
FuncNode(update_camera, (mouse, camera, environment)), FuncNode(update_camera, (mouse, camera, environment)),
TextureGroup({tiles_shader.u_texture_sampler: tiles_texture}, TextureNode({0: tiles_texture},
ShaderGroup(tiles_shader, ShaderNode(tiles_shader,
InputNode(tiles_shader, camera, environment), InputNode(tiles_shader, camera, environment),
PerfGroup('tiles_batch', PerfNode('tiles_batch',
DrawNode(tiles_batch)))), DrawNode(tiles_batch)))),
FuncNode(update_tests, (blob, cube, clouds)), FuncNode(update_tests, (blob, cube, clouds)),
TextureGroup({tests_shader.u_texture_sampler: tests_texture}, TextureNode({0: tests_texture},
ShaderGroup(tests_shader, ShaderNode(tests_shader,
InputNode(tests_shader, camera, environment), InputNode(tests_shader, camera, environment),
PerfGroup('tests_batch', PerfNode('tests_batch',
DrawNode(tests_batch))))), DrawNode(tests_batch))))),
FuncNode(update_sea, (camera, sea_phase)), FuncNode(update_sea, (camera, sea_phase)),
TextureGroup( TextureNode({0: sea_polar_textures, 1: sea_detail_texture},
{sea_shader.u_polar_sampler: sea_polar_textures, sea_shader.u_detail_sampler: sea_detail_texture}, ShaderNode(sea_shader,
ShaderGroup(sea_shader,
InputNode(sea_shader, camera, environment, sea_phase), InputNode(sea_shader, camera, environment, sea_phase),
PerfGroup('sea_triangles', PerfNode('sea_triangles',
DrawNode(sea_triangles)))))) DrawNode(sea_triangles))))))
def loop(display): def loop(display):

View File

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

View File

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

View File

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