📄 gxj_putpixel.c
字号:
* the exact pixel locations x1,y1 is computed if the leading pixels are clipped * (CLIPPED), the correct major axis ending pixel (+1) is computed xyEnd, * the exact initial Bresenham decision variable and increments (incX,incY) are * computed for clipping and finally an octant flag (REFLECT) is returned if * the segment is on a major Y axis. * * NOTE: Some values (adjIncX,adjIncY) may be changed before OUTSIDE is returned. * IMPL_NOTE: Does MIDP require reversibility, a line (x1,y1)<->(x2,y2) produce * the same set of pixels in both directions? */static intSetUpClippedLineParams(int *x1, int *y1, int x2, int y2, int *xyEnd, int *decision, int *incrY, int *incrX, int *adjIncX, int *adjIncY, const jshort *clip) { int lineX, lineY, lineEnd, deltaX, deltaY, deltaXtimes2, deltaYtimes2; int lineX1 = *x1; int lineX2 = x2; int lineY1 = *y1; int lineY2 = y2; int clipX1 = clip[0]; int clipX2 = clip[2]-1; int clipY1 = clip[1]; int clipY2 = clip[3]-1; int ret = INSIDE; int tmp, remainder, error; /* empty clip test */ if ((clipX1 > clipX2) || (clipY1 > clipY2)) return OUTSIDE; /* start clip testing X axis */ if (lineX1 < lineX2) { if ((lineX1 > clipX2) || (lineX2 < clipX1)) return OUTSIDE; /* line is in octant 1,2,7 or 8 */ *adjIncX = 1; } else { if ((lineX2 > clipX2) || (lineX1 < clipX1)) return OUTSIDE; /* line is in octant 3,4,5, or 6 */ *adjIncX = -1; lineX1 = -lineX1; lineX2 = -lineX2; clipX1 = -clipX1; clipX2 = -clipX2; SWAP(clipX1, clipX2); } /* start clip testing Y axis */ if (lineY1 < lineY2) { if ((lineY1 > clipY2) || (lineY2 < clipY1)) return OUTSIDE; /* line is in octant 1 or 2 */ *adjIncY = 1; } else { if ((lineY2 > clipY2) || (lineY1 < clipY1)) return OUTSIDE; /* line is in octant 7 or 8 */ *adjIncY = -1; lineY1 = -lineY1; lineY2 = -lineY2; clipY1 = -clipY1; clipY2 = -clipY2; SWAP(clipY1, clipY2); } /* line has been rotated into octant 1 or 2 * now calculate the bresenham terms */ deltaX = lineX2 - lineX1; deltaY = lineY2 - lineY1; if (deltaX < deltaY) { /* line is in octant 2, reflect into octant 1 */ ret |= REFLECT; SWAP(lineX1,lineY1); SWAP(lineX2,lineY2); SWAP(deltaX,deltaY); SWAP(clipX1,clipY1); SWAP(clipX2,clipY2); SWAP(*adjIncX,*adjIncY); } if (deltaX == 0) { /* point at x1, y1 */ return POINT; } if (deltaY == 0) { ret |= HORIZONTAL; lineX = (lineX1 < clipX1) ? clipX1 : lineX1; lineY = lineY1; lineEnd = lineX2; deltaXtimes2 = 0; deltaYtimes2 = 0; error = -1; goto SimpleClipTail; } /* IMPL_NOTE: Adjust error by bias (per octant 0/-1) * to produce symetric line patterns */ deltaXtimes2 = 2*deltaX; deltaYtimes2 = 2*deltaY; lineX = lineX1; lineY = lineY1; error = deltaYtimes2 - deltaX; lineEnd = lineX2; /* determine where line enters clip */ if (lineY1 < clipY1) { ret |= CLIPPED; tmp = deltaXtimes2*(clipY1-lineY1)-deltaX; lineX += tmp/deltaYtimes2; remainder = tmp%deltaYtimes2; if (lineX > clipX2) return OUTSIDE; if (lineX/*+1*/ >= clipX1) { lineY = clipY1; error -= remainder + deltaX; if (remainder > 0) { lineX += 1; error += deltaYtimes2; } goto ClipTail; } } if (lineX1 < clipX1) { ret |= CLIPPED; tmp = deltaYtimes2*(clipX1-lineX1); lineY += tmp/deltaXtimes2; remainder = tmp%deltaXtimes2; if ((lineY > clipY2) || (lineY == clipY2 && remainder >= deltaX)) return OUTSIDE; lineX = clipX1; error += remainder; if (remainder >= deltaX) { lineY += 1; error -= deltaXtimes2; } }ClipTail: /* clip the tail of the line */ if (lineY2 > clipY2) { tmp = deltaXtimes2*(clipY2-lineY1)+deltaX; lineEnd = lineX1+tmp/deltaYtimes2; remainder = tmp%deltaYtimes2; if (remainder == 0) /* direct hit on pixel */ lineEnd -= 1; } deltaXtimes2 -= deltaYtimes2;SimpleClipTail: if (lineEnd > clipX2) lineEnd = clipX2; lineEnd += 1; /* reflect line coordinates back into original quadrant */ if (*adjIncY < 0) lineY = -lineY; if (*adjIncX < 0) { lineX = -lineX; lineEnd = -lineEnd; } *x1 = lineX; *y1 = lineY; *xyEnd = lineEnd; *incrY = deltaXtimes2; *incrX = deltaYtimes2; *decision = error; return ret;}/** * Generates pixels for line segments that match the MIDP * specification. This function generates the set of pixels between * (x1,y1) -> (x2,y2) inclusive, in the order specified. The * function uses the Bresenham midpoint algorithm. The set of * pixels generated is within the bounds (CLIP_X1,CLIP_Y1) -> * (CLIP_X2-1,CLIP_Y2-1). For DOTTED lines the set of generated * pixels is a subset of the pixels generated for SOLID. The * affect of clipping a DOTTED line is to generate the set of pixels * unclipped and then to remove the pixels beyond the clip bounds. * The maximum and minumum values of pixels and clip bounds are * constrained to avoid an overflow during line segment to clip * bounds calculations. * * @param sbuf Virtual Device Context passed to primDrawPixel * @param color gxj_pixel_type value for generated pixels * @param lineStyle SOLID to generate all pixels or DOTTED for a subset * @param x1,y1 coordinate of first pixel generated must be * between (-32768 to 32767) inclusive * @param x2,y2 coordinate of the last pixel generated must be * between (-32768 to 32767) inclusive * @param clip ->clipX1,clipY1,clipX2,clipY2 bounds must be * between (0 to 32767) inclusive * * Clip constraints: (per the MIDP specification) * if clipX2-1 is less than clipX1 or * if clipY2-1 is less than clipY1 then * the clip bounds are empty and no pixels are generated * */voiddraw_clipped_line(gxj_screen_buffer *sbuf, gxj_pixel_type color, int lineStyle, const jshort *clip, int x1, int y1, int x2, int y2) { int incrY, incrX, decision; int adjIncX, adjIncY; int xyEnd; int ret; int *ptrX, *ptrY; dotted_draw_state dds; /* for lineStyle == DOTTED */ int x0 = x1; int y0 = y1; CHECK_SBUF_CLIP_BOUNDS(sbuf, clip); ret = SetUpClippedLineParams(&x1, &y1, x2, y2, &xyEnd, &decision, &incrY, &incrX, &adjIncX, &adjIncY, clip); if (ret == OUTSIDE) return; if (ret & POINT) { PRIMDRAWPIXEL(sbuf, color, x1, y1); return; } if (ret & REFLECT) { ptrX = &y1; ptrY = &x1; } else { ptrX = &x1; ptrY = &y1; } if (lineStyle == SOLID) { if ((ret & (HORIZONTAL|REFLECT)) == (HORIZONTAL|REFLECT)) { CHECK_XY_CLIP(sbuf, *ptrX, *ptrY); CHECK_XY_CLIP(sbuf, *ptrX, xyEnd-adjIncX); primDrawVertLine(sbuf, color, *ptrX, *ptrY, *ptrX, xyEnd-adjIncX); return; } if (ret & HORIZONTAL) { CHECK_XY_CLIP(sbuf, *ptrX, *ptrY); CHECK_XY_CLIP(sbuf, xyEnd-adjIncX, *ptrY); primDrawHorzLine(sbuf, color, *ptrX, *ptrY, xyEnd-adjIncX, *ptrY); return; } /* The combination of adjIncX/adjIncY (+1 or -1) * and REFLECT allow us to use the single octant * version of the loop for all octants. */ while (x1 != xyEnd) { PRIMDRAWPIXEL(sbuf, color, *ptrX, *ptrY); if (decision >= 0) { y1 += adjIncY; decision -= incrY; } else { decision += incrX; } x1 += adjIncX; } return; } dds = START_STROKE; if (ret & CLIPPED) { /* compute the offset into pattern compensating for clip */ dds.solidcount = (ret & REFLECT) ? y1 - y0 : x1 - x0; if (dds.solidcount < 0) dds.solidcount = -dds.solidcount; dds.solidcount %= (DOTTED_SOLID_SIZE+DOTTED_EMPTY_SIZE); if (dds.solidcount >= DOTTED_SOLID_SIZE) { dds.drawing = FALSE; dds.emptycount = dds.solidcount-DOTTED_SOLID_SIZE; dds.solidcount = 0; } } while (x1 != xyEnd) { drawDottedPixel(sbuf, color, *ptrX, *ptrY, &dds); if (decision >= 0) { y1 += adjIncY; decision -= incrY; } else { decision += incrX; } x1 += adjIncX; } return;}/** * draw pixels from (x1,y1) through (x1,y2) * y1 should be <= y2, x1 == x2 * coordinates are clipped against the clip */static voiddrawClippedVertLine(const jshort *clip, gxj_screen_buffer *sbuf, gxj_pixel_type color, int x1, int y1, int x2, int y2) { const jshort clipX1 = clip[0]; const jshort clipY1 = clip[1]; const jshort clipX2 = clip[2]; const jshort clipY2 = clip[3]; (void)x2; if (y1 >= clipY2 || y2 < clipY1 || x2 < clipX1 || x1 >= clipX2) return; y1 = (y1 < clipY1) ? clipY1 : y1; y2 = (y2 >= clipY2) ? clipY2-1 : y2; CHECK_XY_CLIP(sbuf, x1, y1); CHECK_XY_CLIP(sbuf, x1, y2); primDrawVertLine(sbuf, color, x1, y1, x1, y2);}/** * draw pixels from (x1,y1) through (x2,y1) * x1 should be <= x2, y1 == y2 * coordinates are clipped against the clip */static voiddrawClippedHorzLine(const jshort *clip, gxj_screen_buffer *sbuf, gxj_pixel_type color, int x1, int y1, int x2, int y2) { const jshort clipX1 = clip[0]; const jshort clipY1 = clip[1]; const jshort clipX2 = clip[2]; const jshort clipY2 = clip[3]; (void)y2; if (x1 >= clipX2 || x2 < clipX1 || y1 < clipY1 ||y1 >= clipY2) return; x1 = (x1 < clipX1) ? clipX1 : x1; x2 = (x2 >= clipX2) ? clipX2-1 : x2; CHECK_XY_CLIP(sbuf, x1, y1); CHECK_XY_CLIP(sbuf, x2, y1); primDrawHorzLine(sbuf, color, x1, y1, x2, y1);}/** * Evaluate dotted stroke parameters for the point distant * from the current one by specified number of pixels. * The current point is presented with its stroke state, * i.e. with dds structure (solidcount, emptycount & drawing). * * Note, that stroke can be either solid, or empty line, * while unstroke is considered as a line of the opposite type, * i.e. empty or solid accordingly. * * @param nPixels number of pixels from the current point * @param stroke pointer to the number of pixels drawn already for the * current stroke, on exit from the method will be evaluated for the * distant point * @param unstroke if the distant point belongs to a stroke of the * opposite type than the current point has, this parameter will * refer to number of pixels already drawn in the distant stroke, * otherwise it will refer to 0. * @param drawing refers to the stroke type of the current point, * on return refers to the stroke type of the distant point * @param DOTTED_STROKE_SIZE fixed stroke size of the current stroke type * @param DOTTED_UNSTROKE_SIZE fixed size of the stroke type opposite * to the current stroke type */static voidSetUpDottedStrokeParamsByPixels(int nPixels, /*INOUT*/ int *stroke, /*OUT*/ int *unstroke, /*INOUT*/ int *drawing, const int DOTTED_STROKE_SIZE, const int DOTTED_UNSTROKE_SIZE) { if (nPixels > DOTTED_STROKE_SIZE - *stroke) { int offset = (nPixels - DOTTED_STROKE_SIZE + *stroke) % (DOTTED_STROKE_SIZE + DOTTED_UNSTROKE_SIZE); if (offset < DOTTED_UNSTROKE_SIZE) { *drawing = !(*drawing); *unstroke = offset; *stroke = 0; } else { *stroke = offset - DOTTED_UNSTROKE_SIZE; *unstroke = 0; } } else { *stroke += nPixels; *unstroke = 0; }}/** * Init dotted stroke params for the point distant from * the current point by specified number of pixels. * The current point state is presented by dds. */static voidSetUpDottedParamsByPixels(int nPixels, dotted_draw_state * dds) { if (dds->drawing) { SetUpDottedStrokeParamsByPixels(nPixels, &dds->solidcount, &dds->emptycount, &dds->drawing, DOTTED_SOLID_SIZE, DOTTED_EMPTY_SIZE); } else { SetUpDottedStrokeParamsByPixels(nPixels, &dds->emptycount, &dds->solidcount, &dds->drawing, DOTTED_EMPTY_SIZE, DOTTED_SOLID_SIZE); }}/** * draw dotted pixels from (x1,y1) through (x1,y2) * y1 should be <= y2, x1 == x2 * coordinates are clipped against the clip */static voiddrawClippedDottedVertLine(const jshort *clip, gxj_screen_buffer *sbuf, gxj_pixel_type color, int x1, int y1, int x2, int y2, dotted_draw_state dds) { const jshort clipX1 = clip[0]; const jshort clipY1 = clip[1]; const jshort clipX2 = clip[2]; const jshort clipY2 = clip[3]; (void)x2; if (y1 >= clipY2 || y2 < clipY1 || x2 < clipX1 || x1 >= clipX2) return; if (y1 < clipY1) { SetUpDottedParamsByPixels(clipY1 - y1, &dds); y1 = clipY1; } y2 = (y2 >= clipY2) ? clipY2-1 : y2; CHECK_XY_CLIP(sbuf, x1, y1); CHECK_XY_CLIP(sbuf, x1, y2); drawDottedVertLine(sbuf, color, x1, y1, x1, y2, dds);}/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -