scummvm/graphics/tinygl/zline.cpp
Stefano Musumeci 2cf70d6d76 Merge branch 'master' into tinygl-dirty-rects-fixed
Conflicts:
	graphics/tinygl/ztriangle.cpp
2014-08-16 16:03:27 +02:00

223 lines
6.5 KiB
C++

/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution.
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
/*
* This file is based on, or a modified version of code from TinyGL (C) 1997-1998 Fabrice Bellard,
* which is licensed under the zlib-license (see LICENSE).
* It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
*/
#include "graphics/tinygl/zbuffer.h"
namespace TinyGL {
template <bool kInterpRGB, bool kInterpZ, bool kDepthWrite>
FORCEINLINE static void putPixel(FrameBuffer *buffer, int pixelOffset,
const Graphics::PixelFormat &cmode, unsigned int *pz, unsigned int &z, int &color, unsigned int &r,
unsigned int &g, unsigned int &b) {
if (buffer->scissorPixel(pixelOffset)) {
return;
}
if (kInterpZ) {
if (buffer->compareDepth(z, *pz)) {
if (kInterpRGB) {
buffer->writePixel(pixelOffset, RGB_TO_PIXEL(r, g, b));
} else {
buffer->writePixel(pixelOffset, color);
}
if (kDepthWrite) {
*pz = z;
}
}
} else {
if (kInterpRGB) {
buffer->writePixel(pixelOffset, RGB_TO_PIXEL(r, g, b));
} else {
buffer->writePixel(pixelOffset, color);
}
}
}
template <bool kInterpRGB, bool kInterpZ, bool kDepthWrite>
FORCEINLINE static void drawLine(FrameBuffer *buffer, ZBufferPoint *p1, ZBufferPoint *p2,
int &pixelOffset, const Graphics::PixelFormat &cmode, unsigned int *pz, unsigned int &z, int &color,
unsigned int &r, unsigned int &g, unsigned int &b, int dx, int dy, int inc_1, int inc_2) {
int n = dx;
int rinc, ginc, binc;
int zinc;
if (kInterpZ) {
zinc = (p2->z - p1->z) / n;
}
if (kInterpRGB) {
rinc = ((p2->r - p1->r) << 8) / n;
ginc = ((p2->g - p1->g) << 8) / n;
binc = ((p2->b - p1->b) << 8) / n;
}
int a = 2 * dy - dx;
dy = 2 * dy;
dx = 2 * dx - dy;
int pp_inc_1 = (inc_1);
int pp_inc_2 = (inc_2);
do {
putPixel<kInterpRGB, kInterpZ, kDepthWrite>(buffer, pixelOffset, cmode, pz, z, color, r, g, b);
if (kInterpZ) {
z += zinc;
}
if (kInterpRGB) {
r += rinc;
g += ginc;
b += binc;
}
if (a > 0) {
pixelOffset += pp_inc_1;
if (kInterpZ) {
pz += inc_1;
}
a -= dx;
} else {
pixelOffset += pp_inc_2;
if (kInterpZ) {
pz += inc_2;
}
a += dy;
}
} while (--n >= 0);
}
template <bool kInterpRGB, bool kInterpZ, bool kDepthWrite>
void FrameBuffer::fillLineGeneric(ZBufferPoint *p1, ZBufferPoint *p2, int color) {
int dx, dy, sx;
unsigned int r, g, b;
unsigned int *pz = NULL;
unsigned int z;
int pixelOffset;
if (p1->y > p2->y || (p1->y == p2->y && p1->x > p2->x)) {
ZBufferPoint *tmp;
tmp = p1;
p1 = p2;
p2 = tmp;
}
sx = xsize;
pixelOffset = xsize * p1->y + p1->x;
if (kInterpZ) {
pz = _zbuf + (p1->y * sx + p1->x);
z = p1->z;
}
dx = p2->x - p1->x;
dy = p2->y - p1->y;
if (kInterpRGB) {
r = p2->r << 8;
g = p2->g << 8;
b = p2->b << 8;
}
if (dx == 0 && dy == 0) {
putPixel<kInterpRGB, kInterpZ, kDepthWrite>(this, pixelOffset, cmode, pz, z, color, r, g, b);
} else if (dx > 0) {
if (dx >= dy) {
drawLine<kInterpRGB, kInterpZ, kDepthWrite>(this, p1, p2, pixelOffset, cmode, pz, z, color, r, g, b, dx, dy, sx + 1, 1);
} else {
drawLine<kInterpRGB, kInterpZ, kDepthWrite>(this, p1, p2, pixelOffset, cmode, pz, z, color, r, g, b, dx, dy, sx + 1, sx);
}
} else {
dx = -dx;
if (dx >= dy) {
drawLine<kInterpRGB, kInterpZ, kDepthWrite>(this, p1, p2, pixelOffset, cmode, pz, z, color, r, g, b, dx, dy, sx - 1, -1);
} else {
drawLine<kInterpRGB, kInterpZ, kDepthWrite>(this, p1, p2, pixelOffset, cmode, pz, z, color, r, g, b, dx, dy, sx - 1, sx);
}
}
}
void FrameBuffer::plot(ZBufferPoint *p) {
unsigned int *pz;
unsigned int r, g, b;
pz = _zbuf + (p->y * xsize + p->x);
int col = RGB_TO_PIXEL(p->r, p->g, p->b);
unsigned int z = p->z;
if (_depthWrite && _depthTestEnabled)
putPixel<false, true, true>(this, linesize * p->y + p->x * PSZB, cmode, pz, z, col, r, g, b);
else
putPixel<false, true, false>(this, linesize * p->y + p->x * PSZB, cmode, pz, z, col, r, g, b);
}
void FrameBuffer::fillLineFlatZ(ZBufferPoint *p1, ZBufferPoint *p2, int color) {
if (_depthWrite && _depthTestEnabled)
fillLineGeneric<false, true, true>(p1, p2, color);
else
fillLineGeneric<false, true, false>(p1, p2, color);
}
// line with color interpolation
void FrameBuffer::fillLineInterpZ(ZBufferPoint *p1, ZBufferPoint *p2) {
if (_depthWrite && _depthTestEnabled)
fillLineGeneric<true, true, true>(p1, p2, 0);
else
fillLineGeneric<true, true, false>(p1, p2, 0);
}
// no Z interpolation
void FrameBuffer::fillLineFlat(ZBufferPoint *p1, ZBufferPoint *p2, int color) {
if (_depthWrite && _depthTestEnabled)
fillLineGeneric<false, false, true>(p1, p2, color);
else
fillLineGeneric<false, false, false>(p1, p2, color);
}
void FrameBuffer::fillLineInterp(ZBufferPoint *p1, ZBufferPoint *p2) {
if (_depthWrite && _depthTestEnabled)
fillLineGeneric<false, true, true>(p1, p2, 0);
else
fillLineGeneric<false, true, false>(p1, p2, 0);
}
void FrameBuffer::fillLineZ(ZBufferPoint *p1, ZBufferPoint *p2) {
int color1, color2;
color1 = RGB_TO_PIXEL(p1->r, p1->g, p1->b);
color2 = RGB_TO_PIXEL(p2->r, p2->g, p2->b);
// choose if the line should have its color interpolated or not
if (color1 == color2) {
fillLineFlatZ(p1, p2, color1);
} else {
fillLineInterpZ(p1, p2);
}
}
void FrameBuffer::fillLine(ZBufferPoint *p1, ZBufferPoint *p2) {
int color1, color2;
color1 = RGB_TO_PIXEL(p1->r, p1->g, p1->b);
color2 = RGB_TO_PIXEL(p2->r, p2->g, p2->b);
// choose if the line should have its color interpolated or not
if (color1 == color2) {
fillLineFlat(p1, p2, color1);
} else {
fillLineInterp(p1, p2);
}
}
} // end of namespace TinyGL