/* source/draw/sgl_draw_xform.c * * MIT License * * Copyright(c) 2023-present All contributors of SGL * Document reference link: https://sgl-docs.readthedocs.io * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include /** * @brief calculate a point color by bilinear interpolate * @param buffer point to image pixmap start buffer * @param w width of buffer * @param h height of buffer * @param fx x coordinate of point * @param fy y coordinate of point * @return point color */ sgl_color_t sgl_draw_biln_color(const sgl_color_t *buffer, int16_t w, int16_t h, int32_t fx, int32_t fy) { sgl_color_t ret; int32_t max_x = (((int32_t)w) - 1) << SGL_FIXED_SHIFT; int32_t max_y = (((int32_t)h) - 1) << SGL_FIXED_SHIFT; fx = fx < 0 ? 0 : (fx > max_x ? max_x : fx); fy = fy < 0 ? 0 : (fy > max_y ? max_y : fy); const int32_t x0 = fx >> SGL_FIXED_SHIFT; const int32_t y0 = fy >> SGL_FIXED_SHIFT; const int32_t dx = fx & SGL_FIXED_MASK; const int32_t dy = fy & SGL_FIXED_MASK; const int32_t dx1 = SGL_FIXED_ONE - dx; const int32_t dy1 = SGL_FIXED_ONE - dy; const int32_t point = (y0 * w) + x0; const sgl_color_t p00 = buffer[point]; const sgl_color_t p01 = buffer[point + 1]; const sgl_color_t p10 = buffer[point + w]; const sgl_color_t p11 = buffer[point + w + 1]; const uint8_t r00 = p00.ch.red; const uint8_t r01 = p01.ch.red; const uint8_t r10 = p10.ch.red; const uint8_t r11 = p11.ch.red; const uint8_t g00 = p00.ch.green; const uint8_t g01 = p01.ch.green; const uint8_t g10 = p10.ch.green; const uint8_t g11 = p11.ch.green; const uint8_t b00 = p00.ch.blue; const uint8_t b01 = p01.ch.blue; const uint8_t b10 = p10.ch.blue; const uint8_t b11 = p11.ch.blue; ret.ch.red = ((r00 * dx1 * dy1) + (r01 * dx * dy1) + (r10 * dx1 * dy) + (r11 * dx * dy)) >> (2 * SGL_FIXED_SHIFT); ret.ch.green = ((g00 * dx1 * dy1) + (g01 * dx * dy1) + (g10 * dx1 * dy) + (g11 * dx * dy)) >> (2 * SGL_FIXED_SHIFT); ret.ch.blue = ((b00 * dx1 * dy1) + (b01 * dx * dy1) + (b10 * dx1 * dy) + (b11 * dx * dy)) >> (2 * SGL_FIXED_SHIFT); return ret; } /** * @brief transform a surface * @param dst destination surface * @param src source surface * @param area area of surface * @param x x coordinate of surface * @param y y coordinate of surface * @param rotation rotation angle * @return none * @note This function has implemented angle normalization to the range of 0 to 360 degrees. */ void sgl_draw_xform_surf(sgl_surf_t *dst, sgl_surf_t *src, sgl_area_t *area, int16_t x, int16_t y, int16_t rotation) { const int32_t sin_val = sgl_sin(rotation); const int32_t cos_val = sgl_cos(rotation); const int16_t half_w = src->w / 2; const int16_t half_h = src->h / 2; const int16_t x1r = (cos_val * (-half_w) - sin_val * (-half_h)) / SGL_SIN_FIXED_ONE; const int16_t y1r = (sin_val * (-half_w) + cos_val * (-half_h)) / SGL_SIN_FIXED_ONE; const int16_t x2r = (cos_val * half_w - sin_val * (-half_h)) / SGL_SIN_FIXED_ONE; const int16_t y2r = (sin_val * half_w + cos_val * (-half_h)) / SGL_SIN_FIXED_ONE; const int16_t x3r = (cos_val * half_w - sin_val * half_h) / SGL_SIN_FIXED_ONE; const int16_t y3r = (sin_val * half_w + cos_val * half_h) / SGL_SIN_FIXED_ONE; const int16_t x4r = (cos_val * (-half_w) - sin_val * half_h) / SGL_SIN_FIXED_ONE; const int16_t y4r = (sin_val * (-half_w) + cos_val * half_h) / SGL_SIN_FIXED_ONE; const int16_t min_x = sgl_min4(x1r, x2r, x3r, x4r); const int16_t min_y = sgl_min4(y1r, y2r, y3r, y4r); const int16_t max_x = sgl_max4(x1r, x2r, x3r, x4r); const int16_t max_y = sgl_max4(y1r, y2r, y3r, y4r); const int16_t center_x = x + half_w; const int16_t center_y = y + half_h; const int16_t buf_width = src->w > 0 ? src->w : 1; const int16_t buf_height = src->h > 0 ? src->h : 1; const int16_t buf_size = buf_width * buf_height; if (buf_size <= 0 || src->w <= 0) { return; } for (int py = (int)min_y; py <= max_y; py++) { for (int px = (int)min_x; px <= max_x; px++) { int rel_x = px; int rel_y = py; int32_t orig_x_fixed = cos_val * rel_x + sin_val * rel_y; int32_t orig_y_fixed = -sin_val * rel_x + cos_val * rel_y; const int orig_x = (orig_x_fixed / SGL_SIN_FIXED_ONE) + half_w; const int orig_y = (orig_y_fixed / SGL_SIN_FIXED_ONE) + half_h; if (orig_x >= 0 && orig_x < buf_width && orig_y >= 0 && orig_y < buf_height) { int src_idx = orig_y * buf_width + orig_x; const int dst_x = center_x + px; const int dst_y = center_y + py; if (dst_x >= area->x1 && dst_x <= area->x2 && dst_y >= area->y1 && dst_y <= area->y2 && dst_x >= dst->x1 && dst_x <= dst->x2 && dst_y >= dst->y1 && dst_y <= dst->y2 ) { int dst_idx = (dst_y - dst->y1) * dst->w + (dst_x - dst->x1); dst->buffer[dst_idx] = src->buffer[src_idx]; } } } } }