Compare commits

...

3 Commits

14 changed files with 165 additions and 166 deletions

2
engine

@ -1 +1 @@
Subproject commit 2095e335ead1967fde413b0d61d35e2f3b90461a
Subproject commit ae3333e22e36667a0c02817fafb16ab7b8d1341b

View File

@ -13,14 +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 engine import vec3_origin, mat4, mat4_projection, mat4_orbit, resolve_input, set_input_mat4
class _Inputs:
__slots__ = 'projection', 'view'
def __init__(self, shader, projection, view):
self.projection = resolve_input(shader, projection)
self.view = resolve_input(shader, view)
from engine import vec3_origin, mat4, mat4_projection, mat4_orbit, set_input_mat4
class Camera:
__slots__ = 'yaw', 'pitch', 'distance', 'projection', 'view'
@ -44,9 +37,6 @@ class Camera:
def to_km(self):
mat4_orbit(self.view, vec3_origin, self.yaw, self.pitch, self.distance * 0.001)
def resolve_inputs(self, shader, projection = b'u_projection', view = b'u_view'):
return _Inputs(shader, projection, view)
def update_inputs(self, inputs):
set_input_mat4(inputs.projection, self.projection)
set_input_mat4(inputs.view, self.view)
def set_inputs(self, shader):
set_input_mat4(shader.u_projection, self.projection)
set_input_mat4(shader.u_view, self.view)

View File

@ -14,7 +14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from math import radians, cos
from engine import vec3, mat4_mul_vec3, resolve_input, set_input_vec3
from engine import vec3, mat4_mul_vec3, set_input_vec3
from game.math import vec3_up, vec3_add, vec3_sub, vec3_scale, vec3_mul, vec3_dot
def _angles(start, end):
@ -62,16 +62,6 @@ def _resolve_color(ranges, c):
w, (a, b) = _resolve(ranges, c)
return vec3_add(a, vec3_scale(b, w))
class _Inputs:
__slots__ = 'light_direction', 'light_color', 'horizon_color', 'sky_color', 'sun_color'
def __init__(self, shader):
self.light_direction = resolve_input(shader, b'u_light_direction')
self.light_color = resolve_input(shader, b'u_light_color')
self.horizon_color = resolve_input(shader, b'u_horizon_color')
self.sky_color = resolve_input(shader, b'u_sky_color')
self.sun_color = resolve_input(shader, b'u_sun_color')
class Environment:
__slots__ = 'light_direction', 'light_color', 'horizon_color', 'sky_color', 'sun_color'
@ -91,12 +81,9 @@ class Environment:
self.sky_color.set(*vec3_scale(_resolve_color(_sky_color, c), light_power))
self.sun_color.set(*_resolve_color(_sun_color, c))
def resolve_inputs(self, shader):
return _Inputs(shader)
def update_inputs(self, inputs):
set_input_vec3(inputs.light_direction, self.light_direction)
set_input_vec3(inputs.light_color, self.light_color)
set_input_vec3(inputs.horizon_color, self.horizon_color)
set_input_vec3(inputs.sky_color, self.sky_color)
set_input_vec3(inputs.sun_color, self.sun_color)
def set_inputs(self, shader):
set_input_vec3(shader.u_light_direction, self.light_direction)
set_input_vec3(shader.u_light_color, self.light_color)
set_input_vec3(shader.u_horizon_color, self.horizon_color)
set_input_vec3(shader.u_sky_color, self.sky_color)
set_input_vec3(shader.u_sun_color, self.sun_color)

View File

@ -20,9 +20,9 @@ from ctypes import Structure
from engine import *
from game import math
from game import shader
from game import triangles
from game import sea
from game.shader import Shader
from game.generator import Generator
from game.resources import RuntimeArchive
from game.batch import Batch
@ -53,28 +53,22 @@ def main():
mouse = Mouse(events, wheel = 60, wheel_min = 20)
keyboard = Keyboard(events)
render_initialize(__debug__)
terrain_shader = shader.load('terrain', 'common')
tests_shader = shader.load('tests', 'common')
sky_shader = shader.load('sky')
terrain_shader = Shader('terrain', 'common')
tests_shader = Shader('tests', 'common')
sky_shader = Shader('sky')
heightmap = create_texture(
TEXTURE_FORMAT_FLOAT_32, 256, 256, 0, TEXTURE_FLAG_MIN_LINEAR | TEXTURE_FLAG_MAG_LINEAR,
generated.packed_heights)
terrain_heightmap_sampler = resolve_input(terrain_shader, b'u_height_sampler')
tests_heightmap_sampler = resolve_input(tests_shader, b'u_height_sampler')
normalmap = create_texture(
TEXTURE_FORMAT_RGB10_A2, 256, 256, 0, TEXTURE_FLAG_MIN_LINEAR | TEXTURE_FLAG_MAG_LINEAR,
generated.packed_normals)
terrain_normalmap_sampler = resolve_input(terrain_shader, b'u_normal_sampler')
tests_normalmap_sampler = resolve_input(tests_shader, b'u_normal_sampler')
print("Loading resources...")
archive = RuntimeArchive.load('data/rk_island.rkar')
print("Building tiles...")
tiles_texture = archive.get_texture('tiles')
tiles_sampler = resolve_input(terrain_shader, b'u_texture_sampler')
tiles_vertices = archive.get_vertices('tiles')
water_model = archive.get_model('water')
sand_model = archive.get_model('sand')
@ -117,7 +111,6 @@ def main():
model.spawn(terrain_batch, vec3(float(((mx - 128) * 8) + 4), float(((127 - my) * 8) + 4), 0.0))
tests_texture = archive.get_texture('tests')
tests_sampler = resolve_input(tests_shader, b'u_texture_sampler')
tests_vertices = archive.get_vertices('tests')
blob_model = archive.get_model('blob')
cube_model = archive.get_model('cube')
@ -134,23 +127,13 @@ def main():
cube_id = cube_model.spawn(tests_batch, cube_spawn_translation, mat3_identity)
clouds_id = clouds_model.spawn(tests_batch, vec3(0.0, 0.0, 32.0), mat3_identity)
sea_phase = resolve_input(sky_shader, b'u_sea_phase')
sea_polar_textures = sea.load_polar_textures(('data/sea_bump1.png', 'data/sea_bump2.png'))
sea_polar_sampler = resolve_input(sky_shader, b'u_sea_polar_sampler')
sea_detail_texture = sea.load_detail_texture('data/sea_bump.png')
sea_detail_sampler = resolve_input(sky_shader, b'u_sea_detail_sampler')
sky_triangles = create_triangles(triangles.sky_triangles(64, proj_far_z - 0.1, proj_ratio))
camera = Camera()
camera.set_projection(proj_hfov, proj_ratio, proj_near_z, proj_far_z)
terrain_camera_inputs = camera.resolve_inputs(terrain_shader)
tests_camera_inputs = camera.resolve_inputs(tests_shader)
sky_camera_inputs = camera.resolve_inputs(sky_shader)
environment = Environment()
terrain_environment_inputs = environment.resolve_inputs(terrain_shader)
tests_environment_inputs = environment.resolve_inputs(tests_shader)
sky_environment_inputs = environment.resolve_inputs(sky_shader)
blob_translation = tests_batch.translation[blob_id]
cube_translation = tests_batch.translation[cube_id]
@ -185,19 +168,19 @@ def main():
camera.set_view(camera_yaw, camera_pitch, camera_distance)
environment.from_sun(camera.view, sun_direction, sun_power)
select_shader(terrain_shader)
camera.update_inputs(terrain_camera_inputs)
environment.update_inputs(terrain_environment_inputs)
select_texture(0, tiles_texture, tiles_sampler)
select_texture(1, heightmap, terrain_heightmap_sampler)
select_texture(2, normalmap, terrain_normalmap_sampler)
terrain_shader.select()
camera.set_inputs(terrain_shader)
environment.set_inputs(terrain_shader)
select_texture(0, tiles_texture)
select_texture(1, heightmap)
select_texture(2, normalmap)
draw_begin = time.thread_time()
terrain_batch.draw()
draw_end = time.thread_time()
unselect_texture(0, tiles_texture)
unselect_texture(1, heightmap)
unselect_texture(2, normalmap)
unselect_shader(terrain_shader)
terrain_shader.unselect()
rotation = mat3()
mat3_rotation(rotation, vec3_up, (current_time * 0.21) % tau)
@ -206,30 +189,30 @@ def main():
mat3_rotation(cube_orientation, vec3_up, (current_time * 0.43) % tau)
mat3_rotation(clouds_orientation, vec3_up, (current_time * -0.037) % tau)
select_shader(tests_shader)
camera.update_inputs(tests_camera_inputs)
environment.update_inputs(tests_environment_inputs)
select_texture(0, tests_texture, tests_sampler)
select_texture(1, heightmap, tests_heightmap_sampler)
select_texture(2, normalmap, tests_normalmap_sampler)
tests_shader.select()
camera.set_inputs(tests_shader)
environment.set_inputs(tests_shader)
select_texture(0, tests_texture)
select_texture(1, heightmap)
select_texture(2, normalmap)
tests_batch.draw()
unselect_texture(0, tests_texture)
unselect_texture(1, heightmap)
unselect_texture(2, normalmap)
unselect_shader(tests_shader)
tests_shader.unselect()
camera.to_km()
select_shader(sky_shader)
camera.update_inputs(sky_camera_inputs)
environment.update_inputs(sky_environment_inputs)
set_input_float(sea_phase, (current_time * 0.023) % 1.0)
select_texture(0, sea_polar_textures, sea_polar_sampler)
select_texture(1, sea_detail_texture, sea_detail_sampler)
sky_shader.select()
camera.set_inputs(sky_shader)
environment.set_inputs(sky_shader)
set_input_float(sky_shader.u_sea_phase, (current_time * 0.023) % 1.0)
select_texture(0, sea_polar_textures)
select_texture(1, sea_detail_texture)
draw_triangles(sky_triangles)
unselect_texture(0, sea_polar_textures)
unselect_texture(1, sea_detail_texture)
unselect_shader(sky_shader)
sky_shader.unselect()
frame_end = time.thread_time()
end_frame()
@ -281,9 +264,9 @@ def main():
destroy_texture(normalmap)
destroy_triangles(sky_triangles)
archive.destroy()
destroy_shader(terrain_shader)
destroy_shader(tests_shader)
destroy_shader(sky_shader)
del terrain_shader
del tests_shader
del sky_shader
render_terminate()
del events
destroy_display(display)

View File

@ -15,33 +15,69 @@
from pathlib import Path
from engine import load_shader
from engine import load_shader, resolve_input, select_shader, unselect_shader, destroy_shader
#TODO: preprocessing (at least includes)
def _cleanup(line):
return line.partition('//')[0].strip()
def load(vert_name, frag_name = ''):
path = Path('.') / 'game' / 'shaders'
if not frag_name:
frag_name = vert_name
def _cleanup(_line):
return _line.partition('//')[0].strip()
def _filter(_line):
return _line
def _convert(_line):
return bytes(_line, 'utf-8') + b'\n'
def load_source(_path):
if not _path.exists():
print("Cannot find", _path)
return None
return list(map(_convert, filter(_filter, map(_cleanup, open(_path, 'rt')))))
print("Loading vertex shader", vert_name)
vert_lines = load_source(path / (vert_name + '_opengles.vert'))
if not vert_lines:
print("Error: Vertex shader is empty.")
return None
print("Loading fragment shader", frag_name)
frag_lines = load_source(path / (frag_name + '_opengles.frag'))
if not frag_lines:
print("Error: Fragment shader is empty.")
return None
return load_shader(vert_lines, frag_lines)
def _filter(line):
return line
def _subst(line):
if line.startswith('#include '):
path = Path('.') / 'game' / 'shaders'
lines = []
for name in line.split()[1:]:
lines.extend(_load_source(path / name.strip('"')))
return lines
return [line]
def _load_source(path):
assert path.exists()
lines = filter(_filter, map(_cleanup, open(path, 'rt')))
source = []
for line in lines:
source.extend(_subst(line))
return source
def _convert(line):
return bytes(line, 'utf-8') + b'\n'
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 '):
name = line.split()[-1].strip(';')
if name not in uniforms:
uniforms.append(name)
for name in uniforms:
setattr(shader, name, resolve_input(shader._shader, bytes(name, 'utf-8')))
class Shader:
__slots__ = '_shader', '__dict__'
def __init__(self, vert_name, frag_name = ''):
path = Path('.') / 'game' / 'shaders'
assert path.exists()
if not frag_name:
frag_name = vert_name
print("Loading vertex shader", vert_name)
vert_lines = _load_source(path / (vert_name + '_opengles.vert'))
assert vert_lines
print("Loading fragment shader", frag_name)
frag_lines = _load_source(path / (frag_name + '_opengles.frag'))
assert frag_lines
self._shader = load_shader(list(map(_convert, vert_lines)), list(map(_convert, frag_lines)))
_parse(self, vert_lines, frag_lines)
def __del__(self):
destroy_shader(self._shader)
def select(self):
select_shader(self._shader)
def unselect(self):
unselect_shader(self._shader)

View File

@ -16,6 +16,8 @@
#version 320 es
precision highp float;
#include "include/environment.glsl"
in vec4 v_position; // view space
in vec4 v_normal; // view space
in vec4 v_terrain_normal; // view space (x, y, z, weight)
@ -23,10 +25,7 @@ in vec4 v_texcoord; // texture space (s, t, pixel_level, material_level)
#define v_weight v_terrain_normal.w
uniform vec3 u_light_direction; // view space (-direction_x, -direction_y, -direction_z)
uniform vec3 u_light_color; // (color.r * power, color.g * power, color.b * power)
uniform highp sampler2DArray u_texture_sampler;
layout(binding=0) uniform highp sampler2DArray u_texture_sampler;
layout(location = 0) out vec4 o_color;

View File

@ -0,0 +1,7 @@
#ifndef CAMERA_INCLUDED
#define CAMERA_INCLUDED
uniform mat4 u_view; // world space -> view space
uniform mat4 u_projection; // view space -> screen space
#endif // CAMERA_INCLUDED

View File

@ -0,0 +1,20 @@
#ifndef COMMON_INCLUDED
#define COMMON_INCLUDED
layout(binding=1) uniform highp sampler2D u_height_sampler;
layout(binding=2) 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;
const vec3 c_world_forward = vec3(0.0, 1.0, 0.0);
out vec4 v_position; // view space
out vec4 v_normal; // view space
out vec4 v_terrain_normal; // view space (x, y, z, weigth)
out vec4 v_texcoord; // texture space (s, t, pixel_level, material_level)
#endif // COMMON_INCLUDED

View File

@ -0,0 +1,10 @@
#ifndef ENVIRONMENT_INCLUDED
#define ENVIRONMENT_INCLUDED
uniform vec3 u_light_direction; // view space
uniform vec3 u_light_color;
uniform vec3 u_horizon_color;
uniform vec3 u_sky_color;
uniform vec3 u_sun_color;
#endif // ENVIRONMENT_INCLUDED

View File

@ -0,0 +1,8 @@
#ifndef VERTEX_FORMAT_INCLUDED
#define VERTEX_FORMAT_INCLUDED
layout(location = 0) in vec3 a_position; // model space
layout(location = 1) in vec3 a_normal; // model space
layout(location = 2) in vec3 a_texcoord; // texture space
#endif // VERTEX_FORMAT_INCLUDED

View File

@ -16,14 +16,11 @@
#version 320 es
precision highp float;
#include "include/camera.glsl"
#include "include/environment.glsl"
in vec3 v_position;
uniform mat4 u_view; // world space -> view space, unit = km
uniform vec3 u_light_direction; // view space (-direction_x, -direction_y, -direction_z)
uniform vec3 u_light_color;
uniform vec3 u_horizon_color;
uniform vec3 u_sky_color;
uniform vec3 u_sun_color;
uniform float u_sea_phase;
#define u_right u_view[0].xyz
@ -31,8 +28,8 @@ uniform float u_sea_phase;
#define u_up u_view[2].xyz
#define u_origin u_view[3].xyz
uniform highp sampler2DArray u_sea_polar_sampler;
uniform highp sampler2D u_sea_detail_sampler;
layout(binding=0) uniform highp sampler2DArray u_sea_polar_sampler;
layout(binding=1) uniform highp sampler2D u_sea_detail_sampler;
const float c_sea_radius = 637.1;
const float c_sea_radius_sq = c_sea_radius * c_sea_radius;

View File

@ -16,9 +16,9 @@
#version 320 es
precision highp float;
layout(location = 0) in vec3 a_position; // view space
#include "include/camera.glsl"
uniform mat4 u_projection; // view space -> screen space
layout(location = 0) in vec3 a_position; // view space
out vec3 v_position; // view space

View File

@ -16,31 +16,12 @@
#version 320 es
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 vec3 a_texcoord; // texture space
#include "include/vertex_format.glsl"
#include "include/camera.glsl"
#include "include/common.glsl"
layout(location = 3) in vec3 i_translation; // per mesh, model space -> world space
uniform mat4 u_view; // world space -> view space
uniform mat4 u_projection; // view space -> screen space
uniform highp sampler2D u_height_sampler;
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;
const vec3 c_world_forward = vec3(0.0, 1.0, 0.0);
out vec4 v_position; // view space
out vec4 v_normal; // view space
out vec4 v_terrain_normal; // view space (x, y, z, weigth)
out vec4 v_texcoord; // texture space (s, t, pixel_level, material_level)
void main(void) {
vec4 world_position = vec4(i_translation + a_position, 1.0);
vec2 terrain_coords = c_terrain_shift + world_position.xy * c_terrain_scale;

View File

@ -16,32 +16,13 @@
#version 320 es
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 vec3 a_texcoord; // texture space
#include "include/vertex_format.glsl"
#include "include/camera.glsl"
#include "include/common.glsl"
layout(location = 3) in vec3 i_translation; // per mesh, model space -> world space
layout(location = 4) in mat3 i_orientation; // per mesh, model space -> world space
uniform mat4 u_view; // world space -> view space
uniform mat4 u_projection; // view space -> screen space
uniform highp sampler2D u_height_sampler;
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;
const vec3 c_world_forward = vec3(0.0, 1.0, 0.0);
out vec4 v_position; // view space
out vec4 v_normal; // view space
out vec4 v_terrain_normal; // view space (x, y, z, weigth)
out vec4 v_texcoord; // texture space (s, t, pixel_level, material_level)
void main(void) {
vec4 world_position = vec4(i_translation + i_orientation * a_position, 1.0);
float weight = max(0.0, 1.0 - world_position.z * c_weight_scale);