# 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 shader from game import triangles from game import sea from game.generator import Generator from game.resources import RuntimeArchive from game.batch import Batch 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.thread_time() generated = Generator(256) gen_end = time.thread_time() print("Done: ", round(gen_end - gen_begin, 2), "seconds") print("Initializing...") display = create_display(b'RK Island', 1600, 900) events = create_events(display) render_initialize() 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 = 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(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(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) blob_translation = tests_batch.params[blob_id].translation cube_translation = tests_batch.params[cube_id].translation cube_orientation = tests_batch.params[cube_id].orientation clouds_orientation = tests_batch.params[clouds_id].orientation print("Running... Click or press q to quit") 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 events_buffer = buffer(Event, 16) try: for frame in range(10000): current_time = time.monotonic() - start_time begin_frame() frame_begin = time.thread_time() rotation = mat3() mat3_rotation(rotation, vec3_up, (current_time * 0.21) % tau) mat3_mul_vec3(blob_translation, rotation, blob_spawn_translation) mat3_mul_vec3(cube_translation, rotation, cube_spawn_translation) vec3_rotate(cube_orientation, vec3_forward, vec3_up, (current_time * 0.43) % tau) vec3_rotate(clouds_orientation, vec3_forward, vec3_up, (current_time * -0.037) % tau) camera.set_view(camera_origin, camera_lookat, vec3_up, (current_time * 0.05) % tau) 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.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) 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() swap_buffers(display) 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 stop = False while True: nevents = consume_events(events, events_buffer, len(events_buffer)) if not nevents: break for event in events_buffer[:nevents]: if event.type == EVENT_FOCUS_IN: print("EVENT_FOCUS_IN") elif event.type == EVENT_FOCUS_OUT: print("EVENT_FOCUS_OUT") elif event.type == EVENT_KEY_PRESS and event.data.key.character == 'q': stop = True elif event.type == EVENT_BUTTON_RELEASE: stop = True if stop: break 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.2 , max = 2.31 , avg = 0.27 ms # Draw * 9999 : min = 0.2 , max = 2.41 , avg = 0.27 ms # Draw * 9999 : min = 0.2 , max = 2.73 , avg = 0.27 ms # Frame * 9999 : min = 0.26 , max = 2.44 , avg = 0.38 ms # Frame * 9999 : min = 0.26 , max = 2.54 , avg = 0.37 ms # Frame * 9999 : min = 0.26 , max = 2.90 , 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_texture(normalmap) destroy_triangles(sky_triangles) archive.destroy() destroy_shader(terrain_shader) destroy_shader(tests_shader) destroy_shader(sky_shader) render_terminate() destroy_events(display, events) destroy_display(display)