|
bw |
249abc |
/*
|
|
bw |
8a6d22 |
......... 2016 Ivan Mahonin
|
|
bw |
249abc |
|
|
bw |
249abc |
This program is free software: you can redistribute it and/or modify
|
|
bw |
249abc |
it under the terms of the GNU General Public License as published by
|
|
bw |
249abc |
the Free Software Foundation, either version 3 of the License, or
|
|
bw |
249abc |
(at your option) any later version.
|
|
bw |
249abc |
|
|
bw |
249abc |
This program is distributed in the hope that it will be useful,
|
|
bw |
249abc |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
bw |
249abc |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
bw |
249abc |
GNU General Public License for more details.
|
|
bw |
249abc |
|
|
bw |
249abc |
You should have received a copy of the GNU General Public License
|
|
bw |
249abc |
along with this program. If not, see <http: licenses="" www.gnu.org="">.</http:>
|
|
bw |
249abc |
*/
|
|
bw |
249abc |
|
|
bw |
249abc |
#include <cstring></cstring>
|
|
bw |
249abc |
#include <cmath></cmath>
|
|
bw |
249abc |
|
|
bw |
249abc |
#include <fstream></fstream>
|
|
bw |
249abc |
|
|
bw |
249abc |
#include "surface.h"
|
|
bw |
249abc |
|
|
bw |
249abc |
|
|
bw |
249abc |
using namespace std;
|
|
bw |
249abc |
|
|
bw |
249abc |
|
|
bw |
249abc |
Surface::Surface(int width, int height):
|
|
bw |
249abc |
buffer(new Color[width*height]),
|
|
bw |
249abc |
width(width),
|
|
bw |
249abc |
height(height),
|
|
bw |
249abc |
color(),
|
|
bw |
249abc |
x(),
|
|
bw |
249abc |
y(),
|
|
bw |
249abc |
blending(true)
|
|
bw |
249abc |
{
|
|
bw |
249abc |
memset(buffer, 0, sizeof(Color)*width*height);
|
|
bw |
249abc |
}
|
|
bw |
249abc |
|
|
bw |
249abc |
Surface::~Surface()
|
|
bw |
249abc |
{ delete[] buffer; }
|
|
bw |
249abc |
|
|
bw |
249abc |
unsigned int Surface::convert_channel(double c) {
|
|
bw |
249abc |
int i = (int)round(c*255.0);
|
|
bw |
249abc |
return i < 0 ? 0 : i > 255 ? 255 : (unsigned char)i;
|
|
bw |
249abc |
}
|
|
bw |
249abc |
|
|
bw |
249abc |
unsigned int Surface::blend_channel(unsigned int a, unsigned int dest, unsigned int src)
|
|
bw |
249abc |
{
|
|
bw |
8a6d22 |
return ((dest*(255-a) + a*src) >> 8) & 0xff;
|
|
bw |
249abc |
}
|
|
bw |
249abc |
|
|
bw |
249abc |
Surface::Color Surface::convert_color(double r, double g, double b, double a) {
|
|
bw |
249abc |
return convert_channel(r)
|
|
bw |
249abc |
| (convert_channel(g) << 8)
|
|
bw |
249abc |
| (convert_channel(b) << 16)
|
|
bw |
249abc |
| (convert_channel(a) << 24);
|
|
bw |
249abc |
}
|
|
bw |
249abc |
|
|
bw |
249abc |
Surface::Color Surface::blend(Color dest, Color src) {
|
|
bw |
249abc |
unsigned int sa = src >> 24;
|
|
bw |
249abc |
if (sa >= 255) return src; else if (sa == 0) return dest;
|
|
bw |
249abc |
unsigned int da = (dest >> 24) + sa;
|
|
bw |
249abc |
if (da > 255) da = 255;
|
|
bw |
8a6d22 |
return blend_channel(sa, dest & 0xff, src & 0xff)
|
|
bw |
8a6d22 |
| (blend_channel(sa, (dest >> 8) & 0xff, (src >> 8) & 0xff) << 8)
|
|
bw |
8a6d22 |
| (blend_channel(sa, (dest >> 16) & 0xff, (src >> 16) & 0xff) << 16)
|
|
bw |
249abc |
| (da << 24);
|
|
bw |
249abc |
}
|
|
bw |
249abc |
|
|
bw |
249abc |
void Surface::line(Color color, int x0, int y0, int x1, int y1, bool blending) {
|
|
bw |
249abc |
if (x1 < x0) swap(x1, x0);
|
|
bw |
249abc |
if (y1 < y0) swap(y1, y0);
|
|
bw |
249abc |
int pdx = y1 - y0;
|
|
bw |
249abc |
int pdy = x0 - x1;
|
|
bw |
249abc |
int d = 0;
|
|
bw |
249abc |
for(int x = x0, y = y0; x <= x1 && y <= y1;) {
|
|
bw |
249abc |
if (blending) blend_point(x, y, color); else set_point(x, y, color);
|
|
bw |
249abc |
if (abs(d+pdx) < abs(d+pdy))
|
|
bw |
249abc |
{ d += pdx; ++x; } else { d += pdy; ++y; }
|
|
bw |
249abc |
}
|
|
bw |
249abc |
}
|
|
bw |
249abc |
|
|
bw |
249abc |
void Surface::rect(Color color, int x0, int y0, int x1, int y1, bool blending) {
|
|
bw |
249abc |
if (x1 < x0) swap(x1, x0);
|
|
bw |
249abc |
if (y1 < y0) swap(y1, y0);
|
|
bw |
249abc |
for(int x = x0; x < x1; ++x)
|
|
bw |
249abc |
for(int y = y0; y < y1; ++y)
|
|
bw |
249abc |
if (blending) blend_point(x, y, color); else set_point(x, y, color);
|
|
bw |
249abc |
}
|
|
bw |
249abc |
|
|
bw |
249abc |
void Surface::save(const string &filename) const
|
|
bw |
249abc |
{
|
|
bw |
249abc |
// create file
|
|
bw |
249abc |
ofstream f(("results/" + filename).c_str(), ofstream::out | ofstream::trunc | ofstream::binary);
|
|
bw |
249abc |
|
|
bw |
249abc |
// write header
|
|
bw |
249abc |
unsigned char targa_header[] = {
|
|
bw |
249abc |
0, // Length of the image ID field (0 - no ID field)
|
|
bw |
249abc |
0, // Whether a color map is included (0 - no colormap)
|
|
bw |
249abc |
2, // Compression and color types (2 - uncompressed true-color image)
|
|
bw |
249abc |
0, 0, 0, 0, 0, // Color map specification (not need for us)
|
|
bw |
249abc |
0, 0, // X-origin
|
|
bw |
249abc |
0, 0, // Y-origin
|
|
bw |
249abc |
(unsigned char)(width & 0xff), // Image width
|
|
bw |
249abc |
(unsigned char)(width >> 8),
|
|
bw |
249abc |
(unsigned char)(height & 0xff), // Image height
|
|
bw |
249abc |
(unsigned char)(height >> 8),
|
|
bw |
249abc |
32, // Bits per pixel
|
|
bw |
249abc |
0 // Image descriptor (keep zero for capability)
|
|
bw |
249abc |
};
|
|
bw |
249abc |
f.write((char*)targa_header, sizeof(targa_header));
|
|
bw |
249abc |
|
|
bw |
249abc |
// write data
|
|
bw |
249abc |
if (true) {
|
|
bw |
249abc |
int line_size = 4*width;
|
|
bw |
249abc |
const char *end = (char*)buffer;
|
|
bw |
249abc |
const char *current = end + height*line_size;
|
|
bw |
249abc |
while(current > end) {
|
|
bw |
249abc |
current -= line_size;
|
|
bw |
249abc |
f.write(current, line_size);
|
|
bw |
249abc |
}
|
|
bw |
249abc |
} else {
|
|
bw |
249abc |
f.write((const char*)buffer, 4*width*height);
|
|
bw |
249abc |
}
|
|
bw |
249abc |
}
|