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