Blender V4.3
MOD_meshcache_mdd.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10#include <cerrno>
11#include <cstdio>
12#include <cstring>
13
14#include "BLI_utildefines.h"
15
16#include "BLI_fileops.h"
17#include "BLI_math_base.h"
18#ifdef __LITTLE_ENDIAN__
19# include "BLI_endian_switch.h"
20#endif
21#ifdef WIN32
22# include "BLI_winstuff.h"
23#endif
24
25#include "BLT_translation.hh"
26
27#include "DNA_modifier_types.h"
28
29#include "MOD_meshcache_util.hh" /* own include */
30
31struct MDDHead {
34}; /* frames, verts */
35
36static bool meshcache_read_mdd_head(FILE *fp,
37 const int verts_tot,
38 MDDHead *mdd_head,
39 const char **r_err_str)
40{
41 if (!fread(mdd_head, sizeof(*mdd_head), 1, fp)) {
42 *r_err_str = RPT_("Missing header");
43 return false;
44 }
45
46#ifdef __LITTLE_ENDIAN__
47 BLI_endian_switch_int32_array((int *)mdd_head, 2);
48#endif
49
50 if (mdd_head->verts_tot != verts_tot) {
51 *r_err_str = RPT_("Vertex count mismatch");
52 return false;
53 }
54
55 if (mdd_head->frame_tot <= 0) {
56 *r_err_str = RPT_("Invalid frame total");
57 return false;
58 }
59 /* Intentionally don't seek back. */
60
61 return true;
62}
63
67static bool meshcache_read_mdd_range(FILE *fp,
68 const int verts_tot,
69 const float frame,
70 const char interp,
71 int r_index_range[2],
72 float *r_factor,
73 const char **r_err_str)
74{
75 MDDHead mdd_head;
76
77 /* first check interpolation and get the vert locations */
78
79 if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, r_err_str) == false) {
80 return false;
81 }
82
83 MOD_meshcache_calc_range(frame, interp, mdd_head.frame_tot, r_index_range, r_factor);
84
85 return true;
86}
87
89 const int verts_tot,
90 const float time,
91 const float /*fps*/,
92 float *r_frame,
93 const char **r_err_str)
94{
95 MDDHead mdd_head;
96 int i;
97 float f_time, f_time_prev = FLT_MAX;
98 float frame;
99
100 if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, r_err_str) == false) {
101 return false;
102 }
103
104 size_t frames_num_read = 0;
105 size_t frames_num_expect = mdd_head.frame_tot;
106 errno = 0;
107 for (i = 0; i < mdd_head.frame_tot; i++) {
108 frames_num_read += fread(&f_time, sizeof(float), 1, fp);
109#ifdef __LITTLE_ENDIAN__
111#endif
112 if (f_time >= time) {
113 frames_num_expect = i + 1;
114 break;
115 }
116 f_time_prev = f_time;
117 }
118
119 if (frames_num_read != frames_num_expect) {
120 *r_err_str = errno ? strerror(errno) : RPT_("Timestamp read failed");
121 return false;
122 }
123
124 if (UNLIKELY(f_time_prev == FLT_MAX)) {
125 frame = 0.0f;
126 }
127 else {
128 const float range = f_time - f_time_prev;
129
130 if (range <= FRAME_SNAP_EPS) {
131 frame = float(i);
132 }
133 else {
134 frame = float(i - 1) + ((time - f_time_prev) / range);
135 }
136 }
137
138 *r_frame = frame;
139 return true;
140}
141
143 float (*vertexCos)[3],
144 const int verts_tot,
145 const int index,
146 const float factor,
147 const char **r_err_str)
148{
149 MDDHead mdd_head;
150
151 if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, r_err_str) == false) {
152 return false;
153 }
154
155 if (BLI_fseek(fp, mdd_head.frame_tot * sizeof(int), SEEK_CUR) != 0) {
156 *r_err_str = RPT_("Header seek failed");
157 return false;
158 }
159
160 if (BLI_fseek(fp, sizeof(float[3]) * index * mdd_head.verts_tot, SEEK_CUR) != 0) {
161 *r_err_str = RPT_("Failed to seek frame");
162 return false;
163 }
164
165 size_t verts_read_num = 0;
166 errno = 0;
167 if (factor >= 1.0f) {
168#if 1
169 float *vco = *vertexCos;
170 uint i;
171 for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) {
172 verts_read_num += fread(vco, sizeof(float[3]), 1, fp);
173
174# ifdef __LITTLE_ENDIAN__
178# endif /* __LITTLE_ENDIAN__ */
179 }
180#else
181 /* no blending */
182 if (!fread(vertexCos, sizeof(float[3]), mdd_head.verts_tot, f)) {
183 *r_err_str = errno ? strerror(errno) : RPT_("Failed to read frame");
184 return false;
185 }
186# ifdef __LITTLE_ENDIAN__
187 BLI_endian_switch_float_array(vertexCos[0], mdd_head.verts_tot * 3);
188# endif
189#endif
190 }
191 else {
192 const float ifactor = 1.0f - factor;
193 float *vco = *vertexCos;
194 uint i;
195 for (i = mdd_head.verts_tot; i != 0; i--, vco += 3) {
196 float tvec[3];
197 verts_read_num += fread(tvec, sizeof(float[3]), 1, fp);
198
199#ifdef __LITTLE_ENDIAN__
200 BLI_endian_switch_float(tvec + 0);
201 BLI_endian_switch_float(tvec + 1);
202 BLI_endian_switch_float(tvec + 2);
203#endif
204
205 vco[0] = (vco[0] * ifactor) + (tvec[0] * factor);
206 vco[1] = (vco[1] * ifactor) + (tvec[1] * factor);
207 vco[2] = (vco[2] * ifactor) + (tvec[2] * factor);
208 }
209 }
210
211 if (verts_read_num != mdd_head.verts_tot) {
212 *r_err_str = errno ? strerror(errno) : RPT_("Vertex coordinate read failed");
213 return false;
214 }
215
216 return true;
217}
218
220 float (*vertexCos)[3],
221 const int verts_tot,
222 const char interp,
223 const float frame,
224 const char **r_err_str)
225{
226 int index_range[2];
227 float factor;
228
230 verts_tot,
231 frame,
232 interp,
233 index_range,
234 &factor, /* read into these values */
235 r_err_str) == false)
236 {
237 return false;
238 }
239
240 if (index_range[0] == index_range[1]) {
241 /* read single */
242 if ((BLI_fseek(fp, 0, SEEK_SET) == 0) &&
243 MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, r_err_str))
244 {
245 return true;
246 }
247
248 return false;
249 }
250
251 /* read both and interpolate */
252 if ((BLI_fseek(fp, 0, SEEK_SET) == 0) &&
253 MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, r_err_str) &&
254 (BLI_fseek(fp, 0, SEEK_SET) == 0) &&
255 MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[1], factor, r_err_str))
256 {
257 return true;
258 }
259
260 return false;
261}
262
263bool MOD_meshcache_read_mdd_times(const char *filepath,
264 float (*vertexCos)[3],
265 const int verts_tot,
266 const char interp,
267 const float time,
268 const float fps,
269 const char time_mode,
270 const char **r_err_str)
271{
272 float frame;
273
274 FILE *fp = BLI_fopen(filepath, "rb");
275 bool ok;
276
277 if (fp == nullptr) {
278 *r_err_str = errno ? strerror(errno) : RPT_("Unknown error opening file");
279 return false;
280 }
281
282 switch (time_mode) {
284 frame = time;
285 break;
286 }
288 /* we need to find the closest time */
289 if (meshcache_read_mdd_range_from_time(fp, verts_tot, time, fps, &frame, r_err_str) == false)
290 {
291 fclose(fp);
292 return false;
293 }
294 rewind(fp);
295 break;
296 }
298 default: {
299 MDDHead mdd_head;
300 if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, r_err_str) == false) {
301 fclose(fp);
302 return false;
303 }
304
305 frame = std::clamp(time, 0.0f, 1.0f) * float(mdd_head.frame_tot);
306 rewind(fp);
307 break;
308 }
309 }
310
311 ok = MOD_meshcache_read_mdd_frame(fp, vertexCos, verts_tot, interp, frame, r_err_str);
312
313 fclose(fp);
314 return ok;
315}
void BLI_endian_switch_float_array(float *val, int size) ATTR_NONNULL(1)
void BLI_endian_switch_int32_array(int *val, int size) ATTR_NONNULL(1)
BLI_INLINE void BLI_endian_switch_float(float *val) ATTR_NONNULL(1)
File and directory operations.
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_fseek(FILE *stream, int64_t offset, int whence)
Definition storage.cc:188
unsigned int uint
#define UNLIKELY(x)
Compatibility-like things for windows.
#define RPT_(msgid)
@ MOD_MESHCACHE_TIME_FRAME
@ MOD_MESHCACHE_TIME_FACTOR
@ MOD_MESHCACHE_TIME_SECONDS
static bool meshcache_read_mdd_range(FILE *fp, const int verts_tot, const float frame, const char interp, int r_index_range[2], float *r_factor, const char **r_err_str)
bool MOD_meshcache_read_mdd_times(const char *filepath, float(*vertexCos)[3], const int verts_tot, const char interp, const float time, const float fps, const char time_mode, const char **r_err_str)
bool MOD_meshcache_read_mdd_frame(FILE *fp, float(*vertexCos)[3], const int verts_tot, const char interp, const float frame, const char **r_err_str)
static bool meshcache_read_mdd_range_from_time(FILE *fp, const int verts_tot, const float time, const float, float *r_frame, const char **r_err_str)
static bool meshcache_read_mdd_head(FILE *fp, const int verts_tot, MDDHead *mdd_head, const char **r_err_str)
bool MOD_meshcache_read_mdd_index(FILE *fp, float(*vertexCos)[3], const int verts_tot, const int index, const float factor, const char **r_err_str)
void MOD_meshcache_calc_range(const float frame, const char interp, const int frame_tot, int r_index_range[2], float *r_factor)
#define FRAME_SNAP_EPS
double time
draw_view in_light_buf[] float
ccl_device_inline float2 interp(const float2 a, const float2 b, float t)
#define FLT_MAX
Definition stdcycles.h:14