sourcepp 2024.11.5.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ # Keep most Python-specific stuff in the root .gitignore
2
+ # because scikit-build-core will use it to ignore everything
3
+ # you want to ship!!!!!!!! This took like an hour to figure
4
+ # out, thanks folks :D
5
+
6
+ # Anyway
7
+
8
+ dist/
9
+ wheelhouse/
@@ -0,0 +1,39 @@
1
+ # Load this to build the sourcepp Python package
2
+
3
+ cmake_minimum_required(VERSION 3.25 FATAL_ERROR)
4
+ set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE INTERNAL "" FORCE)
5
+ project(sourcepp_python)
6
+
7
+ if (NOT SKBUILD)
8
+ message(WARNING "\
9
+ This CMake file is meant to be executed using 'scikit-build-core'.
10
+ Running it directly will almost certainly not produce the desired
11
+ result. If you are a user trying to install this package, use the
12
+ command below, which will install all necessary build dependencies,
13
+ compile the package in an isolated environment, and then install it.
14
+ =====================================================================
15
+ $ pip install .
16
+ =====================================================================
17
+ If you are a software developer, and this is your own package, then
18
+ it is usually much more efficient to install the build dependencies
19
+ in your environment once and use the following command that avoids
20
+ a costly creation of a new virtual environment at every compilation:
21
+ =====================================================================
22
+ $ pip install nanobind scikit-build-core[pyproject]
23
+ $ pip install --no-build-isolation -ve .
24
+ =====================================================================
25
+ You may optionally add -Ceditable.rebuild=true to auto-rebuild when
26
+ the package is imported. Otherwise, you need to rerun the above
27
+ after editing C++ files.")
28
+ endif()
29
+
30
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
31
+
32
+ # As weird as this looks, this is necessary for sdist wheel
33
+ include(FetchContent)
34
+ FetchContent_Declare(
35
+ sourcepp
36
+ GIT_REPOSITORY "https://github.com/craftablescience/sourcepp.git"
37
+ GIT_TAG "origin/main")
38
+ set(SOURCEPP_BUILD_PYTHON_WRAPPERS ON CACHE INTERNAL "" FORCE)
39
+ FetchContent_MakeAvailable(sourcepp)
@@ -0,0 +1,345 @@
1
+ Metadata-Version: 2.1
2
+ Name: sourcepp
3
+ Version: 2024.11.5.dev1
4
+ Summary: Several modern C++20 libraries for sanely parsing Valve formats.
5
+ Home-page: https://github.com/craftablescience/sourcepp
6
+ Author-Email: craftablescience <lauralewisdev@gmail.com>
7
+ Maintainer-Email: craftablescience <lauralewisdev@gmail.com>
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3 :: Only
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Project-URL: Homepage, https://github.com/craftablescience/sourcepp
17
+ Project-URL: Repository, https://github.com/craftablescience/sourcepp
18
+ Project-URL: Issue tracker, https://github.com/craftablescience/sourcepp/issues
19
+ Project-URL: Funding, https://ko-fi.com/craftablescience
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+
23
+ <div>
24
+ <img align="left" width="101px" src="https://github.com/craftablescience/sourcepp/blob/main/branding/logo.png?raw=true" alt="The Source Pretty Parsers logo. A printer-esque device is scanning a page with hex codes and printing a picture of Cordon Freeman." />
25
+ <h1>Source Pretty Parsers</h1>
26
+ </div>
27
+
28
+ ![Build Status](https://img.shields.io/github/actions/workflow/status/craftablescience/sourcepp/build.yml?label=Build&logo=github&logoColor=%23FFFFFF)
29
+ ![License](https://img.shields.io/github/license/craftablescience/sourcepp?label=License&logo=libreofficewriter&logoColor=%23FFFFFF)
30
+ ![Discord](https://img.shields.io/discord/678074864346857482?label=Discord&logo=Discord&logoColor=%23FFFFFF)
31
+ ![Ko-fi](https://img.shields.io/badge/donate-006dae?label=Ko-fi&logo=ko-fi)
32
+
33
+ Several modern C++20 libraries for sanely parsing Valve formats, rolled into one big repository.
34
+
35
+ ## Included Libraries
36
+
37
+ <table>
38
+ <tr>
39
+ <th>Name</th>
40
+ <th>Supports</th>
41
+ <th>Read</th>
42
+ <th>Write</th>
43
+ <th>Wrappers</th>
44
+ </tr>
45
+ <tr><!-- empty row to disable github striped bg color --></tr>
46
+ <tr>
47
+ <td rowspan="1"><code>bsppp</code><sup>*</sup></td>
48
+ <td><a href="https://developer.valvesoftware.com/wiki/BSP_(Source)">BSP</a> v17-27</td>
49
+ <td align="center">✅</td>
50
+ <td align="center">✅</td>
51
+ <td rowspan="1" align="center"></td>
52
+ </tr>
53
+ <tr><!-- empty row to disable github striped bg color --></tr>
54
+ <tr>
55
+ <td rowspan="1"><code>dmxpp</code><sup>*</sup></td>
56
+ <td><a href="https://developer.valvesoftware.com/wiki/DMX">DMX</a> Binary v1-5</td>
57
+ <td align="center">✅</td>
58
+ <td align="center">❌</td>
59
+ <td rowspan="1" align="center"></td>
60
+ </tr>
61
+ <tr><!-- empty row to disable github striped bg color --></tr>
62
+ <tr>
63
+ <td rowspan="3"><code>gamepp</code></td>
64
+ <td>Get Source engine instance window title/position/size</td>
65
+ <td align="center">✅</td>
66
+ <td align="center">❌</td>
67
+ <td rowspan="3" align="center">C<br>Python</td>
68
+ </tr>
69
+ <tr><!-- empty row to disable github striped bg color --></tr>
70
+ <tr>
71
+ <td>Run commands in a Source engine instance remotely</td>
72
+ <td align="center">❌</td>
73
+ <td align="center">✅</td>
74
+ </tr>
75
+ <tr><!-- empty row to disable github striped bg color --></tr>
76
+ <tr>
77
+ <td rowspan="1"><code>kvpp</code></td>
78
+ <td><a href="https://developer.valvesoftware.com/wiki/KeyValues">KeyValues</a> Text v1<sup>&dagger;</sup></td>
79
+ <td align="center">✅</td>
80
+ <td align="center">✅</td>
81
+ <td rowspan="1" align="center"></td>
82
+ </tr>
83
+ <tr><!-- empty row to disable github striped bg color --></tr>
84
+ <tr>
85
+ <td rowspan="5"><code>mdlpp</code><sup>*</sup></td>
86
+ <td><a href="https://developer.valvesoftware.com/wiki/MDL_(Source)">MDL</a> v44-49</td>
87
+ <td align="center">✅</td>
88
+ <td align="center">❌</td>
89
+ <td rowspan="5" align="center"></td>
90
+ </tr>
91
+ <tr><!-- empty row to disable github striped bg color --></tr>
92
+ <tr>
93
+ <td><a href="https://developer.valvesoftware.com/wiki/VTX">VTX</a> v7</td>
94
+ <td align="center">✅</td>
95
+ <td align="center">❌</td>
96
+ </tr>
97
+ <tr><!-- empty row to disable github striped bg color --></tr>
98
+ <tr>
99
+ <td><a href="https://developer.valvesoftware.com/wiki/VVD">VVD</a> v4</td>
100
+ <td align="center">✅</td>
101
+ <td align="center">❌</td>
102
+ </tr>
103
+ <tr><!-- empty row to disable github striped bg color --></tr>
104
+ <tr>
105
+ <td rowspan="3"><code>steampp</code></td>
106
+ <td>Find Steam install folder</td>
107
+ <td align="center">✅</td>
108
+ <td align="center">-</td>
109
+ <td rowspan="3" align="center">C<br>Python</td>
110
+ </tr>
111
+ <tr><!-- empty row to disable github striped bg color --></tr>
112
+ <tr>
113
+ <td>Find installed Steam games</td>
114
+ <td align="center">✅</td>
115
+ <td align="center">-</td>
116
+ </tr>
117
+ <tr><!-- empty row to disable github striped bg color --></tr>
118
+ <tr>
119
+ <td rowspan="3"><code>toolpp</code></td>
120
+ <td>
121
+ <a href="https://developer.valvesoftware.com/wiki/FGD">FGD (Source 1)</a>
122
+ <br> &bull; <a href="https://ficool2.github.io/HammerPlusPlus-Website">Hammer++</a> modifications
123
+ <br> &bull; <a href="https://stratasource.org">Strata Source</a> modifications
124
+ </td>
125
+ <td align="center">✅</td>
126
+ <td align="center">✅</td>
127
+ <td rowspan="3" align="center"></td>
128
+ </tr>
129
+ <tr><!-- empty row to disable github striped bg color --></tr>
130
+ <tr>
131
+ <td>
132
+ <a href="https://developer.valvesoftware.com/wiki/Command_Sequences">WC</a> (CmdSeq) v0.1-0.2
133
+ <br> &bull; <a href="https://stratasource.org">Strata Source</a> modifications
134
+ </td>
135
+ <td align="center">✅</td>
136
+ <td align="center">✅</td>
137
+ </tr>
138
+ <tr><!-- empty row to disable github striped bg color --></tr>
139
+ <tr>
140
+ <td rowspan="3"><code>vcryptpp</code></td>
141
+ <td><a href="https://developer.valvesoftware.com/wiki/VICE">VICE</a> encrypted files</td>
142
+ <td align="center">✅</td>
143
+ <td align="center">✅</td>
144
+ <td rowspan="3" align="center">C<br>C#<br>Python</td>
145
+ </tr>
146
+ <tr><!-- empty row to disable github striped bg color --></tr>
147
+ <tr>
148
+ <td><a href="https://developer.valvesoftware.com/wiki/Vfont">VFONT</a> encrypted fonts</td>
149
+ <td align="center">✅</td>
150
+ <td align="center">❌</td>
151
+ </tr>
152
+ <tr><!-- empty row to disable github striped bg color --></tr>
153
+ <tr>
154
+ <td rowspan="25"><code>vpkpp</code></td>
155
+ <td><a href="https://developer.valvesoftware.com/wiki/Bonus_Maps">BMZ</a></td>
156
+ <td align="center">✅</td>
157
+ <td align="center">✅</td>
158
+ <td rowspan="25" align="center">C<br>C#</td>
159
+ </tr>
160
+ <tr><!-- empty row to disable github striped bg color --></tr>
161
+ <tr>
162
+ <td><a href="https://developer.valvesoftware.com/wiki/BSP_(Source)">BSP</a> v17-27</td>
163
+ <td align="center">✅</td>
164
+ <td align="center">✅</td>
165
+ </tr>
166
+ <tr><!-- empty row to disable github striped bg color --></tr>
167
+ <tr>
168
+ <td>FPX v10 (Tactical Intervention)</td>
169
+ <td align="center">✅</td>
170
+ <td align="center">✅</td>
171
+ </tr>
172
+ <tr><!-- empty row to disable github striped bg color --></tr>
173
+ <tr>
174
+ <td><a href="https://developer.valvesoftware.com/wiki/GCF_archive">GCF</a> v6</td>
175
+ <td align="center">✅</td>
176
+ <td align="center">❌</td>
177
+ </tr>
178
+ <tr><!-- empty row to disable github striped bg color --></tr>
179
+ <tr>
180
+ <td>GMA v1-3 (Garry's Mod)</td>
181
+ <td align="center">✅</td>
182
+ <td align="center">✅</td>
183
+ </tr>
184
+ <tr><!-- empty row to disable github striped bg color --></tr>
185
+ <tr>
186
+ <td><a href="https://quakewiki.org/wiki/.pak">PAK</a> (Quake, WON Half-Life)</td>
187
+ <td align="center">✅</td>
188
+ <td align="center">✅</td>
189
+ </tr>
190
+ <tr><!-- empty row to disable github striped bg color --></tr>
191
+ <tr>
192
+ <td><a href="https://docs.godotengine.org/en/stable/tutorials/export/exporting_pcks.html">PCK</a> v1-2 (Godot Engine)</td>
193
+ <td align="center">✅</td>
194
+ <td align="center">✅</td>
195
+ </tr>
196
+ <tr><!-- empty row to disable github striped bg color --></tr>
197
+ <tr>
198
+ <td><a href="https://doomwiki.org/wiki/PK3">PK3</a> (Quake III)</td>
199
+ <td align="center">✅</td>
200
+ <td align="center">✅</td>
201
+ </tr>
202
+ <tr><!-- empty row to disable github striped bg color --></tr>
203
+ <tr>
204
+ <td><a href="https://doomwiki.org/wiki/PK4">PK4</a> (Quake IV, Doom 3)</td>
205
+ <td align="center">✅</td>
206
+ <td align="center">✅</td>
207
+ </tr>
208
+ <tr><!-- empty row to disable github striped bg color --></tr>
209
+ <tr>
210
+ <td>
211
+ <a href="https://developer.valvesoftware.com/wiki/VPK">VPK</a> pre-v1, v1-2, v54
212
+ <br> &bull; <a href="https://www.counter-strike.net/cs2">Counter-Strike: 2</a> modifications
213
+ <br> &bull; <a href="https://clientmod.ru">Counter-Strike: Source ClientMod</a> modifications
214
+ </td>
215
+ <td align="center">✅</td>
216
+ <td align="center">✅</td>
217
+ </tr>
218
+ <tr><!-- empty row to disable github striped bg color --></tr>
219
+ <tr>
220
+ <td>VPK (Vampire: The Masquerade - Bloodlines)</td>
221
+ <td align="center">✅</td>
222
+ <td align="center">✅</td>
223
+ </tr>
224
+ <tr><!-- empty row to disable github striped bg color --></tr>
225
+ <tr>
226
+ <td>WAD v3</td>
227
+ <td align="center">✅</td>
228
+ <td align="center">✅</td>
229
+ </tr>
230
+ <tr><!-- empty row to disable github striped bg color --></tr>
231
+ <tr>
232
+ <td>ZIP</td>
233
+ <td align="center">✅</td>
234
+ <td align="center">✅</td>
235
+ </tr>
236
+ <tr><!-- empty row to disable github striped bg color --></tr>
237
+ <tr>
238
+ <td rowspan="23"><code>vtfpp</code></td>
239
+ <td><a href="https://en.wikipedia.org/wiki/BMP_file_format">BMP</a></td>
240
+ <td align="center">✅</td>
241
+ <td align="center">✅</td>
242
+ <td rowspan="23" align="center">Python</td>
243
+ </tr>
244
+ <tr><!-- empty row to disable github striped bg color --></tr>
245
+ <tr>
246
+ <td><a href="https://openexr.com">EXR</a> v1</td>
247
+ <td align="center">✅</td>
248
+ <td align="center">✅</td>
249
+ </tr>
250
+ <tr><!-- empty row to disable github striped bg color --></tr>
251
+ <tr>
252
+ <td><a href="https://en.wikipedia.org/wiki/GIF">GIF</a></td>
253
+ <td align="center">✅</td>
254
+ <td align="center">❌</td>
255
+ </tr>
256
+ <tr><!-- empty row to disable github striped bg color --></tr>
257
+ <tr>
258
+ <td><a href="https://en.wikipedia.org/wiki/RGBE_image_format">HDR</a></td>
259
+ <td align="center">✅</td>
260
+ <td align="center">✅</td>
261
+ </tr>
262
+ <tr><!-- empty row to disable github striped bg color --></tr>
263
+ <tr>
264
+ <td><a href="https://en.wikipedia.org/wiki/JPEG">JPEG</a></td>
265
+ <td align="center">✅</td>
266
+ <td align="center">✅</td>
267
+ </tr>
268
+ <tr><!-- empty row to disable github striped bg color --></tr>
269
+ <tr>
270
+ <td>PIC</td>
271
+ <td align="center">✅</td>
272
+ <td align="center">❌</td>
273
+ </tr>
274
+ <tr><!-- empty row to disable github striped bg color --></tr>
275
+ <tr>
276
+ <td><a href="https://en.wikipedia.org/wiki/PNG">PNG</a></td>
277
+ <td align="center">✅</td>
278
+ <td align="center">✅</td>
279
+ </tr>
280
+ <tr><!-- empty row to disable github striped bg color --></tr>
281
+ <tr>
282
+ <td><a href="https://netpbm.sourceforge.net/doc/pnm.html">PNM</a> (PGM, PPM)</td>
283
+ <td align="center">✅</td>
284
+ <td align="center">❌</td>
285
+ </tr>
286
+ <tr><!-- empty row to disable github striped bg color --></tr>
287
+ <tr>
288
+ <td><a href="https://developer.valvesoftware.com/wiki/PPL">PPL</a> v0</td>
289
+ <td align="center">✅</td>
290
+ <td align="center">✅</td>
291
+ </tr>
292
+ <tr><!-- empty row to disable github striped bg color --></tr>
293
+ <tr>
294
+ <td><a href="https://www.adobe.com/creativecloud/file-types/image/raster/psd-file.html">PSD</a></td>
295
+ <td align="center">✅</td>
296
+ <td align="center">❌</td>
297
+ </tr>
298
+ <tr><!-- empty row to disable github striped bg color --></tr>
299
+ <tr>
300
+ <td><a href="https://en.wikipedia.org/wiki/Truevision_TGA">TGA</a></td>
301
+ <td align="center">✅</td>
302
+ <td align="center">✅</td>
303
+ </tr>
304
+ <tr><!-- empty row to disable github striped bg color --></tr>
305
+ <tr>
306
+ <td>
307
+ <a href="https://developer.valvesoftware.com/wiki/VTF_(Valve_Texture_Format)">VTF</a> v7.0-7.6
308
+ <br> &bull; <a href="https://stratasource.org">Strata Source</a> modifications
309
+ </td>
310
+ <td align="center">✅</td>
311
+ <td align="center">✅</td>
312
+ </tr>
313
+ </table>
314
+
315
+ (\*) These libraries are incomplete and still in development. Their interfaces are unstable and will likely change in the future.
316
+ Libraries not starred should be considered stable, and their existing interfaces will not change much if at all. Note that wrappers
317
+ only exist for stable libraries.
318
+
319
+ (&dagger;) Many text-based formats in Source are close to (if not identical to) KeyValues v1, such as [VMT](https://developer.valvesoftware.com/wiki/VMT) and [VMF](https://developer.valvesoftware.com/wiki/VMF_(Valve_Map_Format)).
320
+
321
+ ## Wrappers
322
+
323
+ Wrappers for libraries considered complete exist for C, C#, and/or Python, depending on the library. The Python wrappers can be
324
+ found on PyPI in the `sourcepp` package.
325
+
326
+ ## Special Thanks
327
+
328
+ - `steampp` is based on the [SteamAppPathProvider](https://github.com/Trico-Everfire/SteamAppPathProvider) library by [@Trico Everfire](https://github.com/Trico-Everfire) and [Momentum Mod](https://momentum-mod.org) contributors.
329
+ - `vpkpp`'s GCF parser was contributed by [@bt](https://github.com/caatge) and [@ymgve](https://github.com/ymgve).
330
+ - `vpkpp`'s WAD3 parser was contributed by [@ozxybox](https://github.com/ozxybox).
331
+ - `vtfpp`'s write support is based on work by [@Trico Everfire](https://github.com/Trico-Everfire).
332
+
333
+ ## Gallery
334
+
335
+ A list of projects using the `sourcepp` parser set. If you'd like to see your project here, make a PR!
336
+
337
+ - [VPKEdit](https://github.com/craftablescience/VPKEdit): An open source MIT-licensed tool that can create, extract from,
338
+ preview the contents of and write to several pack file formats. A CLI application is bundled with the program which replicates
339
+ the functionality of Valve's `vpk.exe`.
340
+ - [GodotSource](https://github.com/craftablescience/godotsource): A work-in-progress set of bindings to connect the `sourcepp`
341
+ libraries to Godot. Allows GDScript to work with the libraries, and allows Godot to directly load Source engine assets from
342
+ a user project or from installed Source games.
343
+ - [Verifier](https://github.com/StrataSource/verifier): A small program that can build an index of a game's files, and validate
344
+ existing files based on that index. Think Steam's "Verify integrity of game files" option, but without actually overwriting any
345
+ files. `sourcepp` is used to parse Steam depot configs, as well as enable indexing the contents of VPKs.
@@ -0,0 +1,52 @@
1
+ [build-system]
2
+ requires = ["scikit-build-core >=0.10.7", "nanobind >=1.3.2"]
3
+ build-backend = "scikit_build_core.build"
4
+
5
+
6
+ [project]
7
+ name = "sourcepp"
8
+ version = "2024.11.5dev1" # change __init__.py when this is updated
9
+ authors = [{ name = "craftablescience", email = "lauralewisdev@gmail.com" }]
10
+ maintainers = [{ name = "craftablescience", email = "lauralewisdev@gmail.com" }]
11
+ description = "Several modern C++20 libraries for sanely parsing Valve formats."
12
+ readme = "../../README.md"
13
+ requires-python = ">=3.9"
14
+ classifiers = [
15
+ "License :: OSI Approved :: MIT License",
16
+ "Intended Audience :: Developers",
17
+ "Programming Language :: Python :: 3 :: Only",
18
+ "Programming Language :: Python :: 3.9",
19
+ "Programming Language :: Python :: 3.10",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ ]
24
+
25
+ [project.urls]
26
+ "homepage" = "https://github.com/craftablescience/sourcepp"
27
+ "repository" = "https://github.com/craftablescience/sourcepp"
28
+ "issue tracker" = "https://github.com/craftablescience/sourcepp/issues"
29
+ "funding" = "https://ko-fi.com/craftablescience"
30
+
31
+ [tool.scikit-build]
32
+ minimum-version = "build-system.requires"
33
+ build-dir = "build/{wheel_tag}"
34
+ build.targets = ["sourcepp_python_all"]
35
+ sdist.reproducible = true
36
+ wheel.py-api = "cp312"
37
+ wheel.license-files = ["../../LICENSE", "../../THIRDPARTY_LEGAL_NOTICES.txt"]
38
+ build.verbose = true
39
+ logging.level = "INFO"
40
+
41
+
42
+ [tool.cibuildwheel]
43
+ archs = ["auto64"]
44
+ build-verbosity = 1
45
+ #test-command = "pytest {project}/test"
46
+ #test-requires = "pytest"
47
+
48
+ [tool.cibuildwheel.macos]
49
+ archs = ["arm64"]
50
+
51
+ [tool.cibuildwheel.macos.environment]
52
+ MACOSX_DEPLOYMENT_TARGET = "14.7"
@@ -0,0 +1,31 @@
1
+ #pragma once
2
+
3
+ #include <nanobind/nanobind.h>
4
+ #include <nanobind/stl/optional.h>
5
+ #include <nanobind/stl/string.h>
6
+ #include <nanobind/stl/string_view.h>
7
+
8
+ namespace py = nanobind;
9
+
10
+ #include <gamepp/gamepp.h>
11
+
12
+ namespace gamepp {
13
+
14
+ inline void register_python(py::module_& m) {
15
+ auto gamepp = m.def_submodule("gamepp");
16
+ using namespace gamepp;
17
+
18
+ py::class_<GameInstance>(gamepp, "GameInstance")
19
+ .def_static("find", &GameInstance::find, py::arg("window_name_override") = "")
20
+ .def_prop_ro("window_title", &GameInstance::getWindowTitle)
21
+ .def_prop_ro("window_pos", &GameInstance::getWindowPos)
22
+ .def_prop_ro("window_size", &GameInstance::getWindowSize)
23
+ .def("command", &GameInstance::command, py::arg("command"))
24
+ .def("input_begin", &GameInstance::inputBegin, py::arg("input"))
25
+ .def("input_end", &GameInstance::inputEnd, py::arg("input"))
26
+ .def("input_once", &GameInstance::inputOnce, py::arg("input"))
27
+ .def("input_hold", &GameInstance::inputHold, py::arg("input"), py::arg("sec"))
28
+ .def("wait", &GameInstance::wait, py::arg("sec"));
29
+ }
30
+
31
+ } // namespace gamepp
@@ -0,0 +1,5 @@
1
+ from ._sourcepp_impl import __doc__, gamepp, sourcepp, steampp, vcryptpp, vtfpp
2
+
3
+ __author__ = "craftablescience"
4
+ __version__ = "2024.11.5dev1" # change pyproject.toml version when this is updated
5
+ __all__ = ['__author__', '__doc__', '__version__', 'gamepp', 'sourcepp', 'steampp', 'vcryptpp', 'vtfpp']
@@ -0,0 +1,47 @@
1
+ #include "sourcepp.h"
2
+
3
+ #ifdef GAMEPP
4
+ #include "gamepp.h"
5
+ #endif
6
+
7
+ #ifdef STEAMPP
8
+ #include "steampp.h"
9
+ #endif
10
+
11
+ #ifdef VCRYPTPP
12
+ #include "vcryptpp.h"
13
+ #endif
14
+
15
+ #ifdef VTFPP
16
+ #include "vtfpp.h"
17
+ #endif
18
+
19
+ NB_MODULE(_sourcepp_impl, m) {
20
+ m.doc() = "SourcePP: A Python wrapper around several modern C++20 libraries for sanely parsing Valve's formats.";
21
+
22
+ sourcepp::register_python(m);
23
+
24
+ #ifdef GAMEPP
25
+ gamepp::register_python(m);
26
+ #else
27
+ m.def_submodule("gamepp");
28
+ #endif
29
+
30
+ #ifdef STEAMPP
31
+ steampp::register_python(m);
32
+ #else
33
+ m.def_submodule("steampp");
34
+ #endif
35
+
36
+ #ifdef VCRYPTPP
37
+ vcryptpp::register_python(m);
38
+ #else
39
+ m.def_submodule("vcryptpp");
40
+ #endif
41
+
42
+ #ifdef VTFPP
43
+ vtfpp::register_python(m);
44
+ #else
45
+ m.def_submodule("vtfpp");
46
+ #endif
47
+ }
@@ -0,0 +1,84 @@
1
+ #pragma once
2
+
3
+ #include <string_view>
4
+
5
+ #include <nanobind/nanobind.h>
6
+ #include <nanobind/operators.h>
7
+
8
+ namespace py = nanobind;
9
+
10
+ #include <sourcepp/Math.h>
11
+
12
+ namespace sourcepp {
13
+
14
+ inline void register_python(py::module_& m) {
15
+ auto sourcepp = m.def_submodule("sourcepp");
16
+ using namespace sourcepp;
17
+
18
+ {
19
+ auto math = sourcepp.def_submodule("math");
20
+ using namespace math;
21
+
22
+ const auto registerVecType = [&math]<typename V>(std::string_view name) {
23
+ py::class_<V>(math, name.data())
24
+ .def("__len__", &V::size)
25
+ .def("__setitem__", [](V& self, uint8_t index, typename V::value_type val) { self[index] = val; })
26
+ .def("__getitem__", [](V& self, uint8_t index) { return self[index]; })
27
+ .def_static("zero", &V::zero)
28
+ .def("is_zero", &V::isZero);
29
+ };
30
+
31
+ registerVecType.operator()<Vec2i8>("Vec2i8");
32
+ registerVecType.operator()<Vec2i16>("Vec2i16");
33
+ registerVecType.operator()<Vec2i32>("Vec2i32");
34
+ registerVecType.operator()<Vec2i64>("Vec2i64");
35
+ //registerVecType.operator()<Vec2i>("Vec2i");
36
+
37
+ registerVecType.operator()<Vec2ui8>("Vec2ui8");
38
+ registerVecType.operator()<Vec2ui16>("Vec2ui16");
39
+ registerVecType.operator()<Vec2ui32>("Vec2ui32");
40
+ registerVecType.operator()<Vec2ui64>("Vec2ui64");
41
+ //registerVecType.operator()<Vec2ui>("Vec2ui");
42
+
43
+ //registerVecType.operator()<Vec2f16>("Vec2f16");
44
+ registerVecType.operator()<Vec2f32>("Vec2f32");
45
+ registerVecType.operator()<Vec2f64>("Vec2f64");
46
+ //registerVecType.operator()<Vec2f>("Vec2f");
47
+
48
+ registerVecType.operator()<Vec3i8>("Vec3i8");
49
+ registerVecType.operator()<Vec3i16>("Vec3i16");
50
+ registerVecType.operator()<Vec3i32>("Vec3i32");
51
+ registerVecType.operator()<Vec3i64>("Vec3i64");
52
+ //registerVecType.operator()<Vec3i>("Vec3i");
53
+
54
+ registerVecType.operator()<Vec3ui8>("Vec3ui8");
55
+ registerVecType.operator()<Vec3ui16>("Vec3ui16");
56
+ registerVecType.operator()<Vec3ui32>("Vec3ui32");
57
+ registerVecType.operator()<Vec3ui64>("Vec3ui64");
58
+ //registerVecType.operator()<Vec3ui>("Vec3ui");
59
+
60
+ //registerVecType.operator()<Vec3f16>("Vec3f16");
61
+ registerVecType.operator()<Vec3f32>("Vec3f32");
62
+ registerVecType.operator()<Vec3f64>("Vec3f64");
63
+ //registerVecType.operator()<Vec3f>("Vec3f");
64
+
65
+ registerVecType.operator()<Vec4i8>("Vec4i8");
66
+ registerVecType.operator()<Vec4i16>("Vec4i16");
67
+ registerVecType.operator()<Vec4i32>("Vec4i32");
68
+ registerVecType.operator()<Vec4i64>("Vec4i64");
69
+ //registerVecType.operator()<Vec4i>("Vec4i");
70
+
71
+ registerVecType.operator()<Vec4ui8>("Vec4ui8");
72
+ registerVecType.operator()<Vec4ui16>("Vec4ui16");
73
+ registerVecType.operator()<Vec4ui32>("Vec4ui32");
74
+ registerVecType.operator()<Vec4ui64>("Vec4ui64");
75
+ //registerVecType.operator()<Vec4ui>("Vec4ui");
76
+
77
+ //registerVecType.operator()<Vec4f16>("Vec4f16");
78
+ registerVecType.operator()<Vec4f32>("Vec4f32");
79
+ registerVecType.operator()<Vec4f64>("Vec4f64");
80
+ //registerVecType.operator()<Vec4f>("Vec4f");
81
+ }
82
+ }
83
+
84
+ } // namespace sourcepp
@@ -0,0 +1,36 @@
1
+ #pragma once
2
+
3
+ #include <nanobind/nanobind.h>
4
+ #include <nanobind/stl/string_view.h>
5
+ #include <nanobind/stl/string.h>
6
+ #include <nanobind/stl/vector.h>
7
+
8
+ namespace py = nanobind;
9
+
10
+ #include <steampp/steampp.h>
11
+
12
+ namespace steampp {
13
+
14
+ inline void register_python(py::module_& m) {
15
+ auto steampp = m.def_submodule("steampp");
16
+ using namespace steampp;
17
+
18
+ py::class_<Steam>(steampp, "Steam")
19
+ .def(py::init<>())
20
+ .def_prop_ro("install_dir", &Steam::getInstallDir)
21
+ .def_prop_ro("library_dirs", &Steam::getLibraryDirs)
22
+ .def_prop_ro("sourcemod_dir", &Steam::getSourceModDir)
23
+ .def_prop_ro("installed_apps", &Steam::getInstalledApps)
24
+ .def("is_app_installed", &Steam::isAppInstalled, py::arg("appID"))
25
+ .def("get_app_name", &Steam::getAppName, py::arg("appID"))
26
+ .def("get_app_install_dir", &Steam::getAppInstallDir, py::arg("appID"))
27
+ .def("get_app_icon_path", &Steam::getAppIconPath, py::arg("appID"))
28
+ .def("get_app_logo_path", &Steam::getAppLogoPath, py::arg("appID"))
29
+ .def("get_app_box_art_path", &Steam::getAppBoxArtPath, py::arg("appID"))
30
+ .def("get_app_store_art_path", &Steam::getAppStoreArtPath, py::arg("appID"))
31
+ .def("is_app_using_source_engine", &Steam::isAppUsingSourceEngine, py::arg("appID"))
32
+ .def("is_app_using_source_2_engine", &Steam::isAppUsingSource2Engine, py::arg("appID"))
33
+ .def_prop_ro("__bool__", &Steam::operator bool, py::is_operator());
34
+ }
35
+
36
+ } // namespace steampp
@@ -0,0 +1,90 @@
1
+ #pragma once
2
+
3
+ #include <nanobind/nanobind.h>
4
+ #include <nanobind/stl/string_view.h>
5
+
6
+ namespace py = nanobind;
7
+
8
+ #include <vcryptpp/vcryptpp.h>
9
+
10
+ namespace vcryptpp {
11
+
12
+ inline void register_python(py::module_& m) {
13
+ auto vcryptpp = m.def_submodule("vcryptpp");
14
+ using namespace vcryptpp;
15
+
16
+ {
17
+ auto VFONT = vcryptpp.def_submodule("VFONT");
18
+ using namespace VFONT;
19
+
20
+ VFONT.attr("IDENTIFIER") = IDENTIFIER;
21
+
22
+ VFONT.attr("MAGIC") = MAGIC;
23
+
24
+ VFONT.def("decrypt_bytes", [](const py::bytes& data) {
25
+ const auto d = decrypt({reinterpret_cast<const std::byte*>(data.data()), data.size()});
26
+ return py::bytes{d.data(), d.size()};
27
+ }, py::arg("data"));
28
+ }
29
+
30
+ {
31
+ auto VICE = vcryptpp.def_submodule("VICE");
32
+ using namespace VICE;
33
+
34
+ {
35
+ auto KnownCodes = VICE.def_submodule("KnownCodes");
36
+ using namespace KnownCodes;
37
+
38
+ KnownCodes.attr("DEFAULT") = DEFAULT;
39
+ KnownCodes.attr("CONTAGION_WEAPONS") = CONTAGION_WEAPONS;
40
+ KnownCodes.attr("CONTAGION_SCRIPTS") = CONTAGION_SCRIPTS;
41
+ KnownCodes.attr("COUNTER_STRIKE_SOURCE") = COUNTER_STRIKE_SOURCE;
42
+ KnownCodes.attr("COUNTER_STRIKE_GLOBAL_OFFENSIVE") = COUNTER_STRIKE_GLOBAL_OFFENSIVE;
43
+ KnownCodes.attr("COUNTER_STRIKE_2") = COUNTER_STRIKE_2;
44
+ KnownCodes.attr("COUNTER_STRIKE_PROMOD") = COUNTER_STRIKE_PROMOD;
45
+ KnownCodes.attr("DAY_OF_DEFEAT_SOURCE") = DAY_OF_DEFEAT_SOURCE;
46
+ KnownCodes.attr("DYSTOPIA_1_2") = DYSTOPIA_1_2;
47
+ KnownCodes.attr("DYSTOPIA_1_3") = DYSTOPIA_1_3;
48
+ KnownCodes.attr("GOLDEN_EYE_SOURCE") = GOLDEN_EYE_SOURCE;
49
+ KnownCodes.attr("HALF_LIFE_2_CTF") = HALF_LIFE_2_CTF;
50
+ KnownCodes.attr("HALF_LIFE_2_DM") = HALF_LIFE_2_DM;
51
+ KnownCodes.attr("INSURGENCY") = INSURGENCY;
52
+ KnownCodes.attr("LEFT_4_DEAD_2") = LEFT_4_DEAD_2;
53
+ KnownCodes.attr("NO_MORE_ROOM_IN_HELL") = NO_MORE_ROOM_IN_HELL;
54
+ KnownCodes.attr("NUCLEAR_DAWN") = NUCLEAR_DAWN;
55
+ KnownCodes.attr("TACTICAL_INTERVENTION") = TACTICAL_INTERVENTION;
56
+ KnownCodes.attr("TEAM_FORTRESS_2") = TEAM_FORTRESS_2;
57
+ KnownCodes.attr("TEAM_FORTRESS_2_ITEMS") = TEAM_FORTRESS_2_ITEMS;
58
+ KnownCodes.attr("THE_SHIP") = THE_SHIP;
59
+ KnownCodes.attr("ZOMBIE_PANIC_SOURCE") = ZOMBIE_PANIC_SOURCE;
60
+
61
+ KnownCodes.attr("EKV_GPU_DEFAULT") = EKV_GPU_DEFAULT;
62
+ KnownCodes.attr("EKV_GPU_ALIEN_SWARM") = EKV_GPU_ALIEN_SWARM;
63
+ KnownCodes.attr("EKV_GPU_LEFT_4_DEAD_1") = EKV_GPU_LEFT_4_DEAD_1;
64
+ KnownCodes.attr("EKV_GPU_LEFT_4_DEAD_2") = EKV_GPU_LEFT_4_DEAD_2;
65
+ KnownCodes.attr("EKV_GPU_PORTAL_2") = EKV_GPU_PORTAL_2;
66
+ }
67
+
68
+ VICE.def("decrypt_bytes", [](const py::bytes& data, std::string_view code = KnownCodes::DEFAULT) {
69
+ const auto d = decrypt({reinterpret_cast<const std::byte*>(data.data()), data.size()}, code);
70
+ return py::bytes{d.data(), d.size()};
71
+ }, py::arg("data"), py::arg("code") = KnownCodes::DEFAULT);
72
+
73
+ VICE.def("decrypt_str", [](std::string_view data, std::string_view code = KnownCodes::DEFAULT) -> std::string {
74
+ const auto d = decrypt({reinterpret_cast<const std::byte*>(data.data()), data.size()}, code);
75
+ return {reinterpret_cast<const char*>(d.data()), d.size()};
76
+ }, py::arg("data"), py::arg("code") = KnownCodes::DEFAULT);
77
+
78
+ VICE.def("encrypt_bytes", [](const py::bytes& data, std::string_view code = KnownCodes::DEFAULT) {
79
+ const auto d = encrypt({reinterpret_cast<const std::byte*>(data.data()), data.size()}, code);
80
+ return py::bytes{d.data(), d.size()};
81
+ }, py::arg("data"), py::arg("code") = KnownCodes::DEFAULT);
82
+
83
+ VICE.def("encrypt_str", [](std::string_view data, std::string_view code = KnownCodes::DEFAULT) -> std::string {
84
+ const auto d = encrypt({reinterpret_cast<const std::byte*>(data.data()), data.size()}, code);
85
+ return {reinterpret_cast<const char*>(d.data()), d.size()};
86
+ }, py::arg("data"), py::arg("code") = KnownCodes::DEFAULT);
87
+ }
88
+ }
89
+
90
+ } // namespace vcryptpp
@@ -0,0 +1,436 @@
1
+ #pragma once
2
+
3
+ #include <tuple>
4
+
5
+ #include <nanobind/nanobind.h>
6
+ #include <nanobind/stl/pair.h>
7
+ #include <nanobind/stl/string.h>
8
+ #include <nanobind/stl/string_view.h>
9
+ #include <nanobind/stl/tuple.h>
10
+
11
+ namespace py = nanobind;
12
+
13
+ #include <vtfpp/vtfpp.h>
14
+
15
+ namespace vtfpp {
16
+
17
+ void register_python(py::module_& m) {
18
+ using namespace vtfpp;
19
+ auto vtfpp = m.def_submodule("vtfpp");
20
+
21
+ py::enum_<ImageFormat>(vtfpp, "ImageFormat")
22
+ .value("RGBA8888", ImageFormat::RGBA8888)
23
+ .value("ABGR8888", ImageFormat::ABGR8888)
24
+ .value("RGB888", ImageFormat::RGB888)
25
+ .value("BGR888", ImageFormat::BGR888)
26
+ .value("RGB565", ImageFormat::RGB565)
27
+ .value("I8", ImageFormat::I8)
28
+ .value("IA88", ImageFormat::IA88)
29
+ .value("P8", ImageFormat::P8)
30
+ .value("A8", ImageFormat::A8)
31
+ .value("RGB888_BLUESCREEN", ImageFormat::RGB888_BLUESCREEN)
32
+ .value("BGR888_BLUESCREEN", ImageFormat::BGR888_BLUESCREEN)
33
+ .value("ARGB8888", ImageFormat::ARGB8888)
34
+ .value("BGRA8888", ImageFormat::BGRA8888)
35
+ .value("DXT1", ImageFormat::DXT1)
36
+ .value("DXT3", ImageFormat::DXT3)
37
+ .value("DXT5", ImageFormat::DXT5)
38
+ .value("BGRX8888", ImageFormat::BGRX8888)
39
+ .value("BGR565", ImageFormat::BGR565)
40
+ .value("BGRX5551", ImageFormat::BGRX5551)
41
+ .value("BGRA4444", ImageFormat::BGRA4444)
42
+ .value("DXT1_ONE_BIT_ALPHA", ImageFormat::DXT1_ONE_BIT_ALPHA)
43
+ .value("BGRA5551", ImageFormat::BGRA5551)
44
+ .value("UV88", ImageFormat::UV88)
45
+ .value("UVWQ8888", ImageFormat::UVWQ8888)
46
+ .value("RGBA16161616F", ImageFormat::RGBA16161616F)
47
+ .value("RGBA16161616", ImageFormat::RGBA16161616)
48
+ .value("UVLX8888", ImageFormat::UVLX8888)
49
+ .value("R32F", ImageFormat::R32F)
50
+ .value("RGB323232F", ImageFormat::RGB323232F)
51
+ .value("RGBA32323232F", ImageFormat::RGBA32323232F)
52
+ .value("RG1616F", ImageFormat::RG1616F)
53
+ .value("RG3232F", ImageFormat::RG3232F)
54
+ .value("RGBX8888", ImageFormat::RGBX8888)
55
+ .value("EMPTY", ImageFormat::EMPTY)
56
+ .value("ATI2N", ImageFormat::ATI2N)
57
+ .value("ATI1N", ImageFormat::ATI1N)
58
+ .value("RGBA1010102", ImageFormat::RGBA1010102)
59
+ .value("BGRA1010102", ImageFormat::BGRA1010102)
60
+ .value("R16F", ImageFormat::R16F)
61
+ .value("R8", ImageFormat::R8)
62
+ .value("BC7", ImageFormat::BC7)
63
+ .value("BC6H", ImageFormat::BC6H)
64
+ .export_values();
65
+
66
+ {
67
+ using namespace ImageFormatDetails;
68
+ auto ImageFormatDetails = vtfpp.def_submodule("ImageFormatDetails");
69
+
70
+ ImageFormatDetails.def("red", &red, py::arg("format"));
71
+ ImageFormatDetails.def("decompressedRed", &decompressedRed, py::arg("format"));
72
+ ImageFormatDetails.def("green", &green, py::arg("format"));
73
+ ImageFormatDetails.def("decompressedGreen", &decompressedGreen, py::arg("format"));
74
+ ImageFormatDetails.def("blue", &blue, py::arg("format"));
75
+ ImageFormatDetails.def("decompressedBlue", &decompressedBlue, py::arg("format"));
76
+ ImageFormatDetails.def("alpha", &alpha, py::arg("format"));
77
+ ImageFormatDetails.def("decompressedAlpha", &decompressedAlpha, py::arg("format"));
78
+ ImageFormatDetails.def("bpp", &bpp, py::arg("format"));
79
+ ImageFormatDetails.def("containerFormat", &containerFormat, py::arg("format"));
80
+ ImageFormatDetails.def("large", &large, py::arg("format"));
81
+ ImageFormatDetails.def("decimal", &decimal, py::arg("format"));
82
+ ImageFormatDetails.def("compressed", &compressed, py::arg("format"));
83
+ ImageFormatDetails.def("transparent", &transparent, py::arg("format"));
84
+ ImageFormatDetails.def("opaque", &opaque, py::arg("format"));
85
+
86
+ ImageFormatDetails.def("get_data_length", py::overload_cast<ImageFormat, uint16_t, uint16_t, uint16_t>(&getDataLength), py::arg("format"), py::arg("width"), py::arg("height"), py::arg("slice_count") = 1);
87
+ ImageFormatDetails.def("get_data_length_extended", py::overload_cast<ImageFormat, uint8_t, uint16_t, uint8_t, uint16_t, uint16_t, uint16_t>(&getDataLength), py::arg("format"), py::arg("mip_count"), py::arg("frame_count"), py::arg("face_count"), py::arg("width"), py::arg("height"), py::arg("slice_count"));
88
+ ImageFormatDetails.def("get_data_position", [](ImageFormat format, uint8_t mip, uint8_t mipCount, uint16_t frame, uint16_t frameCount, uint8_t face, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t slice = 0, uint16_t sliceCount = 1) -> std::pair<uint32_t, uint32_t> {
89
+ uint32_t offset, length;
90
+ if (getDataPosition(offset, length, format, mip, mipCount, frame, frameCount, face, faceCount, width, height, slice, sliceCount)) {
91
+ return {offset, length};
92
+ }
93
+ return {0, 0};
94
+ }, py::arg("format"), py::arg("mip"), py::arg("mip_count"), py::arg("frame"), py::arg("frame_count"), py::arg("face"), py::arg("face_count"), py::arg("width"), py::arg("height"), py::arg("slice") = 0, py::arg("slice_count") = 1);
95
+ }
96
+
97
+ {
98
+ using namespace ImageDimensions;
99
+ auto ImageDimensions = vtfpp.def_submodule("ImageDimensions");
100
+
101
+ ImageDimensions.def("get_mip_dim", &getMipDim, py::arg("mip"), py::arg("dim"));
102
+ ImageDimensions.def("get_recommended_mip_count_for_dims", &getRecommendedMipCountForDims, py::arg("format"), py::arg("width"), py::arg("height"));
103
+ }
104
+
105
+ // Skip ImagePixel, difficult to bind
106
+
107
+ {
108
+ using namespace ImageConversion;
109
+ auto ImageConversion = vtfpp.def_submodule("ImageConversion");
110
+
111
+ // todo(python): still need to bind the following:
112
+ ImageConversion.def("convert_image_data_to_format", [](const py::bytes& imageData, ImageFormat oldFormat, ImageFormat newFormat, uint16_t width, uint16_t height) {
113
+ const auto d = convertImageDataToFormat({reinterpret_cast<const std::byte*>(imageData.data()), imageData.size()}, oldFormat, newFormat, width, height);
114
+ return py::bytes{d.data(), d.size()};
115
+ }, py::arg("image_data"), py::arg("old_format"), py::arg("new_format"), py::arg("width"), py::arg("height"));
116
+
117
+ ImageConversion.def("convert_several_image_data_to_format", [](const py::bytes& imageData, ImageFormat oldFormat, ImageFormat newFormat, uint8_t mipCount, uint16_t frameCount, uint16_t faceCount, uint16_t width, uint16_t height, uint16_t sliceCount) {
118
+ const auto d = convertSeveralImageDataToFormat({reinterpret_cast<const std::byte*>(imageData.data()), imageData.size()}, oldFormat, newFormat, mipCount, frameCount, faceCount, width, height, sliceCount);
119
+ return py::bytes{d.data(), d.size()};
120
+ }, py::arg("image_data"), py::arg("old_format"), py::arg("new_format"), py::arg("mip_count"), py::arg("frame_count"), py::arg("face_count"), py::arg("width"), py::arg("height"), py::arg("slice_count"));
121
+
122
+ py::enum_<FileFormat>(ImageConversion, "FileFormat")
123
+ .value("DEFAULT", FileFormat::DEFAULT)
124
+ .value("PNG", FileFormat::PNG)
125
+ .value("JPEG", FileFormat::JPEG)
126
+ .value("BMP", FileFormat::BMP)
127
+ .value("TGA", FileFormat::TGA)
128
+ .value("HDR", FileFormat::HDR)
129
+ .export_values();
130
+
131
+ ImageConversion.def("get_default_file_format_for_image_format", &getDefaultFileFormatForImageFormat, py::arg("format"));
132
+
133
+ ImageConversion.def("convert_image_data_to_file", [](const py::bytes& imageData, ImageFormat format, uint16_t width, uint16_t height, FileFormat fileFormat = FileFormat::DEFAULT) {
134
+ const auto d = convertImageDataToFile({reinterpret_cast<const std::byte*>(imageData.data()), imageData.size()}, format, width, height, fileFormat);
135
+ return py::bytes{d.data(), d.size()};
136
+ }, py::arg("image_data"), py::arg("format"), py::arg("width"), py::arg("height"), py::arg("file_format") = FileFormat::DEFAULT);
137
+
138
+ ImageConversion.def("convert_file_to_image_data", [](const py::bytes& fileData) -> std::tuple<py::bytes, ImageFormat, int, int, int> {
139
+ ImageFormat format;
140
+ int width, height, frame;
141
+ const auto d = convertFileToImageData({reinterpret_cast<const std::byte*>(fileData.data()), fileData.size()}, format, width, height, frame);
142
+ return {py::bytes{d.data(), d.size()}, format, width, height, frame};
143
+ }, py::arg("file_data"));
144
+
145
+ py::enum_<ResizeEdge>(ImageConversion, "ResizeEdge")
146
+ .value("CLAMP", ResizeEdge::CLAMP)
147
+ .value("REFLECT", ResizeEdge::REFLECT)
148
+ .value("WRAP", ResizeEdge::WRAP)
149
+ .value("ZERO", ResizeEdge::ZERO)
150
+ .export_values();
151
+
152
+ py::enum_<ResizeFilter>(ImageConversion, "ResizeFilter")
153
+ .value("DEFAULT", ResizeFilter::DEFAULT)
154
+ .value("BOX", ResizeFilter::BOX)
155
+ .value("BILINEAR", ResizeFilter::BILINEAR)
156
+ .value("CUBIC_BSPLINE", ResizeFilter::CUBIC_BSPLINE)
157
+ .value("CATMULLROM", ResizeFilter::CATMULLROM)
158
+ .value("MITCHELL", ResizeFilter::MITCHELL)
159
+ .export_values();
160
+
161
+ py::enum_<ResizeMethod>(ImageConversion, "ResizeMethod")
162
+ .value("NONE", ResizeMethod::NONE)
163
+ .value("POWER_OF_TWO_BIGGER", ResizeMethod::POWER_OF_TWO_BIGGER)
164
+ .value("POWER_OF_TWO_SMALLER", ResizeMethod::POWER_OF_TWO_SMALLER)
165
+ .value("POWER_OF_TWO_NEAREST", ResizeMethod::POWER_OF_TWO_NEAREST)
166
+ .export_values();
167
+
168
+ ImageConversion.def("get_resized_dim", &getResizedDim, py::arg("n"), py::arg("resize_method"));
169
+ ImageConversion.def("get_resized_dims", [](uint16_t width, ResizeMethod widthResize, uint16_t height, ResizeMethod heightResize) -> std::pair<uint16_t, uint16_t> {
170
+ setResizedDims(width, widthResize, height, heightResize);
171
+ return {width, height};
172
+ }, py::arg("width"), py::arg("resize_width"), py::arg("height"), py::arg("resize_height"));
173
+
174
+ ImageConversion.def("resize_image_data", [](const py::bytes& imageData, ImageFormat format, uint16_t width, uint16_t newWidth, uint16_t height, uint16_t newHeight, bool srgb, ResizeFilter filter, ResizeEdge edge = ResizeEdge::CLAMP) {
175
+ const auto d = resizeImageData({reinterpret_cast<const std::byte*>(imageData.data()), imageData.size()}, format, width, newWidth, height, newHeight, srgb, filter, edge);
176
+ return py::bytes{d.data(), d.size()};
177
+ }, py::arg("image_data"), py::arg("format"), py::arg("width"), py::arg("new_width"), py::arg("height"), py::arg("new_height"), py::arg("srgb"), py::arg("filter"), py::arg("edge") = ResizeEdge::CLAMP);
178
+
179
+ ImageConversion.def("resize_image_data_strict", [](const py::bytes& imageData, ImageFormat format, uint16_t width, uint16_t newWidth, ResizeMethod widthResize, uint16_t height, uint16_t newHeight, ResizeMethod heightResize, bool srgb, ResizeFilter filter, ResizeEdge edge = ResizeEdge::CLAMP) -> std::tuple<py::bytes, int, int> {
180
+ uint16_t widthOut, heightOut;
181
+ const auto d = resizeImageDataStrict({reinterpret_cast<const std::byte*>(imageData.data()), imageData.size()}, format, width, newWidth, widthOut, widthResize, height, newHeight, heightOut, heightResize, srgb, filter, edge);
182
+ return {py::bytes{d.data(), d.size()}, widthOut, heightOut};
183
+ }, py::arg("image_data"), py::arg("format"), py::arg("width"), py::arg("new_width"), py::arg("width_resize"), py::arg("height"), py::arg("new_height"), py::arg("height_resize"), py::arg("srgb"), py::arg("filter"), py::arg("edge") = ResizeEdge::CLAMP);
184
+
185
+ // Skip extractChannelFromImageData, difficult to bind
186
+ }
187
+
188
+ py::class_<PPL::Image>(vtfpp, "PPLImage")
189
+ .def_ro("width", &PPL::Image::width)
190
+ .def_ro("height", &PPL::Image::height)
191
+ .def_prop_ro("data", [](const PPL::Image& self) {
192
+ return py::bytes{self.data.data(), self.data.size()};
193
+ });
194
+
195
+ py::class_<PPL>(vtfpp, "PPL")
196
+ .def(py::init<uint32_t, ImageFormat, uint32_t>(), py::arg("checksum"), py::arg("format") = ImageFormat::RGB888, py::arg("version") = 0)
197
+ .def("__init__", [](PPL* self, const py::bytes& pplData) {
198
+ return new(self) PPL{{reinterpret_cast<const std::byte*>(pplData.data()), pplData.size()}};
199
+ }, py::arg("ppl_data"))
200
+ .def(py::init<const std::string&>(), py::arg("path"))
201
+ .def("__bool__", &PPL::operator bool, py::is_operator())
202
+ .def_prop_rw("version", &PPL::getVersion, &PPL::setVersion)
203
+ .def_prop_rw("checksum", &PPL::getChecksum, &PPL::setChecksum)
204
+ .def_prop_rw("format", &PPL::getFormat, &PPL::setFormat)
205
+ .def("has_image_for_lod", &PPL::hasImageForLOD, py::arg("lod"))
206
+ .def_prop_ro("image_lods", &PPL::getImageLODs)
207
+ .def("get_image_raw", [](const PPL& self, uint32_t lod = 0) -> std::optional<PPL::Image> {
208
+ const auto* image = self.getImageRaw(lod);
209
+ if (!image) {
210
+ return std::nullopt;
211
+ }
212
+ return *image;
213
+ }, py::arg("lod"))
214
+ .def("get_image_as", &PPL::getImageAs, py::arg("new_format"), py::arg("lod"))
215
+ .def("get_image_as_rgb888", &PPL::getImageAsRGB888, py::arg("lod"))
216
+ .def("set_image", [](PPL& self, const py::bytes& imageData, ImageFormat format, uint32_t width, uint32_t height, uint32_t lod = 0) {
217
+ self.setImage({reinterpret_cast<const std::byte*>(imageData.data()), imageData.size()}, format, width, height, lod);
218
+ }, py::arg("imageData"), py::arg("format"), py::arg("width"), py::arg("height"), py::arg("lod") = 0)
219
+ .def("set_image_resized", [](PPL& self, const py::bytes& imageData, ImageFormat format, uint32_t width, uint32_t height, uint32_t resizedWidth, uint32_t resizedHeight, uint32_t lod = 0, ImageConversion::ResizeFilter filter = ImageConversion::ResizeFilter::BILINEAR) {
220
+ self.setImage({reinterpret_cast<const std::byte*>(imageData.data()), imageData.size()}, format, width, height, resizedWidth, resizedHeight, lod, filter);
221
+ }, py::arg("imageData"), py::arg("format"), py::arg("width"), py::arg("height"), py::arg("resized_width"), py::arg("resized_height"), py::arg("lod") = 0, py::arg("filter") = ImageConversion::ResizeFilter::BILINEAR)
222
+ .def("set_image_from_file", py::overload_cast<const std::string&, uint32_t>(&PPL::setImage), py::arg("image_path"), py::arg("lod") = 0)
223
+ .def("set_image_resized_from_file", py::overload_cast<const std::string&, uint32_t, uint32_t, uint32_t, ImageConversion::ResizeFilter>(&PPL::setImage), py::arg("image_path"), py::arg("resized_width"), py::arg("resized_height"), py::arg("lod") = 0, py::arg("filter") = ImageConversion::ResizeFilter::BILINEAR)
224
+ .def("save_image", [](const PPL& self, uint32_t lod = 0, ImageConversion::FileFormat fileFormat = ImageConversion::FileFormat::DEFAULT) {
225
+ const auto d = self.saveImageToFile(lod, fileFormat);
226
+ return py::bytes{d.data(), d.size()};
227
+ }, py::arg("lod") = 0, py::arg("file_format") = ImageConversion::FileFormat::DEFAULT)
228
+ .def("save_image_to_file", py::overload_cast<const std::string&, uint32_t, ImageConversion::FileFormat>(&PPL::saveImageToFile, py::const_), py::arg("image_path"), py::arg("lod") = 0, py::arg("file_format") = ImageConversion::FileFormat::DEFAULT)
229
+ .def("bake", [](PPL& self) {
230
+ const auto d = self.bake();
231
+ return py::bytes{d.data(), d.size()};
232
+ })
233
+ .def("bake_to_file", py::overload_cast<const std::string&>(&PPL::bake), py::arg("ppl_path"));
234
+
235
+ vtfpp.attr("VTF_SIGNATURE") = VTF_SIGNATURE;
236
+
237
+ py::enum_<CompressionMethod>(vtfpp, "CompressionMethod")
238
+ .value("DEFLATE", CompressionMethod::DEFLATE)
239
+ .value("ZSTD", CompressionMethod::ZSTD)
240
+ .export_values();
241
+
242
+ py::enum_<Resource::Type>(vtfpp, "ResourceType")
243
+ .value("UNKNOWN", Resource::TYPE_UNKNOWN)
244
+ .value("THUMBNAIL_DATA", Resource::TYPE_THUMBNAIL_DATA)
245
+ .value("IMAGE_DATA", Resource::TYPE_IMAGE_DATA)
246
+ .value("PARTICLE_SHEET_DATA", Resource::TYPE_PARTICLE_SHEET_DATA)
247
+ .value("CRC", Resource::TYPE_CRC)
248
+ .value("LOD_CONTROL_INFO", Resource::TYPE_LOD_CONTROL_INFO)
249
+ .value("EXTENDED_FLAGS", Resource::TYPE_EXTENDED_FLAGS)
250
+ .value("KEYVALUES_DATA", Resource::TYPE_KEYVALUES_DATA)
251
+ .value("AUX_COMPRESSION", Resource::TYPE_AUX_COMPRESSION)
252
+ .export_values();
253
+
254
+ py::enum_<Resource::Flags>(vtfpp, "ResourceFlags")
255
+ .value("NONE", Resource::FLAG_NONE)
256
+ .value("LOCAL_DATA", Resource::FLAG_LOCAL_DATA)
257
+ .export_values();
258
+
259
+ // Skip Resource, mostly useless outside C++
260
+
261
+ py::enum_<VTF::Flags>(vtfpp, "VTFFlags")
262
+ .value("NONE", VTF::FLAG_NONE)
263
+ .value("POINT_SAMPLE", VTF::FLAG_POINT_SAMPLE)
264
+ .value("TRILINEAR", VTF::FLAG_TRILINEAR)
265
+ .value("CLAMP_S", VTF::FLAG_CLAMP_S)
266
+ .value("CLAMP_T", VTF::FLAG_CLAMP_T)
267
+ .value("ANISOTROPIC", VTF::FLAG_ANISOTROPIC)
268
+ .value("HINT_DXT5", VTF::FLAG_HINT_DXT5)
269
+ .value("SRGB", VTF::FLAG_SRGB)
270
+ .value("NO_COMPRESS", VTF::FLAG_NO_COMPRESS)
271
+ .value("NORMAL", VTF::FLAG_NORMAL)
272
+ .value("NO_MIP", VTF::FLAG_NO_MIP)
273
+ .value("NO_LOD", VTF::FLAG_NO_LOD)
274
+ .value("MIN_MIP", VTF::FLAG_MIN_MIP)
275
+ .value("PROCEDURAL", VTF::FLAG_PROCEDURAL)
276
+ .value("ONE_BIT_ALPHA", VTF::FLAG_ONE_BIT_ALPHA)
277
+ .value("MULTI_BIT_ALPHA", VTF::FLAG_MULTI_BIT_ALPHA)
278
+ .value("ENVMAP", VTF::FLAG_ENVMAP)
279
+ .value("RENDERTARGET", VTF::FLAG_RENDERTARGET)
280
+ .value("DEPTH_RENDERTARGET", VTF::FLAG_DEPTH_RENDERTARGET)
281
+ .value("NO_DEBUG_OVERRIDE", VTF::FLAG_NO_DEBUG_OVERRIDE)
282
+ .value("SINGLE_COPY", VTF::FLAG_SINGLE_COPY)
283
+ .value("ONE_OVER_MIP_LEVEL_IN_ALPHA", VTF::FLAG_ONE_OVER_MIP_LEVEL_IN_ALPHA)
284
+ .value("PREMULTIPLY_COLOR_BY_ONE_OVER_MIP_LEVEL", VTF::FLAG_PREMULTIPLY_COLOR_BY_ONE_OVER_MIP_LEVEL)
285
+ .value("NORMAL_TO_DUDV", VTF::FLAG_NORMAL_TO_DUDV)
286
+ .value("ALPHA_TEST_MIP_GENERATION", VTF::FLAG_ALPHA_TEST_MIP_GENERATION)
287
+ .value("NO_DEPTH_BUFFER", VTF::FLAG_NO_DEPTH_BUFFER)
288
+ .value("NICE_FILTERED", VTF::FLAG_NICE_FILTERED)
289
+ .value("CLAMP_U", VTF::FLAG_CLAMP_U)
290
+ .value("VERTEX_TEXTURE", VTF::FLAG_VERTEX_TEXTURE)
291
+ .value("SSBUMP", VTF::FLAG_SSBUMP)
292
+ .value("UNFILTERABLE_OK", VTF::FLAG_UNFILTERABLE_OK)
293
+ .value("BORDER", VTF::FLAG_BORDER)
294
+ .value("SPECVAR_RED", VTF::FLAG_SPECVAR_RED)
295
+ .value("SPECVAR_ALPHA", VTF::FLAG_SPECVAR_ALPHA)
296
+ .export_values();
297
+
298
+ py::class_<VTF::CreationOptions>(vtfpp, "VTFCreationOptions")
299
+ .def(py::init<>())
300
+ .def_rw("major_version", &VTF::CreationOptions::majorVersion)
301
+ .def_rw("minor_version", &VTF::CreationOptions::minorVersion)
302
+ .def_rw("output_format", &VTF::CreationOptions::outputFormat)
303
+ .def_rw("width_resize_method", &VTF::CreationOptions::widthResizeMethod)
304
+ .def_rw("height_resize_method", &VTF::CreationOptions::heightResizeMethod)
305
+ .def_rw("filter", &VTF::CreationOptions::filter)
306
+ .def_rw("flags", &VTF::CreationOptions::flags)
307
+ .def_rw("initial_frame_count", &VTF::CreationOptions::initialFrameCount)
308
+ .def_rw("start_frame", &VTF::CreationOptions::startFrame)
309
+ .def_rw("is_cubemap", &VTF::CreationOptions::isCubeMap)
310
+ .def_rw("has_spheremap", &VTF::CreationOptions::hasSphereMap)
311
+ .def_rw("initial_slice_count", &VTF::CreationOptions::initialSliceCount)
312
+ .def_rw("create_mips", &VTF::CreationOptions::createMips)
313
+ .def_rw("create_thumbnail", &VTF::CreationOptions::createThumbnail)
314
+ .def_rw("create_reflectivity", &VTF::CreationOptions::createReflectivity)
315
+ .def_rw("compression_level", &VTF::CreationOptions::compressionLevel)
316
+ .def_rw("compression_method", &VTF::CreationOptions::compressionMethod)
317
+ .def_rw("bumpmap_scale", &VTF::CreationOptions::bumpMapScale);
318
+
319
+ py::class_<VTF>(vtfpp, "VTF")
320
+ .def_ro_static("FLAG_MASK_GENERATED", &VTF::FLAG_MASK_GENERATED)
321
+ .def_ro_static("FORMAT_UNCHANGED", &VTF::FORMAT_UNCHANGED)
322
+ .def_ro_static("FORMAT_DEFAULT", &VTF::FORMAT_DEFAULT)
323
+ .def_ro_static("MAX_RESOURCES", &VTF::MAX_RESOURCES)
324
+ .def(py::init<>())
325
+ .def("__init__", [](VTF* self, const py::bytes& vtfData, bool parseHeaderOnly = false) {
326
+ return new(self) VTF{std::span{reinterpret_cast<const std::byte*>(vtfData.data()), vtfData.size()}, parseHeaderOnly};
327
+ }, py::arg("vtf_data"), py::arg("parse_header_only") = false)
328
+ .def(py::init<const std::string&, bool>(), py::arg("vtf_path"), py::arg("parse_header_only") = false)
329
+ .def("__bool__", &VTF::operator bool, py::is_operator())
330
+ .def_static("create_and_bake", [](const py::bytes& imageData, ImageFormat format, uint16_t width, uint16_t height, const std::string& vtfPath, VTF::CreationOptions options) {
331
+ VTF::create({reinterpret_cast<const std::byte*>(imageData.data()), imageData.size()}, format, width, height, vtfPath, options);
332
+ }, py::arg("image_data"), py::arg("format"), py::arg("width"), py::arg("height"), py::arg("vtf_path"), py::arg("creation_options") = VTF::CreationOptions{})
333
+ .def_static("create_blank_and_bake", py::overload_cast<ImageFormat, uint16_t, uint16_t, const std::string&, VTF::CreationOptions>(&VTF::create), py::arg("format"), py::arg("width"), py::arg("height"), py::arg("vtf_path"), py::arg("creation_options") = VTF::CreationOptions{})
334
+ .def_static("create", [](const py::bytes& imageData, ImageFormat format, uint16_t width, uint16_t height, VTF::CreationOptions options) {
335
+ return VTF::create({reinterpret_cast<const std::byte*>(imageData.data()), imageData.size()}, format, width, height, options);
336
+ }, py::arg("image_data"), py::arg("format"), py::arg("width"), py::arg("height"), py::arg("creation_options") = VTF::CreationOptions{})
337
+ .def_static("create_blank", py::overload_cast<ImageFormat, uint16_t, uint16_t, VTF::CreationOptions>(&VTF::create), py::arg("format"), py::arg("width"), py::arg("height"), py::arg("creation_options") = VTF::CreationOptions{})
338
+ .def_static("create_from_file_and_bake", py::overload_cast<const std::string&, const std::string&, VTF::CreationOptions>(&VTF::create), py::arg("image_path"), py::arg("vtf_path"), py::arg("creation_options") = VTF::CreationOptions{})
339
+ .def_static("create_from_file", py::overload_cast<const std::string&, VTF::CreationOptions>(&VTF::create), py::arg("image_path"), py::arg("creation_options") = VTF::CreationOptions{})
340
+ .def_prop_rw("version_major", &VTF::getMajorVersion, &VTF::setMajorVersion)
341
+ .def_prop_rw("version_minor", &VTF::getMinorVersion, &VTF::setMinorVersion)
342
+ .def_prop_rw("image_width_resize_method", &VTF::getImageWidthResizeMethod, &VTF::setImageWidthResizeMethod)
343
+ .def_prop_rw("image_height_resize_method", &VTF::getImageHeightResizeMethod, &VTF::setImageHeightResizeMethod)
344
+ .def_prop_ro("width", &VTF::getWidth)
345
+ .def("width_for_mip", [](const VTF& self, uint8_t mip = 0) { return self.getWidth(mip); }, py::arg("mip") = 0)
346
+ .def_prop_ro("height", &VTF::getHeight)
347
+ .def("height_for_mip", [](const VTF& self, uint8_t mip = 0) { return self.getHeight(mip); }, py::arg("mip") = 0)
348
+ .def("set_size", &VTF::setSize, py::arg("width"), py::arg("height"), py::arg("filter"))
349
+ .def_prop_rw("flags", &VTF::getFlags, &VTF::setFlags)
350
+ .def("add_flags", &VTF::addFlags, py::arg("flags"))
351
+ .def("remove_flags", &VTF::removeFlags, py::arg("flags"))
352
+ .def_prop_ro("format", &VTF::getFormat)
353
+ .def("set_format", &VTF::setFormat, py::arg("new_format"), py::arg("filter") = ImageConversion::ResizeFilter::BILINEAR)
354
+ .def_prop_rw("mip_count", &VTF::getMipCount, &VTF::setMipCount)
355
+ .def("set_recommended_mip_count", &VTF::setRecommendedMipCount)
356
+ .def("compute_mips", &VTF::computeMips, py::arg("filter") = ImageConversion::ResizeFilter::BILINEAR)
357
+ .def_prop_rw("frame_count", &VTF::getFrameCount, &VTF::setFrameCount)
358
+ .def_prop_ro("face_count", &VTF::getFaceCount)
359
+ .def("set_face_count", &VTF::setFaceCount, py::arg("is_cubemap"), py::arg("has_spheremap") = false)
360
+ .def_prop_rw("slice_count", &VTF::getSliceCount, &VTF::setSliceCount)
361
+ .def("set_frame_face_and_slice_count", &VTF::setFrameFaceAndSliceCount, py::arg("new_frame_count"), py::arg("is_cubemap"), py::arg("has_spheremap") = false, py::arg("new_slice_count") = 1)
362
+ .def_prop_rw("start_frame", &VTF::getStartFrame, &VTF::setStartFrame)
363
+ .def_prop_rw("reflectivity", &VTF::getReflectivity, &VTF::setReflectivity)
364
+ .def("compute_reflectivity", &VTF::computeReflectivity)
365
+ .def_prop_rw("bumpmap_scale", &VTF::getBumpMapScale, &VTF::setBumpMapScale)
366
+ .def_prop_ro("thumbnail_format", &VTF::getThumbnailFormat)
367
+ .def_prop_ro("thumbnail_width", &VTF::getThumbnailWidth)
368
+ .def_prop_ro("thumbnail_height", &VTF::getThumbnailHeight)
369
+ // Skip getResources
370
+ // Skip getResource
371
+ .def("set_particle_sheet_resource", [](VTF& self, const py::bytes& value) { return self.setParticleSheetResource({reinterpret_cast<const std::byte*>(value.data()), value.size()}); }, py::arg("value"))
372
+ .def("remove_particle_sheet_resource", &VTF::removeParticleSheetResource)
373
+ .def("set_crc_resource", &VTF::setCRCResource, py::arg("value"))
374
+ .def("remove_crc_resource", &VTF::removeCRCResource)
375
+ .def("set_lod_resource", &VTF::setLODResource, py::arg("u"), py::arg("v"))
376
+ .def("remove_lod_resource", &VTF::removeLODResource)
377
+ .def("set_extended_flags_resource", &VTF::setExtendedFlagsResource, py::arg("value"))
378
+ .def("remove_extended_flags_resource", &VTF::removeExtendedFlagsResource)
379
+ .def("set_keyvalues_data_resource", &VTF::setKeyValuesDataResource, py::arg("value"))
380
+ .def("remove_keyvalues_data_resource", &VTF::removeKeyValuesDataResource)
381
+ .def_prop_rw("compression_level", &VTF::getCompressionLevel, &VTF::setCompressionLevel)
382
+ .def_prop_rw("compression_method", &VTF::getCompressionMethod, &VTF::setCompressionMethod)
383
+ .def("has_image_data", &VTF::hasImageData)
384
+ .def("image_data_is_srgb", &VTF::imageDataIsSRGB)
385
+ .def("get_image_data_raw", [](const VTF& self, uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, uint16_t slice = 0) {
386
+ const auto d = self.getImageDataRaw(mip, frame, face, slice);
387
+ return py::bytes{d.data(), d.size()};
388
+ }, py::arg("mip") = 0, py::arg("frame") = 0, py::arg("face") = 0, py::arg("slice") = 0)
389
+ .def("get_image_data_as", [](const VTF& self, ImageFormat newFormat, uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, uint16_t slice = 0) {
390
+ const auto d = self.getImageDataAs(newFormat, mip, frame, face, slice);
391
+ return py::bytes{d.data(), d.size()};
392
+ }, py::arg("new_format"), py::arg("mip") = 0, py::arg("frame") = 0, py::arg("face") = 0, py::arg("slice") = 0)
393
+ .def("get_image_data_as_rgba8888", [](const VTF& self, uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, uint16_t slice = 0) {
394
+ const auto d = self.getImageDataAsRGBA8888(mip, frame, face, slice);
395
+ return py::bytes{d.data(), d.size()};
396
+ }, py::arg("mip") = 0, py::arg("frame") = 0, py::arg("face") = 0, py::arg("slice") = 0)
397
+ .def("set_image", [](VTF& self, const py::bytes& imageData, ImageFormat format, uint16_t width, uint16_t height, ImageConversion::ResizeFilter filter = ImageConversion::ResizeFilter::BILINEAR, uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, uint16_t slice = 0) {
398
+ return self.setImage({reinterpret_cast<const std::byte*>(imageData.data()), imageData.size()}, format, width, height, filter, mip, frame, face, slice);
399
+ }, py::arg("image_data"), py::arg("format"), py::arg("width"), py::arg("height"), py::arg("filter"), py::arg("mip") = 0, py::arg("frame") = 0, py::arg("face") = 0, py::arg("slice") = 0)
400
+ .def("set_image_from_file", py::overload_cast<const std::string&, ImageConversion::ResizeFilter, uint8_t, uint16_t, uint8_t, uint16_t>(&VTF::setImage), py::arg("image_path"), py::arg("filter") = ImageConversion::ResizeFilter::BILINEAR, py::arg("mip") = 0, py::arg("frame") = 0, py::arg("face") = 0, py::arg("slice") = 0)
401
+ .def("save_image", [](const VTF& self, uint8_t mip = 0, uint16_t frame = 0, uint8_t face = 0, uint16_t slice = 0, ImageConversion::FileFormat fileFormat = ImageConversion::FileFormat::DEFAULT) {
402
+ const auto d = self.saveImageToFile(mip, frame, face, slice, fileFormat);
403
+ return py::bytes{d.data(), d.size()};
404
+ }, py::arg("mip") = 0, py::arg("frame") = 0, py::arg("face") = 0, py::arg("slice") = 0, py::arg("file_format") = ImageConversion::FileFormat::DEFAULT)
405
+ .def("save_image_to_file", py::overload_cast<const std::string&, uint8_t, uint16_t, uint8_t, uint16_t, ImageConversion::FileFormat>(&VTF::saveImageToFile, py::const_), py::arg("image_path"), py::arg("mip") = 0, py::arg("frame") = 0, py::arg("face") = 0, py::arg("slice") = 0, py::arg("file_format") = ImageConversion::FileFormat::DEFAULT)
406
+ .def("has_thumbnail_data", &VTF::hasThumbnailData)
407
+ .def("get_thumbnail_data_raw", [](const VTF& self) {
408
+ const auto d = self.getThumbnailDataRaw();
409
+ return py::bytes{d.data(), d.size()};
410
+ })
411
+ .def("get_thumbnail_data_as", [](const VTF& self, ImageFormat newFormat) {
412
+ const auto d = self.getThumbnailDataAs(newFormat);
413
+ return py::bytes{d.data(), d.size()};
414
+ }, py::arg("new_format"))
415
+ .def("get_thumbnail_data_as_rgba8888", [](const VTF& self) {
416
+ const auto d = self.getThumbnailDataAsRGBA8888();
417
+ return py::bytes{d.data(), d.size()};
418
+ })
419
+ .def("set_thumbnail", [](VTF& self, const py::bytes& imageData, ImageFormat format, uint16_t width, uint16_t height) {
420
+ return self.setThumbnail({reinterpret_cast<const std::byte*>(imageData.data()), imageData.size()}, format, width, height);
421
+ }, py::arg("image_data"), py::arg("format"), py::arg("width"), py::arg("height"))
422
+ .def("compute_thumbnail", &VTF::computeThumbnail, py::arg("filter") = ImageConversion::ResizeFilter::BILINEAR)
423
+ .def("remove_thumbnail", &VTF::removeThumbnail)
424
+ .def("save_thumbnail", [](const VTF& self, ImageConversion::FileFormat fileFormat = ImageConversion::FileFormat::DEFAULT) {
425
+ const auto d = self.saveThumbnailToFile(fileFormat);
426
+ return py::bytes{d.data(), d.size()};
427
+ }, py::arg("file_format") = ImageConversion::FileFormat::DEFAULT)
428
+ .def("save_thumbnail_to_file", py::overload_cast<const std::string&, ImageConversion::FileFormat>(&VTF::saveThumbnailToFile, py::const_), py::arg("image_path"), py::arg("file_format") = ImageConversion::FileFormat::DEFAULT)
429
+ .def("bake", [](const VTF& self) {
430
+ const auto d = self.bake();
431
+ return py::bytes{d.data(), d.size()};
432
+ })
433
+ .def("bake_to_file", py::overload_cast<const std::string&>(&VTF::bake, py::const_), py::arg("vtf_path"));
434
+ }
435
+
436
+ } // namespace vtfpp