diff --git a/Docs/README.3DClouds b/Docs/README.3DClouds index 8bc6039d4..13bd33bd1 100644 --- a/Docs/README.3DClouds +++ b/Docs/README.3DClouds @@ -43,8 +43,6 @@ The cloud is defined by the following properties: - whether to choose the vertical texture index based on sprite height within the clouds (default false) - Number of sprite to generate for the cloud (default 20) - - Light multiplier for sprites at the bottom of the cloud - (default 1.0) - minimum width of the sprites used to create the cloud (default 200) - maximum width of the sprites used to create the cloud @@ -56,7 +54,39 @@ The cloud is defined by the following properties: - vertical scaling factor to apply to to the sprite after billboarding. A small value would create a sprite that looks squashed when viewed from the side. (default 1.0) - + - See Shading below (default 1.0) + - See Shading below (default min-...-factor + 0.1) + - See Shading below (default 1.0) + - See Shading below (default min-...-factor + 0.1) + - See Shading below (default 1.0) + - See Shading below (default min-...-factor + 0.1) + - See Shading below (default 0.5) + - See Shading below (default min-...-factor + 0.1) + +Shading +------- + +the [min|max]-...-lighting-factor properties allow you to define diffuse lighting +multipliers to the bottom, middle, top, sunny and shaded parts of the cloud. In +each case, individual clouds will have a random multiplier between the min and +max values used to allow for some variation between individual clouds. + +The top, middle and bottom lighting factors are applied based on the pixels vertical +positon in the cloud. A linear interpolation is used either between top/middle (if +the pixel is above the middle of the cloud) or middle/bottom (if the pixel is below +the middle of the cloud). + +The top factor is also applied to _all_ pixels on the sunny side of the cloud. The +shade factor is applied based on the pixel position away from the sun, linearly +interpolated from top to shade. E.g this is not a straight linear interpolation +from top to shade across the entire cloud. + +The final lighting factor is determined by the minimum of the vertical factor and +the sunny/shade factor. Note that this is applied to the individual pixels, not +sprites. + +Textures +-------- The texture to use for the sprites is defined in the tag. To allow some variation, you can create a texture file containing multiple diff --git a/Effects/cloud.eff b/Effects/cloud.eff index 8ac147507..93f2c3747 100644 --- a/Effects/cloud.eff +++ b/Effects/cloud.eff @@ -60,6 +60,10 @@ usrAttr2 11 + + usrAttr3 + 12 + baseTexture diff --git a/Environment/cloudlayers.xml b/Environment/cloudlayers.xml index 613f51622..d4d9a520b 100644 --- a/Environment/cloudlayers.xml +++ b/Environment/cloudlayers.xml @@ -35,33 +35,29 @@ ns = Nimbostratus (Rain cloud) 1600 - 2000 4000 - 3000 10 cl_cumulus.png 4 4 - 0.3 + 0.3 + 0.4 800 - 1200 800 - 1200 + true 800 - 400 - 500 - 200 + 800 10 cl_cumulus.png 4 4 - 0.3 + 0.3 + 0.4 400 - 800 400 - 800 + true 600 @@ -69,89 +65,95 @@ ns = Nimbostratus (Rain cloud) 400 800 20 - cl_cumulus.png + cl_cumulus2.png 4 4 - 0.6 + 0.2 + 0.3 400 700 300 700 + true - 300 - 800 - 200 - 300 - 10 - cl_cumulus.png + 600 + 900 + 400 + 600 + 20 + cl_cumulus2.png 4 4 - 0.7 - 200 + 0.4 + 0.5 + 300 400 - 150 + 200 300 + true 1200 3000 - 200 - 400 + 400 + 800 40 cl_st.png 1 1 - 0.2 + 0.2 300 600 100 200 + false + 0.5 600 2000 - 200 - 300 + 400 + 600 40 cl_st.png 1 1 - 0.3 + 0.3 300 600 100 200 + false + 0.5 - 800 - 1500 - 100 - 200 - 40 - cl_st.png - 1 - 1 - 0.9 - 300 - 600 - 200 - 400 - - - 1800 - 2500 + 1000 200 - 400 40 - cl_st.png - 1 - 1 - 0.9 + cl_cumulus.png + 4 + 4 + 0.9 400 800 - 300 - 500 + 400 + 800 + false + 0.3 + + + 2000 + 1000 + 40 + cl_st.png + 1 + 1 + 0.9 + 600 + 600 + false + 0.4 diff --git a/Nasal/mp_broadcast.nas b/Nasal/mp_broadcast.nas index 63323bc11..62d4a7411 100644 --- a/Nasal/mp_broadcast.nas +++ b/Nasal/mp_broadcast.nas @@ -7,6 +7,65 @@ ## ############################################################################### +############################################################################### +# Event broadcast channel using a MP enabled string property. +# Events from users in multiplayer.ignore are ignored. +# +# EventChannel.new(mpp_path) +# Create a new event broadcast channel. Any MP user with the same +# primitive will receive all messages sent to the channel from the point +# she/he joined (barring severe MP packet loss). +# NOTE: Message delivery is not guaranteed. +# mpp_path - MP property path : string +# +# EventChannel.register(event_hash, handler) +# Register a handler for the event identified by the hash event_hash. +# event_hash - hash value for the event : a unique 4 character string +# handler - a handler function for the event : func (msg) +# +# EventChannel.deregister(event_hash) +# Deregister the handler for the event identified by the hash event_hash. +# event_hash - hash value for the event : a unique 4 character string +# +# EventChannel.send(event_hash, msg) +# Sends the event event_hash with the message msg to the channel. +# event_hash - hash value for the event : a unique 4 character string +# msg - text string with Binary data encoded data : string +# +# EventChannel.die() +# Destroy this EventChannel instance. +# +var EventChannel = {}; +EventChannel.new = func (mpp_path) { + var obj = BroadcastChannel.new(mpp_path, + func (n, msg) { obj._process(n, msg) }); + # Save send from being overriden. + obj.parent_send = obj.send; + # Put EventChannel methods before BroadcastChannel methods. + obj.parents = [EventChannel] ~ obj.parents; + obj.events = {}; + return obj; +} +EventChannel.register = func (event_hash, + handler) { + me.events[event_hash] = handler; +} +EventChannel.deregister = func (event_hash) { + delete(me.events, event_hash); +} +EventChannel.send = func (event_hash, + msg) { + me.parent_send(event_hash ~ msg); +} +############################################################ +# Internals. +EventChannel._process = func (n, msg) { + var event_hash = Binary.readHash(msg); + if (contains(me.events, event_hash)) { + me.events[event_hash](substr(msg, Binary.sizeOf["Hash"])); + } +} + ############################################################################### # Broadcast primitive using a MP enabled string property. # Broadcasts from users in multiplayer.ignore are ignored. @@ -60,6 +119,7 @@ BroadcastChannel.new = func (mpp_path, process, send_buf : [], peers : {}, loopid : 0, + running : 0, PERIOD : 1.3, last_time : 0.0, # For join handling. last_send : 0.0, # For the send queue @@ -74,7 +134,8 @@ BroadcastChannel.new = func (mpp_path, process, return obj; } BroadcastChannel.send = func (msg) { - if (me.send_node == nil) return; + if (!me.running or me.send_node == nil) + return; var t = getprop("/sim/time/elapsed-sec"); if (((t - me.last_send) > me.SEND_TIME) and (size(me.send_buf) == 0)) { @@ -83,17 +144,25 @@ BroadcastChannel.send = func (msg) { if (me.send_to_self) me.process_msg(props.globals, msg); } else { append(me.send_buf, msg); - } + } } BroadcastChannel.die = func { me.loopid += 1; + me.running = 0; # print("BroadcastChannel[" ~ me.mpp_path ~ "] ... destroyed."); } BroadcastChannel.start = func { - me.loopid += 1; - settimer(func { me._loop_(me.loopid); }, 0, 1); + if (!getprop("/sim/multiplay/online")) { + me.stop(); + } else { + #print("mp_broadcast.nas: starting channel " ~ me.send_node.getPath() ~ "."); + me.running = 1; + me._loop_(me.loopid += 1); + } } BroadcastChannel.stop = func { + #print("mp_broadcast.nas: stopping channel " ~ me.send_node.getPath() ~ "."); + me.running = 0; me.loopid += 1; } @@ -147,8 +216,11 @@ BroadcastChannel.update = func { } } } -BroadcastChannel._loop_ = func(id) { +BroadcastChannel._loop_ = func (id) { + me.running or return; id == me.loopid or return; + + #print("mp_broadcast.nas: " ~ me.send_node.getPath() ~ ":" ~ id ~ "."); me.update(); settimer(func { me._loop_(id); }, 0, 1); } @@ -159,6 +231,7 @@ BroadcastChannel._loop_ = func(id) { # NOTE: MP is picky about what it sends in a string propery. # Encode 7 bits as a printable 8 bit character. var Binary = {}; +Binary.TWOTO28 = 268435456; Binary.TWOTO31 = 2147483648; Binary.TWOTO32 = 4294967296; Binary.sizeOf = {}; @@ -230,6 +303,21 @@ Binary.decodeCoord = func (str) { Binary.decodeDouble(substr(str, 20))); return coord; } +############################################################ +# Encodes a string as a hash value. +Binary.sizeOf["Hash"] = 4; +Binary.stringHash = func (str) { + var hash = 0; + for(var i=0; i + + false + + +