REVIEWED: GetPixelDataSize(), avoid allocations >2GB - ROS: CLN-013
REVIEWED: `GenImageColor()`, `ImageRotate()`
This commit is contained in:
parent
97d2b0146c
commit
cfe56d97ea
2 changed files with 61 additions and 42 deletions
18
src/rlgl.h
18
src/rlgl.h
|
|
@ -5236,7 +5236,9 @@ static int rlGetPixelDataSize(int width, int height, int format)
|
||||||
{
|
{
|
||||||
int blockWidth = (width + 3)/4;
|
int blockWidth = (width + 3)/4;
|
||||||
int blockHeight = (height + 3)/4;
|
int blockHeight = (height + 3)/4;
|
||||||
dataSize = blockWidth*blockHeight*8;
|
unsigned long long dataSizeBytes = blockWidth*blockHeight*8;
|
||||||
|
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA:
|
case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA:
|
||||||
case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA:
|
case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA:
|
||||||
|
|
@ -5245,13 +5247,17 @@ static int rlGetPixelDataSize(int width, int height, int format)
|
||||||
{
|
{
|
||||||
int blockWidth = (width + 3)/4;
|
int blockWidth = (width + 3)/4;
|
||||||
int blockHeight = (height + 3)/4;
|
int blockHeight = (height + 3)/4;
|
||||||
dataSize = blockWidth*blockHeight*16;
|
unsigned long long dataSizeBytes = blockWidth*blockHeight*16;
|
||||||
|
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 4 bytes per each 4x4 block
|
case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 4 bytes per each 4x4 block
|
||||||
{
|
{
|
||||||
int blockWidth = (width + 3)/4;
|
int blockWidth = (width + 3)/4;
|
||||||
int blockHeight = (height + 3)/4;
|
int blockHeight = (height + 3)/4;
|
||||||
dataSize = blockWidth*blockHeight*4;
|
unsigned long long dataSizeBytes = blockWidth*blockHeight*4;
|
||||||
|
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
@ -5260,9 +5266,11 @@ static int rlGetPixelDataSize(int width, int height, int format)
|
||||||
if ((format >= RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) &&
|
if ((format >= RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) &&
|
||||||
(format <= RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16))
|
(format <= RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16))
|
||||||
{
|
{
|
||||||
double bytesPerPixel = (double)bpp/8.0;
|
unsigned long long dataSizeBytes = (width*height*bpp) >> 3; // Get size in bytes (dividing by 8)
|
||||||
dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes
|
if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dataSize == 0) TRACELOG(LOG_WARNING, "Requested image size is larger than 2GB, it can not be allocated");
|
||||||
|
|
||||||
return dataSize;
|
return dataSize;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -843,9 +843,10 @@ bool ExportImageAsCode(Image image, const char *fileName)
|
||||||
// Generate image: plain color
|
// Generate image: plain color
|
||||||
Image GenImageColor(int width, int height, Color color)
|
Image GenImageColor(int width, int height, Color color)
|
||||||
{
|
{
|
||||||
Color *pixels = (Color *)RL_CALLOC(width*height, sizeof(Color));
|
int dataSize = GetPixelDataSize(width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
|
||||||
|
Color *pixels = (Color *)RL_CALLOC(dataSize, 1);
|
||||||
|
|
||||||
for (int i = 0; i < width*height; i++) pixels[i] = color;
|
for (int i = 0; (pixels != NULL) && (i < width*height); i++) pixels[i] = color;
|
||||||
|
|
||||||
Image image = {
|
Image image = {
|
||||||
.data = pixels,
|
.data = pixels,
|
||||||
|
|
@ -2691,45 +2692,48 @@ void ImageRotate(Image *image, int degrees)
|
||||||
int width = (int)(fabsf(image->width*cosRadius) + fabsf(image->height*sinRadius));
|
int width = (int)(fabsf(image->width*cosRadius) + fabsf(image->height*sinRadius));
|
||||||
int height = (int)(fabsf(image->height*cosRadius) + fabsf(image->width*sinRadius));
|
int height = (int)(fabsf(image->height*cosRadius) + fabsf(image->width*sinRadius));
|
||||||
|
|
||||||
int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
|
int bytesPerPixel = GetPixelDataSize(width, height, image->format);
|
||||||
unsigned char *rotatedData = (unsigned char *)RL_CALLOC(width*height, bytesPerPixel);
|
unsigned char *rotatedData = (unsigned char *)RL_CALLOC(bytesPerPixel, 1);
|
||||||
|
|
||||||
for (int y = 0; y < height; y++)
|
if (rotatedData != NULL)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < width; x++)
|
for (int y = 0; y < height; y++)
|
||||||
{
|
{
|
||||||
float oldX = ((x - width/2.0f)*cosRadius + (y - height/2.0f)*sinRadius) + image->width/2.0f;
|
for (int x = 0; x < width; x++)
|
||||||
float oldY = ((y - height/2.0f)*cosRadius - (x - width/2.0f)*sinRadius) + image->height/2.0f;
|
|
||||||
|
|
||||||
if ((oldX >= 0) && (oldX < image->width) && (oldY >= 0) && (oldY < image->height))
|
|
||||||
{
|
{
|
||||||
int x1 = (int)floorf(oldX);
|
float oldX = ((x - width/2.0f)*cosRadius + (y - height/2.0f)*sinRadius) + image->width/2.0f;
|
||||||
int y1 = (int)floorf(oldY);
|
float oldY = ((y - height/2.0f)*cosRadius - (x - width/2.0f)*sinRadius) + image->height/2.0f;
|
||||||
int x2 = MIN(x1 + 1, image->width - 1);
|
|
||||||
int y2 = MIN(y1 + 1, image->height - 1);
|
|
||||||
|
|
||||||
float px = oldX - x1;
|
if ((oldX >= 0) && (oldX < image->width) && (oldY >= 0) && (oldY < image->height))
|
||||||
float py = oldY - y1;
|
|
||||||
|
|
||||||
for (int i = 0; i < bytesPerPixel; i++)
|
|
||||||
{
|
{
|
||||||
float f1 = ((unsigned char *)image->data)[(y1*image->width + x1)*bytesPerPixel + i];
|
int x1 = (int)floorf(oldX);
|
||||||
float f2 = ((unsigned char *)image->data)[(y1*image->width + x2)*bytesPerPixel + i];
|
int y1 = (int)floorf(oldY);
|
||||||
float f3 = ((unsigned char *)image->data)[(y2*image->width + x1)*bytesPerPixel + i];
|
int x2 = MIN(x1 + 1, image->width - 1);
|
||||||
float f4 = ((unsigned char *)image->data)[(y2*image->width + x2)*bytesPerPixel + i];
|
int y2 = MIN(y1 + 1, image->height - 1);
|
||||||
|
|
||||||
float val = f1*(1 - px)*(1 - py) + f2*px*(1 - py) + f3*(1 - px)*py + f4*px*py;
|
float px = oldX - x1;
|
||||||
|
float py = oldY - y1;
|
||||||
|
|
||||||
rotatedData[(y*width + x)*bytesPerPixel + i] = (unsigned char)val;
|
for (int i = 0; i < bytesPerPixel; i++)
|
||||||
|
{
|
||||||
|
float f1 = ((unsigned char *)image->data)[(y1*image->width + x1)*bytesPerPixel + i];
|
||||||
|
float f2 = ((unsigned char *)image->data)[(y1*image->width + x2)*bytesPerPixel + i];
|
||||||
|
float f3 = ((unsigned char *)image->data)[(y2*image->width + x1)*bytesPerPixel + i];
|
||||||
|
float f4 = ((unsigned char *)image->data)[(y2*image->width + x2)*bytesPerPixel + i];
|
||||||
|
|
||||||
|
float val = f1*(1 - px)*(1 - py) + f2*px*(1 - py) + f3*(1 - px)*py + f4*px*py;
|
||||||
|
|
||||||
|
rotatedData[(y*width + x)*bytesPerPixel + i] = (unsigned char)val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
RL_FREE(image->data);
|
RL_FREE(image->data);
|
||||||
image->data = rotatedData;
|
image->data = rotatedData;
|
||||||
image->width = width;
|
image->width = width;
|
||||||
image->height = height;
|
image->height = height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5508,17 +5512,24 @@ int GetPixelDataSize(int width, int height, int format)
|
||||||
case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
|
case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long long dataSizeBytes = (width*height*bpp) >> 3; // Get size in bytes (dividing by 8)
|
||||||
|
|
||||||
double bytesPerPixel = (double)bpp/8.0;
|
if (dataSizeBytes < INT_MAX)
|
||||||
dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes
|
|
||||||
|
|
||||||
// Most compressed formats works on 4x4 blocks,
|
|
||||||
// if texture is smaller, minimum dataSize is 8 or 16
|
|
||||||
if ((width < 4) && (height < 4))
|
|
||||||
{
|
{
|
||||||
if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8;
|
dataSize = (int)dataSizeBytes;
|
||||||
else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16;
|
|
||||||
|
// Most compressed formats works on 4x4 blocks,
|
||||||
|
// if texture is smaller, minimum dataSize is 8 or 16
|
||||||
|
if ((width < 4) && (height < 4))
|
||||||
|
{
|
||||||
|
if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8;
|
||||||
|
else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: In case required image data larger than 2GB, no memory allocated at all (NULL)
|
||||||
|
if (dataSize == 0) TRACELOG(LOG_WARNING, "Requested image size is larger than 2GB, it can not be allocated");
|
||||||
|
|
||||||
return dataSize;
|
return dataSize;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue