974 lines
32 KiB
C
974 lines
32 KiB
C
/*
|
|
* Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)
|
|
*
|
|
* 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 "gdx2d.h"
|
|
#include <stdlib.h>
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#define STBI_NO_FAILURE_STRINGS
|
|
#include "stb_image.h"
|
|
#include "jpgd_c.h"
|
|
|
|
#include <android/log.h>
|
|
#define APP_LOG "GDX"
|
|
|
|
static uint32_t gdx2d_blend = GDX2D_BLEND_NONE;
|
|
static uint32_t gdx2d_scale = GDX2D_SCALE_NEAREST;
|
|
|
|
static uint32_t* lu4 = 0;
|
|
static uint32_t* lu5 = 0;
|
|
static uint32_t* lu6 = 0;
|
|
|
|
typedef void(*set_pixel_func)(unsigned char* pixel_addr, uint32_t color);
|
|
typedef uint32_t(*get_pixel_func)(unsigned char* pixel_addr);
|
|
|
|
static inline void generate_look_ups() {
|
|
uint32_t i = 0;
|
|
lu4 = malloc(sizeof(uint32_t) * 16);
|
|
lu5 = malloc(sizeof(uint32_t) * 32);
|
|
lu6 = malloc(sizeof(uint32_t) * 64);
|
|
|
|
for(i = 0; i < 16; i++) {
|
|
lu4[i] = (uint32_t) i / 15.0f * 255;
|
|
lu5[i] = (uint32_t) i / 31.0f * 255;
|
|
lu6[i] = (uint32_t) i / 63.0f * 255;
|
|
}
|
|
|
|
for(i = 16; i < 32; i++) {
|
|
lu5[i] = (uint32_t) i / 31.0f * 255;
|
|
lu6[i] = (uint32_t) i / 63.0f * 255;
|
|
}
|
|
|
|
for(i = 32; i < 64; i++) {
|
|
lu6[i] = (uint32_t) i / 63.0f * 255;
|
|
}
|
|
}
|
|
|
|
static inline uint32_t to_format(uint32_t format, uint32_t color) {
|
|
uint32_t r, g, b, a, l;
|
|
|
|
switch(format) {
|
|
case GDX2D_FORMAT_ALPHA:
|
|
return color & 0xff;
|
|
case GDX2D_FORMAT_LUMINANCE_ALPHA:
|
|
r = (color & 0xff000000) >> 24;
|
|
g = (color & 0xff0000) >> 16;
|
|
b = (color & 0xff00) >> 8;
|
|
a = (color & 0xff);
|
|
l = ((uint32_t)(0.2126f * r + 0.7152 * g + 0.0722 * b) & 0xff) << 8;
|
|
return (l & 0xffffff00) | a;
|
|
case GDX2D_FORMAT_RGB888:
|
|
return color >> 8;
|
|
case GDX2D_FORMAT_RGBA8888:
|
|
return color;
|
|
case GDX2D_FORMAT_RGB565:
|
|
r = (((color & 0xff000000) >> 27) << 11) & 0xf800;
|
|
g = (((color & 0xff0000) >> 18) << 5) & 0x7e0;
|
|
b = ((color & 0xff00) >> 11) & 0x1f;
|
|
return r | g | b;
|
|
case GDX2D_FORMAT_RGBA4444:
|
|
r = (((color & 0xff000000) >> 28) << 12) & 0xf000;
|
|
g = (((color & 0xff0000) >> 20) << 8) & 0xf00;
|
|
b = (((color & 0xff00) >> 12) << 4) & 0xf0;
|
|
a = ((color & 0xff) >> 4) & 0xf;
|
|
return r | g | b | a;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#define min(a, b) (a > b?b:a)
|
|
|
|
static inline uint32_t weight_RGBA8888(uint32_t color, float weight) {
|
|
uint32_t r, g, b, a;
|
|
r = min((uint32_t)(((color & 0xff000000) >> 24) * weight), 255);
|
|
g = min((uint32_t)(((color & 0xff0000) >> 16) * weight), 255);
|
|
b = min((uint32_t)(((color & 0xff00) >> 8) * weight), 255);
|
|
a = min((uint32_t)(((color & 0xff)) * weight), 255);
|
|
|
|
return (r << 24) | (g << 16) | (b << 8) | a;
|
|
}
|
|
|
|
static inline uint32_t to_RGBA8888(uint32_t format, uint32_t color) {
|
|
uint32_t r, g, b, a;
|
|
|
|
if(!lu5) generate_look_ups();
|
|
|
|
switch(format) {
|
|
case GDX2D_FORMAT_ALPHA:
|
|
return (color & 0xff) | 0xffffff00;
|
|
case GDX2D_FORMAT_LUMINANCE_ALPHA:
|
|
return ((color & 0xff00) << 16) | ((color & 0xff00) << 8) | (color & 0xffff);
|
|
case GDX2D_FORMAT_RGB888:
|
|
return (color << 8) | 0x000000ff;
|
|
case GDX2D_FORMAT_RGBA8888:
|
|
return color;
|
|
case GDX2D_FORMAT_RGB565:
|
|
r = lu5[(color & 0xf800) >> 11] << 24;
|
|
g = lu6[(color & 0x7e0) >> 5] << 16;
|
|
b = lu5[(color & 0x1f)] << 8;
|
|
return r | g | b | 0xff;
|
|
case GDX2D_FORMAT_RGBA4444:
|
|
r = lu4[(color & 0xf000) >> 12] << 24;
|
|
g = lu4[(color & 0xf00) >> 8] << 16;
|
|
b = lu4[(color & 0xf0) >> 4] << 8;
|
|
a = lu4[(color & 0xf)];
|
|
return r | g | b | a;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static inline void set_pixel_alpha(unsigned char *pixel_addr, uint32_t color) {
|
|
*pixel_addr = (unsigned char)(color & 0xff);
|
|
}
|
|
|
|
static inline void set_pixel_luminance_alpha(unsigned char *pixel_addr, uint32_t color) {
|
|
*(unsigned short*)pixel_addr = (unsigned short)color;
|
|
}
|
|
|
|
static inline void set_pixel_RGB888(unsigned char *pixel_addr, uint32_t color) {
|
|
//*(unsigned short*)pixel_addr = (unsigned short)(((color & 0xff0000) >> 16) | (color & 0xff00));
|
|
pixel_addr[0] = (color & 0xff0000) >> 16;
|
|
pixel_addr[1] = (color & 0xff00) >> 8;
|
|
pixel_addr[2] = (color & 0xff);
|
|
}
|
|
|
|
static inline void set_pixel_RGBA8888(unsigned char *pixel_addr, uint32_t color) {
|
|
*(uint32_t*)pixel_addr = ((color & 0xff000000) >> 24) |
|
|
((color & 0xff0000) >> 8) |
|
|
((color & 0xff00) << 8) |
|
|
((color & 0xff) << 24);
|
|
}
|
|
|
|
static inline void set_pixel_RGB565(unsigned char *pixel_addr, uint32_t color) {
|
|
*(uint16_t*)pixel_addr = (uint16_t)(color);
|
|
}
|
|
|
|
static inline void set_pixel_RGBA4444(unsigned char *pixel_addr, uint32_t color) {
|
|
*(uint16_t*)pixel_addr = (uint16_t)(color);
|
|
}
|
|
|
|
static inline set_pixel_func set_pixel_func_ptr(uint32_t format) {
|
|
switch(format) {
|
|
case GDX2D_FORMAT_ALPHA: return &set_pixel_alpha;
|
|
case GDX2D_FORMAT_LUMINANCE_ALPHA: return &set_pixel_luminance_alpha;
|
|
case GDX2D_FORMAT_RGB888: return &set_pixel_RGB888;
|
|
case GDX2D_FORMAT_RGBA8888: return &set_pixel_RGBA8888;
|
|
case GDX2D_FORMAT_RGB565: return &set_pixel_RGB565;
|
|
case GDX2D_FORMAT_RGBA4444: return &set_pixel_RGBA4444;
|
|
default: return &set_pixel_alpha; // better idea for a default?
|
|
}
|
|
}
|
|
|
|
static inline uint32_t blend(uint32_t src, uint32_t dst) {
|
|
int32_t src_r = (src & 0xff000000) >> 24;
|
|
int32_t src_g = (src & 0xff0000) >> 16;
|
|
int32_t src_b = (src & 0xff00) >> 8;
|
|
int32_t src_a = (src & 0xff);
|
|
|
|
int32_t dst_r = (dst & 0xff000000) >> 24;
|
|
int32_t dst_g = (dst & 0xff0000) >> 16;
|
|
int32_t dst_b = (dst & 0xff00) >> 8;
|
|
int32_t dst_a = (dst & 0xff);
|
|
|
|
dst_r = dst_r + src_a * (src_r - dst_r) / 255;
|
|
dst_g = dst_g + src_a * (src_g - dst_g) / 255;
|
|
dst_b = dst_b + src_a * (src_b - dst_b) / 255;
|
|
dst_a = (int32_t)((1.0f - (1.0f - src_a / 255.0f) * (1.0f - dst_a / 255.0f)) * 255);
|
|
return (uint32_t)((dst_r << 24) | (dst_g << 16) | (dst_b << 8) | dst_a);
|
|
}
|
|
|
|
static inline uint32_t get_pixel_alpha(unsigned char *pixel_addr) {
|
|
return *pixel_addr;
|
|
}
|
|
|
|
static inline uint32_t get_pixel_luminance_alpha(unsigned char *pixel_addr) {
|
|
return (((uint32_t)pixel_addr[0]) << 8) | pixel_addr[1];
|
|
}
|
|
|
|
static inline uint32_t get_pixel_RGB888(unsigned char *pixel_addr) {
|
|
return (((uint32_t)pixel_addr[0]) << 16) | (((uint32_t)pixel_addr[1]) << 8) | (pixel_addr[2]);
|
|
}
|
|
|
|
static inline uint32_t get_pixel_RGBA8888(unsigned char *pixel_addr) {
|
|
return (((uint32_t)pixel_addr[0]) << 24) | (((uint32_t)pixel_addr[1]) << 16) | (((uint32_t)pixel_addr[2]) << 8) | pixel_addr[3];
|
|
}
|
|
|
|
static inline uint32_t get_pixel_RGB565(unsigned char *pixel_addr) {
|
|
return *(uint16_t*)pixel_addr;
|
|
}
|
|
|
|
static inline uint32_t get_pixel_RGBA4444(unsigned char *pixel_addr) {
|
|
return *(uint16_t*)pixel_addr;
|
|
}
|
|
|
|
static inline get_pixel_func get_pixel_func_ptr(uint32_t format) {
|
|
switch(format) {
|
|
case GDX2D_FORMAT_ALPHA: return &get_pixel_alpha;
|
|
case GDX2D_FORMAT_LUMINANCE_ALPHA: return &get_pixel_luminance_alpha;
|
|
case GDX2D_FORMAT_RGB888: return &get_pixel_RGB888;
|
|
case GDX2D_FORMAT_RGBA8888: return &get_pixel_RGBA8888;
|
|
case GDX2D_FORMAT_RGB565: return &get_pixel_RGB565;
|
|
case GDX2D_FORMAT_RGBA4444: return &get_pixel_RGBA4444;
|
|
default: return &get_pixel_alpha; // better idea for a default?
|
|
}
|
|
}
|
|
|
|
gdx2d_pixmap* gdx2d_load(const unsigned char *buffer, uint32_t len) {
|
|
int32_t width, height, format;
|
|
|
|
const unsigned char* pixels = stbi_load_from_memory(buffer, len, &width, &height, &format, 0);
|
|
if (pixels == NULL) {
|
|
pixels = jpgd_decompress_jpeg_image_from_memory(buffer, len, &width, &height, &format, 3);
|
|
}
|
|
if (pixels == NULL)
|
|
return NULL;
|
|
|
|
gdx2d_pixmap* pixmap = (gdx2d_pixmap*)malloc(sizeof(gdx2d_pixmap));
|
|
if (!pixmap) return 0;
|
|
pixmap->width = (uint32_t)width;
|
|
pixmap->height = (uint32_t)height;
|
|
pixmap->format = (uint32_t)format;
|
|
pixmap->pixels = pixels;
|
|
return pixmap;
|
|
}
|
|
|
|
uint32_t gdx2d_bytes_per_pixel(uint32_t format) {
|
|
switch(format) {
|
|
case GDX2D_FORMAT_ALPHA:
|
|
return 1;
|
|
case GDX2D_FORMAT_LUMINANCE_ALPHA:
|
|
case GDX2D_FORMAT_RGB565:
|
|
case GDX2D_FORMAT_RGBA4444:
|
|
return 2;
|
|
case GDX2D_FORMAT_RGB888:
|
|
return 3;
|
|
case GDX2D_FORMAT_RGBA8888:
|
|
return 4;
|
|
default:
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
gdx2d_pixmap* gdx2d_new(uint32_t width, uint32_t height, uint32_t format) {
|
|
gdx2d_pixmap* pixmap = (gdx2d_pixmap*)malloc(sizeof(gdx2d_pixmap));
|
|
if (!pixmap) return 0;
|
|
pixmap->width = width;
|
|
pixmap->height = height;
|
|
pixmap->format = format;
|
|
pixmap->pixels = (unsigned char*)malloc(width * height * gdx2d_bytes_per_pixel(format));
|
|
if (!pixmap->pixels) {
|
|
free((void*)pixmap);
|
|
return 0;
|
|
}
|
|
return pixmap;
|
|
}
|
|
void gdx2d_free(const gdx2d_pixmap* pixmap) {
|
|
free((void*)pixmap->pixels);
|
|
free((void*)pixmap);
|
|
}
|
|
|
|
void gdx2d_set_blend (uint32_t blend) {
|
|
gdx2d_blend = blend;
|
|
}
|
|
|
|
void gdx2d_set_scale (uint32_t scale) {
|
|
gdx2d_scale = scale;
|
|
}
|
|
|
|
const char *gdx2d_get_failure_reason(void) {
|
|
if (stbi_failure_reason())
|
|
return stbi_failure_reason();
|
|
return jpgd_failure_reason();
|
|
}
|
|
|
|
static inline void clear_alpha(const gdx2d_pixmap* pixmap, uint32_t col) {
|
|
int pixels = pixmap->width * pixmap->height;
|
|
memset((void*)pixmap->pixels, col, pixels);
|
|
}
|
|
|
|
static inline void clear_luminance_alpha(const gdx2d_pixmap* pixmap, uint32_t col) {
|
|
int pixels = pixmap->width * pixmap->height;
|
|
unsigned short* ptr = (unsigned short*)pixmap->pixels;
|
|
unsigned short l = (col & 0xff) << 8 | (col >> 8);
|
|
|
|
for(; pixels > 0; pixels--) {
|
|
*ptr = l;
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
static inline void clear_RGB888(const gdx2d_pixmap* pixmap, uint32_t col) {
|
|
int pixels = pixmap->width * pixmap->height;
|
|
unsigned char* ptr = (unsigned char*)pixmap->pixels;
|
|
unsigned char r = (col & 0xff0000) >> 16;
|
|
unsigned char g = (col & 0xff00) >> 8;
|
|
unsigned char b = (col & 0xff);
|
|
|
|
for(; pixels > 0; pixels--) {
|
|
*ptr = r;
|
|
ptr++;
|
|
*ptr = g;
|
|
ptr++;
|
|
*ptr = b;
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
static inline void clear_RGBA8888(const gdx2d_pixmap* pixmap, uint32_t col) {
|
|
int pixels = pixmap->width * pixmap->height;
|
|
uint32_t* ptr = (uint32_t*)pixmap->pixels;
|
|
unsigned char r = (col & 0xff000000) >> 24;
|
|
unsigned char g = (col & 0xff0000) >> 16;
|
|
unsigned char b = (col & 0xff00) >> 8;
|
|
unsigned char a = (col & 0xff);
|
|
col = (a << 24) | (b << 16) | (g << 8) | r;
|
|
|
|
for(; pixels > 0; pixels--) {
|
|
*ptr = col;
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
static inline void clear_RGB565(const gdx2d_pixmap* pixmap, uint32_t col) {
|
|
int pixels = pixmap->width * pixmap->height;
|
|
unsigned short* ptr = (unsigned short*)pixmap->pixels;
|
|
unsigned short l = col & 0xffff;
|
|
|
|
for(; pixels > 0; pixels--) {
|
|
*ptr = l;
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
static inline void clear_RGBA4444(const gdx2d_pixmap* pixmap, uint32_t col) {
|
|
int pixels = pixmap->width * pixmap->height;
|
|
unsigned short* ptr = (unsigned short*)pixmap->pixels;
|
|
unsigned short l = col & 0xffff;
|
|
|
|
for(; pixels > 0; pixels--) {
|
|
*ptr = l;
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
void gdx2d_clear(const gdx2d_pixmap* pixmap, uint32_t col) {
|
|
if (pixmap == 0)
|
|
return;
|
|
|
|
col = to_format(pixmap->format, col);
|
|
|
|
// Check for malformed Pixmap
|
|
size_t requestedSize = pixmap->width * pixmap->height * sizeof(col);
|
|
size_t pixelsSize = sizeof(pixmap->pixels);
|
|
if (requestedSize > pixelsSize) {
|
|
__android_log_print(ANDROID_LOG_VERBOSE,
|
|
APP_LOG, "Invalid pixmap. %ix%i - Size should be %u but found %u",
|
|
pixmap->width,
|
|
pixmap->height,
|
|
requestedSize,
|
|
pixelsSize);
|
|
return;
|
|
}
|
|
|
|
switch(pixmap->format) {
|
|
case GDX2D_FORMAT_ALPHA:
|
|
clear_alpha(pixmap, col);
|
|
break;
|
|
case GDX2D_FORMAT_LUMINANCE_ALPHA:
|
|
clear_luminance_alpha(pixmap, col);
|
|
break;
|
|
case GDX2D_FORMAT_RGB888:
|
|
clear_RGB888(pixmap, col);
|
|
break;
|
|
case GDX2D_FORMAT_RGBA8888:
|
|
clear_RGBA8888(pixmap, col);
|
|
break;
|
|
case GDX2D_FORMAT_RGB565:
|
|
clear_RGB565(pixmap, col);
|
|
break;
|
|
case GDX2D_FORMAT_RGBA4444:
|
|
clear_RGBA4444(pixmap, col);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static inline int32_t in_pixmap(const gdx2d_pixmap* pixmap, int32_t x, int32_t y) {
|
|
if(x < 0 || y < 0)
|
|
return 0;
|
|
if(x >= pixmap->width || y >= pixmap->height)
|
|
return 0;
|
|
return -1;
|
|
}
|
|
|
|
static inline void set_pixel(unsigned char* pixels, uint32_t width, uint32_t height, uint32_t bpp, set_pixel_func pixel_func, int32_t x, int32_t y, uint32_t col) {
|
|
if(x < 0 || y < 0) return;
|
|
if(x >= (int32_t)width || y >= (int32_t)height) return;
|
|
pixels = pixels + (x + width * y) * bpp;
|
|
pixel_func(pixels, col);
|
|
}
|
|
|
|
uint32_t gdx2d_get_pixel(const gdx2d_pixmap* pixmap, int32_t x, int32_t y) {
|
|
if(!in_pixmap(pixmap, x, y))
|
|
return 0;
|
|
unsigned char* ptr = (unsigned char*)pixmap->pixels + (x + pixmap->width * y) * gdx2d_bytes_per_pixel(pixmap->format);
|
|
return to_RGBA8888(pixmap->format, get_pixel_func_ptr(pixmap->format)(ptr));
|
|
}
|
|
|
|
void gdx2d_set_pixel(const gdx2d_pixmap* pixmap, int32_t x, int32_t y, uint32_t col) {
|
|
if(gdx2d_blend) {
|
|
uint32_t dst = gdx2d_get_pixel(pixmap, x, y);
|
|
col = blend(col, dst);
|
|
col = to_format(pixmap->format, col);
|
|
set_pixel((unsigned char*)pixmap->pixels, pixmap->width, pixmap->height, gdx2d_bytes_per_pixel(pixmap->format), set_pixel_func_ptr(pixmap->format), x, y, col);
|
|
} else {
|
|
col = to_format(pixmap->format, col);
|
|
set_pixel((unsigned char*)pixmap->pixels, pixmap->width, pixmap->height, gdx2d_bytes_per_pixel(pixmap->format), set_pixel_func_ptr(pixmap->format), x, y, col);
|
|
}
|
|
}
|
|
|
|
void gdx2d_draw_line(const gdx2d_pixmap* pixmap, int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t col) {
|
|
int32_t dy = y1 - y0;
|
|
int32_t dx = x1 - x0;
|
|
int32_t fraction = 0;
|
|
int32_t stepx, stepy;
|
|
unsigned char* ptr = (unsigned char*)pixmap->pixels;
|
|
uint32_t bpp = gdx2d_bytes_per_pixel(pixmap->format);
|
|
set_pixel_func pset = set_pixel_func_ptr(pixmap->format);
|
|
get_pixel_func pget = get_pixel_func_ptr(pixmap->format);
|
|
uint32_t col_format = to_format(pixmap->format, col);
|
|
void* addr = ptr + (x0 + y0 * pixmap->width) * bpp;
|
|
|
|
if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
|
|
if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
|
|
dy <<= 1;
|
|
dx <<= 1;
|
|
|
|
if(in_pixmap(pixmap, x0, y0)) {
|
|
if(gdx2d_blend) {
|
|
col_format = to_format(pixmap->format, blend(col, to_RGBA8888(pixmap->format, pget(addr))));
|
|
}
|
|
pset(addr, col_format);
|
|
}
|
|
if (dx > dy) {
|
|
fraction = dy - (dx >> 1);
|
|
while (x0 != x1) {
|
|
if (fraction >= 0) {
|
|
y0 += stepy;
|
|
fraction -= dx;
|
|
}
|
|
x0 += stepx;
|
|
fraction += dy;
|
|
if(in_pixmap(pixmap, x0, y0)) {
|
|
addr = ptr + (x0 + y0 * pixmap->width) * bpp;
|
|
if(gdx2d_blend) {
|
|
col_format = to_format(pixmap->format, blend(col, to_RGBA8888(pixmap->format, pget(addr))));
|
|
}
|
|
pset(addr, col_format);
|
|
}
|
|
}
|
|
} else {
|
|
fraction = dx - (dy >> 1);
|
|
while (y0 != y1) {
|
|
if (fraction >= 0) {
|
|
x0 += stepx;
|
|
fraction -= dy;
|
|
}
|
|
y0 += stepy;
|
|
fraction += dx;
|
|
if(in_pixmap(pixmap, x0, y0)) {
|
|
addr = ptr + (x0 + y0 * pixmap->width) * bpp;
|
|
if(gdx2d_blend) {
|
|
col_format = to_format(pixmap->format, blend(col, to_RGBA8888(pixmap->format, pget(addr))));
|
|
}
|
|
pset(addr, col_format);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void hline(const gdx2d_pixmap* pixmap, int32_t x1, int32_t x2, int32_t y, uint32_t col) {
|
|
int32_t tmp = 0;
|
|
set_pixel_func pset = set_pixel_func_ptr(pixmap->format);
|
|
get_pixel_func pget = get_pixel_func_ptr(pixmap->format);
|
|
unsigned char* ptr = (unsigned char*)pixmap->pixels;
|
|
uint32_t bpp = gdx2d_bytes_per_pixel(pixmap->format);
|
|
uint32_t col_format = to_format(pixmap->format, col);
|
|
|
|
if(y < 0 || y >= (int32_t)pixmap->height) return;
|
|
|
|
if(x1 > x2) {
|
|
tmp = x1;
|
|
x1 = x2;
|
|
x2 = tmp;
|
|
}
|
|
|
|
if(x1 >= (int32_t)pixmap->width) return;
|
|
if(x2 < 0) return;
|
|
|
|
if(x1 < 0) x1 = 0;
|
|
if(x2 >= (int32_t)pixmap->width) x2 = pixmap->width - 1;
|
|
x2 += 1;
|
|
|
|
ptr += (x1 + y * pixmap->width) * bpp;
|
|
|
|
while(x1 != x2) {
|
|
if(gdx2d_blend) {
|
|
col_format = to_format(pixmap->format, blend(col, to_RGBA8888(pixmap->format, pget(ptr))));
|
|
}
|
|
pset(ptr, col_format);
|
|
x1++;
|
|
ptr += bpp;
|
|
}
|
|
}
|
|
|
|
static inline void vline(const gdx2d_pixmap* pixmap, int32_t y1, int32_t y2, int32_t x, uint32_t col) {
|
|
int32_t tmp = 0;
|
|
set_pixel_func pset = set_pixel_func_ptr(pixmap->format);
|
|
get_pixel_func pget = get_pixel_func_ptr(pixmap->format);
|
|
unsigned char* ptr = (unsigned char*)pixmap->pixels;
|
|
uint32_t bpp = gdx2d_bytes_per_pixel(pixmap->format);
|
|
uint32_t stride = bpp * pixmap->width;
|
|
uint32_t col_format = to_format(pixmap->format, col);
|
|
|
|
if(x < 0 || x >= pixmap->width) return;
|
|
|
|
if(y1 > y2) {
|
|
tmp = y1;
|
|
y1 = y2;
|
|
y2 = tmp;
|
|
}
|
|
|
|
if(y1 >= (int32_t)pixmap->height) return;
|
|
if(y2 < 0) return;
|
|
|
|
if(y1 < 0) y1 = 0;
|
|
if(y2 >= (int32_t)pixmap->height) y2 = pixmap->height - 1;
|
|
y2 += 1;
|
|
|
|
ptr += (x + y1 * pixmap->width) * bpp;
|
|
|
|
while(y1 != y2) {
|
|
if(gdx2d_blend) {
|
|
col_format = to_format(pixmap->format, blend(col, to_RGBA8888(pixmap->format, pget(ptr))));
|
|
}
|
|
pset(ptr, col_format);
|
|
y1++;
|
|
ptr += stride;
|
|
}
|
|
}
|
|
|
|
void gdx2d_draw_rect(const gdx2d_pixmap* pixmap, int32_t x, int32_t y, uint32_t width, uint32_t height, uint32_t col) {
|
|
hline(pixmap, x, x + width - 1, y, col);
|
|
hline(pixmap, x, x + width - 1, y + height - 1, col);
|
|
vline(pixmap, y, y + height - 1, x, col);
|
|
vline(pixmap, y, y + height - 1, x + width - 1, col);
|
|
}
|
|
|
|
static inline void circle_points(unsigned char* pixels, uint32_t width, uint32_t height, uint32_t bpp, set_pixel_func pixel_func, int32_t cx, int32_t cy, int32_t x, int32_t y, uint32_t col) {
|
|
if (x == 0) {
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx, cy + y, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx, cy - y, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx + y, cy, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx - y, cy, col);
|
|
} else
|
|
if (x == y) {
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx + x, cy + y, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx - x, cy + y, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx + x, cy - y, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx - x, cy - y, col);
|
|
} else
|
|
if (x < y) {
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx + x, cy + y, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx - x, cy + y, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx + x, cy - y, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx - x, cy - y, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx + y, cy + x, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx - y, cy + x, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx + y, cy - x, col);
|
|
set_pixel(pixels, width, height, bpp, pixel_func, cx - y, cy - x, col);
|
|
}
|
|
}
|
|
|
|
void gdx2d_draw_circle(const gdx2d_pixmap* pixmap, int32_t x, int32_t y, uint32_t radius, uint32_t col) {
|
|
int32_t px = 0;
|
|
int32_t py = radius;
|
|
int32_t p = (5 - (int32_t)radius*4)/4;
|
|
unsigned char* pixels = (unsigned char*)pixmap->pixels;
|
|
uint32_t width = pixmap->width;
|
|
uint32_t height = pixmap->height;
|
|
uint32_t bpp = gdx2d_bytes_per_pixel(pixmap->format);
|
|
set_pixel_func pixel_func = set_pixel_func_ptr(pixmap->format);
|
|
col = to_format(pixmap->format, col);
|
|
|
|
circle_points(pixels, width, height, bpp, pixel_func, x, y, px, py, col);
|
|
while (px < py) {
|
|
px++;
|
|
if (p < 0) {
|
|
p += 2*px+1;
|
|
} else {
|
|
py--;
|
|
p += 2*(px-py)+1;
|
|
}
|
|
circle_points(pixels, width, height, bpp, pixel_func, x, y, px, py, col);
|
|
}
|
|
}
|
|
|
|
void gdx2d_fill_rect(const gdx2d_pixmap* pixmap, int32_t x, int32_t y, uint32_t width, uint32_t height, uint32_t col) {
|
|
int32_t x2 = x + width - 1;
|
|
int32_t y2 = y + height - 1;
|
|
|
|
if(x >= (int32_t)pixmap->width) return;
|
|
if(y >= (int32_t)pixmap->height) return;
|
|
if(x2 < 0) return;
|
|
if(y2 < 0) return;
|
|
|
|
if(x < 0) x = 0;
|
|
if(y < 0) y = 0;
|
|
if(x2 >= (int32_t)pixmap->width) x2 = pixmap->width - 1;
|
|
if(y2 >= (int32_t)pixmap->height) y2 = pixmap->height - 1;
|
|
|
|
y2++;
|
|
while(y!=y2) {
|
|
hline(pixmap, x, x2, y, col);
|
|
y++;
|
|
}
|
|
}
|
|
|
|
void gdx2d_fill_circle(const gdx2d_pixmap* pixmap, int32_t x0, int32_t y0, uint32_t radius, uint32_t col) {
|
|
int32_t f = 1 - (int32_t)radius;
|
|
int32_t ddF_x = 1;
|
|
int32_t ddF_y = -2 * (int32_t)radius;
|
|
int32_t px = 0;
|
|
int32_t py = (int32_t)radius;
|
|
|
|
hline(pixmap, x0, x0, y0 + (int32_t)radius, col);
|
|
hline(pixmap, x0, x0, y0 - (int32_t)radius, col);
|
|
hline(pixmap, x0 - (int32_t)radius, x0 + (int32_t)radius, y0, col);
|
|
|
|
|
|
while(px < py)
|
|
{
|
|
if(f >= 0)
|
|
{
|
|
py--;
|
|
ddF_y += 2;
|
|
f += ddF_y;
|
|
}
|
|
px++;
|
|
ddF_x += 2;
|
|
f += ddF_x;
|
|
hline(pixmap, x0 - px, x0 + px, y0 + py, col);
|
|
hline(pixmap, x0 - px, x0 + px, y0 - py, col);
|
|
hline(pixmap, x0 - py, x0 + py, y0 + px, col);
|
|
hline(pixmap, x0 - py, x0 + py, y0 - px, col);
|
|
}
|
|
}
|
|
|
|
#define max(a, b) (a < b?b:a)
|
|
|
|
#define EDGE_ASSIGN(edge,_x1,_y1,_x2,_y2) \
|
|
{ if (_y2 > _y1) { edge.y1 = _y1; edge.y2 = _y2; edge.x1 = _x1; edge.x2 = _x2; } \
|
|
else { edge.y2 = _y1; edge.y1 = _y2; edge.x2 = _x1; edge.x1 = _x2; } }
|
|
|
|
void gdx2d_fill_triangle(const gdx2d_pixmap* pixmap, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x3, int32_t y3, uint32_t col) {
|
|
|
|
// this structure is used to sort edges according to y-component.
|
|
struct edge {
|
|
int32_t x1;
|
|
int32_t y1;
|
|
int32_t x2;
|
|
int32_t y2;
|
|
};
|
|
struct edge edges[3], edge_tmp;
|
|
float slope0, slope1, slope2;
|
|
int32_t edge0_len, edge1_len, edge2_len, edge_len_tmp;
|
|
int32_t y, bound_y1, bound_y2, calc_x1, calc_x2;
|
|
|
|
// do nothing when points are colinear -- we draw the fill not the line.
|
|
if ((x2 - x1) * (y3 - y1) == (x3 - x1) * (y2 - y1)) {
|
|
return;
|
|
}
|
|
|
|
// asign input vertices into internally-sorted edge structures.
|
|
EDGE_ASSIGN(edges[0], x1, y1, x2, y2);
|
|
EDGE_ASSIGN(edges[1], x1, y1, x3, y3);
|
|
EDGE_ASSIGN(edges[2], x2, y2, x3, y3);
|
|
|
|
// order edges according to descending length.
|
|
edge0_len = edges[0].y2 - edges[0].y1;
|
|
edge1_len = edges[1].y2 - edges[1].y1;
|
|
edge2_len = edges[2].y2 - edges[2].y1;
|
|
|
|
if (edge1_len >= edge0_len && edge1_len >= edge2_len) {
|
|
// swap edge0 and edge1 with respective lengths.
|
|
edge_tmp = edges[0];
|
|
edges[0] = edges[1];
|
|
edges[1] = edge_tmp;
|
|
edge_len_tmp = edge0_len;
|
|
edge0_len = edge1_len;
|
|
edge1_len = edge_len_tmp;
|
|
} else if (edge2_len >= edge0_len && edge2_len >= edge1_len) {
|
|
// swap edge0 and edge2 with respective lengths.
|
|
edge_tmp = edges[0];
|
|
edges[0] = edges[2];
|
|
edges[2] = edge_tmp;
|
|
edge_len_tmp = edge0_len;
|
|
edge0_len = edge2_len;
|
|
edge2_len = edge_len_tmp;
|
|
}
|
|
|
|
if (edge2_len > edge1_len) {
|
|
// swap edge1 and edge2 - edge len no longer necessary.
|
|
edge_tmp = edges[1];
|
|
edges[1] = edges[2];
|
|
edges[2] = edge_tmp;
|
|
}
|
|
|
|
// y-component of the two longest y-component edges is provably > 0.
|
|
|
|
slope0 = ((float) (edges[0].x1 - edges[0].x2)) /
|
|
((float) (edges[0].y2 - edges[0].y1));
|
|
slope1 = ((float) (edges[1].x1 - edges[1].x2)) /
|
|
((float) (edges[1].y2 - edges[1].y1));
|
|
|
|
// avoid iterating on y values out of bounds.
|
|
bound_y1 = max(edges[1].y1, 0);
|
|
bound_y2 = min(edges[1].y2, pixmap->height-1);
|
|
|
|
for ( y=bound_y1; y <= bound_y2; y++ ) {
|
|
|
|
// calculate the x values for this y value.
|
|
calc_x1 = (int32_t) ((float) edges[0].x2 +
|
|
slope0 * (float) (edges[0].y2 - y) + 0.5);
|
|
calc_x2 = (int32_t) ((float) edges[1].x2 +
|
|
slope1 * (float) (edges[1].y2 - y) + 0.5);
|
|
|
|
// do not duplicate hline() swap and boundary checking.
|
|
hline(pixmap, calc_x1, calc_x2, y, col);
|
|
}
|
|
|
|
// if there are still values of y which remain, keep calculating.
|
|
|
|
if (edges[2].y2 - edges[2].y1 > 0) {
|
|
|
|
slope2 = ((float) (edges[2].x1 - edges[2].x2)) /
|
|
((float) (edges[2].y2 - edges[2].y1));
|
|
|
|
bound_y1 = max(edges[2].y1, 0);
|
|
bound_y2 = min(edges[2].y2, pixmap->height-1);
|
|
|
|
for ( y=bound_y1; y <= bound_y2; y++ ) {
|
|
|
|
calc_x1 = (int32_t) ((float) edges[0].x2 +
|
|
slope0 * (float) (edges[0].y2 - y) + 0.5);
|
|
calc_x2 = (int32_t) ((float) edges[2].x2 +
|
|
slope2 * (float) (edges[2].y2 - y) + 0.5);
|
|
|
|
hline(pixmap, calc_x1, calc_x2, y, col);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static inline void blit_same_size(const gdx2d_pixmap* src_pixmap, const gdx2d_pixmap* dst_pixmap,
|
|
int32_t src_x, int32_t src_y,
|
|
int32_t dst_x, int32_t dst_y,
|
|
uint32_t width, uint32_t height) {
|
|
set_pixel_func pset = set_pixel_func_ptr(dst_pixmap->format);
|
|
get_pixel_func pget = get_pixel_func_ptr(src_pixmap->format);
|
|
get_pixel_func dpget = get_pixel_func_ptr(dst_pixmap->format);
|
|
uint32_t sbpp = gdx2d_bytes_per_pixel(src_pixmap->format);
|
|
uint32_t dbpp = gdx2d_bytes_per_pixel(dst_pixmap->format);
|
|
uint32_t spitch = sbpp * src_pixmap->width;
|
|
uint32_t dpitch = dbpp * dst_pixmap->width;
|
|
|
|
int sx = src_x;
|
|
int sy = src_y;
|
|
int dx = dst_x;
|
|
int dy = dst_y;
|
|
|
|
for(;sy < src_y + height; sy++, dy++) {
|
|
if(sy < 0 || dy < 0) continue;
|
|
if(sy >= src_pixmap->height || dy >= dst_pixmap->height) break;
|
|
|
|
for(sx = src_x, dx = dst_x; sx < src_x + width; sx++, dx++) {
|
|
if(sx < 0 || dx < 0) continue;
|
|
if(sx >= src_pixmap->width || dx >= dst_pixmap->width) break;
|
|
|
|
const void* src_ptr = src_pixmap->pixels + sx * sbpp + sy * spitch;
|
|
const void* dst_ptr = dst_pixmap->pixels + dx * dbpp + dy * dpitch;
|
|
uint32_t src_col = to_RGBA8888(src_pixmap->format, pget((void*)src_ptr));
|
|
|
|
if(gdx2d_blend) {
|
|
uint32_t dst_col = to_RGBA8888(dst_pixmap->format, dpget((void*)dst_ptr));
|
|
src_col = to_format(dst_pixmap->format, blend(src_col, dst_col));
|
|
} else {
|
|
src_col = to_format(dst_pixmap->format, src_col);
|
|
}
|
|
|
|
pset((void*)dst_ptr, src_col);
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void blit_bilinear(const gdx2d_pixmap* src_pixmap, const gdx2d_pixmap* dst_pixmap,
|
|
int32_t src_x, int32_t src_y, uint32_t src_width, uint32_t src_height,
|
|
int32_t dst_x, int32_t dst_y, uint32_t dst_width, uint32_t dst_height) {
|
|
set_pixel_func pset = set_pixel_func_ptr(dst_pixmap->format);
|
|
get_pixel_func pget = get_pixel_func_ptr(src_pixmap->format);
|
|
get_pixel_func dpget = get_pixel_func_ptr(dst_pixmap->format);
|
|
uint32_t sbpp = gdx2d_bytes_per_pixel(src_pixmap->format);
|
|
uint32_t dbpp = gdx2d_bytes_per_pixel(dst_pixmap->format);
|
|
uint32_t spitch = sbpp * src_pixmap->width;
|
|
uint32_t dpitch = dbpp * dst_pixmap->width;
|
|
|
|
float x_ratio = ((float)src_width - 1)/ dst_width;
|
|
float y_ratio = ((float)src_height - 1) / dst_height;
|
|
float x_diff = 0;
|
|
float y_diff = 0;
|
|
|
|
int dx = dst_x;
|
|
int dy = dst_y;
|
|
int sx = src_x;
|
|
int sy = src_y;
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
for(;i < dst_height; i++) {
|
|
sy = (int)(i * y_ratio) + src_y;
|
|
dy = i + dst_y;
|
|
y_diff = (y_ratio * i + src_y) - sy;
|
|
if(sy < 0 || dy < 0) continue;
|
|
if(sy >= src_pixmap->height || dy >= dst_pixmap->height) break;
|
|
|
|
for(j = 0 ;j < dst_width; j++) {
|
|
sx = (int)(j * x_ratio) + src_x;
|
|
dx = j + dst_x;
|
|
x_diff = (x_ratio * j + src_x) - sx;
|
|
if(sx < 0 || dx < 0) continue;
|
|
if(sx >= src_pixmap->width || dx >= dst_pixmap->width) break;
|
|
|
|
const void* dst_ptr = dst_pixmap->pixels + dx * dbpp + dy * dpitch;
|
|
const void* src_ptr = src_pixmap->pixels + sx * sbpp + sy * spitch;
|
|
uint32_t c1 = 0, c2 = 0, c3 = 0, c4 = 0;
|
|
c1 = to_RGBA8888(src_pixmap->format, pget((void*)src_ptr));
|
|
if(sx + 1 < src_width) c2 = to_RGBA8888(src_pixmap->format, pget((void*)(src_ptr + sbpp))); else c2 = c1;
|
|
if(sy + 1< src_height) c3 = to_RGBA8888(src_pixmap->format, pget((void*)(src_ptr + spitch))); else c3 = c1;
|
|
if(sx + 1< src_width && sy + 1 < src_height) c4 = to_RGBA8888(src_pixmap->format, pget((void*)(src_ptr + spitch + sbpp))); else c4 = c1;
|
|
|
|
float ta = (1 - x_diff) * (1 - y_diff);
|
|
float tb = (x_diff) * (1 - y_diff);
|
|
float tc = (1 - x_diff) * (y_diff);
|
|
float td = (x_diff) * (y_diff);
|
|
|
|
uint32_t r = (uint32_t)(((c1 & 0xff000000) >> 24) * ta +
|
|
((c2 & 0xff000000) >> 24) * tb +
|
|
((c3 & 0xff000000) >> 24) * tc +
|
|
((c4 & 0xff000000) >> 24) * td) & 0xff;
|
|
uint32_t g = (uint32_t)(((c1 & 0xff0000) >> 16) * ta +
|
|
((c2 & 0xff0000) >> 16) * tb +
|
|
((c3 & 0xff0000) >> 16) * tc +
|
|
((c4 & 0xff0000) >> 16) * td) & 0xff;
|
|
uint32_t b = (uint32_t)(((c1 & 0xff00) >> 8) * ta +
|
|
((c2 & 0xff00) >> 8) * tb +
|
|
((c3 & 0xff00) >> 8) * tc +
|
|
((c4 & 0xff00) >> 8) * td) & 0xff;
|
|
uint32_t a = (uint32_t)((c1 & 0xff) * ta +
|
|
(c2 & 0xff) * tb +
|
|
(c3 & 0xff) * tc +
|
|
(c4 & 0xff) * td) & 0xff;
|
|
|
|
uint32_t src_col = (r << 24) | (g << 16) | (b << 8) | a;
|
|
|
|
if(gdx2d_blend) {
|
|
uint32_t dst_col = to_RGBA8888(dst_pixmap->format, dpget((void*)dst_ptr));
|
|
src_col = to_format(dst_pixmap->format, blend(src_col, dst_col));
|
|
} else {
|
|
src_col = to_format(dst_pixmap->format, src_col);
|
|
}
|
|
|
|
pset((void*)dst_ptr, src_col);
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void blit_linear(const gdx2d_pixmap* src_pixmap, const gdx2d_pixmap* dst_pixmap,
|
|
int32_t src_x, int32_t src_y, uint32_t src_width, uint32_t src_height,
|
|
int32_t dst_x, int32_t dst_y, uint32_t dst_width, uint32_t dst_height) {
|
|
set_pixel_func pset = set_pixel_func_ptr(dst_pixmap->format);
|
|
get_pixel_func pget = get_pixel_func_ptr(src_pixmap->format);
|
|
get_pixel_func dpget = get_pixel_func_ptr(dst_pixmap->format);
|
|
uint32_t sbpp = gdx2d_bytes_per_pixel(src_pixmap->format);
|
|
uint32_t dbpp = gdx2d_bytes_per_pixel(dst_pixmap->format);
|
|
uint32_t spitch = sbpp * src_pixmap->width;
|
|
uint32_t dpitch = dbpp * dst_pixmap->width;
|
|
|
|
uint32_t x_ratio = (src_width << 16) / dst_width + 1;
|
|
uint32_t y_ratio = (src_height << 16) / dst_height + 1;
|
|
|
|
int dx = dst_x;
|
|
int dy = dst_y;
|
|
int sx = src_x;
|
|
int sy = src_y;
|
|
int i = 0;
|
|
int j = 0;
|
|
|
|
for(;i < dst_height; i++) {
|
|
sy = ((i * y_ratio) >> 16) + src_y;
|
|
dy = i + dst_y;
|
|
if(sy < 0 || dy < 0) continue;
|
|
if(sy >= src_pixmap->height || dy >= dst_pixmap->height) break;
|
|
|
|
for(j = 0 ;j < dst_width; j++) {
|
|
sx = ((j * x_ratio) >> 16) + src_x;
|
|
dx = j + dst_x;
|
|
if(sx < 0 || dx < 0) continue;
|
|
if(sx >= src_pixmap->width || dx >= dst_pixmap->width) break;
|
|
|
|
const void* src_ptr = src_pixmap->pixels + sx * sbpp + sy * spitch;
|
|
const void* dst_ptr = dst_pixmap->pixels + dx * dbpp + dy * dpitch;
|
|
uint32_t src_col = to_RGBA8888(src_pixmap->format, pget((void*)src_ptr));
|
|
|
|
if(gdx2d_blend) {
|
|
uint32_t dst_col = to_RGBA8888(dst_pixmap->format, dpget((void*)dst_ptr));
|
|
src_col = to_format(dst_pixmap->format, blend(src_col, dst_col));
|
|
} else {
|
|
src_col = to_format(dst_pixmap->format, src_col);
|
|
}
|
|
|
|
pset((void*)dst_ptr, src_col);
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void blit(const gdx2d_pixmap* src_pixmap, const gdx2d_pixmap* dst_pixmap,
|
|
int32_t src_x, int32_t src_y, uint32_t src_width, uint32_t src_height,
|
|
int32_t dst_x, int32_t dst_y, uint32_t dst_width, uint32_t dst_height) {
|
|
if(gdx2d_scale == GDX2D_SCALE_NEAREST)
|
|
blit_linear(src_pixmap, dst_pixmap, src_x, src_y, src_width, src_height, dst_x, dst_y, dst_width, dst_height);
|
|
if(gdx2d_scale == GDX2D_SCALE_BILINEAR)
|
|
blit_bilinear(src_pixmap, dst_pixmap, src_x, src_y, src_width, src_height, dst_x, dst_y, dst_width, dst_height);
|
|
}
|
|
|
|
void gdx2d_draw_pixmap(const gdx2d_pixmap* src_pixmap, const gdx2d_pixmap* dst_pixmap,
|
|
int32_t src_x, int32_t src_y, uint32_t src_width, uint32_t src_height,
|
|
int32_t dst_x, int32_t dst_y, uint32_t dst_width, uint32_t dst_height) {
|
|
if(src_width == dst_width && src_height == dst_height) {
|
|
blit_same_size(src_pixmap, dst_pixmap, src_x, src_y, dst_x, dst_y, src_width, src_height);
|
|
} else {
|
|
blit(src_pixmap, dst_pixmap, src_x, src_y, src_width, src_height, dst_x, dst_y, dst_width, dst_height);
|
|
}
|
|
}
|