| 
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -593,6 +593,74 @@ void SaveImageAs(const char *fileName, Image image) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#endif | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Copy an image to a new image | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			Image ImageCopy(Image image) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    Image newImage = { 0 }; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    int size = GetPixelDataSize(image.width, image.height, image.format); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    newImage.data = malloc(size); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    if (newImage.data != NULL) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // NOTE: Size must be provided in bytes | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        memcpy(newImage.data, image.data, size); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        newImage.width = image.width; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        newImage.height = image.height; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        newImage.mipmaps = image.mipmaps; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        newImage.format = image.format; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    return newImage; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Convert image to POT (power-of-two) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ImageToPOT(Image *image, Color fillColor) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    Color *pixels = GetImageData(*image);   // Get pixels data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    // Calculate next power-of-two values | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    // NOTE: Just add the required amount of pixels at the right and bottom sides of image... | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2))); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2))); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    // Check if POT texture generation is required (if texture is not already POT) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    if ((potWidth != image->width) || (potHeight != image->height)) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        Color *pixelsPOT = NULL; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // Generate POT array from NPOT data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        pixelsPOT = (Color *)malloc(potWidth*potHeight*sizeof(Color)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        for (int j = 0; j < potHeight; j++) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            for (int i = 0; i < potWidth; i++) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                if ((j < image->height) && (i < image->width)) pixelsPOT[j*potWidth + i] = pixels[j*image->width + i]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                else pixelsPOT[j*potWidth + i] = fillColor; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        TraceLog(LOG_WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        free(pixels);                       // Free pixels data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        free(image->data);                  // Free old image data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        int format = image->format;         // Store image data format to reconvert later | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // TODO: Image width and height changes... do we want to store new values or keep the old ones? | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // NOTE: Issues when using image.width and image.height for sprite animations... | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        *image = LoadImageEx(pixelsPOT, potWidth, potHeight); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        free(pixelsPOT);                    // Free POT pixels data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        ImageFormat(image, format);  // Reconvert image to previous format | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Convert image data to desired format | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ImageFormat(Image *image, int newFormat) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			{ | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -806,75 +874,45 @@ void ImageAlphaMask(Image *image, Image alphaMask) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Convert image to POT (power-of-two) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// NOTE: It could be useful on OpenGL ES 2.0 (RPI, HTML5) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ImageToPOT(Image *image, Color fillColor) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Clear alpha channel to desired color | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// NOTE: Threshold defines the alpha limit, 0.0f to 1.0f | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ImageAlphaClear(Image *image, Color color, float threshold) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    Color *pixels = GetImageData(*image);   // Get pixels data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    // Calculate next power-of-two values | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    // NOTE: Just add the required amount of pixels at the right and bottom sides of image... | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2))); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2))); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    // Check if POT texture generation is required (if texture is not already POT) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    if ((potWidth != image->width) || (potHeight != image->height)) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        Color *pixelsPOT = NULL; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // Generate POT array from NPOT data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        pixelsPOT = (Color *)malloc(potWidth*potHeight*sizeof(Color)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        for (int j = 0; j < potHeight; j++) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            for (int i = 0; i < potWidth; i++) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                if ((j < image->height) && (i < image->width)) pixelsPOT[j*potWidth + i] = pixels[j*image->width + i]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                else pixelsPOT[j*potWidth + i] = fillColor; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        TraceLog(LOG_WARNING, "Image converted to POT: (%ix%i) -> (%ix%i)", image->width, image->height, potWidth, potHeight); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        free(pixels);                       // Free pixels data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        free(image->data);                  // Free old image data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        int format = image->format;         // Store image data format to reconvert later | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // TODO: Image width and height changes... do we want to store new values or keep the old ones? | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // NOTE: Issues when using image.width and image.height for sprite animations... | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        *image = LoadImageEx(pixelsPOT, potWidth, potHeight); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        free(pixelsPOT);                    // Free POT pixels data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    Color *pixels = GetImageData(*image); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			     | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    for (int i = 0; i < image->width*image->height; i++) if (pixels[i].a <= (unsigned char)(threshold*255.0f)) pixels[i] = color; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        ImageFormat(image, format);  // Reconvert image to previous format | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    UnloadImage(*image); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			     | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    int prevFormat = image->format; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    *image = LoadImageEx(pixels, image->width, image->height); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			     | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    ImageFormat(image, prevFormat); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#if defined(SUPPORT_IMAGE_MANIPULATION) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Copy an image to a new image | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			Image ImageCopy(Image image) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Premultiply alpha channel | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ImageAlphaPremultiply(Image *image) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    Image newImage = { 0 }; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    int size = GetPixelDataSize(image.width, image.height, image.format); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    newImage.data = malloc(size); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    if (newImage.data != NULL) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    float alpha = 0.0f; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    Color *pixels = GetImageData(*image); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			     | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    for (int i = 0; i < image->width*image->height; i++)  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // NOTE: Size must be provided in bytes | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        memcpy(newImage.data, image.data, size); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        newImage.width = image.width; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        newImage.height = image.height; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        newImage.mipmaps = image.mipmaps; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        newImage.format = image.format; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        alpha = (float)pixels[i].a/255.0f; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        pixels[i].r = (unsigned char)((float)pixels[i].r*alpha); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        pixels[i].g = (unsigned char)((float)pixels[i].g*alpha); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        pixels[i].b = (unsigned char)((float)pixels[i].b*alpha); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    return newImage; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    UnloadImage(*image); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			     | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    int prevFormat = image->format; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    *image = LoadImageEx(pixels, image->width, image->height); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			     | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    ImageFormat(image, prevFormat); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#if defined(SUPPORT_IMAGE_MANIPULATION) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Crop an image to area defined by a rectangle | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// NOTE: Security checks are performed in case rectangle goes out of bounds | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ImageCrop(Image *image, Rectangle crop) | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -982,6 +1020,115 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    free(pixels); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Dither image data to 16bpp or lower (Floyd-Steinberg dithering) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// NOTE: In case selected bpp do not represent an known 16bit format, | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// dithered data is stored in the LSB part of the unsigned short | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    if (image->format >= COMPRESSED_DXT1_RGB) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        TraceLog(LOG_WARNING, "Compressed data formats can not be dithered"); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    if ((rBpp+gBpp+bBpp+aBpp) > 16) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        TraceLog(LOG_WARNING, "Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    else | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        Color *pixels = GetImageData(*image); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        free(image->data);      // free old image data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8)) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            TraceLog(LOG_WARNING, "Image format is already 16bpp or lower, dithering could have no effect"); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // Define new image format, check if desired bpp match internal known format | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = UNCOMPRESSED_R5G6B5; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = UNCOMPRESSED_R5G5B5A1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = UNCOMPRESSED_R4G4B4A4; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        else | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            image->format = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            TraceLog(LOG_WARNING, "Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // NOTE: We will store the dithered data as unsigned short (16bpp) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        Color oldPixel = WHITE; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        Color newPixel = WHITE; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        int rError, gError, bError; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        unsigned short rPixel, gPixel, bPixel, aPixel;   // Used for 16bit pixel composition | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        #define MIN(a,b) (((a)<(b))?(a):(b)) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        for (int y = 0; y < image->height; y++) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            for (int x = 0; x < image->width; x++) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                oldPixel = pixels[y*image->width + x]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                newPixel.r = oldPixel.r >> (8 - rBpp);     // R bits | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                newPixel.g = oldPixel.g >> (8 - gBpp);     // G bits | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                newPixel.b = oldPixel.b >> (8 - bBpp);     // B bits | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                newPixel.a = oldPixel.a >> (8 - aBpp);     // A bits (not used on dithering) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                // NOTE: Error must be computed between new and old pixel but using same number of bits! | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                // We want to know how much color precision we have lost... | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                pixels[y*image->width + x] = newPixel; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                // NOTE: Some cases are out of the array and should be ignored | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                if (x < (image->width - 1)) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                if ((x > 0) && (y < (image->height - 1))) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                if (y < (image->height - 1)) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                if ((x < (image->width - 1)) && (y < (image->height - 1))) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                rPixel = (unsigned short)newPixel.r; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                gPixel = (unsigned short)newPixel.g; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                bPixel = (unsigned short)newPixel.b; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                aPixel = (unsigned short)newPixel.a; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                ((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        free(pixels); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Draw an image (source) within an image (destination) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// TODO: Feel this function could be simplified... | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -1205,115 +1352,6 @@ void ImageFlipHorizontal(Image *image) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    image->data = processed.data; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Dither image data to 16bpp or lower (Floyd-Steinberg dithering) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// NOTE: In case selected bpp do not represent an known 16bit format, | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// dithered data is stored in the LSB part of the unsigned short | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    if (image->format >= COMPRESSED_DXT1_RGB) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        TraceLog(LOG_WARNING, "Compressed data formats can not be dithered"); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    if ((rBpp+gBpp+bBpp+aBpp) > 16) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        TraceLog(LOG_WARNING, "Unsupported dithering bpps (%ibpp), only 16bpp or lower modes supported", (rBpp+gBpp+bBpp+aBpp)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    else | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        Color *pixels = GetImageData(*image); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        free(image->data);      // free old image data | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8)) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            TraceLog(LOG_WARNING, "Image format is already 16bpp or lower, dithering could have no effect"); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // Define new image format, check if desired bpp match internal known format | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = UNCOMPRESSED_R5G6B5; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = UNCOMPRESSED_R5G5B5A1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        else if ((rBpp == 4) && (gBpp == 4) && (bBpp == 4) && (aBpp == 4)) image->format = UNCOMPRESSED_R4G4B4A4; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        else | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            image->format = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            TraceLog(LOG_WARNING, "Unsupported dithered OpenGL internal format: %ibpp (R%iG%iB%iA%i)", (rBpp+gBpp+bBpp+aBpp), rBpp, gBpp, bBpp, aBpp); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        // NOTE: We will store the dithered data as unsigned short (16bpp) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        Color oldPixel = WHITE; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        Color newPixel = WHITE; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        int rError, gError, bError; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        unsigned short rPixel, gPixel, bPixel, aPixel;   // Used for 16bit pixel composition | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        #define MIN(a,b) (((a)<(b))?(a):(b)) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        for (int y = 0; y < image->height; y++) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            for (int x = 0; x < image->width; x++) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                oldPixel = pixels[y*image->width + x]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                newPixel.r = oldPixel.r >> (8 - rBpp);     // R bits | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                newPixel.g = oldPixel.g >> (8 - gBpp);     // G bits | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                newPixel.b = oldPixel.b >> (8 - bBpp);     // B bits | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                newPixel.a = oldPixel.a >> (8 - aBpp);     // A bits (not used on dithering) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                // NOTE: Error must be computed between new and old pixel but using same number of bits! | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                // We want to know how much color precision we have lost... | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                pixels[y*image->width + x] = newPixel; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                // NOTE: Some cases are out of the array and should be ignored | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                if (x < (image->width - 1)) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                if ((x > 0) && (y < (image->height - 1))) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                if (y < (image->height - 1)) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                if ((x < (image->width - 1)) && (y < (image->height - 1))) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                    pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                rPixel = (unsigned short)newPixel.r; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                gPixel = (unsigned short)newPixel.g; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                bPixel = (unsigned short)newPixel.b; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                aPixel = (unsigned short)newPixel.a; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			                ((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			            } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			        free(pixels); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			    } | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			// Modify image color: tint | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ImageColorTint(Image *image, Color color) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			{ | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
				
				 | 
			
			 | 
			
			
 |