Fix loop to be more accuratly timed, and added custom ruby libs inclusion setup
This commit is contained in:
@@ -4,3 +4,5 @@ build/*
|
||||
bin/*
|
||||
|
||||
.clangd
|
||||
|
||||
include/binding/ruby_compiled.h
|
||||
@@ -14,6 +14,7 @@ CXX := $(CCACHE) clang++
|
||||
CC := $(CCACHE) clang
|
||||
|
||||
# ---------------- SDL3 ----------------
|
||||
|
||||
SDL_CFLAGS := $(shell pkg-config --cflags sdl3 sdl3-ttf sdl3-image)
|
||||
SDL_LIBS_DEBUG := $(shell pkg-config --libs sdl3 sdl3-ttf sdl3-image)
|
||||
SDL_LIBS_RELEASE := $(shell pkg-config --libs sdl3 sdl3-ttf sdl3-image)
|
||||
@@ -42,9 +43,11 @@ PCH_CFLAGS_RELEASE := $(CFLAGS_RELEASE) -x c++-header
|
||||
|
||||
LIBS := ./libs/mruby/build/host/lib/libmruby.a
|
||||
|
||||
MGEM_DIR := ./libs/l_mgems
|
||||
|
||||
# ---------------- SOURCES ----------------
|
||||
|
||||
SRC := $(wildcard $(SRC_DIR)/*.cc) $(wildcard $(SRC_DIR)/**/*.cc)
|
||||
SRC := $(shell find $(SRC_DIR) -name "*.cc")
|
||||
|
||||
OBJ_DEBUG := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/debug/%.o,$(SRC))
|
||||
OBJ_RELEASE := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/release/%.o,$(SRC))
|
||||
@@ -54,13 +57,13 @@ DEP_RELEASE := $(OBJ_RELEASE:.o=.d)
|
||||
|
||||
# ---------------- TARGETS ----------------
|
||||
|
||||
.PHONY: all debug release clean setup
|
||||
.PHONY: all debug release clean setup mgems
|
||||
|
||||
all: debug
|
||||
|
||||
debug: $(TARGET_DEBUG)
|
||||
debug: mgems $(TARGET_DEBUG)
|
||||
|
||||
release: $(TARGET_RELEASE)
|
||||
release: mgems $(TARGET_RELEASE)
|
||||
|
||||
# ---------------- CLANGD ----------------
|
||||
|
||||
@@ -68,6 +71,11 @@ setup: setup.rb
|
||||
@echo "Setting up clangd configuration..."
|
||||
ruby setup.rb
|
||||
|
||||
# ---------------- MRB_MGEMS ----------------
|
||||
|
||||
mgems:
|
||||
$(MGEM_DIR)/compile.sh
|
||||
|
||||
# ---------------- PCH ----------------
|
||||
|
||||
$(PCH_DEBUG): $(INCLUDE_DIR)/pch.h
|
||||
|
||||
+12
-8
@@ -54,8 +54,7 @@ struct EImage : Element {
|
||||
Animation &animation = *animation_pool[animation_id];
|
||||
if (animation.frames.empty())
|
||||
return;
|
||||
|
||||
int frame_index = (int)((abs_time * animation.frame_rate) / 1000) % animation.frames.size();
|
||||
int frame_index = (int)((abs_time * animation.frame_rate) / 1e9) % animation.frames.size();
|
||||
window.draw(animation.frames[frame_index], position, z, rotation, scale, alpha);
|
||||
}
|
||||
};
|
||||
@@ -166,11 +165,11 @@ struct Scene {
|
||||
}
|
||||
|
||||
void update_scene(uint64_t delta_time) {
|
||||
if (!mrb_nil_p(update.proc)) {
|
||||
mrb_value dt_val = mrb_int_value(Ruby::mrb, delta_time);
|
||||
if (mrb_nil_p(update.proc))
|
||||
return;
|
||||
mrb_value dt_val = mrb_float_value(Ruby::mrb, delta_time / 1e9);
|
||||
update.call(1, &dt_val);
|
||||
}
|
||||
}
|
||||
|
||||
void click(Vec2<float> position) {
|
||||
std::vector<uint64_t> clicked_elements = elements_at(position);
|
||||
@@ -234,7 +233,7 @@ struct App {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
const uint64_t target_ms = 1000 / 60;
|
||||
const uint64_t TARGET_NS = 1e9 / 60;
|
||||
|
||||
uint64_t time_a = window.get_time();
|
||||
uint64_t time_b = window.get_time();
|
||||
@@ -242,8 +241,13 @@ struct App {
|
||||
while (running) {
|
||||
time_a = window.get_time();
|
||||
uint64_t frame_time = time_a - time_b;
|
||||
if (frame_time <= target_ms)
|
||||
usleep((target_ms - frame_time) * 1000);
|
||||
|
||||
if (frame_time <= TARGET_NS) {
|
||||
struct timespec req;
|
||||
req.tv_sec = 0;
|
||||
req.tv_nsec = TARGET_NS - frame_time;
|
||||
nanosleep(&req, nullptr);
|
||||
}
|
||||
|
||||
time_b = window.get_time();
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "pch.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "binding/ruby_compiled.h"
|
||||
|
||||
#define DEF_SYM(name) inline mrb_sym sym_##name = mrb_intern_cstr(Ruby::mrb, #name);
|
||||
#define SYM(name) mrb_symbol_value(sym_##name)
|
||||
|
||||
@@ -83,7 +85,15 @@ struct Block {
|
||||
};
|
||||
|
||||
inline void run_string(const char *code, size_t length) {
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
mrb_load_nstring(mrb, code, length);
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
}
|
||||
|
||||
inline void load_mgems() {
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
mrb_load_irep(mrb, mgems);
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
}
|
||||
}; // namespace Ruby
|
||||
|
||||
|
||||
@@ -341,8 +341,8 @@ public:
|
||||
|
||||
// Time
|
||||
|
||||
uint64_t get_time(); // returns the time in milliseconds since the window was created
|
||||
uint64_t delta_time(); // returns the time in milliseconds since the last render call
|
||||
uint64_t get_time(); // returns the time in nanoseconds since the window was created
|
||||
uint64_t delta_time(); // returns the time in nanoseconds since the last render call
|
||||
|
||||
private:
|
||||
// internal data and functions
|
||||
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
OUTPUT_TMP=$(mktemp)
|
||||
OUTPUT="$SCRIPT_DIR/../../include/binding/ruby_compiled.h"
|
||||
|
||||
if test "$1" = "clean"; then
|
||||
rm -f "$OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
trap 'rm -f "$OUTPUT_TMP"' EXIT
|
||||
|
||||
mapfile -t FILES < <(find "$SCRIPT_DIR" -name "*.rb" | sort)
|
||||
|
||||
LATEST_FILE_TIME=$(for file in "${FILES[@]}"; do
|
||||
echo $(stat -c "%Y" "$file")
|
||||
done | sort -n | tail -1)
|
||||
|
||||
OUTPUT_TIME=$(stat -c "%Y" "$OUTPUT" 2>/dev/null || echo 0)
|
||||
|
||||
if test "$OUTPUT_TIME" -ge "$LATEST_FILE_TIME"; then
|
||||
echo "mgems is up to date."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
"$SCRIPT_DIR/../mruby/bin/mrbc" -o "$OUTPUT_TMP" "${FILES[@]}"
|
||||
|
||||
{
|
||||
echo "#ifndef MGEMS_H"
|
||||
echo "#define MGEMS_H"
|
||||
xxd -i -n mgems $OUTPUT_TMP \
|
||||
| sed -e 's/^unsigned char /constexpr unsigned char /' \
|
||||
-e 's/^unsigned int /constexpr unsigned int /'
|
||||
echo "#endif"
|
||||
} > "$OUTPUT"
|
||||
|
||||
echo "Compiled mgems!"
|
||||
+1010
File diff suppressed because it is too large
Load Diff
+19
-8
@@ -22,6 +22,7 @@ rect.on_click do
|
||||
rect.color = rect.color == 0xFF0000 ?
|
||||
0x00FF00 :
|
||||
0xFF0000
|
||||
main_scene << text unless main_scene.elements.include?(text)
|
||||
text.params[:name] = text.params[:name] == "Me" ?
|
||||
"You" :
|
||||
"Me"
|
||||
@@ -30,35 +31,45 @@ end
|
||||
|
||||
App.map_key :mouse_left, :press
|
||||
|
||||
start = Time.now
|
||||
c_ = 0.0
|
||||
c_c = 0
|
||||
|
||||
main_scene.on_update do |delta_time|
|
||||
# puts "Delta time: #{delta_time}ms"
|
||||
c_ += delta_time
|
||||
c_c += 1
|
||||
|
||||
# puts "Delta time: #{delta_time}s"
|
||||
# commented out to avoid spamming the console, but you can uncomment to see the delta time being printed every frame
|
||||
# runs at 60fps, so you should see around 16-17ms being printed
|
||||
|
||||
el = main_scene.elements_at(App.mouse_position)
|
||||
|
||||
puts App.text_input if App.text_input != ""
|
||||
pp App.text_input if App.text_input != ""
|
||||
|
||||
next unless App.pressed?(:press)
|
||||
|
||||
puts "#{App.pressed?(:press)}, #{App.down?(:press)}, #{App.released?(:press)}"
|
||||
pp "#{App.pressed?(:press)}, #{App.down?(:press)}, #{App.released?(:press)}"
|
||||
|
||||
for elem in el
|
||||
if elem == image_element
|
||||
puts "Down over image element"
|
||||
pp "Down over image element"
|
||||
elsif elem == rect
|
||||
puts "Down over rect element"
|
||||
pp "Down over rect element"
|
||||
elsif elem == text
|
||||
puts "Down over text element"
|
||||
pp "Down over text element"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
main_scene << text
|
||||
main_scene << rect
|
||||
main_scene << image_element
|
||||
|
||||
# main_scene.delete(text) # Uncomment to test element deletion
|
||||
main_scene.delete(text)
|
||||
|
||||
App.start main_scene
|
||||
|
||||
p "Average delta time: #{c_ / c_c}s"
|
||||
p "Time since start (real): #{Time.now - start}s"
|
||||
p "Time since start (from dt): #{c_}s"
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "binding/definitions.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Ruby::load_mgems();
|
||||
definitions::setup();
|
||||
|
||||
char *startup_script = nullptr;
|
||||
|
||||
@@ -451,14 +451,17 @@ const char *Window::paste() {
|
||||
}
|
||||
|
||||
uint64_t Window::get_time() {
|
||||
return SDL_GetTicks();
|
||||
return SDL_GetTicksNS();
|
||||
}
|
||||
|
||||
uint64_t Window::delta_time() {
|
||||
static uint64_t last_time = 0;
|
||||
uint64_t current_time = SDL_GetTicks();
|
||||
static bool first_call = 1;
|
||||
uint64_t current_time = SDL_GetTicksNS();
|
||||
uint64_t delta = current_time - last_time;
|
||||
last_time = current_time;
|
||||
if (first_call)
|
||||
return (first_call = 0);
|
||||
return delta;
|
||||
}
|
||||
|
||||
|
||||
@@ -234,6 +234,7 @@ Other features that a game engine should have/has (need to go in depth)
|
||||
- audio playing
|
||||
- network interface, with a lib to work with rack backends (and generic socket api)
|
||||
- persistence store
|
||||
- rng helpers
|
||||
|
||||
## Embedded scripting language choice.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user