pebble/tests/fw/graphics/test_graphics_draw_rotated_bitmap.c
2025-01-27 11:38:16 -08:00

355 lines
16 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "applib/graphics/framebuffer.h"
#include "applib/graphics/graphics.h"
#include "applib/graphics/gtypes.h"
#include "util/trig.h"
#include "applib/ui/layer.h"
#include "applib/ui/window_private.h"
#include "clar.h"
#include "util.h"
#include <stdio.h>
// Helper Functions
////////////////////////////////////
#include "test_graphics.h"
#if SCREEN_COLOR_DEPTH_BITS == 1
#include "1bit/test_framebuffer.h"
#else
#include "8bit/test_framebuffer.h"
#endif
// Stubs
////////////////////////////////////
#include "graphics_common_stubs.h"
#include "stubs_applib_resource.h"
///////////////////////////////////////////////////////////
// Fakes
#include "fake_gbitmap_get_data_row.h"
// Setup
////////////////////////////////////
static GBitmap *test_image_bw;
static GBitmap *test_image_color;
static FrameBuffer *fb = NULL;
#if SCREEN_COLOR_DEPTH_BITS == 1
extern bool get_bitmap_bit(GBitmap *bmp, int x, int y);
#elif SCREEN_COLOR_DEPTH_BITS == 8
extern GColor get_bitmap_color(GBitmap *bmp, int x, int y);
#endif
void test_graphics_draw_rotated_bitmap__initialize(void) {
s_fake_data_row_handling = false;
fb = malloc(sizeof(FrameBuffer));
framebuffer_init(fb, &(GSize) {DISP_COLS, DISP_ROWS});
test_image_bw = get_gbitmap_from_pbi("test_rotated_bitmap_no_litter.Xbit.pbi");
cl_assert(test_image_bw != NULL);
test_image_color = get_gbitmap_from_pbi("test_rotated_bitmap_redstar.Xbit.pbi");
cl_assert(test_image_color != NULL);
}
void test_graphics_draw_rotated_bitmap__cleanup(void) {
free(fb);
if (test_image_bw) {
if (test_image_bw->addr) {
free(test_image_bw->addr);
}
free(test_image_bw);
}
if (test_image_color) {
if (test_image_color->addr) {
free(test_image_color->addr);
}
free(test_image_color);
}
}
static void setup_test_rotate_bitmap(GContext *ctx, FrameBuffer *fb,
GRect clip_box, GRect drawing_box,
GCompOp compositing_mode) {
test_graphics_context_reset(ctx, fb);
GDrawState draw_state = {
.clip_box = clip_box,
.drawing_box = drawing_box,
.compositing_mode = compositing_mode,
};
setup_test_context(ctx,
(CTX_FLAG_DS_CLIP_BOX | CTX_FLAG_DS_DRAWING_BOX |
CTX_FLAG_DS_COMPOSITING_MODE),
&draw_state, NULL);
}
#define ORIGIN_RECT_NO_CLIP GRect(0, 0, DISP_COLS, DISP_ROWS)
// Tests
////////////////////////////////////
void test_graphics_draw_rotated_bitmap__get_color(void) {
#if SCREEN_COLOR_DEPTH_BITS == 1
cl_check(get_bitmap_bit(test_image_bw, 8, 16) == 1);
cl_check(get_bitmap_bit(test_image_bw, 8, 24) == 0);
cl_check(get_bitmap_bit(test_image_color, 30, 2) == 0);
cl_check(get_bitmap_bit(test_image_color, 30, 10) == 0);
cl_check(get_bitmap_bit(test_image_color, 30, 30) == 1);
#elif SCREEN_COLOR_DEPTH_BITS == 8
cl_check(gcolor_equal(get_bitmap_color(test_image_bw, 8, 16), GColorWhite));
cl_check(gcolor_equal(get_bitmap_color(test_image_bw, 8, 24), GColorBlack));
cl_check(gcolor_equal(get_bitmap_color(test_image_color, 30, 2), GColorClear));
cl_check(gcolor_equal(get_bitmap_color(test_image_color, 30, 10), GColorRed));
cl_check(gcolor_equal(get_bitmap_color(test_image_color, 30, 30), GColorScreaminGreen));
#endif
}
void test_graphics_draw_rotated_bitmap__origin_bw_assign(void) {
GContext ctx;
test_graphics_context_init(&ctx, fb);
// No Clip, Angle 0
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_bw,
GPointZero, DEG_TO_TRIGANGLE(0), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_origin_bw_assign_0.Xbit.pbi"));
// Top-left corner rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_bw,
GPointZero, DEG_TO_TRIGANGLE(45), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap,
"draw_rotated_bitmap_origin_bw_assign_corner_45.Xbit.pbi"));
// Top-left center rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_bw,
GPoint(27, 40), DEG_TO_TRIGANGLE(45), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap,
"draw_rotated_bitmap_origin_bw_assign_center_45.Xbit.pbi"));
}
void test_graphics_draw_rotated_bitmap__origin_bw_set(void) {
GContext ctx;
test_graphics_context_init(&ctx, fb);
// No Clip, Angle 0
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpSet);
graphics_draw_rotated_bitmap(&ctx, test_image_bw,
GPointZero, DEG_TO_TRIGANGLE(0), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_origin_bw_set_0.Xbit.pbi"));
// Top-left corner rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpSet);
graphics_draw_rotated_bitmap(&ctx, test_image_bw,
GPointZero, DEG_TO_TRIGANGLE(45), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap,
"draw_rotated_bitmap_origin_bw_set_corner_45.Xbit.pbi"));
// Top-left center rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpSet);
graphics_draw_rotated_bitmap(&ctx, test_image_bw,
GPoint(27, 40), DEG_TO_TRIGANGLE(45), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap,
"draw_rotated_bitmap_origin_bw_set_center_45.Xbit.pbi"));
}
void test_graphics_draw_rotated_bitmap__offset_bw(void) {
GContext ctx;
test_graphics_context_init(&ctx, fb);
// No Clip, Angle 0, Offset
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_bw,
GPointZero, DEG_TO_TRIGANGLE(0), GPoint(20, 20));
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_offset_bw_0.Xbit.pbi"));
// Top-left corner rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_bw,
GPointZero, DEG_TO_TRIGANGLE(45), GPoint(20, 20));
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_offset_bw_corner_45.Xbit.pbi"));
// Top-left center rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_bw,
GPoint(27, 40), DEG_TO_TRIGANGLE(45), GPoint(20, 20));
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_offset_bw_center_45.Xbit.pbi"));
}
void test_graphics_draw_rotated_bitmap__origin_color_assign(void) {
GContext ctx;
test_graphics_context_init(&ctx, fb);
// No Clip, Angle 0
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPointZero, DEG_TO_TRIGANGLE(0), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_origin_color_assign_0.Xbit.pbi"));
// Top-left corner rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPointZero, DEG_TO_TRIGANGLE(45), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap,
"draw_rotated_bitmap_origin_color_assign_corner_45.Xbit.pbi"));
// Top-left center rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPoint(30, 30), DEG_TO_TRIGANGLE(45), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap,
"draw_rotated_bitmap_origin_color_assign_center_45.Xbit.pbi"));
// Test transparency
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_context_set_fill_color(&ctx, GColorBlue);
graphics_fill_rect(&ctx, &GRect(0, 0, 20, 10));
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPoint(30, 30), DEG_TO_TRIGANGLE(45), GPointZero);
cl_check(gbitmap_pbi_eq(
&ctx.dest_bitmap,
"draw_rotated_bitmap_origin_color_assign_center_45_transparent.Xbit.pbi"));
}
void test_graphics_draw_rotated_bitmap__origin_color_set(void) {
GContext ctx;
test_graphics_context_init(&ctx, fb);
// No Clip, Angle 0
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpSet);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPointZero, DEG_TO_TRIGANGLE(0), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_origin_color_set_0.Xbit.pbi"));
// Top-left corner rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpSet);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPointZero, DEG_TO_TRIGANGLE(45), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap,
"draw_rotated_bitmap_origin_color_set_corner_45.Xbit.pbi"));
// Top-left center rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpSet);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPoint(30, 30), DEG_TO_TRIGANGLE(45), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap,
"draw_rotated_bitmap_origin_color_set_center_45.Xbit.pbi"));
// Test transparency
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpSet);
graphics_context_set_fill_color(&ctx, GColorBlue);
graphics_fill_rect(&ctx, &GRect(0, 0, 20, 10));
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPoint(30, 30), DEG_TO_TRIGANGLE(45), GPointZero);
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap,
"draw_rotated_bitmap_origin_color_set_center_45_transparent.Xbit.pbi"));
}
void test_graphics_draw_rotated_bitmap__offset_color(void) {
GContext ctx;
test_graphics_context_init(&ctx, fb);
// No Clip, Angle 0
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPointZero, DEG_TO_TRIGANGLE(0), GPoint(20, 20));
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_offset_color_0.Xbit.pbi"));
// Top-left corner rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPointZero, DEG_TO_TRIGANGLE(45), GPoint(20, 20));
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_offset_color_corner_45.Xbit.pbi"));
// Top-left center rotation point, Angle 45
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPoint(30, 30), DEG_TO_TRIGANGLE(45), GPoint(20, 20));
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_offset_color_center_45.Xbit.pbi"));
}
void test_graphics_draw_rotated_bitmap__offset_edge(void) {
GContext ctx;
test_graphics_context_init(&ctx, fb);
// bottom edge center rotation point, Angle 2
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPoint(30, 59), DEG_TO_TRIGANGLE(2), GPoint(72, 84));
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_offset_bottomedge_2.Xbit.pbi"));
// top edge center rotation point, Angle 2
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPoint(30, 1), DEG_TO_TRIGANGLE(2), GPoint(72, 84));
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_offset_topedge_2.Xbit.pbi"));
// left edge center rotation point, Angle 2
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPoint(1, 30), DEG_TO_TRIGANGLE(2), GPoint(72, 84));
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_offset_leftedge_2.Xbit.pbi"));
// right edge center rotation point, Angle 2
setup_test_rotate_bitmap(&ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(&ctx, test_image_color,
GPoint(59, 30), DEG_TO_TRIGANGLE(2), GPoint(72, 84));
cl_check(gbitmap_pbi_eq(&ctx.dest_bitmap, "draw_rotated_bitmap_offset_rightedge_2.Xbit.pbi"));
}
void test_graphics_draw_rotated_bitmap__data_row_handling(void) {
// Enable fake data row handling which will override the gbitmap_get_data_row_xxx() functions
// with their fake counterparts in fake_gbitmap_get_data_row.c
s_fake_data_row_handling = true;
s_fake_data_row_handling_disable_vertical_flip = true;
GContext *ctx = malloc(sizeof(GContext));
test_graphics_context_init(ctx, fb);
framebuffer_clear(fb);
GBitmap *test_image = get_gbitmap_from_pbi("stamp.Xbit.pbi");
cl_assert(test_image != NULL);
// PBL-24705 grect_center_point is off by 1
GPoint center = GPoint(DISP_COLS / 2 - 1, DISP_ROWS / 2 - 1);
// No Clip, Angle 0
setup_test_rotate_bitmap(ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(ctx, test_image, GPoint(
test_image->bounds.size.w / 2 - 1,
test_image->bounds.size.h / 2 - 1),
DEG_TO_TRIGANGLE(0), center);
cl_check(gbitmap_pbi_eq(&ctx->dest_bitmap, "draw_rotated_bitmap_stamp_0deg.Xbit.pbi"));
// Top-left corner rotation point, Angle 45
setup_test_rotate_bitmap(ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(ctx, test_image,
GPoint(71, 71), DEG_TO_TRIGANGLE(45), center);
cl_check(gbitmap_pbi_eq(&ctx->dest_bitmap, "draw_rotated_bitmap_stamp_45deg.Xbit.pbi"));
// Top-left corner rotation point, Angle 180
setup_test_rotate_bitmap(ctx, fb, ORIGIN_RECT_NO_CLIP, ORIGIN_RECT_NO_CLIP, GCompOpAssign);
graphics_draw_rotated_bitmap(ctx, test_image,
GPoint(71, 71), DEG_TO_TRIGANGLE(180), center);
cl_check(gbitmap_pbi_eq(&ctx->dest_bitmap, "draw_rotated_bitmap_stamp_180deg.Xbit.pbi"));
}