diff --git a/config.js b/config.js index 06f09a9..d3d7865 100644 --- a/config.js +++ b/config.js @@ -134,7 +134,7 @@ window.CONFIG = { rankMax: 1, // 0=city, 1=town color: [0.22, 0.55, 1.0], flashHz: 2.2, - nightOnly: true, + nightOnly: false, bright: 1.35 // emergencyVehicles: { enabled: false } // emergencyVehicles: { count: 6, speedKmh: 110, minKm: 25, maxKm: 120 } diff --git a/vendor/clouds3d.js b/vendor/clouds3d.js index e4ad434..bca09a3 100644 --- a/vendor/clouds3d.js +++ b/vendor/clouds3d.js @@ -4256,11 +4256,59 @@ var CARP_FRAG_SRC = [ // piece in the evening and goes dark piece by piece in the morning. 'float thr = mix(uLightHi, uLightLo, hash1(vSeed * 1.618 + 5.13));', 'float lit = 1.0 - smoothstep(thr - uLightSoft, thr + uLightSoft, uSunAlt);', + 'if (uEmergency > 0.5 && uEmergencyNightOnly < 0.5) lit = 1.0;', 'if (lit <= 0.001) discard;', 'gl_FragColor = vec4(col * inten * g * lit * df, 1.0);', '}' ].join('\n'); +function ensureCarPtsProgram(gl) { + if (carPtsProg) return carPtsProg; + var cpp = makeProgram(gl, CARP_VERT_SRC, CARP_FRAG_SRC); + if (!cpp) return null; + carPtsProg = cpp; + carPtsAttribs = { + pos: gl.getAttribLocation(cpp, 'aPos'), + meta: gl.getAttribLocation(cpp, 'aMeta'), + dens: gl.getAttribLocation(cpp, 'aDens'), + seed: gl.getAttribLocation(cpp, 'aSeed'), + len: gl.getAttribLocation(cpp, 'aLen') + }; + carPtsUniforms = { + proj: gl.getUniformLocation(cpp, 'uProj'), + view: gl.getUniformLocation(cpp, 'uView'), + camPos: gl.getUniformLocation(cpp, 'uCamPos'), + earthRadius: gl.getUniformLocation(cpp, 'uEarthRadius'), + curvatureOn: gl.getUniformLocation(cpp, 'uCurvatureOn'), + time: gl.getUniformLocation(cpp, 'uTime'), + night: gl.getUniformLocation(cpp, 'uNight'), + speed: gl.getUniformLocation(cpp, 'uSpeed'), + dash: gl.getUniformLocation(cpp, 'uDash'), + laneW: gl.getUniformLocation(cpp, 'uLaneW'), + lanePx: gl.getUniformLocation(cpp, 'uLanePx'), + pxW: gl.getUniformLocation(cpp, 'uPxW'), + traffic: gl.getUniformLocation(cpp, 'uTraffic'), + minPx: gl.getUniformLocation(cpp, 'uMinPx'), + maxPx: gl.getUniformLocation(cpp, 'uMaxPx'), + boost: gl.getUniformLocation(cpp, 'uBoost'), + dens: gl.getUniformLocation(cpp, 'uDens'), + bright: gl.getUniformLocation(cpp, 'uBright'), + fadeA: gl.getUniformLocation(cpp, 'uFadeA'), + fadeB: gl.getUniformLocation(cpp, 'uFadeB'), + sunAlt: gl.getUniformLocation(cpp, 'uSunAlt'), + lightHi: gl.getUniformLocation(cpp, 'uLightHi'), + lightLo: gl.getUniformLocation(cpp, 'uLightLo'), + lightSoft: gl.getUniformLocation(cpp, 'uLightSoft'), + wet: gl.getUniformLocation(cpp, 'uWet'), + wetGain: gl.getUniformLocation(cpp, 'uWetGain'), + emergency: gl.getUniformLocation(cpp, 'uEmergency'), + emergencyColor: gl.getUniformLocation(cpp, 'uEmergencyColor'), + emergencyFlashHz: gl.getUniformLocation(cpp, 'uEmergencyFlashHz'), + emergencyNightOnly: gl.getUniformLocation(cpp, 'uEmergencyNightOnly') + }; + return cpp; +} + // ---- Off-main-thread geo build ------------------------------------------- // Chain stitching, the motorway distance field and the car/settlement // ribbon geometry are pure functions of plain data, so they run in a Web @@ -7148,51 +7196,7 @@ window.clouds3dRender = function(target) { carDrawGroup(carVboB, carCountB, CAR_B_DENS); // -- vehicle lights: round point sprites -- if (carPtsCountM || carPtsCountB) { - if (!carPtsProg) { - var cpp = makeProgram(gl, CARP_VERT_SRC, CARP_FRAG_SRC); - if (cpp) { - carPtsProg = cpp; - carPtsAttribs = { - pos: gl.getAttribLocation(cpp, 'aPos'), - meta: gl.getAttribLocation(cpp, 'aMeta'), - dens: gl.getAttribLocation(cpp, 'aDens'), - seed: gl.getAttribLocation(cpp, 'aSeed'), - len: gl.getAttribLocation(cpp, 'aLen') - }; - carPtsUniforms = { - proj: gl.getUniformLocation(cpp, 'uProj'), - view: gl.getUniformLocation(cpp, 'uView'), - camPos: gl.getUniformLocation(cpp, 'uCamPos'), - earthRadius: gl.getUniformLocation(cpp, 'uEarthRadius'), - curvatureOn: gl.getUniformLocation(cpp, 'uCurvatureOn'), - time: gl.getUniformLocation(cpp, 'uTime'), - night: gl.getUniformLocation(cpp, 'uNight'), - speed: gl.getUniformLocation(cpp, 'uSpeed'), - dash: gl.getUniformLocation(cpp, 'uDash'), - laneW: gl.getUniformLocation(cpp, 'uLaneW'), - lanePx: gl.getUniformLocation(cpp, 'uLanePx'), - pxW: gl.getUniformLocation(cpp, 'uPxW'), - traffic: gl.getUniformLocation(cpp, 'uTraffic'), - minPx: gl.getUniformLocation(cpp, 'uMinPx'), - maxPx: gl.getUniformLocation(cpp, 'uMaxPx'), - boost: gl.getUniformLocation(cpp, 'uBoost'), - dens: gl.getUniformLocation(cpp, 'uDens'), - bright: gl.getUniformLocation(cpp, 'uBright'), - fadeA: gl.getUniformLocation(cpp, 'uFadeA'), - fadeB: gl.getUniformLocation(cpp, 'uFadeB'), - sunAlt: gl.getUniformLocation(cpp, 'uSunAlt'), - lightHi: gl.getUniformLocation(cpp, 'uLightHi'), - lightLo: gl.getUniformLocation(cpp, 'uLightLo'), - lightSoft: gl.getUniformLocation(cpp, 'uLightSoft'), - wet: gl.getUniformLocation(cpp, 'uWet'), - wetGain: gl.getUniformLocation(cpp, 'uWetGain'), - emergency: gl.getUniformLocation(cpp, 'uEmergency'), - emergencyColor: gl.getUniformLocation(cpp, 'uEmergencyColor'), - emergencyFlashHz: gl.getUniformLocation(cpp, 'uEmergencyFlashHz'), - emergencyNightOnly: gl.getUniformLocation(cpp, 'uEmergencyNightOnly') - }; - } - } + ensureCarPtsProgram(gl); if (carPtsProg) { gl.useProgram(carPtsProg); gl.uniformMatrix4fv(carPtsUniforms.proj, false, proj); @@ -7246,25 +7250,64 @@ window.clouds3dRender = function(target) { }; carPtsGroup(carPtsVboM, carPtsCountM, CAR_M_DASH, CAR_M_SPEED, CAR_M_DENS); carPtsGroup(carPtsVboB, carPtsCountB, CAR_B_DASH, CAR_B_SPEED, CAR_B_DENS); - var emergencyDrawCount = updateEmergencyVehicles(now); - if (emergencyDrawCount > 0) { - if (!emergencyVbo) emergencyVbo = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, emergencyVbo); - gl.bufferData(gl.ARRAY_BUFFER, emergencyPts.subarray(0, emergencyDrawCount * 10), gl.DYNAMIC_DRAW); - gl.vertexAttribPointer(carPtsAttribs.pos, 3, gl.FLOAT, false, 40, 0); - gl.vertexAttribPointer(carPtsAttribs.meta, 4, gl.FLOAT, false, 40, 12); - gl.vertexAttribPointer(carPtsAttribs.dens, 1, gl.FLOAT, false, 40, 28); - gl.vertexAttribPointer(carPtsAttribs.seed, 1, gl.FLOAT, false, 40, 32); - gl.vertexAttribPointer(carPtsAttribs.len, 1, gl.FLOAT, false, 40, 36); - gl.uniform1f(carPtsUniforms.dash, 0.0); - gl.uniform1f(carPtsUniforms.speed, 0.0); - gl.uniform1f(carPtsUniforms.dens, 1.0); - gl.uniform1f(carPtsUniforms.bright, EMERGENCY_BRIGHT); - gl.uniform1f(carPtsUniforms.emergency, 1.0); - gl.drawArrays(gl.POINTS, 0, emergencyDrawCount); - gl.uniform1f(carPtsUniforms.emergency, 0.0); - gl.uniform1f(carPtsUniforms.bright, CAR_BRIGHT); - } + + } + } + var emergencyDrawCount = updateEmergencyVehicles(now); + if (emergencyDrawCount > 0 && (!EMERGENCY_NIGHT_ONLY || carNight > 0.01)) { + ensureCarPtsProgram(gl); + if (carPtsProg) { + var emergencyPxScale = Math.max(0.45, Math.min(1.25, gl.drawingBufferHeight / 1080)); + gl.useProgram(carPtsProg); + gl.uniformMatrix4fv(carPtsUniforms.proj, false, proj); + gl.uniformMatrix4fv(carPtsUniforms.view, false, view); + gl.uniform3f(carPtsUniforms.camPos, camX, camY, camZ); + gl.uniform1f(carPtsUniforms.earthRadius, EARTH_RADIUS_UNITS); + gl.uniform1f(carPtsUniforms.curvatureOn, CURVATURE_ON ? 1.0 : 0.0); + gl.uniform1f(carPtsUniforms.time, now); + gl.uniform1f(carPtsUniforms.night, carNight); + gl.uniform1f(carPtsUniforms.sunAlt, window.__currentSunAlt || 0); + gl.uniform1f(carPtsUniforms.lightHi, LIGHT_HI); + gl.uniform1f(carPtsUniforms.lightLo, LIGHT_LO); + gl.uniform1f(carPtsUniforms.lightSoft, LIGHT_SOFT); + gl.uniform1f(carPtsUniforms.laneW, CAR_LANE_W); + gl.uniform1f(carPtsUniforms.lanePx, CAR_LANE_PX * emergencyPxScale); + gl.uniform1f(carPtsUniforms.pxW, 1.1547 / gl.drawingBufferHeight); + gl.uniform1f(carPtsUniforms.traffic, CAR_TRAFFIC); + gl.uniform1f(carPtsUniforms.minPx, CAR_MIN_PX * emergencyPxScale * 1.35); + gl.uniform1f(carPtsUniforms.maxPx, CAR_MAX_PX * emergencyPxScale * 1.6); + gl.uniform1f(carPtsUniforms.boost, CAR_BOOST * emergencyPxScale * 1.4); + gl.uniform1f(carPtsUniforms.bright, EMERGENCY_BRIGHT); + gl.uniform1f(carPtsUniforms.fadeA, CAR_FADE_A); + gl.uniform1f(carPtsUniforms.fadeB, CAR_FADE_B); + gl.uniform1f(carPtsUniforms.wet, _roadWet); + gl.uniform1f(carPtsUniforms.wetGain, WET_LIGHT_GAIN); + gl.uniform1f(carPtsUniforms.emergency, 1.0); + gl.uniform3f(carPtsUniforms.emergencyColor, EMERGENCY_COLOR[0], EMERGENCY_COLOR[1], EMERGENCY_COLOR[2]); + gl.uniform1f(carPtsUniforms.emergencyFlashHz, EMERGENCY_FLASH_HZ); + gl.uniform1f(carPtsUniforms.emergencyNightOnly, EMERGENCY_NIGHT_ONLY ? 1.0 : 0.0); + gl.uniform1f(carPtsUniforms.dash, 0.0); + gl.uniform1f(carPtsUniforms.speed, 0.0); + gl.uniform1f(carPtsUniforms.dens, 1.0); + gl.enable(gl.DEPTH_TEST); + gl.depthMask(false); + gl.enable(gl.BLEND); + gl.blendFunc(gl.ONE, gl.ONE); + if (!emergencyVbo) emergencyVbo = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, emergencyVbo); + gl.bufferData(gl.ARRAY_BUFFER, emergencyPts.subarray(0, emergencyDrawCount * 10), gl.DYNAMIC_DRAW); + gl.enableVertexAttribArray(carPtsAttribs.pos); + gl.vertexAttribPointer(carPtsAttribs.pos, 3, gl.FLOAT, false, 40, 0); + gl.enableVertexAttribArray(carPtsAttribs.meta); + gl.vertexAttribPointer(carPtsAttribs.meta, 4, gl.FLOAT, false, 40, 12); + gl.enableVertexAttribArray(carPtsAttribs.dens); + gl.vertexAttribPointer(carPtsAttribs.dens, 1, gl.FLOAT, false, 40, 28); + gl.enableVertexAttribArray(carPtsAttribs.seed); + gl.vertexAttribPointer(carPtsAttribs.seed, 1, gl.FLOAT, false, 40, 32); + gl.enableVertexAttribArray(carPtsAttribs.len); + gl.vertexAttribPointer(carPtsAttribs.len, 1, gl.FLOAT, false, 40, 36); + gl.drawArrays(gl.POINTS, 0, emergencyDrawCount); + gl.uniform1f(carPtsUniforms.emergency, 0.0); } } gl.disable(gl.BLEND);