Compare commits

..

2 Commits

Author SHA1 Message Date
0d3c8106cf Merge branch 'main' of git.ktj.st:katajisto/trueno 2025-05-02 12:12:52 +03:00
3550f52530 working text input 2025-05-02 12:11:41 +03:00
14 changed files with 113 additions and 5322 deletions

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
.DS_Store .DS_Store
.build/ .build/
dist/
first

79
dist/index.html vendored
View File

@ -1,79 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta charset="UTF-8"/>
<title>${name}</title>
<style type="text/css">
body {
margin: 0;
background-color: black;
}
.game-title {
pointer-events: none;
position: absolute;
bottom: 10px;
margin-top: 0px;
padding-left: 10px;
color: white;
text-decoration: none;
z-index: 1;
text-align: left;
font-family: "Arial Black", Gadget, sans-serif;
font-size: 30px;
}
.game-menu-item {
pointer-events: auto;
font-size: 18px;
padding-left: 10px;
font-family: Arial, Helvetica, sans-serif;
}
.game-menu-link {
text-decoration: none;
color: white;
}
.game {
position: absolute;
top: 0px;
left: 0px;
margin: 0px;
border: 0;
width: 100%;
height: 100%;
overflow: hidden;
display: block;
image-rendering: optimizeSpeed;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: optimize-contrast;
image-rendering: crisp-edges;
image-rendering: pixelated;
-ms-interpolation-mode: nearest-neighbor;
}
</style>
</head>
<body style="background:black">
<div class="game-title">${name}
<span class="game-menu-item"><a class="game-menu-link" href="index.html">home</a></span>
</div>
<canvas class="game" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
<script type="text/javascript">
var Module = {
onRuntimeInitialized: function () {
const originalSet = HEAPU8.set.bind(HEAPU8);
HEAPU8.set = function(array, offset) {
if (typeof offset === 'bigint') {
offset = Number(offset);
}
return originalSet(array, offset);
};
},
preRun: [],
print: (...args) => console.log('[stdout]: ' + args.join(' ')),
printErr: (...args) => console.log('[stderr]: ' + args.join(' ')),
};
window.onerror = (event) => console.log('[onerror]: ' + event.message);
</script>
<script async type="text/javascript" src="index.js"></script>
</body>
</html>

4927
dist/index.js vendored

File diff suppressed because it is too large Load Diff

BIN
dist/index.wasm vendored

Binary file not shown.

BIN
dist/main.o vendored

Binary file not shown.

Binary file not shown.

BIN
first

Binary file not shown.

8
modules/Clipboard.jai Normal file
View File

@ -0,0 +1,8 @@
// @ToDo: implement clipboard with sokol -ktjst
os_clipboard_get_text :: () -> string {
return "";
}
os_clipboard_set_text :: (s : string) {
}

View File

@ -87,6 +87,28 @@ get_key_code_for_mouse :: (mb: sapp_mousebutton) -> Key_Code {
return .UNKNOWN; return .UNKNOWN;
} }
add_modifier_info :: (sokol_event: *sapp_event, event: *Event) {
if sokol_event.modifiers & MODIFIER_SHIFT {
event.modifier_flags.shift_pressed = true;
}
if sokol_event.modifiers & MODIFIER_CTRL {
event.modifier_flags.ctrl_pressed = true;
}
if sokol_event.modifiers & MODIFIER_ALT {
event.modifier_flags.alt_pressed = true;
}
if sokol_event.modifiers & MODIFIER_SUPER {
event.modifier_flags.cmd_meta_pressed = true;
}
}
modifiers_cause_char_event_ignore :: (sokol_event: *sapp_event) -> bool {
if sokol_event.modifiers & MODIFIER_CTRL then return true;
if sokol_event.modifiers & MODIFIER_ALT then return true;
if sokol_event.modifiers & MODIFIER_SUPER then return true;
return false;
}
#scope_export #scope_export
handle_sokol_event :: (event: *sapp_event) { handle_sokol_event :: (event: *sapp_event) {
@ -97,12 +119,14 @@ handle_sokol_event :: (event: *sapp_event) {
new_event.type = .KEYBOARD; new_event.type = .KEYBOARD;
new_event.key_code = mapped; new_event.key_code = mapped;
new_event.key_pressed = 1; new_event.key_pressed = 1;
add_modifier_info(event, *new_event);
input_button_states[mapped] = .START | .DOWN; input_button_states[mapped] = .START | .DOWN;
case .KEY_UP; case .KEY_UP;
mapped := get_key_code(event.key_code); mapped := get_key_code(event.key_code);
new_event.type = .KEYBOARD; new_event.type = .KEYBOARD;
new_event.key_code = mapped; new_event.key_code = mapped;
new_event.key_pressed = 0; new_event.key_pressed = 0;
add_modifier_info(event, *new_event);
input_button_states[mapped] = .END; input_button_states[mapped] = .END;
case .MOUSE_DOWN; case .MOUSE_DOWN;
mapped := get_key_code_for_mouse(event.mouse_button); mapped := get_key_code_for_mouse(event.mouse_button);
@ -117,6 +141,7 @@ handle_sokol_event :: (event: *sapp_event) {
new_event.key_pressed = 0; new_event.key_pressed = 0;
input_button_states[mapped] = .END; input_button_states[mapped] = .END;
case .CHAR; case .CHAR;
if modifiers_cause_char_event_ignore(event) then return;
new_event.type = .TEXT_INPUT; new_event.type = .TEXT_INPUT;
new_event.utf32 = event.char_code; new_event.utf32 = event.char_code;
case .FOCUSED; case .FOCUSED;
@ -133,274 +158,6 @@ handle_sokol_event :: (event: *sapp_event) {
array_add(*events_this_frame, new_event); array_add(*events_this_frame, new_event);
} }
// using Key_Code;
// input_per_frame_event_and_flag_update();
// display := x_global_display;
// XLockDisplay(display);
// key_press_repeat := false;
// while XPending(display) {
// xev: XEvent;
// XNextEvent(display, *xev);
// if XFilterEvent(*xev, None) continue;
// if xev.type == {
// case ClientMessage;
// message_type := xev.xclient.message_type;
// if message_type == XdndEnter {
// drop_handled := maybe_handle_xdnd_drop_events(display, *xev, *drop_info);
// if drop_handled continue;
// } else if message_type == x_global_wm_protocols {
// message0 := cast(Atom) xev.xclient.data.l[0];
// // This can't be a switch, because the values are not constant!
// // Except come on guys, every single implementation of X11 in the universe
// // is going to agree on these values. Why are we pretending they are not constant?
// // How about if we just look them up once and then hardcode them into this program?
// // We'd save startup time...
// if message0 == x_global_wm_delete_window {
// event: Event;
// event.type = .QUIT;
// array_add(*events_this_frame, event);
// }
// }
// case KeyPress;
// event: Event;
// shift: u32;
// if xev.xkey.state & ShiftMask
// shift = 1;
// if xev.xkey.state & ControlMask
// event.ctrl_pressed = true;
// if xev.xkey.state & Mod1Mask
// event.alt_pressed = true;
// status: Status;
// keysym: KeySym;
// text: [16]u32;
// lookup_count := XwcLookupString(x_global_input_context, *xev.xkey, xx text.data, xx text.count, *keysym, *status);
// has_keysym := (status == XLookupKeySym || status == XLookupBoth);
// has_text := (status == XLookupChars || status == XLookupBoth);
// if has_keysym {
// if xev.xkey.state & ShiftMask event.shift_pressed = true;
// if xev.xkey.state & ControlMask event.ctrl_pressed = true;
// if xev.xkey.state & Mod1Mask event.alt_pressed = true;
// if xev.xkey.state & Mod4Mask event.cmd_meta_pressed = true;
// event.type = .KEYBOARD;
// event.key_pressed = 1;
// event.key_code = get_key_code(keysym);
// for 0..lookup_count - 1 {
// utf32 := text[it];
// if utf32 >= 32 && utf32 != 127 event.text_input_count += 1;
// }
// if event.key_code == {
// case .SHIFT; event.shift_pressed = true;
// case .CTRL; event.ctrl_pressed = true;
// case .ALT; event.alt_pressed = true;
// case .META; event.cmd_meta_pressed = true;
// }
// event.repeat = key_press_repeat;
// key_press_repeat = false;
// array_add(*events_this_frame, event);
// input_button_states[event.key_code] = .START | .DOWN;
// }
// event.shift_pressed = cast(bool) shift;
// if has_text {
// for 0..lookup_count - 1 {
// utf32 := text[it];
// if utf32 < 32 || utf32 == 127 continue;
// char_event: Event;
// char_event.type = .TEXT_INPUT;
// char_event.key_pressed = 1;
// char_event.key_code = get_key_code(keysym);
// char_event.utf32 = utf32;
// array_add(*events_this_frame, char_event);
// }
// }
// case KeyRelease;
// // For some odd reason X11 generates KeyRelease followed by a near identical KeyPress to simulate repeat events so we have to filter that out
// if XEventsQueued(display, QueuedAfterReading) {
// nev: XEvent;
// XPeekEvent(display, *nev);
// if nev.type == KeyPress
// && nev.xkey.time == xev.xkey.time
// && nev.xkey.keycode == xev.xkey.keycode {
// // This is a repeat, so we ignore the KeyRelease and set the repeat flag.
// key_press_repeat = true;
// continue;
// }
// }
// event: Event;
// shift: u32;
// if xev.xkey.state & ShiftMask
// shift = 1;
// if xev.xkey.state & ControlMask
// event.ctrl_pressed = true;
// if xev.xkey.state & Mod1Mask
// event.alt_pressed = true;
// keysym := XkbKeycodeToKeysym(display, xx xev.xkey.keycode, 0, 0 /* English lowercase group*/);
// event.type = .KEYBOARD;
// event.key_pressed = 0;
// event.shift_pressed = cast(bool) shift;
// event.key_code = get_key_code(keysym);
// input_button_states[event.key_code] = .END;
// array_add(*events_this_frame, event);
// case ButtonPress;
// event: Event;
// event.type = .KEYBOARD;
// event.key_pressed = 1;
// button := xev.xbutton.button;
// // 6/7 is horizontal/secondary wheel, don't handle it
// if (button == 6) || (button == 7) continue;
// // button 4/5 is mwheel up/down
// if (button == 4) || (button == 5) {
// event.type = .MOUSE_WHEEL;
// event.typical_wheel_delta = WHEEL_DELTA;
// event.wheel_delta = event.typical_wheel_delta * ifx button & 1 then cast(s32) - 1 else 1;
// array_add(*events_this_frame, event);
// mouse_delta_z += event.wheel_delta;
// continue;
// }
// if button == Button1 {
// event.key_code = MOUSE_BUTTON_LEFT;
// } else if button == Button2 {
// event.key_code = MOUSE_BUTTON_MIDDLE;
// } else if button == Button3 {
// event.key_code = MOUSE_BUTTON_RIGHT;
// }
// input_button_states[event.key_code] = .START | .DOWN;
// array_add(*events_this_frame, event);
// case ButtonRelease;
// // it seems that mouse input doesnt generate repeat events so we dont have to peek the queue
// event: Event;
// event.type = .KEYBOARD;
// event.key_pressed = 0;
// button := xev.xbutton.button;
// if (button >= 4) && (button <= 7) continue; // No action on button release of mouse wheels.
// if button == Button1 {
// event.key_code = MOUSE_BUTTON_LEFT;
// } else if button == Button2 {
// event.key_code = MOUSE_BUTTON_MIDDLE;
// } else if button == Button3 {
// event.key_code = MOUSE_BUTTON_RIGHT;
// }
// input_button_states[event.key_code] = .END;
// array_add(*events_this_frame, event);
// case SelectionRequest;
// selreq := cast(*XSelectionRequestEvent) *xev;
// out: XEvent;
// selnot := cast(*XSelectionEvent) *out;
// selnot.type = SelectionNotify;
// selnot.requestor = selreq.requestor;
// selnot.selection = selreq.selection;
// selnot.target = selreq.target;
// selnot.time = selreq.time;
// selnot.property = None;
// if x_window_is_ours(x_global_display, selreq.owner) {
// if selreq.target == x_global_xa_utf8 {
// selnot.property = selreq.property;
// text_data := x_global_clipboard_buffer.text_data;
// XChangeProperty(selreq.display, selreq.requestor, selreq.property, selreq.target, 8, PropModeReplace,
// text_data.data, cast(s32) text_data.count);
// } else if selreq.target == x_global_xa_targets {
// selnot.property = selreq.property;
// atoms: [..] Atom;
// array_add(*atoms, x_global_xa_utf8);
// array_add(*atoms, x_global_xa_targets);
// array_add(*atoms, x_global_xa_multiple);
// if x_global_clipboard_buffer.rgb_data {
// array_add(*atoms, x_global_image_bmp);
// }
// XChangeProperty(selreq.display, selreq.requestor, selreq.property, x_global_xa_atom, 32, PropModeReplace,
// xx atoms.data, cast(s32) atoms.count);
// array_reset(*atoms);
// } else if selreq.target == x_global_image_bmp {
// #import "stb_image_write";
// Data :: struct {
// _context: *#Context;
// data: [..] u8;
// }
// write_func :: (data_pointer: *void, _data: *void, size: s32) #c_call {
// data := cast(*Data) data_pointer;
// push_context data._context.* {
// data8 := cast(*u8) _data;
// for 0..size-1 {
// array_add(*data.data, data8[it]);
// }
// }
// }
// data: Data;
// data._context = *context;
// w := x_global_clipboard_buffer.width;
// h := x_global_clipboard_buffer.height;
// comp: s32 = 3;
// stride := x_global_clipboard_buffer.pitch;
// stbi_write_bmp_to_func(write_func, *data, w, h, comp, x_global_clipboard_buffer.rgb_data);
// selnot.property = selreq.property;
// XChangeProperty(selreq.display, selreq.requestor, selreq.property, selreq.target, 8, PropModeReplace,
// xx data.data.data, cast(s32) data.data.count);
// array_reset(*data.data);
// } else {
// // print("GOT REQ: %\n", to_string(XGetAtomName(x_global_display, selreq.target)));
// }
// }
// XSendEvent(selreq.display, selreq.requestor, True, 0, *out);
// case ConfigureNotify;
// config := cast(*XConfigureEvent) *xev;
// add_resize_record(config.window, config.width, config.height);
// case FocusIn;
// input_application_has_focus = true;
// case FocusOut;
// input_application_has_focus = false;
// }
// }
// XUnlockDisplay(display);
WHEEL_DELTA :: 120; WHEEL_DELTA :: 120;
/* /*

View File

@ -1,29 +1,3 @@
mpos : Vector2;
Queued_State_Set :: struct {
code : Input.Key_Code;
state : Input.Key_Current_State;
ticks : int;
};
state_set_queue : [..]Queued_State_Set;
state_set_queue_add :: (qss: Queued_State_Set) {
array_add(*state_set_queue, qss);
}
handle_event :: (e: *sapp_event) { handle_event :: (e: *sapp_event) {
handle_sokol_event(xx,force e); handle_sokol_event(xx,force e);
// if e.type == .MOUSE_MOVE {
// mpos.x = e.mouse_x;
// mpos.y = e.mouse_y;
// }
// if e.type == .MOUSE_DOWN {
// GR.set_state_for_key(Input.Key_Code.MOUSE_BUTTON_LEFT, .START);
// state_set_queue_add(.{Input.Key_Code.MOUSE_BUTTON_LEFT, .DOWN, 2});
// }
// if e.type == .MOUSE_UP {
// GR.set_state_for_key(Input.Key_Code.MOUSE_BUTTON_LEFT, .END);
// state_set_queue_add(.{Input.Key_Code.MOUSE_BUTTON_LEFT, .NONE, 2});
// }
} }

View File

@ -1,6 +1,13 @@
MAX_FILE_SIZE :: 200_000; MAX_FILE_SIZE :: 200_000;
buf : [MAX_FILE_SIZE]u8; buf : [MAX_FILE_SIZE]u8;
mandatory_done : bool = false;
init_after_mandatory_done : bool = false;
mandatory_loads_done :: () -> bool {
return mandatory_done;
}
init_font_loads :: () { init_font_loads :: () {
print("SENDING LOAD!!!!\n"); print("SENDING LOAD!!!!\n");
sfetch_send(*(sfetch_request_t.{ sfetch_send(*(sfetch_request_t.{
@ -16,5 +23,7 @@ init_font_loads :: () {
fontcb :: (res: *sfetch_response_t) #c_call { fontcb :: (res: *sfetch_response_t) #c_call {
push_context,defer_pop default_context; push_context,defer_pop default_context;
print("RDY! Finished? % Fetched? % \n", res.fetched, res.finished); print("RDY! Finished? % Fetched? % \n", res.fetched, res.finished);
state.font_default = fonsAddFontMem(state.fons, "sans", res.data.ptr, xx res.data.size, 0); state.font_default.fons_font = fonsAddFontMem(state.fons, "sans", res.data.ptr, xx res.data.size, 0);
ui_init_font_fields(*state.font_default);
mandatory_done = true;
} }

View File

@ -16,7 +16,7 @@ state: struct {
pass_action: sg_pass_action; pass_action: sg_pass_action;
dpi_scale: float; dpi_scale: float;
fons: *FONScontext; fons: *FONScontext;
font_default: s32; font_default: Ui_Font;
}; };
Window_Info :: struct { Window_Info :: struct {
@ -60,19 +60,30 @@ init :: () {
height = atlas_dim, height = atlas_dim,
})); }));
state.fons = fons_context; state.fons = fons_context;
state.font_default = FONS_INVALID; state.font_default.fons_font = FONS_INVALID;
create_pipelines(); create_pipelines();
state.pass_action.colors[0] = .{ load_action = .CLEAR, clear_value = .{ r = 0.5, g = 0.5, b = 0.9, a = 1 } }; state.pass_action.colors[0] = .{ load_action = .CLEAR, clear_value = .{ r = 0.5, g = 0.5, b = 0.9, a = 1 } };
init_ui();
init_font_loads(); init_font_loads();
} }
init_after_mandatory_loads :: () {
init_ui();
}
frame :: () { frame :: () {
dpis := state.dpi_scale;
sfetch_dowork(); sfetch_dowork();
if mandatory_loads_done() && !init_after_mandatory_done {
init_after_mandatory_loads();
init_after_mandatory_done = true;
}
if !mandatory_loads_done() then return;
dpis := state.dpi_scale;
fonsClearState(state.fons); fonsClearState(state.fons);
for event: Input.events_this_frame { for event: Input.events_this_frame {
GR.getrect_handle_event(event); GR.getrect_handle_event(event);

View File

@ -11,7 +11,7 @@ create_pipelines :: () {
create_arbtri_pipeline(); create_arbtri_pipeline();
} }
gArbtriMem : [1000*3*9]float; gArbtriMem : [100000*3*9]float;
create_arbtri_pipeline :: () { create_arbtri_pipeline :: () {
pipeline: sg_pipeline_desc; pipeline: sg_pipeline_desc;
@ -31,7 +31,7 @@ create_arbtri_pipeline :: () {
} }
}; };
pipeline.color_count = 4; pipeline.color_count = 1;
pipeline.colors[0] = color_state; pipeline.colors[0] = color_state;
gPipelines.arbtri.pipeline = sg_make_pipeline(*pipeline); gPipelines.arbtri.pipeline = sg_make_pipeline(*pipeline);

View File

@ -7,14 +7,30 @@ Ui_Font_Glyph :: struct {
}; };
Ui_Font :: struct { Ui_Font :: struct {
em_width: u32 = 1; em_width : int = 1;
character_height: u32 = 30; character_height : int = 30;
typical_descender: u32 = 1; typical_descender : int = 1;
typical_ascender: u32 = 1; typical_ascender : int = 1;
temporary_glyphs: [..]Ui_Font_Glyph; fons_font : s32 = 0;
temporary_glyphs : [..]Ui_Font_Glyph;
temporary_glyphs_byte_offsets : [..]u32; temporary_glyphs_byte_offsets : [..]u32;
}; };
ui_init_font_fields :: (font: *Ui_Font) {
m_str := "M";
fonsSetFont(state.fons, xx font.fons_font);
fonsSetSize(state.fons, xx font.character_height);
ascender, descender, line_h : float;
fonsVertMetrics(state.fons, *ascender, *descender, *line_h);
font.typical_descender = cast(int) descender;
font.typical_ascender = cast(int) (ascender * 0.85); // @stupid fix to make the ascender not be so big.
w := fonsTextBounds(state.fons, 0.0, 0.0, m_str.data, m_str.data + m_str.count, null);
font.em_width = xx w;
}
Ui_Texture :: struct { Ui_Texture :: struct {
tex: sg_image; tex: sg_image;
} }
@ -25,9 +41,9 @@ Ui_Rect :: struct {
Ui_Type_Indicator :: struct { Ui_Type_Indicator :: struct {
Texture : Type : Ui_Texture; Texture : Type : Ui_Texture;
Window_Type: Type : s32; Window_Type : Type : s32;
Font: Type: Ui_Font; Font : Type : Ui_Font;
Font_Effects: Type: u32; Font_Effects : Type : u32;
}; };
Font :: Ui_Font; Font :: Ui_Font;
@ -95,11 +111,24 @@ gPreppedText: string;
gPreppedTextWidth : s32; gPreppedTextWidth : s32;
prepare_text :: (font: *Ui_Type_Indicator.Font, text: string, effects: Ui_Type_Indicator.Font_Effects = 0) -> s64 { prepare_text :: (font: *Ui_Type_Indicator.Font, text: string, effects: Ui_Type_Indicator.Font_Effects = 0) -> s64 {
fonsSetFont(state.fons, state.font_default); fonsSetFont(state.fons, state.font_default.fons_font);
fonsSetSize(state.fons, xx font.character_height); fonsSetSize(state.fons, xx font.character_height);
w := fonsTextBounds(state.fons, 0.0, 0.0, text.data, text.data + text.count, null); w := fonsTextBounds(state.fons, 0.0, 0.0, text.data, text.data + text.count, null);
gPreppedText = text; gPreppedText = text;
gPreppedTextWidth = cast(s32) w; gPreppedTextWidth = cast(s32) w;
array_reset(*font.temporary_glyphs);
array_reset(*font.temporary_glyphs_byte_offsets);
for 0..(text.count-1) {
glyph : Ui_Font_Glyph;
glyph.advance = cast(u32) fonsTextBounds(state.fons, 0.0, 0.0, text.data + it, text.data + it + 1, null);
array_add(*font.temporary_glyphs, glyph);
array_add(*font.temporary_glyphs_byte_offsets, cast(u32) it);
}
return cast(s64) w; return cast(s64) w;
} }
draw_prepared_text :: (font: *Ui_Type_Indicator.Font, x: s64, y: s64, text_color: Vector4, effects: Ui_Type_Indicator.Font_Effects = 0) { draw_prepared_text :: (font: *Ui_Type_Indicator.Font, x: s64, y: s64, text_color: Vector4, effects: Ui_Type_Indicator.Font_Effects = 0) {
@ -115,8 +144,8 @@ get_mouse_pointer_position :: (window: Ui_Type_Indicator.Window_Type, right_hand
} }
get_font_at_size :: (memory: [] u8, pixel_height: int) -> *Font { get_font_at_size :: (memory: [] u8, pixel_height: int) -> *Font {
f : *Font = New(Font); f : *Font = New(Font);
// f.character_height = cast(u32) pixel_height; f.character_height = cast(u32) pixel_height;
// f.em_width = cast(u32) get_font_letter_width(109, cast (s32) pixel_height); ui_init_font_fields(f);
return f; return f;
} }
@ -202,8 +231,10 @@ get_font_at_size :: (pixel_height: int) -> *Font {
idk : bool; idk : bool;
test_color : Vector3 = .{1.0, 0.0, 1.0};
render_ui :: () { render_ui :: () {
proc := GR.default_theme_procs[3]; proc := GR.default_theme_procs[0];
my_theme := proc(); my_theme := proc();
GR.set_default_theme(my_theme); GR.set_default_theme(my_theme);
@ -220,6 +251,11 @@ render_ui :: () {
if GR.base_checkbox(r, "CHECK!!!", idk, null) { if GR.base_checkbox(r, "CHECK!!!", idk, null) {
idk = !idk; idk = !idk;
} }
r.y += 150;
r.h = 500;
GR.color_picker(r, *test_color);
} }