説明
Unlike our other backends, Widgetry's WebGL 1.0 backend does not support textures.
Until #504, Widgetry apps in the browser required WebGL 2.0, and thus widgetry would not load at all in an iOS browser (or desktop Safari) unless the user enabled the "Experimental: WebGL 2.0" option in their browser configuration.
Though there are benefits to our users being on WebGL 2.0, we want the app to basically work for users on these platforms by default. To that end, with #504, there is a WebGL 1.0 backend which we fall back to whenever a WebGL 2.0 context cannot be constructed. So things will now load for these users.
Before that, when I was originally adding texture support back in #333, #335 I relied on some more modern GLSL features which ended up not being available in WebGL 1.0. In particular, sampler2DArray is not available in shaders, nor is its corollary glTexStorage3D available in the client program.
For now I've simply punted - textures are ignored in our Web GL 1.0 pipeline.
Here's the basic architecture for how textures work on the existing platforms (e.g. WebGL 2.0):
-
All of our textures are of uniform size and stored in a single sprite sheet
-
Widgetry apps can "paint" a shape with one of those textures using
Fill::Texture(Texture(some_texture_id)). The texture is repeated/tiled to fill the entire shape. You can see an example in the widgetry demo: -
The bytes of the spreadsheet are transposed in a particular way, and loaded to graphics card as a single
sampler2DArray, viaglTextStorage3D. (It's "3D" storage, because though each sprite is 2D, since we have an array of them, it's 3 dimensions all together.) -
In the fragment shader, a 3 dimensional texture coordinate specifies (1) which sprite, and (2,3) the coordinate within that sprite to apply to the pixel. In the event that a shape is a solid color, and no texture should be applied, we actually still apply a "no-op" (pure white) texture, just to keep our shader code branchless.
The files/methods likely to be of interest:
-
https://github.com/a-b-street/abstreet/pull/504/files#diff-4fe9ac03b455f13b66ccfd7d025880e2a8c1c3de677086d16c04e5ac90d14f3dR585 Here the WebGL program loader needs to read in and upload the spritesheet to the graphics card, preferably as a single object. There are limits to how many individual textures can be loaded at once (sometimes as few as 8), which is why we went the route of storing everything in a single sprite sheet texture.
-
https://github.com/a-b-street/abstreet/pull/504/files#diff-a8a5cb47db86df4e4faac558aa0137f93875397f21074d3c66c9a3ff62cdfda2 The WebGL 1.0 fragment shader already has a texture coordinate passed to it, referring which sprite_index and the (x, y) within that sprite. We need to use that information to offset into our uploaded textures and apply it to the output color.
And a disclaimer to anyone who takes this on, I know basically nothing about graphics programming. The code that exists was hacked together from tutorials. It's very likely not how we should be doing things, so don't be afraid to take a radically different approach if a radically different approach makes more sense.