/*
......... 2016 Ivan Mahonin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SURFACE_H_
#define _SURFACE_H_
#include <cassert>
#include <string>
class Surface {
public:
typedef unsigned int Color;
Color* const buffer;
const int width;
const int height;
Color color;
int x, y;
bool blending;
Surface(int width, int height);
~Surface();
static unsigned int convert_channel(double c);
static unsigned int blend_channel(unsigned int a, unsigned int dest, unsigned int src);
static Color convert_color(double r, double g, double b, double a = 1.0);
static Color blend(Color dest, Color src);
bool is_inside(int x, int y) const
{ return x >= 0 && x < width && y >= 0 && y < height; }
Color& point(int x, int y)
{ assert(is_inside(x, y)); return buffer[y*width + x]; }
const Color& point(int x, int y) const
{ assert(is_inside(x, y)); return buffer[y*width + x]; }
void set_color(Color color)
{ this->color = color; }
void set_color(double r, double g, double b, double a = 1.0)
{ set_color(convert_color(r, g, b, a)); }
void set_blending(bool blending) { this->blending = blending; }
void line(Color color, int x0, int y0, int x1, int y1, bool blending = true);
void rect(Color color, int x0, int y0, int x1, int y1, bool blending = true);
void move_to(int x, int y) { this->x = x; this->y = y; }
void line_to(int x, int y) { line(color, this->x, this->y, x, y, blending); move_to(x, y); };
void rect_to(int x, int y) { rect(color, this->x, this->y, x, y, blending); move_to(x, y); };
void move_by(int x, int y) { move_to(this->x + x, this->y + y); }
void line_by(int x, int y) { line_to(this->x + x, this->y + y); }
void rect_by(int x, int y) { rect_to(this->x + x, this->y + y); }
void clear(Color color = 0) { rect(color, 0, 0, width, height, false); }
void clear(double r, double g, double b, double a) { clear(convert_color(r, g, b, a)); }
void set_point(int x, int y, unsigned int color)
{ if (is_inside(x, y)) point(x, y) = color; }
void blend_point(int x, int y, unsigned int color) {
if (is_inside(x, y)) {
Color& p = point(x, y);
p = blend(p, color);
}
}
void save(const std::string &filename) const;
};
#endif