diff --git a/docs/sdk/script/fn/GetLightColor.xml b/docs/sdk/script/fn/GetLightColor.xml new file mode 100644 index 000000000..5ef268880 --- /dev/null +++ b/docs/sdk/script/fn/GetLightColor.xml @@ -0,0 +1,18 @@ + + + + + + GetLightColor + Objects + 7.0 OC + int + Gets the RGB color value of the light that the object emits. The color can be changed with SetLightColor. + + SetLightColor + SetLightRange + + + Marky2015-06 + diff --git a/docs/sdk/script/fn/SetLightColor.xml b/docs/sdk/script/fn/SetLightColor.xml new file mode 100644 index 000000000..804b4bb21 --- /dev/null +++ b/docs/sdk/script/fn/SetLightColor.xml @@ -0,0 +1,37 @@ + + + + + + SetLightColor + Objects + 7.0 OC + + void + + + int + color + 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 RGB(128, 0, 0) has a value/intensity of 50%. This means that it will be weaker than a light withRGB(255, 0, 0), but it will cover the same area as that light. + + + + 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 SetLightRange for further details. + + + + var candle_shine=CreateObject(EnvPack_Candle_Shine); + candle_shine->SetLightRange(30, 20); + candle_shine->SetLightColor(RGB(255,163,58)); + + Gives a warm shine to a candle shine object. + + + + GetLightColor + SetLightRange + + + Marky2015-06 + diff --git a/docs/sdk/script/fn/SetLightRange.xml b/docs/sdk/script/fn/SetLightRange.xml index e5f3d2420..01cf6cec1 100644 --- a/docs/sdk/script/fn/SetLightRange.xml +++ b/docs/sdk/script/fn/SetLightRange.xml @@ -38,6 +38,7 @@ SetPlrView SetFoW + SetLightColor diff --git a/planet/Graphics.ocg/LightShader.glsl b/planet/Graphics.ocg/LightShader.glsl index 8d33ed10a..6eba1e256 100644 --- a/planet/Graphics.ocg/LightShader.glsl +++ b/planet/Graphics.ocg/LightShader.glsl @@ -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 } diff --git a/planet/Tests.ocf/ColorfulLights.ocs/Map.bmp b/planet/Tests.ocf/ColorfulLights.ocs/Map.bmp new file mode 100644 index 000000000..bd9ed8d7d Binary files /dev/null and b/planet/Tests.ocf/ColorfulLights.ocs/Map.bmp differ diff --git a/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/TEXMAP.TXT b/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/TEXMAP.TXT new file mode 100644 index 000000000..bc470fe44 --- /dev/null +++ b/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/TEXMAP.TXT @@ -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 diff --git a/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brick2.png b/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brick2.png new file mode 100644 index 000000000..8ba865d91 Binary files /dev/null and b/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brick2.png differ diff --git a/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brickback2.png b/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brickback2.png new file mode 100644 index 000000000..9da9a48dd Binary files /dev/null and b/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brickback2.png differ diff --git a/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brickback2.psd b/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brickback2.psd new file mode 100644 index 000000000..9d50fd54f Binary files /dev/null and b/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brickback2.psd differ diff --git a/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brickback3.png b/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brickback3.png new file mode 100644 index 000000000..3f28fe724 Binary files /dev/null and b/planet/Tests.ocf/ColorfulLights.ocs/Material.ocg/brickback3.png differ diff --git a/planet/Tests.ocf/ColorfulLights.ocs/Objects.c b/planet/Tests.ocf/ColorfulLights.ocs/Objects.c new file mode 100644 index 000000000..d26510d8a --- /dev/null +++ b/planet/Tests.ocf/ColorfulLights.ocs/Objects.c @@ -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; +} diff --git a/planet/Tests.ocf/ColorfulLights.ocs/Scenario.txt b/planet/Tests.ocf/ColorfulLights.ocs/Scenario.txt new file mode 100644 index 000000000..4ff0c6a17 --- /dev/null +++ b/planet/Tests.ocf/ColorfulLights.ocs/Scenario.txt @@ -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 diff --git a/planet/Tests.ocf/ColorfulLights.ocs/Script.c b/planet/Tests.ocf/ColorfulLights.ocs/Script.c new file mode 100644 index 000000000..32e62916b --- /dev/null +++ b/planet/Tests.ocf/ColorfulLights.ocs/Script.c @@ -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; +} diff --git a/planet/Tests.ocf/ColorfulLights.ocs/System.ocg/Scorches.c b/planet/Tests.ocf/ColorfulLights.ocs/System.ocg/Scorches.c new file mode 100644 index 000000000..fac1ce5a2 --- /dev/null +++ b/planet/Tests.ocf/ColorfulLights.ocs/System.ocg/Scorches.c @@ -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; +} diff --git a/planet/Tests.ocf/ColorfulLights.ocs/Teams.txt b/planet/Tests.ocf/ColorfulLights.ocs/Teams.txt new file mode 100644 index 000000000..e0f02c84a --- /dev/null +++ b/planet/Tests.ocf/ColorfulLights.ocs/Teams.txt @@ -0,0 +1,4 @@ +[Teams] +Active=false +Custom=false +AutoGenerateTeams=true diff --git a/planet/Tests.ocf/ColorfulLights.ocs/Title.txt b/planet/Tests.ocf/ColorfulLights.ocs/Title.txt new file mode 100644 index 000000000..a8f207fa2 --- /dev/null +++ b/planet/Tests.ocf/ColorfulLights.ocs/Title.txt @@ -0,0 +1,2 @@ +DE:Farbiges Licht +US:Colorful lights \ No newline at end of file diff --git a/src/landscape/fow/C4FoW.cpp b/src/landscape/fow/C4FoW.cpp index be9019bd8..b24003286 100644 --- a/src/landscape/fow/C4FoW.cpp +++ b/src/landscape/fow/C4FoW.cpp @@ -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 { diff --git a/src/landscape/fow/C4FoWDrawStrategy.cpp b/src/landscape/fow/C4FoWDrawStrategy.cpp index cc55c0913..9fd89c4cc 100644 --- a/src/landscape/fow/C4FoWDrawStrategy.cpp +++ b/src/landscape/fow/C4FoWDrawStrategy.cpp @@ -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) diff --git a/src/landscape/fow/C4FoWDrawStrategy.h b/src/landscape/fow/C4FoWDrawStrategy.h index 4743c11fe..a11d09eeb 100644 --- a/src/landscape/fow/C4FoWDrawStrategy.h +++ b/src/landscape/fow/C4FoWDrawStrategy.h @@ -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); diff --git a/src/landscape/fow/C4FoWLight.cpp b/src/landscape/fow/C4FoWLight.cpp index 4e35db91e..8f805632c 100644 --- a/src/landscape/fow/C4FoWLight.cpp +++ b/src/landscape/fow/C4FoWLight.cpp @@ -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)); } } - } } diff --git a/src/landscape/fow/C4FoWLight.h b/src/landscape/fow/C4FoWLight.h index 52f0457f9..b9e152b9d 100644 --- a/src/landscape/fow/C4FoWLight.h +++ b/src/landscape/fow/C4FoWLight.h @@ -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); diff --git a/src/landscape/fow/C4FoWRegion.cpp b/src/landscape/fow/C4FoWRegion.cpp index 1df661e1a..0a00a62b2 100644 --- a/src/landscape/fow/C4FoWRegion.cpp +++ b/src/landscape/fow/C4FoWRegion.cpp @@ -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; } diff --git a/src/object/C4Object.cpp b/src/object/C4Object.cpp index f6da7d205..54e939e5b 100644 --- a/src/object/C4Object.cpp +++ b/src/object/C4Object.cpp @@ -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); diff --git a/src/object/C4Object.h b/src/object/C4Object.h index 4063b9a89..a1bbf2a72 100644 --- a/src/object/C4Object.h +++ b/src/object/C4Object.h @@ -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(); } diff --git a/src/object/C4ObjectScript.cpp b/src/object/C4ObjectScript.cpp index c2bdeb9c3..2f7ad30a7 100644 --- a/src/object/C4ObjectScript.cpp +++ b/src/object/C4ObjectScript.cpp @@ -1334,6 +1334,24 @@ static C4Void FnSetLightRange(C4Object *Obj, long iRange, Nillable iFadeou return C4Void(); } +static long FnGetLightColor(C4Object *Obj) +{ + // get it + return Obj->GetLightColor(); +} + + +static C4Void FnSetLightColor(C4Object *Obj, Nillable 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);