forked from Mirrors/openclonk
250 lines
7.1 KiB
C++
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));
|
|
}
|