Example #1
0
static void bitmapLayerUpdate(struct Layer *layer, GContext *ctx){
  GBitmap *framebuffer;
  const GBitmap *graphic = bitmap_layer_get_bitmap((BitmapLayer *)layer);
  int height;
  uint8_t finalBits;
  uint8_t *bfr, *bitmap;;
  
//  printf("bitmap layer update proc\n");
  framebuffer = graphics_capture_frame_buffer(ctx);
  height = graphic->bounds.size.h;
//  APP_LOG(APP_LOG_LEVEL_DEBUG, "bitmaplayerupdate: %d, height: %d", framebuffer->row_size_bytes, height);
  
  for (int yindex =0; yindex < height; yindex++){
    // APP_LOG(APP_LOG_LEVEL_DEBUG, "----- yindex %d", yindex);
    for ( int xindex = 0; xindex < graphic->row_size_bytes; xindex++){
      bfr = (((uint8_t*)framebuffer->addr)+(yindex * framebuffer->row_size_bytes)+xindex);
      bitmap = (((uint8_t*)graphic->addr)+(yindex * graphic->row_size_bytes)+xindex);
      finalBits = *bitmap ^ *bfr;
      // APP_LOG(APP_LOG_LEVEL_DEBUG, "bfr: %0x, bitmsp: %0x, finalBits: %x", (unsigned int)bfr, (unsigned int)bitmap, finalBits );
      
      *bfr = finalBits;
    }
  }

  graphics_release_frame_buffer(ctx, framebuffer);
  
}
/*
 * Draws linear gradient using direct frame buffer access.
 *
 * This function isn't being used directly by any layer. Instead, update_proc_frame_buffer_1()
 * and update_proc_frame_buffer_20() will call it before they draw additional information.
 */
static void update_proc_frame_buffer(Layer *layer, GContext *ctx) {
  // obtains direct access to the frame buffer,
  // determines gray_ values per row
  // calculates dithering pattern for the row, and
  // sets all pixels of the row at once

  // obtain frame buffer (must be released, again using graphics_release_frame_buffer!)
  GBitmap *fb = graphics_capture_frame_buffer(ctx);

  // during the loop, row always points to the byte of the first 8 pixels of the current row
  uint8_t *row = (uint8_t *)fb->addr;
  row += fb->bounds.origin.y * fb->row_size_bytes;

  for (int16_t y = fb->bounds.origin.y; y < fb->bounds.size.h; y++) {
    const uint8_t row_gray = gray_for_row(y);

    // as our dither pattern repeats itself after 8 pixels (8x8 dither matrix), we can store the
    // whole pattern of this row in a single byte and set all pixels with a single call to memset
    uint8_t row_gray_dither_pattern = dither_pattern_8(y, row_gray);
    memset(row, row_gray_dither_pattern, fb->row_size_bytes);

    // move row pointer to the start of the next row
    row += fb->row_size_bytes;
  }

  // do not forget to release the frame buffer after usage. Other graphics_* functions are blocked
  // while it is capture.
  graphics_release_frame_buffer(ctx, fb);
}
Example #3
0
void gpath_draw_outline_antialiased(GContext* ctx, GPath *path, GColor8 stroke_color){
	if(path->num_points == 0)
		return;	

	GPoint offset = path->offset;
	int32_t rotation = path->rotation;
	GBitmap* bitmap = graphics_capture_frame_buffer(ctx);

  	int32_t s = sin_lookup(rotation);
  	int32_t c = cos_lookup(rotation);

	GPoint p = path->points[path->num_points-1];
	GPoint p1;
  	p1.x = (p.x * c - p.y * s) / TRIG_MAX_RATIO + offset.x;
  	p1.y = (p.x * s + p.y * c) / TRIG_MAX_RATIO + offset.y;

	for(uint32_t i=0; i<path->num_points; i++){
		GPoint p2;
		p2.x = (path->points[i].x * c - path->points[i].y * s) / TRIG_MAX_RATIO  + offset.x;
		p2.y = (path->points[i].x * s + path->points[i].y * c) / TRIG_MAX_RATIO  + offset.y;
		draw_line_antialias_(bitmap, p1.x, p1.y, p2.x, p2.y, stroke_color);
		p1 = p2;
	}

	graphics_release_frame_buffer(ctx, bitmap);
}
Example #4
0
static void offscreen_layer_update(Layer* layer, GContext *ctx) {
  if (data_loaded) {
    GRect bounds = layer_get_bounds(layer);

    // Draw the night slice
    const GRect entire_screen = GRect(0, 0, 180, 180);

    graphics_context_set_fill_color(ctx, GColorWhite);
    graphics_fill_radial(
      ctx, entire_screen, 
      GOvalScaleModeFillCircle,
      90,
      DEG_TO_TRIGANGLE(degreeify(hour_set, minute_set)),
      DEG_TO_TRIGANGLE(degreeify(hour_rise, minute_rise))
    );

    // Capture the graphics context framebuffer
    GBitmap *framebuffer = graphics_capture_frame_buffer(ctx);

    bitmap_make_transparent(stars, framebuffer);

    // Release the framebuffer now that we are free to modify it
    graphics_release_frame_buffer(ctx, framebuffer);
  }
}
Example #5
0
void graphics_draw_line_antialiased(GContext* ctx, GPoint p0, GPoint p1, GColor8 stroke_color){
	if(p0.x == p1.x || p0.y == p1.y){
		graphics_draw_line(ctx, p0, p1);
	}
	else {
		GBitmap* bitmap = graphics_capture_frame_buffer(ctx);
		draw_line_antialias_(bitmap, p0.x, p0.y, p1.x, p1.y, stroke_color);
		graphics_release_frame_buffer(ctx, bitmap);
	}
}
Example #6
0
static void update_proc_round_frame_buffer(Layer *layer, GContext *ctx) {
  GBitmap *fb = graphics_capture_frame_buffer(ctx);
  GRect bounds = layer_get_bounds(layer);
  for(int y = 0; y < bounds.size.h; y++) {
    GBitmapDataRowInfo info = gbitmap_get_data_row_info(fb, y);
    for(int x = info.min_x; x < info.max_x; x++) {
      memset(&info.data[x], rand(), 1);
    }
  }
  graphics_release_frame_buffer(ctx, fb);
}
Example #7
0
static void layer_update_proc(Layer *layer, GContext *ctx) {
  int length_red, length_blue, length_green, x, y;
  GColor bar_color;
  
  // Get the framebuffer
  GBitmap *fb = graphics_capture_frame_buffer(ctx);

  // Manipulate the image data...
  
  GBitmapDataRowInfo info = gbitmap_get_data_row_info(fb, BAR_BEGINNING);
  length_red =  s_temperature * (info.max_x - info.min_x) / RANGE_RED;
  length_green = s_batt * (info.max_x - info.min_x) / RANGE_GREEN;
  length_blue = s_pop * (info.max_x - info.min_x) / RANGE_BLUE;
  int temp_red = length_red + (info.max_x - info.min_x);
//  int bar_length = info.max_x - info.min_x;

  // Iterate over desired rows
  for(y = BAR_BEGINNING; y < BAR_END; y++) {
    // Get this row's range and data
    info = gbitmap_get_data_row_info(fb, y);
    
    // Iterate over all visible columns
    if (0 <= length_red) {
      for(x = info.min_x; x < info.max_x; x++) {
        bar_color.argb = 0b11000000;
        
        if (x < length_red) { bar_color.argb = bar_color.argb | 0b00110000; }
        if (x < length_green) { bar_color.argb = bar_color.argb | 0b00001100; }
        if (x < length_blue) { bar_color.argb = bar_color.argb | 0b00000011; }
        
        // Manipulate the pixel at x,y
        set_pixel_color(info, GPoint(x, y), bar_color);
      }
    }
    else {
      for(x = info.min_x; x < info.max_x; x++) {
        bar_color.argb = 0b11000000;
        
        if (x > temp_red) { bar_color.argb = bar_color.argb | 0b00110000; }
        if (x < length_green) { bar_color.argb = bar_color.argb | 0b00001100; }
        if (x < length_blue) { bar_color.argb = bar_color.argb | 0b00000011; }

        // Manipulate the pixel at x,y
        set_pixel_color(info, GPoint(x, y), bar_color);
      }
    }
  }
  
  // Finally, release the framebuffer
  graphics_release_frame_buffer(ctx, fb);
}
static void bg_update_proc(Layer *layer, GContext *ctx) {
	if(!is_encoding) {
		is_encoding = true;
		GBitmap *fb = graphics_capture_frame_buffer(ctx); 
		APP_LOG(APP_LOG_LEVEL_DEBUG, "Captured framebuffer");
		bmpData(fb);	
		APP_LOG(APP_LOG_LEVEL_DEBUG, "Converted bitmap");
		png_encode((const unsigned char*)imagedata);	
		APP_LOG(APP_LOG_LEVEL_DEBUG, "Encoded PNG");
		graphics_release_frame_buffer(ctx, fb); 
		APP_LOG(APP_LOG_LEVEL_DEBUG, "Released framebuffer");	
		//is_encoding = false;
	}

}
Example #9
0
static void update_proc_frame_buffer(Layer *layer, GContext *ctx){
#if defined(PBL_ROUND)
	update_proc_round_frame_buffer(layer, ctx);
#else
  GBitmap *fb = graphics_capture_frame_buffer(ctx);
	if (fb!=NULL){
	  GRect bounds=gbitmap_get_bounds(fb);
	  uint8_t *pos = gbitmap_get_data(fb);
	  for (int16_t y = bounds.origin.y; y < bounds.size.h; y++) {
		  for (int16_t x = bounds.origin.x; x < gbitmap_get_bytes_per_row(fb); x++){
			  memset(++pos, rand(), 1);
		  }
    }
	  graphics_release_frame_buffer(ctx, fb);
  }
#endif
}
static void render_layer_update(Layer* layer, GContext *ctx) {
  GRect bounds = layer_get_bounds(layer);

  // Capture the graphics context framebuffer
  GBitmap *framebuffer = graphics_capture_frame_buffer(ctx);

  //backup old framebuffer format data
  uint8_t *orig_addr = gbitmap_get_data(framebuffer);
  GBitmapFormat orig_format = gbitmap_get_format(framebuffer);
  uint16_t orig_stride = gbitmap_get_bytes_per_row(framebuffer);

  //Release the framebuffer now that we are free to modify it
  graphics_release_frame_buffer(ctx, framebuffer);

#if 0 // BUG: Currently not working
  GBitmap *render_bitmap = gbitmap_create_blank(bounds.size, GBitmapFormat8BitCircular);
#else
  GBitmap *render_bitmap = gbitmap_create_blank(bounds.size, GBitmapFormat8Bit);
#endif

  //replace screen bitmap with our offscreen render bitmap
  gbitmap_set_data(framebuffer, gbitmap_get_data(render_bitmap),
    gbitmap_get_format(render_bitmap), gbitmap_get_bytes_per_row(render_bitmap), false);

  graphics_context_set_compositing_mode(ctx, GCompOpAssign);
  digital_update_proc(layer, ctx);

  //restore original context bitmap
  gbitmap_set_data(framebuffer, orig_addr, orig_format, orig_stride, false);

  //draw the bitmap to the screen
  graphics_context_set_compositing_mode(ctx, GCompOpSet);
  // Make the render_bitmap transparent
  bitmap_make_semi_transparent(render_bitmap);
  graphics_draw_bitmap_in_rect(ctx, render_bitmap, bounds);
  gbitmap_destroy(render_bitmap);
}
Example #11
0
static void draw_row_callback(GContext *ctx, Layer *cell_layer, MenuIndex *idx, void *context) {
  GRect bounds = layer_get_bounds(cell_layer);

#if defined(PBL_ROUND)
  // get info of pixel row in the middle of menu row
  GBitmap *fb = graphics_capture_frame_buffer(ctx);
  GPoint sc_coord = layer_convert_point_to_screen(cell_layer, GPoint(0, bounds.size.h/2));
  GBitmapDataRowInfo info = gbitmap_get_data_row_info(fb, sc_coord.y);
  graphics_release_frame_buffer(ctx, fb);
  // adapt bounds for round displays
  bounds.origin.x = info.min_x + PADDING;
  bounds.size.w = info.max_x - info.min_x - PADDING;
#endif

  GRect frame = GRect(
      bounds.origin.x + ICON_SIZE + 3*PADDING,
      0,
      bounds.size.w - 2*ICON_SIZE - PADDING,
      bounds.size.h/2
      );

  // draw direction
  // expand frame width if countdown on the right is small
  if(deps_items[idx->row].countdown > 0 && deps_items[idx->row].countdown < 10) {
    frame.size.w += 10;
  }
  graphics_draw_text(ctx,
      deps_items[idx->row].direction,
      fonts_get_system_font(FONT_KEY_GOTHIC_14),
      frame,
      GTextOverflowModeTrailingEllipsis,
      GTextAlignmentLeft,
      NULL);

  // draw time of scheduled departure plus delay
  frame.origin.y += 12;
  graphics_draw_text(ctx,
      deps_items[idx->row].time,
      fonts_get_system_font(FONT_KEY_GOTHIC_18),
      frame,
      GTextOverflowModeTrailingEllipsis,
      GTextAlignmentLeft,
      NULL);

  // draw time until real time departure
  frame.origin.x = bounds.origin.x + bounds.size.w - ICON_SIZE - PADDING;
  frame.origin.y = 0;
  frame.size.w = ICON_SIZE;
  frame.size.h = ICON_SIZE;
  if(deps_items[idx->row].countdown == 0) {
    // draw icon if departure is imminent
    char* icon_number;
    if (strcmp(deps_items[idx->row].icon, "bus") == 0) {
      icon_number = "1";
    } else if (strcmp(deps_items[idx->row].icon, "tram") == 0) {
      icon_number = "2";
    } else if (strcmp(deps_items[idx->row].icon, "train") == 0) {
      icon_number = "3";
    } else if (strcmp(deps_items[idx->row].icon, "boat") == 0) {
      icon_number = "4";
    } else if (strcmp(deps_items[idx->row].icon, "funicular") == 0) {
      icon_number = "5";
    } else if (strcmp(deps_items[idx->row].icon, "cable_car") == 0) {
      icon_number = "6";
    } else {
      icon_number = "";
    }
    frame.origin.x = bounds.origin.x + bounds.size.w - ICON_SIZE;
    frame.origin.y = 0;
    frame.size.w = ICON_SIZE+2;
    frame.size.h = ICON_SIZE;
    graphics_draw_text(ctx,
        icon_number,
        s_icons,
        frame,
        GTextOverflowModeWordWrap,
        GTextAlignmentCenter,
        NULL);
  } else {
    static char s_buff[16];
    if(deps_items[idx->row].countdown > 60) {
      strncpy(s_buff, ">1h", 16);
    } else if(deps_items[idx->row].countdown > 0) {
      snprintf(s_buff, sizeof(s_buff), "%d'", deps_items[idx->row].countdown);
    }
    graphics_draw_text(ctx,
        s_buff,
        fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD),
        frame,
        GTextOverflowModeFill,
        GTextAlignmentRight,
        NULL);
  }

  // draw line icon with colors
  frame.origin.x = bounds.origin.x + PADDING;
  frame.origin.y = (bounds.size.h / 2) - (ICON_SIZE / 2);
  frame.size.w = ICON_SIZE;
  frame.size.h = ICON_SIZE;

  GColor color_bg;
  // correct some coloring
  switch(deps_items[idx->row].color_bg) {
    case 9090335 : color_bg = GColorSpringBud; break;
    case 12703135 : color_bg = GColorInchworm; break;
    default : color_bg = GColorFromHEX(deps_items[idx->row].color_bg);
  }
  GColor color_fg = GColorFromHEX(deps_items[idx->row].color_fg);
  graphics_context_set_fill_color(ctx, COLOR_FALLBACK(color_bg, GColorClear));
  graphics_fill_rect(ctx, frame, 3, GCornersAll);
  if(!gcolor_equal(color_bg, GColorWhite) || menu_cell_layer_is_highlighted(cell_layer)) {
    graphics_context_set_stroke_color(ctx, COLOR_FALLBACK(GColorWhite, GColorClear));
  }
  graphics_draw_round_rect(ctx, frame, 3);
  graphics_context_set_text_color(ctx, COLOR_FALLBACK(color_fg, GColorBlack));
  char * name = deps_items[idx->row].name;
  GFont font;
  if(strlen(name) == 1) {
    frame.origin.x += 1;
    frame.origin.y += 3;
    /*font = fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD);*/
    font = s_helvetic_bold;
  } else if(strlen(name) == 2) {
    // correct position if 2nd digit is "1"
    if (strstr(name+1, "1") != NULL) {
      frame.origin.x += 2;
    }
    frame.origin.y += 3;
    /*font = fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD);*/
    font = s_helvetic_bold;
    /*if(strlen(name) == 1) { frame.origin.x += 1; }*/
  } else if(strlen(name) == 3){
    frame.origin.y += 3;
    font = fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD);
  } else {
    frame.origin.y += 6;
    font = fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD);
  }

  graphics_draw_text(ctx,
      name,
      font,
      frame,
      GTextOverflowModeFill,
      GTextAlignmentCenter,
      NULL);
}
Example #12
0
static void gpath_draw_filled_custom(GContext* ctx, GPath *path, GColor8 fill_color){
	if(path->num_points == 0)
		return;	

	GPoint offset = path->offset;
	int32_t rotation = path->rotation;

	int32_t s = sin_lookup(rotation);
  	int32_t c = cos_lookup(rotation);

  	// Rotate each point of the gpath and memorize the min/max
	GPoint* points_rot = malloc(sizeof(GPoint) * path->num_points);
	GPoint top_right = (GPoint){(1 << 15)-1,(1 << 15)-1};
	GPoint bottom_left= (GPoint){-(1 << 15),-(1 << 15)};

  	for(uint32_t i=0; i<path->num_points; i++){
  		points_rot[i].x = (path->points[i].x * c - path->points[i].y * s) / TRIG_MAX_RATIO  + offset.x;
		points_rot[i].y = (path->points[i].x * s + path->points[i].y * c) / TRIG_MAX_RATIO  + offset.y;
		if(points_rot[i].x > bottom_left.x)
			bottom_left.x = points_rot[i].x;
		if(points_rot[i].x < top_right.x)
			top_right.x = points_rot[i].x;
		if(points_rot[i].y > bottom_left.y)
			bottom_left.y = points_rot[i].y;
		if(points_rot[i].y < top_right.y)
			top_right.y = points_rot[i].y;
  	}

  	// Create an array bitmap pebble v2 style (1 bit equals 1 pixel)
  	int32_t bytes_per_row = (bottom_left.x - top_right.x + 1) / 8 + ((bottom_left.x - top_right.x  + 1) % 8 == 0 ? 0 : 1);
  	int32_t h = bottom_left.y - top_right.y + 1;
  	uint8_t* pixels = malloc(bytes_per_row * h);
  	memset(pixels, 0, bytes_per_row * h);

  	// And draw the outline path in this 1 bit image
  	GPoint prev_p = points_rot[path->num_points - 1];
  	GPoint p;
  	for(uint32_t i=0; i<path->num_points; i++){
  		p = points_rot[i];
  		bmpDrawLine(pixels, bytes_per_row, prev_p.x - top_right.x, prev_p.y - top_right.y, p.x - top_right.x, p.y - top_right.y);
  		prev_p = p;
  	}

  	free(points_rot);

  	// Compute the starting point for the flow fill algorithm 
  	// TODO tobe improved
  	GPoint start;
  	start.x = (points_rot[0].x + points_rot[1].x) / 2;
  	start.y = (points_rot[0].y + points_rot[1].y) / 2;

  	if(points_rot[0].x < points_rot[1].x){
  		if(points_rot[0].y < points_rot[1].y){
  			start.x--;
  			start.y++;
  		}
  		else {
  			start.x++;
  			start.y++;
  		}
  	}
  	else {
  		if(points_rot[0].y < points_rot[1].y){
  			start.x--;
  			start.y--;
  		}
  		else {
  			start.x++;
  			start.y--;
  		}
  	}

  	// Capture the frame buffer
  	GBitmap* bitmap = graphics_capture_frame_buffer(ctx);

  	// flood fill the gpath
  	floodFill(bitmap, pixels, bytes_per_row, start, top_right, fill_color);

  	// Release the frame buffer
  	graphics_release_frame_buffer(ctx, bitmap);  	

  	//Release the working variables
  	free(pixels);
}