-
Notifications
You must be signed in to change notification settings - Fork 0
/
writeObj.c
222 lines (182 loc) · 6.67 KB
/
writeObj.c
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
/* Functions that given a MODL structure (defined in modl.h) write the appropriate data to a Wavefront .obj file */
#include "modl.h"
#include <stdio.h>
#include <stdlib.h>
#include "matScaler.h"
/* Writes a MESH structure to a file stream as part of a .obj file.*/
void printMesh( MODL *model, MESH *mesh, float offset[3], FILE *ofp )
{
//make each mesh a separate group
fprintf(ofp, "o %s\n\n", mesh->meshName);
//write out the vertices, adding the correct offset
for(int i=0; i < mesh->numVertices; i++)
{
//add the correct offset to each coordinate of the vertex
float v[3];
for(int j=0; j<3; j++) v[j] = mesh->vertices[i][j] + offset[j];
fprintf(ofp, "v %f %f %f\n", v[0], v[1], v[2]);
}
fprintf(ofp, "\n");
//write out the texture vertices
for(int i=0; i < mesh->numTexVertices; i++)
{
float *vt = mesh->texVertices[i];
//NOTE: Writing out the texture vertices here is tied to how they must be read back in within readObj.c Whatever happens here must be "undone" when reading back in after editing
fprintf(ofp, "vt %f %f\n", vt[0], -vt[1]);
}
fprintf(ofp, "\n");
//write out the vertex normals
for(int i=0; i < mesh->numVertices; i++)
{
float *vn = mesh->normals[i];
fprintf(ofp, "vn %f %f %f\n", vn[0], vn[1], vn[2]);
}
fprintf(ofp, "\n");
//these will be used to store the offset to add to all vertex indices
//NOTE: .3do indexes from 0, .obj indexes from 1, intialise offsets with 1
//NOTE: vertices and vertex normals are BOTH indexed with the same value
static int vertexIndexOffset = 1;
static int texVertexIndexOffset = 1;
//remember the previous material index
int prevMatIndex = -1;
//PRINT THE FACES
for(int i=0; i < mesh->numFaces; i++)
{
FACE *face = mesh->faces[i];
//determine the material to use
if(face->hasMaterial != 0 && face->materialIndex != prevMatIndex)
{
//update index and declare new material in .obj file
fprintf(ofp, "usemtl ");
char *m = model->materialNames[face->materialIndex];
/*
//replace the .mat with some other format for whatever texture
//may not use this, see replacement directly below
int c = 0;
do {fprintf(ofp, "%c", m[c]);} while(m[c++] != '.');
fprintf(ofp, "gif\n");
*/
//print "whatever.mat" as the material name, if eventually do a .mtl as will this can remain the name and the texture specified within the .mtl Then when reading back in can just use the material name directly to determine which .mat to use
fprintf(ofp, "%s\n", m);
prevMatIndex = face->materialIndex;
}
//format "f v/vt/vn v/vt/vn ..." a triplet of indices for each vertex
fprintf(ofp, "f ");
//print the indices for each vertex
for(int j=0; j < face->numVertices; j++)
{
//calculate the indice triplets
int vi = face->vertexIndices[j] + vertexIndexOffset;
int tvi = face->texVertexIndices[j] + texVertexIndexOffset;
fprintf(ofp, "%d/%d/%d ", vi, tvi, vi);
}
fprintf(ofp, "\n");
}
fprintf(ofp, "\n");
//update the index offsets
vertexIndexOffset += mesh->numVertices;
texVertexIndexOffset += mesh->numTexVertices;
//all for now
return;
}
/* Recursively print a node hierarchy to a file stream in the .obj format */
void printNode(MODL *model, NODE *node, float parentOffset[3], FILE *ofp)
{
//add this nodes offset to it's parent (accumulating as we recurse)
float nodeOffset[3];
for(int i=0; i<3; i++) nodeOffset[i] = parentOffset[i] + node->position[i];
//the mesh if further offset by a pivot offset (and then should be rotated but not done here yet)
float meshOffset[3];
for(int i=0; i<3; i++) meshOffset[i] = nodeOffset[i] + node->pivot[i];
//draw the mesh for this node if it has one
if(node->meshID != -1)
{
printMesh(model, model->meshes[node->meshID], meshOffset, ofp);
}
//recurse and print the child nodes if it has any
if(node->hasChildren != 0)
{
//just recurses to the first child which will then itself recurse to
//any remaining siblings, see next block down
printNode(model, model->nodes[node->childID], nodeOffset, ofp);
}
//recurse and print the current node's siblings if it has any
if(node->hasSibling != 0)
{
//NOTE: siblings all share the same original parent offset
printNode(model, model->nodes[node->siblingID], parentOffset, ofp);
}
}
/* Accepts a MODL structure previously filled by read3d0() and the name of the file to write to. */
void printObj( MODL *model, char *filename )
{
if(model == NULL)
{
fprintf(stderr, "printObj() called with null MODL*\n");
return;
}
if(filename == NULL)
{
fprintf(stderr, "printObj() called with null filename.\n");
return;
}
//SCALE THE TEXTURE VERTICES TO THE .OBJ format (0 - 1)
scaleTexVerts(model, 0); //MUST UNDO WHEN READING BACK In
//open the file for writing and ensure success
FILE *ofp = fopen(filename, "w");
if(ofp == NULL)
{
fprintf(stderr, "Could not open %s for writing.\n", filename);
return;
}
//print the nodes recursively by starting with the first
if(model->numNodes != 0)
{
float startingOffset[3] = {0.0, 0.0, 0.0};
printNode(model, model->nodes[0], startingOffset, ofp);
}
//close the file (ideally check to ensure it closed properly)
fclose(ofp);
return;
}
/* Accepts a MODL structure previously filled by read3do() and the name of the file to write to. It then produces a .mtl file to accompany the .obj file. Each material name will be for example "m_eye.mat" and it will then specify a texture for that material (perhaps "m_eye.gif" pr whatever format is passed in via the imFormat paramter */
void printMtl( MODL *model, char *filename, char *imFormat )
{
if(model == NULL)
{
fprintf(stderr, "printMtl() called with null MODL*\n");
return;
}
if(filename == NULL)
{
fprintf(stderr, "printMtl() called with null filename.\n");
return;
}
//open the file for writing and ensure success
FILE *ofp = fopen(filename, "w");
if(ofp == NULL)
{
fprintf(stderr, "Could not open %s for writing.\n", filename);
return;
}
fprintf(ofp, "# Material Count: %d\n", model->numMaterials);
//for each material in the MODL create a new material in the .mtl file
for(int i=0; i < model->numMaterials; i++)
{
fprintf(ofp, "newmtl %s\n", model->materialNames[i]);
fprintf(ofp, "map_Kd ");
//swap the .mat for .gif (or whatever is needed)
char *t = model->materialNames[i];
while(*t != '.')
{
fprintf(ofp, "%c", *t);
t++;
}
fprintf(ofp, "%s\n", imFormat);
//i.e newmtl m_eye.mat
// map_Ka m_eye.gif
}
//close the file and return
fclose(ofp);
return;
}