📄 graphic.cpp
字号:
}
#define DRAWLINE(dx,dy,inc_1,inc_2) \
n=dx;\
a=2*dy-dx;\
dy=2*dy;\
dx=2*dx-dy;\
do {\
PUTPIXEL();\
if (a>0) { pp+=(inc_1); a-=dx; }\
else { pp+=(inc_2); a+=dy; }\
} while (--n >= 0);
/* fin macro */
if (dx == 0 && dy == 0) {
PUTPIXEL();
} else if (dx > 0) {
if (dx >= dy) {
DRAWLINE(dx, dy, sx + 1, 1);
} else {
DRAWLINE(dy, dx, sx + 1, sx);
}
} else {
dx = -dx;
if (dx >= dy) {
DRAWLINE(dx, dy, sx - 1, -1);
} else {
DRAWLINE(dy, dx, sx - 1, sx);
}
}
#undef DRAWLINE
#undef PUTPIXEL
} else {
#define PUTPIXEL() \
{ \
*pp=mix_alpha(*pp,color,alpha); \
}
#define DRAWLINE(dx,dy,inc_1,inc_2) \
n=dx;\
a=2*dy-dx;\
dy=2*dy;\
dx=2*dx-dy;\
do {\
PUTPIXEL();\
if (a>0) { pp+=(inc_1); a-=dx; }\
else { pp+=(inc_2); a+=dy; }\
} while (--n >= 0);
/* fin macro */
if (dx == 0 && dy == 0) {
PUTPIXEL();
} else if (dx > 0) {
if (dx >= dy) {
DRAWLINE(dx, dy, sx + 1, 1);
} else {
DRAWLINE(dy, dx, sx + 1, sx);
}
} else {
dx = -dx;
if (dx >= dy) {
DRAWLINE(dx, dy, sx - 1, -1);
} else {
DRAWLINE(dy, dx, sx - 1, sx);
}
}
#undef DRAWLINE
#undef PUTPIXEL
}
}
/************************************************************************/
/* polygon rasteriser */
static inline Segment *allocSeg(GraphicDevice *gd)
{
Segment *seg;
if ( (gd->seg_pool_cur - gd->seg_pool) >= NB_SEGMENT_MAX )
return NULL;
seg = gd->seg_pool_cur++;
return seg;
}
/* add a segment to the current path */
/* XXX: handle reverse here ? */
/* XXX: should not malloc here */
/* XXX: handle y1 == y2 case (different for fill / line) */
void GraphicDevice::addSegment(long x1, long y1, long x2, long y2,
FillStyleDef *f0,
FillStyleDef *f1,
int aa)
{
Segment *seg,**segs;
long dX, X, Y, ymin, ymax, tmp;
FillStyleDef *ff;
#if 0
if ( ((y1 + (FRAC-1)) & ~(FRAC-1)) == ((y2 + (FRAC-1)) & ~(FRAC-1)) ) {
return;
}
#else
if ( y1 == y2 ) {
return;
}
#endif
if (y1 < y2) {
ymin = y1;
ymax = y2;
ff = f0;
f0 = f1;
f1 = ff;
} else {
ymin = y2;
ymax = y1;
tmp = x1;
x1 = x2;
x2 = tmp;
}
if (ymin>>FRAC_BITS > clip_rect.ymax) {
return;
}
X = x1 << SEGFRAC;
dX = ((x2 - x1)<<SEGFRAC)/(ymax-ymin);
if (ymin < 0) {
X += dX * (-ymin);
ymin = 0;
}
Y = (ymin + (FRAC-1)) & ~(FRAC-1);
if (Y > ymax) {
//printf("Elimine @ y = %d ymin = %d, ymax = %d\n", Y, ymin, seg->ymax);
return;
}
X += dX * (Y-ymin);
Y >>= FRAC_BITS;
if (Y >= clip_rect.ymax) {
return;
}
seg = allocSeg(this);
if (seg == NULL) {
// printf("addSegment: too many segments\n");.
return;
}
seg->next = 0;
seg->nextValid = 0;
seg->aa = aa;
seg->ymax = ymax;
seg->x1 = x1;
seg->x2 = x2;
seg->X = X;
seg->dX = dX;
seg->fs[0] = f0;
seg->fs[1] = f1;
if (Y < this->ymin) this->ymin = Y;
ymax = (seg->ymax + FRAC - 1) >> FRAC_BITS;
if (ymax >= this->height) ymax = this->height-1;
if (ymax > this->ymax) this->ymax = ymax;
segs = this->segs;
if (segs[Y] == 0) {
segs[Y] = seg;
} else {
Segment *s,*prev;
prev = 0;
for(s = segs[Y]; s; prev = s, s = s->next) {
if (s->X > seg->X) {
if (prev) {
prev->next = seg;
seg->next = s;
} else {
seg->next = segs[Y];
segs[Y] = seg;
}
break;
}
}
if (s == 0) {
prev->next = seg;
seg->next = s;
}
}
}
static Segment *progressSegments(Segment * curSegs, long y)
{
Segment *seg,*prev;
// Update current segments
seg = curSegs;
prev = 0;
while(seg)
{
if ((y*FRAC) > seg->ymax) {
// Remove this segment, no more valid
if (prev) {
prev->nextValid = seg->nextValid;
} else {
curSegs = seg->nextValid;
}
seg = seg->nextValid;
} else {
seg->X += seg->dX * FRAC;
#if 0
if (prev && prev->X > seg->X) {
s = &curSegs;
while ((*s)->X < seg->X) s=&(*s)->nextValid;
prev->nextValid = seg->nextValid;
seg->nextValid = *s;
*s = seg;
seg = prev->nextValid;
} else
#endif
{
prev = seg;
seg = seg->nextValid;
}
}
}
return curSegs;
}
static Segment *newSegments(Segment *curSegs, Segment *newSegs)
{
Segment *s,*seg,*prev;
s = curSegs;
prev = 0;
// Check for new segments
for (seg = newSegs; seg; seg=seg->next)
{
// Place it at the correct position according to X
if (curSegs == 0) {
curSegs = seg;
seg->nextValid = 0;
} else {
for(; s; prev = s, s = s->nextValid)
{
if ( s->X > seg->X ||
( (s->X == seg->X) &&
( (seg->x1 == s->x1 && seg->dX < s->dX) ||
(seg->x2 == s->x2 && seg->dX > s->dX)
))) {
// Insert before s
if (prev) {
seg->nextValid = s;
prev->nextValid = seg;
} else {
seg->nextValid = curSegs;
curSegs = seg;
}
break;
}
}
// Append at the end
if (s == 0) {
prev->nextValid = seg;
seg->nextValid = 0;
}
}
s = seg;
}
return curSegs;
}
#if 0
static void
printSeg(Segment *seg)
{
/*
printf("Seg %08x : X = %5d, Ft = %d, Cl = %2x/%2x/%2x, Cr = %2x/%2x/%2x, x1=%5d, x2=%5d, ymin=%5d, ymax=%5d\n", seg,
seg->X>>SEGFRAC,
seg->right ? seg->right->type: -1,
seg->left ? seg->left->color.red : -1,
seg->left ? seg->left->color.green : -1,
seg->left ? seg->left->color.blue : -1,
seg->right ? seg->right->color.red : -1,
seg->right ? seg->right->color.green : -1,
seg->right ? seg->right->color.blue : -1,
seg->x1, seg->x2, seg->ymin, seg->ymax);
*/
}
#endif
static void
renderScanLine(GraphicDevice *gd, long y, Segment *curSegs)
{
Segment *seg;
long width;
int fi = 1;
FillStyleDef *f;
width = gd->getWidth() * FRAC;
if (curSegs && curSegs->fs[0] && curSegs->fs[1] == 0) {
fi = 0;
}
for(seg = curSegs; seg && seg->nextValid; seg = seg->nextValid)
{
if (seg->nextValid->X <0) continue;
if ((seg->X>>SEGFRAC) > width) break;
#if 0
if (seg->X > seg->nextValid->X) {
printf("error %d %d\n",seg->X,seg->nextValid->X);
}
#endif
f = seg->fs[fi];
if (f) {
switch (f->type) {
case f_Solid:
if (seg->aa) {
gd->fillLineAA(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
} else {
gd->fillLine(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
}
break;
case f_TiledBitmap:
case f_clippedBitmap:
gd->fillLineBitmap(f, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
break;
case f_LinearGradient:
gd->fillLineLG(&f->gradient, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
break;
case f_RadialGradient:
gd->fillLineRG(&f->gradient, y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
break;
case f_None:
break;
}
}
}
}
/* draw the current path */
void GraphicDevice::drawPolygon(void)
{
long y;
Segment *curSegs,*seg;
// no segments ?
if (this->ymax == -1)
return;
// Foreach scanline
curSegs = 0;
for(y=this->ymin; y <= this->ymax; y++) {
// Make X values progess and remove unuseful segments
curSegs = progressSegments(curSegs, y);
// Add the new segment starting at the y position.
curSegs = newSegments(curSegs, this->segs[y]);
// Render the scanline
if (this->scan_line_func == NULL) {
renderScanLine(this, y, curSegs);
} else {
for(seg = curSegs; seg && seg->nextValid; seg = seg->nextValid) {
if (seg->nextValid->X >= seg->X) {
this->scan_line_func(this->scan_line_func_id,
y, seg->X>>SEGFRAC, seg->nextValid->X>>SEGFRAC);
}
}
}
}
/* free the segments */
memset(this->segs + this->ymin, 0,
(this->ymax - this->ymin + 1) * sizeof(Segment *));
this->ymax = -1;
this->ymin = this->height;
this->seg_pool_cur = this->seg_pool;
}
void
GraphicDevice::updateClippingRegion(Rect *rect)
{
if (!clipping) return;
transformBoundingBox(&clip_rect, adjust, rect, 1);
clip_rect.xmin >>= FRAC_BITS;
clip_rect.xmax >>= FRAC_BITS;
clip_rect.ymin >>= FRAC_BITS;
clip_rect.ymax >>= FRAC_BITS;
#if PRINT&1
clip_rect.print();
#endif
clip_rect.xmin-=2;
clip_rect.ymin-=2;
clip_rect.xmax+=2;
clip_rect.ymax+=2;
if (clip_rect.xmin < viewPort.xmin) clip_rect.xmin = viewPort.xmin;
if (clip_rect.xmax < viewPort.xmin) clip_rect.xmax = viewPort.xmin;
if (clip_rect.ymin < viewPort.ymin) clip_rect.ymin = viewPort.ymin;
if (clip_rect.ymax < viewPort.ymin) clip_rect.ymax = viewPort.ymin;
if (clip_rect.xmax > viewPort.xmax) clip_rect.xmax = viewPort.xmax;
if (clip_rect.ymax > viewPort.ymax) clip_rect.ymax = viewPort.ymax;
if (clip_rect.xmin > viewPort.xmax) clip_rect.xmin = viewPort.xmax;
if (clip_rect.ymin > viewPort.ymax) clip_rect.ymin = viewPort.ymax;
}
void
GraphicDevice::setClipping(int value)
{
clipping = value;
if (clipping == 0) {
//printf("Clipping Off\n");
// Reset region
clip_rect.xmin = viewPort.xmin;
clip_rect.xmax = viewPort.xmax;
clip_rect.ymin = viewPort.ymin;
clip_rect.ymax = viewPort.ymax;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -