Пример #1
0
void C4SolidMask::PutTemporary(C4Rect where) {
  if (!MaskPut || !pSolidMask || !pSolidMaskMatBuff) return;
  where.Intersect(MaskPutRect);
  // reput vehicle pixels
  for (int y = where.y; y < where.y + where.Hgt; ++y) {
    for (int x = where.x; x < where.x + where.Wdt; ++x) {
      BYTE *pPix = pSolidMaskMatBuff +
                   (y - MaskPutRect.y + MaskPutRect.ty) * MatBuffPitch + x -
                   MaskPutRect.x + MaskPutRect.tx;
      // only if mask was used here
      if (*pPix != MCVehic) {
        // put
        assert(GBackPix(x, y) == *pPix);
        _SBackPix(x, y, MCVehic);
      }
    }
  }
}
Пример #2
0
void C4SolidMask::Repair(C4Rect where) {
  if (!MaskPut || !pSolidMask || !pSolidMaskMatBuff) return;
  where.Intersect(MaskPutRect);
  // reput vehicle pixels
  for (int y = where.y; y < where.y + where.Hgt; ++y) {
    for (int x = where.x; x < where.x + where.Wdt; ++x) {
      BYTE *pPix = pSolidMaskMatBuff +
                   (y - MaskPutRect.y + MaskPutRect.ty) * MatBuffPitch + x -
                   MaskPutRect.x + MaskPutRect.tx;
      // only if mask was used here
      if (*pPix != MCVehic) {
        // record changed landscape in MatBuff
        *pPix = GBackPix(x, y);
        // put
        _SBackPix(x, y, MCVehic);
      }
    }
  }
}
void C4LandscapeRenderClassic::Update(C4Rect To, C4Landscape *pSource)
{
	// clip to landscape size
	To.Intersect(C4Rect(0,0,iWidth,iHeight));
	// everything clipped?
	if (To.Wdt<=0 || To.Hgt<=0) return;
	if (!Surface32->Lock()) return;

	// We clear the affected region here because ClearBoxDw allocates the
	// main memory buffer for the box, so that only that box needs to be
	// sent to the gpu, and not the whole texture, or every pixel
	// separately. It's an important optimization.
	Surface32->ClearBoxDw(To.x, To.y, To.Wdt, To.Hgt);

	// do lightning
	for (int32_t iX=To.x; iX<To.x+To.Wdt; ++iX)
	{
		int AboveDensity = 0, BelowDensity = 0;
		for (int i = 1; i <= 8; ++i)
		{
			AboveDensity += pSource->GetPlacement(iX, To.y - i - 1);
			BelowDensity += pSource->GetPlacement(iX, To.y + i - 1);
		}
		for (int32_t iY=To.y; iY<To.y+To.Hgt; ++iY)
		{
			AboveDensity -= pSource->GetPlacement(iX, iY - 9);
			AboveDensity += pSource->GetPlacement(iX, iY - 1);
			BelowDensity -= pSource->GetPlacement(iX, iY);
			BelowDensity += pSource->GetPlacement(iX, iY + 8);
			BYTE pix = pSource->_GetPix(iX, iY);
			// Sky
			if (!pix)
			{
				Surface32->SetPixDw(iX, iY, 0x00ffffff);
				continue;
			}
			// get density
			int iOwnDens = pSource->_GetPlacement(iX, iY);
			if (!iOwnDens) continue;
			iOwnDens *= 2;
			iOwnDens += pSource->GetPlacement(iX + 1, iY) + pSource->GetPlacement(iX - 1, iY);
			iOwnDens /= 4;
			// get texture map entry for pixel
			const C4TexMapEntry *pTex = pTexs->GetEntry(PixCol2Tex(pix));
			assert(pTex);
			// get texture contents
			DWORD dwBackClr = 0u;
			if (pTex) dwBackClr = pTex->GetPattern().PatternClr(iX, iY);
			// get density of surrounding materials
			int iCompareDens = AboveDensity / 8;
			if (iOwnDens > iCompareDens)
			{
				// apply light
				LightenClrBy(dwBackClr, std::min(30, 2 * (iOwnDens - iCompareDens)));
			}
			else if (iOwnDens < iCompareDens && iOwnDens < 30)
			{
				DarkenClrBy(dwBackClr, std::min(30, 2 * (iCompareDens - iOwnDens)));
			}
			iCompareDens = BelowDensity / 8;
			if (iOwnDens > iCompareDens)
			{
				DarkenClrBy(dwBackClr, std::min(30, 2 * (iOwnDens - iCompareDens)));
			}
			Surface32->SetPixDw(iX, iY, dwBackClr);
		}
	}
	Surface32->Unlock();
}
Пример #4
0
void C4LandscapeRenderGL::Update(C4Rect To, C4Landscape *pSource)
{
	// clip to landscape size
	To.Intersect(C4Rect(0,0,iWidth,iHeight));
	// everything clipped?
	if (To.Wdt<=0 || To.Hgt<=0) return;

	// Lock surfaces
	// We clear the affected region here because ClearBoxDw allocates the
	// main memory buffer for the box, so that only that box needs to be
	// sent to the gpu, and not the whole texture, or every pixel
	// separately. It's an important optimization.
	for (int i = 0; i < C4LR_SurfaceCount; i++)
	{
		if (!Surfaces[i]->Lock()) return;
		Surfaces[i]->ClearBoxDw(To.x, To.y, To.Wdt, To.Hgt);
	}

	// Initialize up & down placement arrays. These arrays are always updated
	// so that they contain the placement sums of C4LR_BiasDistanceY pixels
	// above and below the current row.
	int x, y;
	int placementSumsWidth = C4LR_BiasDistanceX * 2 + To.Wdt;
	int *placementSumsUp = new int [placementSumsWidth * 2];
	int *placementSumsDown = placementSumsUp + placementSumsWidth;
	for(x = 0; x < placementSumsWidth; x++)
	{
		placementSumsUp[x] = 0;
		placementSumsDown[x] = 0;
		if (To.x + x - C4LR_BiasDistanceX < 0 || To.x + x - C4LR_BiasDistanceX >= iWidth) continue;
		for(y = 1; y <= std::min(C4LR_BiasDistanceY, To.y); y++)
			placementSumsUp[x] += pSource->_GetPlacement(To.x+x-C4LR_BiasDistanceX, To.y-y);
		for(y = 1; y <= std::min(C4LR_BiasDistanceY, iHeight - 1 - To.y); y++)
			placementSumsDown[x] += pSource->_GetPlacement(To.x+x-C4LR_BiasDistanceX, To.y+y);
	}

	// Get tex refs (shortcut, we will use them quite heavily)
	C4TexRef *texture[C4LR_SurfaceCount];
	x = y = 0;
	for(int i = 0; i < C4LR_SurfaceCount; i++)
		texture[i] = Surfaces[i]->texture.get();

	// Go through it from top to bottom
	for(y = 0; y < To.Hgt; y++)
	{
		// Initialize left & right placement sums. These are meant to contain
		// the placement sum of a (C4LR_BiasDistanceX, 2*C4LR_BiasDistanceY+1)
		// rectangle left/right of the current pixel. So we initialise it to
		// be correct at x=0. Note that the placementSum arrays don't contain
		// information about the current row, therefore we need a special case
		// for those pixels.
		int sumLeft = 0, sumRight = 0;
		for(x = 1; x <= std::min(C4LR_BiasDistanceX, To.x); x++)
			sumLeft += pSource->_GetPlacement(To.x-x,To.y+y);
		for(x = 1; x <= std::min(C4LR_BiasDistanceX, iWidth - 1 - To.x ); x++)
			sumRight += pSource->_GetPlacement(To.x+x,To.y+y);
		for (int i = 1; i <= C4LR_BiasDistanceX; i++) {
			sumLeft += placementSumsUp[C4LR_BiasDistanceX - i];
			sumLeft += placementSumsDown[C4LR_BiasDistanceX - i];
			sumRight += placementSumsUp[C4LR_BiasDistanceX + i];
			sumRight += placementSumsDown[C4LR_BiasDistanceX + i];
		}

		// Initialise up & down sums. Same principle as above, but slightly
		// easier as we do not miss pixels if we just use the placement sums.
		int sumUp = 0, sumDown = 0;
		for (int i = -C4LR_BiasDistanceX; i <= C4LR_BiasDistanceX; i++) {
			sumUp += placementSumsUp[C4LR_BiasDistanceX + i];
			sumDown += placementSumsDown[C4LR_BiasDistanceX + i];
		}

		for(x = 0; x < To.Wdt; x++)
		{
			int pixel = pSource->_GetPix(To.x+x, To.y+y);
			int placement = pSource->_GetPlacement(To.x+x, To.y+y);

			// Calculate bias. The scale here is the size of the rectangle (see above)
			const int horizontalFactor = C4LR_BiasDistanceX * (2 * C4LR_BiasDistanceY + 1);
			int horizontalBias = std::max(0, placement * horizontalFactor - sumRight) -
			                     std::max(0, placement * horizontalFactor - sumLeft);
			const int verticalFactor = C4LR_BiasDistanceY * (2 * C4LR_BiasDistanceX + 1);
			int verticalBias = std::max(0, placement * verticalFactor - sumDown) -
			                   std::max(0, placement * verticalFactor - sumUp);

			// Maximum placement differences that make a difference in the result,  after which we are at the limits of
			// what can be packed into a byte
			const int maximumPlacementDifference = 40;
			int horizontalBiasScaled = Clamp(horizontalBias * 127 / maximumPlacementDifference / horizontalFactor + 128, 0, 255);
			int verticalBiasScaled = Clamp(verticalBias * 127 / maximumPlacementDifference / verticalFactor + 128, 0, 255);

			// Collect data to save per pixel
			unsigned char data[C4LR_SurfaceCount * 4];
			memset(data, 0, sizeof(data));

			data[C4LR_Material] = pixel;
			data[C4LR_BiasX] = horizontalBiasScaled;
			data[C4LR_BiasY] = verticalBiasScaled;
			data[C4LR_Scaler] = CalculateScalerBitmask(x, y, To, pSource);
			data[C4LR_Place] = placement;

			for(int i = 0; i < C4LR_SurfaceCount; i++)
				texture[i]->SetPix(To.x+x, To.y+y, 
					RGBA(data[i*4+0], data[i*4+1], data[i*4+2], data[i*4+3]));

			// Update sums (last column would be out-of-bounds, and not
			// necessary as we will re-initialise it for the next row)
			if (x < To.Wdt - 1) {
				sumLeft -= placementSumsUp[x] + placementSumsDown[x];
				sumLeft += placementSumsUp[x + C4LR_BiasDistanceX] + placementSumsDown[x + C4LR_BiasDistanceX];
				sumRight -= placementSumsUp[x + C4LR_BiasDistanceX + 1] + placementSumsDown[x + C4LR_BiasDistanceX + 1];
				sumUp -= placementSumsUp[x];
				sumDown -= placementSumsDown[x];
				sumRight += placementSumsUp[x + 2 * C4LR_BiasDistanceX + 1] + placementSumsDown[x + 2 * C4LR_BiasDistanceX + 1];
				sumUp += placementSumsUp[x + 2 * C4LR_BiasDistanceX + 1];
				sumDown += placementSumsDown[x + 2 * C4LR_BiasDistanceX + 1];
			}

			// Update left & right for next pixel in line
			if(x + To.x + 1 < iWidth)
				sumRight -= pSource->_GetPlacement(To.x+x + 1, To.y+y);
			if(To.x+x + C4LR_BiasDistanceX + 1 < iWidth)
				sumRight += pSource->_GetPlacement(To.x+x + C4LR_BiasDistanceX + 1, To.y+y);
			sumLeft += placement;
			if(To.x+x - C4LR_BiasDistanceX >= 0)
				sumLeft -= pSource->_GetPlacement(To.x+x - C4LR_BiasDistanceX, To.y+y);

			// Update up & down arrays (for next line already)
			if (To.x + x >= C4LR_BiasDistanceX) {
				if (To.y + y + 1 < iHeight)
					placementSumsDown[x] -= pSource->_GetPlacement(To.x + x - C4LR_BiasDistanceX, To.y + y + 1);
				if (To.y + y + C4LR_BiasDistanceY + 1 < iHeight)
					placementSumsDown[x] += pSource->_GetPlacement(To.x + x - C4LR_BiasDistanceX, To.y + y + C4LR_BiasDistanceY + 1);
				if (To.y + y - C4LR_BiasDistanceY >= 0)
					placementSumsUp[x] -= pSource->_GetPlacement(To.x + x - C4LR_BiasDistanceX, To.y + y - C4LR_BiasDistanceY);
				placementSumsUp[x] += pSource->_GetPlacement(To.x + x - C4LR_BiasDistanceX, To.y + y);
			}
		}

		// Finish updating up & down arrays for the next line
		if (To.x + x >= C4LR_BiasDistanceX)
		{
			for (; x < std::min(placementSumsWidth, iWidth - To.x + C4LR_BiasDistanceX); x++) {
				if (To.y + y + 1 < iHeight)
					placementSumsDown[x] -= pSource->_GetPlacement(To.x + x - C4LR_BiasDistanceX, To.y + y + 1);
				if (To.y + y + C4LR_BiasDistanceY + 1 < iHeight)
					placementSumsDown[x] += pSource->_GetPlacement(To.x + x - C4LR_BiasDistanceX, To.y + y + C4LR_BiasDistanceY + 1);
				if (To.y + y - C4LR_BiasDistanceY >= 0)
					placementSumsUp[x] -= pSource->_GetPlacement(To.x + x - C4LR_BiasDistanceX, To.y + y - C4LR_BiasDistanceY);
				placementSumsUp[x] += pSource->_GetPlacement(To.x + x - C4LR_BiasDistanceX, To.y + y);
			}
		}
	}

	// done
	delete[] placementSumsUp;
	for (int i = 0; i < C4LR_SurfaceCount; i++)
		Surfaces[i]->Unlock();
}