/*############################################################################# ## Author: Shaun Reed ## ## Legal: All Content (c) 2025 Shaun Reed, all rights reserved ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ## ############################################################################## */ /** * Calculate byte offset for the pixel at [x,y] within a horizontally-mapped * monochrome uint8 draw buffer, using the initialized horizontal resolution. * * We use `>> 3` because each pixel requires 1 bit, but each uint8 in the draw * buffer can hold 8 bits. To find the uint8 value in our draw buffer that * stores this pixel's value we must compensate for this when using pixel * coordinates in byte math. * * Therefore, each uint8 in the draw buffer stores the state of 8 pixels. * Below is an example of calculating for [x, y] pixel coordinates [20, 10]. * The example uses a horizontal resolution of 128. * * For the horizontal case, each row (y) of the image is represented by * `hor_res >> 3` bytes (16). The byte-offset of the first pixel in the 10th * row for example is `16 * 10` = 160. * * Since the pixels are stored horizontally we must calculate the 20th pixel * column (x) as `160 + (20 >> 3)`, or `160 + (20 / 8)` to get a final offset * of 162. * * @param x X pixel coordinate to find byte offset. * @param y Y pixel coordinate to find byte offset. * @param hor_res horizontal resolution of the display. * @return byte offset for a single-byte monochrome pixel at [x,y]. */ static ptrdiff_t horizontal_byte_offset_long(const int32_t x, const int32_t y, const int32_t hor_res) { // Convert pixel (bit) coordinates to byte coordinates in the draw buffer. return (hor_res >> 3) * y + (x >> 3); } /** * Calculate byte offset for the pixel at [x,y] within a vertically-mapped * monochrome uint8 draw buffer, using the initialized horizontal resolution. * * We use `>> 3` because each pixel requires 1 bit, but each uint8 in the draw * buffer can hold 8 bits. To find the uint8 value in our draw buffer that * stores this pixel's value we must compensate for this when using pixel * coordinates in byte math. * * Therefore, each uint8 in the draw buffer stores the state of 8 pixels. * Below is an example of calculating for [x, y] pixel coordinates [20, 10]. * The example uses a horizontal resolution of 128. * * For the vertical case, each row (y) of the image is represented by * `hor_res` bytes (128) - one for each column (x). Because the pixels are * stored vertically, the byte-offset of the first pixel in the 10th row is * `128 * (10 >> 3)` or * `128 * (10 / 8)` = 128. * * From this location we can simply calculate the 20th pixel column (x) as * `128 + 20` to get a final offset of 148, because the pixels are stored in a * columnar format. * * @param x X pixel coordinate to find byte offset. * @param y Y pixel coordinate to find byte offset. * @param hor_res horizontal resolution of the display. * @return byte offset for a single-byte monochrome pixel at [x,y]. */ static ptrdiff_t vertical_byte_offset_long(const int32_t x, const int32_t y, const int32_t hor_res) { // Convert pixel (bit) coordinates to byte coordinates in the draw buffer. return hor_res * (y >> 3) + x; } /** * Finds the Most Significant Bit location of bit `i` in a byte. * * MSB LSB * bits 7 6 5 4 3 2 1 0 * data 8 7 6 5 4 3 2 1 * Left Right * * @return bitmask for MSB location of `i`. */ static uint8_t msb_mask(const int32_t i) { return 1 << (7 - i % 8); } /** * Finds the Least Significant Bit location of bit `i` in a byte. * * LSB MSB * bits 0 1 2 3 4 5 6 7 * data 1 2 3 4 5 6 7 8 * Left Right * * @return bitmask for LSB location of `i`. */ static uint8_t lsb_mask(const int32_t i) { return 1 << (i % 8); }