aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Hanspeter Portner <dev@open-music-kontrollers.ch>2019-07-19 16:24:23 +0200
committerGravatar Hanspeter Portner <dev@open-music-kontrollers.ch>2019-07-19 16:24:23 +0200
commit47aa369d0e0788ef069d7bb5448e467d64f393eb (patch)
treeeebe84a6a818c6f6f4ba540f8e247a4395df352f
parent2af0ffccfad0a5e2398524b70f3fd224cd6489b7 (diff)
downloadtracker.lv2-47aa369d0e0788ef069d7bb5448e467d64f393eb.zip
tracker.lv2-47aa369d0e0788ef069d7bb5448e467d64f393eb.tar.gz
tracker.lv2-47aa369d0e0788ef069d7bb5448e467d64f393eb.tar.bz2
tracker.lv2-47aa369d0e0788ef069d7bb5448e467d64f393eb.tar.xz
Squashed 'subprojects/d2tk/' changes from c87e3dd..8d3a4dc
8d3a4dc Merge commit '14c56cc6b6881c65b1a10692ffcb64276bf6bacd' 14c56cc Squashed 'nanovg/' changes from 1fd049e..75dbf61 df63823 core/base: make bitmap surface premultiplied ARGB 8df0c1a core/base: finish implementing bitmap widget. 34dbdfd core: only store bitmap pointer in bitmap's body. 6a388b9 core: prototype bitmap primitive. 5841ebb prototype d2tk_base_image. 460ba8c add step argument to pane widget. 368fdd4 gitlab-ci: simplify. 66124ee gitlab-ci: add aarch64 compile target. 368e55d update mum to version 3, compile with -std=gnu11. 9c2db75 base: add d2tk_flowmatrix_get_{src,dst} methods. git-subtree-dir: subprojects/d2tk git-subtree-split: 8d3a4dcf9c65b399b90be1746856be02120c0d85
-rw-r--r--.gitlab-ci.yml5
-rw-r--r--VERSION2
-rw-r--r--d2tk/base.h20
-rw-r--r--d2tk/core.h6
-rw-r--r--example/example.c34
-rw-r--r--meson.build2
-rw-r--r--nanovg/src/nanovg.c5
-rw-r--r--nanovg/src/nanovg.h5
-rw-r--r--nanovg/src/nanovg_gl.h10
-rw-r--r--src/backend_cairo.c150
-rw-r--r--src/backend_nanovg.c139
-rw-r--r--src/base.c132
-rw-r--r--src/core.c28
-rw-r--r--src/core_internal.h17
-rw-r--r--src/mum.h45
-rw-r--r--test/base.c47
-rw-r--r--test/core.c90
17 files changed, 571 insertions, 166 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f8f8464..ec929aa 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -81,6 +81,11 @@ arm-linux-gnueabihf:
- apt-get install -y libglu1-mesa-dev:armhf libevdev-dev:armhf
<<: *arm_linux_definition
+aarch64-linux-gnu:
+ before_script:
+ - apt-get install -y libglu1-mesa-dev:arm64 libevdev-dev:arm64
+ <<: *arm_linux_definition
+
x86_64-w64-mingw32:
<<: *universal_w64_definition
diff --git a/VERSION b/VERSION
index 7428e76..105b719 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.717
+0.1.737
diff --git a/d2tk/base.h b/d2tk/base.h
index 2d4774f..547749b 100644
--- a/d2tk/base.h
+++ b/d2tk/base.h
@@ -221,7 +221,7 @@ d2tk_scrollbar_get_rect(d2tk_scrollbar_t *scrollbar);
D2TK_API d2tk_pane_t *
d2tk_pane_begin(d2tk_base_t *base, const d2tk_rect_t *rect, d2tk_id_t id,
- d2tk_flag_t flags, float fmin, float fmax, d2tk_pane_t *pane);
+ d2tk_flag_t flags, float fmin, float fmax, float fstep, d2tk_pane_t *pane);
D2TK_API bool
d2tk_pane_not_end(d2tk_pane_t *pane);
@@ -238,9 +238,9 @@ d2tk_pane_get_index(d2tk_pane_t *pane);
D2TK_API const d2tk_rect_t *
d2tk_pane_get_rect(d2tk_pane_t *pane);
-#define D2TK_BASE_PANE(BASE, RECT, ID, FLAGS, FMIN, FMAX, PANE) \
+#define D2TK_BASE_PANE(BASE, RECT, ID, FLAGS, FMIN, FMAX, FSTEP, PANE) \
for(d2tk_pane_t *(PANE) = d2tk_pane_begin((BASE), (RECT), \
- (ID), (FLAGS), (FMIN), (FMAX), alloca(d2tk_pane_sz)); \
+ (ID), (FLAGS), (FMIN), (FMAX), (FSTEP), alloca(d2tk_pane_sz)); \
d2tk_pane_not_end((PANE)); \
(PANE) = d2tk_pane_next((PANE)))
@@ -382,6 +382,14 @@ d2tk_base_toggle(d2tk_base_t *base, d2tk_id_t id, const d2tk_rect_t *rect,
#define d2tk_base_toggle_is_changed(...) \
d2tk_state_is_changed(d2tk_base_toggle(__VA_ARGS__))
+D2TK_API void
+d2tk_base_image(d2tk_base_t *base, ssize_t path_len, const char *path,
+ const d2tk_rect_t *rect, d2tk_align_t align);
+
+D2TK_API void
+d2tk_base_bitmap(d2tk_base_t *base, uint32_t w, uint32_t h, uint32_t stride,
+ const uint32_t *argb, const d2tk_rect_t *rect, d2tk_align_t align);
+
D2TK_API d2tk_state_t
d2tk_base_meter(d2tk_base_t *base, d2tk_id_t id, const d2tk_rect_t *rect,
const int32_t *value);
@@ -480,6 +488,12 @@ D2TK_API void
d2tk_flowmatrix_set_dst(d2tk_flowmatrix_t *flowmatrix, d2tk_id_t id,
const d2tk_pos_t *pos);
+D2TK_API d2tk_id_t
+d2tk_flowmatrix_get_src(d2tk_flowmatrix_t *flowmatrix, d2tk_pos_t *pos);
+
+D2TK_API d2tk_id_t
+d2tk_flowmatrix_get_dst(d2tk_flowmatrix_t *flowmatrix, d2tk_pos_t *pos);
+
D2TK_API d2tk_flowmatrix_node_t *
d2tk_flowmatrix_node_begin(d2tk_base_t *base, d2tk_flowmatrix_t *flowmatrix,
d2tk_pos_t *pos, d2tk_flowmatrix_node_t *node);
diff --git a/d2tk/core.h b/d2tk/core.h
index 1fec3f2..586de73 100644
--- a/d2tk/core.h
+++ b/d2tk/core.h
@@ -169,10 +169,14 @@ d2tk_core_text(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
const char *text, d2tk_align_t align);
D2TK_API void
-d2tk_core_image(d2tk_core_t *core, d2tk_rect_t *rect, size_t sz,
+d2tk_core_image(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
const char *path, d2tk_align_t align);
D2TK_API void
+d2tk_core_bitmap(d2tk_core_t *core, const d2tk_rect_t *rect, uint32_t w,
+ uint32_t h, uint32_t stride, const uint32_t *argb, d2tk_align_t align);
+
+D2TK_API void
d2tk_core_stroke_width(d2tk_core_t *core, d2tk_coord_t width);
D2TK_API void
diff --git a/example/example.c b/example/example.c
index caaea41..f41c4eb 100644
--- a/example/example.c
+++ b/example/example.c
@@ -89,7 +89,7 @@ static const char *bar_lbl [BAR_MAX] = {
static inline void
_render_c_mix(d2tk_base_t *base, const d2tk_rect_t *rect)
{
-#define N 12
+#define N 14
#define M 24
static val_t value [N*M];
@@ -212,6 +212,21 @@ _render_c_mix(d2tk_base_t *base, const d2tk_rect_t *rect)
}
#undef NITMS
} break;
+ case 12:
+ {
+ d2tk_base_image(base, -1, "libre-gui-folder.png", bnd,
+ D2TK_ALIGN_CENTERED);
+ } break;
+ case 13:
+ {
+ static const uint32_t argb [4] = {
+ 0xffff0000, 0x7f007f00,
+ 0x00000000, 0x3f3f3f00
+ };
+
+ d2tk_base_bitmap(base, 2, 2, 2*sizeof(uint32_t), argb, bnd,
+ D2TK_ALIGN_CENTERED);
+ } break;
default:
{
// nothing to do
@@ -425,7 +440,7 @@ _render_c_scroll(d2tk_base_t *base, const d2tk_rect_t *rect)
static inline void
_render_c_pane(d2tk_base_t *base, const d2tk_rect_t *rect)
{
- D2TK_BASE_PANE(base, rect, D2TK_ID, D2TK_FLAG_PANE_X, 0.1f, 0.9f, hpane)
+ D2TK_BASE_PANE(base, rect, D2TK_ID, D2TK_FLAG_PANE_X, 0.1f, 0.9f, 0.1f, hpane)
{
const unsigned x = d2tk_pane_get_index(hpane);
const d2tk_rect_t *hrect = d2tk_pane_get_rect(hpane);
@@ -442,7 +457,8 @@ _render_c_pane(d2tk_base_t *base, const d2tk_rect_t *rect)
}
// 2nd
- D2TK_BASE_PANE(base, hrect, D2TK_ID, D2TK_FLAG_PANE_Y, 0.25f, 0.75f, vpane)
+ D2TK_BASE_PANE(base, hrect, D2TK_ID, D2TK_FLAG_PANE_Y, 0.25f, 0.75f, 0.125f,
+ vpane)
{
const unsigned y = d2tk_pane_get_index(vpane);
const d2tk_rect_t *vrect = d2tk_pane_get_rect(vpane);
@@ -598,14 +614,22 @@ _render_c_flowmatrix(d2tk_base_t *base, const d2tk_rect_t *rect)
state = d2tk_base_toggle_label(base, id, lbl_len, lbl, bnd, val);
if(d2tk_state_is_active(state))
{
- fprintf(stderr, "Connecting from node %u\n", i);
d2tk_flowmatrix_set_src(flowm, id, &pos_nodes[i]);
}
if(d2tk_state_is_over(state))
{
- fprintf(stderr, "Connecting to node %u\n", i);
d2tk_flowmatrix_set_dst(flowm, id, &pos_nodes[i]);
}
+ if(d2tk_state_is_up(state))
+ {
+ const d2tk_id_t dst_id = d2tk_flowmatrix_get_dst(flowm, NULL);
+
+ if(dst_id)
+ {
+ fprintf(stderr, "Connecting nodes %016"PRIx64" -> %016"PRIx64"\n",
+ id, dst_id);
+ }
+ }
state = D2TK_STATE_NONE;
//else if(d2tk_state_is_changed(state))
//{
diff --git a/meson.build b/meson.build
index b11bb64..4e1f4dd 100644
--- a/meson.build
+++ b/meson.build
@@ -3,7 +3,7 @@ project('d2tk', 'c', default_options : [
'warning_level=3',
'werror=false',
'b_lto=false',
- 'c_std=c11'])
+ 'c_std=gnu11'])
static_link = false #meson.is_cross_build()
build_debug = get_option('build-debug')
diff --git a/nanovg/src/nanovg.c b/nanovg/src/nanovg.c
index 1ab49f0..f82f76c 100644
--- a/nanovg/src/nanovg.c
+++ b/nanovg/src/nanovg.c
@@ -829,6 +829,11 @@ int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsi
return ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_RGBA, w, h, imageFlags, data);
}
+int nvgCreateImageARGB(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data)
+{
+ return ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ARGB, w, h, imageFlags, data);
+}
+
void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data)
{
int w, h;
diff --git a/nanovg/src/nanovg.h b/nanovg/src/nanovg.h
index 2255d6a..e3d7ee1 100644
--- a/nanovg/src/nanovg.h
+++ b/nanovg/src/nanovg.h
@@ -379,6 +379,10 @@ int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int
// Returns handle to the image.
int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data);
+// Creates image from specified image data.
+// Returns handle to the image.
+int nvgCreateImageARGB(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data);
+
// Updates image data specified by image handle.
void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data);
@@ -618,6 +622,7 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa
enum NVGtexture {
NVG_TEXTURE_ALPHA = 0x01,
NVG_TEXTURE_RGBA = 0x02,
+ NVG_TEXTURE_ARGB = 0x03,
};
struct NVGscissor {
diff --git a/nanovg/src/nanovg_gl.h b/nanovg/src/nanovg_gl.h
index 5292181..75d51e9 100644
--- a/nanovg/src/nanovg_gl.h
+++ b/nanovg/src/nanovg_gl.h
@@ -753,6 +753,8 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im
if (type == NVG_TEXTURE_RGBA)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ else if (type == NVG_TEXTURE_ARGB)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data);
else
#if defined(NANOVG_GLES2) || defined (NANOVG_GL2)
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
@@ -837,6 +839,8 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w
// No support for all of skip, need to update a whole row at a time.
if (tex->type == NVG_TEXTURE_RGBA)
data += y*tex->width*4;
+ else if (tex->type == NVG_TEXTURE_ARGB)
+ data += y*tex->width*4;
else
data += y*tex->width;
x = 0;
@@ -845,6 +849,8 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w
if (tex->type == NVG_TEXTURE_RGBA)
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ else if (tex->type == NVG_TEXTURE_ARGB)
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGRA, GL_UNSIGNED_BYTE, data);
else
#if defined(NANOVG_GLES2) || defined(NANOVG_GL2)
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
@@ -948,11 +954,15 @@ static int glnvg__convertPaint(GLNVGcontext* gl, GLNVGfragUniforms* frag, NVGpai
#if NANOVG_GL_USE_UNIFORMBUFFER
if (tex->type == NVG_TEXTURE_RGBA)
frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0 : 1;
+ else if (tex->type == NVG_TEXTURE_ARGB)
+ frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0 : 1;
else
frag->texType = 2;
#else
if (tex->type == NVG_TEXTURE_RGBA)
frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0.0f : 1.0f;
+ else if (tex->type == NVG_TEXTURE_ARGB)
+ frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0.0f : 1.0f;
else
frag->texType = 2.0f;
#endif
diff --git a/src/backend_cairo.c b/src/backend_cairo.c
index 8d0905b..9ab0f5b 100644
--- a/src/backend_cairo.c
+++ b/src/backend_cairo.c
@@ -233,6 +233,78 @@ _d2tk_cairo_free_font_face(void *data)
}
static inline void
+_d2tk_cairo_surf_draw(cairo_t *ctx, cairo_surface_t *surf, d2tk_coord_t xo,
+ d2tk_coord_t yo, d2tk_align_t align, const d2tk_rect_t *rect)
+{
+ const int W = cairo_image_surface_get_width(surf);
+ const int H = cairo_image_surface_get_height(surf);
+
+ d2tk_coord_t w = W;
+ d2tk_coord_t h = H;
+ float scale = 1.f;
+
+ if(h != rect->h)
+ {
+ scale = (float)rect->h / h;
+ w *= scale;
+ h = rect->h;
+ }
+
+ if(w > rect->w)
+ {
+ scale = (float)rect->w / w;
+ h *= scale;
+ w = rect->w;
+ }
+
+ d2tk_coord_t x = rect->x + xo;
+ d2tk_coord_t y = rect->y + yo;
+
+ if(align & D2TK_ALIGN_LEFT)
+ {
+ x += 0;
+ }
+ else if(align & D2TK_ALIGN_CENTER)
+ {
+ x += rect->w / 2;
+ x -= w / 2;
+ }
+ else if(align & D2TK_ALIGN_RIGHT)
+ {
+ x += rect->w;
+ x -= w;
+ }
+
+ if(align & D2TK_ALIGN_TOP)
+ {
+ y += 0;
+ }
+ else if(align & D2TK_ALIGN_MIDDLE)
+ {
+ y += rect->h / 2;
+ y -= h / 2;
+ }
+ else if(align & D2TK_ALIGN_BOTTOM)
+ {
+ y += rect->h;
+ y -= h;
+ }
+
+ const float scale_1 = 1.f / scale;
+ cairo_matrix_t matrix;
+ cairo_matrix_init_scale(&matrix, scale_1, scale_1);
+ cairo_matrix_translate(&matrix, -x, -y);
+
+ cairo_rectangle(ctx, x, y, w, h);
+ cairo_clip(ctx);
+
+ cairo_new_sub_path(ctx);
+ cairo_set_source_surface(ctx, surf, 0, 0);
+ cairo_pattern_set_matrix(cairo_get_source(ctx), &matrix);
+ cairo_paint(ctx);
+}
+
+static inline void
d2tk_cairo_process(void *data, d2tk_core_t *core, const d2tk_com_t *com,
d2tk_coord_t xo, d2tk_coord_t yo, const d2tk_clip_t *clip, unsigned pass)
{
@@ -611,72 +683,32 @@ d2tk_cairo_process(void *data, d2tk_core_t *core, const d2tk_com_t *com,
cairo_surface_t *surf = (cairo_surface_t *)*sprite;
assert(surf);
- const int W = cairo_image_surface_get_width(surf);
- const int H = cairo_image_surface_get_height(surf);
-
- d2tk_coord_t w = W;
- d2tk_coord_t h = H;
- float scale = 1.f;
-
- if(w > body->w)
- {
- scale = (float)body->w / w;
- h *= scale;
- w = body->w;
- }
-
- if(h > body->h)
- {
- scale = (float)body->h / h;
- w *= scale;
- h = body->h;
- }
+ _d2tk_cairo_surf_draw(ctx, surf, xo, yo, body->align,
+ &D2TK_RECT(body->x, body->y, body->w, body->h));
+ } break;
+ case D2TK_INSTR_BITMAP:
+ {
+ const d2tk_body_bitmap_t *body = &com->body->bitmap;
- d2tk_coord_t x = body->x + xo;
- d2tk_coord_t y = body->y + yo;
+ const size_t rgba_sz = body->surf.stride * body->surf.h;
+ const uint64_t hash = d2tk_hash(body->surf.argb, rgba_sz);
+ uintptr_t *sprite = d2tk_core_get_sprite(core, hash, SPRITE_TYPE_SURF);
+ assert(sprite);
- if(body->align & D2TK_ALIGN_LEFT)
- {
- x += 0;
- }
- else if(body->align & D2TK_ALIGN_CENTER)
- {
- x += body->w / 2;
- x -= w / 2;
- }
- else if(body->align & D2TK_ALIGN_RIGHT)
+ if(!*sprite)
{
- x += body->w;
- x -= w;
- }
+ cairo_surface_t *surf = cairo_image_surface_create_for_data(
+ (uint8_t *)body->surf.argb, CAIRO_FORMAT_ARGB32,
+ body->surf.w, body->surf.h, body->surf.stride);
- if(body->align & D2TK_ALIGN_TOP)
- {
- y += 0;
- }
- else if(body->align & D2TK_ALIGN_MIDDLE)
- {
- y += body->h / 2;
- y -= h / 2;
- }
- else if(body->align & D2TK_ALIGN_BOTTOM)
- {
- y += body->h;
- y -= h;
+ *sprite = (uintptr_t)surf;
}
- const float scale_1 = 1.f / scale;
- cairo_matrix_t matrix;
- cairo_matrix_init_scale(&matrix, scale_1, scale_1);
- cairo_matrix_translate(&matrix, -x, -y);
-
- cairo_rectangle(ctx, x, y, w, h);
- cairo_clip(ctx);
+ cairo_surface_t *surf = (cairo_surface_t *)*sprite;
+ assert(surf);
- cairo_new_sub_path(ctx);
- cairo_set_source_surface(ctx, surf, 0, 0);
- cairo_pattern_set_matrix(cairo_get_source(ctx), &matrix);
- cairo_paint(ctx);
+ _d2tk_cairo_surf_draw(ctx, surf, xo, yo, body->align,
+ &D2TK_RECT(body->x, body->y, body->w, body->h));
} break;
case D2TK_INSTR_STROKE_WIDTH:
{
diff --git a/src/backend_nanovg.c b/src/backend_nanovg.c
index 5e6352f..5d78813 100644
--- a/src/backend_nanovg.c
+++ b/src/backend_nanovg.c
@@ -344,6 +344,72 @@ d2tk_nanovg_sprite_free(void *data, uint8_t type, uintptr_t body)
}
static inline void
+_d2tk_nanovg_surf_draw(NVGcontext *ctx, int img, d2tk_coord_t xo,
+ d2tk_coord_t yo, d2tk_align_t align, const d2tk_rect_t *rect)
+{
+ int W, H;
+ nvgImageSize(ctx, img, &W, &H);
+
+ d2tk_coord_t w = W;
+ d2tk_coord_t h = H;
+ float scale = 1.f;
+
+ if(h != rect->h)
+ {
+ scale = (float)rect->h / h;
+ w *= scale;
+ h = rect->h;
+ }
+
+ if(w > rect->w)
+ {
+ scale = (float)rect->w / w;
+ h *= scale;
+ w = rect->w;
+ }
+
+ d2tk_coord_t x = rect->x + xo;
+ d2tk_coord_t y = rect->y + yo;
+
+ if(align & D2TK_ALIGN_LEFT)
+ {
+ x += 0;
+ }
+ else if(align & D2TK_ALIGN_CENTER)
+ {
+ x += rect->w / 2;
+ x -= w / 2;
+ }
+ else if(align & D2TK_ALIGN_RIGHT)
+ {
+ x += rect->w;
+ x -= w;
+ }
+
+ if(align & D2TK_ALIGN_TOP)
+ {
+ y += 0;
+ }
+ else if(align & D2TK_ALIGN_MIDDLE)
+ {
+ y += rect->h / 2;
+ y -= h / 2;
+ }
+ else if(align & D2TK_ALIGN_BOTTOM)
+ {
+ y += rect->h;
+ y -= h;
+ }
+
+ const NVGpaint bg = nvgImagePattern(ctx, x, y, w, h, 0, img, 1.f);
+ nvgBeginPath(ctx);
+ nvgRect(ctx, x, y, w, h);
+ nvgStrokeWidth(ctx, 0);
+ nvgFillPaint(ctx, bg);
+ nvgFill(ctx);
+}
+
+static inline void
d2tk_nanovg_process(void *data, d2tk_core_t *core, const d2tk_com_t *com,
d2tk_coord_t xo, d2tk_coord_t yo, const d2tk_clip_t *clip, unsigned pass)
{
@@ -665,66 +731,31 @@ d2tk_nanovg_process(void *data, d2tk_core_t *core, const d2tk_com_t *com,
const int img = *sprite;
assert(img);
- int W, H;
- nvgImageSize(ctx, img, &W, &H);
-
- d2tk_coord_t w = W;
- d2tk_coord_t h = H;
- float scale = 1.f;
-
- if(w > body->w)
- {
- scale = (float)body->w / w;
- h *= scale;
- w = body->w;
- }
-
- if(h > body->h)
- {
- scale = (float)body->h / h;
- w *= scale;
- h = body->h;
- }
+ _d2tk_nanovg_surf_draw(ctx, img, xo, yo, body->align,
+ &D2TK_RECT(body->x, body->y, body->w, body->h));
+ } break;
+ case D2TK_INSTR_BITMAP:
+ {
+ const d2tk_body_bitmap_t *body = &com->body->bitmap;
- d2tk_coord_t x = body->x + xo;
- d2tk_coord_t y = body->y + yo;
+ const size_t rgba_sz = body->surf.stride * body->surf.h;
+ const uint64_t hash = d2tk_hash(body->surf.argb, rgba_sz);
+ uintptr_t *sprite = d2tk_core_get_sprite(core, hash, SPRITE_TYPE_IMG);
+ assert(sprite);
- if(body->align & D2TK_ALIGN_LEFT)
- {
- x += 0;
- }
- else if(body->align & D2TK_ALIGN_CENTER)
- {
- x += body->w / 2;
- x -= w / 2;
- }
- else if(body->align & D2TK_ALIGN_RIGHT)
+ if(!*sprite)
{
- x += body->w;
- x -= w;
+ *sprite = nvgCreateImageARGB(ctx, body->surf.w, body->surf.h,
+ NVG_IMAGE_GENERATE_MIPMAPS | NVG_IMAGE_PREMULTIPLIED,
+ (const uint8_t *)body->surf.argb);
+ //TODO use nvgUpdateImage for changed content
}
- if(body->align & D2TK_ALIGN_TOP)
- {
- y += 0;
- }
- else if(body->align & D2TK_ALIGN_MIDDLE)
- {
- y += body->h / 2;
- y -= h / 2;
- }
- else if(body->align & D2TK_ALIGN_BOTTOM)
- {
- y += body->h;
- y -= h;
- }
+ const int img = *sprite;
+ assert(img);
- const NVGpaint bg = nvgImagePattern(ctx, x, y, w, h, 0, img, 1.f);
- nvgBeginPath(ctx);
- nvgRect(ctx, x, y, w, h);
- nvgStrokeWidth(ctx, 0);
- nvgFillPaint(ctx, bg);
- nvgFill(ctx);
+ _d2tk_nanovg_surf_draw(ctx, img, xo, yo, body->align,
+ &D2TK_RECT(body->x, body->y, body->w, body->h));
} break;
case D2TK_INSTR_STROKE_WIDTH:
{
diff --git a/src/base.c b/src/base.c
index 0bbbb8a..8bb0072 100644
--- a/src/base.c
+++ b/src/base.c
@@ -62,6 +62,8 @@ struct _d2tk_atom_body_flow_t {
d2tk_coord_t lx;
d2tk_coord_t ly;
float exponent;
+ d2tk_id_t src_id;
+ d2tk_id_t dst_id;
};
union _d2tk_atom_body_t {
@@ -181,8 +183,8 @@ struct _d2tk_flowmatrix_t {
d2tk_coord_t dd;
d2tk_coord_t r;
d2tk_coord_t s;
- d2tk_id_t src_id;
- d2tk_id_t dst_id;
+ bool src_conn;
+ bool dst_conn;
d2tk_pos_t src_pos;
d2tk_pos_t dst_pos;
};
@@ -1482,7 +1484,7 @@ _d2tk_draw_pane(d2tk_core_t *core, d2tk_state_t state, const d2tk_rect_t *sub,
D2TK_API d2tk_pane_t *
d2tk_pane_begin(d2tk_base_t *base, const d2tk_rect_t *rect, d2tk_id_t id,
- d2tk_flag_t flags, float fmin, float fmax, d2tk_pane_t *pane)
+ d2tk_flag_t flags, float fmin, float fmax, float fstep, d2tk_pane_t *pane)
{
pane->k = 0;
pane->rect[0] = *rect;
@@ -1536,38 +1538,30 @@ d2tk_pane_begin(d2tk_base_t *base, const d2tk_rect_t *rect, d2tk_id_t id,
{
if(d2tk_state_is_scroll_left(state))
{
- *fraction -= 0.1f;
+ *fraction -= fstep;
}
else if(d2tk_state_is_scroll_right(state))
{
- *fraction += 0.1f;
+ *fraction += fstep;
}
else if(d2tk_state_is_motion(state))
{
- d2tk_coord_t w;
-
- d2tk_base_get_dimensions(base, &w, NULL);
-
- *fraction = (float)base->mouse.x / w;
+ *fraction = roundf((float)(base->mouse.x - rect->x) / rect->w / fstep) * fstep;
}
}
else if(flags & D2TK_FLAG_PANE_Y)
{
if(d2tk_state_is_scroll_up(state))
{
- *fraction -= 0.1f;
+ *fraction -= fstep;
}
else if(d2tk_state_is_scroll_down(state))
{
- *fraction += 0.1f;
+ *fraction += fstep;
}
else if(d2tk_state_is_motion(state))
{
- d2tk_coord_t h;
-
- d2tk_base_get_dimensions(base, NULL, &h);
-
- *fraction = (float)base->mouse.y / h;
+ *fraction = roundf((float)(base->mouse.y - rect->y) / rect->h / fstep) * fstep;
}
}
@@ -1840,6 +1834,59 @@ d2tk_base_toggle(d2tk_base_t *base, d2tk_id_t id, const d2tk_rect_t *rect,
return d2tk_base_toggle_label(base, id, 0, NULL, rect, value);
}
+D2TK_API void
+d2tk_base_image(d2tk_base_t *base, ssize_t path_len, const char *path,
+ const d2tk_rect_t *rect, d2tk_align_t align)
+{
+ const bool has_img = path_len && path;
+
+ if(has_img && (path_len == -1) ) // zero-terminated string
+ {
+ path_len = strlen(path);
+ }
+
+ const uint64_t hash = d2tk_hash_foreach(rect, sizeof(d2tk_rect_t),
+ (path ? path : NULL), (path ? path_len : 0),
+ NULL);
+
+ d2tk_core_t *core = base->core;;
+
+ D2TK_CORE_WIDGET(core, hash, widget)
+ {
+ if(has_img)
+ {
+ const size_t ref = d2tk_core_bbox_push(core, true, rect);
+
+ d2tk_core_image(core, rect, path_len, path, align);
+
+ d2tk_core_bbox_pop(core, ref);
+ }
+ }
+}
+
+D2TK_API void
+d2tk_base_bitmap(d2tk_base_t *base, uint32_t w, uint32_t h, uint32_t stride,
+ const uint32_t *argb, const d2tk_rect_t *rect, d2tk_align_t align)
+{
+ const uint64_t hash = d2tk_hash_foreach(rect, sizeof(d2tk_rect_t),
+ &w, sizeof(uint32_t),
+ &h, sizeof(uint32_t),
+ &stride, sizeof(uint32_t),
+ argb, stride*h, //FIXME
+ NULL);
+
+ d2tk_core_t *core = base->core;;
+
+ D2TK_CORE_WIDGET(core, hash, widget)
+ {
+ const size_t ref = d2tk_core_bbox_push(core, true, rect);
+
+ d2tk_core_bitmap(core, rect, w, h, stride, argb, align);
+
+ d2tk_core_bbox_pop(core, ref);
+ }
+}
+
static inline void
_d2tk_base_draw_meter(d2tk_core_t *core, const d2tk_rect_t *rect,
d2tk_state_t state, int32_t value, const d2tk_style_t *style)
@@ -3067,8 +3114,8 @@ d2tk_flowmatrix_begin(d2tk_base_t *base, const d2tk_rect_t *rect, d2tk_id_t id,
flowmatrix->r = flowmatrix->scale * 4; //FIXME
flowmatrix->s = flowmatrix->scale * 20; //FIXME
- flowmatrix->src_id = 0;
- flowmatrix->dst_id = 0;
+ flowmatrix->src_conn = false;
+ flowmatrix->dst_conn = false;
d2tk_core_t *core = base->core;
flowmatrix->ref = d2tk_core_bbox_container_push(core, false, flowmatrix->rect);
@@ -3127,9 +3174,9 @@ d2tk_flowmatrix_next(d2tk_flowmatrix_t *flowmatrix)
d2tk_base_set_again(base);
}
- if(flowmatrix->src_id)
+ if(flowmatrix->src_conn)
{
- if(flowmatrix->dst_id)
+ if(flowmatrix->dst_conn)
{
_d2tk_flowmatrix_connect(base, flowmatrix, &flowmatrix->src_pos,
&flowmatrix->dst_pos);
@@ -3137,6 +3184,9 @@ d2tk_flowmatrix_next(d2tk_flowmatrix_t *flowmatrix)
else
{
_d2tk_flowmatrix_connect(base, flowmatrix, &flowmatrix->src_pos, NULL);
+
+ // invalidate dst_id
+ flowmatrix->atom_body->flow.dst_id = 0;
}
}
@@ -3160,16 +3210,48 @@ D2TK_API void
d2tk_flowmatrix_set_src(d2tk_flowmatrix_t *flowmatrix, d2tk_id_t id,
const d2tk_pos_t *pos)
{
- flowmatrix->src_id = id;
- flowmatrix->src_pos = *pos;
+ flowmatrix->src_conn = true;
+ flowmatrix->atom_body->flow.src_id = id;
+
+ if(pos)
+ {
+ flowmatrix->src_pos = *pos;
+ }
}
D2TK_API void
d2tk_flowmatrix_set_dst(d2tk_flowmatrix_t *flowmatrix, d2tk_id_t id,
const d2tk_pos_t *pos)
{
- flowmatrix->dst_id = id;
- flowmatrix->dst_pos = *pos;
+ flowmatrix->dst_conn = true;
+ flowmatrix->atom_body->flow.dst_id = id;
+
+ if(pos)
+ {
+ flowmatrix->dst_pos = *pos;
+ }
+}
+
+D2TK_API d2tk_id_t
+d2tk_flowmatrix_get_src(d2tk_flowmatrix_t *flowmatrix, d2tk_pos_t *pos)
+{
+ if(pos)
+ {
+ *pos = flowmatrix->src_pos;
+ }
+
+ return flowmatrix->atom_body->flow.src_id;
+}
+
+D2TK_API d2tk_id_t
+d2tk_flowmatrix_get_dst(d2tk_flowmatrix_t *flowmatrix, d2tk_pos_t *pos)
+{
+ if(pos)
+ {
+ *pos = flowmatrix->dst_pos;
+ }
+
+ return flowmatrix->atom_body->flow.dst_id;
}
D2TK_API d2tk_flowmatrix_node_t *
diff --git a/src/core.c b/src/core.c
index 41aac0c..1c6fc3c 100644
--- a/src/core.c
+++ b/src/core.c
@@ -1014,7 +1014,7 @@ d2tk_core_text(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
}
D2TK_API void
-d2tk_core_image(d2tk_core_t *core, d2tk_rect_t *rect, size_t sz,
+d2tk_core_image(d2tk_core_t *core, const d2tk_rect_t *rect, size_t sz,
const char *path, d2tk_align_t align)
{
const size_t len = sizeof(d2tk_body_image_t) + sz;
@@ -1038,6 +1038,32 @@ d2tk_core_image(d2tk_core_t *core, d2tk_rect_t *rect, size_t sz,
}
D2TK_API void
+d2tk_core_bitmap(d2tk_core_t *core, const d2tk_rect_t *rect, uint32_t w,
+ uint32_t h, uint32_t stride, const uint32_t *argb, d2tk_align_t align)
+{
+ const size_t len = sizeof(d2tk_body_bitmap_t);
+ d2tk_body_t *body = _d2tk_append_request(core, len, D2TK_INSTR_BITMAP);
+
+ if(body)
+ {
+ body->bitmap.x = rect->x;
+ body->bitmap.y = rect->y;
+ body->bitmap.w = rect->w;
+ body->bitmap.h = rect->h;
+ body->bitmap.align = align;
+ body->bitmap.surf.w = w;
+ body->bitmap.surf.h = h;
+ body->bitmap.surf.stride = stride;
+ body->bitmap.surf.argb = argb;
+
+ body->bitmap.x -= core->ref.x;
+ body->bitmap.y -= core->ref.y;
+
+ _d2tk_append_advance(core, len);
+ }
+}
+
+D2TK_API void
d2tk_core_stroke_width(d2tk_core_t *core, d2tk_coord_t width)
{
const size_t len = sizeof(d2tk_body_stroke_width_t);
diff --git a/src/core_internal.h b/src/core_internal.h
index 884c71a..96f93ab 100644
--- a/src/core_internal.h
+++ b/src/core_internal.h
@@ -54,6 +54,7 @@ typedef struct _d2tk_body_font_face_t d2tk_body_font_face_t;
typedef struct _d2tk_body_font_size_t d2tk_body_font_size_t;
typedef struct _d2tk_body_text_t d2tk_body_text_t;
typedef struct _d2tk_body_image_t d2tk_body_image_t;
+typedef struct _d2tk_body_bitmap_t d2tk_body_bitmap_t;
typedef struct _d2tk_body_stroke_width_t d2tk_body_stroke_width_t;
typedef struct _d2tk_body_bbox_t d2tk_body_bbox_t;
typedef union _d2tk_body_t d2tk_body_t;
@@ -165,6 +166,20 @@ struct _d2tk_body_image_t {
char path [1]; // at least zero-terminator
};
+struct _d2tk_body_bitmap_t {
+ d2tk_coord_t x;
+ d2tk_coord_t y;
+ d2tk_coord_t w;
+ d2tk_coord_t h;
+ d2tk_align_t align;
+ struct {
+ uint32_t w;
+ uint32_t h;
+ uint32_t stride;
+ const uint32_t *argb;
+ } surf;
+};
+
struct _d2tk_body_stroke_width_t {
d2tk_coord_t width;
};
@@ -192,6 +207,7 @@ union _d2tk_body_t {
d2tk_body_font_size_t font_size;
d2tk_body_text_t text;
d2tk_body_image_t image;
+ d2tk_body_bitmap_t bitmap;
d2tk_body_stroke_width_t stroke_width;
d2tk_body_bbox_t bbox;
};
@@ -219,6 +235,7 @@ typedef enum _d2tk_instr_t {
D2TK_INSTR_FONT_FACE,
D2TK_INSTR_TEXT,
D2TK_INSTR_IMAGE,
+ D2TK_INSTR_BITMAP,
D2TK_INSTR_STROKE_WIDTH
} d2tk_instr_t;
diff --git a/src/mum.h b/src/mum.h
index afe23a1..e42e2d7 100644
--- a/src/mum.h
+++ b/src/mum.h
@@ -183,6 +183,17 @@ _mum_le32 (uint32_t v) {
#endif
}
+static inline uint64_t
+_mum_le16 (uint16_t v) {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(MUM_TARGET_INDEPENDENT_HASH)
+ return v;
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ return (v >> 8) | ((v & 0xff) << 8);
+#else
+#error "Unknown endianess"
+#endif
+}
+
/* Macro defining how many times the most nested loop in
_mum_hash_aligned will be unrolled by the compiler (although it can
make an own decision:). Use only a constant here to help a
@@ -196,8 +207,10 @@ _mum_le32 (uint32_t v) {
#define _MUM_UNROLL_FACTOR_POWER 3
#elif defined(__aarch64__) && !defined(MUM_TARGET_INDEPENDENT_HASH)
#define _MUM_UNROLL_FACTOR_POWER 4
-#else
+#elif defined (MUM_V1) || defined (MUM_V2)
#define _MUM_UNROLL_FACTOR_POWER 2
+#else
+#define _MUM_UNROLL_FACTOR_POWER 3
#endif
#endif
@@ -222,7 +235,7 @@ _mum_hash_aligned (uint64_t start, const void *key, size_t len) {
size_t i;
size_t n;
-#ifdef MUM_V1
+#ifndef MUM_V2
result = _mum (result, _mum_block_start_prime);
#endif
while (len > _MUM_UNROLL_FACTOR * sizeof (uint64_t)) {
@@ -230,8 +243,14 @@ _mum_hash_aligned (uint64_t start, const void *key, size_t len) {
64x64->128-bit multiplication. AVX2 currently only have vector
insns for 4 32x32->64-bit multiplication and for 1
64x64->128-bit multiplication (pclmulqdq). */
+#if defined (MUM_V1) || defined (MUM_V2)
for (i = 0; i < _MUM_UNROLL_FACTOR; i++)
result ^= _mum (_mum_le (((uint64_t *) str)[i]), _mum_primes[i]);
+#else
+ for (i = 0; i < _MUM_UNROLL_FACTOR; i += 2)
+ result ^= _mum (_mum_le (((uint64_t *) str)[i]) ^ _mum_primes[i],
+ _mum_le (((uint64_t *) str)[i + 1]) ^ _mum_primes[i + 1]);
+#endif
len -= _MUM_UNROLL_FACTOR * sizeof (uint64_t);
str += _MUM_UNROLL_FACTOR * sizeof (uint64_t);
/* We will use the same prime numbers on the next iterations --
@@ -245,14 +264,12 @@ _mum_hash_aligned (uint64_t start, const void *key, size_t len) {
switch (len) {
case 7:
u64 = _mum_le32 (*(uint32_t *) str);
- u64 |= (uint64_t) str[4] << 32;
- u64 |= (uint64_t) str[5] << 40;
+ u64 |= _mum_le16 (*(uint16_t *) (str + 4)) << 32;
u64 |= (uint64_t) str[6] << 48;
return result ^ _mum (u64, _mum_tail_prime);
case 6:
u64 = _mum_le32 (*(uint32_t *) str);
- u64 |= (uint64_t) str[4] << 32;
- u64 |= (uint64_t) str[5] << 40;
+ u64 |= _mum_le16 (*(uint16_t *) (str + 4)) << 32;
return result ^ _mum (u64, _mum_tail_prime);
case 5:
u64 = _mum_le32 (*(uint32_t *) str);
@@ -262,13 +279,11 @@ _mum_hash_aligned (uint64_t start, const void *key, size_t len) {
u64 = _mum_le32 (*(uint32_t *) str);
return result ^ _mum (u64, _mum_tail_prime);
case 3:
- u64 = str[0];
- u64 |= (uint64_t) str[1] << 8;
+ u64 = _mum_le16 (*(uint16_t *) str);
u64 |= (uint64_t) str[2] << 16;
return result ^ _mum (u64, _mum_tail_prime);
case 2:
- u64 = str[0];
- u64 |= (uint64_t) str[1] << 8;
+ u64 = _mum_le16 (*(uint16_t *) str);
return result ^ _mum (u64, _mum_tail_prime);
case 1:
u64 = str[0];
@@ -280,12 +295,14 @@ _mum_hash_aligned (uint64_t start, const void *key, size_t len) {
/* Final randomization of H. */
static inline uint64_t
_mum_final (uint64_t h) {
-#ifndef MUM_V1
- h ^= _mum_rotl (h, 33);
-#endif
+#if defined (MUM_V1)
h ^= _mum (h, _mum_finish_prime1);
-#ifdef MUM_V1
h ^= _mum (h, _mum_finish_prime2);
+#elif defined (MUM_V2)
+ h ^= _mum_rotl (h, 33);
+ h ^= _mum (h, _mum_finish_prime1);
+#else
+ h = _mum (h, h);
#endif
return h;
}
diff --git a/test/base.c b/test/base.c
index 367c0af..93271b3 100644
--- a/test/base.c
+++ b/test/base.c
@@ -1185,7 +1185,8 @@ _test_pane_x()
#define fmin 0.25f
#define fmax 0.75f
- D2TK_BASE_PANE(base, &rect, D2TK_ID, D2TK_FLAG_PANE_X, fmin, fmax, pane)
+#define fstep 0.25f
+ D2TK_BASE_PANE(base, &rect, D2TK_ID, D2TK_FLAG_PANE_X, fmin, fmax, fstep, pane)
{
const d2tk_rect_t *bnd = d2tk_pane_get_rect(pane);
const unsigned k = d2tk_pane_get_index(pane);
@@ -1207,6 +1208,7 @@ _test_pane_x()
//FIXME test panning
#undef fmin
#undef fmax
+#undef fstep
d2tk_base_free(base);
}
@@ -1224,7 +1226,8 @@ _test_pane_y()
#define fmin 0.25f
#define fmax 0.75f
- D2TK_BASE_PANE(base, &rect, D2TK_ID, D2TK_FLAG_PANE_Y, fmin, fmax, pane)
+#define fstep 0.25f
+ D2TK_BASE_PANE(base, &rect, D2TK_ID, D2TK_FLAG_PANE_Y, fmin, fmax, fstep, pane)
{
const d2tk_rect_t *bnd = d2tk_pane_get_rect(pane);
const unsigned k = d2tk_pane_get_index(pane);
@@ -1246,6 +1249,7 @@ _test_pane_y()
//FIXME test panning
#undef fmin
#undef fmax
+#undef fstep
d2tk_base_free(base);
}
@@ -1385,6 +1389,43 @@ _test_toggle()
}
static void
+_test_image()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = NULL
+ };
+
+ d2tk_base_t *base = d2tk_base_new(&d2tk_mock_driver_lazy, &ctx);
+ const d2tk_rect_t rect = D2TK_RECT(0, 0, DIM_W, DIM_H);
+ assert(base);
+
+ d2tk_base_image(base, -1, "image.png", &rect, D2TK_ALIGN_CENTERED);
+
+ d2tk_base_free(base);
+}
+
+static void
+_test_bitmap()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = NULL
+ };
+
+ d2tk_base_t *base = d2tk_base_new(&d2tk_mock_driver_lazy, &ctx);
+ const d2tk_rect_t rect = D2TK_RECT(0, 0, DIM_W, DIM_H);
+ assert(base);
+
+ const uint32_t bmp [4] = {
+ 0xff0000ff, 0x00ff001f,
+ 0x0000ff7f, 0xffff003f
+ };
+
+ d2tk_base_bitmap(base, 2, 2, 2*sizeof(uint32_t), bmp, &rect, D2TK_ALIGN_CENTERED);
+
+ d2tk_base_free(base);
+}
+
+static void
_test_meter()
{
d2tk_mock_ctx_t ctx = {
@@ -1790,6 +1831,8 @@ main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
_test_button();
_test_toggle_label();
_test_toggle();
+ _test_image();
+ _test_bitmap();
_test_meter();
_test_combo();
_test_combo_scroll_up();
diff --git a/test/core.c b/test/core.c
index f2b0b17..3a8ca81 100644
--- a/test/core.c
+++ b/test/core.c
@@ -1141,6 +1141,95 @@ _test_image()
#undef IMAGE_PATH
#undef IMAGE_ALIGN
+#define BITMAP_X 10
+#define BITMAP_Y 20
+#define BITMAP_W 30
+#define BITMAP_H 40
+#define BITMAP_WIDTH 24
+#define BITMAP_HEIGHT 24
+#define BITMAP_STRIDE 32*sizeof(uint32_t)
+#define BITMAP_ALIGN D2TK_ALIGN_LEFT
+
+static void
+_check_bitmap(const d2tk_com_t *com, const d2tk_clip_t *clip)
+{
+ assert(clip->x0 == CLIP_X);
+ assert(clip->y0 == CLIP_Y);
+ assert(clip->x1 == CLIP_X + CLIP_W);
+ assert(clip->y1 == CLIP_Y + CLIP_H);
+ assert(clip->w == CLIP_W);
+ assert(clip->h == CLIP_H);
+
+ assert(com->size == sizeof(d2tk_body_bitmap_t));
+ assert(com->instr == D2TK_INSTR_BITMAP);
+ assert(com->body->bitmap.x == BITMAP_X - CLIP_X);
+ assert(com->body->bitmap.y == BITMAP_Y - CLIP_Y);
+ assert(com->body->bitmap.w == BITMAP_W);
+ assert(com->body->bitmap.h == BITMAP_H);
+ assert(com->body->bitmap.align == BITMAP_ALIGN);
+ assert(com->body->bitmap.surf.w == BITMAP_WIDTH);
+ assert(com->body->bitmap.surf.h == BITMAP_HEIGHT);
+ assert(com->body->bitmap.surf.stride == BITMAP_STRIDE);
+ for(unsigned y = 0, o = 0;
+ y < com->body->bitmap.surf.h;
+ y++, o += com->body->bitmap.surf.stride/sizeof(uint32_t))
+ {
+ for(unsigned x = 0; x < com->body->bitmap.surf.w; x++)
+ {
+ const unsigned idx = o + x;
+
+ assert(com->body->bitmap.surf.argb[idx] == 999 - idx);
+ }
+ }
+}
+
+static void
+_test_bitmap()
+{
+ d2tk_mock_ctx_t ctx = {
+ .check = _check_bitmap
+ };
+
+ d2tk_core_t *core = d2tk_core_new(&d2tk_mock_driver, &ctx);
+ assert(core);
+
+ d2tk_core_set_dimensions(core, DIM_W, DIM_H);
+
+ d2tk_core_pre(core);
+ const ssize_t ref = d2tk_core_bbox_push(core, true,
+ &D2TK_RECT(CLIP_X, CLIP_Y, CLIP_W, CLIP_H));
+ assert(ref >= 0);
+
+ uint32_t surf [BITMAP_STRIDE/sizeof(uint32_t)*BITMAP_HEIGHT];
+ for(unsigned y = 0, o = 0;
+ y < BITMAP_HEIGHT;
+ y++, o += BITMAP_STRIDE/sizeof(uint32_t))
+ {
+ for(unsigned x = 0; x < BITMAP_WIDTH; x++)
+ {
+ const unsigned idx = o + x;
+
+ surf[idx] = 999 - idx;
+ }
+ }
+
+ d2tk_core_bitmap(core, &D2TK_RECT(BITMAP_X, BITMAP_Y, BITMAP_W, BITMAP_H),
+ BITMAP_WIDTH, BITMAP_HEIGHT, BITMAP_STRIDE, surf, BITMAP_ALIGN);
+
+ d2tk_core_bbox_pop(core, ref);
+ d2tk_core_post(core);
+ d2tk_core_free(core);
+}
+
+#undef BITMAP_X
+#undef BITMAP_Y
+#undef BITMAP_W
+#undef BITMAP_H
+#undef BITMAP_WIDTH
+#undef BITMAP_HEIGHT
+#undef BITMAP_STRIDE
+#undef BITMAP_ALIGN
+
#define STROKE_WIDTH 2
static void
@@ -1283,6 +1372,7 @@ main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
_test_font_face();
_test_text();
_test_image();
+ _test_bitmap();
_test_stroke_width();
_test_triple();