Update C sources
This commit is contained in:
parent
2a66186c7d
commit
1868520849
27 changed files with 4582 additions and 2234 deletions
|
@ -42,7 +42,7 @@
|
|||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -71,10 +71,10 @@
|
|||
#if defined(SUPPORT_MODULE_RTEXTURES)
|
||||
|
||||
#include "utils.h" // Required for: TRACELOG()
|
||||
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2
|
||||
#include "rlgl.h" // OpenGL abstraction layer to multiple versions
|
||||
|
||||
#include <stdlib.h> // Required for: malloc(), free()
|
||||
#include <string.h> // Required for: strlen() [Used in ImageTextEx()], strcmp() [Used in LoadImageFromMemory()]
|
||||
#include <stdlib.h> // Required for: malloc(), calloc(), free()
|
||||
#include <string.h> // Required for: strlen() [Used in ImageTextEx()], strcmp() [Used in LoadImageFromMemory()/LoadImageAnimFromMemory()/ExportImageToMemory()]
|
||||
#include <math.h> // Required for: fabsf() [Used in DrawTextureRec()]
|
||||
#include <stdio.h> // Required for: sprintf() [Used in ExportImageAsCode()]
|
||||
|
||||
|
@ -212,15 +212,25 @@
|
|||
|
||||
#define STBIR_MALLOC(size,c) ((void)(c), RL_MALLOC(size))
|
||||
#define STBIR_FREE(ptr,c) ((void)(c), RL_FREE(ptr))
|
||||
|
||||
#if defined(__GNUC__) // GCC and Clang
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include "external/stb_image_resize2.h" // Required for: stbir_resize_uint8_linear() [ImageResize()]
|
||||
#include "external/stb_image_resize2.h" // Required for: stbir_resize_uint8_linear() [ImageResize()]
|
||||
|
||||
#if defined(__GNUC__) // GCC and Clang
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORT_FILEFORMAT_SVG)
|
||||
#define NANOSVG_IMPLEMENTATION // Expands implementation
|
||||
#include "external/nanosvg.h"
|
||||
#define NANOSVG_IMPLEMENTATION // Expands implementation
|
||||
#include "external/nanosvg.h"
|
||||
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
#include "external/nanosvgrast.h"
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
#include "external/nanosvgrast.h"
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
@ -283,9 +293,12 @@ Image LoadImage(const char *fileName)
|
|||
unsigned char *fileData = LoadFileData(fileName, &dataSize);
|
||||
|
||||
// Loading image from memory data
|
||||
if (fileData != NULL) image = LoadImageFromMemory(GetFileExtension(fileName), fileData, dataSize);
|
||||
if (fileData != NULL)
|
||||
{
|
||||
image = LoadImageFromMemory(GetFileExtension(fileName), fileData, dataSize);
|
||||
|
||||
RL_FREE(fileData);
|
||||
UnloadFileData(fileData);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
@ -301,18 +314,22 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
|
|||
if (fileData != NULL)
|
||||
{
|
||||
unsigned char *dataPtr = fileData;
|
||||
unsigned int size = GetPixelDataSize(width, height, format);
|
||||
int size = GetPixelDataSize(width, height, format);
|
||||
|
||||
if (headerSize > 0) dataPtr += headerSize;
|
||||
if (size <= dataSize) // Security check
|
||||
{
|
||||
// Offset file data to expected raw image by header size
|
||||
if ((headerSize > 0) && ((headerSize + size) <= dataSize)) dataPtr += headerSize;
|
||||
|
||||
image.data = RL_MALLOC(size); // Allocate required memory in bytes
|
||||
memcpy(image.data, dataPtr, size); // Copy required data to image
|
||||
image.width = width;
|
||||
image.height = height;
|
||||
image.mipmaps = 1;
|
||||
image.format = format;
|
||||
image.data = RL_MALLOC(size); // Allocate required memory in bytes
|
||||
memcpy(image.data, dataPtr, size); // Copy required data to image
|
||||
image.width = width;
|
||||
image.height = height;
|
||||
image.mipmaps = 1;
|
||||
image.format = format;
|
||||
}
|
||||
|
||||
RL_FREE(fileData);
|
||||
UnloadFileData(fileData);
|
||||
}
|
||||
|
||||
return image;
|
||||
|
@ -368,8 +385,8 @@ Image LoadImageSvg(const char *fileNameOrString, int width, int height)
|
|||
int offsetX = 0;
|
||||
int offsetY = 0;
|
||||
|
||||
if (scaleHeight > scaleWidth) offsetY = (height - svgImage->height*scale) / 2;
|
||||
else offsetX = (width - svgImage->width*scale) / 2;
|
||||
if (scaleHeight > scaleWidth) offsetY = (height - svgImage->height*scale)/2;
|
||||
else offsetX = (width - svgImage->width*scale)/2;
|
||||
|
||||
// Rasterize
|
||||
struct NSVGrasterizer *rast = nsvgCreateRasterizer();
|
||||
|
@ -421,7 +438,7 @@ Image LoadImageAnim(const char *fileName, int *frames)
|
|||
image.mipmaps = 1;
|
||||
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||
|
||||
RL_FREE(fileData);
|
||||
UnloadFileData(fileData);
|
||||
RL_FREE(delays); // NOTE: Frames delays are discarded
|
||||
}
|
||||
}
|
||||
|
@ -438,12 +455,56 @@ Image LoadImageAnim(const char *fileName, int *frames)
|
|||
return image;
|
||||
}
|
||||
|
||||
// Load animated image data
|
||||
// - Image.data buffer includes all frames: [image#0][image#1][image#2][...]
|
||||
// - Number of frames is returned through 'frames' parameter
|
||||
// - All frames are returned in RGBA format
|
||||
// - Frames delay data is discarded
|
||||
Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames)
|
||||
{
|
||||
Image image = { 0 };
|
||||
int frameCount = 0;
|
||||
|
||||
// Security check for input data
|
||||
if ((fileType == NULL) || (fileData == NULL) || (dataSize == 0)) return image;
|
||||
|
||||
#if defined(SUPPORT_FILEFORMAT_GIF)
|
||||
if ((strcmp(fileType, ".gif") == 0) || (strcmp(fileType, ".GIF") == 0))
|
||||
{
|
||||
if (fileData != NULL)
|
||||
{
|
||||
int comp = 0;
|
||||
int *delays = NULL;
|
||||
image.data = stbi_load_gif_from_memory(fileData, dataSize, &delays, &image.width, &image.height, &frameCount, &comp, 4);
|
||||
|
||||
image.mipmaps = 1;
|
||||
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||
|
||||
RL_FREE(delays); // NOTE: Frames delays are discarded
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (false) { }
|
||||
#endif
|
||||
else
|
||||
{
|
||||
image = LoadImageFromMemory(fileType, fileData, dataSize);
|
||||
frameCount = 1;
|
||||
}
|
||||
|
||||
*frames = frameCount;
|
||||
return image;
|
||||
}
|
||||
|
||||
// Load image from memory buffer, fileType refers to extension: i.e. ".png"
|
||||
// WARNING: File extension must be provided in lower-case
|
||||
Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize)
|
||||
{
|
||||
Image image = { 0 };
|
||||
|
||||
// Security check for input data
|
||||
if ((fileType == NULL) || (fileData == NULL) || (dataSize == 0)) return image;
|
||||
|
||||
if ((false)
|
||||
#if defined(SUPPORT_FILEFORMAT_PNG)
|
||||
|| (strcmp(fileType, ".png") == 0) || (strcmp(fileType, ".PNG") == 0)
|
||||
|
@ -633,10 +694,11 @@ Image LoadImageFromTexture(Texture2D texture)
|
|||
// Load image from screen buffer and (screenshot)
|
||||
Image LoadImageFromScreen(void)
|
||||
{
|
||||
Vector2 scale = GetWindowScaleDPI();
|
||||
Image image = { 0 };
|
||||
|
||||
image.width = GetScreenWidth();
|
||||
image.height = GetScreenHeight();
|
||||
image.width = (int)(GetScreenWidth()*scale.x);
|
||||
image.height = (int)(GetScreenHeight()*scale.y);
|
||||
image.mipmaps = 1;
|
||||
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||
image.data = rlReadScreenPixels(image.width, image.height);
|
||||
|
@ -647,11 +709,15 @@ Image LoadImageFromScreen(void)
|
|||
// Check if an image is ready
|
||||
bool IsImageReady(Image image)
|
||||
{
|
||||
return ((image.data != NULL) && // Validate pixel data available
|
||||
(image.width > 0) &&
|
||||
(image.height > 0) && // Validate image size
|
||||
(image.format > 0) && // Validate image format
|
||||
(image.mipmaps > 0)); // Validate image mipmaps (at least 1 for basic mipmap level)
|
||||
bool result = false;
|
||||
|
||||
if ((image.data != NULL) && // Validate pixel data available
|
||||
(image.width > 0) &&
|
||||
(image.height > 0) && // Validate image size
|
||||
(image.format > 0) && // Validate image format
|
||||
(image.mipmaps > 0)) result = true; // Validate image mipmaps (at least 1 for basic mipmap level)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Unload image from CPU memory (RAM)
|
||||
|
@ -666,6 +732,7 @@ bool ExportImage(Image image, const char *fileName)
|
|||
{
|
||||
int result = 0;
|
||||
|
||||
// Security check for input data
|
||||
if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return result;
|
||||
|
||||
#if defined(SUPPORT_IMAGE_EXPORT)
|
||||
|
@ -753,6 +820,7 @@ unsigned char *ExportImageToMemory(Image image, const char *fileType, int *dataS
|
|||
unsigned char *fileData = NULL;
|
||||
*dataSize = 0;
|
||||
|
||||
// Security check for input data
|
||||
if ((image.width == 0) || (image.height == 0) || (image.data == NULL)) return NULL;
|
||||
|
||||
#if defined(SUPPORT_IMAGE_EXPORT)
|
||||
|
@ -800,7 +868,7 @@ bool ExportImageAsCode(Image image, const char *fileName)
|
|||
byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
|
||||
byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
|
||||
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||
byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2023 Ramon Santamaria (@raysan5) //\n");
|
||||
byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2024 Ramon Santamaria (@raysan5) //\n");
|
||||
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
|
||||
|
||||
|
@ -856,8 +924,8 @@ Image GenImageColor(int width, int height, Color color)
|
|||
#if defined(SUPPORT_IMAGE_GENERATION)
|
||||
// Generate image: linear gradient
|
||||
// The direction value specifies the direction of the gradient (in degrees)
|
||||
// with 0 being vertical (from top to bottom), 90 being horizontal (from left to right).
|
||||
// The gradient effectively rotates counter-clockwise by the specified amount.
|
||||
// with 0 being vertical (from top to bottom), 90 being horizontal (from left to right)
|
||||
// The gradient effectively rotates counter-clockwise by the specified amount
|
||||
Image GenImageGradientLinear(int width, int height, int direction, Color start, Color end)
|
||||
{
|
||||
Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
|
||||
|
@ -950,8 +1018,8 @@ Image GenImageGradientSquare(int width, int height, float density, Color inner,
|
|||
float distY = fabsf(y - centerY);
|
||||
|
||||
// Normalize the distances by the dimensions of the gradient rectangle
|
||||
float normalizedDistX = distX / centerX;
|
||||
float normalizedDistY = distY / centerY;
|
||||
float normalizedDistX = distX/centerX;
|
||||
float normalizedDistY = distY/centerY;
|
||||
|
||||
// Calculate the total normalized Manhattan distance
|
||||
float manhattanDist = fmaxf(normalizedDistX, normalizedDistY);
|
||||
|
@ -1008,6 +1076,7 @@ Image GenImageChecked(int width, int height, int checksX, int checksY, Color col
|
|||
}
|
||||
|
||||
// Generate image: white noise
|
||||
// NOTE: It requires GetRandomValue(), defined in [rcore]
|
||||
Image GenImageWhiteNoise(int width, int height, float factor)
|
||||
{
|
||||
Color *pixels = (Color *)RL_MALLOC(width*height*sizeof(Color));
|
||||
|
@ -1546,7 +1615,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
|
|||
// Scale image depending on text size
|
||||
if (textSize.y != imSize.y)
|
||||
{
|
||||
float scaleFactor = textSize.y / imSize.y;
|
||||
float scaleFactor = textSize.y/imSize.y;
|
||||
TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor);
|
||||
|
||||
// Using nearest-neighbor scaling algorithm for default font
|
||||
|
@ -1600,7 +1669,6 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight)
|
|||
UnloadImageColors(pixels);
|
||||
}
|
||||
|
||||
|
||||
// Resize and image to new size
|
||||
// NOTE: Uses stb default scaling filters (both bicubic):
|
||||
// STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
|
||||
|
@ -1693,8 +1761,22 @@ void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, i
|
|||
int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
|
||||
unsigned char *resizedData = (unsigned char *)RL_CALLOC(newWidth*newHeight*bytesPerPixel, 1);
|
||||
|
||||
// TODO: Fill resized canvas with fill color (must be formatted to image->format)
|
||||
// Fill resized canvas with fill color
|
||||
// Set first pixel with image->format
|
||||
SetPixelColor(resizedData, fill, image->format);
|
||||
|
||||
// Fill remaining bytes of first row
|
||||
for (int x = 1; x < newWidth; x++)
|
||||
{
|
||||
memcpy(resizedData + x*bytesPerPixel, resizedData, bytesPerPixel);
|
||||
}
|
||||
// Copy the first row into the other rows
|
||||
for (int y = 1; y < newHeight; y++)
|
||||
{
|
||||
memcpy(resizedData + y*newWidth*bytesPerPixel, resizedData, newWidth*bytesPerPixel);
|
||||
}
|
||||
|
||||
// Copy old image to resized canvas
|
||||
int dstOffsetSize = ((int)dstPos.y*newWidth + (int)dstPos.x)*bytesPerPixel;
|
||||
|
||||
for (int y = 0; y < (int)srcRec.height; y++)
|
||||
|
@ -1930,8 +2012,9 @@ void ImageAlphaPremultiply(Image *image)
|
|||
ImageFormat(image, format);
|
||||
}
|
||||
|
||||
// Apply box blur
|
||||
void ImageBlurGaussian(Image *image, int blurSize) {
|
||||
// Apply box blur to image
|
||||
void ImageBlurGaussian(Image *image, int blurSize)
|
||||
{
|
||||
// Security check to avoid program crash
|
||||
if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
|
||||
|
||||
|
@ -1943,7 +2026,8 @@ void ImageBlurGaussian(Image *image, int blurSize) {
|
|||
Vector4 *pixelsCopy1 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *pixelsCopy2 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
|
||||
for (int i = 0; i < (image->height)*(image->width); i++) {
|
||||
for (int i = 0; i < (image->height*image->width); i++)
|
||||
{
|
||||
pixelsCopy1[i].x = pixels[i].r;
|
||||
pixelsCopy1[i].y = pixels[i].g;
|
||||
pixelsCopy1[i].z = pixels[i].b;
|
||||
|
@ -1951,7 +2035,8 @@ void ImageBlurGaussian(Image *image, int blurSize) {
|
|||
}
|
||||
|
||||
// Repeated convolution of rectangular window signal by itself converges to a gaussian distribution
|
||||
for (int j = 0; j < GAUSSIAN_BLUR_ITERATIONS; j++) {
|
||||
for (int j = 0; j < GAUSSIAN_BLUR_ITERATIONS; j++)
|
||||
{
|
||||
// Horizontal motion blur
|
||||
for (int row = 0; row < image->height; row++)
|
||||
{
|
||||
|
@ -1959,9 +2044,9 @@ void ImageBlurGaussian(Image *image, int blurSize) {
|
|||
float avgG = 0.0f;
|
||||
float avgB = 0.0f;
|
||||
float avgAlpha = 0.0f;
|
||||
int convolutionSize = blurSize+1;
|
||||
int convolutionSize = blurSize;
|
||||
|
||||
for (int i = 0; i < blurSize+1; i++)
|
||||
for (int i = 0; i < blurSize; i++)
|
||||
{
|
||||
avgR += pixelsCopy1[row*image->width + i].x;
|
||||
avgG += pixelsCopy1[row*image->width + i].y;
|
||||
|
@ -1969,19 +2054,14 @@ void ImageBlurGaussian(Image *image, int blurSize) {
|
|||
avgAlpha += pixelsCopy1[row*image->width + i].w;
|
||||
}
|
||||
|
||||
pixelsCopy2[row*image->width].x = avgR/convolutionSize;
|
||||
pixelsCopy2[row*image->width].y = avgG/convolutionSize;
|
||||
pixelsCopy2[row*image->width].z = avgB/convolutionSize;
|
||||
pixelsCopy2[row*image->width].w = avgAlpha/convolutionSize;
|
||||
|
||||
for (int x = 1; x < image->width; x++)
|
||||
for (int x = 0; x < image->width; x++)
|
||||
{
|
||||
if (x-blurSize >= 0)
|
||||
if (x-blurSize-1 >= 0)
|
||||
{
|
||||
avgR -= pixelsCopy1[row*image->width + x-blurSize].x;
|
||||
avgG -= pixelsCopy1[row*image->width + x-blurSize].y;
|
||||
avgB -= pixelsCopy1[row*image->width + x-blurSize].z;
|
||||
avgAlpha -= pixelsCopy1[row*image->width + x-blurSize].w;
|
||||
avgR -= pixelsCopy1[row*image->width + x-blurSize-1].x;
|
||||
avgG -= pixelsCopy1[row*image->width + x-blurSize-1].y;
|
||||
avgB -= pixelsCopy1[row*image->width + x-blurSize-1].z;
|
||||
avgAlpha -= pixelsCopy1[row*image->width + x-blurSize-1].w;
|
||||
convolutionSize--;
|
||||
}
|
||||
|
||||
|
@ -1999,7 +2079,7 @@ void ImageBlurGaussian(Image *image, int blurSize) {
|
|||
pixelsCopy2[row*image->width + x].z = avgB/convolutionSize;
|
||||
pixelsCopy2[row*image->width + x].w = avgAlpha/convolutionSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical motion blur
|
||||
for (int col = 0; col < image->width; col++)
|
||||
|
@ -2008,9 +2088,9 @@ void ImageBlurGaussian(Image *image, int blurSize) {
|
|||
float avgG = 0.0f;
|
||||
float avgB = 0.0f;
|
||||
float avgAlpha = 0.0f;
|
||||
int convolutionSize = blurSize+1;
|
||||
int convolutionSize = blurSize;
|
||||
|
||||
for (int i = 0; i < blurSize+1; i++)
|
||||
for (int i = 0; i < blurSize; i++)
|
||||
{
|
||||
avgR += pixelsCopy2[i*image->width + col].x;
|
||||
avgG += pixelsCopy2[i*image->width + col].y;
|
||||
|
@ -2018,19 +2098,14 @@ void ImageBlurGaussian(Image *image, int blurSize) {
|
|||
avgAlpha += pixelsCopy2[i*image->width + col].w;
|
||||
}
|
||||
|
||||
pixelsCopy1[col].x = (unsigned char) (avgR/convolutionSize);
|
||||
pixelsCopy1[col].y = (unsigned char) (avgG/convolutionSize);
|
||||
pixelsCopy1[col].z = (unsigned char) (avgB/convolutionSize);
|
||||
pixelsCopy1[col].w = (unsigned char) (avgAlpha/convolutionSize);
|
||||
|
||||
for (int y = 1; y < image->height; y++)
|
||||
for (int y = 0; y < image->height; y++)
|
||||
{
|
||||
if (y-blurSize >= 0)
|
||||
if (y-blurSize-1 >= 0)
|
||||
{
|
||||
avgR -= pixelsCopy2[(y-blurSize)*image->width + col].x;
|
||||
avgG -= pixelsCopy2[(y-blurSize)*image->width + col].y;
|
||||
avgB -= pixelsCopy2[(y-blurSize)*image->width + col].z;
|
||||
avgAlpha -= pixelsCopy2[(y-blurSize)*image->width + col].w;
|
||||
avgR -= pixelsCopy2[(y-blurSize-1)*image->width + col].x;
|
||||
avgG -= pixelsCopy2[(y-blurSize-1)*image->width + col].y;
|
||||
avgB -= pixelsCopy2[(y-blurSize-1)*image->width + col].z;
|
||||
avgAlpha -= pixelsCopy2[(y-blurSize-1)*image->width + col].w;
|
||||
convolutionSize--;
|
||||
}
|
||||
if (y+blurSize < image->height)
|
||||
|
@ -2050,7 +2125,6 @@ void ImageBlurGaussian(Image *image, int blurSize) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Reverse premultiply
|
||||
for (int i = 0; i < (image->width)*(image->height); i++)
|
||||
{
|
||||
|
@ -2082,6 +2156,135 @@ void ImageBlurGaussian(Image *image, int blurSize) {
|
|||
ImageFormat(image, format);
|
||||
}
|
||||
|
||||
// The kernel matrix is assumed to be square. Only supply the width of the kernel
|
||||
void ImageKernelConvolution(Image *image, float* kernel, int kernelSize)
|
||||
{
|
||||
if ((image->data == NULL) || (image->width == 0) || (image->height == 0) || kernel == NULL) return;
|
||||
|
||||
int kernelWidth = (int)sqrtf((float)kernelSize);
|
||||
|
||||
if (kernelWidth*kernelWidth != kernelSize)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "IMAGE: Convolution kernel must be square to be applied");
|
||||
return;
|
||||
}
|
||||
|
||||
Color *pixels = LoadImageColors(*image);
|
||||
|
||||
Vector4 *imageCopy2 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||
Vector4 *temp = RL_MALLOC(kernelSize*sizeof(Vector4));
|
||||
|
||||
for (int i = 0; i < kernelSize; i++)
|
||||
{
|
||||
temp[i].x = 0.0f;
|
||||
temp[i].y = 0.0f;
|
||||
temp[i].z = 0.0f;
|
||||
temp[i].w = 0.0f;
|
||||
}
|
||||
|
||||
float rRes = 0.0f;
|
||||
float gRes = 0.0f;
|
||||
float bRes = 0.0f;
|
||||
float aRes = 0.0f;
|
||||
|
||||
int startRange = 0, endRange = 0;
|
||||
|
||||
if (kernelWidth%2 == 0)
|
||||
{
|
||||
startRange = -kernelWidth/2;
|
||||
endRange = kernelWidth/2;
|
||||
}
|
||||
else
|
||||
{
|
||||
startRange = -kernelWidth/2;
|
||||
endRange = kernelWidth/2 + 1;
|
||||
}
|
||||
|
||||
for (int x = 0; x < image->height; x++)
|
||||
{
|
||||
for (int y = 0; y < image->width; y++)
|
||||
{
|
||||
for (int xk = startRange; xk < endRange; xk++)
|
||||
{
|
||||
for (int yk = startRange; yk < endRange; yk++)
|
||||
{
|
||||
int xkabs = xk + kernelWidth/2;
|
||||
int ykabs = yk + kernelWidth/2;
|
||||
unsigned int imgindex = image->width*(x + xk) + (y + yk);
|
||||
|
||||
if (imgindex >= (unsigned int)(image->width*image->height))
|
||||
{
|
||||
temp[kernelWidth*xkabs + ykabs].x = 0.0f;
|
||||
temp[kernelWidth*xkabs + ykabs].y = 0.0f;
|
||||
temp[kernelWidth*xkabs + ykabs].z = 0.0f;
|
||||
temp[kernelWidth*xkabs + ykabs].w = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp[kernelWidth*xkabs + ykabs].x = ((float)pixels[imgindex].r)/255.0f*kernel[kernelWidth*xkabs + ykabs];
|
||||
temp[kernelWidth*xkabs + ykabs].y = ((float)pixels[imgindex].g)/255.0f*kernel[kernelWidth*xkabs + ykabs];
|
||||
temp[kernelWidth*xkabs + ykabs].z = ((float)pixels[imgindex].b)/255.0f*kernel[kernelWidth*xkabs + ykabs];
|
||||
temp[kernelWidth*xkabs + ykabs].w = ((float)pixels[imgindex].a)/255.0f*kernel[kernelWidth*xkabs + ykabs];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < kernelSize; i++)
|
||||
{
|
||||
rRes += temp[i].x;
|
||||
gRes += temp[i].y;
|
||||
bRes += temp[i].z;
|
||||
aRes += temp[i].w;
|
||||
}
|
||||
|
||||
if (rRes < 0.0f) rRes = 0.0f;
|
||||
if (gRes < 0.0f) gRes = 0.0f;
|
||||
if (bRes < 0.0f) bRes = 0.0f;
|
||||
|
||||
if (rRes > 1.0f) rRes = 1.0f;
|
||||
if (gRes > 1.0f) gRes = 1.0f;
|
||||
if (bRes > 1.0f) bRes = 1.0f;
|
||||
|
||||
imageCopy2[image->width*x + y].x = rRes;
|
||||
imageCopy2[image->width*x + y].y = gRes;
|
||||
imageCopy2[image->width*x + y].z = bRes;
|
||||
imageCopy2[image->width*x + y].w = aRes;
|
||||
|
||||
rRes = 0.0f;
|
||||
gRes = 0.0f;
|
||||
bRes = 0.0f;
|
||||
aRes = 0.0f;
|
||||
|
||||
for (int i = 0; i < kernelSize; i++)
|
||||
{
|
||||
temp[i].x = 0.0f;
|
||||
temp[i].y = 0.0f;
|
||||
temp[i].z = 0.0f;
|
||||
temp[i].w = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < (image->width*image->height); i++)
|
||||
{
|
||||
float alpha = (float)imageCopy2[i].w;
|
||||
|
||||
pixels[i].r = (unsigned char)((imageCopy2[i].x)*255.0f);
|
||||
pixels[i].g = (unsigned char)((imageCopy2[i].y)*255.0f);
|
||||
pixels[i].b = (unsigned char)((imageCopy2[i].z)*255.0f);
|
||||
pixels[i].a = (unsigned char)((alpha)*255.0f);
|
||||
}
|
||||
|
||||
int format = image->format;
|
||||
RL_FREE(image->data);
|
||||
RL_FREE(imageCopy2);
|
||||
RL_FREE(temp);
|
||||
|
||||
image->data = pixels;
|
||||
image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||
ImageFormat(image, format);
|
||||
}
|
||||
|
||||
// Generate all mipmap levels for a provided image
|
||||
// NOTE 1: Supports POT and NPOT images
|
||||
// NOTE 2: image.data is scaled to include mipmap levels
|
||||
|
@ -2469,21 +2672,17 @@ void ImageColorTint(Image *image, Color color)
|
|||
float cB = (float)color.b/255;
|
||||
float cA = (float)color.a/255;
|
||||
|
||||
for (int y = 0; y < image->height; y++)
|
||||
for (int i = 0; i < image->width*image->height; i++)
|
||||
{
|
||||
for (int x = 0; x < image->width; x++)
|
||||
{
|
||||
int index = y*image->width + x;
|
||||
unsigned char r = (unsigned char)(((float)pixels[index].r/255*cR)*255.0f);
|
||||
unsigned char g = (unsigned char)(((float)pixels[index].g/255*cG)*255.0f);
|
||||
unsigned char b = (unsigned char)(((float)pixels[index].b/255*cB)*255.0f);
|
||||
unsigned char a = (unsigned char)(((float)pixels[index].a/255*cA)*255.0f);
|
||||
unsigned char r = (unsigned char)(((float)pixels[i].r/255*cR)*255.0f);
|
||||
unsigned char g = (unsigned char)(((float)pixels[i].g/255*cG)*255.0f);
|
||||
unsigned char b = (unsigned char)(((float)pixels[i].b/255*cB)*255.0f);
|
||||
unsigned char a = (unsigned char)(((float)pixels[i].a/255*cA)*255.0f);
|
||||
|
||||
pixels[index].r = r;
|
||||
pixels[index].g = g;
|
||||
pixels[index].b = b;
|
||||
pixels[index].a = a;
|
||||
}
|
||||
pixels[i].r = r;
|
||||
pixels[i].g = g;
|
||||
pixels[i].b = b;
|
||||
pixels[i].a = a;
|
||||
}
|
||||
|
||||
int format = image->format;
|
||||
|
@ -2503,14 +2702,11 @@ void ImageColorInvert(Image *image)
|
|||
|
||||
Color *pixels = LoadImageColors(*image);
|
||||
|
||||
for (int y = 0; y < image->height; y++)
|
||||
for (int i = 0; i < image->width*image->height; i++)
|
||||
{
|
||||
for (int x = 0; x < image->width; x++)
|
||||
{
|
||||
pixels[y*image->width + x].r = 255 - pixels[y*image->width + x].r;
|
||||
pixels[y*image->width + x].g = 255 - pixels[y*image->width + x].g;
|
||||
pixels[y*image->width + x].b = 255 - pixels[y*image->width + x].b;
|
||||
}
|
||||
pixels[i].r = 255 - pixels[i].r;
|
||||
pixels[i].g = 255 - pixels[i].g;
|
||||
pixels[i].b = 255 - pixels[i].b;
|
||||
}
|
||||
|
||||
int format = image->format;
|
||||
|
@ -2543,38 +2739,35 @@ void ImageColorContrast(Image *image, float contrast)
|
|||
|
||||
Color *pixels = LoadImageColors(*image);
|
||||
|
||||
for (int y = 0; y < image->height; y++)
|
||||
for (int i = 0; i < image->width*image->height; i++)
|
||||
{
|
||||
for (int x = 0; x < image->width; x++)
|
||||
{
|
||||
float pR = (float)pixels[y*image->width + x].r/255.0f;
|
||||
pR -= 0.5f;
|
||||
pR *= contrast;
|
||||
pR += 0.5f;
|
||||
pR *= 255;
|
||||
if (pR < 0) pR = 0;
|
||||
if (pR > 255) pR = 255;
|
||||
float pR = (float)pixels[i].r/255.0f;
|
||||
pR -= 0.5f;
|
||||
pR *= contrast;
|
||||
pR += 0.5f;
|
||||
pR *= 255;
|
||||
if (pR < 0) pR = 0;
|
||||
if (pR > 255) pR = 255;
|
||||
|
||||
float pG = (float)pixels[y*image->width + x].g/255.0f;
|
||||
pG -= 0.5f;
|
||||
pG *= contrast;
|
||||
pG += 0.5f;
|
||||
pG *= 255;
|
||||
if (pG < 0) pG = 0;
|
||||
if (pG > 255) pG = 255;
|
||||
float pG = (float)pixels[i].g/255.0f;
|
||||
pG -= 0.5f;
|
||||
pG *= contrast;
|
||||
pG += 0.5f;
|
||||
pG *= 255;
|
||||
if (pG < 0) pG = 0;
|
||||
if (pG > 255) pG = 255;
|
||||
|
||||
float pB = (float)pixels[y*image->width + x].b/255.0f;
|
||||
pB -= 0.5f;
|
||||
pB *= contrast;
|
||||
pB += 0.5f;
|
||||
pB *= 255;
|
||||
if (pB < 0) pB = 0;
|
||||
if (pB > 255) pB = 255;
|
||||
float pB = (float)pixels[i].b/255.0f;
|
||||
pB -= 0.5f;
|
||||
pB *= contrast;
|
||||
pB += 0.5f;
|
||||
pB *= 255;
|
||||
if (pB < 0) pB = 0;
|
||||
if (pB > 255) pB = 255;
|
||||
|
||||
pixels[y*image->width + x].r = (unsigned char)pR;
|
||||
pixels[y*image->width + x].g = (unsigned char)pG;
|
||||
pixels[y*image->width + x].b = (unsigned char)pB;
|
||||
}
|
||||
pixels[i].r = (unsigned char)pR;
|
||||
pixels[i].g = (unsigned char)pG;
|
||||
pixels[i].b = (unsigned char)pB;
|
||||
}
|
||||
|
||||
int format = image->format;
|
||||
|
@ -2598,27 +2791,24 @@ void ImageColorBrightness(Image *image, int brightness)
|
|||
|
||||
Color *pixels = LoadImageColors(*image);
|
||||
|
||||
for (int y = 0; y < image->height; y++)
|
||||
for (int i = 0; i < image->width*image->height; i++)
|
||||
{
|
||||
for (int x = 0; x < image->width; x++)
|
||||
{
|
||||
int cR = pixels[y*image->width + x].r + brightness;
|
||||
int cG = pixels[y*image->width + x].g + brightness;
|
||||
int cB = pixels[y*image->width + x].b + brightness;
|
||||
int cR = pixels[i].r + brightness;
|
||||
int cG = pixels[i].g + brightness;
|
||||
int cB = pixels[i].b + brightness;
|
||||
|
||||
if (cR < 0) cR = 1;
|
||||
if (cR > 255) cR = 255;
|
||||
if (cR < 0) cR = 1;
|
||||
if (cR > 255) cR = 255;
|
||||
|
||||
if (cG < 0) cG = 1;
|
||||
if (cG > 255) cG = 255;
|
||||
if (cG < 0) cG = 1;
|
||||
if (cG > 255) cG = 255;
|
||||
|
||||
if (cB < 0) cB = 1;
|
||||
if (cB > 255) cB = 255;
|
||||
if (cB < 0) cB = 1;
|
||||
if (cB > 255) cB = 255;
|
||||
|
||||
pixels[y*image->width + x].r = (unsigned char)cR;
|
||||
pixels[y*image->width + x].g = (unsigned char)cG;
|
||||
pixels[y*image->width + x].b = (unsigned char)cB;
|
||||
}
|
||||
pixels[i].r = (unsigned char)cR;
|
||||
pixels[i].g = (unsigned char)cG;
|
||||
pixels[i].b = (unsigned char)cB;
|
||||
}
|
||||
|
||||
int format = image->format;
|
||||
|
@ -2638,20 +2828,17 @@ void ImageColorReplace(Image *image, Color color, Color replace)
|
|||
|
||||
Color *pixels = LoadImageColors(*image);
|
||||
|
||||
for (int y = 0; y < image->height; y++)
|
||||
for (int i = 0; i < image->width*image->height; i++)
|
||||
{
|
||||
for (int x = 0; x < image->width; x++)
|
||||
if ((pixels[i].r == color.r) &&
|
||||
(pixels[i].g == color.g) &&
|
||||
(pixels[i].b == color.b) &&
|
||||
(pixels[i].a == color.a))
|
||||
{
|
||||
if ((pixels[y*image->width + x].r == color.r) &&
|
||||
(pixels[y*image->width + x].g == color.g) &&
|
||||
(pixels[y*image->width + x].b == color.b) &&
|
||||
(pixels[y*image->width + x].a == color.a))
|
||||
{
|
||||
pixels[y*image->width + x].r = replace.r;
|
||||
pixels[y*image->width + x].g = replace.g;
|
||||
pixels[y*image->width + x].b = replace.b;
|
||||
pixels[y*image->width + x].a = replace.a;
|
||||
}
|
||||
pixels[i].r = replace.r;
|
||||
pixels[i].g = replace.g;
|
||||
pixels[i].b = replace.b;
|
||||
pixels[i].a = replace.a;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3398,8 +3585,8 @@ void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
|
|||
if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0)) return;
|
||||
|
||||
// Security check to avoid drawing out of bounds in case of bad user data
|
||||
if (rec.x < 0) { rec.width -= rec.x; rec.x = 0; }
|
||||
if (rec.y < 0) { rec.height -= rec.y; rec.y = 0; }
|
||||
if (rec.x < 0) { rec.width += rec.x; rec.x = 0; }
|
||||
if (rec.y < 0) { rec.height += rec.y; rec.y = 0; }
|
||||
if (rec.width < 0) rec.width = 0;
|
||||
if (rec.height < 0) rec.height = 0;
|
||||
|
||||
|
@ -3408,8 +3595,8 @@ void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
|
|||
if ((rec.y + rec.height) >= dst->height) rec.height = dst->height - rec.y;
|
||||
|
||||
// Check if the rect is even inside the image
|
||||
if ((rec.x > dst->width) || (rec.y > dst->height)) return;
|
||||
if (((rec.x + rec.width) < 0) || (rec.y + rec.height < 0)) return;
|
||||
if ((rec.x >= dst->width) || (rec.y >= dst->height)) return;
|
||||
if (((rec.x + rec.width) <= 0) || (rec.y + rec.height <= 0)) return;
|
||||
|
||||
int sy = (int)rec.y;
|
||||
int sx = (int)rec.x;
|
||||
|
@ -3429,7 +3616,7 @@ void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
|
|||
}
|
||||
|
||||
// Repeat the first row data for all other rows
|
||||
int bytesPerRow = bytesPerPixel * (int)rec.width;
|
||||
int bytesPerRow = bytesPerPixel*(int)rec.width;
|
||||
for (int y = 1; y < (int)rec.height; y++)
|
||||
{
|
||||
memcpy(pSrcPixel + (y*dst->width)*bytesPerPixel, pSrcPixel, bytesPerRow);
|
||||
|
@ -3564,7 +3751,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
|
|||
// Draw text (default font) within an image (destination)
|
||||
void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color)
|
||||
{
|
||||
#if defined(SUPPORT_MODULE_RTEXT)
|
||||
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
|
||||
// Make sure default font is loaded to be used on image text drawing
|
||||
if (GetFontDefault().texture.id == 0) LoadFontDefault();
|
||||
|
||||
|
@ -3646,7 +3833,9 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
|
|||
if ((image.height/6) == image.width) { layout = CUBEMAP_LAYOUT_LINE_VERTICAL; cubemap.width = image.height/6; }
|
||||
else if ((image.width/3) == (image.height/4)) { layout = CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR; cubemap.width = image.width/3; }
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (layout == CUBEMAP_LAYOUT_LINE_VERTICAL) cubemap.width = image.height/6;
|
||||
if (layout == CUBEMAP_LAYOUT_LINE_HORIZONTAL) cubemap.width = image.width/6;
|
||||
if (layout == CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR) cubemap.width = image.width/3;
|
||||
|
@ -3663,6 +3852,7 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
|
|||
|
||||
Image faces = { 0 }; // Vertical column image
|
||||
Rectangle faceRecs[6] = { 0 }; // Face source rectangles
|
||||
|
||||
for (int i = 0; i < 6; i++) faceRecs[i] = (Rectangle){ 0, 0, (float)size, (float)size };
|
||||
|
||||
if (layout == CUBEMAP_LAYOUT_LINE_VERTICAL)
|
||||
|
@ -3708,7 +3898,13 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
|
|||
// NOTE: Cubemap data is expected to be provided as 6 images in a single data array,
|
||||
// one after the other (that's a vertical image), following convention: +X, -X, +Y, -Y, +Z, -Z
|
||||
cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format);
|
||||
if (cubemap.id == 0) TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image");
|
||||
|
||||
if (cubemap.id != 0)
|
||||
{
|
||||
cubemap.format = faces.format;
|
||||
cubemap.mipmaps = 1;
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image");
|
||||
|
||||
UnloadImage(faces);
|
||||
}
|
||||
|
@ -3723,7 +3919,7 @@ RenderTexture2D LoadRenderTexture(int width, int height)
|
|||
{
|
||||
RenderTexture2D target = { 0 };
|
||||
|
||||
target.id = rlLoadFramebuffer(width, height); // Load an empty framebuffer
|
||||
target.id = rlLoadFramebuffer(); // Load an empty framebuffer
|
||||
|
||||
if (target.id > 0)
|
||||
{
|
||||
|
@ -3760,13 +3956,17 @@ RenderTexture2D LoadRenderTexture(int width, int height)
|
|||
// Check if a texture is ready
|
||||
bool IsTextureReady(Texture2D texture)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// TODO: Validate maximum texture size supported by GPU?
|
||||
|
||||
return ((texture.id > 0) && // Validate OpenGL id
|
||||
(texture.width > 0) &&
|
||||
(texture.height > 0) && // Validate texture size
|
||||
(texture.format > 0) && // Validate texture pixel format
|
||||
(texture.mipmaps > 0)); // Validate texture mipmaps (at least 1 for basic mipmap level)
|
||||
if ((texture.id > 0) && // Validate OpenGL id
|
||||
(texture.width > 0) &&
|
||||
(texture.height > 0) && // Validate texture size
|
||||
(texture.format > 0) && // Validate texture pixel format
|
||||
(texture.mipmaps > 0)) result = true; // Validate texture mipmaps (at least 1 for basic mipmap level)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Unload texture from GPU memory (VRAM)
|
||||
|
@ -3783,9 +3983,13 @@ void UnloadTexture(Texture2D texture)
|
|||
// Check if a render texture is ready
|
||||
bool IsRenderTextureReady(RenderTexture2D target)
|
||||
{
|
||||
return ((target.id > 0) && // Validate OpenGL id
|
||||
IsTextureReady(target.depth) && // Validate FBO depth texture/renderbuffer
|
||||
IsTextureReady(target.texture)); // Validate FBO texture
|
||||
bool result = false;
|
||||
|
||||
if ((target.id > 0) && // Validate OpenGL id
|
||||
IsTextureReady(target.depth) && // Validate FBO depth texture/renderbuffer
|
||||
IsTextureReady(target.texture)) result = true; // Validate FBO texture
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Unload render texture from GPU memory (VRAM)
|
||||
|
@ -4043,7 +4247,7 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
|
|||
|
||||
// NOTE: Vertex position can be transformed using matrices
|
||||
// but the process is way more costly than just calculating
|
||||
// the vertex positions manually, like done above.
|
||||
// the vertex positions manually, like done above
|
||||
// I leave here the old implementation for educational purposes,
|
||||
// just in case someone wants to do some performance test
|
||||
/*
|
||||
|
@ -4280,19 +4484,35 @@ void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest,
|
|||
}
|
||||
}
|
||||
|
||||
// Check if two colors are equal
|
||||
bool ColorIsEqual(Color col1, Color col2)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if ((col1.r == col2.r) && (col1.g == col2.g) && (col1.b == col2.b) && (col1.a == col2.a)) result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get color with alpha applied, alpha goes from 0.0f to 1.0f
|
||||
Color Fade(Color color, float alpha)
|
||||
{
|
||||
Color result = color;
|
||||
|
||||
if (alpha < 0.0f) alpha = 0.0f;
|
||||
else if (alpha > 1.0f) alpha = 1.0f;
|
||||
|
||||
return (Color){ color.r, color.g, color.b, (unsigned char)(255.0f*alpha) };
|
||||
result.a = (unsigned char)(255.0f*alpha);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get hexadecimal value for a Color
|
||||
int ColorToInt(Color color)
|
||||
{
|
||||
return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
|
||||
int result = (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get color normalized as float [0..1]
|
||||
|
@ -4511,10 +4731,14 @@ Color ColorContrast(Color color, float contrast)
|
|||
// Get color with alpha applied, alpha goes from 0.0f to 1.0f
|
||||
Color ColorAlpha(Color color, float alpha)
|
||||
{
|
||||
Color result = color;
|
||||
|
||||
if (alpha < 0.0f) alpha = 0.0f;
|
||||
else if (alpha > 1.0f) alpha = 1.0f;
|
||||
|
||||
return (Color){color.r, color.g, color.b, (unsigned char)(255.0f*alpha)};
|
||||
result.a = (unsigned char)(255.0f*alpha);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get src alpha-blended into dst color with tint
|
||||
|
@ -4813,22 +5037,35 @@ int GetPixelDataSize(int width, int height, int format)
|
|||
//----------------------------------------------------------------------------------
|
||||
// Module specific Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
// From https://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion/60047308#60047308
|
||||
// Convert half-float (stored as unsigned short) to float
|
||||
// REF: https://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion/60047308#60047308
|
||||
static float HalfToFloat(unsigned short x)
|
||||
{
|
||||
float result = 0.0f;
|
||||
|
||||
static float HalfToFloat(unsigned short x) {
|
||||
const unsigned int e = (x&0x7C00)>>10; // exponent
|
||||
const unsigned int m = (x&0x03FF)<<13; // mantissa
|
||||
const unsigned int e = (x & 0x7C00) >> 10; // Exponent
|
||||
const unsigned int m = (x & 0x03FF) << 13; // Mantissa
|
||||
const float fm = (float)m;
|
||||
const unsigned int v = (*(unsigned int*)&fm)>>23; // evil log2 bit hack to count leading zeros in denormalized format
|
||||
const unsigned int r = (x&0x8000)<<16 | (e!=0)*((e+112)<<23|m) | ((e==0)&(m!=0))*((v-37)<<23|((m<<(150-v))&0x007FE000)); // sign : normalized : denormalized
|
||||
return *(float*)&r;
|
||||
const unsigned int v = (*(unsigned int*)&fm) >> 23; // Evil log2 bit hack to count leading zeros in denormalized format
|
||||
const unsigned int r = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007FE000)); // sign : normalized : denormalized
|
||||
|
||||
result = *(float *)&r;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned short FloatToHalf(float x) {
|
||||
const unsigned int b = (*(unsigned int*)&x)+0x00001000; // round-to-nearest-even: add last bit after truncated mantissa
|
||||
const unsigned int e = (b&0x7F800000)>>23; // exponent
|
||||
const unsigned int m = b&0x007FFFFF; // mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
|
||||
return (b&0x80000000)>>16 | (e>112)*((((e-112)<<10)&0x7C00)|m>>13) | ((e<113)&(e>101))*((((0x007FF000+m)>>(125-e))+1)>>1) | (e>143)*0x7FFF; // sign : normalized : denormalized : saturate
|
||||
// Convert float to half-float (stored as unsigned short)
|
||||
static unsigned short FloatToHalf(float x)
|
||||
{
|
||||
unsigned short result = 0;
|
||||
|
||||
const unsigned int b = (*(unsigned int*) & x) + 0x00001000; // Round-to-nearest-even: add last bit after truncated mantissa
|
||||
const unsigned int e = (b & 0x7F800000) >> 23; // Exponent
|
||||
const unsigned int m = b & 0x007FFFFF; // Mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
|
||||
|
||||
result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7C00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007FF000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7FFF; // sign : normalized : denormalized : saturate
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get pixel data from image as Vector4 array (float normalized)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue