예제 #1
0
//
// AddMinisegs
//
void AddMinisegs(seg_t *part, 
    superblock_t *left_list, superblock_t *right_list, 
    intersection_t *cut_list)
{
  intersection_t *cur, *next;
  seg_t *seg, *buddy;

  if (! cut_list)
    return;

# if DEBUG_CUTLIST
  PrintDebug("CUT LIST:\n");
  PrintDebug("PARTITION: (%1.1f,%1.1f) += (%1.1f,%1.1f)\n",
      part->psx, part->psy, part->pdx, part->pdy);

  for (cur=cut_list; cur; cur=cur->next)
  {
    PrintDebug("  Vertex %8X (%1.1f,%1.1f)  Along %1.2f  [%d/%d]  %s\n", 
        cur->vertex->index, cur->vertex->x, cur->vertex->y,
        cur->along_dist,
        cur->before ? cur->before->index : -1,
        cur->after ? cur->after->index : -1,
        cur->self_ref ? "SELFREF" : "");
  }
# endif

  // STEP 1: fix problems the intersection list...

  cur  = cut_list;
  next = cur->next;

  while (cur && next)
  {
    float_g len = next->along_dist - cur->along_dist;

    if (len < -0.1)
      InternalError("Bad order in intersect list: %1.3f > %1.3f\n",
          cur->along_dist, next->along_dist);

    if (len > 0.2)
    {
      cur  = next;
      next = cur->next;
      continue;
    }

    if (len > DIST_EPSILON)
    {
      PrintMiniWarn("Skipping very short seg (len=%1.3f) near (%1.1f,%1.1f)\n",
          len, cur->vertex->x, cur->vertex->y);
    }

    // merge the two intersections into one

# if DEBUG_CUTLIST
    PrintDebug("Merging cut (%1.0f,%1.0f) [%d/%d] with %p (%1.0f,%1.0f) [%d/%d]\n",
        cur->vertex->x, cur->vertex->y,
        cur->before ? cur->before->index : -1,
        cur->after ? cur->after->index : -1,
        next->vertex,
        next->vertex->x, next->vertex->y,
        next->before ? next->before->index : -1,
        next->after ? next->after->index : -1);
# endif

    if (cur->self_ref && !next->self_ref)
    {
      if (cur->before && next->before)
        cur->before = next->before;

      if (cur->after && next->after)
        cur->after = next->after;

      cur->self_ref = FALSE;
    }

    if (!cur->before && next->before)
      cur->before = next->before;

    if (!cur->after && next->after)
      cur->after = next->after;

# if DEBUG_CUTLIST
    PrintDebug("---> merged (%1.0f,%1.0f) [%d/%d] %s\n",
        cur->vertex->x, cur->vertex->y,
        cur->before ? cur->before->index : -1,
        cur->after ? cur->after->index : -1,
        cur->self_ref ? "SELFREF" : "");
# endif

    // free the unused cut

    cur->next = next->next;

    next->next = quick_alloc_cuts;
    quick_alloc_cuts = next;

    next = cur->next;
  }

  // STEP 2: find connections in the intersection list...

  for (cur = cut_list; cur && cur->next; cur = cur->next)
  {
    next = cur->next;
    
    if (!cur->after && !next->before)
      continue;
 
    // check for some nasty OPEN/CLOSED or CLOSED/OPEN cases
    if (cur->after && !next->before)
    {
      if (!cur->self_ref && !cur->after->warned_unclosed)
      {
        PrintMiniWarn("Sector #%d is unclosed near (%1.1f,%1.1f)\n",
            cur->after->index,
            (cur->vertex->x + next->vertex->x) / 2.0,
            (cur->vertex->y + next->vertex->y) / 2.0);
        cur->after->warned_unclosed = 1;
      }
      continue;
    }
    else if (!cur->after && next->before)
    {
      if (!next->self_ref && !next->before->warned_unclosed)
      {
        PrintMiniWarn("Sector #%d is unclosed near (%1.1f,%1.1f)\n",
            next->before->index,
            (cur->vertex->x + next->vertex->x) / 2.0,
            (cur->vertex->y + next->vertex->y) / 2.0);
        next->before->warned_unclosed = 1;
      }
      continue;
    }

    // righteo, here we have definite open space.
    // do a sanity check on the sectors (just for good measure).

    if (cur->after != next->before)
    {
      if (!cur->self_ref && !next->self_ref)
        PrintMiniWarn("Sector mismatch: #%d (%1.1f,%1.1f) != #%d (%1.1f,%1.1f)\n",
            cur->after->index, cur->vertex->x, cur->vertex->y,
            next->before->index, next->vertex->x, next->vertex->y);

      // choose the non-self-referencing sector when we can
      if (cur->self_ref && !next->self_ref)
      {
        cur->after = next->before;
      }
    }

    // create the miniseg pair
    seg = NewSeg();
    buddy = NewSeg();

    seg->partner = buddy;
    buddy->partner = seg;

    seg->start = cur->vertex;
    seg->end   = next->vertex;

    buddy->start = next->vertex;
    buddy->end   = cur->vertex;

    // leave 'linedef' field as NULL.
    // leave 'side' as zero too (not needed for minisegs).

    seg->sector = buddy->sector = cur->after;

    seg->index = buddy->index = -1;

    seg->source_line = buddy->source_line = part->linedef;

    RecomputeSeg(seg);
    RecomputeSeg(buddy);

    // add the new segs to the appropriate lists
    AddSegToSuper(right_list, seg);
    AddSegToSuper(left_list, buddy);

#   if DEBUG_CUTLIST
    PrintDebug("AddMiniseg: %p RIGHT  sector %d  (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n",
        seg, seg->sector ? seg->sector->index : -1, 
        seg->start->x, seg->start->y, seg->end->x, seg->end->y);

    PrintDebug("AddMiniseg: %p LEFT   sector %d  (%1.1f,%1.1f) -> (%1.1f,%1.1f)\n",
        buddy, buddy->sector ? buddy->sector->index : -1, 
        buddy->start->x, buddy->start->y, buddy->end->x, buddy->end->y);
#   endif
  }

  // free intersection structures into quick-alloc list
  while (cut_list)
  {
    cur = cut_list;
    cut_list = cur->next;

    cur->next = quick_alloc_cuts;
    quick_alloc_cuts = cur;
  }
}
예제 #2
0
void TestForWindowEffect(linedef_t *L)
{
  // cast a line horizontally or vertically and see what we hit.
  // OUCH, we have to iterate over all linedefs.

  int i;

  float_g mx = (L->start->x + L->end->x) / 2.0;
  float_g my = (L->start->y + L->end->y) / 2.0;

  float_g dx = L->end->x - L->start->x;
  float_g dy = L->end->y - L->start->y;

  int cast_horiz = fabs(dx) < fabs(dy) ? 1 : 0;

  float_g back_dist = 999999.0;
  sector_t * back_open = NULL;
  int back_line = -1;

  float_g front_dist = 999999.0;
  sector_t * front_open = NULL;
  int front_line = -1;

  for (i=0; i < num_linedefs; i++)
  {
    linedef_t *N = lev_linedefs[i];

    float_g dist;
    boolean_g is_front;
    sidedef_t *hit_side;

    float_g dx2, dy2;

    if (N == L || N->zero_len || N->overlap)
      continue;

    if (cast_horiz)
    {
      dx2 = N->end->x - N->start->x;
      dy2 = N->end->y - N->start->y;

      if (fabs(dy2) < DIST_EPSILON)
        continue;

      if ((MAX(N->start->y, N->end->y) < my - DIST_EPSILON) ||
          (MIN(N->start->y, N->end->y) > my + DIST_EPSILON))
        continue;

      dist = (N->start->x + (my - N->start->y) * dx2 / dy2) - mx;

      is_front = ((dy > 0) == (dist > 0)) ? TRUE : FALSE;

      dist = fabs(dist);
      if (dist < DIST_EPSILON)  // too close (overlapping lines ?)
        continue;

      hit_side = ((dy > 0) ^ (dy2 > 0) ^ !is_front) ? N->right : N->left;
    }
    else  /* vert */
    {
      dx2 = N->end->x - N->start->x;
      dy2 = N->end->y - N->start->y;

      if (fabs(dx2) < DIST_EPSILON)
        continue;

      if ((MAX(N->start->x, N->end->x) < mx - DIST_EPSILON) ||
          (MIN(N->start->x, N->end->x) > mx + DIST_EPSILON))
        continue;

      dist = (N->start->y + (mx - N->start->x) * dy2 / dx2) - my;

      is_front = ((dx > 0) != (dist > 0)) ? TRUE : FALSE;

      dist = fabs(dist);

      hit_side = ((dx > 0) ^ (dx2 > 0) ^ !is_front) ? N->right : N->left;
    }

    if (dist < DIST_EPSILON)  // too close (overlapping lines ?)
      continue;

    if (is_front)
    {
      if (dist < front_dist)
      {
        front_dist = dist;
        front_open = hit_side ? hit_side->sector : NULL;
        front_line = i;
      }
    }
    else
    {
      if (dist < back_dist)
      {
        back_dist = dist;
        back_open = hit_side ? hit_side->sector : NULL;
        back_line = i;
      }
    }
  }

#if DEBUG_WINDOW_FX
  PrintDebug("back line: %d  back dist: %1.1f  back_open: %s\n",
      back_line, back_dist, back_open ? "OPEN" : "CLOSED");
  PrintDebug("front line: %d  front dist: %1.1f  front_open: %s\n",
      front_line, front_dist, front_open ? "OPEN" : "CLOSED");
#endif

  if (back_open && front_open && L->right->sector == front_open)
  {
    L->window_effect = back_open;
    PrintMiniWarn("Linedef #%d seems to be a One-Sided Window (back faces sector #%d).\n", L->index, back_open->index);
  }
}