feat(reader): add vtkF3DLYSReader to support .lys files natively - #3413
feat(reader): add vtkF3DLYSReader to support .lys files natively#3413srividya-77 wants to merge 2 commits into
Conversation
|
\ci fast |
| #if VTK_VERSION_NUMBER < VTK_VERSION_CHECK(9, 6, 2) | ||
| if (actor->GetProperty()->GetInterpolation() == VTK_PBR && | ||
| this->PrimitiveInfo[this->LastBoundBO].LastLightComplexity == primitiveInfo::NoLighting) | ||
| this->PrimitiveInfo[this->LastBoundBO].LastLightComplexity == 0) |
There was a problem hiding this comment.
NoLighting evaluates to 0, and the comparison
is against the integer value anyway. I changed it to == 0 for clarity and
consistency.
There was a problem hiding this comment.
clarity and consistency with what ?
There was a problem hiding this comment.
add mention in DATA_LICENSES.md
There was a problem hiding this comment.
Will do! I'll add the license and origin details for bunny.lys to DATA_LICENSES.md.
There was a problem hiding this comment.
You're right, it's not needed - I'll remove it! I originally downloaded bunny.lys as a .zip from the issue , but since the reader parses .lys directly, the zip file has nothing to do with it. I'll delete it in the next commit.
There was a problem hiding this comment.
I initially included newton.lys to inspect and verify the json metadata format across different files. Since one test file was enough, I didn't end up wiring it into CMake.
| * Note: Initially thought LYS was a ZIP archive based on the spec docs, but after inspecting | ||
| * the actual file with a hex editor, discovered it's actually a custom binary format. | ||
| * The JSON key is "mangoFiles" not "files" - this was confirmed after checking the data. | ||
| * The geometry .bin file is identified by looking for a .bin entry that is NOT "scene.bin". | ||
| * | ||
| * Important: The data section offset must be calculated as (16 + jsonBlockSize + offset_from_json). | ||
| * Don't hardcode offset 0 for the geometry - always read it from the JSON entry. | ||
| * The mesh .bin header is 12 bytes: indexCount (uint32), coordCount (uint32), reserved (uint32). | ||
| * The index buffer starts at byte 12, immediately after the mesh header. |
There was a problem hiding this comment.
lets not mention your own thoughts, instead focus on factual info about the file format and how it is strucutured.
Also add links that helped you figure out that structure
There was a problem hiding this comment.
Will rewrite the doc comment to describe only factual format details and remove the personal discovery
notes. I'll also add links to the Lychee Slicer documentation/spec.
| // Full string search is used here instead of full JSON parsing. | ||
| // Performance can be evaluated later if needed. | ||
| std::vector<char> jsonBuf(jsonLen); |
There was a problem hiding this comment.
defintely better to do a proper json parsing, its just metadata anyway right ? it does not scale with data size ?
There was a problem hiding this comment.
I'll replace the string search in CanReadFile with a proper nlohmann::json::parse - the json block is metadata only, so it won't scale with mesh data size and the overhead is negligible.
| //---------------------------------------------------------------------------- | ||
| namespace | ||
| { | ||
| uint32_t ReadU32LE(const unsigned char* buf, size_t offset) |
There was a problem hiding this comment.
not following why this is needed, a reinterpret_cast should work right ?
There was a problem hiding this comment.
The helper avoids potential undefined behavior from unaligned reads.But I can replace it with memcpy into a uint32_t local variable, which is both safe and as readable. Or if you prefer, I can use reinterpret_cast — the buffer is std::vector so alignment is technically not guaranteed, but in practice it works. What do you prefer?
There was a problem hiding this comment.
just read directly into a uint32_t ?
| stream = fileStream; | ||
| } | ||
| // Read the 16-byte container header | ||
| // bytes 0- 3 : unknown |
There was a problem hiding this comment.
unknown ? what does it contains ? is it always the same ?
There was a problem hiding this comment.
I checked the hex dumps for both bunny.lys and newton.lys to analyze the container header:bytes 0–3 constant container version (4). I'll add a check in CanReadFile to validate this version integer.bytes 8–11 Varies per file (always jsonBlockSize - 4), acting as an unpadded/intermediate chunk descriptor size field.I will update the comments in vtkF3DLYSReader.cxx and add the version check to CanReadFile.
| // Read the 16-byte container header | ||
| // bytes 0- 3 : unknown | ||
| // bytes 4- 7 : padded JSON block size (uint32 LE) - includes trailing alignment bytes | ||
| // bytes 8-11 : unknown |
There was a problem hiding this comment.
unknown ? what does it contains ? is it always the same ?
| // Assuming string format based on bunny.lys observation. | ||
| // TODO: may need to handle numeric offset if future LYS versions change this. |
There was a problem hiding this comment.
I suppose you checked other files ?
There was a problem hiding this comment.
I verified both bunny.lys and newton.lys and found that offset is stored as a string,while size is an integer.However, since I can't guarantee how older or future LYS format versions handle this,mentioned it as TODO.
There was a problem hiding this comment.
It should be more like a XXX cause there is nothing to do.
| for (auto it = mangoFiles.begin(); it != mangoFiles.end(); ++it) | ||
| { | ||
| const std::string& key = it.key(); | ||
| if (key.size() >= 4 && key.substr(key.size() - 4) == ".bin" && key != "scene.bin") |
There was a problem hiding this comment.
| if (key.size() >= 4 && key.substr(key.size() - 4) == ".bin" && key != "scene.bin") | |
| // The geomtery is the first entry finishing by `.bin` that is not named `scene.bin` | |
| if (key.size() >= 4 && key.substr(key.size() - 4) == ".bin" && key != "scene.bin") |
Also is an entry named .bin without any name in front valid ?
There was a problem hiding this comment.
Will add the suggested comment. Regarding a key named exactly .bin - yes, it would currently match since it ends in .bin and isn't scene.bin. In practice this seems unlikely given the LYS format spec, but I can add
key.size() > 4 to require at least one character before .bin as a safeguard.
| } | ||
|
|
||
| // Round indexCount down to a multiple of 3 to get only complete triangles | ||
| const uint32_t indexCount = (::ReadU32LE(geomBuf.data(), 0) / 3) * 3; |
There was a problem hiding this comment.
what if it contains incomplete triangles ? is the file still valid ?
There was a problem hiding this comment.
Currently I silently round down - if indexCount % 3 != 0, trailing indices are ignored. I haven't found anything in the spec about this. I can add a warning log when this happens, or treat it as an error. What would you prefer?
| // Layout: XYZ float32 triplets, coordCount floats total = coordCount/3 points. | ||
| const float* coords = reinterpret_cast<const float*>(geomBuf.data() + 12 + indexBufSize); | ||
| const vtkIdType nPoints = static_cast<vtkIdType>(coordCount / 3); | ||
| vtkNew<vtkFloatArray> pointData; |
There was a problem hiding this comment.
lets names this differently, like pointArray
| pointData->SetNumberOfTuples(nPoints); | ||
| for (vtkIdType i = 0; i < nPoints; ++i) | ||
| { | ||
| pointData->SetTypedTuple(i, coords + i * 3); |
There was a problem hiding this comment.
I think you can use SetArray instead of copying the data
| return 0; | ||
| } | ||
|
|
||
| triangles->InsertNextCell(3, tri); |
There was a problem hiding this comment.
use SetCells instead, you may even be able to use SetArray depending on memory layout
There was a problem hiding this comment.
for points : I’ll use pointArray->SetArray with save=1 (transferring ownership) so vtk frees the buffer directly, avoiding per-tuple loops.For cells: I’ll validate indices in a quick pass first, then bulk-populate the connectivity arrays and call vtkCellArray::SetData. This gets rid of the InsertNextCell loop while keeping bounds checking safe
| f3d_plugin_declare_reader( | ||
| NAME LYS | ||
| EXTENSIONS lys | ||
| MIMETYPES application/vnd.lys |
There was a problem hiding this comment.
Will add the missing system mimeype declaration. I'll look at how other formats ( the spz reader) declare their mimetypes and follow the same pattern.
mwestphal
left a comment
There was a problem hiding this comment.
Missing:
- Config
- Thumbnail config
- Config test
- Thumbnail test
- Piped test
| - Added a `--dpi-aware` option to rescale font automatically on HiDPI screens (Windows only) | ||
| - Added a `webifc` plugin to add support for .ifc files | ||
| - Added a `pdal` plugin to add support for many point cloud formats, including .las and .laz | ||
| - Added support for `.lys` (Lychee Slicer) files in the native plugin |
There was a problem hiding this comment.
My mistake -I misunderstood the workflow. The changelog entry for v3.5.0 is maintained by the F3D team, not by contributors. I should not have added the lys line myself. I'll remove it in the next commit
| - Box_draco\*: glTF-Sample-Models/Cesium: [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/) | ||
| - BoxAnimated\*: glTF-Sample-Models/Cesium: [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/) | ||
| - Cameras.gltf: glTF-Sample-Models: Public Domain | ||
| - cow.vtk: VTK Data: BSD-3-Clause |
There was a problem hiding this comment.
why did you remove a file ?
There was a problem hiding this comment.
I didn't intentionally remove any file - I accidentally deleted a newline when removing the newton.lys entry.
64216e2 to
ce4722e
Compare
577cfc4 to
ae2da38
Compare
Describe your changes
This PR adds native support for reading Lychee Slicer scene files (
.lys).Key implementation details:
vtkF3DLYSReaderto parse.lysbinary containers.[indexCount, coordCount, reserved])..lysextension with the native plugin.TestF3DLYSReaderunit test along with sample test datasets (bunny.lys,newton.lys).Issue ticket number and link if any
#3341
Checklist for finalizing the PR
.github/workflows/versions.json, I have updateddocker_timestampAI Disclosure
...
Continuous integration
Please write a comment to run CI, eg:
\ci fast.See here for more info.