home *** CD-ROM | disk | FTP | other *** search
- /**
- ** THICKLNE.C
- **
- ** Copyright (C) 1992, Csaba Biegl
- ** 820 Stirrup Dr, Nashville, TN, 37221
- ** csaba@vuse.vanderbilt.edu
- **
- ** This file is distributed under the terms listed in the document
- ** "copying.cb", available from the author at the address above.
- ** A copy of "copying.cb" should accompany this file; if not, a copy
- ** should be available from where this file was obtained. This file
- ** may not be distributed without a verbatim copy of "copying.cb".
- ** You should also have received a copy of the GNU General Public
- ** License along with this program (it is in the file "copying");
- ** if not, write to the Free Software Foundation, Inc., 675 Mass Ave,
- ** Cambridge, MA 02139, USA.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **/
-
- #include "grx.h"
- #include "libgrx.h"
- #include "clipping.h"
- #include "thicklne.h"
-
- void _GrBuildCustomLineData(GrLineOption *opt,GrCustomLineData *where)
- {
- int total,ii;
-
- where->opt = *opt;
- if(opt->lno_pattlen > 1) {
- for(total = 0,ii = opt->lno_pattlen; --ii >= 0; total += opt->lno_dashpat[ii]);
- where->total_pattlen = total;
- where->next_sect = 0;
- where->cursect_left = 0;
- where->drawn_sect = FALSE;
- }
- else where->total_pattlen = 0;
- }
-
- extern void _GrDoCustomSegment(int x1,int y1,int x2,int y2,void *arg)
- {
- #define DIAG(x,y) ((x)*(x) + (y)*(y))
-
- GrCustomLineData *dta = (GrCustomLineData *)arg;
- int dx1,dy1,dx2,dy2; /* offsets to corner points of thick line segment */
- int sx1,sx2,sy1,sy2,length; /* line segment length and end points */
- int pts[4][2]; /* polygon corner points */
- int dx = x2 - x1;
- int dy = y2 - y1;
- int wdt = dta->opt.lno_width;
- int Xmajor = (IABS(dx) > IABS(dy)) ? TRUE : FALSE;
- int done;
-
- if(wdt > 1) {
- int wsq = wdt * wdt;
- if(dx == 0) {
- dy2 = 0;
- dx2 = wdt;
- }
- else if(dy == 0) {
- dx2 = 0;
- dy2 = wdt;
- }
- else if(Xmajor) {
- dy1 = ((7 * wdt) / 10) - 1; /* at least !! (tangent is less than 45 deg) */
- dx1 = -(dy1 * dy) / dx; /* scale according to slope */
- for( ; ; ) {
- dy2 = dy1 + 1;
- dx2 = -(dy2 * dy) / dx;
- if(DIAG(dx2,dy2) > wsq) break;
- dx1 = dx2;
- dy1 = dy2;
- }
- if((DIAG(dx2,dy2) - wsq) > (wsq - DIAG(dx1,dy1))) {
- dx2 = dx1;
- dy2 = dy1;
- }
- }
- else {
- dx1 = ((7 * wdt) / 10) - 1; /* at least !! (tangent is more than 45 deg) */
- dy1 = -(dx1 * dx) / dy; /* scale according to slope */
- for( ; ; ) {
- dx2 = dx1 + 1;
- dy2 = -(dx2 * dx) / dy;
- if(DIAG(dx2,dy2) > wsq) break;
- dx1 = dx2;
- dy1 = dy2;
- }
- if((DIAG(dx2,dy2) - wsq) > (wsq - DIAG(dx1,dy1))) {
- dx2 = dx1;
- dy2 = dy1;
- }
- }
- dx1 = dx2 >> 1;
- dy1 = dy2 >> 1;
- dx2 = dx1 - dx2;
- dy2 = dy1 - dy2;
- }
- if((dta->total_pattlen == 0) || ((dx == 0) && (dy == 0))) {
- if(wdt <= 1) {
- (*dta->borderproc)(x1,y1,x2,y2,dta->fillarg);
- return;
- }
- pts[0][0] = x1 + dx1;
- pts[0][1] = y1 + dy1;
- pts[1][0] = x1 + dx2;
- pts[1][1] = y1 + dy2;
- pts[2][0] = x2 + dx2;
- pts[2][1] = y2 + dy2;
- pts[3][0] = x2 + dx1;
- pts[3][1] = y2 + dy1;
- _GrScanConvexPoly(4,pts,
- dta->is_XOR_color,
- dta->pixelproc,
- dta->borderproc,
- dta->scanfillproc,
- dta->fillarg
- );
- return;
- }
- sx1 = x1;
- sy1 = y1;
- done = FALSE;
- while(!done) {
- if((length = dta->cursect_left) == 0) do {
- if(dta->next_sect == dta->opt.lno_pattlen) {
- dta->next_sect = 0;
- dta->drawn_sect = FALSE;
- }
- length = dta->opt.lno_dashpat[dta->next_sect++];
- dta->drawn_sect ^= 1;
- } while(length == 0);
- else dta->cursect_left = 0;
- if(Xmajor) {
- if(dx < 0) {
- if((sx2 = sx1 - length) <= x2) {
- dta->cursect_left = x2 - sx2;
- length = sx1 - (sx2 = x2);
- done = TRUE;
- }
- else sx2++;
- }
- else {
- if((sx2 = sx1 + length) >= x2) {
- dta->cursect_left = sx2 - x2;
- length = (sx2 = x2) - x1;
- done = TRUE;
- }
- else sx2--;
- }
- sy1 = y1 + (((sx1 - x1) * dy) / dx);
- sy2 = y1 + (((sx2 - x1) * dy) / dx);
- }
- else {
- if(dy < 0) {
- if((sy2 = sy1 - length) <= y2) {
- dta->cursect_left = y2 - sy2;
- length = sy1 - (sy2 = y2);
- done = TRUE;
- }
- else sy2++;
- }
- else {
- if((sy2 = sy1 + length) >= y2) {
- dta->cursect_left = sy2 - y2;
- length = (sy2 = y2) - y1;
- done = TRUE;
- }
- else sy2--;
- }
- sx1 = x1 + (((sy1 - y1) * dx) / dy);
- sx2 = x1 + (((sy2 - y1) * dx) / dy);
- }
- if(dta->drawn_sect && (length > 0)) {
- if(wdt <= 1)
- (*dta->borderproc)(sx1,sy1,sx2,sy2,dta->fillarg);
- else {
- pts[0][0] = sx1 + dx1;
- pts[0][1] = sy1 + dy1;
- pts[1][0] = sx1 + dx2;
- pts[1][1] = sy1 + dy2;
- pts[2][0] = sx2 + dx2;
- pts[2][1] = sy2 + dy2;
- pts[3][0] = sx2 + dx1;
- pts[3][1] = sy2 + dy1;
- _GrScanConvexPoly(4,pts,
- dta->is_XOR_color,
- dta->pixelproc,
- dta->borderproc,
- dta->scanfillproc,
- dta->fillarg
- );
- }
- }
- if(Xmajor) {
- if(dx < 0) sx1 -= length;
- else sx1 += length;
- }
- else {
- if(dy < 0) sy1 -= length;
- else sy1 += length;
- }
- }
- }
-
- extern void _GrDoSingleCustomSegment(int x1,int y1,int x2,int y2,GrCustomLineData *dta)
- {
- int minx = x1,maxx = x2;
- int miny = y1,maxy = y2;
- MOUSE_FLAG;
-
- SORT2(minx,maxx);
- SORT2(miny,maxy);
- if(dta->opt.lno_width > 1) {
- minx -= dta->opt.lno_width;
- maxx += dta->opt.lno_width;
- miny -= dta->opt.lno_width;
- maxy += dta->opt.lno_width;
- }
- CLIPSORTEDBOX(CURC,minx,miny,maxx,maxy);
- MOUSE_BLOCK(CURC,minx,miny,maxx,maxy);
- _GrDoCustomSegment(x1,y1,x2,y2,dta);
- MOUSE_UNBLOCK();
- }
-