Files
test/source/blender/modifiers/intern/MOD_meshcache_pc2.cc
Sergey Sharybin c1bc70b711 Cleanup: Add a copyright notice to files and use SPDX format
A lot of files were missing copyright field in the header and
the Blender Foundation contributed to them in a sense of bug
fixing and general maintenance.

This change makes it explicit that those files are at least
partially copyrighted by the Blender Foundation.

Note that this does not make it so the Blender Foundation is
the only holder of the copyright in those files, and developers
who do not have a signed contract with the foundation still
hold the copyright as well.

Another aspect of this change is using SPDX format for the
header. We already used it for the license specification,
and now we state it for the copyright as well, following the
FAQ:

    https://reuse.software/faq/
2023-05-31 16:19:06 +02:00

281 lines
7.3 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup modifiers
*/
#include <cerrno>
#include <cstdio>
#include <cstring>
#include "BLI_utildefines.h"
#include "BLI_fileops.h"
#ifdef __BIG_ENDIAN__
# include "BLI_endian_switch.h"
#endif
#ifdef WIN32
# include "BLI_winstuff.h"
#endif
#include "DNA_modifier_types.h"
#include "MOD_meshcache_util.hh" /* own include */
struct PC2Head {
char header[12]; /* 'POINTCACHE2\0' */
int file_version; /* unused - should be 1 */
int verts_tot;
float start;
float sampling;
int frame_tot;
}; /* frames, verts */
static bool meshcache_read_pc2_head(FILE *fp,
const int verts_tot,
PC2Head *pc2_head,
const char **err_str)
{
if (!fread(pc2_head, sizeof(*pc2_head), 1, fp)) {
*err_str = "Missing header";
return false;
}
if (!STREQ(pc2_head->header, "POINTCACHE2")) {
*err_str = "Invalid header";
return false;
}
#ifdef __BIG_ENDIAN__
BLI_endian_switch_int32_array(&pc2_head->file_version,
(sizeof(*pc2_head) - sizeof(pc2_head->header)) / sizeof(int));
#endif
if (pc2_head->verts_tot != verts_tot) {
*err_str = "Vertex count mismatch";
return false;
}
if (pc2_head->frame_tot <= 0) {
*err_str = "Invalid frame total";
return false;
}
/* Intentionally don't seek back. */
return true;
}
/**
* Gets the index range and factor
*
* currently same as for MDD
*/
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)
{
PC2Head pc2_head;
/* first check interpolation and get the vert locations */
if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) {
return false;
}
MOD_meshcache_calc_range(frame, interp, pc2_head.frame_tot, r_index_range, r_factor);
return true;
}
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)
{
PC2Head pc2_head;
float frame;
if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) {
return false;
}
frame = ((time / fps) - pc2_head.start) / pc2_head.sampling;
if (frame >= pc2_head.frame_tot) {
frame = float(pc2_head.frame_tot - 1);
}
else if (frame < 0.0f) {
frame = 0.0f;
}
*r_frame = frame;
return true;
}
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)
{
PC2Head pc2_head;
if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) {
return false;
}
if (BLI_fseek(fp, sizeof(float[3]) * index * pc2_head.verts_tot, SEEK_CUR) != 0) {
*err_str = "Failed to seek frame";
return false;
}
size_t verts_read_num = 0;
errno = 0;
if (factor >= 1.0f) {
float *vco = *vertexCos;
uint i;
for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
verts_read_num += fread(vco, sizeof(float[3]), 1, fp);
#ifdef __BIG_ENDIAN__
BLI_endian_switch_float(vco + 0);
BLI_endian_switch_float(vco + 1);
BLI_endian_switch_float(vco + 2);
#endif /* __BIG_ENDIAN__ */
}
}
else {
const float ifactor = 1.0f - factor;
float *vco = *vertexCos;
uint i;
for (i = pc2_head.verts_tot; i != 0; i--, vco += 3) {
float tvec[3];
verts_read_num += fread(tvec, sizeof(float[3]), 1, fp);
#ifdef __BIG_ENDIAN__
BLI_endian_switch_float(tvec + 0);
BLI_endian_switch_float(tvec + 1);
BLI_endian_switch_float(tvec + 2);
#endif /* __BIG_ENDIAN__ */
vco[0] = (vco[0] * ifactor) + (tvec[0] * factor);
vco[1] = (vco[1] * ifactor) + (tvec[1] * factor);
vco[2] = (vco[2] * ifactor) + (tvec[2] * factor);
}
}
if (verts_read_num != pc2_head.verts_tot) {
*err_str = errno ? strerror(errno) : "Vertex coordinate read failed";
return false;
}
return true;
}
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)
{
int index_range[2];
float factor;
if (meshcache_read_pc2_range(fp,
verts_tot,
frame,
interp,
index_range,
&factor, /* read into these values */
err_str) == false)
{
return false;
}
if (index_range[0] == index_range[1]) {
/* read single */
if ((BLI_fseek(fp, 0, SEEK_SET) == 0) &&
MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str))
{
return true;
}
return false;
}
/* read both and interpolate */
if ((BLI_fseek(fp, 0, SEEK_SET) == 0) &&
MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[0], 1.0f, err_str) &&
(BLI_fseek(fp, 0, SEEK_SET) == 0) &&
MOD_meshcache_read_pc2_index(fp, vertexCos, verts_tot, index_range[1], factor, err_str))
{
return true;
}
return false;
}
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)
{
float frame;
FILE *fp = BLI_fopen(filepath, "rb");
bool ok;
if (fp == nullptr) {
*err_str = errno ? strerror(errno) : "Unknown error opening file";
return false;
}
switch (time_mode) {
case MOD_MESHCACHE_TIME_FRAME: {
frame = time;
break;
}
case MOD_MESHCACHE_TIME_SECONDS: {
/* we need to find the closest time */
if (meshcache_read_pc2_range_from_time(fp, verts_tot, time, fps, &frame, err_str) == false) {
fclose(fp);
return false;
}
rewind(fp);
break;
}
case MOD_MESHCACHE_TIME_FACTOR:
default: {
PC2Head pc2_head;
if (meshcache_read_pc2_head(fp, verts_tot, &pc2_head, err_str) == false) {
fclose(fp);
return false;
}
frame = CLAMPIS(time, 0.0f, 1.0f) * float(pc2_head.frame_tot);
rewind(fp);
break;
}
}
ok = MOD_meshcache_read_pc2_frame(fp, vertexCos, verts_tot, interp, frame, err_str);
fclose(fp);
return ok;
}