From 52b3ab04c32a53f886ba05686d00ad5ed66f9045 Mon Sep 17 00:00:00 2001 From: Anders Gidenstam Date: Sat, 1 Oct 2011 00:29:23 +0200 Subject: [PATCH 1/2] Added support for sharing scenery events (e.g. opening hangar doors) over MP. Set the property /scenery/share-events to true to enabled the feature. --- Nasal/mp_broadcast.nas | 98 +++++++++++++++++++++++++++++++++++++++--- Nasal/scenery.nas | 62 ++++++++++++++++++++++++++ preferences.xml | 5 +++ 3 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 Nasal/scenery.nas 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 + + + From c0bebf540498761d0bb71e3f2f0963198a453959 Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Thu, 6 Oct 2011 21:21:13 +0100 Subject: [PATCH 2/2] Updates to 3D clouds to use the new shading parameters. --- Docs/README.3DClouds | 36 +++++++++++- Effects/cloud.eff | 4 ++ Environment/cloudlayers.xml | 106 ++++++++++++++++++------------------ Shaders/3dcloud.vert | 45 +++++++++------ 4 files changed, 120 insertions(+), 71 deletions(-) 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/Shaders/3dcloud.vert b/Shaders/3dcloud.vert index e69a4b7c5..001e2dfc8 100644 --- a/Shaders/3dcloud.vert +++ b/Shaders/3dcloud.vert @@ -7,13 +7,17 @@ uniform float range; // From /sim/rendering/clouds3d-vis-range attribute vec3 usrAttr1; attribute vec3 usrAttr2; +attribute vec3 usrAttr3; float textureIndexX = usrAttr1.r; float textureIndexY = usrAttr1.g; float wScale = usrAttr1.b; float hScale = usrAttr2.r; -float shade = usrAttr2.g; +float shade_factor = usrAttr2.g; float cloud_height = usrAttr2.b; +float bottom_factor = usrAttr3.r; +float middle_factor = usrAttr3.g; +float top_factor = usrAttr3.b; void main(void) { @@ -34,35 +38,44 @@ void main(void) gl_Position.xyz = gl_Vertex.x * u; gl_Position.xyz += gl_Vertex.y * r * wScale; gl_Position.xyz += gl_Vertex.z * w * hScale; - gl_Position.xyz += gl_Color.xyz; - // Apply Z scaling to allow sprites to be squashed in the z-axis gl_Position.z = gl_Position.z * gl_Color.w; + // Now shift the sprite to the correct position in the cloud. + gl_Position.xyz += gl_Color.xyz; + // Determine a lighting normal based on the vertex position from the // center of the cloud, so that sprite on the opposite side of the cloud to the sun are darker. float n = dot(normalize(-gl_LightSource[0].position.xyz), - normalize(vec3(gl_ModelViewMatrix * vec4(- gl_Position.x, - gl_Position.y, - gl_Position.z,0.0)))); + normalize(vec3(gl_ModelViewMatrix * vec4(- gl_Position.x, - gl_Position.y, - gl_Position.z, 0.0)))); // Determine the position - used for fog and shading calculations vec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Position); float fogCoord = abs(ecPosition.z); - // Determine fractional height of vertex from 0 at the bottom, and 1 at mid-height. - // Used to determine shading. - float fract = smoothstep(0.0, cloud_height, gl_Position.z + cloud_height); - + // Determine the shading of the vertex. We shade it based on it's position + // in the cloud relative to the sun, and it's vertical position in the cloud. + float shade = mix(shade_factor, top_factor, smoothstep(-0.3, 0.0, n)); + //if (n < 0) { + // shade = mix(top_factor, shade_factor, abs(n)); + //} + + float h = gl_Position.z; + shade = min(shade, + min(mix(bottom_factor, middle_factor, smoothstep(0.0, 0.5 * h, h)), + mix(middle_factor, top_factor, smoothstep(0.5 * h, h, h)) ) ); + + //float h = gl_Position.z / cloud_height; + //if (h < 0.5) { + // shade = min(shade, mix(bottom_factor, middle_factor, smoothstep(0.0, 0.5, h))); + //} else { + // shade = min(shade, mix(middle_factor, top_factor, smoothstep(2.0 * (h - 0.5))); + // } + // Final position of the sprite gl_Position = gl_ModelViewProjectionMatrix * gl_Position; - - // Determine the shading of the sprite based on its vertical position and position relative to the sun. - n = min(smoothstep(-0.5, 0.0, n), fract); - // Determine the shading based on a mixture from the backlight to the front - vec4 backlight = gl_LightSource[0].diffuse * shade; - - gl_FrontColor = mix(backlight, gl_LightSource[0].diffuse, n); - gl_FrontColor += gl_FrontLightModelProduct.sceneColor; + gl_FrontColor = gl_LightSource[0].diffuse * shade + gl_FrontLightModelProduct.sceneColor; // As we get within 100m of the sprite, it is faded out. Equally at large distances it also fades out. gl_FrontColor.a = min(smoothstep(10.0, 100.0, fogCoord), 1.0 - smoothstep(range*0.8, range, fogCoord));