forked from Mirrors/openclonk
269 lines
7.5 KiB
C++
269 lines
7.5 KiB
C++
/*
|
|
* OpenClonk, http://www.openclonk.org
|
|
*
|
|
* Copyright (c) 1998-2000 Matthes Bender
|
|
* Copyright (c) 2002, 2005-2006 Sven Eberhardt
|
|
* Copyright (c) 2005-2010 Günther Brammer
|
|
* Copyright (c) 2005 Peter Wortmann
|
|
* Copyright (c) 2009 Armin Burgmeier
|
|
* Copyright (c) 2009 Nicolas Hake
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
|
*
|
|
* Portions might be copyrighted by other authors who have contributed
|
|
* to OpenClonk.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
* See isc_license.txt for full license and disclaimer.
|
|
*
|
|
* "Clonk" is a registered trademark of Matthes Bender.
|
|
* See clonk_trademark_license.txt for full license.
|
|
*/
|
|
|
|
/* Small member of the landscape class to handle the sky background */
|
|
|
|
#include <C4Include.h>
|
|
#include <C4Sky.h>
|
|
|
|
#include <C4Game.h>
|
|
#include <C4Random.h>
|
|
#include <C4Components.h>
|
|
#include <C4Weather.h>
|
|
#include <C4GraphicsResource.h>
|
|
|
|
static bool SurfaceEnsureSize(C4Surface **ppSfc, int iMinWdt, int iMinHgt)
|
|
{
|
|
// safety
|
|
if (!ppSfc) return false; if (!*ppSfc) return false;
|
|
// get size
|
|
int iWdt=(*ppSfc)->Wdt, iHgt=(*ppSfc)->Hgt;
|
|
int iDstWdt=iWdt, iDstHgt=iHgt;
|
|
// check if it must be enlarged
|
|
while (iDstWdt<iMinWdt) iDstWdt+=iWdt;
|
|
while (iDstHgt<iMinHgt) iDstHgt+=iHgt;
|
|
// Without shaders, the textures need to be small for the FoW.
|
|
if (iDstWdt==iWdt && iDstHgt==iHgt && pDraw->IsShaderific()) return true;
|
|
// create new surface
|
|
C4Surface *pNewSfc=new C4Surface();
|
|
if (!pNewSfc->Create(iDstWdt, iDstHgt, false, false, pDraw->IsShaderific() ? 0 : 64))
|
|
{
|
|
delete pNewSfc;
|
|
return false;
|
|
}
|
|
// blit tiled into dest surface
|
|
pDraw->BlitSurfaceTile2(*ppSfc, pNewSfc, 0, 0, iDstWdt, iDstHgt, 0, 0, false);
|
|
// destroy old surface, assign new
|
|
delete *ppSfc; *ppSfc=pNewSfc;
|
|
// success
|
|
return true;
|
|
}
|
|
|
|
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)
|
|
{
|
|
int32_t skylistn;
|
|
|
|
// 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 = !!Surface->LoadAny(Game.ScenarioFile,C4CFN_Sky,true,true);
|
|
|
|
// Else, evaluate scenario core landscape sky default list
|
|
if (!loaded)
|
|
{
|
|
// Scan list sections
|
|
SReplaceChar(Game.C4S.Landscape.SkyDef,',',';'); // modifying the C4S here...!
|
|
skylistn=SCharCount(';',Game.C4S.Landscape.SkyDef)+1;
|
|
char str[402];
|
|
SCopySegment(Game.C4S.Landscape.SkyDef,SeededRandom(Game.RandomSeed,skylistn),str,';');
|
|
SClearFrontBack(str);
|
|
// Sky tile specified, try load
|
|
if (*str && !SEqual(str,"Default"))
|
|
{
|
|
// Check for sky tile in scenario file
|
|
loaded = !!Surface->LoadAny(Game.ScenarioFile,str,true,true);
|
|
if (!loaded)
|
|
{
|
|
loaded = !!Surface->LoadAny(::GraphicsResource.Files, str, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (loaded)
|
|
{
|
|
// surface loaded, store first color index
|
|
FadeClr1=FadeClr2=0xffffffff;
|
|
// enlarge surface to avoid slow 1*1-px-skies
|
|
if (!SurfaceEnsureSize(&Surface, 128, 128)) return false;
|
|
|
|
// 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 = 0;
|
|
}
|
|
|
|
// 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=NULL;
|
|
x=y=xdir=ydir=0;
|
|
Modulation=0xffffffff;
|
|
ParX=ParY=10;
|
|
ParallaxMode=C4SkyPM_Fixed;
|
|
BackClr=0;
|
|
BackClrEnabled=false;
|
|
}
|
|
|
|
C4Sky::~C4Sky()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
void C4Sky::Clear()
|
|
{
|
|
delete Surface; Surface=NULL;
|
|
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);
|
|
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->BlitSurfaceTile2(Surface, cgo.Surface, cgo.X, cgo.Y, cgo.Wdt * zoom / resultzoom, cgo.Hgt * zoom / resultzoom, -resultx, -resulty, false);
|
|
}
|
|
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, cgo.TargetX, cgo.TargetY);
|
|
}
|
|
if (Modulation != 0xffffffff) pDraw->DeactivateBlitModulation();
|
|
// done
|
|
}
|
|
|
|
DWORD C4Sky::GetSkyFadeClr(int32_t iY)
|
|
{
|
|
int32_t iPos2=(iY*256)/GBackHgt; 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));
|
|
}
|