Repository navigation
Conversation
KnifeLemon
left a comment
There was a problem hiding this comment.
Thanks @ltsammy, this is a clean addition. It follows the PDN wiring closely and reads and writes VTF with no new dependency. I checked the header offsets (the 7.2 depth field, the 7.3+ resource list), the cube-map face count, the mipmap → frame → face → slice layout and the DXT decoding against VTFLib's layout, and they line up. The writer's order (thumbnail, then the smallest mipmap first, every frame per mipmap) matches too.
Two things before it can go in:
-
Size limits in
Vtf.cs. Filee opens files from anywhere, so the reader needs a tighter budget and 64-bit size math:MaxPixelsallows about 1.07 billion pixels and there's no limit per side. A DXT1 file of roughly 512 MB makes Filee allocate 4 GB of RGBA, plus the same again inside ImageMagick. Our other readers stay at or under 256 million pixels (PaintNet.MaxPixels).DataSizeandnew byte[width * height * 4]multiply inint. A 100-byte header claiming 65535 × 16384 RGBA8888 passes the budget check.DataSizethen comes out negative, slips past thestart + imageSize > data.Lengthcheck, and fails inAsSpanwith anArgumentOutOfRangeExceptioninstead of a clear "too large" message.
Suggested fix:
- Return
longfromDataSize. - Cap each side (16384 is plenty) and the total at
PaintNet.MaxPixels. - Compare the expected data length with
data.Lengthaslong. - A test with an oversized header and one with truncated data would cover it.
-
CI hasn't run on this repository yet. It's waiting for approval on our side. We'll start it, and look again once it's green on all platforms.
Small things, take them or leave them:
mipmapscomes from a byte. Shifts of 32 or more wrap in C# (Width >> 33isWidth >> 1), so rejecting a count above1 + log2(max(width, height))keeps the offset math honest.VtfWriter.Writecaps frames only atushort.MaxValue, so it can write a texture the reader then refuses (e.g. 65 frames at 4096²). The same budget in the writer would keep them in step.- Please add
Closes #1478to the description.
Thanks for the careful write-up and the srctools cross-check!
…the Source engine Pictures become a version 7.2 VTF as VTFEdit writes it by default: sides rounded to the nearest power of two, every mipmap, DXT1 when opaque and DXT5 with transparency, a DXT1 thumbnail and the reflectivity. An animation becomes an animated texture. VTF 7.0 to 7.5 is read (DXT1/3/5 and the uncompressed formats), so textures convert back to PNG and the other pictures. VTF belongs to the Games field; .vtf files learn the images donut (schema 90).
Review of KnifeLemon#1483: a side is at most 16,384 px and every frame together at most PaintNet.MaxPixels, sizes are counted in 64 bits, a file holding less image data than its header claims is refused before anything is decoded, and so is one claiming more mipmaps than its sides allow. The writer keeps to the same budget, so every texture Filee writes can be read back.
|
Thanks for the thorough review! All points are addressed in 66c7dfc, on top of a rebase onto current main:
CI on my fork is green on Windows x64, Windows ARM64 and the Linux packages. The macOS arm64 job there never got a runner, which is unrelated to the change. |
What does this change?
Adds VTF (Valve Texture Format), the texture format of the Source engine: Garry's Mod, Counter-Strike: Source, Team Fortress 2 and Half-Life 2 mods. Modders currently need VTFEdit (Windows only, and it needs VTFLib) to turn a PNG into a texture. With this PR Filee does it with a drag.
Filee reads and writes VTF itself, so it needs no new package and no native DLL. It is wired into the image engine the same way as PDN.
Closes #1478
Type of change
How was it tested?
dotnet format --verify-no-changes(CI on the fork)dotnet test(CI on the fork: Windows x64, Windows ARM64, Linux portable packages, all green)Checklist
src/Filee.App/Assets/i18n/*.jsonfiles (none added; the format name comes fromFormatRegistry)THIRD-PARTY-NOTICES.md(none added)Details
Writing (picture → VTF)
vtfjoinsMultiFrame.Reading (VTF → picture)
PaintNet.MaxPixels, it claims more mipmaps than its sides allow, or it holds less image data than its header claims. Sizes are counted in 64 bits. The writer keeps to the same budget (16 frames at 4096 × 4096), so Filee reads back every texture it writes.Where it goes
FormatRegistry:vtf, Image category, writable.FormatFields: graded specialist, Games field only. Following the admission rule, it is a target only where the Games field is on..vtflearns the images donut, and custom claims stay put. (89 went to.krcon main; the number may need renumbering again if another change takes 90 first.)ImageEncoder/ImageReader/ImageJoiner/MagickImageConverter: wired in like PDN (Packages,MaxSide,Write,WriteImage, edges,CanWrite).docs/ENGINES.mddescribe the format.The
.vmtmaterial that points to a texture is not written. Its$basetexturepath depends on where the texture ends up undermaterials/, which Filee can't know.Tests
VtfFormatTests(Core): detection, images donut, grade and field, migration from schema 89.VtfTests(Engines):FormatFieldsTests: updated pinned lists and the specialist count (123 → 124).The layout was also checked against an independent reader, srctools'
VTF.read, during development.