Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. #include <stdbool.h>
  2.  
  3. #define NULL 0
  4. #include "palette.h"
  5. #include "libnsfb.h"
  6. #include "libnsfb_plot.h"
  7. #include "libnsfb_plot_util.h"
  8.  
  9. #include "nsfb.h"
  10.  
  11. enum {
  12.         POINT_LEFTOF_REGION = 1,
  13.         POINT_RIGHTOF_REGION = 2,
  14.         POINT_ABOVE_REGION = 4,
  15.         POINT_BELOW_REGION = 8,
  16. };
  17.  
  18. #define REGION(x,y,cx1,cx2,cy1,cy2) \
  19.     ( ( (y) > (cy2) ? POINT_BELOW_REGION : 0) |                         \
  20.       ( (y) < (cy1) ? POINT_ABOVE_REGION : 0) |                         \
  21.       ( (x) > (cx2) ? POINT_RIGHTOF_REGION : 0) |                       \
  22.       ( (x) < (cx1) ? POINT_LEFTOF_REGION : 0) )
  23.  
  24. #define SWAP(a, b) do { int t; t=(a); (a)=(b); (b)=t;  } while(0)
  25.  
  26. /* clip a rectangle with another clipping rectangle.
  27.  *
  28.  * @param clip The rectangle to clip to.
  29.  * @param rect The rectangle to clip.
  30.  * @return false if the \a rect lies completely outside the \a clip rectangle,
  31.  *         true if some of the \a rect is still visible.
  32.  */
  33. bool
  34. nsfb_plot_clip(const nsfb_bbox_t *  clip, nsfb_bbox_t *  rect)
  35. {
  36.         char region1;
  37.         char region2;
  38.  
  39.         if (rect->x1 < rect->x0) SWAP(rect->x0, rect->x1);
  40.  
  41.         if (rect->y1 < rect->y0) SWAP(rect->y0, rect->y1);
  42.  
  43.         region1 = REGION(rect->x0, rect->y0, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
  44.         region2 = REGION(rect->x1, rect->y1, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
  45.  
  46.         /* area lies entirely outside the clipping rectangle */
  47.         if ((region1 | region2) && (region1 & region2))
  48.                 return false;
  49.  
  50.         if (rect->x0 < clip->x0)
  51.                 rect->x0 = clip->x0;
  52.         if (rect->x0 > clip->x1)
  53.                 rect->x0 = clip->x1;
  54.  
  55.         if (rect->x1 < clip->x0)
  56.                 rect->x1 = clip->x0;
  57.         if (rect->x1 > clip->x1)
  58.                 rect->x1 = clip->x1;
  59.  
  60.         if (rect->y0 < clip->y0)
  61.                 rect->y0 = clip->y0;
  62.         if (rect->y0 > clip->y1)
  63.                 rect->y0 = clip->y1;
  64.  
  65.         if (rect->y1 < clip->y0)
  66.                 rect->y1 = clip->y0;
  67.         if (rect->y1 > clip->y1)
  68.                 rect->y1 = clip->y1;
  69.  
  70.         return true;
  71. }
  72.  
  73. bool
  74. nsfb_plot_clip_ctx(nsfb_t *nsfb, nsfb_bbox_t *  rect)
  75. {
  76.     return nsfb_plot_clip(&nsfb->clip, rect);
  77. }
  78.  
  79. /** Clip a line to a bounding box.
  80.  */
  81. bool nsfb_plot_clip_line(const nsfb_bbox_t *clip, nsfb_bbox_t *  line)
  82. {
  83.         char region1;
  84.         char region2;
  85.         region1 = REGION(line->x0, line->y0, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
  86.         region2 = REGION(line->x1, line->y1, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
  87.  
  88.         while (region1 | region2) {
  89.                 if (region1 & region2) {
  90.                         /* line lies entirely outside the clipping rectangle */
  91.                         return false;
  92.                 }
  93.  
  94.                 if (region1) {
  95.                         /* first point */
  96.                         if (region1 & POINT_BELOW_REGION) {
  97.                                 /* divide line at bottom */
  98.                                 line->x0 = (line->x0 + (line->x1 - line->x0) *
  99.                                        (clip->y1 - 1 - line->y0) / (line->y1 - line->y0));
  100.                                 line->y0 = clip->y1 - 1;
  101.                         } else if (region1 & POINT_ABOVE_REGION) {
  102.                                 /* divide line at top */
  103.                                 line->x0 = (line->x0 + (line->x1 - line->x0) *
  104.                                        (clip->y0 - line->y0) / (line->y1 - line->y0));
  105.                                 line->y0 = clip->y0;
  106.                         } else if (region1 & POINT_RIGHTOF_REGION) {
  107.                                 /* divide line at right */
  108.                                 line->y0 = (line->y0 + (line->y1 - line->y0) *
  109.                                        (clip->x1  - 1 - line->x0) / (line->x1 - line->x0));
  110.                                 line->x0 = clip->x1 - 1;
  111.                         } else if (region1 & POINT_LEFTOF_REGION) {
  112.                                 /* divide line at right */
  113.                                 line->y0 = (line->y0 + (line->y1 - line->y0) *
  114.                                        (clip->x0 - line->x0) / (line->x1 - line->x0));
  115.                                 line->x0 = clip->x0;
  116.                         }
  117.  
  118.                         region1 = REGION(line->x0, line->y0, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
  119.                 } else {
  120.                         /* second point */
  121.                         if (region2 & POINT_BELOW_REGION) {
  122.                                 /* divide line at bottom*/
  123.                                 line->x1 = (line->x0 + (line->x1 - line->x0) *
  124.                                        (clip->y1  - 1 - line->y0) / (line->y1 - line->y0));
  125.                                 line->y1 = clip->y1 - 1;
  126.                         } else if (region2 & POINT_ABOVE_REGION) {
  127.                                 /* divide line at top*/
  128.                                 line->x1 = (line->x0 + (line->x1 - line->x0) *
  129.                                        (clip->y0 - line->y0) / (line->y1 - line->y0));
  130.                                 line->y1 = clip->y0;
  131.                         } else if (region2 & POINT_RIGHTOF_REGION) {
  132.                                 /* divide line at right*/
  133.                                 line->y1 = (line->y0 + (line->y1 - line->y0) *
  134.                                        (clip->x1  - 1 - line->x0) / (line->x1 - line->x0));
  135.                                 line->x1 = clip->x1 - 1;
  136.                         } else if (region2 & POINT_LEFTOF_REGION) {
  137.                                 /* divide line at right*/
  138.                                 line->y1 = (line->y0 + (line->y1 - line->y0) *
  139.                                        (clip->x0 - line->x0) / (line->x1 - line->x0));
  140.                                 line->x1 = clip->x0;
  141.                         }
  142.  
  143.                         region2 = REGION(line->x1, line->y1, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
  144.                 }
  145.         }
  146.  
  147.         return true;
  148. }
  149.  
  150. bool nsfb_plot_clip_line_ctx(nsfb_t *nsfb, nsfb_bbox_t *  line)
  151. {
  152.     return nsfb_plot_clip_line(&nsfb->clip, line);
  153. }
  154.  
  155. /* documented in libnsfb_plot_util.h */
  156. bool
  157. nsfb_plot_add_rect(const nsfb_bbox_t *box1, const nsfb_bbox_t *box2, nsfb_bbox_t *result)
  158. {
  159.     /* lower x coordinate */
  160.     if (box1->x0 < box2->x0)
  161.         result->x0 = box1->x0;
  162.     else
  163.         result->x0 = box2->x0;
  164.  
  165.     /* lower y coordinate */
  166.     if (box1->y0 < box2->y0)
  167.         result->y0 = box1->y0;
  168.     else
  169.         result->y0 = box2->y0;
  170.  
  171.     /* upper x coordinate */
  172.     if (box1->x1 > box2->x1)
  173.         result->x1 = box1->x1;
  174.     else
  175.         result->x1 = box2->x1;
  176.  
  177.     /* upper y coordinate */
  178.     if (box1->y1 > box2->y1)
  179.         result->y1 = box1->y1;
  180.     else
  181.         result->y1 = box2->y1;
  182.  
  183.     return true;
  184. }
  185.  
  186. bool nsfb_plot_bbox_intersect(const nsfb_bbox_t *box1, const nsfb_bbox_t *box2)
  187. {
  188.     if (box2->x1 < box1->x0)
  189.         return false;
  190.  
  191.     if (box2->y1 < box1->y0)
  192.         return false;
  193.  
  194.     if (box2->x0 > box1->x1)
  195.         return false;
  196.  
  197.     if (box2->y0 > box1->y1)
  198.         return false;
  199.  
  200.     return true;
  201. }
  202.