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