Skip to content

Conversation

Copy link

Copilot AI commented Dec 25, 2025

PR craftablescience#72 added partial C# bindings for vtfpp but stopped short due to concerns about "nested structs" that the compiler couldn't handle. The solution is to bind directly to the C API layer (vtfppc) which already provides flattened functions that avoid complex struct marshalling.

Changes

  • VTF.cs (761 lines): Complete bindings for all VTF operations

    • 50+ LibraryImport declarations for C API functions
    • Properties: Version, Platform, Flags, Format, MipCount, FrameCount, FaceCount, Depth, StartFrame, BumpmapScale, ThumbnailFormat/Width/Height, ResourcesCount, CompressionLevel/Method, IsSRGB, HasImageData/HasThumbnailData
    • Methods: GetReflectivity, SetReflectivity, ComputeReflectivity, SetFormat, ComputeMips, SetFaceCount, GetPaddedWidth/Height, Bake, BakeToFile, GetThumbnailDataAsRGBA8888, SetThumbnail, ComputeThumbnail, RemoveThumbnail, GetResourceAtIndex, GetResourceWithType
    • Resource class with type-safe accessors for CRC, LOD, extended flags, and keyvalues data
  • ImageFormats.cs (318 lines, from PR vtfpp: C# bindings craftablescience/sourcepp#72): ImageFormat enum and ImageFormatDetails/ImageDimensions utility classes

  • CMakeLists.txt: Enabled CSHARP flag for vtfpp

  • Tests: Added test project with ImageFormatDetailsTest and VTFTest (configurable test data path via environment variable)

Example Usage

using vtfpp;

// Open and inspect a VTF file
var vtf = VTF.OpenFromFile("texture.vtf");
Console.WriteLine($"Version: {vtf.Version}, Format: {vtf.Format}");
Console.WriteLine($"Size: {vtf.GetWidth()}x{vtf.GetHeight()}, Mips: {vtf.MipCount}");

// Get image data
byte[] rgba = vtf.GetImageDataAsRGBA8888(mip: 0, frame: 0, face: 0, slice: 0);

// Modify properties
vtf.Flags |= VTFFlags.SRGB;
vtf.ComputeReflectivity();
vtf.ComputeThumbnail();

// Save
vtf.BakeToFile("modified.vtf");

All bindings use LibraryImport for AOT compatibility and follow patterns established by vpkpp/vcryptpp C# bindings.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • gitlab.com
    • Triggering command: /usr/lib/git-core/git-remote-https /usr/lib/git-core/git-remote-https origin REDACTED src.c.c -dumpbase-ext FYk -mavx2 -mbmi2 -mtune=generic -march=x86-64 -std=c11 -fno-lto -plu�� /usr/libexec/gcc/x86_64-linux-gnu/13/liblto_plugin.so epp/build/_deps/tsl_hat_trie-subbuild/tsl_hat_trie-populate-prefix/src/tsl_hat_trie-populate-sta-fno-lto inja -plugin-opt=-pasas -plugin-opt=-pas--64 d86c7.dir/ inja (dns block)
    • Triggering command: /usr/lib/git-core/git-remote-https /usr/lib/git-core/git-remote-https origin REDACTED make LOG_�� mi2 -mtune=cascadelake -fno-lto -std=c11 -fPIE -o CMakeFiles/cmTC_c9f3b.dir/src.c.o -c /home/REDACTED/work/sourcepp/sourcepp/build/CMakeFiles/CMakeScratch/TryCompile-dhzFYk/src 86_avx2.cpp.o /home/REDACTED/.local/bin/make --noprofile epp/build/_deps/-C 13 h/TryCompile-znJ-t --ve�� (dns block)
    • Triggering command: /usr/lib/git-core/git-remote-https /usr/lib/git-core/git-remote-https origin REDACTED e/git -c /usr/bin/c++ --plugin-opt=-pass-through=-lgcc 86_avx2.cpp.o inja /sourcepp/build//usr/bin/cc izip-ng-populate-DHAVE_SSE2_INTRIN /usr/local/sbin/-msse2 inja --ve�� epp/build/_deps/-fPIE bash /usr/bin/gettextCMakeFiles/cmTC_d664b.dir/src.c.o in.so /lto-wrapper /snap/bin/git gettext (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

Below is a markdown doc of a chat just now, where you detailed how to fully implement C# bindings for vtfpp. Fully implement your solution, and make a pull request.

Copilot Chat Conversation Export: Implementing C# bindings for vtfpp library

User: @tsa96
Thread URL: https://github.com/copilot/c/669c0991-51de-4ecf-ab0e-9152ddd1dd81

@tsa96

Changes to lang/csharp/* stuff here is adding partial C# bindings to vtfpp (C++ library). The code with committed with the comment "Very basic VTF bindings. I would've implemented the rest but the compiler isn't privy to nested structs :(". I dunno what that means, but figure it out and implement the rest somehow

Copilot

@tsa96

Changes to lang/csharp/* stuff here is adding partial C# bindings to vtfpp (C++ library). The code with committed with the comment "Very basic VTF bindings. I would've implemented the rest but the compiler isn't privy to nested structs :(". I dunno what that means, but figure it out and implement the rest somehow

Copilot

I'll analyze the partial C# bindings for vtfpp and implement the missing functionality. The comment about "nested structs" likely refers to P/Invoke limitations with complex nested structures in C#.

Let me first examine the existing C++ code to understand what's missing and then search for any C bindings that might exist. Let me look at more of the C bindings to understand the pattern better, particularly looking at VTF and the structures: Based on my analysis of the code, I can see the issue. The commit message mentions "the compiler isn't privy to nested structs". Looking at the C# bindings and comparing them with the C API, I can see that several complex structures from the C API haven't been implemented in C#, particularly:

  1. vtfpp_vtf_creation_options_t - A large struct with many fields (lines 121-143 in VTF.h)
  2. vtfpp_hot_rect_t - A nested struct for hotspot rectangles
  3. vtfpp_sht_sequence_t and related frame structures
  4. Resource-related structures and their complex accessors

The problem is that C# LibraryImport (which is used for Native AOT compatibility) has limitations with complex structs, especially those with nested members or arrays. The developer only implemented the simple parts (basic VTF reading, image format details) but couldn't complete the bindings that require passing complex structs between C# and native code.

Let me create a comprehensive issue to document what needs to be done: Based on my analysis of the code, I can explain what the developer meant by "the compiler isn't privy to nested structs" and provide guidance on how to complete the bindings.

The Problem

The issue is that C# P/Invoke and LibraryImport cannot directly marshal nested C++ structs or complex C++ types. The current implementation only exposes very basic VTF operations (open, close, get image data) but doesn't expose:

  • VTF header information (version, width, height, flags, etc.)
  • Resource types and metadata
  • Complex struct types that are nested within other types
  • Thumbnail, fallback data access
  • Many other VTF features

Looking at the C API header (lang/c/include/vtfppc/VTF.h), there are already many extern C functions defined (lines 176-405) that the C# bindings haven't wrapped yet!

The Solution

The existing C library already has the flattened API you need. You just need to add C# bindings for all those existing C functions. Here's what needs to be done:

1. Add Missing LibraryImport Declarations

In VTF.cs, add declarations for all the C functions that are already defined in the C library. For example:

// Version info
[LibraryImport("sourcepp_vtfppc", EntryPoint = "vtfpp_vtf_get_version")]
public static partial uint VTFGetVersion(void* handle);

[LibraryImport("sourcepp_vtfppc", EntryPoint = "vtfpp_vtf_set_version")]
public static partial void VTFSetVersion(void* handle, uint version);

// Platform info
[LibraryImport("sourcepp_vtfppc", EntryPoint = "vtfpp_vtf_get_platform")]
public static partial VTFPlatform VTFGetPlatform(void* handle);

// Flags
[LibraryImport("sourcepp_vtfppc", EntryPoint = "vtfpp_vtf_get_flags")]
public static partial uint VTFGetFlags(void* handle);

[LibraryImport("sourcepp_vtfppc", EntryPoint = "vtfpp_vtf_set_flags")]
public static partial void VTFSetFlags(void* handle, uint flags);

// Format
[LibraryImport("sourcepp_vtfppc", EntryPoint = "vtfpp_vtf_get_format")]
public static partial ImageFormat VTFGetFormat(void* handle);

// Mip count
[LibraryImport("sourcepp_vtfppc", EntryPoint = "vtfpp_vtf_get_mip_count")]
public static partial byte VTFGetMipCount(void* handle);

// Frame count
[LibraryImport("sourcepp_vtfppc", EntryPoint = "vtfpp_vtf_get_frame_count")]
public static partial ushort VTFGetFrameCount(void* handle);

// Face count
[LibraryImport("sourcepp_vtfppc", EntryPoint = "vtfpp_vtf_get_face_count")]
public static partial byte VTFGetFaceCount(void* handle);

// Reflectivity
[LibraryIm...

</details>



<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

Copilot AI and others added 4 commits December 25, 2025 19:30
Co-authored-by: tsa96 <35813309+tsa96@users.noreply.github.com>
Co-authored-by: tsa96 <35813309+tsa96@users.noreply.github.com>
…compile

Co-authored-by: tsa96 <35813309+tsa96@users.noreply.github.com>
… public

Co-authored-by: tsa96 <35813309+tsa96@users.noreply.github.com>
Copilot AI changed the title [WIP] Fully implement C# bindings for vtfpp library Implement complete C# bindings for vtfpp Dec 25, 2025
Copilot AI requested a review from tsa96 December 25, 2025 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants