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); } } } }
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(); }
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(); }