openclonk/src/landscape/C4Sky.cpp

250 lines
7.1 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 1998-2000, Matthes Bender
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2009-2016, 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.
*/
/* Small member of the landscape class to handle the sky background */
#include "C4Include.h"
#include "landscape/C4Sky.h"
#include "c4group/C4Components.h"
#include "graphics/C4Draw.h"
#include "graphics/C4GraphicsResource.h"
#include "landscape/C4Weather.h"
#include "lib/C4Random.h"
#include "lib/StdColors.h"
void C4Sky::SetFadePalette(int32_t *ipColors)
{
// If colors all zero, use game palette default blue
if (ipColors[0]+ipColors[1]+ipColors[2]+ipColors[3]+ipColors[4]+ipColors[5]==0)
{
FadeClr1=C4RGB(0x1c, 0x40, 0x99);
FadeClr2=C4RGB(0xc2, 0xc6, 0xff);
}
else
{
// set colors
FadeClr1=C4RGB(ipColors[0], ipColors[1], ipColors[2]);
FadeClr2=C4RGB(ipColors[3], ipColors[4], ipColors[5]);
}
}
bool C4Sky::Init(bool fSavegame, std::string names)
{
// reset scrolling pos+speed
// not in savegame, because it will have been loaded from game data there
if (!fSavegame)
{
x=y=xdir=ydir=0; ParX=ParY=10; ParallaxMode=0;
}
// Check for sky bitmap in scenario file
Surface = new C4Surface();
bool loaded = false;
if (names.empty())
{
loaded = !!Surface->LoadAny(Game.ScenarioFile,C4CFN_Sky,true,true, C4SF_Tileable | C4SF_MipMap);
}
// Else, evaluate scenario core landscape sky default list
if (!loaded)
{
if (names.empty()) names = Game.C4S.Landscape.SkyDef;
static std::regex separator(R"([,;\s]+)");
std::vector<std::string> parts;
std::copy(
std::sregex_token_iterator(names.begin(), names.end(), separator, -1),
std::sregex_token_iterator(),
std::back_inserter(parts));
auto name = parts.at(SeededRandom(Game.RandomSeed, parts.size()));
// Sky tile specified, try load
if (name != "Default")
{
// Check for sky tile in scenario file
loaded = !!Surface->LoadAny(Game.ScenarioFile, name.c_str(), true, true, C4SF_Tileable | C4SF_MipMap);
if (!loaded)
{
loaded = !!Surface->LoadAny(::GraphicsResource.Files, name.c_str(), true, false, C4SF_Tileable | C4SF_MipMap);
}
}
}
if (loaded)
{
// surface loaded, store first color index
FadeClr1=FadeClr2=0xffffffff;
// set parallax scroll mode
switch (Game.C4S.Landscape.SkyScrollMode)
{
case 0: // default: no scrolling
break;
case 1: // go with the wind in xdir, and do some parallax scrolling in ydir
ParallaxMode=C4SkyPM_Wind;
ParY=20;
break;
case 2: // parallax in both directions
ParX=ParY=20;
break;
}
}
// Else, try creating default Surface
if (!loaded)
{
SetFadePalette(Game.C4S.Landscape.SkyDefFade);
delete Surface;
Surface = nullptr;
}
// Load sky shaders: regular sprite shaders with OC_SKY define
const char* const SkyDefines[] = { "OC_SKY", nullptr };
if (!pDraw->PrepareSpriteShader(Shader, "Sky", Surface ? C4SSC_BASE : 0, &::GraphicsResource.Files, SkyDefines, nullptr))
return false;
if (!pDraw->PrepareSpriteShader(ShaderLight, "SkyLight", (Surface ? C4SSC_BASE : 0) | C4SSC_LIGHT, &::GraphicsResource.Files, SkyDefines, nullptr))
return false;
// no sky - using fade in newgfx
if (!Surface)
return true;
// Store size
if (Surface)
{
int iWdt,iHgt;
if (Surface->GetSurfaceSize(iWdt, iHgt))
{
Width = iWdt; Height = iHgt;
}
}
// Success
return true;
}
void C4Sky::Default()
{
Width=Height=0;
Surface=nullptr;
x=y=xdir=ydir=0;
Modulation=0xffffffff;
ParX=ParY=10;
ParallaxMode=C4SkyPM_Fixed;
BackClr=0;
BackClrEnabled=false;
}
C4Sky::~C4Sky()
{
Clear();
}
void C4Sky::Clear()
{
Shader.Clear();
ShaderLight.Clear();
delete Surface; Surface=nullptr;
Modulation=0xffffffff;
}
void C4Sky::Execute()
{
// surface exists?
if (!Surface) return;
// advance pos
x+=xdir; y+=ydir;
// clip by bounds
if (x>=itofix(Width)) x-=itofix(Width);
if (y>=itofix(Height)) y-=itofix(Height);
// update speed
if (ParallaxMode == C4SkyPM_Wind) xdir=C4REAL100(::Weather.Wind);
}
void C4Sky::Draw(C4TargetFacet &cgo)
{
// background color?
if (BackClrEnabled) pDraw->DrawBoxDw(cgo.Surface, cgo.X, cgo.Y, cgo.X+cgo.Wdt, cgo.Y+cgo.Hgt, BackClr);
// sky surface?
if (Modulation != 0xffffffff) pDraw->ActivateBlitModulation(Modulation);
C4ShaderCall call(pDraw->GetFoW() ? &ShaderLight : &Shader); // call is started in C4Draw
if (Surface)
{
// blit parallax sky
float zoom = cgo.Zoom;
float targetx = cgo.TargetX; float targety = cgo.TargetY;
float parx = 10.0f / ParX; float pary = 10.0f / ParY;
float par = parx; //todo: pary?
// Step 1: project to landscape coordinates
float resultzoom = 1.0 / (1.0 - (par - par/zoom));
float rx = ((1 - parx) * targetx) * resultzoom + fixtof(x) / (parx + zoom - parx * zoom);
float ry = ((1 - pary) * targety) * resultzoom + fixtof(y) / (pary + zoom - pary * zoom);
// Step 2: convert to screen coordinates
float resultx = (rx - targetx) * zoom / resultzoom;
float resulty = (ry - targety) * zoom / resultzoom;
ZoomDataStackItem zdsi(resultzoom);
pDraw->BlitSurfaceTile(Surface, cgo.Surface, cgo.X, cgo.Y, cgo.Wdt * zoom / resultzoom, cgo.Hgt * zoom / resultzoom, -resultx, -resulty, &call);
}
else
{
// no sky surface: blit sky fade
DWORD dwClr1=GetSkyFadeClr(cgo.TargetY);
DWORD dwClr2=GetSkyFadeClr(cgo.TargetY+cgo.Hgt);
pDraw->DrawBoxFade(cgo.Surface, cgo.X, cgo.Y, cgo.Wdt, cgo.Hgt, dwClr1, dwClr1, dwClr2, dwClr2, &call);
}
if (Modulation != 0xffffffff) pDraw->DeactivateBlitModulation();
// done
}
DWORD C4Sky::GetSkyFadeClr(int32_t iY)
{
int32_t iPos2=(iY*256)/::Landscape.GetHeight(); int32_t iPos1=256-iPos2;
return (((((FadeClr1&0xff00ff)*iPos1 + (FadeClr2&0xff00ff)*iPos2) & 0xff00ff00)
| (((FadeClr1&0x00ff00)*iPos1 + (FadeClr2&0x00ff00)*iPos2) & 0x00ff0000))>>8)
| (FadeClr1 & 0xff000000);
}
bool C4Sky::SetModulation(DWORD dwWithClr, DWORD dwBackClr)
{
Modulation=dwWithClr;
BackClr=dwBackClr;
BackClrEnabled=(Modulation>>24 != 0xff) ? true : false;
return true;
}
void C4Sky::CompileFunc(StdCompiler *pComp)
{
pComp->Value(mkNamingAdapt(mkCastIntAdapt(x), "X", Fix0));
pComp->Value(mkNamingAdapt(mkCastIntAdapt(y), "Y", Fix0));
pComp->Value(mkNamingAdapt(mkCastIntAdapt(xdir),"XDir", Fix0));
pComp->Value(mkNamingAdapt(mkCastIntAdapt(ydir),"YDir", Fix0));
pComp->Value(mkNamingAdapt(Modulation, "Modulation", 0xffffffffU));
pComp->Value(mkNamingAdapt(ParX, "ParX", 10));
pComp->Value(mkNamingAdapt(ParY, "ParY", 10));
pComp->Value(mkNamingAdapt(ParallaxMode, "ParMode", C4SkyPM_Fixed));
pComp->Value(mkNamingAdapt(BackClr, "BackClr", 0));
pComp->Value(mkNamingAdapt(BackClrEnabled, "BackClrEnabled", false));
}