Coverage Report

Created: 2026-02-05 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/MMD/MMDVmdParser.h
Line
Count
Source
1
/*
2
Open Asset Import Library (assimp)
3
----------------------------------------------------------------------
4
5
Copyright (c) 2006-2026, assimp team
6
7
All rights reserved.
8
9
Redistribution and use of this software in source and binary forms,
10
with or without modification, are permitted provided that the
11
following conditions are met:
12
13
* Redistributions of source code must retain the above
14
copyright notice, this list of conditions and the
15
following disclaimer.
16
17
* Redistributions in binary form must reproduce the above
18
copyright notice, this list of conditions and the
19
following disclaimer in the documentation and/or other
20
materials provided with the distribution.
21
22
* Neither the name of the assimp team, nor the names of its
23
contributors may be used to endorse or promote products
24
derived from this software without specific prior
25
written permission of the assimp team.
26
27
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39
----------------------------------------------------------------------
40
*/
41
#pragma once
42
43
#include <vector>
44
#include <string>
45
#include <memory>
46
#include <iostream>
47
#include <fstream>
48
#include <ostream>
49
#include "MMDCpp14.h"
50
51
namespace vmd
52
{
53
  class VmdBoneFrame
54
  {
55
  public:
56
    std::string name;
57
    int frame;
58
    float position[3];
59
    float orientation[4];
60
    char interpolation[4][4][4];
61
62
    void Read(std::istream* stream)
63
0
    {
64
0
      char buffer[15];
65
0
      stream->read((char*) buffer, sizeof(char)*15);
66
0
      name = std::string(buffer);
67
0
      stream->read((char*) &frame, sizeof(int));
68
0
      stream->read((char*) position, sizeof(float)*3);
69
0
      stream->read((char*) orientation, sizeof(float)*4);
70
0
      stream->read((char*) interpolation, sizeof(char) * 4 * 4 * 4);
71
0
    }
72
73
    void Write(std::ostream* stream)
74
0
    {
75
0
      stream->write((char*)name.c_str(), sizeof(char) * 15);
76
0
      stream->write((char*)&frame, sizeof(int));
77
0
      stream->write((char*)position, sizeof(float) * 3);
78
0
      stream->write((char*)orientation, sizeof(float) * 4);
79
0
      stream->write((char*)interpolation, sizeof(char) * 4 * 4 * 4);
80
0
    }
81
  };
82
83
  class VmdFaceFrame
84
  {
85
  public:
86
    std::string face_name;
87
    float weight;
88
    uint32_t frame;
89
90
    void Read(std::istream* stream)
91
0
    {
92
0
      char buffer[15];
93
0
      stream->read((char*) &buffer, sizeof(char) * 15);
94
0
      face_name = std::string(buffer);
95
0
      stream->read((char*) &frame, sizeof(int));
96
0
      stream->read((char*) &weight, sizeof(float));
97
0
    }
98
99
    void Write(std::ostream* stream)
100
0
    {
101
0
      stream->write((char*)face_name.c_str(), sizeof(char) * 15);
102
0
      stream->write((char*)&frame, sizeof(int));
103
0
      stream->write((char*)&weight, sizeof(float));
104
0
    }
105
  };
106
107
  class VmdCameraFrame
108
  {
109
  public:
110
    int frame;
111
    float distance;
112
    float position[3];
113
    float orientation[3];
114
    char interpolation[6][4];
115
    float angle;
116
    char unknown[3];
117
118
    void Read(std::istream *stream)
119
0
    {
120
0
      stream->read((char*) &frame, sizeof(int));
121
0
      stream->read((char*) &distance, sizeof(float));
122
0
      stream->read((char*) position, sizeof(float) * 3);
123
0
      stream->read((char*) orientation, sizeof(float) * 3);
124
0
      stream->read((char*) interpolation, sizeof(char) * 24);
125
0
      stream->read((char*) &angle, sizeof(float));
126
0
      stream->read((char*) unknown, sizeof(char) * 3);
127
0
    }
128
129
    void Write(std::ostream *stream)
130
0
    {
131
0
      stream->write((char*)&frame, sizeof(int));
132
0
      stream->write((char*)&distance, sizeof(float));
133
0
      stream->write((char*)position, sizeof(float) * 3);
134
0
      stream->write((char*)orientation, sizeof(float) * 3);
135
0
      stream->write((char*)interpolation, sizeof(char) * 24);
136
0
      stream->write((char*)&angle, sizeof(float));
137
0
      stream->write((char*)unknown, sizeof(char) * 3);
138
0
    }
139
  };
140
141
  class VmdLightFrame
142
  {
143
  public:
144
    int frame;
145
    float color[3];
146
    float position[3];
147
148
    void Read(std::istream* stream)
149
0
    {
150
0
      stream->read((char*) &frame, sizeof(int));
151
0
      stream->read((char*) color, sizeof(float) * 3);
152
0
      stream->read((char*) position, sizeof(float) * 3);
153
0
    }
154
155
    void Write(std::ostream* stream)
156
0
    {
157
0
      stream->write((char*)&frame, sizeof(int));
158
0
      stream->write((char*)color, sizeof(float) * 3);
159
0
      stream->write((char*)position, sizeof(float) * 3);
160
0
    }
161
  };
162
163
  class VmdIkEnable
164
  {
165
  public:
166
    std::string ik_name;
167
    bool enable;
168
  };
169
170
  class VmdIkFrame
171
  {
172
  public:
173
    int frame;
174
    bool display;
175
    std::vector<VmdIkEnable> ik_enable;
176
177
    void Read(std::istream *stream)
178
0
    {
179
0
      char buffer[20];
180
0
      stream->read((char*) &frame, sizeof(int));
181
0
      stream->read((char*) &display, sizeof(uint8_t));
182
0
      int ik_count;
183
0
      stream->read((char*) &ik_count, sizeof(int));
184
0
      ik_enable.resize(ik_count);
185
0
      for (int i = 0; i < ik_count; i++)
186
0
      {
187
0
        stream->read(buffer, 20);
188
0
        ik_enable[i].ik_name = std::string(buffer);
189
0
        stream->read((char*) &ik_enable[i].enable, sizeof(uint8_t));
190
0
      }
191
0
    }
192
193
    void Write(std::ostream *stream)
194
0
    {
195
0
      stream->write((char*)&frame, sizeof(int));
196
0
      stream->write((char*)&display, sizeof(uint8_t));
197
0
      int ik_count = static_cast<int>(ik_enable.size());
198
0
      stream->write((char*)&ik_count, sizeof(int));
199
0
      for (int i = 0; i < ik_count; i++)
200
0
      {
201
0
        const VmdIkEnable& ik_enable_ref = this->ik_enable.at(i);
202
0
                stream->write(ik_enable_ref.ik_name.c_str(), 20);
203
0
                stream->write((char *)&ik_enable_ref.enable, sizeof(uint8_t));
204
0
      }
205
0
    }
206
  };
207
208
  class VmdMotion
209
  {
210
  public:
211
    std::string model_name;
212
    int version;
213
    std::vector<VmdBoneFrame> bone_frames;
214
    std::vector<VmdFaceFrame> face_frames;
215
    std::vector<VmdCameraFrame> camera_frames;
216
    std::vector<VmdLightFrame> light_frames;
217
    std::vector<VmdIkFrame> ik_frames;
218
219
    static std::unique_ptr<VmdMotion> LoadFromFile(char const *filename)
220
0
    {
221
0
      std::ifstream stream(filename, std::ios::binary);
222
0
      auto result = LoadFromStream(&stream);
223
0
      stream.close();
224
0
      return result;
225
0
    }
226
227
    static std::unique_ptr<VmdMotion> LoadFromStream(std::ifstream *stream)
228
0
    {
229
0
230
0
      char buffer[30];
231
0
      auto result = mmd::make_unique<VmdMotion>();
232
0
233
0
      // magic and version
234
0
      stream->read((char*) buffer, 30);
235
0
      if (strncmp(buffer, "Vocaloid Motion Data", 20))
236
0
      {
237
0
        std::cerr << "invalid vmd file." << std::endl;
238
0
        return nullptr;
239
0
      }
240
0
      result->version = std::atoi(buffer + 20);
241
0
242
0
      // name
243
0
      stream->read(buffer, 20);
244
0
      result->model_name = std::string(buffer);
245
0
246
0
      // bone frames
247
0
      int bone_frame_num;
248
0
      stream->read((char*) &bone_frame_num, sizeof(int));
249
0
      result->bone_frames.resize(bone_frame_num);
250
0
      for (int i = 0; i < bone_frame_num; i++)
251
0
      {
252
0
        result->bone_frames[i].Read(stream);
253
0
      }
254
0
255
0
      // face frames
256
0
      int face_frame_num;
257
0
      stream->read((char*) &face_frame_num, sizeof(int));
258
0
      result->face_frames.resize(face_frame_num);
259
0
      for (int i = 0; i < face_frame_num; i++)
260
0
      {
261
0
        result->face_frames[i].Read(stream);
262
0
      }
263
0
264
0
      // camera frames
265
0
      int camera_frame_num;
266
0
      stream->read((char*) &camera_frame_num, sizeof(int));
267
0
      result->camera_frames.resize(camera_frame_num);
268
0
      for (int i = 0; i < camera_frame_num; i++)
269
0
      {
270
0
        result->camera_frames[i].Read(stream);
271
0
      }
272
0
273
0
      // light frames
274
0
      int light_frame_num;
275
0
      stream->read((char*) &light_frame_num, sizeof(int));
276
0
      result->light_frames.resize(light_frame_num);
277
0
      for (int i = 0; i < light_frame_num; i++)
278
0
      {
279
0
        result->light_frames[i].Read(stream);
280
0
      }
281
0
282
0
      // unknown2
283
0
      stream->read(buffer, 4);
284
0
285
0
      // ik frames
286
0
      if (stream->peek() != std::ios::traits_type::eof())
287
0
      {
288
0
        int ik_num;
289
0
        stream->read((char*) &ik_num, sizeof(int));
290
0
        result->ik_frames.resize(ik_num);
291
0
        for (int i = 0; i < ik_num; i++)
292
0
        {
293
0
          result->ik_frames[i].Read(stream);
294
0
        }
295
0
      }
296
0
297
0
      if (stream->peek() != std::ios::traits_type::eof())
298
0
      {
299
0
        std::cerr << "vmd stream has unknown data." << std::endl;
300
0
      }
301
0
302
0
      return result;
303
0
    }
304
305
        bool SaveToFile(const std::u16string& /*filename*/)
306
0
    {
307
0
      // TODO: How to adapt u16string to string?
308
0
      /*
309
0
      std::ofstream stream(filename.c_str(), std::ios::binary);
310
0
      auto result = SaveToStream(&stream);
311
0
      stream.close();
312
0
      return result;
313
0
      */
314
0
      return false;
315
0
    }
316
317
    bool SaveToStream(std::ofstream *stream)
318
0
    {
319
0
      std::string magic = "Vocaloid Motion Data 0002\0";
320
0
      magic.resize(30);
321
0
322
0
      // magic and version
323
0
      stream->write(magic.c_str(), 30);
324
0
325
0
      // name
326
0
      stream->write(model_name.c_str(), 20);
327
0
328
0
      // bone frames
329
0
      const int bone_frame_num = static_cast<int>(bone_frames.size());
330
0
      stream->write(reinterpret_cast<const char*>(&bone_frame_num), sizeof(int));
331
0
      for (int i = 0; i < bone_frame_num; i++)
332
0
      {
333
0
        bone_frames[i].Write(stream);
334
0
      }
335
0
336
0
      // face frames
337
0
      const int face_frame_num = static_cast<int>(face_frames.size());
338
0
      stream->write(reinterpret_cast<const char*>(&face_frame_num), sizeof(int));
339
0
      for (int i = 0; i < face_frame_num; i++)
340
0
      {
341
0
        face_frames[i].Write(stream);
342
0
      }
343
0
344
0
      // camera frames
345
0
      const int camera_frame_num = static_cast<int>(camera_frames.size());
346
0
      stream->write(reinterpret_cast<const char*>(&camera_frame_num), sizeof(int));
347
0
      for (int i = 0; i < camera_frame_num; i++)
348
0
      {
349
0
        camera_frames[i].Write(stream);
350
0
      }
351
0
352
0
      // light frames
353
0
      const int light_frame_num = static_cast<int>(light_frames.size());
354
0
      stream->write(reinterpret_cast<const char*>(&light_frame_num), sizeof(int));
355
0
      for (int i = 0; i < light_frame_num; i++)
356
0
      {
357
0
        light_frames[i].Write(stream);
358
0
      }
359
0
360
0
      // self shadow data
361
0
      const int self_shadow_num = 0;
362
0
      stream->write(reinterpret_cast<const char*>(&self_shadow_num), sizeof(int));
363
0
364
0
      // ik frames
365
0
      const int ik_num = static_cast<int>(ik_frames.size());
366
0
      stream->write(reinterpret_cast<const char*>(&ik_num), sizeof(int));
367
0
      for (int i = 0; i < ik_num; i++)
368
0
      {
369
0
        ik_frames[i].Write(stream);
370
0
      }
371
0
372
0
      return true;
373
0
    }
374
  };
375
}