diff --git a/.gitignore b/.gitignore index 1a33935..c35714c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ examples/viewer/viewer test/tinyobj_tests *.dSYM *.o +/nd_config/Working Data diff --git a/doc/classes/C/COMPATtinyobj_attrib_t-Summary.js b/doc/classes/C/COMPATtinyobj_attrib_t-Summary.js new file mode 100644 index 0000000..7d8a2d4 --- /dev/null +++ b/doc/classes/C/COMPATtinyobj_attrib_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:COMPATtinyobj_attrib_t","COMPATtinyobj_attrib_t");NDSummary.OnSummaryLoaded("CClass:COMPATtinyobj_attrib_t",[["C/C++","C"]],[["Constants","Constant"],["Functions","Function"],["Groups","Group"],["Structs","Struct"]],[[40,0,3,"COMPATtinyobj_attrib_t"],[41,0,2,"String handling","String_handling"],[42,0,1,"String handling macros","String_handling_macros"],[43,0,1,,"IS_SPACE"],[44,0,1,,"IS_DIGIT"],[45,0,1,,"IS_NEW_LINE"],[120,0,1,"is_line_ending","is_line_ending"],[47,0,1,"skip_space","skip_space"],[48,0,1,"skip_space_and_cr","skip_space_and_cr"],[49,0,1,"length_until_space","length_until_space"],[50,0,1,"until_space","until_space"],[51,0,1,"until_space_cr_slash","until_space_cr_slash"],[52,0,1,"length_until_newline_comment_space","length_until_newline_comment_space"],[53,0,1,"length_until_line_feed","length_until_line_feed"],[123,0,1,"strdup_ml","strdup_ml"],[55,0,1,"strndup","strndup"],[124,0,1,"dynamic_fgets","dynamic_fgets"],[57,0,2,"Triplet handling","Triplet_handling"],[34,0,1,"fixIndex","fixIndex"],[59,0,1,"parseRawTriple","parseRawTriple"],[60,0,2,"Integer/Double/Float handling","Integer/Double/Float_handling"],[61,0,1,"parseInt","parseInt"],[62,0,1,"tryParseDouble_assemble","tryParseDouble_assemble"],[63,0,1,"tryParseDouble_integer","tryParseDouble_integer"],[125,0,1,"tryParseDouble","tryParseDouble"],[65,0,1,"try_parse_float","try_parse_float"],[66,0,1,"parseFloat","parseFloat"],[67,0,1,"parseFloat2","parseFloat2"],[68,0,1,"parseFloat3","parseFloat3"],[78,0,2,"TINYOBJ hashtable implementation","TINYOBJ_hashtable_implementation"],[70,0,0,"Hash table return codes","Hash_table_return_codes"],[71,0,0,,"TINYOBJ_HASH_TABLE_SUCCESS"],[72,0,0,,"TINYOBJ_HASH_TABLE_ERROR"],[73,0,0,"TINYOBJ_HASH_TABLE_DEFAULT_SIZE","TINYOBJ_HASH_TABLE_DEFAULT_SIZE"]]); \ No newline at end of file diff --git a/doc/classes/C/COMPATtinyobj_attrib_t-SummaryToolTips.js b/doc/classes/C/COMPATtinyobj_attrib_t-SummaryToolTips.js new file mode 100644 index 0000000..e702c5f --- /dev/null +++ b/doc/classes/C/COMPATtinyobj_attrib_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:COMPATtinyobj_attrib_t",{40:"
Object attributes (deprecated)
",120:"
static int is_line_ending(
const char *p,
size_t i,
size_t end_i
)
Is given line ending in this character?
",47:"
static void skip_space(
const char **token
)
Skips the next spacing characters in given token
",48:"
static void skip_space_and_cr(
const char **token
)
Skips the next spacing characters and also carriage return in given token
",49:"
static size_t length_until_space(
const char *token,
size_t n
)
Calculates and returns the length until next space character in this token
",50:"
static int until_space(
const char *token
)
Skips the next spacing characters
",51:"
static void until_space_cr_slash(
const char **token
)
Skips the next characters in given token
",52:"
static size_t length_until_newline_comment_space(
const char *token,
size_t n
)
Returns the length until the next characters:
",53:"
static size_t length_until_line_feed(
const char *token,
size_t n
)
Returns the length until the next line feed
",123:"
static char *strdup_ml(
const char *s,
size_t max_length
)
Duplicates \'max_length\' characters of given string (strdup with max length specified)
",55:"
char *strndup(
const char *s,
size_t len
)
strndup implementation for non-GNU compliant compilers
",124:"
static char *dynamic_fgets(
char **buf,
int *size,
FILE *file
)
fgets with a dynamic buffer
",34:"
static int fixIndex(
int idx,
size_t n
)
Converts given absolute index, from triplet to zero-base, supports relative indices
",59:"
static tinyobj_vertex_index_t parseRawTriple(
const char **token
)
Parses raw triplets of given tokens
",61:"
static int parseInt(
const char **token
)
Returns equivalent integer of next non-space character, the token is advanced until next space
",62:"
static double tryParseDouble_assemble(
char sign,
double mantissa,
char exp_sign,
int exponent
)
Last step of tryParseDouble
",63:"
static unsigned char tryParseDouble_integer(
const char **curr,
const char *s_end,
char *sign,
int *integer
)
Part of tryParseDouble
",125:"
static unsigned char tryParseDouble(
const char *s,
const char *s_end,
double *result
)
Tries to parse a floating point number located at s.
",65:"
static unsigned char try_parse_float(
const char **token,
float *result
)
Tries to parse next float, if there\'s none fails
",66:"
static float parseFloat(
const char **token
)
Returns equivalent float of next non-space character, the token is advanced until next space
",67:"
static void parseFloat2(
float *x,
float *y,
const char **token
)
Parses the two next floats in given token
",68:"
static void parseFloat3(
float *x,
float *y,
float *z,
const char **token
)
Parses the three next floats in given token
",78:"
String to int hashtable
",73:"
Default starting size for tinyobj own hash table implementation tables
"}); \ No newline at end of file diff --git a/doc/classes/C/COMPATtinyobj_attrib_t-ToolTips.js b/doc/classes/C/COMPATtinyobj_attrib_t-ToolTips.js new file mode 100644 index 0000000..7e7c562 --- /dev/null +++ b/doc/classes/C/COMPATtinyobj_attrib_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({31:"
Indices for each vertex type, used for triplets in faces See: tinyobj_face_t
",59:"
static tinyobj_vertex_index_t parseRawTriple(
const char **token
)
Parses raw triplets of given tokens
",66:"
static float parseFloat(
const char **token
)
Returns equivalent float of next non-space character, the token is advanced until next space
",77:"
Invalid vertex index used when referencing vertices in couples/tuples
",125:"
static unsigned char tryParseDouble(
const char *s,
const char *s_end,
double *result
)
Tries to parse a floating point number located at s.
"}); \ No newline at end of file diff --git a/doc/classes/C/COMPATtinyobj_attrib_t.html b/doc/classes/C/COMPATtinyobj_attrib_t.html new file mode 100644 index 0000000..dfdc04c --- /dev/null +++ b/doc/classes/C/COMPATtinyobj_attrib_t.html @@ -0,0 +1,174 @@ + + +COMPATtinyobj_attrib_t + + + + + + + +
+
COMPATtinyobj_attrib_t
+

Object attributes (deprecated)

Fields
vertices

Array of geometric vertices (x0, y0, z0, x1, y1, z1, ...)

num_vertices

Number of vertices in 'vertices' (the actual array length is num_vertices*3)

normals

Array of vertex normals (i0, j0, k0, i1, j1, k1, ...)

num_normals

Number of vertices in 'normals' (the actual array length is num_normals*3)

texcoords

Array of  texture vertices (u0, w0, u1, w1, ...)

num_texcoords

Number of vertices in 'texcoords' (the actual array length is num_normals*2)

faces

Array of faces (containing tinyobj_vertex_index_t information)

num_faces

Length of 'faces'

face_num_verts

Array of number of vertices in each face (3 for triangulated faces)

num_face_num_verts

Total number of triangles in this object (length of face_num_verts)

material_ids

Array with the id of the material for each face (length is num_faces)

+
+ +
+
String handling
+
+ +
+
String handling macros
+
IS_SPACE

Is this character a spacing character ' ' or '\t'

IS_DIGIT

Is this character a digit

IS_NEW_LINE

Is this character a new line character '\r','\n','\0'

+
+ +
+
is_line_ending
+
static int is_line_ending(
const char *p,
size_t i,
size_t end_i
)
+

Is given line ending in this character?

Returns

True if line is ending

+
+ +
+
skip_space
+
static void skip_space(
const char **token
)
+

Skips the next spacing characters in given token

+
+ +
+
skip_space_and_cr
+
static void skip_space_and_cr(
const char **token
)
+

Skips the next spacing characters and also carriage return in given token

+
+ +
+
length_until_space
+
static size_t length_until_space(
const char *token,
size_t n
)
+

Calculates and returns the length until next space character in this token

Parameters
token
const char*

Token to be used

n
size_t

Maximum number of characters to count

Returns

Length until next space character

+
+ +
+
until_space
+
static int until_space(
const char *token
)
+

Skips the next spacing characters

'\0',' ', '\t', '\r'
+
+ +
+
until_space_cr_slash
+
static void until_space_cr_slash(
const char **token
)
+

Skips the next characters in given token

'\0','/', ' ', '\t', '\r'
+
+ +
+
length_until_newline_comment_space
+
static size_t length_until_newline_comment_space(
const char *token,
size_t n
)
+

Returns the length until the next characters:

\n \r\n \0 ' ' \t #
Parameters
token
const char*

Buffer

n
size_t

Maximum number of characters to count

Returns

Length until next character

+
+ +
+
length_until_line_feed
+
static size_t length_until_line_feed(
const char *token,
size_t n
)
+

Returns the length until the next line feed

Assumes token[n-1] = '\0'

Parameters
token
const char*

Buffer

n
size_t

Maximum number of characters to count

+
+ +
+
strdup_ml
+
static char *strdup_ml(
const char *s,
size_t max_length
)
+

Duplicates 'max_length' characters of given string (strdup with max length specified)

Parameters
s
const char*

String to be duplicated

max_length
size_t

Maximum length to be duplicated

Returns

Duplicated string (should be freed by the caller)

+
+ +
+
strndup
+
char *strndup(
const char *s,
size_t len
)
+

strndup implementation for non-GNU compliant compilers

+
+ +
+
dynamic_fgets
+
static char *dynamic_fgets(
char **buf,
int *size,
FILE *file
)
+

fgets with a dynamic buffer

+
+ +
+
Triplet handling
+
+ +
+
fixIndex
+
static int fixIndex(
int idx,
size_t n
)
+

Converts given absolute index, from triplet to zero-base, supports relative indices

See
Parameters
idx
int

Index to be converted

n
size_t

Position of this couple/tuple regarding to the vertex type of this index

Returns
+
+ +
+
parseRawTriple
+
static tinyobj_vertex_index_t parseRawTriple(
const char **token
)
+

Parses raw triplets of given tokens

v, v/vt/vn, v//vn, v/vt
Valid triplets:
<x> 1//1
<x> 1//1 2//2 3//3 4//4
<x> 1/1/1 2/2/2 3/3/3 4/4/4
The following are examples of illegal statements
<x> 1/1/1 2/2/2 3//3 4//4
<x> 1/ 1/1 2/2/2 3/3/3 4/4/4
Parameters
token
const char**

Token to parse

Returns

Indices parsed from given token, if one of the indices is not present it's equal to TINYOBJ_INVALID_INDEX

+
+ +
+
Integer/Double/Float handling
+
+ +
+
parseInt
+
static int parseInt(
const char **token
)
+

Returns equivalent integer of next non-space character, the token is advanced until next space

+
+ +
+
tryParseDouble_assemble
+
static double tryParseDouble_assemble(
char sign,
double mantissa,
char exp_sign,
int exponent
)
+

Last step of tryParseDouble

Assembles given information into double

Parameters
sign
char

Sign of this double

mantissa
double

Mantissa

exp_sign
char

Exponent sign

exponent
int

Exponent

Returns

Assembled double

+
+ +
+
tryParseDouble_integer
+
static unsigned char tryParseDouble_integer(
const char **curr,
const char *s_end,
char *sign,
int *integer
)
+

Part of tryParseDouble

Parses integer part of a double (advances curr)

Parameters
curr
const char**

Current position in a buffer

s_end
const char*

End of the buffer

sign
char*

[out] Sign to be filled

integer
int*

[out] Integer to be filled

Returns

True integer was successfuly parsed, false if nothing was read

+
+ +
+
tryParseDouble
+
static unsigned char tryParseDouble(
const char *s,
const char *s_end,
double *result
)
+

Tries to parse a floating point number located at s.

Parses the following EBNF grammar:
sign = "+" | "-" ;
END = ? anything not in digit ?
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
integer = [sign] , digit , {digit} ;
decimal = integer , ["." , integer] ;
float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ;
Valid strings are for example:
-0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2

The function is greedy and will parse until any of the following happens:

The following situations triggers a failure:

Parameters
s
const char*

String to be parsed

s_end
const char*

Location in the string where reading should halt, e.g. the end of

the string result

[out] Parsed double

Returns If the parsing is a success, result is set to the parsed value and true is returned.

+
+ +
+
try_parse_float
+
static unsigned char try_parse_float(
const char **token,
float *result
)
+

Tries to parse next float, if there's none fails

Parameters
token
const char**

Buffer to be read

result
float*

[out] Result, not set if return is false

Returns

If the parsing is a success, result is set to the parsed value and true is returned.

+
+ +
+
parseFloat
+
static float parseFloat(
const char **token
)
+

Returns equivalent float of next non-space character, the token is advanced until next space

+
+ +
+
parseFloat2
+
static void parseFloat2(
float *x,
float *y,
const char **token
)
+

Parses the two next floats in given token

See

parseFloat

+
+ +
+
parseFloat3
+
static void parseFloat3(
float *x,
float *y,
float *z,
const char **token
)
+

Parses the three next floats in given token

See

parseFloat

+
+ +
+
TINYOBJ hashtable implementation
+

String to int hashtable

+
+ +
+
Hash table return codes
+
TINYOBJ_HASH_TABLE_SUCCESS

Success

TINYOBJ_HASH_TABLE_ERROR

Failure

+
+ +
+
TINYOBJ_HASH_TABLE_DEFAULT_SIZE
+

Default starting size for tinyobj own hash table implementation tables

+
+ + \ No newline at end of file diff --git a/doc/classes/C/Command-Summary.js b/doc/classes/C/Command-Summary.js new file mode 100644 index 0000000..4fca7df --- /dev/null +++ b/doc/classes/C/Command-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:Command","Command");NDSummary.OnSummaryLoaded("CClass:Command",[["C/C++","C"]],[["Structs","Struct"]],[[118,0,0,"Command"]]); \ No newline at end of file diff --git a/doc/classes/C/Command-SummaryToolTips.js b/doc/classes/C/Command-SummaryToolTips.js new file mode 100644 index 0000000..1af055f --- /dev/null +++ b/doc/classes/C/Command-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:Command",{118:"
Command information used to parse obj files <tinyobj_parse_obj_line>
"}); \ No newline at end of file diff --git a/doc/classes/C/Command-ToolTips.js b/doc/classes/C/Command-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/Command-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/Command.html b/doc/classes/C/Command.html new file mode 100644 index 0000000..07e66c1 --- /dev/null +++ b/doc/classes/C/Command.html @@ -0,0 +1,16 @@ + + +Command + + + + + + + +
+
Command
+

Command information used to parse obj files <tinyobj_parse_obj_line>

Fields
type

Command

info

Specific command information

+
+ + \ No newline at end of file diff --git a/doc/classes/C/Command/s_group_information-Summary.js b/doc/classes/C/Command/s_group_information-Summary.js new file mode 100644 index 0000000..f145162 --- /dev/null +++ b/doc/classes/C/Command/s_group_information-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:Command.s_group_information","s_group_information");NDSummary.OnSummaryLoaded("CClass:Command.s_group_information",[["C/C++","C"]],[["Structs","Struct"]],[[122,0,0,"Command.​s_group_information"]]); \ No newline at end of file diff --git a/doc/classes/C/Command/s_group_information-SummaryToolTips.js b/doc/classes/C/Command/s_group_information-SummaryToolTips.js new file mode 100644 index 0000000..a82f1c7 --- /dev/null +++ b/doc/classes/C/Command/s_group_information-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:Command.s_group_information",{122:"
Grouping and Display/Render attributes
"}); \ No newline at end of file diff --git a/doc/classes/C/Command/s_group_information-ToolTips.js b/doc/classes/C/Command/s_group_information-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/Command/s_group_information-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/Command/s_group_information.html b/doc/classes/C/Command/s_group_information.html new file mode 100644 index 0000000..a54a38d --- /dev/null +++ b/doc/classes/C/Command/s_group_information.html @@ -0,0 +1,16 @@ + + +s_group_information + + + + + + + +
+
Command.​s_group_information
+

Grouping and Display/Render attributes

Fields
Name

Name of group

len

Group name length

+
+ + \ No newline at end of file diff --git a/doc/classes/C/Command/u_information-Summary.js b/doc/classes/C/Command/u_information-Summary.js new file mode 100644 index 0000000..0814b16 --- /dev/null +++ b/doc/classes/C/Command/u_information-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:Command.u_information","u_information");NDSummary.OnSummaryLoaded("CClass:Command.u_information",[["C/C++","C"]],[["Structs","Struct"]],[[85,0,0,"Command.​u_information"]]); \ No newline at end of file diff --git a/doc/classes/C/Command/u_information-SummaryToolTips.js b/doc/classes/C/Command/u_information-SummaryToolTips.js new file mode 100644 index 0000000..d262228 --- /dev/null +++ b/doc/classes/C/Command/u_information-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:Command.u_information",{85:"
Specific command information
"}); \ No newline at end of file diff --git a/doc/classes/C/Command/u_information-ToolTips.js b/doc/classes/C/Command/u_information-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/Command/u_information-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/Command/u_information.html b/doc/classes/C/Command/u_information.html new file mode 100644 index 0000000..13c17f4 --- /dev/null +++ b/doc/classes/C/Command/u_information.html @@ -0,0 +1,16 @@ + + +u_information + + + + + + + +
+
Command.​u_information
+

Specific command information

Fields
v

Geometric vertex <COMMAND_V>

vn

Vertex normal <COMMAND_VN>

vt

Texture vertex <COMMAND_VT>

vp

Parameter space vertex <COMMAND_VP>

f

Face <COMMAND_F>

l

Line <COMMAND_L>

p

Point <COMMAND_P>

g

Group <COMMAND_G>

o

Object <COMMAND_O>

usemtl

Use material <COMMAND_USEMTL>

mtllib

Material lib (file) <COMMAND_MTLLIB>

smoothing_id

Smoothing group <COMMAND_S>

See

<CommandType>

+
+ + \ No newline at end of file diff --git a/doc/classes/C/CommandInformation-Summary.js b/doc/classes/C/CommandInformation-Summary.js new file mode 100644 index 0000000..057f0fd --- /dev/null +++ b/doc/classes/C/CommandInformation-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:CommandInformation","CommandInformation");NDSummary.OnSummaryLoaded("CClass:CommandInformation",[["C/C++","C"]],[["Structs","Struct"]],[[119,0,0,"CommandInformation"]]); \ No newline at end of file diff --git a/doc/classes/C/CommandInformation-SummaryToolTips.js b/doc/classes/C/CommandInformation-SummaryToolTips.js new file mode 100644 index 0000000..532f678 --- /dev/null +++ b/doc/classes/C/CommandInformation-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:CommandInformation",{119:"
General information regarding the commands of a given file
"}); \ No newline at end of file diff --git a/doc/classes/C/CommandInformation-ToolTips.js b/doc/classes/C/CommandInformation-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/CommandInformation-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/CommandInformation.html b/doc/classes/C/CommandInformation.html new file mode 100644 index 0000000..848b211 --- /dev/null +++ b/doc/classes/C/CommandInformation.html @@ -0,0 +1,16 @@ + + +CommandInformation + + + + + + + +
+
CommandInformation
+

General information regarding the commands of a given file

Fields
command_list

Array of commands

mtllib_line_index

Index of MLLIB in command list (-1 no command)

count

command_list count

counter

Counter of command types

+
+ + \ No newline at end of file diff --git a/doc/classes/C/CommandInformation/s_counter-Summary.js b/doc/classes/C/CommandInformation/s_counter-Summary.js new file mode 100644 index 0000000..5ad1b70 --- /dev/null +++ b/doc/classes/C/CommandInformation/s_counter-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:CommandInformation.s_counter","s_counter");NDSummary.OnSummaryLoaded("CClass:CommandInformation.s_counter",[["C/C++","C"]],[["Functions","Function"],["Groups","Group"],["Structs","Struct"]],[[84,0,2,"CommandInformation.​s_counter"],[69,0,1,"Object handling (.obj)","Object_handling"],[146,0,0,"tinyobj_obj_free_point","tinyobj_obj_free_point"],[147,0,0,"tinyobj_obj_parse_point","tinyobj_obj_parse_point"],[148,0,0,"tinyobj_triplet_list_grow","tinyobj_triplet_list_grow"],[149,0,0,"tinyobj_triplet_list_new","tinyobj_triplet_list_new"],[150,0,0,"tinyobj_obj_free_line","tinyobj_obj_free_line"],[151,0,0,"tinyuobj_obj_parse_line","tinyuobj_obj_parse_line"],[152,0,0,"tinyobj_obj_free_face","tinyobj_obj_free_face"],[83,0,0,"tinyobj_obj_parse_face","tinyobj_obj_parse_face"],[154,0,0,"tinyobj_obj_parse_vertex","tinyobj_obj_parse_vertex"],[138,0,0,"tinyobj_parse_obj_line","tinyobj_parse_obj_line"],[139,0,0,"tinyobj_parse_obj_line_traverse","tinyobj_parse_obj_line_traverse"],[157,0,0,"tinyobj_command_info_free","tinyobj_command_info_free"],[158,0,0,"tinyobj_shape_construct","tinyobj_shape_construct"],[159,0,0,"tinyobj_shape_free","tinyobj_shape_free"],[160,0,0,"tinyobj_attrib_construct","tinyobj_attrib_construct"],[54,0,1,"Aplication Programming Interface (.obj)","Aplication_Programming_Interface"],[161,0,0,"tinyobj_attrib_free","tinyobj_attrib_free"],[162,0,0,"tinyobj_attrib_init","tinyobj_attrib_init"],[140,0,0,"tinyobj_parse_obj","tinyobj_parse_obj"],[56,0,1,"Compatibility with older versions (deprecated)","Compatibility_with_older_versions"],[164,0,0,"tinyobj_attrib_free_compat","tinyobj_attrib_free_compat"],[39,0,0,"tinyobj_new2old","tinyobj_new2old"]]); \ No newline at end of file diff --git a/doc/classes/C/CommandInformation/s_counter-SummaryToolTips.js b/doc/classes/C/CommandInformation/s_counter-SummaryToolTips.js new file mode 100644 index 0000000..5f6c67b --- /dev/null +++ b/doc/classes/C/CommandInformation/s_counter-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:CommandInformation.s_counter",{84:"
Counter of command types
",146:"
static void tinyobj_obj_free_point(
tinyobj_point_t *p
)
Frees allocated data of a given point
",147:"
static int tinyobj_obj_parse_point(
Command *command,
const char **token
)
Parses a point from token (\'p\')
",148:"
unsigned char tinyobj_triplet_list_grow(
tinyobj_vertex_index_t **list,
size_t new_len
)
Grows the given triplet list to a new size If the growth fails the list is unchanged
",149:"
static tinyobj_vertex_index_t *tinyobj_triplet_list_new(
size_t len
)
Allocates memory for a new triplet list
",150:"
static void tinyobj_obj_free_line(
tinyobj_line_t *l
)
Frees allocated data of a given line
",151:"
Parses a line from token (\'l\')
",152:"
static void tinyobj_obj_free_face(
tinyobj_face_t *f
)
Frees allocated data of a given face
",83:"
static int tinyobj_obj_parse_face(
Command *command,
const char **token,
int triangulate
)
Parses a face from token (\'f\') and fills given command with face information
",154:"
static int tinyobj_obj_parse_vertex(
Command *command,
const char **token
)
Parses a vertex from token (\'v\')
",138:"
static int tinyobj_parse_obj_line(
CommandInformation *command_info,
int pos,
const char *p,
size_t p_len,
int flags
)
Parses line of an .obj file
",139:"
static int tinyobj_parse_obj_line_traverse(
const char *buf,
size_t len,
CommandInformation *command_info,
unsigned int flags
)
Traverses and parses all lines of given buffer
",157:"
static void tinyobj_command_info_free(
CommandInformation *command_info
)
Frees given command information
",158:"
static void tinyobj_shape_construct(
tinyobj_shape_t **shapes,
unsigned int *num_shapes,
CommandInformation *command_info
)
Constructs shape information
",159:"
void tinyobj_shape_free(
tinyobj_shape_t *shapes,
unsigned int num_shapes
)
Frees shape data
",160:"
static void tinyobj_attrib_construct(
tinyobj_attrib_t *attrib,
CommandInformation *command_info,
tinyobj_material_table_t *material_table
)
Constructs attribute data with given information
",161:"
void tinyobj_attrib_free(
tinyobj_attrib_t *attrib
)
Frees attribute data
",162:"
static void tinyobj_attrib_init(
tinyobj_attrib_t *attrib
)
Initializes given attribute information to default values
",140:"
int tinyobj_parse_obj(
tinyobj_attrib_t *attrib,
tinyobj_shape_t **shapes,
unsigned int *num_shapes,
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *buf,
size_t len,
unsigned int flags
)
Parses .obj file
",164:"
void tinyobj_attrib_free_compat(
COMPATtinyobj_attrib_t *attrib
)
Frees given attribute
",39:"
int tinyobj_new2old(
tinyobj_attrib_t *attrib,
COMPATtinyobj_attrib_t *out_attrib
)
Converts new attribute format to the old one This expects that the faces were triangulated
"}); \ No newline at end of file diff --git a/doc/classes/C/CommandInformation/s_counter-ToolTips.js b/doc/classes/C/CommandInformation/s_counter-ToolTips.js new file mode 100644 index 0000000..670af77 --- /dev/null +++ b/doc/classes/C/CommandInformation/s_counter-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({4:"
Should the faces be triangulated upon loading When triangulating we parse the vertices as if they were part of a triangle fan, so every three indices the next is always the first triplet of this face
",5:"
Material attribute .mtl format
",8:"
Success
",10:"
Memory failure
",11:"
Empty file
",13:"
Invalid parameter (function)
",14:"
Unknown parameter for object/material
",15:"
Malformed parameter for object/material
",31:"
Indices for each vertex type, used for triplets in faces See: tinyobj_face_t
",32:"
Point (p) Specifies a point element and its vertex
",33:"
Line (l) Specifies a line and its vertex reference numbers
",35:"
Face (f) Specifies a face element and its vertex reference number
",37:"
Object attributes .obj format
",38:"
Shapes contained in a given attribute
",40:"
Object attributes (deprecated)
",75:"
Hash table used in tinyobj\'s own hash table implementation
",118:"
Command information used to parse obj files <tinyobj_parse_obj_line>
",119:"
General information regarding the commands of a given file
"}); \ No newline at end of file diff --git a/doc/classes/C/CommandInformation/s_counter.html b/doc/classes/C/CommandInformation/s_counter.html new file mode 100644 index 0000000..41e65ee --- /dev/null +++ b/doc/classes/C/CommandInformation/s_counter.html @@ -0,0 +1,147 @@ + + +s_counter + + + + + + + +
+
CommandInformation.​s_counter
+

Counter of command types

Fields
v

Count of geometric vertices

vn

Count of vertex normals

vt

Count of texture vertices

vp

Count of parameter space vertices

f

Count of faces

l

Count of lines

p

Count of points

shapes

Shapes

+
+ +
+
Object handling (.obj)
+
+ +
+
tinyobj_obj_free_point
+
static void tinyobj_obj_free_point(
tinyobj_point_t *p
)
+

Frees allocated data of a given point

+
+ +
+
tinyobj_obj_parse_point
+
static int tinyobj_obj_parse_point(
Command *command,
const char **token
)
+

Parses a point from token ('p')

Parameters
command

Command information to be filled

token
const char**

Token to be parsed

Returns
+
+ +
+
tinyobj_triplet_list_grow
+
unsigned char tinyobj_triplet_list_grow(
tinyobj_vertex_index_t **list,
size_t new_len
)
+

Grows the given triplet list to a new size If the growth fails the list is unchanged

Parameters
list

List to grow

new_len
size_t

New length

Returns

True if successful, false otherwise

+
+ +
+
tinyobj_triplet_list_new
+
static tinyobj_vertex_index_t *tinyobj_triplet_list_new(
size_t len
)
+

Allocates memory for a new triplet list

Parameters
len
size_t

Initial length of list

Returns

Pointer to new list when successful, NULL if failure

+
+ +
+
tinyobj_obj_free_line
+
static void tinyobj_obj_free_line(
tinyobj_line_t *l
)
+

Frees allocated data of a given line

+
+ +
+
tinyuobj_obj_parse_line
+

Parses a line from token ('l')

Parameters
command

Command information to be filled

token

Token to be parsed

Returns
+
+ +
+
tinyobj_obj_free_face
+
static void tinyobj_obj_free_face(
tinyobj_face_t *f
)
+

Frees allocated data of a given face

+
+ +
+
tinyobj_obj_parse_face
+
static int tinyobj_obj_parse_face(
Command *command,
const char **token,
int triangulate
)
+

Parses a face from token ('f') and fills given command with face information

Parameters
command

Command information to be filled

token
const char**

Token to be parsed

triangulate
int

(bool) Should this face be triangulated? TINYOBJ_FLAG_TRIANGULATE

Returns
+
+ +
+
tinyobj_obj_parse_vertex
+
static int tinyobj_obj_parse_vertex(
Command *command,
const char **token
)
+

Parses a vertex from token ('v')

v, vn, vt, vp
Parameters
command

Command information to be filled

token
const char**

Token to be parsed

Returns
+
+ +
+
tinyobj_parse_obj_line
+
static int tinyobj_parse_obj_line(
CommandInformation *command_info,
int pos,
const char *p,
size_t p_len,
int flags
)
+

Parses line of an .obj file

Parameters
command_info

Command information list

pos
int

Current position in command information

p
const char*

String containing line

p_len
size_t

Line length

flags
int

Reading flags

Returns
+
+ +
+
tinyobj_parse_obj_line_traverse
+
static int tinyobj_parse_obj_line_traverse(
const char *buf,
size_t len,
CommandInformation *command_info,
unsigned int flags
)
+

Traverses and parses all lines of given buffer

Parameters
buf
const char*

Buffer to be parsed

len
size_t

Buffer length

command_info

Command information to be filled

flags
unsigned int

Parsing flags

Returns
+
+ +
+
tinyobj_command_info_free
+
static void tinyobj_command_info_free(
CommandInformation *command_info
)
+

Frees given command information

+
+ +
+
tinyobj_shape_construct
+
static void tinyobj_shape_construct(
tinyobj_shape_t **shapes,
unsigned int *num_shapes,
CommandInformation *command_info
)
+

Constructs shape information

Parameters
shapes

[in/out] Pointer to be filled

num_shapes
unsigned int*

[out] Length of shapes

command_info

Information used to construct the shapes

+
+ +
+
tinyobj_shape_free
+
void tinyobj_shape_free(
tinyobj_shape_t *shapes,
unsigned int num_shapes
)
+

Frees shape data

Parameters
shapes

Shape information to be freed

num_shapes
unsigned int

Length of shapes

+
+ +
+
tinyobj_attrib_construct
+
static void tinyobj_attrib_construct(
tinyobj_attrib_t *attrib,
CommandInformation *command_info,
tinyobj_material_table_t *material_table
)
+

Constructs attribute data with given information

Parameters
attrib

[in/out] Attribute to be filled

command_info

Information used to fill attrib

material_table

Material table used (can be NULL)

+
+ +
+
Aplication Programming Interface (.obj)
+
+ +
+
tinyobj_attrib_free
+
void tinyobj_attrib_free(
tinyobj_attrib_t *attrib
)
+

Frees attribute data

+
+ +
+
tinyobj_attrib_init
+
static void tinyobj_attrib_init(
tinyobj_attrib_t *attrib
)
+

Initializes given attribute information to default values

+
+ +
+
tinyobj_parse_obj
+
int tinyobj_parse_obj(
tinyobj_attrib_t *attrib,
tinyobj_shape_t **shapes,
unsigned int *num_shapes,
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *buf,
size_t len,
unsigned int flags
)
+

Parses .obj file

Parameters
attrib

[in/out] Attributes to be filled

shapes

[in/out] Shapes to be filled

num_shapes
unsigned int*

[in/out] Length of shapes

materials_out

[in/out] Materials to be filled

num_materials_out
unsigned int*

[in/out] Length of materials

buf
const char*

Buffer to be read

len
size_t

Buffer length

flags
unsigned int

Parsing flags

Returns
+
+ +
+
Compatibility with older versions (deprecated)
+
+ +
+
tinyobj_attrib_free_compat
+
void tinyobj_attrib_free_compat(
COMPATtinyobj_attrib_t *attrib
)
+

Frees given attribute

+
+ +
+
tinyobj_new2old
+
int tinyobj_new2old(
tinyobj_attrib_t *attrib,
COMPATtinyobj_attrib_t *out_attrib
)
+

Converts new attribute format to the old one This expects that the faces were triangulated

Parameters
attrib

[in] Attribute to be converted

out_attrib

[out] Attribute to be filled

Returns
+
+ + \ No newline at end of file diff --git a/doc/classes/C/hash_table_entry_t-Summary.js b/doc/classes/C/hash_table_entry_t-Summary.js new file mode 100644 index 0000000..ea76b12 --- /dev/null +++ b/doc/classes/C/hash_table_entry_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:hash_table_entry_t","hash_table_entry_t");NDSummary.OnSummaryLoaded("CClass:hash_table_entry_t",[["C/C++","C"]],[["Structs","Struct"]],[[74,0,0,"hash_table_entry_t"]]); \ No newline at end of file diff --git a/doc/classes/C/hash_table_entry_t-SummaryToolTips.js b/doc/classes/C/hash_table_entry_t-SummaryToolTips.js new file mode 100644 index 0000000..cbe3c27 --- /dev/null +++ b/doc/classes/C/hash_table_entry_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:hash_table_entry_t",{74:"
Entries used in tinyobj\'s own hash table implementation
"}); \ No newline at end of file diff --git a/doc/classes/C/hash_table_entry_t-ToolTips.js b/doc/classes/C/hash_table_entry_t-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/hash_table_entry_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/hash_table_entry_t.html b/doc/classes/C/hash_table_entry_t.html new file mode 100644 index 0000000..440d0f7 --- /dev/null +++ b/doc/classes/C/hash_table_entry_t.html @@ -0,0 +1,16 @@ + + +hash_table_entry_t + + + + + + + +
+
hash_table_entry_t
+

Entries used in tinyobj's own hash table implementation

Fields
hash

Hash value

filled

Is this entry filled

value

Value

next

Next entry

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_attrib_t-Summary.js b/doc/classes/C/tinyobj_attrib_t-Summary.js new file mode 100644 index 0000000..9b9933b --- /dev/null +++ b/doc/classes/C/tinyobj_attrib_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_attrib_t","tinyobj_attrib_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_attrib_t",[["C/C++","C"]],[["Structs","Struct"]],[[37,0,0,"tinyobj_attrib_t"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_attrib_t-SummaryToolTips.js b/doc/classes/C/tinyobj_attrib_t-SummaryToolTips.js new file mode 100644 index 0000000..c3c6ec6 --- /dev/null +++ b/doc/classes/C/tinyobj_attrib_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_attrib_t",{37:"
Object attributes .obj format
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_attrib_t-ToolTips.js b/doc/classes/C/tinyobj_attrib_t-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/tinyobj_attrib_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_attrib_t.html b/doc/classes/C/tinyobj_attrib_t.html new file mode 100644 index 0000000..d80c541 --- /dev/null +++ b/doc/classes/C/tinyobj_attrib_t.html @@ -0,0 +1,16 @@ + + +tinyobj_attrib_t + + + + + + + +
+
tinyobj_attrib_t
+

Object attributes .obj format

Fields
v

Geometric vertices

v_count

Geometric vertex count

vn

Vertex normals

vn_count

Vertex normal count

vt

Texture vertices

vt_count

Texture vertex count

vp

Parameter space vertices

vp_count

Parameter space vertex count

f

Object faces

f_count

Face count

triangle_count_total

Total count of triangles

l

Lines

l_count

Line count

p

Points

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_coefficient_t-Summary.js b/doc/classes/C/tinyobj_coefficient_t-Summary.js new file mode 100644 index 0000000..0b5d64c --- /dev/null +++ b/doc/classes/C/tinyobj_coefficient_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_coefficient_t","tinyobj_coefficient_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_coefficient_t",[["C/C++","C"]],[["Structs","Struct"]],[[36,0,0,"tinyobj_coefficient_t"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_coefficient_t-SummaryToolTips.js b/doc/classes/C/tinyobj_coefficient_t-SummaryToolTips.js new file mode 100644 index 0000000..f79002f --- /dev/null +++ b/doc/classes/C/tinyobj_coefficient_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_coefficient_t",{36:"
RGB Color coefficient information used in materials tinyobj_material_t
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_coefficient_t-ToolTips.js b/doc/classes/C/tinyobj_coefficient_t-ToolTips.js new file mode 100644 index 0000000..de02670 --- /dev/null +++ b/doc/classes/C/tinyobj_coefficient_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({5:"
Material attribute .mtl format
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_coefficient_t.html b/doc/classes/C/tinyobj_coefficient_t.html new file mode 100644 index 0000000..4593432 --- /dev/null +++ b/doc/classes/C/tinyobj_coefficient_t.html @@ -0,0 +1,16 @@ + + +tinyobj_coefficient_t + + + + + + + +
+
tinyobj_coefficient_t
+

RGB Color coefficient information used in materials tinyobj_material_t

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_face_t-Summary.js b/doc/classes/C/tinyobj_face_t-Summary.js new file mode 100644 index 0000000..1395a54 --- /dev/null +++ b/doc/classes/C/tinyobj_face_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_face_t","tinyobj_face_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_face_t",[["C/C++","C"]],[["Structs","Struct"]],[[35,0,0,"tinyobj_face_t"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_face_t-SummaryToolTips.js b/doc/classes/C/tinyobj_face_t-SummaryToolTips.js new file mode 100644 index 0000000..e0e2580 --- /dev/null +++ b/doc/classes/C/tinyobj_face_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_face_t",{35:"
Face (f) Specifies a face element and its vertex reference number
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_face_t-ToolTips.js b/doc/classes/C/tinyobj_face_t-ToolTips.js new file mode 100644 index 0000000..17b2d7a --- /dev/null +++ b/doc/classes/C/tinyobj_face_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({77:"
Invalid vertex index used when referencing vertices in couples/tuples
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_face_t.html b/doc/classes/C/tinyobj_face_t.html new file mode 100644 index 0000000..cb7d0cc --- /dev/null +++ b/doc/classes/C/tinyobj_face_t.html @@ -0,0 +1,16 @@ + + +tinyobj_face_t + + + + + + + +
+
tinyobj_face_t
+

Face (f) Specifies a face element and its vertex reference number

f  v1/vt1/vn1   v2/vt2/vn2
fo (deprecated)
Fields
triplet list

A list of triplets contained in this face

v  Geometric vertex (minimum of 3)

vt Texture vertex (optional)

vn Vertex normal (optional)

When an index is empty it is equal to TINYOBJ_INVALID_INDEX

count

Count of triplets

length

Length of triplet list

triangle_count

Number of triangles in this face

material_id

Material to be applied to this face (defaults to -1)

smoothing_id

Smoothing group to be applied to this face (defaults to 0)

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_line_t-Summary.js b/doc/classes/C/tinyobj_line_t-Summary.js new file mode 100644 index 0000000..0bd177a --- /dev/null +++ b/doc/classes/C/tinyobj_line_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_line_t","tinyobj_line_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_line_t",[["C/C++","C"]],[["Structs","Struct"]],[[33,0,0,"tinyobj_line_t"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_line_t-SummaryToolTips.js b/doc/classes/C/tinyobj_line_t-SummaryToolTips.js new file mode 100644 index 0000000..a366101 --- /dev/null +++ b/doc/classes/C/tinyobj_line_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_line_t",{33:"
Line (l) Specifies a line and its vertex reference numbers
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_line_t-ToolTips.js b/doc/classes/C/tinyobj_line_t-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/tinyobj_line_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_line_t.html b/doc/classes/C/tinyobj_line_t.html new file mode 100644 index 0000000..8596857 --- /dev/null +++ b/doc/classes/C/tinyobj_line_t.html @@ -0,0 +1,16 @@ + + +tinyobj_line_t + + + + + + + +
+
tinyobj_line_t
+

Line (l) Specifies a line and its vertex reference numbers

l  v1/vt1   v2/vt2   v3/vt3
Fields
couple_list

List of couples contained in this line

count

Count of couples

length

Total length of couple list

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_line_t/s_line_vertex_index-Summary.js b/doc/classes/C/tinyobj_line_t/s_line_vertex_index-Summary.js new file mode 100644 index 0000000..261ed49 --- /dev/null +++ b/doc/classes/C/tinyobj_line_t/s_line_vertex_index-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_line_t.s_line_vertex_index","s_line_vertex_index");NDSummary.OnSummaryLoaded("CClass:tinyobj_line_t.s_line_vertex_index",[["C/C++","C"]],[["Structs","Struct"]],[[26,0,0,"tinyobj_line_t.​s_line_vertex_index"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_line_t/s_line_vertex_index-SummaryToolTips.js b/doc/classes/C/tinyobj_line_t/s_line_vertex_index-SummaryToolTips.js new file mode 100644 index 0000000..38ff58f --- /dev/null +++ b/doc/classes/C/tinyobj_line_t/s_line_vertex_index-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_line_t.s_line_vertex_index",{26:"
List of couples
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_line_t/s_line_vertex_index-ToolTips.js b/doc/classes/C/tinyobj_line_t/s_line_vertex_index-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/tinyobj_line_t/s_line_vertex_index-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_line_t/s_line_vertex_index.html b/doc/classes/C/tinyobj_line_t/s_line_vertex_index.html new file mode 100644 index 0000000..4b46a71 --- /dev/null +++ b/doc/classes/C/tinyobj_line_t/s_line_vertex_index.html @@ -0,0 +1,16 @@ + + +s_line_vertex_index + + + + + + + +
+
tinyobj_line_t.​s_line_vertex_index
+

List of couples

Fields
v_idx

Geometric vertex

vt_idx

Texture vertex (optional)

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_material_t-Summary.js b/doc/classes/C/tinyobj_material_t-Summary.js new file mode 100644 index 0000000..30dc6e5 --- /dev/null +++ b/doc/classes/C/tinyobj_material_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_material_t","tinyobj_material_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_material_t",[["C/C++","C"]],[["Structs","Struct"]],[[5,0,0,"tinyobj_material_t"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_material_t-SummaryToolTips.js b/doc/classes/C/tinyobj_material_t-SummaryToolTips.js new file mode 100644 index 0000000..3027c41 --- /dev/null +++ b/doc/classes/C/tinyobj_material_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_material_t",{5:"
Material attribute .mtl format
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_material_t-ToolTips.js b/doc/classes/C/tinyobj_material_t-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/tinyobj_material_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_material_t.html b/doc/classes/C/tinyobj_material_t.html new file mode 100644 index 0000000..7643946 --- /dev/null +++ b/doc/classes/C/tinyobj_material_t.html @@ -0,0 +1,16 @@ + + +tinyobj_material_t + + + + + + + +
+
tinyobj_material_t
+

Material attribute .mtl format

Fields
name

Material name

ambient

Ambient color coefficient (reflectivity)

diffuse

Diffuse color coefficient (reflectivity)

specular

Specular color coefficient (reflectivity)

transmittance

Transmittance color coefficient (reflectivity)

emission

Emission color coefficient (reflectivity)

shininess

Specular exponent

ior

Index Of Refraction (ior) 'optical density'

dissolve

Non-transparency to be alpha 'dissolve' (0.0f transparent-1.0f opaque)

illum

Illumination model (0-10)

ambient_texname

map_Ka

diffuse_texname

map_Kd

specular_texname

map_Ks

specular_highlight_texname

map_Ns

bump_texname

map_bump, bump

displacement_texname

disp

alpha_texname

map_d

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_material_table_t-Summary.js b/doc/classes/C/tinyobj_material_table_t-Summary.js new file mode 100644 index 0000000..8f98910 --- /dev/null +++ b/doc/classes/C/tinyobj_material_table_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_material_table_t","tinyobj_material_table_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_material_table_t",[["C/C++","C"]],[["Constants","Constant"],["Enums","Enumeration"],["Functions","Function"],["Groups","Group"],["Structs","Struct"]],[[75,0,4,"tinyobj_material_table_t"],[79,0,3,"TINYOBJ hashtable implementation","TINYOBJ_hashtable_implementation"],[126,0,2,"hash_djb2","hash_djb2"],[80,0,2,"create_hash_table","create_hash_table"],[128,0,2,"destroy_hash_table","destroy_hash_table"],[129,0,2,"hash_table_insert_value","hash_table_insert_value"],[130,0,2,"hash_table_insert","hash_table_insert"],[131,0,2,"hash_table_find","hash_table_find"],[132,0,2,"hash_table_maybe_grow","hash_table_maybe_grow"],[58,0,2,"hash_table_exists","hash_table_exists"],[81,0,2,"hash_table_set","hash_table_set"],[135,0,2,"hash_table_get","hash_table_get"],[86,0,3,"UTHash interface to tinyobj","UTHash_interface_to_tinyobj"],[87,0,4,"tinyobj_material_table_t"],[143,0,3,"UTHash interface to tinyobj","UTHash_interface_to_tinyobj(2)"],[88,0,0,"tinyobj_reserved","tinyobj_reserved"],[89,0,2,"tinyobj_hash_find","tinyobj_hash_find"],[90,0,2,"tinyobj_hash_add","tinyobj_hash_add"],[91,0,2,"tinyobj_hash_free","tinyobj_hash_free"],[92,0,2,"tinyobj_hash_init","tinyobj_hash_init"],[82,0,3,"Material handling (.mtl)","Material_handling"],[94,0,2,"initMaterial","initMaterial"],[95,0,2,"tinyobj_mtl_parse_map","tinyobj_mtl_parse_map"],[96,0,2,"tinyobj_mtl_parse_optical","tinyobj_mtl_parse_optical"],[97,0,2,"tinyobj_mtl_parse_color","tinyobj_mtl_parse_color"],[136,0,2,"tinyobj_parse_and_index_mtl_file","tinyobj_parse_and_index_mtl_file"],[46,0,3,"Aplication Programming Interface (.mtl)","Aplication_Programming_Interface"],[99,0,2,"tinyobj_parse_mtl_file","tinyobj_parse_mtl_file"],[100,0,2,"tinyobj_material_free","tinyobj_material_free"],[3,0,3,"Object handling (.obj)","Object_handling"],[102,0,1,"CommandType","CommandType"],[103,0,0,,"COMMAND_EMPTY"],[104,0,0,,"COMMAND_V"],[105,0,0,,"COMMAND_VN"],[106,0,0,,"COMMAND_VT"],[107,0,0,,"COMMAND_VP"],[108,0,0,,"COMMAND_F"],[109,0,0,,"COMMAND_P"],[110,0,0,,"COMMAND_L"],[111,0,0,,"COMMAND_G"],[112,0,0,,"COMMAND_O"],[113,0,0,,"COMMAND_S"],[114,0,0,,"COMMAND_USEMTL"],[115,0,0,,"COMMAND_MTLLIB"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_material_table_t-SummaryToolTips.js b/doc/classes/C/tinyobj_material_table_t-SummaryToolTips.js new file mode 100644 index 0000000..16cb10e --- /dev/null +++ b/doc/classes/C/tinyobj_material_table_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_material_table_t",{75:"
Hash table used in tinyobj\'s own hash table implementation
",79:"
String to int hashtable
",126:"
static unsigned long hash_djb2(
const unsigned char *str
)
Converts given string to hash
",80:"
static void create_hash_table(
size_t start_capacity,
tinyobj_material_table_t *hash_table
)
Creates a new hash table in \'hash_table\'
",128:"
static void destroy_hash_table(
tinyobj_material_table_t *hash_table
)
Finalizes given hash_table
",129:"
static int hash_table_insert_value(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
Subroutine of hash_table_insert Inserts given value in hash, uses quadratic probing
",130:"
static int hash_table_insert(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
Inserts given value in hash, calls hash_table_insert_value
",131:"
static hash_table_entry_t *hash_table_find(
unsigned long hash,
tinyobj_material_table_t *hash_table
)
Tries to find given hash in the table
",132:"
static void hash_table_maybe_grow(
size_t new_n,
tinyobj_material_table_t *hash_table
)
Grows given hash_table to new_n if new_n is less or equal to capacity
",58:"
static int hash_table_exists(
const char *name,
tinyobj_material_table_t *hash_table
)
Tries to find \'name\' in hash_table, returns true if successful
",81:"
static void hash_table_set(
const char *name,
size_t val,
tinyobj_material_table_t *hash_table
)
Inserts value into hash_table, in name; creates new entry if it doesn\'t exist
",135:"
static long hash_table_get(
const char *name,
tinyobj_material_table_t *hash_table
)
Returns value of entity with name, -1 when failing
",87:"
Material table
",88:"
Reserved key used by the hashtable implementation so the table isn\'t deleted
",89:"
static void tinyobj_hash_find(
tinyobj_material_table_t *table,
const char *name,
tinyobj_material_table_tEntry **entryOUT
)
Tries to find object with \'name\' as key
",90:"
static int tinyobj_hash_add(
tinyobj_material_table_t *table,
const char *name,
size_t length,
long value
)
Adds a material to the given material table If the material was already added its value is replaced
",91:"
static void tinyobj_hash_free(
tinyobj_material_table_t *table,
unsigned char bfree_name
)
Frees all entries of a given tinyobj_material_table_t
",92:"
static void tinyobj_hash_init(
tinyobj_material_table_t *table
)
Initialises given table, and adds a reserved key
",94:"
static void initMaterial(
tinyobj_material_t *material
)
Defaults given material
",95:"
static int tinyobj_mtl_parse_map(
tinyobj_material_t *material,
const char **token,
const char *line_end
)
Parses a texture name from token (\'map_\')
",96:"
static int tinyobj_mtl_parse_optical(
tinyobj_material_t *material,
const char **token
)
Parses an optical coefficient from token (\'N\')
",97:"
static int tinyobj_mtl_parse_color(
tinyobj_material_t *material,
const char **token
)
Parses a color coefficient from token (\'K\')
",136:"
static int tinyobj_parse_and_index_mtl_file(
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *filename,
tinyobj_material_table_t *material_table
)
Parses and indexes a given material file
",99:"
int tinyobj_parse_mtl_file(
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *filename
)
Parses a material file, see tinyobj_parse_and_index_mtl_file
",100:"
void tinyobj_material_free(
tinyobj_material_t *materials,
unsigned int num_materials
)
Frees material data
",102:"
Command identifiers used when parsing
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_material_table_t-ToolTips.js b/doc/classes/C/tinyobj_material_table_t-ToolTips.js new file mode 100644 index 0000000..ae10525 --- /dev/null +++ b/doc/classes/C/tinyobj_material_table_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({5:"
Material attribute .mtl format
",8:"
Success
",10:"
Memory failure
",12:"
Failed file operation
",14:"
Unknown parameter for object/material
",74:"
Entries used in tinyobj\'s own hash table implementation
",75:"
Hash table used in tinyobj\'s own hash table implementation
",126:"
static unsigned long hash_djb2(
const unsigned char *str
)
Converts given string to hash
",129:"
static int hash_table_insert_value(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
Subroutine of hash_table_insert Inserts given value in hash, uses quadratic probing
",130:"
static int hash_table_insert(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
Inserts given value in hash, calls hash_table_insert_value
",131:"
static hash_table_entry_t *hash_table_find(
unsigned long hash,
tinyobj_material_table_t *hash_table
)
Tries to find given hash in the table
",136:"
static int tinyobj_parse_and_index_mtl_file(
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *filename,
tinyobj_material_table_t *material_table
)
Parses and indexes a given material file
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_material_table_t.html b/doc/classes/C/tinyobj_material_table_t.html new file mode 100644 index 0000000..b956034 --- /dev/null +++ b/doc/classes/C/tinyobj_material_table_t.html @@ -0,0 +1,182 @@ + + +tinyobj_material_table_t + + + + + + + +
+
tinyobj_material_table_t
+

Hash table used in tinyobj's own hash table implementation

Fields
hashes

Hashes used

entries

Linked list of entries in this table

capacity

Total capacity of this table

n

Count of elements

+
+ +
+
TINYOBJ hashtable implementation
+

String to int hashtable

+
+ +
+
hash_djb2
+
static unsigned long hash_djb2(
const unsigned char *str
)
+

Converts given string to hash

+
+ +
+
create_hash_table
+
static void create_hash_table(
size_t start_capacity,
tinyobj_material_table_t *hash_table
)
+

Creates a new hash table in 'hash_table'

Parameters
start_capacity
size_t

Starting capacity, if equal to zero is <TINYOBJ_HASH_TABLE_DEFAULT_SIZE>

hash_table

[in/out] Table to be initialized

+
+ +
+
destroy_hash_table
+
static void destroy_hash_table(
tinyobj_material_table_t *hash_table
)
+

Finalizes given hash_table

+
+ +
+
hash_table_insert_value
+
static int hash_table_insert_value(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
+

Subroutine of hash_table_insert Inserts given value in hash, uses quadratic probing

Parameters
hash
unsigned long

Hash to be used

value
long

Value of this entity

hash_table

Table to be used

Returns

<TINYOBJ_HASH_TABLE_ERROR> upon failure or <TINYOBJ_HASH_TABLE_SUCCESS> after succeding

+
+ +
+
hash_table_insert
+
static int hash_table_insert(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
+

Inserts given value in hash, calls hash_table_insert_value

Parameters
hash
unsigned long

Hash to be used

value
long

Value of this entity

hash_table

Table to be used

Returns

<TINYOBJ_HASH_TABLE_ERROR> upon failure or <TINYOBJ_HASH_TABLE_SUCCESS> after succeding

+
+ +
+
hash_table_find
+
static hash_table_entry_t *hash_table_find(
unsigned long hash,
tinyobj_material_table_t *hash_table
)
+

Tries to find given hash in the table

Parameters
hash
unsigned long

Hash to be found

hash_table

Table to be used

Returns

Entry upon succeding or NULL if failure to find

+
+ +
+
hash_table_maybe_grow
+
static void hash_table_maybe_grow(
size_t new_n,
tinyobj_material_table_t *hash_table
)
+

Grows given hash_table to new_n if new_n is less or equal to capacity

+
+ +
+
hash_table_exists
+
static int hash_table_exists(
const char *name,
tinyobj_material_table_t *hash_table
)
+

Tries to find 'name' in hash_table, returns true if successful

See
+
+ +
+
hash_table_set
+
static void hash_table_set(
const char *name,
size_t val,
tinyobj_material_table_t *hash_table
)
+

Inserts value into hash_table, in name; creates new entry if it doesn't exist

See
+
+ +
+
hash_table_get
+
static long hash_table_get(
const char *name,
tinyobj_material_table_t *hash_table
)
+

Returns value of entity with name, -1 when failing

+
+ +
+
UTHash interface to tinyobj
+
+ +
+
tinyobj_material_table_t
+

Material table

+
+ +
+
UTHash interface to tinyobj
+
+ +
+
tinyobj_reserved
+

Reserved key used by the hashtable implementation so the table isn't deleted

+
+ +
+
tinyobj_hash_find
+
static void tinyobj_hash_find(
tinyobj_material_table_t *table,
const char *name,
tinyobj_material_table_tEntry **entryOUT
)
+

Tries to find object with 'name' as key

Parameters
table

Table to be used

name
const char*

Key

entryOUT
tinyobj_material_table_tEntry**

[out] Result

Returns

Sets entry to a valid result if entry was found, otherwise sets it to NULL

+
+ +
+
tinyobj_hash_add
+
static int tinyobj_hash_add(
tinyobj_material_table_t *table,
const char *name,
size_t length,
long value
)
+

Adds a material to the given material table If the material was already added its value is replaced

Parameters
table

Table to be used

name
const char*

Key

length
size_t

Name length

value
long

Value of the new entity

Returns

Returns true if successful, false otherwise

+
+ +
+
tinyobj_hash_free
+
static void tinyobj_hash_free(
tinyobj_material_table_t *table,
unsigned char bfree_name
)
+

Frees all entries of a given tinyobj_material_table_t

Parameters
table

Table to be freed

bfree_name
unsigned char

Should the key (name) be freed

Usually the name pointer is owned by the materials list by this point

See tinyobj_parse_and_index_mtl_file, freeing could lead to a segfault

+
+ +
+
tinyobj_hash_init
+
static void tinyobj_hash_init(
tinyobj_material_table_t *table
)
+

Initialises given table, and adds a reserved key

+
+ +
+
Material handling (.mtl)
+
+ +
+
initMaterial
+
static void initMaterial(
tinyobj_material_t *material
)
+

Defaults given material

+
+ +
+
tinyobj_mtl_parse_map
+
static int tinyobj_mtl_parse_map(
tinyobj_material_t *material,
const char **token,
const char *line_end
)
+

Parses a texture name from token ('map_')

Supported map types:
map_Ka - ambient texture
map_Kd - diffuse texture
map_Ks - specular texture
map_Ns - specular highlight texture
map_bump - bump texture
map_d - alpha texture
Parameters
material

Material to be filled

token
const char**

Buffer

line_end
const char*

Buffer end (halting point)

Returns
+
+ +
+
tinyobj_mtl_parse_optical
+
static int tinyobj_mtl_parse_optical(
tinyobj_material_t *material,
const char **token
)
+

Parses an optical coefficient from token ('N')

Supported coefficient types:
Ni - Index Of Refraction (ior) 'optical density'
Ns - Specular exponent 'shininess'
Parameters
material

Material to be filled

token
const char**

Buffer

Returns
+
+ +
+
tinyobj_mtl_parse_color
+
static int tinyobj_mtl_parse_color(
tinyobj_material_t *material,
const char **token
)
+

Parses a color coefficient from token ('K')

Supported coefficient types:
Ka - Ambient
Kd - Diffuse
Ks - Specular
Kt - Transmittance
Ke - Emissive
Parameters
material

Material to be filled

token
const char**

Buffer

Returns
+
+ +
+
tinyobj_parse_and_index_mtl_file
+
static int tinyobj_parse_and_index_mtl_file(
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *filename,
tinyobj_material_table_t *material_table
)
+

Parses and indexes a given material file

Parameters
materials_out

[out] Completed list of materials

num_materials_out
unsigned int*

[out] Length of materials_out

filename
const char*

File to be parsed

material_table

Table to be filled (can be NULL)

Returns
+
+ +
+
Aplication Programming Interface (.mtl)
+
+ +
+
tinyobj_parse_mtl_file
+
int tinyobj_parse_mtl_file(
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *filename
)
+

Parses a material file, see tinyobj_parse_and_index_mtl_file

+
+ +
+
tinyobj_material_free
+
void tinyobj_material_free(
tinyobj_material_t *materials,
unsigned int num_materials
)
+

Frees material data

Parameters
materials

Material list to be freed

num_materials
unsigned int

Length of materials

+
+ +
+
Object handling (.obj)
+
+ +
+
CommandType
+

Command identifiers used when parsing

<tinyobj_parse_obj_line>

COMMAND_EMPTY

No command

COMMAND_V

'v' Vertex <tinyobj_obj_parse_vertex>

COMMAND_VN

'vn' Vertex normal <tinyobj_obj_parse_vertex>

COMMAND_VT

'vt' Texture coordinate <tinyobj_obj_parse_vertex>

COMMAND_VP

'vp' Parameter space vertex <tinyobj_obj_parse_vertex>

COMMAND_F

'f' Face  <tinyobj_obj_parse_face>

COMMAND_P

'p' Point <tinyobj_obj_parse_point>

COMMAND_L

'l' Line  <tinyobj_obj_parse_line>

COMMAND_G

'g' Group name

COMMAND_O

'o' Object name

COMMAND_S

's' Smoothing group

COMMAND_USEMTL

'usemtl' Use material

COMMAND_MTLLIB

'mtllib' Load material

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_point_t-Summary.js b/doc/classes/C/tinyobj_point_t-Summary.js new file mode 100644 index 0000000..bb797fd --- /dev/null +++ b/doc/classes/C/tinyobj_point_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_point_t","tinyobj_point_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_point_t",[["C/C++","C"]],[["Structs","Struct"]],[[32,0,0,"tinyobj_point_t"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_point_t-SummaryToolTips.js b/doc/classes/C/tinyobj_point_t-SummaryToolTips.js new file mode 100644 index 0000000..0467f6e --- /dev/null +++ b/doc/classes/C/tinyobj_point_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_point_t",{32:"
Point (p) Specifies a point element and its vertex
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_point_t-ToolTips.js b/doc/classes/C/tinyobj_point_t-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/tinyobj_point_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_point_t.html b/doc/classes/C/tinyobj_point_t.html new file mode 100644 index 0000000..cfe6967 --- /dev/null +++ b/doc/classes/C/tinyobj_point_t.html @@ -0,0 +1,16 @@ + + +tinyobj_point_t + + + + + + + +
+
tinyobj_point_t
+

Point (p) Specifies a point element and its vertex

p  v1 v2 v3
Fields
v_idx

List of vertices

count

Point count

length

List length

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_shape_t-Summary.js b/doc/classes/C/tinyobj_shape_t-Summary.js new file mode 100644 index 0000000..41a8971 --- /dev/null +++ b/doc/classes/C/tinyobj_shape_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_shape_t","tinyobj_shape_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_shape_t",[["C/C++","C"]],[["Structs","Struct"]],[[38,0,0,"tinyobj_shape_t"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_shape_t-SummaryToolTips.js b/doc/classes/C/tinyobj_shape_t-SummaryToolTips.js new file mode 100644 index 0000000..76c63ef --- /dev/null +++ b/doc/classes/C/tinyobj_shape_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_shape_t",{38:"
Shapes contained in a given attribute
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_shape_t-ToolTips.js b/doc/classes/C/tinyobj_shape_t-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/tinyobj_shape_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_shape_t.html b/doc/classes/C/tinyobj_shape_t.html new file mode 100644 index 0000000..ff59a98 --- /dev/null +++ b/doc/classes/C/tinyobj_shape_t.html @@ -0,0 +1,16 @@ + + +tinyobj_shape_t + + + + + + + +
+
tinyobj_shape_t
+

Shapes contained in a given attribute

Fields
name

Group name or object name

face_offset

Face offset of this shape (starting point)

length

Length of this shape (ending point)

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_index_t-Summary.js b/doc/classes/C/tinyobj_vertex_index_t-Summary.js new file mode 100644 index 0000000..3c80766 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_index_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_vertex_index_t","tinyobj_vertex_index_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_vertex_index_t",[["C/C++","C"]],[["Structs","Struct"]],[[31,0,0,"tinyobj_vertex_index_t"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_index_t-SummaryToolTips.js b/doc/classes/C/tinyobj_vertex_index_t-SummaryToolTips.js new file mode 100644 index 0000000..1400ec5 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_index_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_vertex_index_t",{31:"
Indices for each vertex type, used for triplets in faces See: tinyobj_face_t
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_index_t-ToolTips.js b/doc/classes/C/tinyobj_vertex_index_t-ToolTips.js new file mode 100644 index 0000000..232e96d --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_index_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({35:"
Face (f) Specifies a face element and its vertex reference number
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_index_t.html b/doc/classes/C/tinyobj_vertex_index_t.html new file mode 100644 index 0000000..c718645 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_index_t.html @@ -0,0 +1,16 @@ + + +tinyobj_vertex_index_t + + + + + + + +
+
tinyobj_vertex_index_t
+

Indices for each vertex type, used for triplets in faces See: tinyobj_face_t

Fields
v_idx

Geometric vertex index

vt_idx

Texture vertex index

vn_idx

Normal vertex index

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_normal_t-Summary.js b/doc/classes/C/tinyobj_vertex_normal_t-Summary.js new file mode 100644 index 0000000..00c8704 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_normal_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_vertex_normal_t","tinyobj_vertex_normal_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_vertex_normal_t",[["C/C++","C"]],[["Structs","Struct"]],[[28,0,0,"tinyobj_vertex_normal_t"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_normal_t-SummaryToolTips.js b/doc/classes/C/tinyobj_vertex_normal_t-SummaryToolTips.js new file mode 100644 index 0000000..963971a --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_normal_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_vertex_normal_t",{28:"
Vertex normal (vn) Specifies a normal vector with components i, j, and k
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_normal_t-ToolTips.js b/doc/classes/C/tinyobj_vertex_normal_t-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_normal_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_normal_t.html b/doc/classes/C/tinyobj_vertex_normal_t.html new file mode 100644 index 0000000..01477f4 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_normal_t.html @@ -0,0 +1,16 @@ + + +tinyobj_vertex_normal_t + + + + + + + +
+
tinyobj_vertex_normal_t
+

Vertex normal (vn) Specifies a normal vector with components i, j, and k

vn  i j k
Fields
i

i coordinate

j

j coordinate

k

k coordinate

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_param_t-Summary.js b/doc/classes/C/tinyobj_vertex_param_t-Summary.js new file mode 100644 index 0000000..112e3c7 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_param_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_vertex_param_t","tinyobj_vertex_param_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_vertex_param_t",[["C/C++","C"]],[["Groups","Group"],["Structs","Struct"]],[[30,0,1,"tinyobj_vertex_param_t"],[145,0,0,"Element data","Element_data"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_param_t-SummaryToolTips.js b/doc/classes/C/tinyobj_vertex_param_t-SummaryToolTips.js new file mode 100644 index 0000000..91a1df3 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_param_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_vertex_param_t",{30:"
Parameter space vertex (vp) Specifies a point in the parameter space of a curve or surface.
",145:"
Polygonal and free-form geometry
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_param_t-ToolTips.js b/doc/classes/C/tinyobj_vertex_param_t-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_param_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_param_t.html b/doc/classes/C/tinyobj_vertex_param_t.html new file mode 100644 index 0000000..d40ddae --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_param_t.html @@ -0,0 +1,21 @@ + + +tinyobj_vertex_param_t + + + + + + + +
+
tinyobj_vertex_param_t
+

Parameter space vertex (vp) Specifies a point in the parameter space of a curve or surface.

vp  u v w
Fields
u

(1D) Space control point

v

(2D) Space control point

weight

(Rational trimming curves) Weight (default: 0)

+
+ +
+
Element data
+

Polygonal and free-form geometry

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_t-Summary.js b/doc/classes/C/tinyobj_vertex_t-Summary.js new file mode 100644 index 0000000..d5fb06c --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_vertex_t","tinyobj_vertex_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_vertex_t",[["C/C++","C"]],[["Structs","Struct"]],[[27,0,0,"tinyobj_vertex_t"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_t-SummaryToolTips.js b/doc/classes/C/tinyobj_vertex_t-SummaryToolTips.js new file mode 100644 index 0000000..51442a4 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_vertex_t",{27:"
Geometric vertex (v) Specifies a geometric vertex and its x y z coordinates. Rational curves and surfaces require a fourth homogeneous coordinate, also called the weight.
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_t-ToolTips.js b/doc/classes/C/tinyobj_vertex_t-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_t.html b/doc/classes/C/tinyobj_vertex_t.html new file mode 100644 index 0000000..42c4bd2 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_t.html @@ -0,0 +1,16 @@ + + +tinyobj_vertex_t + + + + + + + +
+
tinyobj_vertex_t
+

Geometric vertex (v) Specifies a geometric vertex and its x y z coordinates. Rational curves and surfaces require a fourth homogeneous coordinate, also called the weight.

v  x y z w
Fields
x

x coordinate

y

y coordinate

z

z coordinate

weight

(Rational curves/surfaces) Weight (default: 1.0f)

+
+ + \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_texture_t-Summary.js b/doc/classes/C/tinyobj_vertex_texture_t-Summary.js new file mode 100644 index 0000000..14527ab --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_texture_t-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("CClass:tinyobj_vertex_texture_t","tinyobj_vertex_texture_t");NDSummary.OnSummaryLoaded("CClass:tinyobj_vertex_texture_t",[["C/C++","C"]],[["Structs","Struct"]],[[29,0,0,"tinyobj_vertex_texture_t"]]); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_texture_t-SummaryToolTips.js b/doc/classes/C/tinyobj_vertex_texture_t-SummaryToolTips.js new file mode 100644 index 0000000..aab8acc --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_texture_t-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("CClass:tinyobj_vertex_texture_t",{29:"
Texture vertex (vt) Specifies a texture vertex and its coordinates
"}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_texture_t-ToolTips.js b/doc/classes/C/tinyobj_vertex_texture_t-ToolTips.js new file mode 100644 index 0000000..59992a1 --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_texture_t-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({}); \ No newline at end of file diff --git a/doc/classes/C/tinyobj_vertex_texture_t.html b/doc/classes/C/tinyobj_vertex_texture_t.html new file mode 100644 index 0000000..18eda7d --- /dev/null +++ b/doc/classes/C/tinyobj_vertex_texture_t.html @@ -0,0 +1,16 @@ + + +tinyobj_vertex_texture_t + + + + + + + +
+
tinyobj_vertex_texture_t
+

Texture vertex (vt) Specifies a texture vertex and its coordinates

vt  u v w
Fields
u

Horizontal direction

v

(2D and 3D) Vertical direction (Default: 0)

w

(3D) Depth (Default: 0)

+
+ + \ No newline at end of file diff --git a/doc/files/tinyobj_loader_c-h-Summary.js b/doc/files/tinyobj_loader_c-h-Summary.js new file mode 100644 index 0000000..b515583 --- /dev/null +++ b/doc/files/tinyobj_loader_c-h-Summary.js @@ -0,0 +1 @@ +NDFramePage.OnPageTitleLoaded("File:tinyobj_loader_c.h","tinyobj_loader_c.h");NDSummary.OnSummaryLoaded("File:tinyobj_loader_c.h",[["C/C++","C"]],[["Constants","Constant"],["Enums","Enumeration"],["Functions","Function"],["Groups","Group"],["Information","Information"],["Structs","Struct"]],[[1,0,4,"License","License"],[116,0,0,"TINYOBJ_LOADER_C_IMPLEMENTATION","TINYOBJ_LOADER_C_IMPLEMENTATION"],[2,0,0,"TINYOBJ_USE_UTHASH","TINYOBJ_USE_UTHASH"],[64,0,0,"TINYOBJ_ENABLE_OLDER_ATTRIBUTE","TINYOBJ_ENABLE_OLDER_ATTRIBUTE"],[4,0,0,"TINYOBJ_FLAG_TRIANGULATE","TINYOBJ_FLAG_TRIANGULATE"],[77,0,0,"TINYOBJ_INVALID_INDEX","TINYOBJ_INVALID_INDEX"],[6,0,0,"Return codes","Return_codes"],[7,0,0,,"TINYOBJ_NO_COMMAND"],[8,0,0,,"TINYOBJ_SUCCESS"],[9,0,0,,"TINYOBJ_ERROR_NOT_SET"],[10,0,0,,"TINYOBJ_ERROR_MEMORY"],[11,0,0,,"TINYOBJ_ERROR_EMPTY"],[12,0,0,,"TINYOBJ_ERROR_FILE_OPERATION"],[13,0,0,,"TINYOBJ_ERROR_INVALID_PARAMETER"],[14,0,0,,"TINYOBJ_ERROR_UNKNOWN_PARAMETER"],[15,0,0,,"TINYOBJ_ERROR_MALFORMED_PARAMETER"],[16,0,0,"Dynamic array basic parameters","Dynamic_array_basic_parameters"],[17,0,0,,"TINYOBJ_POINT_INITIAL_COUNT"],[18,0,0,,"TINYOBJ_POINT_GROWTH_FACTOR"],[19,0,0,,"TINYOBJ_COUPLE_INITIAL_COUNT"],[20,0,0,,"TINYOBJ_COUPLE_GROWTH_FACTOR"],[21,0,0,,"TINYOBJ_TRIPLET_INITIAL_COUNT"],[22,0,0,,"TINYOBJ_TRIPLET_GROWTH_FACTOR"],[23,0,0,,"TINYOBJ_MATERIAL_INITIAL_COUNT"],[24,0,0,,"TINYOBJ_MATERIAL_GROWTH_FACTOR"],[25,0,3,"Vertex data","Vertex_data"],[27,0,5,"tinyobj_vertex_t","tinyobj_vertex_t"],[28,0,5,"tinyobj_vertex_normal_t","tinyobj_vertex_normal_t"],[29,0,5,"tinyobj_vertex_texture_t","tinyobj_vertex_texture_t"],[30,0,5,"tinyobj_vertex_param_t","tinyobj_vertex_param_t"],[145,0,3,"Element data","tinyobj_vertex_param_t.Element_data"],[31,0,5,"tinyobj_vertex_index_t","tinyobj_vertex_index_t"],[32,0,5,"tinyobj_point_t","tinyobj_point_t"],[33,0,5,"tinyobj_line_t","tinyobj_line_t"],[26,0,5,"tinyobj_line_t.​s_line_vertex_index","tinyobj_line_t.s_line_vertex_index"],[35,0,5,"tinyobj_face_t","tinyobj_face_t"],[36,0,5,"tinyobj_coefficient_t","tinyobj_coefficient_t"],[5,0,5,"tinyobj_material_t","tinyobj_material_t"],[38,0,5,"tinyobj_shape_t","tinyobj_shape_t"],[37,0,5,"tinyobj_attrib_t","tinyobj_attrib_t"],[40,0,5,"COMPATtinyobj_attrib_t","COMPATtinyobj_attrib_t"],[41,0,3,"String handling","COMPATtinyobj_attrib_t.String_handling"],[42,0,2,"String handling macros","COMPATtinyobj_attrib_t.String_handling_macros"],[43,0,2,,"COMPATtinyobj_attrib_t.IS_SPACE"],[44,0,2,,"COMPATtinyobj_attrib_t.IS_DIGIT"],[45,0,2,,"COMPATtinyobj_attrib_t.IS_NEW_LINE"],[120,0,2,"is_line_ending","COMPATtinyobj_attrib_t.is_line_ending"],[47,0,2,"skip_space","COMPATtinyobj_attrib_t.skip_space"],[48,0,2,"skip_space_and_cr","COMPATtinyobj_attrib_t.skip_space_and_cr"],[49,0,2,"length_until_space","COMPATtinyobj_attrib_t.length_until_space"],[50,0,2,"until_space","COMPATtinyobj_attrib_t.until_space"],[51,0,2,"until_space_cr_slash","COMPATtinyobj_attrib_t.until_space_cr_slash"],[52,0,2,"length_until_newline_comment_space","COMPATtinyobj_attrib_t.length_until_newline_comment_space"],[53,0,2,"length_until_line_feed","COMPATtinyobj_attrib_t.length_until_line_feed"],[123,0,2,"strdup_ml","COMPATtinyobj_attrib_t.strdup_ml"],[55,0,2,"strndup","COMPATtinyobj_attrib_t.strndup"],[124,0,2,"dynamic_fgets","COMPATtinyobj_attrib_t.dynamic_fgets"],[57,0,3,"Triplet handling","COMPATtinyobj_attrib_t.Triplet_handling"],[34,0,2,"fixIndex","COMPATtinyobj_attrib_t.fixIndex"],[59,0,2,"parseRawTriple","COMPATtinyobj_attrib_t.parseRawTriple"],[60,0,3,"Integer/Double/Float handling","COMPATtinyobj_attrib_t.Integer/Double/Float_handling"],[61,0,2,"parseInt","COMPATtinyobj_attrib_t.parseInt"],[62,0,2,"tryParseDouble_assemble","COMPATtinyobj_attrib_t.tryParseDouble_assemble"],[63,0,2,"tryParseDouble_integer","COMPATtinyobj_attrib_t.tryParseDouble_integer"],[125,0,2,"tryParseDouble","COMPATtinyobj_attrib_t.tryParseDouble"],[65,0,2,"try_parse_float","COMPATtinyobj_attrib_t.try_parse_float"],[66,0,2,"parseFloat","COMPATtinyobj_attrib_t.parseFloat"],[67,0,2,"parseFloat2","COMPATtinyobj_attrib_t.parseFloat2"],[68,0,2,"parseFloat3","COMPATtinyobj_attrib_t.parseFloat3"],[78,0,3,"TINYOBJ hashtable implementation","COMPATtinyobj_attrib_t.TINYOBJ_hashtable_implementation"],[70,0,0,"Hash table return codes","COMPATtinyobj_attrib_t.Hash_table_return_codes"],[71,0,0,,"COMPATtinyobj_attrib_t.TINYOBJ_HASH_TABLE_SUCCESS"],[72,0,0,,"COMPATtinyobj_attrib_t.TINYOBJ_HASH_TABLE_ERROR"],[73,0,0,"TINYOBJ_HASH_TABLE_DEFAULT_SIZE","COMPATtinyobj_attrib_t.TINYOBJ_HASH_TABLE_DEFAULT_SIZE"],[74,0,5,"hash_table_entry_t","hash_table_entry_t"],[75,0,5,"tinyobj_material_table_t","tinyobj_material_table_t"],[79,0,3,"TINYOBJ hashtable implementation","tinyobj_material_table_t.TINYOBJ_hashtable_implementation"],[126,0,2,"hash_djb2","tinyobj_material_table_t.hash_djb2"],[80,0,2,"create_hash_table","tinyobj_material_table_t.create_hash_table"],[128,0,2,"destroy_hash_table","tinyobj_material_table_t.destroy_hash_table"],[129,0,2,"hash_table_insert_value","tinyobj_material_table_t.hash_table_insert_value"],[130,0,2,"hash_table_insert","tinyobj_material_table_t.hash_table_insert"],[131,0,2,"hash_table_find","tinyobj_material_table_t.hash_table_find"],[132,0,2,"hash_table_maybe_grow","tinyobj_material_table_t.hash_table_maybe_grow"],[58,0,2,"hash_table_exists","tinyobj_material_table_t.hash_table_exists"],[81,0,2,"hash_table_set","tinyobj_material_table_t.hash_table_set"],[135,0,2,"hash_table_get","tinyobj_material_table_t.hash_table_get"],[86,0,3,"UTHash interface to tinyobj","tinyobj_material_table_t.UTHash_interface_to_tinyobj"],[87,0,5,"tinyobj_material_table_t","tinyobj_material_table_t(2)"],[143,0,3,"UTHash interface to tinyobj","tinyobj_material_table_t.UTHash_interface_to_tinyobj(2)"],[88,0,0,"tinyobj_reserved","tinyobj_material_table_t.tinyobj_reserved"],[89,0,2,"tinyobj_hash_find","tinyobj_material_table_t.tinyobj_hash_find"],[90,0,2,"tinyobj_hash_add","tinyobj_material_table_t.tinyobj_hash_add"],[91,0,2,"tinyobj_hash_free","tinyobj_material_table_t.tinyobj_hash_free"],[92,0,2,"tinyobj_hash_init","tinyobj_material_table_t.tinyobj_hash_init"],[82,0,3,"Material handling (.mtl)","tinyobj_material_table_t.Material_handling"],[94,0,2,"initMaterial","tinyobj_material_table_t.initMaterial"],[95,0,2,"tinyobj_mtl_parse_map","tinyobj_material_table_t.tinyobj_mtl_parse_map"],[96,0,2,"tinyobj_mtl_parse_optical","tinyobj_material_table_t.tinyobj_mtl_parse_optical"],[97,0,2,"tinyobj_mtl_parse_color","tinyobj_material_table_t.tinyobj_mtl_parse_color"],[136,0,2,"tinyobj_parse_and_index_mtl_file","tinyobj_material_table_t.tinyobj_parse_and_index_mtl_file"],[46,0,3,"Aplication Programming Interface (.mtl)","tinyobj_material_table_t.Aplication_Programming_Interface"],[99,0,2,"tinyobj_parse_mtl_file","tinyobj_material_table_t.tinyobj_parse_mtl_file"],[100,0,2,"tinyobj_material_free","tinyobj_material_table_t.tinyobj_material_free"],[3,0,3,"Object handling (.obj)","tinyobj_material_table_t.Object_handling"],[102,0,1,"CommandType","tinyobj_material_table_t.CommandType"],[103,0,0,,"tinyobj_material_table_t.COMMAND_EMPTY"],[104,0,0,,"tinyobj_material_table_t.COMMAND_V"],[105,0,0,,"tinyobj_material_table_t.COMMAND_VN"],[106,0,0,,"tinyobj_material_table_t.COMMAND_VT"],[107,0,0,,"tinyobj_material_table_t.COMMAND_VP"],[108,0,0,,"tinyobj_material_table_t.COMMAND_F"],[109,0,0,,"tinyobj_material_table_t.COMMAND_P"],[110,0,0,,"tinyobj_material_table_t.COMMAND_L"],[111,0,0,,"tinyobj_material_table_t.COMMAND_G"],[112,0,0,,"tinyobj_material_table_t.COMMAND_O"],[113,0,0,,"tinyobj_material_table_t.COMMAND_S"],[114,0,0,,"tinyobj_material_table_t.COMMAND_USEMTL"],[115,0,0,,"tinyobj_material_table_t.COMMAND_MTLLIB"],[118,0,5,"Command","Command"],[85,0,5,"Command.​u_information","Command.u_information"],[122,0,5,"Command.​s_group_information","Command.s_group_information"],[119,0,5,"CommandInformation","CommandInformation"],[84,0,5,"CommandInformation.​s_counter","CommandInformation.s_counter"],[69,0,3,"Object handling (.obj)","CommandInformation.s_counter.Object_handling"],[146,0,2,"tinyobj_obj_free_point","CommandInformation.s_counter.tinyobj_obj_free_point"],[147,0,2,"tinyobj_obj_parse_point","CommandInformation.s_counter.tinyobj_obj_parse_point"],[148,0,2,"tinyobj_triplet_list_grow","CommandInformation.s_counter.tinyobj_triplet_list_grow"],[149,0,2,"tinyobj_triplet_list_new","CommandInformation.s_counter.tinyobj_triplet_list_new"],[150,0,2,"tinyobj_obj_free_line","CommandInformation.s_counter.tinyobj_obj_free_line"],[151,0,2,"tinyuobj_obj_parse_line","CommandInformation.s_counter.tinyuobj_obj_parse_line"],[152,0,2,"tinyobj_obj_free_face","CommandInformation.s_counter.tinyobj_obj_free_face"],[83,0,2,"tinyobj_obj_parse_face","CommandInformation.s_counter.tinyobj_obj_parse_face"],[154,0,2,"tinyobj_obj_parse_vertex","CommandInformation.s_counter.tinyobj_obj_parse_vertex"],[138,0,2,"tinyobj_parse_obj_line","CommandInformation.s_counter.tinyobj_parse_obj_line"],[139,0,2,"tinyobj_parse_obj_line_traverse","CommandInformation.s_counter.tinyobj_parse_obj_line_traverse"],[157,0,2,"tinyobj_command_info_free","CommandInformation.s_counter.tinyobj_command_info_free"],[158,0,2,"tinyobj_shape_construct","CommandInformation.s_counter.tinyobj_shape_construct"],[159,0,2,"tinyobj_shape_free","CommandInformation.s_counter.tinyobj_shape_free"],[160,0,2,"tinyobj_attrib_construct","CommandInformation.s_counter.tinyobj_attrib_construct"],[54,0,3,"Aplication Programming Interface (.obj)","CommandInformation.s_counter.Aplication_Programming_Interface"],[161,0,2,"tinyobj_attrib_free","CommandInformation.s_counter.tinyobj_attrib_free"],[162,0,2,"tinyobj_attrib_init","CommandInformation.s_counter.tinyobj_attrib_init"],[140,0,2,"tinyobj_parse_obj","CommandInformation.s_counter.tinyobj_parse_obj"],[56,0,3,"Compatibility with older versions (deprecated)","CommandInformation.s_counter.Compatibility_with_older_versions"],[164,0,2,"tinyobj_attrib_free_compat","CommandInformation.s_counter.tinyobj_attrib_free_compat"],[39,0,2,"tinyobj_new2old","CommandInformation.s_counter.tinyobj_new2old"]]); \ No newline at end of file diff --git a/doc/files/tinyobj_loader_c-h-SummaryToolTips.js b/doc/files/tinyobj_loader_c-h-SummaryToolTips.js new file mode 100644 index 0000000..18414bf --- /dev/null +++ b/doc/files/tinyobj_loader_c-h-SummaryToolTips.js @@ -0,0 +1 @@ +NDSummary.OnToolTipsLoaded("File:tinyobj_loader_c.h",{1:"
The MIT License (MIT)
",116:"
Constant used to mark the .c file that holds the implementation of tinyobj
",2:"
Use UThash hashtable implementation instead of tinyobj\'s implementation
",64:"
Enable use of older attribute type for objects (deprecated)
",4:"
Should the faces be triangulated upon loading When triangulating we parse the vertices as if they were part of a triangle fan, so every three indices the next is always the first triplet of this face
",77:"
Invalid vertex index used when referencing vertices in couples/tuples
",16:"
Initial array lengths and growth factors
",27:"
Geometric vertex (v) Specifies a geometric vertex and its x y z coordinates. Rational curves and surfaces require a fourth homogeneous coordinate, also called the weight.
",28:"
Vertex normal (vn) Specifies a normal vector with components i, j, and k
",29:"
Texture vertex (vt) Specifies a texture vertex and its coordinates
",30:"
Parameter space vertex (vp) Specifies a point in the parameter space of a curve or surface.
",145:"
Polygonal and free-form geometry
",31:"
Indices for each vertex type, used for triplets in faces See: tinyobj_face_t
",32:"
Point (p) Specifies a point element and its vertex
",33:"
Line (l) Specifies a line and its vertex reference numbers
",26:"
List of couples
",35:"
Face (f) Specifies a face element and its vertex reference number
",36:"
RGB Color coefficient information used in materials tinyobj_material_t
",5:"
Material attribute .mtl format
",38:"
Shapes contained in a given attribute
",37:"
Object attributes .obj format
",40:"
Object attributes (deprecated)
",120:"
static int is_line_ending(
const char *p,
size_t i,
size_t end_i
)
Is given line ending in this character?
",47:"
static void skip_space(
const char **token
)
Skips the next spacing characters in given token
",48:"
static void skip_space_and_cr(
const char **token
)
Skips the next spacing characters and also carriage return in given token
",49:"
static size_t length_until_space(
const char *token,
size_t n
)
Calculates and returns the length until next space character in this token
",50:"
static int until_space(
const char *token
)
Skips the next spacing characters
",51:"
static void until_space_cr_slash(
const char **token
)
Skips the next characters in given token
",52:"
static size_t length_until_newline_comment_space(
const char *token,
size_t n
)
Returns the length until the next characters:
",53:"
static size_t length_until_line_feed(
const char *token,
size_t n
)
Returns the length until the next line feed
",123:"
static char *strdup_ml(
const char *s,
size_t max_length
)
Duplicates \'max_length\' characters of given string (strdup with max length specified)
",55:"
char *strndup(
const char *s,
size_t len
)
strndup implementation for non-GNU compliant compilers
",124:"
static char *dynamic_fgets(
char **buf,
int *size,
FILE *file
)
fgets with a dynamic buffer
",34:"
static int fixIndex(
int idx,
size_t n
)
Converts given absolute index, from triplet to zero-base, supports relative indices
",59:"
static tinyobj_vertex_index_t parseRawTriple(
const char **token
)
Parses raw triplets of given tokens
",61:"
static int parseInt(
const char **token
)
Returns equivalent integer of next non-space character, the token is advanced until next space
",62:"
static double tryParseDouble_assemble(
char sign,
double mantissa,
char exp_sign,
int exponent
)
Last step of tryParseDouble
",63:"
static unsigned char tryParseDouble_integer(
const char **curr,
const char *s_end,
char *sign,
int *integer
)
Part of tryParseDouble
",125:"
static unsigned char tryParseDouble(
const char *s,
const char *s_end,
double *result
)
Tries to parse a floating point number located at s.
",65:"
static unsigned char try_parse_float(
const char **token,
float *result
)
Tries to parse next float, if there\'s none fails
",66:"
static float parseFloat(
const char **token
)
Returns equivalent float of next non-space character, the token is advanced until next space
",67:"
static void parseFloat2(
float *x,
float *y,
const char **token
)
Parses the two next floats in given token
",68:"
static void parseFloat3(
float *x,
float *y,
float *z,
const char **token
)
Parses the three next floats in given token
",78:"
String to int hashtable
",73:"
Default starting size for tinyobj own hash table implementation tables
",74:"
Entries used in tinyobj\'s own hash table implementation
",75:"
Hash table used in tinyobj\'s own hash table implementation
",79:"
String to int hashtable
",126:"
static unsigned long hash_djb2(
const unsigned char *str
)
Converts given string to hash
",80:"
static void create_hash_table(
size_t start_capacity,
tinyobj_material_table_t *hash_table
)
Creates a new hash table in \'hash_table\'
",128:"
static void destroy_hash_table(
tinyobj_material_table_t *hash_table
)
Finalizes given hash_table
",129:"
static int hash_table_insert_value(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
Subroutine of hash_table_insert Inserts given value in hash, uses quadratic probing
",130:"
static int hash_table_insert(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
Inserts given value in hash, calls hash_table_insert_value
",131:"
static hash_table_entry_t *hash_table_find(
unsigned long hash,
tinyobj_material_table_t *hash_table
)
Tries to find given hash in the table
",132:"
static void hash_table_maybe_grow(
size_t new_n,
tinyobj_material_table_t *hash_table
)
Grows given hash_table to new_n if new_n is less or equal to capacity
",58:"
static int hash_table_exists(
const char *name,
tinyobj_material_table_t *hash_table
)
Tries to find \'name\' in hash_table, returns true if successful
",81:"
static void hash_table_set(
const char *name,
size_t val,
tinyobj_material_table_t *hash_table
)
Inserts value into hash_table, in name; creates new entry if it doesn\'t exist
",135:"
static long hash_table_get(
const char *name,
tinyobj_material_table_t *hash_table
)
Returns value of entity with name, -1 when failing
",87:"
Material table
",88:"
Reserved key used by the hashtable implementation so the table isn\'t deleted
",89:"
static void tinyobj_hash_find(
tinyobj_material_table_t *table,
const char *name,
tinyobj_material_table_tEntry **entryOUT
)
Tries to find object with \'name\' as key
",90:"
static int tinyobj_hash_add(
tinyobj_material_table_t *table,
const char *name,
size_t length,
long value
)
Adds a material to the given material table If the material was already added its value is replaced
",91:"
static void tinyobj_hash_free(
tinyobj_material_table_t *table,
unsigned char bfree_name
)
Frees all entries of a given tinyobj_material_table_t
",92:"
static void tinyobj_hash_init(
tinyobj_material_table_t *table
)
Initialises given table, and adds a reserved key
",94:"
static void initMaterial(
tinyobj_material_t *material
)
Defaults given material
",95:"
static int tinyobj_mtl_parse_map(
tinyobj_material_t *material,
const char **token,
const char *line_end
)
Parses a texture name from token (\'map_\')
",96:"
static int tinyobj_mtl_parse_optical(
tinyobj_material_t *material,
const char **token
)
Parses an optical coefficient from token (\'N\')
",97:"
static int tinyobj_mtl_parse_color(
tinyobj_material_t *material,
const char **token
)
Parses a color coefficient from token (\'K\')
",136:"
static int tinyobj_parse_and_index_mtl_file(
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *filename,
tinyobj_material_table_t *material_table
)
Parses and indexes a given material file
",99:"
int tinyobj_parse_mtl_file(
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *filename
)
Parses a material file, see tinyobj_parse_and_index_mtl_file
",100:"
void tinyobj_material_free(
tinyobj_material_t *materials,
unsigned int num_materials
)
Frees material data
",102:"
Command identifiers used when parsing
",118:"
Command information used to parse obj files <tinyobj_parse_obj_line>
",85:"
Specific command information
",122:"
Grouping and Display/Render attributes
",119:"
General information regarding the commands of a given file
",84:"
Counter of command types
",146:"
static void tinyobj_obj_free_point(
tinyobj_point_t *p
)
Frees allocated data of a given point
",147:"
static int tinyobj_obj_parse_point(
Command *command,
const char **token
)
Parses a point from token (\'p\')
",148:"
unsigned char tinyobj_triplet_list_grow(
tinyobj_vertex_index_t **list,
size_t new_len
)
Grows the given triplet list to a new size If the growth fails the list is unchanged
",149:"
static tinyobj_vertex_index_t *tinyobj_triplet_list_new(
size_t len
)
Allocates memory for a new triplet list
",150:"
static void tinyobj_obj_free_line(
tinyobj_line_t *l
)
Frees allocated data of a given line
",151:"
Parses a line from token (\'l\')
",152:"
static void tinyobj_obj_free_face(
tinyobj_face_t *f
)
Frees allocated data of a given face
",83:"
static int tinyobj_obj_parse_face(
Command *command,
const char **token,
int triangulate
)
Parses a face from token (\'f\') and fills given command with face information
",154:"
static int tinyobj_obj_parse_vertex(
Command *command,
const char **token
)
Parses a vertex from token (\'v\')
",138:"
static int tinyobj_parse_obj_line(
CommandInformation *command_info,
int pos,
const char *p,
size_t p_len,
int flags
)
Parses line of an .obj file
",139:"
static int tinyobj_parse_obj_line_traverse(
const char *buf,
size_t len,
CommandInformation *command_info,
unsigned int flags
)
Traverses and parses all lines of given buffer
",157:"
static void tinyobj_command_info_free(
CommandInformation *command_info
)
Frees given command information
",158:"
static void tinyobj_shape_construct(
tinyobj_shape_t **shapes,
unsigned int *num_shapes,
CommandInformation *command_info
)
Constructs shape information
",159:"
void tinyobj_shape_free(
tinyobj_shape_t *shapes,
unsigned int num_shapes
)
Frees shape data
",160:"
static void tinyobj_attrib_construct(
tinyobj_attrib_t *attrib,
CommandInformation *command_info,
tinyobj_material_table_t *material_table
)
Constructs attribute data with given information
",161:"
void tinyobj_attrib_free(
tinyobj_attrib_t *attrib
)
Frees attribute data
",162:"
static void tinyobj_attrib_init(
tinyobj_attrib_t *attrib
)
Initializes given attribute information to default values
",140:"
int tinyobj_parse_obj(
tinyobj_attrib_t *attrib,
tinyobj_shape_t **shapes,
unsigned int *num_shapes,
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *buf,
size_t len,
unsigned int flags
)
Parses .obj file
",164:"
void tinyobj_attrib_free_compat(
COMPATtinyobj_attrib_t *attrib
)
Frees given attribute
",39:"
int tinyobj_new2old(
tinyobj_attrib_t *attrib,
COMPATtinyobj_attrib_t *out_attrib
)
Converts new attribute format to the old one This expects that the faces were triangulated
"}); \ No newline at end of file diff --git a/doc/files/tinyobj_loader_c-h-ToolTips.js b/doc/files/tinyobj_loader_c-h-ToolTips.js new file mode 100644 index 0000000..ef438d9 --- /dev/null +++ b/doc/files/tinyobj_loader_c-h-ToolTips.js @@ -0,0 +1 @@ +NDContentPage.OnToolTipsLoaded({4:"
Should the faces be triangulated upon loading When triangulating we parse the vertices as if they were part of a triangle fan, so every three indices the next is always the first triplet of this face
",5:"
Material attribute .mtl format
",8:"
Success
",10:"
Memory failure
",11:"
Empty file
",12:"
Failed file operation
",13:"
Invalid parameter (function)
",14:"
Unknown parameter for object/material
",15:"
Malformed parameter for object/material
",31:"
Indices for each vertex type, used for triplets in faces See: tinyobj_face_t
",32:"
Point (p) Specifies a point element and its vertex
",33:"
Line (l) Specifies a line and its vertex reference numbers
",35:"
Face (f) Specifies a face element and its vertex reference number
",37:"
Object attributes .obj format
",38:"
Shapes contained in a given attribute
",40:"
Object attributes (deprecated)
",59:"
static tinyobj_vertex_index_t parseRawTriple(
const char **token
)
Parses raw triplets of given tokens
",66:"
static float parseFloat(
const char **token
)
Returns equivalent float of next non-space character, the token is advanced until next space
",74:"
Entries used in tinyobj\'s own hash table implementation
",75:"
Hash table used in tinyobj\'s own hash table implementation
",77:"
Invalid vertex index used when referencing vertices in couples/tuples
",118:"
Command information used to parse obj files <tinyobj_parse_obj_line>
",119:"
General information regarding the commands of a given file
",125:"
static unsigned char tryParseDouble(
const char *s,
const char *s_end,
double *result
)
Tries to parse a floating point number located at s.
",126:"
static unsigned long hash_djb2(
const unsigned char *str
)
Converts given string to hash
",129:"
static int hash_table_insert_value(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
Subroutine of hash_table_insert Inserts given value in hash, uses quadratic probing
",130:"
static int hash_table_insert(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
Inserts given value in hash, calls hash_table_insert_value
",131:"
static hash_table_entry_t *hash_table_find(
unsigned long hash,
tinyobj_material_table_t *hash_table
)
Tries to find given hash in the table
",136:"
static int tinyobj_parse_and_index_mtl_file(
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *filename,
tinyobj_material_table_t *material_table
)
Parses and indexes a given material file
"}); \ No newline at end of file diff --git a/doc/files/tinyobj_loader_c-h.html b/doc/files/tinyobj_loader_c-h.html new file mode 100644 index 0000000..090d70c --- /dev/null +++ b/doc/files/tinyobj_loader_c-h.html @@ -0,0 +1,620 @@ + + +tinyobj_loader_c.h + + + + + + + +
+
License
+

The MIT License (MIT)

Copyright (c) 2016-2019 Syoyo Fujita and many contributors.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+
+ +
+
TINYOBJ_LOADER_C_IMPLEMENTATION
+

Constant used to mark the .c file that holds the implementation of tinyobj

Only one file should have this definition!

+
+ +
+
TINYOBJ_USE_UTHASH
+

Use UThash hashtable implementation instead of tinyobj's implementation

+
+ +
+
TINYOBJ_ENABLE_OLDER_ATTRIBUTE
+

Enable use of older attribute type for objects (deprecated)

See
+
+ +
+
TINYOBJ_FLAG_TRIANGULATE
+

Should the faces be triangulated upon loading When triangulating we parse the vertices as if they were part of a triangle fan, so every three indices the next is always the first triplet of this face

See

<tinyobj_obj_parse_face>

+
+ +
+
TINYOBJ_INVALID_INDEX
+

Invalid vertex index used when referencing vertices in couples/tuples

See
+
+ +
+
Return codes
+
TINYOBJ_NO_COMMAND

No command

TINYOBJ_SUCCESS

Success

TINYOBJ_ERROR_NOT_SET

Default error

TINYOBJ_ERROR_MEMORY

Memory failure

TINYOBJ_ERROR_EMPTY

Empty file

TINYOBJ_ERROR_FILE_OPERATION

Failed file operation

TINYOBJ_ERROR_INVALID_PARAMETER

Invalid parameter (function)

TINYOBJ_ERROR_UNKNOWN_PARAMETER

Unknown parameter for object/material

TINYOBJ_ERROR_MALFORMED_PARAMETER

Malformed parameter for object/material

+
+ +
+
Dynamic array basic parameters
+

Initial array lengths and growth factors

TINYOBJ_POINT_INITIAL_COUNT

Point array initial length

TINYOBJ_POINT_GROWTH_FACTOR

Point array growth factor

TINYOBJ_COUPLE_INITIAL_COUNT

Couple (line) array initial length

TINYOBJ_COUPLE_GROWTH_FACTOR

Couple (line) array growth factor

TINYOBJ_TRIPLET_INITIAL_COUNT

Triplet (face) array initial length

TINYOBJ_TRIPLET_GROWTH_FACTOR

Triplet (face) array growth factor

TINYOBJ_MATERIAL_INITIAL_COUNT

Material array initial length

TINYOBJ_MATERIAL_GROWTH_FACTOR

Material array growth factor

+
+ +
+
Vertex data
+
+ +
+
tinyobj_vertex_t
+

Geometric vertex (v) Specifies a geometric vertex and its x y z coordinates. Rational curves and surfaces require a fourth homogeneous coordinate, also called the weight.

v  x y z w
Fields
x

x coordinate

y

y coordinate

z

z coordinate

weight

(Rational curves/surfaces) Weight (default: 1.0f)

+
+ +
+
tinyobj_vertex_normal_t
+

Vertex normal (vn) Specifies a normal vector with components i, j, and k

vn  i j k
Fields
i

i coordinate

j

j coordinate

k

k coordinate

+
+ +
+
tinyobj_vertex_texture_t
+

Texture vertex (vt) Specifies a texture vertex and its coordinates

vt  u v w
Fields
u

Horizontal direction

v

(2D and 3D) Vertical direction (Default: 0)

w

(3D) Depth (Default: 0)

+
+ +
+
tinyobj_vertex_param_t
+

Parameter space vertex (vp) Specifies a point in the parameter space of a curve or surface.

vp  u v w
Fields
u

(1D) Space control point

v

(2D) Space control point

weight

(Rational trimming curves) Weight (default: 0)

+
+ +
+
Element data
+

Polygonal and free-form geometry

+
+ +
+
tinyobj_vertex_index_t
+

Indices for each vertex type, used for triplets in faces See: tinyobj_face_t

Fields
v_idx

Geometric vertex index

vt_idx

Texture vertex index

vn_idx

Normal vertex index

+
+ +
+
tinyobj_point_t
+

Point (p) Specifies a point element and its vertex

p  v1 v2 v3
Fields
v_idx

List of vertices

count

Point count

length

List length

+
+ +
+
tinyobj_line_t
+

Line (l) Specifies a line and its vertex reference numbers

l  v1/vt1   v2/vt2   v3/vt3
Fields
couple_list

List of couples contained in this line

count

Count of couples

length

Total length of couple list

+
+ +
+
tinyobj_line_t.​s_line_vertex_index
+

List of couples

Fields
v_idx

Geometric vertex

vt_idx

Texture vertex (optional)

+
+ +
+
tinyobj_face_t
+

Face (f) Specifies a face element and its vertex reference number

f  v1/vt1/vn1   v2/vt2/vn2
fo (deprecated)
Fields
triplet list

A list of triplets contained in this face

v  Geometric vertex (minimum of 3)

vt Texture vertex (optional)

vn Vertex normal (optional)

When an index is empty it is equal to TINYOBJ_INVALID_INDEX

count

Count of triplets

length

Length of triplet list

triangle_count

Number of triangles in this face

material_id

Material to be applied to this face (defaults to -1)

smoothing_id

Smoothing group to be applied to this face (defaults to 0)

+
+ +
+
tinyobj_coefficient_t
+

RGB Color coefficient information used in materials tinyobj_material_t

+
+ +
+
tinyobj_material_t
+

Material attribute .mtl format

Fields
name

Material name

ambient

Ambient color coefficient (reflectivity)

diffuse

Diffuse color coefficient (reflectivity)

specular

Specular color coefficient (reflectivity)

transmittance

Transmittance color coefficient (reflectivity)

emission

Emission color coefficient (reflectivity)

shininess

Specular exponent

ior

Index Of Refraction (ior) 'optical density'

dissolve

Non-transparency to be alpha 'dissolve' (0.0f transparent-1.0f opaque)

illum

Illumination model (0-10)

ambient_texname

map_Ka

diffuse_texname

map_Kd

specular_texname

map_Ks

specular_highlight_texname

map_Ns

bump_texname

map_bump, bump

displacement_texname

disp

alpha_texname

map_d

+
+ +
+
tinyobj_shape_t
+

Shapes contained in a given attribute

Fields
name

Group name or object name

face_offset

Face offset of this shape (starting point)

length

Length of this shape (ending point)

+
+ +
+
tinyobj_attrib_t
+

Object attributes .obj format

Fields
v

Geometric vertices

v_count

Geometric vertex count

vn

Vertex normals

vn_count

Vertex normal count

vt

Texture vertices

vt_count

Texture vertex count

vp

Parameter space vertices

vp_count

Parameter space vertex count

f

Object faces

f_count

Face count

triangle_count_total

Total count of triangles

l

Lines

l_count

Line count

p

Points

+
+ +
+
COMPATtinyobj_attrib_t
+

Object attributes (deprecated)

Fields
vertices

Array of geometric vertices (x0, y0, z0, x1, y1, z1, ...)

num_vertices

Number of vertices in 'vertices' (the actual array length is num_vertices*3)

normals

Array of vertex normals (i0, j0, k0, i1, j1, k1, ...)

num_normals

Number of vertices in 'normals' (the actual array length is num_normals*3)

texcoords

Array of  texture vertices (u0, w0, u1, w1, ...)

num_texcoords

Number of vertices in 'texcoords' (the actual array length is num_normals*2)

faces

Array of faces (containing tinyobj_vertex_index_t information)

num_faces

Length of 'faces'

face_num_verts

Array of number of vertices in each face (3 for triangulated faces)

num_face_num_verts

Total number of triangles in this object (length of face_num_verts)

material_ids

Array with the id of the material for each face (length is num_faces)

+
+ +
+
String handling
+
+ +
+
String handling macros
+
IS_SPACE

Is this character a spacing character ' ' or '\t'

IS_DIGIT

Is this character a digit

IS_NEW_LINE

Is this character a new line character '\r','\n','\0'

+
+ +
+
is_line_ending
+
static int is_line_ending(
const char *p,
size_t i,
size_t end_i
)
+

Is given line ending in this character?

Returns

True if line is ending

+
+ +
+
skip_space
+
static void skip_space(
const char **token
)
+

Skips the next spacing characters in given token

+
+ +
+
skip_space_and_cr
+
static void skip_space_and_cr(
const char **token
)
+

Skips the next spacing characters and also carriage return in given token

+
+ +
+
length_until_space
+
static size_t length_until_space(
const char *token,
size_t n
)
+

Calculates and returns the length until next space character in this token

Parameters
token
const char*

Token to be used

n
size_t

Maximum number of characters to count

Returns

Length until next space character

+
+ +
+
until_space
+
static int until_space(
const char *token
)
+

Skips the next spacing characters

'\0',' ', '\t', '\r'
+
+ +
+
until_space_cr_slash
+
static void until_space_cr_slash(
const char **token
)
+

Skips the next characters in given token

'\0','/', ' ', '\t', '\r'
+
+ +
+
length_until_newline_comment_space
+
static size_t length_until_newline_comment_space(
const char *token,
size_t n
)
+

Returns the length until the next characters:

\n \r\n \0 ' ' \t #
Parameters
token
const char*

Buffer

n
size_t

Maximum number of characters to count

Returns

Length until next character

+
+ +
+
length_until_line_feed
+
static size_t length_until_line_feed(
const char *token,
size_t n
)
+

Returns the length until the next line feed

Assumes token[n-1] = '\0'

Parameters
token
const char*

Buffer

n
size_t

Maximum number of characters to count

+
+ +
+
strdup_ml
+
static char *strdup_ml(
const char *s,
size_t max_length
)
+

Duplicates 'max_length' characters of given string (strdup with max length specified)

Parameters
s
const char*

String to be duplicated

max_length
size_t

Maximum length to be duplicated

Returns

Duplicated string (should be freed by the caller)

+
+ +
+
strndup
+
char *strndup(
const char *s,
size_t len
)
+

strndup implementation for non-GNU compliant compilers

+
+ +
+
dynamic_fgets
+
static char *dynamic_fgets(
char **buf,
int *size,
FILE *file
)
+

fgets with a dynamic buffer

+
+ +
+
Triplet handling
+
+ +
+
fixIndex
+
static int fixIndex(
int idx,
size_t n
)
+

Converts given absolute index, from triplet to zero-base, supports relative indices

See
Parameters
idx
int

Index to be converted

n
size_t

Position of this couple/tuple regarding to the vertex type of this index

Returns
+
+ +
+
parseRawTriple
+
static tinyobj_vertex_index_t parseRawTriple(
const char **token
)
+

Parses raw triplets of given tokens

v, v/vt/vn, v//vn, v/vt
Valid triplets:
<x> 1//1
<x> 1//1 2//2 3//3 4//4
<x> 1/1/1 2/2/2 3/3/3 4/4/4
The following are examples of illegal statements
<x> 1/1/1 2/2/2 3//3 4//4
<x> 1/ 1/1 2/2/2 3/3/3 4/4/4
Parameters
token
const char**

Token to parse

Returns

Indices parsed from given token, if one of the indices is not present it's equal to TINYOBJ_INVALID_INDEX

+
+ +
+
Integer/Double/Float handling
+
+ +
+
parseInt
+
static int parseInt(
const char **token
)
+

Returns equivalent integer of next non-space character, the token is advanced until next space

+
+ +
+
tryParseDouble_assemble
+
static double tryParseDouble_assemble(
char sign,
double mantissa,
char exp_sign,
int exponent
)
+

Last step of tryParseDouble

Assembles given information into double

Parameters
sign
char

Sign of this double

mantissa
double

Mantissa

exp_sign
char

Exponent sign

exponent
int

Exponent

Returns

Assembled double

+
+ +
+
tryParseDouble_integer
+
static unsigned char tryParseDouble_integer(
const char **curr,
const char *s_end,
char *sign,
int *integer
)
+

Part of tryParseDouble

Parses integer part of a double (advances curr)

Parameters
curr
const char**

Current position in a buffer

s_end
const char*

End of the buffer

sign
char*

[out] Sign to be filled

integer
int*

[out] Integer to be filled

Returns

True integer was successfuly parsed, false if nothing was read

+
+ +
+
tryParseDouble
+
static unsigned char tryParseDouble(
const char *s,
const char *s_end,
double *result
)
+

Tries to parse a floating point number located at s.

Parses the following EBNF grammar:
sign = "+" | "-" ;
END = ? anything not in digit ?
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
integer = [sign] , digit , {digit} ;
decimal = integer , ["." , integer] ;
float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ;
Valid strings are for example:
-0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2

The function is greedy and will parse until any of the following happens:

The following situations triggers a failure:

Parameters
s
const char*

String to be parsed

s_end
const char*

Location in the string where reading should halt, e.g. the end of

the string result

[out] Parsed double

Returns If the parsing is a success, result is set to the parsed value and true is returned.

+
+ +
+
try_parse_float
+
static unsigned char try_parse_float(
const char **token,
float *result
)
+

Tries to parse next float, if there's none fails

Parameters
token
const char**

Buffer to be read

result
float*

[out] Result, not set if return is false

Returns

If the parsing is a success, result is set to the parsed value and true is returned.

+
+ +
+
parseFloat
+
static float parseFloat(
const char **token
)
+

Returns equivalent float of next non-space character, the token is advanced until next space

+
+ +
+
parseFloat2
+
static void parseFloat2(
float *x,
float *y,
const char **token
)
+

Parses the two next floats in given token

See

parseFloat

+
+ +
+
parseFloat3
+
static void parseFloat3(
float *x,
float *y,
float *z,
const char **token
)
+

Parses the three next floats in given token

See

parseFloat

+
+ +
+
TINYOBJ hashtable implementation
+

String to int hashtable

+
+ +
+
Hash table return codes
+
TINYOBJ_HASH_TABLE_SUCCESS

Success

TINYOBJ_HASH_TABLE_ERROR

Failure

+
+ +
+
TINYOBJ_HASH_TABLE_DEFAULT_SIZE
+

Default starting size for tinyobj own hash table implementation tables

+
+ +
+
hash_table_entry_t
+

Entries used in tinyobj's own hash table implementation

Fields
hash

Hash value

filled

Is this entry filled

value

Value

next

Next entry

+
+ +
+
tinyobj_material_table_t
+

Hash table used in tinyobj's own hash table implementation

Fields
hashes

Hashes used

entries

Linked list of entries in this table

capacity

Total capacity of this table

n

Count of elements

+
+ +
+
TINYOBJ hashtable implementation
+

String to int hashtable

+
+ +
+
hash_djb2
+
static unsigned long hash_djb2(
const unsigned char *str
)
+

Converts given string to hash

+
+ +
+
create_hash_table
+
static void create_hash_table(
size_t start_capacity,
tinyobj_material_table_t *hash_table
)
+

Creates a new hash table in 'hash_table'

Parameters
start_capacity
size_t

Starting capacity, if equal to zero is <TINYOBJ_HASH_TABLE_DEFAULT_SIZE>

hash_table

[in/out] Table to be initialized

+
+ +
+
destroy_hash_table
+
static void destroy_hash_table(
tinyobj_material_table_t *hash_table
)
+

Finalizes given hash_table

+
+ +
+
hash_table_insert_value
+
static int hash_table_insert_value(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
+

Subroutine of hash_table_insert Inserts given value in hash, uses quadratic probing

Parameters
hash
unsigned long

Hash to be used

value
long

Value of this entity

hash_table

Table to be used

Returns

<TINYOBJ_HASH_TABLE_ERROR> upon failure or <TINYOBJ_HASH_TABLE_SUCCESS> after succeding

+
+ +
+
hash_table_insert
+
static int hash_table_insert(
unsigned long hash,
long value,
tinyobj_material_table_t *hash_table
)
+

Inserts given value in hash, calls hash_table_insert_value

Parameters
hash
unsigned long

Hash to be used

value
long

Value of this entity

hash_table

Table to be used

Returns

<TINYOBJ_HASH_TABLE_ERROR> upon failure or <TINYOBJ_HASH_TABLE_SUCCESS> after succeding

+
+ +
+
hash_table_find
+
static hash_table_entry_t *hash_table_find(
unsigned long hash,
tinyobj_material_table_t *hash_table
)
+

Tries to find given hash in the table

Parameters
hash
unsigned long

Hash to be found

hash_table

Table to be used

Returns

Entry upon succeding or NULL if failure to find

+
+ +
+
hash_table_maybe_grow
+
static void hash_table_maybe_grow(
size_t new_n,
tinyobj_material_table_t *hash_table
)
+

Grows given hash_table to new_n if new_n is less or equal to capacity

+
+ +
+
hash_table_exists
+
static int hash_table_exists(
const char *name,
tinyobj_material_table_t *hash_table
)
+

Tries to find 'name' in hash_table, returns true if successful

See
+
+ +
+
hash_table_set
+
static void hash_table_set(
const char *name,
size_t val,
tinyobj_material_table_t *hash_table
)
+

Inserts value into hash_table, in name; creates new entry if it doesn't exist

See
+
+ +
+
hash_table_get
+
static long hash_table_get(
const char *name,
tinyobj_material_table_t *hash_table
)
+

Returns value of entity with name, -1 when failing

+
+ +
+
UTHash interface to tinyobj
+
+ +
+
tinyobj_material_table_t
+

Material table

+
+ +
+
UTHash interface to tinyobj
+
+ +
+
tinyobj_reserved
+

Reserved key used by the hashtable implementation so the table isn't deleted

+
+ +
+
tinyobj_hash_find
+
static void tinyobj_hash_find(
tinyobj_material_table_t *table,
const char *name,
tinyobj_material_table_tEntry **entryOUT
)
+

Tries to find object with 'name' as key

Parameters
table

Table to be used

name
const char*

Key

entryOUT
tinyobj_material_table_tEntry**

[out] Result

Returns

Sets entry to a valid result if entry was found, otherwise sets it to NULL

+
+ +
+
tinyobj_hash_add
+
static int tinyobj_hash_add(
tinyobj_material_table_t *table,
const char *name,
size_t length,
long value
)
+

Adds a material to the given material table If the material was already added its value is replaced

Parameters
table

Table to be used

name
const char*

Key

length
size_t

Name length

value
long

Value of the new entity

Returns

Returns true if successful, false otherwise

+
+ +
+
tinyobj_hash_free
+
static void tinyobj_hash_free(
tinyobj_material_table_t *table,
unsigned char bfree_name
)
+

Frees all entries of a given tinyobj_material_table_t

Parameters
table

Table to be freed

bfree_name
unsigned char

Should the key (name) be freed

Usually the name pointer is owned by the materials list by this point

See tinyobj_parse_and_index_mtl_file, freeing could lead to a segfault

+
+ +
+
tinyobj_hash_init
+
static void tinyobj_hash_init(
tinyobj_material_table_t *table
)
+

Initialises given table, and adds a reserved key

+
+ +
+
Material handling (.mtl)
+
+ +
+
initMaterial
+
static void initMaterial(
tinyobj_material_t *material
)
+

Defaults given material

+
+ +
+
tinyobj_mtl_parse_map
+
static int tinyobj_mtl_parse_map(
tinyobj_material_t *material,
const char **token,
const char *line_end
)
+

Parses a texture name from token ('map_')

Supported map types:
map_Ka - ambient texture
map_Kd - diffuse texture
map_Ks - specular texture
map_Ns - specular highlight texture
map_bump - bump texture
map_d - alpha texture
Parameters
material

Material to be filled

token
const char**

Buffer

line_end
const char*

Buffer end (halting point)

Returns
+
+ +
+
tinyobj_mtl_parse_optical
+
static int tinyobj_mtl_parse_optical(
tinyobj_material_t *material,
const char **token
)
+

Parses an optical coefficient from token ('N')

Supported coefficient types:
Ni - Index Of Refraction (ior) 'optical density'
Ns - Specular exponent 'shininess'
Parameters
material

Material to be filled

token
const char**

Buffer

Returns
+
+ +
+
tinyobj_mtl_parse_color
+
static int tinyobj_mtl_parse_color(
tinyobj_material_t *material,
const char **token
)
+

Parses a color coefficient from token ('K')

Supported coefficient types:
Ka - Ambient
Kd - Diffuse
Ks - Specular
Kt - Transmittance
Ke - Emissive
Parameters
material

Material to be filled

token
const char**

Buffer

Returns
+
+ +
+
tinyobj_parse_and_index_mtl_file
+
static int tinyobj_parse_and_index_mtl_file(
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *filename,
tinyobj_material_table_t *material_table
)
+

Parses and indexes a given material file

Parameters
materials_out

[out] Completed list of materials

num_materials_out
unsigned int*

[out] Length of materials_out

filename
const char*

File to be parsed

material_table

Table to be filled (can be NULL)

Returns
+
+ +
+
Aplication Programming Interface (.mtl)
+
+ +
+
tinyobj_parse_mtl_file
+
int tinyobj_parse_mtl_file(
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *filename
)
+

Parses a material file, see tinyobj_parse_and_index_mtl_file

+
+ +
+
tinyobj_material_free
+
void tinyobj_material_free(
tinyobj_material_t *materials,
unsigned int num_materials
)
+

Frees material data

Parameters
materials

Material list to be freed

num_materials
unsigned int

Length of materials

+
+ +
+
Object handling (.obj)
+
+ +
+
CommandType
+

Command identifiers used when parsing

<tinyobj_parse_obj_line>

COMMAND_EMPTY

No command

COMMAND_V

'v' Vertex <tinyobj_obj_parse_vertex>

COMMAND_VN

'vn' Vertex normal <tinyobj_obj_parse_vertex>

COMMAND_VT

'vt' Texture coordinate <tinyobj_obj_parse_vertex>

COMMAND_VP

'vp' Parameter space vertex <tinyobj_obj_parse_vertex>

COMMAND_F

'f' Face  <tinyobj_obj_parse_face>

COMMAND_P

'p' Point <tinyobj_obj_parse_point>

COMMAND_L

'l' Line  <tinyobj_obj_parse_line>

COMMAND_G

'g' Group name

COMMAND_O

'o' Object name

COMMAND_S

's' Smoothing group

COMMAND_USEMTL

'usemtl' Use material

COMMAND_MTLLIB

'mtllib' Load material

+
+ +
+
Command
+

Command information used to parse obj files <tinyobj_parse_obj_line>

Fields
type

Command

info

Specific command information

+
+ +
+
Command.​u_information
+

Specific command information

Fields
v

Geometric vertex <COMMAND_V>

vn

Vertex normal <COMMAND_VN>

vt

Texture vertex <COMMAND_VT>

vp

Parameter space vertex <COMMAND_VP>

f

Face <COMMAND_F>

l

Line <COMMAND_L>

p

Point <COMMAND_P>

g

Group <COMMAND_G>

o

Object <COMMAND_O>

usemtl

Use material <COMMAND_USEMTL>

mtllib

Material lib (file) <COMMAND_MTLLIB>

smoothing_id

Smoothing group <COMMAND_S>

See

<CommandType>

+
+ +
+
Command.​s_group_information
+

Grouping and Display/Render attributes

Fields
Name

Name of group

len

Group name length

+
+ +
+
CommandInformation
+

General information regarding the commands of a given file

Fields
command_list

Array of commands

mtllib_line_index

Index of MLLIB in command list (-1 no command)

count

command_list count

counter

Counter of command types

+
+ +
+
CommandInformation.​s_counter
+

Counter of command types

Fields
v

Count of geometric vertices

vn

Count of vertex normals

vt

Count of texture vertices

vp

Count of parameter space vertices

f

Count of faces

l

Count of lines

p

Count of points

shapes

Shapes

+
+ +
+
Object handling (.obj)
+
+ +
+
tinyobj_obj_free_point
+
static void tinyobj_obj_free_point(
tinyobj_point_t *p
)
+

Frees allocated data of a given point

+
+ +
+
tinyobj_obj_parse_point
+
static int tinyobj_obj_parse_point(
Command *command,
const char **token
)
+

Parses a point from token ('p')

Parameters
command

Command information to be filled

token
const char**

Token to be parsed

Returns
+
+ +
+
tinyobj_triplet_list_grow
+
unsigned char tinyobj_triplet_list_grow(
tinyobj_vertex_index_t **list,
size_t new_len
)
+

Grows the given triplet list to a new size If the growth fails the list is unchanged

Parameters
list

List to grow

new_len
size_t

New length

Returns

True if successful, false otherwise

+
+ +
+
tinyobj_triplet_list_new
+
static tinyobj_vertex_index_t *tinyobj_triplet_list_new(
size_t len
)
+

Allocates memory for a new triplet list

Parameters
len
size_t

Initial length of list

Returns

Pointer to new list when successful, NULL if failure

+
+ +
+
tinyobj_obj_free_line
+
static void tinyobj_obj_free_line(
tinyobj_line_t *l
)
+

Frees allocated data of a given line

+
+ +
+
tinyuobj_obj_parse_line
+

Parses a line from token ('l')

Parameters
command

Command information to be filled

token

Token to be parsed

Returns
+
+ +
+
tinyobj_obj_free_face
+
static void tinyobj_obj_free_face(
tinyobj_face_t *f
)
+

Frees allocated data of a given face

+
+ +
+
tinyobj_obj_parse_face
+
static int tinyobj_obj_parse_face(
Command *command,
const char **token,
int triangulate
)
+

Parses a face from token ('f') and fills given command with face information

Parameters
command

Command information to be filled

token
const char**

Token to be parsed

triangulate
int

(bool) Should this face be triangulated? TINYOBJ_FLAG_TRIANGULATE

Returns
+
+ +
+
tinyobj_obj_parse_vertex
+
static int tinyobj_obj_parse_vertex(
Command *command,
const char **token
)
+

Parses a vertex from token ('v')

v, vn, vt, vp
Parameters
command

Command information to be filled

token
const char**

Token to be parsed

Returns
+
+ +
+
tinyobj_parse_obj_line
+
static int tinyobj_parse_obj_line(
CommandInformation *command_info,
int pos,
const char *p,
size_t p_len,
int flags
)
+

Parses line of an .obj file

Parameters
command_info

Command information list

pos
int

Current position in command information

p
const char*

String containing line

p_len
size_t

Line length

flags
int

Reading flags

Returns
+
+ +
+
tinyobj_parse_obj_line_traverse
+
static int tinyobj_parse_obj_line_traverse(
const char *buf,
size_t len,
CommandInformation *command_info,
unsigned int flags
)
+

Traverses and parses all lines of given buffer

Parameters
buf
const char*

Buffer to be parsed

len
size_t

Buffer length

command_info

Command information to be filled

flags
unsigned int

Parsing flags

Returns
+
+ +
+
tinyobj_command_info_free
+
static void tinyobj_command_info_free(
CommandInformation *command_info
)
+

Frees given command information

+
+ +
+
tinyobj_shape_construct
+
static void tinyobj_shape_construct(
tinyobj_shape_t **shapes,
unsigned int *num_shapes,
CommandInformation *command_info
)
+

Constructs shape information

Parameters
shapes

[in/out] Pointer to be filled

num_shapes
unsigned int*

[out] Length of shapes

command_info

Information used to construct the shapes

+
+ +
+
tinyobj_shape_free
+
void tinyobj_shape_free(
tinyobj_shape_t *shapes,
unsigned int num_shapes
)
+

Frees shape data

Parameters
shapes

Shape information to be freed

num_shapes
unsigned int

Length of shapes

+
+ +
+
tinyobj_attrib_construct
+
static void tinyobj_attrib_construct(
tinyobj_attrib_t *attrib,
CommandInformation *command_info,
tinyobj_material_table_t *material_table
)
+

Constructs attribute data with given information

Parameters
attrib

[in/out] Attribute to be filled

command_info

Information used to fill attrib

material_table

Material table used (can be NULL)

+
+ +
+
Aplication Programming Interface (.obj)
+
+ +
+
tinyobj_attrib_free
+
void tinyobj_attrib_free(
tinyobj_attrib_t *attrib
)
+

Frees attribute data

+
+ +
+
tinyobj_attrib_init
+
static void tinyobj_attrib_init(
tinyobj_attrib_t *attrib
)
+

Initializes given attribute information to default values

+
+ +
+
tinyobj_parse_obj
+
int tinyobj_parse_obj(
tinyobj_attrib_t *attrib,
tinyobj_shape_t **shapes,
unsigned int *num_shapes,
tinyobj_material_t **materials_out,
unsigned int *num_materials_out,
const char *buf,
size_t len,
unsigned int flags
)
+

Parses .obj file

Parameters
attrib

[in/out] Attributes to be filled

shapes

[in/out] Shapes to be filled

num_shapes
unsigned int*

[in/out] Length of shapes

materials_out

[in/out] Materials to be filled

num_materials_out
unsigned int*

[in/out] Length of materials

buf
const char*

Buffer to be read

len
size_t

Buffer length

flags
unsigned int

Parsing flags

Returns
+
+ +
+
Compatibility with older versions (deprecated)
+
+ +
+
tinyobj_attrib_free_compat
+
void tinyobj_attrib_free_compat(
COMPATtinyobj_attrib_t *attrib
)
+

Frees given attribute

+
+ +
+
tinyobj_new2old
+
int tinyobj_new2old(
tinyobj_attrib_t *attrib,
COMPATtinyobj_attrib_t *out_attrib
)
+

Converts new attribute format to the old one This expects that the faces were triangulated

Parameters
attrib

[in] Attribute to be converted

out_attrib

[out] Attribute to be filled

Returns
+
+ + \ No newline at end of file diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..82619a8 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,9 @@ + + +TinyObj Documentation + + + + + +
Close
TinyObj
Tiny but powerful single file wavefront obj loader
Copyright © 2016 - 2019 Syoyo Fujita and many contributors (the MIT license).
Last updated 2019/Aug/08
Generated by Natural Docs
\ No newline at end of file diff --git a/doc/menu/classes.js b/doc/menu/classes.js new file mode 100644 index 0000000..5df92c7 --- /dev/null +++ b/doc/menu/classes.js @@ -0,0 +1 @@ +NDMenu.OnSectionLoaded("classes.js",[[1,"Command"],[2,"Command","CClass:Command.",[[1,"s_group_information"],[1,"u_information"]]],[1,"CommandInformation"],[2,"CommandInformation","CClass:CommandInformation.",[[1,"s_counter"]]],[1,"COMPATtinyobj_attrib_t"],[1,"hash_table_entry_t"],[1,"tinyobj_attrib_t"],[1,"tinyobj_coefficient_t"],[1,"tinyobj_face_t"],[1,"tinyobj_line_t"],[2,"tinyobj_line_t","CClass:tinyobj_line_t.",[[1,"s_line_vertex_index"]]],[1,"tinyobj_material_t"],[1,"tinyobj_material_table_t"],[1,"tinyobj_point_t"],[1,"tinyobj_shape_t"],[1,"tinyobj_vertex_index_t"],[1,"tinyobj_vertex_normal_t"],[1,"tinyobj_vertex_param_t"],[1,"tinyobj_vertex_t"],[1,"tinyobj_vertex_texture_t"]]); \ No newline at end of file diff --git a/doc/menu/files.js b/doc/menu/files.js new file mode 100644 index 0000000..fedbe23 --- /dev/null +++ b/doc/menu/files.js @@ -0,0 +1 @@ +NDMenu.OnSectionLoaded("files.js",[[1,"tinyobj_loader_c.h"]]); \ No newline at end of file diff --git a/doc/menu/tabs.js b/doc/menu/tabs.js new file mode 100644 index 0000000..4cdef48 --- /dev/null +++ b/doc/menu/tabs.js @@ -0,0 +1 @@ +NDMenu.OnTabsLoaded([["File","Files","File:","files.js"],["Class","Classes","CClass:","classes.js"]]); \ No newline at end of file diff --git a/doc/other/home.html b/doc/other/home.html new file mode 100644 index 0000000..ed862c0 --- /dev/null +++ b/doc/other/home.html @@ -0,0 +1,13 @@ + + +TinyObj Documentation + + + + + + + +
TinyObj
Tiny but powerful single file wavefront obj loader
+ +
Copyright © 2016 - 2019 Syoyo Fujita and many contributors (the MIT license).
Last updated 2019/Aug/08
\ No newline at end of file diff --git a/doc/search/index.js b/doc/search/index.js new file mode 100644 index 0000000..a8ad783 --- /dev/null +++ b/doc/search/index.js @@ -0,0 +1 @@ +NDSearch.OnPrefixIndexLoaded(["arr","bas","cod","com","cre","des","dyn","fix","han","has","ini","is_","len","lic","mac","par","ret","s_c","s_g","s_l","ski","str","tab","tin","try","u_i","unt"]); \ No newline at end of file diff --git a/doc/search/keywords/006100720072.js b/doc/search/keywords/006100720072.js new file mode 100644 index 0000000..d842931 --- /dev/null +++ b/doc/search/keywords/006100720072.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("arr",["Constant"],[["array",,[[,"Dynamic array basic parameters",,,0,"File:tinyobj_loader_c.h:Dynamic_array_basic_parameters"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/006200610073.js b/doc/search/keywords/006200610073.js new file mode 100644 index 0000000..11b661e --- /dev/null +++ b/doc/search/keywords/006200610073.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("bas",["Constant"],[["basic",,[[,"Dynamic array basic parameters",,,0,"File:tinyobj_loader_c.h:Dynamic_array_basic_parameters"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/0063006f0064.js b/doc/search/keywords/0063006f0064.js new file mode 100644 index 0000000..2bd704d --- /dev/null +++ b/doc/search/keywords/0063006f0064.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("cod",["Constant"],[["codes",,[["COMPATtinyobj_attrib_t","Hash table return codes",,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.Hash_table_return_codes","CClass:COMPATtinyobj_attrib_t:Hash_table_return_codes"],[,"Return codes",,,0,"File:tinyobj_loader_c.h:Return_codes"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/0063006f006d.js b/doc/search/keywords/0063006f006d.js new file mode 100644 index 0000000..355d97d --- /dev/null +++ b/doc/search/keywords/0063006f006d.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("com",["Struct","Constant","Enumeration"],[["Command",,[[,,,,0,"File:tinyobj_loader_c.h:Command","CClass:Command"]]],["COMMAND_EMPTY",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_EMPTY","CClass:tinyobj_material_table_t:COMMAND_EMPTY"]]],["COMMAND_F",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_F","CClass:tinyobj_material_table_t:COMMAND_F"]]],["COMMAND_G",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_G","CClass:tinyobj_material_table_t:COMMAND_G"]]],["COMMAND_L",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_L","CClass:tinyobj_material_table_t:COMMAND_L"]]],["COMMAND_MTLLIB",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_MTLLIB","CClass:tinyobj_material_table_t:COMMAND_MTLLIB"]]],["COMMAND_O",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_O","CClass:tinyobj_material_table_t:COMMAND_O"]]],["COMMAND_P",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_P","CClass:tinyobj_material_table_t:COMMAND_P"]]],["COMMAND_S",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_S","CClass:tinyobj_material_table_t:COMMAND_S"]]],["COMMAND_USEMTL",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_USEMTL","CClass:tinyobj_material_table_t:COMMAND_USEMTL"]]],["COMMAND_V",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_V","CClass:tinyobj_material_table_t:COMMAND_V"]]],["COMMAND_VN",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_VN","CClass:tinyobj_material_table_t:COMMAND_VN"]]],["COMMAND_VP",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_VP","CClass:tinyobj_material_table_t:COMMAND_VP"]]],["COMMAND_VT",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.COMMAND_VT","CClass:tinyobj_material_table_t:COMMAND_VT"]]],["CommandInformation",,[[,,,,0,"File:tinyobj_loader_c.h:CommandInformation","CClass:CommandInformation"]]],["CommandType",,[["tinyobj_material_table_t",,,,2,"File:tinyobj_loader_c.h:tinyobj_material_table_t.CommandType","CClass:tinyobj_material_table_t:CommandType"]]],["COMPATtinyobj_attrib_t",,[[,,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t","CClass:COMPATtinyobj_attrib_t"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/006300720065.js b/doc/search/keywords/006300720065.js new file mode 100644 index 0000000..911b38d --- /dev/null +++ b/doc/search/keywords/006300720065.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("cre",["Function"],[["create_hash_table",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.create_hash_table","CClass:tinyobj_material_table_t:create_hash_table"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/006400650073.js b/doc/search/keywords/006400650073.js new file mode 100644 index 0000000..043bc5f --- /dev/null +++ b/doc/search/keywords/006400650073.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("des",["Function"],[["destroy_hash_table",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.destroy_hash_table","CClass:tinyobj_material_table_t:destroy_hash_table"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/00640079006e.js b/doc/search/keywords/00640079006e.js new file mode 100644 index 0000000..89db2c6 --- /dev/null +++ b/doc/search/keywords/00640079006e.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("dyn",["Constant","Function"],[["Dynamic",,[[,"Dynamic array basic parameters",,,0,"File:tinyobj_loader_c.h:Dynamic_array_basic_parameters"]]],["dynamic_fgets",,[["COMPATtinyobj_attrib_t",,,,1,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.dynamic_fgets","CClass:COMPATtinyobj_attrib_t:dynamic_fgets"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/006600690078.js b/doc/search/keywords/006600690078.js new file mode 100644 index 0000000..044b29c --- /dev/null +++ b/doc/search/keywords/006600690078.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("fix",["Function"],[["fixIndex",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.fixIndex","CClass:COMPATtinyobj_attrib_t:fixIndex"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/00680061006e.js b/doc/search/keywords/00680061006e.js new file mode 100644 index 0000000..4c51f16 --- /dev/null +++ b/doc/search/keywords/00680061006e.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("han",["Function"],[["handling",,[["COMPATtinyobj_attrib_t","String handling macros",,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.String_handling_macros","CClass:COMPATtinyobj_attrib_t:String_handling_macros"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/006800610073.js b/doc/search/keywords/006800610073.js new file mode 100644 index 0000000..aa866e5 --- /dev/null +++ b/doc/search/keywords/006800610073.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("has",["Constant","Function","Struct"],[["Hash",,[["COMPATtinyobj_attrib_t","Hash table return codes",,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.Hash_table_return_codes","CClass:COMPATtinyobj_attrib_t:Hash_table_return_codes"]]],["hash_djb2",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.hash_djb2","CClass:tinyobj_material_table_t:hash_djb2"]]],["hash_table_entry_t",,[[,,,,2,"File:tinyobj_loader_c.h:hash_table_entry_t","CClass:hash_table_entry_t"]]],["hash_table_exists",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.hash_table_exists","CClass:tinyobj_material_table_t:hash_table_exists"]]],["hash_table_find",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.hash_table_find","CClass:tinyobj_material_table_t:hash_table_find"]]],["hash_table_get",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.hash_table_get","CClass:tinyobj_material_table_t:hash_table_get"]]],["hash_table_insert",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.hash_table_insert","CClass:tinyobj_material_table_t:hash_table_insert"]]],["hash_table_insert_value",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.hash_table_insert_value","CClass:tinyobj_material_table_t:hash_table_insert_value"]]],["hash_table_maybe_grow",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.hash_table_maybe_grow","CClass:tinyobj_material_table_t:hash_table_maybe_grow"]]],["hash_table_set",,[["tinyobj_material_table_t",,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t.hash_table_set","CClass:tinyobj_material_table_t:hash_table_set"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/0069006e0069.js b/doc/search/keywords/0069006e0069.js new file mode 100644 index 0000000..2f0c61c --- /dev/null +++ b/doc/search/keywords/0069006e0069.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("ini",["Function"],[["initMaterial",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.initMaterial","CClass:tinyobj_material_table_t:initMaterial"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/00690073005f.js b/doc/search/keywords/00690073005f.js new file mode 100644 index 0000000..19e3f2b --- /dev/null +++ b/doc/search/keywords/00690073005f.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("is_",["Function"],[["IS_DIGIT",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.IS_DIGIT","CClass:COMPATtinyobj_attrib_t:IS_DIGIT"]]],["is_line_ending",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.is_line_ending","CClass:COMPATtinyobj_attrib_t:is_line_ending"]]],["IS_NEW_LINE",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.IS_NEW_LINE","CClass:COMPATtinyobj_attrib_t:IS_NEW_LINE"]]],["IS_SPACE",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.IS_SPACE","CClass:COMPATtinyobj_attrib_t:IS_SPACE"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/006c0065006e.js b/doc/search/keywords/006c0065006e.js new file mode 100644 index 0000000..0c8ffdb --- /dev/null +++ b/doc/search/keywords/006c0065006e.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("len",["Function"],[["length_until_line_feed",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.length_until_line_feed","CClass:COMPATtinyobj_attrib_t:length_until_line_feed"]]],["length_until_newline_comment_space",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.length_until_newline_comment_space","CClass:COMPATtinyobj_attrib_t:length_until_newline_comment_space"]]],["length_until_space",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.length_until_space","CClass:COMPATtinyobj_attrib_t:length_until_space"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/006c00690063.js b/doc/search/keywords/006c00690063.js new file mode 100644 index 0000000..551ee8c --- /dev/null +++ b/doc/search/keywords/006c00690063.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("lic",["Information"],[["License",,[[,,,,0,"File:tinyobj_loader_c.h:License"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/006d00610063.js b/doc/search/keywords/006d00610063.js new file mode 100644 index 0000000..26f9bde --- /dev/null +++ b/doc/search/keywords/006d00610063.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("mac",["Function"],[["macros",,[["COMPATtinyobj_attrib_t","String handling macros",,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.String_handling_macros","CClass:COMPATtinyobj_attrib_t:String_handling_macros"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/007000610072.js b/doc/search/keywords/007000610072.js new file mode 100644 index 0000000..3661354 --- /dev/null +++ b/doc/search/keywords/007000610072.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("par",["Constant","Function"],[["parameters",,[[,"Dynamic array basic parameters",,,0,"File:tinyobj_loader_c.h:Dynamic_array_basic_parameters"]]],["parseFloat",,[["COMPATtinyobj_attrib_t",,,,1,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.parseFloat","CClass:COMPATtinyobj_attrib_t:parseFloat"]]],["parseFloat2",,[["COMPATtinyobj_attrib_t",,,,1,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.parseFloat2","CClass:COMPATtinyobj_attrib_t:parseFloat2"]]],["parseFloat3",,[["COMPATtinyobj_attrib_t",,,,1,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.parseFloat3","CClass:COMPATtinyobj_attrib_t:parseFloat3"]]],["parseInt",,[["COMPATtinyobj_attrib_t",,,,1,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.parseInt","CClass:COMPATtinyobj_attrib_t:parseInt"]]],["parseRawTriple",,[["COMPATtinyobj_attrib_t",,,,1,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.parseRawTriple","CClass:COMPATtinyobj_attrib_t:parseRawTriple"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/007200650074.js b/doc/search/keywords/007200650074.js new file mode 100644 index 0000000..492ee90 --- /dev/null +++ b/doc/search/keywords/007200650074.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("ret",["Constant"],[["Return",,[[,"Return codes",,,0,"File:tinyobj_loader_c.h:Return_codes"],["COMPATtinyobj_attrib_t","Hash table return codes",,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.Hash_table_return_codes","CClass:COMPATtinyobj_attrib_t:Hash_table_return_codes"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/0073005f0063.js b/doc/search/keywords/0073005f0063.js new file mode 100644 index 0000000..4c513ac --- /dev/null +++ b/doc/search/keywords/0073005f0063.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("s_c",["Struct"],[["s_counter",,[["CommandInformation",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter","CClass:CommandInformation.s_counter"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/0073005f0067.js b/doc/search/keywords/0073005f0067.js new file mode 100644 index 0000000..86f3cca --- /dev/null +++ b/doc/search/keywords/0073005f0067.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("s_g",["Struct"],[["s_group_information",,[["Command",,,,0,"File:tinyobj_loader_c.h:Command.s_group_information","CClass:Command.s_group_information"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/0073005f006c.js b/doc/search/keywords/0073005f006c.js new file mode 100644 index 0000000..db9a99d --- /dev/null +++ b/doc/search/keywords/0073005f006c.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("s_l",["Struct"],[["s_line_vertex_index",,[["tinyobj_line_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_line_t.s_line_vertex_index","CClass:tinyobj_line_t.s_line_vertex_index"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/0073006b0069.js b/doc/search/keywords/0073006b0069.js new file mode 100644 index 0000000..58dbbbc --- /dev/null +++ b/doc/search/keywords/0073006b0069.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("ski",["Function"],[["skip_space",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.skip_space","CClass:COMPATtinyobj_attrib_t:skip_space"]]],["skip_space_and_cr",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.skip_space_and_cr","CClass:COMPATtinyobj_attrib_t:skip_space_and_cr"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/007300740072.js b/doc/search/keywords/007300740072.js new file mode 100644 index 0000000..d714a71 --- /dev/null +++ b/doc/search/keywords/007300740072.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("str",["Function"],[["strdup_ml",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.strdup_ml","CClass:COMPATtinyobj_attrib_t:strdup_ml"]]],["String",,[["COMPATtinyobj_attrib_t","String handling macros",,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.String_handling_macros","CClass:COMPATtinyobj_attrib_t:String_handling_macros"]]],["strndup",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.strndup","CClass:COMPATtinyobj_attrib_t:strndup"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/007400610062.js b/doc/search/keywords/007400610062.js new file mode 100644 index 0000000..27288d8 --- /dev/null +++ b/doc/search/keywords/007400610062.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("tab",["Constant"],[["table",,[["COMPATtinyobj_attrib_t","Hash table return codes",,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.Hash_table_return_codes","CClass:COMPATtinyobj_attrib_t:Hash_table_return_codes"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/00740069006e.js b/doc/search/keywords/00740069006e.js new file mode 100644 index 0000000..be2f54f --- /dev/null +++ b/doc/search/keywords/00740069006e.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("tin",["Function","Struct","Constant"],[["tinyobj_attrib_construct",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_attrib_construct","CClass:CommandInformation.s_counter:tinyobj_attrib_construct"]]],["tinyobj_attrib_free",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_attrib_free","CClass:CommandInformation.s_counter:tinyobj_attrib_free"]]],["tinyobj_attrib_free_compat",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_attrib_free_compat","CClass:CommandInformation.s_counter:tinyobj_attrib_free_compat"]]],["tinyobj_attrib_init",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_attrib_init","CClass:CommandInformation.s_counter:tinyobj_attrib_init"]]],["tinyobj_attrib_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_attrib_t","CClass:tinyobj_attrib_t"]]],["tinyobj_coefficient_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_coefficient_t","CClass:tinyobj_coefficient_t"]]],["tinyobj_command_info_free",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_command_info_free","CClass:CommandInformation.s_counter:tinyobj_command_info_free"]]],["TINYOBJ_COUPLE_GROWTH_FACTOR",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_COUPLE_GROWTH_FACTOR"]]],["TINYOBJ_COUPLE_INITIAL_COUNT",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_COUPLE_INITIAL_COUNT"]]],["TINYOBJ_ENABLE_OLDER_ATTRIBUTE",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_ENABLE_OLDER_ATTRIBUTE"]]],["TINYOBJ_ERROR_EMPTY",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_ERROR_EMPTY"]]],["TINYOBJ_ERROR_FILE_OPERATION",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_ERROR_FILE_OPERATION"]]],["TINYOBJ_ERROR_INVALID_PARAMETER",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_ERROR_INVALID_PARAMETER"]]],["TINYOBJ_ERROR_MALFORMED_PARAMETER",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_ERROR_MALFORMED_PARAMETER"]]],["TINYOBJ_ERROR_MEMORY",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_ERROR_MEMORY"]]],["TINYOBJ_ERROR_NOT_SET",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_ERROR_NOT_SET"]]],["TINYOBJ_ERROR_UNKNOWN_PARAMETER",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_ERROR_UNKNOWN_PARAMETER"]]],["tinyobj_face_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_face_t","CClass:tinyobj_face_t"]]],["TINYOBJ_FLAG_TRIANGULATE",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_FLAG_TRIANGULATE"]]],["tinyobj_hash_add",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.tinyobj_hash_add","CClass:tinyobj_material_table_t:tinyobj_hash_add"]]],["tinyobj_hash_find",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.tinyobj_hash_find","CClass:tinyobj_material_table_t:tinyobj_hash_find"]]],["tinyobj_hash_free",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.tinyobj_hash_free","CClass:tinyobj_material_table_t:tinyobj_hash_free"]]],["tinyobj_hash_init",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.tinyobj_hash_init","CClass:tinyobj_material_table_t:tinyobj_hash_init"]]],["TINYOBJ_HASH_TABLE_DEFAULT_SIZE",,[["COMPATtinyobj_attrib_t",,,,2,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.TINYOBJ_HASH_TABLE_DEFAULT_SIZE","CClass:COMPATtinyobj_attrib_t:TINYOBJ_HASH_TABLE_DEFAULT_SIZE"]]],["TINYOBJ_HASH_TABLE_ERROR",,[["COMPATtinyobj_attrib_t",,,,2,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.TINYOBJ_HASH_TABLE_ERROR","CClass:COMPATtinyobj_attrib_t:TINYOBJ_HASH_TABLE_ERROR"]]],["TINYOBJ_HASH_TABLE_SUCCESS",,[["COMPATtinyobj_attrib_t",,,,2,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.TINYOBJ_HASH_TABLE_SUCCESS","CClass:COMPATtinyobj_attrib_t:TINYOBJ_HASH_TABLE_SUCCESS"]]],["TINYOBJ_INVALID_INDEX",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_INVALID_INDEX"]]],["tinyobj_line_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_line_t","CClass:tinyobj_line_t"]]],["TINYOBJ_LOADER_C_IMPLEMENTATION",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_LOADER_C_IMPLEMENTATION"]]],["tinyobj_material_free",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.tinyobj_material_free","CClass:tinyobj_material_table_t:tinyobj_material_free"]]],["TINYOBJ_MATERIAL_GROWTH_FACTOR",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_MATERIAL_GROWTH_FACTOR"]]],["TINYOBJ_MATERIAL_INITIAL_COUNT",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_MATERIAL_INITIAL_COUNT"]]],["tinyobj_material_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_material_t","CClass:tinyobj_material_t"]]],["tinyobj_material_table_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_material_table_t","CClass:tinyobj_material_table_t"]]],["tinyobj_mtl_parse_color",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.tinyobj_mtl_parse_color","CClass:tinyobj_material_table_t:tinyobj_mtl_parse_color"]]],["tinyobj_mtl_parse_map",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.tinyobj_mtl_parse_map","CClass:tinyobj_material_table_t:tinyobj_mtl_parse_map"]]],["tinyobj_mtl_parse_optical",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.tinyobj_mtl_parse_optical","CClass:tinyobj_material_table_t:tinyobj_mtl_parse_optical"]]],["tinyobj_new2old",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_new2old","CClass:CommandInformation.s_counter:tinyobj_new2old"]]],["TINYOBJ_NO_COMMAND",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_NO_COMMAND"]]],["tinyobj_obj_free_face",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_obj_free_face","CClass:CommandInformation.s_counter:tinyobj_obj_free_face"]]],["tinyobj_obj_free_line",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_obj_free_line","CClass:CommandInformation.s_counter:tinyobj_obj_free_line"]]],["tinyobj_obj_free_point",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_obj_free_point","CClass:CommandInformation.s_counter:tinyobj_obj_free_point"]]],["tinyobj_obj_parse_face",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_obj_parse_face","CClass:CommandInformation.s_counter:tinyobj_obj_parse_face"]]],["tinyobj_obj_parse_point",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_obj_parse_point","CClass:CommandInformation.s_counter:tinyobj_obj_parse_point"]]],["tinyobj_obj_parse_vertex",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_obj_parse_vertex","CClass:CommandInformation.s_counter:tinyobj_obj_parse_vertex"]]],["tinyobj_parse_and_index_mtl_file",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.tinyobj_parse_and_index_mtl_file","CClass:tinyobj_material_table_t:tinyobj_parse_and_index_mtl_file"]]],["tinyobj_parse_mtl_file",,[["tinyobj_material_table_t",,,,0,"File:tinyobj_loader_c.h:tinyobj_material_table_t.tinyobj_parse_mtl_file","CClass:tinyobj_material_table_t:tinyobj_parse_mtl_file"]]],["tinyobj_parse_obj",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_parse_obj","CClass:CommandInformation.s_counter:tinyobj_parse_obj"]]],["tinyobj_parse_obj_line",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_parse_obj_line","CClass:CommandInformation.s_counter:tinyobj_parse_obj_line"]]],["tinyobj_parse_obj_line_traverse",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_parse_obj_line_traverse","CClass:CommandInformation.s_counter:tinyobj_parse_obj_line_traverse"]]],["TINYOBJ_POINT_GROWTH_FACTOR",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_POINT_GROWTH_FACTOR"]]],["TINYOBJ_POINT_INITIAL_COUNT",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_POINT_INITIAL_COUNT"]]],["tinyobj_point_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_point_t","CClass:tinyobj_point_t"]]],["tinyobj_reserved",,[["tinyobj_material_table_t",,,,2,"File:tinyobj_loader_c.h:tinyobj_material_table_t.tinyobj_reserved","CClass:tinyobj_material_table_t:tinyobj_reserved"]]],["tinyobj_shape_construct",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_shape_construct","CClass:CommandInformation.s_counter:tinyobj_shape_construct"]]],["tinyobj_shape_free",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_shape_free","CClass:CommandInformation.s_counter:tinyobj_shape_free"]]],["tinyobj_shape_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_shape_t","CClass:tinyobj_shape_t"]]],["TINYOBJ_SUCCESS",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_SUCCESS"]]],["TINYOBJ_TRIPLET_GROWTH_FACTOR",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_TRIPLET_GROWTH_FACTOR"]]],["TINYOBJ_TRIPLET_INITIAL_COUNT",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_TRIPLET_INITIAL_COUNT"]]],["tinyobj_triplet_list_grow",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_triplet_list_grow","CClass:CommandInformation.s_counter:tinyobj_triplet_list_grow"]]],["tinyobj_triplet_list_new",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyobj_triplet_list_new","CClass:CommandInformation.s_counter:tinyobj_triplet_list_new"]]],["TINYOBJ_USE_UTHASH",,[[,,,,2,"File:tinyobj_loader_c.h:TINYOBJ_USE_UTHASH"]]],["tinyobj_vertex_index_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_vertex_index_t","CClass:tinyobj_vertex_index_t"]]],["tinyobj_vertex_normal_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_vertex_normal_t","CClass:tinyobj_vertex_normal_t"]]],["tinyobj_vertex_param_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_vertex_param_t","CClass:tinyobj_vertex_param_t"]]],["tinyobj_vertex_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_vertex_t","CClass:tinyobj_vertex_t"]]],["tinyobj_vertex_texture_t",,[[,,,,1,"File:tinyobj_loader_c.h:tinyobj_vertex_texture_t","CClass:tinyobj_vertex_texture_t"]]],["tinyuobj_obj_parse_line",,[["CommandInformation::s_counter",,,,0,"File:tinyobj_loader_c.h:CommandInformation.s_counter.tinyuobj_obj_parse_line","CClass:CommandInformation.s_counter:tinyuobj_obj_parse_line"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/007400720079.js b/doc/search/keywords/007400720079.js new file mode 100644 index 0000000..8f7a61c --- /dev/null +++ b/doc/search/keywords/007400720079.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("try",["Function"],[["try_parse_float",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.try_parse_float","CClass:COMPATtinyobj_attrib_t:try_parse_float"]]],["tryParseDouble",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.tryParseDouble","CClass:COMPATtinyobj_attrib_t:tryParseDouble"]]],["tryParseDouble_assemble",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.tryParseDouble_assemble","CClass:COMPATtinyobj_attrib_t:tryParseDouble_assemble"]]],["tryParseDouble_integer",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.tryParseDouble_integer","CClass:COMPATtinyobj_attrib_t:tryParseDouble_integer"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/0075005f0069.js b/doc/search/keywords/0075005f0069.js new file mode 100644 index 0000000..b494621 --- /dev/null +++ b/doc/search/keywords/0075005f0069.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("u_i",["Struct"],[["u_information",,[["Command",,,,0,"File:tinyobj_loader_c.h:Command.u_information","CClass:Command.u_information"]]]]); \ No newline at end of file diff --git a/doc/search/keywords/0075006e0074.js b/doc/search/keywords/0075006e0074.js new file mode 100644 index 0000000..2e16873 --- /dev/null +++ b/doc/search/keywords/0075006e0074.js @@ -0,0 +1 @@ +NDSearch.OnPrefixDataLoaded("unt",["Function"],[["until_space",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.until_space","CClass:COMPATtinyobj_attrib_t:until_space"]]],["until_space_cr_slash",,[["COMPATtinyobj_attrib_t",,,,0,"File:tinyobj_loader_c.h:COMPATtinyobj_attrib_t.until_space_cr_slash","CClass:COMPATtinyobj_attrib_t:until_space_cr_slash"]]]]); \ No newline at end of file diff --git a/doc/styles/Default/Default.css b/doc/styles/Default/Default.css new file mode 100644 index 0000000..6cc2700 --- /dev/null +++ b/doc/styles/Default/Default.css @@ -0,0 +1,12 @@ +/* +This file is part of Natural Docs, which is Copyright © 2003-2018 Code Clear LLC. +Natural Docs is licensed under version 3 of the GNU Affero General Public +License (AGPL). Refer to License.txt or www.naturaldocs.org for the +complete details. + +This file may be distributed with documentation files generated by Natural Docs. +Such documentation is not covered by Natural Docs' copyright and licensing, +and may have its own copyright and distribution terms as decided by its author. +*/ + +html{height:100%;font:10pt "Trebuchet MS",Tahoma,Geneva,sans-serif}body.NDFramePage{background-color:#E0E0E0;margin:0;padding:0}a:link,a:visited{text-decoration:none}a:hover,a:active{text-decoration:underline}table{margin:0;padding:0;border:0 none;border-spacing:0}td{margin:0;padding:0;border:0 none;border-spacing:0;vertical-align:top}#NDLoadingNotice{height:40px;background:URL("images/menu-loading.gif") no-repeat center center}#NDJavaScriptRequiredNotice{margin:20px;text-align:center;font:10pt Tahoma,Geneva,"Trebuchet MS",Verdana,sans-serif}#NDHeader{background-color:#7070C0;padding:.65em .65em .55em .65em;border-bottom:1px solid #7070C0;z-index:2}#HTitle{font:22pt Georgia,serif;text-shadow:0 .1ex .3ex #202020;line-height:90%}#HTitle,#HTitle a:link,#HTitle a:hover,#HTitle a:active,#HTitle a:visited{color:#FFFFFF;text-decoration:none}#HSubtitle{font:10pt Georgia,serif;margin-left:.65em;text-shadow:0 .1ex .3ex #202020}#HSubtitle,#HSubtitle a:link,#HSubtitle a:hover,#HSubtitle a:active,#HSubtitle a:visited{color:#C8C8C8;text-decoration:none}#NDSearchField{z-index:201;width:25ex;color:#000000;font:10pt Tahoma,Geneva,"Trebuchet MS",Verdana,sans-serif;background:#FFFFFF URL("images/search.png") no-repeat left center;padding:.5ex 1.5ex .5ex 3.5ex;border:0 none;-moz-border-radius:5ex;border-radius:5ex;display:none}.IE #NDSearchField{font:inherit}#NDSearchField.DefaultText{color:#808080;font-style:italic}#NDSearchField:focus{outline:none}#NDSearchResults{z-index:200;overflow:auto;font:10pt Tahoma,Geneva,"Trebuchet MS",Verdana,sans-serif;background-color:#FFFFFF;padding:.5ex 0;border-style:solid;border-width:1px;border-color:#BCBCBC #747474 #747474 #BCBCBC;-moz-box-shadow:.15ex .25ex .4ex #606060;-webkit-box-shadow:.15ex .25ex .4ex #606060;box-shadow:.15ex .25ex .4ex #606060}.SeEntry{padding:.2ex 1.25ex .2ex 3.25ex;color:#000000;border-width:1px 0;border-style:solid;border-color:#FFFFFF}.SeEntry:hover{background-color:#E8E8E8}#SeSelectedEntry{background-color:#E8E8E8;border-color:#D0D0D0}a.SeEntry{display:block}a.SeEntry:link,a.SeEntry:hover,a.SeEntry:active,a.SeEntry:visited{color:#000000;text-decoration:none}.SeQualifier,.SeChildCount{font-weight:normal;color:#7C7C7C}.SeParent.open .SeChildCount{display:none}.SeChildren.closed{display:none}.SeChildren .SeEntry{padding-left:5.5ex}.SeEntryIcon{position:absolute;left:1.7ex;width:.8ex;height:.9em;margin-top:2px}.SeChildren .SeEntryIcon{left:3.9ex}.SeParent .SeEntryIcon{margin-top:4px;margin-left:1px;background:url("images/search-parent.png") center center no-repeat}.TClass .SeEntryIcon,.TInterface .SeEntryIcon,.TStruct .SeEntryIcon{width:2ex;height:1em;left:.9ex;background:url("images/search-class.png") center center no-repeat}.SeChildren .TClass .SeEntryIcon,.SeChildren .TInterface .SeEntryIcon,.SeChildren .TStruct .SeEntryIcon{left:3.15ex}.SeEntry.TClass,.SeEntry.TInterface,.SeEntry.TStruct{font-weight:bold}.SeEntry.MoreResults{font-weight:bold;margin-top:.75em}.SeStatus{margin:.25ex 1.25ex;color:#A0A0A0;text-align:center}.SeEntry+.SeStatus,.SeChildren+.SeStatus{margin-top:.75ex;padding-top:.75ex;border-top:1px solid #C0C0C0}.SeStatus.Searching{font-style:italic}#NDMenu{background-color:#E0E0E0;z-index:5;overflow:auto;width:30ex;display:none}.IE7 #NDMenu{overflow-x:hidden}#NDMenu a:hover,#NDMenu a:active{text-decoration:none}.MLoadingNotice{height:20px;background:URL("images/menu-loading.gif") no-repeat center bottom}#MTabBar{background-color:#C0C0C0}.MTab{background-color:#E0E0E0;border-right:1px solid #C0C0C0;border-bottom:1px solid #C0C0C0;display:inline-block;padding:2px 5px;opacity:.55}.MTab:hover{background-color:#EEEEEE;opacity:1}.MTab.Selected{border-bottom:1px solid #E0E0E0;opacity:1}a.MTab:active,a.MTab:focus{outline:0}.IE6 .MTab,.IE7 .MTab,.IE8 .MTab{background-color:#D0D0D0}.IE6 .MTab.Selected,.IE7 .MTab.Selected,.IE8 .MTab.Selected{background-color:#E0E0E0}.IE6 .MTab:hover,.IE7 .MTab:hover,.IE8 .MTab:hover{background-color:#EEEEEE}.MTabIcon{display:inline-block;width:16px;height:16px;position:relative;top:3px}.IE7 .MTabIcon,.IE6 .MTabIcon{top:0}#MFileTab .MTabIcon{background:url("images/menu-tab-files.png") center center no-repeat}#MClassTab .MTabIcon{background:url("images/menu-tab-classes.png") center center no-repeat}#MDatabaseTab .MTabIcon{background:url("images/menu-tab-database.png") center center no-repeat}.MTabTitle{display:inline-block;color:#606060;font:italic 10pt "Trebuchet MS",Tahoma,Geneva,sans-serif;margin:0 4px}.MTab.Narrow .MTabTitle{width:1px;margin:0 -1px 0 0;visibility:hidden}.IE6 .MTab.Narrow .MTabTitle{display:none}.MEntry{display:block;font:10pt "Trebuchet MS",Tahoma,Geneva,sans-serif;padding:.4ex 1.5ex .4ex 3ex}.MEntry,a.MEntry{color:#606060}a.MEntry:hover,a.MEntry:active{background-color:#EEEEEE}.MTabAsFolder{padding-left:1ex}.MFolder{font-weight:bold}.MFolder.Parent{border-bottom:1px solid #C0C0C0}.MFolder.Parent,a.MFolder.Parent{color:#808080}.MFolder.Parent,.MFolder.Selected{padding-left:1.5ex}.MFolder.Parent.Empty{border-bottom-style:dashed;color:#B0B0B0}.MFolder.Child{padding-right:2.5ex}.MFolderIcon{position:absolute;right:0;background:url("images/menu-folder-arrow.png") center center no-repeat;width:6px;height:7px;padding:.8em 1.2em 0 0}.IE6 .MFolderIcon{padding-top:0}.MFolder.Selected{font-weight:bold;background-color:#FFFFFF;border-bottom:3px solid #888888}.MFile.Selected{background-color:#FFFFFF;font-weight:bold}#NDSummary{background-color:#F8F8F8;border-left:1px solid #D8D8D8;border-right:1px solid #E8E8E8;z-index:4;overflow:auto;width:30ex;display:none}#NDSummary a:hover,#NDSummary a:active{text-decoration:none}.SuLoadingNotice{height:20px;background:URL("images/summary-loading.gif") no-repeat center bottom}.SuEntry{display:block;font:10pt Tahoma,Geneva,"Trebuchet MS",Verdana,sans-serif;padding:1px 1.5ex 1px 3.5ex}.SuEntry.first{margin-top:1ex}.SuEntry.last{margin-bottom:2ex}.SuEntry{color:#707070}.SuEntryIcon{position:absolute;left:1.8ex;width:.8ex;height:.9em;margin-top:2px}.SuEntry.TClass,.SuEntry.TInterface,.SuEntry.TStruct,.SuEntry.TSection,.SuEntry.TDatabase,.SuEntry.TDatabaseTable,.SuEntry.TFile.first{font:bold 11pt "Trebuchet MS",Tahoma,Geneva,sans-serif;color:#6B6B6B;padding-left:1.25ex;padding-top:.75ex;padding-bottom:.75ex;margin:2.5ex 0 .5ex 0;line-height:120%;border-bottom:1px solid #D4D4D4}.SuEntry.TClass.first,.SuEntry.TInterface.first,.SuEntry.TStruct.first,.SuEntry.TSection.first,.SuEntry.TDatabase.first,.SuEntry.TDatabaseTable.first,.SuEntry.TFile.first{border-top:0 none;margin-top:0}.SuEntry .Qualifier{font-weight:normal}.SuEntry.TGroup{font:bold 10pt "Trebuchet MS",Tahoma,Geneva,sans-serif;color:#6B6B6B;padding-left:1.5ex;padding-top:.25ex;padding-bottom:.25ex;margin:1.25ex 0 0 0;line-height:120%}.SuEntry.TClass+.SuEntry.TGroup,.SuEntry.TInterface+.SuEntry.TGroup{margin-top:.75ex}a.SuEntry:hover,a.SuEntry:active{background-color:#E6E6E6}#NDMenuSizer,#NDSummarySizer{cursor:e-resize;width:.8ex;z-index:101}#NDMenuSizer:hover,#NDMenuSizer.Dragging{background-color:#F8F8F8;border-left:1px solid #D8D8D8;border-right:1px solid #D8D8D8}#NDSummarySizer:hover,#NDSummarySizer.Dragging{background-color:#FFFFFF;border-right:1px solid #E8E8E8}#NDContentCover{position:fixed;z-index:100;background:url("images/transparent.gif") no-repeat}#NDContent{z-index:3;overflow:hidden;display:none}#CFrame{width:100%;height:100%;border:0 none}body.NDContentPage{background-color:#FFFFFF;padding:.5em 1em;margin:0}.CTopic{margin-bottom:1em;font:10pt Tahoma,Geneva,"Trebuchet MS",Verdana,sans-serif}.CTitle{font:bold 14pt "Trebuchet MS",Tahoma,Geneva,sans-serif;margin:1.5em 0 .5em 0;border-bottom:1px solid #C0C0C0}.CTopic.first .CTitle{margin-top:0}.CTitle .Qualifier{color:#404040;font-weight:normal}.TClass .CTitle,.TInterface .CTitle,.TStruct .CTitle,.TSection .CTitle,.TDatabase .CTitle,.TDatabaseTable .CTitle,.TFile.first .CTitle{font-size:20pt;border-color:#A8A8A8;line-height:110%;padding-bottom:.05em}.TGroup .CTitle{text-transform:uppercase;font-size:16pt;border-bottom:2px solid #000000}.CHeading{font:bold 11pt "Trebuchet MS",Tahoma,Geneva,sans-serif;margin:1.2em 0 .5em 0}.CHeading:first-child{margin-top:0}.CTopic p{margin:0 0 .5em 0;text-indent:4ex}.CTopic a:link,.CTopic a:visited,.CTopic a:hover{color:#880000}.CTopic a:active{color:#F04040}.CTopic ul{margin:0 0 0 6ex;padding:0}.CTopic ul ul{margin:0 0 0 2.5ex}.CTopic li{list-style-type:disc}.CTopic li p{text-indent:0}table.CDefinitionList{margin:0 0 0 4ex}td.CDLEntry{font:bold 10pt "Trebuchet MS",Tahoma,Geneva,sans-serif;padding:0 2ex .5em 0;min-width:18%;line-height:123%}.CDLParameterType{opacity:0.5}td.CDLDefinition p{text-indent:0}.CTopic pre{font:9pt Consolas,"Courier New",monospace;overflow:auto;margin:1em 4.5ex;border-style:solid;border-color:#E0E0E0;border-width:1px 1px 1px 1.5ex;padding:.5ex 1ex}.CBodyNDMarkup{font:8pt Verdana,sans-serif;color:#787800;background-color:#FFFFF0;border:1px solid #A0A000;padding:.5em}.NDPrototype{font:10pt Consolas,"Courier New",monospace;background-color:#FFFFFF;border:1px solid #808080;margin:0 5ex 1em 5ex;padding:.75ex 1.25ex 1.25ex 1.25ex;overflow:auto}.NDPrototype td{white-space:nowrap}.NDPrototype.NarrowForm td.PBeforeParameters,.NDPrototype.NarrowForm td.PAfterParameters,.NDPrototype.NarrowForm td.PDefaultValue{white-space:normal}.NarrowForm table.PParameters td.last{width:100%}.NarrowForm table.PParameters td.first,.NarrowForm.CStyle td.PAfterParameters{padding-left:3.5ex}.WideForm td.PAfterParameters{vertical-align:bottom}.CStyle .PPostPrototypeLine{padding-left:3.5ex}.CDLParameterType{font:8pt Consolas,"Courier New",monospace;white-space:nowrap}.NDPrototype a:link,.NDPrototype a:visited,.NDPrototype a:hover,.NDPrototype a:active,.CDLParameterType a:link,.CDLParameterType a:visited,.CDLParameterType a:hover,.CDLParameterType a:active{color:#000000}.NDPrototype:hover a:link,.NDPrototype:hover a:visited,.NDPrototype:hover a:hover,.NDPrototype:hover a:active,.CDLEntry:hover .CDLParameterType a:link,.CDLEntry:hover .CDLParameterType a:visited,.CDLEntry:hover .CDLParameterType a:hover,.CDLEntry:hover .CDLParameterType a:active{text-decoration:underline}.PNameModifier,.CStyle .PModifierQualifier,.PDefaultValue,.PDefaultValueSeparator{opacity:0.45}.PNameModifier,.CStyle .PModifierQualifier,.CStyle .PNamePrefix{text-align:right}.NDClassPrototype{margin:0 4ex 1em 4ex}.CPEntry{border-width:1px 2px 2px 1px;border-style:solid;border-color:#000000;padding:.5ex 1ex;margin-bottom:4px;-moz-border-radius:1ex;border-radius:1ex;background-color:#FFFFFF;overflow:auto}a.CPEntry,a.CPAdditionalChildrenNotice{display:block}a.CPEntry:link,a.CPEntry:hover,a.CPEntry:visited,a.CPEntry:active{color:#000000;text-decoration:none}a.CPEntry:hover .CPName,a.CPEntry:active .CPName{text-decoration:underline}.NDClassPrototype .CPEntry.Parent{margin-right:3.5ex}.NDClassPrototype.HasChildren .CPEntry.Parent{margin-right:7ex}.NDClassPrototype.HasParents .CPEntry.Current{margin-left:3.5ex}.NDClassPrototype.HasChildren .CPEntry.Current{margin-right:3.5ex}.NDClassPrototype .CPEntry.Child,.NDClassPrototype .CPAdditionalChildrenNotice{margin-left:3.5ex}.NDClassPrototype.HasParents .CPEntry.Child,.NDClassPrototype.HasParents .CPAdditionalChildrenNotice{margin-left:7ex}.CPName{font:bold 11pt "Trebuchet MS",Tahoma,Geneva,sans-serif;line-height:110%}.CPName .Qualifier,.CPName .TemplateSignature{font-weight:normal;color:#282828}.CPEntry.Parent .CPName,.CPEntry.Child .CPName{font-size:10pt}.CPEntry.Parent,.CPEntry.Child{opacity:.5}.CPEntry .CPPrePrototypeLine,.CPEntry .CPModifiers,.CPEntry .CPPostPrototypeLine{font:8pt Consolas,"Courier New",monospace;opacity:.5}.CPEntry.Parent .CPModifiers,.CPEntry.Child .CPModifiers{opacity:.75}.CPEntry .CPPostPrototypeLine{margin-left:4ex}a.CPAdditionalChildrenNotice:link,a.CPAdditionalChildrenNotice:visited,a.CPAdditionalChildrenNotice:hover,a.CPAdditionalChildrenNotice:active{color:#949494;font:italic 10pt "Trebuchet MS",Tahoma,Geneva,sans-serif;padding:0 1.5ex}.CPAdditionalChildren{display:none}.TFunction .NDPrototype,.TOperator .NDPrototype{background-color:#F0F0F0;border-color:#C8C8C8}.TFunction .SuEntryIcon,.TOperator .SuEntryIcon{background-color:#EAEAEA;border:1px solid #C7C7C7}.TFunction .SeEntryIcon,.TOperator .SeEntryIcon{background-color:#ECECEC;border:1px solid #C2C2C2}.TProperty .NDPrototype{background-color:#ECECFF;border-color:#C0C0D6}.TProperty .SuEntryIcon{background-color:#DCDCFF;border:1px solid #BEBED4}.TProperty .SeEntryIcon{background-color:#D8DAFF;border:1px solid #BABAD0}.TVariable .NDPrototype,.TDatabaseField .NDPrototype{background-color:#FCFCE6;border-color:#D2D2B8}.TVariable .SuEntryIcon,.TDatabaseField .SuEntryIcon{background-color:#F9F9C5;border:1px solid #D0D09A}.TVariable .SeEntryIcon,.TDatabaseField .SeEntryIcon{background-color:#F9F9C4;border:1px solid #CFCEB4}.TConstant .NDPrototype{background-color:#CACACA;border-color:#979797}.TConstant .SuEntryIcon{background-color:#C6C6C6;border:1px solid #A6A6A6}.TConstant .SeEntryIcon{background-color:#C6C6C6;border:1px solid #969696}.TType .NDPrototype,.TEnumeration .NDPrototype,.TDelegate .NDPrototype{background-color:#FCEFDE;border-color:#D8CBBA}.TType .SuEntryIcon,.TEnumeration .SuEntryIcon,.TDelegate .SuEntryIcon{background-color:#F7E6D3;border:1px solid #D8C7B3}.TType .SeEntryIcon,.TEnumeration .SeEntryIcon,.TDelegate .SeEntryIcon{background-color:#F5E3D1;border:1px solid #D4C3B2}.TEvent .NDPrototype{background-color:#E6F9E6;border-color:#BCCFBC}.TEvent .SuEntryIcon{background-color:#D3F3D3;border:1px solid #B2D1B1}.TEvent .SeEntryIcon{background-color:#D3F3D3;border:1px solid #B2D1B1}.NDClassPrototype .CPEntry{border-color:#686868;background-color:#EAEAEA}.IE6 .NDClassPrototype .CPEntry.Parent,.IE6 .NDClassPrototype .CPEntry.Child,.IE7 .NDClassPrototype .CPEntry.Parent,.IE7 .NDClassPrototype .CPEntry.Child,.IE8 .NDClassPrototype .CPEntry.Parent,.IE8 .NDClassPrototype .CPEntry.Child{border-color:#B4B4B4;background-color:#F5F5F5}.NDClassPrototype .CPEntry.TInterface{border-color:#686879;background-color:#EAEAFF}.IE6 .NDClassPrototype .CPEntry.TInterface.Parent,.IE6 .NDClassPrototype .CPEntry.TInterface.Child,.IE7 .NDClassPrototype .CPEntry.TInterface.Parent,.IE7 .NDClassPrototype .CPEntry.TInterface.Child,.IE8 .NDClassPrototype .CPEntry.TInterface.Parent,.IE8 .NDClassPrototype .CPEntry.TInterface.Child{border-color:#B3B3BB;background-color:#F5F5FF}.SHComment{color:#808080}.SHKeyword{color:#880000}.SHNumber,.SHString{color:#000088}.SHPreprocessingDirective{color:#000000;font-weight:bold}.SHMetadata{color:#808000}.CPPrePrototypeLine .SHMetadata{color:#484800}.NDToolTip{background-color:#FFFFF0;border-style:solid;border-width:1px;border-color:#A0A193 #57574B #57574B #A0A193;padding:1ex;overflow:hidden;-moz-border-radius:1ex;border-radius:1ex;-moz-box-shadow:.15ex .25ex .4ex #606060;-webkit-box-shadow:.15ex .25ex .4ex #606060;box-shadow:.15ex .25ex .4ex #606060}.NDToolTip .NDPrototype,.NDToolTip .NDClassPrototype{margin:0;overflow:hidden}.NDToolTip .NDClassPrototype .CPEntry{margin-left:0 !important;margin-right:0 !important}.TTSummary{font:10pt Tahoma,Geneva,"Trebuchet MS",Verdana,sans-serif;max-width:75ex}.NDPrototype+.TTSummary{margin-top:.5em}#NDFooter{background-color:#E0E0E0;font:7pt "Trebuchet MS",Tahoma,Geneva,sans-serif;padding:.1em 1ex;text-align:right;z-index:1}#NDFooter,#NDFooter a{color:#808080}#FCopyright,#FTimestamp{display:inline}#FCopyright:after,#FTimestamp:after{white-space:pre;content:" · "}.IE6 #FCopyright,.IE7 #FCopyright,.IE6 #FTimestamp,.IE7 #FTimestamp{margin-right:3ex}#FGeneratedBy{display:inline}body.NDHomePage{padding:0;margin:0;background-color:#E0E0E0;background-image:-moz-linear-gradient(top,#7070C0,#E0E0E0);background-image:-webkit-gradient(linear,left top,left bottom,from(#7070C0),to(#E0E0E0));background-image:-o-linear-gradient(top,#7070C0,#E0E0E0);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#7070C0',endColorstr='#E0E0E0',GradientType=0 );background-image:-ms-linear-gradient(top,#7070C0 0%,#E0E0E0 100%);background-image:linear-gradient(top,#7070C0,#E0E0E0);background-repeat:no-repeat;background-attachment:fixed;height:100%}.HTitle,.HSubtitle,.HCopyright,.HTimestamp,.HGeneratedBy,.NDHomePage p{text-align:center}.HFrame{padding:4em 5em .5em 5em}.HContent{max-width:28em;margin:0 auto 3em auto;padding:1.5em 2em;overflow:hidden;background-color:#FFFFFF;border-width:.5ex;border-style:solid;border-color:#E0E0E0 #A0A0A0 #202020 #C0C0C0;-moz-box-shadow:0 .25ex .75ex #383838;-webkit-box-shadow:0 .25ex .75ex #383838;box-shadow:0 .25ex .75ex #383838}.HTitle{font:34pt Georgia,serif;line-height:95%}.HSubtitle{font:16pt Georgia,serif;padding-top:.075em}.HFooter{margin:0 auto;margin-top:2em;border-top:1px solid #A0A0A0;padding-top:2em;font:8pt Tahoma,Geneva,"Trebuchet MS",Verdana,sans-serif}.HFooter div{margin-bottom:.5em;color:#A0A0A0}.HFooter a:link,.HFooter a:visited,.HFooter a:hover,.HFooter a:active{color:#A0A0A0}#NDMessages{background-color:#FFFFF0;z-index:9999;overflow:auto;max-height:33%;display:none;padding:.8ex 1ex 1ex 1ex;border-bottom:3px solid #A0A000;border-left:1px solid #A0A000}#MsgCloseButton{float:right;font:bold 8pt Verdana,sans-serif;color:#000000}a#MsgCloseButton:hover,a#MsgCloseButton:active{text-decoration:none}.MsgMessage{color:#787800;font:italic 8pt Verdana,sans-serif}.MsgMessage ~ .MsgMessage{padding-top:.9ex;border-top:1px dashed #D0D0C8;margin-top:1.2ex}.IE6 .MTab{border-bottom:0px none}.IE6 #MContent .Selected{background-color:#FFFFFF}.IE6 .NDPrototype .PModifierQualifier,.IE6 .NDPrototype .PType{font:10pt Consolas,"Courier New",monospace;padding:0;border-bottom:0px none}.IE6 .CTopic p,.IE6 .CTopic .CTitle,.IE6 .NDClassPrototype .CPName{color:#000000}.IE6 .NDClassPrototype .CPEntry{margin-top:0}.IE6 .SeEntry{border-bottom:0px none;padding:.2ex 1.25ex .2ex 3.25ex;margin:0;font:10pt Tahoma,Geneva,"Trebuchet MS",Verdana,sans-serif}.IE6 .SeChildren .SeEntry{padding-left:5.5ex}.IE6 #SeSelectedEntry{border-style:solid;border-width:1px} \ No newline at end of file diff --git a/doc/styles/Default/images/menu-folder-arrow.png b/doc/styles/Default/images/menu-folder-arrow.png new file mode 100644 index 0000000..7aec69c Binary files /dev/null and b/doc/styles/Default/images/menu-folder-arrow.png differ diff --git a/doc/styles/Default/images/menu-loading.gif b/doc/styles/Default/images/menu-loading.gif new file mode 100644 index 0000000..d8d0608 Binary files /dev/null and b/doc/styles/Default/images/menu-loading.gif differ diff --git a/doc/styles/Default/images/menu-tab-classes.png b/doc/styles/Default/images/menu-tab-classes.png new file mode 100644 index 0000000..d126b4a Binary files /dev/null and b/doc/styles/Default/images/menu-tab-classes.png differ diff --git a/doc/styles/Default/images/menu-tab-database.png b/doc/styles/Default/images/menu-tab-database.png new file mode 100644 index 0000000..01f6108 Binary files /dev/null and b/doc/styles/Default/images/menu-tab-database.png differ diff --git a/doc/styles/Default/images/menu-tab-files.png b/doc/styles/Default/images/menu-tab-files.png new file mode 100644 index 0000000..ebe763d Binary files /dev/null and b/doc/styles/Default/images/menu-tab-files.png differ diff --git a/doc/styles/Default/images/search-class.png b/doc/styles/Default/images/search-class.png new file mode 100644 index 0000000..1494838 Binary files /dev/null and b/doc/styles/Default/images/search-class.png differ diff --git a/doc/styles/Default/images/search-parent.png b/doc/styles/Default/images/search-parent.png new file mode 100644 index 0000000..54d1a8d Binary files /dev/null and b/doc/styles/Default/images/search-parent.png differ diff --git a/doc/styles/Default/images/search.png b/doc/styles/Default/images/search.png new file mode 100644 index 0000000..6edae9f Binary files /dev/null and b/doc/styles/Default/images/search.png differ diff --git a/doc/styles/Default/images/summary-loading.gif b/doc/styles/Default/images/summary-loading.gif new file mode 100644 index 0000000..2f6f3fe Binary files /dev/null and b/doc/styles/Default/images/summary-loading.gif differ diff --git a/doc/styles/Default/images/transparent.gif b/doc/styles/Default/images/transparent.gif new file mode 100644 index 0000000..f191b28 Binary files /dev/null and b/doc/styles/Default/images/transparent.gif differ diff --git a/doc/styles/DefaultJS/NDContentPage.js b/doc/styles/DefaultJS/NDContentPage.js new file mode 100644 index 0000000..14ecb1f --- /dev/null +++ b/doc/styles/DefaultJS/NDContentPage.js @@ -0,0 +1,12 @@ +/* +This file is part of Natural Docs, which is Copyright © 2003-2018 Code Clear LLC. +Natural Docs is licensed under version 3 of the GNU Affero General Public +License (AGPL). Refer to License.txt or www.naturaldocs.org for the +complete details. + +This file may be distributed with documentation files generated by Natural Docs. +Such documentation is not covered by Natural Docs' copyright and licensing, +and may have its own copyright and distribution terms as decided by its author. +*/ + +"use strict";var NDContentPage=new function(){this.Start=function(){var ieVersion=NDCore.IEVersion();if(ieVersion==undefined||ieVersion>=8){this.CalculateWideFormPrototypeWidths();for(var key in this.wideFormPrototypeWidths){if(this.wideFormPrototypeWidths[key]==0){setTimeout("NDContentPage.Start();",200);return;}}this.ReformatPrototypes();window.onresize=function(){NDContentPage.OnResize();}}this.toolTipHolder=document.createElement("div");this.toolTipHolder.style.display="none";this.toolTipHolder.style.position="fixed";if(ieVersion==6){this.toolTipHolder.style.position="absolute";}this.toolTipHolder.style.zIndex=20;document.body.appendChild(this.toolTipHolder);var ttLocation=location.href;var hashIndex=ttLocation.indexOf('#');if(hashIndex!=-1){ttLocation=ttLocation.substr(0,hashIndex);}ttLocation=ttLocation.substr(0,ttLocation.length-5)+"-ToolTips.js";NDCore.LoadJavaScript(ttLocation);};this.OnResize=function(){if(this.reformatPrototypesTimeout==undefined){this.reformatPrototypesTimeout=setTimeout("NDContentPage.ReformatPrototypes()",200);}};this.GetPrototypeIDNumber=function(element){if(element.id.indexOf("NDPrototype")==0){var id=parseInt(element.id.substr(11),10);if(id!=NaN&&id>0){return id;}}return-1;};this.CalculateWideFormPrototypeWidths=function(){var prototypes=NDCore.GetElementsByClassName(document,"NDPrototype","div");for(var i=0;i=wideFormWidth&&NDCore.HasClass(prototypes[i],"NarrowForm")){NDCore.ChangePrototypeToWideForm(prototypes[i]);}else if(availableWidthdocument.body.offsetWidth){x=document.body.offsetWidth-this.toolTipHolder.offsetWidth-2;if(x<2){x=2;newWidth=document.body.offsetWidth-4;}}NDCore.SetToAbsolutePosition(this.toolTipHolder,x,y,newWidth,undefined);var prototypes=NDCore.GetElementsByClassName(this.toolTipHolder,"NDPrototype","div");if(prototypes.length>0&&NDCore.HasClass(prototypes[0],"WideForm")&&prototypes[0].scrollWidth>prototypes[0].offsetWidth){NDCore.ChangePrototypeToNarrowForm(prototypes[0]);}if(y+this.toolTipHolder.offsetHeight+2>document.body.parentNode.offsetHeight){var newY=linkOffsets.offsetTop-this.toolTipHolder.offsetHeight-scrollParent.scrollTop-5;if(newY>=0){NDCore.SetToAbsolutePosition(this.toolTipHolder,undefined,newY,undefined,undefined);}}this.toolTipHolder.style.visibility="visible";};this.ResetToolTip=function(){if(this.showingToolTip!=undefined){this.toolTipHolder.style.display="none";this.toolTipHolder.style.width=null;this.lastToolTip=this.showingToolTip;this.showingToolTip=undefined;}if(this.toolTipTimeout!=undefined){clearTimeout(this.toolTipTimeout);this.toolTipTimeout=undefined;}};this.wideFormPrototypeWidths={};}; \ No newline at end of file diff --git a/doc/styles/DefaultJS/NDCore.js b/doc/styles/DefaultJS/NDCore.js new file mode 100644 index 0000000..a928e52 --- /dev/null +++ b/doc/styles/DefaultJS/NDCore.js @@ -0,0 +1,12 @@ +/* +This file is part of Natural Docs, which is Copyright © 2003-2018 Code Clear LLC. +Natural Docs is licensed under version 3 of the GNU Affero General Public +License (AGPL). Refer to License.txt or www.naturaldocs.org for the +complete details. + +This file may be distributed with documentation files generated by Natural Docs. +Such documentation is not covered by Natural Docs' copyright and licensing, +and may have its own copyright and distribution terms as decided by its author. +*/ + +"use strict";var NDCore=new function(){this.GetElementsByClassName=function(baseElement,className,tagHint){if(baseElement.getElementsByClassName){return baseElement.getElementsByClassName(className);}if(!tagHint){tagHint="*";}var tagArray=baseElement.getElementsByTagName(tagHint);var matchArray=new Array();var tagIndex=0;var matchIndex=0;while(tagIndex0){newClassName+=element.className.substr(0,index);}if(index+targetClassName.length!=element.className.length){newClassName+=element.className.substr(index+targetClassName.length);}element.className=newClassName;return;}index=element.className.indexOf(targetClassName,index+1);}};this.LoadJavaScript=function(path,id){var script=document.createElement("script");script.src=path;script.type="text/javascript";if(id!=undefined){script.id=id;}document.getElementsByTagName("head")[0].appendChild(script);};this.RemoveScriptElement=function(id){var script=document.getElementById(id);if(this.IEVersion()==6){setTimeout(function(){script.parentNode.removeChild(script);},1);}else{script.parentNode.removeChild(script);}};this.WindowClientWidth=function(){var width=window.innerWidth;if(width===undefined){width=document.documentElement.clientWidth;}return width;};this.WindowClientHeight=function(){var height=window.innerHeight;if(height===undefined){height=document.documentElement.clientHeight;}return height;};this.SetToAbsolutePosition=function(element,x,y,width,height){if(x!=undefined&&element.offsetLeft!=x){element.style.left=x+"px";}if(y!=undefined&&element.offsetTop!=y){element.style.top=y+"px";}if(width!=undefined&&element.offsetWidth!=width){if(!this.pxRegex.test(element.style.width)){element.style.width=width+"px";if(element.offsetWidth!=width){var adjustment=width-element.offsetWidth;element.style.width=(width+adjustment)+"px";}}else{var styleWidth=RegExp.$1;var adjustment=styleWidth-element.offsetWidth;element.style.width=(width+adjustment)+"px";}}if(height!=undefined&&element.offsetHeight!=height){if(!this.pxRegex.test(element.style.height)){element.style.height=height+"px";if(element.offsetHeight!=height){var adjustment=height-element.offsetHeight;element.style.height=(height+adjustment)+"px";}}else{var styleHeight=RegExp.$1;var adjustment=styleHeight-element.offsetHeight;element.style.height=(height+adjustment)+"px";}}};this.GetFullOffsets=function(element){var result={offsetTop:element.offsetTop,offsetLeft:element.offsetLeft};element=element.offsetParent;while(element!=undefined&&element.nodeName!="BODY"){result.offsetTop+=element.offsetTop;result.offsetLeft+=element.offsetLeft;element=element.offsetParent;}return result;};this.NormalizeHash=function(hashString){if(hashString==undefined){return"";}if(hashString.charAt(0)=="#"){hashString=hashString.substr(1);}hashString=decodeURI(hashString);return hashString;};this.IsIE=function(){return(navigator.userAgent.indexOf("MSIE")!=-1||navigator.userAgent.indexOf("Trident")!=-1);};this.IEVersion=function(){var ieIndex=navigator.userAgent.indexOf("MSIE");if(ieIndex!=-1){ieIndex+=5;}else{ieIndex=navigator.userAgent.indexOf("Trident");if(ieIndex!=-1){ieIndex=navigator.userAgent.indexOf("rv:");if(ieIndex!=-1){ieIndex+=3;}}}if(ieIndex!=-1){return parseInt(navigator.userAgent.substr(ieIndex));}else{return undefined;}};this.AddIEClassesToBody=function(){var ieVersion=this.IEVersion();if(ieVersion!=undefined){this.AddClass(document.body,"IE");if(ieVersion>=6&&ieVersion<=8){this.AddClass(document.body,"IE"+ieVersion);}}};this.SupportsOnInput=function(){if(this.IEVersion()==9){return false;}else{return(window.oninput!==undefined);}};this.ChangePrototypeToNarrowForm=function(prototype){var newPrototype=document.createElement("div");newPrototype.id=prototype.id;newPrototype.className=prototype.className;this.RemoveClass(newPrototype,"WideForm");this.AddClass(newPrototype,"NarrowForm");var prePrototypeLines=NDCore.GetElementsByClassName(prototype,"PPrePrototypeLine","div");for(var i=0;i=other.length&&this.substr(0,other.length)==other);};String.prototype.EntityDecode=function(){var output=this;output=output.replace(/</g,"<");output=output.replace(/>/g,">");output=output.replace(/"/g,"\"");output=output.replace(/&/g,"&");return output;};function NDLocation(hashString){this.Constructor=function(hashString){this.hashString=NDCore.NormalizeHash(hashString);if(this.hashString.match(/^File[0-9]*:/)!=null){this.type="File";this.SplitPathAndMember();this.AddFileURLs();}else if(this.hashString.match(/^[A-Z]+Class:/i)!=null){this.type="Class";this.SplitPathAndMember();this.AddClassURLs();}else if(this.hashString.substr(0,9).toLowerCase()=="database:"){this.type="Database";this.SplitPathAndMember();this.AddDatabaseURLs();}else{this.type="Home";this.AddHomeURLs();}};this.SplitPathAndMember=function(){var pathSeparator=this.hashString.indexOf(':');var memberSeparator=this.hashString.indexOf(':',pathSeparator+1);if(memberSeparator==-1){this.path=this.hashString;}else{this.path=this.hashString.substr(0,memberSeparator);this.member=this.hashString.substr(memberSeparator+1);if(this.member==""){this.member=undefined;}}};this.AddHomeURLs=function(){this.contentPage="other/home.html";};this.AddFileURLs=function(){var pathPrefix=this.path.match(/^File([0-9]*):/);var basePath="files"+pathPrefix[1]+"/"+this.path.substr(pathPrefix[0].length);var lastSeparator=basePath.lastIndexOf('/');var filename=basePath.substr(lastSeparator+1);filename=filename.replace(/\./g,'-');basePath=basePath.substr(0,lastSeparator+1)+filename;this.contentPage=basePath+".html";this.summaryFile=basePath+"-Summary.js";this.summaryTTFile=basePath+"-SummaryToolTips.js";if(this.member!=undefined){this.contentPage+='#'+this.member;}};this.AddClassURLs=function(){var pathPrefix=this.path.match(/^([A-Z]+)Class:/i);var basePath="classes/"+pathPrefix[1]+"/"+this.path.substr(pathPrefix[0].length);basePath=basePath.replace(/\.|::/g,"/");this.contentPage=basePath+".html";this.summaryFile=basePath+"-Summary.js";this.summaryTTFile=basePath+"-SummaryToolTips.js";if(this.member!=undefined){this.contentPage+='#'+this.member;}};this.AddDatabaseURLs=function(){var basePath="database/"+this.path.substr(9);basePath=basePath.replace(/\./g,"/");this.contentPage=basePath+".html";this.summaryFile=basePath+"-Summary.js";this.summaryTTFile=basePath+"-SummaryToolTips.js";if(this.member!=undefined){this.contentPage+='#'+this.member;}};this.Constructor(hashString);};if(!Array.prototype.indexOf){Array.prototype.indexOf=function(searchElement){"use strict";if(this==null){throw new TypeError();}var n,k,t=Object(this),len=t.length>>>0;if(len===0){return-1;}n=0;if(arguments.length>1){n=Number(arguments[1]);if(n!=n){n=0;}else if(n!=0&&n!=Infinity&&n!=-Infinity){n=(n>0||-1)*Math.floor(Math.abs(n));}}if(n>=len){return-1;}for(k=n>=0?n:Math.max(len-Math.abs(n),0);k7));if(supportsOnHashChange){window.onhashchange=function(){NDFramePage.OnHashChange();};}if(!supportsOnHashChange||NDCore.IsIE()){this.hashChangePoller={timeoutLength:200,lastHash:location.hash};if(!NDCore.IsIE()||supportsOnHashChange){this.hashChangePoller.Start=function(){this.Poll();};this.hashChangePoller.Stop=function(){if(this.timeoutID!=undefined){clearTimeout(this.timeoutID);this.timeoutID=undefined;}};this.hashChangePoller.Poll=function(){if(location.hash!=this.lastHash){this.lastHash=location.hash;NDFramePage.OnHashChange();}this.timeoutID=setTimeout("NDFramePage.hashChangePoller.Poll()",this.timeoutLength);};}else{this.hashChangePoller.Start=function(){var iframeElement=document.createElement("iframe");iframeElement.title="empty";iframeElement.tabindex=-1;iframeElement.style.display="none";iframeElement.width=0;iframeElement.height=0;iframeElement.src="javascript:0";this.firstRun=true;iframeElement.attachEvent("onload",function(){if(NDFramePage.hashChangePoller.firstRun){NDFramePage.hashChangePoller.firstRun=false;NDFramePage.hashChangePoller.SetHistory(location.hash);NDFramePage.hashChangePoller.Poll();}});document.body.appendChild(iframeElement);this.iframe=iframeElement.contentWindow;document.onpropertychange=function(){if(event.propertyName=="title"){try{NDFramePage.hashChangePoller.iframe.document.title=document.title;}catch(e){}}};};this.hashChangePoller.Stop=function(){};this.hashChangePoller.Poll=function(){var hash=location.hash;var historyHash=this.GetHistory();if(hash!=this.lastHash){this.lastHash=location.hash;this.SetHistory(hash,historyHash);NDFramePage.OnHashChange();}else if(historyHash!=this.lastHash){location.href=location.href.replace(/#.*/,'')+historyHash;}this.timeoutID=setTimeout("NDFramePage.hashChangePoller.Poll()",this.timeoutLength);};this.hashChangePoller.GetHistory=function(){return this.iframe.location.hash;};this.hashChangePoller.SetHistory=function(hash,historyHash){if(hash!=historyHash){this.iframe.document.title=document.title;this.iframe.document.open();this.iframe.document.close();this.iframe.location.hash=hash;}};}this.hashChangePoller.Start();}};this.OnResize=function(){this.UpdateLayout();};this.UpdateLayout=function(){var ieVersion=NDCore.IEVersion();var useSizers=(ieVersion==undefined||ieVersion>=8);var fullWidth=NDCore.WindowClientWidth();var fullHeight=NDCore.WindowClientHeight();var header=document.getElementById("NDHeader");var searchField=document.getElementById("NDSearchField");var footer=document.getElementById("NDFooter");var menu=document.getElementById("NDMenu");var menuSizer=document.getElementById("NDMenuSizer");var summary=document.getElementById("NDSummary");var summarySizer=document.getElementById("NDSummarySizer");var content=document.getElementById("NDContent");var messages=document.getElementById("NDMessages");NDCore.SetToAbsolutePosition(header,0,0,fullWidth,undefined);NDCore.SetToAbsolutePosition(footer,0,undefined,fullWidth,undefined);var headerHeight=header.offsetHeight-1;var footerHeight=footer.offsetHeight;NDCore.SetToAbsolutePosition(footer,undefined,fullHeight-footerHeight,undefined,undefined);var searchMargin=(headerHeight-searchField.offsetHeight)/2;NDCore.SetToAbsolutePosition(searchField,fullWidth-searchField.offsetWidth-searchMargin,searchMargin,undefined,undefined);var remainingHeight=fullHeight-headerHeight-footerHeight;var remainingWidth=fullWidth;var currentX=0;if(this.MenuIsVisible()){menu.style.display="block";NDCore.SetToAbsolutePosition(menu,currentX,headerHeight,undefined,remainingHeight);currentX+=menu.offsetWidth;remainingWidth-=menu.offsetWidth;if(this.desiredMenuWidth==undefined){this.desiredMenuWidth=menu.offsetWidth;}if(useSizers){menuSizer.style.display="block";NDCore.SetToAbsolutePosition(menuSizer,currentX,headerHeight,undefined,remainingHeight);}NDMenu.OnUpdateLayout();}else{menu.style.display="none";menuSizer.style.display="none";}if(this.SummaryIsVisible()){summary.style.display="block";NDCore.SetToAbsolutePosition(summary,currentX,headerHeight,undefined,remainingHeight);currentX+=summary.offsetWidth;remainingWidth-=summary.offsetWidth;if(this.desiredSummaryWidth==undefined){this.desiredSummaryWidth=summary.offsetWidth;}if(useSizers){summarySizer.style.display="block";NDCore.SetToAbsolutePosition(summarySizer,currentX,headerHeight,undefined,remainingHeight);}}else{summary.style.display="none";summarySizer.style.display="none";}NDCore.SetToAbsolutePosition(content,currentX,headerHeight,remainingWidth,remainingHeight);NDCore.SetToAbsolutePosition(messages,currentX,0,remainingWidth,undefined);NDSearch.OnUpdateLayout();};this.MenuIsVisible=function(){return true;};this.SummaryIsVisible=function(){return(this.currentLocation!=undefined&&this.currentLocation.summaryFile!=undefined);};this.OnMouseDown=function(event){if(event==undefined){event=window.event;}var target=event.target||event.srcElement;if(NDSearch.SearchFieldIsActive()){var targetIsInResults=false;for(var element=target;element!=undefined;element=element.parentNode){if(element.id=="NDSearchResults"){targetIsInResults=true;break;}}if(!targetIsInResults){NDSearch.ClearResults();NDSearch.DeactivateSearchField();}}if(target.id=="NDMenuSizer"||target.id=="NDSummarySizer"){var element;if(target.id=="NDMenuSizer"){element=document.getElementById("NDMenu");}else{element=document.getElementById("NDSummary");}this.sizerDragging={"sizer":target,"element":element,"originalSizerX":target.offsetLeft,"originalElementWidth":element.offsetWidth,"originalClientX":event.clientX};NDCore.AddClass(target,"Dragging");document.onmousemove=function(e){return NDFramePage.OnSizerMouseMove(e);};document.onmouseup=function(e){return NDFramePage.OnSizerMouseUp(e);};document.onselectstart=function(){return false;};var contentCover=document.createElement("div");contentCover.id="NDContentCover";document.body.appendChild(contentCover);NDCore.SetToAbsolutePosition(contentCover,0,0,NDCore.WindowClientWidth(),NDCore.WindowClientHeight());return false;}else{return true;}};this.OnSizerMouseMove=function(event){if(event==undefined){event=window.event;}var offset=event.clientX-this.sizerDragging.originalClientX;var windowClientWidth=NDCore.WindowClientWidth();if(this.sizerDragging.sizer.id=="NDMenuSizer"){if(this.sizerDragging.originalSizerX+offset<0){offset=0-this.sizerDragging.originalSizerX;}else if(this.sizerDragging.originalSizerX+offset+this.sizerDragging.sizer.offsetWidth>windowClientWidth){offset=windowClientWidth-this.sizerDragging.sizer.offsetWidth-this.sizerDragging.originalSizerX;}}else{var menuSizer=document.getElementById("NDMenuSizer");var leftLimit=menuSizer.offsetLeft+menuSizer.offsetWidth;if(this.sizerDragging.originalSizerX+offsetwindowClientWidth){offset=windowClientWidth-this.sizerDragging.sizer.offsetWidth-this.sizerDragging.originalSizerX;}}NDCore.SetToAbsolutePosition(this.sizerDragging.sizer,this.sizerDragging.originalSizerX+offset,undefined,undefined,undefined);NDCore.SetToAbsolutePosition(this.sizerDragging.element,undefined,undefined,this.sizerDragging.originalElementWidth+offset,undefined);if(this.sizerDragging.sizer.id=="NDMenuSizer"){this.desiredMenuWidth=document.getElementById("NDMenu").offsetWidth;}else{this.desiredSummaryWidth=document.getElementById("NDSummary").offsetWidth;}this.UpdateLayout();};this.OnSizerMouseUp=function(event){document.onmousemove=null;document.onmouseup=null;document.onselectstart=null;document.body.removeChild(document.getElementById("NDContentCover"));NDCore.RemoveClass(this.sizerDragging.sizer,"Dragging");this.sizerDragging=undefined;};this.SizeSummaryToContent=function(){this.SizePanelToContent(document.getElementById("NDSummary"),this.desiredSummaryWidth);};this.SizePanelToContent=function(panel,desiredOffsetWidth){if(this.desiredSummaryWidth==undefined){return;}var resized=false;if(panel.clientWidth==panel.scrollWidth){if(panel.offsetWidth==desiredOffsetWidth){return;}else{NDCore.SetToAbsolutePosition(panel,undefined,undefined,desiredOffsetWidth,undefined);resized=true;}}var newOffsetWidth=panel.scrollWidth;if(panel.scrollHeight>panel.clientHeight){newOffsetWidth+=panel.offsetWidth-panel.clientWidth;}else{newOffsetWidth+=NDCore.GetComputedPixelWidth(panel,"borderLeftWidth")+NDCore.GetComputedPixelWidth(panel,"borderRightWidth");}if(newOffsetWidth!=desiredOffsetWidth){newOffsetWidth+=3;if(newOffsetWidth/desiredOffsetWidth>1.333){newOffsetWidth=Math.floor(desiredOffsetWidth*1.333);}if(panel.offsetWidth!=newOffsetWidth){NDCore.SetToAbsolutePosition(panel,undefined,undefined,newOffsetWidth,undefined);resized=true;}}if(resized){this.UpdateLayout();}};}; \ No newline at end of file diff --git a/doc/styles/DefaultJS/NDMenu.js b/doc/styles/DefaultJS/NDMenu.js new file mode 100644 index 0000000..383bfee --- /dev/null +++ b/doc/styles/DefaultJS/NDMenu.js @@ -0,0 +1,12 @@ +/* +This file is part of Natural Docs, which is Copyright © 2003-2018 Code Clear LLC. +Natural Docs is licensed under version 3 of the GNU Affero General Public +License (AGPL). Refer to License.txt or www.naturaldocs.org for the +complete details. + +This file may be distributed with documentation files generated by Natural Docs. +Such documentation is not covered by Natural Docs' copyright and licensing, +and may have its own copyright and distribution terms as decided by its author. +*/ + +"use strict";var NDMenu=new function(){this.Start=function(){this.menuSections=[];this.firstUnusedMenuSection=0;var menuContainer=document.getElementById("NDMenu");var menuTabBar=document.createElement("div");menuTabBar.id="MTabBar";menuContainer.appendChild(menuTabBar);var menuContent=document.createElement("div");menuContent.id="MContent";menuContainer.appendChild(menuContent);NDCore.LoadJavaScript("menu/tabs.js","NDMenuTabsLoader");};this.OnLocationChange=function(oldLocation,newLocation){if(newLocation.type=="Home"&&this.tabs!=undefined&&this.tabs.length==1){this.GoToOffsets([0]);return;}if(oldLocation==undefined||oldLocation.type!=newLocation.type){this.UpdateTabs(newLocation.type);}if(oldLocation==undefined||oldLocation.type!=newLocation.type||oldLocation.path!=newLocation.path){this.Build(new NDMenuHashPath(newLocation.type,newLocation.path));}};this.GoToOffsets=function(offsets){if(this.tabs!=undefined){var newSelectedTab;if(offsets.length>=1){newSelectedTab=this.tabs[offsets[0]][0];if(newSelectedTab!=this.selectedTabType){this.UpdateTabs(newSelectedTab);}}}this.Build(new NDMenuOffsetPath(offsets));};this.Build=function(path){if(path!=undefined){this.pathBeingBuilt=path;}else if(this.pathBeingBuilt==undefined){return;}this.firstUnusedMenuSection=0;var newMenuContent=document.createElement("div");newMenuContent.id="MContent";var result;if(this.tabs!=undefined){result=this.BuildEntries(newMenuContent,this.pathBeingBuilt);}else{result={completed:false};}if(!result.completed){var htmlEntry=document.createElement("div");htmlEntry.className="MLoadingNotice";newMenuContent.appendChild(htmlEntry);}var oldMenuContent=document.getElementById("MContent");var menuContainer=oldMenuContent.parentNode;menuContainer.replaceChild(newMenuContent,oldMenuContent);if(NDCore.IsIE()&&NDCore.IEVersion()==10){setTimeout(function(){document.getElementById("NDMenu").style.zoom="100%";},0);}if(result.completed){if(result.selectedFile){if(result.selectedFile.offsetTop+result.selectedFile.offsetHeight>menuContainer.scrollTop+menuContainer.clientHeight){result.selectedFile.scrollIntoView(false);}else if(result.selectedFile.offsetTop"+""+""+tabTitle+"";htmlMenu.appendChild(htmlEntry);}}else{for(var i=0;i";if(typeof(member[1])=="object"){title+=member[1][0];}else{title+=member[1];}var targetPath=(pathSoFar.length==0?i:pathSoFar.join(",")+","+i);var htmlEntry=document.createElement("a");htmlEntry.className="MEntry MFolder Child";htmlEntry.setAttribute("href","javascript:NDMenu.GoToOffsets(["+targetPath+"])");htmlEntry.innerHTML=title;htmlMenu.appendChild(htmlEntry);}}}result.completed=true;if(selectedTab!=undefined){selectedTab[6]=pathSoFar;}return result;};this.MenuSection=function(file){for(var i=0;i=this.firstUnusedMenuSection){if(i>this.firstUnusedMenuSection){this.menuSections.splice(i,1);this.menuSections.splice(this.firstUnusedMenuSection,0,section);}this.firstUnusedMenuSection++;}if(section.ready==true){return section.contents;}else{return undefined;}}}return undefined;};this.LoadMenuSection=function(file){for(var i=0;i10){for(var i=this.menuSections.length-1;i>=this.firstUnusedMenuSection&&this.menuSections.length>10;i--){if(this.menuSections[i].ready==false){break;}this.menuSections.pop();}}};this.OnTabsLoaded=function(tabs){this.tabs=tabs;NDCore.RemoveScriptElement("NDMenuTabsLoader");var tabBar=document.getElementById("MTabBar");for(var i=0;i"+tabTitle+"";tab.style.position="absolute";tab.style.visibility="hidden";tabBar.appendChild(tab);tabs[i][4]=tab.offsetWidth;tab.className="MTab Narrow";tabs[i][5]=tab.offsetWidth;if(tabs[i][0]==this.selectedTabType){tab.className+=" Selected";}}this.ResizeTabs();if(this.ShouldTabsShow()==false){tabBar.style.display="none";}for(var i=0;i1&&this.selectedTabType!=undefined&&this.selectedTabType!="Home");};this.OnUpdateLayout=function(){this.ResizeTabs();};this.GoToTab=function(newTabType){var tabIndex;for(var i=0;i=this.pathObject.path.length){return;}else if(this.currentContainer==undefined){this.pathIndex++;}else{var currentEntry=this.currentContainer[this.pathObject.path[this.pathIndex]];this.currentContainer=undefined;this.currentContainerHashPath=undefined;this.needToLoad=undefined;if(this.pathIndex==0){this.currentContainerHashPath=currentEntry[2];this.needToLoad=currentEntry[3];}else if(currentEntry[0]==2){this.currentContainerHashPath=currentEntry[2];if(typeof currentEntry[3]=="string"){this.needToLoad=currentEntry[3];}else{this.currentContainer=currentEntry[3];}}this.pathIndex++;if(this.needToLoad!=undefined){this.currentContainer=NDMenu.MenuSection(this.needToLoad);if(this.currentContainer!=undefined){this.needToLoad=undefined;}}}};this.NavigationType=function(){if(this.currentContainer==undefined){return 9;}if(this.pathIndex>=this.pathObject.path.length){return-1;}var currentEntry=this.currentContainer[this.pathObject.path[this.pathIndex]];if(this.InTabs()==false&¤tEntry[0]==1){return 3;}if(this.pathIndex==this.pathObject.path.length-1){return 2;}if(this.pathIndex+2<=this.pathObject.path.length-1){return 1;}var lookahead=this.Duplicate();lookahead.Next();if(lookahead.NavigationType()==9){this.needToLoad=lookahead.NeedToLoad();return 9;}else if(lookahead.CurrentEntry()[0]==2){return 1;}else{return 2;}};this.Duplicate=function(){var newObject=new NDMenuOffsetPathIterator(this.pathObject);newObject.pathIndex=this.pathIndex;newObject.currentContainer=this.currentContainer;newObject.needToLoad=this.needToLoad;return newObject;};this.CurrentEntry=function(){if(this.currentContainer!=undefined&&this.pathIndex0){this.domResults.scrollTop--;}};this.LoadMoreResults=function(){this.moreResultsThreshold=this.visibleEntryCount+25;this.domSearchField.focus();this.Update();};this.ActivateLinkFromKeyboard=function(domLink){var address=domLink.getAttribute("href");if(address.substr(0,11)=="javascript:"){address=address.substr(11);address=address.replace(/^(NDSearch.ToggleParent\([0-9]+,)false(.*)$/,"$1true$2");eval(address);}else{location.href=address;}};this.OnSearchFieldFocus=function(){if(!this.SearchFieldIsActive()){this.ActivateSearchField();if(this.allPrefixesStatus==1){this.allPrefixesStatus=2;NDCore.LoadJavaScript("search/index.js");}}};this.OnSearchFieldKey=function(event){if(event===undefined){event=window.event;}if(event.keyCode==27){this.ClearResults();this.DeactivateSearchField();document.getElementById("CFrame").contentWindow.focus();}else if(event.keyCode==38){if(this.keyboardSelectionIndex<=0){this.keyboardSelectionIndex=this.visibleEntryCount-1;}else{this.keyboardSelectionIndex--;}this.UpdateSelection();}else if(event.keyCode==40){if(this.visibleEntryCount==0){this.keyboardSelectionIndex=-1;}else if(this.keyboardSelectionIndex>=this.visibleEntryCount-1){this.keyboardSelectionIndex=0;}else{this.keyboardSelectionIndex++;}this.UpdateSelection();}else if(event.keyCode==37){if(this.keyboardSelectionIndex!=-1){var domSelectedEntry=document.getElementById("SeSelectedEntry");if(NDCore.HasClass(domSelectedEntry,"SeParent")&&NDCore.HasClass(domSelectedEntry,"open")){this.ActivateLinkFromKeyboard(domSelectedEntry);}}}else if(event.keyCode==39){if(this.keyboardSelectionIndex!=-1){var domSelectedEntry=document.getElementById("SeSelectedEntry");if(NDCore.HasClass(domSelectedEntry,"SeParent")&&NDCore.HasClass(domSelectedEntry,"closed")){this.ActivateLinkFromKeyboard(domSelectedEntry);}}}else if(event.keyCode==13){var domSelectedEntry=undefined;if(this.keyboardSelectionIndex!=-1){domSelectedEntry=document.getElementById("SeSelectedEntry");}else if(this.visibleEntryCount==1){domSelectedEntry=this.domResultsContent.firstChild;}else if(this.visibleEntryCount==2&&NDCore.HasClass(this.domResultsContent.firstChild,"SeParent")){domSelectedEntry=this.domResultsContent.childNodes[1].firstChild;}if(domSelectedEntry!=undefined){this.ActivateLinkFromKeyboard(domSelectedEntry);}else if(this.keyboardSelectionIndex==-1&&this.visibleEntryCount>0){this.keyboardSelectionIndex=0;this.UpdateSelection();}}else if(NDCore.SupportsOnInput()==false){if(event.keyCode!=37&&event.keyCode!=39){this.OnSearchFieldChange(event);}}};this.OnSearchFieldChange=function(event){if(event===undefined){event=window.event;}this.keyboardSelectionIndex=-1;if(this.initialTimeoutStatus==3){if(this.updateTimeout==undefined){this.updateTimeout=setTimeout(function(){clearTimeout(NDSearch.updateTimeout);NDSearch.updateTimeout=undefined;NDSearch.Update();},350);}}else{var searchInterpretations=this.GetSearchInterpretations();if(searchInterpretations.length!=0&&this.allPrefixesStatus==3&&this.GetMatchingPrefixes(searchInterpretations).length<=1){if(this.initialTimeoutStatus==2){clearTimeout(this.initialTimeout);this.initialTimeout=undefined;}this.initialTimeoutStatus=3;this.Update();}else if(this.initialTimeoutStatus==1){this.initialTimeoutStatus=2;this.initialTimeout=setTimeout(function(){if(NDSearch.initialTimeoutStatus==2){clearTimeout(NDSearch.initialTimeout);NDSearch.initialTimeout=undefined;NDSearch.initialTimeoutStatus=3;NDSearch.Update();}},1250);}}};this.OnResultsFocus=function(){this.domSearchField.focus();};this.OnUpdateLayout=function(){if(this.domResults!=undefined){this.PositionResults();if(this.keyboardSelectionIndex!=-1){var domSelectedEntry=document.getElementById("SeSelectedEntry");if(domSelectedEntry!=undefined){this.ScrollEntryIntoView(domSelectedEntry,false);}}}};this.GetSearchInterpretations=function(){var interpretations=[];var normalizedSearchText=this.domSearchField.value.toLowerCase();normalizedSearchText=normalizedSearchText.replace(/\s+/g," ");normalizedSearchText=normalizedSearchText.replace(/^ /,"");normalizedSearchText=normalizedSearchText.replace(/ $/,"");normalizedSearchText=normalizedSearchText.replace(/([^a-z0-9_]) /g,"$1");normalizedSearchText=normalizedSearchText.replace(/ (?=[^a-z0-9_])/g,"");normalizedSearchText=normalizedSearchText.replace(/::|->/g,".");normalizedSearchText=normalizedSearchText.replace(/\\/g,"/");normalizedSearchText=normalizedSearchText.replace(/^[./]+/,"");if(normalizedSearchText==""){return interpretations;}interpretations.push(normalizedSearchText);var lastChar=normalizedSearchText.charAt(normalizedSearchText.length-1);if(lastChar==":"||lastChar=="-"){interpretations.push(normalizedSearchText.substr(0,normalizedSearchText.length-1)+".");}return interpretations;};this.GetMatchingPrefixes=function(searchTextArray){var matchingPrefixes=[];if(this.allPrefixesStatus!=3){return matchingPrefixes;}for(var i=0;i=searchPrefix.length&&this.allPrefixes[prefixIndex].substr(0,searchPrefix.length)==searchPrefix){matchingPrefixes.push(this.allPrefixes[prefixIndex]);prefixIndex++;}else{break;}}}}if(searchTextArray.length<=1){return matchingPrefixes;}matchingPrefixes.sort();for(var i=1;i>1;if(prefix==this.allPrefixes[testIndex]){return testIndex;}else if(prefixmaximum){return true;}}}}}}return false;};this.BuildResults=function(searchInterpretations,searchInterpretationPrefixes,favorClasses,forceExpansion){var results={html:""};this.topLevelEntryCount=0;this.visibleEntryCount=0;var addSearchingStatus=false;for(var p=0;p"+"
"+lastMatchingMemberObject[1];if(lastMatchingMemberObject[0]!=undefined||lastMatchingMemberObject[2]!=undefined){html+="";if(lastMatchingMemberObject[0]!=undefined){html+=", "+lastMatchingMemberObject[0];}if(lastMatchingMemberObject[2]!=undefined){html+=", "+lastMatchingMemberObject[2];}html+="";}html+="";this.topLevelEntryCount++;this.visibleEntryCount++;return html;}else{var selected=(this.keyboardSelectionIndex==this.visibleEntryCount);var openClosed;if(forceExpansion||this.openParents.indexOf(this.topLevelEntryCount)!=-1){openClosed="open";}else{openClosed="closed";}var html=""+"
"+keywordObject[0]+" ("+memberMatches+")"+"
";this.topLevelEntryCount++;this.visibleEntryCount++;if(openClosed=="open"){html+="
";for(var i=0;i"+"
"+memberObject[1];if(memberObject[0]!=undefined||memberObject[2]!=undefined){html+="";if(memberObject[0]!=undefined){html+=", "+memberObject[0];}if(memberObject[2]!=undefined){html+=", "+memberObject[2];}html+="";}html+="";this.visibleEntryCount++;}}html+="
";}return html;}};this.BuildSearchingStatus=function(){return"
"+"Searching..."+"
";};this.BuildNoMatchesStatus=function(){return"
"+"No Matches"+"
";};this.BuildMoreResultsEntry=function(){var selected=(this.keyboardSelectionIndex==this.visibleEntryCount);var html=""+"
"+"More Results..."+"
";this.visibleEntryCount++;this.topLevelEntryCount++;return html;};this.MakePrefix=function(searchText){var prefix="";for(var i=0;i<3;i++){if(i>=searchText.length){break;}var char=searchText.charAt(i);if(char==" "||char=="."||char=="/"){break;}prefix+=char;}if(prefix.length>0){return prefix;}else{return undefined;}};this.PrefixToHex=function(prefix){var hex="";for(var i=0;imaxHeight){NDCore.SetToAbsolutePosition(this.domResults,undefined,undefined,undefined,maxHeight);}if(this.domResults.offsetWidth>maxWidth){NDCore.SetToAbsolutePosition(this.domResults,undefined,undefined,maxWidth,undefined);}else{if(this.domResults.scrollWidth>this.domResults.clientWidth){var newWidth=this.domResults.offsetWidth+(this.domResults.scrollWidth-this.domResults.clientWidth)+5;if(newWidth>maxWidth){newWidth=maxWidth;}NDCore.SetToAbsolutePosition(this.domResults,undefined,undefined,newWidth,undefined);}if(this.domResults.offsetWidthitemTop){offset=itemTop-windowTop;}if(offset!=0){this.domResults.scrollTop+=offset;}};this.OnPrefixIndexLoaded=function(prefixes){this.allPrefixes=prefixes;this.allPrefixesStatus=3;if(this.initialTimeoutStatus==3){this.Update();}};this.LoadPrefixData=function(prefix){if(this.prefixObjects[prefix]==undefined){var prefixObject=[];prefixObject[0]=prefix;prefixObject[2]=false;prefixObject[3]="NDPrefixLoader_"+this.PrefixToHex(prefix);this.prefixObjects[prefix]=prefixObject;NDCore.LoadJavaScript(this.PrefixToDataFile(prefix),prefixObject[3]);}};this.OnPrefixDataLoaded=function(prefix,commentTypes,keywordObjects){var prefixObject=this.prefixObjects[prefix];if(prefixObject==undefined){return;}for(var k=0;k"+entry[3];entryHTML.onmouseover=mouseOverHandler;entryHTML.onmouseout=mouseOutHandler;var entryHTMLChild=entryHTML.firstChild;if(entryHTMLChild!=undefined&&NDCore.HasClass(entryHTMLChild,"Qualifier")){entryHTMLChild.onmouseover=mouseOverHandler;entryHTMLChild.onmouseout=mouseOutHandler;}newContent.appendChild(entryHTML);}}}var summaryContainer=document.getElementById("NDSummary");var oldContent=document.getElementById("SuContent");if(oldContent!=undefined){summaryContainer.replaceChild(newContent,oldContent);}else{summaryContainer.appendChild(newContent);}newContent.scrollIntoView(true);if(this.summaryEntries!=undefined){NDFramePage.SizeSummaryToContent();}if(NDCore.IsIE()&&NDCore.IEVersion()==10){setTimeout(function(){document.getElementById("NDSummary").style.zoom="100%";},0);}};this.FinishIENavigation=function(){if(NDCore.IsIE()&&this.summaryEntries!=undefined&&NDFramePage.currentLocation!=undefined&&NDFramePage.currentLocation.type=="File"&&NDFramePage.currentLocation.member!=undefined){var topicID=-1;for(var i=0;i0){return id;}else{return-1;}};this.ShowToolTip=function(){var entry=document.getElementById("SuEntry"+this.showingToolTip);this.toolTipHolder.innerHTML=this.summaryToolTips[this.showingToolTip];this.toolTipHolder.style.visibility="hidden";this.toolTipHolder.style.display="block";var summaryBlock=document.getElementById("NDSummary");var x=summaryBlock.offsetLeft+entry.offsetLeft+entry.offsetWidth;var y=summaryBlock.offsetTop+entry.offsetTop-summaryBlock.scrollTop;var newWidth=undefined;var maxWidth=NDCore.WindowClientWidth()-x;if(this.toolTipHolder.offsetWidth>maxWidth){newWidth=maxWidth;}NDCore.SetToAbsolutePosition(this.toolTipHolder,x,y,newWidth,undefined);var prototypes=NDCore.GetElementsByClassName(this.toolTipHolder,"NDPrototype","div");if(prototypes.length>0&&NDCore.HasClass(prototypes[0],"WideForm")&&prototypes[0].scrollWidth>prototypes[0].offsetWidth){NDCore.ChangePrototypeToNarrowForm(prototypes[0]);}var footer=document.getElementById("NDFooter");if(y+this.toolTipHolder.offsetHeight+(footer.offsetHeight*2)>NDCore.WindowClientHeight()){var newY=NDCore.WindowClientHeight()-this.toolTipHolder.offsetHeight-(footer.offsetHeight*2);if(newY<0){newY=0;}NDCore.SetToAbsolutePosition(this.toolTipHolder,undefined,newY,undefined,undefined);}this.toolTipHolder.style.visibility="visible";};this.ResetToolTip=function(){if(this.showingToolTip!=undefined){this.toolTipHolder.style.display="none";this.toolTipHolder.style.width=null;this.lastToolTip=this.showingToolTip;this.showingToolTip=undefined;}if(this.toolTipTimeout!=undefined){clearTimeout(this.toolTipTimeout);this.toolTipTimeout=undefined;}};}; \ No newline at end of file diff --git a/doc/styles/main.css b/doc/styles/main.css new file mode 100644 index 0000000..4333a29 --- /dev/null +++ b/doc/styles/main.css @@ -0,0 +1 @@ +@import URL("Default/Default.css"); \ No newline at end of file diff --git a/doc/styles/main.js b/doc/styles/main.js new file mode 100644 index 0000000..e47a88e --- /dev/null +++ b/doc/styles/main.js @@ -0,0 +1 @@ +"use strict";var NDLoader=new function(){this.JSLinks_All=["DefaultJS/NDCore.js"];this.JSLinks_Frame=["DefaultJS/NDFramePage.js","DefaultJS/NDMenu.js","DefaultJS/NDSummary.js","DefaultJS/NDSearch.js"];this.JSLinks_Content=["DefaultJS/NDContentPage.js"];this.JSLinks_Home=[];this.LoadJS=function(pageType,relativePrefix){this.LoadJSArray(this.JSLinks_All,relativePrefix);this.LoadJSArray(this['JSLinks_'+pageType],relativePrefix);};this.LoadJSArray=function(links,relativePrefix){if(navigator.userAgent.indexOf('KHTML')!=-1){for(var i=0;i');}}else{var head=document.getElementsByTagName('head')[0];for(var i=0;i @@ -7,16 +10,16 @@ #include #include -#ifdef _WIN64 +#if defined(_MSC_VER) || defined(_WIN64) #define atoll(S) _atoi64(S) #include +#include #else #include #include #include #include #include -#include #endif #ifdef __APPLE__ @@ -85,18 +88,24 @@ static void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) { } static const char* mmap_file(size_t* len, const char* filename) { -#ifdef _WIN64 +#if defined(_MSC_VER) || defined(_WIN64) HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); + HANDLE fileMapping; + LPVOID fileMapView; assert(file != INVALID_HANDLE_VALUE); - HANDLE fileMapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); + fileMapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); assert(fileMapping != INVALID_HANDLE_VALUE); - LPVOID fileMapView = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0, 0); - auto fileMapViewChar = (const char*)fileMapView; - assert(fileMapView != NULL); + fileMapView = MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0, 0); + { + auto fileMapViewChar = (const char*)fileMapView; + assert(fileMapView != NULL); + (*len) = GetFileSize(file, NULL); + return fileMapViewChar; + } #else FILE* f; @@ -166,7 +175,8 @@ static const char* get_file_data(size_t* len, const char* filename) { static int LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename) { - tinyobj_attrib_t attrib; + COMPATtinyobj_attrib_t attrib; + tinyobj_attrib_t new_attrib; tinyobj_shape_t* shapes = NULL; size_t num_shapes; tinyobj_material_t* materials = NULL; @@ -182,7 +192,7 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], { unsigned int flags = TINYOBJ_FLAG_TRIANGULATE; - int ret = tinyobj_parse_obj(&attrib, &shapes, &num_shapes, &materials, + int ret = tinyobj_parse_obj(&new_attrib, &shapes, &num_shapes, &materials, &num_materials, data, data_len, flags); if (ret != TINYOBJ_SUCCESS) { return 0; @@ -190,7 +200,8 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], printf("# of shapes = %d\n", (int)num_shapes); printf("# of materials = %d\n", (int)num_materials); - + if(tinyobj_new2old(&new_attrib, &attrib) != TINYOBJ_SUCCESS) + exit(-1); /* { int i; @@ -334,9 +345,10 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], printf("bmax = %f, %f, %f\n", (double)bmax[0], (double)bmax[1], (double)bmax[2]); - tinyobj_attrib_free(&attrib); - tinyobj_shapes_free(shapes, num_shapes); - tinyobj_materials_free(materials, num_materials); + tinyobj_attrib_free(&new_attrib); + tinyobj_attrib_free_compat(&attrib); + tinyobj_shape_free(shapes, num_shapes); + tinyobj_material_free(materials, num_materials); return 1; } diff --git a/nd_config/Comments.txt b/nd_config/Comments.txt new file mode 100644 index 0000000..5990768 --- /dev/null +++ b/nd_config/Comments.txt @@ -0,0 +1,85 @@ +Format: 2.0.2 + +# This is the Natural Docs comments file for this project. If you change +# anything here, it will apply to THIS PROJECT ONLY. You can edit the version +# in Natural Docs' Config folder to make the changes apply to all projects, +# but it's recommended that you edit this version instead. + + +# Ignored Keywords +# ------------------------------------------------------------------------ + +# If you'd like to prevent keywords from being recognized by Natural Docs, +# you can do it like this: +# +# Ignore Keywords: +# [keyword] +# [keyword] +# ... + + +# Comment Types +# ------------------------------------------------------------------------ + +Comment Type: Union + + Plural Display Name: Unions + + Scope: Normal + + Keywords: + union, unions + + +# Each Natural Docs comment has a corresponding type which determine its +# behavior. You can define your own here or override the settings of the +# existing ones. +# +# Comment Type: [name] +# Alter Comment Type: [name] +# Creates a new comment type or changes an existing one. +# +# Display Name: [name] +# Plural Display Name: [name] +# The singular and plural name of the comment type as it should appear in +# the output. +# +# Simple Identifier: [name] +# The name of the comment type using only the letters A to Z. No spaces, +# numbers, symbols, or Unicode allowed. Defaults to the comment type name +# minus any unacceptable characters. This is used to generate things like +# CSS class names. +# +# Scope: [normal|start|end|always global] +# How the comment affects scope. Defaults to normal. +# normal - The comment stays within the current scope. +# start - The comment starts a new scope for all the comments +# beneath it, like class comments. +# end - The comment resets the scope back to global for all the +# comments beneath it, like section comments. +# always global - The comment is defined as a global symbol, but does not +# change the scope for any other comments. +# +# Flags: [flag], [flag], ... +# A combination of settings that apply to the comment type. +# Code, File, or Documentation +# Whether it's used to describe a code element, a file, or is a +# standalone documentation comment. Defaults to Code. +# Variable Type +# Whether it describes a code element that can be used as a variable's +# type. +# Class Hierarchy or Database Hierarchy +# Whether it describes a code element that should be included in the +# class or database hierarchy. Requires Scope: Start. +# Enum +# Whether it describes an enum. +# +# Keywords: +# [keyword] +# [keyword], [plural keyword] +# ... +# A list of the comment type's keywords. Each line after the heading is +# the keyword and optionally its plural form for list comments. You can +# reuse existing keywords to change their definition. When using +# "Alter Comment Type", these keywords are added to the existing ones +# rather than replacing them. diff --git a/nd_config/Languages.txt b/nd_config/Languages.txt new file mode 100644 index 0000000..232d50d --- /dev/null +++ b/nd_config/Languages.txt @@ -0,0 +1,95 @@ +Format: 2.0.2 + +# This is the Natural Docs languages file for this project. If you change +# anything here, it will apply to THIS PROJECT ONLY. You can edit the version +# in Natural Docs' Config folder to make the changes apply to all projects, +# but it's recommended that you edit this version instead. + + +# Ignored Extensions +# ------------------------------------------------------------------------ + +# If you'd like to prevent certain file extensions from being scanned by +# Natural Docs, you can do it like this: +# +# Ignore Extensions: [extension] [extension] ... + + +# Languages +# ------------------------------------------------------------------------ + +# These settings define the languages Natural Docs knows how to parse. You +# can define your own here or override the settings of the existing ones. +# Note that all lists are space separated so that commas can be used as +# values. +# +# Language: [name] +# Alter Language: [name] +# Defines a new language or alters an existing one. Its name can use any +# characters. If any of the properties below have an add/replace form, you +# must use that when using Alter Language. +# +# The language Shebang Script is special. It's entry is only used for +# extensions, and files with those extensions have their shebang (#!) lines +# read to determine the real language of the file. Extensionless files are +# always treated this way. +# +# The language Text File is also special. It's treated as one big comment +# so you can put Natural Docs content in them without special symbols. +# +# Extensions: [extension] [extension] ... +# [Add/Replace] Extensions: [extension] [extension] ... +# Defines the file extensions of the language's source files. +# +# Shebang Strings: [string] [string] ... +# [Add/Replace] Shebang Strings: [string] [string] ... +# Defines a list of strings that can appear in the shebang (#!) line to +# designate that it's part of the language. +# +# Simple Identifier: [name] +# The name of the language using only the letters A to Z. No spaces, +# numbers, symbols, or Unicode allowed. Defaults to the language name +# minus any unacceptable characters. This is used to generate things like +# CSS class names. +# +# Aliases: [alias] [alias] ... +# [Add/Replace] Aliases: [alias] [alias] ... +# Defines alternate names for the language that can be used to start a code +# block. +# +# +# Properties for Basic Language Support Only +# ------------------------------------------------------------------------ +# If you're adding your own language to Natural Docs you must define these. +# +# Line Comments: [symbol] [symbol] ... +# Defines a space-separated list of symbols that are used for line comments, +# if any. +# +# Block Comments: [opening sym] [closing sym] [opening sym] [closing sym] ... +# Defines a space-separated list of symbol pairs that are used for block +# comments, if any. +# +# Member Operator: [symbol] +# Defines the default member operator symbol. The default is a dot. +# +# Line Extender: [symbol] +# Defines the symbol that allows a prototype to span multiple lines if +# normally a line break would end it. +# +# Enum Values: [global|under type|under parent] +# Defines how enum values are referenced. The default is global. +# global - Values are always global, referenced as 'value'. +# under type - Values are under the enum type, referenced as +# 'class.enum.value'. +# under parent - Values are under the enum's parent, referenced as +# 'class.value'. +# +# Case Sensitive: [yes|no] +# Defines whether the language's identifiers are case sensitive. The +# default is yes. +# +# [Comment Type] Prototype Enders: [symbol] [symbol] ... +# When defined, Natural Docs will attempt to get a prototype from the code +# immediately following the comment type. It stops when it reaches one of +# these symbols. Use \n for line breaks. diff --git a/nd_config/Project.txt b/nd_config/Project.txt new file mode 100644 index 0000000..211c2be --- /dev/null +++ b/nd_config/Project.txt @@ -0,0 +1,121 @@ +Format: 2.0.2 + +# This is the file you use to provide information about your project. It can +# also be used to specify input and output settings so you don't have to +# include them on the command line. + + +# Project Information +# ------------------------------------------------------------------------ + +Title: TinyObj +Subtitle: Tiny but powerful single file wavefront obj loader + +Copyright: Copyright © 2016 - 2019 Syoyo Fujita and many contributors (the MIT license). + +Timestamp: Last updated yyyy/mon/dd +# m - Single digit month, when possible. January is "1". +# mm - Always double digit month. January is "01". +# mon - Short month word. January is "Jan". +# month - Long month word. January is "January". +# d - Single digit day, when possible. 1 is "1". +# dd - Always double digit day. 1 is "01". +# day - Day with text extension. 1 is "1st". +# yy - Double digit year. 2017 is "17". +# yyyy - Four digit year. 2017 is "2017". +# year - Four digit year. 2017 is "2017". + + +# This is where you specify general information about your project. +# +# Style: [style] +# The style to apply to the generated documentation. It can be the name of +# a CSS file in the project configuration folder or a subfolder that +# contains Style.txt. Do not include ".css" if using a CSS file. + + +# Source Code +# ------------------------------------------------------------------------ + +Source Folder: .. + + + +# This is where you specify what files and folders Natural Docs should be +# scanning. If you use any of these options on the command line, this entire +# section is ignored except for names and numbers. +# +# All paths are relative to the project configuration folder, which lets this +# file remain portable across computers and not cause problems in version +# control systems. You can enter absolute paths and they will be converted +# automatically. +# +# Source Folder: [path] +# Name: [name] +# +# Specifies a folder which will be searched for source files. If you have +# more than one, add the Name property to set how it will show up in the +# menu. + + +# Source Filtering +# ------------------------------------------------------------------------ + +# If there are any subfolders in the source code that you would like Natural +# Docs to ignore, they can be specified here. If you use any of these options +# on the command line, this entire section is ignored. +# +# Ignore Source Folder: [path] +# Tells Natural Docs to skip this folder when scanning files. +# +# Ignore Source Folder Pattern: [pattern] +# Tells Natural Docs to skip all folder names which match this pattern when +# scanning files. ? matches a single character, * matches zero or more +# characters. It applies to the entire folder name, so "cli" will not +# match "client", although "cli*" will. +# +# The data folders of common version control systems (.git, .svn, .cvs, .hg) +# are ignored automatically. You do not have to specify them here. + + +# Generated Documentation +# ------------------------------------------------------------------------ + +HTML Output Folder: ..\doc + + +# This is where you specify what kind of documentation you want Natural Docs +# to build and where it should be put. If you use any of these options on the +# command line, this entire section is ignored except for secondary settings. +# +# All paths are relative to the project configuration folder, which lets this +# file remain portable across computers and not cause problems in version +# control systems. You can enter absolute paths and they will be converted +# automatically. +# +# You can override any of the project information settings under each entry, +# so if you have multiple output folders you can give them each different +# styles or subtitles. +# +# HTML Output Folder: [path] +# [Project Information] +# +# Generates HTML documentation in the specified folder. + + +# Global Settings +# ------------------------------------------------------------------------ + +Auto Group: No + +# Other settings that apply to your entire project. Settings specified on the +# command line override the settings here. +# +# Tab Width: [width] +# The number of spaces tabs should be expanded to. +# +# Documented Only: [yes|no] +# Whether only documented code elements should appear in the output. +# Defaults to no. + + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..5f79dd8 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.14) + +project(tinyobjloader LANGUAGES C) + +file(GLOB SOURCE_FILES "*.c") +file(GLOB HEADER_FILES "*.h") + +add_executable(tinyobjloader ${SOURCE_FILES} ${HEADER_FILES} "../tinyobj_loader_c.h") +target_compile_definitions(tinyobjloader PUBLIC "_CRT_SECURE_NO_WARNINGS") +target_include_directories(tinyobjloader PUBLIC "../") diff --git a/test/acutest.h b/test/acutest.h index fd8c185..bbd284a 100644 --- a/test/acutest.h +++ b/test/acutest.h @@ -2,7 +2,7 @@ * Acutest -- Another C/C++ Unit Test facility * * - * Copyright (c) 2013-2017 Martin Mitas + * Copyright (c) 2013-2019 Martin Mitas * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -56,7 +56,7 @@ * * void test_func(void); */ -#define TEST_LIST const struct test__ test_list__[] +#define TEST_LIST const struct test__ test_list__[] /* Macros for testing whether an unit test succeeds or fails. These macros @@ -78,31 +78,130 @@ * TEST_CHECK(ptr->member2 > 200); * } */ -#define TEST_CHECK_(cond,...) test_check__((cond), __FILE__, __LINE__, __VA_ARGS__) -#define TEST_CHECK(cond) test_check__((cond), __FILE__, __LINE__, "%s", #cond) +#define TEST_CHECK_(cond,...) test_check__((cond), __FILE__, __LINE__, __VA_ARGS__) +#define TEST_CHECK(cond) test_check__((cond), __FILE__, __LINE__, "%s", #cond) + +#ifdef __cplusplus +/* Macros to verify that the code (the 1st argument) throws exception of given + * type (the 2nd argument). (Note these macros are only available in C++.) + * + * TEST_EXCEPTION_ is like TEST_EXCEPTION but accepts custom printf-like + * message. + * + * For example: + * + * TEST_EXCEPTION(function_that_throw(), ExpectedExceptionType); + * + * If the function_that_throw() throws ExpectedExceptionType, the check passes. + * If the function throws anything incompatible with ExpectedExceptionType + * (or if it does not thrown an exception at all), the check fails. + */ +#define TEST_EXCEPTION(code, exctype) \ + do { \ + bool exc_ok__ = false; \ + const char *msg__ = NULL; \ + try { \ + code; \ + msg__ = "No exception thrown."; \ + } catch(exctype const&) { \ + exc_ok__= true; \ + } catch(...) { \ + msg__ = "Unexpected exception thrown."; \ + } \ + test_check__(exc_ok__, __FILE__, __LINE__, #code " throws " #exctype); \ + if(msg__ != NULL) \ + test_message__("%s", msg__); \ + } while(0) +#define TEST_EXCEPTION_(code, exctype, ...) \ + do { \ + bool exc_ok__ = false; \ + const char *msg__ = NULL; \ + try { \ + code; \ + msg__ = "No exception thrown."; \ + } catch(exctype const&) { \ + exc_ok__= true; \ + } catch(...) { \ + msg__ = "Unexpected exception thrown."; \ + } \ + test_check__(exc_ok__, __FILE__, __LINE__, __VA_ARGS__); \ + if(msg__ != NULL) \ + test_message__("%s", msg__); \ + } while(0) +#endif /* #ifdef __cplusplus */ + + +/* Sometimes it is useful to split execution of more complex unit tests to some + * smaller parts and associate those parts with some names. + * + * This is especially handy if the given unit test is implemented as a loop + * over some vector of multiple testing inputs. Using these macros allow to use + * sort of subtitle for each iteration of the loop (e.g. outputting the input + * itself or a name associated to it), so that if any TEST_CHECK condition + * fails in the loop, it can be easily seen which iteration triggers the + * failure, without the need to manually output the iteration-specific data in + * every single TEST_CHECK inside the loop body. + * + * TEST_CASE allows to specify only single string as the name of the case, + * TEST_CASE_ provides all the power of printf-like string formatting. + * + * Note that the test cases cannot be nested. Starting a new test case ends + * implicitly the previous one. To end the test case explicitly (e.g. to end + * the last test case after exiting the loop), you may use TEST_CASE(NULL). + */ +#define TEST_CASE_(...) test_case__(__VA_ARGS__) +#define TEST_CASE(name) test_case__("%s", name); /* printf-like macro for outputting an extra information about a failure. * - * Note it does not output anything if there was not (yet) failed condition - * in the current test. Intended use is to output some computed output - * versus the expected value, e.g. like this: + * Intended use is to output some computed output versus the expected value, + * e.g. like this: * * if(!TEST_CHECK(produced == expected)) { * TEST_MSG("Expected: %d", expected); * TEST_MSG("Produced: %d", produced); * } * + * Note the message is only written down if the most recent use of any checking + * macro (like e.g. TEST_CHECK or TEST_EXCEPTION) in the current test failed. + * This means the above is equivalent to just this: + * + * TEST_CHECK(produced == expected); + * TEST_MSG("Expected: %d", expected); + * TEST_MSG("Produced: %d", produced); + * * The macro can deal with multi-line output fairly well. It also automatically * adds a final new-line if there is none present. */ -#define TEST_MSG(...) test_message__(__VA_ARGS__) +#define TEST_MSG(...) test_message__(__VA_ARGS__) + /* Maximal output per TEST_MSG call. Longer messages are cut. * You may define another limit prior including "acutest.h" */ #ifndef TEST_MSG_MAXSIZE -#define TEST_MSG_MAXSIZE 1024 + #define TEST_MSG_MAXSIZE 1024 +#endif + + +/* Macro for dumping a block of memory. + * + * Its inteded use is very similar to what TEST_MSG is for, but instead of + * generating any printf-like message, this is for dumping raw block of a + * memory in a hexadecimal form: + * + * TEST_CHECK(size_produced == size_expected && memcmp(addr_produced, addr_expected, size_produced) == 0); + * TEST_DUMP("Expected:", addr_expected, size_expected); + * TEST_DUMP("Produced:", addr_produced, size_produced); + */ +#define TEST_DUMP(title, addr, size) test_dump__(title, addr, size) + +/* Maximal output per TEST_DUMP call (in bytes to dump). Longer blocks are cut. + * You may define another limit prior including "acutest.h" + */ +#ifndef TEST_DUMP_MAXSIZE + #define TEST_DUMP_MAXSIZE 1024 #endif @@ -112,34 +211,41 @@ /* The unit test files should not rely on anything below. */ +#include #include #include #include #include #if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__) -#define ACUTEST_UNIX__ 1 + #define ACUTEST_UNIX__ 1 #include + #include #include #include #include #include + #include + + #if defined CLOCK_PROCESS_CPUTIME_ID && defined CLOCK_MONOTONIC + #define ACUTEST_HAS_POSIX_TIMER__ 1 + #endif #endif #if defined(__gnu_linux__) -#define ACUTEST_LINUX__ 1 + #define ACUTEST_LINUX__ 1 #include #include #endif #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) -#define ACUTEST_WIN__ 1 + #define ACUTEST_WIN__ 1 #include #include #endif #ifdef __cplusplus -#include + #include #endif @@ -148,7 +254,7 @@ #ifdef __cplusplus -extern "C" { + extern "C" { #endif @@ -157,31 +263,151 @@ struct test__ { void (*func)(void); }; +struct test_detail__ { + unsigned char flags; + double duration; +}; + +enum { + TEST_FLAG_RUN__ = 1 << 0, + TEST_FLAG_SUCCESS__ = 1 << 1, + TEST_FLAG_FAILURE__ = 1 << 2, +}; + extern const struct test__ test_list__[]; int test_check__(int cond, const char* file, int line, const char* fmt, ...); +void test_case__(const char* fmt, ...); void test_message__(const char* fmt, ...); +void test_dump__(const char* title, const void* addr, size_t size); #ifndef TEST_NO_MAIN static char* test_argv0__ = NULL; static size_t test_list_size__ = 0; -static const struct test__** tests__ = NULL; -static char* test_flags__ = NULL; +static struct test_detail__ *test_details__ = NULL; static size_t test_count__ = 0; static int test_no_exec__ = -1; static int test_no_summary__ = 0; +static int test_tap__ = 0; static int test_skip_mode__ = 0; +static int test_worker__ = 0; +static int test_worker_index__ = 0; +static int test_cond_failed__ = 0; +static FILE *test_xml_output__ = NULL; static int test_stat_failed_units__ = 0; static int test_stat_run_units__ = 0; static const struct test__* test_current_unit__ = NULL; +static int test_current_index__ = 0; +static char test_case_name__[64] = ""; static int test_current_already_logged__ = 0; +static int test_case_current_already_logged__ = 0; static int test_verbose_level__ = 2; static int test_current_failures__ = 0; static int test_colorize__ = 0; +static int test_timer__ = 0; + +#if defined ACUTEST_WIN__ + typedef LARGE_INTEGER test_timer_type__; + static LARGE_INTEGER test_timer_freq__; + static test_timer_type__ test_timer_start__; + static test_timer_type__ test_timer_end__; + + static void + test_timer_init__(void) + { + QueryPerformanceFrequency(&test_timer_freq__); + } + + static void + test_timer_get_time__(LARGE_INTEGER* ts) + { + QueryPerformanceCounter(ts); + } + + static double + test_timer_diff__(LARGE_INTEGER start, LARGE_INTEGER end) + { + double duration = end.QuadPart - start.QuadPart; + duration /= test_timer_freq__.QuadPart; + return duration; + } + + static void + test_timer_print_diff__(void) + { + printf("%.6lf secs", test_timer_diff__(test_timer_start__, test_timer_end__)); + } +#elif defined ACUTEST_HAS_POSIX_TIMER__ + static clockid_t test_timer_id__; + typedef struct timespec test_timer_type__; + static test_timer_type__ test_timer_start__; + static test_timer_type__ test_timer_end__; + + static void + test_timer_init__(void) + { + if(test_timer__ == 1) + #ifdef CLOCK_MONOTONIC_RAW + /* linux specific; not subject of NTP adjustements or adjtime() */ + test_timer_id__ = CLOCK_MONOTONIC_RAW; + #else + test_timer_id__ = CLOCK_MONOTONIC; + #endif + else if(test_timer__ == 2) + test_timer_id__ = CLOCK_PROCESS_CPUTIME_ID; + } + + static void + test_timer_get_time__(struct timespec* ts) + { + clock_gettime(test_timer_id__, ts); + } + + static double + test_timer_diff__(struct timespec start, struct timespec end) + { + return ((double) end.tv_sec + + (double) end.tv_nsec * 10e-9) + - + ((double) start.tv_sec + + (double) start.tv_nsec * 10e-9); + } + + static void + test_timer_print_diff__(void) + { + printf("%.6lf secs", + test_timer_diff__(test_timer_start__, test_timer_end__)); + } +#else + typedef int test_timer_type__; + static test_timer_type__ test_timer_start__; + static test_timer_type__ test_timer_end__; + + void + test_timer_init__(void) + {} + + static void + test_timer_get_time__(int* ts) + { + (void) ts; + } + + static double + test_timer_diff__(int start, int end) + { + return 0.0; + } + + static void + test_timer_print_diff__(void) + {} +#endif #define TEST_COLOR_DEFAULT__ 0 #define TEST_COLOR_GREEN__ 1 @@ -215,7 +441,7 @@ test_print_in_color__(int color, const char* fmt, ...) case TEST_COLOR_GREEN_INTENSIVE__: col_str = "\033[1;32m"; break; case TEST_COLOR_RED_INTENSIVE__: col_str = "\033[1;31m"; break; case TEST_COLOR_DEFAULT_INTENSIVE__: col_str = "\033[1m"; break; - default: col_str = "\033[0m"; break; + default: col_str = "\033[0m"; break; } printf("%s", col_str); n = printf("%s", buffer); @@ -237,7 +463,7 @@ test_print_in_color__(int color, const char* fmt, ...) case TEST_COLOR_GREEN_INTENSIVE__: attr = FOREGROUND_GREEN | FOREGROUND_INTENSITY; break; case TEST_COLOR_RED_INTENSIVE__: attr = FOREGROUND_RED | FOREGROUND_INTENSITY; break; case TEST_COLOR_DEFAULT_INTENSIVE__: attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; break; - default: attr = 0; break; + default: attr = 0; break; } if(attr != 0) SetConsoleTextAttribute(h, attr); @@ -251,6 +477,74 @@ test_print_in_color__(int color, const char* fmt, ...) #endif } +static void +test_begin_test_line__(const struct test__* test) +{ + if(!test_tap__) { + if(test_verbose_level__ >= 3) { + test_print_in_color__(TEST_COLOR_DEFAULT_INTENSIVE__, "Test %s:\n", test->name); + test_current_already_logged__++; + } else if(test_verbose_level__ >= 1) { + int n; + char spaces[48]; + + n = test_print_in_color__(TEST_COLOR_DEFAULT_INTENSIVE__, "Test %s... ", test->name); + memset(spaces, ' ', sizeof(spaces)); + if(n < (int) sizeof(spaces)) + printf("%.*s", (int) sizeof(spaces) - n, spaces); + } else { + test_current_already_logged__ = 1; + } + } +} + +static void +test_finish_test_line__(int result) +{ + if(test_tap__) { + const char* str = (result == 0) ? "ok" : "not ok"; + + printf("%s %u - %s\n", str, test_current_index__ + 1, test_current_unit__->name); + + if(result == 0 && test_timer__) { + printf("# Duration: "); + test_timer_print_diff__(); + printf("\n"); + } + } else { + int color = (result == 0) ? TEST_COLOR_GREEN_INTENSIVE__ : TEST_COLOR_RED_INTENSIVE__; + const char* str = (result == 0) ? "OK" : "FAILED"; + printf("[ "); + test_print_in_color__(color, str); + printf(" ]"); + + if(result == 0 && test_timer__) { + printf(" "); + test_timer_print_diff__(); + } + + printf("\n"); + } +} + +static void +test_line_indent__(int level) +{ + static const char spaces[] = " "; + int n = level * 2; + + if(test_tap__ && n > 0) { + n--; + printf("#"); + } + + while(n > 16) { + printf("%s", spaces); + n -= 16; + } + printf("%.*s", n, spaces); +} + int test_check__(int cond, const char* file, int line, const char* fmt, ...) { @@ -263,11 +557,9 @@ test_check__(int cond, const char* file, int line, const char* fmt, ...) result_color = TEST_COLOR_GREEN__; verbose_level = 3; } else { - if(!test_current_already_logged__ && test_current_unit__ != NULL) { - printf("[ "); - test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, "FAILED"); - printf(" ]\n"); - } + if(!test_current_already_logged__ && test_current_unit__ != NULL) + test_finish_test_line__(-1); + result_str = "failed"; result_color = TEST_COLOR_RED__; verbose_level = 2; @@ -278,8 +570,14 @@ test_check__(int cond, const char* file, int line, const char* fmt, ...) if(test_verbose_level__ >= verbose_level) { va_list args; - printf(" "); + if(!test_case_current_already_logged__ && test_case_name__[0]) { + test_line_indent__(1); + test_print_in_color__(TEST_COLOR_DEFAULT_INTENSIVE__, "Case %s:\n", test_case_name__); + test_current_already_logged__++; + test_case_current_already_logged__++; + } + test_line_indent__(test_case_name__[0] ? 2 : 1); if(file != NULL) { if(test_verbose_level__ < 3) { #ifdef ACUTEST_WIN__ @@ -309,7 +607,37 @@ test_check__(int cond, const char* file, int line, const char* fmt, ...) test_current_already_logged__++; } - return (cond != 0); + test_cond_failed__ = (cond == 0); + return !test_cond_failed__; +} + +void +test_case__(const char* fmt, ...) +{ + va_list args; + + if(test_verbose_level__ < 2) + return; + + if(test_case_name__[0]) { + test_case_current_already_logged__ = 0; + test_case_name__[0] = '\0'; + } + + if(fmt == NULL) + return; + + va_start(args, fmt); + vsnprintf(test_case_name__, sizeof(test_case_name__) - 1, fmt, args); + va_end(args); + test_case_name__[sizeof(test_case_name__) - 1] = '\0'; + + if(test_verbose_level__ >= 3) { + test_line_indent__(1); + test_print_in_color__(TEST_COLOR_DEFAULT_INTENSIVE__, "Case %s:\n", test_case_name__); + test_current_already_logged__++; + test_case_current_already_logged__++; + } } void @@ -325,7 +653,7 @@ test_message__(const char* fmt, ...) /* We allow extra message only when something is already wrong in the * current test. */ - if(!test_current_already_logged__ || test_current_unit__ == NULL) + if(test_current_unit__ == NULL || !test_cond_failed__) return; va_start(args, fmt); @@ -338,11 +666,68 @@ test_message__(const char* fmt, ...) line_end = strchr(line_beg, '\n'); if(line_end == NULL) break; - printf(" %.*s\n", (int)(line_end - line_beg), line_beg); + test_line_indent__(test_case_name__[0] ? 3 : 2); + printf("%.*s\n", (int)(line_end - line_beg), line_beg); line_beg = line_end + 1; } - if(line_beg[0] != '\0') - printf(" %s\n", line_beg); + if(line_beg[0] != '\0') { + test_line_indent__(test_case_name__[0] ? 3 : 2); + printf("%s\n", line_beg); + } +} + +void +test_dump__(const char* title, const void* addr, size_t size) +{ + static const size_t BYTES_PER_LINE = 16; + size_t line_beg; + size_t truncate = 0; + + if(test_verbose_level__ < 2) + return; + + /* We allow extra message only when something is already wrong in the + * current test. */ + if(test_current_unit__ == NULL || !test_cond_failed__) + return; + + if(size > TEST_DUMP_MAXSIZE) { + truncate = size - TEST_DUMP_MAXSIZE; + size = TEST_DUMP_MAXSIZE; + } + + test_line_indent__(test_case_name__[0] ? 3 : 2); + printf((title[strlen(title)-1] == ':') ? "%s\n" : "%s:\n", title); + + for(line_beg = 0; line_beg < size; line_beg += BYTES_PER_LINE) { + size_t line_end = line_beg + BYTES_PER_LINE; + size_t off; + + test_line_indent__(test_case_name__[0] ? 4 : 3); + printf("%08lx: ", (unsigned long)line_beg); + for(off = line_beg; off < line_end; off++) { + if(off < size) + printf(" %02x", ((unsigned char*)addr)[off]); + else + printf(" "); + } + + printf(" "); + for(off = line_beg; off < line_end; off++) { + unsigned char byte = ((unsigned char*)addr)[off]; + if(off < size) + printf("%c", (iscntrl(byte) ? '.' : byte)); + else + break; + } + + printf("\n"); + } + + if(truncate > 0) { + test_line_indent__(test_case_name__[0] ? 4 : 3); + printf(" ... (and more %u bytes)\n", (unsigned) truncate); + } } static void @@ -358,15 +743,25 @@ test_list_names__(void) static void test_remember__(int i) { - if(test_flags__[i]) + if(test_details__[i].flags & TEST_FLAG_RUN__) return; - else - test_flags__[i] = 1; - tests__[test_count__] = &test_list__[i]; + test_details__[i].flags |= TEST_FLAG_RUN__; test_count__++; } +static void +test_set_success__(int i, int success) +{ + test_details__[i].flags |= success ? TEST_FLAG_SUCCESS__ : TEST_FLAG_FAILURE__; +} + +static void +test_set_duration__(int i, double duration) +{ + test_details__[i].duration = duration; +} + static int test_name_contains_word__(const char* name, const char* pattern) { @@ -430,68 +825,7 @@ test_lookup__(const char* pattern) return n; } -/* Call directly the given test unit function. */ -static int -test_do_run__(const struct test__* test) -{ - test_current_unit__ = test; - test_current_failures__ = 0; - test_current_already_logged__ = 0; - - if(test_verbose_level__ >= 3) { - test_print_in_color__(TEST_COLOR_DEFAULT_INTENSIVE__, "Test %s:\n", test->name); - test_current_already_logged__++; - } else if(test_verbose_level__ >= 1) { - int n; - char spaces[48]; - - n = test_print_in_color__(TEST_COLOR_DEFAULT_INTENSIVE__, "Test %s... ", test->name); - memset(spaces, ' ', sizeof(spaces)); - if(n < (int) sizeof(spaces)) - printf("%.*s", (int) sizeof(spaces) - n, spaces); - } else { - test_current_already_logged__ = 1; - } - -#ifdef __cplusplus - try { -#endif - - /* This is good to do for case the test unit e.g. crashes. */ - fflush(stdout); - fflush(stderr); - - test->func(); -#ifdef __cplusplus - } catch(std::exception& e) { - const char* what = e.what(); - if(what != NULL) - test_check__(0, NULL, 0, "Threw std::exception: %s", what); - else - test_check__(0, NULL, 0, "Threw std::exception"); - } catch(...) { - test_check__(0, NULL, 0, "Threw an exception"); - } -#endif - - if(test_verbose_level__ >= 3) { - switch(test_current_failures__) { - case 0: test_print_in_color__(TEST_COLOR_GREEN_INTENSIVE__, " All conditions have passed.\n\n"); break; - case 1: test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, " One condition has FAILED.\n\n"); break; - default: test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, " %d conditions have FAILED.\n\n", test_current_failures__); break; - } - } else if(test_verbose_level__ >= 1 && test_current_failures__ == 0) { - printf("[ "); - test_print_in_color__(TEST_COLOR_GREEN_INTENSIVE__, "OK"); - printf(" ]\n"); - } - - test_current_unit__ = NULL; - return (test_current_failures__ == 0) ? 0 : -1; -} - -#if defined(ACUTEST_UNIX__) || defined(ACUTEST_WIN__) /* Called if anything goes bad in Acutest, or if the unit test ends in other * way then by normal returning from its function (e.g. exception or some * abnormal child process termination). */ @@ -504,31 +838,109 @@ test_error__(const char* fmt, ...) return; if(test_verbose_level__ <= 2 && !test_current_already_logged__ && test_current_unit__ != NULL) { - printf("[ "); - test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, "FAILED"); - printf(" ]\n"); + if(test_tap__) { + test_finish_test_line__(-1); + } else { + printf("[ "); + test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, "FAILED"); + printf(" ]\n"); + } } if(test_verbose_level__ >= 2) { - test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, " Error: "); + test_line_indent__(1); + if(test_verbose_level__ >= 3) + test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, "ERROR: "); va_start(args, fmt); vprintf(fmt, args); va_end(args); printf("\n"); } + + if(test_verbose_level__ >= 3) { + printf("\n"); + } } + +/* Call directly the given test unit function. */ +static int +test_do_run__(const struct test__* test, int index) +{ + test_current_unit__ = test; + test_current_index__ = index; + test_current_failures__ = 0; + test_current_already_logged__ = 0; + test_cond_failed__ = 0; + + test_begin_test_line__(test); + +#ifdef __cplusplus + try { #endif + /* This is good to do for case the test unit e.g. crashes. */ + fflush(stdout); + fflush(stderr); + + test_timer_get_time__(&test_timer_start__); + test->func(); + test_timer_get_time__(&test_timer_end__); + + if(test_verbose_level__ >= 3) { + test_line_indent__(1); + if(test_current_failures__ == 0) { + test_print_in_color__(TEST_COLOR_GREEN_INTENSIVE__, "SUCCESS: "); + printf("All conditions have passed.\n"); + + if(test_timer__) { + test_line_indent__(1); + printf("Duration: "); + test_timer_print_diff__(); + printf("\n"); + } + } else { + test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, "FAILED: "); + printf("%d condition%s %s failed.\n", + test_current_failures__, + (test_current_failures__ == 1) ? "" : "s", + (test_current_failures__ == 1) ? "has" : "have"); + } + printf("\n"); + } else if(test_verbose_level__ >= 1 && test_current_failures__ == 0) { + test_finish_test_line__(0); + } + + test_case__(NULL); + test_current_unit__ = NULL; + return (test_current_failures__ == 0) ? 0 : -1; + +#ifdef __cplusplus + } catch(std::exception& e) { + const char* what = e.what(); + if(what != NULL) + test_error__("Threw std::exception: %s", what); + else + test_error__("Threw std::exception"); + return -1; + } catch(...) { + test_error__("Threw an exception"); + return -1; + } +#endif +} + /* Trigger the unit test. If possible (and not suppressed) it starts a child * process who calls test_do_run__(), otherwise it calls test_do_run__() * directly. */ static void -test_run__(const struct test__* test) +test_run__(const struct test__* test, int index, int master_index) { int failed = 1; + test_timer_type__ start, end; test_current_unit__ = test; test_current_already_logged__ = 0; + test_timer_get_time__(&start); if(!test_no_exec__) { @@ -537,13 +949,17 @@ test_run__(const struct test__* test) pid_t pid; int exit_code; + /* Make sure the child starts with empty I/O buffers. */ + fflush(stdout); + fflush(stderr); + pid = fork(); if(pid == (pid_t)-1) { test_error__("Cannot fork. %s [%d]", strerror(errno), errno); failed = 1; } else if(pid == 0) { /* Child: Do the test. */ - failed = (test_do_run__(test) != 0); + failed = (test_do_run__(test, index) != 0); exit(failed ? 1 : 0); } else { /* Parent: Wait until child terminates and analyze its exit code. */ @@ -584,9 +1000,11 @@ test_run__(const struct test__* test) /* Windows has no fork(). So we propagate all info into the child * through a command line arguments. */ _snprintf(buffer, sizeof(buffer)-1, - "%s --no-exec --no-summary --verbose=%d --color=%s -- \"%s\"", - test_argv0__, test_verbose_level__, - test_colorize__ ? "always" : "never", test->name); + "%s --worker=%d %s --no-exec --no-summary %s --verbose=%d --color=%s -- \"%s\"", + test_argv0__, index, test_timer__ ? "--timer" : "", + test_tap__ ? "--tap" : "", test_verbose_level__, + test_colorize__ ? "always" : "never", + test->name); memset(&startupInfo, 0, sizeof(startupInfo)); startupInfo.cb = sizeof(STARTUPINFO); if(CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) { @@ -603,20 +1021,24 @@ test_run__(const struct test__* test) #else /* A platform where we don't know how to run child process. */ - failed = (test_do_run__(test) != 0); + failed = (test_do_run__(test, index) != 0); #endif } else { /* Child processes suppressed through --no-exec. */ - failed = (test_do_run__(test) != 0); + failed = (test_do_run__(test, index) != 0); } + test_timer_get_time__(&end); test_current_unit__ = NULL; test_stat_run_units__++; if(failed) test_stat_failed_units__++; + + test_set_success__(master_index, !failed); + test_set_duration__(master_index, test_timer_diff__(start, end)); } #if defined(ACUTEST_WIN__) @@ -634,29 +1056,199 @@ test_exception_filter__(EXCEPTION_POINTERS *ptrs) #endif +#define TEST_CMDLINE_OPTFLAG_OPTIONALARG__ 0x0001 +#define TEST_CMDLINE_OPTFLAG_REQUIREDARG__ 0x0002 + +#define TEST_CMDLINE_OPTID_NONE__ 0 +#define TEST_CMDLINE_OPTID_UNKNOWN__ (-0x7fffffff + 0) +#define TEST_CMDLINE_OPTID_MISSINGARG__ (-0x7fffffff + 1) +#define TEST_CMDLINE_OPTID_BOGUSARG__ (-0x7fffffff + 2) + +typedef struct TEST_CMDLINE_OPTION__ { + char shortname; + const char* longname; + int id; + unsigned flags; +} TEST_CMDLINE_OPTION__; + +static int +test_cmdline_handle_short_opt_group__(const TEST_CMDLINE_OPTION__* options, + const char* arggroup, + int (*callback)(int /*optval*/, const char* /*arg*/)) +{ + const TEST_CMDLINE_OPTION__* opt; + int i; + int ret = 0; + + for(i = 0; arggroup[i] != '\0'; i++) { + for(opt = options; opt->id != 0; opt++) { + if(arggroup[i] == opt->shortname) + break; + } + + if(opt->id != 0 && !(opt->flags & TEST_CMDLINE_OPTFLAG_REQUIREDARG__)) { + ret = callback(opt->id, NULL); + } else { + /* Unknown option. */ + char badoptname[3]; + badoptname[0] = '-'; + badoptname[1] = arggroup[i]; + badoptname[2] = '\0'; + ret = callback((opt->id != 0 ? TEST_CMDLINE_OPTID_MISSINGARG__ : TEST_CMDLINE_OPTID_UNKNOWN__), + badoptname); + } + + if(ret != 0) + break; + } + + return ret; +} + +#define TEST_CMDLINE_AUXBUF_SIZE__ 32 + +static int +test_cmdline_read__(const TEST_CMDLINE_OPTION__* options, int argc, char** argv, + int (*callback)(int /*optval*/, const char* /*arg*/)) +{ + + const TEST_CMDLINE_OPTION__* opt; + char auxbuf[TEST_CMDLINE_AUXBUF_SIZE__+1]; + int after_doubledash = 0; + int i = 1; + int ret = 0; + + auxbuf[TEST_CMDLINE_AUXBUF_SIZE__] = '\0'; + + while(i < argc) { + if(after_doubledash || strcmp(argv[i], "-") == 0) { + /* Non-option argument. */ + ret = callback(TEST_CMDLINE_OPTID_NONE__, argv[i]); + } else if(strcmp(argv[i], "--") == 0) { + /* End of options. All the remaining members are non-option arguments. */ + after_doubledash = 1; + } else if(argv[i][0] != '-') { + /* Non-option argument. */ + ret = callback(TEST_CMDLINE_OPTID_NONE__, argv[i]); + } else { + for(opt = options; opt->id != 0; opt++) { + if(opt->longname != NULL && strncmp(argv[i], "--", 2) == 0) { + size_t len = strlen(opt->longname); + if(strncmp(argv[i]+2, opt->longname, len) == 0) { + /* Regular long option. */ + if(argv[i][2+len] == '\0') { + /* with no argument provided. */ + if(!(opt->flags & TEST_CMDLINE_OPTFLAG_REQUIREDARG__)) + ret = callback(opt->id, NULL); + else + ret = callback(TEST_CMDLINE_OPTID_MISSINGARG__, argv[i]); + break; + } else if(argv[i][2+len] == '=') { + /* with an argument provided. */ + if(opt->flags & (TEST_CMDLINE_OPTFLAG_OPTIONALARG__ | TEST_CMDLINE_OPTFLAG_REQUIREDARG__)) { + ret = callback(opt->id, argv[i]+2+len+1); + } else { + sprintf(auxbuf, "--%s", opt->longname); + ret = callback(TEST_CMDLINE_OPTID_BOGUSARG__, auxbuf); + } + break; + } else { + continue; + } + } + } else if(opt->shortname != '\0' && argv[i][0] == '-') { + if(argv[i][1] == opt->shortname) { + /* Regular short option. */ + if(opt->flags & TEST_CMDLINE_OPTFLAG_REQUIREDARG__) { + if(argv[i][2] != '\0') + ret = callback(opt->id, argv[i]+2); + else if(i+1 < argc) + ret = callback(opt->id, argv[++i]); + else + ret = callback(TEST_CMDLINE_OPTID_MISSINGARG__, argv[i]); + break; + } else { + ret = callback(opt->id, NULL); + + /* There might be more (argument-less) short options + * grouped together. */ + if(ret == 0 && argv[i][2] != '\0') + ret = test_cmdline_handle_short_opt_group__(options, argv[i]+2, callback); + break; + } + } + } + } + + if(opt->id == 0) { /* still not handled? */ + if(argv[i][0] != '-') { + /* Non-option argument. */ + ret = callback(TEST_CMDLINE_OPTID_NONE__, argv[i]); + } else { + /* Unknown option. */ + char* badoptname = argv[i]; + + if(strncmp(badoptname, "--", 2) == 0) { + /* Strip any argument from the long option. */ + char* assignement = strchr(badoptname, '='); + if(assignement != NULL) { + size_t len = assignement - badoptname; + if(len > TEST_CMDLINE_AUXBUF_SIZE__) + len = TEST_CMDLINE_AUXBUF_SIZE__; + strncpy(auxbuf, badoptname, len); + auxbuf[len] = '\0'; + badoptname = auxbuf; + } + } + + ret = callback(TEST_CMDLINE_OPTID_UNKNOWN__, badoptname); + } + } + } + + if(ret != 0) + return ret; + i++; + } + + return ret; +} + static void test_help__(void) { printf("Usage: %s [options] [test...]\n", test_argv0__); + printf("\n"); printf("Run the specified unit tests; or if the option '--skip' is used, run all\n"); printf("tests in the suite but those listed. By default, if no tests are specified\n"); printf("on the command line, all unit tests in the suite are run.\n"); printf("\n"); printf("Options:\n"); printf(" -s, --skip Execute all unit tests but the listed ones\n"); - printf(" --exec=WHEN If supported, execute unit tests as child processes\n"); + printf(" --exec[=WHEN] If supported, execute unit tests as child processes\n"); printf(" (WHEN is one of 'auto', 'always', 'never')\n"); +#if defined ACUTEST_WIN__ + printf(" -t, --timer Measure test duration\n"); +#elif defined ACUTEST_HAS_POSIX_TIMER__ + printf(" -t, --timer Measure test duration (real time)\n"); + printf(" --timer=TIMER Measure test duration, using given timer\n"); + printf(" (TIMER is one of 'real', 'cpu')\n"); +#endif printf(" -E, --no-exec Same as --exec=never\n"); printf(" --no-summary Suppress printing of test results summary\n"); + printf(" --tap Produce TAP-compliant output\n"); + printf(" (See https://testanything.org/)\n"); + printf(" -x, --xml-output=FILE Enable XUnit output to the given file\n"); printf(" -l, --list List unit tests in the suite and exit\n"); - printf(" -v, --verbose Enable more verbose output\n"); + printf(" -v, --verbose Make output more verbose\n"); printf(" --verbose=LEVEL Set verbose level to LEVEL:\n"); printf(" 0 ... Be silent\n"); printf(" 1 ... Output one line per test (and summary)\n"); printf(" 2 ... As 1 and failed conditions (this is default)\n"); printf(" 3 ... As 1 and all conditions (and extended summary)\n"); - printf(" --color=WHEN Enable colorized output\n"); + printf(" --color[=WHEN] Enable colorized output\n"); printf(" (WHEN is one of 'auto', 'always', 'never')\n"); + printf(" --no-color Same as --color=never\n"); printf(" -h, --help Display this help and exit\n"); if(test_list_size__ < 16) { @@ -665,6 +1257,147 @@ test_help__(void) } } +static const TEST_CMDLINE_OPTION__ test_cmdline_options__[] = { + { 's', "skip", 's', 0 }, + { 0, "exec", 'e', TEST_CMDLINE_OPTFLAG_OPTIONALARG__ }, + { 'E', "no-exec", 'E', 0 }, +#if defined ACUTEST_WIN__ + { 't', "timer", 't', 0 }, +#elif defined ACUTEST_HAS_POSIX_TIMER__ + { 't', "timer", 't', TEST_CMDLINE_OPTFLAG_OPTIONALARG__ }, +#endif + { 0, "no-summary", 'S', 0 }, + { 0, "tap", 'T', 0 }, + { 'l', "list", 'l', 0 }, + { 'v', "verbose", 'v', TEST_CMDLINE_OPTFLAG_OPTIONALARG__ }, + { 0, "color", 'c', TEST_CMDLINE_OPTFLAG_OPTIONALARG__ }, + { 0, "no-color", 'C', 0 }, + { 'h', "help", 'h', 0 }, + { 0, "worker", 'w', TEST_CMDLINE_OPTFLAG_REQUIREDARG__ }, /* internal */ + { 'x', "xml-output", 'x', TEST_CMDLINE_OPTFLAG_REQUIREDARG__ }, + { 0, NULL, 0, 0 } +}; + +static int +test_cmdline_callback__(int id, const char* arg) +{ + switch(id) { + case 's': + test_skip_mode__ = 1; + break; + + case 'e': + if(arg == NULL || strcmp(arg, "always") == 0) { + test_no_exec__ = 0; + } else if(strcmp(arg, "never") == 0) { + test_no_exec__ = 1; + } else if(strcmp(arg, "auto") == 0) { + /*noop*/ + } else { + fprintf(stderr, "%s: Unrecognized argument '%s' for option --exec.\n", test_argv0__, arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__); + exit(2); + } + break; + + case 'E': + test_no_exec__ = 1; + break; + + case 't': +#if defined ACUTEST_WIN__ || defined ACUTEST_HAS_POSIX_TIMER__ + if(arg == NULL || strcmp(arg, "real") == 0) { + test_timer__ = 1; + #ifndef ACUTEST_WIN__ + } else if(strcmp(arg, "cpu") == 0) { + test_timer__ = 2; + #endif + } else { + fprintf(stderr, "%s: Unrecognized argument '%s' for option --timer.\n", test_argv0__, arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__); + exit(2); + } +#endif + break; + + case 'S': + test_no_summary__ = 1; + break; + + case 'T': + test_tap__ = 1; + break; + + case 'l': + test_list_names__(); + exit(0); + + case 'v': + test_verbose_level__ = (arg != NULL ? atoi(arg) : test_verbose_level__+1); + break; + + case 'c': + if(arg == NULL || strcmp(arg, "always") == 0) { + test_colorize__ = 1; + } else if(strcmp(arg, "never") == 0) { + test_colorize__ = 0; + } else if(strcmp(arg, "auto") == 0) { + /*noop*/ + } else { + fprintf(stderr, "%s: Unrecognized argument '%s' for option --color.\n", test_argv0__, arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__); + exit(2); + } + break; + + case 'C': + test_colorize__ = 0; + break; + + case 'h': + test_help__(); + exit(0); + + case 'w': + test_worker__ = 1; + test_worker_index__ = atoi(arg); + break; + case 'x': + test_xml_output__ = fopen(arg, "w"); + if (!test_xml_output__) { + fprintf(stderr, "Unable to open '%s': %s\n", arg, strerror(errno)); + exit(2); + } + break; + + case 0: + if(test_lookup__(arg) == 0) { + fprintf(stderr, "%s: Unrecognized unit test '%s'\n", test_argv0__, arg); + fprintf(stderr, "Try '%s --list' for list of unit tests.\n", test_argv0__); + exit(2); + } + break; + + case TEST_CMDLINE_OPTID_UNKNOWN__: + fprintf(stderr, "Unrecognized command line option '%s'.\n", arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__); + exit(2); + + case TEST_CMDLINE_OPTID_MISSINGARG__: + fprintf(stderr, "The command line option '%s' requires an argument.\n", arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__); + exit(2); + + case TEST_CMDLINE_OPTID_BOGUSARG__: + fprintf(stderr, "The command line option '%s' does not expect an argument.\n", arg); + fprintf(stderr, "Try '%s --help' for more information.\n", test_argv0__); + exit(2); + } + + return 0; +} + + #ifdef ACUTEST_LINUX__ static int test_is_tracer_present__(void) @@ -708,14 +1441,12 @@ int main(int argc, char** argv) { int i; - int seen_double_dash = 0; - test_argv0__ = argv[0]; #if defined ACUTEST_UNIX__ test_colorize__ = isatty(STDOUT_FILENO); #elif defined ACUTEST_WIN__ - #if defined __BORLANDC__ + #if defined __BORLANDC__ test_colorize__ = isatty(_fileno(stdout)); #else test_colorize__ = _isatty(_fileno(stdout)); @@ -724,61 +1455,21 @@ main(int argc, char** argv) test_colorize__ = 0; #endif + test_timer_init__(); + /* Count all test units */ test_list_size__ = 0; for(i = 0; test_list__[i].func != NULL; i++) test_list_size__++; - tests__ = (const struct test__**) malloc(sizeof(const struct test__*) * test_list_size__); - test_flags__ = (char*) malloc(sizeof(char) * test_list_size__); - if(tests__ == NULL || test_flags__ == NULL) { + test_details__ = (struct test_detail__*)calloc(test_list_size__, sizeof(struct test_detail__)); + if(test_details__ == NULL) { fprintf(stderr, "Out of memory.\n"); exit(2); } - memset((void*) test_flags__, 0, sizeof(char) * test_list_size__); /* Parse options */ - for(i = 1; i < argc; i++) { - if(seen_double_dash || argv[i][0] != '-') { - if(test_lookup__(argv[i]) == 0) { - fprintf(stderr, "%s: Unrecognized unit test '%s'\n", argv[0], argv[i]); - fprintf(stderr, "Try '%s --list' for list of unit tests.\n", argv[0]); - exit(2); - } - } else if(strcmp(argv[i], "--") == 0) { - seen_double_dash = 1; - } else if(strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { - test_help__(); - exit(0); - } else if(strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) { - test_verbose_level__++; - } else if(strncmp(argv[i], "--verbose=", 10) == 0) { - test_verbose_level__ = atoi(argv[i] + 10); - } else if(strcmp(argv[i], "--color=auto") == 0) { - /* noop (set from above) */ - } else if(strcmp(argv[i], "--color=always") == 0 || strcmp(argv[i], "--color") == 0) { - test_colorize__ = 1; - } else if(strcmp(argv[i], "--color=never") == 0 || strcmp(argv[i], "--no-color") == 0) { - test_colorize__ = 0; - } else if(strcmp(argv[i], "--skip") == 0 || strcmp(argv[i], "-s") == 0) { - test_skip_mode__ = 1; - } else if(strcmp(argv[i], "--exec=auto") == 0) { - /* noop (set from above) */ - } else if(strcmp(argv[i], "--exec=always") == 0 || strcmp(argv[i], "--exec") == 0) { - test_no_exec__ = 0; - } else if(strcmp(argv[i], "--exec=never") == 0 || strcmp(argv[i], "--no-exec") == 0 || strcmp(argv[i], "-E") == 0) { - test_no_exec__ = 1; - } else if(strcmp(argv[i], "--no-summary") == 0) { - test_no_summary__ = 1; - } else if(strcmp(argv[i], "--list") == 0 || strcmp(argv[i], "-l") == 0) { - test_list_names__(); - exit(0); - } else { - fprintf(stderr, "%s: Unrecognized option '%s'\n", argv[0], argv[i]); - fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); - exit(2); - } - } + test_cmdline_read__(test_cmdline_options__, argc, argv, test_cmdline_callback__); #if defined(ACUTEST_WIN__) SetUnhandledExceptionFilter(test_exception_filter__); @@ -787,8 +1478,7 @@ main(int argc, char** argv) /* By default, we want to run all tests. */ if(test_count__ == 0) { for(i = 0; test_list__[i].func != NULL; i++) - tests__[i] = &test_list__[i]; - test_count__ = test_list_size__; + test_remember__(i); } /* Guess whether we want to run unit tests as child processes. */ @@ -809,17 +1499,27 @@ main(int argc, char** argv) } } - /* Run the tests */ - if(!test_skip_mode__) { - /* Run the listed tests. */ - for(i = 0; i < (int) test_count__; i++) - test_run__(tests__[i]); - } else { - /* Run all tests except those listed. */ - for(i = 0; test_list__[i].func != NULL; i++) { - if(!test_flags__[i]) - test_run__(&test_list__[i]); - } + if(test_tap__) { + /* TAP requires we know test result ("ok", "not ok") before we output + * anything about the test, and this gets problematic for larger verbose + * levels. */ + if(test_verbose_level__ > 2) + test_verbose_level__ = 2; + + /* TAP harness should provide some summary. */ + test_no_summary__ = 1; + + if(!test_worker__) + printf("1..%d\n", (int) test_count__); + } + + int index = test_worker_index__; + for(i = 0; test_list__[i].func != NULL; i++) { + int run = (test_details__[i].flags & TEST_FLAG_RUN__); + if (test_skip_mode__) /* Run all tests except those listed. */ + run = !run; + if(run) + test_run__(&test_list__[i], index++, i); } /* Write a summary */ @@ -831,7 +1531,6 @@ main(int argc, char** argv) printf(" Count of run unit tests: %4d\n", test_stat_run_units__); printf(" Count of failed unit tests: %4d\n", test_stat_failed_units__); printf(" Count of skipped unit tests: %4d\n", (int) test_list_size__ - test_stat_run_units__); - printf(" "); } if(test_stat_failed_units__ == 0) { @@ -839,16 +1538,42 @@ main(int argc, char** argv) printf(" All unit tests have passed.\n"); } else { test_print_in_color__(TEST_COLOR_RED_INTENSIVE__, "FAILED:"); - printf(" %d of %d unit tests have failed.\n", - test_stat_failed_units__, test_stat_run_units__); + printf(" %d of %d unit tests %s failed.\n", + test_stat_failed_units__, test_stat_run_units__, + (test_stat_failed_units__ == 1) ? "has" : "have"); } if(test_verbose_level__ >= 3) printf("\n"); } - free((void*) tests__); - free((void*) test_flags__); + if (test_xml_output__) { +#if defined ACUTEST_UNIX__ + char *suite_name = basename(argv[0]); +#elif defined ACUTEST_WIN__ + char suite_name[_MAX_FNAME]; + _splitpath(argv[0], NULL, NULL, suite_name, NULL); +#else + const char *suite_name = argv[0]; +#endif + fprintf(test_xml_output__, "\n"); + fprintf(test_xml_output__, "\n", + suite_name, (int)test_list_size__, test_stat_failed_units__, test_stat_failed_units__, + (int)test_list_size__ - test_stat_run_units__); + for(i = 0; test_list__[i].func != NULL; i++) { + struct test_detail__ *details = &test_details__[i]; + fprintf(test_xml_output__, " \n", test_list__[i].name, details->duration); + if (details->flags & TEST_FLAG_FAILURE__) + fprintf(test_xml_output__, " \n"); + if (!(details->flags & TEST_FLAG_FAILURE__) && !(details->flags & TEST_FLAG_SUCCESS__)) + fprintf(test_xml_output__, " \n"); + fprintf(test_xml_output__, " \n"); + } + fprintf(test_xml_output__, "\n"); + fclose(test_xml_output__); + } + + free((void*) test_details__); return (test_stat_failed_units__ == 0) ? 0 : 1; } @@ -857,8 +1582,8 @@ main(int argc, char** argv) #endif /* #ifndef TEST_NO_MAIN */ #ifdef __cplusplus -} /* extern "C" */ + } /* extern "C" */ #endif -#endif /* #ifndef ACUTEST_H__ */ \ No newline at end of file +#endif /* #ifndef ACUTEST_H__ */ diff --git a/test/tinyobj_api_tests.c b/test/tinyobj_api_tests.c index 1fda159..c182ed2 100644 --- a/test/tinyobj_api_tests.c +++ b/test/tinyobj_api_tests.c @@ -4,45 +4,31 @@ #include "tinyobj_loader_c.h" #include "acutest.h" -void test_tinyobj_attrib_init(void) -{ - tinyobj_attrib_t attrib; - tinyobj_attrib_init(&attrib); - - TEST_CHECK(attrib.vertices == NULL); - TEST_CHECK(attrib.num_vertices == 0); - TEST_CHECK(attrib.normals == NULL); - TEST_CHECK(attrib.num_normals == 0); - TEST_CHECK(attrib.texcoords == NULL); - TEST_CHECK(attrib.num_texcoords == 0); - TEST_CHECK(attrib.faces == NULL); - TEST_CHECK(attrib.num_faces == 0); - TEST_CHECK(attrib.face_num_verts == NULL); - TEST_CHECK(attrib.num_face_num_verts == 0); - TEST_CHECK(attrib.material_ids == NULL); -} - -size_t loadFile(const char * filename, char ** buffer) -{ - *buffer = NULL; - long string_size = 0, read_size = 0; - FILE * handler = fopen(filename, "r"); - - if (handler) { - fseek(handler, 0, SEEK_END); - string_size = ftell(handler); - rewind(handler); - *buffer = (char *) malloc(sizeof(char) * (string_size + 1)); - read_size = fread(*buffer, sizeof(char), (size_t) string_size, handler); - (*buffer)[string_size] = '\0'; - if (string_size != read_size) { - free(buffer); - *buffer = NULL; - } - fclose(handler); +size_t loadFile(const char *filename, char **buffer) { + long string_size = 0, read_size = 0; + FILE *handler = fopen(filename, "r"); + *buffer = NULL; + + if (handler) { + if (fseek(handler, 0, SEEK_END) != 0) { + fprintf(stderr, "loadFile: fseek %s failure (errno %d)\n", filename, + errno); + return 0; } - - return (size_t) read_size; + string_size = ftell(handler); + rewind(handler); + *buffer = (char *)malloc(sizeof(char) * (string_size + 1)); + read_size = (long)fread(*buffer, sizeof(char), string_size, handler); + (*buffer)[string_size] = '\0'; + if (string_size != read_size && errno) { + fprintf(stderr, "loadFile: fread %s failure (errno %d)\n", filename, + errno); + free(*buffer); + *buffer = NULL; + } + fclose(handler); + } + return (size_t)read_size; } void test_tinyobj_parse_mtl_file(void) @@ -51,67 +37,175 @@ void test_tinyobj_parse_mtl_file(void) const char * filename = "fixtures/cube.mtl"; tinyobj_material_t * material; - size_t num_materials; + unsigned int num_materials; + int ret; - TEST_CHECK(tinyobj_parse_mtl_file(&material, &num_materials, filename) == TINYOBJ_SUCCESS); + ret = tinyobj_parse_mtl_file(&material, &num_materials, filename); + TEST_CHECK(ret == TINYOBJ_SUCCESS); + if(ret != TINYOBJ_SUCCESS) + return; TEST_CHECK(num_materials == 1); - TEST_CHECK(strcmp(material->name, "CubeMaterial") == 0); + TEST_MSG("num_materials %ld\n", num_materials); + TEST_CHECK(strcmp(material[0].name, "CubeMaterial") == 0); + TEST_MSG("material name: %s\n", material[0].name); - TEST_CHECK(material->diffuse[0] == 1.0); - TEST_CHECK(material->diffuse[1] == 0.0); - TEST_CHECK(material->diffuse[2] == 0.0); + TEST_CHECK(material[0].diffuse.r == 1.0); + TEST_CHECK(material[0].diffuse.g == 0.0); + TEST_CHECK(material[0].diffuse.b == 0.0); - TEST_CHECK(material->specular[0] == 0.5); - TEST_CHECK(material->specular[1] == 0.25); - TEST_CHECK(material->specular[2] == 0.125); + TEST_CHECK(material[0].specular.r == 0.5); + TEST_CHECK(material[0].specular.g == 0.25); + TEST_CHECK(material[0].specular.b == 0.125); - TEST_CHECK(material->ambient[0] == 1.0); - TEST_CHECK(material->ambient[1] == 1.0); - TEST_CHECK(material->ambient[2] == 1.0); + TEST_CHECK(material[0].ambient.r == 1.0); + TEST_CHECK(material[0].ambient.g == 1.0); + TEST_CHECK(material[0].ambient.b == 1.0); - TEST_CHECK(material->emission[0] == 0.0); - TEST_CHECK(material->emission[1] == 1.0); - TEST_CHECK(material->emission[2] == 0.0); + TEST_CHECK(material[0].emission.r == 0.0); + TEST_CHECK(material[0].emission.g == 1.0); + TEST_CHECK(material[0].emission.b == 0.0); - TEST_CHECK(material->illum == 2); - TEST_CHECK(material->dissolve == 1.0); + TEST_CHECK(material[0].illum == 2); + TEST_CHECK(material[0].dissolve == 1.0); } } -void test_tinyobj_parse_obj(void) -{ - const char * filename = "fixtures/cube.obj"; - - tinyobj_shape_t * shape = NULL; - tinyobj_material_t * material = NULL; - tinyobj_attrib_t attrib; - - unsigned long num_shapes; - unsigned long num_materials; - - tinyobj_attrib_init(&attrib); - - char * obj_contents; - size_t file_size = loadFile(filename, &obj_contents); - - int result = tinyobj_parse_obj(&attrib, &shape, &num_shapes, &material, &num_materials, obj_contents, file_size, TINYOBJ_FLAG_TRIANGULATE); - - TEST_CHECK(result == TINYOBJ_SUCCESS); +tinyobj_vertex_normal_t vertex_normal_test_vector[] = { + { 0.0f, -1.0f, 0.0f}, // vn1 + { 0.0f, 1.0f, 0.0f}, // vn2 + { 1.0f, 0.0f, 0.0f}, // vn3 + {-0.0f, -0.0f, 1.0f}, // vn4 + {-1.0f, -0.0f, -0.0f}, // vn5 + { 0.0f, 0.0f, -1.0f}, // vn6 +}; + +tinyobj_vertex_t vertex_test_vector[] = { + { 1.0f, -1.0f, -1.0f, 1.0f}, // v1 + { 1.0f, -1.0f, 1.0f, 1.0f}, // v2 + {-1.0f, -1.0f, 1.0f, 1.0f}, // v3 + {-1.0f, -1.0f, -1.0f, 1.0f}, // v4 + { 1.0f, 1.0f, -0.999999f, 1.0f}, // v5 + { 0.999999f, 1.0f, 1.000001f, 1.0f}, // v6 + {-1.0f, 1.0f, 1.0f, 1.0f}, // v7 + {-1.0f, 1.0f, -1.0f, 1.0f}, // v8 +}; + +/** + * Test vector containing the triplets of all faces (without triangulation) + **/ +tinyobj_vertex_index_t vi_test_vector[] = { + // Face 1 + {1, TINYOBJ_INVALID_INDEX, 1}, {2, TINYOBJ_INVALID_INDEX, 1}, + {3, TINYOBJ_INVALID_INDEX, 1}, {4, TINYOBJ_INVALID_INDEX, 1}, + // Face 2 + {5, TINYOBJ_INVALID_INDEX, 2}, {8, TINYOBJ_INVALID_INDEX, 2}, + {7, TINYOBJ_INVALID_INDEX, 2}, {6, TINYOBJ_INVALID_INDEX, 2}, + // Face 3 + {1, TINYOBJ_INVALID_INDEX, 3}, {5, TINYOBJ_INVALID_INDEX, 3}, + {6, TINYOBJ_INVALID_INDEX, 3}, {2, TINYOBJ_INVALID_INDEX, 3}, + // Face 4 + {2, TINYOBJ_INVALID_INDEX, 4}, {6, TINYOBJ_INVALID_INDEX, 4}, + {7, TINYOBJ_INVALID_INDEX, 4}, {3, TINYOBJ_INVALID_INDEX, 4}, + // Face 5 + {3, TINYOBJ_INVALID_INDEX, 5}, {7, TINYOBJ_INVALID_INDEX, 5}, + {8, TINYOBJ_INVALID_INDEX, 5}, {4, TINYOBJ_INVALID_INDEX, 5}, + // Face 6 + {5, TINYOBJ_INVALID_INDEX, 6}, {1, TINYOBJ_INVALID_INDEX, 6}, + {4, TINYOBJ_INVALID_INDEX, 6}, {8, TINYOBJ_INVALID_INDEX, 6}, +}; + +/** + * Test vector containing the triplets of all faces (triangulated) + * (already fixed) + **/ +tinyobj_vertex_index_t vi_test_vector_trig[] = { + // Face 1 + {0, TINYOBJ_INVALID_INDEX, 0}, {1, TINYOBJ_INVALID_INDEX, 0}, {2, TINYOBJ_INVALID_INDEX, 0}, + {0, TINYOBJ_INVALID_INDEX, 0}, {2, TINYOBJ_INVALID_INDEX, 0}, {3, TINYOBJ_INVALID_INDEX, 0}, + // Face 2 + {4, TINYOBJ_INVALID_INDEX, 1}, {7, TINYOBJ_INVALID_INDEX, 1}, {6, TINYOBJ_INVALID_INDEX, 1}, + {4, TINYOBJ_INVALID_INDEX, 1}, {6, TINYOBJ_INVALID_INDEX, 1}, {5, TINYOBJ_INVALID_INDEX, 1}, + // Face 3 + {0, TINYOBJ_INVALID_INDEX, 2}, {4, TINYOBJ_INVALID_INDEX, 2}, {5, TINYOBJ_INVALID_INDEX, 2}, + {0, TINYOBJ_INVALID_INDEX, 2}, {5, TINYOBJ_INVALID_INDEX, 2}, {1, TINYOBJ_INVALID_INDEX, 2}, + // Face 4 + {1, TINYOBJ_INVALID_INDEX, 3}, {5, TINYOBJ_INVALID_INDEX, 3}, {6, TINYOBJ_INVALID_INDEX, 3}, + {1, TINYOBJ_INVALID_INDEX, 3}, {6, TINYOBJ_INVALID_INDEX, 3}, {2, TINYOBJ_INVALID_INDEX, 3}, + // Face 5 + {2, TINYOBJ_INVALID_INDEX, 4}, {6, TINYOBJ_INVALID_INDEX, 4}, {7, TINYOBJ_INVALID_INDEX, 4}, + {2, TINYOBJ_INVALID_INDEX, 4}, {7, TINYOBJ_INVALID_INDEX, 4}, {3, TINYOBJ_INVALID_INDEX, 4}, + // Face 6 + {4, TINYOBJ_INVALID_INDEX, 5}, {0, TINYOBJ_INVALID_INDEX, 5}, {3, TINYOBJ_INVALID_INDEX, 5}, + {4, TINYOBJ_INVALID_INDEX, 5}, {3, TINYOBJ_INVALID_INDEX, 5}, {7, TINYOBJ_INVALID_INDEX, 5}, +}; + +unsigned char test_compare_vertex_texture(tinyobj_vertex_texture_t *vt, tinyobj_vertex_texture_t *vt1) { + return (vt->u == vt1->u && vt->v == vt1->v && vt->w == vt1->w); +} - // TODO: should these two values be swapped? - TEST_CHECK(attrib.num_faces == 36); - TEST_CHECK(attrib.num_face_num_verts == 12); +unsigned char test_compare_vertex_normal(tinyobj_vertex_normal_t *vn, tinyobj_vertex_normal_t *vn1) { + return (vn->i == vn1->i && vn->j == vn1->j && vn->k == vn1->k); +} - TEST_CHECK(attrib.num_normals == 6); - TEST_CHECK(attrib.num_vertices == 8); - TEST_CHECK(attrib.num_texcoords == 0); +unsigned char test_compare_vertex(tinyobj_vertex_t *v, tinyobj_vertex_t *v1) { + return (v->x == v1->x && v->y == v1->y && v->z == v1->z && v->weight == v1->weight); +} - tinyobj_attrib_free(&attrib); - if (shape) { - tinyobj_shapes_free(shape, num_shapes); - } - if (material) { - tinyobj_materials_free(material, num_materials); - } +/** + * Tests .obj parsing function + **/ +void test_tinyobj_parse_obj(void) { + const char * filename = "fixtures/cube.obj"; + tinyobj_shape_t * shape = NULL; + tinyobj_material_t * material = NULL; + tinyobj_attrib_t attrib; + + unsigned int num_shapes; + unsigned int num_materials; + + char * obj_contents; + size_t file_size = loadFile(filename, &obj_contents); + + int result = tinyobj_parse_obj(&attrib, &shape, &num_shapes, &material, &num_materials, obj_contents, file_size, TINYOBJ_FLAG_TRIANGULATE); + TEST_CHECK(result == TINYOBJ_SUCCESS); + if(result != TINYOBJ_SUCCESS) + return; + + // Face tests + TEST_CHECK(attrib.f_count == (sizeof(vi_test_vector)/sizeof(vi_test_vector[0]))/4); + { // Test if vertex indices match + size_t i = 0; + for(i = 0; i < attrib.f_count; i++) { + size_t j = 0; + TEST_CHECK(attrib.f[i].count == 6); + TEST_CHECK(attrib.f[i].smoothing_id == 0); + + for(j = 0; j < attrib.f[i].count; j++) { + size_t tpos = attrib.f[i].count*i+j; + tinyobj_vertex_index_t vi; + memcpy(&vi, &attrib.f[i].triplet_list[j], sizeof(vi)); + TEST_CASE("Triplet indices match test"); + TEST_CHECK(vi.v_idx == vi_test_vector_trig[tpos].v_idx); + TEST_CHECK(vi.vt_idx == vi_test_vector_trig[tpos].vt_idx + || vi.vt_idx == TINYOBJ_INVALID_INDEX && vi_test_vector_trig[tpos].vt_idx == TINYOBJ_INVALID_INDEX); + TEST_CHECK(vi.vn_idx == vi_test_vector_trig[tpos].vn_idx + || vi.vn_idx == TINYOBJ_INVALID_INDEX && vi_test_vector_trig[tpos].vn_idx == TINYOBJ_INVALID_INDEX); + TEST_CASE("Triplet values match test"); + TEST_CHECK(vi.v_idx < attrib.v_count); + TEST_CHECK(test_compare_vertex(&attrib.v[vi.v_idx], &vertex_test_vector[vi.v_idx])); + TEST_CHECK(vi.vn_idx < attrib.vn_count); + TEST_CHECK(test_compare_vertex_normal(&attrib.vn[vi.vn_idx], &vertex_normal_test_vector[vi.vn_idx])); + } + } + } + TEST_CASE(NULL); + + TEST_CHECK(attrib.v_count == 8); + TEST_CHECK(attrib.vn_count == 6); + TEST_CHECK(attrib.vt_count == 0); + + tinyobj_attrib_free(&attrib); + tinyobj_shape_free(shape, num_shapes); + tinyobj_material_free(material, num_materials); } diff --git a/test/tinyobj_api_tests.h b/test/tinyobj_api_tests.h index 96726b7..e96e363 100644 --- a/test/tinyobj_api_tests.h +++ b/test/tinyobj_api_tests.h @@ -1,7 +1,6 @@ #ifndef TINYOBJ_API_TESTS #define TINYOBJ_API_TESTS -void test_tinyobj_attrib_init(void); void test_tinyobj_parse_mtl_file(void); void test_tinyobj_parse_obj(void); diff --git a/test/tinyobj_internal_tests.c b/test/tinyobj_internal_tests.c index a007fa9..31e8f9c 100644 --- a/test/tinyobj_internal_tests.c +++ b/test/tinyobj_internal_tests.c @@ -101,54 +101,48 @@ void test_length_until_newline(void) // Return value for null-terminated string without line breaks should be // number of non-null chars. char test_string[] = "potato"; - TEST_CHECK(length_until_newline(test_string, sizeof(test_string)) == 6); + TEST_CHECK(length_until_newline_comment_space( + test_string, sizeof(test_string)) == 6); } { // Return value for null terminated string with a linebreak at the end should // be number of chars to newline. char test_string[] = "potato\n"; - TEST_CHECK(length_until_newline(test_string, sizeof(test_string)) == 6); + TEST_CHECK(length_until_newline_comment_space( + test_string, sizeof(test_string)) == 6); } { // Return value for null-terminated string with a linebreak in the middle // should be number of chars to newline. char test_string[] = "potato\nmonkey"; - TEST_CHECK(length_until_newline(test_string, sizeof(test_string)) == 6); + TEST_CHECK(length_until_newline_comment_space( + test_string, sizeof(test_string)) == 6); } { // Return value for null-terminated string with a linebreak in the middle and // at the end should be number of chars to first newline. char test_string[] = "potato\nmonkey\n"; - TEST_CHECK(length_until_newline(test_string, sizeof(test_string)) == 6); + TEST_CHECK(length_until_newline_comment_space( + test_string, sizeof(test_string)) == 6); } { // Return value for empty null-terminated string should be 0. char test_string[] = ""; - TEST_CHECK(length_until_newline(test_string, sizeof(test_string)) == 0); + TEST_CHECK(length_until_newline_comment_space( + test_string, sizeof(test_string)) == 0); } - { - // Return value for null-terminated string with a null character in the middle - // should be the number of non-null chars plus the number of null characters - // before the end of the string. - char test_string[] = "pot\0ato"; - TEST_CHECK(length_until_newline(test_string, sizeof(test_string)) == 7); - } -} - -void test_my_atoi(void) -{ - // Results for input strings should become corresponding ints. - TEST_CHECK(my_atoi("1") == 1); - TEST_CHECK(my_atoi("-1") == -1); - TEST_CHECK(my_atoi("+1") == 1); - TEST_CHECK(my_atoi("0") == 0); - TEST_CHECK(my_atoi("-0") == 0); - TEST_CHECK(my_atoi("+0") == 0); +// { +// // Return value for null-terminated string with a null character in the middle +// // should be the number of non-null chars plus the number of null characters +// // before the end of the string. +// char test_string[] = "pot\0ato"; +// TEST_CHECK(length_until_newline(test_string, sizeof(test_string)) == 7); +// } } void test_fix_index(void) @@ -637,7 +631,7 @@ void test_my_strdup(void) // Return value for a regular string should be a new string whose // contents are equal to the original. char * test_string = "potato"; - char * result = my_strdup(test_string, strlen(test_string)); + char * result = strdup_ml(test_string, strlen(test_string)); TEST_CHECK(test_string != result); TEST_CHECK(strcmp(test_string, result) == 0); free(result); @@ -646,7 +640,7 @@ void test_my_strdup(void) { // Return value for empty string should be a new empty string. char * test_string = ""; - char * result = my_strdup(test_string, strlen(test_string)); + char* result = strdup_ml(test_string, strlen(test_string)); TEST_CHECK(test_string != result); TEST_CHECK(strcmp(test_string, result) == 0); free(result); @@ -659,7 +653,7 @@ void test_my_strndup(void) // Return value for a regular string and the length of that string should be a new // string whose contents are equal to the original. char * test_string = "potato"; - char * result = my_strndup(test_string, 6); + char * result = strndup(test_string, 6); TEST_CHECK(test_string != result); TEST_CHECK(strcmp(test_string, result) == 0); free(result); @@ -668,54 +662,28 @@ void test_my_strndup(void) { // Return value for a regular string and zero should be a new empty string. char * test_string = "potato"; - char * result = my_strndup(test_string, 0); + char * result = strndup(test_string, 0); TEST_CHECK(result == 0); } } -void test_initMaterial(void) -{ - // Initialised material should have expected defaults. - int i; - tinyobj_material_t material; - initMaterial(&material); - TEST_CHECK(material.name == NULL); - TEST_CHECK(material.ambient_texname == NULL); - TEST_CHECK(material.diffuse_texname == NULL); - TEST_CHECK(material.specular_texname == NULL); - TEST_CHECK(material.specular_highlight_texname == NULL); - TEST_CHECK(material.bump_texname == NULL); - TEST_CHECK(material.displacement_texname == NULL); - TEST_CHECK(material.alpha_texname == NULL); - for (i = 0; i < 3; i++) { - TEST_CHECK(material.ambient[i] == 0.f); - TEST_CHECK(material.diffuse[i] == 0.f); - TEST_CHECK(material.specular[i] == 0.f); - TEST_CHECK(material.transmittance[i] == 0.f); - TEST_CHECK(material.emission[i] == 0.f); - } - TEST_CHECK(material.illum == 0); - TEST_CHECK(material.dissolve == 1.f); - TEST_CHECK(material.shininess == 1.f); - TEST_CHECK(material.ior == 1.f); -} - +#ifndef TINYOBJ_USE_UTHASH void test_create_hash_table(void) { { // Initialised hash table should be initialised with a default capacity. - hash_table_t table; + tinyobj_material_table_t table; create_hash_table(0, &table); TEST_CHECK(table.hashes != NULL); TEST_CHECK(table.entries != NULL); - TEST_CHECK(table.capacity == HASH_TABLE_DEFAULT_SIZE); + TEST_CHECK(table.capacity == TINYOBJ_HASH_TABLE_DEFAULT_SIZE); TEST_CHECK(table.n == 0); destroy_hash_table(&table); } { // Initialised hash table should be initialised with supplied capacity. - hash_table_t table; + tinyobj_material_table_t table; create_hash_table(20, &table); TEST_CHECK(table.hashes != NULL); TEST_CHECK(table.entries != NULL); @@ -729,7 +697,7 @@ void test_hash_table_set(void) { { // Values should be stored in the hash table. - hash_table_t table; + tinyobj_material_table_t table; int foundFirst = 0; int foundSecond = 0; int foundOther = 0; @@ -768,7 +736,7 @@ void test_hash_table_set(void) { // Values with different hashes but same % capacity value should exist in the // the same hash table. - hash_table_t table; + tinyobj_material_table_t table; int foundFirst = 0; int foundSecond = 0; int foundOther = 0; @@ -812,7 +780,7 @@ void test_hash_table_set(void) // TODO: This fails. Should the key also be stored in the entry so it can be compared // with the key being inserted? // Values with identical hashes but different keys should exist in the same hash table. - hash_table_t table; + tinyobj_material_table_t table; int foundFirst = 0; int foundSecond = 0; int foundOther = 0; @@ -855,7 +823,7 @@ void test_hash_table_set(void) void test_hash_table_exists(void) { // It should be possible to test for the presence of items in the hash table. - hash_table_t table; + tinyobj_material_table_t table; create_hash_table(20, &table); hash_table_set("potato", 3, &table); @@ -871,7 +839,7 @@ void test_hash_table_exists(void) void test_hash_table_get(void) { // It should be possible to retrieve item values from the hash table. - hash_table_t table; + tinyobj_material_table_t table; create_hash_table(20, &table); hash_table_set("potato", 3, &table); @@ -890,7 +858,7 @@ void test_hash_table_get(void) void test_hash_table_maybe_grow(void) { // It should be possible for the table to grow, preserving all previous values - hash_table_t table; + tinyobj_material_table_t table; create_hash_table(10, &table); hash_table_set("Pottery_clay0", 0, &table); @@ -922,3 +890,5 @@ void test_hash_table_maybe_grow(void) destroy_hash_table(&table); } + +#endif // TINYOBJ_USE_UTHASH diff --git a/test/tinyobj_internal_tests.h b/test/tinyobj_internal_tests.h index 01f7098..f2d5d3d 100644 --- a/test/tinyobj_internal_tests.h +++ b/test/tinyobj_internal_tests.h @@ -5,7 +5,6 @@ void test_skip_space(void); void test_skip_space_and_cr(void); void test_until_space(void); void test_length_until_newline(void); -void test_my_atoi(void); void test_fix_index(void); void test_parseRawTriple(void); void test_parseInt(void); @@ -15,7 +14,6 @@ void test_parseFloat2(void); void test_parseFloat3(void); void test_my_strdup(void); void test_my_strndup(void); -void test_initMaterial(void); void test_create_hash_table(void); void test_hash_table_set(void); void test_hash_table_exists(void); diff --git a/test/tinyobj_regression_tests.c b/test/tinyobj_regression_tests.c index 5a9d50c..1a6bcf8 100644 --- a/test/tinyobj_regression_tests.c +++ b/test/tinyobj_regression_tests.c @@ -16,27 +16,31 @@ static int float_equals(float x, float y) return 0; } -static size_t loadFile(const char * filename, char ** buffer) -{ - *buffer = NULL; - long string_size = 0, read_size = 0; - FILE * handler = fopen(filename, "r"); - - if (handler) { - fseek(handler, 0, SEEK_END); - string_size = ftell(handler); - rewind(handler); - *buffer = (char *) malloc(sizeof(char) * (string_size + 1)); - read_size = fread(*buffer, sizeof(char), (size_t) string_size, handler); - (*buffer)[string_size] = '\0'; - if (string_size != read_size) { - free(buffer); - *buffer = NULL; - } - fclose(handler); +size_t loadFile_d(const char *filename, char **buffer) { + long string_size = 0, read_size = 0; + FILE *handler = fopen(filename, "r"); + *buffer = NULL; + + if (handler) { + if (fseek(handler, 0, SEEK_END) != 0) { + fprintf(stderr, "loadFile: fseek %s failure (errno %d)\n", filename, + errno); + return 0; } - - return (size_t) read_size; + string_size = ftell(handler); + rewind(handler); + *buffer = (char *)malloc(sizeof(char) * (string_size + 1)); + read_size = (long)fread(*buffer, sizeof(char), string_size, handler); + (*buffer)[string_size] = '\0'; + if (string_size != read_size && errno) { + fprintf(stderr, "loadFile: fread %s failure (errno %d)\n", filename, + errno); + free(*buffer); + *buffer = NULL; + } + fclose(handler); + } + return (size_t)read_size; } void test_tinyobj_crlf_string(void) @@ -45,9 +49,13 @@ void test_tinyobj_crlf_string(void) const char * filename = "fixtures/texname-crlf.mtl"; tinyobj_material_t * material; - size_t num_materials; + unsigned int num_materials; + int ret; - TEST_CHECK(tinyobj_parse_mtl_file(&material, &num_materials, filename) == TINYOBJ_SUCCESS); + ret = tinyobj_parse_mtl_file(&material, &num_materials, filename); + TEST_CHECK(ret == TINYOBJ_SUCCESS); + if(ret != TINYOBJ_SUCCESS) + return; TEST_CHECK(num_materials == 1); TEST_CHECK(strcmp(material->name, "CubeMaterial") == 0); @@ -68,21 +76,17 @@ void test_tinyobj_negative_exponent(void) unsigned long num_shapes; unsigned long num_materials; - tinyobj_attrib_init(&attrib); - char * obj_contents; - size_t file_size = loadFile(filename, &obj_contents); + size_t file_size = loadFile_d(filename, &obj_contents); int result = tinyobj_parse_obj(&attrib, &shape, &num_shapes, &material, &num_materials, obj_contents, file_size, TINYOBJ_FLAG_TRIANGULATE); TEST_CHECK(result == TINYOBJ_SUCCESS); + if(result != TINYOBJ_SUCCESS) + return; - // TODO: should these two values be swapped? - TEST_CHECK(attrib.num_faces == 36); - TEST_CHECK(attrib.num_face_num_verts == 12); - - TEST_CHECK(float_equals(attrib.vertices[0], 2.0e+5f)); - TEST_CHECK(float_equals(attrib.vertices[1], 2.0e-5f)); - TEST_CHECK(float_equals(attrib.vertices[2], 2.0e-0f)); + TEST_CHECK(float_equals(attrib.v[0].x, 2.0e+5f)); + TEST_CHECK(float_equals(attrib.v[0].y, 2.0e-5f)); + TEST_CHECK(float_equals(attrib.v[0].z, 2.0e-0f)); } } diff --git a/test/tinyobj_tests.c b/test/tinyobj_tests.c index 0137ed1..035b191 100644 --- a/test/tinyobj_tests.c +++ b/test/tinyobj_tests.c @@ -6,7 +6,6 @@ TEST_LIST = { // API Tests - { "tinyobj_attrib_init", test_tinyobj_attrib_init }, { "tinyobj_parse_mtl_file", test_tinyobj_parse_mtl_file }, { "tinyobj_parse_obj", test_tinyobj_parse_obj }, @@ -15,7 +14,6 @@ TEST_LIST = { { "skip_space_and_cr", test_skip_space_and_cr }, { "until_space", test_until_space }, { "length_until_newline", test_length_until_newline }, - { "my_atoi", test_my_atoi }, { "fix_index", test_fix_index }, { "parseRawTriple", test_parseRawTriple }, { "parseInt", test_parseInt }, @@ -25,12 +23,13 @@ TEST_LIST = { { "parseFloat3", test_parseFloat3 }, { "my_strdup", test_my_strdup }, { "my_strndup", test_my_strndup }, - { "initMaterial", test_initMaterial }, +#ifdef TINYOBJ_USE_UTHASH { "create_hash_table", test_create_hash_table }, { "hash_table_set", test_hash_table_set }, { "hash_table_exists", test_hash_table_exists }, { "hash_table_get", test_hash_table_get }, { "hash_table_maybe_grow", test_hash_table_maybe_grow }, +#endif // TINYOBJ_USE_UTHASH { "crlf_string", test_tinyobj_crlf_string }, { "negative_exponent_issue26", test_tinyobj_negative_exponent }, diff --git a/tinyobj_loader_c.h b/tinyobj_loader_c.h index 30ff22e..ebafa1b 100644 --- a/tinyobj_loader_c.h +++ b/tinyobj_loader_c.h @@ -1,47 +1,343 @@ -/* - The MIT License (MIT) - - Copyright (c) 2016 - 2019 Syoyo Fujita and many contributors. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ +/* About: License + * The MIT License (MIT) + * + * Copyright (c) 2016-2019 Syoyo Fujita and many contributors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ #ifndef TINOBJ_LOADER_C_H_ #define TINOBJ_LOADER_C_H_ /* @todo { Remove stddef dependency. size_t? } */ #include +/* Constant: TINYOBJ_LOADER_C_IMPLEMENTATION + * Constant used to mark the .c file that holds the implementation of tinyobj + * + * Only *one* file should have this definition! + */ + +/* Constant: TINYOBJ_USE_UTHASH + * Use hashtable implementation + * instead of tinyobj's implementation + */ +//#define TINYOBJ_USE_UTHASH + +/* Constant: TINYOBJ_ENABLE_OLDER_ATTRIBUTE + * + * Enable use of older attribute type for objects (deprecated) + * + * See: + * - + * - + * - + */ +#define TINYOBJ_ENABLE_OLDER_ATTRIBUTE + +/* Constant: TINYOBJ_FLAG_TRIANGULATE + * + * Should the faces be triangulated upon loading + * When triangulating we parse the vertices as if they were part of + * a triangle fan, so every three indices the next is always the first + * triplet of this face + * + * See: + * + */ +#define TINYOBJ_FLAG_TRIANGULATE (1 << 0) + +/* Constant: TINYOBJ_INVALID_INDEX + * + * Invalid vertex index used when referencing vertices in couples/tuples + * + * See: + * - + * - + * - + */ +#define TINYOBJ_INVALID_INDEX (0x80000000) + +/* Constants: Return codes + * + * TINYOBJ_NO_COMMAND - No command + * TINYOBJ_SUCCESS - Success + * TINYOBJ_ERROR_NOT_SET - Default error + * TINYOBJ_ERROR_MEMORY - Memory failure + * TINYOBJ_ERROR_EMPTY - Empty file + * TINYOBJ_ERROR_FILE_OPERATION - Failed file operation + * TINYOBJ_ERROR_INVALID_PARAMETER - Invalid parameter (function) + * TINYOBJ_ERROR_UNKNOWN_PARAMETER - Unknown parameter for object/material + * TINYOBJ_ERROR_MALFORMED_PARAMETER - Malformed parameter for object/material + */ +#define TINYOBJ_NO_COMMAND (1) +#define TINYOBJ_SUCCESS (0) +#define TINYOBJ_ERROR_NOT_SET (-1) +#define TINYOBJ_ERROR_MEMORY (-2) +#define TINYOBJ_ERROR_EMPTY (-3) +#define TINYOBJ_ERROR_FILE_OPERATION (-4) +#define TINYOBJ_ERROR_INVALID_PARAMETER (-5) +#define TINYOBJ_ERROR_UNKNOWN_PARAMETER (-6) +#define TINYOBJ_ERROR_MALFORMED_PARAMETER (-7) + +/* Constants: Dynamic array basic parameters + * + * Initial array lengths and growth factors + * + * TINYOBJ_POINT_INITIAL_COUNT - Point array initial length + * TINYOBJ_POINT_GROWTH_FACTOR - Point array growth factor + * TINYOBJ_COUPLE_INITIAL_COUNT - Couple (line) array initial length + * TINYOBJ_COUPLE_GROWTH_FACTOR - Couple (line) array growth factor + * TINYOBJ_TRIPLET_INITIAL_COUNT - Triplet (face) array initial length + * TINYOBJ_TRIPLET_GROWTH_FACTOR - Triplet (face) array growth factor + * TINYOBJ_MATERIAL_INITIAL_COUNT - Material array initial length + * TINYOBJ_MATERIAL_GROWTH_FACTOR - Material array growth factor + */ +#define TINYOBJ_POINT_INITIAL_COUNT (16) +#define TINYOBJ_POINT_GROWTH_FACTOR (2) +#define TINYOBJ_COUPLE_INITIAL_COUNT (16) +#define TINYOBJ_COUPLE_GROWTH_FACTOR (2) +#define TINYOBJ_TRIPLET_INITIAL_COUNT (16) +#define TINYOBJ_TRIPLET_GROWTH_FACTOR (2) +#define TINYOBJ_MATERIAL_INITIAL_COUNT (2) +#define TINYOBJ_MATERIAL_GROWTH_FACTOR (2) + +/*********************************************************************************************** + * Group: Vertex data + ***********************************************************************************************/ + +/* Structure: tinyobj_vertex_t + * + * Geometric vertex (v) + * Specifies a geometric vertex and its x y z coordinates. Rational + * curves and surfaces require a fourth homogeneous coordinate, also + * called the weight. + * > v x y z w + * + * Fields: + * + * x - x coordinate + * y - y coordinate + * z - z coordinate + * weight - (Rational curves/surfaces) Weight (default: 1.0f) + */ +typedef struct s_tinyobj_vertex { + float x, y, z; //< Coordinates + float weight; //< (Rational curves/surfaces) Weight (default: 1.0f) +} tinyobj_vertex_t; + +/* Structure: tinyobj_vertex_normal_t + * + * Vertex normal (vn) + * Specifies a normal vector with components i, j, and k + * > vn i j k + * + * Fields: + * + * i - i coordinate + * j - j coordinate + * k - k coordinate + */ +typedef struct s_tinyobj_vertex_normal { + float i, j, k; //< Coordinates +} tinyobj_vertex_normal_t; + +/* Structure: tinyobj_vertex_texture_t + * + * Texture vertex (vt) + * Specifies a texture vertex and its coordinates + * > vt u v w + * + * Fields: + * + * u - Horizontal direction + * v - (2D and 3D) Vertical direction (Default: 0) + * w - (3D) Depth (Default: 0) + */ +typedef struct s_tinyobj_vertex_texture { + float u; //< Horizontal direction + float v; //< (2D and 3D) Vertical direction (Default: 0) + float w; //< (3D) Depth (Default: 0) +} tinyobj_vertex_texture_t; + +/* Structure: tinyobj_vertex_param_t + * + * Parameter space vertex (vp) + * Specifies a point in the parameter space of a curve or surface. + * > vp u v w + * + * Fields: + * + * u - (1D) Space control point + * v - (2D) Space control point + * weight - (Rational trimming curves) Weight (default: 0) + */ +typedef struct s_tinyobj_vertex_param { + float u, v; + float weight; +} tinyobj_vertex_param_t; + +/*********************************************************************************************** + * Group: Element data + * Polygonal and free-form geometry + ***********************************************************************************************/ + +/* Structure: tinyobj_vertex_index_t + * Indices for each vertex type, used for triplets in faces + * See: + * + * + * Fields: + * + * v_idx - Geometric vertex index + * vt_idx - Texture vertex index + * vn_idx - Normal vertex index + */ typedef struct { - char *name; + int v_idx, vt_idx, vn_idx; +} tinyobj_vertex_index_t; - float ambient[3]; - float diffuse[3]; - float specular[3]; - float transmittance[3]; - float emission[3]; - float shininess; - float ior; /* index of refraction */ - float dissolve; /* 1 == opaque; 0 == fully transparent */ - /* illumination model (see http://www.fileformat.info/format/material/) */ - int illum; +/* Structure: tinyobj_point_t + * Point (p) + * Specifies a point element and its vertex + * > p v1 v2 v3 + * + * Fields: + * + * v_idx - List of vertices + * count - Point count + * length - List length + */ +typedef struct s_tinyobj_point { + int *v_idx; //< List of vertices + size_t count; //< Point count + size_t length; //< List length +} tinyobj_point_t; + +/* Structure: tinyobj_line_t + * Line (l) + * Specifies a line and its vertex reference numbers + * > l v1/vt1 v2/vt2 v3/vt3 + * + * Fields: + * + * couple_list - List of couples contained in this line + * count - Count of couples + * length - Total length of couple list + */ +typedef struct s_tinyobj_line { + /* Structure: tinyobj_line_t.s_line_vertex_index + * List of couples + * + * Fields: + * + * v_idx - Geometric vertex + * vt_idx - Texture vertex (optional) + */ + struct s_line_vertex_index { + int v_idx, //< Geometric Vertex + vt_idx; //< Texture Vertex (optional) + } * couple_list; + size_t count; //< Count of couples + size_t length; //< Length of couple list +} tinyobj_line_t; + +/* Structure: tinyobj_face_t + * Face (f) + * Specifies a face element and its vertex reference number + * > f v1/vt1/vn1 v2/vt2/vn2 + * > fo (deprecated) + * + * Fields: + * + * triplet list - A list of triplets contained in this face + * + * *v* Geometric vertex (minimum of 3) + * + * *vt* Texture vertex (optional) + * + * *vn* Vertex normal (optional) + * + * When an index is empty it is equal to + * count - Count of triplets + * length - Length of triplet list + * triangle_count - Number of triangles in this face + * material_id - Material to be applied to this face (defaults to -1) + * smoothing_id - Smoothing group to be applied to this face (defaults to 0) + */ +typedef struct s_tinyobj_face { + tinyobj_vertex_index_t *triplet_list; + unsigned int count; //< Count of triplets + unsigned int length; //< Length of triplet list + unsigned int triangle_count; //< Number of triangles in this face + int material_id; //< Material to be applied to this face (defaults to -1) + int smoothing_id; //< Smoothing group to be applied to this face (defaults to 0) +} tinyobj_face_t; + +/* Structure: tinyobj_coefficient_t + * RGB Color coefficient information used in materials + * + */ +typedef struct s_coefficient_information { + float r, g, b; +} tinyobj_coefficient_t; - int pad0; +/* Structure: tinyobj_material_t + * Material attribute + * <.mtl format: http://paulbourke.net/dataformats/mtl/> + * + * Fields: + * + * name - Material name + * ambient - Ambient color coefficient (reflectivity) + * diffuse - Diffuse color coefficient (reflectivity) + * specular - Specular color coefficient (reflectivity) + * transmittance - Transmittance color coefficient (reflectivity) + * emission - Emission color coefficient (reflectivity) + * shininess - Specular exponent + * ior - Index Of Refraction (ior) 'optical density' + * dissolve - Non-transparency to be alpha 'dissolve' (0.0f transparent-1.0f opaque) + * illum - Illumination model (0-10) + * ambient_texname - map_Ka + * diffuse_texname - map_Kd + * specular_texname - map_Ks + * specular_highlight_texname - map_Ns + * bump_texname - map_bump, bump + * displacement_texname - disp + * alpha_texname - map_d + */ +typedef struct s_tinyobj_material { + char *name; //< Name + + /** + * Color coefficients (reflectivity) + **/ + tinyobj_coefficient_t ambient; + tinyobj_coefficient_t diffuse; + tinyobj_coefficient_t specular; + tinyobj_coefficient_t transmittance; + tinyobj_coefficient_t emission; + + float shininess; //< Specular exponent + float ior; //< Index Of Refraction (ior) 'optical density' + float dissolve; //< Non-transparency to be alpha 'dissolve' (0.0f transparent -> 1.0f opaque) + int illum; //< Illumination model (0 - 10) char *ambient_texname; /* map_Ka */ char *diffuse_texname; /* map_Kd */ @@ -52,14 +348,87 @@ typedef struct { char *alpha_texname; /* map_d */ } tinyobj_material_t; -typedef struct { - char *name; /* group name or object name. */ - unsigned int face_offset; - unsigned int length; +/* Structure: tinyobj_shape_t + * Shapes contained in a given attribute + * + * Fields: + * + * name - Group name or object name + * face_offset - Face offset of this shape (starting point) + * length - Length of this shape (ending point) + */ +typedef struct s_tinyobj_shape { + char *name; + size_t face_offset; + size_t length; } tinyobj_shape_t; -typedef struct { int v_idx, vt_idx, vn_idx; } tinyobj_vertex_index_t; +/* Structure: tinyobj_attrib_t + * Object attributes + * <.obj format: http://paulbourke.net/dataformats/obj/> + * + * Fields: + * + * v - Geometric vertices + * v_count - Geometric vertex count + * vn - Vertex normals + * vn_count - Vertex normal count + * vt - Texture vertices + * vt_count - Texture vertex count + * vp - Parameter space vertices + * vp_count - Parameter space vertex count + * f - Object faces + * f_count - Face count + * triangle_count_total - Total count of triangles + * l - Lines + * l_count - Line count + * p - Points + */ +typedef struct s_tinyobj_attrib { + tinyobj_vertex_t *v; //< Geometric vertices + size_t v_count; //< Geometric vertex count + tinyobj_vertex_normal_t *vn; //< Vertex normals + size_t vn_count; //< Vertex normal count + tinyobj_vertex_texture_t *vt; //< Texture vertices + size_t vt_count; //< Texture vertex count + tinyobj_vertex_param_t *vp; //< Parameter space vertices + size_t vp_count; //< Parameter space vertex count + + tinyobj_face_t *f; //< Object faces + size_t f_count; //< Face count + size_t triangle_count_total; //< Total count of triangles + + tinyobj_line_t *l; //< Lines + size_t l_count; //< Line count + tinyobj_point_t p; //< Points +} tinyobj_attrib_t; + +#ifdef TINYOBJ_ENABLE_OLDER_ATTRIBUTE +#ifdef _MSC_VER +#pragma message( \ + "warning: Using deprecated attribute type in TINYOBJ (TINYOBJ_ENABLE_OLDER_ATTRIBUTE)") +#else +#warning \ + "Using deprecated attribute type in TINYOBJ (TINYOBJ_ENABLE_OLDER_ATTRIBUTE)" +#endif +/* Structure: COMPATtinyobj_attrib_t + * Object attributes *(deprecated)* + * + * Fields: + * + * vertices - Array of geometric vertices (x0, y0, z0, x1, y1, z1, ...) + * num_vertices - Number of vertices in 'vertices' (the actual array length is num_vertices*3) + * normals - Array of vertex normals (i0, j0, k0, i1, j1, k1, ...) + * num_normals - Number of vertices in 'normals' (the actual array length is num_normals*3) + * texcoords - Array of texture vertices (u0, w0, u1, w1, ...) + * num_texcoords - Number of vertices in 'texcoords' (the actual array length is num_normals*2) + * faces - Array of faces (containing information) + * num_faces - Length of 'faces' + * face_num_verts - Array of number of vertices in each face (3 for triangulated faces) + * num_face_num_verts - Total number of triangles in this object (length of face_num_verts) + * material_ids - Array with the id of the material for each face (length is num_faces) + **/ typedef struct { unsigned int num_vertices; unsigned int num_normals; @@ -75,77 +444,136 @@ typedef struct { tinyobj_vertex_index_t *faces; int *face_num_verts; int *material_ids; -} tinyobj_attrib_t; - - -#define TINYOBJ_FLAG_TRIANGULATE (1 << 0) +} COMPATtinyobj_attrib_t; -#define TINYOBJ_INVALID_INDEX (0x80000000) +int tinyobj_new2old(tinyobj_attrib_t *attrib, + COMPATtinyobj_attrib_t *out_attrib); +void tinyobj_attrib_free_compat(COMPATtinyobj_attrib_t *attrib); +#endif // TINYOBJ_ENABLE_OLDER_ATTRIBUTE -#define TINYOBJ_SUCCESS (0) -#define TINYOBJ_ERROR_EMPTY (-1) -#define TINYOBJ_ERROR_INVALID_PARAMETER (-2) -#define TINYOBJ_ERROR_FILE_OPERATION (-3) - -/* Parse wavefront .obj(.obj string data is expanded to linear char array `buf') - * flags are combination of TINYOBJ_FLAG_*** - * Returns TINYOBJ_SUCCESS if things goes well. - * Returns TINYOBJ_ERR_*** when there is an error. - */ -extern int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, - size_t *num_shapes, tinyobj_material_t **materials, - size_t *num_materials, const char *buf, size_t len, - unsigned int flags); -extern int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, - size_t *num_materials_out, - const char *filename); - -extern void tinyobj_attrib_init(tinyobj_attrib_t *attrib); -extern void tinyobj_attrib_free(tinyobj_attrib_t *attrib); -extern void tinyobj_shapes_free(tinyobj_shape_t *shapes, size_t num_shapes); -extern void tinyobj_materials_free(tinyobj_material_t *materials, - size_t num_materials); +int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, + unsigned int *num_materials_out, + const char *filename); +void tinyobj_material_free(tinyobj_material_t *materials, + unsigned int num_materials); +void tinyobj_shape_free(tinyobj_shape_t *shapes, unsigned int num_shapes); +void tinyobj_attrib_free(tinyobj_attrib_t *attrib); +int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, + unsigned int *num_shapes, + tinyobj_material_t **materials_out, + unsigned int *num_materials_out, const char *buf, + size_t len, unsigned int flags); #ifdef TINYOBJ_LOADER_C_IMPLEMENTATION -#include #include -#include #include +#include +#include // atoi +#include -#if defined(TINYOBJ_MALLOC) && defined(TINYOBJ_REALLOC) && defined(TINYOBJ_CALLOC) && defined(TINYOBJ_FREE) +#if defined(TINYOBJ_MALLOC) && defined(TINYOBJ_REALLOC) && \ + defined(TINYOBJ_CALLOC) && defined(TINYOBJ_FREE) /* ok */ -#elif !defined(TINYOBJ_MALLOC) && !defined(TINYOBJ_REALLOC) && !defined(TINYOBJ_CALLOC) && !defined(TINYOBJ_FREE) +#elif !defined(TINYOBJ_MALLOC) && !defined(TINYOBJ_REALLOC) && \ + !defined(TINYOBJ_CALLOC) && !defined(TINYOBJ_FREE) /* ok */ #else -#error "Must define all or none of TINYOBJ_MALLOC, TINYOBJ_REALLOC, TINYOBJ_CALLOC and TINYOBJ_FREE." +#error \ + "Must define all or none of TINYOBJ_MALLOC, TINYOBJ_REALLOC, TINYOBJ_CALLOC and TINYOBJ_FREE." #endif #ifndef TINYOBJ_MALLOC -#include #define TINYOBJ_MALLOC malloc #define TINYOBJ_REALLOC realloc #define TINYOBJ_CALLOC calloc #define TINYOBJ_FREE free #endif -#define TINYOBJ_MAX_FACES_PER_F_LINE (16) +#ifdef TINYOBJ_USE_UTHASH +#include +#endif + +#ifdef _MSC_VER +#define __func__ __FUNCTION__ +#endif + +/*********************************************************************************************** + * Group: String handling + ***********************************************************************************************/ +/* Functions: String handling macros + * + * IS_SPACE - Is this character a spacing character ' ' or '\t' + * IS_DIGIT - Is this character a digit + * IS_NEW_LINE - Is this character a new line character '\r','\n','\0' + */ #define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) #define IS_DIGIT(x) ((unsigned int)((x) - '0') < (unsigned int)(10)) #define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) +/* Function: is_line_ending + * Is given line ending in this character? + * + * Returns: + * True if line is ending + **/ +static int is_line_ending(const char *p, size_t i, size_t end_i) { + if (p[i] == '\0') return 1; + if (p[i] == '\n') return 1; // this includes \r\n + if (p[i] == '\r') { + if (((i + 1) < end_i) && (p[i + 1] != '\n')) { // detect only \r case + return 1; + } + } + return 0; +} + +/* Function: skip_space + * Skips the next spacing characters in given token + */ static void skip_space(const char **token) { while ((*token)[0] == ' ' || (*token)[0] == '\t') { + if ((*token)[0] == '\0') return; (*token)++; } } +/* Function: skip_space_and_cr + * Skips the next spacing characters and also carriage return in given token + */ static void skip_space_and_cr(const char **token) { while ((*token)[0] == ' ' || (*token)[0] == '\t' || (*token)[0] == '\r') { + if ((*token)[0] == '\0') return; (*token)++; } } +/* Function: length_until_space + * Calculates and returns the length until next space character in this token + * + * Parameters: + * + * token - Token to be used + * n - Maximum number of characters to count + * + * Returns: + * + * Length until next space character + */ +static size_t length_until_space(const char *token, size_t n) { + size_t len = 0; + for (len = 0; len < n - 1; len++) { + if (token[len] == '\n' || token[len] == ' ' || token[len] == '\t' || + token[len] == '\r') + break; + } + return len; +} + +/* Function: until_space + * Skips the next spacing characters + * > '\0',' ', '\t', '\r' + */ static int until_space(const char *token) { const char *p = token; while (p[0] != '\0' && p[0] != ' ' && p[0] != '\t' && p[0] != '\r') { @@ -155,150 +583,366 @@ static int until_space(const char *token) { return (int)(p - token); } -static size_t length_until_newline(const char *token, size_t n) { - size_t len = 0; - - /* Assume token[n-1] = '\0' */ - for (len = 0; len < n - 1; len++) { - if (token[len] == '\n') { - break; - } - if ((token[len] == '\r') && ((len < (n - 2)) && (token[len + 1] != '\n'))) { - break; - } - } +/* Function: until_space_cr_slash + * Skips the next characters in given token + * > '\0','/', ' ', '\t', '\r' + */ +static void until_space_cr_slash(const char **token) { + while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && + (*token)[0] != '\t' && (*token)[0] != '\r') + (*token)++; +} - return len; +/* Function: length_until_newline_comment_space + * + * Returns the length until the next characters: + * > \n \r\n \0 ' ' \t # + * + * Parameters: + * token - Buffer + * n - Maximum number of characters to count + * + * Returns: + * + * Length until next character + */ +static size_t length_until_newline_comment_space(const char *token, size_t n) { + size_t len = 0; + for(len = 0; len < n-1; len++) { + if(token[len] == '\n') + break; + if((token[len] == '\r') && ((len < (n - 2)) && (token[len + 1] != '\n'))) + break; + if(token[len] == '\0' || token[len] == ' ' || token[len] == '\t' || token[len] == '#') + break; + } + return len; } +/* Function: length_until_line_feed + * + * Returns the length until the next line feed + * + * *Assumes token[n-1] = '\0'* + * + * Parameters: + * token - Buffer + * n - Maximum number of characters to count + */ static size_t length_until_line_feed(const char *token, size_t n) { size_t len = 0; - /* Assume token[n-1] = '\0' */ for (len = 0; len < n; len++) { - if ((token[len] == '\n') || (token[len] == '\r')) { - break; - } + if ((token[len] == '\n') || (token[len] == '\r')) break; } - return len; } -/* http://stackoverflow.com/questions/5710091/how-does-atoi-function-in-c-work -*/ -static int my_atoi(const char *c) { - int value = 0; - int sign = 1; - if (*c == '+' || *c == '-') { - if (*c == '-') sign = -1; - c++; +/* Function: strdup_ml + * Duplicates 'max_length' characters of given string + * (strdup with max length specified) + * + * Parameters: + * + * s - String to be duplicated + * max_length - Maximum length to be duplicated + * + * Returns: + * + * Duplicated string (*should be freed by the caller*) + */ +static char *strdup_ml(const char *s, size_t max_length) { + char *d; + size_t len; + + if (s == NULL) return NULL; + + /* Do not consider CRLF line ending(#19) */ + len = length_until_line_feed(s, max_length); + /* len = strlen(s); */ + + /* trim line ending and append '\0' */ + d = TINYOBJ_MALLOC(len + 1); /* + '\0' */ + memcpy(d, s, len); + d[len] = '\0'; + + return d; +} + +#ifndef strndup +/* Function: strndup + * strndup implementation for non-GNU compliant compilers + */ +char *strndup(const char *s, size_t len) { + char *d; + size_t slen; + + if (s == NULL || len == 0) return NULL; + + d = TINYOBJ_MALLOC(len + 1); /* + '\0' */ + if (d == NULL) return NULL; + + slen = strlen(s); + if (slen < len) { + memcpy(d, s, slen); + d[slen] = '\0'; + } else { + memcpy(d, s, len); + d[len] = '\0'; + } + + return d; +} +#endif + +/* Function: dynamic_fgets + * fgets with a dynamic buffer + */ +static char *dynamic_fgets(char **buf, int *size, FILE *file) { + char *offset; + char *ret; + int old_size; + + if (!(ret = fgets(*buf, (int)*size, file))) { + return ret; } - while (((*c) >= '0') && ((*c) <= '9')) { /* isdigit(*c) */ - value *= 10; - value += (int)(*c - '0'); - c++; + + if (NULL != strchr(*buf, '\n')) { + return ret; } - return value * sign; + + do { + old_size = *size; + *size *= 2; + *buf = TINYOBJ_REALLOC(*buf, *size); + offset = &((*buf)[old_size - 1]); + + ret = fgets(offset, (int)(old_size + 1), file); + } while (ret && (NULL == strchr(*buf, '\n'))); + + return ret; } -/* Make index zero-base, and also support relative index. */ +/*********************************************************************************************** + * Group: Triplet handling + ***********************************************************************************************/ + +/* Function: fixIndex + * + * Converts given absolute index, from triplet to zero-base, supports relative + * indices + * + * See: + * + * - + * - + * - + * + * + * Parameters: + * + * idx - Index to be converted + * n - Position of this couple/tuple regarding to the vertex type of this index + * + * Returns: + * + * - Fixed index value that's able to be used when accessing vertex arrays + * - when there's no equivalent index + */ static int fixIndex(int idx, size_t n) { if (idx > 0) return idx - 1; if (idx == 0) return 0; - return (int)n + idx; /* negative value = relative */ + if (idx == TINYOBJ_INVALID_INDEX) return TINYOBJ_INVALID_INDEX; + + return (int)n + idx; // Negative value = relative } -/* Parse raw triples: i, i/j/k, i//k, i/j */ +/* Function: parseRawTriple + * + * Parses raw triplets of given tokens + * > v, v/vt/vn, v//vn, v/vt + * + * > Valid triplets: + * > 1//1 + * > 1//1 2//2 3//3 4//4 + * > 1/1/1 2/2/2 3/3/3 4/4/4 + * > The following are examples of illegal statements + * > 1/1/1 2/2/2 3//3 4//4 + * > 1/ 1/1 2/2/2 3/3/3 4/4/4 + * + * Parameters: + * token - Token to parse + * + * Returns: + * Indices parsed from given token, if one of the indices is not present it's + * equal to + */ static tinyobj_vertex_index_t parseRawTriple(const char **token) { tinyobj_vertex_index_t vi; - /* 0x80000000 = -2147483648 = invalid */ - vi.v_idx = (int)(0x80000000); - vi.vn_idx = (int)(0x80000000); - vi.vt_idx = (int)(0x80000000); - vi.v_idx = my_atoi((*token)); - while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && - (*token)[0] != '\t' && (*token)[0] != '\r') { - (*token)++; - } - if ((*token)[0] != '/') { - return vi; - } + vi.v_idx = (int)(TINYOBJ_INVALID_INDEX); + vi.vn_idx = (int)(TINYOBJ_INVALID_INDEX); + vi.vt_idx = (int)(TINYOBJ_INVALID_INDEX); + + // v + vi.v_idx = atoi((*token)); + until_space_cr_slash(token); + if ((*token)[0] != '/') return vi; (*token)++; - /* i//k */ + // v//vn if ((*token)[0] == '/') { (*token)++; - vi.vn_idx = my_atoi((*token)); - while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && - (*token)[0] != '\t' && (*token)[0] != '\r') { - (*token)++; - } + vi.vn_idx = atoi((*token)); + until_space_cr_slash(token); return vi; } - /* i/j/k or i/j */ - vi.vt_idx = my_atoi((*token)); - while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && - (*token)[0] != '\t' && (*token)[0] != '\r') { - (*token)++; - } - if ((*token)[0] != '/') { - return vi; - } + // v/vt/vn or v/vt + vi.vt_idx = atoi((*token)); + until_space_cr_slash(token); + if ((*token)[0] != '/') return vi; + + // v/vt/vn + (*token)++; // skip '/' + vi.vn_idx = atoi((*token)); + until_space_cr_slash(token); - /* i/j/k */ - (*token)++; /* skip '/' */ - vi.vn_idx = my_atoi((*token)); - while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && - (*token)[0] != '\t' && (*token)[0] != '\r') { - (*token)++; - } return vi; } +/*********************************************************************************************** + * Group: Integer/Double/Float handling + ***********************************************************************************************/ + +/* Function: parseInt + * Returns equivalent integer of next non-space character, the token is advanced + * until next space + */ static int parseInt(const char **token) { int i = 0; skip_space(token); - i = my_atoi((*token)); + i = atoi((*token)); (*token) += until_space((*token)); return i; } -/* - * Tries to parse a floating point number located at s. +/* Function: tryParseDouble_assemble * - * s_end should be a location in the string where reading should absolutely - * stop. For example at the end of the string, to prevent buffer overflows. + * Last step of * - * Parses the following EBNF grammar: - * sign = "+" | "-" ; - * END = ? anything not in digit ? - * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; - * integer = [sign] , digit , {digit} ; - * decimal = integer , ["." , integer] ; - * float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; + * Assembles given information into double * - * Valid strings are for example: - * -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 + * Parameters: + * sign - Sign of this double + * mantissa - Mantissa + * exp_sign - Exponent sign + * exponent - Exponent * - * If the parsing is a success, result is set to the parsed value and true - * is returned. - * - * The function is greedy and will parse until any of the following happens: - * - a non-conforming character is encountered. - * - s_end is reached. + * Returns: * - * The following situations triggers a failure: - * - s >= s_end. - * - parse failure. + * Assembled double */ -static int tryParseDouble(const char *s, const char *s_end, double *result) { - double mantissa = 0.0; - /* This exponent is base 2 rather than 10. - * However the exponent we parse is supposed to be one of ten, - * thus we must take care to convert the exponent/and or the - * mantissa to a * 2^E, where a is the mantissa and E is the +static double tryParseDouble_assemble(char sign, double mantissa, char exp_sign, + int exponent) { + double a = 1.0; /* = pow(5.0, exponent); */ + double b = 1.0; /* = 2.0^exponent */ + int i; + + for (i = 0; i < exponent; i++) a = a * 5.0; + + for (i = 0; i < exponent; i++) b = b * 2.0; + + if (exp_sign == '-') { + a = 1.0 / a; + b = 1.0 / b; + } + + /* (sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), + exponent); */ + return (sign == '+' ? 1 : -1) * (mantissa * a * b); +} + +/* Function: tryParseDouble_integer + * + * Part of + * + * Parses integer part of a double (advances curr) + * + * Parameters: + * + * curr - Current position in a buffer + * s_end - End of the buffer + * sign - [out] Sign to be filled + * integer - [out] Integer to be filled + * + * Returns: + * True integer was successfuly parsed, false if nothing was read + */ +static unsigned char tryParseDouble_integer(const char **curr, + const char *s_end, char *sign, + int *integer) { + unsigned int read = 0; + *sign = '+'; // Default sign + + // Read sign + if ((*curr)[0] == '+' || (*curr)[0] == '-') { + (*sign) = (*curr)[0]; + if ((*curr)++ == s_end) return 0; // No more data to read (invalid number) + } else if (!IS_DIGIT((*curr)[0])) { + return 0; // A digit is expected + } + + // Read integer + for (; (*curr) != s_end && IS_DIGIT(((*curr)[0])); (*curr)++, read++) { + (*integer) *= 10; + (*integer) += (int)((*curr)[0] - 0x30); + } + return (read > 0); +} + +/* Function: tryParseDouble + * + * Tries to parse a floating point number located at s. + * > Parses the following EBNF grammar: + * > sign = "+" | "-" ; + * > END = ? anything not in digit ? + * > digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; + * > integer = [sign] , digit , {digit} ; + * > decimal = integer , ["." , integer] ; + * > float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; + * + * > Valid strings are for example: + * > -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 + * + * The function is greedy and will parse until any of the following happens: + * + * - a non-conforming character is encountered. + * - s_end is reached. + * + * The following situations triggers a failure: + * + * - s >= s_end. + * - parse failure. + * + * Parameters: + * + * s - String to be parsed + * s_end - Location in the string where reading should halt, e.g. the end of + * the string result - [out] Parsed double + * + * Returns + * If the parsing is a success, result is set to the parsed value and true + * is returned. + */ +static unsigned char tryParseDouble(const char *s, const char *s_end, + double *result) { + double mantissa = 0.0; + int integer = 0; + /* This exponent is base 2 rather than 10. + * However the exponent we parse is supposed to be one of ten, + * thus we must take care to convert the exponent/and or the + * mantissa to a * 2^E, where a is the mantissa and E is the * exponent. * To get the final double we will use ldexp, it requires the * exponent to be in base 2. @@ -314,261 +958,182 @@ static int tryParseDouble(const char *s, const char *s_end, double *result) { /* How many characters were read in a loop. */ int read = 0; - /* Tells whether a loop terminated due to reaching s_end. */ - int end_not_reached = 0; - - /* - BEGIN PARSING. - */ - - if (s >= s_end) { - return 0; /* fail */ - } - /* Find out what sign we've got. */ - if (*curr == '+' || *curr == '-') { - sign = *curr; - curr++; - } else if (IS_DIGIT(*curr)) { /* Pass through. */ - } else { - goto fail; - } + /* BEGIN PARSING. */ - /* Read the integer part. */ - end_not_reached = (curr != s_end); - while (end_not_reached && IS_DIGIT(*curr)) { - mantissa *= 10; - mantissa += (int)(*curr - 0x30); - curr++; - read++; - end_not_reached = (curr != s_end); - } + if (s >= s_end) // Passed stopping point + return 0; - /* We must make sure we actually got something. */ - if (read == 0) goto fail; - /* We allow numbers of form "#", "###" etc. */ - if (!end_not_reached) goto assemble; - - /* Read the decimal part. */ - if (*curr == '.') { - curr++; - read = 1; - end_not_reached = (curr != s_end); - while (end_not_reached && IS_DIGIT(*curr)) { - /* pow(10.0, -read) */ - double frac_value = 1.0; - int f; - for (f = 0; f < read; f++) { - frac_value *= 0.1; + // Read integer and sign + if (!tryParseDouble_integer(&curr, s_end, &sign, &integer)) + return 0; // Nothing was read + mantissa = integer; + + while (curr != s_end) { + switch (*curr) { + // Read decimal + case '.': { + if (curr++ == s_end) return 0; + read = 1; + while (curr != s_end && IS_DIGIT(*curr)) { + /* pow(10.0, -read) */ + double frac_value = 1.0; + int f; + for (f = 0; f < read; f++) frac_value *= 0.1; + mantissa += (int)(*curr - 0x30) * frac_value; + read++; + curr++; + } + break; } - mantissa += (int)(*curr - 0x30) * frac_value; - read++; - curr++; - end_not_reached = (curr != s_end); - } - } else if (*curr == 'e' || *curr == 'E') { - } else { - goto assemble; - } - - if (!end_not_reached) goto assemble; - - /* Read the exponent part. */ - if (*curr == 'e' || *curr == 'E') { - curr++; - /* Figure out if a sign is present and if it is. */ - end_not_reached = (curr != s_end); - if (end_not_reached && (*curr == '+' || *curr == '-')) { - exp_sign = *curr; - curr++; - } else if (IS_DIGIT(*curr)) { /* Pass through. */ - } else { - /* Empty E is not allowed. */ - goto fail; - } - - read = 0; - end_not_reached = (curr != s_end); - while (end_not_reached && IS_DIGIT(*curr)) { - exponent *= 10; - exponent += (int)(*curr - 0x30); - curr++; - read++; - end_not_reached = (curr != s_end); - } - if (read == 0) goto fail; - } - -assemble : - - { - double a = 1.0; /* = pow(5.0, exponent); */ - double b = 1.0; /* = 2.0^exponent */ - int i; - for (i = 0; i < exponent; i++) { - a = a * 5.0; - } - - for (i = 0; i < exponent; i++) { - b = b * 2.0; - } - - if (exp_sign == '-') { - a = 1.0 / a; - b = 1.0 / b; + // Read Exponent + case 'E': + case 'e': { + if (curr++ == s_end) return 0; + if (!tryParseDouble_integer(&curr, s_end, &exp_sign, &exponent)) + return 0; // Empty E is not allowed + break; + } + default: + curr++; + break; } - - *result = - /* (sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), - exponent); */ - (sign == '+' ? 1 : -1) * (mantissa * a * b); } - + *result = tryParseDouble_assemble(sign, mantissa, exp_sign, exponent); return 1; -fail: - return 0; } -static float parseFloat(const char **token) { +/* Function: try_parse_float + * + * Tries to parse next float, if there's none fails + * + * Parameters: + * + * token - Buffer to be read + * result - [out] Result, not set if return is false + * + * Returns: + * + * If the parsing is a success, result is set to the parsed value and true + * is returned. + **/ +static unsigned char try_parse_float(const char **token, float *result) { const char *end; double val = 0.0; float f = 0.0f; + unsigned char retval; + skip_space(token); end = (*token) + until_space((*token)); val = 0.0; - tryParseDouble((*token), end, &val); - f = (float)(val); + retval = tryParseDouble((*token), end, &val); + *result = (retval) ? (float)val : f; (*token) = end; + return retval; +} + +/* Function: parseFloat + * + * Returns equivalent float of next non-space character, the token is advanced + * until next space + */ +static float parseFloat(const char **token) { + float f = 0.0f; + try_parse_float(token, &f); return f; } +/* Function: parseFloat2 + * + * Parses the two next floats in given token + * + * See: + * + * + */ static void parseFloat2(float *x, float *y, const char **token) { (*x) = parseFloat(token); (*y) = parseFloat(token); } +/* Function: parseFloat3 + * + * Parses the three next floats in given token + * + * See: + * + * + */ static void parseFloat3(float *x, float *y, float *z, const char **token) { (*x) = parseFloat(token); (*y) = parseFloat(token); (*z) = parseFloat(token); } -static size_t my_strnlen(const char *s, size_t n) { - const char *p = memchr(s, 0, n); - return p ? (size_t)(p - s) : n; -} - -static char *my_strdup(const char *s, size_t max_length) { - char *d; - size_t len; - - if (s == NULL) return NULL; - - /* Do not consider CRLF line ending(#19) */ - len = length_until_line_feed(s, max_length); - /* len = strlen(s); */ - - /* trim line ending and append '\0' */ - d = (char *)TINYOBJ_MALLOC(len + 1); /* + '\0' */ - memcpy(d, s, (size_t)(len)); - d[len] = '\0'; - - return d; -} - -static char *my_strndup(const char *s, size_t len) { - char *d; - size_t slen; - - if (s == NULL) return NULL; - if (len == 0) return NULL; - - slen = my_strnlen(s, len); - d = (char *)TINYOBJ_MALLOC(slen + 1); /* + '\0' */ - if (!d) { - return NULL; - } - memcpy(d, s, slen); - d[slen] = '\0'; - - return d; -} - -char *dynamic_fgets(char **buf, size_t *size, FILE *file) { - char *offset; - char *ret; - size_t old_size; - - if (!(ret = fgets(*buf, (int)*size, file))) { - return ret; - } - - if (NULL != strchr(*buf, '\n')) { - return ret; - } - - do { - old_size = *size; - *size *= 2; - *buf = (char*)TINYOBJ_REALLOC(*buf, *size); - offset = &((*buf)[old_size - 1]); - - ret = fgets(offset, (int)(old_size + 1), file); - } while(ret && (NULL == strchr(*buf, '\n'))); - - return ret; -} - -static void initMaterial(tinyobj_material_t *material) { - int i; - material->name = NULL; - material->ambient_texname = NULL; - material->diffuse_texname = NULL; - material->specular_texname = NULL; - material->specular_highlight_texname = NULL; - material->bump_texname = NULL; - material->displacement_texname = NULL; - material->alpha_texname = NULL; - for (i = 0; i < 3; i++) { - material->ambient[i] = 0.f; - material->diffuse[i] = 0.f; - material->specular[i] = 0.f; - material->transmittance[i] = 0.f; - material->emission[i] = 0.f; - } - material->illum = 0; - material->dissolve = 1.f; - material->shininess = 1.f; - material->ior = 1.f; -} - -/* Implementation of string to int hashtable */ +/*********************************************************************************************** + * Group: TINYOBJ hashtable implementation + * String to int hashtable + ***********************************************************************************************/ -#define HASH_TABLE_ERROR 1 -#define HASH_TABLE_SUCCESS 0 +/* Constants: Hash table return codes + * + * TINYOBJ_HASH_TABLE_SUCCESS - Success + * TINYOBJ_HASH_TABLE_ERROR - Failure + */ +#define TINYOBJ_HASH_TABLE_SUCCESS (0) +#define TINYOBJ_HASH_TABLE_ERROR (-1) -#define HASH_TABLE_DEFAULT_SIZE 10 +/* Constant: TINYOBJ_HASH_TABLE_DEFAULT_SIZE + * Default starting size for tinyobj own hash table implementation tables + */ +#define TINYOBJ_HASH_TABLE_DEFAULT_SIZE (10) -typedef struct hash_table_entry_t -{ +#ifndef TINYOBJ_USE_UTHASH +/* Structure: hash_table_entry_t + * + * Entries used in tinyobj's own hash table implementation + * + * Fields: + * + * hash - Hash value + * filled - Is this entry filled + * value - Value + * next - Next entry + */ +typedef struct s_hash_table_entry_t { unsigned long hash; int filled; int pad0; long value; - struct hash_table_entry_t* next; + struct hash_table_entry_t *next; } hash_table_entry_t; -typedef struct -{ - unsigned long* hashes; - hash_table_entry_t* entries; +/* Structure: tinyobj_material_table_t + * + * Hash table used in tinyobj's own hash table implementation + * + * Fields: + * + * hashes - Hashes used + * entries - Linked list of entries in this table + * capacity - Total capacity of this table + * n - Count of elements + */ +typedef struct { + unsigned long *hashes; + hash_table_entry_t *entries; size_t capacity; size_t n; -} hash_table_t; +} tinyobj_material_table_t; + +// Group: TINYOBJ hashtable implementation +// String to int hashtable -static unsigned long hash_djb2(const unsigned char* str) -{ +/* Function: hash_djb2 + * Converts given string to hash + */ +static unsigned long hash_djb2(const unsigned char *str) { unsigned long hash = 5381; int c; @@ -579,37 +1144,61 @@ static unsigned long hash_djb2(const unsigned char* str) return hash; } -static void create_hash_table(size_t start_capacity, hash_table_t* hash_table) -{ - if (start_capacity < 1) - start_capacity = HASH_TABLE_DEFAULT_SIZE; - hash_table->hashes = (unsigned long*) TINYOBJ_MALLOC(start_capacity * sizeof(unsigned long)); - hash_table->entries = (hash_table_entry_t*) TINYOBJ_CALLOC(start_capacity, sizeof(hash_table_entry_t)); +/* Function: create_hash_table + * + * Creates a new hash table in 'hash_table' + * + * Parameters: + * + * start_capacity - Starting capacity, if equal to zero is + * hash_table - [in/out] Table to be initialized + */ +static void create_hash_table(size_t start_capacity, + tinyobj_material_table_t *hash_table) { + if (start_capacity < 1) start_capacity = TINYOBJ_HASH_TABLE_DEFAULT_SIZE; + hash_table->hashes = + (unsigned long *)TINYOBJ_MALLOC(start_capacity * sizeof(unsigned long)); + hash_table->entries = (hash_table_entry_t *)TINYOBJ_CALLOC( + start_capacity, sizeof(hash_table_entry_t)); hash_table->capacity = start_capacity; hash_table->n = 0; } -static void destroy_hash_table(hash_table_t* hash_table) -{ - TINYOBJ_FREE(hash_table->entries); - TINYOBJ_FREE(hash_table->hashes); +/* Function: destroy_hash_table + * Finalizes given hash_table + */ +static void destroy_hash_table(tinyobj_material_table_t *hash_table) { + if (!hash_table) return; + if (hash_table->entries) TINYOBJ_FREE(hash_table->entries); + if (hash_table->hashes) TINYOBJ_FREE(hash_table->hashes); } -/* Insert with quadratic probing */ -static int hash_table_insert_value(unsigned long hash, long value, hash_table_t* hash_table) -{ +/* Function: hash_table_insert_value + * + * Subroutine of + * Inserts given value in hash, uses quadratic probing + * + * Parameters: + * + * hash - Hash to be used + * value - Value of this entity + * hash_table - Table to be used + * + * Returns: + * upon failure or after succeding + */ +static int hash_table_insert_value(unsigned long hash, long value, + tinyobj_material_table_t *hash_table) { /* Insert value */ size_t start_index = hash % hash_table->capacity; size_t index = start_index; - hash_table_entry_t* start_entry = hash_table->entries + start_index; + hash_table_entry_t *start_entry = hash_table->entries + start_index; size_t i; - hash_table_entry_t* entry; + hash_table_entry_t *entry; - for (i = 1; hash_table->entries[index].filled; i++) - { - if (i >= hash_table->capacity) - return HASH_TABLE_ERROR; - index = (start_index + (i * i)) % hash_table->capacity; + for (i = 1; hash_table->entries[index].filled; i++) { + if (i >= hash_table->capacity) return TINYOBJ_HASH_TABLE_ERROR; + index = (start_index + (i * i)) % hash_table->capacity; } entry = hash_table->entries + index; @@ -618,79 +1207,125 @@ static int hash_table_insert_value(unsigned long hash, long value, hash_table_t* entry->value = value; if (index != start_index) { - /* This is a new entry, but not the start entry, hence we need to add a next pointer to our entry */ + /* This is a new entry, but not the start entry, hence we need to add a next + * pointer to our entry */ entry->next = start_entry->next; start_entry->next = entry; } - return HASH_TABLE_SUCCESS; + return TINYOBJ_HASH_TABLE_SUCCESS; } -static int hash_table_insert(unsigned long hash, long value, hash_table_t* hash_table) -{ +/* Function: hash_table_insert + * + * Inserts given value in hash, calls + * + * Parameters: + * + * hash - Hash to be used + * value - Value of this entity + * hash_table - Table to be used + * + * Returns: + * upon failure or after succeding + */ +static int hash_table_insert(unsigned long hash, long value, + tinyobj_material_table_t *hash_table) { int ret = hash_table_insert_value(hash, value, hash_table); - if (ret == HASH_TABLE_SUCCESS) - { + if (ret == TINYOBJ_HASH_TABLE_SUCCESS) { hash_table->hashes[hash_table->n] = hash; hash_table->n++; } return ret; } -static hash_table_entry_t* hash_table_find(unsigned long hash, hash_table_t* hash_table) -{ - hash_table_entry_t* entry = hash_table->entries + (hash % hash_table->capacity); - while (entry) - { - if (entry->hash == hash && entry->filled) - { - return entry; - } +/* Function: hash_table_find + * + * Tries to find given hash in the table + * + * Parameters: + * + * hash - Hash to be found + * hash_table - Table to be used + * + * Returns: + * + * Entry upon succeding or NULL if failure to find + */ +static hash_table_entry_t *hash_table_find( + unsigned long hash, tinyobj_material_table_t *hash_table) { + hash_table_entry_t *entry = + hash_table->entries + (hash % hash_table->capacity); + while (entry) { + if (entry->hash == hash && entry->filled) return entry; entry = entry->next; } return NULL; } -static void hash_table_maybe_grow(size_t new_n, hash_table_t* hash_table) -{ +/* Function: hash_table_maybe_grow + * Grows given hash_table to new_n if new_n is less or equal to capacity + */ +static void hash_table_maybe_grow(size_t new_n, + tinyobj_material_table_t *hash_table) { size_t new_capacity; - hash_table_t new_hash_table; + tinyobj_material_table_t new_hash_table; size_t i; - if (new_n <= hash_table->capacity) { - return; - } - new_capacity = 2 * ((2 * hash_table->capacity) > new_n ? hash_table->capacity : new_n); - /* Create a new hash table. We're not calling create_hash_table because we want to realloc the hash array */ - new_hash_table.hashes = hash_table->hashes = (unsigned long*) TINYOBJ_REALLOC((void*) hash_table->hashes, sizeof(unsigned long) * new_capacity); - new_hash_table.entries = (hash_table_entry_t*) TINYOBJ_CALLOC(new_capacity, sizeof(hash_table_entry_t)); + if (new_n <= hash_table->capacity) return; + new_capacity = + 2 * ((2 * hash_table->capacity) > new_n ? hash_table->capacity : new_n); + /* Create a new hash table. We're not calling create_hash_table because we + * want to realloc the hash array */ + new_hash_table.hashes = hash_table->hashes = (unsigned long *)TINYOBJ_REALLOC( + (void *)hash_table->hashes, sizeof(unsigned long) * new_capacity); + new_hash_table.entries = (hash_table_entry_t *)TINYOBJ_CALLOC( + new_capacity, sizeof(hash_table_entry_t)); new_hash_table.capacity = new_capacity; new_hash_table.n = hash_table->n; /* Rehash */ - for (i = 0; i < hash_table->capacity; i++) - { - hash_table_entry_t* entry = hash_table_find(hash_table->hashes[i], hash_table); - hash_table_insert_value(hash_table->hashes[i], entry->value, &new_hash_table); + for (i = 0; i < hash_table->capacity; i++) { + hash_table_entry_t *entry = + hash_table_find(hash_table->hashes[i], hash_table); + hash_table_insert_value(hash_table->hashes[i], entry->value, + &new_hash_table); } TINYOBJ_FREE(hash_table->entries); (*hash_table) = new_hash_table; } -static int hash_table_exists(const char* name, hash_table_t* hash_table) -{ - return hash_table_find(hash_djb2((const unsigned char*)name), hash_table) != NULL; +/* Function: hash_table_exists + * Tries to find 'name' in hash_table, returns true if successful + * + * See: + * + * - + * - + */ +static int hash_table_exists(const char *name, + tinyobj_material_table_t *hash_table) { + return hash_table_find(hash_djb2((const unsigned char *)name), hash_table) != + NULL; } -static void hash_table_set(const char* name, size_t val, hash_table_t* hash_table) -{ +/* Function: hash_table_set + * Inserts value into hash_table, in name; creates new entry if it doesn't + * exist + * + * See: + * + * - + * - + */ +static void hash_table_set(const char *name, size_t val, + tinyobj_material_table_t *hash_table) { /* Hash name */ unsigned long hash = hash_djb2((const unsigned char *)name); - hash_table_entry_t* entry = hash_table_find(hash, hash_table); - if (entry) - { + hash_table_entry_t *entry = hash_table_find(hash, hash_table); + if (entry) { entry->value = (long)val; return; } @@ -698,850 +1333,1827 @@ static void hash_table_set(const char* name, size_t val, hash_table_t* hash_tabl /* Expand if necessary * Grow until the element has been added */ - do - { + do { hash_table_maybe_grow(hash_table->n + 1, hash_table); - } - while (hash_table_insert(hash, (long)val, hash_table) != HASH_TABLE_SUCCESS); + } while (hash_table_insert(hash, (long)val, hash_table) != + TINYOBJ_HASH_TABLE_SUCCESS); } -static long hash_table_get(const char* name, hash_table_t* hash_table) -{ - hash_table_entry_t* ret = hash_table_find(hash_djb2((const unsigned char*)(name)), hash_table); - return ret->value; +/* Function: hash_table_get + * Returns value of entity with name, -1 when failing + */ +static long hash_table_get(const char *name, + tinyobj_material_table_t *hash_table) { + hash_table_entry_t *ret = + hash_table_find(hash_djb2((const unsigned char *)(name)), hash_table); + return (ret) ? ret->value : -1; } +#else +/*********************************************************************************************** + * Group: UTHash interface to tinyobj + ***********************************************************************************************/ -static tinyobj_material_t *tinyobj_material_add(tinyobj_material_t *prev, - size_t num_materials, - tinyobj_material_t *new_mat) { - tinyobj_material_t *dst; - dst = (tinyobj_material_t *)TINYOBJ_REALLOC( - prev, sizeof(tinyobj_material_t) * (num_materials + 1)); - - dst[num_materials] = (*new_mat); /* Just copy pointer for char* members */ - return dst; -} +/* Sturcture: tinyobj_material_table_tEntry + * + * Material table entry information + * + * Fields: + * + * name - Nul terminated name (key) + * value - Value of this entity + * hh - UTHash handle + */ +typedef struct s_material_table_entry { + char *name; // Nul terminated name (key) + long value; -static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out, - size_t *num_materials_out, - const char *filename, - hash_table_t* material_table) { - tinyobj_material_t material; - size_t buffer_size = 128; - char *linebuf; - FILE *fp; - size_t num_materials = 0; - tinyobj_material_t *materials = NULL; - int has_previous_material = 0; - const char *line_end = NULL; + UT_hash_handle hh; +} tinyobj_material_table_tEntry; - if (materials_out == NULL) { - return TINYOBJ_ERROR_INVALID_PARAMETER; - } +/* Structure: tinyobj_material_table_t + * Material table + */ +typedef struct s_material_table { + tinyobj_material_table_tEntry *head; +} tinyobj_material_table_t; - if (num_materials_out == NULL) { - return TINYOBJ_ERROR_INVALID_PARAMETER; - } +// Group: UTHash interface to tinyobj - (*materials_out) = NULL; - (*num_materials_out) = 0; +/* Constant: tinyobj_reserved + * Reserved key used by the hashtable implementation so the table isn't deleted + */ +const char *tinyobj_reserved = "_RESERVED_KEY_"; - fp = fopen(filename, "r"); - if (!fp) { - fprintf(stderr, "TINYOBJ: Error reading file '%s': %s (%d)\n", filename, strerror(errno), errno); - return TINYOBJ_ERROR_FILE_OPERATION; - } +/* Function: tinyobj_hash_find + * + * Tries to find object with 'name' as key + * + * Parameters: + * + * table - Table to be used + * name - Key + * entryOUT - [out] Result + * + * Returns: + * + * Sets entry to a valid result if entry was found, otherwise sets it to NULL + */ +static void tinyobj_hash_find(tinyobj_material_table_t *table, const char *name, + tinyobj_material_table_tEntry **entryOUT) { + tinyobj_material_table_tEntry *entry = NULL; + if (table) HASH_FIND_STR(table->head, name, entry); + *entryOUT = entry; +} - /* Create a default material */ - initMaterial(&material); +/* Function: tinyobj_hash_add + * + * Adds a material to the given material table + * If the material was already added its value is replaced + * + * Parameters: + * + * table - Table to be used + * name - Key + * length - Name length + * value - Value of the new entity + * + * Returns: + * Returns true if successful, false otherwise + */ +static int tinyobj_hash_add(tinyobj_material_table_t *table, const char *name, + size_t length, long value) { + tinyobj_material_table_tEntry *entry = NULL; - linebuf = (char*)TINYOBJ_MALLOC(buffer_size); - while (NULL != dynamic_fgets(&linebuf, &buffer_size, fp)) { - const char *token = linebuf; + if (!table) return TINYOBJ_HASH_TABLE_ERROR; - line_end = token + strlen(token); + HASH_FIND_STR(table->head, name, entry); + if (entry) { + entry->value = value; + return TINYOBJ_HASH_TABLE_SUCCESS; + } + entry = TINYOBJ_MALLOC(sizeof(*entry)); + if (!entry) return TINYOBJ_HASH_TABLE_ERROR; - /* Skip leading space. */ - token += strspn(token, " \t"); + entry->name = name; + entry->value = value; - assert(token); - if (token[0] == '\0') continue; /* empty line */ + HASH_ADD_KEYPTR(hh, table->head, name, length, entry); + return TINYOBJ_HASH_TABLE_SUCCESS; +} - if (token[0] == '#') continue; /* comment line */ +/* Function: tinyobj_hash_free + * + * Frees all entries of a given tinyobj_material_table_t + * + * Parameters: + * + * table - Table to be freed + * bfree_name - Should the key (name) be freed + * + * Usually the name pointer is owned by the materials list by this point + * + * See , freeing could lead to a segfault + */ +static void tinyobj_hash_free(tinyobj_material_table_t *table, + unsigned char bfree_name) { + tinyobj_material_table_tEntry *entry, *tmp; + if (!table) return; + + HASH_ITER(hh, table->head, entry, tmp) { + HASH_DEL(table->head, entry); + if (entry->name && bfree_name && entry->value != -1) + TINYOBJ_FREE(entry->name); + TINYOBJ_FREE(entry); + } +} - /* new mtl */ - if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { - char namebuf[4096]; - - /* flush previous material. */ - if (has_previous_material) { - materials = tinyobj_material_add(materials, num_materials, &material); - num_materials++; - } else { - has_previous_material = 1; - } +/* Function: tinyobj_hash_init + * Initialises given table, and adds a reserved key + */ +static void tinyobj_hash_init(tinyobj_material_table_t *table) { + table->head = NULL; + tinyobj_hash_add(table, tinyobj_reserved, strlen(tinyobj_reserved), -1); +} - /* initial temporary material */ - initMaterial(&material); +#endif // TINYOBJ_USE_UTHASH +/*********************************************************************************************** + * Group: Material handling (.mtl) + ***********************************************************************************************/ - /* set new mtl name */ - token += 7; -#ifdef _MSC_VER - sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); -#else - sscanf(token, "%s", namebuf); -#endif - material.name = my_strdup(namebuf, (size_t) (line_end - token)); +/* Function: initMaterial + * Defaults given material + */ +static void initMaterial(tinyobj_material_t *material) { + material->name = NULL; + material->ambient_texname = NULL; + material->diffuse_texname = NULL; + material->specular_texname = NULL; + material->specular_highlight_texname = NULL; + material->bump_texname = NULL; + material->displacement_texname = NULL; + material->alpha_texname = NULL; + material->ambient.r = material->ambient.g = material->ambient.b = 0.f; + material->diffuse.r = material->diffuse.g = material->diffuse.b = 0.f; + material->specular.r = material->specular.g = material->specular.b = 0.f; + material->transmittance.r = material->transmittance.g = + material->transmittance.b = 0.f; + material->emission.r = material->emission.g = material->emission.b = 0.f; - /* Add material to material table */ - if (material_table) - hash_table_set(material.name, num_materials, material_table); + material->illum = 0; + material->dissolve = 1.f; + material->shininess = 1.f; + material->ior = 1.f; +} - continue; +/* Function: tinyobj_mtl_parse_map + * + * Parses a texture name from token ('map_') + * > Supported map types: + * > map_Ka - ambient texture + * > map_Kd - diffuse texture + * > map_Ks - specular texture + * > map_Ns - specular highlight texture + * > map_bump - bump texture + * > map_d - alpha texture + * + * Parameters: + * + * material - Material to be filled + * token - Buffer + * line_end - Buffer end (halting point) + * + * Returns: + * - + * - + */ +static int tinyobj_mtl_parse_map(tinyobj_material_t *material, + const char **token, const char *line_end) { + *token += 4; + switch ((*token)[0]) { + case 'K': { + char subtype = (*token)[1]; + if (!IS_SPACE((*token)[2])) return TINYOBJ_ERROR_UNKNOWN_PARAMETER; + *token += 3; + switch (subtype) { + case 'a': // ambient texture + material->ambient_texname = strdup_ml(*token, (line_end - (*token))); + break; + case 'd': // diffuse texture + material->diffuse_texname = strdup_ml(*token, (line_end - (*token))); + break; + case 's': // specular texture + material->specular_texname = strdup_ml(*token, (line_end - (*token))); + break; + default: + return TINYOBJ_ERROR_UNKNOWN_PARAMETER; + } + break; } + case 'N': // specular highlight texture + if ((*token)[1] != 's' || !IS_SPACE((*token)[2])) + return TINYOBJ_ERROR_UNKNOWN_PARAMETER; + *token += 3; + material->specular_highlight_texname = + strdup_ml(*token, (line_end - (*token))); + break; + case 'b': // bump texture + if (strncmp(*token, "bump", 4) && !IS_SPACE((*token)[5])) + return TINYOBJ_ERROR_UNKNOWN_PARAMETER; + *token += 6; + material->bump_texname = strdup_ml(*token, (line_end - (*token))); + break; + case 'd': // alpha texture + if (!IS_SPACE((*token)[1])) return TINYOBJ_ERROR_UNKNOWN_PARAMETER; + *token += 2; + material->alpha_texname = strdup_ml(*token, (line_end - (*token))); + break; + } + return TINYOBJ_SUCCESS; +} - /* ambient */ - if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { - float r, g, b; - token += 2; - parseFloat3(&r, &g, &b, &token); - material.ambient[0] = r; - material.ambient[1] = g; - material.ambient[2] = b; - continue; - } +/* Function: tinyobj_mtl_parse_optical + * + * Parses an optical coefficient from token ('N') + * > Supported coefficient types: + * > Ni - Index Of Refraction (ior) 'optical density' + * > Ns - Specular exponent 'shininess' + * + * Parameters: + * + * material - Material to be filled + * token - Buffer + * + * Returns: + * - + * - + */ +static int tinyobj_mtl_parse_optical(tinyobj_material_t *material, + const char **token) { + char subtype = (*token)[1]; - /* diffuse */ - if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { - float r, g, b; - token += 2; - parseFloat3(&r, &g, &b, &token); - material.diffuse[0] = r; - material.diffuse[1] = g; - material.diffuse[2] = b; - continue; - } + if (!IS_SPACE(((*token)[2]))) return TINYOBJ_ERROR_UNKNOWN_PARAMETER; - /* specular */ - if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { - float r, g, b; - token += 2; - parseFloat3(&r, &g, &b, &token); - material.specular[0] = r; - material.specular[1] = g; - material.specular[2] = b; - continue; - } + *token += 3; + switch (subtype) { + case 'i': // ior (index of refraction) + material->ior = parseFloat(token); + break; + case 's': // shininess + material->shininess = parseFloat(token); + break; + default: + return TINYOBJ_ERROR_UNKNOWN_PARAMETER; + } + return TINYOBJ_SUCCESS; +} - /* transmittance */ - if (token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) { - float r, g, b; - token += 2; - parseFloat3(&r, &g, &b, &token); - material.transmittance[0] = r; - material.transmittance[1] = g; - material.transmittance[2] = b; - continue; - } +/* Function: tinyobj_mtl_parse_color + * + * Parses a color coefficient from token ('K') + * > Supported coefficient types: + * > Ka - Ambient + * > Kd - Diffuse + * > Ks - Specular + * > Kt - Transmittance + * > Ke - Emissive + * + * Parameters: + * + * material - Material to be filled + * token - Buffer + * + * Returns: + * - + * - + */ +static int tinyobj_mtl_parse_color(tinyobj_material_t *material, + const char **token) { + float r, g, b; + char subtype = (*token)[1]; + + if (!IS_SPACE(((*token)[2]))) return TINYOBJ_ERROR_UNKNOWN_PARAMETER; + + *token += 3; + parseFloat3(&r, &g, &b, token); + switch (subtype) { + case 'a': // ambient + material->ambient.r = r; + material->ambient.g = g; + material->ambient.b = b; + break; + case 'd': // diffuse + material->diffuse.r = r; + material->diffuse.g = g; + material->diffuse.b = b; + break; + case 's': // specular + material->specular.r = r; + material->specular.g = g; + material->specular.b = b; + break; + case 't': // transmittance + material->transmittance.r = r; + material->transmittance.g = g; + material->transmittance.b = b; + break; + case 'e': // emission + material->emission.r = r; + material->emission.g = g; + material->emission.b = b; + break; + default: + return TINYOBJ_ERROR_UNKNOWN_PARAMETER; + } + return TINYOBJ_SUCCESS; +} - /* ior(index of refraction) */ - if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { - token += 2; - material.ior = parseFloat(&token); - continue; - } +/* Function: tinyobj_parse_and_index_mtl_file + * + * Parses and indexes a given material file + * + * Parameters: + * + * materials_out - [out] Completed list of materials + * num_materials_out - [out] Length of materials_out + * filename - File to be parsed + * material_table - Table to be filled (can be NULL) + * + * Returns: + * - + * - + * - + * - + */ +static int tinyobj_parse_and_index_mtl_file( + tinyobj_material_t **materials_out, unsigned int *num_materials_out, + const char *filename, tinyobj_material_table_t *material_table) { + int buffer_size = 128; // dynamic_fgets supports only integers as sizes + char *linebuf; + FILE *fp; + tinyobj_material_t *material = NULL; + tinyobj_material_t *material_list = NULL; + size_t material_list_length = 0; + unsigned int material_count = 0; + const char *line_end = NULL; - /* emission */ - if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { - float r, g, b; - token += 2; - parseFloat3(&r, &g, &b, &token); - material.emission[0] = r; - material.emission[1] = g; - material.emission[2] = b; - continue; - } + if (materials_out == NULL || num_materials_out == NULL) + return TINYOBJ_ERROR_INVALID_PARAMETER; - /* shininess */ - if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { - token += 2; - material.shininess = parseFloat(&token); - continue; - } + (*materials_out) = NULL; + (*num_materials_out) = 0; - /* illum model */ - if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) { - token += 6; - material.illum = parseInt(&token); - continue; - } + material_list = + malloc(sizeof(*material_list) * TINYOBJ_MATERIAL_INITIAL_COUNT); + material_list_length = TINYOBJ_MATERIAL_INITIAL_COUNT; + if (!material_list) return TINYOBJ_ERROR_MEMORY; + material = &material_list[0]; + initMaterial(material); - /* dissolve */ - if ((token[0] == 'd' && IS_SPACE(token[1]))) { - token += 1; - material.dissolve = parseFloat(&token); - continue; - } - if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { - token += 2; - /* Invert value of Tr(assume Tr is in range [0, 1]) */ - material.dissolve = 1.0f - parseFloat(&token); - continue; - } + fp = fopen(filename, "r"); + if (!fp) { + free(material_list); + return TINYOBJ_ERROR_FILE_OPERATION; + } - /* ambient texture */ - if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { - token += 7; - material.ambient_texname = my_strdup(token, (size_t) (line_end - token)); - continue; - } + linebuf = TINYOBJ_MALLOC(buffer_size); + while (NULL != dynamic_fgets(&linebuf, &buffer_size, fp)) { + const char *token = linebuf; + int retval = TINYOBJ_ERROR_NOT_SET; + line_end = token + strlen(token); - /* diffuse texture */ - if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { - token += 7; - material.diffuse_texname = my_strdup(token, (size_t) (line_end - token)); - continue; - } + // Skip leading space + token += strspn(token, " \t"); - /* specular texture */ - if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { - token += 7; - material.specular_texname = my_strdup(token, (size_t) (line_end - token)); - continue; - } + assert(token); + if (token[0] == '\0') continue; // Empty line + if (token[0] == '#') continue; // Comment line - /* specular highlight texture */ - if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { + // New material + if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { + char namebuf[4096]; + material_count++; + // Update current material + if (material->name) { + if (material_count == material_list_length) { + tinyobj_material_t *temp; + size_t temp_length; + temp_length = material_list_length * TINYOBJ_MATERIAL_GROWTH_FACTOR; + temp = TINYOBJ_REALLOC(material_list, + sizeof(*material_list) * temp_length); + if (!temp) { + free(material_list); + return TINYOBJ_ERROR_MEMORY; + } + material_list_length = temp_length; + material_list = temp; + } + material = &material_list[material_count]; + } + initMaterial(material); token += 7; - material.specular_highlight_texname = my_strdup(token, (size_t) (line_end - token)); - continue; - } - - /* bump texture */ - if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { - token += 9; - material.bump_texname = my_strdup(token, (size_t) (line_end - token)); - continue; - } - - /* alpha texture */ - if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { - token += 6; - material.alpha_texname = my_strdup(token, (size_t) (line_end - token)); +#ifdef _MSC_VER + sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); +#else + sscanf(token, "%s", namebuf); +#endif + material->name = strdup_ml(namebuf, (line_end - token)); + // Add material to the table + if (material_table) { +#ifndef TINYOBJ_USE_UTHASH + hash_table_set(material->name, material_count, material_table); +#else + tinyobj_hash_add(material_table, material->name, strlen(material->name), + material_count); +#endif // TINYOBJ_USE_UTHASH + } continue; } - /* bump texture */ - if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { - token += 5; - material.bump_texname = my_strdup(token, (size_t) (line_end - token)); - continue; + switch (token[0]) { + case 'K': // Color coefficients + retval = tinyobj_mtl_parse_color(material, &token); + break; + case 'N': // Optical coefficients + retval = tinyobj_mtl_parse_optical(material, &token); + break; + case 'd': // Non-transparency to be alpha 'dissolve' 'd' + // 'disp' Displacement texture + if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { + token += 5; + material->displacement_texname = strdup_ml(token, (line_end - token)); + continue; + } + // Fall-through + case 'T': { // Transparency to be alpha + float tr; + unsigned char type; + + if (!(token[1] == 'r' && IS_SPACE(token[2])) && + !(token[0] == 'd' && IS_SPACE(token[1]))) { + retval = TINYOBJ_ERROR_UNKNOWN_PARAMETER; + break; + } + type = (token[1] == 'r') ? 2 : 1; + token += type; + tr = parseFloat(&token); + if (tr < 0 || tr > 1) { // Must be in range [0, 1] + fprintf(stderr, + "%s: Error reading file '%s': Invalid transparency parameter " + "'%f', expected range [0, 1]\n", + __func__, filename, tr); + return TINYOBJ_ERROR_MALFORMED_PARAMETER; + } + // Invert value of Tr + material->dissolve = (type == 2) ? 1.0f - tr : tr; + continue; + } + case 'm': // texture maps + if (strncmp(token, "map_", 4)) { + retval = TINYOBJ_ERROR_UNKNOWN_PARAMETER; + break; + } + retval = tinyobj_mtl_parse_map(material, &token, line_end); + break; + case 'i': // illum model + if (strncmp(token, "illum", 5) || !IS_SPACE(token[5])) { + retval = TINYOBJ_ERROR_UNKNOWN_PARAMETER; + break; + } + token += 6; + material->illum = parseInt(&token); + continue; + case 'b': + if (strncmp(token, "bump", 4) || !IS_SPACE(token[4])) { + retval = TINYOBJ_ERROR_UNKNOWN_PARAMETER; + break; + } + token += 5; + material->bump_texname = strdup_ml(token, (line_end - token)); + continue; + case ' ': + case '\t': + case '\n': + case '\r': + case '\0': + continue; + default: + retval = TINYOBJ_ERROR_UNKNOWN_PARAMETER; + break; } - - /* displacement texture */ - if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { - token += 5; - material.displacement_texname = my_strdup(token, (size_t) (line_end - token)); - continue; + if (retval == TINYOBJ_ERROR_UNKNOWN_PARAMETER) { + char *command_name = NULL; + size_t length; + length = length_until_space(token, ((line_end - token)) + 1); + command_name = strndup(token, length); + fprintf(stderr, "%s: Unsupported command '%s'\n", __func__, command_name); + TINYOBJ_FREE(command_name); } - - /* @todo { unknown parameter } */ } - if (material.name) { - /* Flush last material element */ - materials = tinyobj_material_add(materials, num_materials, &material); - num_materials++; - } + (*num_materials_out) = material_count; + (*materials_out) = material_list; - (*num_materials_out) = num_materials; - (*materials_out) = materials; - - if (linebuf) { - TINYOBJ_FREE(linebuf); - } + if (linebuf) TINYOBJ_FREE(linebuf); return TINYOBJ_SUCCESS; } +// Group: Aplication Programming Interface (.mtl) + +/* Function: tinyobj_parse_mtl_file + * Parses a material file, see + */ int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, - size_t *num_materials_out, + unsigned int *num_materials_out, const char *filename) { - return tinyobj_parse_and_index_mtl_file(materials_out, num_materials_out, filename, NULL); -} - - -typedef enum { - COMMAND_EMPTY, - COMMAND_V, - COMMAND_VN, - COMMAND_VT, - COMMAND_F, - COMMAND_G, - COMMAND_O, - COMMAND_USEMTL, - COMMAND_MTLLIB - -} CommandType; - -typedef struct { - float vx, vy, vz; - float nx, ny, nz; - float tx, ty; - - /* @todo { Use dynamic array } */ - tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; - size_t num_f; - - int f_num_verts[TINYOBJ_MAX_FACES_PER_F_LINE]; - size_t num_f_num_verts; + int retval = tinyobj_parse_and_index_mtl_file( + materials_out, num_materials_out, filename, NULL); + return retval; +} - const char *group_name; - unsigned int group_name_len; - int pad0; +/* Function: tinyobj_material_free + * + * Frees material data + * + * Parameters: + * + * materials - Material list to be freed + * num_materials - Length of materials + */ +void tinyobj_material_free(tinyobj_material_t *materials, + unsigned int num_materials) { + unsigned int i; + if (!materials || !num_materials) return; - const char *object_name; - unsigned int object_name_len; - int pad1; + for (i = 0; i < num_materials; i++) { + if (materials[i].name) TINYOBJ_FREE(materials[i].name); + if (materials[i].ambient_texname) + TINYOBJ_FREE(materials[i].ambient_texname); + if (materials[i].diffuse_texname) + TINYOBJ_FREE(materials[i].diffuse_texname); + if (materials[i].specular_texname) + TINYOBJ_FREE(materials[i].specular_texname); + if (materials[i].specular_highlight_texname) + TINYOBJ_FREE(materials[i].specular_highlight_texname); + if (materials[i].bump_texname) TINYOBJ_FREE(materials[i].bump_texname); + if (materials[i].displacement_texname) + TINYOBJ_FREE(materials[i].displacement_texname); + if (materials[i].alpha_texname) TINYOBJ_FREE(materials[i].alpha_texname); + } + TINYOBJ_FREE(materials); +} - const char *material_name; - unsigned int material_name_len; - int pad2; +/*********************************************************************************************** + * Group: Object handling (.obj) + ***********************************************************************************************/ - const char *mtllib_name; - unsigned int mtllib_name_len; +/* Enum: CommandType + * + * Command identifiers used when parsing + * + * + * + * COMMAND_EMPTY - No command + * COMMAND_V - 'v' Vertex + * COMMAND_VN - 'vn' Vertex normal + * COMMAND_VT - 'vt' Texture coordinate + * COMMAND_VP - 'vp' Parameter space vertex + * COMMAND_F - 'f' Face + * COMMAND_P - 'p' Point + * COMMAND_L - 'l' Line + * COMMAND_G - 'g' Group name + * COMMAND_O - 'o' Object name + * COMMAND_S - 's' Smoothing group + * COMMAND_USEMTL - 'usemtl' Use material + * COMMAND_MTLLIB - 'mtllib' Load material + */ +typedef enum { + COMMAND_EMPTY, //< No command + // @see tinyobj_obj_parse_vertex + COMMAND_V, //< 'v' Vertex + COMMAND_VN, //< 'vn' Vertex normal + COMMAND_VT, //< 'vt' Texture coordinate + COMMAND_VP, //< 'vp' Parameter space vertex + + COMMAND_F, //< 'f' Face @see tinyobj_obj_parse_face + COMMAND_P, //< 'p' Point @see tinyobj_obj_parse_point + COMMAND_L, //< 'l' Line @see tinyobj_obj_parse_line + + COMMAND_G, //< 'g' Group name + COMMAND_O, //< 'o' Object name + COMMAND_S, //< 's' Smoothing group + COMMAND_USEMTL, //< 'usemtl' Use material + COMMAND_MTLLIB //< 'mtllib' Load material +} CommandType; +/* Structure: Command + * + * Command information used to parse obj files + * + * + * Fields: + * + * type - Command + * info - Specific command information + */ +typedef struct s_tinyobj_command { CommandType type; + /* Structure: Command.u_information + * + * Specific command information + * + * Fields: + * + * v - Geometric vertex + * vn - Vertex normal + * vt - Texture vertex + * vp - Parameter space vertex + * f - Face + * l - Line + * p - Point + * g - Group + * o - Object + * usemtl - Use material + * mtllib - Material lib (file) + * smoothing_id - Smoothing group + * + * See: + * + * + */ + union u_information { + /** + * Vertex Data + **/ + tinyobj_vertex_t v; + tinyobj_vertex_normal_t vn; + tinyobj_vertex_texture_t vt; + tinyobj_vertex_param_t vp; + /** + * Element data + **/ + tinyobj_face_t f; + tinyobj_line_t l; + tinyobj_point_t p; + /* Structure: Command.s_group_information + * + * Grouping and Display/Render attributes + * + * Fields: + * + * Name - Name of group + * len - Group name length + */ + struct s_group_information { + const char *name; //< Name of group + size_t len; //< Group name length + } g, o, usemtl, mtllib; + int smoothing_id; //< 's' Smoothing group + } info; } Command; -static int parseLine(Command *command, const char *p, size_t p_len, - int triangulate) { - char linebuf[4096]; - const char *token; - assert(p_len < 4095); - - memcpy(linebuf, p, p_len); - linebuf[p_len] = '\0'; - - token = linebuf; - - command->type = COMMAND_EMPTY; - - /* Skip leading space. */ - skip_space(&token); - - assert(token); - if (token[0] == '\0') { /* empty line */ - return 0; - } +/* Structure: CommandInformation + * + * General information regarding the commands of a given file + * + * Fields: + * + * command_list - Array of commands + * mtllib_line_index - Index of MLLIB in command list (-1 no command) + * count - command_list count + * counter - Counter of command types + */ +typedef struct s_command_information { + Command *command_list; //< Array of commands + int mtllib_line_index; //< Index of MLLIB in command list (-1 no command) + size_t count; //< Command count + /* Structure: CommandInformation.s_counter + * Counter of command types + * + * Fields: + * + * v - Count of geometric vertices + * vn - Count of vertex normals + * vt - Count of texture vertices + * vp - Count of parameter space vertices + * f - Count of faces + * l - Count of lines + * p - Count of points + * shapes - Shapes + */ + struct s_counter { + size_t v, vn, vt, vp; + size_t f, l, p; + size_t shapes; + } counter; +} CommandInformation; - if (token[0] == '#') { /* comment line */ - return 0; - } +// Group: Object handling (.obj) - /* vertex */ - if (token[0] == 'v' && IS_SPACE((token[1]))) { - float x, y, z; - token += 2; - parseFloat3(&x, &y, &z, &token); - command->vx = x; - command->vy = y; - command->vz = z; - command->type = COMMAND_V; - return 1; - } +/* Function: tinyobj_obj_free_point + * Frees allocated data of a given point + */ +static void tinyobj_obj_free_point(tinyobj_point_t *p) { + if (p) return; + if (p->v_idx) TINYOBJ_FREE(p->v_idx); +} - /* normal */ - if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { - float x, y, z; - token += 3; - parseFloat3(&x, &y, &z, &token); - command->nx = x; - command->ny = y; - command->nz = z; - command->type = COMMAND_VN; - return 1; - } +/* Function: tinyobj_obj_parse_point + * + * Parses a point from token ('p') + * + * Parameters: + * + * command - Command information to be filled + * token - Token to be parsed + * + * Returns: + * + * - + * - + * - + * - + */ +static int tinyobj_obj_parse_point(Command *command, const char **token) { + tinyobj_point_t *p; + if (!IS_SPACE(((*token)[1]))) return TINYOBJ_ERROR_UNKNOWN_PARAMETER; - /* texcoord */ - if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { - float x, y; - token += 3; - parseFloat2(&x, &y, &token); - command->tx = x; - command->ty = y; - command->type = COMMAND_VT; - return 1; + *token += 2; + skip_space(token); + if ((*token)[0] == '#' || !IS_DIGIT(*token[0])) + return TINYOBJ_ERROR_MALFORMED_PARAMETER; + + p = &command->info.p; + p->count = 0; + p->length = TINYOBJ_POINT_INITIAL_COUNT; + p->v_idx = TINYOBJ_MALLOC(sizeof(*p->v_idx) * p->length); + if (!p->v_idx) return TINYOBJ_ERROR_MEMORY; + + command->type = COMMAND_P; + while (!IS_NEW_LINE((*token)[0])) { + if ((*token)[0] == '#') break; + if (p->count == p->length) { + int *tmp; + p->length *= TINYOBJ_POINT_GROWTH_FACTOR; + tmp = TINYOBJ_REALLOC(p->v_idx, sizeof(*p->v_idx) * p->length); + if (tmp) { + p->v_idx = tmp; + continue; + } + TINYOBJ_FREE(p->v_idx); + return TINYOBJ_ERROR_MEMORY; + } + p->v_idx[p->count] = parseInt(token); + p->count++; + skip_space(token); } + return TINYOBJ_SUCCESS; +} - /* face */ - if (token[0] == 'f' && IS_SPACE((token[1]))) { - size_t num_f = 0; - - tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; - token += 2; - skip_space(&token); +/* Function: tinyobj_triplet_list_grow + * + * Grows the given triplet list to a new size + * If the growth fails the list is unchanged + * + * Parameters: + * + * list - List to grow + * new_len - New length + * + * Returns: + * + * True if successful, false otherwise + */ +unsigned char tinyobj_triplet_list_grow(tinyobj_vertex_index_t **list, + size_t new_len) { + tinyobj_vertex_index_t *new_list; - while (!IS_NEW_LINE(token[0])) { - tinyobj_vertex_index_t vi = parseRawTriple(&token); - skip_space_and_cr(&token); + new_list = TINYOBJ_REALLOC(*list, new_len * sizeof(**list)); + if (!new_list) return 0; + *list = new_list; + return 1; +} - f[num_f] = vi; - num_f++; - } +/* Function: tinyobj_triplet_list_new + * + * Allocates memory for a new triplet list + * + * Parameters: + * + * len - Initial length of list + * + * Returns: + * + * Pointer to new list when successful, NULL if failure + */ +static tinyobj_vertex_index_t *tinyobj_triplet_list_new(size_t len) { + return TINYOBJ_MALLOC(sizeof(tinyobj_vertex_index_t) * len); +} - command->type = COMMAND_F; +/* Function: tinyobj_obj_free_line + * Frees allocated data of a given line + */ +static void tinyobj_obj_free_line(tinyobj_line_t *l) { + if (l) return; + if (l->couple_list) TINYOBJ_FREE(l->couple_list); +} - if (triangulate) { - size_t k; - size_t n = 0; +/* Function: tinyuobj_obj_parse_line + * + * Parses a line from token ('l') + * + * Parameters: + * + * command - Command information to be filled + * token - Token to be parsed + * + * Returns: + * + * - + * - + * - + * - + */ +static int tinyobj_obj_parse_line(Command *command, const char **token) { + tinyobj_line_t *l; + if (!IS_SPACE(((*token)[1]))) return TINYOBJ_ERROR_UNKNOWN_PARAMETER; - tinyobj_vertex_index_t i0 = f[0]; - tinyobj_vertex_index_t i1; - tinyobj_vertex_index_t i2 = f[1]; + l = &command->info.l; + l->count = 0; + l->length = TINYOBJ_COUPLE_INITIAL_COUNT; + l->couple_list = TINYOBJ_MALLOC(sizeof(*l->couple_list) * l->length); + if (!l->couple_list) return TINYOBJ_ERROR_MEMORY; - assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE); + command->type = COMMAND_L; - for (k = 2; k < num_f; k++) { - i1 = i2; - i2 = f[k]; - command->f[3 * n + 0] = i0; - command->f[3 * n + 1] = i1; - command->f[3 * n + 2] = i2; + *token += 2; + skip_space(token); - command->f_num_verts[n] = 3; - n++; - } - command->num_f = 3 * n; - command->num_f_num_verts = n; + while (!IS_NEW_LINE((*token)[0])) { + tinyobj_vertex_index_t vi = parseRawTriple(token); + skip_space_and_cr(token); - } else { - size_t k = 0; - assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE); - for (k = 0; k < num_f; k++) { - command->f[k] = f[k]; + if (vi.vn_idx != TINYOBJ_INVALID_INDEX) { // This is a triple not a couple + TINYOBJ_FREE(l->couple_list); + return TINYOBJ_ERROR_MALFORMED_PARAMETER; + } + l->couple_list->v_idx = vi.v_idx; + l->couple_list->vt_idx = vi.vt_idx; + l->count++; + if (l->count == l->length) { + tinyobj_line_t *tmp; + l->length *= TINYOBJ_TRIPLET_GROWTH_FACTOR; + tmp = + TINYOBJ_REALLOC(l->couple_list, sizeof(*l->couple_list) * l->length); + if (tmp) { + l->couple_list = tmp; + continue; } - - command->num_f = num_f; - command->f_num_verts[0] = (int)num_f; - command->num_f_num_verts = 1; + TINYOBJ_FREE(l->couple_list); + return TINYOBJ_ERROR_MALFORMED_PARAMETER; } + } - return 1; + if (l->count < 2) { + // A line must have at least 2 geometric vertices + fprintf(stderr, + "%s: malformed line with %ld geometric vertices (minimum of l)\n", + __func__, l->count); + TINYOBJ_FREE(l->couple_list); + return TINYOBJ_ERROR_MALFORMED_PARAMETER; } + return TINYOBJ_SUCCESS; +} + +/* Function: tinyobj_obj_free_face + * Frees allocated data of a given face + */ +static void tinyobj_obj_free_face(tinyobj_face_t *f) { + if (!f) return; + if (f->triplet_list) TINYOBJ_FREE(f->triplet_list); +} + +/* Function: tinyobj_obj_parse_face + * + * Parses a face from token ('f') and fills given command with face information + * + * Parameters: + * + * command - Command information to be filled + * token - Token to be parsed + * triangulate - (bool) Should this face be triangulated? + * + * Returns: + * + * - + * - + * - + * - + */ +static int tinyobj_obj_parse_face(Command *command, const char **token, + int triangulate) { + tinyobj_face_t *f; + tinyobj_vertex_index_t *temp_triplet_list; + unsigned int triplet_count, triplet_length, triangle_count; + unsigned char last_corner = + 0; // Is the next vertex index the last corner of a face? - /* use mtl */ - if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { - token += 7; + if (!IS_SPACE(((*token)[1]))) return TINYOBJ_ERROR_UNKNOWN_PARAMETER; - skip_space(&token); - command->material_name = p + (token - linebuf); - command->material_name_len = (unsigned int)length_until_newline( - token, (p_len - (size_t)(token - linebuf)) + 1); - command->type = COMMAND_USEMTL; + f = &command->info.f; - return 1; - } + temp_triplet_list = tinyobj_triplet_list_new(TINYOBJ_TRIPLET_INITIAL_COUNT); + triplet_length = TINYOBJ_TRIPLET_INITIAL_COUNT; + triplet_count = 0; + triangle_count = 0; + if (!temp_triplet_list) return TINYOBJ_ERROR_MEMORY; - /* load mtl */ - if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { - /* By specification, `mtllib` should be appear only once in .obj */ - token += 7; + command->type = COMMAND_F; - skip_space(&token); - command->mtllib_name = p + (token - linebuf); - command->mtllib_name_len = (unsigned int)length_until_newline( - token, p_len - (size_t)(token - linebuf)) + - 1; - command->type = COMMAND_MTLLIB; + *token += 2; + skip_space(token); - return 1; + if ((*token)[0] == '#') { // Unexpected comment + TINYOBJ_FREE(temp_triplet_list); + return TINYOBJ_ERROR_MALFORMED_PARAMETER; } - /* group name */ - if (token[0] == 'g' && IS_SPACE((token[1]))) { - /* @todo { multiple group name. } */ - token += 2; - - command->group_name = p + (token - linebuf); - command->group_name_len = (unsigned int)length_until_newline( - token, p_len - (size_t)(token - linebuf)) + - 1; - command->type = COMMAND_G; + while (!IS_NEW_LINE((*token)[0])) { + tinyobj_vertex_index_t vi = parseRawTriple(token); + skip_space_and_cr(token); + if ((*token)[0] == '#') break; + + /** + * When triangulating we parse the vertices as if they were part of + * a triangle fan, so every three indices the next is always the first + * triplet of this face + **/ + if (triangulate && !last_corner && triplet_count > 2) { + if (triplet_count == 3) triangle_count++; // Count first triangle + temp_triplet_list[triplet_count] = temp_triplet_list[0]; + temp_triplet_list[triplet_count + 1] = + temp_triplet_list[triplet_count - 1]; + temp_triplet_list[triplet_count + 2] = vi; + triplet_count += 3; + triangle_count++; + last_corner = 1; + } else { + temp_triplet_list[triplet_count] = vi; + triplet_count++; + last_corner = 0; + } - return 1; + if (triplet_count == triplet_length) { + triplet_length *= TINYOBJ_TRIPLET_GROWTH_FACTOR; + if (tinyobj_triplet_list_grow(&temp_triplet_list, triplet_length)) + continue; + TINYOBJ_FREE(temp_triplet_list); + return TINYOBJ_ERROR_MEMORY; + } } - - /* object name */ - if (token[0] == 'o' && IS_SPACE((token[1]))) { - /* @todo { multiple object name? } */ - token += 2; - - command->object_name = p + (token - linebuf); - command->object_name_len = (unsigned int)length_until_newline( - token, p_len - (size_t)(token - linebuf)) + - 1; - command->type = COMMAND_O; - - return 1; + if (f->count < 3) { + // A face must have at least 3 geometric vertices + fprintf(stderr, + "%s: malformed face with %ld geometric vertices (minimum of 3)\n", + __func__, f->count); + TINYOBJ_FREE(temp_triplet_list); + return TINYOBJ_ERROR_MALFORMED_PARAMETER; } - return 0; + f->triplet_list = temp_triplet_list; + f->count = triplet_count; + f->length = triplet_length; + f->triangle_count = (triangulate) ? triangle_count : 1; + return TINYOBJ_SUCCESS; } -typedef struct { - size_t pos; - size_t len; -} LineInfo; - -static int is_line_ending(const char *p, size_t i, size_t end_i) { - if (p[i] == '\0') return 1; - if (p[i] == '\n') return 1; /* this includes \r\n */ - if (p[i] == '\r') { - if (((i + 1) < end_i) && (p[i + 1] != '\n')) { /* detect only \r case */ - return 1; - } +/* Function: tinyobj_obj_parse_vertex + * + * Parses a vertex from token ('v') + * > v, vn, vt, vp + * + * Parameters: + * + * command - Command information to be filled + * token - Token to be parsed + * + * Returns: + * + * - + * - + * - + * - + */ +static int tinyobj_obj_parse_vertex(Command *command, const char **token) { + float tmp; + unsigned char retval; + char subtype = (*token)[1]; + char type = (IS_SPACE(subtype)) ? 2 : 3; + + if (!IS_SPACE(((*token)[type - 1]))) return TINYOBJ_ERROR_UNKNOWN_PARAMETER; + *token += type; + + switch (subtype) { + case ' ': + case '\t': // Geometric vertex + command->type = COMMAND_V; + parseFloat3(&command->info.v.x, &command->info.v.y, &command->info.v.z, + token); + command->info.v.weight = (try_parse_float(token, &tmp)) ? tmp : 1.0f; + break; + case 'n': // Vertex normal + command->type = COMMAND_VN; + parseFloat3(&command->info.vn.i, &command->info.vn.j, &command->info.vn.k, + token); + break; + case 't': // Texture vertex + command->type = COMMAND_VT; + command->info.vt.u = parseFloat(token); + retval = try_parse_float(token, &tmp); + command->info.vt.v = (retval) ? tmp : 0.0f; + if (retval) + command->info.vt.w = (try_parse_float(token, &tmp)) ? tmp : 0.0f; + break; + case 'p': // Parameter space vertex + command->type = COMMAND_VP; + command->info.vp.u = parseFloat(token); + retval = try_parse_float(token, &tmp); + command->info.vp.v = (retval) ? tmp : 0.0f; + if (retval) + command->info.vp.weight = (try_parse_float(token, &tmp)) ? tmp : 0.0f; + break; + default: + return TINYOBJ_ERROR_UNKNOWN_PARAMETER; } - return 0; + return TINYOBJ_SUCCESS; } -int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, - size_t *num_shapes, tinyobj_material_t **materials_out, - size_t *num_materials_out, const char *buf, size_t len, - unsigned int flags) { - LineInfo *line_infos = NULL; - Command *commands = NULL; - size_t num_lines = 0; - - size_t num_v = 0; - size_t num_vn = 0; - size_t num_vt = 0; - size_t num_f = 0; - size_t num_faces = 0; - - int mtllib_line_index = -1; +/* Function: tinyobj_parse_obj_line + * + * Parses line of an .obj file + * + * Parameters: + * + * command_info - Command information list + * pos - Current position in command information + * p - String containing line + * p_len - Line length + * flags - Reading flags + * + * Returns: + * + * - + * - + * - + * - + */ +static int tinyobj_parse_obj_line(CommandInformation *command_info, int pos, + const char *p, size_t p_len, int flags) { + char linebuf[4096]; + const char *token; + int retval = TINYOBJ_ERROR_NOT_SET; + Command *command = NULL; + assert(p_len < 4095); - tinyobj_material_t *materials = NULL; - size_t num_materials = 0; + memcpy(linebuf, p, p_len); + linebuf[p_len] = '\0'; - hash_table_t material_table; + token = linebuf; + command = &command_info->command_list[pos]; + command->type = COMMAND_EMPTY; - if (len < 1) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (attrib == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (num_shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (buf == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (num_materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + /* Skip leading space. */ + skip_space(&token); - tinyobj_attrib_init(attrib); - /* 1. Find '\n' and create line data. */ - { - size_t i; - size_t end_idx = len; - size_t prev_pos = 0; - size_t line_no = 0; - size_t last_line_ending = 0; - - /* Count # of lines. */ - for (i = 0; i < end_idx; i++) { - if (is_line_ending(buf, i, end_idx)) { - num_lines++; - last_line_ending = i; + assert(token); + if (token[0] == '\0' || token[0] == '\r') + return TINYOBJ_NO_COMMAND; // Empty line + if (token[0] == '#') return TINYOBJ_NO_COMMAND; // Comment line + + /** + * Initial parameter parsing + **/ + switch (token[0]) { + /** + * Vertex data + **/ + case 'v': // v, vt, vn, vp + retval = tinyobj_obj_parse_vertex(command, &token); + break; + /** + * @todo { + * . rational or non-rational forms of curve or surface type: + * basis matrix, Bezier, B-spline, Cardinal, Taylor (cstype) + * . degree (deg) + * . basis matrix (bmat) + * . step size (step) + * } + **/ + /** + * Elements + **/ + case 'f': // Faces + retval = tinyobj_obj_parse_face(command, &token, + flags & TINYOBJ_FLAG_TRIANGULATE); + break; + case 'l': // Lines + retval = tinyobj_obj_parse_line(command, &token); + case 'p': // Points + retval = tinyobj_obj_parse_point(command, &token); + break; + // @todo { curve (curv); 2D curve (curv2); surface (surf) } + /** + * Free-form curve/surface body statements + **/ + /** + * @todo { + * . parameter values (parm) + * . outer trimming loop (trim) + * . inner trimming loop (hole) + * . special curve (scrv) + * . special point (sp) + * . end statement (end) + * } + **/ + /** + * Connectivity between free-form surfaces + **/ + // @todo { connect (con) } + /** + * Grouping + **/ + case 'g': // Group name + /* @todo { multiple group name. } */ + if (!IS_SPACE(token[1])) { + retval = TINYOBJ_ERROR_UNKNOWN_PARAMETER; + break; } - } - /* The last char from the input may not be a line - * ending character so add an extra line if there - * are more characters after the last line ending - * that was found. */ - if (end_idx - last_line_ending > 0) { - num_lines++; - } - - if (num_lines == 0) return TINYOBJ_ERROR_EMPTY; + token += 2; + command->info.g.name = p + (token - linebuf); + command->info.g.len = + length_until_newline_comment_space(token, p_len - (token - linebuf)) + + 1; + command->type = COMMAND_G; + retval = TINYOBJ_SUCCESS; + break; + case 'o': // Object name + /* @todo { multiple object name? } */ + if (!IS_SPACE(token[1])) { + retval = TINYOBJ_ERROR_UNKNOWN_PARAMETER; + break; + } + token += 2; + command->info.o.name = p + (token - linebuf); + command->info.o.len = + length_until_newline_comment_space(token, p_len - (token - linebuf)) + + 1; + command->type = COMMAND_O; + retval = TINYOBJ_SUCCESS; + break; + case 's': // Smoothing group + if (!IS_SPACE(token[1])) { + retval = TINYOBJ_ERROR_UNKNOWN_PARAMETER; + break; + } + token += 2; + command->type = COMMAND_S; + if (IS_DIGIT(token[0])) + command->info.smoothing_id = parseInt(&token); + else + command->info.smoothing_id = (token[1] == 'f') ? 0 : 1; + retval = TINYOBJ_SUCCESS; + break; + // @todo { merging group (mg) } + /** + * Display/Render attributes + **/ + case 'u': // Material name + if (strncmp(token, "usemtl", 6) || !IS_SPACE((token[6]))) { + retval = TINYOBJ_ERROR_UNKNOWN_PARAMETER; + break; + } + token += 7; + skip_space(&token); + command->info.usemtl.name = p + (token - linebuf); + command->info.usemtl.len = length_until_newline_comment_space( + token, (token, (p_len - (token - linebuf)) + 1)); + command->type = COMMAND_USEMTL; + retval = TINYOBJ_SUCCESS; + break; + case 'm': // Material library + if (strncmp(token, "mtllib", 6) || !IS_SPACE((token[6]))) { + retval = TINYOBJ_ERROR_UNKNOWN_PARAMETER; + break; + } + // By specification, `mtllib` should be appear only once in .obj + token += 7; + skip_space(&token); + command->info.mtllib.name = p + (token - linebuf); + command->info.mtllib.len = + length_until_newline_comment_space(token, p_len - (token - linebuf)) + + 1; + command->type = COMMAND_MTLLIB; + retval = TINYOBJ_SUCCESS; + break; + /** + * @todo { + * . bevel interpolation (bevel) + * . color interpolation (c_interp) + * . dissolve interpolation (d_interp) + * . level of detail (lod) + * . shadow casting (shadow_obj) + * . ray tracing (trace_obj) + * . curve approximation technique (ctech) + * . surface approximation technique (stech) + * } + **/ + default: + retval = TINYOBJ_ERROR_UNKNOWN_PARAMETER; + break; + } + if (retval == TINYOBJ_ERROR_UNKNOWN_PARAMETER) { + char *command_name = NULL; + size_t length; + length = length_until_space(token, (p_len - (token - linebuf)) + 1); + command_name = strndup(token, length); + fprintf(stderr, "%s: Unsupported command '%s'\n", __func__, command_name); + TINYOBJ_FREE(command_name); + return retval; + } + // Increment specific counters + switch (command->type) { + case COMMAND_V: + command_info->counter.v++; + break; + case COMMAND_VN: + command_info->counter.vn++; + break; + case COMMAND_VT: + command_info->counter.vt++; + break; + case COMMAND_VP: + command_info->counter.vp++; + break; + case COMMAND_F: + command_info->counter.f++; + break; + case COMMAND_P: + command_info->counter.p += command->info.p.length; + break; + case COMMAND_L: + command_info->counter.l++; + break; - line_infos = (LineInfo *)TINYOBJ_MALLOC(sizeof(LineInfo) * num_lines); + case COMMAND_G: + case COMMAND_O: + command_info->counter.shapes++; + break; + case COMMAND_MTLLIB: + command_info->mtllib_line_index = pos; + break; + default: + break; + } + return retval; +} - /* Fill line infos. */ - for (i = 0; i < end_idx; i++) { - if (is_line_ending(buf, i, end_idx)) { - line_infos[line_no].pos = prev_pos; - line_infos[line_no].len = i - prev_pos; - prev_pos = i + 1; - line_no++; - } +/* Function: tinyobj_parse_obj_line_traverse + * + * Traverses and parses all lines of given buffer + * + * Parameters: + * + * buf - Buffer to be parsed + * len - Buffer length + * command_info - Command information to be filled + * flags - Parsing flags + * + * Returns: + * + * - + * - + * - + */ +static int tinyobj_parse_obj_line_traverse(const char *buf, size_t len, + CommandInformation *command_info, + unsigned int flags) { + size_t i; + unsigned int pos; + size_t end_idx = len; + unsigned int prev_pos = 0; + unsigned int line_no = 0; + size_t last_line_ending = 0; + unsigned int num_lines = 0; + + // Count number of lines + for (i = 0; i < end_idx; i++) { + if (is_line_ending(buf, i, end_idx)) { + num_lines++; + last_line_ending = i; } - if (end_idx - last_line_ending > 0) { - line_infos[line_no].pos = prev_pos; - line_infos[line_no].len = end_idx - 1 - last_line_ending; + } + /** + * The last char from the input may not be a line + * ending character so add an extra line if there + * are more characters after the last line ending + * that was found. + **/ + if (end_idx - last_line_ending > 0) num_lines++; + + if (num_lines == 0) return TINYOBJ_ERROR_EMPTY; + + command_info->command_list = + TINYOBJ_MALLOC(sizeof(*command_info->command_list) * num_lines); + if (!command_info->command_list) return TINYOBJ_ERROR_MEMORY; + command_info->mtllib_line_index = -1; + command_info->count = 0; + memset(&command_info->counter, 0, sizeof(command_info->counter)); + + pos = 0; + for (i = 0; i < end_idx; i++) { + if (is_line_ending(buf, i, end_idx)) { + int ret; + ret = tinyobj_parse_obj_line(command_info, pos, &buf[prev_pos], + i - prev_pos, flags); + + prev_pos = i + 1; + line_no++; + if (ret == TINYOBJ_SUCCESS || ret == TINYOBJ_NO_COMMAND) { + pos++; + assert(pos < num_lines); + command_info->count++; + } else + fprintf(stderr, "%s: Failed to parse line (%d): TINYOBJ ERROR: %d\n", + __func__, line_no, ret); } } + if (end_idx - last_line_ending > 0) { + int ret; + assert(pos < num_lines); + ret = tinyobj_parse_obj_line(command_info, pos, &buf[prev_pos], + end_idx - 1 - last_line_ending, flags); + if (ret == TINYOBJ_SUCCESS) command_info->count++; + } + return TINYOBJ_SUCCESS; +} - commands = (Command *)TINYOBJ_MALLOC(sizeof(Command) * num_lines); - - create_hash_table(HASH_TABLE_DEFAULT_SIZE, &material_table); - - /* 2. parse each line */ - { - size_t i = 0; - for (i = 0; i < num_lines; i++) { - int ret = parseLine(&commands[i], &buf[line_infos[i].pos], - line_infos[i].len, flags & TINYOBJ_FLAG_TRIANGULATE); - if (ret) { - if (commands[i].type == COMMAND_V) { - num_v++; - } else if (commands[i].type == COMMAND_VN) { - num_vn++; - } else if (commands[i].type == COMMAND_VT) { - num_vt++; - } else if (commands[i].type == COMMAND_F) { - num_f += commands[i].num_f; - num_faces += commands[i].num_f_num_verts; - } +/* Function: tinyobj_command_info_free + * Frees given command information + */ +static void tinyobj_command_info_free(CommandInformation *command_info) { + if (!command_info) return; + if (command_info->command_list) TINYOBJ_FREE(command_info->command_list); +} - if (commands[i].type == COMMAND_MTLLIB) { - mtllib_line_index = (int)i; +/* Function: tinyobj_shape_construct + * + * Constructs shape information + * + * Parameters: + * + * shapes - [in/out] Pointer to be filled + * num_shapes - [out] Length of shapes + * command_info - Information used to construct the shapes + */ +static void tinyobj_shape_construct(tinyobj_shape_t **shapes, + unsigned int *num_shapes, + CommandInformation *command_info) { + unsigned int face_count = 0; + + const char *shape_name = NULL; + size_t shape_name_len = 0; + unsigned int shape_idx = 0; + + const char *prev_shape_name = NULL; + size_t prev_shape_name_len = 0; + unsigned int prev_shape_face_offset = 0; + unsigned int prev_face_offset = 0; + tinyobj_shape_t prev_shape = {NULL, 0, 0}; + + Command *command_list = command_info->command_list; + unsigned int i; + + /** + * Allocate array of shapes with maximum possible size(+1 for unnamed + * group/object). + * Actual # of shapes found in .obj is determined later + **/ + (*shapes) = + TINYOBJ_MALLOC(sizeof(**shapes) * (command_info->counter.shapes + 1)); + + for (i = 0; i < command_info->count; i++) { + switch (command_list[i].type) { + case COMMAND_O: + case COMMAND_G: + if (command_list[i].type == COMMAND_O) { + shape_name = command_list[i].info.o.name; + shape_name_len = command_list[i].info.o.len; + } else { + shape_name = command_list[i].info.g.name; + shape_name_len = command_list[i].info.g.len; } - } + if (face_count == 0) { + // 'o' or 'g' appears before any 'f' + prev_shape_name = shape_name; + prev_shape_name_len = shape_name_len; + prev_shape_face_offset = face_count; + prev_face_offset = face_count; + continue; + } + if (shape_idx == 0) { + // 'o' or 'g' after some 'v' lines + (*shapes)[shape_idx].name = + strndup(prev_shape_name, prev_shape_name_len); // may be NULL + (*shapes)[shape_idx].face_offset = prev_shape.face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; + prev_face_offset = face_count; + } else if ((face_count - prev_face_offset) > 0) { + (*shapes)[shape_idx].name = + strndup(prev_shape_name, prev_shape_name_len); + (*shapes)[shape_idx].face_offset = prev_face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; + prev_face_offset = face_count; + } + // Record shape info for succeeding 'o' or 'g' command + prev_shape_name = shape_name; + prev_shape_name_len = shape_name_len; + prev_shape_face_offset = face_count; + continue; + case COMMAND_F: + face_count++; + continue; + default: + continue; } } - /* line_infos are not used anymore. Release memory. */ - if (line_infos) { - TINYOBJ_FREE(line_infos); - } - - /* Load material(if exits) */ - if (mtllib_line_index >= 0 && commands[mtllib_line_index].mtllib_name && - commands[mtllib_line_index].mtllib_name_len > 0) { - char *filename = my_strndup(commands[mtllib_line_index].mtllib_name, - commands[mtllib_line_index].mtllib_name_len); - - int ret = tinyobj_parse_and_index_mtl_file(&materials, &num_materials, filename, &material_table); - - if (ret != TINYOBJ_SUCCESS) { - /* warning. */ - fprintf(stderr, "TINYOBJ: Failed to parse material file '%s': %d\n", filename, ret); + if ((face_count - prev_face_offset) > 0) { + unsigned int length = face_count - prev_shape_face_offset; + if (length > 0) { + (*shapes)[shape_idx].name = strndup(prev_shape_name, prev_shape_name_len); + (*shapes)[shape_idx].face_offset = prev_face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; } + } else { + /** + * Guess no 'v' line occurrence after 'o' or 'g', so discards current + * shape information. + **/ + } + (*num_shapes) = shape_idx; + TINYOBJ_FREE(*shapes); + *shapes = NULL; +} - TINYOBJ_FREE(filename); +/* Function: tinyobj_shape_free + * + * Frees shape data + * + * Parameters: + * + * shapes - Shape information to be freed + * num_shapes - Length of shapes + */ +void tinyobj_shape_free(tinyobj_shape_t *shapes, unsigned int num_shapes) { + unsigned int i; + if (!shapes || !num_shapes) return; + for (i = 0; i < num_shapes; i++) { + if (shapes[i].name) TINYOBJ_FREE(shapes[i].name); } + TINYOBJ_FREE(shapes); +} - /* Construct attributes */ - - { - size_t v_count = 0; - size_t n_count = 0; - size_t t_count = 0; - size_t f_count = 0; - size_t face_count = 0; - int material_id = -1; /* -1 = default unknown material. */ - size_t i = 0; - - attrib->vertices = (float *)TINYOBJ_MALLOC(sizeof(float) * num_v * 3); - attrib->num_vertices = (unsigned int)num_v; - attrib->normals = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vn * 3); - attrib->num_normals = (unsigned int)num_vn; - attrib->texcoords = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vt * 2); - attrib->num_texcoords = (unsigned int)num_vt; - attrib->faces = (tinyobj_vertex_index_t *)TINYOBJ_MALLOC( - sizeof(tinyobj_vertex_index_t) * num_f); - attrib->num_faces = (unsigned int)num_f; - attrib->face_num_verts = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces); - attrib->material_ids = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces); - attrib->num_face_num_verts = (unsigned int)num_faces; - - for (i = 0; i < num_lines; i++) { - if (commands[i].type == COMMAND_EMPTY) { - continue; - } else if (commands[i].type == COMMAND_USEMTL) { - /* @todo - if (commands[t][i].material_name && - commands[t][i].material_name_len > 0) { - std::string material_name(commands[t][i].material_name, - commands[t][i].material_name_len); - - if (material_map.find(material_name) != material_map.end()) { - material_id = material_map[material_name]; - } else { - // Assign invalid material ID - material_id = -1; - } - } - */ - if (commands[i].material_name && - commands[i].material_name_len >0) +/* Function: tinyobj_attrib_construct + * + * Constructs attribute data with given information + * + * Parameters: + * + * attrib - [in/out] Attribute to be filled + * command_info - Information used to fill attrib + * material_table - Material table used (can be NULL) + */ +static void tinyobj_attrib_construct(tinyobj_attrib_t *attrib, + CommandInformation *command_info, + tinyobj_material_table_t *material_table) { + int mtl_material_id = + -1; //< COMMAND_USEMTL material id defaults to -1 'Unknown material' + int smoothing_id = 0; //< Defaults to 0, no group + struct { + unsigned int v, vn, vt, vp; + unsigned int f, /* p,*/ l; + } count; + unsigned int i; + Command *command_list = command_info->command_list; + memset(&count, 0, sizeof(count)); + + attrib->v_count = command_info->counter.v; + attrib->v = (attrib->v_count) + ? TINYOBJ_MALLOC(sizeof(*attrib->v) * attrib->v_count) + : NULL; + + attrib->vn_count = command_info->counter.vn; + attrib->vn = (attrib->vn_count) + ? TINYOBJ_MALLOC(sizeof(*attrib->vn) * attrib->vn_count) + : NULL; + + attrib->vt_count = command_info->counter.vt; + attrib->vt = (attrib->vt_count) + ? TINYOBJ_MALLOC(sizeof(*attrib->vt) * attrib->vt_count) + : NULL; + + attrib->vp_count = command_info->counter.vp; + attrib->vp = (attrib->vp_count) + ? TINYOBJ_MALLOC(sizeof(*attrib->vp) * attrib->vp_count) + : NULL; + + attrib->f_count = command_info->counter.f; + attrib->f = (attrib->f_count) + ? TINYOBJ_MALLOC(sizeof(*attrib->f) * attrib->f_count) + : NULL; + attrib->triangle_count_total = 0; + + attrib->l_count = command_info->counter.l; + attrib->l = (attrib->l_count) + ? TINYOBJ_MALLOC(sizeof(*attrib->l) * attrib->l_count) + : NULL; + + attrib->p.count = 0; + attrib->p.length = command_info->counter.p; + attrib->p.v_idx = + (attrib->p.length) + ? TINYOBJ_MALLOC(sizeof(*attrib->p.v_idx) * attrib->p.length) + : NULL; + + for (i = 0; i < command_info->count; i++) { + switch (command_list[i].type) { + case COMMAND_USEMTL: { + char *material_name_null_term; + if (!command_list[i].info.usemtl.name || + !command_list[i].info.usemtl.len) + continue; + if (!material_table) continue; + material_name_null_term = + TINYOBJ_MALLOC(command_list[i].info.usemtl.len + 1); + memcpy(material_name_null_term, command_list[i].info.usemtl.name, + command_list[i].info.usemtl.len); + material_name_null_term[command_list[i].info.usemtl.len] = '\0'; +#ifndef TINYOBJ_USE_UTHASH + if (hash_table_exists(material_name_null_term, material_table)) + mtl_material_id = + hash_table_get(material_name_null_term, material_table); + else + mtl_material_id = -1; +#else { - /* Create a null terminated string */ - char* material_name_null_term = (char*) TINYOBJ_MALLOC(commands[i].material_name_len + 1); - memcpy((void*) material_name_null_term, (const void*) commands[i].material_name, commands[i].material_name_len); - material_name_null_term[commands[i].material_name_len - 1] = 0; - - if (hash_table_exists(material_name_null_term, &material_table)) - material_id = (int)hash_table_get(material_name_null_term, &material_table); - else - material_id = -1; - - TINYOBJ_FREE(material_name_null_term); + tinyobj_material_table_tEntry *entry = NULL; + tinyobj_hash_find(material_table, material_name_null_term, &entry); + mtl_material_id = (entry) ? entry->value : -1; } - } else if (commands[i].type == COMMAND_V) { - attrib->vertices[3 * v_count + 0] = commands[i].vx; - attrib->vertices[3 * v_count + 1] = commands[i].vy; - attrib->vertices[3 * v_count + 2] = commands[i].vz; - v_count++; - } else if (commands[i].type == COMMAND_VN) { - attrib->normals[3 * n_count + 0] = commands[i].nx; - attrib->normals[3 * n_count + 1] = commands[i].ny; - attrib->normals[3 * n_count + 2] = commands[i].nz; - n_count++; - } else if (commands[i].type == COMMAND_VT) { - attrib->texcoords[2 * t_count + 0] = commands[i].tx; - attrib->texcoords[2 * t_count + 1] = commands[i].ty; - t_count++; - } else if (commands[i].type == COMMAND_F) { - size_t k = 0; - for (k = 0; k < commands[i].num_f; k++) { - tinyobj_vertex_index_t vi = commands[i].f[k]; - int v_idx = fixIndex(vi.v_idx, v_count); - int vn_idx = fixIndex(vi.vn_idx, n_count); - int vt_idx = fixIndex(vi.vt_idx, t_count); - attrib->faces[f_count + k].v_idx = v_idx; - attrib->faces[f_count + k].vn_idx = vn_idx; - attrib->faces[f_count + k].vt_idx = vt_idx; +#endif + if (mtl_material_id < 0) + fprintf(stderr, "%s: USEMTL %s not found in table!\n", __func__, + material_name_null_term); + TINYOBJ_FREE(material_name_null_term); + continue; + } + case COMMAND_S: + smoothing_id = command_list[i].info.smoothing_id; + continue; + case COMMAND_V: + assert(attrib->v != NULL); + memcpy(&attrib->v[count.v], &command_list[i].info.v, + sizeof(*attrib->v)); + count.v++; + continue; + case COMMAND_VN: + assert(attrib->vn != NULL); + memcpy(&attrib->vn[count.vn], &command_list[i].info.vn, + sizeof(*attrib->vn)); + count.vn++; + continue; + case COMMAND_VT: + assert(attrib->vt != NULL); + memcpy(&attrib->vt[count.vt], &command_list[i].info.vt, + sizeof(*attrib->vt)); + count.vt++; + continue; + case COMMAND_VP: + assert(attrib->vp != NULL); + memcpy(&attrib->vp[count.vp], &command_list[i].info.vp, + sizeof(*attrib->vp)); + count.vp++; + continue; + case COMMAND_F: { + unsigned int k = 0; + assert(attrib->f != NULL); + attrib->f[count.f].triangle_count = + command_list[i].info.f.triangle_count; + attrib->f[count.f].triplet_list = command_list[i].info.f.triplet_list; + attrib->f[count.f].count = command_list[i].info.f.count; + attrib->f[count.f].length = command_list[i].info.f.length; + // Fix triplet index + for (k = 0; k < command_list[i].info.f.count; k++) { + tinyobj_vertex_index_t *vi = &command_list[i].info.f.triplet_list[k]; + attrib->f[count.f].triplet_list[k].v_idx = + fixIndex(vi->v_idx, count.v); + attrib->f[count.f].triplet_list[k].vt_idx = + fixIndex(vi->vt_idx, count.vt); + attrib->f[count.f].triplet_list[k].vn_idx = + fixIndex(vi->vn_idx, count.vn); } - - for (k = 0; k < commands[i].num_f_num_verts; k++) { - attrib->material_ids[face_count + k] = material_id; - attrib->face_num_verts[face_count + k] = commands[i].f_num_verts[k]; + attrib->f[count.f].material_id = mtl_material_id; + attrib->f[count.f].smoothing_id = smoothing_id; + count.f++; + attrib->triangle_count_total += command_list[i].info.f.triangle_count; + continue; + } + case COMMAND_P: { + size_t copy_len = command_list[i].info.p.count; + assert(attrib->p.v_idx != NULL); + if (copy_len + attrib->p.count > attrib->p.length) { + fprintf(stderr, "%s: Point count is greater than counter length!\n", + __func__); + continue; } - - f_count += commands[i].num_f; - face_count += commands[i].num_f_num_verts; + memcpy(&attrib->p.v_idx[attrib->p.count], command_list[i].info.p.v_idx, + sizeof(*attrib->p.v_idx) * copy_len); + attrib->p.count += copy_len; + tinyobj_obj_free_point(&command_list[i].info.p); + continue; } - } - } - - /* 5. Construct shape information. */ - { - unsigned int face_count = 0; - size_t i = 0; - size_t n = 0; - size_t shape_idx = 0; - - const char *shape_name = NULL; - unsigned int shape_name_len = 0; - const char *prev_shape_name = NULL; - unsigned int prev_shape_name_len = 0; - unsigned int prev_shape_face_offset = 0; - unsigned int prev_face_offset = 0; - tinyobj_shape_t prev_shape = {NULL, 0, 0}; - - /* Find the number of shapes in .obj */ - for (i = 0; i < num_lines; i++) { - if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) { - n++; + case COMMAND_L: { + unsigned int k = 0; + assert(attrib->l != NULL); + attrib->l[count.l].couple_list = command_list[i].info.l.couple_list; + attrib->l[count.l].count = command_list[i].info.l.count; + attrib->l[count.l].length = command_list[i].info.l.length; + // Fix couple index + for (k = 0; k < command_list[i].info.l.count; k++) { + attrib->l[count.l].couple_list[k].v_idx = + fixIndex(command_list[i].info.l.couple_list[k].v_idx, count.v); + attrib->l[count.l].couple_list[k].vt_idx = + fixIndex(command_list[i].info.l.couple_list[k].vt_idx, count.vt); + } + count.f++; } + default: + case COMMAND_EMPTY: + continue; } + } +} - /* Allocate array of shapes with maximum possible size(+1 for unnamed - * group/object). - * Actual # of shapes found in .obj is determined in the later */ - (*shapes) = (tinyobj_shape_t*)TINYOBJ_MALLOC(sizeof(tinyobj_shape_t) * (n + 1)); +// Group: Aplication Programming Interface (.obj) - for (i = 0; i < num_lines; i++) { - if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) { - if (commands[i].type == COMMAND_O) { - shape_name = commands[i].object_name; - shape_name_len = commands[i].object_name_len; - } else { - shape_name = commands[i].group_name; - shape_name_len = commands[i].group_name_len; - } +/* Function: tinyobj_attrib_free + * Frees attribute data + */ +void tinyobj_attrib_free(tinyobj_attrib_t *attrib) { + unsigned int i; + if (!attrib) return; + if (attrib->v) TINYOBJ_FREE(attrib->v); + if (attrib->vn) TINYOBJ_FREE(attrib->vn); + if (attrib->vt) TINYOBJ_FREE(attrib->vt); + if (attrib->vp) TINYOBJ_FREE(attrib->vp); + if (attrib->f) { + for (i = 0; i < attrib->f_count; i++) tinyobj_obj_free_face(&attrib->f[i]); + } + if (attrib->l) { + for (i = 0; i < attrib->l_count; i++) tinyobj_obj_free_line(&attrib->l[i]); + } + if (attrib->p.v_idx) tinyobj_obj_free_point(&attrib->p); +} - if (face_count == 0) { - /* 'o' or 'g' appears before any 'f' */ - prev_shape_name = shape_name; - prev_shape_name_len = shape_name_len; - prev_shape_face_offset = face_count; - prev_face_offset = face_count; - } else { - if (shape_idx == 0) { - /* 'o' or 'g' after some 'v' lines. */ - (*shapes)[shape_idx].name = my_strndup( - prev_shape_name, prev_shape_name_len); /* may be NULL */ - (*shapes)[shape_idx].face_offset = prev_shape.face_offset; - (*shapes)[shape_idx].length = face_count - prev_face_offset; - shape_idx++; - - prev_face_offset = face_count; - - } else { - if ((face_count - prev_face_offset) > 0) { - (*shapes)[shape_idx].name = - my_strndup(prev_shape_name, prev_shape_name_len); - (*shapes)[shape_idx].face_offset = prev_face_offset; - (*shapes)[shape_idx].length = face_count - prev_face_offset; - shape_idx++; - prev_face_offset = face_count; - } - } +/* Function: tinyobj_attrib_init + * Initializes given attribute information to default values + */ +static void tinyobj_attrib_init(tinyobj_attrib_t *attrib) { + if (!attrib) return; + attrib->f = NULL; + attrib->l = NULL; + attrib->v = NULL; + attrib->vn = NULL; + attrib->vp = NULL; + attrib->vt = NULL; + attrib->p.v_idx = NULL; + attrib->p.count = 0; + attrib->p.length = 0; + + attrib->f_count = 0; + attrib->l_count = 0; + attrib->v_count = 0; + attrib->vn_count = 0; + attrib->vp_count = 0; + attrib->vt_count = 0; + // memset(&attrib, 0, sizeof(*attrib)); +} - /* Record shape info for succeeding 'o' or 'g' command. */ - prev_shape_name = shape_name; - prev_shape_name_len = shape_name_len; - prev_shape_face_offset = face_count; - } - } - if (commands[i].type == COMMAND_F) { - face_count++; - } - } +/* Function: tinyobj_parse_obj + * + * Parses .obj file + * + * Parameters: + * + * attrib - [in/out] Attributes to be filled + * shapes - [in/out] Shapes to be filled + * num_shapes - [in/out] Length of shapes + * materials_out - [in/out] Materials to be filled + * num_materials_out - [in/out] Length of materials + * buf - Buffer to be read + * len - Buffer length + * flags - Parsing flags + * + * Returns: + * + * - + * - + * - + */ +int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, + unsigned int *num_shapes, + tinyobj_material_t **materials_out, + unsigned int *num_materials_out, const char *buf, + size_t len, unsigned int flags) { + CommandInformation command_info; + Command *command_list = NULL; + tinyobj_material_table_t material_table; - if ((face_count - prev_face_offset) > 0) { - size_t length = face_count - prev_shape_face_offset; - if (length > 0) { - (*shapes)[shape_idx].name = - my_strndup(prev_shape_name, prev_shape_name_len); - (*shapes)[shape_idx].face_offset = prev_face_offset; - (*shapes)[shape_idx].length = face_count - prev_face_offset; - shape_idx++; - } - } else { - /* Guess no 'v' line occurrence after 'o' or 'g', so discards current - * shape information. */ - } + tinyobj_material_t *materials = NULL; + unsigned int num_materials = 0; + int ret; + + // Verify if parameters are valid + if (len < 1 || buf == NULL || attrib == NULL || shapes == NULL || + num_shapes == NULL || materials_out == NULL || + num_materials_out == NULL) { + fprintf(stderr, "%s: Failed to parse object, invalid parameters\n", + __func__); + return TINYOBJ_ERROR_INVALID_PARAMETER; + } - (*num_shapes) = shape_idx; + tinyobj_attrib_init(attrib); + // Traverse lines and fill command information + command_info.command_list = NULL; + ret = tinyobj_parse_obj_line_traverse(buf, len, &command_info, flags); + if (ret != TINYOBJ_SUCCESS) { + tinyobj_command_info_free(&command_info); + fprintf(stderr, "%s: Failed to traverse lines for given object: %d\n", + __func__, ret); + return ret; } + command_list = command_info.command_list; +#ifndef TINYOBJ_USE_UTHASH + create_hash_table(TINYOBJ_HASH_TABLE_DEFAULT_SIZE, &material_table); +#else + tinyobj_hash_init(&material_table); +#endif - if (commands) { - TINYOBJ_FREE(commands); + // Load material if 'mtllib' is defined + if (command_info.mtllib_line_index >= 0 && + command_list[command_info.mtllib_line_index].type == COMMAND_MTLLIB && + command_list[command_info.mtllib_line_index].info.mtllib.len > 0) { + char *filename = + strndup(command_list[command_info.mtllib_line_index].info.mtllib.name, + command_list[command_info.mtllib_line_index].info.mtllib.len); + ret = tinyobj_parse_and_index_mtl_file(&materials, &num_materials, filename, + &material_table); + if (ret != TINYOBJ_SUCCESS) { + fprintf(stderr, "%s: Failed to parse material file '%s': '%d'\n", + __func__, filename, ret); + } + TINYOBJ_FREE(filename); } + // Construct attributes + tinyobj_attrib_construct(attrib, &command_info, &material_table); +#ifndef TINYOBJ_USE_UTHASH destroy_hash_table(&material_table); - +#else + tinyobj_hash_free(&material_table, 0); +#endif + + tinyobj_shape_construct(shapes, num_shapes, &command_info); + + tinyobj_command_info_free(&command_info); (*materials_out) = materials; (*num_materials_out) = num_materials; return TINYOBJ_SUCCESS; } -void tinyobj_attrib_init(tinyobj_attrib_t *attrib) { - attrib->vertices = NULL; - attrib->num_vertices = 0; - attrib->normals = NULL; - attrib->num_normals = 0; - attrib->texcoords = NULL; - attrib->num_texcoords = 0; - attrib->faces = NULL; - attrib->num_faces = 0; - attrib->face_num_verts = NULL; - attrib->num_face_num_verts = 0; - attrib->material_ids = NULL; -} +#ifdef TINYOBJ_ENABLE_OLDER_ATTRIBUTE +// Group: Compatibility with older versions (deprecated) -void tinyobj_attrib_free(tinyobj_attrib_t *attrib) { +/* Function: tinyobj_attrib_free_compat + * Frees given attribute + */ +void tinyobj_attrib_free_compat(COMPATtinyobj_attrib_t *attrib) { + if (!attrib) return; if (attrib->vertices) TINYOBJ_FREE(attrib->vertices); if (attrib->normals) TINYOBJ_FREE(attrib->normals); if (attrib->texcoords) TINYOBJ_FREE(attrib->texcoords); @@ -1550,37 +3162,121 @@ void tinyobj_attrib_free(tinyobj_attrib_t *attrib) { if (attrib->material_ids) TINYOBJ_FREE(attrib->material_ids); } -void tinyobj_shapes_free(tinyobj_shape_t *shapes, size_t num_shapes) { - size_t i; - if (shapes == NULL) return; - - for (i = 0; i < num_shapes; i++) { - if (shapes[i].name) TINYOBJ_FREE(shapes[i].name); +/* Function: tinyobj_new2old + * + * Converts new attribute format to the old one + * This expects that the faces were triangulated + * + * Parameters: + * + * attrib - [in] Attribute to be converted + * out_attrib - [out] Attribute to be filled + * + * Returns: + * + * - + * - + * - + */ +int tinyobj_new2old(tinyobj_attrib_t *attrib, + COMPATtinyobj_attrib_t *out_attrib) { + unsigned int i, j, face_pos, l; + + if (!attrib || !out_attrib) return TINYOBJ_ERROR_INVALID_PARAMETER; + + // Initialize old attributes + out_attrib->vertices = NULL; + out_attrib->num_vertices = 0; + out_attrib->normals = NULL; + out_attrib->num_normals = 0; + out_attrib->texcoords = NULL; + out_attrib->num_texcoords = 0; + out_attrib->faces = NULL; + out_attrib->num_faces = 0; + out_attrib->face_num_verts = NULL; + out_attrib->num_face_num_verts = 0; + out_attrib->material_ids = NULL; + + assert(attrib->v_count > 0); + out_attrib->num_vertices = attrib->v_count; + out_attrib->vertices = TINYOBJ_MALLOC(sizeof(*out_attrib->vertices) * + out_attrib->num_vertices * 3); + if (!out_attrib->vertices) return TINYOBJ_ERROR_MEMORY; + for (i = 0, j = 0; i < attrib->v_count; i++, j += 3) { + out_attrib->vertices[j + 0] = attrib->v[i].x; + out_attrib->vertices[j + 1] = attrib->v[i].y; + out_attrib->vertices[j + 2] = attrib->v[i].z; } - TINYOBJ_FREE(shapes); -} - -void tinyobj_materials_free(tinyobj_material_t *materials, - size_t num_materials) { - size_t i; - if (materials == NULL) return; + if (attrib->vn_count) { + out_attrib->num_normals = attrib->vn_count; + out_attrib->normals = TINYOBJ_MALLOC(sizeof(*out_attrib->normals) * + out_attrib->num_normals * 3); + if (!out_attrib->normals) { + tinyobj_attrib_free_compat(out_attrib); + return TINYOBJ_ERROR_MEMORY; + } + for (i = 0, j = 0; i < attrib->vn_count; i++, j += 3) { + out_attrib->normals[j + 0] = attrib->vn[i].i; + out_attrib->normals[j + 1] = attrib->vn[i].j; + out_attrib->normals[j + 2] = attrib->vn[i].k; + } + } + if (attrib->vt_count) { + out_attrib->num_texcoords = attrib->vt_count; + out_attrib->texcoords = TINYOBJ_MALLOC(sizeof(*out_attrib->texcoords) * + out_attrib->num_texcoords * 2); + if (!out_attrib->texcoords) { + tinyobj_attrib_free_compat(out_attrib); + return TINYOBJ_ERROR_MEMORY; + } + for (i = 0, j = 0; i < attrib->vt_count; i++, j += 2) { + out_attrib->texcoords[j + 0] = attrib->vt[i].u; + out_attrib->texcoords[j + 1] = attrib->vt[i].v; + } + } - for (i = 0; i < num_materials; i++) { - if (materials[i].name) TINYOBJ_FREE(materials[i].name); - if (materials[i].ambient_texname) TINYOBJ_FREE(materials[i].ambient_texname); - if (materials[i].diffuse_texname) TINYOBJ_FREE(materials[i].diffuse_texname); - if (materials[i].specular_texname) TINYOBJ_FREE(materials[i].specular_texname); - if (materials[i].specular_highlight_texname) - TINYOBJ_FREE(materials[i].specular_highlight_texname); - if (materials[i].bump_texname) TINYOBJ_FREE(materials[i].bump_texname); - if (materials[i].displacement_texname) - TINYOBJ_FREE(materials[i].displacement_texname); - if (materials[i].alpha_texname) TINYOBJ_FREE(materials[i].alpha_texname); + out_attrib->num_faces = 0; + for (i = 0; i < attrib->f_count; i++) + out_attrib->num_faces += attrib->f[i].count; + out_attrib->faces = + TINYOBJ_MALLOC(sizeof(*out_attrib->faces) * out_attrib->num_faces); + out_attrib->material_ids = + TINYOBJ_MALLOC(sizeof(*out_attrib->material_ids) * attrib->f_count); + out_attrib->num_face_num_verts = attrib->triangle_count_total; + out_attrib->face_num_verts = TINYOBJ_MALLOC( + sizeof(*out_attrib->face_num_verts) * out_attrib->num_face_num_verts); + if (!out_attrib->faces || !out_attrib->face_num_verts || + !out_attrib->material_ids) { + tinyobj_attrib_free_compat(out_attrib); + return TINYOBJ_ERROR_MEMORY; + } + face_pos = 0; + l = 0; + for (i = 0; i < attrib->f_count; i++) { + unsigned int m; + for (j = 0; j < attrib->f[i].count; j++) { + out_attrib->faces[face_pos].v_idx = attrib->f[i].triplet_list[j].v_idx; + out_attrib->faces[face_pos].vn_idx = attrib->f[i].triplet_list[j].vn_idx; + out_attrib->faces[face_pos].vt_idx = attrib->f[i].triplet_list[j].vt_idx; + face_pos++; + } + if (attrib->f[i].count % 3 == 0) { + for (m = 0; m < attrib->f[i].triangle_count; m++) { + out_attrib->face_num_verts[l] = 3; + l++; + } + } else { + out_attrib->face_num_verts[l] = 1; + l++; + } + out_attrib->material_ids[i] = attrib->f[i].material_id; } - TINYOBJ_FREE(materials); + return TINYOBJ_SUCCESS; } -#endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */ +#endif // TINYOBJ_ENABLE_OLDER_ATTRIBUTE + +#endif // TINYOBJ_LOADER_C_IMPLEMENTATION -#endif /* TINOBJ_LOADER_C_H_ */ +#endif // TINOBJ_LOADER_C_H_