2016-05-15 10:42:10 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
namespace nall {
|
|
|
|
|
|
|
|
image::image(const image& source) {
|
|
|
|
operator=(source);
|
|
|
|
}
|
|
|
|
|
|
|
|
image::image(image&& source) {
|
|
|
|
operator=(forward<image>(source));
|
|
|
|
}
|
|
|
|
|
|
|
|
image::image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask) {
|
|
|
|
_endian = endian;
|
|
|
|
_depth = depth;
|
|
|
|
|
|
|
|
_alpha = {alphaMask, bitDepth(alphaMask), bitShift(alphaMask)};
|
|
|
|
_red = {redMask, bitDepth(redMask), bitShift(redMask )};
|
|
|
|
_green = {greenMask, bitDepth(greenMask), bitShift(greenMask)};
|
|
|
|
_blue = {blueMask, bitDepth(blueMask), bitShift(blueMask )};
|
|
|
|
}
|
|
|
|
|
|
|
|
image::image(const string& filename) {
|
|
|
|
load(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
image::image(const vector<uint8_t>& buffer) {
|
|
|
|
auto data = buffer.data();
|
|
|
|
auto size = buffer.size();
|
|
|
|
if(0);
|
|
|
|
else if(data[0] == 'B' && data[1] == 'M') loadBMP(data, size);
|
|
|
|
else if(data[1] == 'P' && data[2] == 'N' && data[3] == 'G') loadPNG(data, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
image::image(const uint8_t* data, unsigned size) {
|
|
|
|
if(0);
|
|
|
|
else if(data[0] == 'B' && data[1] == 'M') loadBMP(data, size);
|
|
|
|
else if(data[1] == 'P' && data[2] == 'N' && data[3] == 'G') loadPNG(data, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
image::image() {
|
|
|
|
}
|
|
|
|
|
|
|
|
image::~image() {
|
|
|
|
free();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto image::operator=(const image& source) -> image& {
|
|
|
|
if(this == &source) return *this;
|
|
|
|
free();
|
|
|
|
|
|
|
|
_width = source._width;
|
|
|
|
_height = source._height;
|
|
|
|
|
|
|
|
_endian = source._endian;
|
|
|
|
_depth = source._depth;
|
|
|
|
|
|
|
|
_alpha = source._alpha;
|
|
|
|
_red = source._red;
|
|
|
|
_green = source._green;
|
|
|
|
_blue = source._blue;
|
|
|
|
|
|
|
|
_data = allocate(_width, _height, stride());
|
|
|
|
memory::copy(_data, source._data, source.size());
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto image::operator=(image&& source) -> image& {
|
|
|
|
if(this == &source) return *this;
|
|
|
|
free();
|
|
|
|
|
|
|
|
_width = source._width;
|
|
|
|
_height = source._height;
|
|
|
|
|
|
|
|
_endian = source._endian;
|
|
|
|
_depth = source._depth;
|
|
|
|
|
|
|
|
_alpha = source._alpha;
|
|
|
|
_red = source._red;
|
|
|
|
_green = source._green;
|
|
|
|
_blue = source._blue;
|
|
|
|
|
|
|
|
_data = source._data;
|
|
|
|
source._data = nullptr;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
image::operator bool() const {
|
2016-07-03 11:35:22 +00:00
|
|
|
return _data && _width && _height;
|
2016-05-15 10:42:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto image::operator==(const image& source) const -> bool {
|
|
|
|
if(_width != source._width) return false;
|
|
|
|
if(_height != source._height) return false;
|
|
|
|
|
|
|
|
if(_endian != source._endian) return false;
|
|
|
|
if(_depth != source._depth) return false;
|
|
|
|
|
|
|
|
if(_alpha != source._alpha) return false;
|
|
|
|
if(_red != source._red) return false;
|
|
|
|
if(_green != source._green) return false;
|
|
|
|
if(_blue != source._blue) return false;
|
|
|
|
|
|
|
|
return memory::compare(_data, source._data, size()) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto image::operator!=(const image& source) const -> bool {
|
|
|
|
return !operator==(source);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto image::read(const uint8_t* data) const -> uint64_t {
|
|
|
|
uint64_t result = 0;
|
|
|
|
if(_endian == 0) {
|
|
|
|
for(signed n = stride() - 1; n >= 0; n--) result = (result << 8) | data[n];
|
|
|
|
} else {
|
|
|
|
for(signed n = 0; n < stride(); n++) result = (result << 8) | data[n];
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto image::write(uint8_t* data, uint64_t value) const -> void {
|
|
|
|
if(_endian == 0) {
|
|
|
|
for(signed n = 0; n < stride(); n++) {
|
|
|
|
data[n] = value;
|
|
|
|
value >>= 8;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for(signed n = stride() - 1; n >= 0; n--) {
|
|
|
|
data[n] = value;
|
|
|
|
value >>= 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto image::free() -> void {
|
|
|
|
if(_data) delete[] _data;
|
|
|
|
_data = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto image::load(const string& filename) -> bool {
|
|
|
|
if(loadBMP(filename) == true) return true;
|
|
|
|
if(loadPNG(filename) == true) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto image::allocate(unsigned width, unsigned height) -> void {
|
|
|
|
if(_data && _width == width && _height == height) return;
|
|
|
|
free();
|
|
|
|
_width = width;
|
|
|
|
_height = height;
|
|
|
|
_data = allocate(_width, _height, stride());
|
|
|
|
}
|
|
|
|
|
|
|
|
auto image::allocate(unsigned width, unsigned height, unsigned stride) -> uint8_t* {
|
|
|
|
//allocate 1x1 larger than requested; so that linear interpolation does not require bounds-checking
|
|
|
|
unsigned size = width * height * stride;
|
|
|
|
unsigned padding = width * stride + stride;
|
|
|
|
auto data = new uint8_t[size + padding];
|
|
|
|
memory::fill(data + size, padding);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|