static ply_renderer_head_t * ply_renderer_head_new (ply_renderer_backend_t *backend, drmModeConnector *connector, uint32_t encoder_id, uint32_t controller_id, uint32_t console_buffer_id, drmModeModeInfo *mode) { ply_renderer_head_t *head; head = calloc (1, sizeof (ply_renderer_head_t)); head->backend = backend; head->connector = connector; head->encoder_id = encoder_id; head->controller_id = controller_id; head->console_buffer_id = console_buffer_id; head->mode = mode; head->area.x = 0; head->area.y = 0; head->area.width = mode->hdisplay; head->area.height = mode->vdisplay; head->pixel_buffer = ply_pixel_buffer_new (head->area.width, head->area.height); ply_trace ("Creating %ldx%ld renderer head", head->area.width, head->area.height); ply_pixel_buffer_fill_with_color (head->pixel_buffer, NULL, 0.0, 0.0, 0.0, 1.0); return head; }
static ply_renderer_head_t * ply_renderer_head_new (ply_renderer_backend_t *backend, drmModeConnector *connector, int connector_mode_index, uint32_t encoder_id, uint32_t controller_id, uint32_t console_buffer_id) { ply_renderer_head_t *head; drmModeModeInfo *mode; head = calloc (1, sizeof (ply_renderer_head_t)); head->backend = backend; head->encoder_id = encoder_id; head->connector_ids = ply_array_new (PLY_ARRAY_ELEMENT_TYPE_UINT32); head->controller_id = controller_id; head->console_buffer_id = console_buffer_id; assert (connector_mode_index < connector->count_modes); mode = &connector->modes[connector_mode_index]; head->connector0 = connector; head->connector0_mode_index = connector_mode_index; head->area.x = 0; head->area.y = 0; head->area.width = mode->hdisplay; head->area.height = mode->vdisplay; ply_renderer_head_add_connector (head, connector, connector_mode_index); assert (ply_array_get_size (head->connector_ids) > 0); head->pixel_buffer = ply_pixel_buffer_new (head->area.width, head->area.height); ply_trace ("Creating %ldx%ld renderer head", head->area.width, head->area.height); ply_pixel_buffer_fill_with_color (head->pixel_buffer, NULL, 0.0, 0.0, 0.0, 1.0); return head; }
bool ply_image_load (ply_image_t *image) { png_struct *png; png_info *info; png_uint_32 width, height, row; int bits_per_pixel, color_type, interlace_method; png_byte **rows; uint32_t *bytes; FILE *fp; assert (image != NULL); fp = fopen (image->filename, "r"); if (fp == NULL) return false; png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); assert (png != NULL); info = png_create_info_struct (png); assert (info != NULL); png_init_io (png, fp); if (setjmp (png_jmpbuf (png)) != 0) { fclose (fp); return false; } png_read_info (png, info); png_get_IHDR (png, info, &width, &height, &bits_per_pixel, &color_type, &interlace_method, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb (png); if ((color_type == PNG_COLOR_TYPE_GRAY) && (bits_per_pixel < 8)) png_set_expand_gray_1_2_4_to_8 (png); if (png_get_valid (png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha (png); if (bits_per_pixel == 16) png_set_strip_16 (png); if (bits_per_pixel < 8) png_set_packing (png); if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_set_gray_to_rgb (png); if (interlace_method != PNG_INTERLACE_NONE) png_set_interlace_handling (png); png_set_filler (png, 0xff, PNG_FILLER_AFTER); png_set_read_user_transform_fn (png, transform_to_argb32); png_read_update_info (png, info); rows = malloc (height * sizeof (png_byte *)); image->buffer = ply_pixel_buffer_new (width, height); bytes = ply_pixel_buffer_get_argb32_data (image->buffer); for (row = 0; row < height; row++) rows[row] = (png_byte*) &bytes[row * width]; png_read_image (png, rows); free (rows); png_read_end (png, info); fclose (fp); png_destroy_read_struct (&png, &info, NULL); return true; }
void ply_progress_animation_draw (ply_progress_animation_t *progress_animation) { int number_of_frames; int frame_number; ply_image_t * const * frames; uint32_t *previous_frame_data, *frame_data; if (progress_animation->is_hidden) return; number_of_frames = ply_array_get_size (progress_animation->frames); if (number_of_frames == 0) return; frame_number = progress_animation->percent_done * (number_of_frames - 1); if (progress_animation->previous_frame_number != frame_number && progress_animation->transition != PLY_PROGRESS_ANIMATION_TRANSITION_NONE && progress_animation->transition_duration > 0.0) { progress_animation->is_transitioning = true; progress_animation->transition_start_time = ply_get_timestamp (); } frames = (ply_image_t * const *) ply_array_get_elements (progress_animation->frames); progress_animation->frame_area.x = progress_animation->area.x; progress_animation->frame_area.y = progress_animation->area.y; frame_data = ply_image_get_data (frames[frame_number]); if (progress_animation->is_transitioning) { double now; double fade_percentage; double fade_out_opacity; int width, height; uint32_t* faded_data; now = ply_get_timestamp (); fade_percentage = (now - progress_animation->transition_start_time) / progress_animation->transition_duration; if (fade_percentage >= 1.0) progress_animation->is_transitioning = false; fade_percentage = CLAMP (fade_percentage, 0.0, 1.0); if (progress_animation->transition == PLY_PROGRESS_ANIMATION_TRANSITION_MERGE_FADE) { width = MAX(ply_image_get_width (frames[frame_number]), ply_image_get_width (frames[frame_number - 1])); height = MAX(ply_image_get_height (frames[frame_number]), ply_image_get_width (frames[frame_number - 1])); progress_animation->frame_area.width = width; progress_animation->frame_area.height = height; ply_pixel_buffer_free (progress_animation->last_rendered_frame); progress_animation->last_rendered_frame = ply_pixel_buffer_new (width, height); faded_data = ply_pixel_buffer_get_argb32_data (progress_animation->last_rendered_frame); image_fade_merge (frames[frame_number - 1], frames[frame_number], fade_percentage, width, height, faded_data); ply_pixel_display_draw_area (progress_animation->display, progress_animation->frame_area.x, progress_animation->frame_area.y, progress_animation->frame_area.width, progress_animation->frame_area.height); } else { ply_rectangle_t fill_area; previous_frame_data = ply_image_get_data (frames[frame_number - 1]); if (progress_animation->transition == PLY_PROGRESS_ANIMATION_TRANSITION_FADE_OVER) { ply_pixel_buffer_free (progress_animation->last_rendered_frame); progress_animation->frame_area.width = ply_image_get_width (frames[frame_number - 1]); progress_animation->frame_area.height = ply_image_get_height (frames[frame_number - 1]); progress_animation->last_rendered_frame = ply_pixel_buffer_new (progress_animation->frame_area.width, progress_animation->frame_area.height); fill_area.x = 0; fill_area.y = 0; fill_area.width = progress_animation->frame_area.width; fill_area.height = progress_animation->frame_area.height; ply_pixel_buffer_fill_with_argb32_data (progress_animation->last_rendered_frame, &fill_area, 0, 0, previous_frame_data); } else { fade_out_opacity = 1.0 - fade_percentage; progress_animation->frame_area.width = ply_image_get_width (frames[frame_number - 1]); progress_animation->frame_area.height = ply_image_get_height (frames[frame_number - 1]); fill_area.x = 0; fill_area.y = 0; fill_area.width = progress_animation->frame_area.width; fill_area.height = progress_animation->frame_area.height; ply_pixel_buffer_fill_with_argb32_data_at_opacity (progress_animation->last_rendered_frame, &fill_area, 0, 0, previous_frame_data, fade_out_opacity); } progress_animation->frame_area.width = ply_image_get_width (frames[frame_number]); progress_animation->frame_area.height = ply_image_get_height (frames[frame_number]); fill_area.x = 0; fill_area.y = 0; fill_area.width = progress_animation->frame_area.width; fill_area.height = progress_animation->frame_area.height; ply_pixel_buffer_fill_with_argb32_data_at_opacity (progress_animation->last_rendered_frame, &fill_area, 0, 0, frame_data, fade_percentage); width = MAX(ply_image_get_width (frames[frame_number]), ply_image_get_width (frames[frame_number - 1])); height = MAX(ply_image_get_height (frames[frame_number]), ply_image_get_width (frames[frame_number - 1])); progress_animation->frame_area.width = width; progress_animation->frame_area.height = height; } } else { ply_rectangle_t fill_area; ply_pixel_buffer_free (progress_animation->last_rendered_frame); progress_animation->frame_area.width = ply_image_get_width (frames[frame_number]); progress_animation->frame_area.height = ply_image_get_height (frames[frame_number]); progress_animation->last_rendered_frame = ply_pixel_buffer_new (progress_animation->frame_area.width, progress_animation->frame_area.height); fill_area.x = 0; fill_area.y = 0; fill_area.width = progress_animation->frame_area.width; fill_area.height = progress_animation->frame_area.height; ply_pixel_buffer_fill_with_argb32_data (progress_animation->last_rendered_frame, &fill_area, 0, 0, frame_data); } progress_animation->previous_frame_number = frame_number; ply_pixel_display_draw_area (progress_animation->display, progress_animation->frame_area.x, progress_animation->frame_area.y, progress_animation->frame_area.width, progress_animation->frame_area.height); }
static bool ply_renderer_head_set_scan_out_buffer_to_console (ply_renderer_backend_t *backend, ply_renderer_head_t *head, bool should_set_to_black) { unsigned long width; unsigned long height; unsigned long row_stride; uint32_t *shadow_buffer; ply_pixel_buffer_t *pixel_buffer; char *map_address; ply_rectangle_t area; if (!backend->driver_interface->fetch_buffer (backend->driver, head->console_buffer_id, &width, &height, &row_stride)) return false; if (!backend->driver_interface->map_buffer (backend->driver, head->console_buffer_id)) { backend->driver_interface->destroy_buffer (backend->driver, head->console_buffer_id); return false; } if (head->area.width != width || head->area.height != height) { /* Force black if the fb console resolution doesn't match our resolution */ area.x = 0; area.y = 0; area.width = width; area.height = height; should_set_to_black = true; ply_trace ("Console fb is %ldx%ld and screen contents are %ldx%ld. " "They aren't the same dimensions; forcing black", width, height, head->area.width, head->area.height); } else area = head->area; if (should_set_to_black) { pixel_buffer = ply_pixel_buffer_new (width, height); shadow_buffer = ply_pixel_buffer_get_argb32_data (pixel_buffer); } else { pixel_buffer = NULL; shadow_buffer = ply_pixel_buffer_get_argb32_data (head->pixel_buffer); } ply_trace ("Drawing %s to console fb", should_set_to_black? "black" : "screen contents"); map_address = backend->driver_interface->begin_flush (backend->driver, head->console_buffer_id); flush_area ((char *) shadow_buffer, area.width * 4, map_address, row_stride, &area); backend->driver_interface->end_flush (backend->driver, head->console_buffer_id); backend->driver_interface->unmap_buffer (backend->driver, head->console_buffer_id); ply_trace ("Setting scan out hardware to console fb"); ply_renderer_head_set_scan_out_buffer (backend, head, head->console_buffer_id); backend->driver_interface->destroy_buffer (backend->driver, head->console_buffer_id); if (pixel_buffer != NULL) ply_pixel_buffer_free (pixel_buffer); return true; }