ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

zline.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 /*
00024  * This file is based on, or a modified version of code from TinyGL (C) 1997-1998 Fabrice Bellard,
00025  * which is licensed under the zlib-license (see LICENSE).
00026  * It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
00027  */
00028 
00029 #include "graphics/tinygl/zbuffer.h"
00030 
00031 namespace TinyGL {
00032 
00033 template <bool kDepthWrite>
00034 FORCEINLINE void FrameBuffer::putPixel(unsigned int pixelOffset, int color, int x, int y, unsigned int z) {
00035     if (_enableScissor)
00036         putPixel<kDepthWrite, true>(pixelOffset, color, x, y, z);
00037     else
00038         putPixel<kDepthWrite, false>(pixelOffset, color, x, y, z);
00039 }
00040 
00041 template <bool kDepthWrite, bool kEnableScissor>
00042 FORCEINLINE void FrameBuffer::putPixel(unsigned int pixelOffset, int color, int x, int y, unsigned int z) {
00043     if (kEnableScissor && scissorPixel(x, y)) {
00044         return;
00045     }
00046     unsigned int *pz = _zbuf + pixelOffset;
00047     if (compareDepth(z, *pz)) {
00048         writePixel<true, true, kDepthWrite>(pixelOffset, color, z);
00049     }
00050 }
00051 
00052 template <bool kEnableScissor>
00053 FORCEINLINE void FrameBuffer::putPixel(unsigned int pixelOffset, int color, int x, int y) {
00054     if (kEnableScissor && scissorPixel(x, y)) {
00055         return;
00056     }
00057     writePixel<true, true>(pixelOffset, color);
00058 }
00059 
00060 template <bool kInterpRGB, bool kInterpZ, bool kDepthWrite>
00061 FORCEINLINE void FrameBuffer::drawLine(const ZBufferPoint *p1, const ZBufferPoint *p2) {
00062     if (_enableScissor)
00063         drawLine<kInterpRGB, kInterpZ, kDepthWrite, true>(p1, p2);
00064     else
00065         drawLine<kInterpRGB, kInterpZ, kDepthWrite, false>(p1, p2);
00066 }
00067 
00068 template <bool kInterpRGB, bool kInterpZ, bool kDepthWrite, bool kEnableScissor>
00069 void FrameBuffer::drawLine(const ZBufferPoint *p1, const ZBufferPoint *p2) {
00070     // Based on Bresenham's line algorithm, as implemented in
00071     // https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C
00072     // with a loop exit condition based on the (unidimensional) taxicab
00073     // distance between p1 and p2 (which is cheap to compute and
00074     // rounding-error-free) so that interpolations are possible without
00075     // code duplication.
00076 
00077     // Where we are in unidimensional framebuffer coordinate
00078     unsigned int pixelOffset = p1->y * xsize + p1->x;
00079     // and in 2d
00080     int x = p1->x;
00081     int y = p1->y;
00082 
00083     // How to move on each axis, in both coordinates systems
00084     const int dx = abs(p2->x - p1->x);
00085     const int inc_x = p1->x < p2->x ? 1 : -1;
00086     const int dy = abs(p2->y - p1->y);
00087     const int inc_y = p1->y < p2->y ? 1 : -1;
00088     const int inc_y_pixel = p1->y < p2->y ? xsize : -xsize;
00089 
00090     // When to move on each axis
00091     int err = (dx > dy ? dx : -dy) / 2;
00092     int e2;
00093 
00094     // How many moves
00095     int n = dx > dy ? dx : dy;
00096 
00097     // kInterpZ
00098     unsigned int z;
00099     int sz;
00100 
00101     // kInterpRGB
00102     int r = p1->r >> (ZB_POINT_RED_BITS - 8);
00103     int g = p1->g >> (ZB_POINT_GREEN_BITS - 8);
00104     int b = p1->b >> (ZB_POINT_BLUE_BITS - 8);
00105     int color = RGB_TO_PIXEL(r, g, b);
00106     int sr, sg, sb;
00107 
00108         if (kInterpZ) {
00109         sz = (p2->z - p1->z) / n;
00110         z = p1->z;
00111     }
00112     if (kInterpRGB) {
00113         sr = ((p2->r - p1->r) / n) >> (ZB_POINT_RED_BITS - 8);
00114         sg = ((p2->g - p1->g) / n) >> (ZB_POINT_GREEN_BITS - 8);
00115         sb = ((p2->b - p1->b) / n) >> (ZB_POINT_BLUE_BITS - 8);
00116     }
00117     while (n--) {
00118         if (kInterpZ)
00119             putPixel<kDepthWrite, kEnableScissor>(pixelOffset, color, x, y, z);
00120         else
00121             putPixel<kEnableScissor>(pixelOffset, color, x, y);
00122         e2 = err;
00123         if (e2 > -dx) {
00124             err -= dy;
00125             pixelOffset += inc_x;
00126             x += inc_x;
00127         }
00128         if (e2 < dy) {
00129             err += dx;
00130             pixelOffset += inc_y_pixel;
00131             y += inc_y;
00132         }
00133         if (kInterpZ)
00134             z += sz;
00135         if (kInterpRGB) {
00136             r += sr;
00137             g += sg;
00138             b += sb;
00139             color = RGB_TO_PIXEL(r, g, b);
00140         }
00141     }
00142 }
00143 
00144 void FrameBuffer::plot(ZBufferPoint *p) {
00145     const unsigned int pixelOffset = p->y * xsize + p->x;
00146     const int col = RGB_TO_PIXEL(p->r, p->g, p->b);
00147     const unsigned int z = p->z;
00148     if (_depthWrite && _depthTestEnabled)
00149         putPixel<true>(pixelOffset, col, p->x, p->y, z);
00150     else 
00151         putPixel<false>(pixelOffset, col, p->x, p->y, z);
00152 }
00153 
00154 void FrameBuffer::fillLineFlatZ(ZBufferPoint *p1, ZBufferPoint *p2) {
00155     if (_depthWrite && _depthTestEnabled)
00156         drawLine<false, true, true>(p1, p2);
00157     else
00158         drawLine<false, true, false>(p1, p2);
00159 }
00160 
00161 // line with color interpolation
00162 void FrameBuffer::fillLineInterpZ(ZBufferPoint *p1, ZBufferPoint *p2) {
00163     if (_depthWrite && _depthTestEnabled)
00164         drawLine<true, true, true>(p1, p2);
00165     else
00166         drawLine<true, true, false>(p1, p2);
00167 }
00168 
00169 // no Z interpolation
00170 void FrameBuffer::fillLineFlat(ZBufferPoint *p1, ZBufferPoint *p2) {
00171     if (_depthWrite && _depthTestEnabled)
00172         drawLine<false, false, true>(p1, p2);
00173     else
00174         drawLine<false, false, false>(p1, p2);
00175 }
00176 
00177 void FrameBuffer::fillLineInterp(ZBufferPoint *p1, ZBufferPoint *p2) {
00178     if (_depthWrite && _depthTestEnabled)
00179         drawLine<false, true, true>(p1, p2);
00180     else
00181         drawLine<false, true, false>(p1, p2);
00182 }
00183 
00184 void FrameBuffer::fillLineZ(ZBufferPoint *p1, ZBufferPoint *p2) {
00185     // choose if the line should have its color interpolated or not
00186     if (p1->r == p2->r && p1->g == p2->g && p1->b == p2->b)
00187         fillLineFlatZ(p1, p2);
00188     else
00189         fillLineInterpZ(p1, p2);
00190 }
00191 
00192 void FrameBuffer::fillLine(ZBufferPoint *p1, ZBufferPoint *p2) {
00193     // choose if the line should have its color interpolated or not
00194     if (p1->r == p2->r && p1->g == p2->g && p1->b == p2->b)
00195         fillLineFlat(p1, p2);
00196     else
00197         fillLineInterp(p1, p2);
00198 }
00199 
00200 } // end of namespace TinyGL


Generated on Sat Dec 14 2019 05:00:47 for ResidualVM by doxygen 1.7.1
curved edge   curved edge