1 /*
2 This file is part of Warzone 2100.
3 Copyright (C) 2007-2020 Warzone 2100 Project
4
5 Warzone 2100 is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 Warzone 2100 is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Warzone 2100; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 // compile command: gcc obj2pie.c -o obj2pie -lm
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26
27 #ifndef WIN32
28 #include <stdbool.h>
29 #include <limits.h>
30 #else
31 typedef int bool;
32 #define PATH_MAX 255
33 #define true 1
34 #define false 0
35 #endif
36
37 static char *input_file = "";
38 static char *output_file = "";
39 static char *texture_file;
40 static bool swapYZ = true;
41 static bool reverseWinding = true;
42 static bool invertV = true;
43 static int pieVersion = 3;
44 static bool twoSided = false;
45 static unsigned int pieType = 0x200;
46 static float scaleFactor = 1.0f;
47
48 typedef struct _vector3f
49 {
50 float x, y, z;
51 } vector3f;
52
53 typedef struct _vector2f
54 {
55 float u, v;
56 } vector2f;
57
58 typedef struct _face
59 {
60 int index_a_vertex, index_a_texture;
61 int index_b_vertex, index_b_texture;
62 int index_c_vertex, index_c_texture;
63 } face;
64
65 static vector3f *points;
66 static int count_points;
67
68 static vector2f *uvcoords;
69 static int count_uvcoords;
70
71 static face *faces;
72 static int count_faces;
73
addpoint(float x,float y,float z)74 void addpoint(float x, float y, float z)
75 {
76 if (points == NULL)
77 {
78 points = (vector3f*) malloc(sizeof(vector3f));
79 count_points = 1;
80 }
81 else
82 {
83 count_points++;
84 points = (vector3f*)realloc(points, count_points * sizeof(vector3f));
85 }
86
87 if( pieVersion == 2)
88 {
89 points[count_points-1].x = rintf(x);
90 points[count_points-1].y = rintf(y);
91 points[count_points-1].z = rintf(z);
92 }
93 else // pieVersion == 3
94 {
95 points[count_points-1].x = x;
96 points[count_points-1].y = y;
97 points[count_points-1].z = z;
98 }
99 }
100
adduvcoord(float u,float v)101 void adduvcoord(float u, float v)
102 {
103 if (uvcoords == NULL )
104 {
105 uvcoords = (vector2f*) malloc(sizeof(vector2f));
106 count_uvcoords = 1;
107 }
108 else
109 {
110 count_uvcoords++;
111 uvcoords = (vector2f*)realloc(uvcoords, count_uvcoords * sizeof(vector2f));
112 }
113
114 if( pieVersion == 2)
115 {
116 uvcoords[count_uvcoords-1].u = rintf(u*256.0f);
117 uvcoords[count_uvcoords-1].v = rintf(v*256.0f);;
118 }
119 else // pieVersion == 3
120 {
121 uvcoords[count_uvcoords-1].u = u;
122 uvcoords[count_uvcoords-1].v = v;
123 }
124 }
125
addface(int index_a_vertex,int index_a_texture,int index_b_vertex,int index_b_texture,int index_c_vertex,int index_c_texture)126 void addface(int index_a_vertex, int index_a_texture, int index_b_vertex, int index_b_texture, int index_c_vertex, int index_c_texture)
127 {
128 if (faces == NULL)
129 {
130 faces = (face*) malloc(sizeof(face));
131 count_faces = 1;
132 }
133 else
134 {
135 count_faces++;
136 faces = (face*) realloc(faces, count_faces * sizeof(face));
137 }
138 faces[count_faces-1].index_a_vertex = index_a_vertex;
139 faces[count_faces-1].index_a_texture = index_a_texture;
140 faces[count_faces-1].index_b_vertex = index_b_vertex;
141 faces[count_faces-1].index_b_texture = index_b_texture;
142 faces[count_faces-1].index_c_vertex = index_c_vertex;
143 faces[count_faces-1].index_c_texture = index_c_texture;
144 }
145
readobj(FILE * input)146 void readobj(FILE *input)
147 {
148 char buffer[256];
149 int index_a_vertex, index_a_texture, index_b_vertex, index_b_texture, index_c_vertex, index_c_texture;
150 int ignored_a_normal, ignored_b_normal, ignored_c_normal;
151 float u, v;
152 float x, y, z;
153 bool normalsDetected = false;
154
155 if (input == NULL)
156 {
157 return;
158 }
159
160 points = NULL;
161 count_points = 0;
162
163 uvcoords = NULL;
164 count_uvcoords = 0;
165
166 faces = NULL;
167 count_faces = 0;
168
169 while (fgets(buffer, 256, input) != NULL)
170 {
171 if (buffer[0] == 'v' && buffer[1] == 'n')
172 {
173 normalsDetected = true;
174 }
175 else if (buffer[0] == 'v' && buffer[1] == 't')
176 {
177 sscanf(&buffer[3], "%f %f", &u, &v);
178 if (invertV)
179 v = 1.0f - v;
180 adduvcoord(u,v);
181 }
182 else if (buffer[0] == 'v') // && buffer[1] != 't' && buffer[1] != 'n'
183 {
184 sscanf(&buffer[2], "%f %f %f", &x, &y, &z);
185 addpoint(x*scaleFactor,
186 (swapYZ?z:y)*scaleFactor,
187 (swapYZ?y:z)*scaleFactor);
188 }
189 else if (buffer[0] == 'f' )
190 {
191 if(normalsDetected)
192 {
193 sscanf(&buffer[2], "%d/%d/%d %d/%d/%d %d/%d/%d",
194 &index_a_vertex, &index_a_texture, &ignored_a_normal,
195 &index_b_vertex, &index_b_texture, &ignored_b_normal,
196 &index_c_vertex, &index_c_texture, &ignored_c_normal);
197 }
198 else
199 {
200 sscanf(&buffer[2], "%d/%d %d/%d %d/%d",
201 &index_a_vertex, &index_a_texture,
202 &index_b_vertex, &index_b_texture,
203 &index_c_vertex, &index_c_texture);
204 }
205
206 if(reverseWinding || twoSided)
207 {
208 addface(index_c_vertex - 1, index_c_texture - 1,
209 index_b_vertex - 1, index_b_texture - 1,
210 index_a_vertex - 1, index_a_texture - 1);
211 }
212 if(!reverseWinding || twoSided)
213 {
214 addface(index_a_vertex - 1, index_a_texture - 1,
215 index_b_vertex - 1, index_b_texture - 1,
216 index_c_vertex - 1, index_c_texture - 1);
217 }
218 }
219 }
220 }
221
222
writepie(FILE * output)223 void writepie(FILE *output)
224 {
225 size_t i;
226
227 if (output == NULL)
228 {
229 return;
230 }
231
232 fprintf(output, "PIE %d\nTYPE %x\n", pieVersion, pieType);
233 fprintf(output, "TEXTURE 0 %s 256 256\n", texture_file);
234 fprintf(output, "LEVELS 1\nLEVEL 1\n");
235
236 fprintf(output, "POINTS %d\n", count_points);
237 for (i = 0;i < count_points;i++)
238 {
239 if( pieVersion == 2)
240 {
241 fprintf(output, "\t%d %d %d\n", (int)points[i].x, (int)points[i].y, (int)points[i].z);
242 }
243 else // pieVersion == 3
244 {
245 fprintf(output, "\t%f %f %f\n", points[i].x, points[i].y, points[i].z);
246 }
247 }
248
249 fprintf(output, "POLYGONS %d\n", count_faces);
250 for (i = 0;i < count_faces;i++)
251 {
252 if(pieVersion == 2)
253 {
254 fprintf(output, "\t200 3 %d %d %d %d %d %d %d %d %d\n",
255 faces[i].index_a_vertex,
256 faces[i].index_b_vertex,
257 faces[i].index_c_vertex,
258 (int)uvcoords[faces[i].index_a_texture].u,
259 (int)uvcoords[faces[i].index_a_texture].v,
260 (int)uvcoords[faces[i].index_b_texture].u,
261 (int)uvcoords[faces[i].index_b_texture].v,
262 (int)uvcoords[faces[i].index_c_texture].u,
263 (int)uvcoords[faces[i].index_c_texture].v);
264 }
265 else // pieVersion == 3
266 {
267 fprintf(output, "\t200 3 %d %d %d %f %f %f %f %f %f\n",
268 faces[i].index_a_vertex,
269 faces[i].index_b_vertex,
270 faces[i].index_c_vertex,
271 uvcoords[faces[i].index_a_texture].u,
272 uvcoords[faces[i].index_a_texture].v,
273 uvcoords[faces[i].index_b_texture].u,
274 uvcoords[faces[i].index_b_texture].v,
275 uvcoords[faces[i].index_c_texture].u,
276 uvcoords[faces[i].index_c_texture].v);
277 }
278 }
279 }
280
objtopie()281 void objtopie()
282 {
283 FILE *input = NULL;
284 FILE *output = NULL;
285
286 input = fopen(input_file, "rt");
287 if (input == NULL)
288 {
289 perror("Couldn't open input file");
290 return;
291 }
292
293 output = fopen(output_file, "wt");
294 if (output == NULL)
295 {
296 perror("Couldn't open output file");
297 fclose(input);
298 return;
299 }
300
301 readobj(input);
302 writepie(output);
303
304 fclose(input);
305 fclose(output);
306 }
307
parse_args(int argc,char ** argv)308 static void parse_args(int argc, char **argv)
309 {
310 unsigned int i = 1;
311
312 for (i = 1; argc >= 3 + i && argv[i][0] == '-'; i++)
313 {
314 if (argv[i][1] == 'y')
315 {
316 swapYZ = false; // exporting program used Y-axis as "up", like we do, don't switch
317 }
318 else if (argv[i][1] == 'i')
319 {
320 invertV = false;
321 }
322 else if (argv[i][1] == 't')
323 {
324 twoSided = true;
325 }
326 else if (argv[i][1] == 'r')
327 {
328 reverseWinding = false;
329 }
330 else if (argv[i][1] == 's')
331 {
332 int ret;
333
334 i++;
335 if (argc < i)
336 {
337 fprintf(stderr, "Missing parameter to scale option.\n");
338 exit(1);
339 }
340 ret = sscanf(argv[i], "%f", &scaleFactor);
341 if (ret != 1)
342 {
343 fprintf(stderr, "Bad parameter to scale option.\n");
344 exit(1);
345 }
346 }
347 else if (argv[i][1] == 'v')
348 {
349 int ret;
350
351 i++;
352 if (argc < i)
353 {
354 fprintf(stderr, "Missing parameter to pie version option.\n");
355 exit(1);
356 }
357 ret = sscanf(argv[i], "%d", &pieVersion);
358 if (ret != 1)
359 {
360 fprintf(stderr, "Bad parameter to pie version option.\n");
361 exit(1);
362 }
363 if( pieVersion < 2 || pieVersion > 3)
364 {
365 fprintf(stderr, "Unsupported pie version %d.\n",pieVersion);
366 exit(1);
367 }
368 }
369 else if (argv[i][1] == 'm')
370 {
371 pieType |= 0x10000;
372 }
373 else
374 {
375 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
376 exit(1);
377 }
378 }
379 if (argc < 3 + i)
380 {
381 fprintf(stderr, "Usage: obj2pie [options] input_filename output_filename texture_filename\n");
382 fprintf(stderr, "Options:\n");
383 fprintf(stderr, " -y Do not swap Y and Z axis. Exporter uses Y-axis as \"up\".\n");
384 fprintf(stderr, " -r Do not reverse winding of all polygons.\n");
385 fprintf(stderr, " -i Do not invert the vertical texture coordinates.\n");
386 fprintf(stderr, " -s N Scale model points by N before converting.\n");
387 fprintf(stderr, " -t Use two sided polygons (Create duplicate faces with reverse winding).\n");
388 fprintf(stderr, " -v N Pie export version ( 2 and 3 supported, 3 is default).\n");
389 fprintf(stderr, " -m Use tcmask pie type.\n");
390
391 exit(1);
392 }
393 input_file = argv[i++];
394 output_file = argv[i++];
395 texture_file = argv[i++];
396 }
397
main(int argc,char * argv[])398 int main(int argc, char *argv[])
399 {
400 parse_args(argc, argv);
401 objtopie();
402 return 0;
403 }
404