⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 region.cc

📁 Algorithms for Image Processing and Computer Vision Source Code
💻 CC
字号:
/* This is file REGION.CC */
/*
** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
**
** This file is distributed under the terms listed in the document
** "copying.dj", available from DJ Delorie at the address above.
** A copy of "copying.dj" 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.dj".
**
** This file is distributed WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

/* History:251,33 */
#include <std.h>
#include <sys/registers.h>
#include "graphics.h"

static GrRegion *screen_region = 0;
extern int _GrCurMode;

static void SetModeHook()
{
  screen_region->width = GrSizeX();
  screen_region->height = GrSizeY();
  screen_region->row_scale = GrSizeX();
  screen_region->data = (unsigned char *)0xd0000000;
  screen_region->rdata = (unsigned char *)0xd0100000;
  screen_region->wdata = (unsigned char *)0xd0200000;
}

extern int _GrSetModeHook;


GrRegion *GrScreenRegion()
{
  if (_GrCurMode < GR_320_200_graphics)
    GrSetMode(GR_default_graphics);
  if (!screen_region)
    screen_region = new GrRegion();
  _GrSetModeHook = (int)SetModeHook;
  SetModeHook();
  return screen_region;
}

GrRegion::GrRegion()
{
  flags = width = height = row_scale = 0;
  rdata = wdata = data = 0;
  parent = 0;
  rel_x = rel_y = abs_x = abs_y = 0;
  color = GrWhite();
}

GrRegion::GrRegion(int w, int h)
{
  flags = 1;
  rdata = wdata = data = (unsigned char *)malloc(w*h);
  bzero(data,w*h);
  width = w;
  height = h;
  row_scale = w;
  color = GrWhite();
  parent = 0;
  rel_x = rel_y = abs_x = abs_y = 0;
}

GrRegion::~GrRegion()
{
  if (flags && data)
    free(data);
}

GrRegion *GrRegion::SubRegion(int x, int y, int w, int h)
{
  if (!data) return 0;
  GrRegion *tmp = new GrRegion();
  if (!tmp) return 0;
  if ((x < 0) || (y < 0))
    return tmp;
  if ((x >= width) || (y >= height))
    return tmp;
  if (x+w > width)
    w = width - x;
  if (y+h > height)
    h = height - y;
  tmp->parent = this;
  tmp->rel_x = x;
  tmp->rel_y = y;
  tmp->abs_x = x + rel_x;
  tmp->abs_y = y + rel_y;
  tmp->data = data + y*row_scale + x;
  tmp->rdata = rdata + y*row_scale + x;
  tmp->wdata = wdata + y*row_scale + x;
  tmp->width = w;
  tmp->height = h;
  tmp->row_scale = row_scale;
  return tmp;
}

int GrRegion::MaxX()
{
  return width-1;
}

int GrRegion::MaxY()
{
  return height-1;
}

int GrRegion::SizeX()
{
  return width;
}

int GrRegion::SizeY()
{
  return height;
}

void GrRegion::Plot(int x, int y, int c)
{
  if (!data) return;
  if (c == -1) c = color;
  if ((x < 0) || (y < 0) || (x >= width) || (y >= height))
    return;
  if (c & 0x100)
    data[x+y*row_scale] ^= c;
  else
    data[x+y*row_scale] = c;
}

/** Test a single point to be within the xleft,xright,ybot,ytop bbox.
 ** Sets the returned integers 4 l.s.b. as follows:
 ** bit 0 if to the left of xleft.
 ** bit 1 if to the right of xright.
 ** bit 2 if above of ytop.
 ** bit 3 if below of ybot.
 ** 0 is returned if inside.
 */
static inline int clipPoint(int x, int y, int width, int height)
{
  int ret_val = 0;

  if (x < 0) ret_val |= 0x01;
  if (x > width) ret_val |= 0x02;
  if (y < 0) ret_val |= 0x04;
  if (y > height) ret_val |= 0x08;

  return ret_val;
}

/**
 ** Draw a line assumed to be clipped with respect to current region.
 **/
static void drawClippedLine(GrRegion *Region,
			    int x1, int y1, int x2, int y2, int c)
{
  unsigned char *d = &Region->data[x1+y1*Region->row_scale];

  if (c == -1) c = Region->color;

  if (x1 == x2)
  {
    Region->VLine(x1, y1, y2, c);
    return;
  }
  if (y1 == y2)
  {
    Region->HLine(x1, x2, y1, c);
    return;
  }

  int dx, dy, sx, sy;
  int count;
  int brc, brmax;

  sx = 1;
  sy = Region->row_scale;
  dx = x2 - x1;
  dy = y2 - y1;
  if (dx < 0)
  {
    dx = -dx;
    sx = -sx;
  }
  if (dy < 0)
  {
    dy = -dy;
    sy = -sy;
  }

  if (c & 0x100)
    *d ^= c;
  else
    *d = c;

  if (dx > dy)
  {
    brmax = dx;
    brc = dx / 2;

    for (count = dx; count; count--)
    {
      d += sx;
      brc += dy;
      if (brc > brmax)
      {
        brc -= dx;
        d += sy;
      }

      if (c & 0x100)
        *d ^= c;
      else
        *d = c;
    }
  }
  else
  {
    brmax = dy;
    brc = dy / 2;

    for (count = dy; count; count--)
    {
      d += sy;
      brc += dx;
      if (brc > brmax)
      {
        brc -= dy;
        d += sx;
      }

      if (c & 0x100)
        *d ^= c;
      else
        *d = c;
    }
  }
}

static inline int min(int x1, int x2)
{
  return x1 < x2 ? x1 : x2;
}

static inline int max(int x1, int x2)
{
  return x1 > x2 ? x1 : x2;
}

/** Clip and draw the given line to viewport defined using clipX/Y/min/max.
 **   This routine uses the cohen & sutherland bit mapping for fast clipping -
 ** see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
 */
static void clipLine(GrRegion *Region, int x1, int y1, int x2, int y2, int c)
{
  int x, y, x_intr[4], y_intr[4], count, pos1, pos2,
    width = Region->width - 1,
    height = Region->height - 1;
  long dx, dy;

  pos1 = clipPoint(x1, y1, width, height);
  pos2 = clipPoint(x2, y2, width, height);

  if (pos1 || pos2) {
    int x_max, x_min, y_max, y_min;

    if (pos1 & pos2) return;		  /* segment is totally out. */

    x_min = min(x1, x2);
    x_max = max(x1, x2);
    y_min = min(y1, y2);
    y_max = max(y1, y2);

    /* Compute a bound on extrema of clipped line. */
    x_min = max(x_min, 0);
    x_max = min(x_max, width);
    y_min = max(y_min, 0);
    y_max = min(y_max, height);

    /* Here part of the segment MAY be inside. test the intersection
     * of this segment with the 4 boundaries for hopefully 2 intersections
     * in. If non found segment is totaly out.
     */
    count = 0;
    dx = (long) (x2 - x1);
    dy = (long) (y2 - y1);

    /* Find intersections with the x parallel bbox lines: */
    if (dy != 0) {
      if (0 == y_min) {		    	    /* Test clipYmin boundary. */
	x = (int) (-y2 * dx / dy + x2);

	if (x >= x_min && x <= x_max) {
	  x_intr[count] = x;
	  y_intr[count++] = 0;
        }
      }
      if (height == y_max) {		    /* Test clipYmax boundary. */
	x = (int) ((height - y2) * dx / dy + x2);

	if (x >= x_min && x <= x_max) {
	  x_intr[count] = x;
	  y_intr[count++] = height;
	}
      }
    }

    /* Find intersections with the y parallel bbox lines: */
    if (dx != 0) {
      if (0 == x_min) {		            /* Test clipXmin boundary. */
	y = (int) (-x2 * dy / dx + y2);

	if (y >= y_min && y <= y_max) {
	  x_intr[count] = 0;
	  y_intr[count++] = y;
	}
      }
      if (width == x_max) {		    /* Test clipXmax boundary. */
	y = (int) ((width - x2) * dy / dx + y2);

	if (y >= y_min && y <= y_max) {
	  x_intr[count] = width;
	  y_intr[count++] = y;
	}
      }
    }

    if (count >= 2) {
      if (pos1 && pos2) {	               /* Both were out - update both. */
	x1 = x_intr[0];
	y1 = y_intr[0];
	x2 = x_intr[1];
	y2 = y_intr[1];
      }
      else if (pos1) {	       /* Only x1/y1 was out - update only it. */
	if (dx * (x2 - x_intr[0]) + dy * (y2 - y_intr[0]) > 0) {
	  x1 = x_intr[0];
	  y1 = y_intr[0];
	}
	else {
	  x1 = x_intr[1];
	  y1 = y_intr[1];
	}
      }
      else {	       	       /* Only x2/y2 was out - update only it. */
	if (dx * (x_intr[0] - x1) + dy * (y_intr[0] - x1) > 0) {
	  x2 = x_intr[0];
	  y2 = y_intr[0];
	}
        else {
	  x2 = x_intr[1];
	  y2 = y_intr[1];
	}
      }
    }
    else if (count == 1) {
      if (pos1) {		       /* Only x1/y1 was out - update only it. */
	x1 = x_intr[0];
	y1 = y_intr[0];
      }
      else {	       	       /* Only x2/y2 was out - update only it. */
	x2 = x_intr[0];
	y2 = y_intr[0];
      }
    }
    else {		    /* Count = 0 which means the lines is totally out. */
      return;
    }

    if (x1 < x_min || x1 > x_max ||
        x2 < x_min || x2 > x_max ||
	y1 < y_min || y1 > y_max ||
	y2 < y_min || y2 > y_max) {
      /* This is extreme and rare case in which integer round off causes */
      /* no trimming in one direction.				         */

      /* Eliminate the trivial cases in which the line end point is on   */
      /* the viewport boundary and the line is totally out.	         */
      if ((x1 <= x_min && x2 <= x_min) ||
	  (x1 >= x_max && x2 >= x_max) ||
	  (y1 <= y_min && y2 <= y_min) ||
	  (y1 >= y_max && y2 >= y_max))
	return;

      /* Otherwise try to clip again... */
      clipLine(Region, x1, y1, x2, y2, c);
      return;
    }
  }

  drawClippedLine(Region, x1, y1, x2, y2, c);
}

void GrRegion::Line(int x1, int y1, int x2, int y2, int c)
{
  if (!data) return;
  if (c == -1) c = color;

  if (x1 == x2)
    VLine(x1, y1, y2, c);
  else if (y1 == y2)
    HLine(x1, x2, y1, c);
  else
    clipLine(this, x1, y1, x2, y2, c);
}

void GrRegion::HLine(int x1, int x2, int y, int c)
{
  if (!data) return;
  if (c == -1) c = color;
  if ((y < 0) || (y >= height))
    return;
  if (x1 > x2)
  {
    x1 ^= x2; x2 ^= x1; x1 ^= x2;
  }
  if ((x1 >= width) || (x2 < 0))
    return;
  if (x1 < 0) x1 = 0;
  if (x2 >= width) x2 = width - 1;
  if (c & 0x100)
  {
    register int cnt=x2-x1+1;
    register unsigned char *ptr = data+x1+y*row_scale;
    while(cnt--)
      *ptr++ ^= c;
  }
  else
    memset(data + x1 + y * row_scale, c, x2 - x1 + 1);
}

void GrRegion::VLine(int x, int y1, int y2, int c)
{
  if (!data) return;
  if (c == -1) c = color;
  if ((x < 0) || (x >= width))
    return;
  if (y1 > y2)
  {
    y1 ^= y2; y2 ^= y1; y1 ^= y2;
  }
  if ((y1 >= height) || (y2 < 0))
    return;
  if (y1 < 0) y1 = 0;
  if (y2 >= height) y2 = height-1;
  register unsigned char *ptr = data + y1 * row_scale + x;
  register int yc=y2-y1+1;
  register int rs = row_scale;
  if (c & 0x100)
  {
    for (; yc; yc--, ptr+=rs)
      *ptr ^= c;
  }
  else
  {
    for (; yc; yc--, ptr+=rs)
      *ptr = c;
  }
}

void GrRegion::Rectangle(int x1, int y1, int x2, int y2, int c)
{
  if (!data) return;
  if (c == -1) c = color;
  if (x1 > x2)
  {
    x1 ^= x2; x2 ^= x1; x1 ^= x2;
  }
  if (y1 > y2)
  {
    y1 ^= y2; y2 ^= y1; y1 ^= y2;
  }
  if ((x1 == x2) || (y1 == y2))
  {
    Line(x1, y1, x2, y2, c);
    return;
  }
  Line(x1, y1, x2, y1, c);	// top
  Line(x1, y1+1, x1, y2, c);	// left
  Line(x2, y1+1, x2, y2, c);	// right
  Line(x1+1, y2, x2-1, y2, c);	// botton
}

void GrRegion::Box(int x, int y, int w, int h, int c)
{
  if (!data) return;
  if (c == -1) c = color;
  if (x < 0)
  {
    w += x;
    x = 0;
  }
  if (y < 0)
  {
    h += y;
    y = 0;
  }
  if (x > width)
    return;
  if (y > height)
    return;
  if (w > width)
    w = width;
  if (h > height)
    h = height;
  if ((w <= 0) || (h <= 0))
    return;
  if (c & 0x100)
  {
    while (h--)
      HLine(x, x+w-1, y++, c);
  }
  else
  {
    while (h--)
      memset(data+x+(y++)*row_scale, c, w);
  }
}

static unsigned char *fontptr=0;

extern "C" void int10(REGISTERS *);

void GrRegion::Text(int x, int y, char *text, int fgc, int bgc)
{
  if (!data) return;
  if (fgc == -1) fgc = color;
  if (!fontptr)
  {
    REGISTERS r;
    r.ax = 0x1130;
#define CHARHEIGHT 16 /* must correspond to value below */
    r.bx = 0x0600;
    int10(&r);
    fontptr = (unsigned char *)r.bp;
  }
  int r, c, bits;
  unsigned char *fp;
  while (*text)
  {
    fp = fontptr + CHARHEIGHT * *(unsigned char *)text;
    for (r=0; r<CHARHEIGHT; r++)
    {
      bits = *fp++;
      for (c=0; c<8; c++)
        if (bits & (0x80>>c))
          Plot(x+c, y+r, fgc);
        else if (bgc != -1)
          Plot(x+c, y+r, bgc);
    }
    text++;
    x += 8;
  }
}

int GrRegion::Point(int x, int y)
{
  if (!data) return 0;
  if ((x < 0) || (y < 0) || (x >= width) || (y >= height))
    return 0;
  return data[x+y*row_scale];
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -