mirror of
https://github.com/dbalsom/x86_microcode.git
synced 2026-06-09 13:04:17 +03:00
203 lines
6.0 KiB
C++
203 lines
6.0 KiB
C++
#include "alfe/main.h"
|
|
|
|
#ifndef INCLUDED_BITMAP_H
|
|
#define INCLUDED_BITMAP_H
|
|
|
|
#include "alfe/colour_space.h"
|
|
#include "alfe/vectors.h"
|
|
|
|
template<class Pixel> class Bitmap;
|
|
|
|
template<class Pixel> class BitmapFileFormat : public Handle
|
|
{
|
|
public:
|
|
Bitmap<Pixel> load(const File& file) const
|
|
{
|
|
return body()->load(file);
|
|
}
|
|
void save(Bitmap<Pixel>& bitmap, const File& file) const
|
|
{
|
|
return body()->save(bitmap, file);
|
|
}
|
|
protected:
|
|
class Body : public Handle::Body
|
|
{
|
|
public:
|
|
virtual void save(Bitmap<Pixel>& bitmap, const File& file) const = 0;
|
|
virtual Bitmap<Pixel> load(const File& file) const = 0;
|
|
};
|
|
BitmapFileFormat(const Handle& handle) : Handle(handle) { }
|
|
Body* body() { return as<Body>(); }
|
|
const Body* body() const { return as<Body>(); }
|
|
private:
|
|
friend class Bitmap<Pixel>;
|
|
};
|
|
|
|
template<class T> class RawFileFormatTemplate;
|
|
typedef RawFileFormatTemplate<SRGB> RawFileFormat;
|
|
|
|
template<class T> class RawFileFormatTemplate : public BitmapFileFormat<T>
|
|
{
|
|
public:
|
|
RawFileFormatTemplate(Vector size)
|
|
: BitmapFileFormat(this->create<Body>(size)) { }
|
|
private:
|
|
class Body : public BitmapFileFormat<T>::Body
|
|
{
|
|
public:
|
|
Body(Vector size) : _size(size) { }
|
|
// The bitmap needs to be 8-bit sRGB data for this to work.
|
|
virtual void save(Bitmap<T>& bitmap, const File& file) const
|
|
{
|
|
FileStream stream = file.openWrite();
|
|
Byte* data = bitmap.data();
|
|
int stride = bitmap.stride();
|
|
Vector size = bitmap.size();
|
|
for (int y = 0; y < size.y; ++y) {
|
|
stream.write(static_cast<void*>(data), size.x*sizeof(T));
|
|
data += stride;
|
|
}
|
|
}
|
|
// This will put 8-bit sRGB data in the bitmap.
|
|
virtual Bitmap<T> load(const File& file) const
|
|
{
|
|
FileStream stream = file.openRead();
|
|
Bitmap<SRGB> bitmap(_size);
|
|
Byte* data = bitmap.data();
|
|
int stride = bitmap.stride();
|
|
for (int y = 0; y < _size.y; ++y) {
|
|
stream.read(static_cast<void*>(data), _size.x*sizeof(T));
|
|
data += stride;
|
|
}
|
|
return bitmap;
|
|
}
|
|
private:
|
|
Vector _size;
|
|
};
|
|
};
|
|
|
|
// A Bitmap is a value class encapsulating a 2D image. Its width, height,
|
|
// stride and pixel format are immutable but the pixels themselves are not.
|
|
template<class Pixel> class Bitmap : private Array<Pixel>
|
|
{
|
|
public:
|
|
Bitmap() : _size(0, 0) { }
|
|
Bitmap(Vector size)
|
|
{
|
|
_stride = size.x*sizeof(Pixel);
|
|
_size = size;
|
|
this->allocate(size.x*size.y);
|
|
_topLeft = reinterpret_cast<Byte*>(&Array<Pixel>::operator[](0));
|
|
}
|
|
void ensure(Vector s)
|
|
{
|
|
if (size().x < s.x || size().y < s.y)
|
|
*this = Bitmap(Vector(max(size().x, s.x), max(size().y, s.y)));
|
|
}
|
|
|
|
// Convert from one pixel format to another.
|
|
template<class TargetPixel, class Converter> void convert(
|
|
Bitmap<TargetPixel>& target, Converter converter)
|
|
{
|
|
Byte* row = data();
|
|
Byte* targetRow = target.data();
|
|
for (int y = 0; y < _size.y; ++y) {
|
|
Pixel* p = reinterpret_cast<Pixel*>(row);
|
|
TargetPixel* tp = reinterpret_cast<TargetPixel*>(targetRow);
|
|
for (int x = 0; x < _size.x; ++x) {
|
|
*tp = converter.convert(*p);
|
|
++p;
|
|
++tp;
|
|
}
|
|
row += _stride;
|
|
targetRow += target.stride();
|
|
}
|
|
}
|
|
|
|
void load(const BitmapFileFormat<Pixel>& format, const File& file)
|
|
{
|
|
*this = format.load(file);
|
|
}
|
|
|
|
void save(const BitmapFileFormat<Pixel>& format, const File& file)
|
|
{
|
|
format.save(*this, file);
|
|
}
|
|
Byte* data() { return _topLeft; }
|
|
const Byte* data() const { return _topLeft; }
|
|
int stride() const { return _stride; }
|
|
Vector size() const { return _size; }
|
|
bool valid() const { return _size.x != 0; }
|
|
Pixel* row(int y)
|
|
{
|
|
return reinterpret_cast<Pixel*>(_topLeft + y*_stride);
|
|
}
|
|
Pixel& operator[](Vector position) { return row(position.y)[position.x]; }
|
|
|
|
// A sub-bitmap of a bitmap is a pointer into the same set of data, so
|
|
// drawing on a subBitmap will also draw on the parent bitmap, and any
|
|
// other overlapping sub-bitmaps. This can be used in conjunction with
|
|
// fill() to draw rectangles. To avoid this behavior, use
|
|
// subBitmap().clone().
|
|
Bitmap subBitmap(Vector topLeft, Vector size)
|
|
{
|
|
return Bitmap(*this,
|
|
_topLeft + topLeft.x*sizeof(Pixel) + topLeft.y*_stride, size,
|
|
_stride);
|
|
}
|
|
|
|
Bitmap clone() const
|
|
{
|
|
Bitmap c(_size);
|
|
copyTo(c);
|
|
return c;
|
|
}
|
|
|
|
void fill(const Pixel& pixel)
|
|
{
|
|
Byte* row = data();
|
|
for (int y = 0; y < _size.y; ++y) {
|
|
Pixel* p = reinterpret_cast<Pixel*>(row);
|
|
for (int x = 0; x < _size.x; ++x) {
|
|
*p = pixel;
|
|
++p;
|
|
}
|
|
row += _stride;
|
|
}
|
|
}
|
|
|
|
// Copy with pixel format conversion but no resizing. Bitmaps must be the
|
|
// same dimensions.
|
|
template<class OtherPixel> void copyFrom(const Bitmap<OtherPixel>& other)
|
|
{
|
|
Byte* row = data();
|
|
const Byte* otherRow = other.data();
|
|
for (int y = 0; y < _size.y; ++y) {
|
|
Pixel* p = reinterpret_cast<Pixel*>(row);
|
|
const OtherPixel* op =
|
|
reinterpret_cast<const OtherPixel*>(otherRow);
|
|
for (int x = 0; x < _size.x; ++x) {
|
|
*p = *op;
|
|
++p;
|
|
++op;
|
|
}
|
|
row += _stride;
|
|
otherRow += other._stride;
|
|
}
|
|
}
|
|
template<class OtherPixel> void copyTo(Bitmap<OtherPixel>& other) const
|
|
{
|
|
other.copyFrom(*this);
|
|
}
|
|
|
|
private:
|
|
Bitmap(Array<Pixel> array, Byte* topLeft, Vector size, int stride)
|
|
: Array(array), _topLeft(topLeft), _size(size), _stride(stride) { }
|
|
|
|
Vector _size;
|
|
Byte* _topLeft;
|
|
int _stride;
|
|
};
|
|
|
|
#endif // INCLUDED_BITMAP_H
|