diff --git a/lua.c b/lua.c index f754987..0c9b9da 100644 --- a/lua.c +++ b/lua.c @@ -83,6 +83,7 @@ struct icelua_entry icelua_client[] = { {icelua_fn_client_model_render_bone_global, "model_render_bone_global"}, {icelua_fn_client_model_render_bone_local, "model_render_bone_local"}, {icelua_fn_client_img_blit, "img_blit"}, + {icelua_fn_client_img_blit_to, "img_blit_to"}, {NULL, NULL} }; diff --git a/lua_image.h b/lua_image.h index 6f394a8..14e546c 100644 --- a/lua_image.h +++ b/lua_image.h @@ -151,3 +151,31 @@ int icelua_fn_common_img_get_dims(lua_State *L) return 2; } + +int icelua_fn_client_img_blit_to(lua_State *L) +{ + int top = icelua_assert_stack(L, 4, 9); + int dx, dy, bw, bh, sx, sy; + uint32_t color; + + img_t *dest = lua_touserdata(L, 1); + if(dest == NULL || dest->udtype != UD_IMG) + return luaL_error(L, "not an image"); + img_t *source = lua_touserdata(L, 2); + if(source == NULL || source->udtype != UD_IMG) + return luaL_error(L, "not an image"); + + dx = lua_tointeger(L, 3); + dy = lua_tointeger(L, 4); + bw = (top < 5 ? source->head.width : lua_tointeger(L, 5)); + bh = (top < 6 ? source->head.height : lua_tointeger(L, 6)); + sx = (top < 7 ? 0 : lua_tointeger(L, 7)); + sy = (top < 8 ? 0 : lua_tointeger(L, 8)); + color = (top < 9 ? 0xFFFFFFFF : (uint32_t)lua_tointeger(L, 9)); + + render_blit_img(dest->pixels, dest->head.width, dest->head.height, + dest->head.width, + source, dx, dy, bw, bh, sx, sy, color); + + return 0; +} diff --git a/pkg/base/icegui/widgets.lua b/pkg/base/icegui/widgets.lua index 33b46df..5147bbe 100644 --- a/pkg/base/icegui/widgets.lua +++ b/pkg/base/icegui/widgets.lua @@ -1,12 +1,4 @@ --- look into actual drawing functionality!~ --- the client drawing code requires manual memory management: --- we have to allocate a buffer and draw pixels to it --- this code can't deal with that problem... --- lib_gui will have to provide a layer that takes the abstract APIs here and adds drawing functions --- on top. the abstract API can assist by adding a "dirty" flag so that cache management is straightforward. - -- sketch listener and collision system: --- rect and layers detection (derive layers from hierarchy) -- onDown onUp onMove onClick(down+up inside collision) onDrag(down inside collision, movement) onKeyboard -- when will mouse cursor be visible? important engine consideration! diff --git a/pkg/base/lib_gui.lua b/pkg/base/lib_gui.lua index 1a40d6c..fb858da 100644 --- a/pkg/base/lib_gui.lua +++ b/pkg/base/lib_gui.lua @@ -190,20 +190,27 @@ function gui_create_fixwidth_font(image, char_width, char_height, indexing_fn) -- print text with topleft at x, y, color c, string str function this.print(x, y, c, str, buffer) - buffer = buffer or client - local i for i=1,#str do local idx = this.indexing_fn(string.byte(str, i)) - buffer.img_blit(this.image, x, y, this.width, this.height, idx*this.width, 0, c) + if buffer == nil then + local temp = common.img_new(this.width, this.height) + client.img_blit_to(temp, this.image, 0, 0, this.width, this.height, + idx*this.width, 0, c) + common.img_pixel_set(temp, 0, 0, 0xFFFF0000) + client.img_blit(temp, x, y) + common.img_free(temp) + --client.img_blit(this.image, x, y, this.width, this.height, idx*this.width, 0, c) + else + client.img_blit_to(buffer, this.image, x, y, this.width, this.height, idx*this.width, 0, c) + end x = x + this.width end + local i end -- print a selection of precomputed text function this.print_precomputed(data, offx, offy, buffer) - buffer = buffer or client - for y=1,#data do for x=1,#data[y] do local char = data[y][x][1] @@ -211,8 +218,13 @@ function gui_create_fixwidth_font(image, char_width, char_height, indexing_fn) local px = data[y][x][3] + offx local py = data[y][x][4] + offy local c = data[y][x][5] - buffer.img_blit(this.image, px, py, this.width, this.height, - idx*this.width, 0, c) + if buffer == nil then + client.img_blit(this.image, px, py, this.width, this.height, + idx*this.width, 0, c) + else + client.img_blit_to(buffer, this.image, px, py, this.width, this.height, + idx*this.width, 0, c) + end end end @@ -354,24 +366,83 @@ function gui_create_scene(width, height) end function scene.textfield(options) - -- store a text buffer in here and its last render state in here... - -- define the width and height to be the width and height of the text... - -- additional formatting? local this = scene.display_object(options) - -- if we specified width and height in options, we are implicitly using wordwrapping? - -- no... + this.wordwrap = options.wordwrap or true + this.color = options.color or 0xFF88FF88 + this.autosize = options.autosize or true + this.font = options.font or font_mini + this.use_img = true + + -- so, we are computing the text around offset 0, 0 + -- but when we go to display or collide with it, we're going to have to + -- apply the widget offsets on top. + + -- TODO: cursor + text selection collision, data structure, rendering + -- TODO: compute_unwrapped should allow new lines... + -- TODO: check to see if the draw-to-buffer method I made is actually any good + + function this.setter_keys.width(w) + if this.autosize == false then + rawset(this, 'width', w) + end + end + + function this.setter_keys.height(h) + if this.autosize == false then + rawset(this, 'height', h) + end + end + + function this._recalc_size() + if this.wordwrap == true then + this.text_cache = this.font.compute_wordwrap(this.width, + 0, 0, this.color, this._text) + else + this.text_cache = this.font.compute_unwrapped(0, 0, + this.color, this._text) + end + if this.autosize then + local dim = this.font.dimensions(this.text_cache) + rawset(this, 'width', dim.width) + rawset(this, 'height', dim.height) + end + this.dirty = true + end + + function this.getter_keys.text() + return this._text + end + + function this.setter_keys.text(str) + this._text = str + this._recalc_size() + end + + function this.draw_update() + this.font.print_precomputed(this.text_cache, 0, 0, this.img) + common.img_pixel_set(this.img, 0, 0, 0xFFFF0000) + common.img_pixel_set(this.img, 1, 0, 0xFFFF0000) + common.img_pixel_set(this.img, 0, 1, 0xFFFF0000) + common.img_pixel_set(this.img, 1, 1, 0xFFFF0000) + end + + this.text = options.text or "" + + return this end -- TEST CODE - --local frame = scene.rect_frame{width=320,height=320, x=width/2, y=height/2} - --local frame2 = scene.rect_frame{width=32,height=32, x=0, y=0} - --local frame3 = scene.rect_frame{width=32,height=32, x=64, y=96} + local frame = scene.rect_frame{width=320,height=320, x=width/2, y=height/2} + local frame2 = scene.rect_frame{width=32,height=32, x=0, y=0} + local frame3 = scene.rect_frame{width=32,height=32, x=64, y=96} + local text1 = scene.textfield{width=400,height=100, text="hello world"} --root.add_child(frame) --frame.add_child(frame2) --frame.add_child(frame3) + root.add_child(text1) return scene