I found myself wanting to draw a sprite but flipped on the x-axis. Yes, I know that for the best performance, I should create the flipped sprite and draw it directly.

Anyway, here's what I came up with at first:

Code:
void draw_x_flipped_sprite(gfx_sprite_t* sprite, int dest_x, int dest_y, bool transparency) {
    char* data     = (char*) sprite;
    uint8_t width  = data[0];
    uint8_t height = data[1];

    for (int y = 0; y < height; y++) {
        int draw_y = dest_y + y;

        // clipping check in the y direction
        if (draw_y < 0 || draw_y >= LCD_HEIGHT) {
            continue;
        }

        for (int x = 0; x < width; x++) {
            int draw_x = dest_x + x;
           
            // clipping check in the x direction
            if (draw_x < 0 || draw_x >= LCD_WIDTH) {
                continue;
            }

            char pixel = data[y * width + width - x + 1];

            // transparency check
            if (transparency && pixel == MAGENTA) {
                continue;
            } else {
                gfx_vbuffer[draw_y][draw_x] = pixel;
            }
        }
    }
}


The above is inefficient: the framerate dropped by 10%. After pleading the #c-on-the-ce channel on the Cemetech Discord, calc84maniac, LogicalJoe, c4ooo, and fghsgh gave me some tips to optimize it a little. I now have this:


Code:
void draw_x_flipped_sprite(gfx_sprite_t* sprite, int dest_x, int dest_y, bool transparency) {
    // kinda optimized compared to the inefficient version
    // thanks, calc84maniac, c4ooo, LogicalJoe, fghsgh!
    // all of you helped me to squeeze a few more frames out

    char* data     = (char*) sprite;
    uint8_t width  = data[0];
    uint8_t height = data[1];

    // clipping checks

    // we might end up drawing out of the bounds of uint8_t in the x direction
    int start_x = 0 > dest_x ? 0 : dest_x;
    int start_y = 0 > dest_y ? 0 : dest_y;
    int end_x   = LCD_WIDTH <= (dest_x + width) ? (LCD_WIDTH - 1) : (dest_x + width);
    int end_y   = LCD_HEIGHT <= (dest_y + width) ? (LCD_HEIGHT - 1) : (dest_y + height);

    int source_x_left_bound   = dest_x < 0 ? (width + dest_x - 1) : 0;
    int source_x_right_bound  = (dest_x + width) >= LCD_WIDTH ? (LCD_WIDTH - dest_x) : width;
    int source_y_top_bound    = dest_y < 0 ? (height + dest_y - 1) : 0;
    int source_y_bottom_bound = (dest_y + height) >= LCD_HEIGHT ? (LCD_HEIGHT - dest_y) : height;

    int source_pixel_pointer     = source_y_top_bound * width + 1;
    uint8_t* destination_pointer = &(gfx_vbuffer[start_y][start_x]);
    int destination_offset       = &(gfx_vbuffer[1][start_x]) - &(gfx_vbuffer[0][end_x]);

    for (int y = start_y; y < end_y; y++, source_pixel_pointer += width + source_x_right_bound, destination_pointer += destination_offset) {
        for (int x = start_x; x < end_x; x++, source_pixel_pointer--, destination_pointer++) {
            char pixel = data[source_pixel_pointer];
            if (transparency && (pixel == MAGENTA)) {
                continue;
            } else {
                *(destination_pointer) = pixel;
            }
        }
    }
}


I managed to claw back a few frames! Laughing I do plan on writing a no-clip version and a non-transparency version for even faster performance, as well as variants for flipping on the y-axis. And a few more nice-to-have graphics functions... I'll post them here once I get them working. And I'll prepare a few carving knives so that you guys can gut me thoroughly for being so wasteful with my calculator's CPU cycles.

Is there anything else that I can do to make this faster? Is there a faster way of drawing a sprite flipped on the x-axis without generating a flipped sprite beforehand?
After some more keyboard mashing and desperate debugging, I managed to write this function that draws only a section of a sprite:

Code:
void draw_sprite_section(gfx_sprite_t* sprite, int dest_x, int dest_y, uint8_t source_start_x, uint8_t source_start_y, uint8_t width, uint8_t height) {
    char* data = (char*) sprite;

    char sprite_width  = data[0];
    char sprite_height = data[1];

    // you know the drill: clipping checks
    int start_x = dest_x < 0 ? 0 : dest_x;
    int start_y = dest_y < 0 ? 0 : dest_y;

    // because we're drawing a section of the sprite here, we also want to check whether we're going to draw out of the bounds of the sprite
    uint8_t draw_width  = (uint8_t) ((start_x + width) >= LCD_WIDTH ? (LCD_WIDTH - start_x - 1) : width);
    draw_width          = (source_start_x + draw_width) >= sprite_width ? (sprite_width - source_start_x - 1) : draw_width;
    int draw_height     = (start_y + height) >= LCD_HEIGHT ? (LCD_HEIGHT - start_y - 1) : height;
    draw_height         = (source_start_y + draw_height) >= sprite_height ? (sprite_height - source_start_y - 1) : draw_height;

    // all of these checks will be skipped in the no-clip version

    // the plan: calculate pointers to rows of pixels, use memcpy
    // we must add 2 to the starting pointer because the first two char values are the width and height of the sprite
    char* source_pointer  = &(data[sprite_width * source_start_y + source_start_x + 2]);
    uint8_t source_offset = sprite_width * sizeof(char);
    uint8_t* dest_pointer = &(gfx_vbuffer[start_y][start_x]);
    int     dest_offset   = &(gfx_vbuffer[1][start_x]) - &(gfx_vbuffer[0][start_x]);

    while (draw_height >= 0) {
        memcpy(dest_pointer, source_pointer, draw_width);
        dest_pointer   += dest_offset;
        source_pointer += source_offset;
        draw_height--;
    }
}


There's no transparency support yet. I don't know if there's a way to efficiently check for transparent pixels without looping through all of them. Or if there's a way to do all of the clipping checks without as many ternary statements...
Here is an algorithm to draw a non-transparent sprite flipped about its x-axis:


Code:
void draw_x_flipped_sprite_noclip(gfx_sprite_t* sprite, uint24_t x, uint8_t y)
{
  uint8_t sprite_width = sprite->width;
  uint8_t sprite_height = sprite->height;
  uint8_t counter = sprite_width;
  uint8_t* sprite_data_ptr = sprite->data + (sprite_width * sprite_height) - 1;
  uint8_t* dest_ptr = &(gfx_vbuffer[y - 1 + sprite_height][x]);

  do
  {
    if (!counter)
    {
      counter = sprite_width;
      sprite_height--;
      dest_ptr -= (LCD_WIDTH + sprite_width);
    }
    else
    {
      *dest_ptr = *sprite_data_ptr;
      dest_ptr++;
      sprite_data_ptr--;
      counter--;
    }

  } while (sprite_height);

  return;
}


It reads the sprite data from the end to the start and draws the sprite onscreen from left-to-right, and from the bottom-up. If GraphX had a function like gfx_GetTransparentColor() (hint, hint Wink ), you could add an if-statement before copying a sprite pixel to check if it was transparent, and then if it was, skip the copy.
Oh wow! That's a lot better, especially since it doesn't have any nested for loops. Maybe that's how I'm going to write graphics functions from now on...

I'm thinking of implementing the following twenty functions in C:

Code:

void gfx_Sprite_FlipX(gfx_sprite_t* sprite, int x, int y);
void gfx_TransparentSprite_FlipX(gfx_sprite_t* sprite, int x, int y);
void gfx_Sprite_FlipY(gfx_sprite_t* sprite, int x, int y);
void gfx_TransparentSprite_FlipY(gfx_sprite_t* sprite, int x, int y);

void gfx_Sprite_FlipX_NoClip(gfx_sprite_t* sprite, int x, int y);
void gfx_TransparentSprite_FlipX_NoClip(gfx_sprite_t* sprite, int x, int y);
void gfx_Sprite_FlipY_NoClip(gfx_sprite_t* sprite, int x, int y);
void gfx_TransparentSprite_FlipY_NoClip(gfx_sprite_t* sprite, int x, int y);

void gfx_Sprite_Section(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
void gfx_TransparentSprite_Section(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
void gfx_Sprite_Section_FlipX(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
void gfx_TransparentSprite_Section_FlipX(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
void gfx_Sprite_Section_FlipY(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
void gfx_TransparentSprite_Section_FlipY(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);

void gfx_Sprite_Section_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
void gfx_TransparentSprite_Section_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
void gfx_Sprite_Section_FlipX_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
void gfx_TransparentSprite_Section_FlipX_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
void gfx_Sprite_Section_FlipY_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);
void gfx_TransparentSprite_Section_FlipY_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y);


Assembly would be much faster, but I'll have to make do with C until the graphx officially supports something like this.
I wouldn't really say getting rid of nested loops is better, unless you've reduced the complexity of the actual algorithm.
Drawing a sprite is an O(m*n) algorithm by nature, so you end up with that many iterations of the inner (pixel drawing) loop no matter what.

Folding it all into one loop means you end up checking the outer loop condition on every iteration, even when there's no way the condition could have changed.
Big code block incoming.

Code:

#define set_draw_coordinates(draw_x, draw_y, draw_width, draw_height) \
    draw_x = draw_x < 0 ? 0 : draw_x; \
    draw_y = draw_y < 0 ? 0 : draw_y;

#define lower_right_corner_of(sprite) \
    (&(sprite->data[sprite->width * sprite->height]))

#define pointer_to_pixel_of(sprite, x, y) \
    (&(sprite->data[sprite->width * (y) + (x)]))

void draw_frame_time() {
    gfx_SetColor(BLACK);
    gfx_FillRectangle_NoClip(3, 3, 60, 12);
    gfx_SetColor(WHITE);
    gfx_Rectangle_NoClip(3, 3, 60, 12);
    gfx_SetTextXY(5, 5);
    gfx_PrintString("FPS ");
    gfx_PrintInt(32768 / timer_1_Counter, 2);
    timer_1_Counter = 0;
}

void get_clipping_bounds(int x, int y, int* clipped_width, int* clipped_height, int draw_width, int draw_height) {
    *clipped_width  = draw_width;
    *clipped_height = draw_height;

    int draw_x = x;
    int draw_y = y;

    // clipped on the left side
    if (draw_x < 0) {
        *clipped_width += draw_x;
        draw_x          = 0;
    }
    if ((draw_x + *clipped_width) > LCD_WIDTH) {
        *clipped_width = LCD_WIDTH - draw_x;
    }

    *clipped_width = *clipped_width < 0 ? 0 : *clipped_width;

    // clipped on the top
    if (draw_y < 0) {
        *clipped_height += draw_y;
        draw_y = 0;
        // reset draw_y, because we've accounted for clipping on the top already
        // if this is not done, then we might accidentally account for top clipping twice
    }
    if ((draw_y + *clipped_height) > LCD_HEIGHT) {
        *clipped_height = LCD_HEIGHT - (draw_y > 0 ? draw_y : 0);
    }

    *clipped_height = *clipped_height < 0 ? 0 : *clipped_height;
}

void gfx_Sprite_FlipX(gfx_sprite_t* sprite, int x, int y) {
    if (x >= LCD_WIDTH || y >= LCD_HEIGHT) return;

    int width = sprite->width, height = sprite->height;
    get_clipping_bounds(x, y, &width, &height, sprite->width, sprite->height);

    // we now need to figure out where to start on the sprite
    // this is much easier, since we're drawing the whole sprite

    uint8_t* source_pointer = &sprite->data[0];
    int dest_offset         = LCD_WIDTH - width;
    int source_offset       = sprite->width + width;
    source_pointer         += sprite->width - 1;

    // we calculate the destination pointer later, to avoid accidentally pointing to something offscreen

    if (x < 0) {
        source_pointer += x;
    }

    if (y < 0) {
        source_pointer -= sprite->width * y;
    }

    int draw_x = x, draw_y = y;
    set_draw_coordinates(draw_x, draw_y, width, height);
    uint8_t* dest_pointer = &(gfx_vbuffer[draw_y][draw_x]);
    int draw_width;

    while (height) {
        draw_width = width;
        while (draw_width) {
            *dest_pointer = *source_pointer;
            source_pointer--;
            dest_pointer++;
            draw_width--;
        }
        dest_pointer   += dest_offset;
        source_pointer += source_offset;
        height--;
    }
}

void gfx_TransparentSprite_FlipX(gfx_sprite_t* sprite, int x, int y) {
    if (x >= LCD_WIDTH || y >= LCD_HEIGHT) return;

    int width = sprite->width, height = sprite->height;
    get_clipping_bounds(x, y, &width, &height, sprite->width, sprite->height);

    // we now need to figure out where to start on the sprite
    // this is much easier, since we're drawing the whole sprite

    uint8_t* source_pointer = &sprite->data[0];
    int dest_offset         = LCD_WIDTH - width;
    int source_offset       = sprite->width + width;
    source_pointer         += sprite->width - 1;

    // we calculate the destination pointer later, to avoid accidentally pointing to something offscreen

    if (x < 0) {
        source_pointer += x;
    }

    if (y < 0) {
        source_pointer -= sprite->width * y;
    }
   
    int draw_x = x, draw_y = y;
    set_draw_coordinates(draw_x, draw_y, width, height);
    uint8_t* dest_pointer = &(gfx_vbuffer[draw_y][draw_x]);
    int draw_width;
    uint8_t pixel;

    while (height) {
        draw_width = width;
        while (draw_width) {
            pixel = *source_pointer;
            if (pixel) *dest_pointer = pixel;
            source_pointer--;
            dest_pointer++;
            draw_width--;
        }
        dest_pointer   += dest_offset;
        source_pointer += source_offset;
        height--;
    }
}

void gfx_Sprite_FlipY(gfx_sprite_t* sprite, int x, int y) {
    if (x >= LCD_WIDTH || y >= LCD_HEIGHT) return;

    int width = sprite->width, height = sprite->height;
    get_clipping_bounds(x, y, &width, &height, sprite->width, sprite->height);

    // we now need to figure out where to start on the sprite
    // this is much easier, since we're drawing the whole sprite

    uint8_t* source_pointer = lower_right_corner_of(sprite);
    int source_offset       = sprite->width * sizeof(uint8_t);
    int copy_size           = width * sizeof(uint8_t);

    source_pointer -= source_offset;

    // we calculate the destination pointer later, to avoid accidentally pointing to something offscreen

    if (x < 0) {
        source_pointer += -1 * x;
    }

    if (y < 0) {
        source_pointer += sprite->width * y;
    }

    if (y >= LCD_HEIGHT) {
        source_pointer -= (y - LCD_HEIGHT) * sprite->width;
    }

    int draw_x = x, draw_y = y;
    set_draw_coordinates(draw_x, draw_y, width, height);
    uint8_t* dest_pointer = &(gfx_vbuffer[draw_y][draw_x]);

    while (height) {
        memcpy(dest_pointer, source_pointer, copy_size);
        dest_pointer   += LCD_WIDTH;
        source_pointer -= source_offset;
        height--;
    }
}

void gfx_TransparentSprite_FlipY(gfx_sprite_t* sprite, int x, int y) {
    if (x >= LCD_WIDTH || y >= LCD_HEIGHT) return;

    int width = sprite->width, height = sprite->height;
    get_clipping_bounds(x, y, &width, &height, sprite->width, sprite->height);

    // we now need to figure out where to start on the sprite
    // this is much easier, since we're drawing the whole sprite

    uint8_t* source_pointer = lower_right_corner_of(sprite);
    int dest_offset         = LCD_WIDTH - width;
    int source_offset       = sprite->width + width;
    source_pointer         -= sprite->width;

    // we calculate the destination pointer later, to avoid accidentally pointing to something offscreen

    if (x < 0) {
        source_pointer += -1 * x;
    }

    if (y < 0) {
        source_pointer += sprite->width * y;
    }

    if (y >= LCD_HEIGHT) {
        source_pointer -= (y - LCD_HEIGHT) * sprite->width;
    }

    int draw_x = x, draw_y = y;
    set_draw_coordinates(draw_x, draw_y, width, height);
    uint8_t* dest_pointer  = &(gfx_vbuffer[draw_y][draw_x]);
    int draw_width         = width;
    uint8_t pixel;

    while (height) {
        draw_width = width;
        while (draw_width) {
            pixel = *source_pointer;
            if (pixel) {
                *dest_pointer = pixel;
            }
            source_pointer++;
            dest_pointer++;
            draw_width--;
        }
        source_pointer -= source_offset;
        dest_pointer   += dest_offset;
        height--;
    }
}

void gfx_Sprite_FlipX_NoClip(gfx_sprite_t* sprite, int x, int y) {
    uint8_t width  = sprite->width;
    uint8_t height = sprite->height;

    uint8_t* source_pointer = &(sprite->data[width * (height - 1) + width - 1]);
    uint8_t* dest_pointer   = &(gfx_vbuffer[y + height - 1][x]);

    uint8_t counter;

    while (height) {
        counter = width;
        while (counter) {
            *dest_pointer = *source_pointer;
            source_pointer--;
            dest_pointer++;
            counter--;
        }
        dest_pointer -= LCD_WIDTH + width;
        height--;
    }
}

void gfx_TransparentSprite_FlipX_NoClip(gfx_sprite_t* sprite, int x, int y) {
    uint8_t width  = sprite->width;
    uint8_t height = sprite->height;

    uint8_t* source_pointer = &(sprite->data[width * (height - 1) + width - 1]);
    uint8_t* dest_pointer   = &(gfx_vbuffer[y + height - 1][x]);

    uint8_t counter;

    while (height) {
        counter = width;
        while (counter) {
            if (*source_pointer != MAGENTA) {
                *dest_pointer = *source_pointer;
            }
            source_pointer--;
            dest_pointer++;
            counter--;
        }
        dest_pointer -= LCD_WIDTH + width;
        height--;
    }
}

void gfx_Sprite_FlipY_NoClip(gfx_sprite_t* sprite, int x, int y) {
    uint8_t width  = sprite->width;
    uint8_t height = sprite->height;

    uint8_t* source_pointer = &(sprite->data[width * (height - 1)]);
    uint8_t* dest_pointer   = &(gfx_vbuffer[y][x]);

    size_t copy_size = width * sizeof(uint8_t);
   
    while (height) {
        memcpy(dest_pointer, source_pointer, copy_size);
        height--;
        dest_pointer   += LCD_WIDTH;
        source_pointer -= width;
    }
}

void gfx_TransparentSprite_FlipY_NoClip(gfx_sprite_t* sprite, int x, int y) {
    uint8_t width  = sprite->width;
    uint8_t height = sprite->height;

    uint8_t* source_pointer = &(sprite->data[width * (height - 1)]);
    uint8_t* dest_pointer   = &(gfx_vbuffer[y][x]);

    uint8_t counter;
   
    while (height) {
        counter = width;
        while (counter) {
            if (*source_pointer != MAGENTA) {
                *dest_pointer = *source_pointer;
            }
            source_pointer++;
            dest_pointer++;
            counter--;
        }
        height--;
        dest_pointer   += LCD_WIDTH - width;
        source_pointer -= 2 * width;
    }
}

void gfx_Sprite_Section(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
    if (dest_x >= LCD_WIDTH || dest_y >= LCD_HEIGHT) return;
    int draw_width, draw_height;

    get_clipping_bounds(dest_x, dest_y, &draw_width, &draw_height, width, height);

    uint8_t* source_pointer = pointer_to_pixel_of(sprite, src_x, src_y);
    int source_offset       = sprite->width;
    int copy_size           = sizeof(uint8_t) * draw_width;

    if (dest_x < 0) {
        source_pointer -= dest_x;
    }

    if (dest_y < 0) {
        source_pointer -= sprite->width * dest_y;
    }

    int draw_x = dest_x, draw_y = dest_y;
    set_draw_coordinates(draw_x, draw_y, draw_width, draw_height);
    uint8_t* dest_pointer = &(gfx_vbuffer[draw_y][draw_x]);

    while (draw_height) {
        memcpy(dest_pointer, source_pointer, copy_size);
        dest_pointer   += LCD_WIDTH;
        source_pointer += source_offset;
        draw_height--;
    }
}

void gfx_TransparentSprite_Section(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
    if (dest_x >= LCD_WIDTH || dest_y >= LCD_HEIGHT) return;
    int draw_width, draw_height;

    get_clipping_bounds(dest_x, dest_y, &draw_width, &draw_height, width, height);

    uint8_t* source_pointer = pointer_to_pixel_of(sprite, src_x, src_y);
    int source_offset       = sprite->width - draw_width;

    if (dest_x < 0) {
        source_pointer -= dest_x;
    }

    if (dest_y < 0) {
        source_pointer -= sprite->width * dest_y;
    }

    int draw_x = dest_x, draw_y = dest_y;
    set_draw_coordinates(draw_x, draw_y, draw_width, draw_height);
    uint8_t* dest_pointer = &(gfx_vbuffer[draw_y][draw_x]);
    int dest_offset       = LCD_WIDTH - draw_width;

    int counter;
    uint8_t pixel;
    while (draw_height) {
        counter = draw_width;
        while (counter) {
            pixel = *source_pointer;
            if (pixel) *dest_pointer = pixel;
            dest_pointer++;
            source_pointer++;
            counter--;
        }
        dest_pointer   += dest_offset;
        source_pointer += source_offset;
        draw_height--;
    }
}

void gfx_Sprite_Section_FlipX(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
    if (dest_x >= LCD_WIDTH || dest_y >= LCD_HEIGHT) return;

    int draw_width, draw_height;
    get_clipping_bounds(dest_x, dest_y, &draw_width, &draw_height, width, height);

    // we now need to figure out where to start on the sprite

    uint8_t* source_pointer = pointer_to_pixel_of(sprite, src_x, src_y);
    int dest_offset         = LCD_WIDTH - draw_width;
    int source_offset       = sprite->width + draw_width;
    source_pointer         += width - 1;

    // we calculate the destination pointer later, to avoid accidentally pointing to something offscreen

    if (dest_x < 0) {
        source_pointer += dest_x;
    }

    if (dest_y < 0) {
        source_pointer -= sprite->width * dest_y;
    }

    int draw_x = dest_x, draw_y = dest_y;
    set_draw_coordinates(draw_x, draw_y, width, height);
    uint8_t* dest_pointer = &(gfx_vbuffer[draw_y][draw_x]);
    int counter;

    while (draw_height) {
        counter = draw_width;
        while (counter) {
            *dest_pointer = *source_pointer;
            source_pointer--;
            dest_pointer++;
            counter--;
        }
        dest_pointer   += dest_offset;
        source_pointer += source_offset;
        draw_height--;
    }
}

void gfx_TransparentSprite_Section_FlipX(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
if (dest_x >= LCD_WIDTH || dest_y >= LCD_HEIGHT) return;

    int draw_width, draw_height;
    get_clipping_bounds(dest_x, dest_y, &draw_width, &draw_height, width, height);

    // we now need to figure out where to start on the sprite

    uint8_t* source_pointer = pointer_to_pixel_of(sprite, src_x, src_y);
    int dest_offset         = LCD_WIDTH - draw_width;
    int source_offset       = sprite->width + draw_width;
    source_pointer         += width - 1;

    // we calculate the destination pointer later, to avoid accidentally pointing to something offscreen

    if (dest_x < 0) {
        source_pointer += dest_x;
    }

    if (dest_y < 0) {
        source_pointer -= sprite->width * dest_y;
    }

    int draw_x = dest_x, draw_y = dest_y;
    set_draw_coordinates(draw_x, draw_y, width, height);
    uint8_t* dest_pointer = &(gfx_vbuffer[draw_y][draw_x]);
    int counter;
    uint8_t pixel;

    while (draw_height) {
        counter = draw_width;
        while (counter) {
            pixel = *source_pointer;
            if (pixel) *dest_pointer = pixel;
            source_pointer--;
            dest_pointer++;
            counter--;
        }
        dest_pointer   += dest_offset;
        source_pointer += source_offset;
        draw_height--;
    }
}

void gfx_Sprite_Section_FlipY(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
    if (dest_x >= LCD_WIDTH || dest_y >= LCD_HEIGHT) return;

    int draw_width, draw_height;
    get_clipping_bounds(dest_x, dest_y, &draw_width, &draw_height, width, height);

    // we now need to figure out where to start on the sprite
    uint8_t* source_pointer = pointer_to_pixel_of(sprite, src_x, src_y + height - 1);
    size_t copy_size        = sizeof(uint8_t) * draw_width;
    int source_offset       = sprite->width;

    if (dest_x < 0) {
        source_pointer -= dest_x;
    }
    if (dest_y < 0) {
        source_pointer += dest_y * sprite->width;
    }

    int draw_x = dest_x, draw_y = dest_y;
    set_draw_coordinates(draw_x, draw_y, draw_width, draw_height);
    uint8_t* dest_pointer = &(gfx_vbuffer[draw_y][draw_x]);

    while (draw_height) {
        memcpy(dest_pointer, source_pointer, copy_size);
        dest_pointer   += LCD_WIDTH;
        source_pointer -= source_offset;
        draw_height--;
    }
}

void gfx_TransparentSprite_Section_FlipY(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
    if (dest_x >= LCD_WIDTH || dest_y >= LCD_HEIGHT) return;

    int draw_width, draw_height;
    get_clipping_bounds(dest_x, dest_y, &draw_width, &draw_height, width, height);

    // we now need to figure out where to start on the sprite
    uint8_t* source_pointer = pointer_to_pixel_of(sprite, src_x, src_y + height - 1);
    int source_offset       = sprite->width + draw_width;

    if (dest_x < 0) {
        source_pointer -= dest_x;
    }
    if (dest_y < 0) {
        source_pointer += dest_y * sprite->width;
    }

    int draw_x = dest_x, draw_y = dest_y;
    set_draw_coordinates(draw_x, draw_y, draw_width, draw_height);
    uint8_t* dest_pointer = &(gfx_vbuffer[draw_y][draw_x]);
    int dest_offset       = LCD_WIDTH - draw_width;

    int counter;
    uint8_t pixel;

    while (draw_height) {
        counter = draw_width;
        while (counter) {
            pixel = *source_pointer;
            if (pixel) *dest_pointer = pixel;
            dest_pointer++;
            source_pointer++;
            counter--;
        }
        dest_pointer   += dest_offset;
        source_pointer -= source_offset;
        draw_height--;
    }
}

void gfx_Sprite_Section_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
    uint8_t* source_pointer = &(sprite->data[src_y * sprite->width + src_x]);
    uint8_t* dest_pointer   = &(gfx_vbuffer[dest_y][dest_x]);

    uint8_t sprite_width = sprite->width;
    uint8_t draw_height  = height;
    size_t draw_size     = width * sizeof(char);

    while (draw_height) {
        memcpy(dest_pointer, source_pointer, draw_size);
        draw_height--;
        source_pointer += sprite_width;
        dest_pointer   += LCD_WIDTH;
    }
}

void gfx_TransparentSprite_Section_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
    uint8_t* source_pointer = &(sprite->data[src_y * sprite->width + src_x]);
    uint8_t* dest_pointer   = &(gfx_vbuffer[dest_y][dest_x]);

    int draw_height   = height;
    int draw_width    = width;
    int source_offset = sprite->width - width;
    int dest_offset   = LCD_WIDTH - width;

    while (draw_height) {
        while (draw_width) {
            draw_width--;
            uint8_t pixel = *source_pointer;
            if (pixel != MAGENTA) {
                *dest_pointer = pixel;
            }
            dest_pointer++;
            source_pointer++;
        }

        dest_pointer   += dest_offset;
        source_pointer += source_offset;

        draw_height--;
        draw_width = width;
    }
}

void gfx_Sprite_Section_FlipX_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
    uint8_t* source_pointer = &(sprite->data[src_y * sprite->width + src_x + width - 1]);
    uint8_t* dest_pointer   = &(gfx_vbuffer[dest_y][dest_x]);

    int dest_offset = (LCD_WIDTH - width) * sizeof(uint8_t);
    int src_offset  = (sprite->width + width) * sizeof(uint8_t);
    int draw_height = height;
    int draw_width  = width;

    while (draw_height) {
        while (draw_width) {
            *dest_pointer = *source_pointer;
            dest_pointer++;
            source_pointer--;
            draw_width--;
        }
        source_pointer += src_offset;
        dest_pointer   += dest_offset;
        draw_height--;
        draw_width = width;
    }
}

void gfx_TransparentSprite_Section_FlipX_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
    uint8_t* source_pointer = &(sprite->data[src_y * sprite->width + src_x + width - 1]);
    uint8_t* dest_pointer   = &(gfx_vbuffer[dest_y][dest_x]);

    int dest_offset = (LCD_WIDTH - width) * sizeof(uint8_t);
    int src_offset  = (sprite->width + width) * sizeof(uint8_t);
    int draw_height = height;
    int draw_width  = width;

    while (draw_height) {
        while (draw_width) {
            uint8_t pixel = *source_pointer;
            if (pixel != MAGENTA) {
                *dest_pointer = *source_pointer;
            }
            dest_pointer++;
            source_pointer--;
            draw_width--;
        }
        source_pointer += src_offset;
        dest_pointer   += dest_offset;
        draw_height--;
        draw_width = width;
    }
}

void gfx_Sprite_Section_FlipY_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
    size_t draw_size = width * sizeof(uint8_t);

    uint8_t* source_pointer = &(sprite->data[sprite->width * (src_y + height - 1) + src_x]);
    uint8_t* dest_pointer   = &(gfx_vbuffer[dest_y][dest_x]);

    int src_offset  = (sprite->width) * sizeof(uint8_t);
    int draw_height = height;
    while (draw_height) {
        memcpy(dest_pointer, source_pointer, draw_size);
        draw_height--;
        source_pointer -= src_offset;
        dest_pointer   += LCD_WIDTH;
    }
}

void gfx_TransparentSprite_Section_FlipY_NoClip(gfx_sprite_t* sprite, int src_x, int src_y, int width, int height, int dest_x, int dest_y) {
    uint8_t* source_pointer = &(sprite->data[sprite->width * (src_y + height - 1) + src_x]);
    uint8_t* dest_pointer   = &(gfx_vbuffer[dest_y][dest_x]);

    int src_offset  = (sprite->width + width);
    int dest_offset = (LCD_WIDTH - width);
    int draw_height = height;
    int draw_width  = width;
    while (draw_height) {
        while (draw_width) {
            uint8_t pixel = *source_pointer;
            if (pixel != MAGENTA) {
                *dest_pointer = pixel;
            }
            dest_pointer++;
            source_pointer++;
            draw_width--;
        }
        draw_width = width;
        draw_height--;
        source_pointer -= src_offset;
        dest_pointer   += dest_offset;
    }
}


All of this is pretty slow. I'm not sure how to make this faster (you can laugh at me, that's okay). I'm kind of surprised this all works. I guess to optimize it we'd probably have to dig in and rewrite all of this in assembly.

Now... to find some way to turn this into a linkable library...
I am seriously not understanding literally all of those functions - they can be made already with the default graphx functions much faster than you have there????
Maybe just create the mirrored sprite before you put it on the calculator? It may cost some space, but you will gain it back by not having to use a bunch of function calls. Plus, it will be faster.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement