Exemple #1
0
void C4SolidMask::Remove(bool fCauseInstability, bool fBackupAttachment) {
  // If put, restore background pixels from buffer

  // Not put
  if (!MaskPut || !pSolidMask || !pSolidMaskMatBuff) return;

  CheckConsistency();

  // reput background pixels
  for (int ycnt = 0; ycnt < MaskPutRect.Hgt; ++ycnt) {
    BYTE *pPix = pSolidMaskMatBuff + (ycnt + MaskPutRect.ty) * MatBuffPitch +
                 MaskPutRect.tx;
    for (int xcnt = 0; xcnt < MaskPutRect.Wdt; ++xcnt, ++pPix)
      // only if mask was used here
      if (*pPix != MCVehic) {
        // calc position in landscape
        int iTx = MaskPutRect.x + xcnt;
        int iTy = MaskPutRect.y + ycnt;
        // restore pixel here
        // The pPix-check ensures that only pixels that hads been overwritten by
        // this SolidMask are restored
        // Non-SolidMask-pixels should not happen here, because all relevant
        // landscape change routines should
        // temp remove SolidMasks before
        assert(_GBackPix(iTx, iTy) == MCVehic);
        _SBackPixIfMask(iTx, iTy, *pPix, MCVehic);
        // Instability
        if (fCauseInstability) Game.Landscape.CheckInstabilityRange(iTx, iTy);
      }
  }
  // Mask not put flag
  MaskPut = false;
  // update surrounding masks in that range
  C4TargetRect ClipRect;
  for (C4SolidMask *pSolid = C4SolidMask::Last; pSolid; pSolid = pSolid->Prev)
    if (pSolid->MaskPut)
      if (pSolid->MaskPutRect.Overlap(MaskPutRect)) {
        // set clipping rect for all calls, since they may modify it
        ClipRect.Set(MaskPutRect.x, MaskPutRect.y, MaskPutRect.Wdt,
                     MaskPutRect.Hgt, 0, 0);
        // doubled solidmask-pixels have just been removed in the clipped area!
        pSolid->MaskPut = false;
        // re-put the solidmask
        pSolid->Put(false, &ClipRect, false);
      }

  // backup attachment if desired: Backup old pos and all objects that attach to
  // or lie on the SolidMask
  if (fBackupAttachment) {
    MaskRemovalX = pForObject->x;
    MaskRemovalY = pForObject->y;
    iAttachingObjectsCount = 0;
    C4LArea SolidArea(&Game.Objects.Sectors, MaskPutRect.x - 1,
                      MaskPutRect.y - 1, MaskPutRect.Wdt + 2,
                      MaskPutRect.Hgt + 2);
    C4LSector *pSct;
    C4Object *pObj;
    for (C4ObjectList *pLst = SolidArea.FirstObjectShapes(&pSct); pLst;
         pLst = SolidArea.NextObjectShapes(pLst, &pSct))
      for (C4ObjectLink *clnk = pLst->First; clnk; clnk = clnk->Next)
        if ((pObj = clnk->Obj) && pObj != pForObject &&
            pObj->IsMoveableBySolidMask() &&
            !pObj->Shape.CheckContact(pObj->x, pObj->y)) {
          // check for any contact to own SolidMask - attach-directions, bottom
          // - "stuck" (CNAT_Center) is ignored, because that causes problems
          // with things being stuck in basements :(
          int iVtx = 0;
          for (; iVtx < pObj->Shape.VtxNum; ++iVtx)
            if (pObj->Shape.GetVertexContact(
                    iVtx, pObj->Action.t_attach | CNAT_Bottom, pObj->x, pObj->y,
                    DensityProvider(pForObject, *this)))
              if (pObj->Shape.GetVertexContact(
                      iVtx, pObj->Action.t_attach | CNAT_Bottom, pObj->x,
                      pObj->y, DensityProvider(pForObject, *this)))
                break;
          if (iVtx == pObj->Shape.VtxNum) continue;  // no contact
          // contact: Add object to list
          if (iAttachingObjectsCapacity == iAttachingObjectsCount) {
            iAttachingObjectsCapacity += 4;
            C4Object **ppNewAttachingObjects =
                new C4Object *[iAttachingObjectsCapacity];
            if (iAttachingObjectsCount)
              memcpy(ppNewAttachingObjects, ppAttachingObjects,
                     sizeof(C4Object *) * iAttachingObjectsCount);
            delete[] ppAttachingObjects;
            ppAttachingObjects = ppNewAttachingObjects;
          }
          ppAttachingObjects[iAttachingObjectsCount++] = pObj;
        }
  }

  CheckConsistency();
}
Exemple #2
0
void C4SolidMask::Put(bool fCauseInstability, C4TargetRect *pClipRect,
                      bool fRestoreAttachment) {
  // If not put, put mask to background,
  // storing background pixels in cSolidMask.

  // No mask
  if (!pSolidMask || !pSolidMaskMatBuff) {
    iAttachingObjectsCount = 0;
    return;
  }
  // Contained
  if (pForObject->Contained) {
    iAttachingObjectsCount = 0;
    return;
  }
  // Mask is put
  if (fCauseInstability) CheckConsistency();

  bool RegularPut;
  if (!pClipRect) {
    // Regular Put: Update MaskPutRect and MaskPutRotation
    MaskPutRotation = pForObject->r;
    pClipRect = &MaskPutRect;
    RegularPut = true;
  } else {
    // Reput by C4SolidMask::Remove
    // Don't change MaskPutRotation or MaskPutRect
    // Intersect ClipRect with the MaskPutRect
    if (!pClipRect->ClipBy(MaskPutRect)) return;
    RegularPut = false;
  }
  // Lock mask surface
  int iPitch = pForObject->SolidMask.Wdt;
  int xcnt, ycnt, iTx, iTy;
  // Put mask pixels
  BYTE byPixel;
  // not rotated?
  if (!MaskPutRotation) {
    // calc put rect
    if (RegularPut) {
      int ox, oy;
      ox = pForObject->x + pForObject->Def->Shape.x + pForObject->SolidMask.tx;
      oy = pForObject->y + pForObject->Def->Shape.y + pForObject->SolidMask.ty;
      MaskPutRect.x = ox;
      if (MaskPutRect.x < 0) {
        MaskPutRect.tx = -MaskPutRect.x;
        MaskPutRect.x = 0;
      } else
        MaskPutRect.tx = 0;
      MaskPutRect.y = oy;
      if (MaskPutRect.y < 0) {
        MaskPutRect.ty = -MaskPutRect.y;
        MaskPutRect.y = 0;
      } else
        MaskPutRect.ty = 0;
      MaskPutRect.Wdt = Min<int32_t>(ox + pForObject->SolidMask.Wdt, GBackWdt) -
                        MaskPutRect.x;
      MaskPutRect.Hgt = Min<int32_t>(oy + pForObject->SolidMask.Hgt, GBackHgt) -
                        MaskPutRect.y;
    }
    // fill rect with mask
    for (ycnt = 0; ycnt < pClipRect->Hgt; ++ycnt) {
      BYTE *pPix = pSolidMask +
                   (ycnt + pClipRect->ty) * pForObject->SolidMask.Wdt +
                   pClipRect->tx;
      for (xcnt = 0; xcnt < pClipRect->Wdt; ++xcnt, ++pPix) {
        if (*pPix) {
          // solid mask present here
          // calc position in landscape
          iTx = pClipRect->x + xcnt;
          iTy = pClipRect->y + ycnt;
          // is background mat to be stored? always do this in the given rect
          if (!MaskPut) {
            // get background pixel
            byPixel = GBackPix(iTx, iTy);
            // store it. If MCVehic, also store in initial put, but won't be
            // used in restore
            // do not overwrite current value in re-put issued by
            // SolidMask-remover
            if (byPixel != MCVehic || RegularPut)
              pSolidMaskMatBuff[(ycnt + pClipRect->ty) * MatBuffPitch + xcnt +
                                pClipRect->tx] = byPixel;
          }
          // and set mask
          _SBackPix(iTx, iTy, MCVehic);
        } else
            // no SolidMask: mark buffer as unused here
            if (!MaskPut)
          pSolidMaskMatBuff[(ycnt + pClipRect->ty) * MatBuffPitch + xcnt +
                            pClipRect->tx] = MCVehic;
      }
    }
  } else {
    // calc matrix for given rotation
    FIXED Ma1 = Cos(itofix(-MaskPutRotation)),
          Ma2 = -Sin(itofix(-MaskPutRotation)),
          Mb1 = Sin(itofix(-MaskPutRotation)),
          Mb2 = Cos(itofix(-MaskPutRotation));
    // get upper-left corner of landscape copy rect
    int centerx = pForObject->Def->Shape.x + pForObject->SolidMask.tx +
                  pForObject->SolidMask.Wdt / 2;
    int centery = pForObject->Def->Shape.y + pForObject->SolidMask.ty +
                  pForObject->SolidMask.Hgt / 2;
    int xstart = pForObject->x +
                 fixtoi(Ma1 * itofix(centerx) - Ma2 * itofix(centery)) -
                 MatBuffPitch / 2;
    int ystart = pForObject->y +
                 fixtoi(-Mb1 * itofix(centerx) + Mb2 * itofix(centery)) -
                 MatBuffPitch / 2;
    // store put rect
    if (RegularPut) {
      MaskPutRect.x = xstart;
      if (MaskPutRect.x < 0) {
        MaskPutRect.tx = -MaskPutRect.x;
        MaskPutRect.Wdt = MaskPutRect.x;
        MaskPutRect.x = 0;
      } else {
        MaskPutRect.tx = 0;
        MaskPutRect.Wdt = 0;
      }
      MaskPutRect.y = ystart;
      if (MaskPutRect.y < 0) {
        MaskPutRect.ty = -MaskPutRect.y;
        MaskPutRect.Hgt = MaskPutRect.y;
        MaskPutRect.y = 0;
      } else {
        MaskPutRect.ty = 0;
        MaskPutRect.Hgt = 0;
      }
      MaskPutRect.Wdt =
          Min<int32_t>(xstart + MatBuffPitch, GBackWdt) - MaskPutRect.x;
      MaskPutRect.Hgt =
          Min<int32_t>(ystart + MatBuffPitch, GBackHgt) - MaskPutRect.y;
    }
    // go through clipping rect
    const FIXED y0 = itofix(pClipRect->ty - MatBuffPitch / 2);
    const FIXED x0 = itofix(pClipRect->tx - MatBuffPitch / 2);
    iTy = pClipRect->y;
    int w = pForObject->SolidMask.Wdt;
    int h = pForObject->SolidMask.Hgt;
    FIXED ya = y0 * Ma2;
    FIXED yb = y0 * Mb2;
    for (ycnt = 0; ycnt < pClipRect->Hgt; ycnt++) {
      iTx = pClipRect->x;
      int i = (ycnt + pClipRect->ty) * MatBuffPitch + pClipRect->tx;
      FIXED xa = x0 * Ma1;
      FIXED xb = x0 * Mb1;
      for (xcnt = 0; xcnt < pClipRect->Wdt; xcnt++) {
        // calc position in solidmask buffer
        int iMx = fixtoi(xa + ya) + w / 2;
        int iMy = fixtoi(xb + yb) + h / 2;
        // in bounds? and solidmask?
        if (iMx >= 0 && iMy >= 0 && iMx < w && iMy < h &&
            pSolidMask[iMy * iPitch + iMx]) {
          // is background mat to be stored?
          if (!MaskPut) {
            // get background pixel
            byPixel = _GBackPix(iTx, iTy);
            // store it. If MCVehic, also store in initial put, but won't be
            // used in restore
            // do not overwrite current value in re-put issued by
            // SolidMask-remover
            if (byPixel != MCVehic || RegularPut)
              pSolidMaskMatBuff[i + xcnt] = byPixel;
          }
          // set mask pix
          _SBackPix(iTx, iTy, MCVehic);
        } else if (!MaskPut)
          // mark pix as unused in buf
          pSolidMaskMatBuff[i + xcnt] = MCVehic;
        xa += Ma1;
        xb += Mb1;
        ++iTx;
      }
      ya += Ma2;
      yb += Mb2;
      ++iTy;
    }
  }
  // Store mask put status
  MaskPut = TRUE;
  // restore attached object positions if moved
  if (fRestoreAttachment && iAttachingObjectsCount) {
    int32_t dx = pForObject->x - MaskRemovalX;
    int32_t dy = pForObject->y - MaskRemovalY;
    if (dx | dy)
      for (int i = 0; i < iAttachingObjectsCount; ++i) {
        C4Object *pObj = ppAttachingObjects[i];
        if (pObj->IsMoveableBySolidMask())
          if (!pObj->Shape.ContactCheck(pObj->x + dx, pObj->y + dy))
            if (pObj->iLastAttachMovementFrame != Game.FrameCounter) {
              pObj->iLastAttachMovementFrame = Game.FrameCounter;
              pObj->MovePosition(dx, dy);
            }
      }
    iAttachingObjectsCount = 0;
  }

  if (fCauseInstability) CheckConsistency();
}