objJedi.h 44 KB
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 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857
#ifndef OBJJEDI_H
#define OBJJEDI_H

/*OBJ reader and writer.

One aspect of the writer is based on OpenGL output commands.  You can send OpenGL commands
(replacing "gl" and "GL" with "obj" and "OBJ" respectively to render to an Wavefront OBJ file
*/

//#include "rtsMath.h"
#include "rtsLinearAlgebra.h"
#include <vector>
#include <fstream>
#include <iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;

//masks for valid vertex components
#define OBJ_V_X		0x1
#define OBJ_V_Y		0x2
#define OBJ_V_Z		0x4
#define OBJ_V_W		0x8

#define OBJ_VT_U	0x1
#define OBJ_VT_V	0x2
#define OBJ_VT_W	0x4

#define OBJ_VN_I	0x1
#define OBJ_VN_J	0x2
#define OBJ_VN_K	0x4

#define OBJ_V		0x1
#define OBJ_VT		0x2
#define OBJ_VN		0x4

//primitive types
typedef unsigned char primitive_type;

#define OBJ_END				0x0
#define OBJ_POINTS			0x1
#define OBJ_LINES			0x2
#define OBJ_FACE			0x3


#define OBJ_INVALID		ULONG_MAX
//define the point structures
struct vertex_position{float x,y,z,w; unsigned char mask;};
struct vertex_texture{float u,v,w; unsigned char mask;};
struct vertex_normal{float i,j,k; unsigned char mask;};
//the point structure contains indices to the relative 3-vectors in the lists
struct vertex
{
	unsigned int v;
	unsigned int vt;
	unsigned int vn;
};

struct primitive
{
	vector<vertex> p;		//indices to the point
	unsigned char mask;		//mask describing which features (v, vt, vn) are used
	primitive_type type;	//the type of primitive (points, lines, face)
};

//axis-aligned bounding box
struct AABB
{
	vertex_position min;
	vertex_position max;
};

//create variable types
typedef unsigned int OBJint;

//define the OBJ data class
class rtsOBJ
{
private:

	/*Current state variables.  These variables are committed to the OBJ object
	when a vertex is added.  However, we are careful to only add them once (if they don't
	change with every vertex.
	*/
	vertex_texture current_vt;
	vertex_normal current_vn;
	bool vt_changed;				//true if a new vt or vn was inserted since the last vertex
	bool vn_changed;
	unsigned char current_primitive_mask;	//defines what coordinates are being used by the current primitive
	//global variable storing the current render mode
	OBJint g_CurrentMode;
	//output file stream
	ofstream g_objFile;
	//obj file object
	//objData g_OBJ;
	//number of vertices since the last BEGIN
	unsigned int g_NumVertices;
	/*Attribute mask.  This indicates what attributes are stored for each vertex.
	Only a single mask applies to each vertex between objBegin() and objEnd().  The
	attribute mask is flipped the first time an attribute is set but it is fixed after
	the first vertex is passed.*/
	unsigned char g_AttributeMask;
	/*Attribute reset mask.  This indicates whether or not an attribute has been
	reset since the last vertex was rendered.  This applies to OBJ_VT and OBJ_VN*/
	unsigned char g_AttributeResetMask;
	//latest texture coordinate sent
	unsigned int g_LatestVT;
	//latest vertex normal sent
	unsigned int g_LatestVN;

	//extents of the points in the OBJ file
	AABB m_bounds;

	OBJint f_InsertPointVertex();
	OBJint f_InsertLineVertex();
	OBJint f_InsertLineLoopVertex();
	OBJint f_InsertLineStripVertex();
	OBJint f_InsertTriangleVertex();
	OBJint f_InsertTriangleStripVertex();
	OBJint f_InsertTriangleFanVertex();
	OBJint f_InsertQuadVertex();
	OBJint f_InsertQuadStripVertex();
	OBJint f_InsertPolygonVertex();
	OBJint f_InsertPreviousFaceVertex(unsigned int v_index);
	OBJint f_InsertFirstFaceVertex(unsigned int v_index);
	OBJint f_InsertNewFaceVertex();
	OBJint f_InsertNewLineVertex();
	OBJint f_CreateNewFace();
	OBJint f_CreateNewLine();
	OBJint f_TerminateLineLoop();
	OBJint f_LoadOBJ(const char* filename);
	OBJint f_LoadSWC(const char* filename);

	//insert coordinate commands
	//these are used to handle coordinates of different dimensions (and are called by the associated public function)
	OBJint f_InsertVertexf(float x, float y, float z, float w, unsigned char mask);
	OBJint f_InsertTexCoordf(float u, float v, float w, unsigned char mask);
	OBJint f_InsertNormalf(float i, float j, float k, unsigned char mask);
	//output functions
	void f_OutputVertices();
	void f_OutputPoints();
	void f_OutputLines();
	void f_OutputFaces();
	void f_OutputVertexNormals();
	void f_OutputTextureCoordinates();
	void f_ClearAll();

	//methods for reading from a file
	OBJint f_ReadPosition(ifstream &infile);
	OBJint f_ReadNormal(ifstream &infile);
	OBJint f_ReadTexCoord(ifstream &infile);
	OBJint f_ReadVertex(ifstream &infile, vertex &new_point, unsigned char &mask);
	OBJint f_ReadPrimitive(ifstream &infile, primitive_type type);
	OBJint f_AdjustExtents(vertex_position v);

public:
	/*These vectors store the vertex and primitive data from the obj file.
	All vertices, texture coordinates, and normals are stored in m_v, m_vt, m_vn
	respectively.  The vectors for each primitive store an index into m_v, m_vt,
	and m_vn identifying the associated coordinate.  Basically, the data is stored
	in a structure very similar to the OBJ file itself.
	*/
	vector<vertex_position> v_list;
	vector<vertex_texture> vt_list;
	vector<vertex_normal> vn_list;
	vector<primitive> primitives;

	vector<unsigned int> points;
	vector<unsigned int> lines;
	vector<unsigned int> faces;

public:

	OBJint objOpen(const char* filename);
	OBJint objBegin(OBJint obj_mode);
	OBJint objEnd();
	OBJint objClose();
	OBJint objNormal3f(float i, float j, float k);
	OBJint objNormal2f(float i, float j);
	OBJint objNormal1f(float i);
	OBJint objTexCoord3f(float u, float v, float w);
	OBJint objTexCoord2f(float u, float v);
	OBJint objTexCoord1f(float u);
	OBJint objVertex1f(float x);
	OBJint objVertex2f(float x, float y);
	OBJint objVertex3f(float x, float y, float z);
	OBJint objVertex4f(float x, float y, float z, float w);
	OBJint LoadFile(const char* filename);
	OBJint SaveFile(const char* filename);

	//direct insertion methods
	void insertVertexPosition(float x, float y, float z, unsigned char mask = OBJ_V_X | OBJ_V_Y | OBJ_V_Z);
	void insertLine(unsigned int num_points, unsigned int* pointlist, unsigned int* normallist, unsigned int* texturelist);

	//get methods
	unsigned int getNumVertices();
	unsigned int getNumLines();
	unsigned int getNumFaces();
	unsigned int getNumPointLists();
	unsigned int getNumTexCoords();
	unsigned int getNumNormals();

	//these functions return the coordinate index as well as the value
	unsigned int getNumFaceVertices(unsigned int face);
	unsigned int getFaceVertex(unsigned int face, unsigned int vertex);
	unsigned int getFaceNormal(unsigned int face, unsigned int normal);
	unsigned int getFaceTexCoord(unsigned int face, unsigned int texcoord);
	unsigned int getNumLineVertices(unsigned int line);
	unsigned int getLineVertex(unsigned int line, unsigned int vertex);
	unsigned int getLineTexCoord(unsigned int line, unsigned int texcoord);
	point3D<float> getVertex3d(unsigned int index);
	point3D<float> getTexCoord3d(unsigned int index);
	point3D<float> getNormal3d(unsigned int index);
	vertex_position getVertex(unsigned int index);
	vertex_texture getTexCoord(unsigned int index);
	vertex_normal getNormal(unsigned int index);
	AABB getBoundingBox(){return m_bounds;}
	void Scale(float scale_x, float scale_y, float scale_z);
	void Translate(float trans_x, float trans_y, float trans_z);

	float GetDistance(float x, float y, float z);

	//return data about primitives
	unsigned int getPrimitiveType(unsigned int primitive);

	//constructors
	rtsOBJ();
	void CopyOBJ(const rtsOBJ& obj);
	//assignment
	rtsOBJ& operator=(const rtsOBJ& obj)
	{
		CopyOBJ(obj);
		return *this;
	}
	//copy
	rtsOBJ(const rtsOBJ& obj)
	{
		CopyOBJ(obj);
		//return *this;
	}



	//Iterator stuff
	class iterator
	{
		friend class rtsOBJ;
	private:
		rtsOBJ* obj;
		bool end_primitive;
		bool end_object;
		unsigned int primitive_index;
	public:
		unsigned int operator*();
		void operator++();
		bool operator==(rtsOBJ::iterator operand);
		bool operator!=(rtsOBJ::iterator operand);
		unsigned int size(){return obj->primitives[primitive_index].p.size();};
		void print();
	};

	iterator begin();
	iterator end();
};

//define error codes
#define OBJ_OK				0x0100
#define OBJ_ERROR			0x0101

//define the different modes
#define OBJ_NONE			0x0
#define OBJ_POINTS			0x1
#define OBJ_LINES			0x2
#define OBJ_LINE_STRIP		0x3
#define OBJ_LINE_LOOP		0x4
#define OBJ_TRIANGLES		0x5
#define OBJ_TRIANGLE_STRIP	0x6
#define OBJ_TRIANGLE_FAN	0x7
#define OBJ_QUADS			0x8
#define OBJ_QUAD_STRIP		0x9
#define OBJ_POLYGON			0x10






//initialize the OBJ file
OBJint objOpen(char* filename);
//close the obj file
OBJint objClose();

//start rendering in a certain mode
OBJint objBegin(OBJint mode);
//stop the current rendering sequence
OBJint objEnd(void);
//render a vertex to the file
OBJint objVertex1f(float x);
OBJint objVertex2f(float x, float y);
OBJint objVertex3f(float x, float y, float z);
OBJint objVertex4f(float x, float y, float z, float w);
//set a normal vector for a vertex
OBJint objNormal3f(float i, float j, float k);
OBJint objNormal2f(float i, float j);
OBJint objNormal1f(float i);
//set a texture coordinate for a vertex
OBJint objTexCoord3f(float u, float v, float w);
OBJint objTexCoord2f(float u, float v);
OBJint objTexCoord1f(float u);

//global variable for global functions
extern rtsOBJ g_OBJ;

/*BUG NOTES
The standard function calls for inserting vertices don't work anymore.  I've fixed points
but everything beyond that has to be updated.
*/

#include "objJedi.h"
#include "rtsVector3d.h"
#include "rtsPoint3d.h"
#include <string>
//variable for use in global functions
rtsOBJ g_OBJ;

/********UTILITY METHODS*******************************/
void rtsOBJ::Scale(float scale_x, float scale_y, float scale_z)
{
	vector<vertex_position>::iterator i;
	for(i = v_list.begin(); i!= v_list.end(); i++)
	{
		(*i).x *= scale_x;
		(*i).y *= scale_y;
		(*i).z *= scale_z;
	}
}

void rtsOBJ::Translate(float trans_x, float trans_y, float trans_z)
{
	vector<vertex_position>::iterator i;
	for(i = v_list.begin(); i!= v_list.end(); i++)
	{
		(*i).x += trans_x;
		(*i).y += trans_y;
		(*i).z += trans_z;
	}

}

float rtsOBJ::GetDistance(float x, float y, float z)
{
	//gets the distance between the specified point and the nearest surface of the OBJ
	//currently only works for lines

	//cout<<"Primitives: "<<primitives.size()<<endl;
	unsigned int num_primitives = primitives.size();
	point3D<float> p0, p1, p2;
	float min_dist = 255;
	float dist;
	unsigned int p, l;
	vector3D<float> v, w;
	float c1, c2, b;
	point3D<float> Pb;

	//for each line
	for(l=0; l<num_primitives; l++)
	{
		if(primitives[l].type & OBJ_LINES)
		{
			//for each point
			for(p = 1; p<primitives[l].p.size(); p++)
			{

				vertex_position v1 = v_list[primitives[l].p[p-1].v];
				vertex_position v2 = v_list[primitives[l].p[p].v];
				p1.x = v1.x;
				p1.y = v1.y;
				p1.z = v1.z;
				p2.x = v2.x;
				p2.y = v2.y;
				p2.z = v2.z;

				p0.x = x;
				p0.y = y;
				p0.z = z;

				v = p2 - p1;
				w = p0 - p1;
				if((c1 = w*v) <= 0)
					dist = (p1 - p0).Length();
				else if((c2 = v*v) <= c1)
					dist = (p2 - p0).Length();
				else
				{
					b = c1/c2;
					Pb = p1 + b*v;
					dist = (Pb - p0).Length();
				}
				if(dist < min_dist)
					min_dist = dist;



			}
		}
	}
	//cout<<"---------------------------------------------"<<endl;

	return min_dist;


}

/********CLASS METHOD DEFINITIONS**********************/
//constructors

//constructor
rtsOBJ::rtsOBJ()
{
	g_CurrentMode = OBJ_NONE;
	g_NumVertices = 0;
	g_AttributeMask = 0x0;
	g_AttributeResetMask = 0x0;
	g_LatestVT = 0;
	g_LatestVN = 0;

	m_bounds.min.x = m_bounds.min.y = m_bounds.min.z = 99999;
	m_bounds.max.x = m_bounds.max.y = m_bounds.max.z = -99999;

	current_primitive_mask = 0x0;
}

void rtsOBJ::CopyOBJ(const rtsOBJ& obj)
{
	current_vt = obj.current_vt;
	current_vn = obj.current_vn;
	vt_changed = obj.vt_changed;				//true if a new vt or vn was inserted since the last vertex
	vn_changed = obj.vn_changed;
	current_primitive_mask = obj.current_primitive_mask;	//defines what coordinates are being used by the current primitive
	//global variable storing the current render mode
	g_CurrentMode = obj.g_CurrentMode;
	//output file stream
	//g_objFile = obj.g_objFile;
	//obj file object
	//objData g_OBJ;
	//number of vertices since the last BEGIN
	g_NumVertices = obj.g_NumVertices;
	/*Attribute mask.  This indicates what attributes are stored for each vertex.
	Only a single mask applies to each vertex between objBegin() and objEnd().  The
	attribute mask is flipped the first time an attribute is set but it is fixed after
	the first vertex is passed.*/
	g_AttributeMask = obj.g_AttributeMask;
	/*Attribute reset mask.  This indicates whether or not an attribute has been
	reset since the last vertex was rendered.  This applies to OBJ_VT and OBJ_VN*/
	g_AttributeResetMask = obj.g_AttributeResetMask;
	//latest texture coordinate sent
	g_LatestVT = obj.g_LatestVT;
	//latest vertex normal sent
	g_LatestVN = obj.g_LatestVN;
	m_bounds = obj.m_bounds;


	v_list = obj.v_list;
	vt_list = obj.vt_list;
	vn_list = obj.vn_list;
	primitives = obj.primitives;

	points = obj.points;
	lines = obj.lines;
	faces = obj.faces;
}

//opens an obj file for rendering
OBJint rtsOBJ::objOpen(const char* filename)
{
	g_objFile.open(filename);
	return OBJ_OK;
}

//close the obj file
OBJint rtsOBJ::objClose()
{
	//TODO: write obj data
	f_OutputVertices();
	f_OutputTextureCoordinates();
	f_OutputVertexNormals();
	f_OutputPoints();
	f_OutputLines();
	f_OutputFaces();

	//close the file
	g_objFile.close();

	//delete all of the data from the global object
	f_ClearAll();
	return OBJ_OK;
}

OBJint rtsOBJ::objBegin(OBJint mode)
{
	//make sure that we aren't currently rendering
	if(g_CurrentMode != OBJ_NONE)
		return OBJ_ERROR;
	//make sure that the given mode is valid
	if(mode < OBJ_POINTS || mode > OBJ_POLYGON)
		return OBJ_ERROR;

	//otherwise, go ahead and set the mode
	g_CurrentMode = mode;
	//set the number of vertices to zero
	g_NumVertices = 0;

	//reset the current state primitive state
	current_primitive_mask = 0x0;

	return OBJ_OK;
}

OBJint rtsOBJ::objEnd()
{
	OBJint error = OBJ_OK;
	//check to make sure the number of rendered vertices is valid for the current mode
	switch(g_CurrentMode)
	{
	case OBJ_NONE:
		//can't quit if we haven't started
		error = OBJ_ERROR;
		break;
	case OBJ_LINES:
		//if less than two vertices or an odd number of vertices
		if(g_NumVertices < 2 || g_NumVertices%2 != 0)
		{
			//if there wasn't a vertex at all
			if(g_NumVertices == 0)
				error = OBJ_ERROR;
			//if there was at least one vertex
			else
			{
				//pop the last line off the list
				primitives.pop_back();
				lines.pop_back();
				error = OBJ_ERROR;
			}
		}
		break;
	case OBJ_LINE_STRIP:
		//if less than two vertices
		if(g_NumVertices < 2)
		{
			//if there wasn't a vertex at all
			if(g_NumVertices == 0)
				error = OBJ_ERROR;
			//if there was at least one vertex
			else
			{
				//pop the last line off the list
				primitives.pop_back();
				lines.pop_back();
				error = OBJ_ERROR;
			}
		}
		break;
	case OBJ_LINE_LOOP:
		//if less than three vertices
		if(g_NumVertices < 3)
		{
			//pop the last line off the list
			primitives.pop_back();
			lines.pop_back();
			error = OBJ_ERROR;
		}
		//connect the first and last points
		else
		{
			error = f_TerminateLineLoop();
		}
		break;
	case OBJ_TRIANGLES:
		//if less than three vertices or not a power of three
		if(g_NumVertices < 3 || g_NumVertices%3 !=0)
		{
			primitives.pop_back();
			faces.pop_back();
			error = OBJ_ERROR;
		}
		break;
	case OBJ_TRIANGLE_STRIP:
		//if less than three vertices
		if(g_NumVertices < 3)
		{
			primitives.pop_back();
			faces.pop_back();
			error = OBJ_ERROR;
		}
		break;
	case OBJ_TRIANGLE_FAN:
		//if less than three vertices
		if(g_NumVertices < 3)
		{
			primitives.pop_back();
			faces.pop_back();
			error = OBJ_ERROR;
		}
		break;
	case OBJ_QUADS:
		if(g_NumVertices < 4 || g_NumVertices%4 != 0)
		{
			primitives.pop_back();
			faces.pop_back();
			error = OBJ_ERROR;
		}
		break;
	case OBJ_QUAD_STRIP:
		//has to be at least 4 vertices and an even number
		if(g_NumVertices < 4 || g_NumVertices%2 != 0)
		{
			primitives.pop_back();
			faces.pop_back();
			error = OBJ_ERROR;
		}
		break;
	case OBJ_POLYGON:
		//has to be at least three vertices
		if(g_NumVertices < 3)
		{
			primitives.pop_back();
			faces.pop_back();
			error = OBJ_ERROR;
		}
		break;
	}

	//reset the attribute mask
	g_AttributeMask = 0x0;
	//just for closure, reset the attribute reset mask
	g_AttributeResetMask = 0x0;
	//stop rendering
	g_CurrentMode = OBJ_NONE;
	return error;
}

OBJint rtsOBJ::f_InsertVertexf(float x, float y, float z, float w, unsigned char mask)
{
	//make sure we're rendering
	if(g_CurrentMode == OBJ_NONE)
		return OBJ_ERROR;

	//insert the vertex into the vertex vector
	vertex_position v;
	v.x = x; v.y = y; v.z=z; v.w=w; v.mask = mask;
	v_list.push_back(v);
	f_AdjustExtents(v);			//set the bounding box
	//insert texture coordinate and normal if specified for this primitive
	if((current_primitive_mask & OBJ_VT)  && (vt_changed))
		vt_list.push_back(current_vt);
	if((current_primitive_mask & OBJ_VN) && (vn_changed))
		vn_list.push_back(current_vn);


	//increment the number of vertices inserted
	g_NumVertices++;

	//handle each case of the vertex creation individually
	OBJint error = OBJ_OK;
	switch(g_CurrentMode)
	{
	case OBJ_POINTS:
		error = f_InsertPointVertex();
		break;
	case OBJ_LINES:
		error = f_InsertLineVertex();
		break;
	case OBJ_LINE_LOOP:
		error = f_InsertLineLoopVertex();
		break;
	case OBJ_LINE_STRIP:
		error = f_InsertLineStripVertex();
		break;
	case OBJ_TRIANGLES:
		error = f_InsertTriangleVertex();
		break;
	case OBJ_TRIANGLE_STRIP:
		error = f_InsertTriangleStripVertex();
		break;
	case OBJ_TRIANGLE_FAN:
		error = f_InsertTriangleFanVertex();
		break;
	case OBJ_QUADS:
		error = f_InsertQuadVertex();
		break;
	case OBJ_QUAD_STRIP:
		error = f_InsertQuadStripVertex();
		break;
	case OBJ_POLYGON:
		error = f_InsertPolygonVertex();
		break;
	}
	//set the reset mask to zero
	g_AttributeResetMask = 0x0;

	//set the attribute mask to include vertex position
	g_AttributeMask = g_AttributeMask | OBJ_V;

	//return the result of the insertion
	return error;
}

OBJint rtsOBJ::objVertex1f(float x)
{
	return f_InsertVertexf(x, 0.0, 0.0, 0.0, OBJ_V_X);
}

OBJint rtsOBJ::objVertex2f(float x, float y)
{
	return f_InsertVertexf(x, y, 0.0, 0.0, OBJ_V_X | OBJ_V_Y);
}

OBJint rtsOBJ::objVertex3f(float x, float y, float z)
{
	return f_InsertVertexf(x, y, z, 0.0, OBJ_V_X | OBJ_V_Y | OBJ_V_Z);

}

OBJint rtsOBJ::objVertex4f(float x, float y, float z, float w)
{
	return f_InsertVertexf(x, y, z, w, OBJ_V_X | OBJ_V_Y | OBJ_V_Z | OBJ_V_W);
}

OBJint rtsOBJ::objNormal3f(float i, float j, float k)
{
	return f_InsertNormalf(i, j, k, OBJ_VN_I | OBJ_VN_J | OBJ_VN_K);
}
OBJint rtsOBJ::objNormal2f(float i, float j)
{
	return f_InsertNormalf(i, j, 0.0, OBJ_VN_I | OBJ_VN_J);
}

OBJint rtsOBJ::objNormal1f(float i)
{
	return f_InsertNormalf(i, 0.0, 0.0, OBJ_VN_I);
}

OBJint rtsOBJ::f_InsertNormalf(float i, float j, float k, unsigned char mask)
{
	/*DEPRECATED
	//if the mode is not rendering faces, there is an error
	if(g_CurrentMode < OBJ_TRIANGLES)
		return OBJ_ERROR;
	//if the normal attribute flag is not set, set it (as long as a vertex hasn't been written)
	if(!(g_AttributeMask & OBJ_VN))
	{
		//if a vertex has been rendered, then we can't change the attribute, so exit
		if(g_NumVertices > 0)
			return OBJ_ERROR;
		else
			//otherwise, just set the attribute flag
			g_AttributeMask = g_AttributeMask | OBJ_VN;
	}


	//insert the new normal into the normal list for the file
	vertex_normal new_vn;
	new_vn.i = i;  new_vn.j = j;  new_vn.k = k;
	new_vn.mask = mask;
	vn_list.push_back(new_vn);
	*/
	current_vn.i = i;											//set the current texture state to the given coordinates
	current_vn.j = j;
	current_vn.k = k;
	current_vn.mask = mask;										//set the mask as appropriate
	vn_changed = true;											//the texture coordinate state has changed
	current_primitive_mask = current_primitive_mask | OBJ_VN;	//the current primitive now uses texture coordinates (if it didn't previously)

	return OBJ_OK;
}

OBJint rtsOBJ::objTexCoord3f(float u, float v, float w)
{
	return f_InsertTexCoordf(u, v, w, OBJ_VT_U | OBJ_VT_V | OBJ_VT_W);
}

OBJint rtsOBJ::objTexCoord2f(float u, float v)
{
	return f_InsertTexCoordf(u, v, 0.0, OBJ_VT_U | OBJ_VT_V);
}

OBJint rtsOBJ::objTexCoord1f(float u)
{
	return f_InsertTexCoordf(u, 0.0, 0.0, OBJ_VT_U);
}

OBJint rtsOBJ::f_InsertTexCoordf(float u, float v, float w, unsigned char mask)
{
	/*
	DEPRECATED
	//if the normal attribute flag is not set, set it (as long as a vertex hasn't been written)
	if(!(g_AttributeMask & OBJ_VT))
	{
		//if a vertex has been rendered, then we can't change the attribute, so exit
		if(g_NumVertices > 0)
			return OBJ_ERROR;
		else
			//otherwise, just set the attribute flag
			g_AttributeMask = g_AttributeMask | OBJ_VT;
	}

	//insert the new texture coordinate into the list for the file
	vertex_texture new_vt;
	new_vt.u = u;  new_vt.v = v;  new_vt.w = w;
	new_vt.mask = mask;
	vt_list.push_back(new_vt);
	*/
	current_vt.u = u;											//set the current texture state to the given coordinates
	current_vt.v = v;
	current_vt.w = w;
	current_vt.mask = mask;										//set the mask as appropriate
	vt_changed = true;											//the texture coordinate state has changed
	current_primitive_mask = current_primitive_mask | OBJ_VT;	//the current primitive now uses texture coordinates (if it didn't previously)

	return OBJ_OK;
}


void rtsOBJ::insertVertexPosition(float x, float y, float z, unsigned char mask)
{
	vertex_position v;
	v.x = x;
	v.y = y;
	v.z = z;
	v.mask = mask;

	v_list.push_back(v);
}

void rtsOBJ::insertLine(unsigned int num_points, unsigned int* pointlist, unsigned int* normallist, unsigned int* texturelist)
{
	//create the new primitive
	primitive line;
	line.type = OBJ_LINES;
	line.mask = 0;

	//set the mask based on the passed data
	if(pointlist != NULL)
		line.mask = line.mask | OBJ_V;
	if(normallist != NULL)
		line.mask = line.mask | OBJ_VN;
	if(texturelist != NULL)
		line.mask = line.mask | OBJ_VT;

	//insert the line
	unsigned int v;
	vertex new_vert;
	for(v=0; v<num_points; v++)
	{
		if(pointlist)
			new_vert.v = pointlist[v];
		if(normallist)
			new_vert.vn = normallist[v];
		if(texturelist)
			new_vert.vt = texturelist[v];
		line.p.push_back(new_vert);
	}
	//insert the new primitive into the list
	primitives.push_back(line);
}
OBJint rtsOBJ::f_InsertPointVertex()
{
	//insert the most recent point into the most recent point list
	//if this is the first vertex, create the point list
	if(g_NumVertices == 1)
	{
		primitive new_p;						//create the new point
		new_p.type = OBJ_POINTS;
		new_p.mask = current_primitive_mask;
		points.push_back(primitives.size());	//store the primitive id in the points list
		primitives.push_back(new_p);
	}

	//find the id of the most recent primitive
	unsigned int p_index = primitives.size() - 1;
	//find the index of the recent point
	vertex p;
	p.v = v_list.size() - 1;
	//insert the indices for texture coordinates and normal if necessary
	if(primitives[p_index].mask & OBJ_VT)
		p.vt = vt_list.size() - 1;
	if(primitives[p_index].mask & OBJ_VN)
		p.vn = vn_list.size() - 1;

	//insert the vertex index into the primitive's point list
	primitives[p_index].p.push_back(p);

	//push the point into the points list if it is not the only point in the primitive
	if(g_NumVertices > 1)
		points.push_back(p_index);

	return OBJ_OK;
}

OBJint rtsOBJ::f_InsertLineVertex()
{
	//if this is an odd vertex, create a new line
	if(g_NumVertices%2 == 1)
	{
		f_CreateNewLine();
	}

	f_InsertNewLineVertex();

	return OBJ_OK;
}
OBJint rtsOBJ::f_InsertLineLoopVertex()
{
	//technically, this is the same as inserting a line strip vertex
	f_InsertLineStripVertex();
	return OBJ_OK;
}

OBJint rtsOBJ::f_InsertLineStripVertex()
{
	if(g_NumVertices == 1)
	{
		f_CreateNewLine();
	}

	f_InsertNewLineVertex();

	return OBJ_OK;
}

OBJint rtsOBJ::f_InsertTriangleVertex()
{
	//if this is the first vertex in a triangle, create a new triangle
	if(g_NumVertices%3 == 1)
	{
		f_CreateNewFace();
	}


	f_InsertNewFaceVertex();

	return OBJ_OK;
}
OBJint rtsOBJ::f_InsertTriangleStripVertex()
{
	//in the special case of the first three vertices, just create a triangle
	if(g_NumVertices < 4)
		f_InsertTriangleVertex();
	else
	{

		//create a new face for the new triangle
		f_CreateNewFace();

		//make sure to get the ordering right:
		//		Even vertices provide the previous two vertices "in order": (v2, v3, v4)
		//		Odd vertices provide the previous two vertices in reverse order: (v1, v3, v2)
		if(g_NumVertices % 2 == 1)
		{
			f_InsertPreviousFaceVertex(2);
			f_InsertPreviousFaceVertex(1);
			f_InsertNewFaceVertex();
		}
		else
		{
			f_InsertPreviousFaceVertex(1);
			f_InsertNewFaceVertex();
			f_InsertPreviousFaceVertex(2);
		}
	}

	return OBJ_OK;
}
OBJint rtsOBJ::f_InsertTriangleFanVertex()
{
	//in the special case of the first three vertices, just create a triangle
	if(g_NumVertices <4)
		f_InsertTriangleVertex();
	else
	{
		//create a new face for the new triangle
		f_CreateNewFace();
		//add the previous vertices to the face
		f_InsertFirstFaceVertex(0);
		f_InsertPreviousFaceVertex(2);
		//insert the current vertex
		f_InsertNewFaceVertex();
	}

	return OBJ_OK;
}
OBJint rtsOBJ::f_InsertQuadVertex()
{
	//if this is the first vertex in a quad, create a new quad
	if(g_NumVertices%4 == 1)
	{
		f_CreateNewFace();
	}

	f_InsertNewFaceVertex();

	return OBJ_OK;
}
OBJint rtsOBJ::f_InsertQuadStripVertex()
{
	//in the case of one of the first four vertices, just create a quad
	if(g_NumVertices < 5)
		f_InsertQuadVertex();
	//if the vertex is odd (it will be the third vertex of a quad)
	else if(g_NumVertices%2 == 1)
	{
		//create a new face for the new quad
		f_CreateNewFace();
		//add the previous two vertices
		f_InsertPreviousFaceVertex(2);
		f_InsertPreviousFaceVertex(3);
		//add the current vertex
		f_InsertNewFaceVertex();
	}
	else
	{
		//if this is the last vertex of the quad, just add it
		f_InsertNewFaceVertex();

	}
	return OBJ_OK;
}
OBJint rtsOBJ::f_InsertPolygonVertex()
{
	//if this is the first vertex, create the quad
	if(g_NumVertices == 1)
	{
		f_CreateNewFace();
	}
	f_InsertNewFaceVertex();

	return OBJ_OK;
}

OBJint rtsOBJ::f_InsertPreviousFaceVertex(unsigned int v_index)
{
	/*Finds the vertex used in the previous face with the given index and
	inserts it into the current face.  This limits the redundancy in the file
	for re-used vertices (in strips and fans).  This also transfers texture
	and normal information.*/

	//find the index of the previous face
	unsigned int prev_f_index = primitives.size() - 2;
	//find the index of the current face
	unsigned int f_index = prev_f_index +1;
	//add the vertex information from the previous face to this face
	primitives[f_index].p.push_back(primitives[prev_f_index].p[v_index]);

	return OBJ_OK;
}

OBJint rtsOBJ::f_InsertFirstFaceVertex(unsigned int v_index)
{
	/*Finds the vertex used in the first face (since the last objBegin())
	with the given index and inserts it at the end of the current face.
	This includes texture and normal information.*/

	//The result depends on the type of face being rendered
	//So far, this function only applies to triangle fans
	if(g_CurrentMode != OBJ_TRIANGLE_FAN)
		return OBJ_ERROR;

	//calculate the number of faces that have been rendered
	unsigned int num_faces = g_NumVertices - 2;
	//find the index of the first face
	unsigned int first_f_index = primitives.size() - num_faces;
	//find the index of the current face
	unsigned int f_index = primitives.size() - 1;
	//transfer the vertex information from the first face to this one
	primitives[f_index].p.push_back(primitives[first_f_index].p[v_index]);


	return OBJ_OK;
}

OBJint rtsOBJ::f_InsertNewFaceVertex()
{
	/*This inserts information about the current vertex into the current face*/
	//find the new vertex index
	vertex p;
	p.v = v_list.size() -1;
	p.vt = vt_list.size() - 1;
	p.vn = vn_list.size() -1;
	//find the face index
	unsigned int f_index = primitives.size() -1;
	//INSERT VERTEX AND ATTRIBUTE DATA
	//just add the vertex to the face
	primitives[f_index].p.push_back(p);

	return OBJ_OK;
}

OBJint rtsOBJ::f_InsertNewLineVertex()
{
	/*This inserts information about the current vertex into the current line*/
	//find the new vertex index
	vertex p;
	p.v = v_list.size() -1;
	p.vt = vt_list.size() - 1;
	//find the line index
	unsigned int l_index = primitives.size() -1;

	//ADD VERTEX AND ATTRIBUTE INFORMATION
	//add the vertex to the line
	primitives[l_index].p.push_back(p);

	return OBJ_OK;
}

OBJint rtsOBJ::f_CreateNewFace()
{
	primitive new_f;
	new_f.type = OBJ_FACE;
	new_f.mask = g_AttributeMask;
	faces.push_back(primitives.size());
	primitives.push_back(new_f);


	return OBJ_OK;
}

OBJint rtsOBJ::f_CreateNewLine()
{
	primitive new_l;
	new_l.type = OBJ_LINES;
	new_l.mask = g_AttributeMask;
	lines.push_back(primitives.size());
	primitives.push_back(new_l);

	return OBJ_OK;
}


OBJint rtsOBJ::f_TerminateLineLoop()
{
	/*This function just terminates the line loop by setting the last vertex
	to the first vertex.*/
	if(g_CurrentMode != OBJ_LINE_LOOP)
		return OBJ_ERROR;
	//find the index for the current line
	unsigned int l_index = lines.size() -1;
	//insert the first vertex as the last vertex
	primitives[l_index].p.push_back(primitives[l_index].p[0]);

	return OBJ_OK;
}

void rtsOBJ::f_OutputVertices()
{
	//get the number of vertices in the object
	unsigned int v_num = v_list.size();
	for(unsigned int i=0; i<v_num; i++)
	{
		g_objFile<<"v";
		if(v_list[i].mask & OBJ_V_X)
			g_objFile<<" "<<v_list[i].x;
		if(v_list[i].mask & OBJ_V_Y)
			g_objFile<<" "<<v_list[i].y;
		if(v_list[i].mask & OBJ_V_Z)
			g_objFile<<" "<<v_list[i].z;
		if(v_list[i].mask & OBJ_V_W)
			g_objFile<<" "<<v_list[i].w;
		g_objFile<<endl;
	}

}

void rtsOBJ::f_OutputVertexNormals()
{
	//get the number of normals in the object
	unsigned int vn_num = vn_list.size();
	for(unsigned int i=0; i<vn_num; i++)
	{
		g_objFile<<"vn ";
		if(vn_list[i].mask & OBJ_VN_I)
		{
			g_objFile<<vn_list[i].i;
			if(vn_list[i].mask & OBJ_VN_J)
			{
				g_objFile<<" "<<vn_list[i].j;
				if(vn_list[i].mask & OBJ_VN_K)
					g_objFile<<" "<<vn_list[i].k;
			}
		}
		g_objFile<<endl;
	}
}

void rtsOBJ::f_OutputTextureCoordinates()
{
	//get the number of vertices in the object
	unsigned int vt_num = vt_list.size();
	for(unsigned int i=0; i<vt_num; i++)
	{
		g_objFile<<"vt ";
		if(vt_list[i].mask & OBJ_VT_U)
		{
			g_objFile<<vt_list[i].u;
			if(vt_list[i].mask & OBJ_VT_V)
			{
				g_objFile<<" "<<vt_list[i].v;
				if(vt_list[i].mask & OBJ_VT_W)
					g_objFile<<" "<<vt_list[i].w;
			}
		}
		g_objFile<<endl;
	}
}

void rtsOBJ::f_OutputPoints()
{
	/*
	//get the number of point vectors
	unsigned int p_num = points.size();

	//for each point vector, output the points
	for(unsigned int i=0; i<p_num; i++)
	{
		g_objFile<<"p";
		unsigned int v_num = points[i].p.size();
		for(unsigned int j=0; j<v_num; j++)
		{
			g_objFile<<" "<<points[i].p[j].v+1;
		}
		g_objFile<<endl;
	}
	*/
}

void rtsOBJ::f_OutputLines()
{
	/*
	//get the number of line vectors
	unsigned int l_num = lines.size();

	//for each line vector, output the associated points
	for(unsigned int i=0; i<l_num; i++)
	{
		g_objFile<<"l";
		unsigned int v_num = lines[i].p.size();
		for(unsigned int j=0; j<v_num; j++)
		{
			g_objFile<<" "<<lines[i].p[j].v+1;
			//output texture coordinate if there are any
			if(lines[i].mask & OBJ_VT)
				g_objFile<<"/"<<lines[i].p[j].vt+1;
		}
		g_objFile<<endl;
	}
	*/
}

void rtsOBJ::f_OutputFaces()
{
	/*
	//get the number of faces
	unsigned int f_num = faces.size();

	//for each face, output the associated points
	for(unsigned int i=0; i<f_num; i++)
	{
		g_objFile<<"f";
		//get the number of face vertices
		unsigned int v_num = faces[i].p.size();
		for(unsigned int j=0; j<v_num; j++)
		{
			g_objFile<<" "<<faces[i].p[j].v+1;
			//if there are texture coordinates
			if(faces[i].mask & OBJ_VT)
				g_objFile<<"/"<<faces[i].p[j].vt+1;
			//if there is a normal
			if(faces[i].mask & OBJ_VN)
			{
				//but no texture coordinates, put an extra slash
				if(!(faces[i].mask & OBJ_VT))
					g_objFile<<"/";
				g_objFile<<"/"<<faces[i].p[j].vn+1;
			}

		}
		g_objFile<<endl;
	}
	*/
}

void rtsOBJ::f_ClearAll()
{
	rtsOBJ();
	//clear all data from the global obj function
	faces.clear();
	lines.clear();
	points.clear();
	v_list.clear();
	vn_list.clear();
	vt_list.clear();
	primitives.clear();
}

/*GLOBAL FUNCTION DEFINITIONS*/
//initialize the OBJ file
OBJint objOpen(char* filename)
{
	return g_OBJ.objOpen(filename);
}
//close the obj file
OBJint objClose()
{
	return g_OBJ.objClose();
}

//start rendering in a certain mode
OBJint objBegin(OBJint mode)
{
	return g_OBJ.objBegin(mode);
}
//stop the current rendering sequence
OBJint objEnd(void)
{
	return g_OBJ.objEnd();
}
//render a vertex to the file
OBJint objVertex1f(float x)
{
	return g_OBJ.objVertex1f(x);
}

OBJint objVertex2f(float x, float y)
{
	return g_OBJ.objVertex2f(x, y);
}

OBJint objVertex3f(float x, float y, float z)
{
	return g_OBJ.objVertex3f(x, y, z);
}

OBJint objVertex4f(float x, float y, float z, float w)
{
	return g_OBJ.objVertex4f(x, y, z, w);
}
//set a normal vector for a vertex
OBJint objNormal3f(float i, float j, float k)
{
	return g_OBJ.objNormal3f(i, j, k);
}
OBJint objNormal2f(float i, float j)
{
	return g_OBJ.objNormal2f(i, j);
}
OBJint objNormal1f(float i)
{
	return g_OBJ.objNormal1f(i);
}
//set a texture coordinate for a vertex
OBJint objTexCoord3f(float u, float v, float w)
{
	return g_OBJ.objTexCoord3f(u, v, w);
}

OBJint objTexCoord2f(float u, float v)
{
	return g_OBJ.objTexCoord2f(u,v);
}

OBJint objTexCoord1f(float u)
{
	return g_OBJ.objTexCoord1f(u);
}

OBJint rtsOBJ::f_ReadPosition(ifstream &infile)
{
	vertex_position new_vertex;
	//get each coordinate
	infile>>new_vertex.x;
	new_vertex.mask = OBJ_V_X;

	if(infile.peek() == ' ')
	{
		infile>>new_vertex.y;
		new_vertex.mask = new_vertex.mask | OBJ_V_Y;
	}
	if(infile.peek() == ' ')
	{
		infile>>new_vertex.z;
		new_vertex.mask = new_vertex.mask | OBJ_V_Z;
	}
	if(infile.peek() == ' ')
	{
		infile>>new_vertex.w;
		new_vertex.mask = new_vertex.mask | OBJ_V_W;
	}
	int c = infile.peek();
	//ignore the rest of the line
	infile.ignore(1000, '\n');
	c = infile.peek();

	//cout<<"vertex read: "<<new_vertex.x<<","<<new_vertex.y<<","<<new_vertex.z<<","<<new_vertex.w<<endl;
	//insert the vertex into the list
	v_list.push_back(new_vertex);

	//adjust the extents of the model
	f_AdjustExtents(new_vertex);

	return OBJ_OK;
}

OBJint rtsOBJ::f_ReadNormal(ifstream &infile)
{
	vertex_normal new_normal;
	infile>>new_normal.i;
	new_normal.mask = OBJ_VN_I;
	//get every other component
	if(infile.peek() == ' ')
	{
		infile>>new_normal.j;
		new_normal.mask = new_normal.mask | OBJ_VN_J;
	}
	if(infile.peek() == ' ')
	{
		infile>>new_normal.k;
		new_normal.mask = new_normal.mask | OBJ_VN_K;
	}
	//ignore the rest of the line
	infile.ignore(1000, '\n');
	//insert the normal
	vn_list.push_back(new_normal);

	return OBJ_OK;
}

OBJint rtsOBJ::f_ReadTexCoord(ifstream &infile)
{
	vertex_texture new_texcoord;
	infile>>new_texcoord.u;
	new_texcoord.mask = OBJ_VT_U;
	//get every other component
	if(infile.peek() == ' ')
	{
		infile>>new_texcoord.v;
		new_texcoord.mask = new_texcoord.mask | OBJ_VT_V;
	}
	if(infile.peek() == ' ')
	{
		infile>>new_texcoord.w;
		new_texcoord.mask = new_texcoord.mask | OBJ_VT_W;
	}

	//ignore the rest of the line
	infile.ignore(1000, '\n');
	//insert the texture coordinate
	vt_list.push_back(new_texcoord);

	return OBJ_OK;

}

OBJint rtsOBJ::f_ReadVertex(ifstream &infile, vertex &new_point, unsigned char &mask)
{
	//store the line vertex
	infile>>new_point.v;
	new_point.v--;
	mask = OBJ_V;
	//new_face.v.push_back(new_v - 1);
	if(infile.peek() == '/')
	{
		infile.get();
		//if there actually is a texcoord
		if(infile.peek() != '/')
		{
			infile>>new_point.vt;						//get the index
			new_point.vt--;
			mask = mask | OBJ_VT;				//update the mask
			//new_face.vt.push_back(new_vt - 1);
		}
	}
	//check for a normal
	if(infile.peek() == '/')
	{
		infile.get();
		infile>>new_point.vn;							//get the index
		new_point.vn--;
		mask = mask | OBJ_VN;	//update the mask
	}

	return OBJ_OK;
}

OBJint rtsOBJ::f_ReadPrimitive(ifstream &infile, primitive_type type)
{
	//create a new point list
	primitive new_primitive;
	new_primitive.type = type;
	//until the end of the line
	while(infile.peek() != '\n')
	{
		//read each point
		if(infile.peek() == ' ')
			infile.get();
		else
		{
			vertex new_point;
			f_ReadVertex(infile, new_point, new_primitive.mask);
			new_primitive.p.push_back(new_point);
		}
	}
	//ignore the rest of the line
	infile.ignore(1000, '\n');

	//push the id of the primitive into the new list
	//:DEBUG:
	if(type == OBJ_POINTS)
		points.push_back(primitives.size());
	else if(type == OBJ_LINES)
		lines.push_back(primitives.size());
	else if(type == OBJ_FACE)
		faces.push_back(primitives.size());

	primitives.push_back(new_primitive);	//push the new primitive

	return OBJ_OK;
}


OBJint rtsOBJ::f_AdjustExtents(vertex_position v)
{
	if(v.x < m_bounds.min.x)
		m_bounds.min.x = v.x;
	if(v.y < m_bounds.min.y)
		m_bounds.min.y = v.y;
	if(v.z < m_bounds.min.z)
		m_bounds.min.z = v.z;

	if(v.x > m_bounds.max.x) m_bounds.max.x = v.x;
	if(v.y > m_bounds.max.y) m_bounds.max.y = v.y;
	if(v.z > m_bounds.max.z) m_bounds.max.z = v.z;

	return OBJ_OK;
}

OBJint rtsOBJ::f_LoadOBJ(const char* filename)
{
	f_ClearAll();
	//open the file as a stream
	ifstream infile;
	infile.open(filename);
	if(!infile)
		exit(1);

	unsigned int vertices = 0;

	string token;
	infile>>token;
	while(!infile.eof())
	{
		//if the token is some vertex property
		if(token == "v")
			f_ReadPosition(infile);
		else if(token == "vn")
			f_ReadNormal(infile);
		else if(token == "vt")
			f_ReadTexCoord(infile);
		else if(token == "p")
			f_ReadPrimitive(infile, OBJ_POINTS);
		else if(token == "l")
			f_ReadPrimitive(infile, OBJ_LINES);
		else if(token == "f")
			f_ReadPrimitive(infile, OBJ_FACE);
		else
			infile.ignore(9999, '\n');
		//vertices++;

		infile>>token;
	}

}

OBJint rtsOBJ::f_LoadSWC(const char* filename)
{
	f_ClearAll();
	//open the file as a stream
	ifstream infile;
	infile.open(filename);
	if(!infile.is_open())
		return OBJ_ERROR;

	vector<vertex_position> swcVertices;
	float token;
	objBegin(OBJ_LINES);
	while(!infile.eof())
	{
		vertex_position v;
		infile>>token;			//get the id
		infile>>token;			//get the fiber type
		infile>>v.x;			//get the node position
		infile>>v.y;
		infile>>v.z;
		infile>>token;			//get the radius
		infile>>token;			//get the parent

		//insert the node into the swc vector
		swcVertices.push_back(v);
		//now draw the line from the parent to the current node
		if(token != -1)
		{
			unsigned int i = (unsigned int)token - 1;
			objVertex3f(swcVertices[i].x, swcVertices[i].y, swcVertices[i].z);
			objVertex3f(v.x, v.y, v.z);
		}
	}
	objEnd();


	return OBJ_OK;

}
OBJint rtsOBJ::LoadFile(const char* filename)
{
	string strFilename = filename;
	int length = strFilename.length();
	string extension = strFilename.substr(strFilename.length() - 3, 3);
	if(!extension.compare(string("obj")))
		return f_LoadOBJ(filename);
	else if(!extension.compare(string("swc")))
		return f_LoadSWC(filename);
	else return f_LoadOBJ(filename);

}

OBJint rtsOBJ::SaveFile(const char* filename)
{
	//open the file as a stream
	ofstream outfile;
	outfile.open(filename);
	if(!outfile.is_open())
		return OBJ_ERROR;

	//output vertex positions
	vector<vertex_position>::iterator v;
	for(v=v_list.begin(); v!= v_list.end(); v++)
	{
		outfile<<"v";
		if((*v).mask & OBJ_V_X)
		{
			outfile<<' '<<(*v).x;
			if((*v).mask & OBJ_V_Y)
			{
				outfile<<' '<<(*v).y;
				if((*v).mask & OBJ_V_Z)
				{
					outfile<<' '<<(*v).z;
					if((*v).mask & OBJ_V_W)
						outfile<<' '<<(*v).w;
				}
			}
		}
		outfile<<'\n';
	}

	//output vertex texture coordinates
	vector<vertex_texture>::iterator vt;
	for(vt=vt_list.begin(); vt!= vt_list.end(); vt++)
	{
		outfile<<"vt";
		if((*vt).mask & OBJ_VT_U)
		{
			outfile<<' '<<(*vt).u;
			if((*vt).mask & OBJ_VT_V)
			{
				outfile<<' '<<(*vt).v;
				if((*vt).mask & OBJ_VT_W)
					outfile<<' '<<(*vt).w;
			}
		}
		outfile<<'\n';
	}

	//output vertex normal coordinates
	vector<vertex_normal>::iterator vn;
	for(vn=vn_list.begin(); vn!= vn_list.end(); vn++)
	{
		outfile<<"vn";
		if((*vn).mask & OBJ_VN_I)
		{
			outfile<<' '<<(*vn).i;
			if((*vn).mask & OBJ_VN_J)
			{
				outfile<<' '<<(*vn).j;
				if((*vn).mask & OBJ_VN_K)
					outfile<<' '<<(*vn).k;
			}
		}
		outfile<<'\n';
	}

	//output each primitive
	vector<primitive>::iterator p;
	vector<vertex>::iterator vert;
	for(p=primitives.begin(); p!= primitives.end(); p++)
	{
		switch((*p).type)
		{
		case OBJ_POINTS:
			outfile<<"p";			//output the points token
			break;
		case OBJ_LINES:
			outfile<<"l";			//output the lines token
			break;
		case OBJ_FACE:
			outfile<<"f";			//output the face token
			break;
		}

		//for each vertex in the list for the primitive
		for(vert = (*p).p.begin(); vert != (*p).p.end(); vert++)
		{
			outfile<<' '<<(*vert).v + 1;
			if((*p).mask & OBJ_VT)
				outfile<<'/'<<(*vert).vt + 1;
			if((*p).mask & OBJ_VN)
			{
				if(!((*p).mask & OBJ_VT))
					outfile<<'/';
				outfile<<'/'<<(*vert).vn + 1;
			}
		}
		outfile<<'\n';

	}



}

//get methods
unsigned int rtsOBJ::getNumVertices(){return v_list.size();}
unsigned int rtsOBJ::getNumLines(){return lines.size();}
unsigned int rtsOBJ::getNumFaces(){return faces.size();}
unsigned int rtsOBJ::getNumPointLists(){return points.size();}
unsigned int rtsOBJ::getNumTexCoords(){return vt_list.size();}
unsigned int rtsOBJ::getNumNormals(){return vn_list.size();}

//these functions return the coordinate index as well as the value
unsigned int rtsOBJ::getNumFaceVertices(unsigned int face){return primitives[face].p.size();}
unsigned int rtsOBJ::getFaceVertex(unsigned int face, unsigned int vertex){return primitives[face].p[vertex].v;}
unsigned int rtsOBJ::getFaceNormal(unsigned int face, unsigned int normal){return primitives[face].p[normal].vn;}
unsigned int rtsOBJ::getFaceTexCoord(unsigned int face, unsigned int texcoord){return primitives[face].p[texcoord].vt;}
unsigned int rtsOBJ::getNumLineVertices(unsigned int line){return primitives[line].p.size();}
unsigned int rtsOBJ::getLineVertex(unsigned int line, unsigned int vertex){return primitives[line].p[vertex].v;}
unsigned int rtsOBJ::getLineTexCoord(unsigned int line, unsigned int texcoord){return primitives[line].p[texcoord].vt;}
point3D<float> rtsOBJ::getVertex3d(unsigned int index)
{
	return point3D<float>(v_list[index].x, v_list[index].y, v_list[index].z);
}
point3D<float> rtsOBJ::getTexCoord3d(unsigned int index)
{
	return point3D<float>(vt_list[index].u, vt_list[index].v, vt_list[index].w);
}
point3D<float> rtsOBJ::getNormal3d(unsigned int index)
{
	return point3D<float>(vn_list[index].i, vn_list[index].j, vn_list[index].k);
}
vertex_position rtsOBJ::getVertex(unsigned int index){return v_list[index];}
vertex_texture rtsOBJ::getTexCoord(unsigned int index){return vt_list[index];}
vertex_normal rtsOBJ::getNormal(unsigned int index){return vn_list[index];}


unsigned int rtsOBJ::getPrimitiveType(unsigned int primitive)
{
	/*
	switch(primitives[i].type)
	{
	case OBJ_POINTS:
		return OBJ_POINTS;
		break;
	case OBJ_LINES:
		return OBJ_LINES;
		break;
	case OBJ_FACE:
		f_RenderFace(i);
		break;
	}*/
	return 0;
}
/****************************************************/
/*******Iterator Methods*****************************/
/****************************************************/

rtsOBJ::iterator rtsOBJ::begin()
{
	//create an iterator that will be returned and assign it to this OBJ
	iterator result;
	result.obj = this;
	result.end_object = false;
	result.end_primitive = false;

	//if there are no primitives, return the end iterator
	if(primitives.size() == 0)
		return end();

	//start at the beginning of the primitive array
	result.primitive_index = 0;

	return result;
}

rtsOBJ::iterator rtsOBJ::end()
{
	//create an end iterator to return
	iterator result;
	result.obj = this;
	result.end_primitive = true;
	result.primitive_index = result.obj->primitives.size();

	return result;
}

void rtsOBJ::iterator::operator++()
{
	primitive_index++;
	if(primitive_index >= obj->primitives.size())
		(*this) = obj->end();

}

bool rtsOBJ::iterator::operator ==(rtsOBJ::iterator operand)
{
	if(operand.primitive_index == primitive_index)
	   return true;
	else return false;
}

bool rtsOBJ::iterator::operator !=(rtsOBJ::iterator operand)
{
	if(operand.primitive_index != primitive_index)
	   return true;
	else return false;
}

unsigned int rtsOBJ::iterator::operator*()
{
	return primitive_index;
}

void rtsOBJ::iterator::print()
{
	cout<<"This is a test"<<endl;
}




#endif