|
1 | 1 | // SPDX-License-Identifier: MIT |
2 | 2 | // Copyright contributors to the kepler.gl project |
3 | 3 |
|
4 | | -// @ts-nocheck This is a hack, don't check types |
| 4 | +// @ts-nocheck |
5 | 5 |
|
6 | | -import {LightingEffect, shadow} from '@deck.gl/core'; |
| 6 | +import {LightingEffect} from '@deck.gl/core'; |
7 | 7 |
|
8 | 8 | /** |
9 | | - * Inserts shader code before detected part. |
10 | | - * @param {string} vs Original shader code. |
11 | | - * @param {string} type Debug string. |
12 | | - * @param {string} insertBeforeText Text chunk to insert before. |
13 | | - * @param {string} textToInsert Text to insert. |
14 | | - * @returns Modified shader code. |
15 | | - */ |
16 | | -export function insertBefore(vs, type, insertBeforeText, textToInsert) { |
17 | | - const at = vs.indexOf(insertBeforeText); |
18 | | - if (at < 0) { |
19 | | - return vs; |
20 | | - } |
21 | | - |
22 | | - return vs.slice(0, at) + textToInsert + vs.slice(at); |
23 | | -} |
24 | | - |
25 | | -const CustomShadowModule = shadow ? {...shadow} : undefined; |
26 | | - |
27 | | -/** |
28 | | - * Custom shadow module |
29 | | - * 1) Add u_outputUniformShadow uniform |
30 | | - * 2) always produce full shadow when the uniform is set to true. |
31 | | - */ |
32 | | -if (CustomShadowModule?.fs) { |
33 | | - CustomShadowModule.fs = insertBefore( |
34 | | - CustomShadowModule.fs, |
35 | | - 'custom shadow #1', |
36 | | - 'uniform vec4 shadow_uColor;', |
37 | | - 'uniform bool u_outputUniformShadow;' |
38 | | - ); |
39 | | - |
40 | | - CustomShadowModule.fs = insertBefore( |
41 | | - CustomShadowModule.fs, |
42 | | - 'custom shadow #1', |
43 | | - 'vec4 rgbaDepth = texture2D(shadowMap, position.xy);', |
44 | | - 'if(u_outputUniformShadow) return 1.0;' |
45 | | - ); |
46 | | -} |
47 | | - |
48 | | -if (CustomShadowModule) { |
49 | | - CustomShadowModule.getUniforms = (opts = {}, context = {}) => { |
50 | | - const u = shadow.getUniforms(opts, context); |
51 | | - if (opts.outputUniformShadow !== undefined) { |
52 | | - u.u_outputUniformShadow = opts.outputUniformShadow; |
53 | | - } |
54 | | - return u; |
55 | | - }; |
56 | | -} |
57 | | - |
58 | | -/** |
59 | | - * Custom LightingEffect |
60 | | - * 1) adds CustomShadowModule |
61 | | - * 2) pass outputUniformShadow as module parameters |
62 | | - * 3) properly removes CustomShadowModule |
| 9 | + * Custom LightingEffect for kepler.gl. |
| 10 | + * |
| 11 | + * This is a thin wrapper around deck.gl's LightingEffect. The original |
| 12 | + * deck.gl 8 version patched the shadow shader module with custom GLSL, |
| 13 | + * but that approach doesn't work with deck.gl 9's UBO-based shadow module. |
| 14 | + * |
| 15 | + * We override getShaderModuleProps to always include dummyShadowMap in |
| 16 | + * the shadow props, even when shadows are disabled. This prevents "Bad |
| 17 | + * texture binding" errors: the shadow module's createShadowUniforms needs |
| 18 | + * a valid texture for shadow_uShadowMap0/1 bindings, and without |
| 19 | + * dummyShadowMap it would set them to undefined. |
63 | 20 | */ |
64 | 21 | class CustomDeckLightingEffect extends LightingEffect { |
| 22 | + useOutputUniformShadow: boolean; |
| 23 | + |
65 | 24 | constructor(props) { |
66 | 25 | super(props); |
67 | 26 | this.useOutputUniformShadow = false; |
68 | 27 | } |
69 | 28 |
|
70 | | - preRender(context) { |
71 | | - if (!this.shadow) return; |
72 | | - |
73 | | - // In deck.gl 9.x, preRender receives a context object instead of positional args |
74 | | - const device = context?.device; |
75 | | - |
76 | | - this.shadowMatrices = this._calculateMatrices(); |
77 | | - |
78 | | - if (this.shadowPasses.length === 0) { |
79 | | - this._createShadowPasses(device); |
80 | | - } |
81 | | - |
82 | | - if (!this.dummyShadowMap && device) { |
83 | | - this.dummyShadowMap = device.createTexture({ |
84 | | - width: 1, |
85 | | - height: 1 |
86 | | - }); |
87 | | - } |
| 29 | + getShaderModuleProps(layer, otherShaderModuleProps) { |
| 30 | + const props = super.getShaderModuleProps(layer, otherShaderModuleProps); |
88 | 31 |
|
89 | | - for (let i = 0; i < this.shadowPasses.length; i++) { |
90 | | - const shadowPass = this.shadowPasses[i]; |
91 | | - shadowPass.render({ |
92 | | - layers: context.layers, |
93 | | - layerFilter: context.layerFilter, |
94 | | - viewports: context.viewports, |
95 | | - onViewportActive: context.onViewportActive, |
96 | | - views: context.views, |
97 | | - moduleParameters: { |
98 | | - shadowLightId: i, |
99 | | - dummyShadowMap: this.dummyShadowMap, |
100 | | - shadowMatrices: this.shadowMatrices, |
101 | | - useOutputUniformShadow: false |
102 | | - } |
103 | | - }); |
| 32 | + // When shadow is disabled, the parent returns shadow: {} without |
| 33 | + // dummyShadowMap. The shadow module's getUniforms then sets |
| 34 | + // shadow_uShadowMap0/1 to undefined, causing texture binding errors. |
| 35 | + // Always provide the dummy texture so bindings remain valid. |
| 36 | + if (props.shadow && !props.shadow.dummyShadowMap && this.dummyShadowMap) { |
| 37 | + props.shadow.dummyShadowMap = this.dummyShadowMap; |
104 | 38 | } |
105 | | - } |
106 | 39 |
|
107 | | - getModuleParameters(layer) { |
108 | | - const parameters = super.getModuleParameters(layer); |
109 | | - parameters.outputUniformShadow = this.outputUniformShadow; |
110 | | - return parameters; |
111 | | - } |
112 | | - |
113 | | - cleanup() { |
114 | | - for (const shadowPass of this.shadowPasses) { |
115 | | - shadowPass.delete?.() || shadowPass.destroy?.(); |
116 | | - } |
117 | | - this.shadowPasses.length = 0; |
118 | | - this.shadowMaps.length = 0; |
119 | | - |
120 | | - if (this.dummyShadowMap) { |
121 | | - this.dummyShadowMap.delete?.() || this.dummyShadowMap.destroy?.(); |
122 | | - this.dummyShadowMap = null; |
123 | | - } |
124 | | - |
125 | | - if (this.shadow && this.programManager) { |
126 | | - this.programManager.removeDefaultModule?.(CustomShadowModule); |
127 | | - this.programManager = null; |
128 | | - } |
| 40 | + return props; |
129 | 41 | } |
130 | 42 | } |
131 | 43 |
|
|
0 commit comments