-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
vtfmerge.cxx
152 lines (131 loc) · 4.46 KB
/
vtfmerge.cxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "vtfshared.hxx"
int main (int argc, char** argv)
{
using namespace VTFLib;
// Get the number of animation frames
const auto* const app = argv[0];
++argv, --argc;
if (argc < 2) {
printf("Error: at least two textures must be specified (got %d)\n", argc);
usage:
printf("Usage: %s frame1.vtf frame2.vtf [frame3.vtf ...]\n", app);
return (argc == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
// Load the first texture
auto const dir = argv[0];
auto frame = CVTFFile{};
if (!frame.Load(argv[0])) {
printf("Error: couldn't load \"%s\"\n", argv[0]);
goto usage;
}
// The first texture defines parameters for the entire animation.
// All other textures must be identical in size, mimpmap count, and format.
auto const width = frame.GetWidth();
auto const height = frame.GetHeight();
auto const depth = frame.GetDepth();
auto const mips = frame.GetMipmapCount();
auto const frames = frame.GetFrameCount();
auto const format = frame.GetFormat();
// Individual frame textures cannot have multiple frames
if (frames != 1) {
printf("Error: frame \"%s\": contains multiple frames on its own\n", argv[0]);
return EXIT_FAILURE;
}
// Calculate the size of resulting
// animated texture image data
auto const thumb_size = frame.GetThumbnailDataSize();
auto const off = VTF_HDR_SIZE + thumb_size;
size_t* const mip_lut = re_cast<size_t*>(malloc(sizeof(mip_lut[0]) * (mips + 1)));
if (mip_lut == NULL) {
printf("Error: out of memory\n");
return EXIT_FAILURE;
}
mip_lut[0] = off;
vlUInt img_size_new = 0;
auto m = mips;
while (m--) {
auto const mip = mips - m;
auto const mip_size = frame.ComputeImageSize(max(width >> m, 1)
, max(height >> m, 1), depth, format);
mip_lut[mip] = mip_lut[mip - 1] + mip_size * argc;
img_size_new += mip_size;
}
// Allocate the memory for entire animated VTF
auto vtf_size = vtf_get_real_size(frame);
auto const vtf_size_new = off + img_size_new * argc;
auto const vtf_mem = malloc(max(vtf_size, vtf_size_new));
if (vtf_mem == NULL) {
printf("Error: out of memory\n");
goto fail;
}
// Write the first frame
auto const img_size = frame.GetImageDataSize();
frame.Save(vtf_mem, vtf_size, vtf_size);
// Set the number of frames and other metadata
vtf_force_72(frame, vtf_mem, true);
*(short*)((char*)vtf_mem + VTF_HDR_OFF_FRAMES) = argc;
*(short*)((char*)vtf_mem + VTF_HDR_OFF_START) = 0;
// Load the rest of textures
auto const total = argc;
while (true) {
--argc;
auto const num = total - argc;
// Write the next frame for each mipmap
m = mips;
while (m--) {
auto const mip = mips - m;
auto const data = frame.GetData(0, 0, 0, m);
auto const mip_size = frame.ComputeImageSize(max(width >> m, 1)
, max(height >> m, 1), depth, format);
auto const mip_off = mip_lut[mip - 1]
+ mip_size * (num - 1);
memcpy((char*)vtf_mem + mip_off, data, mip_size);
}
if (argc == 0) {
break;
}
// Load the next frame
++argv;
if (!frame.Load(argv[0])) {
printf("Error: couldn't load \"%s\"\n", argv[0]);
goto fail;
}
// Validate against the first frame
if (frame.GetWidth() != width) {printf("Error: frame \"%s\": inconsistent width\n", argv[0]); goto fail;}
if (frame.GetHeight() != height) {printf("Error: frame \"%s\": inconsistent height\n", argv[0]); goto fail;}
if (frame.GetDepth() != depth) {printf("Error: frame \"%s\": inconsistent depth\n", argv[0]); goto fail;}
if (frame.GetMipmapCount() != mips) {printf("Error: frame \"%s\": inconsistent mipmap count\n", argv[0]); goto fail;}
if (frame.GetFormat() != format) {printf("Error: frame \"%s\": inconsistent format\n", argv[0]); goto fail;}
// Individual frame textures must not be animated themselves
if (frame.GetFrameCount() != 1) {printf("Error: frame \"%s\": contains multiple frames on its own\n", argv[0]); goto fail;}
}
// Get the file name
char fname[256];
auto dot = strrchr(dir, '\\');
if (dot == NULL) {
dot = strrchr(dir, '/');
}
if (dot != NULL) {
dot[0] = '\0';
}
if (strlen(dir) > sizeof(fname) - 5) {
goto fail;
}
sprintf(fname, "%s.vtf", dir);
// Write the file
auto const f = fopen(fname, "wb");
if (f == NULL) {
printf("Error: couldn't write \"%s\"\n", fname);
goto fail;
}
fwrite(vtf_mem, 1, vtf_size_new, f);
fclose(f);
// Cleanup
free(vtf_mem);
free(mip_lut);
return EXIT_SUCCESS;
fail:
free(vtf_mem);
free(mip_lut);
return EXIT_FAILURE;
}