warzone2100/tools/conversion/obj2pie.c

404 lines
9.1 KiB
C

/*
This file is part of Warzone 2100.
Copyright (C) 2007-2010 Warzone 2100 Project
Warzone 2100 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 2 of the License, or
(at your option) any later version.
Warzone 2100 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 Warzone 2100; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
// compile command: gcc obj2pie.c -o obj2pie -lm
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#ifndef WIN32
#include <stdbool.h>
#include <limits.h>
#else
typedef int bool;
#define PATH_MAX 255
#define true 1
#define false 0
#endif
static char *input_file = "";
static char *output_file = "";
static char *texture_file;
static bool swapYZ = true;
static bool reverseWinding = true;
static bool invertV = true;
static int pieVersion = 3;
static bool twoSided = false;
static unsigned int pieType = 0x200;
static float scaleFactor = 1.0f;
typedef struct _vector3f
{
float x, y, z;
} vector3f;
typedef struct _vector2f
{
float u, v;
} vector2f;
typedef struct _face
{
int index_a_vertex, index_a_texture;
int index_b_vertex, index_b_texture;
int index_c_vertex, index_c_texture;
} face;
static vector3f *points;
static int count_points;
static vector2f *uvcoords;
static int count_uvcoords;
static face *faces;
static int count_faces;
void addpoint(float x, float y, float z)
{
if (points == NULL)
{
points = (vector3f*) malloc(sizeof(vector3f));
count_points = 1;
}
else
{
count_points++;
points = (vector3f*)realloc(points, count_points * sizeof(vector3f));
}
if( pieVersion == 2)
{
points[count_points-1].x = rintf(x);
points[count_points-1].y = rintf(y);
points[count_points-1].z = rintf(z);
}
else // pieVersion == 3
{
points[count_points-1].x = x;
points[count_points-1].y = y;
points[count_points-1].z = z;
}
}
void adduvcoord(float u, float v)
{
if (uvcoords == NULL )
{
uvcoords = (vector2f*) malloc(sizeof(vector2f));
count_uvcoords = 1;
}
else
{
count_uvcoords++;
uvcoords = (vector2f*)realloc(uvcoords, count_uvcoords * sizeof(vector2f));
}
if( pieVersion == 2)
{
uvcoords[count_uvcoords-1].u = rintf(u*256.0f);
uvcoords[count_uvcoords-1].v = rintf(v*256.0f);;
}
else // pieVersion == 3
{
uvcoords[count_uvcoords-1].u = u;
uvcoords[count_uvcoords-1].v = v;
}
}
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)
{
if (faces == NULL)
{
faces = (face*) malloc(sizeof(face));
count_faces = 1;
}
else
{
count_faces++;
faces = (face*) realloc(faces, count_faces * sizeof(face));
}
faces[count_faces-1].index_a_vertex = index_a_vertex;
faces[count_faces-1].index_a_texture = index_a_texture;
faces[count_faces-1].index_b_vertex = index_b_vertex;
faces[count_faces-1].index_b_texture = index_b_texture;
faces[count_faces-1].index_c_vertex = index_c_vertex;
faces[count_faces-1].index_c_texture = index_c_texture;
}
void readobj(FILE *input)
{
char buffer[256];
int index_a_vertex, index_a_texture, index_b_vertex, index_b_texture, index_c_vertex, index_c_texture;
int ignored_a_normal, ignored_b_normal, ignored_c_normal;
float u, v;
float x, y, z;
bool normalsDetected = false;
if (input == NULL)
{
return;
}
points = NULL;
count_points = 0;
uvcoords = NULL;
count_uvcoords = 0;
faces = NULL;
count_faces = 0;
while (fgets(buffer, 256, input) != NULL)
{
if (buffer[0] == 'v' && buffer[1] == 'n')
{
normalsDetected = true;
}
else if (buffer[0] == 'v' && buffer[1] == 't')
{
sscanf(&buffer[3], "%f %f", &u, &v);
if (invertV)
v = 1.0f - v;
adduvcoord(u,v);
}
else if (buffer[0] == 'v') // && buffer[1] != 't' && buffer[1] != 'n'
{
sscanf(&buffer[2], "%f %f %f", &x, &y, &z);
addpoint(x*scaleFactor,
(swapYZ?z:y)*scaleFactor,
(swapYZ?y:z)*scaleFactor);
}
else if (buffer[0] == 'f' )
{
if(normalsDetected)
{
sscanf(&buffer[2], "%d/%d/%d %d/%d/%d %d/%d/%d",
&index_a_vertex, &index_a_texture, &ignored_a_normal,
&index_b_vertex, &index_b_texture, &ignored_b_normal,
&index_c_vertex, &index_c_texture, &ignored_c_normal);
}
else
{
sscanf(&buffer[2], "%d/%d %d/%d %d/%d",
&index_a_vertex, &index_a_texture,
&index_b_vertex, &index_b_texture,
&index_c_vertex, &index_c_texture);
}
if(reverseWinding || twoSided)
{
addface(index_c_vertex - 1, index_c_texture - 1,
index_b_vertex - 1, index_b_texture - 1,
index_a_vertex - 1, index_a_texture - 1);
}
if(!reverseWinding || twoSided)
{
addface(index_a_vertex - 1, index_a_texture - 1,
index_b_vertex - 1, index_b_texture - 1,
index_c_vertex - 1, index_c_texture - 1);
}
}
}
}
void writepie(FILE *output)
{
size_t i;
if (output == NULL)
{
return;
}
fprintf(output, "PIE %d\nTYPE %x\n", pieVersion, pieType);
fprintf(output, "TEXTURE 0 %s 256 256\n", texture_file);
fprintf(output, "LEVELS 1\nLEVEL 1\n");
fprintf(output, "POINTS %d\n", count_points);
for (i = 0;i < count_points;i++)
{
if( pieVersion == 2)
{
fprintf(output, "\t%d %d %d\n", (int)points[i].x, (int)points[i].y, (int)points[i].z);
}
else // pieVersion == 3
{
fprintf(output, "\t%f %f %f\n", points[i].x, points[i].y, points[i].z);
}
}
fprintf(output, "POLYGONS %d\n", count_faces);
for (i = 0;i < count_faces;i++)
{
if(pieVersion == 2)
{
fprintf(output, "\t200 3 %d %d %d %d %d %d %d %d %d\n",
faces[i].index_a_vertex,
faces[i].index_b_vertex,
faces[i].index_c_vertex,
(int)uvcoords[faces[i].index_a_texture].u,
(int)uvcoords[faces[i].index_a_texture].v,
(int)uvcoords[faces[i].index_b_texture].u,
(int)uvcoords[faces[i].index_b_texture].v,
(int)uvcoords[faces[i].index_c_texture].u,
(int)uvcoords[faces[i].index_c_texture].v);
}
else // pieVersion == 3
{
fprintf(output, "\t200 3 %d %d %d %f %f %f %f %f %f\n",
faces[i].index_a_vertex,
faces[i].index_b_vertex,
faces[i].index_c_vertex,
uvcoords[faces[i].index_a_texture].u,
uvcoords[faces[i].index_a_texture].v,
uvcoords[faces[i].index_b_texture].u,
uvcoords[faces[i].index_b_texture].v,
uvcoords[faces[i].index_c_texture].u,
uvcoords[faces[i].index_c_texture].v);
}
}
}
void objtopie()
{
FILE *input = NULL;
FILE *output = NULL;
input = fopen(input_file, "rt");
if (input == NULL)
{
perror("Couldn't open input file");
return;
}
output = fopen(output_file, "wt");
if (output == NULL)
{
perror("Couldn't open output file");
fclose(input);
return;
}
readobj(input);
writepie(output);
fclose(input);
fclose(output);
}
static void parse_args(int argc, char **argv)
{
unsigned int i = 1;
for (i = 1; argc >= 3 + i && argv[i][0] == '-'; i++)
{
if (argv[i][1] == 'y')
{
swapYZ = false; // exporting program used Y-axis as "up", like we do, don't switch
}
else if (argv[i][1] == 'i')
{
invertV = false;
}
else if (argv[i][1] == 't')
{
twoSided = true;
}
else if (argv[i][1] == 'r')
{
reverseWinding = false;
}
else if (argv[i][1] == 's')
{
int ret;
i++;
if (argc < i)
{
fprintf(stderr, "Missing parameter to scale option.\n");
exit(1);
}
ret = sscanf(argv[i], "%f", &scaleFactor);
if (ret != 1)
{
fprintf(stderr, "Bad parameter to scale option.\n");
exit(1);
}
}
else if (argv[i][1] == 'v')
{
int ret;
i++;
if (argc < i)
{
fprintf(stderr, "Missing parameter to pie version option.\n");
exit(1);
}
ret = sscanf(argv[i], "%d", &pieVersion);
if (ret != 1)
{
fprintf(stderr, "Bad parameter to pie version option.\n");
exit(1);
}
if( pieVersion < 2 || pieVersion > 3)
{
fprintf(stderr, "Unsupported pie version %d.\n",pieVersion);
exit(1);
}
}
else if (argv[i][1] == 'm')
{
pieType |= 0x10000;
}
else
{
fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
exit(1);
}
}
if (argc < 3 + i)
{
fprintf(stderr, "Usage: obj2pie [options] input_filename output_filename texture_filename\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, " -y Do not swap Y and Z axis. Exporter uses Y-axis as \"up\".\n");
fprintf(stderr, " -r Do not reverse winding of all polygons.\n");
fprintf(stderr, " -i Do not invert the vertical texture coordinates.\n");
fprintf(stderr, " -s N Scale model points by N before converting.\n");
fprintf(stderr, " -t Use two sided polygons (Create duplicate faces with reverse winding).\n");
fprintf(stderr, " -v N Pie export version ( 2 and 3 supported, 3 is default).\n");
fprintf(stderr, " -m Use tcmask pie type.\n");
exit(1);
}
input_file = argv[i++];
output_file = argv[i++];
texture_file = argv[i++];
}
int main(int argc, char *argv[])
{
parse_args(argc, argv);
objtopie();
return 0;
}