Skip to content

Commit c03bc9c

Browse files
committed
Add hit_test()
1 parent 0c04a27 commit c03bc9c

2 files changed

Lines changed: 103 additions & 14 deletions

File tree

src/material_text.c

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include "render_bindings.h"
1818
#include "tmpbuffer.h"
1919

20+
#define PIXEL_SCALE 256
21+
2022
struct text {
2123
struct draw_primitive_external header;
2224
int codepoint;
@@ -72,8 +74,8 @@ submit(lua_State *L, void *m_, struct draw_primitive *prim, int n) {
7274
// todo: support multiply srbuffer
7375
luaL_error(L, "sr buffer is full");
7476
}
75-
tmp[count].x = (float)p->x / 256.0f;
76-
tmp[count].y = (float)p->y / 256.0f;
77+
tmp[count].x = (float)p->x / PIXEL_SCALE;
78+
tmp[count].y = (float)p->y / PIXEL_SCALE;
7779
tmp[count].sr_index = (float)sr_index;
7880
++count;
7981
} else {
@@ -372,6 +374,8 @@ struct layout {
372374
int height;
373375
int top;
374376
int line_height;
377+
int line_gap;
378+
int text_height;
375379
int ascent;
376380
int decent;
377381
struct position pos[];
@@ -398,10 +402,10 @@ newline(struct block_context *ctx, struct text_primitive * prim, int n, struct l
398402
int align = ctx->alignment & ALIGNMENT_MASK;
399403
switch (align) {
400404
case ALIGNMENT_CENTER:
401-
offx = (ctx->width - line_width) / 2 * 256;
405+
offx = (ctx->width - line_width) / 2 * PIXEL_SCALE;
402406
break;
403407
case ALIGNMENT_RIGHT:
404-
offx = (ctx->width - line_width) * 256;
408+
offx = (ctx->width - line_width) * PIXEL_SCALE;
405409
break;
406410
}
407411

@@ -414,7 +418,7 @@ newline(struct block_context *ctx, struct text_primitive * prim, int n, struct l
414418
}
415419
if (pos != NULL) {
416420
for (i=from;i<n;i++) {
417-
pos->pos[i].x += offx / 256;
421+
pos->pos[i].x += offx / PIXEL_SCALE;
418422
}
419423
}
420424
}
@@ -502,8 +506,10 @@ ltext_(lua_State *L, int gen_layout) {
502506
pos->n = 0;
503507
pos->width = ctx.width;
504508
pos->height = ctx.height;
509+
pos->text_height = 0;
505510
pos->top = 0;
506511
pos->line_height = ctx.ascent + ctx.decent - gap;
512+
pos->line_gap = gap;
507513
pos->ascent = ctx.ascent;
508514
pos->decent = ctx.decent;
509515
} else {
@@ -557,8 +563,8 @@ ltext_(lua_State *L, int gen_layout) {
557563
}
558564

559565
if (prim) {
560-
prim[n].pos.x = ctx.x * 256;
561-
prim[n].pos.y = ctx.y * 256 + dy * 256;
566+
prim[n].pos.x = ctx.x * PIXEL_SCALE;
567+
prim[n].pos.y = ( ctx.y + dy ) * PIXEL_SCALE;
562568
prim[n].pos.sr = 0;
563569
prim[n].pos.sprite = -material_id;
564570
} else {
@@ -578,8 +584,8 @@ ltext_(lua_State *L, int gen_layout) {
578584
if (newline(&ctx, prim, n, pos))
579585
break;
580586
if (prim) {
581-
prim[n].pos.x = ctx.x * 256;
582-
prim[n].pos.y = ctx.y * 256 + dy * 256;
587+
prim[n].pos.x = ctx.x * PIXEL_SCALE;
588+
prim[n].pos.y = ( ctx.y + dy ) * PIXEL_SCALE;
583589
} else {
584590
struct position *p = &pos->pos[n];
585591
p->x = ctx.x;
@@ -614,10 +620,10 @@ ltext_(lua_State *L, int gen_layout) {
614620
int valign = ctx.alignment & VALIGNMENT_MASK;
615621
switch (valign) {
616622
case VALIGNMENT_CENTER:
617-
offy = (ctx.height - height) / 2 * 256;
623+
offy = (ctx.height - height) / 2 * PIXEL_SCALE;
618624
break;
619625
case VALIGNMENT_BOTTOM:
620-
offy = (ctx.height - height) * 256;
626+
offy = (ctx.height - height) * PIXEL_SCALE;
621627
break;
622628
default:
623629
offy = 0;
@@ -635,10 +641,10 @@ ltext_(lua_State *L, int gen_layout) {
635641
} else {
636642
if (n > 0)
637643
++n;
638-
pos->height = height;
644+
pos->text_height = height;
639645
pos->n = n;
640646
if (offy != 0) {
641-
int offset = offy / 256 - ctx.ascent;
647+
int offset = offy / PIXEL_SCALE - ctx.ascent;
642648
for (i=0;i<n;i++) {
643649
pos->pos[i].y += offset;
644650
}
@@ -679,6 +685,61 @@ ltext_cursor(lua_State *L) {
679685
return 6;
680686
}
681687

688+
static int
689+
get_pos(lua_State *L, int index) {
690+
int isnum;
691+
int r = lua_tointegerx (L, index, &isnum);
692+
if (isnum) {
693+
return r;
694+
}
695+
return (int)(luaL_checknumber(L, index) + 0.5);
696+
}
697+
698+
static int
699+
bsearch_pos(struct layout * pos, int x, int y) {
700+
int from = 0;
701+
int to = pos->n - 1;
702+
int advance_y = pos->line_height + pos->line_gap;
703+
while (from < to) {
704+
int mid = from + (to - from) / 2;
705+
struct position *p = &pos->pos[mid];
706+
if (y < p->y) {
707+
to = mid;
708+
} else if (y >= p->y + advance_y) {
709+
from = mid + 1;
710+
} else if (x < p->x) {
711+
to = mid;
712+
} else if (x >= p->x + p->w) {
713+
from = mid + 1;
714+
} else {
715+
return mid;
716+
}
717+
}
718+
return from;
719+
}
720+
721+
static int
722+
ltext_hit_test(lua_State *L) {
723+
struct layout * pos = (struct layout *)lua_touserdata(L, 1);
724+
int x = get_pos(L, 2);
725+
int y = get_pos(L, 3);
726+
int top = pos->top + pos->ascent;
727+
if (y < top) {
728+
lua_pushinteger(L, 0);
729+
lua_pushboolean(L, y < 0); // out of box
730+
return 2;
731+
}
732+
if (y - top >= pos->text_height) {
733+
lua_pushinteger(L, pos->n-1);
734+
lua_pushboolean(L, y >= pos->height); // out of box
735+
return 2;
736+
}
737+
int index = bsearch_pos(pos, x, y);
738+
lua_pushinteger(L, index);
739+
lua_pushboolean(L, (x < 0 || x >= pos->width));
740+
return 2;
741+
}
742+
682743
static uint32_t
683744
parse_alignment(lua_State *L, int index) {
684745
const char *alignment_string = lua_tostring(L, index);
@@ -764,6 +825,7 @@ luaopen_material_text(lua_State *L) {
764825
if (luaL_newmetatable(L, "SOLUNA_TEXT_LAYOUT")) {
765826
luaL_Reg meta[] = {
766827
{ "cursor", ltext_cursor },
828+
{ "hit_test", ltext_hit_test },
767829
{ NULL, NULL },
768830
};
769831
luaL_setfuncs(L, meta, 0);

test/text.lua

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,14 @@ local label_layout = layout(TEXT, WIDTH, HEIGHT)
6464

6565
local CURSOR_N = 0
6666

67-
function callback.frame(count)
67+
local function position()
6868
local x = (screen_w - WIDTH) / 2
6969
local y = (screen_h - HEIGHT) / 2
70+
return x, y
71+
end
72+
73+
function callback.frame(count)
74+
local x, y = position()
7075
batch:add(matquad.quad(WIDTH, HEIGHT, 0x400000ff), x, y)
7176
batch:add(label, x, y)
7277
-- cursor
@@ -87,4 +92,26 @@ function callback.key(keycode, state)
8792
end
8893
end
8994

95+
96+
local mouse_x = 0
97+
local mouse_y = 0
98+
99+
function callback.mouse_move(x, y)
100+
mouse_x = x
101+
mouse_y = y
102+
end
103+
104+
local MOUSE_LEFT <const> = 0
105+
local MOUSE_PRESS <const> = 1
106+
107+
function callback.mouse_button(button, state)
108+
if button ~= MOUSE_LEFT or state ~= MOUSE_PRESS then
109+
return
110+
end
111+
local x, y = position()
112+
x = mouse_x - x
113+
y = mouse_y - y
114+
CURSOR_N = label_layout:hit_test(x, y)
115+
end
116+
90117
return callback

0 commit comments

Comments
 (0)