/* * 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. */ #pragma once #include "gtypes.h" #include "text_layout_private.h" #include "text_resources.h" #define GDRAWMASK_BITS_PER_PIXEL PBL_IF_COLOR_ELSE(2, 1) #define GDRAWMASK_PIXELS_PER_BYTE (8 / GDRAWMASK_BITS_PER_PIXEL) //! @internal typedef struct FrameBuffer FrameBuffer; //! @internal typedef struct GContext { GBitmap dest_bitmap; //! Which framebuffer dest_bitmap points into. This may be null if the //! bitmap doesn't point into a framebuffer. FrameBuffer* parent_framebuffer; //! Number of rows between the top of the dest_bitmap and the top of it's //! parent framebuffer. This value is invalid if parent_framebuffer is null. uint8_t parent_framebuffer_vertical_offset; // Keep state here for drawing commands: GDrawState draw_state; TextDrawState text_draw_state; FontCache font_cache; //! When the frame buffer accessed directly all graphics functions using this //! context are locked bool lock; } GContext; //! @internal typedef enum { GContextInitializationMode_App, GContextInitializationMode_System, } GContextInitializationMode; //! @internal typedef enum { //! Pixels within the range are considered to be fully opaque GDrawMaskRowInfoType_Opaque, //! The opacity of the pixels within the range varies and needs individual checks GDrawMaskRowInfoType_SemiTransparent, } GDrawMaskRowInfoType; //! @internal //! Describes mask values for a given scan line. //! The sole purpose of this data structure is performance optimization so that callers don't need //! to test every single pixel on a GDrawMask's pixel_mask_data. typedef struct { //! Describes how to treat the range between .min_x and .max_x GDrawMaskRowInfoType type; //! Left-most pixel, 3.0 means that pixel 3 is fully visible, 3.5 means it's half visible Fixed_S16_3 min_x; //! Right-most pixel, 10.7 means that pixel 10 is fully opaque Fixed_S16_3 max_x; } GDrawMaskRowInfo; //! @internal //! Describes how draw operations in GDrawRawImplementation should treat the final opacity //! conceptually. Each pixel's alpha value should be multiplied with the corresponding //! .pixel_mask_data of this struct. typedef struct GDrawMask { //! Describes the mask values for each of the scan lines GDrawMaskRowInfo *mask_row_infos; //! Pixel mask that follows the structure and size of the actual framebuffer void *pixel_mask_data; //! A contiguous block of data that contains .row_infos and .pixel_mask_data uint8_t data[]; } GDrawMask; //! @addtogroup Graphics //! @{ //! @addtogroup GraphicsContext Graphics Context //! \brief The "canvas" into which an application draws //! //! The Pebble OS graphics engine, inspired by several notable graphics systems, including //! Apple’s Quartz 2D and its predecessor QuickDraw, provides your app with a canvas into //! which to draw, namely, the graphics context. A graphics context is the target into which //! graphics functions can paint, using Pebble drawing routines (see \ref Drawing, //! \ref PathDrawing and \ref TextDrawing). //! //! A graphics context holds a reference to the bitmap into which to paint. It also holds the //! current drawing state, like the current fill color, stroke color, clipping box, drawing box, //! compositing mode, and so on. The GContext struct is the type representing the graphics context. //! //! For drawing in your Pebble watchface or watchapp, you won't need to create a GContext //! yourself. In most cases, it is provided by Pebble OS as an argument passed into a render //! callback (the .update_proc of a Layer). //! //! Your app can’t call drawing functions at any given point in time: Pebble OS will request your //! app to render. Typically, your app will be calling out to graphics functions in //! the .update_proc callback of a Layer. //! @see \ref Layer //! @see \ref Drawing //! @see \ref PathDrawing //! @see \ref TextDrawing //! @{ //! @internal void graphics_context_init(GContext *ctx, FrameBuffer *framebuffer, GContextInitializationMode init_mode); //! @internal void graphics_context_set_default_drawing_state(GContext *ctx, GContextInitializationMode init_mode); //! @internal //! Gets the current drawing state (fill/stroke/text colors, compositing mode, ...) GDrawState graphics_context_get_drawing_state(GContext* ctx); //! @internal //! Sets the current drawing state (fill/stroke/text colors, compositing mode, ...) void graphics_context_set_drawing_state(GContext* ctx, GDrawState draw_state); //! @internal //! Move the drawing box origin by the translation offset specified void graphics_context_move_draw_box(GContext* ctx, GPoint offset); //! Sets the current stroke color of the graphics context. //! @param ctx The graphics context onto which to set the stroke color //! @param color The new stroke color void graphics_context_set_stroke_color(GContext* ctx, GColor color); void graphics_context_set_stroke_color_2bit(GContext* ctx, GColor2 color); //! Sets the current fill color of the graphics context. //! @param ctx The graphics context onto which to set the fill color //! @param color The new fill color void graphics_context_set_fill_color(GContext* ctx, GColor color); void graphics_context_set_fill_color_2bit(GContext* ctx, GColor2 color); //! Sets the current text color of the graphics context. //! @param ctx The graphics context onto which to set the text color //! @param color The new text color void graphics_context_set_text_color(GContext* ctx, GColor color); void graphics_context_set_text_color_2bit(GContext* ctx, GColor2 color); //! Sets the tint color of the graphics context. This is used when drawing under //! the GCompOpOr compositing mode. //! @param ctx The graphics context onto which to set the tint color //! @param color The new tint color void graphics_context_set_tint_color(GContext *ctx, GColor color); //! Sets the current bitmap compositing mode of the graphics context. //! @param ctx The graphics context onto which to set the compositing mode //! @param mode The new compositing mode //! @see \ref GCompOp //! @see \ref bitmap_layer_set_compositing_mode() //! @note At the moment, this only affects the bitmaps drawing operations //! -- \ref graphics_draw_bitmap_in_rect(), \ref graphics_draw_rotated_bitmap, and //! anything that uses those APIs --, but it currently does not affect the filling or stroking //! operations. void graphics_context_set_compositing_mode(GContext* ctx, GCompOp mode); //! Sets whether antialiasing is applied to stroke drawing //! @param ctx The graphics context onto which to set the antialiasing //! @param enable True = antialiasing enabled, False = antialiasing disabled //! @note Default value is true. void graphics_context_set_antialiased(GContext* ctx, bool enable); //! @internal //! Gets whether antialiasing is applied to stroke drawing //! @param ctx The graphics context for which to get the current state of antialiasing //! @return True if antialiasing is enabled, false otherwise bool graphics_context_get_antialiased(GContext *ctx); //! Sets the width of the stroke for drawing routines //! @param ctx The graphics context onto which to set the stroke width //! @param stroke_width Width in pixels of the stroke. //! @note If stroke width of zero is passed, it will be ignored and will not change the value //! stored in GContext. Currently, only odd stroke_width values are supported. If an even value //! is passed in, the value will be stored as is, but the drawing routines will round down to the //! previous integral value when drawing. Default value is 1. void graphics_context_set_stroke_width(GContext* ctx, uint8_t stroke_width); //! Instantiates and initializes a mask. //! @param ctx The graphics context to use to initialize the new mask //! @param transparent Whether the initial mask pixel values should all be transparent or opaque //! @return The new clipping mask, or NULL on failure GDrawMask *graphics_context_mask_create(const GContext *ctx, bool transparent); //! Attaches a mask to the provided GContext for recording. Subsequent drawing operations will //! change the mask values. The luminance of the drawing operations corresponds with the resulting //! opacity in the mask, so the brighter a drawn pixel is, the more opaque its corresponding mask //! value will be. //! @param ctx The GContext to attach the mask to for recording //! @param mask The mask to use for recording //! @return True if the mask was successfully attached to the GContext for recording, false //! otherwise bool graphics_context_mask_record(GContext *ctx, GDrawMask *mask); //! Attaches a mask to the provided GContext and activates it for subsequent drawing operations. //! Upon activation, subsequent drawing operations will be multiplied with the given mask. //! @param ctx The GContext to attach the mask to for use //! @param mask The mask to use //! @return True if the mask was successfully attached to the GContext for use, false otherwise bool graphics_context_mask_use(GContext *ctx, GDrawMask *mask); //! Destroys a previously created mask. //! @param ctx The GContext the mask was used with //! @param mask The mask to destroy void graphics_context_mask_destroy(GContext *ctx, GDrawMask *mask); //! @internal //! Gets the size of the backing framebuffer for the graphics context or GSize(DISP_COLS, DISP_ROWS) //! if there is no backing framebuffer. GSize graphics_context_get_framebuffer_size(GContext *ctx); //! @internal //! Retrieves the destination bitmap for the graphics context. //! @param ctx The graphics context to retrieve the bitmap for. GBitmap* graphics_context_get_bitmap(GContext* ctx); //! @internal //! Updates the parent framebuffers dirty state based on a change to the //! graphic context's bitmap. void graphics_context_mark_dirty_rect(GContext* ctx, GRect rect); //! @} // end addtogroup GraphicsContext //! @} // end addtogroup Graphics