160 lines
4.3 KiB
C++
160 lines
4.3 KiB
C++
/* -----------------------------------------------------------------------------
|
|
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 <float> *p_in, Point <float> *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 <float> *point, float r, float g, float b, float a, const Rect <float> *clip_rect)
|
|
{
|
|
// Output validity.
|
|
if (!data || (pxformat.GetBpp() != 32) || pxformat.IsReal())
|
|
return;
|
|
|
|
// Clip primitive.
|
|
Point <float> *_point = point;
|
|
|
|
if (clip_rect)
|
|
{
|
|
_point = new Point <float> [128];
|
|
if (!_point)
|
|
__ERRRAW__(__LOG_E__ << "failed to allocate polygon clipping array.\n")
|
|
|
|
// Old boring clipping code...
|
|
Point <float> *_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);
|
|
}
|
|
//------------------------------------------------------------------------------
|