Colored lights

The color of object lights can now be changed. This includes the following changes:
- added light test scenario, based on DarkCastle, with some lights,
- new functions SetLightColor() and GetLightColor() with C4Script documentation,
- third drawing pass for rendering the light color, the drawing passes are now referenced by enum,
- the blending of light from multiple colored light sources works correctly with alpha blending,
- light color value affects the intensity of the light,
- alpha blending of the light depends on color value and lightness. This means that brighter (= more value) and lighter (= more whiteish) light will be preferred in blending over other lights,
- the object light color is rendered to the lower half of the fow light texture now,
- the shader accesses the brightness/direction information and color information correctly,

The patch was created from the following commits:
dab898a SetLightColor()
f57286e Color texture experiment
d0702f5 Dynamic color
fa14cdf Light test scenario
f99203d Alternate lights
474bade Bugfixes
3113698 Brightness handled better
516fb21 GetLightColor
1d91ec9 Improvements
3cfbf6c Documentation
95ec185 Improvements: Light Shader
a63bffc Scope of alpha
20c7ca0 Improvement: C4FoWLight
17d9123 Undo code style
d79411b Cleaner code

(cherry picked from commit 36dec610e36860b88417e91ce727250673bc2ec2)

Conflicts:
	src/landscape/fow/C4FoWRegion.cpp, merged
Controls
Mark 2015-06-28 20:58:53 +02:00
parent 1021c51fe8
commit 02fd798631
25 changed files with 753 additions and 45 deletions

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE funcs
SYSTEM '../../../clonk.dtd'>
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
<funcs>
<func>
<title>GetLightColor</title>
<category>Objects</category>
<version>7.0 OC</version>
<syntax><rtype>int</rtype></syntax>
<desc>Gets the RGB color value of the light that the object emits. The color can be changed with <funclink>SetLightColor</funclink>.</desc>
<related>
<funclink>SetLightColor</funclink>
<funclink>SetLightRange</funclink>
</related>
</func>
<author>Marky</author><date>2015-06</date>
</funcs>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE funcs
SYSTEM '../../../clonk.dtd'>
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
<funcs>
<func>
<title>SetLightColor</title>
<category>Objects</category>
<version>7.0 OC</version>
<syntax>
<rtype>void</rtype>
<params>
<param>
<type>int</type>
<name>color</name>
<desc>New color for the light. The color value (V in HSV notation of the color) determines the intensity of the light. A light color of <code><funclink>RGB</funclink>(128, 0, 0)</code> has a value/intensity of 50%. This means that it will be weaker than a light with<code><funclink>RGB</funclink>(255, 0, 0)</code>, but it will cover the same area as that light.</desc>
</param>
</params>
</syntax>
<desc>Sets the color of the light that is emitted from this object. By default the object emits white light, if it has a light range. See <funclink>SetLightRange</funclink> for further details.</desc>
<examples>
<example>
<code>
var candle_shine=<funclink>CreateObject</funclink>(EnvPack_Candle_Shine);
candle_shine-&gt;<funclink>SetLightRange</funclink>(30, 20);
candle_shine-&gt;SetLightColor(RGB(255,163,58));
</code>
<text>Gives a warm shine to a candle shine object.</text>
</example>
</examples>
<related>
<funclink>GetLightColor</funclink>
<funclink>SetLightRange</funclink>
</related>
</func>
<author>Marky</author><date>2015-06</date>
</funcs>

View File

@ -38,6 +38,7 @@
<related>
<funclink>SetPlrView</funclink>
<funclink>SetFoW</funclink>
<funclink>SetLightColor</funclink>
</related>
</func>
</funcs>

View File

@ -10,24 +10,46 @@ uniform sampler2D lightTex;
// brightness: light strength
//#define LIGHT_DEBUG
// uncomment the following lines for debugging light color:
// the light will always come from the front and have a uniform brightness.
//#define LIGHT_DEBUG_COLOR
// uncomment the following lines to set the light color to pink for all lights for debugging:
//#define LIGHT_DEBUG_PINK
// At what point of light intensity we set the "darkness" point. This
// is to compensate for the fact that the engien "smoothes" the light
// is to compensate for the fact that the engine "smooths" the light
// and therefore will often never arrive at 0 light intensity.
const float lightDarknessLevel = 8.0 / 256.0;
slice(texture+5)
{
#ifdef HAVE_LIGHT
// Query light texture
vec4 lightPx = texture2D(lightTex, lightCoord.st);
vec2 lightDirCoord = lightCoord.st;
vec4 lightPx = texture2D(lightTex, lightDirCoord);
float lightBright = max(0.0, lightPx.x-lightDarknessLevel);
vec3 lightDir = extend_normal(vec2(1.0, 1.0) - lightPx.yz * 3.0);
vec3 lightDir = extend_normal(vec2(1.0, 1.0) - lightPx.yz * 3.0);
// Query light color texture (part of the light texture)
vec2 lightColorCoord = lightCoord.st - vec2(0.0, 0.5); // subtract offset for the color texture
vec4 lightColor = texture2D(lightTex, lightColorCoord.st);
#ifdef LIGHT_DEBUG_COLOR
lightBright = 0.5;
lightDir = vec3(0.0, 0.0, 1.0);
#endif
#else
// When lighting is disabled, put a light source coming from the camera.
// Note that in most cases this does not actually matter, since in the
// case with lighting disabled, ambient lighting takes fully over.
float lightBright = 0.5;
vec3 lightDir = vec3(0.0, 0.0, 1.0);
vec3 lightDir = vec3(0.0, 0.0, 1.0);
vec4 lightColor = vec4(1.0, 1.0, 1.0, 1.0);
#endif
}
@ -41,10 +63,17 @@ slice(light)
slice(color+5)
{
// pink shade for debugging!
#ifdef LIGHT_DEBUG_PINK
lightColor = vec4(1.0, 0.0, 1.0, 1.0);
#endif
lightColor.rgb = sqrt(3.0) * normalize(lightColor.rgb);
// Add light
color = vec4(light * color.rgb, color.a);
color = vec4(light * color.rgb * lightColor.rgb, color.a);
#ifdef HAVE_2PX
color2 = vec4(light2 * color2.rgb, color2.a);
color2 = vec4(light2 * color2.rgb * lightColor.rgb, color2.a);
#endif
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -0,0 +1,53 @@
# Static Map Material/Texture Table
# Index +128 for underground materials
1=Vehicle-none
8=Tunnel-brickback3
9=Tunnel-brickback2
10=Tunnel-tunnel
12=Tunnel-brickback
13=BrickSoft-brick1
19=DuroLava-lava_red
20=Water-water1-water2-water3-water1-water3-water2
22=Acid-acid
23=Lava-lava_red
25=Water-water
28=Earth-earth
29=Earth-earth_dry
30=Earth-earth_rough
31=Earth-earth_topsoil
32=Earth-earth_midsoil
33=Ashes-ashes
35=SandDry-sand_rough
36=Ore-ore
40=Granite-granite
42=Granite-rock
45=Gold-gold
50=Rock-rock
51=Rock-rock_cracked
53=Firestone-firestone
54=Coal-coal
55=Sand-sand_rough
56=Sand-sand_smooth
65=Ice-ice2
67=Ice-ice3
70=Snow-snow1
73=Brick-brick1
74=Brick-brick2
OverloadMaterials
OverloadTextures

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 KiB

View File

@ -0,0 +1,304 @@
/* Automatically created objects file */
static g_ruin1, g_ruin2, g_ruin3, g_elev2, g_elev1, g_cannon, g_king, g_farmer, g_cannoneer;
func InitializeObjects()
{
var Grass001 = CreateObjectAbove(Grass, 396, 1149);
Grass001->SetClrModulation(0xffa08060);
var Grass002 = CreateObjectAbove(Grass, 232, 1181);
Grass002->SetClrModulation(0xffa08060);
var Grass003 = CreateObjectAbove(Grass, 228, 1180);
Grass003->SetClrModulation(0xffa08060);
var Rule_BaseRespawn001 = CreateObject(Rule_BaseRespawn);
Rule_BaseRespawn001->SetInventoryTransfer(true);
Rule_BaseRespawn001->SetFreeCrew(true);
var Tree_Coniferous_Burned001 = CreateObject(Tree_Coniferous_Burned, 17, 1097);
Tree_Coniferous_Burned001->SetR(10);
var Tree_Coniferous_Burned002 = CreateObject(Tree_Coniferous_Burned, 43, 1246);
Tree_Coniferous_Burned002->SetCon(75);
Tree_Coniferous_Burned002->SetR(100);
var Tree_Coniferous001 = CreateObject(Tree_Coniferous, 415, 1117);
Tree_Coniferous001->SetR(10);
Tree_Coniferous001->SetClrModulation(0xffc08060);
var Branch001 = CreateObject(Branch, 241, 1176);
Branch001->SetR(17);
var Fern001 = CreateObjectAbove(Fern, 312, 1432);
Fern001->SetClrModulation(0xffa08060);
var LargeCaveMushroom001 = CreateObjectAbove(LargeCaveMushroom, 1355, 1451);
LargeCaveMushroom001->SetClrModulation(0xffcddfdf);
var LargeCaveMushroom002 = CreateObject(LargeCaveMushroom, 1308, 1384);
LargeCaveMushroom002->SetR(180);
LargeCaveMushroom002->SetClrModulation(0xffdae7dc);
var LargeCaveMushroom003 = CreateObjectAbove(LargeCaveMushroom, 1411, 1447);
LargeCaveMushroom003->SetClrModulation(0xffe9d5dd);
var LargeCaveMushroom004 = CreateObject(LargeCaveMushroom, 1420, 1374);
LargeCaveMushroom004->SetR(160);
LargeCaveMushroom004->SetClrModulation(0xffeaedfb);
var Branch002 = CreateObject(Branch, 1430, 1417);
Branch002->SetR(-25);
var Lichen001 = CreateObjectAbove(Lichen, 1387, 1440);
Lichen001->SetAction("Grown");
var Lichen002 = CreateObjectAbove(Lichen, 1310, 1456);
Lichen002->SetAction("Grown");
var Lichen003 = CreateObjectAbove(Lichen, 1466, 1415);
Lichen003->SetAction("Grown");
var Trunk001 = CreateObject(Trunk, 217, 1159);
Trunk001->SetR(-10);
var EnvPack_Bag001 = CreateObjectAbove(EnvPack_Bag, 846, 885);
EnvPack_Bag001->SetClrModulation(0xffa0a0a0);
CreateObjectAbove(EnvPack_Bag, 840, 888);
CreateObjectAbove(EnvPack_Bag, 844, 888);
CreateObjectAbove(EnvPack_BridgeRustic, 1096, 673);
CreateObjectAbove(EnvPack_Candle, 1054, 672);
CreateObjectAbove(EnvPack_Candle, 1054, 575);
CreateObjectAbove(EnvPack_Candle, 1185, 616);
CreateObjectAbove(EnvPack_Candle, 1531, 448);
CreateObjectAbove(EnvPack_Candle, 1362, 432);
CreateObjectAbove(EnvPack_CandleSmall, 1556, 432);
CreateObjectAbove(EnvPack_Crate, 1017, 576);
CreateObjectAbove(EnvPack_FenceRustic, 1111, 728);
CreateObjectAbove(EnvPack_FenceRustic, 1089, 735);
CreateObjectAbove(EnvPack_Guidepost, 315, 1167);
CreateObjectAbove(EnvPack_Lantern, 894, 488);
CreateObjectAbove(EnvPack_Lantern, 1291, 472);
CreateObjectAbove(EnvPack_Painting, 1235, 537);
CreateObjectAbove(EnvPack_Rail, 1121, 672);
CreateObjectAbove(EnvPack_Scarecrow, 204, 1185);
CreateObject(EnvPack_TreeTrunks, 788, 888);
CreateObjectAbove(EnvPack_WineBarrel, 1438, 552);
CreateObjectAbove(EnvPack_WineBarrel, 1455, 553);
CreateObjectAbove(EnvPack_Candle, 1471, 552);
CreateObject(Rule_TeamAccount);
CreateObject(Rule_NoPowerNeed);
var LargeCaveMushroom005 = CreateObjectAbove(LargeCaveMushroom, 1334, 1459);
LargeCaveMushroom005->SetClrModulation(0xffd0dbdf);
var LargeCaveMushroom006 = CreateObjectAbove(LargeCaveMushroom, 1396, 1451);
LargeCaveMushroom006->SetClrModulation(0xffe7e6f0);
var LargeCaveMushroom007 = CreateObjectAbove(LargeCaveMushroom, 1426, 1437);
LargeCaveMushroom007->SetClrModulation(0xffcfcbe5);
var Fern002 = CreateObject(Fern, 276, 1442);
Fern002->SetCon(22);
CreateObjectAbove(Tree_Coniferous, 408, 1167);
var Tree_Coniferous002 = CreateObject(Tree_Coniferous, 408, 1191);
Tree_Coniferous002->SetCon(47);
var Tree_Coniferous003 = CreateObjectAbove(Tree_Coniferous, 217, 1191);
Tree_Coniferous003->SetCon(39);
var Tree_Coniferous004 = CreateObject(Tree_Coniferous, 392, 1148);
Tree_Coniferous004->SetCon(27);
var Tree_Coniferous005 = CreateObject(Tree_Coniferous, 410, 1168);
Tree_Coniferous005->SetCon(3);
g_ruin1 = CreateObject(Ruin_WoodenCabin, 97, 1150);
g_ruin1->SetR(16);
g_ruin1.StaticSaveVar = "g_ruin1";
g_ruin2 = CreateObjectAbove(Ruin_Windmill, 353, 1145);
g_ruin2.StaticSaveVar = "g_ruin2";
g_ruin3 = CreateObjectAbove(Ruin_ChemicalLab, 267, 1180);
g_ruin3.StaticSaveVar = "g_ruin3";
CreateObjectAbove(Foundry, 238, 1287);
var Chest002 = CreateObjectAbove(Chest, 1475, 1415);
var Chest006 = CreateObjectAbove(Chest, 1574, 583);
var Chest005 = CreateObjectAbove(Chest, 823, 887);
var Chest001 = CreateObjectAbove(Chest, 856, 887);
var Chest003 = CreateObjectAbove(Chest, 1032, 575);
var Chest004 = CreateObjectAbove(Chest, 136, 103);
var StoneDoor001 = CreateObject(StoneDoor, 940, 652);
StoneDoor001->SetComDir(COMD_Down);
var StoneDoor002 = CreateObject(StoneDoor, 1348, 508);
StoneDoor002->SetComDir(COMD_Down);
var StoneDoor003 = CreateObject(StoneDoor, 1347, 412);
StoneDoor003->SetComDir(COMD_Down);
var SpinWheel001 = CreateObjectAbove(SpinWheel, 961, 672);
SpinWheel001->SetStoneDoor(StoneDoor001);
var SpinWheel002 = CreateObjectAbove(SpinWheel, 1367, 527);
SpinWheel002->SetStoneDoor(StoneDoor002);
var SpinWheel003 = CreateObjectAbove(SpinWheel, 1384, 471);
SpinWheel003->SetStoneDoor(StoneDoor003);
CreateObject(Column, 1197, 551);
CreateObject(Column, 1218, 463);
CreateObjectAbove(Idol, 1080, 575);
var SteamEngine001 = CreateObjectAbove(SteamEngine, 1529, 585);
var Flagpole001 = CreateObjectAbove(Flagpole, 135, 1182);
Flagpole001->SetNeutral(true);
g_elev2 = CreateObjectAbove(Elevator, 1366, 614);
g_elev2.StaticSaveVar = "g_elev2";
g_elev2->CreateShaft(477);
g_elev2->SetCasePosition(1079);
g_elev1 = CreateObjectAbove(Elevator, 167, 1184);
g_elev1.StaticSaveVar = "g_elev1";
g_elev1->SetClrModulation(0xffa08060);
g_elev1->CreateShaft(95);
g_elev1->SetCasePosition(1267);
var Catapult001 = CreateObjectAbove(Catapult, 697, 887);
Catapult001->SetRDir(-7);
var Lorry001 = CreateObject(Lorry, 149, 1314);
Lorry001->SetR(24);
var Lorry002 = CreateObject(Lorry, 1425, 1244);
Lorry002->SetR(-36);
CreateObjectAbove(Airship_Burnt, 38, 1152);
CreateObject(Rock, 879, 1002);
CreateObjectAbove(Rock, 262, 1182);
CreateObjectAbove(Rock, 140, 1183);
CreateObjectAbove(Rock, 48, 1151);
CreateObject(Rock, 154, 1205);
CreateObject(Rock, 154, 1205);
CreateObjectAbove(Rock, 241, 1287);
CreateObject(Rock, 338, 1256);
CreateObject(Rock, 661, 1392);
CreateObjectAbove(Rock, 813, 887);
CreateObject(Rock, 893, 1290);
CreateObject(Rock, 1248, 1087);
CreateObject(Rock, 1334, 1011);
CreateObject(Rock, 1268, 932);
CreateObject(Rock, 1298, 795);
CreateObject(Rock, 1501, 932);
CreateObject(Rock, 1473, 675);
CreateObject(Rock, 1367, 654);
CreateObject(Rock, 1505, 1162);
CreateObject(Rock, 1482, 1049);
CreateObject(Rock, 1402, 1447);
CreateObject(Rock, 1025, 1392);
CreateObject(Rock, 742, 1521);
CreateObject(Rock, 712, 1350);
CreateObject(Rock, 1047, 1206);
CreateObject(Ore, 227, 1365);
CreateObjectAbove(Ore, 64, 1421);
CreateObject(Ore, 264, 1453);
CreateObject(Ore, 462, 1478);
CreateObject(Ore, 77, 1485);
CreateObject(Ore, 1481, 1448);
CreateObject(Ore, 1438, 1463);
CreateObject(Ore, 1566, 1561);
CreateObject(Nugget, 1079, 1216);
CreateObject(Nugget, 1244, 1138);
CreateObject(Nugget, 1156, 1163);
CreateObject(Nugget, 1127, 1165);
var GoldBar001 = CreateObject(GoldBar, 1293, 1235);
GoldBar001->SetR(22);
CreateObjectAbove(Airship, 931, 495);
var Barrel001 = CreateObject(Barrel, 167, 1327);
Barrel001->SetR(-13);
Barrel001->SetColor(0xff000000);
var Barrel002 = Chest002->CreateContents(Barrel);
Barrel002->SetColor(0xff000000);
CreateObjectAbove(Seaweed, 169, 1543);
CreateObjectAbove(Seaweed, 815, 1342);
CreateObjectAbove(Seaweed, 719, 1078);
CreateObjectAbove(Seaweed, 772, 1087);
CreateObjectAbove(Seaweed, 1258, 1279);
var Seaweed001 = CreateObject(Seaweed, 592, 1425);
Seaweed001->SetCon(1);
var Seaweed002 = CreateObject(Seaweed, 652, 1304);
Seaweed002->SetCon(1);
var Seaweed003 = CreateObject(Seaweed, 182, 1575);
Seaweed003->SetCon(1);
var Seaweed004 = CreateObjectAbove(Seaweed, 353, 1558);
Seaweed004->SetCon(1);
var Seaweed005 = CreateObject(Seaweed, 435, 1239);
Seaweed005->SetCon(1);
var Seaweed006 = CreateObject(Seaweed, 461, 1252);
Seaweed006->SetCon(1);
var Seaweed007 = CreateObject(Seaweed, 490, 1303);
Seaweed007->SetCon(1);
var Seaweed008 = CreateObject(Seaweed, 515, 1365);
Seaweed008->SetCon(1);
CreateObjectAbove(Mushroom, 126, 1320);
CreateObjectAbove(Mushroom, 212, 1288);
CreateObjectAbove(Mushroom, 367, 1392);
CreateObjectAbove(Mushroom, 268, 1432);
CreateObject(Mushroom, 247, 1303);
CreateObject(Mushroom, 384, 1419);
var Mushroom001 = CreateObject(Mushroom, 184, 1314);
Mushroom001->SetCon(98);
var Mushroom002 = CreateObject(Mushroom, 195, 1314);
Mushroom002->SetCon(95);
var Mushroom003 = CreateObject(Mushroom, 215, 1315);
Mushroom003->SetCon(92);
var Mushroom004 = CreateObject(Mushroom, 205, 1296);
Mushroom004->SetCon(46);
var Mushroom005 = CreateObject(Mushroom, 409, 1436);
Mushroom005->SetCon(33);
var Mushroom006 = CreateObject(Mushroom, 396, 1410);
Mushroom006->SetCon(13);
// lava
var light01 = CreateObject(Rock, 520, 1210);
light01->SetCategory(C4D_StaticBack);
light01->SetLightRange(100, 100);
light01->SetLightColor(RGB(255,144,16));
light01.Visibility = VIS_None;
// candles
for (var candle_shine in FindObjects(Find_ID(EnvPack_Candle_Shine)))
{
candle_shine->SetLightRange(30, 20);
candle_shine->SetLightColor(RGB(255,163,58));
}
// large cave mushroom
LargeCaveMushroom003->SetLightRange(80,50);
LargeCaveMushroom003->SetLightColor(RGB(0,100,0));
Object(17)->SetLightRange(80,50);
Object(17)->SetLightColor(RGB(0,100,0));
// small cave mushrooms
for (var mushroom in FindObjects(Find_ID(Mushroom), Find_InRect(160, 1240, 200, 60)))
{
mushroom->SetLightColor(RGB(100,0,0));
mushroom->SetLightRange(50,30);
}
Object(463)->SetLightRange(50,10);
Object(463)->SetLightColor(RGB(100,0,200));
Object(13)->SetLightRange(50,10);
Object(13)->SetLightColor(RGB(100,200,0));
return true;
}

View File

@ -0,0 +1,37 @@
[Head]
Icon=36
Title=ColorfulLights
Version=6,0
Difficulty=45
NoInitialize=true
[Definitions]
Definition1=Objects.ocd
Definition2=Decoration.ocd
[Game]
Rules=Rule_TeamAccount=1;Rule_NoPowerNeed=1;Rule_BaseRespawn=1;
[Player1]
Knowledge=ToolsWorkshop=1;Foundry=1;Flagpole=1;Elevator=1;Armory=1;ChemicalLab=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;Bucket=1;Sword=1;Metal=1;GoldBar=1;Balloon=1;Boompack=1;GrappleBow=1;JarOfWinds=1;Pipe=1;Pump=1;PowderKeg=1;Ropeladder=1;Bow=1;Arrow=1;Club=1;IronBomb=1;Javelin=1;Shield=1;InventorsLab=1;Sawmill=1;BombArrow=1;FireArrow=1;GrenadeLauncher=1;Torch=1;
[Player2]
Knowledge=ToolsWorkshop=1;Foundry=1;Flagpole=1;Elevator=1;Armory=1;ChemicalLab=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;Bucket=1;Sword=1;Metal=1;GoldBar=1;Balloon=1;Boompack=1;GrappleBow=1;JarOfWinds=1;Pipe=1;Pump=1;PowderKeg=1;Ropeladder=1;Bow=1;Arrow=1;Club=1;IronBomb=1;Javelin=1;Shield=1;InventorsLab=1;Sawmill=1;BombArrow=1;FireArrow=1;GrenadeLauncher=1;Torch=1;
[Player3]
Knowledge=ToolsWorkshop=1;Foundry=1;Flagpole=1;Elevator=1;Armory=1;ChemicalLab=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;Bucket=1;Sword=1;Metal=1;GoldBar=1;Balloon=1;Boompack=1;GrappleBow=1;JarOfWinds=1;Pipe=1;Pump=1;PowderKeg=1;Ropeladder=1;Bow=1;Arrow=1;Club=1;IronBomb=1;Javelin=1;Shield=1;InventorsLab=1;Sawmill=1;BombArrow=1;FireArrow=1;GrenadeLauncher=1;Torch=1;
[Player4]
Knowledge=ToolsWorkshop=1;Foundry=1;Flagpole=1;Elevator=1;Armory=1;ChemicalLab=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;Bucket=1;Sword=1;Metal=1;GoldBar=1;Balloon=1;Boompack=1;GrappleBow=1;JarOfWinds=1;Pipe=1;Pump=1;PowderKeg=1;Ropeladder=1;Bow=1;Arrow=1;Club=1;IronBomb=1;Javelin=1;Shield=1;InventorsLab=1;Sawmill=1;BombArrow=1;FireArrow=1;GrenadeLauncher=1;Torch=1;
[Landscape]
Sky=Clouds2
MapWidth=200,0,64,10000
MapHeight=200,0,40,10000
NoScan=true
FlatChunkShapes=0
[Weather]
Climate=0,10,0,100
YearSpeed=0,0,0,100
Wind=0,100,-100,100

View File

@ -0,0 +1,65 @@
/**
Evil Castle
Desc
@authors Sven2
*/
static g_is_initialized;
static g_ruin1, g_ruin2, g_ruin3, g_elev1, g_elev2, g_farmer, g_king;
static npc_pyrit, g_cannon, g_cannoneer;
func DoInit(int first_player)
{
// Message when first player enters shroom area
ScheduleCall(nil, Scenario.ShroomCaveCheck, 21, 0xffffff);
// Scorching village
g_ruin1->AddScorch(-20,-10, -45, 50, 1500);
g_ruin2->AddScorch(-15,42, 90, 50, 1200);
g_ruin3->AddScorch(-12,18, 130, 80, 1300);
// Update AI stuff
var fx;
for (var enemy in FindObjects(Find_ID(Clonk), Find_Owner(NO_OWNER)))
if (fx = S2AI->GetAI(enemy))
{
fx.weapon = fx.target = nil;
S2AI->BindInventory(enemy);
enemy->DoEnergy(10000);
enemy->AddEnergyBar();
}
return true;
}
func InitializePlayer(int plr)
{
// Players only
if (GetPlayerType(plr)!=C4PT_User) return;
// Scenario init
if (!g_is_initialized) g_is_initialized = DoInit(plr);
// Harsh zoom range
for (var flag in [PLRZOOM_LimitMax, PLRZOOM_Direct])
SetPlayerZoomByViewRange(plr,400,250,flag);
SetPlayerViewLock(plr, true);
// Initial join
var crew = GetCrew(plr);
crew->SetPosition(35 + Random(10) , 1140);
crew->SetDir(DIR_Right);
crew->CreateContents(Shovel);
crew->CreateContents(Hammer);
crew->CreateContents(Axe);
crew->SetLightRange(100, 80);
crew->SetLightColor(RGB(0,0,200));
return true;
}
/* Mushroom cave encounter */
func ShroomCaveCheck()
{
var intruder = FindObject(Find_InRect(1252,1342,320,138), Find_OCF(OCF_CrewMember));
if (!intruder) return true;
ClearScheduleCall(nil, Scenario.ShroomCaveCheck);
return true;
}

View File

@ -0,0 +1,24 @@
global func AddScorch(int x, int y, int r, int strength, int duration)
{
var scorch = CreateObjectAbove(Wood, x,y, NO_OWNER);
if (!scorch) return nil;
scorch->SetObjectLayer(scorch);
scorch->SetR(r);
scorch->SetClrModulation(0x80804000);
scorch->SetCategory(C4D_StaticBack);
scorch.Collectible = false; // SetObjectLayer is not enough...
scorch.Plane = this.Plane+1;
var fx = AddEffect("FireScorching", scorch, 1, 2, scorch);
fx.strength = strength;
fx.duration = duration;
return scorch;
}
global func FxFireScorchingTimer(object target, proplist effect, int time)
{
if (time >= effect.duration) { RemoveObject(); return FX_Execute_Kill; }
// particles
var wind = BoundBy(GetWind(), -5, 5);
CreateParticle("SmokeDirty", PV_Random(-5, 5), PV_Random(-5, 5), wind, -effect.strength/8, PV_Random(20, 40), Particles_SmokeTrail(), 2);
return FX_OK;
}

View File

@ -0,0 +1,4 @@
[Teams]
Active=false
Custom=false
AutoGenerateTeams=true

View File

@ -0,0 +1,2 @@
DE:Farbiges Licht
US:Colorful lights

View File

@ -71,9 +71,9 @@ void C4FoW::Add(C4Object *pObj)
if (pLight)
{
// Update reach
// Update reach and light color
pLight->SetReach(pObj->lightRange, pObj->lightFadeoutRange);
pLight->SetColor(pObj->lightColor);
}
else
{

View File

@ -22,6 +22,13 @@
#include "C4FoWRegion.h"
#include "C4DrawGL.h"
enum C4DrawPass
{
C4DP_First = 0,
C4DP_Second = 1,
C4DP_Color = 2,
C4DP_Last
};
void C4FoWDrawLightTextureStrategy::Begin(int32_t passPar)
{
@ -29,24 +36,40 @@ void C4FoWDrawLightTextureStrategy::Begin(int32_t passPar)
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
float width = region->getSurface()->Wdt;
float height = region->getSurface()->Hgt / 2.0;
// Set up blend equation, see C4FoWDrawLightTextureStrategy::DrawVertex
// for details.
if(pass == 0)
switch (pass)
{
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
}
else if(pass == 1)
{
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
case C4DP_First:
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
glScissor(0, height, width, height);
break;
case C4DP_Second:
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glScissor(0, height, width, height);
break;
case C4DP_Color:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
glScissor(0, 0, width, height);
break;
default:
assert(false);
break;
}
glEnable(GL_SCISSOR_TEST);
}
void C4FoWDrawLightTextureStrategy::End(int32_t pass)
{
glBlendEquation( GL_FUNC_ADD );
glDisable(GL_SCISSOR_TEST);
}
void C4FoWDrawLightTextureStrategy::DrawVertex(float x, float y, bool shadow)
@ -76,27 +99,58 @@ void C4FoWDrawLightTextureStrategy::DrawVertex(float x, float y, bool shadow)
// G_new = BoundBy(BoundBy(G_old + G / 1.5), 0.0, 1.0) - 0.5 / 1.5, 0.0, 1.0)
// B_new = BoundBy(BoundBy(B_old + B / 1.5), 0.0, 1.0) - 0.5 / 1.5, 0.0, 1.0)
if (pass > 0)
glColor3f(0.0f, 0.5f/1.5f, 0.5f/1.5f);
else if (shadow)
float y_offset = 0.0f;
switch (pass)
{
float dx = x - light->getX();
float dy = y - light->getY();
float dist = sqrt(dx*dx+dy*dy);
float bright = light->getBrightness();
float mult = Min(0.5f / light->getNormalSize(), 0.5f / dist);
float normX = Clamp(0.5f + dx * mult, 0.0f, 1.0f) / 1.5f;
float normY = Clamp(0.5f + dy * mult, 0.0f, 1.0f) / 1.5f;
glColor3f(bright, normX, normY);
case C4DP_First:
if (shadow)
{
float dx = x - light->getX();
float dy = y - light->getY();
float dist = sqrt(dx*dx + dy*dy);
float bright = light->getBrightness();
float mult = Min(0.5f / light->getNormalSize(), 0.5f / dist);
float normX = Clamp(0.5f + dx * mult, 0.0f, 1.0f) / 1.5f;
float normY = Clamp(0.5f + dy * mult, 0.0f, 1.0f) / 1.5f;
glColor4f(bright, normX, normY, 0.0f);
}
else
{
glColor4f(0.0f, 0.5f / 1.5f, 0.5f / 1.5f, 0.0f);
}
break;
case C4DP_Second:
glColor4f(0.0f, 0.5f / 1.5f, 0.5f / 1.5f, 0.5f);
break;
case C4DP_Color: // has a block so that alpha is scoped to this block only
{
y_offset = region->getSurface()->Hgt / 2;
float alpha; // 0.0 == fully transparent (takes old color), 1.0 == solid color (takes new color)
if (shadow) // draw the center of the light
{
alpha = 0.3 + 0.6 * light->getValue() * light->getLightness();
}
else // draw the edge of the light
{
alpha = 0.0;
}
glColor4f(light->getR(), light->getG(), light->getB(), alpha);
break;
}
default:
glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
break;
}
else
glColor3f(0.0f, 0.5f/1.5f, 0.5f/1.5f);
// global coords -> region coords
x += -region->getRegion().x;
y += -region->getRegion().y;
y += -region->getRegion().y + y_offset;
glVertex2f(x,y);
glVertex2f(x, y);
}
void C4FoWDrawLightTextureStrategy::DrawDarkVertex(float x, float y)

View File

@ -85,7 +85,7 @@ class C4FoWDrawLightTextureStrategy : public C4FoWDrawStrategy
public:
C4FoWDrawLightTextureStrategy(const C4FoWLight* light, const C4FoWRegion* region) : light(light), region(region) {};
virtual int32_t GetRequestedPasses() { return 2; };
virtual int32_t GetRequestedPasses() { return 3; };
virtual void DrawLightVertex(float x, float y);
virtual void DrawDarkVertex(float x, float y);
virtual void Begin(int32_t pass);

View File

@ -31,7 +31,8 @@ C4FoWLight::C4FoWLight(C4Object *pObj)
iY(fixtoi(pObj->fix_y)),
iReach(pObj->lightRange),
iFadeout(pObj->lightFadeoutRange),
iSize(20), gBright(0.5),
iSize(20), gBright(0.5), colorR(1.0), colorG(1.0), colorB(1.0),
colorV(1.0), colorL(1.0),
pNext(NULL),
pObj(pObj),
sections(4)
@ -77,6 +78,22 @@ void C4FoWLight::SetReach(int32_t iReach2, int32_t iFadeout2)
}
}
void C4FoWLight::SetColor(uint32_t iValue)
{
colorR = (GetRedValue(iValue) & 255) / 255.0f;
colorG = (GetGreenValue(iValue) & 255) / 255.0f;
colorB = (GetBlueValue(iValue) & 255) / 255.0f;
float min = Min(colorR, Min(colorG, colorB));
colorV = Max(Max(colorR, Max(colorG, colorB)), 1e-3f); // prevent division by 0
colorL = (min + colorV) / 2.0f;
// maximize color, so that dark colors will not be desaturated after normalization
colorR = Min(colorR / colorV, 1.0f);
colorG = Min(colorG / colorV, 1.0f);
colorB = Min(colorB / colorV, 1.0f);
}
void C4FoWLight::Update(C4Rect Rec)
{
// Update position from object. Clear if we moved in any way
@ -119,7 +136,7 @@ void C4FoWLight::Render(C4FoWRegion *region, const C4TargetFacet *onScreen)
else pen = new C4FoWDrawLightTextureStrategy(this, region);
for(int pass = 0; pass < pen->GetRequestedPasses(); pass++)
{
{
pen->Begin(pass);
DrawFan(pen, triangles);
@ -193,7 +210,7 @@ void C4FoWLight::CalculateIntermediateFadeTriangles(TriangleList &triangles) con
// an extra intermediate fade point is only necessary on cliffs
tri.descending = distFanR > distNextFanL;
if (tri.descending) {
if (tri.descending) {
if (distFanR < distNextFadeL)
{
tri.fadeIX = nextTri.fadeLX;
@ -220,7 +237,6 @@ void C4FoWLight::CalculateIntermediateFadeTriangles(TriangleList &triangles) con
ProjectPointOutward(tri.fadeIX, tri.fadeIY, sqrt(distNextFadeL));
}
}
}
}

View File

@ -42,7 +42,12 @@ private:
int32_t iReach; // maximum length of beams
int32_t iFadeout; // number of pixels over which beams fade out
int32_t iSize; // size of the light source. Decides smoothness of shadows
float gBright; // brigtness of the light source. 1.0 is maximum.
float gBright; // brightness of the light source. 1.0 is maximum.
float colorR; // red color component of the light source. 1.0 is maximum.
float colorG; // green color component of the light source. 1.0 is maximum.
float colorB; // blue color component of the light source. 1.0 is maximum.
float colorV; // color value. 1.0 is maximum.
float colorL; // color lightness. 1.0 is maximum.
C4FoWLight *pNext;
C4Object *pObj; // Associated object
@ -56,13 +61,21 @@ public:
int32_t getTotalReach() const { return iReach + iFadeout; }
int32_t getSize() const { return iSize; }
int32_t getNormalSize() const { return iSize * 2; }
float getBrightness() const { return gBright; }
float getBrightness() const { return colorV * gBright; }
float getR() const { return colorR; }
float getG() const { return colorG; }
float getB() const { return colorB; }
float getValue() const { return colorV; }
float getLightness() const { return colorL; }
C4FoWLight *getNext() const { return pNext; }
C4Object *getObj() const { return pObj; }
/** Sets the light's size in pixels. The reach is the total radius of the light while the fadeout is the number of
pixels after which the light should dim down */
void SetReach(int32_t iReach, int32_t iFadeout);
/** Sets the light's color in rgba format. */
void SetColor(uint32_t iValue);
/** Triggers the recalculation of all light beams within the given rectangle for this light because the landscape changed. */
void Invalidate(C4Rect r);

View File

@ -40,9 +40,9 @@ bool C4FoWRegion::BindFramebuf()
pBackSurface = pSfc;
// Can simply reuse old texture?
if (!pSurface || pSurface->Wdt < Region.Wdt || pSurface->Hgt < Region.Hgt)
if (!pSurface || pSurface->Wdt < Region.Wdt || (pSurface->Hgt / 2) < Region.Hgt)
{
// Create texture. Round up to next power of two in order to
// Determine texture size. Round up to next power of two in order to
// prevent rounding errors, as well as preventing lots of
// re-allocations when region size changes quickly (think zoom).
if (!pSurface)
@ -50,12 +50,20 @@ bool C4FoWRegion::BindFramebuf()
int iWdt = 1, iHgt = 1;
while (iWdt < Region.Wdt) iWdt *= 2;
while (iHgt < Region.Hgt) iHgt *= 2;
// Double the texture size. The second half of the texture
// will contain the light color information, while the
// first half contains the brightness and direction information
iHgt *= 2;
// Create the texture
if (!pSurface->Create(iWdt, iHgt))
return false;
}
// Generate frame buffer object
if (!hFrameBufDraw) {
if (!hFrameBufDraw)
{
glGenFramebuffersEXT(1, &hFrameBufDraw);
glGenFramebuffersEXT(1, &hFrameBufRead);
}
@ -144,16 +152,24 @@ void C4FoWRegion::Render(const C4TargetFacet *pOnScreen)
gluOrtho2D(0, getSurface()->Wdt, getSurface()->Hgt, 0);
// Clear texture contents
glClearColor(0.0f, 0.5f/1.5f, 0.5f/1.5f, 1.0f);
glScissor(0, getSurface()->Hgt / 2.0, getSurface()->Wdt, getSurface()->Hgt / 2.0);
glClearColor(0.0f, 0.5f / 1.5f, 0.5f / 1.5f, 1.0f);
glEnable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
// clear lower half of texture
glScissor(0, 0, getSurface()->Wdt, getSurface()->Hgt / 2.0);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_SCISSOR_TEST);
// Render FoW to frame buffer object
glBlendFunc(GL_ONE, GL_ONE);
pFoW->Render(this, NULL, pPlayer);
// Copy over the old state
if (OldRegion.Wdt > 0) {
if (OldRegion.Wdt > 0)
{
// Set up shader. If this one doesn't work, we're really in trouble.
C4Shader *pShader = pFoW->GetFramebufShader();
assert(pShader);
@ -176,7 +192,8 @@ void C4FoWRegion::Render(const C4TargetFacet *pOnScreen)
int tquad[8] = { sx0, ty0, tx0, ty1, tx1, ty1, tx1, ty0, };
// Transform into texture coordinates
for (int i = 0; i < 4; i++) {
for (int i = 0; i < 4; i++)
{
squad[i*2] = squad[i*2] / getBackSurface()->Wdt;
squad[i*2+1] = 1.0 - squad[i*2+1] / getBackSurface()->Hgt;
}

View File

@ -4129,6 +4129,17 @@ bool C4Object::SetLightRange(int32_t iToRange, int32_t iToFadeoutRange)
}
bool C4Object::SetLightColor(long iValue)
{
// set new color value
lightColor = iValue;
// resort into player's FoW-repeller-list
UpdateLight();
// success
return true;
}
void C4Object::UpdateLight()
{
if (Landscape.pFoW) Landscape.pFoW->Add(this);

View File

@ -139,6 +139,7 @@ public:
int32_t Audible, AudiblePan; // NoSave //
int32_t lightRange;
int32_t lightFadeoutRange;
long lightColor;
C4Real fix_x,fix_y,fix_r; // SyncClearance-Fix //
C4Real xdir,ydir,rdir;
int32_t iLastAttachMovementFrame; // last frame in which Attach-movement by a SolidMask was done
@ -321,6 +322,8 @@ public:
int32_t GetValue(C4Object *pInBase, int32_t iForPlayer);
bool SetOwner(int32_t iOwner);
bool SetLightRange(int32_t iToRange, int32_t iToFadeoutRange);
long GetLightColor() const { return lightColor; }
bool SetLightColor(long iValue);
void SetOnFire(bool OnFire) { this->OnFire = OnFire; SetOCF(); }
bool GetOnFire() const { return OnFire; }
void SetAlive(bool Alive) { this->Alive = Alive; SetOCF(); }

View File

@ -1334,6 +1334,24 @@ static C4Void FnSetLightRange(C4Object *Obj, long iRange, Nillable<long> iFadeou
return C4Void();
}
static long FnGetLightColor(C4Object *Obj)
{
// get it
return Obj->GetLightColor();
}
static C4Void FnSetLightColor(C4Object *Obj, Nillable<long> iValue)
{
if (iValue.IsNil())
{
iValue = 0;
}
Obj->SetLightColor(iValue);
return C4Void();
}
static C4Void FnSetPicture(C4Object *Obj, long iX, long iY, long iWdt, long iHgt)
{
// set new picture rect
@ -2638,6 +2656,8 @@ void InitObjectFunctionMap(C4AulScriptEngine *pEngine)
AddFunc(pEngine, "GetColor", FnGetColor);
AddFunc(pEngine, "SetColor", FnSetColor);
AddFunc(pEngine, "SetLightRange", FnSetLightRange);
AddFunc(pEngine, "GetLightColor", FnGetLightColor);
AddFunc(pEngine, "SetLightColor", FnSetLightColor);
AddFunc(pEngine, "SetPicture", FnSetPicture);
AddFunc(pEngine, "GetProcedure", FnGetProcedure);
AddFunc(pEngine, "CanConcatPictureWith", FnCanConcatPictureWith);