====== Using the Producers in the TerrainNode ======
/* Started on 19/02/2022 */
* In proland the actual usage of the TileSamplers happens in the **drawTerrain** method assigned to the terrain node: but from my perspective, there is no real interest to store the TileSamplers separately and then retrieve them in the draw call: we can just as well store them as elements of our TerrainNode (I think...).
* So we add in the TerrainNode class: // We store the TileSamplers directly in this TerrainNode:
protected samplers: TileSampler[] = [];
// Add one TileSampler:
public addTileSampler(sampler: TileSampler) {
this.samplers.push(sampler);
}
* And we assing the samplers accordingly in our Test8 Scene setup: **OK**
* => back from "vacation mode": so now checking if everything is still working as needed on main dev server: **OK** everything seems to be in order.
* Next we have to understand what's happening in the draw() call.
* but first we need to implement a few missing methods:
* ''TileSampler.getTerrain()'': **OK**
* ''TileSampler.checkUniforms()'': **OK**
* ''GPUTileStorage.getTileMap()'': **OK**
* ''GPUTileStorage.generateMipMap()'': **OK**
* ''FrameBuffer.drawQuad()'': **OK**
* **Note**: to implement the drawQuad method in FrameBuffer, we added a mechanism directly in the ResourceManager to create a default Quad object: public getDefaultQuad(): Mesh {
if (this.quad == null) {
let indexType = AttributeType.UNSIGNED_SHORT;
let meshMode = MeshMode.TRIANGLE_STRIP;
let meshUsage = MeshUsage.GPU_STATIC;
// For each vertex, we pass the 4 position coordinates as float:
let nverts = 4;
// Size of 1 vertex in bytes:
let vertSize = 4 * 4;
// create the mesh:
this.quad = new Mesh(vertSize, indexType, meshMode, meshUsage, nverts);
this.quad.addAttributeType(0, 4, AttributeType.FLOAT, false);
this.quad.addVertexElements([-1, -1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, 1, 1, 0, 1]);
}
return this.quad;
}
* Also implemented ''TileSampler.setTileMap()'': **OK**
* **Note**: One thing that we just changed that is going to break the system already is the addition of the **setTexture2DArrayBuffer** method in the FrameBuffer class => now we also need to setup the attachments correctly for Texture2DArray objects.
* Ouughhtt... it seems we may have a serious problem here: when attaching a Texture2DArray with layer==-1, we are calling the opengl function **glFramebufferTexture()** in proland, but it seems there is nothing corresponding to this in WebGL2 ?
* => Checking what the mipmapProg shader is doing in **GPUTileStorage**:
* This is loaded with: this.mipmapProg = await rman.loadProgram('tileStorageMipMap');
* **Note**: we are only loading that program if mipmaps are required, which doesn't seem to be the case for now ?
* Arrgh... that shader is using a Geometry shader, and contains a **gl_Layer** instruction: **we can probably not use this as is**.
* **Note**: there is no **gl_Layer** at all in OpenGL ES 3.0 (cf. https://www.khronos.org/registry/OpenGL-Refpages/es3/html/gl_Layer.xhtml), so we will need to attach the layers we want to render one by one, and using "layer==-1" should be prevented. => **TO BE fixed eventually**
* Next issue we have in with the non implemented ''TileSampler.setTile()'' function, let's fix that: **OK**
* But now we also need the ''Tile.getData()'' method.
* And now things are getting a bit more tricky: because this getData() method is going to check the result of a Tile generation task: TileStorage::Slot *TileCache::Tile::getData(bool check)
{
bool isDone = task->isDone();
assert(isDone || !check);
assert(getTId() == data->id || !check);
return isDone ? data : NULL;
}
* hmmm... 🤔 how can we handle that properly ? Arrff... I think the easiest option here is to use a similar implementation with a dedicated "Task" class too.
* So let's write the **Task** class: **OK**, now I have an initial Task class. Let's continue with the Tile class.
* Actually, there is still something not quite clear at this level: when we check the getTId() value against the id in the TileStorageSlot: currently I have no idea where that id is written => **to be clarified eventually**.
* => Surprisingly, we have now reached a point with the application will still compile and run properly 😅 So, let's make a commit and then keep messing even further lol.
* What I find strange here, is that we call ''setTile()'' on the TileSamplers, but there is no location where we actually create a task to "produce that tile", what am I missing in this process ?
* => from the proland terrain1 example helloworld.xml file, we see that the **TileCache** object should be "linked" to the scheduler somehow: maybe this is what I'm missing then ? Checking... (actually, the point is, my ''Tile'' constructor is never called in fact.)
* Or, in fact, something else interesting here is that in **TileSampler.setTile()** we will exist the method early if samplerU == null which is the case here since I haven't changed the terrain program yet.
* Ohh, okay: there is definitely a lot missing in my **TileCache** implementation... for instance ''TileCache.getTile'': this should probably be called somewhere...
* One step further: it seems this tile creation process is all starting with a call to ''TileProducer.startCreateTile'' (which I have not implemented yet in my Elevation/normal producers).
* Hmm, okay, so in the TerrainNode draw method, we are actually also calling ''TileProducer.hasTile'' and ''TileProducer.findTile'' at some locations => So this could be where we start the creation of the tiles ?
* And finally, I just found that the "real magic" is probably what is happening in **TileSampler.update()** 😁! Where do we call that ?
* => We have the **UpdateTileSamplersTask** for that.
* Ahh! Eureka: now I have it in the helloworld.xml file:
* hmmmm... 🥴 OK, so... I'm not really convinced anymore I can really go somewhere with this implementation of the project: in Javascript we don't have any real/proper support for multithreading: so, whenever I want to update an object on a different thread, I'm in serious trouble. And I'm just realizing that the "TaskGraph" system in use in Proland is doing precisely that all over the place 😳 So how am I doing to cope with that ? Sounds too complex for too limited results.
* And now... I'm starting to think I should give **Rust** and **wgpu** a try instead 😭 That is so absolutely crazy and will take me so much more time to rebuild everything again from scratches... Sometimes I really wish I could simply just die instead lol [//That would simplify my life a lot!// 🤣]
* => Now the nice thing is, when building an app in Rust, it seems it should then be possible to compile it to web assembly (mostly?) and then run it in a webbrowser... ? I'm not quite sure about all this. But just using plain Javascript/Typescript doesn't seem to be the way to go anyway.
* => So **let's give Rust** a try now!