Blender  V3.3
MOD_meshcache_pc2.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 #ifdef __BIG_ENDIAN__
15 # include "BLI_endian_switch.h"
16 #endif
17 
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 PC2Head {
27  char header[12]; /* 'POINTCACHE2\0' */
28  int file_version; /* unused - should be 1 */
29  int verts_tot;
30  float start;
31  float sampling;
32  int frame_tot;
33 } PC2Head; /* frames, verts */
34 
35 static bool meshcache_read_pc2_head(FILE *fp,
36  const int verts_tot,
37  PC2Head *pc2_head,
38  const char **err_str)
39 {
40  if (!fread(pc2_head, sizeof(*pc2_head), 1, fp)) {
41  *err_str = "Missing header";
42  return false;
43  }
44 
45  if (!STREQ(pc2_head->header, "POINTCACHE2")) {
46  *err_str = "Invalid header";
47  return false;
48  }
49 
50 #ifdef __BIG_ENDIAN__
52  (sizeof(*pc2_head) - sizeof(pc2_head->header)) / sizeof(int));
53 #endif
54 
55  if (pc2_head->verts_tot != verts_tot) {
56  *err_str = "Vertex count mismatch";
57  return false;
58  }
59 
60  if (pc2_head->frame_tot <= 0) {
61  *err_str = "Invalid frame total";
62  return false;
63  }
64  /* Intentionally don't seek back. */
65 
66  return true;
67 }
68 
74 static bool meshcache_read_pc2_range(FILE *fp,
75  const int verts_tot,
76  const float frame,
77  const char interp,
78  int r_index_range[2],
79  float *r_factor,
80  const char **err_str)
81 {
82  PC2Head pc2_head;
83 
84  /* first check interpolation and get the vert locations */
85 
86  if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) {
87  return false;
88  }
89 
90  MOD_meshcache_calc_range(frame, interp, pc2_head.frame_tot, r_index_range, r_factor);
91 
92  return true;
93 }
94 
96  const int verts_tot,
97  const float time,
98  const float fps,
99  float *r_frame,
100  const char **err_str)
101 {
102  PC2Head pc2_head;
103  float frame;
104 
105  if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) {
106  return false;
107  }
108 
109  frame = ((time / fps) - pc2_head.start) / pc2_head.sampling;
110 
111  if (frame >= pc2_head.frame_tot) {
112  frame = (float)(pc2_head.frame_tot - 1);
113  }
114  else if (frame < 0.0f) {
115  frame = 0.0f;
116  }
117 
118  *r_frame = frame;
119  return true;
120 }
121 
123  float (*vertexCos)[3],
124  const int verts_tot,
125  const int index,
126  const float factor,
127  const char **err_str)
128 {
129  PC2Head pc2_head;
130 
131  if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) {
132  return false;
133  }
134 
135  if (BLI_fseek(fp, sizeof(float[3]) * index * pc2_head.verts_tot, SEEK_CUR) != 0) {
136  *err_str = "Failed to seek frame";
137  return false;
138  }
139 
140  size_t verts_read_num = 0;
141  errno = 0;
142  if (factor >= 1.0f) {
143  float *vco = *vertexCos;
144  uint i;
145  for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
146  verts_read_num += fread(vco, sizeof(float[3]), 1, fp);
147 
148 #ifdef __BIG_ENDIAN__
149  BLI_endian_switch_float(vco + 0);
150  BLI_endian_switch_float(vco + 1);
151  BLI_endian_switch_float(vco + 2);
152 #endif /* __BIG_ENDIAN__ */
153  }
154  }
155  else {
156  const float ifactor = 1.0f - factor;
157  float *vco = *vertexCos;
158  uint i;
159  for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
160  float tvec[3];
161  verts_read_num += fread(tvec, sizeof(float[3]), 1, fp);
162 
163 #ifdef __BIG_ENDIAN__
164  BLI_endian_switch_float(tvec + 0);
165  BLI_endian_switch_float(tvec + 1);
166  BLI_endian_switch_float(tvec + 2);
167 #endif /* __BIG_ENDIAN__ */
168 
169  vco[0] = (vco[0] * ifactor) + (tvec[0] * factor);
170  vco[1] = (vco[1] * ifactor) + (tvec[1] * factor);
171  vco[2] = (vco[2] * ifactor) + (tvec[2] * factor);
172  }
173  }
174 
175  if (verts_read_num != pc2_head.verts_tot) {
176  *err_str = errno ? strerror(errno) : "Vertex coordinate read failed";
177  return false;
178  }
179 
180  return true;
181 }
182 
184  float (*vertexCos)[3],
185  const int verts_tot,
186  const char interp,
187  const float frame,
188  const char **err_str)
189 {
190  int index_range[2];
191  float factor;
192 
194  verts_tot,
195  frame,
196  interp,
197  index_range,
198  &factor, /* read into these values */
199  err_str) == false) {
200  return false;
201  }
202 
203  if (index_range[0] == index_range[1]) {
204  /* read single */
205  if ((BLI_fseek(fp, 0, SEEK_SET) == 0) &&
206  MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str)) {
207  return true;
208  }
209 
210  return false;
211  }
212 
213  /* read both and interpolate */
214  if ((BLI_fseek(fp, 0, SEEK_SET) == 0) &&
215  MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str) &&
216  (BLI_fseek(fp, 0, SEEK_SET) == 0) &&
217  MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[1], factor, err_str)) {
218  return true;
219  }
220 
221  return false;
222 }
223 
224 bool MOD_meshcache_read_pc2_times(const char *filepath,
225  float (*vertexCos)[3],
226  const int verts_tot,
227  const char interp,
228  const float time,
229  const float fps,
230  const char time_mode,
231  const char **err_str)
232 {
233  float frame;
234 
235  FILE *fp = BLI_fopen(filepath, "rb");
236  bool ok;
237 
238  if (fp == NULL) {
239  *err_str = errno ? strerror(errno) : "Unknown error opening file";
240  return false;
241  }
242 
243  switch (time_mode) {
245  frame = time;
246  break;
247  }
249  /* we need to find the closest time */
250  if (meshcache_read_pc2_range_from_time(fp, verts_tot, time, fps, &frame, err_str) == false) {
251  fclose(fp);
252  return false;
253  }
254  rewind(fp);
255  break;
256  }
258  default: {
259  PC2Head pc2_head;
260  if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) {
261  fclose(fp);
262  return false;
263  }
264 
265  frame = CLAMPIS(time, 0.0f, 1.0f) * (float)pc2_head.frame_tot;
266  rewind(fp);
267  break;
268  }
269  }
270 
271  ok = MOD_meshcache_read_pc2_frame(fp, vertexCos, verts_tot, interp, frame, err_str);
272 
273  fclose(fp);
274  return ok;
275 }
typedef float(TangentPoint)[2]
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 STREQ(a, b)
Compatibility-like things for windows.
@ MOD_MESHCACHE_TIME_FRAME
@ MOD_MESHCACHE_TIME_FACTOR
@ MOD_MESHCACHE_TIME_SECONDS
bool MOD_meshcache_read_pc2_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)
static bool meshcache_read_pc2_head(FILE *fp, const int verts_tot, PC2Head *pc2_head, const char **err_str)
static bool meshcache_read_pc2_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)
static bool meshcache_read_pc2_range_from_time(FILE *fp, const int verts_tot, const float time, const float fps, float *r_frame, const char **err_str)
struct PC2Head PC2Head
bool MOD_meshcache_read_pc2_frame(FILE *fp, float(*vertexCos)[3], const int verts_tot, const char interp, const float frame, const char **err_str)
bool MOD_meshcache_read_pc2_index(FILE *fp, float(*vertexCos)[3], const int verts_tot, const int index, const float factor, 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)
double time
ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t)
Definition: math_float2.h:232
float sampling
char header[12]