static int repaint(glw_gradient_t *gg, glw_root_t *gr, int tile, int w, int h, int tiles) { int x, y, n = showtime_get_ts(), m = 0; uint8_t *p, *pixmap; size_t s = h * w * GRAD_BPP; if(w < 1 || h < 1) return 0; p = pixmap = malloc(s); for(y = 0; y < h; y++) { float a = (float)y / (float)h; int r = 65280 * GLW_LERP(a, gg->gg_col1[0], gg->gg_col2[0]); int g = 65280 * GLW_LERP(a, gg->gg_col1[1], gg->gg_col2[1]); int b = 65280 * GLW_LERP(a, gg->gg_col1[2], gg->gg_col2[2]); for(x = 0; x < w; x++) { n = n * 1664525 + 1013904223; *p++ = (b + (n & 0xff)) >> 8; n = n * 1664525 + 1013904223; *p++ = (g + (n & 0xff)) >> 8; n = n * 1664525 + 1013904223; *p++ = (r + (n & 0xff)) >> 8; } n = n ^ m; m = m * 1664525 + 1013904223; } if(gg->gg_image_flags & GLW_IMAGE_BEVEL_TOP) bevel_top(pixmap, w, h); if(gg->gg_image_flags & GLW_IMAGE_BEVEL_BOTTOM) bevel_bottom(pixmap, w, h); glw_tex_upload(gr, &gg->gg_tex[0], pixmap, GLW_TEXTURE_FORMAT_RGB, w, h, GLW_TEX_REPEAT); if(tiles == 3) { p = malloc(s); memcpy(p, pixmap, s); if(gg->gg_image_flags & GLW_IMAGE_BEVEL_LEFT) bevel_left(p, w, h); glw_tex_upload(gr, &gg->gg_tex[1], p, GLW_TEXTURE_FORMAT_RGB, w, h, GLW_TEX_REPEAT); memcpy(p, pixmap, s); if(gg->gg_image_flags & GLW_IMAGE_BEVEL_RIGHT) bevel_right(p, w, h); glw_tex_upload(gr, &gg->gg_tex[2], p, GLW_TEXTURE_FORMAT_RGB, w, h, GLW_TEX_REPEAT); free(p); } free(pixmap); return 1; }
static void glw_raster_render(glw_t *w, const glw_rctx_t *rc) { glw_raster_t *q = (void *)w; #if 0 printf("RASTER W=%d H=%d\n", rc->rc_width, rc->rc_height); int i; for(i = 0; i < 16; i++) { printf("%f%c", rc->rc_be.gbr_mtx[i], "\t\t\t\n"[i&3]); } #endif if(!glw_is_tex_inited(&q->tex)) glw_tex_upload(w->glw_root, &q->tex, rastermap, GLW_TEXTURE_FORMAT_RGB, RASTER_TILE_SIZE, RASTER_TILE_SIZE, GLW_TEX_REPEAT); if(!glw_renderer_initialized(&q->r)) glw_renderer_init_quad(&q->r); if(q->width != rc->rc_width || q->height != rc->rc_height) { q->width = rc->rc_width; q->height = rc->rc_height; glw_renderer_vtx_pos(&q->r, 0, -1, -1, 0); glw_renderer_vtx_st (&q->r, 0, 0, rc->rc_height / (float)RASTER_TILE_SIZE); glw_renderer_vtx_pos(&q->r, 1, 1, -1, 0); glw_renderer_vtx_st (&q->r, 1, rc->rc_width / (float)RASTER_TILE_SIZE, rc->rc_height / (float)RASTER_TILE_SIZE); glw_renderer_vtx_pos(&q->r, 2, 1, 1, 0); glw_renderer_vtx_st (&q->r, 2, rc->rc_width / (float)RASTER_TILE_SIZE, 0); glw_renderer_vtx_pos(&q->r, 3, -1, 1, 0); glw_renderer_vtx_st (&q->r, 3, 0, 0); } glw_renderer_draw(&q->r, w->glw_root, rc, &q->tex, &q->color, NULL, rc->rc_alpha * w->glw_alpha, 0, NULL); }
static void glw_text_bitmap_layout(glw_t *w, const glw_rctx_t *rc) { glw_text_bitmap_t *gtb = (void *)w; glw_root_t *gr = w->glw_root; gr->gr_can_externalize = 0; // Initialize renderers if(unlikely(!glw_renderer_initialized(>b->gtb_text_renderer))) glw_renderer_init_quad(>b->gtb_text_renderer); if(w->glw_class == &glw_text && unlikely(!glw_renderer_initialized(>b->gtb_cursor_renderer))) glw_renderer_init_quad(>b->gtb_cursor_renderer); if(gtb->gtb_background_alpha > GLW_ALPHA_EPSILON && unlikely(!glw_renderer_initialized(>b->gtb_cursor_renderer))) { glw_renderer_init_quad(>b->gtb_background_renderer); glw_renderer_vtx_pos(>b->gtb_background_renderer, 0, -1, -1, 0); glw_renderer_vtx_pos(>b->gtb_background_renderer, 1, 1, -1, 0); glw_renderer_vtx_pos(>b->gtb_background_renderer, 2, 1, 1, 0); glw_renderer_vtx_pos(>b->gtb_background_renderer, 3, -1, 1, 0); } // Upload texture image_component_t *ic = image_find_component(gtb->gtb_image, IMAGE_PIXMAP); if(ic != NULL) { glw_tex_upload(gr, >b->gtb_texture, ic->pm, 0); gtb->gtb_margin = ic->pm->pm_margin; image_clear_component(ic); gtb->gtb_need_layout = 1; } const int tex_width = glw_tex_width(>b->gtb_texture); const int tex_height = glw_tex_height(>b->gtb_texture); ic = image_find_component(gtb->gtb_image, IMAGE_TEXT_INFO); image_component_text_info_t *ti = ic ? &ic->text_info : NULL; // Check if we need to repaint if(gtb->gtb_saved_width != rc->rc_width || gtb->gtb_saved_height != rc->rc_height) { if(ti != NULL && gtb->gtb_state == GTB_VALID) { if(ti->ti_flags & IMAGE_TEXT_WRAPPED) gtb->gtb_state = GTB_NEED_RENDER; if(rc->rc_width > gtb->gtb_saved_width && ti->ti_flags & IMAGE_TEXT_TRUNCATED) gtb->gtb_state = GTB_NEED_RENDER; if(gtb->gtb_flags & GTB_ELLIPSIZE) { if(ti->ti_flags & IMAGE_TEXT_TRUNCATED) { gtb->gtb_state = GTB_NEED_RENDER; } else { if(rc->rc_width - gtb->gtb_padding[2] - gtb->gtb_padding[0] < tex_width - gtb->gtb_margin * 2) gtb->gtb_state = GTB_NEED_RENDER; if(rc->rc_height - gtb->gtb_padding[1] - gtb->gtb_padding[3] < tex_height - gtb->gtb_margin * 2) gtb->gtb_state = GTB_NEED_RENDER; } } } gtb->gtb_saved_width = rc->rc_width; gtb->gtb_saved_height = rc->rc_height; gtb->gtb_update_cursor = 1; gtb->gtb_need_layout = 1; if(gtb->w.glw_flags2 & GLW2_DEBUG) printf(" textbitmap: Parent widget gives us :%d x %d ti=%p\n", rc->rc_width, rc->rc_height, ti); } if(ti != NULL && gtb->gtb_need_layout) { const int margin = gtb->gtb_margin; int left = gtb->gtb_padding[0] - margin; int top = rc->rc_height - gtb->gtb_padding[1] + margin; int right = rc->rc_width - gtb->gtb_padding[2] + margin; int bottom = gtb->gtb_padding[3] - margin; int text_width = tex_width; int text_height = tex_height; float x1, y1, x2, y2; if(gtb->w.glw_flags2 & GLW2_DEBUG) printf(" textbitmap: text_width:%d left:%d right:%d margin:%d\n", text_width, left, right, margin); // Vertical if(text_height > top - bottom) { // Oversized, must cut text_height = top - bottom; } else { switch(w->glw_alignment) { case LAYOUT_ALIGN_CENTER: case LAYOUT_ALIGN_LEFT: case LAYOUT_ALIGN_RIGHT: bottom = (bottom + top - text_height) / 2; top = bottom + text_height; break; case LAYOUT_ALIGN_TOP_LEFT: case LAYOUT_ALIGN_TOP_RIGHT: case LAYOUT_ALIGN_TOP: case LAYOUT_ALIGN_JUSTIFIED: bottom = top - tex_height; break; case LAYOUT_ALIGN_BOTTOM: case LAYOUT_ALIGN_BOTTOM_LEFT: case LAYOUT_ALIGN_BOTTOM_RIGHT: top = bottom + tex_height; break; } } y1 = -1.0f + 2.0f * bottom / (float)rc->rc_height; y2 = -1.0f + 2.0f * top / (float)rc->rc_height; // Horizontal if(text_width > right - left || ti->ti_flags & IMAGE_TEXT_TRUNCATED) { // Oversized, must cut text_width = right - left; if(gtb->w.glw_flags2 & GLW2_DEBUG) printf(" textbitmap: Oversized, must cut. Width is now %d\n", text_width); #if 0 if(!(gtb->gtb_flags & GTB_ELLIPSIZE)) { glw_renderer_vtx_col(>b->gtb_text_renderer, 0, 1,1,1,1+text_width/20); glw_renderer_vtx_col(>b->gtb_text_renderer, 1, 1,1,1,0); glw_renderer_vtx_col(>b->gtb_text_renderer, 2, 1,1,1,0); glw_renderer_vtx_col(>b->gtb_text_renderer, 3, 1,1,1,1+text_width/20); } #endif } else { glw_renderer_vtx_col_reset(>b->gtb_text_renderer); switch(w->glw_alignment) { case LAYOUT_ALIGN_JUSTIFIED: case LAYOUT_ALIGN_CENTER: case LAYOUT_ALIGN_BOTTOM: case LAYOUT_ALIGN_TOP: left = (left + right - text_width) / 2; right = left + text_width; break; case LAYOUT_ALIGN_LEFT: case LAYOUT_ALIGN_TOP_LEFT: case LAYOUT_ALIGN_BOTTOM_LEFT: right = left + tex_width; break; case LAYOUT_ALIGN_RIGHT: case LAYOUT_ALIGN_TOP_RIGHT: case LAYOUT_ALIGN_BOTTOM_RIGHT: left = right - tex_width; break; } } x1 = -1.0f + 2.0f * left / (float)rc->rc_width; x2 = -1.0f + 2.0f * right / (float)rc->rc_width; const float s = text_width / (float)tex_width; const float t = text_height / (float)tex_height; if(gtb->w.glw_flags2 & GLW2_DEBUG) printf(" s=%f t=%f\n", s, t); glw_renderer_vtx_pos(>b->gtb_text_renderer, 0, x1, y1, 0.0); glw_renderer_vtx_st (>b->gtb_text_renderer, 0, 0, t); glw_renderer_vtx_pos(>b->gtb_text_renderer, 1, x2, y1, 0.0); glw_renderer_vtx_st (>b->gtb_text_renderer, 1, s, t); glw_renderer_vtx_pos(>b->gtb_text_renderer, 2, x2, y2, 0.0); glw_renderer_vtx_st (>b->gtb_text_renderer, 2, s, 0); glw_renderer_vtx_pos(>b->gtb_text_renderer, 3, x1, y2, 0.0); glw_renderer_vtx_st (>b->gtb_text_renderer, 3, 0, 0); } if(w->glw_class == &glw_text && gtb->gtb_update_cursor && gtb->gtb_state == GTB_VALID) { int i = gtb->gtb_edit_ptr; int left; float x1, y1, x2, y2; if(ti != NULL && ti->ti_charpos != NULL) { if(i < ti->ti_charposlen) { left = ti->ti_charpos[i*2 ]; } else { left = ti->ti_charpos[2 * ti->ti_charposlen - 1]; } } else { left = 0; } left += gtb->gtb_padding[0]; x1 = -1.0f + 2.0f * (left - 1) / (float)rc->rc_width; x2 = -1.0f + 2.0f * (left ) / (float)rc->rc_width; y1 = -1.0f + 2.0f * gtb->gtb_padding[3] / (float)rc->rc_height; y2 = 1.0f - 2.0f * gtb->gtb_padding[1] / (float)rc->rc_height; glw_renderer_vtx_pos(>b->gtb_cursor_renderer, 0, x1, y1, 0.0); glw_renderer_vtx_pos(>b->gtb_cursor_renderer, 1, x2, y1, 0.0); glw_renderer_vtx_pos(>b->gtb_cursor_renderer, 2, x2, y2, 0.0); glw_renderer_vtx_pos(>b->gtb_cursor_renderer, 3, x1, y2, 0.0); if(w->glw_flags2 & GLW2_DEBUG) { printf("Cursor updated %f %f %f %f rect:%d,%d\n", x1, y1, x2, y2, rc->rc_width, rc->rc_height); } gtb->gtb_update_cursor = 0; } gtb->gtb_paint_cursor = gtb->gtb_flags & GTB_PERMANENT_CURSOR || (w->glw_class == &glw_text && glw_is_focused(w)); if(gtb->gtb_paint_cursor && rc->rc_alpha > GLW_ALPHA_EPSILON) glw_need_refresh(gr, 0); gtb->gtb_need_layout = 0; if(gtb->gtb_state == GTB_VALID && gtb->gtb_deferred_realize) { gtb->gtb_deferred_realize = 0; gtb_realize(gtb); } if(gtb->gtb_state != GTB_NEED_RENDER) return; TAILQ_INSERT_TAIL(&gr->gr_gtb_render_queue, gtb, gtb_workq_link); gtb->gtb_state = GTB_QUEUED_FOR_RENDERING; hts_cond_signal(&gr->gr_gtb_work_cond); }
static void glw_text_bitmap_layout(glw_t *w, glw_rctx_t *rc) { glw_text_bitmap_t *gtb = (void *)w; glw_root_t *gr = w->glw_root; pixmap_t *pm = gtb->gtb_pixmap; // Initialize renderers if(!glw_renderer_initialized(>b->gtb_text_renderer)) glw_renderer_init_quad(>b->gtb_text_renderer); if(w->glw_class == &glw_text && !glw_renderer_initialized(>b->gtb_cursor_renderer)) glw_renderer_init_quad(>b->gtb_cursor_renderer); // Upload texture if(pm != NULL && pm->pm_pixels != NULL) { int fmt; fmt = pm->pm_type == PIXMAP_IA ? GLW_TEXTURE_FORMAT_I8A8 : GLW_TEXTURE_FORMAT_BGR32; glw_tex_upload(gr, >b->gtb_texture, pm->pm_pixels, fmt, pm->pm_width, pm->pm_height, 0); free(pm->pm_pixels); pm->pm_pixels = NULL; gtb->gtb_need_layout = 1; } // Check if we need to repaint if((gtb->gtb_saved_width != rc->rc_width || gtb->gtb_saved_height != rc->rc_height)) { if(pm != NULL && gtb->gtb_state == GTB_VALID) { if(pm->pm_flags & PIXMAP_TEXT_WRAPPED) gtb->gtb_state = GTB_NEED_RENDER; if(rc->rc_width > gtb->gtb_saved_width && pm->pm_flags & PIXMAP_TEXT_TRUNCATED) gtb->gtb_state = GTB_NEED_RENDER; if(gtb->gtb_flags & GTB_ELLIPSIZE) { if(pm->pm_flags & PIXMAP_TEXT_TRUNCATED) { gtb->gtb_state = GTB_NEED_RENDER; } else { if(rc->rc_width - gtb->gtb_padding_right - gtb->gtb_padding_left < pm->pm_width - pm->pm_margin * 2) gtb->gtb_state = GTB_NEED_RENDER; if(rc->rc_height - gtb->gtb_padding_top - gtb->gtb_padding_bottom < pm->pm_height - pm->pm_margin * 2) gtb->gtb_state = GTB_NEED_RENDER; } } } gtb->gtb_saved_width = rc->rc_width; gtb->gtb_saved_height = rc->rc_height; gtb->gtb_need_layout = 1; if(gtb->w.glw_flags & GLW_DEBUG) printf(" parent widget gives us :%d x %d\n", rc->rc_width, rc->rc_height); } if(pm != NULL && gtb->gtb_need_layout) { int left = gtb->gtb_padding_left - pm->pm_margin; int top = rc->rc_height - gtb->gtb_padding_top + pm->pm_margin; int right = rc->rc_width - gtb->gtb_padding_right + pm->pm_margin; int bottom = gtb->gtb_padding_bottom - pm->pm_margin; int text_width = pm->pm_width; int text_height = pm->pm_height; float x1, y1, x2, y2; // Horizontal if(text_width > right - left) { // Oversized, must cut text_width = right - left; if(!(gtb->gtb_flags & GTB_ELLIPSIZE)) { glw_renderer_vtx_col(>b->gtb_text_renderer, 0, 1,1,1,1+text_width/20); glw_renderer_vtx_col(>b->gtb_text_renderer, 1, 1,1,1,0); glw_renderer_vtx_col(>b->gtb_text_renderer, 2, 1,1,1,0); glw_renderer_vtx_col(>b->gtb_text_renderer, 3, 1,1,1,1+text_width/20); } } else { glw_renderer_vtx_col(>b->gtb_text_renderer, 0, 1,1,1,1); glw_renderer_vtx_col(>b->gtb_text_renderer, 1, 1,1,1,1); glw_renderer_vtx_col(>b->gtb_text_renderer, 2, 1,1,1,1); glw_renderer_vtx_col(>b->gtb_text_renderer, 3, 1,1,1,1); switch(w->glw_alignment) { case LAYOUT_ALIGN_JUSTIFIED: case LAYOUT_ALIGN_CENTER: case LAYOUT_ALIGN_BOTTOM: case LAYOUT_ALIGN_TOP: left = (left + right - text_width) / 2; right = left + text_width; break; case LAYOUT_ALIGN_LEFT: case LAYOUT_ALIGN_TOP_LEFT: case LAYOUT_ALIGN_BOTTOM_LEFT: right = left + pm->pm_width; break; case LAYOUT_ALIGN_RIGHT: case LAYOUT_ALIGN_TOP_RIGHT: case LAYOUT_ALIGN_BOTTOM_RIGHT: left = right - pm->pm_width; break; } } // Vertical if(text_height > top - bottom) { // Oversized, must cut text_height = top - bottom; } else { switch(w->glw_alignment) { case LAYOUT_ALIGN_CENTER: case LAYOUT_ALIGN_LEFT: case LAYOUT_ALIGN_RIGHT: bottom = (bottom + top - text_height) / 2; top = bottom + text_height; break; case LAYOUT_ALIGN_TOP_LEFT: case LAYOUT_ALIGN_TOP_RIGHT: case LAYOUT_ALIGN_TOP: case LAYOUT_ALIGN_JUSTIFIED: bottom = top - pm->pm_height; break; case LAYOUT_ALIGN_BOTTOM: case LAYOUT_ALIGN_BOTTOM_LEFT: case LAYOUT_ALIGN_BOTTOM_RIGHT: top = bottom + pm->pm_height; break; } } x1 = -1.0f + 2.0f * left / (float)rc->rc_width; y1 = -1.0f + 2.0f * bottom / (float)rc->rc_height; x2 = -1.0f + 2.0f * right / (float)rc->rc_width; y2 = -1.0f + 2.0f * top / (float)rc->rc_height; float s, t; if(gr->gr_normalized_texture_coords) { s = text_width / (float)pm->pm_width; t = text_height / (float)pm->pm_height; } else { s = text_width; t = text_height; } glw_renderer_vtx_pos(>b->gtb_text_renderer, 0, x1, y1, 0.0); glw_renderer_vtx_st (>b->gtb_text_renderer, 0, 0, t); glw_renderer_vtx_pos(>b->gtb_text_renderer, 1, x2, y1, 0.0); glw_renderer_vtx_st (>b->gtb_text_renderer, 1, s, t); glw_renderer_vtx_pos(>b->gtb_text_renderer, 2, x2, y2, 0.0); glw_renderer_vtx_st (>b->gtb_text_renderer, 2, s, 0); glw_renderer_vtx_pos(>b->gtb_text_renderer, 3, x1, y2, 0.0); glw_renderer_vtx_st (>b->gtb_text_renderer, 3, 0, 0); } if(w->glw_class == &glw_text && gtb->gtb_update_cursor && gtb->gtb_state == GTB_VALID) { int i = gtb->gtb_edit_ptr; int left, right; float x1, y1, x2, y2; if(pm != NULL && pm->pm_charpos != NULL) { if(i < pm->pm_charposlen) { left = pm->pm_charpos[i*2 ]; right = pm->pm_charpos[i*2+1]; } else { left = pm->pm_charpos[2*pm->pm_charposlen - 1]; right = left + 10; } left += gtb->gtb_padding_left; right += gtb->gtb_padding_left; } else { left = 0; right = 10; } x1 = -1.0f + 2.0f * left / (float)rc->rc_width; x2 = -1.0f + 2.0f * right / (float)rc->rc_width; y1 = -0.9f; y2 = 0.9f; glw_renderer_vtx_pos(>b->gtb_cursor_renderer, 0, x1, y1, 0.0); glw_renderer_vtx_pos(>b->gtb_cursor_renderer, 1, x2, y1, 0.0); glw_renderer_vtx_pos(>b->gtb_cursor_renderer, 2, x2, y2, 0.0); glw_renderer_vtx_pos(>b->gtb_cursor_renderer, 3, x1, y2, 0.0); gtb->gtb_update_cursor = 0; } gtb->gtb_paint_cursor = w->glw_class == &glw_text && glw_is_focused(w); gtb->gtb_need_layout = 0; if(gtb->gtb_state == GTB_VALID && gtb->gtb_deferred_realize) { gtb->gtb_deferred_realize = 0; gtb_realize(gtb); } if(gtb->gtb_state != GTB_NEED_RENDER) return; TAILQ_INSERT_TAIL(&gr->gr_gtb_render_queue, gtb, gtb_workq_link); gtb->gtb_state = GTB_QUEUED_FOR_RENDERING; hts_cond_signal(&gr->gr_gtb_work_cond); }