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