Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
#pragma once
|
||||
#include "color.h"
|
||||
#include "vec2.h"
|
||||
#include "rect.h"
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
|
||||
enum ColorFormat {
|
||||
FMT_Grey,
|
||||
FMT_Alpha,
|
||||
FMT_RGB,
|
||||
FMT_RGBA,
|
||||
FMT_INVALID
|
||||
};
|
||||
|
||||
enum ColorDepth {
|
||||
DEPTH_Grey = sizeof(unsigned char),
|
||||
DEPTH_Alpha = sizeof(unsigned char),
|
||||
DEPTH_RGB = sizeof(ColorRGB),
|
||||
DEPTH_RGBA = sizeof(Color)
|
||||
};
|
||||
|
||||
//Color depths by format (e.g. ColorDepths[FMT_RGB] == DEPTH_RGB)
|
||||
extern unsigned ColorDepths[4];
|
||||
|
||||
//Standard image in 32-bit RGBA format
|
||||
struct Image {
|
||||
union {
|
||||
unsigned char* grey;
|
||||
ColorRGB* rgb;
|
||||
Color* rgba;
|
||||
};
|
||||
|
||||
ColorFormat format;
|
||||
unsigned int width, height;
|
||||
|
||||
unsigned char& get_alpha(unsigned int x, unsigned int y) {
|
||||
return grey[x + (y * width)];
|
||||
}
|
||||
|
||||
unsigned char get_alpha(unsigned int x, unsigned int y) const {
|
||||
return grey[x + (y * width)];
|
||||
}
|
||||
|
||||
unsigned char& get_grey(unsigned int x, unsigned int y) {
|
||||
return grey[x + (y * width)];
|
||||
}
|
||||
|
||||
unsigned char get_grey(unsigned int x, unsigned int y) const {
|
||||
return grey[x + (y * width)];
|
||||
}
|
||||
|
||||
ColorRGB& get_rgb(unsigned int x, unsigned int y) {
|
||||
return rgb[x + (y * width)];
|
||||
}
|
||||
|
||||
ColorRGB get_rgb(unsigned int x, unsigned int y) const {
|
||||
return rgb[x + (y * width)];
|
||||
}
|
||||
|
||||
Color& get_rgba(unsigned int x, unsigned int y) {
|
||||
return rgba[x + (y * width)];
|
||||
}
|
||||
|
||||
Color get_rgba(unsigned int x, unsigned int y) const {
|
||||
return rgba[x + (y * width)];
|
||||
}
|
||||
|
||||
Color get(unsigned int x, unsigned int y) const {
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
return grey[x + (y * width)];
|
||||
case FMT_RGB:
|
||||
return rgb[x + (y * width)];
|
||||
case FMT_RGBA:
|
||||
return rgba[x + (y * width)];
|
||||
}
|
||||
return Color();
|
||||
}
|
||||
|
||||
Color getTexel(float x, float y) {
|
||||
float ipart;
|
||||
float u = std::modf(x,&ipart), v = std::modf(y,&ipart);
|
||||
if(u < 0)
|
||||
u = 1.f + u;
|
||||
u *= (float)width;
|
||||
if(v < 0)
|
||||
v = 1.f + v;
|
||||
v *= (float)height;
|
||||
|
||||
int x1 = (int)u;
|
||||
int x2 = (x1 + 1) % (int)width;
|
||||
int y1 = (int)v;
|
||||
int y2 = (y1 + 1) % (int)height;
|
||||
|
||||
Color upper = get(x1,y1).getInterpolated(get(x2,y1), std::modf(u,&ipart));
|
||||
Color lower = get(x1,y2).getInterpolated(get(x2,y2), std::modf(u,&ipart));
|
||||
|
||||
return upper.getInterpolated(lower, std::modf(v,&ipart));
|
||||
}
|
||||
|
||||
Color getTexel(const vec2f& pos) {
|
||||
return getTexel(pos.x, pos.y);
|
||||
}
|
||||
|
||||
static Image* random(const vec2u& resolution, int(int,int));
|
||||
|
||||
//Returns an image that is a sphere-distortion-corrected version of this one
|
||||
Image* sphereDistort() const;
|
||||
|
||||
//Returns a half-resolution version of this image
|
||||
//If the image is too small, returns 0
|
||||
Image* makeMipmap() const;
|
||||
|
||||
Image* crop(const rect<unsigned>& bound) const;
|
||||
|
||||
Image() : width(0), height(0), rgba(0) {}
|
||||
|
||||
Image(const Image& other) : width(0), height(0), rgba(0) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
void operator=(const Image& other) {
|
||||
if(other.width != width || other.height != height || other.format != format) {
|
||||
width = other.width;
|
||||
height = other.height;
|
||||
format = other.format;
|
||||
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
delete[] grey;
|
||||
grey = new unsigned char[width*height];
|
||||
break;
|
||||
case FMT_RGB:
|
||||
delete[] rgb;
|
||||
rgb = new ColorRGB[width*height];
|
||||
break;
|
||||
case FMT_RGBA:
|
||||
delete[] rgba;
|
||||
rgba = new Color[width*height];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
memcpy(grey, other.grey, width*height*sizeof(unsigned char));
|
||||
break;
|
||||
case FMT_RGB:
|
||||
memcpy(rgb, other.rgb, width*height*sizeof(ColorRGB));
|
||||
break;
|
||||
case FMT_RGBA:
|
||||
memcpy(rgba, other.rgba, width*height*sizeof(Color));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Image(unsigned int Width, unsigned int Height, ColorFormat Format)
|
||||
: width(Width), height(Height), format(Format), rgba(0)
|
||||
{
|
||||
if(width > 0 && height > 0) {
|
||||
switch(Format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
grey = new unsigned char[Width*Height]; break;
|
||||
case FMT_RGB:
|
||||
rgb = new ColorRGB[Width*Height]; break;
|
||||
case FMT_RGBA:
|
||||
rgba = new Color[Width*Height]; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image(unsigned int Width, unsigned int Height, ColorFormat Format, unsigned char defaultLevel)
|
||||
: width(Width), height(Height), format(Format), rgba(0)
|
||||
{
|
||||
if(width > 0 && height > 0) {
|
||||
switch(Format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
grey = new unsigned char[Width*Height]; break;
|
||||
case FMT_RGB:
|
||||
rgb = new ColorRGB[Width*Height]; break;
|
||||
case FMT_RGBA:
|
||||
rgba = new Color[Width*Height]; break;
|
||||
}
|
||||
|
||||
if(grey)
|
||||
memset(grey, defaultLevel, Width * Height * ColorDepths[format]);
|
||||
}
|
||||
}
|
||||
|
||||
void makeRGBA(const Image& other) {
|
||||
resize(other.width, other.height, FMT_RGBA);
|
||||
switch(other.format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
for(size_t i = 0, sz = other.width * other.height; i < sz; ++i) {
|
||||
Color& col = rgba[i];
|
||||
col.r = other.grey[i];
|
||||
col.g = col.r;
|
||||
col.b = col.r;
|
||||
col.a = 0xff;
|
||||
}
|
||||
break;
|
||||
case FMT_RGB:
|
||||
for(size_t i = 0, sz = other.width * other.height; i < sz; ++i) {
|
||||
Color& col = rgba[i];
|
||||
ColorRGB& ocol = other.rgb[i];
|
||||
col.r = ocol.r;
|
||||
col.g = ocol.g;
|
||||
col.b = ocol.b;
|
||||
col.a = 0xff;
|
||||
}
|
||||
break;
|
||||
case FMT_RGBA:
|
||||
for(size_t i = 0, sz = other.width * other.height; i < sz; ++i)
|
||||
rgba[i] = other.rgba[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void resize(unsigned Width, unsigned Height, ColorFormat newFormat = FMT_INVALID) {
|
||||
if(newFormat == FMT_INVALID)
|
||||
newFormat = format;
|
||||
|
||||
width = Width;
|
||||
height = Height;
|
||||
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
delete[] grey; break;
|
||||
case FMT_RGB:
|
||||
delete[] rgb; break;
|
||||
case FMT_RGBA:
|
||||
delete[] rgba; break;
|
||||
}
|
||||
if(width > 0 && height > 0) {
|
||||
format = newFormat;
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
grey = new unsigned char[Width*Height]; break;
|
||||
case FMT_RGB:
|
||||
rgb = new ColorRGB[Width*Height]; break;
|
||||
case FMT_RGBA:
|
||||
rgba = new Color[Width*Height]; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~Image() {
|
||||
switch(format) {
|
||||
case FMT_Grey:
|
||||
case FMT_Alpha:
|
||||
delete[] grey; break;
|
||||
case FMT_RGB:
|
||||
delete[] rgb; break;
|
||||
case FMT_RGBA:
|
||||
delete[] rgba; break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//Attempts to load the file according to the extension. If the file cannot be loaded, 0 is returned.
|
||||
Image* loadImage(const char* filename);
|
||||
bool saveImage(const Image* img, const char* filename, bool flip = false);
|
||||
Reference in New Issue
Block a user