Mercurial > hg > dmlib
view dmlineclip.h @ 570:a26636faa6b7
Update copyright.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 05 Jan 2013 19:58:23 +0200 |
parents | 4ad2b9739c4a |
children |
line wrap: on
line source
/* Clip line coordinates. Return value: * = 0 : No clipping needed. * > 0 : Clipped. Line partially inside the clipping area. * < 0 : Line completely outside the clipping area. */ #ifndef DM_HEADER #define DM_CLIP_BITS(QB, QX, QY) \ do { \ QB = 0; \ if (QX < clipX0) QB |= CLIP_LEFT; \ else \ if (QX > clipX1) QB |= CLIP_RIGHT; \ \ if (QY < clipY0) QB |= CLIP_TOP; \ else \ if (QY > clipY1) QB |= CLIP_BOTTOM; \ } while (0) #define xA (fx0) #define xB (fx1) #define yA (fy0) #define yB (fy1) #endif #ifdef DM_CLIP_DEBUG #define CLIPDEB(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) #else #define CLIPDEB(fmt, ...) #endif int DM_CLIP_FUNC (SDL_Surface *screen, DM_COORD_TYPE *x0, DM_COORD_TYPE *y0, DM_COORD_TYPE *x1, DM_COORD_TYPE *y1) #ifdef DM_HEADER ; #else { const DM_COORD_TYPE clipX0 = screen->clip_rect.x, clipY0 = screen->clip_rect.y, clipX1 = clipX0 + screen->clip_rect.w - 1, clipY1 = clipY0 + screen->clip_rect.h - 1; double fx0 = *x0, fy0 = *y0, fx1 = *x1, fy1 = *y1; int clipA, clipB; DM_CLIP_BITS(clipA, xA, yA); DM_CLIP_BITS(clipB, xB, yB); CLIPDEB("-- clip [%1.3f, %1.3f - %1.3f, %1.3f] --\n", xA, yA, xB, yB); #if 1 // Cohen-Sutherland clipping method do { const int c = clipA ? clipA : clipB; DM_COORD_TYPE x, y; // The segment is inside? if ((clipA | clipB) == 0) { *x0 = fx0; *y0 = fy0; *x1 = fx1; *y1 = fy1; return 0; } // The line segment is outside of the clip region if (clipA & clipB) return -1; #ifdef DM_CLIP_DEBUG CLIPDEB "CLIP : "); if (c == clipA) CLIPDEB("A [%1.3f, %1.3f]\n", xA, yA); else CLIPDEB("B [%1.3f, %1.3f]\n", xB, yB); #endif if (c & CLIP_TOP) { if (yB - yA != 0) x = xA + ((clipY0 - yA) * (xB - xA)) / (yB - yA); else x = xA; y = clipY0; CLIPDEB("TOP : %1.3f, %1.3f\n", x, y); } else if (c & CLIP_BOTTOM) { if (yB - yA != 0) x = xA + ((clipY1 - yA) * (xB - xA)) / (yB - yA); else x = xA; y = clipY1; CLIPDEB("BOTTOM : %1.3f, %1.3f\n", x, y); } else if (c & CLIP_RIGHT) { if (xB - xA != 0) y = yA + ((clipX1 - xA) * (yB - yA)) / (xB - xA); else y = yA; x = clipX1; CLIPDEB("RIGHT : %1.3f, %1.3f\n", x, y); } else { if (xB - xA != 0) y = yA + ((clipX0 - xA) * (yB - yA)) / (xB - xA); else y = yA; x = clipX0; CLIPDEB("LEFT : %1.3f, %1.3f\n", x, y); } if (c == clipA) { xA = x; yA = y; DM_CLIP_BITS(clipA, xA, yA); } else { xB = x; yB = y; DM_CLIP_BITS(clipB, xB, yB); } } while (1); #else // Buyu-Skala clipping method const DM_COORD_TYPE dx = xB - xA; const DM_COORD_TYPE dy = yB - yA; float k, m; int z; switch (clipA + clipB) { case 1: if (clipA == 1) { xA = clipX0; yA = (clipX0 - xB) * dy / dx + yB; } else { xB = clipX0; yB = (clipX0 - xA) * dy / dx + yA; } break; case 3: k = dy / dx; yA = (clipX0 - xA) * k + yA; xA = clipX0; yB = (clipX1 - xB) * k + yB; xB = clipX1; break; case 5: k = dy / dx; z = (clipX0 - xA) * k + yA; if (z < clipY0) { switch (clipA) { case 0: xB = xB + (clipY0 - yB) / k; yB = clipY0; break; case 5: xA = xA + (clipY0 - yA) / k; yA = clipY0; break; default: return -1; /* the line segment is outside */ } } else { switch (clipA) { case 0: xB = clipX0; yB = z; break; case 1: xB = xB + (clipY0 - yB) / k; yB = clipY0; xA = clipX0; yA = z; break; case 4: xA = xA + (clipY0 - yA) / k; yA = clipY0; xB = clipX0; yB = z; break; case 5: xA = clipX0; yA = z; break; } } break; case 7: switch (clipA) { case 1: k = dy / dx; yA = (clipX0 - xB) * k + yB; if (yA < clipY0) return -1; /* the line segment is outside */ xA = clipX0; yB = (clipX1 - clipX0) * k + yA; if (yB < clipY0) { xB = (clipY0 - yB) / k + clipX1; yB = clipY0; } else xB = clipX1; break; /* similarly for cases clipA == 2, 5, 6 */ } case 15: switch (clipA) { case 5: if (dy * (clipX1 - clipX0) < dx * (clipY1 - clipY0)) { k = dy / dx; yA = (clipX0 - xB) * k + yB; if (yA > clipY1) return -1; /* the line segment is outside */ yB = (clipX1 - clipX0) * k + yA; if (yB < clipY0) return -1; /* the line segment is outside */ if (yA < clipY0) { xA = (clipY0 - yA) / k + clipX0; yA = clipY0; xB = clipX1; } else { xA = clipX0; if (yB > clipY1) { xB = (clipY1 - yB) / k + clipX1; yB = clipY1; } else xB = clipX1; } } else { m = dx / dy; xA = (clipY0 - yB) * m + xB; if (xA > clipX1) return -1; /* the line segment is outside */ xB = (clipY1 - clipY0) * m + xA; if (xB < clipX0) return -1; /* the line segment is outside */ if (xA < clipX0) { yA = (clipX0 - xA) / m + clipY0; xA = clipX0; yB = clipY1; } else { yA = clipY0; if (xB > clipX1) { yB = (clipX1 - xB) / m + clipY1; xB = clipX1; } else yB = clipY1; } } /* similarly for cases clipA == 6, 9, 10 */ } /* cases 2, 4, 8 are similar as case 1, cases 6, 9, 10 are similar as case 5 */ /* cases 11, 13, 14 are similar as case 7, case 12 is similar case 3 */ } /* of case clipA + clipB */ #endif return 1; } #undef DM_CLIP_BITS #undef xA #undef xB #undef yA #undef yB #undef CLIPDEB #endif #undef DM_CLIP_FUNC #undef DM_COORD_TYPE