Files
jail_engine/quickcg.cpp

428 lines
11 KiB
C++

/*
QuickCG 20191227
Copyright (c) 2004-2019, Lode Vandevenne
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
QuickCG is an SDL codebase that wraps some of the SDL functionality.
It' used by Lode's Computer Graphics Tutorial to work with simple C++ calls
to demonstrate graphical programs.
QuickCG can handle some things that standard C++ doesn't but that are commonly useful, such as:
-drawing graphics
-a bitmap font
-simplified saving and loading of files
-reading keyboard and mouse input
-playing sound
-color models
-loading images
*/
#include "quickcg.h"
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <iostream>
#include <fstream>
namespace QuickCG
{
////////////////////////////////////////////////////////////////////////////////
// COLOR STRUCTS/////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
ColorRGB::ColorRGB(Uint8 r, Uint8 g, Uint8 b)
{
this->r = r;
this->g = g;
this->b = b;
}
ColorRGB::ColorRGB(const ColorRGB8bit &color)
{
this->r = color.r;
this->g = color.g;
this->b = color.b;
}
ColorRGB::ColorRGB()
{
this->r = 0;
this->g = 0;
this->b = 0;
}
ColorRGB8bit::ColorRGB8bit(Uint8 r, Uint8 g, Uint8 b)
{
this->r = r;
this->g = g;
this->b = b;
}
ColorRGB8bit::ColorRGB8bit(const ColorRGB &color)
{
this->r = color.r;
this->g = color.g;
this->b = color.b;
}
ColorRGB8bit::ColorRGB8bit()
{
this->r = 0;
this->g = 0;
this->b = 0;
}
// Add two colors
ColorRGB operator+(const ColorRGB &color, const ColorRGB &color2)
{
ColorRGB c;
c.r = color.r + color2.r;
c.g = color.g + color2.g;
c.b = color.b + color2.b;
return c;
}
// Subtract two colors
ColorRGB operator-(const ColorRGB &color, const ColorRGB &color2)
{
ColorRGB c;
c.r = color.r - color2.r;
c.g = color.g - color2.g;
c.b = color.b - color2.b;
return c;
}
// Multiplies a color with an integer
ColorRGB operator*(const ColorRGB &color, int a)
{
ColorRGB c;
c.r = color.r * a;
c.g = color.g * a;
c.b = color.b * a;
return c;
}
// Multiplies a color with an integer
ColorRGB operator*(int a, const ColorRGB &color)
{
ColorRGB c;
c.r = color.r * a;
c.g = color.g * a;
c.b = color.b * a;
return c;
}
// Divides a color through an integer
ColorRGB operator/(const ColorRGB &color, int a)
{
if (a == 0)
return color;
ColorRGB c;
c.r = color.r / a;
c.g = color.g / a;
c.b = color.b / a;
return c;
}
// Are both colors equal?
bool operator==(const ColorRGB &color, const ColorRGB &color2)
{
return (color.r == color2.r && color.g == color2.g && color.b == color2.b);
}
// Are both colors not equal?
bool operator!=(const ColorRGB &color, const ColorRGB &color2)
{
return (!(color.r == color2.r && color.g == color2.g && color.b == color2.b));
}
ColorHSL::ColorHSL(Uint8 h, Uint8 s, Uint8 l)
{
this->h = h;
this->s = s;
this->l = l;
}
ColorHSL::ColorHSL()
{
this->h = 0;
this->s = 0;
this->l = 0;
}
ColorHSV::ColorHSV(Uint8 h, Uint8 s, Uint8 v)
{
this->h = h;
this->s = s;
this->v = v;
}
ColorHSV::ColorHSV()
{
this->h = 0;
this->s = 0;
this->v = 0;
}
////////////////////////////////////////////////////////////////////////////////
// COLOR CONVERSIONS/////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/*
Convert colors from one type to another
r=red g=green b=blue h=hue s=saturation l=lightness v=value
Color components from the color structs are Uint8's between 0 and 255
color components used in the calculations are normalized between 0.0-1.0
*/
// Converts an RGB color to HSL color
ColorHSL RGBtoHSL(const ColorRGB &colorRGB)
{
float r, g, b, h = 0, s = 0, l; // this function works with floats between 0 and 1
r = colorRGB.r / 256.0;
g = colorRGB.g / 256.0;
b = colorRGB.b / 256.0;
float maxColor = std::max(r, std::max(g, b));
float minColor = std::min(r, std::min(g, b));
if (minColor == maxColor) // R = G = B, so it's a shade of grey
{
h = 0; // it doesn't matter what value it has
s = 0;
l = r; // doesn't matter if you pick r, g, or b
}
else
{
l = (minColor + maxColor) / 2;
if (l < 0.5)
s = (maxColor - minColor) / (maxColor + minColor);
if (l >= 0.5)
s = (maxColor - minColor) / (2.0 - maxColor - minColor);
if (r == maxColor)
h = (g - b) / (maxColor - minColor);
if (g == maxColor)
h = 2.0 + (b - r) / (maxColor - minColor);
if (b == maxColor)
h = 4.0 + (r - g) / (maxColor - minColor);
h /= 6; // to bring it to a number between 0 and 1
if (h < 0)
h += 1;
}
ColorHSL colorHSL;
colorHSL.h = int(h * 255.0);
colorHSL.s = int(s * 255.0);
colorHSL.l = int(l * 255.0);
return colorHSL;
}
// Converts an HSL color to RGB color
ColorRGB HSLtoRGB(const ColorHSL &colorHSL)
{
float r, g, b, h, s, l; // this function works with floats between 0 and 1
float temp1, temp2, tempr, tempg, tempb;
h = colorHSL.h / 256.0;
s = colorHSL.s / 256.0;
l = colorHSL.l / 256.0;
// If saturation is 0, the color is a shade of grey
if (s == 0)
r = g = b = l;
// If saturation > 0, more complex calculations are needed
else
{
// set the temporary values
if (l < 0.5)
temp2 = l * (1 + s);
else
temp2 = (l + s) - (l * s);
temp1 = 2 * l - temp2;
tempr = h + 1.0 / 3.0;
if (tempr > 1.0)
tempr--;
tempg = h;
tempb = h - 1.0 / 3.0;
if (tempb < 0.0)
tempb++;
// red
if (tempr < 1.0 / 6.0)
r = temp1 + (temp2 - temp1) * 6.0 * tempr;
else if (tempr < 0.5)
r = temp2;
else if (tempr < 2.0 / 3.0)
r = temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempr) * 6.0;
else
r = temp1;
// green
if (tempg < 1.0 / 6.0)
g = temp1 + (temp2 - temp1) * 6.0 * tempg;
else if (tempg < 0.5)
g = temp2;
else if (tempg < 2.0 / 3.0)
g = temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempg) * 6.0;
else
g = temp1;
// blue
if (tempb < 1.0 / 6.0)
b = temp1 + (temp2 - temp1) * 6.0 * tempb;
else if (tempb < 0.5)
b = temp2;
else if (tempb < 2.0 / 3.0)
b = temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempb) * 6.0;
else
b = temp1;
}
ColorRGB colorRGB;
colorRGB.r = int(r * 255.0);
colorRGB.g = int(g * 255.0);
colorRGB.b = int(b * 255.0);
return colorRGB;
}
// Converts an RGB color to HSV color
ColorHSV RGBtoHSV(const ColorRGB &colorRGB)
{
float r, g, b, h = 0.0, s = 0.0, v; // this function works with floats between 0 and 1
r = colorRGB.r / 256.0;
g = colorRGB.g / 256.0;
b = colorRGB.b / 256.0;
float maxColor = std::max(r, std::max(g, b));
float minColor = std::min(r, std::min(g, b));
v = maxColor;
if (maxColor != 0.0) // avoid division by zero when the color is black
{
s = (maxColor - minColor) / maxColor;
}
if (s == 0.0)
{
h = 0.0; // it doesn't matter what value it has
}
else
{
if (r == maxColor)
h = (g - b) / (maxColor - minColor);
if (g == maxColor)
h = 2.0 + (b - r) / (maxColor - minColor);
if (b == maxColor)
h = 4.0 + (r - g) / (maxColor - minColor);
h /= 6.0; // to bring it to a number between 0 and 1
if (h < 0.0)
h++;
}
ColorHSV colorHSV;
colorHSV.h = int(h * 255.0);
colorHSV.s = int(s * 255.0);
colorHSV.v = int(v * 255.0);
return colorHSV;
}
// Converts an HSV color to RGB color
ColorRGB HSVtoRGB(const ColorHSV &colorHSV)
{
float r, g, b, h, s, v; // this function works with floats between 0 and 1
h = colorHSV.h / 256.0;
s = colorHSV.s / 256.0;
v = colorHSV.v / 256.0;
// if saturation is 0, the color is a shade of grey
if (s == 0.0)
r = g = b = v;
// if saturation > 0, more complex calculations are needed
else
{
float f, p, q, t;
int i;
h *= 6.0; // to bring hue to a number between 0 and 6, better for the calculations
i = int(floor(h)); // e.g. 2.7 becomes 2 and 3.01 becomes 3 or 4.9999 becomes 4
f = h - i; // the fractional part of h
p = v * (1.0 - s);
q = v * (1.0 - (s * f));
t = v * (1.0 - (s * (1.0 - f)));
switch (i)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
r = v;
g = p;
b = q;
break;
default:
r = g = b = 0;
break;
}
}
ColorRGB colorRGB;
colorRGB.r = int(r * 255.0);
colorRGB.g = int(g * 255.0);
colorRGB.b = int(b * 255.0);
return colorRGB;
}
Uint32 RGBtoINT(const ColorRGB &colorRGB)
{
return 65536 * colorRGB.r + 256 * colorRGB.g + colorRGB.b;
}
ColorRGB INTtoRGB(Uint32 colorINT)
{
ColorRGB colorRGB;
colorRGB.r = (colorINT / 65536) % 256;
colorRGB.g = (colorINT / 256) % 256;
colorRGB.b = colorINT % 256;
return colorRGB;
}
}