ale/d3/tfile.h
2022-07-30 14:46:04 -03:00

585 lines
14 KiB
C

// Copyright 2002, 2003, 2005 David Hilvert <dhilvert@auricle.dyndns.org>,
// <dhilvert@ugcs.caltech.edu>
/* This file is part of the Anti-Lamenessing Engine.
The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the Anti-Lamenessing Engine; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* d3/tfile.h: Read and write 3D transformation data files.
*/
/*
* This version of ALE reads and writes version 0 3D transformation data files.
*/
#ifndef __d3tfile_h__
#define __d3tfile_h__
#include "pt.h"
#define D3_TFILE_VERSION 0
#define D3_TFILE_VERSION_MAX 0
extern int tfile_input_version;
extern int tfile_output_version;
/*
* Structure to describe a transformation data file to load data from.
*/
struct tload_t {
const char *filename;
FILE *file;
};
/*
* Structure to describe a transformation data file to write data to.
*/
struct tsave_t {
const char *filename;
const char *target;
const char *orig;
FILE *file;
};
/*
* Create a new tload_t transformation data file structure, used for
* reading data from transformation data files.
*/
static inline struct tload_t *tload_new(const char *filename) {
FILE *file = fopen (filename, "r");
struct tload_t *result = NULL;
if (!file) {
fprintf(stderr, "tload: Error: could not open transformation data file '%s'.", filename);
exit(1);
}
result = (struct tload_t *)
malloc(sizeof(struct tload_t));
result->filename = filename;
result->file = file;
return result;
}
/*
* Load the first transformation from a transformation data file associated with
* transformation data file structure T, or return the default transformation
* if no transformation is available.
*
* T is a pointer to the tload_t transformation data file structure.
*
* DEFAULT_TRANSFORM is the default transformation result.
*
* IS_DEFAULT is used to signal a non-default transformation result.
*/
static inline pt tload_first(struct tload_t *t,
pt default_transform, int *is_default) {
pt result = default_transform;
*is_default = 1;
/*
* If there is no file, return the default.
*/
if (t == NULL)
return result;
/*
* Search through the initial part of the file to determine
* its version.
*/
/*
* Skip comments
*/
int first_character;
first_character = fgetc(t->file);
while (first_character == ' '
|| first_character == 0xa
|| first_character == 0xd
|| first_character == '\t'
|| first_character == '#') {
ungetc(first_character, t->file);
char line[1024];
fgets(line, 1024, t->file);
if (strlen(line) >= 1023) {
fprintf(stderr,
"\n3d-trans-load: Error: line too long in input file\n");
exit(1);
}
first_character = fgetc(t->file);
}
if (first_character != EOF)
ungetc(first_character, t->file);
if (first_character != 'W') {
fprintf(stderr, "\n3d-trans-load: First command must be a version number.\n");
exit(1);
}
/*
* Obtain version from version command string.
*/
char line[1024];
fgets(line, 1024, t->file);
if (strlen(line) >= 1023) {
fprintf(stderr,
"\n3d-trans-load: Error: line too long in input file\n");
exit(1);
}
int count = sscanf(line, "W %d", &tfile_input_version);
if (count < 1) {
fprintf(stderr, "Error in 3d transformation "
"file version command.\n");
exit(1);
} else if (tfile_input_version > D3_TFILE_VERSION_MAX) {
fprintf(stderr, "Unsupported 3D transformation "
"file version %d\n",
tfile_input_version);
exit(1);
}
/*
* Read each line of the file until we find a transformation
* or EOF.
*/
while (!feof(t->file)) {
char line[1024];
fgets(line, 1024, t->file);
if (feof(t->file))
return result;
if (strlen(line) >= 1023) {
fprintf(stderr,
"\ntrans-load: Error: line too long in input file\n");
exit(1);
}
const double rtod_multiplier = 180 / M_PI;
switch (line[0]) {
case ' ':
case 0xa:
case 0xd:
case '\t':
case '#':
/* Comment or whitespace */
break;
case 'D':
case 'd':
/* Default transformation */
return result;
case 'V':
case 'v':
unsigned int count;
double view_angle;
count = sscanf(line, "V %lf", &view_angle);
if (count < 1) {
fprintf(stderr, "\n3d-trans-load: Error: "
"Malformed 'V' command.\n");
exit(1);
}
result.view_angle(view_angle / rtod_multiplier);
break;
case 'E':
case 'e':
/* Euclidean transformation data */
*is_default = 0;
{
double width, height;
double values[6] = {0, 0, -1, 0, 0, 0};
int count;
count = sscanf(line, "E %lf%lf%lf%lf%lf%lf%lf%lf",
&width, &height,
&values[1], &values[0], &values[2],
&values[4], &values[3], &values[5]);
if (count < 8)
fprintf(stderr, "\n3d-trans-load: warning: "
"Missing args for 'E'\n");
if (width != result.scaled_width()
|| height != result.scaled_height()) {
fprintf(stderr, "\n3d-trans-load: Error: "
"Scaled image width and/or height mismatch.");
}
for (int i = 3; i < 6; i++) {
values [i] /= rtod_multiplier;
}
result.e().set(values);
return result;
}
break;
default:
fprintf(stderr,
"\ntrans-load: Error in tload_first: unrecognized command '%s'\n",
line);
exit(1);
}
}
/*
* EOF reached: return default transformation.
*/
return result;
}
/*
* Load the next transformation from a transformation data file associated with
* transformation data file structure T, or return the default transformation
* if no transformation is available.
*
* T is a pointer to the tload_t transformation data file structure.
*
* IS_P is nonzero if a projective transformation is expected.
*
* DEFAULT_TRANSFORM is the default transformation result.
*
* IS_DEFAULT is used to signal a non-default transformation result.
*/
static inline pt tload_next(struct tload_t *t,
pt default_transform, int *is_default) {
pt result = default_transform;
*is_default = 1;
/*
* Read each line of the file until we find a transformation.
*/
while (t && !feof(t->file)) {
char line[1024];
fgets(line, 1024, t->file);
if (feof(t->file))
return result;
if (strlen(line) >= 1023) {
fprintf(stderr,
"\ntrans-load: warning: line too long in input file\n");
}
const double rtod_multiplier = 180 / M_PI;
switch (line[0]) {
case ' ':
case 0xa:
case 0xd:
case '\t':
case '#':
/* Comment or whitespace */
break;
case 'D':
case 'd':
/* Default transformation */
return result;
case 'V':
case 'v':
unsigned int count;
double view_angle;
count = sscanf(line, "V %lf", &view_angle);
if (count < 1) {
fprintf(stderr, "\n3d-trans-load: Error: "
"Malformed 'V' command.\n");
exit(1);
}
result.view_angle(view_angle / rtod_multiplier);
break;
case 'E':
case 'e':
/* Euclidean transformation data */
*is_default = 0;
{
double width, height;
double values[6] = {0, 0, -1, 0, 0, 0};
int count;
count = sscanf(line, "E %lf%lf%lf%lf%lf%lf%lf%lf",
&width, &height,
&values[1], &values[0], &values[2],
&values[4], &values[3], &values[5]);
if (count < 8)
fprintf(stderr, "\n3d-trans-load: warning: "
"Missing args for 'E'\n");
if (width != result.scaled_width()
|| height != result.scaled_height()) {
fprintf(stderr, "\n3d-trans-load: Error: "
"Scaled image width and/or height mismatch.");
}
for (int i = 3; i < 6; i++) {
values [i] /= rtod_multiplier;
}
result.e().set(values);
return result;
}
break;
default:
fprintf(stderr,
"\ntrans-load: Error in tload_next: unrecognized command '%s'\n",
line);
exit(1);
}
}
return result;
}
/*
* Create a new tsave_t transformation data file structure, used for
* writing data to transformation data files.
*/
static inline struct tsave_t *tsave_new(const char *filename) {
FILE *file = fopen (filename, "w");
struct tsave_t *result = NULL;
if (!file) {
fprintf(stderr, "tsave: Error: could not open transformation data file '%s'.", filename);
exit(1);
}
result = (struct tsave_t *)
malloc(sizeof(struct tsave_t));
result->filename = filename;
result->file = file;
result->orig = "unknown";
result->target = "unknown";
fprintf(file, "# created by ALE 3D transformation file handler version %d\n",
D3_TFILE_VERSION);
fclose(file);
return result;
}
/*
* Save the first transformation to a transformation data file associated with
* transformation data file structure T, or do nothing if T is NULL. This
* function also establishes the output file version.
*
* OFFSET is the transformation to be saved.
*
* IS_PROJECTIVE indicates whether to write a projective transformation.
*
*/
static inline void tsave_first(struct tsave_t *t, pt offset) {
if (t == NULL)
return;
t->file = fopen(t->filename, "a");
tfile_output_version = 0;
fprintf(t->file, "# producing 3D transformation file syntax version %d\n", tfile_output_version);
fprintf(t->file, "W %d\n", tfile_output_version);
// fprintf(t->file, "# Comment: Target output file is %s\n", t->target);
// fprintf(t->file, "# Comment: Original frame is %s\n", t->orig);
const double rtod_multiplier = 180 / M_PI;
fprintf(t->file, "V %lf\n", (double) offset.view_angle() * rtod_multiplier);
fprintf(t->file, "E ");
fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
fprintf(t->file, "%f ", (double) offset.e().get_translation(1));
fprintf(t->file, "%f ", (double) offset.e().get_translation(0));
fprintf(t->file, "%f ", (double) offset.e().get_translation(2));
fprintf(t->file, "%f ", (double) offset.e().get_rotation(1) * rtod_multiplier);
fprintf(t->file, "%f ", (double) offset.e().get_rotation(0) * rtod_multiplier);
fprintf(t->file, "%f ", (double) offset.e().get_rotation(2) * rtod_multiplier);
fprintf(t->file, "\n");
fclose(t->file);
}
/*
* Save the next transformation to a transformation data file associated with
* transformation data file structure T, or do nothing if T is NULL.
*
* OFFSET is the transformation to be saved.
*
* IS_PROJECTIVE indicates whether to write a projective transformation.
*
*/
static inline void tsave_next(struct tsave_t *t, pt offset) {
if (t == NULL)
return;
t->file = fopen(t->filename, "a");
const double rtod_multiplier = 180 / M_PI;
fprintf(t->file, "V %lf\n", (double) offset.view_angle() * rtod_multiplier);
fprintf(t->file, "E ");
fprintf(t->file, "%f %f ", (double) offset.scaled_width(), (double) offset.scaled_height());
fprintf(t->file, "%f ", (double) offset.e().get_translation(1));
fprintf(t->file, "%f ", (double) offset.e().get_translation(0));
fprintf(t->file, "%f ", (double) offset.e().get_translation(2));
fprintf(t->file, "%f ", (double) offset.e().get_rotation(1) * rtod_multiplier);
fprintf(t->file, "%f ", (double) offset.e().get_rotation(0) * rtod_multiplier);
fprintf(t->file, "%f ", (double) offset.e().get_rotation(2) * rtod_multiplier);
fprintf(t->file, "\n");
fclose(t->file);
}
/*
* Write information to a transformation file indicating the target output
* file.
*/
static inline void tsave_target(struct tsave_t *t, const char *filename) {
if (t == NULL)
return;
t->target = filename;
if (t != NULL) {
t->file = fopen(t->filename, "a");
fclose(t->file);
}
}
/*
* Write information to a transformation data file indicating the filename
* of the original frame (i.e. the first frame in the sequence of input
* frames).
*/
static inline void tsave_orig(struct tsave_t *t, const char *filename) {
if (t == NULL)
return;
t->orig = filename;
}
/*
* Write information to a transformation data file indicating the filename
* of a supplemental frame (i.e. a frame in the sequence of input frames
* that is not the first frame).
*/
static inline void tsave_info(struct tsave_t *t, const char *filename) {
if (t != NULL) {
t->file = fopen(t->filename, "a");
fprintf(t->file, "# Comment: Supplemental frame %s\n", filename);
fclose(t->file);
}
}
/*
* Write information to a transformation data file indicating the tonal
* registration multiplier.
*/
static inline void tsave_trm(struct tsave_t *t, ale_real r, ale_real g, ale_real b) {
if (t != NULL) {
t->file = fopen(t->filename, "a");
fprintf(t->file, "# Comment: Exposure [r=%f g=%f b=%f]\n", (double) r, (double) g, (double) b);
fclose(t->file);
}
}
/*
* Write information to a transformation data file indicating the average
* pixel magnitude.
*/
static inline void tsave_apm(struct tsave_t *t, ale_real r, ale_real g, ale_real b) {
if (t != NULL) {
t->file = fopen(t->filename, "a");
fprintf(t->file, "# Comment: Avg magnitude [r=%f g=%f b=%f]\n", (double) r, (double) g, (double) b);
fclose(t->file);
}
}
/*
* Destroy a tload_t transformation data file structure.
*/
static inline void tload_delete(struct tload_t *victim) {
if (victim)
fclose(victim->file);
free(victim);
}
/*
* Destroy a tsave_t transformation data file structure.
*/
static inline void tsave_delete(struct tsave_t *victim) {
free(victim);
}
#endif