
#include "wavefront_reader_lite.h"

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>



static void _AddVertex(float* &vertex_list, int &vertex_list_size,
					   int &num_verts,
					   float x, float y, float z);

static void _AddTextureCoordinates(float* &tc_list, int &tc_list_size,
								   int &num_tcs,
								   float s, float t);

static int _ParseVertex(char *buff, int &v, int &t);


int WF_Read_Lite(ifstream &iFile,

			int (*VertexCallback) 
				 (int n, float x, float y, float z, void *data_vcb),

			int (*FaceCallback)
				 (int i,
				  const int *vindex, const int *tindex,
				  const float *v, const float *t, 
				  void *data_fcb),

		    void *data_vcb, void *data_fcb) {


	char buff[10000];

	float *vertex_list = NULL;
	int vertex_list_size = 0;
	int num_verts = 0;

	float *tc_list = NULL;
	int tc_list_size = 0;
	int num_tcs = 0;

	int face_v[500];
	int face_t[500];
	int reading_face=0;
	int face_index;

	int done = 0;

	while (!done) {

		iFile >> buff;

		if (iFile.eof())
			done = 1;

		// skip comments
		else if (buff[0] == '#') {
			iFile.getline(buff, 10000);
		}

		// skip g lines
		else if (buff[0] == 'g') {
			iFile.getline(buff, 10000);
		}


		// add vertex:
		else if (!strcasecmp(buff, "v")) {
			float x, y, z;
			iFile >> x >> y >> z;
			if (VertexCallback)
				VertexCallback(num_verts, x, y, z, data_vcb);
			_AddVertex(vertex_list, vertex_list_size, num_verts, x, y, z);
		}

		// add texture coordinates:
		else if (!strcasecmp(buff, "vt")) {
			float s, t;
			iFile >> s >> t;
			_AddTextureCoordinates(tc_list, tc_list_size, num_tcs, s, t);
		}

		// add face:
		else if (!strncasecmp(buff, "f", 1)) {
			if (reading_face) {
				if (FaceCallback)
					FaceCallback(face_index,
								 face_v, face_t,
								 vertex_list, tc_list,
								 data_fcb);
			}
			reading_face = 1;
			face_index = 0;
		}


		else if (reading_face) {
			int v, t;
			if (_ParseVertex(buff, v, t)) {
				cerr << "Error, vertex expected: " << buff << endl;
				return 1;
			}
			// indices start at 1 in file, but zero in array:
			face_v[face_index] = v-1;
			face_t[face_index] = t-1;
			face_index++;
		}


		else {
			cerr << "Unknown token: " << buff << endl;
			return 1;
		}
	}

	// finish last face:
	if (reading_face) {
		if (FaceCallback)
			FaceCallback(face_index,
						 face_v, face_t,
						 vertex_list, tc_list,
						 data_fcb);
	}

	delete [] vertex_list;
	delete [] tc_list;

	return 0;
}



static void _AddVertex(float* &vertex_list, int &vertex_list_size,
					   int &num_verts,
					   float x, float y, float z) {

	assert(num_verts <= vertex_list_size);

	if (num_verts == vertex_list_size) {

		int new_vertex_list_size = 100;
		if (vertex_list_size)
			new_vertex_list_size = vertex_list_size * 1.5;

		float *new_vertex_list = new float[new_vertex_list_size*3];
		assert(new_vertex_list);

		for (int i=0; i<vertex_list_size*3; i++)
			new_vertex_list[i] = vertex_list[i];
		delete [] vertex_list;

		vertex_list = new_vertex_list;
		vertex_list_size = new_vertex_list_size;
	}

	vertex_list[num_verts*3] = x;
	vertex_list[num_verts*3+1] = y;
	vertex_list[num_verts*3+2] = z;
	num_verts++;
}

static void _AddTextureCoordinates(float* &tc_list, int &tc_list_size,
								   int &num_tcs,
								   float s, float t) {

	assert(num_tcs <= tc_list_size);

	if (num_tcs == tc_list_size) {

		int new_tc_list_size = 100;
		if (tc_list_size)
			new_tc_list_size = tc_list_size * 1.5;

		float *new_tc_list = new float[new_tc_list_size*2];
		assert(new_tc_list);

		for (int i=0; i<tc_list_size*2; i++)
			new_tc_list[i] = tc_list[i];
		delete [] tc_list;

		tc_list = new_tc_list;
		tc_list_size = new_tc_list_size;
	}

	tc_list[num_tcs*2] = s;
	tc_list[num_tcs*2+1] = t;
	num_tcs++;
}

static int _ParseVertex(char *buff, int &v, int &t) {

	char v_str[30];
	char t_str[30];
	int i = 0;
	int j;

	j = 0;
	while (isdigit(buff[i]) || (buff[i] == '-') || (buff[i] == '.')) {
		v_str[j] = buff[i];
		i++;
		j++;
	}
	v_str[j] = '\0';
	v = atoi(v_str);

	if (buff[i] == '/') {
		i++;
		j = 0;
		while (isdigit(buff[i]) || (buff[i] == '-') || (buff[i] == '.')) {
			t_str[j] = buff[i];
			i++;
			j++;
		}
		t_str[j] = '\0';
		t = atoi(t_str);
	}
	else
		t = -1;

	if (buff[i] != '\0')
		return 1;

	return 0;
}
