aboutsummaryrefslogtreecommitdiffstats
path: root/fmd.c
blob: d4aa647432f68ddf0cb672f47078bf8f6412f69e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
 * Copyright (C) 2018 Tomasz Kramkowski <tk@the-tk.com>
 * SPDX-License-Identifier: MIT
 */
#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include "eprintf.h"
#include "fmd.h"
#include "ieee754.h"
#include "nelem.h"

static const char *MAGIC = "FMD002\r\n";

static void checkmagic(FILE *f)
{
	for (size_t i = 0; i < strlen(MAGIC); i++)
		assert(fgetc(f) == MAGIC[i]);
}

static inline unsigned long betoul(FILE *src)
{
	unsigned long ret = 0;

	assert(src != NULL);

	for (int i = 0; i < 4; i++) {
		int c = fgetc(src);
		assert(c != EOF);
		ret += (unsigned long)(c & 0xff) << (3 - i) * 8;
	}

	return ret;
}

void readfloats(float *dest, int count, FILE *src)
{
	assert(dest != NULL);
	assert(src != NULL);

	for (int i = 0; i < count; i++)
		dest[i] = ieee754f(betoul(src));
}

void fmd_load(struct fmd *fmd, FILE *f)
{
	assert(fmd != NULL);
	assert(f != NULL);

	checkmagic(f);

	fmd->nverts = betoul(f);
	if (fmd->nverts > 0)
		fmd->verts = emalloc(fmd->nverts * sizeof *fmd->verts);
	else
		fmd->verts = NULL;
	for (int i = 0; i < fmd->nverts; i++) {
		struct vertex *v = &fmd->verts[i];
		readfloats(v->pos, 3, f);
		readfloats(v->norm, 3, f);
		readfloats(v->uv, 2, f);
	}
	fmd->ntris = betoul(f);
	if (fmd->ntris > 0)
		fmd->tris = emalloc(fmd->ntris * sizeof *fmd->tris);
	else
		fmd->tris = NULL;
	for (int i = 0; i < fmd->ntris; i++)
		for (size_t j = 0; j < NELEM(fmd->tris[j]); j++)
			fmd->tris[i][j] = betoul(f);

	fmd->nmtls = betoul(f);
	if (fmd->nmtls > 0)
		fmd->mtls = emalloc(fmd->nmtls * sizeof *fmd->mtls);
	else
		fmd->mtls = NULL;
	for (int i = 0; i < fmd->nmtls; i++) {
		unsigned long len = betoul(f);
		char **m = &fmd->mtls[i];
		size_t ret;

		*m = emalloc(len + 1);

		ret = fread(*m, len, 1, f);
		assert(ret == 1);
		(*m)[len] = '\0';
	}

	fmd->nmeshes = betoul(f);
	if (fmd->nmeshes > 0)
		fmd->meshes = emalloc(fmd->nmeshes * sizeof *fmd->meshes);
	else
		fmd->meshes = NULL;
	for (int i = 0; i < fmd->nmeshes; i++) {
		struct fmd_mesh *m = &fmd->meshes[i];
		unsigned long midx;
		midx = betoul(f);
		m->midx = midx == 0xffffffff ? -1 : (int)midx;
		m->tidx = betoul(f);
		m->tcnt = betoul(f);
	}
}

void fmd_free(struct fmd *fmd)
{
	assert(fmd);

	free(fmd->verts);
	free(fmd->tris);
	for (int i = 0; i < fmd->nmtls; i++)
		free(fmd->mtls[i]);
	free(fmd->mtls);
	free(fmd->meshes);
}