Blender  V3.3
MOD_meshcache_mdd.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <errno.h>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include "BLI_utildefines.h"
12 
13 #include "BLI_fileops.h"
14 #include "BLI_math.h"
15 #ifdef __LITTLE_ENDIAN__
16 # include "BLI_endian_switch.h"
17 #endif
18 #ifdef WIN32
19 # include "BLI_winstuff.h"
20 #endif
21 
22 #include "DNA_modifier_types.h"
23 
24 #include "MOD_meshcache_util.h" /* own include */
25 
26 typedef struct MDDHead {
27  int frame_tot;
28  int verts_tot;
29 } MDDHead; /* frames, verts */
30 
31 static bool meshcache_read_mdd_head(FILE *fp,
32  const int verts_tot,
33  MDDHead *mdd_head,
34  const char **err_str)
35 {
36  if (!fread(mdd_head, sizeof(*mdd_head), 1, fp)) {
37  *err_str = "Missing header";
38  return false;
39  }
40 
41 #ifdef __LITTLE_ENDIAN__
42  BLI_endian_switch_int32_array((int *)mdd_head, 2);
43 #endif
44 
45  if (mdd_head->verts_tot != verts_tot) {
46  *err_str = "Vertex count mismatch";
47  return false;
48  }
49 
50  if (mdd_head->frame_tot <= 0) {
51  *err_str = "Invalid frame total";
52  return false;
53  }
54  /* Intentionally don't seek back. */
55 
56  return true;
57 }
58 
62 static bool meshcache_read_mdd_range(FILE *fp,
63  const int verts_tot,
64  const float frame,
65  const char interp,
66  int r_index_range[2],
67  float *r_factor,
68  const char **err_str)
69 {
70  MDDHead mdd_head;
71 
72  /* first check interpolation and get the vert locations */
73 
74  if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) {
75  return false;
76  }
77 
78  MOD_meshcache_calc_range(frame, interp, mdd_head.frame_tot, r_index_range, r_factor);
79 
80  return true;
81 }
82 
84  const int verts_tot,
85  const float time,
86  const float UNUSED(fps),
87  float *r_frame,
88  const char **err_str)
89 {
90  MDDHead mdd_head;
91  int i;
92  float f_time, f_time_prev = FLT_MAX;
93  float frame;
94 
95  if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) {
96  return false;
97  }
98 
99  size_t frames_num_read = 0;
100  size_t frames_num_expect = mdd_head.frame_tot;
101  errno = 0;
102  for (i = 0; i < mdd_head.frame_tot; i++) {
103  frames_num_read += fread(&f_time, sizeof(float), 1, fp);
104 #ifdef __LITTLE_ENDIAN__
105  BLI_endian_switch_float(&f_time);
106 #endif
107  if (f_time >= time) {
108  frames_num_expect = i + 1;
109  break;
110  }
111  f_time_prev = f_time;
112  }
113 
114  if (frames_num_read != frames_num_expect) {
115  *err_str = errno ? strerror(errno) : "Timestamp read failed";
116  return false;
117  }
118 
119  if (i == mdd_head.frame_tot) {
120  frame = (float)(mdd_head.frame_tot - 1);
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 **err_str)
146 {
147  MDDHead mdd_head;
148 
149  if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) {
150  return false;
151  }
152 
153  if (BLI_fseek(fp, mdd_head.frame_tot * sizeof(int), SEEK_CUR) != 0) {
154  *err_str = "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  *err_str = "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__
173  BLI_endian_switch_float(vco + 0);
174  BLI_endian_switch_float(vco + 1);
175  BLI_endian_switch_float(vco + 2);
176 # endif /* __LITTLE_ENDIAN__ */
177  }
178 #else
179  /* no blending */
180  if (!fread(vertexCos, sizeof(float[3]), mdd_head.verts_tot, f)) {
181  *err_str = errno ? strerror(errno) : "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  *err_str = errno ? strerror(errno) : "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 **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  err_str) == false) {
234  return false;
235  }
236 
237  if (index_range[0] == index_range[1]) {
238  /* read single */
239  if ((BLI_fseek(fp, 0, SEEK_SET) == 0) &&
240  MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str)) {
241  return true;
242  }
243 
244  return false;
245  }
246 
247  /* read both and interpolate */
248  if ((BLI_fseek(fp, 0, SEEK_SET) == 0) &&
249  MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str) &&
250  (BLI_fseek(fp, 0, SEEK_SET) == 0) &&
251  MOD_meshcache_read_mdd_index(fp, vertexCos, verts_tot, index_range[1], factor, err_str)) {
252  return true;
253  }
254 
255  return false;
256 }
257 
258 bool MOD_meshcache_read_mdd_times(const char *filepath,
259  float (*vertexCos)[3],
260  const int verts_tot,
261  const char interp,
262  const float time,
263  const float fps,
264  const char time_mode,
265  const char **err_str)
266 {
267  float frame;
268 
269  FILE *fp = BLI_fopen(filepath, "rb");
270  bool ok;
271 
272  if (fp == NULL) {
273  *err_str = errno ? strerror(errno) : "Unknown error opening file";
274  return false;
275  }
276 
277  switch (time_mode) {
279  frame = time;
280  break;
281  }
283  /* we need to find the closest time */
284  if (meshcache_read_mdd_range_from_time(fp, verts_tot, time, fps, &frame, err_str) == false) {
285  fclose(fp);
286  return false;
287  }
288  rewind(fp);
289  break;
290  }
292  default: {
293  MDDHead mdd_head;
294  if (meshcache_read_mdd_head(fp, verts_tot, &mdd_head, err_str) == false) {
295  fclose(fp);
296  return false;
297  }
298 
299  frame = CLAMPIS(time, 0.0f, 1.0f) * (float)mdd_head.frame_tot;
300  rewind(fp);
301  break;
302  }
303  }
304 
305  ok = MOD_meshcache_read_mdd_frame(fp, vertexCos, verts_tot, interp, frame, err_str);
306 
307  fclose(fp);
308  return ok;
309 }
typedef float(TangentPoint)[2]
void BLI_endian_switch_float_array(float *val, int size) ATTR_NONNULL(1)
Definition: endian_switch.c:51
void BLI_endian_switch_int32_array(int *val, int size) ATTR_NONNULL(1)
Definition: endian_switch.c:31
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()
Definition: fileops.c:906
int BLI_fseek(FILE *stream, int64_t offset, int whence)
Definition: storage.c:160
unsigned int uint
Definition: BLI_sys_types.h:67
#define CLAMPIS(a, b, c)
#define UNUSED(x)
#define UNLIKELY(x)
Compatibility-like things for windows.
@ MOD_MESHCACHE_TIME_FRAME
@ MOD_MESHCACHE_TIME_FACTOR
@ MOD_MESHCACHE_TIME_SECONDS
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 **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 **err_str)
static bool meshcache_read_mdd_range_from_time(FILE *fp, const int verts_tot, const float time, const float UNUSED(fps), float *r_frame, const char **err_str)
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 **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 **err_str)
struct MDDHead MDDHead
static bool meshcache_read_mdd_head(FILE *fp, const int verts_tot, MDDHead *mdd_head, const char **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
ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t)
Definition: math_float2.h:232