/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "picture/pict.h" #include "math/nmath.h" #include "log/log.h" using namespace GS; //------------------------------------------------- static bool ClipValueTestLess(float v, float c) { return v < c; } static bool ClipValueTestGreater(float v, float c) { return v >= c; } //------------------------------------------------- //------------------------------------------------------------------------------ static uint ClipPolygonAxis(float clip, uint axis, bool (*ClipValueTest)(float v, float c), uint count_in, Point *p_in, Point *p_out) { uint p_current = 0, count_out = 0; //-------------------------------------------------------------------------------------------------------- #define __ClipSegment\ {\ float k = (clip - p_in[p_current][axis]) / (p_in[p_next][axis] - p_in[p_current][axis]);\ if (!axis)\ p_out[count_out++].Set (clip, (p_in[p_next].y - p_in[p_current].y) * k + p_in[p_current].y);\ else p_out[count_out++].Set ((p_in[p_next].x - p_in[p_current].x) * k + p_in[p_current].x, clip);\ } //-------------------------------------------------------------------------------------------------------- while (p_current < count_in) { uint p_next = p_current + 1; if (p_next == count_in) p_next = 0; if (ClipValueTest(p_in[p_current][axis], clip)) // Inside. { p_out[count_out++] = p_in[p_current]; if (!ClipValueTest(p_in[p_next][axis], clip)) __ClipSegment } else // Outside. { if (ClipValueTest(p_in[p_next][axis], clip)) __ClipSegment } p_current++; } return count_out; } void Picture::DrawPolygon(uint point_count, Point *point, float r, float g, float b, float a, const Rect *clip_rect) { // Output validity. if (!data || (pxformat.GetBpp() != 32) || pxformat.IsReal()) return; // Clip primitive. Point *_point = point; if (clip_rect) { _point = new Point [128]; if (!_point) __ERRRAW__(__LOG_E__ << "failed to allocate polygon clipping array.\n") // Old boring clipping code... Point *_point_ = _point + 64; point_count = ClipPolygonAxis(clip_rect->sx, 0, ClipValueTestGreater, point_count, point, _point_); point_count = ClipPolygonAxis(clip_rect->ex, 0, ClipValueTestLess, point_count, _point_, _point); point_count = ClipPolygonAxis(clip_rect->sy, 1, ClipValueTestGreater, point_count, _point, _point_); point_count = ClipPolygonAxis(clip_rect->ey, 1, ClipValueTestLess, point_count, _point_, _point); if (point_count < 3) { _safe_delete_array(_point); return; } } // Determine entry vertex. float y_scan = _point[0].y, y_max = _point[0].y; int p_int = 0, p_ext = 0; for (uint n = 1; n < point_count; ++n) { if (_point[n].y < y_scan) { y_scan = _point[n].y; p_int = p_ext = n; } if (_point[n].y > y_max) y_max = _point[n].y; } // Render scanline. float d_int = 0, d_ext = 0; float x_int = _point[p_int].x, x_ext = _point[p_int].x; y_scan = Math::Ceil(y_scan); while (y_scan < y_max) { // Update interior pointer. while (y_scan >= _point[p_int].y) { uint p_next = p_int - 1; if (p_next == -1) p_next = point_count - 1; // Update delta. d_int = (_point[p_next].x - _point[p_int].x) / (_point[p_next].y - _point[p_int].y); x_int = d_int * (y_scan - _point[p_int].y) + _point[p_int].x; p_int = p_next; } // Update exterior pointer. while (y_scan >= _point[p_ext].y) { uint p_next = p_ext + 1; if (p_next == point_count) p_next = 0; // Update delta. d_ext = (_point[p_next].x - _point[p_ext].x) / (_point[p_next].y - _point[p_ext].y); x_ext = d_ext * (y_scan - _point[p_ext].y) + _point[p_ext].x; p_ext = p_next; } // Draw scanline. { float sx, ex; if (x_int > x_ext) { sx = x_ext; ex = x_int; } else { sx = x_int; ex = x_ext; } for (int x = int(sx); x < int(ex); ++x) DrawPlot((float)x, y_scan, r, g, b, a); } // Step scanline boundaries. y_scan += 1; x_int += d_int; x_ext += d_ext; } // Release clipping point array. if (clip_rect) _safe_delete_array(_point); } //------------------------------------------------------------------------------