/*
winnie - an experimental window system
Copyright (C) 2013 Eleni Maria Stea
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 .
Author: Eleni Maria Stea
*/
#include
#include
#include
#include
#include "geom.h"
#include "gfx.h"
#include "sdl/gfx.h"
// used by the polygon rasterizer
#define MAX_SCANLINES 2048
static int32_t left_fx[MAX_SCANLINES], right_fx[MAX_SCANLINES];
void
clear_screen(int r, int g, int b)
{
Rect screen_rect = get_screen_size();
fill_rect(screen_rect, r, g, b);
}
void
fill_rect(const Rect &rect, int r, int g, int b)
{
Rect drect = rect;
Rect screen_rect = get_screen_size();
Rect clipping_rect = get_clipping_rect();
if (drect.x < clipping_rect.x) {
drect.width -= clipping_rect.x - drect.x;
drect.x = clipping_rect.x;
}
if (drect.y < clipping_rect.y) {
drect.height -= clipping_rect.y - drect.y;
drect.y = clipping_rect.y;
}
if (drect.x + drect.width >= clipping_rect.x + clipping_rect.width) {
drect.width = clipping_rect.width + clipping_rect.x - drect.x;
}
if (drect.y + drect.height >= clipping_rect.y + clipping_rect.height) {
drect.height = clipping_rect.height + clipping_rect.y - drect.y;
}
unsigned char *fb
= get_framebuffer() + (drect.x + screen_rect.width * drect.y) * 4;
for (int i = 0; i < drect.height; i++) {
for (int j = 0; j < drect.width; j++) {
fb[j * 4] = b;
fb[j * 4 + 1] = g;
fb[j * 4 + 2] = r;
}
fb += screen_rect.width * 4;
}
}
void
blit(unsigned char *src_img,
const Rect &src_rect,
unsigned char *dest_img,
const Rect &dest_rect,
int dest_x,
int dest_y)
{
int red_offs, green_offs, blue_offs;
get_rgb_order(&red_offs, &green_offs, &blue_offs);
Rect irect = rect_intersection(get_clipping_rect(), dest_rect);
int src_xoffs = 0;
int src_yoffs = 0;
int width = src_rect.width;
int height = src_rect.height;
int xoffs = dest_x - irect.x;
if (xoffs < 0) {
dest_x = irect.x;
width += xoffs;
src_xoffs = -xoffs;
}
int yoffs = dest_y - irect.y;
if (yoffs < 0) {
dest_y = irect.y;
height += yoffs;
src_yoffs = -yoffs;
}
int xend = dest_x + width;
if (xend >= irect.x + irect.width) {
width -= xend - (irect.x + irect.width);
}
int yend = dest_y + height;
if (yend >= irect.y + irect.height) {
height -= yend - (irect.y + irect.height);
}
if (width <= 0 || height <= 0) {
return;
}
unsigned char *sptr
= src_img
+ ((src_rect.y + src_yoffs) * src_rect.width + src_rect.x + src_xoffs)
* 4;
unsigned char *dptr = dest_img + (dest_y * dest_rect.width + dest_x) * 4;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
dptr[j * 4 + red_offs] = sptr[j * 4];
dptr[j * 4 + green_offs] = sptr[j * 4 + 1];
dptr[j * 4 + blue_offs] = sptr[j * 4 + 2];
}
sptr += src_rect.width * 4;
dptr += dest_rect.width * 4;
}
}
void
blit_key(unsigned char *src_img,
const Rect &src_rect,
unsigned char *dest_img,
const Rect &dest_rect,
int dest_x,
int dest_y,
int key_r,
int key_g,
int key_b)
{
int red_offs, green_offs, blue_offs;
get_rgb_order(&red_offs, &green_offs, &blue_offs);
Rect irect = rect_intersection(get_clipping_rect(), dest_rect);
int src_xoffs = 0;
int src_yoffs = 0;
int width = src_rect.width;
int height = src_rect.height;
int xoffs = dest_x - irect.x;
if (xoffs < 0) {
dest_x = irect.x;
width += xoffs;
src_xoffs = -xoffs;
}
int yoffs = dest_y - irect.y;
if (yoffs < 0) {
dest_y = irect.y;
height += yoffs;
src_yoffs = -yoffs;
}
int xend = dest_x + width;
if (xend >= irect.x + irect.width) {
width -= xend - (irect.x + irect.width);
}
int yend = dest_y + height;
if (yend >= irect.y + irect.height) {
height -= yend - (irect.y + irect.height);
}
if (width <= 0 || height <= 0) {
return;
}
unsigned char *sptr
= src_img
+ ((src_rect.y + src_yoffs) * src_rect.width + src_rect.x + src_xoffs)
* 4;
unsigned char *dptr = dest_img + (dest_y * dest_rect.width + dest_x) * 4;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int r = sptr[j * 4];
int g = sptr[j * 4 + 1];
int b = sptr[j * 4 + 2];
if (r != key_r || g != key_g || b != key_b) {
dptr[j * 4 + red_offs] = r;
dptr[j * 4 + green_offs] = g;
dptr[j * 4 + blue_offs] = b;
}
}
sptr += src_rect.width * 4;
dptr += dest_rect.width * 4;
}
}
void
draw_line(Pixmap *pixmap, int x0, int y0, int x1, int y1, int r, int g, int b)
{
int red_offs = 0, green_offs = 1, blue_offs = 2;
if (pixmap == get_framebuffer_pixmap()) {
get_rgb_order(&red_offs, &green_offs, &blue_offs);
}
unsigned char *ptr = pixmap->pixels + (y0 * pixmap->width + x0) * 4;
int dx = x1 - x0;
int dy = y1 - y0;
int x_inc = 4;
int y_inc = pixmap->width * 4;
if (dx < 0) {
x_inc = -x_inc;
dx = -dx;
}
if (dy < 0) {
y_inc = -y_inc;
dy = -dy;
}
if (dx > dy) {
int error = (dy << 1) - dx;
for (int i = 0; i <= dx; i++) {
ptr[red_offs] = r;
ptr[green_offs] = g;
ptr[blue_offs] = b;
if (error >= 0) {
error -= dx << 1;
ptr += y_inc;
}
error += dy << 1;
ptr += x_inc;
}
} else {
int error = (dx << 1) - dy;
for (int i = 0; i <= dy; i++) {
ptr[red_offs] = r;
ptr[green_offs] = g;
ptr[blue_offs] = b;
if (error >= 0) {
error -= dy << 1;
ptr += x_inc;
}
error += dx << 1;
ptr += y_inc;
}
}
}
static inline int
min(int x, int y)
{
return x < y ? x : y;
}
static inline int
max(int x, int y)
{
return x > y ? x : y;
}
void
draw_polygon(
Pixmap *pixmap, int *vpos, int *vtex, int num_verts, int r, int g, int b)
{
int roffs = 0, goffs = 1, boffs = 2;
if (pixmap == get_framebuffer_pixmap()) {
get_rgb_order(&roffs, &goffs, &boffs);
}
int ystart = pixmap->height, yend = 0;
for (int i = 0; i < num_verts; i++) {
int next = (i + 1) % num_verts;
int x0 = vpos[i * 2];
int y0 = vpos[i * 2 + 1];
int x1 = vpos[next * 2];
int y1 = vpos[next * 2 + 1];
int dx = x1 - x0;
int dy = y1 - y0;
if (dy == 0)
continue;
/* continue in 24.8 fixed point */
int32_t fslope = ((int32_t) dx << 8) / (int32_t) abs(dy);
int32_t fx = x0 << 8;
if (dy >= 0) {
for (int j = y0; j <= y1; j++) {
right_fx[j] = fx;
fx += fslope;
}
} else {
for (int j = y0; j >= y1; j--) {
left_fx[j] = fx;
fx += fslope;
}
}
ystart = min(ystart, min(y0, y1));
yend = max(yend, max(y0, y1));
}
if (ystart < 0)
ystart = 0;
if (yend > pixmap->height)
yend = pixmap->height;
for (int i = ystart; i < yend; i++) {
int x = (left_fx[i] + (1 << 7)) >> 8;
int dx = (right_fx[i] - left_fx[i]) >> 8;
// accept polygons of either order
if (dx < 0) {
x = (right_fx[i] + (1 << 7)) >> 8;
dx = -dx;
}
if (x < 0) {
dx += x;
x = 0;
}
if (x + dx >= pixmap->width) {
dx = pixmap->width - x;
}
unsigned char *pixptr = pixmap->pixels + (i * pixmap->width + x) * 4;
for (int j = 0; j <= dx; j++) {
pixptr[roffs] = r;
pixptr[goffs] = g;
pixptr[boffs] = b;
pixptr += 4;
}
}
}