rk_island/game/game.py

295 lines
11 KiB
Python
Raw Normal View History

2022-08-28 05:09:52 +02:00
# 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 <http://www.gnu.org/licenses/>.
import time
from math import pi, tau, dist
from ctypes import Structure
2022-08-28 05:09:52 +02:00
from engine import *
2022-12-18 05:40:52 +01:00
from game import math
from game import shader
from game import triangles
from game import sea
2022-12-23 06:36:24 +01:00
from game.generator import Generator
from game.resources import RuntimeArchive
from game.batch import Batch
2022-12-18 06:35:20 +01:00
from game.camera import Camera
from game.environment import Environment
from game.events import Events
from game.mouse import Mouse
from game.keyboard import Keyboard
2022-12-18 05:40:52 +01:00
proj_hfov = pi * 0.25
proj_ratio = 16.0 / 9.0
proj_near_z = 8.0
proj_far_z = 3000.0
2022-12-29 14:36:30 +01:00
sun_direction = math.vec3_normalize((1.0, 0.0, 0.5))
sun_power = 1.0
2022-08-28 05:09:52 +02:00
def main():
print("Generating terrain...")
2022-12-23 06:36:24 +01:00
gen_begin = time.thread_time()
generated = Generator(256)
gen_end = time.thread_time()
2022-08-28 05:09:52 +02:00
print("Done: ", round(gen_end - gen_begin, 2), "seconds")
print("Initializing...")
display = create_display(b'RK Island - Drag to rotate, wheel to zoom, q to quit', 1600, 900)
2022-12-29 19:19:17 +01:00
assert display
events = Events(display)
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')
2022-08-28 05:09:52 +02:00
heightmap = create_texture(
2022-12-25 04:35:09 +01:00
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...")
2022-12-23 06:36:24 +01:00
archive = RuntimeArchive.load('data/rk_island.rkar')
print("Building tiles...")
2022-08-28 05:09:52 +02:00
tiles_texture = archive.get_texture('tiles')
tiles_sampler = resolve_input(terrain_shader, b'u_texture_sampler')
2022-08-28 05:09:52 +02:00
tiles_vertices = archive.get_vertices('tiles')
2022-12-20 09:00:45 +01:00
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, 8, translation = PARAM_FORMAT_VEC3_SHORT)
2022-08-28 05:09:52 +02:00
#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:
2022-12-20 09:00:45 +01:00
model = water_model
2022-08-28 05:09:52 +02:00
elif h < 2.0:
2022-12-20 09:00:45 +01:00
model = sand_model
2022-08-28 05:09:52 +02:00
elif h < 180:
if nz > 0.9:
if ny < -0.01 and nz > 0.93:
2022-12-20 09:00:45 +01:00
model = forest_model
2022-08-28 05:09:52 +02:00
else:
2022-12-20 09:00:45 +01:00
model = grass_model
2022-08-28 05:09:52 +02:00
else:
2022-12-20 09:00:45 +01:00
model = rock_model
2022-08-28 05:09:52 +02:00
elif vd < vr - 3.0 and nz > 0.999:
2022-12-20 09:00:45 +01:00
model = lava_model
2022-08-28 05:09:52 +02:00
elif vd < vr + 2.0:
2022-12-20 09:00:45 +01:00
model = mud_model
2022-08-28 05:09:52 +02:00
elif vd < vr + 6.0 and nz < 0.67:
2022-12-20 09:00:45 +01:00
model = mud_model
2022-08-28 05:09:52 +02:00
else:
2022-12-20 09:00:45 +01:00
model = rock_model
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')
2022-12-20 09:00:45 +01:00
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)
blob_spawn_translation = vec3(-100.0, -500.0, 0.0)
cube_spawn_translation = vec3(100.0, -500.0, 0.0)
blob_forward = math.vec3_normalize((sun_direction[0], sun_direction[1], 0.0))
blob_right = math.vec3_cross(blob_forward, math.vec3_up)
blob_id = blob_model.spawn(tests_batch,
blob_spawn_translation, mat3(vec3(*blob_right), vec3(*blob_forward), vec3_up))
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)
2022-08-28 05:09:52 +02:00
sea_phase = resolve_input(sky_shader, b'u_sea_phase')
2022-08-28 05:09:52 +02:00
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')
2022-08-28 05:09:52 +02:00
sea_detail_texture = sea.load_detail_texture('data/sea_bump.png')
sea_detail_sampler = resolve_input(sky_shader, b'u_sea_detail_sampler')
2022-08-28 05:09:52 +02:00
sky_triangles = create_triangles(triangles.sky_triangles(64, proj_far_z - 0.1, proj_ratio))
2022-12-18 05:40:52 +01:00
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)
2022-12-18 06:35:20 +01:00
environment = Environment()
2022-12-18 05:40:52 +01:00
terrain_environment_inputs = environment.resolve_inputs(terrain_shader)
tests_environment_inputs = environment.resolve_inputs(tests_shader)
sky_environment_inputs = environment.resolve_inputs(sky_shader)
2022-08-28 05:09:52 +02:00
blob_translation = tests_batch.translation[blob_id]
cube_translation = tests_batch.translation[cube_id]
cube_orientation = tests_batch.orientation[cube_id]
clouds_orientation = tests_batch.orientation[clouds_id]
2022-08-28 05:09:52 +02:00
print("Running... Ctrl+c to quit")
start_time = time.monotonic()
current_time = 0.0
2022-12-29 14:36:30 +01:00
frame = 0
2022-08-28 05:09:52 +02:00
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:
2022-12-29 14:36:30 +01:00
while True:
current_time = time.monotonic() - start_time
2022-08-28 05:09:52 +02:00
frame_begin = time.thread_time()
events.update()
if keyboard.quit:
break
begin_frame()
camera_distance = mouse.wheel * 20.0
camera_yaw = mouse.drag[0] * 0.001
camera_pitch = mouse.drag[1] * 0.001 + pi * 0.25
camera.set_view(camera_yaw, camera_pitch, camera_distance)
environment.from_sun(camera.view, sun_direction, sun_power)
2022-12-18 05:40:52 +01:00
2022-08-28 05:09:52 +02:00
select_shader(terrain_shader)
2022-12-18 05:40:52 +01:00
camera.update_inputs(terrain_camera_inputs)
2022-12-18 06:35:20 +01:00
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)
2022-08-28 05:09:52 +02:00
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)
2022-08-28 05:09:52 +02:00
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)
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)
2022-12-18 05:40:52 +01:00
camera.update_inputs(tests_camera_inputs)
2022-12-18 06:35:20 +01:00
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)
2022-08-28 05:09:52 +02:00
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)
2022-08-28 05:09:52 +02:00
2022-12-20 16:10:09 +01:00
camera.to_km()
2022-12-18 05:40:52 +01:00
2022-08-28 05:09:52 +02:00
select_shader(sky_shader)
2022-12-18 05:40:52 +01:00
camera.update_inputs(sky_camera_inputs)
2022-12-18 06:35:20 +01:00
environment.update_inputs(sky_environment_inputs)
2022-08-28 05:09:52 +02:00
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)
2022-08-28 05:09:52 +02:00
draw_triangles(sky_triangles)
unselect_texture(0, sea_polar_textures)
unselect_texture(1, sea_detail_texture)
2022-08-28 05:09:52 +02:00
unselect_shader(sky_shader)
frame_end = time.thread_time()
end_frame()
2022-12-24 11:35:14 +01:00
swap_buffers(display)
2022-08-28 05:09:52 +02:00
2022-12-17 14:14:11 +01:00
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
2022-12-29 14:36:30 +01:00
frame += 1
2022-12-23 10:25:37 +01:00
2022-08-28 05:09:52 +02:00
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
2022-12-30 12:38:27 +01:00
# for _ in range(10000):
# current_time = 0 # time.monotonic() - start_time
# Draw * 9999 : min = 0.13 , max = 0.86 , avg = 0.2 ms
# Draw * 9999 : min = 0.14 , max = 0.75 , avg = 0.2 ms
# Draw * 9999 : min = 0.14 , max = 0.84 , avg = 0.2 ms
# Frame * 9999 : min = 0.19 , max = 0.98 , avg = 0.34 ms
# Frame * 9999 : min = 0.21 , max = 0.94 , avg = 0.34 ms
# Frame * 9999 : min = 0.21 , max = 1.0 , avg = 0.34 ms
2022-08-28 05:09:52 +02:00
print("Quitting...")
del tests_batch
del terrain_batch
destroy_texture(sea_polar_textures)
destroy_texture(sea_detail_texture)
destroy_texture(heightmap)
2022-12-20 17:47:21 +01:00
destroy_texture(normalmap)
2022-08-28 05:09:52 +02:00
destroy_triangles(sky_triangles)
archive.destroy()
destroy_shader(terrain_shader)
destroy_shader(tests_shader)
2022-08-28 05:09:52 +02:00
destroy_shader(sky_shader)
2022-12-24 11:35:14 +01:00
render_terminate()
del events
2022-12-24 11:35:14 +01:00
destroy_display(display)