# Copyright (C) 2022 RozK # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import time from math import pi, tau, dist from ctypes import Structure from engine import * from game import math from game import generator from game import shader from game import resources from game import batch from game import triangles from game import sea from game.camera import Camera from game.environment import Environment proj_hfov = pi * 0.25 proj_ratio = 16.0 / 9.0 proj_near_z = 8.0 proj_far_z = 3000.0 camera_origin = (0.0, -1200.0, 500.0) camera_lookat = (0.0, 500.0, -500.0) sun_direction = math.vec3_normalize((1.0, 0.0, 1.0)) sun_power = 1.0 def main(): print("Generating terrain...") gen_begin = time.process_time() generated = generator.Generator(256) gen_end = time.process_time() print("Done: ", round(gen_end - gen_begin, 2), "seconds") print("Initializing...") window = initialize(b'RK Island', 1600, 900) terrain_shader = shader.load('terrain', 'common') tests_shader = shader.load('tests', 'common') sky_shader = shader.load('sky') heightmap = create_texture( TEXTURE_FORMAT_32F, 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 = resources.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') 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') terrain_batch = batch.Batch(tiles_vertices, generated.size ** 2, params_format(PARAM_FORMAT_VEC3_SHORT), vec3) #TODO: generator & for real vc = generated.volcano_c vr = generated.volcano_r for my, mx in generated.map_coords: vd = dist((mx + 0.5, my + 0.5), vc) nx, ny, nz, h = generated.unpack(my, mx) r = generated.rivers[my * generated.size + mx] if h == 0.0: continue if r > 0.0: model = water_model elif h < 2.0: model = sand_model elif h < 180: if nz > 0.9: if ny < -0.01 and nz > 0.93: model = forest_model else: model = grass_model else: model = rock_model elif vd < vr - 3.0 and nz > 0.999: model = lava_model elif vd < vr + 2.0: model = mud_model elif vd < vr + 6.0 and nz < 0.67: model = mud_model else: model = rock_model model.spawn(terrain_batch, vec3(float(((mx - 128) * 8) + 4), float(((127 - my) * 8) + 4), 0.0)) class testsparams(Structure): _fields_ = ('translation', vec3), ('orientation', vec3) 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') clouds_model = archive.get_model('clouds') tests_batch = batch.Batch(tests_vertices, 3, params_format(PARAM_FORMAT_VEC3_FLOAT, PARAM_FORMAT_VEC3_INT10 | PARAM_FORMAT_NORMALIZE), testsparams) blob_spawn_translation = vec3(-100.0, -500.0, 0.0) cube_spawn_translation = vec3(100.0, -500.0, 0.0) blob_id = blob_model.spawn(tests_batch, testsparams(blob_spawn_translation, vec3(*math.vec3_normalize((sun_direction[0], sun_direction[1], 0.0))))) cube_id = cube_model.spawn(tests_batch, testsparams(cube_spawn_translation, vec3_forward)) clouds_id = clouds_model.spawn(tests_batch, testsparams(vec3(0.0, 0.0, 32.0), vec3_forward)) 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) _rotation = mat3() _origin = vec3() _lookat = vec3() print("Running...") start_time = time.monotonic() current_time = 0.0 frame_min = 10000.0 frame_max = 0.0 frame_avg = 0.0 draw_min = 10000.0 draw_max = 0.0 draw_avg = 0.0 perf_count = 0 try: for frame in range(10000): current_time = time.monotonic() - start_time begin_frame() frame_begin = time.thread_time() mat3_rotation(_rotation, vec3_up, (current_time * 0.21) % tau) mat3_mul_vec3(tests_batch.params[blob_id].translation, _rotation, blob_spawn_translation) mat3_mul_vec3(tests_batch.params[cube_id].translation, _rotation, cube_spawn_translation) mat3_rotation(_rotation, vec3_up, (current_time * 0.43) % tau) mat3_mul_vec3(tests_batch.params[cube_id].orientation, _rotation, vec3_forward) mat3_rotation(_rotation, vec3_up, (current_time * -0.037) % tau) mat3_mul_vec3(tests_batch.params[clouds_id].orientation, _rotation, vec3_forward) mat3_rotation(_rotation, vec3_up, (current_time * 0.05) % tau) mat3_mul_vec3(_origin, _rotation, vec3(*camera_origin)) mat3_mul_vec3(_lookat, _rotation, vec3(*camera_lookat)) camera.set_view(_origin, _lookat) 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) select_vertices(tiles_vertices) draw_begin = time.thread_time() terrain_batch.draw() draw_end = time.thread_time() unselect_vertices(tiles_vertices) unselect_texture(0, tiles_texture) unselect_texture(1, heightmap) unselect_texture(2, normalmap) unselect_shader(terrain_shader) 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) select_vertices(tests_vertices) tests_batch.draw() unselect_vertices(tests_vertices) unselect_texture(0, tests_texture) unselect_texture(1, heightmap) unselect_texture(2, normalmap) unselect_shader(tests_shader) camera.set_view( vec3(_origin.x * 0.001, _origin.y * 0.001, _origin.z * 0.001), vec3(_lookat.x * 0.001, _lookat.y * 0.001, _lookat.z * 0.001)) 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) draw_triangles(sky_triangles) unselect_texture(0, sea_polar_textures) unselect_texture(1, sea_detail_texture) unselect_shader(sky_shader) frame_end = time.thread_time() end_frame() if frame > 0: draw_ms = draw_end - draw_begin draw_min = min(draw_min, draw_ms) draw_max = max(draw_max, draw_ms) draw_avg += draw_ms frame_ms = frame_end - frame_begin frame_min = min(frame_min, frame_ms) frame_max = max(frame_max, frame_ms) frame_avg += frame_ms perf_count += 1 except KeyboardInterrupt: pass print("\rDraw *", perf_count, ": min =", round(draw_min * 1000.0, 2), ", max =", round(draw_max * 1000.0, 2), ", avg =", round((draw_avg / perf_count) * 1000.0, 2), "ms") print("\rFrame *", perf_count, ": min =", round(frame_min * 1000.0, 2), ", max =", round(frame_max * 1000.0, 2), ", avg =", round((frame_avg / perf_count) * 1000.0, 2), "ms") # seed 666 # camera_origin = vec3((0.0, -1200.0, 500.0)) # camera_lookat = vec3((0.0, 500.0, -500.0)) # for x in range(10000) # current_time = 0 # Draw * 9999 : min = 0.21 , max = 2.16 , avg = 0.27 ms # Draw * 9999 : min = 0.20 , max = 1.96 , avg = 0.27 ms # Draw * 9999 : min = 0.20 , max = 2.43 , avg = 0.27 ms # Frame * 9999 : min = 0.27 , max = 2.29 , avg = 0.38 ms # Frame * 9999 : min = 0.26 , max = 2.08 , avg = 0.37 ms # Frame * 9999 : min = 0.26 , max = 2.59 , avg = 0.38 ms print("Quitting...") del tests_batch del terrain_batch destroy_texture(sea_polar_textures) destroy_texture(sea_detail_texture) destroy_texture(heightmap) destroy_triangles(sky_triangles) archive.destroy() destroy_shader(terrain_shader) destroy_shader(tests_shader) destroy_shader(sky_shader) terminate()