openclonk/src/landscape/C4LandscapeRenderClassic.cpp

147 lines
4.1 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2009-2015, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
#include "C4Include.h"
#include "C4LandscapeRender.h"
#include "C4Landscape.h"
#include "C4Texture.h"
#include "lib/StdColors.h"
const int C4LS_MaxLightDistY = 8;
const int C4LS_MaxLightDistX = 1;
C4LandscapeRenderClassic::C4LandscapeRenderClassic()
: Surface32(NULL)
{
}
C4LandscapeRenderClassic::~C4LandscapeRenderClassic()
{
Clear();
}
bool C4LandscapeRenderClassic::ReInit(int32_t iWidth, int32_t iHeight)
{
// Create surface
delete Surface32; Surface32 = NULL;
Surface32 = new C4Surface();
// without shaders, the FoW is only as detailed as the landscape has tiles.
if (!Surface32->Create(iWidth, iHeight))
return false;
// Safe back info
this->iWidth = iWidth;
this->iHeight = iHeight;
return true;
}
bool C4LandscapeRenderClassic::Init(int32_t iWidth, int32_t iHeight, C4TextureMap *pTexs, C4GroupSet *pGraphics)
{
// Init proc
if (!ReInit(iWidth, iHeight)) return false;
this->pTexs = pTexs;
return true;
}
void C4LandscapeRenderClassic::Clear()
{
delete Surface32; Surface32 = 0;
iWidth = iHeight = 0;
pTexs = NULL;
}
C4Rect C4LandscapeRenderClassic::GetAffectedRect(C4Rect Rect)
{
Rect.Enlarge(C4LS_MaxLightDistX, C4LS_MaxLightDistY);
return Rect;
}
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 C4LandscapeRenderClassic::Draw(const C4TargetFacet &cgo, const C4FoWRegion *Light)
{
// Ignore light for now
pDraw->BlitLandscape(Surface32, cgo.TargetX, cgo.TargetY, cgo.Surface,
cgo.X, cgo.Y, cgo.Wdt, cgo.Hgt);
}