diff --git a/packages/deck.gl-geotiff/src/geotiff/render-pipeline.ts b/packages/deck.gl-geotiff/src/geotiff/render-pipeline.ts index 7dfbd949..90f4703d 100644 --- a/packages/deck.gl-geotiff/src/geotiff/render-pipeline.ts +++ b/packages/deck.gl-geotiff/src/geotiff/render-pipeline.ts @@ -1,10 +1,15 @@ -import { Photometric, SampleFormat } from "@cogeotiff/core"; +import { + Photometric, + PlanarConfiguration, + SampleFormat, +} from "@cogeotiff/core"; import type { RasterModule } from "@developmentseed/deck.gl-raster/gpu-modules"; import { BlackIsZero, CMYKToRGB, Colormap, CreateTexture, + CreateTextureBands, cieLabToRGB, FilterNoDataVal, MaskTexture, @@ -21,14 +26,23 @@ import type { GetTileDataOptions } from "../cog-layer"; import { addAlphaChannel } from "./geotiff"; import { inferTextureFormat } from "./texture"; -export type TextureDataT = { +type BaseTextureData = { height: number; width: number; byteLength: number; - texture: Texture; mask?: Texture; }; +type InterleavedTexture = { + texture: Texture; +} & BaseTextureData; + +type BandSeparateTexture = { + bands: Texture[]; +} & BaseTextureData; + +export type TextureDataT = InterleavedTexture | BandSeparateTexture; + /** * A raster module that can be "unresolved", meaning that its props may come * from the result of `getTileData`. @@ -93,17 +107,30 @@ function createUnormPipeline( photometric, sampleFormat, samplesPerPixel, + planarConfiguration, nodata, } = geotiff.cachedTags; - const renderPipeline: UnresolvedRasterModule[] = [ - { + const renderPipeline: UnresolvedRasterModule[] = []; + + if (planarConfiguration === PlanarConfiguration.Contig) { + renderPipeline.push({ module: CreateTexture, props: { - textureName: (data: TextureDataT) => data.texture, + textureName: (data: InterleavedTexture) => data.texture, }, - }, - ]; + }); + } else { + renderPipeline.push({ + module: CreateTextureBands, + props: { + band1: (data: BandSeparateTexture) => data.bands[0], + band2: (data: BandSeparateTexture) => data.bands[1] ?? undefined, + band3: (data: BandSeparateTexture) => data.bands[2] ?? undefined, + band4: (data: BandSeparateTexture) => data.bands[3] ?? undefined, + }, + }); + } if (nodata !== null) { // Since values are 0-1 for unorm textures, scale nodata to [0, 1] diff --git a/packages/deck.gl-raster/src/gpu-modules/create-texture-bands.ts b/packages/deck.gl-raster/src/gpu-modules/create-texture-bands.ts new file mode 100644 index 00000000..7e259a68 --- /dev/null +++ b/packages/deck.gl-raster/src/gpu-modules/create-texture-bands.ts @@ -0,0 +1,57 @@ +import type { Texture } from "@luma.gl/core"; +import type { ShaderModule } from "@luma.gl/shadertools"; + +// Props expected by the CreateTextureBands shader module. +// Each band is a single-channel (depth=1) texture. Unused bands should be +// omitted — the shader reads only the bands that are declared. +export type CreateTextureBandsProps = { + band1: Texture; + band2?: Texture; + band3?: Texture; + band4?: Texture; +}; + +/** + * A shader module that assembles up to four single-band textures into a single + * vec4 color. Each input texture is expected to have a single channel; the red + * channel (.r) of each is read and placed into the corresponding RGBA slot. + * + * Bands are always read in order: band1 → R, band2 → G, band3 → B, band4 → A. + * Missing bands default to 0.0. + */ +export const CreateTextureBands = { + name: "create-texture-bands", + inject: { + "fs:#decl": /* glsl */ ` + uniform sampler2D band1; + uniform sampler2D band2; + uniform sampler2D band3; + uniform sampler2D band4; + uniform int bandCount; + `, + "fs:DECKGL_FILTER_COLOR": /* glsl */ ` + float r = texture(band1, geometry.uv).r; + float g = bandCount >= 2 ? texture(band2, geometry.uv).r : 0.0; + float b = bandCount >= 3 ? texture(band3, geometry.uv).r : 0.0; + float a = bandCount >= 4 ? texture(band4, geometry.uv).r : 1.0; + color = vec4(r, g, b, a); + `, + }, + getUniforms: (props: Partial) => { + const count = + props.band4 != null + ? 4 + : props.band3 != null + ? 3 + : props.band2 != null + ? 2 + : 1; + return { + band1: props.band1, + band2: props.band2, + band3: props.band3, + band4: props.band4, + bandCount: count, + }; + }, +} as const satisfies ShaderModule; diff --git a/packages/deck.gl-raster/src/gpu-modules/index.ts b/packages/deck.gl-raster/src/gpu-modules/index.ts index 0c9a729b..fff408d7 100644 --- a/packages/deck.gl-raster/src/gpu-modules/index.ts +++ b/packages/deck.gl-raster/src/gpu-modules/index.ts @@ -7,6 +7,7 @@ export { } from "./color"; export { Colormap } from "./colormap"; export { CreateTexture } from "./create-texture"; +export { CreateTextureBands, type CreateTextureBandsProps } from "./create-texture-bands"; export { FilterNoDataVal } from "./filter-nodata"; export { MaskTexture } from "./mask-texture"; export type { RasterModule } from "./types";