Compare commits

..

No commits in common. "758ed8c7f4bf1d06b45990e915e8ea870e3633bd" and "1ac12ea9ea5115d159034957ee7cce3177488e50" have entirely different histories.

6 changed files with 60 additions and 170 deletions

2
engine

@ -1 +1 @@
Subproject commit 33abfd834ad5c9541796ef3f8a4999539a2f91f8 Subproject commit 269d7821c82757cf994370f9ed4b2a6d36e34983

View File

@ -13,7 +13,13 @@
# 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/>.
from engine import vec3_origin, mat4, mat4_projection, mat4_orbit, resolve_input, set_input_mat4 from engine import (
vec3, vec3_mul_vec3,
mat3, mat3_rotation, mat3_mul_vec3,
mat4, mat4_projection, mat4_lookat,
resolve_input, set_input_mat4)
_m2km = vec3(0.001, 0.001, 0.001)
class _Inputs: class _Inputs:
__slots__ = 'projection', 'view' __slots__ = 'projection', 'view'
@ -23,26 +29,30 @@ class _Inputs:
self.view = resolve_input(shader, view) self.view = resolve_input(shader, view)
class Camera: class Camera:
__slots__ = 'yaw', 'pitch', 'distance', 'projection', 'view' __slots__ = 'origin', 'lookat', 'rotation', 'projection', 'view'
def __init__(self): def __init__(self):
self.yaw = 0.0 self.origin = vec3()
self.pitch = 0.0 self.lookat = vec3()
self.distance = 0.0 self.rotation = mat3()
self.projection = mat4() self.projection = mat4()
self.view = mat4() self.view = mat4()
def set_projection(self, half_fov, ratio, near_z, far_z): def set_projection(self, half_fov, ratio, near_z, far_z):
mat4_projection(self.projection, half_fov, ratio, near_z, far_z) mat4_projection(self.projection, half_fov, ratio, near_z, far_z)
def set_view(self, yaw, pitch, distance): def set_view(self, origin, lookat, axis, angle):
self.yaw = yaw self.origin.set(*origin)
self.pitch = pitch self.lookat.set(*lookat)
self.distance = distance mat3_rotation(self.rotation, axis, angle)
mat4_orbit(self.view, vec3_origin, yaw, pitch, distance) mat3_mul_vec3(self.origin, self.rotation, self.origin)
mat3_mul_vec3(self.lookat, self.rotation, self.lookat)
mat4_lookat(self.view, self.origin, self.lookat)
def to_km(self): def to_km(self):
mat4_orbit(self.view, vec3_origin, self.yaw, self.pitch, self.distance * 0.001) vec3_mul_vec3(self.origin, _m2km, self.origin)
vec3_mul_vec3(self.lookat, _m2km, self.lookat)
mat4_lookat(self.view, self.origin, self.lookat)
def resolve_inputs(self, shader, projection = b'u_projection', view = b'u_view'): def resolve_inputs(self, shader, projection = b'u_projection', view = b'u_view'):
return _Inputs(shader, projection, view) return _Inputs(shader, projection, view)

View File

@ -1,54 +0,0 @@
# 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/>.
from engine import (
buffer,
EVENT_FOCUS_IN, EVENT_FOCUS_OUT,
EVENT_KEY_PRESS, EVENT_KEY_RELEASE,
EVENT_BUTTON_PRESS, EVENT_BUTTON_RELEASE,
EVENT_MOTION,
Event, create_events, destroy_events, consume_events)
_max_type = max(
EVENT_FOCUS_IN, EVENT_FOCUS_OUT,
EVENT_KEY_PRESS, EVENT_KEY_RELEASE,
EVENT_BUTTON_PRESS, EVENT_BUTTON_RELEASE,
EVENT_MOTION)
_max_events = 64
class Events:
__slots__ = '_display', '_events', '_buffer', '_handlers'
def __init__(self, display):
self._display = display
self._events = create_events(display)
self._buffer = buffer(Event, _max_events)
self._handlers = [[] for _ in range(_max_type + 1)]
def __del__(self):
destroy_events(self._display, self._events)
def register(self, type, handler):
assert type <= _max_type
self._handlers[type].append(handler)
def update(self):
nevents = consume_events(self._events, self._buffer, _max_events)
if nevents:
for event in self._buffer[:nevents]:
data = event.data
for handler in self._handlers[event.type]:
handler(data)

View File

@ -28,15 +28,15 @@ from game.resources import RuntimeArchive
from game.batch import Batch from game.batch import Batch
from game.camera import Camera from game.camera import Camera
from game.environment import Environment from game.environment import Environment
from game.events import Events
from game.mouse import Mouse
from game.keyboard import Keyboard
proj_hfov = pi * 0.25 proj_hfov = pi * 0.25
proj_ratio = 16.0 / 9.0 proj_ratio = 16.0 / 9.0
proj_near_z = 8.0 proj_near_z = 8.0
proj_far_z = 3000.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_direction = math.vec3_normalize((1.0, 0.0, 1.0))
sun_power = 1.0 sun_power = 1.0
@ -48,10 +48,8 @@ def main():
print("Done: ", round(gen_end - gen_begin, 2), "seconds") print("Done: ", round(gen_end - gen_begin, 2), "seconds")
print("Initializing...") print("Initializing...")
display = create_display(b'RK Island - Drag to rotate, wheel to zoom, q to quit', 1600, 900) display = create_display(b'RK Island', 1600, 900)
events = Events(display) events = create_events(display)
mouse = Mouse(events, wheel = 60, wheel_min = 20)
keyboard = Keyboard(events)
render_initialize() render_initialize()
terrain_shader = shader.load('terrain', 'common') terrain_shader = shader.load('terrain', 'common')
tests_shader = shader.load('tests', 'common') tests_shader = shader.load('tests', 'common')
@ -159,7 +157,7 @@ def main():
cube_orientation = tests_batch.params[cube_id].orientation cube_orientation = tests_batch.params[cube_id].orientation
clouds_orientation = tests_batch.params[clouds_id].orientation clouds_orientation = tests_batch.params[clouds_id].orientation
print("Running... Ctrl+c to quit") print("Running... Click or press q to quit")
start_time = time.monotonic() start_time = time.monotonic()
current_time = 0.0 current_time = 0.0
frame_min = 10000.0 frame_min = 10000.0
@ -169,21 +167,22 @@ def main():
draw_max = 0.0 draw_max = 0.0
draw_avg = 0.0 draw_avg = 0.0
perf_count = 0 perf_count = 0
events_buffer = buffer(Event, 16)
try: try:
for frame in range(10000): for frame in range(10000):
current_time = time.monotonic() - start_time current_time = time.monotonic() - start_time
frame_begin = time.thread_time()
events.update()
if keyboard.quit:
break
begin_frame() begin_frame()
frame_begin = time.thread_time()
camera_distance = mouse.wheel * 20.0 rotation = mat3()
camera_yaw = mouse.drag[0] * 0.001 mat3_rotation(rotation, vec3_up, (current_time * 0.21) % tau)
camera_pitch = mouse.drag[1] * 0.001 + pi * 0.25 mat3_mul_vec3(blob_translation, rotation, blob_spawn_translation)
camera.set_view(camera_yaw, camera_pitch, camera_distance) 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)
camera.set_view(camera_origin, camera_lookat, vec3_up, (current_time * 0.05) % tau)
environment.from_sun(camera.view, sun_direction, sun_power) environment.from_sun(camera.view, sun_direction, sun_power)
select_shader(terrain_shader) select_shader(terrain_shader)
@ -202,13 +201,6 @@ def main():
unselect_texture(2, normalmap) unselect_texture(2, normalmap)
unselect_shader(terrain_shader) unselect_shader(terrain_shader)
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) select_shader(tests_shader)
camera.update_inputs(tests_camera_inputs) camera.update_inputs(tests_camera_inputs)
environment.update_inputs(tests_environment_inputs) environment.update_inputs(tests_environment_inputs)
@ -251,6 +243,23 @@ def main():
frame_avg += frame_ms frame_avg += frame_ms
perf_count += 1 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: except KeyboardInterrupt:
pass pass
@ -265,6 +274,10 @@ def main():
", avg =", round((frame_avg / perf_count) * 1000.0, 2), "ms") ", avg =", round((frame_avg / perf_count) * 1000.0, 2), "ms")
# seed 666 # 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 = 1.32 , avg = 0.27 ms # Draw * 9999 : min = 0.2 , max = 1.32 , avg = 0.27 ms
# Draw * 9999 : min = 0.2 , max = 1.34 , avg = 0.27 ms # Draw * 9999 : min = 0.2 , max = 1.34 , avg = 0.27 ms
@ -287,5 +300,5 @@ def main():
destroy_shader(tests_shader) destroy_shader(tests_shader)
destroy_shader(sky_shader) destroy_shader(sky_shader)
render_terminate() render_terminate()
del events destroy_events(display, events)
destroy_display(display) destroy_display(display)

View File

@ -1,27 +0,0 @@
# 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/>.
from engine import EVENT_KEY_PRESS
class Keyboard:
__slots__ = 'quit'
def __init__(self, events):
self.quit = False
events.register(EVENT_KEY_PRESS, self.key_press_handler)
def key_press_handler(self, data):
if data.key.character == 'q':
self.quit = True

View File

@ -1,52 +0,0 @@
# 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/>.
from engine import (
EVENT_BUTTON_PRESS, EVENT_BUTTON_RELEASE, EVENT_MOTION, BUTTON_LEFT, BUTTON_WHEEL_UP, BUTTON_WHEEL_DOWN)
class Mouse:
__slots__ = 'buttons', 'wheel', 'wheel_min', 'position', 'drag'
def __init__(self, events, wheel = 0, wheel_min = None):
self.buttons = 0
self.wheel = wheel
self.wheel_min = wheel_min
self.position = None
self.drag = (0, 0)
events.register(EVENT_BUTTON_PRESS, self.button_press_handler)
events.register(EVENT_BUTTON_RELEASE, self.button_release_handler)
events.register(EVENT_MOTION, self.motion_handler)
def button_press_handler(self, data):
button = data.button.index
self.buttons |= 1 << button
if button == BUTTON_WHEEL_UP:
self.wheel -= 1
if self.wheel_min is not None and self.wheel < self.wheel_min:
self.wheel = self.wheel_min
elif button == BUTTON_WHEEL_DOWN:
self.wheel += 1
def button_release_handler(self, data):
self.buttons &= ~(1 << data.button.index)
def motion_handler(self, data):
new_x = data.motion.x
new_y = data.motion.y
if self.position and (self.buttons & (1 << BUTTON_LEFT)):
prev_x, prev_y = self.position
prev_dx, prev_dy = self.drag
self.drag = (prev_dx + (new_x - prev_x), prev_dy + (new_y - prev_y))
self.position = (new_x, new_y)