commit 81861157ab0c9d6a7c4ecac80ac4104cad05274c Author: Robert Kooima Date: Fri Feb 28 14:33:26 2014 -0600 Move OBJ to a separate repo diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..c256d61 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,7 @@ +Copyright (c) 2006,2013,2014 Robert Kooima + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..92e626b --- /dev/null +++ b/README.md @@ -0,0 +1,279 @@ +# obj + +`obj` loads, manipulates, optimizes, renders, and stores 3D geometry using the Wavefront OBJ file format. The renderer uses the OpenGL 3.2 Core Profile, making it compatible with OpenGL versions 3 and 4, OpenGL ES 2.0, and also commonly-available extended implementations of OpenGL 2.1. + +- [obj.c](obj.c) +- [obj.h](obj.h) + +An OBJ file consists of sets of *materials*, *vertices*, and *surfaces*. A surface consists of sets of *polygons* and *lines* with a reference to a material to be used when rendering them. A polygon is a triplet of references to vertices in the file, and a line is a pair of references to vertices. + +OBJ files are referenced using pointers to type `obj`. The elements within the OBJ are referenced by integer index. These indices work much like a file or socket descriptor. The internal geometry representation is not accessible to the application. All operations on geometry are performed using the API documented here. + +## Compilation + +To use this module, simply link it with your own code. The renderer requires OpenGL. Linux and Windows compilation also requires [GLEW](http://glew.sourceforge.net/)... + + cc -o program program.c obj.c -lGLEW -lGL -lm + +Though OSX's native OpenGL support suffices... + + cc -o program program.c obj.c -framework OpenGL -lm + +If used only to process OBJ files and not to render them, the OpenGL dependency may be eliminated by defining `CONF_NO_GL`. + + cc -o program program.c obj.c -DCONF_NO_GL -lm + +## Quickstart + +These code fragments implement the common case of loading and displaying a model stored in an OBJ file. First, an OBJ pointer is declared. + + obj *O; + +During initialization, an `obj` structure is allocated, the OBJ file and all of its MTL files and texture images are read, and the `obj` pointer is returned. + + O = obj_create("teapot.obj"); + +During rendering: + + obj_render(O); + +When no longer needed, all resources held by the `obj` data structure are released: + + obj_delete(O); + +## The OBJ API + +### Top level + +As we've just seen, the top level API for manipulation OBJ files is as follows: + +- `obj *obj_create(const char *filename)` + + Create a new file object, load the OBJ file named by `filename`, and return a file object. If `filename` is `NULL` then an empty file is returned. + +- `void obj_delete(obj *O)` + + Delete OBJ `O` and release all resources held by it. + +### Rendering + +- `void obj_set_vert_loc(obj *O, int u, int n, int t, int v)` + + Set the vertex attribute locations for the tangent, normal, texture coordinate, and position. These are acquired by calling [`glGetAttribLocation`](http://www.opengl.org/sdk/docs/man/html/glGetAttribLocation.xhtml) with the intended shader program. Pass `-1` for the location of any attribue that the shader does not receive. + + For example, if program object `program` declares `in` varibles named `vTangent`, `vNormal`, `vTexCoord` and `vPosition` then the syntax is: + + obj_set_vert_loc(object, glGetAttribLocation(program, "vTangent"), + glGetAttribLocation(program, "vNormal"), + glGetAttribLocation(program, "vTexCoord"), + glGetAttribLocation(program, "vPosition")); + + +- `void obj_set_prop_loc(obj *O, int ki, int c, int o, int M)` + + Set the uniform location for the color, texture sampler index, or texture transform for material property `ki`. Pass `-1` for the location of any uniform that the shader does not receive. The value of `ki` must be one of the following: + + + + + + + + +
OBJ_KDDiffuse color
OBJ_KAAmbient color
OBJ_KEEmissive color
OBJ_KSSpecular color
OBJ_NSSpecular exponent
OBJ_KNNormal
+ + For example, if program object `program` declares diffuse and normal samplers named `DiffuseTexture` and `NormalTexture`, but no colors, transforms, or other material properties, then the syntax is: + + obj_set_prop_loc(object, OBJ_KD, -1, glGetUniformLocation(program, "DiffuseTexture"), -1); + obj_set_prop_loc(object, OBJ_KN, -1, glGetUniformLocation(program, "NormalTexture"), -1); + + The material color will be set using `glUniform4fv`, the sampler index with `glUniform1i`, and the texture transform with `glUniformMatrix4fv`. + +- `void obj_render(obj *O)` + + Render OBJ `O`. The polygons and lines of all surfaces are rendered using their assigned materials. Aside from materials and textures, no OpenGL state is modified. In particular, any bound vertex and fragment shaders execute as expected. + +### Element Creation + +- `int obj_add_mtrl(obj *O)` + + Add a new material to OBJ `O`, returning a material index. The new material is initialized with a diffuse color of (0.8, 0.8, 0.8, 1.0), an ambient color of (0.2, 0.2, 0.2, 1.0), an emissive color of (0.0, 0.0, 0.0, 0.0), a specular color of (0.0, 0.0, 0.0, 0.0), and a specular exponent of 8.0. + +- `int obj_add_vert(obj *O)` + + Add a new vertex to OBJ `O`, returning a vertex index. The new vertex position, normal, and texture coordinate are initialized to zero. + +- `int obj_add_surf(obj *O)` + + Add a new surface to OBJ `O`, returning a surface index. The new surface is initialized to reference material index zero. If no materials are defined when this surface is rendered, the default material is applied. + +- `int obj_add_poly(obj *O, int si)` + + Add a new 3-sided polygon to surface `si` of OBJ `O`, returning a polygon index. The new polygon's vertex indices are initialized to zero. + +- `int obj_add_line(obj *O, int si)` + + Add a new line to surface `si` of OBJ `O`, returning a line index. The new line's vertex indices are initialized to zero. + +### Element Counters + +- `int obj_num_mtrl(const obj *O)` +- `int obj_num_vert(const obj *O)` +- `int obj_num_surf(const obj *O)` + + Return the number of materials, vertices, and surfaces contained by OBJ `O`. All indices less than this number are valid indices into that file. + +- `int obj_num_poly(const obj *O, int si)` +- `int obj_num_line(const obj *O, int si)` + + Return the number of polygons and lines contained by surface `si` of OBJ `O`. All indices less than this number are valid indices into that surface. + +### Element deletion + +Note: The element deletion API goes to great lengths to ensure that all geometry blocks are free of gaps, and that all internal references are consistent. If an application removes an element from the middle of a block then all higher-index elements are shifted down, and any references to these elements are decremented. Be aware: if an application caches element indices elsewhere, then these indices may be invalidated by a deletion operation. + +- `void obj_del_mtrl(obj *O, int mi)` + + Remove material `mi` from OBJ `O`. Any surfaces in OBJ `O` that reference this material will also be removed. All higher-indexed materials are shifted down. Surfaces that refer to higher-indexed materials have their material indices decremented. + +- `void obj_del_vert(obj *O, int vi)` + + Remove vertex `vi` from OBJ `O`. Any polygons or lines referencing this vertex in any surface of OBJ `O` are also removed. Higher-indexed vertices are shifted down. Polygons and lines that refer to higher-index vertices have their vertex indices decremented. + +- `void obj_del_poly(obj *O, int si, int pi)` + + Remove polygon `pi` from surface `si` of OBJ `O`. Higher-indexed polygons are shifted down. Vertices referenced by polygon `pi` are *not* removed, as they may be refered-to by other polygons or lines. + +- `void obj_del_line(obj *O, int si, int li)` + + Remove line `li` from surface `si` of OBJ `O`. Higher-indexed lines are shifted down. Vertices referenced by line `li` are *not* removed, as they may be refered-to by other polygons or lines. + +- `void obj_del_surf(obj *O, int si)` + + Remove surface `si` from OBJ `O`. All polygons and lines contained in this surface are also removed. Vertices in OBJ `O` referenced by these polygons and lines are *not* removed. Higher-indexed surfaces are shifted down. + +### Entity Manipulators + +- `void obj_set_mtrl_name(obj *O, int mi, const char *name)` + + Set the name of material `mi` in OBJ `O`. This name is the means by which materials defined in an MTL file are referenced from within an OBJ file. Materials without assigned names are referenced as "default." If materials are not assigned unique names, then then the surface-material mapping is not guaranteed to be preserved when a file is written. + +- `void obj_set_mtrl_map(obj *O, int mi, int ki, const char *image)` + + Set the image map to be used for diffuse color, ambient color, emissive color, specular color, specular exponent, or normal map of material `mi` of OBJ `O`. As of this writing, the file must be given in Targa (`.TGA`) 24-bit or 32-bit format. + +- `void obj_set_mtrl_opt(obj *O, int mi, int ki, unsigned int opt)` + + Set the options on property `ki` of material `mi` in OBJ `O`. + +The `opt` argument gives a bitmap of options to be enabled. The following options are defined. Yeah, there's only one right now. + + + +
OBJ_OPT_CLAMPClamp the property map. Default is to repeat.
+ +- `void obj_set_mtrl_c(obj *O, int mi, int ki, const float c[4])` + + Set the diffuse color, ambient color, emissive color, specular color, or specular exponent of material `mi` of OBJ `O`. The `ki` argument selects the property to be set. Note that the MTL file format supports RGBA diffuse color, but only RGB ambient, and specular colors. So while ambient and specular alpha values will be rendered normally, they cannot be stored in an MTL file, and will always default to 1.0 when a material is loaded. The specular exponent is stored and applied as a scalar. + +- `void obj_set_mtrl_o(obj *O, int mi, int ki, const float o[3])` + + Set the texture coordinate offset for property map `ki` of material `mi` in OBJ `O`. + +- `void obj_set_mtrl_s(obj *O, int mi, int ki, const float s[3])` + + Set the texture coordinate scale for property map `ki` of material `mi` in OBJ `O`. + +- `void obj_set_vert_v(obj *O, int vi, const float *v)` +- `void obj_set_vert_t(obj *O, int vi, const float *t)` +- `void obj_set_vert_n(obj *O, int vi, const float *n)` + + Set the 3D position, 2D texture coordinate, or 3D normal vector of vertex `vi` of file fi. + +- `void obj_set_poly(obj *O, int si, int pi, const int *vi)` + + Set the triplet of vertex indices defining polygon `pi` in surface `si` of OBJ `O`. + +- `void obj_set_line(obj *O, int si, int li, const int *vi)` + + Set the pair of vertex indices defining line `li` in surface `si` of OBJ `O`. + +- `void obj_set_surf(obj *O, int si, int mi)` + + Set the material index of surface `si` of OBJ `O` + +### Entity Query + +- `const char *obj_get_mtrl_name(const obj *O, int mi)` + + Return the name of material `mi` of OBJ `O`. + +- `unsigned int obj_get_mtrl_map(const obj *O, int mi, int ki)` + + Return the property map `ki` of material `mi` of OBJ `O`. The returned value is an OpenGL texture object that may be manipulated normally using the OpenGL API. + +- `unsigned int obj_get_mtrl_opt(const obj *O, int mi, int ki)` + + Return the bitmap of options set on the property map `ki` of material `mi` of OBJ `O`. + +- `void obj_get_mtrl_c(const obj *O, int mi, int ki, float *c)` + + Return the RGBA color of property `ki` of material `mi` in OBJ `O`. + +- `void obj_get_mtrl_o(const obj *O, int mi, int ki, float *o)` + + Return the 3D texture coordinate offset of property map `ki` of material `mi` in OBJ `O`. (This value *is* 3D despite the texture coordinates being 2D.) + +- `void obj_get_mtrl_s(const obj *O, int mi, int ki, float *s)` + + Return the 3D texture coordinate scale of property map `ki` of material `mi` in OBJ `O`. (This value *is* 3D despite the texture coordinates being 2D.) + +- `void obj_get_vert_v(const obj *O, int vi, float *v)` +- `void obj_get_vert_t(const obj *O, int vi, float *t)` +- `void obj_get_vert_n(const obj *O, int vi, float *n)` + + Return the 3D position, 2D texture coordinate, or 3D normal vector of vertex `vi` of OBJ `O`. + +- `void obj_get_poly(const obj *O, int si, int pi, int *vi)` + + Return the triplet of indices defining polygon `pi` in surface `si` of OBJ `O`. + +- `void obj_get_line(const obj *O, int si, int li, int *vi)` + + Return the pair of indices defining line `li` in surface `si` of OBJ `O`. + +- `int obj_get_surf(const obj *O, int si)` + + Return the material index of surface `si` of OBJ `O`. + +### OBJ I/O + +#### Processing + +- `void obj_proc(obj *O)` + + Process OBJ `O` for rendering. All normal vectors are normalized and a tangent vector is computed for each vertex using its normal vector and texture coordinate. Surfaces are sorted in order of increasing transparency in order to correct blending order. + +- `float obj_acmr(obj *O, int qc)` + + Compute the *average cache miss ratio* (ACMR) for OBJ `O` using a cache size of `qc`. The ACMR gives a measure of the effective geometry complexity of a model. It is the average number of vertices processed per triangle, taking into account post-transform vertex caching. In the worst case scenario, an unoptimized model will have an ACMR of 3. A well-optimized, well-behaved model can have an ACMR as low as 0.5, though in practice, any value less than one is excellent. + +- `void obj_sort(obj *O, int qc)` + + Sort the triangles of OBJ `O` in an attempt to reduce the model's average cache miss ratio, as rendered using a vertex cache of size `qc`. A sorted model may be written to a file and will remain optimized when subsequently read. + +Proper selection of `qc` is crucial. Overestimating the cache size will result in bad performance. It is safe to assume a cache size of 16. Recent video hardware provides cache sizes up to 32. Average-case analysis indicates that future video hardware is unlikely to increase cache size far beyond 32. + +Optimal sorting is NP-complete. This implementation is fast (linear in the number of triangles) but not optimal. There is no guarantee that a sorted model will have a lower ACMR than the original unsorted model. Paranoid applications should confirm that sorting reduces the ACMR and reload the model if it does not. + +#### Exporting + +- `void obj_write(obj *O, const char *obj, const char *mtl, int prec)` + + Write all geometry of OBJ `O` to a file named by `obj`. Write all materials of OBJ `O` to a file named by `mtl`. If either file name argument is `NULL` then the corresponding file is not written. The `prec` argument gives the number of digits of precision to write for each floating point value. This can have a significant impact on the resulting file size. + +Note: if geometry is read from one file and written to another then there is no guarantee that the source and destination files are identical. Shared normals and texture coordinates are duplicated per vertex. The number of position, normal, and texture coordinate specifications equal the number of vertices in the file. + +All face specifications are of the form "`f i/i/i j/j/j k/k/k`" for some vertex indices `i`, `j`, `k`. All line specifications are of the form "`l i/i j/j`" for some vertex indices `i`, `j`. All vertex indices are positive, counting from the beginning of the file. + +Any groups specified in the source OBJ are discarded, and the output OBJ is organized by material. Unused specifications in OBJ and MTL files (curves, merging groups, etc) are omitted. Smoothing groups are omitted, and the smoothed normals for each vertex are inserted instead. All comments are stripped. diff --git a/etc/Chest-diffuse.tga b/etc/Chest-diffuse.tga new file mode 100644 index 0000000..f621b54 Binary files /dev/null and b/etc/Chest-diffuse.tga differ diff --git a/etc/Chest-normal.tga b/etc/Chest-normal.tga new file mode 100644 index 0000000..9c99c1b Binary files /dev/null and b/etc/Chest-normal.tga differ diff --git a/etc/Chest-specular.tga b/etc/Chest-specular.tga new file mode 100644 index 0000000..ac029bd Binary files /dev/null and b/etc/Chest-specular.tga differ diff --git a/etc/Chest.mtl b/etc/Chest.mtl new file mode 100644 index 0000000..bb77ca4 --- /dev/null +++ b/etc/Chest.mtl @@ -0,0 +1,13 @@ +# Exported from Wings 3D 1.5.1 +newmtl Chest +Ns 100.0 +d 1.0 +illum 2 +Kd 1.0 1.0 1.0 +Ka 1.0 1.0 1.0 +Ks 1.0 1.0 1.0 +Ke 0.0 0.0 0.0 +map_Kd Chest-diffuse.tga +map_Ks Chest-specular.tga +map_Kn Chest-normal.tga + diff --git a/etc/Chest.obj b/etc/Chest.obj new file mode 100644 index 0000000..2f141bb --- /dev/null +++ b/etc/Chest.obj @@ -0,0 +1,2698 @@ +# Exported from Wings 3D 1.5.1 +mtllib Chest.mtl +o chest +#417 vertices, 400 faces +v -0.59672950 -0.50300957 0.34896430 +v -0.66477504 1.2599554e-2 0.42411932 +v 0.66477504 1.2599554e-2 0.42411932 +v 0.59672950 -0.50300957 0.34896430 +v -0.59672950 -0.50300957 -0.34896430 +v -0.66477504 1.2599554e-2 -0.42411932 +v 0.66477504 1.2599554e-2 -0.42411932 +v 0.59672950 -0.50300957 -0.34896430 +v -0.66477469 0.21626485 0.40902068 +v 0.66477469 0.21626485 0.40902068 +v 0.66477469 0.21626485 -0.40902068 +v -0.66477469 0.21626485 -0.40902068 +v -0.66477469 0.39248482 0.28876860 +v 0.66477469 0.39248482 0.28876860 +v 0.66477469 0.39248482 -0.28876860 +v -0.66477469 0.39248482 -0.28876860 +v -0.66477469 0.48513303 0.0000000e+0 +v 0.66477469 0.48513303 0.0000000e+0 +v -0.43863596 -0.50300957 0.34896430 +v 0.43863596 -0.50300957 0.34896430 +v -0.48865367 1.2599554e-2 0.42411932 +v 0.48865397 1.2599554e-2 0.42411932 +v -0.43863596 -0.50300957 -0.34896430 +v 0.43863596 -0.50300957 -0.34896430 +v -0.48865397 1.2599554e-2 -0.42411932 +v 0.48865397 1.2599554e-2 -0.42411932 +v 0.48865367 0.21626485 0.40902068 +v -0.48865367 0.21626485 0.40902068 +v -0.48865367 0.21626485 -0.40902068 +v 0.48865367 0.21626485 -0.40902068 +v 0.48865367 0.39248482 0.28876860 +v -0.48865367 0.39248482 0.28876860 +v -0.48865367 0.39248482 -0.28876860 +v 0.48865367 0.39248482 -0.28876860 +v -0.48865367 0.48513303 0.0000000e+0 +v 0.48865367 0.48513303 0.0000000e+0 +v -0.61736998 -0.34660813 0.37176132 +v -0.65399209 -6.9107305e-2 0.41220976 +v 0.65399209 -6.9107305e-2 0.41220976 +v 0.61736998 -0.34660813 0.37176132 +v -0.61736998 -0.34660813 -0.37176132 +v -0.65399209 -6.9107305e-2 -0.41220976 +v 0.65399209 -6.9107305e-2 -0.41220976 +v 0.61736998 -0.34660813 -0.37176132 +v -0.48072779 -6.9107305e-2 0.41220976 +v -0.45380809 -0.34660813 0.37176132 +v 0.48072779 -6.9107305e-2 0.41220976 +v 0.45380809 -0.34660813 0.37176132 +v -0.45380809 -0.34660813 -0.37176132 +v -0.48072779 -6.9107305e-2 -0.41220976 +v 0.45380809 -0.34660813 -0.37176132 +v 0.48072779 -6.9107305e-2 -0.41220976 +v -8.7843696e-2 1.2599554e-2 0.42411932 +v 8.7843696e-2 1.2599554e-2 0.42411932 +v -8.7843696e-2 1.2599554e-2 -0.42411932 +v 8.7843696e-2 1.2599554e-2 -0.42411932 +v 9.1216894e-2 0.21626485 0.40902068 +v -9.1216894e-2 0.21626485 0.40902068 +v -9.1216894e-2 0.21626485 -0.40902068 +v 9.1216894e-2 0.21626485 -0.40902068 +v 9.1216894e-2 0.39248482 0.28876860 +v -9.1216894e-2 0.39248482 0.28876860 +v -9.1216894e-2 0.39248482 -0.28876860 +v 9.1216894e-2 0.39248482 -0.28876860 +v -9.1216894e-2 0.48513303 0.0000000e+0 +v 9.1216894e-2 0.48513303 0.0000000e+0 +v -0.66477469 0.11443220 0.41657000 +v 0.66477469 0.11443220 0.41657000 +v 0.66477469 0.11443220 -0.41657000 +v -0.66477469 0.11443220 -0.41657000 +v 0.48865367 0.11443220 0.41657000 +v -0.48865367 0.11443220 0.41657000 +v -0.48865367 0.11443220 -0.41657000 +v 0.48865367 0.11443220 -0.41657000 +v -8.9530295e-2 0.11443220 0.41657000 +v 8.9530295e-2 0.11443220 0.41657000 +v -8.9530295e-2 0.11443220 -0.41657000 +v 8.9530295e-2 0.11443220 -0.41657000 +v -0.66477500 0.10031705 -0.26512296 +v -0.66477500 0.10031705 0.26512296 +v -0.66477470 0.18693846 0.25547502 +v -0.66477472 0.29239022 0.17743004 +v -0.66477473 0.34389921 0.0000000e+0 +v -0.66477472 0.29239022 -0.17743004 +v -0.66477470 0.18693846 -0.25547502 +v 0.66477500 0.10031705 0.26512296 +v 0.66477500 0.10031705 -0.26512296 +v 0.66477470 0.18693846 -0.25547502 +v 0.66477472 0.29239022 -0.17743004 +v 0.66477473 0.34389921 0.0000000e+0 +v 0.66477472 0.29239022 0.17743004 +v 0.66477470 0.18693846 0.25547502 +v -0.59672950 -0.50300957 0.19708315 +v -0.59672950 -0.50300957 -0.19708315 +v -0.66477504 1.2599554e-2 0.27034779 +v -0.66477504 1.2599554e-2 -0.27034779 +v 0.66477504 1.2599554e-2 0.27034779 +v 0.66477504 1.2599554e-2 -0.27034779 +v 0.59672950 -0.50300957 0.19708315 +v 0.59672950 -0.50300957 -0.19708315 +v -0.43863596 -0.50300957 0.19708315 +v -0.43863596 -0.50300957 -0.19708315 +v 0.43863596 -0.50300957 0.19708315 +v 0.43863596 -0.50300957 -0.19708315 +v 0.65399209 -6.9107305e-2 -0.26275624 +v 0.65399209 -6.9107305e-2 0.26275624 +v 0.61736998 -0.34660813 -0.20995813 +v 0.61736998 -0.34660813 0.20995813 +v -0.61736998 -0.34660813 -0.20995813 +v -0.61736998 -0.34660813 0.20995813 +v -0.65399209 -6.9107305e-2 -0.26275624 +v -0.65399209 -6.9107305e-2 0.26275624 +v -0.62149891 -6.4819142e-2 -0.26275624 +v -0.58487680 -0.34231997 -0.20995813 +v -0.58487680 -0.34231997 0.20995813 +v -0.62149891 -6.4819142e-2 0.26275624 +v 0.58487680 -0.34231997 -0.20995813 +v 0.62149891 -6.4819142e-2 -0.26275624 +v 0.62149891 -6.4819142e-2 0.26275624 +v 0.58487680 -0.34231997 0.20995813 +v -0.43863596 -0.47023465 -0.19708315 +v 0.43863596 -0.47023465 -0.19708315 +v 0.43863596 -0.47023465 0.19708315 +v -0.43863596 -0.47023465 0.19708315 +v 0.63200009 0.10031701 0.26512296 +v 0.63200009 0.10031701 -0.26512296 +v 0.63199979 0.18693841 -0.25547502 +v 0.63199981 0.29239018 -0.17743004 +v 0.63199982 0.34389916 0.0000000e+0 +v 0.63199981 0.29239018 0.17743004 +v 0.63199979 0.18693841 0.25547502 +v -0.63200009 0.10031701 -0.26512296 +v -0.63200009 0.10031701 0.26512296 +v -0.63199979 0.18693841 0.25547502 +v -0.63199981 0.29239018 0.17743004 +v -0.63199982 0.34389916 0.0000000e+0 +v -0.63199981 0.29239018 -0.17743004 +v -0.63199979 0.18693841 -0.25547502 +v -0.45380809 -0.34188083 -0.33932912 +v -0.48072779 -6.4379998e-2 -0.37977756 +v 0.48072779 -6.4379998e-2 -0.37977756 +v 0.45380809 -0.34188083 -0.33932912 +v -0.48072779 -6.4379998e-2 0.37977756 +v -0.45380809 -0.34188083 0.33932912 +v 0.45380809 -0.34188083 0.33932912 +v 0.48072779 -6.4379998e-2 0.37977756 +v -0.48865367 0.20506246 0.37698631 +v -0.48865367 0.20506246 -0.37698631 +v -0.48865367 0.36471492 0.26803986 +v -0.48865367 0.36471492 -0.26803986 +v -0.48865367 0.45071254 0.0000000e+0 +v -9.1216894e-2 0.20506246 0.37698631 +v -9.1216894e-2 0.20506246 -0.37698631 +v -9.1216894e-2 0.36471492 0.26803986 +v -9.1216894e-2 0.36471492 -0.26803986 +v -9.1216894e-2 0.45071254 0.0000000e+0 +v -0.48865367 0.11200910 0.38388478 +v -8.9530295e-2 0.11200910 0.38388478 +v -8.9530295e-2 0.11200910 -0.38388478 +v -0.48865367 0.11200910 -0.38388478 +v 0.48865367 0.20506246 0.37698631 +v 0.48865367 0.20506246 -0.37698631 +v 0.48865367 0.36471492 0.26803986 +v 0.48865367 0.36471492 -0.26803986 +v 0.48865367 0.45071254 0.0000000e+0 +v 9.1216894e-2 0.20506246 0.37698631 +v 9.1216894e-2 0.20506246 -0.37698631 +v 9.1216894e-2 0.36471492 0.26803986 +v 9.1216894e-2 0.36471492 -0.26803986 +v 9.1216894e-2 0.45071254 0.0000000e+0 +v 8.9530295e-2 0.11200910 0.38388478 +v 0.48865367 0.11200910 0.38388478 +v 0.48865367 0.11200910 -0.38388478 +v 8.9530295e-2 0.11200910 -0.38388478 +v -0.66477500 0.10031705 0.0000000e+0 +v 0.66477500 0.10031705 0.0000000e+0 +v -0.59672950 -0.50300957 0.0000000e+0 +v -0.66477504 1.2599554e-2 0.0000000e+0 +v 0.66477504 1.2599554e-2 0.0000000e+0 +v 0.59672950 -0.50300957 0.0000000e+0 +v -0.43863596 -0.50300957 0.0000000e+0 +v 0.43863596 -0.50300957 0.0000000e+0 +v 0.65399209 -6.9107305e-2 0.0000000e+0 +v 0.61736998 -0.34660813 -2.7538083e-17 +v -0.61736998 -0.34660813 -2.7538083e-17 +v -0.65399209 -6.9107305e-2 0.0000000e+0 +v -0.58487680 -0.34231997 -2.7538083e-17 +v -0.62149891 -6.4819142e-2 0.0000000e+0 +v 0.62149891 -6.4819142e-2 0.0000000e+0 +v 0.58487680 -0.34231997 -2.7538083e-17 +v 0.43863596 -0.47023465 0.0000000e+0 +v -0.43863596 -0.47023465 0.0000000e+0 +v 0.63200009 0.10031701 0.0000000e+0 +v -0.63200009 0.10031701 0.0000000e+0 +v -5.5076166e-17 -0.50300957 0.34896430 +v -5.5076166e-17 -0.50300957 -0.34896430 +v -5.5076166e-17 -0.34660813 0.37176132 +v -2.7538083e-17 -6.9107305e-2 0.41220976 +v -2.7538083e-17 -0.34660813 -0.37176132 +v -2.7538083e-17 -6.9107305e-2 -0.41220976 +v -3.4422604e-17 1.2599554e-2 0.42411932 +v -3.4422604e-17 1.2599554e-2 -0.42411932 +v 0.0000000e+0 0.11443220 0.41657000 +v -4.1307125e-17 0.11443220 -0.41657000 +v -5.5076166e-17 -0.50300957 0.19708315 +v -5.5076166e-17 -0.50300957 -0.19708315 +v -5.5076166e-17 -0.47023465 -0.19708315 +v -5.5076166e-17 -0.47023465 0.19708315 +v -2.7538083e-17 -6.4379998e-2 -0.37977756 +v -2.7538083e-17 -0.34188083 -0.33932912 +v -5.5076166e-17 -0.34188083 0.33932912 +v -2.7538083e-17 -6.4379998e-2 0.37977756 +v -5.5076166e-17 -0.47023465 0.0000000e+0 +v -0.37399324 -1.6460533e-2 -0.41833374 +v -0.37399324 4.1659640e-2 -0.41833374 +v -0.20250443 4.1659640e-2 -0.41833374 +v -0.20250443 -1.6460533e-2 -0.41833374 +v -0.37399324 5.7690712e-4 -0.44193538 +v -0.37399324 2.4622200e-2 -0.44193538 +v -0.20250443 2.4622200e-2 -0.44193538 +v -0.20250443 5.7690712e-4 -0.44193538 +v 0.20250443 -1.6460533e-2 -0.41833374 +v 0.20250443 4.1659640e-2 -0.41833374 +v 0.37399324 4.1659640e-2 -0.41833374 +v 0.37399324 -1.6460533e-2 -0.41833374 +v 0.20250443 5.7690712e-4 -0.44193538 +v 0.20250443 2.4622200e-2 -0.44193538 +v 0.37399324 2.4622200e-2 -0.44193538 +v 0.37399324 5.7690712e-4 -0.44193538 +v 0.65938357 -2.8253876e-2 8.2712883e-2 +v 0.65938357 5.9643283e-2 8.2712883e-2 +v 0.71613535 3.8718901e-2 8.2712883e-2 +v 0.71613535 -7.3294941e-3 8.2712883e-2 +v 0.65938357 -2.8253876e-2 -8.2712883e-2 +v 0.65938357 5.9643283e-2 -8.2712883e-2 +v 0.71613535 3.8718901e-2 -8.2712883e-2 +v 0.71613535 -7.3294941e-3 -8.2712883e-2 +v 0.68729689 3.1900392e-2 0.11196932 +v 0.68729689 -7.9951452e-2 0.15829986 +v 0.68729689 -0.19180330 0.11196932 +v 0.68729689 -0.23813385 1.1750922e-4 +v 0.68729689 -0.19180330 -0.11173431 +v 0.68729689 -7.9951452e-2 -0.15806484 +v 0.68729689 3.1900392e-2 -0.11173431 +v 0.66353456 1.5097889e-2 9.5166821e-2 +v 0.66353456 -7.9951452e-2 0.13453753 +v 0.66353456 -0.17500079 9.5166821e-2 +v 0.66353456 -0.21437152 1.1750922e-4 +v 0.66353456 -0.17500079 -9.4931802e-2 +v 0.66353456 -7.9951452e-2 -0.13430252 +v 0.66353456 1.5097889e-2 -9.4931802e-2 +v 0.68729689 -1.7046144e-3 7.8364318e-2 +v 0.68729689 -7.9951452e-2 0.11077521 +v 0.68729689 -0.15819829 7.8364318e-2 +v 0.68729689 -0.19060919 1.1750922e-4 +v 0.68729689 -0.15819829 -7.8129299e-2 +v 0.68729689 -7.9951452e-2 -0.11054019 +v 0.68729689 -1.7046144e-3 -7.8129299e-2 +v 0.71105922 1.5097889e-2 9.5166821e-2 +v 0.71105922 -7.9951452e-2 0.13453753 +v 0.71105922 -0.17500079 9.5166821e-2 +v 0.71105922 -0.21437152 1.1750922e-4 +v 0.71105922 -0.17500079 -9.4931802e-2 +v 0.71105922 -7.9951452e-2 -0.13430252 +v 0.71105922 1.5097889e-2 -9.4931802e-2 +v -0.65938357 -2.8253876e-2 -8.2712883e-2 +v -0.65938357 5.9643283e-2 -8.2712883e-2 +v -0.71613535 3.8718901e-2 -8.2712883e-2 +v -0.71613535 -7.3294941e-3 -8.2712883e-2 +v -0.65938357 -2.8253876e-2 8.2712883e-2 +v -0.65938357 5.9643283e-2 8.2712883e-2 +v -0.71613535 3.8718901e-2 8.2712883e-2 +v -0.71613535 -7.3294941e-3 8.2712883e-2 +v -0.68729689 3.1900392e-2 -0.11196932 +v -0.68729689 -7.9951452e-2 -0.15829986 +v -0.68729689 -0.19180330 -0.11196932 +v -0.68729689 -0.23813385 -1.1750922e-4 +v -0.68729689 -0.19180330 0.11173431 +v -0.68729689 -7.9951452e-2 0.15806484 +v -0.68729689 3.1900392e-2 0.11173431 +v -0.66353456 1.5097889e-2 -9.5166821e-2 +v -0.66353456 -7.9951452e-2 -0.13453753 +v -0.66353456 -0.17500079 -9.5166821e-2 +v -0.66353456 -0.21437152 -1.1750922e-4 +v -0.66353456 -0.17500079 9.4931802e-2 +v -0.66353456 -7.9951452e-2 0.13430252 +v -0.66353456 1.5097889e-2 9.4931802e-2 +v -0.68729689 -1.7046144e-3 -7.8364318e-2 +v -0.68729689 -7.9951452e-2 -0.11077521 +v -0.68729689 -0.15819829 -7.8364318e-2 +v -0.68729689 -0.19060919 -1.1750922e-4 +v -0.68729689 -0.15819829 7.8129299e-2 +v -0.68729689 -7.9951452e-2 0.11054019 +v -0.68729689 -1.7046144e-3 7.8129299e-2 +v -0.71105922 1.5097889e-2 -9.5166821e-2 +v -0.71105922 -7.9951452e-2 -0.13453753 +v -0.71105922 -0.17500079 -9.5166821e-2 +v -0.71105922 -0.21437152 -1.1750922e-4 +v -0.71105922 -0.17500079 9.4931802e-2 +v -0.71105922 -7.9951452e-2 0.13430252 +v -0.71105922 1.5097889e-2 9.4931802e-2 +v -1.0584675e-17 -6.5059592e-2 0.47337432 +v -0.11942020 5.4360608e-2 0.47337432 +v 7.9741537e-18 0.17378081 0.47337432 +v 0.11942020 5.4360608e-2 0.47337432 +v -8.0697773e-18 -4.8433049e-2 0.40214078 +v -0.10279366 5.4360608e-2 0.40214078 +v 8.0697773e-18 0.15715427 0.40214078 +v 0.10279366 5.4360608e-2 0.40214078 +v 3.4264552e-2 -1.4168497e-2 0.46161758 +v 6.8529105e-2 2.0096056e-2 0.46161758 +v -6.8529105e-2 8.8625161e-2 0.46161758 +v -3.4264552e-2 0.12288971 0.46161758 +v 3.4264552e-2 -1.4168497e-2 0.40214078 +v 6.8529105e-2 2.0096056e-2 0.40214078 +v -6.8529105e-2 8.8625161e-2 0.40214078 +v -3.4264552e-2 0.12288971 0.40214078 +v -3.4264552e-2 -1.4168497e-2 0.46161758 +v -6.8529105e-2 2.0096056e-2 0.46161758 +v 3.4264552e-2 0.12288971 0.46161758 +v 6.8529105e-2 8.8625161e-2 0.46161758 +v -3.4264552e-2 -1.4168497e-2 0.40214078 +v -6.8529105e-2 2.0096056e-2 0.40214078 +v 3.4264552e-2 0.12288971 0.40214078 +v 6.8529105e-2 8.8625161e-2 0.40214078 +v -3.4264552e-2 5.4360608e-2 0.46161758 +v 0.0000000e+0 2.0096056e-2 0.46161758 +v 0.0000000e+0 8.8625161e-2 0.46161758 +v 3.4264552e-2 5.4360608e-2 0.46161758 +v 0.0000000e+0 2.0096056e-2 0.40214078 +v -3.4264552e-2 5.4360608e-2 0.40214078 +v 3.4264552e-2 5.4360608e-2 0.40214078 +v 6.8845208e-18 8.8625161e-2 0.40214078 +v -0.11942020 5.4360608e-2 0.40214078 +v -7.6842376e-2 9.6938432e-2 0.47337432 +v -7.6842376e-2 1.1782784e-2 0.47337432 +v -7.6842376e-2 9.6938432e-2 0.40214078 +v -3.4264552e-2 5.4360608e-2 0.47337432 +v -7.6842376e-2 1.1782784e-2 0.40214078 +v -1.0680298e-17 -6.5059592e-2 0.40214078 +v 4.2577824e-2 -2.2481768e-2 0.47337432 +v -4.2577824e-2 -2.2481768e-2 0.47337432 +v 4.2577824e-2 -2.2481768e-2 0.40214078 +v 0.0000000e+0 2.0096056e-2 0.47337432 +v -4.2577824e-2 -2.2481768e-2 0.40214078 +v 8.0697773e-18 0.17378081 0.40214078 +v -4.2577824e-2 0.13120298 0.47337432 +v 4.2577824e-2 0.13120298 0.47337432 +v -4.2577824e-2 0.13120298 0.40214078 +v 4.2577824e-2 0.13120298 0.40214078 +v 0.0000000e+0 8.8625161e-2 0.47337432 +v 0.11942020 5.4360608e-2 0.40214078 +v 7.6842376e-2 1.1782784e-2 0.47337432 +v 7.6842376e-2 9.6938432e-2 0.47337432 +v 3.4264552e-2 5.4360608e-2 0.47337432 +v 7.6842376e-2 9.6938432e-2 0.40214078 +v 7.6842376e-2 1.1782784e-2 0.40214078 +v 0.64709069 0.43880893 0.14438430 +v 0.51215638 0.43880893 0.14438430 +v 0.57962353 0.50300957 0.16512302 +v 0.57962353 0.41807021 0.20858494 +v 0.57962353 0.45954764 8.0183658e-2 +v 0.64709086 0.11443220 0.41657000 +v 0.51215656 0.11443220 0.41657000 +v 0.57962371 0.18173361 0.41184376 +v 0.57962371 4.7130795e-2 0.42129624 +v 0.57962371 0.11915844 0.48387141 +v 0.64709069 0.30437483 0.34889464 +v 0.51215638 0.30437483 0.34889464 +v 0.57962353 0.34211175 0.40482086 +v 0.57962353 0.24844862 0.38663155 +v 0.57962353 0.36030105 0.31115772 +v 0.51215638 0.43880893 -0.14438430 +v 0.64709069 0.43880893 -0.14438430 +v 0.57962353 0.50300957 -0.16512302 +v 0.57962353 0.41807021 -0.20858494 +v 0.57962353 0.45954764 -8.0183658e-2 +v 0.51215620 0.11443220 -0.41657000 +v 0.64709051 0.11443220 -0.41657000 +v 0.57962336 0.18173361 -0.41184376 +v 0.57962336 4.7130795e-2 -0.42129624 +v 0.57962336 0.11915844 -0.48387141 +v 0.51215638 0.30437483 -0.34889464 +v 0.64709069 0.30437483 -0.34889464 +v 0.57962353 0.34211175 -0.40482086 +v 0.57962353 0.24844862 -0.38663155 +v 0.57962353 0.36030105 -0.31115772 +v -0.50498173 0.43880893 0.14438430 +v -0.63991603 0.43880893 0.14438430 +v -0.57244888 0.50300957 0.16512302 +v -0.57244888 0.41807021 0.20858494 +v -0.57244888 0.45954764 8.0183658e-2 +v -0.50498155 0.11443220 0.41657000 +v -0.63991586 0.11443220 0.41657000 +v -0.57244870 0.18173361 0.41184376 +v -0.57244870 4.7130795e-2 0.42129624 +v -0.57244870 0.11915844 0.48387141 +v -0.50498173 0.30437483 0.34889464 +v -0.63991603 0.30437483 0.34889464 +v -0.57244888 0.34211175 0.40482086 +v -0.57244888 0.24844862 0.38663155 +v -0.57244888 0.36030105 0.31115772 +v -0.63991603 0.43880893 -0.14438430 +v -0.50498173 0.43880893 -0.14438430 +v -0.57244888 0.50300957 -0.16512302 +v -0.57244888 0.41807021 -0.20858494 +v -0.57244888 0.45954764 -8.0183658e-2 +v -0.63991621 0.11443220 -0.41657000 +v -0.50498191 0.11443220 -0.41657000 +v -0.57244906 0.18173361 -0.41184376 +v -0.57244906 4.7130795e-2 -0.42129624 +v -0.57244906 0.11915844 -0.48387141 +v -0.63991603 0.30437483 -0.34889464 +v -0.50498173 0.30437483 -0.34889464 +v -0.57244888 0.34211175 -0.40482086 +v -0.57244888 0.24844862 -0.38663155 +v -0.57244888 0.36030105 -0.31115772 +vt 3.2935936e-3 0.56873187 +vt 5.2391480e-3 0.56930840 +vt 5.2391480e-3 0.56930840 +vt 5.2391555e-3 0.56930840 +vt 7.2363832e-3 0.61817246 +vt 9.5477718e-3 0.61835980 +vt 9.5477718e-3 0.61835980 +vt 9.5477798e-3 0.61835980 +vt 1.2352160e-2 0.49780349 +vt 1.4056316e-2 0.49849806 +vt 1.4056316e-2 0.49849806 +vt 1.4056323e-2 0.49849807 +vt 1.5113352e-2 0.51555987 +vt 1.6834549e-2 0.51621553 +vt 1.6834549e-2 0.51621553 +vt 1.6834556e-2 0.51621553 +vt 2.7464503e-2 0.33832477 +vt 2.7720788e-2 0.33965649 +vt 2.7720788e-2 0.33965649 +vt 2.7720794e-2 0.33965649 +vt 3.3202993e-2 0.31921297 +vt 3.3339432e-2 0.32047593 +vt 3.3339432e-2 0.32047593 +vt 3.3339438e-2 0.32047593 +vt 4.6403490e-2 0.22869549 +vt 4.6403490e-2 0.22869549 +vt 4.6403495e-2 0.22869550 +vt 4.6881905e-2 0.22795908 +vt 5.5763993e-2 0.13858138 +vt 5.5763993e-2 0.13858138 +vt 5.5763997e-2 0.13858138 +vt 5.6060873e-2 0.11552405 +vt 5.6060873e-2 0.11552405 +vt 5.6060877e-2 0.11552406 +vt 5.6645106e-2 0.13799999 +vt 5.7038952e-2 0.11496734 +vt 5.9350547e-2 0.70072038 +vt 5.9744233e-2 0.64036699 +vt 6.1431396e-2 0.99680265 +vt 6.1457621e-2 0.81988058 +vt 6.1634496e-2 0.70065640 +vt 6.1634496e-2 0.70065640 +vt 6.1634501e-2 0.70065640 +vt 6.1855925e-2 0.64040958 +vt 6.1855925e-2 0.64040958 +vt 6.1855930e-2 0.64040958 +vt 6.2927483e-2 0.62109489 +vt 6.2950630e-2 0.57089291 +vt 6.4006954e-2 0.81944095 +vt 6.4006954e-2 0.81944095 +vt 6.4006957e-2 0.81944095 +vt 6.4315204e-2 0.99584136 +vt 6.4315204e-2 0.99584136 +vt 6.4315205e-2 0.99584136 +vt 6.4727842e-2 0.57127721 +vt 6.4727842e-2 0.57127721 +vt 6.4727849e-2 0.57127721 +vt 6.4937433e-2 0.62119119 +vt 6.4937433e-2 0.62119119 +vt 6.4937439e-2 0.62119119 +vt 6.6082410e-2 5.5671710e-3 +vt 6.6082410e-2 5.5671710e-3 +vt 6.6082412e-2 5.5671783e-3 +vt 6.7712782e-2 5.4088099e-3 +vt 0.27343871 0.36280665 +vt 0.27408267 0.36247166 +vt 0.27408267 0.36247166 +vt 0.27408268 0.36247166 +vt 0.28267135 0.35497553 +vt 0.28324106 0.35467552 +vt 0.28324106 0.35467552 +vt 0.28324106 0.35467552 +vt 0.28417562 0.51604766 +vt 0.28533331 0.51586653 +vt 0.28533331 0.51586653 +vt 0.28533332 0.51586654 +vt 0.29200615 0.52348755 +vt 0.29326649 0.52329351 +vt 0.29326649 0.52329351 +vt 0.29326650 0.52329351 +vt 0.29632657 0.64428384 +vt 0.29711739 0.57643586 +vt 0.29753617 0.64376369 +vt 0.29753617 0.64376369 +vt 0.29753617 0.64376369 +vt 0.29843611 0.57620072 +vt 0.29843631 0.57620072 +vt 0.29843631 0.57620072 +vt 0.30075829 0.26001124 +vt 0.30120206 0.25947815 +vt 0.30120206 0.25947815 +vt 0.30120206 0.25947815 +vt 0.30237697 0.70324671 +vt 0.30383936 0.70263149 +vt 0.30383936 0.70263149 +vt 0.30383936 0.70263149 +vt 0.30404171 0.81873640 +vt 0.30415207 0.15068631 +vt 0.30415207 0.15068631 +vt 0.30415208 0.15068632 +vt 0.30422210 0.15149605 +vt 0.30575855 0.81772603 +vt 0.30575855 0.81772603 +vt 0.30575856 0.81772603 +vt 0.30593609 0.62804536 +vt 0.30729162 0.62764111 +vt 0.30729162 0.62764111 +vt 0.30729163 0.62764111 +vt 0.30823246 0.99321243 +vt 0.31040552 0.99160354 +vt 0.31040552 0.99160354 +vt 0.31040552 0.99160354 +vt 0.31253709 0.16541522 +vt 0.31253709 0.16541522 +vt 0.31253709 0.16541522 +vt 0.31254496 0.16621254 +vt 0.31793580 0.70157335 +vt 0.31906186 0.70089556 +vt 0.31906186 0.70089556 +vt 0.31906187 0.70089557 +vt 0.32413667 0.99788760 +vt 0.32441761 0.81538506 +vt 0.32606959 0.81433811 +vt 0.32606959 0.81433811 +vt 0.32606959 0.81433811 +vt 0.32623129 0.99616438 +vt 0.32623129 0.99616438 +vt 0.32623129 0.99616438 +vt 0.32908022 4.4835473e-2 +vt 0.32908022 4.4835473e-2 +vt 0.32908022 4.4835478e-2 +vt 0.32946699 4.6291216e-2 +vt 0.34444497 4.9954478e-2 +vt 0.34444497 4.9954478e-2 +vt 0.34444497 4.9954482e-2 +vt 0.34460664 5.1491795e-2 +vt 0.39160776 0.27091696 +vt 0.39208405 0.27015805 +vt 0.39208405 0.27015805 +vt 0.39208405 0.27015805 +vt 0.39492258 0.35703011 +vt 0.39584999 0.35631699 +vt 0.39584999 0.35631699 +vt 0.39584999 0.35631699 +vt 0.40334534 0.52126598 +vt 0.40456706 0.52137449 +vt 0.40456706 0.52137449 +vt 0.40456706 0.52137449 +vt 0.40704919 0.57598411 +vt 0.40814637 0.57558998 +vt 0.40814637 0.57558998 +vt 0.40814637 0.57558998 +vt 0.41147503 0.18179128 +vt 0.41179746 0.18085277 +vt 0.41179746 0.18085277 +vt 0.41179746 0.18085277 +vt 0.41377089 0.62383635 +vt 0.41469109 0.62331306 +vt 0.41469109 0.62331306 +vt 0.41469109 0.62331306 +vt 0.42372939 0.69348735 +vt 0.42443381 0.69263839 +vt 0.42443381 0.69263839 +vt 0.42443382 0.69263840 +vt 0.42774598 0.81211245 +vt 0.42900895 0.81076852 +vt 0.42900895 0.81076852 +vt 0.42900895 0.81076853 +vt 0.43182919 0.99714046 +vt 0.43185612 7.3763435e-2 +vt 0.43223459 7.2296370e-2 +vt 0.43223459 7.2296366e-2 +vt 0.43223459 7.2296366e-2 +vt 0.43345833 0.99512014 +vt 0.43345833 0.99512013 +vt 0.43345833 0.99512013 +vt 0.44908862 0.12543001 +vt 0.45594484 0.12555395 +vt 0.45594484 0.12555395 +vt 0.46513543 0.12524919 +vt 0.46513543 0.12524919 +vt 0.46919699 0.24835063 +vt 0.46994444 0.24674646 +vt 0.46994444 0.24674646 +vt 0.46994444 0.24674646 +vt 0.47187079 0.94019439 +vt 0.47213737 0.94004072 +vt 0.47213737 0.94004072 +vt 0.47344131 0.87684366 +vt 0.47344131 0.87684366 +vt 0.47509383 0.12466024 +vt 0.47509383 0.12466024 +vt 0.48017306 0.92485081 +vt 0.48033588 0.89628238 +vt 0.48140343 4.6450795e-2 +vt 0.48140343 4.6450795e-2 +vt 0.48399256 0.19773046 +vt 0.48399256 0.19773046 +vt 0.48500745 0.12363487 +vt 0.48500745 0.12363487 +vt 0.48639526 5.4644527e-2 +vt 0.48639526 5.4644527e-2 +vt 0.48847250 0.19094012 +vt 0.48847250 0.19094012 +vt 0.49150233 0.33017849 +vt 0.49200473 6.0834696e-2 +vt 0.49200473 6.0834696e-2 +vt 0.49220255 0.18404620 +vt 0.49220255 0.18404620 +vt 0.49274654 0.33085810 +vt 0.49314477 0.32933299 +vt 0.49314477 0.32933299 +vt 0.49713138 0.17468271 +vt 0.49713138 0.17468271 +vt 0.49722797 0.51419301 +vt 0.49796884 6.7662838e-2 +vt 0.49796884 6.7662838e-2 +vt 0.49820823 0.51402279 +vt 0.49820823 0.51402279 +vt 0.49820824 0.51402279 +vt 0.50058132 0.16858400 +vt 0.50058132 0.16858400 +vt 0.50270031 7.2891213e-2 +vt 0.50270031 7.2891213e-2 +vt 0.50445162 0.50694554 +vt 0.50505855 0.56609016 +vt 0.50553209 0.33942203 +vt 0.50556921 0.50680911 +vt 0.50556921 0.50680911 +vt 0.50556922 0.50680911 +vt 0.50593407 0.56606576 +vt 0.50593407 0.56606576 +vt 0.50593408 0.56606576 +vt 0.50712839 0.33861625 +vt 0.50712839 0.33861625 +vt 0.50712839 0.33861625 +vt 0.51210608 0.62111135 +vt 0.51295636 0.62104892 +vt 0.51295636 0.62104892 +vt 0.51295636 0.62104893 +vt 0.51472973 0.67349538 +vt 0.51528950 0.67361216 +vt 0.51528950 0.67361216 +vt 0.51528950 0.67361217 +vt 0.52248789 0.62653845 +vt 0.52329108 0.62653383 +vt 0.52329108 0.62653383 +vt 0.52329108 0.62653383 +vt 0.52825301 0.81428087 +vt 0.52825301 0.81428087 +vt 0.52825301 0.81428088 +vt 0.52829868 0.81436331 +vt 0.52901893 0.66514933 +vt 0.52959544 0.66526277 +vt 0.52959544 0.66526277 +vt 0.52959545 0.66526278 +vt 0.56111853 1.2928639e-2 +vt 0.56111853 1.2928639e-2 +vt 0.56143565 2.3615321e-2 +vt 0.56143565 2.3615321e-2 +vt 0.56154577 3.2262950e-2 +vt 0.56154577 3.2262950e-2 +vt 0.56170513 3.9782191e-2 +vt 0.56170513 3.9782191e-2 +vt 0.56185997 4.6830766e-2 +vt 0.56185997 4.6830766e-2 +vt 0.56579819 0.73928232 +vt 0.56595651 0.73949592 +vt 0.56595651 0.73949592 +vt 0.56595651 0.73949593 +vt 0.57384890 0.72763410 +vt 0.57406416 0.72785097 +vt 0.57406416 0.72785097 +vt 0.57406416 0.72785098 +vt 0.58443510 0.21648411 +vt 0.58696950 0.21435134 +vt 0.58696950 0.21435134 +vt 0.58696950 0.21435134 +vt 0.60753269 0.29368632 +vt 0.61028675 0.29306053 +vt 0.61028675 0.29306053 +vt 0.61028675 0.29306053 +vt 0.61474573 0.31083480 +vt 0.61679888 7.7379002e-2 +vt 0.61679888 7.7379002e-2 +vt 0.61750858 0.31054243 +vt 0.61750858 0.31054243 +vt 0.61750859 0.31054243 +vt 0.62344978 0.16667925 +vt 0.62344978 0.16667925 +vt 0.62453939 7.1035704e-2 +vt 0.62453939 7.1035704e-2 +vt 0.62591418 0.17450060 +vt 0.62591418 0.17450060 +vt 0.63048047 0.18432851 +vt 0.63048047 0.18432851 +vt 0.63162959 6.3985638e-2 +vt 0.63162959 6.3985638e-2 +vt 0.63280916 0.19232469 +vt 0.63280916 0.19232469 +vt 0.63664208 5.5739035e-2 +vt 0.63664208 5.5739035e-2 +vt 0.63727255 0.20160718 +vt 0.63727255 0.20160718 +vt 0.63808653 0.89453279 +vt 0.63879935 0.92297263 +vt 0.63990997 0.12137151 +vt 0.63990997 0.12137151 +vt 0.64437850 4.8445911e-2 +vt 0.64437850 4.8445911e-2 +vt 0.64621508 0.87751312 +vt 0.64621508 0.87751312 +vt 0.64627883 0.87735654 +vt 0.64694818 0.93907591 +vt 0.64694818 0.93907591 +vt 0.64713848 0.12317826 +vt 0.64713848 0.12317826 +vt 0.64926783 0.85992026 +vt 0.64926783 0.85992026 +vt 0.64926784 0.85992027 +vt 0.64953024 0.85901070 +vt 0.65278676 0.47830578 +vt 0.65401408 0.12428680 +vt 0.65401408 0.12428680 +vt 0.65401836 0.47853044 +vt 0.65401836 0.47853044 +vt 0.65401836 0.47853044 +vt 0.65462638 0.21158739 +vt 0.65462638 0.21158739 +vt 0.65485005 0.49449282 +vt 0.65504426 0.28011844 +vt 0.65504426 0.28011844 +vt 0.65608402 0.49471829 +vt 0.65608402 0.49471829 +vt 0.65608403 0.49471829 +vt 0.65946172 0.54793122 +vt 0.65955370 0.78121391 +vt 0.65987424 0.78200568 +vt 0.65987424 0.78200568 +vt 0.65987425 0.78200568 +vt 0.66046886 0.54840563 +vt 0.66046886 0.54840563 +vt 0.66046887 0.54840564 +vt 0.66171505 0.59973961 +vt 0.66248290 0.60028068 +vt 0.66248290 0.60028068 +vt 0.66248290 0.60028068 +vt 0.66381778 0.12570976 +vt 0.66381778 0.12570976 +vt 0.66715116 0.23198305 +vt 0.66715116 0.23198305 +vt 0.66747381 0.26099343 +vt 0.66747381 0.26099343 +vt 0.66891988 0.62017055 +vt 0.66960299 0.62071541 +vt 0.66960299 0.62071541 +vt 0.66960300 0.62071542 +vt 0.67044107 0.47380800 +vt 0.67047003 0.92719981 +vt 0.67078769 0.47435440 +vt 0.67124967 0.92671700 +vt 0.67372751 0.12715480 +vt 0.67377342 0.76420837 +vt 0.67414961 0.76497361 +vt 0.67414961 0.76497361 +vt 0.67414961 0.76497362 +vt 0.68538398 0.70306862 +vt 0.68551980 0.70281851 +vt 0.69647429 0.36619349 +vt 0.69654372 0.58151952 +vt 0.69658261 0.58242309 +vt 0.69674742 0.82545813 +vt 0.69678965 0.82491393 +vt 0.69703920 0.36735627 +vt 0.71189995 0.82826491 +vt 0.71720996 0.82826491 +vt 0.72274386 0.52533266 +vt 0.72309049 0.52587907 +vt 0.72323944 0.47447818 +vt 0.72358607 0.47502458 +vt 0.72379656 0.98114220 +vt 0.72395082 0.87538874 +vt 0.72402634 0.92851134 +vt 0.72403763 0.42214849 +vt 0.72438425 0.42269489 +vt 0.72457620 0.98065940 +vt 0.72473046 0.87490594 +vt 0.72480599 0.92802854 +vt 0.72549800 0.84186296 +vt 0.72549800 0.81466686 +vt 0.72815300 0.81732186 +vt 0.72815300 0.83920795 +vt 0.73644104 0.80372382 +vt 0.73644104 0.85280600 +vt 0.73846875 0.70503568 +vt 0.73860457 0.70478557 +vt 0.73909604 0.80637882 +vt 0.73909604 0.82826491 +vt 0.73909604 0.85015100 +vt 0.73996172 0.75550110 +vt 0.74009754 0.75525099 +vt 0.74025580 0.65702351 +vt 0.74039162 0.65677340 +vt 0.74541061 0.31582791 +vt 0.74565892 0.41921727 +vt 0.74597552 0.31699069 +vt 0.74622383 0.42038004 +vt 0.74636152 0.36597579 +vt 0.74692643 0.36713857 +vt 0.75003909 0.83920795 +vt 0.75003909 0.86109404 +vt 0.75003909 0.86640405 +vt 0.75003909 0.79012577 +vt 0.75003909 0.79543578 +vt 0.75003909 0.81732186 +vt 0.75093838 0.77775410 +vt 0.75098061 0.77720990 +vt 0.75098083 0.58077267 +vt 0.75101972 0.58167624 +vt 0.75110901 0.87977109 +vt 0.75115124 0.87922689 +vt 0.75115362 0.52775274 +vt 0.75119251 0.52865632 +vt 0.75145869 0.82604185 +vt 0.75150092 0.82549766 +vt 0.75186716 0.63451128 +vt 0.75190605 0.63541486 +vt 0.76098213 0.80637882 +vt 0.76098213 0.82826491 +vt 0.76098213 0.85015100 +vt 0.76363713 0.80372382 +vt 0.76363713 0.85280600 +vt 0.76671308 0.23220875 +vt 0.76671308 0.23220875 +vt 0.76731819 0.25977762 +vt 0.76830240 0.12373995 +vt 0.77192518 0.81732186 +vt 0.77192518 0.83920795 +vt 0.77458018 0.84186296 +vt 0.77458018 0.81466686 +vt 0.77469170 0.92834767 +vt 0.77547135 0.92786487 +vt 0.77632691 0.47353536 +vt 0.77667354 0.47408177 +vt 0.77980955 0.28029521 +vt 0.78074326 0.21007360 +vt 0.78074326 0.21007360 +vt 0.78286822 0.82826491 +vt 0.78699793 0.16303689 +vt 0.78764871 0.12464599 +vt 0.78817823 0.82826491 +vt 0.79248835 0.70368489 +vt 0.79262417 0.70343478 +vt 0.79466520 8.6529909e-2 +vt 0.79633641 0.17098700 +vt 0.79883711 0.36636330 +vt 0.79940202 0.36752608 +vt 0.80151878 7.8727209e-2 +vt 0.80266208 0.58124975 +vt 0.80270097 0.58215332 +vt 0.80536481 0.82500988 +vt 0.80540704 0.82446568 +vt 0.80918995 9.8647478e-2 +vt 0.80933072 0.14808377 +vt 0.81336992 0.15379406 +vt 0.81345027 9.3257024e-2 +vt 0.82233143 0.20002692 +vt 0.82251539 0.26382867 +vt 0.82274704 0.31093454 +vt 0.82304801 0.98610035 +vt 0.82460382 0.43336536 +vt 0.82490069 0.92485122 +vt 0.82636489 0.61459595 +vt 0.82755612 0.79621922 +vt 0.83076096 5.1311493e-2 +vt 0.83313216 0.12314378 +vt 0.83447901 0.21063356 +vt 0.83799081 4.4959211e-2 +vt 0.84026789 0.12317449 +vt 0.84257170 6.4202820e-2 +vt 0.84284812 0.25528733 +vt 0.84324308 0.99163059 +vt 0.84355505 0.18225222 +vt 0.84507893 0.30896426 +vt 0.84532251 0.43200057 +vt 0.84549050 0.61487308 +vt 0.84596483 0.92847173 +vt 0.84745097 5.8878252e-2 +vt 0.84765450 0.18888130 +vt 0.84778103 0.79719395 +vt 0.85496572 0.93261111 +vt 0.85595229 0.42691188 +vt 0.85595229 0.42691188 +vt 0.85595229 0.47246184 +vt 0.85595229 0.47246184 +vt 0.87112527 2.3338259e-2 +vt 0.87156988 0.20866643 +vt 0.87177962 3.9317563e-2 +vt 0.87205659 8.3637731e-2 +vt 0.87224919 0.16307960 +vt 0.87225217 0.23209129 +vt 0.87251426 9.2549677e-2 +vt 0.87273228 0.15518971 +vt 0.89612413 6.0455916e-2 +vt 0.89673111 0.89084572 +vt 0.89673111 0.89084572 +vt 0.89673111 0.97437650 +vt 0.89676208 0.25643420 +vt 0.89695812 0.18812864 +vt 0.90140060 6.5403718e-2 +vt 0.90218420 0.99606431 +vt 0.90327843 0.18221526 +vt 0.90397485 0.12280398 +vt 0.90784798 4.6130271e-2 +vt 0.91030532 0.12302826 +vt 0.91236922 0.21414830 +vt 0.91353143 5.2816938e-2 +vt 0.92406129 0.20207206 +vt 0.93109168 0.15384930 +vt 0.93292252 9.2794762e-2 +vt 0.93496652 0.14787859 +vt 0.93696172 9.8505052e-2 +vt 0.93849650 0.93261111 +vt 0.94167904 0.42691188 +vt 0.94167904 0.42691188 +vt 0.94167904 0.47246184 +vt 0.94167904 0.47246184 +vt 0.94651573 7.8981476e-2 +vt 0.95236761 0.12069226 +vt 0.95240089 8.8921503e-2 +vt 0.95320246 0.31020172 +vt 0.95406020 0.79660420 +vt 0.95460850 0.17429195 +vt 0.95518626 0.92811017 +vt 0.95574038 0.25767281 +vt 0.95583939 0.99450018 +vt 0.95598123 0.43223107 +vt 0.95641750 0.61375329 +vt 0.96307646 0.16665185 +vt 0.97528346 0.30706788 +vt 0.97657108 0.43366150 +vt 0.97678891 0.61362604 +vt 0.97872489 0.26486081 +vt 0.97897775 0.92699255 +vt 0.97936619 0.79543481 +vt 0.97979702 0.99212290 +vt 0.98345597 0.12353401 +vn 0.0000000e+0 -3.5363198e-2 0.99937453 +vn 0.0000000e+0 -3.5363198e-2 0.99937453 +vn 0.0000000e+0 -3.5363198e-2 -0.99937453 +vn 0.0000000e+0 -3.5363198e-2 -0.99937453 +vn 0.0000000e+0 1.2157609e-3 0.99999926 +vn 0.0000000e+0 1.2157609e-3 0.99999926 +vn 0.0000000e+0 1.2157609e-3 -0.99999926 +vn 0.0000000e+0 1.2157609e-3 -0.99999926 +vn -0.99784871 -6.5558750e-2 2.3145183e-7 +vn -0.99784871 -6.5558750e-2 -2.3145183e-7 +vn 0.99784871 -6.5558750e-2 2.3145183e-7 +vn 0.99784871 -6.5558750e-2 -2.3145183e-7 +vn -0.99784868 -6.5559168e-2 0.0000000e+0 +vn 0.99784868 -6.5559168e-2 0.0000000e+0 +vn 0.0000000e+0 -3.5363198e-2 0.99937453 +vn 0.0000000e+0 -3.5363198e-2 -0.99937453 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.85056210 0.52587461 +vn 0.0000000e+0 8.1802659e-17 1.00000000 +vn 4.0901331e-17 -0.70710671 0.70710685 +vn -4.0901333e-17 -1.00000000 4.0901333e-17 +vn -4.0901331e-17 -0.70710671 -0.70710685 +vn 0.0000000e+0 -2.4540798e-16 -1.00000000 +vn 0.0000000e+0 0.85056210 -0.52587461 +vn -1.00000000 5.2660629e-9 -2.1812740e-9 +vn -1.00000000 2.0450666e-17 -4.0370981e-9 +vn -1.00000000 -6.8917600e-9 -6.8917603e-9 +vn -1.00000000 -4.0371013e-9 2.0450666e-17 +vn -1.00000000 -6.8917601e-9 6.8917602e-9 +vn -1.00000000 0.0000000e+0 4.0370977e-9 +vn -1.00000000 5.2660630e-9 2.1812738e-9 +vn 0.0000000e+0 -0.85056210 -0.52587462 +vn 4.0901329e-17 -4.0901329e-17 -1.00000000 +vn 4.0901331e-17 0.70710670 -0.70710687 +vn 4.0901333e-17 1.00000000 0.0000000e+0 +vn -4.0901331e-17 0.70710670 0.70710687 +vn -4.0901329e-17 2.4540797e-16 1.00000000 +vn 0.0000000e+0 -0.85056210 0.52587462 +vn 1.00000000 5.2660629e-9 -2.1812740e-9 +vn 1.00000000 2.0450666e-17 -4.0370981e-9 +vn 1.00000000 -6.8917600e-9 -6.8917603e-9 +vn 1.00000000 -4.0371014e-9 2.0450666e-17 +vn 1.00000000 -6.8917601e-9 6.8917602e-9 +vn 1.00000000 0.0000000e+0 4.0370977e-9 +vn 1.00000000 5.2660630e-9 2.1812738e-9 +vn 3.4414353e-16 0.85056210 -0.52587461 +vn 6.9532260e-16 0.0000000e+0 -1.00000000 +vn 3.6811198e-16 -0.70710671 -0.70710685 +vn -6.5442133e-16 -1.00000000 4.0901333e-17 +vn -1.3497439e-15 -0.70710671 0.70710685 +vn -1.2679412e-15 -2.8630931e-16 1.00000000 +vn -6.4526912e-16 0.85056210 0.52587461 +vn 1.00000000 5.2660630e-9 2.1812741e-9 +vn 1.00000000 -2.0450666e-17 4.0370980e-9 +vn 1.00000000 -6.8917602e-9 6.8917605e-9 +vn 1.00000000 -4.0371016e-9 2.6585865e-16 +vn 1.00000000 -6.8917602e-9 -6.8917603e-9 +vn 1.00000000 -2.0450666e-17 -4.0370979e-9 +vn 1.00000000 5.2660630e-9 -2.1812737e-9 +vn 3.4414353e-16 -0.85056210 0.52587462 +vn 5.7261861e-16 -4.0901329e-17 1.00000000 +vn 2.8630932e-16 0.70710670 0.70710687 +vn -6.5442133e-16 1.00000000 -2.0450667e-17 +vn -1.2679413e-15 0.70710670 -0.70710687 +vn -1.2679412e-15 2.4540797e-16 -1.00000000 +vn -6.4526913e-16 -0.85056210 -0.52587462 +vn -1.00000000 5.2660627e-9 2.1812737e-9 +vn -1.00000000 -2.0450666e-17 4.0370978e-9 +vn -1.00000000 -6.8917598e-9 6.8917599e-9 +vn -1.00000000 -4.0371013e-9 -2.4540799e-16 +vn -1.00000000 -6.8917601e-9 -6.8917602e-9 +vn -1.00000000 -2.0450666e-17 -4.0370978e-9 +vn -1.00000000 5.2660630e-9 -2.1812740e-9 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -3.5363198e-2 0.99937453 +vn 0.0000000e+0 -3.5363198e-2 0.99937453 +vn -0.99784874 -6.5558333e-2 4.6290368e-7 +vn -0.99784874 -6.5558333e-2 4.6290368e-7 +vn 0.0000000e+0 -3.5363198e-2 0.99937453 +vn 0.0000000e+0 -3.5363198e-2 0.99937453 +vn 0.99784874 -6.5558333e-2 4.6290368e-7 +vn 0.99784874 -6.5558333e-2 4.6290368e-7 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -3.5363198e-2 -0.99937453 +vn 0.0000000e+0 -3.5363198e-2 -0.99937453 +vn -0.99784874 -6.5558333e-2 -4.6290368e-7 +vn -0.99784874 -6.5558333e-2 -4.6290368e-7 +vn 0.0000000e+0 -3.5363198e-2 -0.99937453 +vn 0.0000000e+0 -3.5363198e-2 -0.99937453 +vn 0.99784874 -6.5558333e-2 -4.6290368e-7 +vn 0.99784874 -6.5558333e-2 -4.6290368e-7 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.0000000e+0 0.33009742 0.94394687 +vn -1.00000000 8.5018052e-7 5.0354486e-7 +vn -1.00000000 8.5018052e-7 5.0354486e-7 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 1.00000000 8.5018052e-7 5.0354486e-7 +vn 1.00000000 8.5018052e-7 5.0354486e-7 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 1.00000000 8.5018052e-7 -5.0354486e-7 +vn 1.00000000 8.5018052e-7 -5.0354486e-7 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn -1.00000000 8.5018052e-7 -5.0354486e-7 +vn -1.00000000 8.5018052e-7 -5.0354486e-7 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 0.0000000e+0 0.80136485 0.59817588 +vn -1.00000000 1.6501300e-7 1.3893582e-7 +vn -1.00000000 1.6501300e-7 1.3893582e-7 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 1.00000000 1.6501300e-7 1.3893582e-7 +vn 1.00000000 1.6501300e-7 1.3893582e-7 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 1.00000000 1.6501300e-7 -1.3893582e-7 +vn 1.00000000 1.6501300e-7 -1.3893582e-7 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn -1.00000000 1.6501300e-7 -1.3893582e-7 +vn -1.00000000 1.6501300e-7 -1.3893582e-7 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn -1.00000000 2.8659374e-7 0.0000000e+0 +vn -1.00000000 2.8659374e-7 0.0000000e+0 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn 1.00000000 2.8659374e-7 0.0000000e+0 +vn 1.00000000 2.8659374e-7 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.0000000e+0 0.33009742 0.94394687 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 0.0000000e+0 0.80136485 0.59817588 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.99542425 9.4554828e-2 1.3782283e-2 +vn 0.0000000e+0 -0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.99542425 9.4554828e-2 1.3782283e-2 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 0.98954338 0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn -0.99542425 9.4554828e-2 1.3782283e-2 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 0.98954338 0.14423554 +vn -0.99542425 9.4554828e-2 1.3782283e-2 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.99542425 9.4554828e-2 -1.3782283e-2 +vn 0.0000000e+0 0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.99542425 9.4554828e-2 -1.3782283e-2 +vn 0.0000000e+0 -0.98954338 0.14423554 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn -0.99542425 9.4554828e-2 -1.3782283e-2 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.98954338 0.14423554 +vn -0.99542425 9.4554828e-2 -1.3782283e-2 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.99996209 -8.5203181e-3 1.7937935e-3 +vn 0.99996209 -8.5203181e-3 1.7937935e-3 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.0000000e+0 0.33009742 0.94394687 +vn -0.99996209 -8.5203181e-3 1.7937935e-3 +vn -0.99996209 -8.5203181e-3 1.7937935e-3 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn -0.99996209 -8.5203181e-3 -1.7937935e-3 +vn -0.99996209 -8.5203181e-3 -1.7937935e-3 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.99996209 -8.5203181e-3 -1.7937935e-3 +vn 0.99996209 -8.5203181e-3 -1.7937935e-3 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 1.00000000 4.5028926e-17 -1.3509582e-16 +vn 1.00000000 4.5028926e-17 -1.3509582e-16 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 0.0000000e+0 0.80136485 0.59817588 +vn -1.00000000 -5.2533747e-17 1.5761179e-16 +vn -1.00000000 -5.2533747e-17 1.5761179e-16 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn -1.00000000 -5.2533747e-17 1.5761179e-16 +vn -1.00000000 -5.2533747e-17 1.5761179e-16 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn 1.00000000 4.5028926e-17 -1.3509582e-16 +vn 1.00000000 4.5028926e-17 -1.3509582e-16 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn -1.00000000 1.9093460e-6 8.8012858e-7 +vn -1.00000000 1.9093460e-6 8.8012858e-7 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 1.00000000 1.9093460e-6 8.8012858e-7 +vn 1.00000000 1.9093460e-6 8.8012858e-7 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 1.00000000 1.9093460e-6 -8.8012858e-7 +vn 1.00000000 1.9093460e-6 -8.8012858e-7 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn -1.00000000 1.9093460e-6 -8.8012858e-7 +vn -1.00000000 1.9093460e-6 -8.8012858e-7 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 0.99726330 -7.3931730e-2 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.99726330 -7.3931730e-2 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 0.99726330 7.3931730e-2 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.99726330 7.3931730e-2 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 0.99726330 -7.3931730e-2 +vn -0.99984837 -1.7039990e-2 3.5874509e-3 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.99984837 -1.7039990e-2 3.5874509e-3 +vn 0.0000000e+0 0.99726330 -7.3931730e-2 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn -0.99984837 -1.7039990e-2 -3.5874509e-3 +vn 0.0000000e+0 0.99726330 7.3931730e-2 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 0.99726330 7.3931730e-2 +vn 0.99984837 -1.7039990e-2 -3.5874509e-3 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn -1.00000000 1.4353171e-6 -5.8675239e-7 +vn -1.00000000 1.4353171e-6 -5.8675239e-7 +vn -1.00000000 1.4353171e-6 -5.8675239e-7 +vn -1.5978431e-7 -0.11069599 0.99385431 +vn 1.4434517e-6 1.00000000 0.0000000e+0 +vn -1.00000000 1.4353171e-6 5.8675239e-7 +vn -1.00000000 1.4353171e-6 5.8675239e-7 +vn 1.4434517e-6 1.00000000 0.0000000e+0 +vn -1.5978431e-7 -0.11069599 -0.99385431 +vn -1.00000000 1.4353171e-6 5.8675239e-7 +vn -1.00000000 8.5018052e-7 5.0354486e-7 +vn -1.00000000 8.5018052e-7 5.0354486e-7 +vn -5.2739296e-7 -0.36536933 -0.93086264 +vn -5.2739296e-7 -0.36536933 -0.93086264 +vn -1.00000000 1.6501300e-7 1.3893582e-7 +vn -1.00000000 1.6501300e-7 1.3893582e-7 +vn -1.1846912e-6 -0.82073495 -0.57130915 +vn -1.1846912e-6 -0.82073495 -0.57130915 +vn -1.00000000 2.8659374e-7 0.0000000e+0 +vn -1.00000000 2.8659374e-7 0.0000000e+0 +vn -1.4434517e-6 -1.00000000 0.0000000e+0 +vn -1.4434517e-6 -1.00000000 0.0000000e+0 +vn -1.00000000 1.6501300e-7 -1.3893582e-7 +vn -1.00000000 1.6501300e-7 -1.3893582e-7 +vn -1.1846912e-6 -0.82073495 0.57130915 +vn -1.1846912e-6 -0.82073495 0.57130915 +vn -1.00000000 8.5018052e-7 -5.0354486e-7 +vn -1.00000000 8.5018052e-7 -5.0354486e-7 +vn -5.2739296e-7 -0.36536933 0.93086264 +vn -5.2739296e-7 -0.36536933 0.93086264 +vn 1.00000000 1.4353171e-6 5.8675239e-7 +vn 1.00000000 1.4353171e-6 5.8675239e-7 +vn 1.00000000 1.4353171e-6 5.8675239e-7 +vn 1.5978431e-7 -0.11069599 -0.99385431 +vn -1.4434517e-6 1.00000000 0.0000000e+0 +vn 1.00000000 1.4353171e-6 -5.8675239e-7 +vn 1.00000000 1.4353171e-6 -5.8675239e-7 +vn -1.4434517e-6 1.00000000 0.0000000e+0 +vn 1.5978431e-7 -0.11069599 0.99385431 +vn 1.00000000 1.4353171e-6 -5.8675239e-7 +vn 1.00000000 8.5018052e-7 -5.0354486e-7 +vn 1.00000000 8.5018052e-7 -5.0354486e-7 +vn 5.2739296e-7 -0.36536933 0.93086264 +vn 5.2739296e-7 -0.36536933 0.93086264 +vn 1.00000000 1.6501300e-7 -1.3893582e-7 +vn 1.00000000 1.6501300e-7 -1.3893582e-7 +vn 1.1846912e-6 -0.82073495 0.57130915 +vn 1.1846912e-6 -0.82073495 0.57130915 +vn 1.00000000 2.8659374e-7 0.0000000e+0 +vn 1.00000000 2.8659374e-7 0.0000000e+0 +vn 1.4434517e-6 -1.00000000 0.0000000e+0 +vn 1.4434517e-6 -1.00000000 0.0000000e+0 +vn 1.00000000 1.6501300e-7 1.3893582e-7 +vn 1.00000000 1.6501300e-7 1.3893582e-7 +vn 1.1846912e-6 -0.82073495 -0.57130915 +vn 1.1846912e-6 -0.82073495 -0.57130915 +vn 1.00000000 8.5018052e-7 5.0354486e-7 +vn 1.00000000 8.5018052e-7 5.0354486e-7 +vn 5.2739296e-7 -0.36536933 -0.93086264 +vn 5.2739296e-7 -0.36536933 -0.93086264 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 2.4251721e-2 0.18376529 0.98267094 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 -0.99140393 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 -0.99140393 0.0000000e+0 +vn 2.4251721e-2 0.18376529 -0.98267094 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 2.4251721e-2 0.18376529 0.98267094 +vn 0.13083674 0.99140393 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 2.4251721e-2 0.18376529 -0.98267094 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -2.4251721e-2 0.18376529 0.98267094 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 0.99140393 0.0000000e+0 +vn -2.4251721e-2 0.18376529 -0.98267094 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -2.4251721e-2 0.18376529 0.98267094 +vn 0.13083674 -0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -2.4251721e-2 0.18376529 -0.98267094 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 -0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -2.4251721e-2 0.18376529 0.98267094 +vn 0.13083674 -0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -2.4251721e-2 0.18376529 0.98267094 +vn -0.13083674 0.99140393 0.0000000e+0 +vn -0.13083674 0.99140393 0.0000000e+0 +vn -2.4251721e-2 0.18376529 -0.98267094 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -2.4251721e-2 0.18376529 -0.98267094 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 -0.99140393 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 2.4251721e-2 0.18376529 0.98267094 +vn 0.13083674 0.99140393 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 2.4251721e-2 0.18376529 0.98267094 +vn -0.13083674 -0.99140393 0.0000000e+0 +vn -0.13083674 -0.99140393 0.0000000e+0 +vn 2.4251721e-2 0.18376529 -0.98267094 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 2.4251721e-2 0.18376529 -0.98267094 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 0.99140393 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 1.5978431e-7 -0.11069599 -0.99385431 +vn -1.4434517e-6 1.00000000 0.0000000e+0 +vn 1.00000000 1.4434517e-6 4.9235150e-7 +vn 1.00000000 1.4434517e-6 -4.9235150e-7 +vn -1.4434517e-6 1.00000000 0.0000000e+0 +vn 1.5978431e-7 -0.11069599 0.99385431 +vn 1.00000000 1.4434517e-6 -4.9235150e-7 +vn 5.2739296e-7 -0.36536933 0.93086264 +vn 5.2739296e-7 -0.36536933 0.93086264 +vn 1.00000000 1.4434517e-6 -4.9235150e-7 +vn 1.1846912e-6 -0.82073495 0.57130915 +vn 1.1846912e-6 -0.82073495 0.57130915 +vn 1.00000000 1.4434517e-6 0.0000000e+0 +vn 1.4434517e-6 -1.00000000 0.0000000e+0 +vn 1.4434517e-6 -1.00000000 0.0000000e+0 +vn 1.00000000 1.4434517e-6 0.0000000e+0 +vn 1.1846912e-6 -0.82073495 -0.57130915 +vn 1.1846912e-6 -0.82073495 -0.57130915 +vn 1.00000000 1.4434517e-6 4.9235150e-7 +vn 5.2739296e-7 -0.36536933 -0.93086264 +vn 5.2739296e-7 -0.36536933 -0.93086264 +vn 1.00000000 1.4434517e-6 4.9235150e-7 +vn -1.5978431e-7 -0.11069599 0.99385431 +vn 1.4434517e-6 1.00000000 0.0000000e+0 +vn -1.00000000 1.4434517e-6 -4.9235150e-7 +vn -1.00000000 1.4434517e-6 4.9235150e-7 +vn 1.4434517e-6 1.00000000 0.0000000e+0 +vn -1.5978431e-7 -0.11069599 -0.99385431 +vn -1.00000000 1.4434517e-6 4.9235150e-7 +vn -5.2739296e-7 -0.36536933 -0.93086264 +vn -5.2739296e-7 -0.36536933 -0.93086264 +vn -1.00000000 1.4434517e-6 4.9235150e-7 +vn -1.1846912e-6 -0.82073495 -0.57130915 +vn -1.1846912e-6 -0.82073495 -0.57130915 +vn -1.00000000 1.4434517e-6 0.0000000e+0 +vn -1.4434517e-6 -1.00000000 0.0000000e+0 +vn -1.4434517e-6 -1.00000000 0.0000000e+0 +vn -1.00000000 1.4434517e-6 0.0000000e+0 +vn -1.1846912e-6 -0.82073495 0.57130915 +vn -1.1846912e-6 -0.82073495 0.57130915 +vn -1.00000000 1.4434517e-6 -4.9235150e-7 +vn -5.2739296e-7 -0.36536933 0.93086264 +vn -5.2739296e-7 -0.36536933 0.93086264 +vn -1.00000000 1.4434517e-6 -4.9235150e-7 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.99542425 9.4554828e-2 -1.3782283e-2 +vn 0.0000000e+0 0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.99542425 9.4554828e-2 -1.3782283e-2 +vn 0.0000000e+0 -0.98954338 0.14423554 +vn 0.0000000e+0 -0.98954338 0.14423554 +vn -0.99542425 9.4554828e-2 -1.3782283e-2 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn -0.99542425 9.4554828e-2 -1.3782283e-2 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.99542425 9.4554828e-2 1.3782283e-2 +vn 0.0000000e+0 -0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.99542425 9.4554828e-2 1.3782283e-2 +vn 0.0000000e+0 0.98954338 0.14423554 +vn 0.0000000e+0 0.98954338 0.14423554 +vn -0.99542425 9.4554828e-2 1.3782283e-2 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn -0.99542425 9.4554828e-2 1.3782283e-2 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.98954338 -0.14423554 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 1.00000000 -2.9149138e-17 +vn 0.0000000e+0 1.00000000 -2.9149138e-17 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.0000000e+0 0.33009742 0.94394687 +vn -0.99996209 -8.5203181e-3 1.7937935e-3 +vn -0.99996209 -8.5203181e-3 1.7937935e-3 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn -0.99996209 -8.5203181e-3 -1.7937935e-3 +vn -0.99996209 -8.5203181e-3 -1.7937935e-3 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 0.0000000e+0 0.80136485 0.59817588 +vn -1.00000000 -5.2533747e-17 1.5761179e-16 +vn -1.00000000 -5.2533747e-17 1.5761179e-16 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 1.00000000 -2.9149138e-17 +vn 0.0000000e+0 1.00000000 -2.9149138e-17 +vn -1.00000000 -5.2533747e-17 1.5761179e-16 +vn -1.00000000 -5.2533747e-17 1.5761179e-16 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.99726330 -7.3931730e-2 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 0.99726330 -7.3931730e-2 +vn -0.99984837 -1.7039990e-2 3.5874509e-3 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn -0.99984837 -1.7039990e-2 -3.5874509e-3 +vn 0.0000000e+0 0.99726330 7.3931730e-2 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 0.99726330 7.3931730e-2 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.0000000e+0 0.33009742 0.94394687 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 0.0000000e+0 0.80136485 0.59817588 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 1.00000000 -2.9149138e-17 +vn 0.0000000e+0 1.00000000 -2.9149138e-17 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.0000000e+0 0.33009742 0.94394687 +vn 0.99996209 -8.5203181e-3 1.7937935e-3 +vn 0.99996209 -8.5203181e-3 1.7937935e-3 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.0000000e+0 0.33009742 -0.94394687 +vn 0.99996209 -8.5203181e-3 -1.7937935e-3 +vn 0.99996209 -8.5203181e-3 -1.7937935e-3 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 0.0000000e+0 0.80136485 0.59817588 +vn 1.00000000 4.5028926e-17 -1.3509582e-16 +vn 1.00000000 4.5028926e-17 -1.3509582e-16 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 0.0000000e+0 0.80136485 -0.59817588 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 1.00000000 -2.9149138e-17 +vn 0.0000000e+0 1.00000000 -2.9149138e-17 +vn 1.00000000 4.5028926e-17 -1.3509582e-16 +vn 1.00000000 4.5028926e-17 -1.3509582e-16 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.99984837 -1.7039990e-2 3.5874509e-3 +vn 0.0000000e+0 0.99726330 -7.3931730e-2 +vn 0.0000000e+0 7.3931730e-2 0.99726330 +vn 0.0000000e+0 0.99726330 -7.3931730e-2 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.99726330 7.3931730e-2 +vn 0.0000000e+0 7.3931730e-2 -0.99726330 +vn 0.0000000e+0 0.99726330 7.3931730e-2 +vn 0.99984837 -1.7039990e-2 -3.5874509e-3 +vn -1.00000000 4.8725914e-7 0.0000000e+0 +vn 1.4434517e-6 1.00000000 0.0000000e+0 +vn -1.00000000 4.8725914e-7 0.0000000e+0 +vn 1.4434517e-6 1.00000000 0.0000000e+0 +vn 1.00000000 4.8725914e-7 0.0000000e+0 +vn -1.4434517e-6 1.00000000 0.0000000e+0 +vn 1.00000000 4.8725914e-7 0.0000000e+0 +vn -1.4434517e-6 1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 -0.99140393 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 -0.99140393 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 0.99140393 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 -0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 -0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 -0.99140393 0.0000000e+0 +vn -0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 -0.99140393 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 -0.99140393 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn -0.13083674 -0.99140393 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 0.99140393 0.0000000e+0 +vn 0.99140393 -0.13083674 0.0000000e+0 +vn 0.13083674 0.99140393 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 1.00000000 1.4434517e-6 0.0000000e+0 +vn -1.4434517e-6 1.00000000 0.0000000e+0 +vn -1.4434517e-6 1.00000000 0.0000000e+0 +vn 1.00000000 1.4434517e-6 0.0000000e+0 +vn -1.00000000 1.4434517e-6 0.0000000e+0 +vn 1.4434517e-6 1.00000000 0.0000000e+0 +vn 1.4434517e-6 1.00000000 0.0000000e+0 +vn -1.00000000 1.4434517e-6 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 0.98954338 0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 0.98954338 0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.98954338 0.14423554 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.98954338 0.14423554 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.98954338 0.14423554 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 -0.98954338 0.14423554 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 -0.98954338 +vn 0.0000000e+0 0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 0.98954338 0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 0.98954338 0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.98954338 -0.14423554 +vn 0.0000000e+0 -0.14423554 0.98954338 +vn 0.0000000e+0 -0.98954338 -0.14423554 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 -0.81081265 -0.58530578 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.81081265 -0.58530578 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.81081265 -0.58530578 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -0.81081265 -0.58530578 +vn 0.0000000e+0 -0.45535383 -0.89031056 +vn 0.0000000e+0 -0.45535383 -0.89031056 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.45535383 -0.89031056 +vn 0.0000000e+0 0.45535383 -0.89031056 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.45535383 -0.89031056 +vn 0.0000000e+0 0.45535383 -0.89031056 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -0.45535383 -0.89031056 +vn 0.0000000e+0 -0.45535383 -0.89031056 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 -0.81081265 -0.58530578 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.81081265 -0.58530578 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.81081265 -0.58530578 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -0.81081265 -0.58530578 +vn 0.0000000e+0 -0.45535383 -0.89031056 +vn 0.0000000e+0 -0.45535383 -0.89031056 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.45535383 -0.89031056 +vn 0.0000000e+0 0.45535383 -0.89031056 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.45535383 -0.89031056 +vn 0.0000000e+0 0.45535383 -0.89031056 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 -0.45535383 -0.89031056 +vn 0.0000000e+0 -0.45535383 -0.89031056 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.34593579 -0.93825819 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.34593579 0.93825819 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.34593579 0.93825819 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.34593579 -0.93825819 0.0000000e+0 +vn 0.34593579 -0.93825819 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.34593579 0.93825819 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.34593579 0.93825819 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.34593579 -0.93825819 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -0.34593579 -0.93825819 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -0.34593579 0.93825819 0.0000000e+0 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -0.34593579 0.93825819 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -0.34593579 -0.93825819 0.0000000e+0 +vn -0.34593579 -0.93825819 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn -0.34593579 0.93825819 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -0.34593579 0.93825819 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn -0.34593579 -0.93825819 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 0.70710678 0.0000000e+0 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.70710678 -0.70710678 -7.5831307e-17 +vn 0.70710678 0.70710678 -7.5831307e-17 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.70710678 0.70710678 -9.3346967e-16 +vn 0.70710678 0.70710678 -9.3346967e-16 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 -0.70710678 5.0916528e-16 +vn -0.70710678 -0.70710678 5.0916528e-16 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.70710678 0.70710678 5.0916528e-16 +vn 0.70710678 0.70710678 5.0916528e-16 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 0.70710678 0.0000000e+0 +vn -0.70710678 -0.70710678 -5.0916528e-16 +vn -0.70710678 -0.70710678 -5.0916528e-16 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.70710678 0.70710678 0.0000000e+0 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn -0.70710678 0.70710678 -9.3346967e-16 +vn -0.70710678 0.70710678 -9.3346967e-16 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.70710678 -0.70710678 5.0916528e-16 +vn 0.70710678 -0.70710678 5.0916528e-16 +vn 0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.70710678 -0.70710678 -4.2430440e-16 +vn 0.70710678 -0.70710678 -4.2430440e-16 +vn 0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 0.70710678 5.0916528e-16 +vn -0.70710678 0.70710678 5.0916528e-16 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn 0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.70710678 -0.70710678 1.0183306e-15 +vn 0.70710678 0.70710678 1.0183306e-15 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.70710678 0.70710678 -1.8669393e-15 +vn -0.70710678 0.70710678 -1.8669393e-15 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 -0.70710678 -1.0183306e-15 +vn 0.70710678 -0.70710678 -8.4860879e-16 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 0.70710678 1.0183306e-15 +vn -0.70710678 -0.70710678 1.0183306e-15 +vn -0.70710678 0.70710678 0.0000000e+0 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.70710678 0.70710678 5.0916528e-16 +vn 0.70710678 0.70710678 5.0916528e-16 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.70710678 -0.70710678 5.0916528e-16 +vn 0.70710678 -0.70710678 5.0916528e-16 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.70710678 -0.70710678 1.0183306e-15 +vn 0.70710678 0.70710678 1.0183306e-15 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.70710678 0.70710678 -9.3346967e-16 +vn 0.70710678 0.70710678 -9.3346967e-16 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 0.70710678 -9.3346967e-16 +vn -0.70710678 0.70710678 -9.3346967e-16 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.70710678 0.70710678 -1.8669393e-15 +vn -0.70710678 0.70710678 -1.8669393e-15 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.70710678 0.70710678 0.0000000e+0 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 0.70710678 0.0000000e+0 +vn -0.70710678 -0.70710678 -5.0916528e-16 +vn -0.70710678 -0.70710678 -5.0916528e-16 +vn 0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.70710678 -0.70710678 -4.2430440e-16 +vn 0.70710678 -0.70710678 -4.2430440e-16 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.70710678 0.70710678 0.0000000e+0 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 -0.70710678 -1.0183306e-15 +vn 0.70710678 -0.70710678 -8.4860879e-16 +vn 0.70710678 -0.70710678 -7.5831307e-17 +vn 0.70710678 0.70710678 -7.5831307e-17 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.70710678 -0.70710678 -7.5831307e-17 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 -0.70710678 5.0916528e-16 +vn -0.70710678 -0.70710678 5.0916528e-16 +vn 0.70710678 0.70710678 -7.5831307e-17 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 0.70710678 5.0916528e-16 +vn -0.70710678 0.70710678 5.0916528e-16 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn -0.70710678 0.70710678 1.0183306e-15 +vn -0.70710678 -0.70710678 1.0183306e-15 +vn 0.70710678 0.70710678 -7.5831307e-17 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.70710678 -0.70710678 -7.5831307e-17 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +vn 0.57735027 0.37192549 0.72686869 +vn 0.57735027 0.72686869 -0.37192549 +vn 0.0000000e+0 -0.95158367 -0.30738983 +vn -0.57735027 0.37192549 0.72686869 +vn -0.57735027 0.72686869 -0.37192549 +vn 0.0000000e+0 -0.95158367 -0.30738983 +vn 0.57735027 0.37192549 0.72686869 +vn -0.57735027 0.37192549 0.72686869 +vn 0.57735027 0.72686869 -0.37192549 +vn -0.57735027 0.72686869 -0.37192549 +vn 0.57735027 0.37192549 0.72686869 +vn -0.57735027 0.37192549 0.72686869 +vn 0.0000000e+0 -0.95158367 -0.30738983 +vn 0.57735027 0.72686869 -0.37192549 +vn -0.57735027 0.72686869 -0.37192549 +vn 0.0000000e+0 -0.95158367 -0.30738983 +vn 0.57735027 0.61637670 0.53548709 +vn 0.57735027 -0.53548709 0.61637670 +vn 0.0000000e+0 -7.0052454e-2 -0.99754331 +vn -0.57735027 0.61637670 0.53548709 +vn -0.57735027 -0.53548709 0.61637670 +vn 0.0000000e+0 -7.0052454e-2 -0.99754331 +vn 0.57735027 0.61637670 0.53548709 +vn -0.57735027 0.61637670 0.53548709 +vn 0.0000000e+0 -7.0052454e-2 -0.99754331 +vn 0.57735027 -0.53548709 0.61637670 +vn -0.57735027 -0.53548709 0.61637670 +vn 0.0000000e+0 -7.0052454e-2 -0.99754331 +vn 0.57735027 0.61637670 0.53548709 +vn -0.57735027 0.61637670 0.53548709 +vn 0.57735027 -0.53548709 0.61637670 +vn -0.57735027 -0.53548709 0.61637670 +vn 0.57735027 -0.15565500 0.80152242 +vn 0.57735027 0.80152242 0.15565500 +vn 0.0000000e+0 -0.55933759 -0.82893996 +vn -0.57735027 -0.15565500 0.80152242 +vn -0.57735027 0.80152242 0.15565500 +vn 0.0000000e+0 -0.55933759 -0.82893996 +vn 0.57735027 -0.15565500 0.80152242 +vn -0.57735027 -0.15565500 0.80152242 +vn 0.57735027 0.80152242 0.15565500 +vn -0.57735027 0.80152242 0.15565500 +vn 0.57735027 -0.15565500 0.80152242 +vn -0.57735027 -0.15565500 0.80152242 +vn 0.0000000e+0 -0.55933759 -0.82893996 +vn 0.57735027 0.80152242 0.15565500 +vn -0.57735027 0.80152242 0.15565500 +vn 0.0000000e+0 -0.55933759 -0.82893996 +vn -0.57735027 0.37192549 -0.72686869 +vn -0.57735027 0.72686869 0.37192549 +vn 0.0000000e+0 -0.95158367 0.30738983 +vn 0.57735027 0.37192549 -0.72686869 +vn 0.57735027 0.72686869 0.37192549 +vn 0.0000000e+0 -0.95158367 0.30738983 +vn -0.57735027 0.37192549 -0.72686869 +vn 0.57735027 0.37192549 -0.72686869 +vn -0.57735027 0.72686869 0.37192549 +vn 0.57735027 0.72686869 0.37192549 +vn -0.57735027 0.37192549 -0.72686869 +vn 0.57735027 0.37192549 -0.72686869 +vn 0.0000000e+0 -0.95158367 0.30738983 +vn -0.57735027 0.72686869 0.37192549 +vn 0.57735027 0.72686869 0.37192549 +vn 0.0000000e+0 -0.95158367 0.30738983 +vn -0.57735027 0.61637670 -0.53548709 +vn -0.57735027 -0.53548709 -0.61637670 +vn 0.0000000e+0 -7.0052454e-2 0.99754331 +vn 0.57735027 0.61637670 -0.53548709 +vn 0.57735027 -0.53548709 -0.61637670 +vn 0.0000000e+0 -7.0052454e-2 0.99754331 +vn -0.57735027 0.61637670 -0.53548709 +vn 0.57735027 0.61637670 -0.53548709 +vn 0.0000000e+0 -7.0052454e-2 0.99754331 +vn -0.57735027 -0.53548709 -0.61637670 +vn 0.57735027 -0.53548709 -0.61637670 +vn 0.0000000e+0 -7.0052454e-2 0.99754331 +vn -0.57735027 0.61637670 -0.53548709 +vn 0.57735027 0.61637670 -0.53548709 +vn -0.57735027 -0.53548709 -0.61637670 +vn 0.57735027 -0.53548709 -0.61637670 +vn -0.57735027 -0.15565500 -0.80152242 +vn -0.57735027 0.80152242 -0.15565500 +vn 0.0000000e+0 -0.55933759 0.82893996 +vn 0.57735027 -0.15565500 -0.80152242 +vn 0.57735027 0.80152242 -0.15565500 +vn 0.0000000e+0 -0.55933759 0.82893996 +vn -0.57735027 -0.15565500 -0.80152242 +vn 0.57735027 -0.15565500 -0.80152242 +vn -0.57735027 0.80152242 -0.15565500 +vn 0.57735027 0.80152242 -0.15565500 +vn -0.57735027 -0.15565500 -0.80152242 +vn 0.57735027 -0.15565500 -0.80152242 +vn 0.0000000e+0 -0.55933759 0.82893996 +vn -0.57735027 0.80152242 -0.15565500 +vn 0.57735027 0.80152242 -0.15565500 +vn 0.0000000e+0 -0.55933759 0.82893996 +vn 0.57735027 0.37192549 0.72686869 +vn 0.57735027 0.72686869 -0.37192549 +vn 0.0000000e+0 -0.95158367 -0.30738983 +vn -0.57735027 0.37192549 0.72686869 +vn -0.57735027 0.72686869 -0.37192549 +vn 0.0000000e+0 -0.95158367 -0.30738983 +vn 0.57735027 0.37192549 0.72686869 +vn -0.57735027 0.37192549 0.72686869 +vn 0.57735027 0.72686869 -0.37192549 +vn -0.57735027 0.72686869 -0.37192549 +vn 0.57735027 0.37192549 0.72686869 +vn -0.57735027 0.37192549 0.72686869 +vn 0.0000000e+0 -0.95158367 -0.30738983 +vn 0.57735027 0.72686869 -0.37192549 +vn -0.57735027 0.72686869 -0.37192549 +vn 0.0000000e+0 -0.95158367 -0.30738983 +vn 0.57735027 0.61637670 0.53548709 +vn 0.57735027 -0.53548709 0.61637670 +vn 0.0000000e+0 -7.0052454e-2 -0.99754331 +vn -0.57735027 0.61637670 0.53548709 +vn -0.57735027 -0.53548709 0.61637670 +vn 0.0000000e+0 -7.0052454e-2 -0.99754331 +vn 0.57735027 0.61637670 0.53548709 +vn -0.57735027 0.61637670 0.53548709 +vn 0.0000000e+0 -7.0052454e-2 -0.99754331 +vn 0.57735027 -0.53548709 0.61637670 +vn -0.57735027 -0.53548709 0.61637670 +vn 0.0000000e+0 -7.0052454e-2 -0.99754331 +vn 0.57735027 0.61637670 0.53548709 +vn -0.57735027 0.61637670 0.53548709 +vn 0.57735027 -0.53548709 0.61637670 +vn -0.57735027 -0.53548709 0.61637670 +vn 0.57735027 -0.15565500 0.80152242 +vn 0.57735027 0.80152242 0.15565500 +vn 0.0000000e+0 -0.55933759 -0.82893996 +vn -0.57735027 -0.15565500 0.80152242 +vn -0.57735027 0.80152242 0.15565500 +vn 0.0000000e+0 -0.55933759 -0.82893996 +vn 0.57735027 -0.15565500 0.80152242 +vn -0.57735027 -0.15565500 0.80152242 +vn 0.57735027 0.80152242 0.15565500 +vn -0.57735027 0.80152242 0.15565500 +vn 0.57735027 -0.15565500 0.80152242 +vn -0.57735027 -0.15565500 0.80152242 +vn 0.0000000e+0 -0.55933759 -0.82893996 +vn 0.57735027 0.80152242 0.15565500 +vn -0.57735027 0.80152242 0.15565500 +vn 0.0000000e+0 -0.55933759 -0.82893996 +vn -0.57735027 0.37192549 -0.72686869 +vn -0.57735027 0.72686869 0.37192549 +vn 0.0000000e+0 -0.95158367 0.30738983 +vn 0.57735027 0.37192549 -0.72686869 +vn 0.57735027 0.72686869 0.37192549 +vn 0.0000000e+0 -0.95158367 0.30738983 +vn -0.57735027 0.37192549 -0.72686869 +vn 0.57735027 0.37192549 -0.72686869 +vn -0.57735027 0.72686869 0.37192549 +vn 0.57735027 0.72686869 0.37192549 +vn -0.57735027 0.37192549 -0.72686869 +vn 0.57735027 0.37192549 -0.72686869 +vn 0.0000000e+0 -0.95158367 0.30738983 +vn -0.57735027 0.72686869 0.37192549 +vn 0.57735027 0.72686869 0.37192549 +vn 0.0000000e+0 -0.95158367 0.30738983 +vn -0.57735027 0.61637670 -0.53548709 +vn -0.57735027 -0.53548709 -0.61637670 +vn 0.0000000e+0 -7.0052454e-2 0.99754331 +vn 0.57735027 0.61637670 -0.53548709 +vn 0.57735027 -0.53548709 -0.61637670 +vn 0.0000000e+0 -7.0052454e-2 0.99754331 +vn -0.57735027 0.61637670 -0.53548709 +vn 0.57735027 0.61637670 -0.53548709 +vn 0.0000000e+0 -7.0052454e-2 0.99754331 +vn -0.57735027 -0.53548709 -0.61637670 +vn 0.57735027 -0.53548709 -0.61637670 +vn 0.0000000e+0 -7.0052454e-2 0.99754331 +vn -0.57735027 0.61637670 -0.53548709 +vn 0.57735027 0.61637670 -0.53548709 +vn -0.57735027 -0.53548709 -0.61637670 +vn 0.57735027 -0.53548709 -0.61637670 +vn -0.57735027 -0.15565500 -0.80152242 +vn -0.57735027 0.80152242 -0.15565500 +vn 0.0000000e+0 -0.55933759 0.82893996 +vn 0.57735027 -0.15565500 -0.80152242 +vn 0.57735027 0.80152242 -0.15565500 +vn 0.0000000e+0 -0.55933759 0.82893996 +vn -0.57735027 -0.15565500 -0.80152242 +vn 0.57735027 -0.15565500 -0.80152242 +vn -0.57735027 0.80152242 -0.15565500 +vn 0.57735027 0.80152242 -0.15565500 +vn -0.57735027 -0.15565500 -0.80152242 +vn 0.57735027 -0.15565500 -0.80152242 +vn 0.0000000e+0 -0.55933759 0.82893996 +vn -0.57735027 0.80152242 -0.15565500 +vn 0.57735027 0.80152242 -0.15565500 +vn 0.0000000e+0 -0.55933759 0.82893996 +g chest_Chest +usemtl Chest +s 1 +f 45/80/244 143/76/606 212/12/845 198/16/805 +f 47/77/254 198/13/807 212/9/847 146/73/615 +f 50/79/268 140/75/596 139/67/593 49/71/263 +f 51/70/272 142/66/601 141/74/599 52/78/278 +f 71/105/339 172/81/712 171/38/710 76/47/365 +f 73/107/349 160/84/666 159/45/664 77/59/370 +f 75/60/358 158/46/660 157/85/658 72/108/345 +f 78/58/373 174/44/718 173/83/716 74/106/355 +f 86/237/410 176/344/727 193/354/786 125/245/549 +f 87/238/413 126/247/552 193/356/785 176/346/725 +f 103/116/464 123/101/542 191/132/776 182/136/741 +f 104/114/471 182/133/743 191/130/778 122/98/540 +f 105/218/474 118/228/528 117/234/525 107/210/485 +f 108/205/489 120/227/533 119/225/531 106/215/481 +f 109/211/494 114/235/516 113/229/513 111/219/505 +f 112/220/509 116/230/521 115/236/519 110/212/501 +f 121/99/537 192/129/781 181/134/737 102/113/459 +f 133/248/573 134/256/576 135/274/579 136/366/582 194/357/788 +f 137/272/588 138/255/591 132/246/572 194/355/791 136/364/585 +f 181/135/739 192/131/782 124/100/546 101/115/456 +f 197/24/803 211/20/843 144/68/609 46/72/249 +f 211/17/841 197/21/801 48/69/258 145/65/610 +f 215/315/853 219/306/865 218/305/862 214/311/850 +f 217/189/858 221/194/869 220/193/866 216/187/855 +f 222/190/872 225/313/881 224/314/878 223/186/875 +f 230/328/897 234/446/908 237/433/918 233/350/907 +f 232/352/904 236/435/915 235/445/911 231/331/900 +f 238/203/20 244/299/26 251/303/33 245/197/27 +f 238/203/20 245/197/27 246/177/28 239/179/21 +f 239/179/21 246/177/28 247/195/29 240/201/22 +f 239/179/21 260/180/42 259/208/41 238/203/20 +f 240/201/22 247/195/29 248/257/30 241/259/23 +f 240/201/22 261/206/43 260/180/42 239/179/21 +f 241/259/23 248/257/30 249/310/31 242/301/24 +f 241/259/23 262/262/44 261/206/43 240/201/22 +f 242/301/24 249/310/31 250/362/32 243/349/25 +f 242/301/24 263/298/45 262/262/44 241/259/23 +f 243/349/25 250/362/32 251/303/33 244/299/26 +f 243/349/25 264/323/46 263/298/45 242/301/24 +f 244/299/26 265/295/47 264/323/46 243/349/25 +f 245/221/27 251/289/33 258/293/40 252/213/34 +f 245/221/27 252/213/34 253/191/35 246/199/28 +f 246/199/28 253/191/35 254/216/36 247/223/29 +f 247/223/29 254/216/36 255/263/37 248/266/30 +f 248/266/30 255/263/37 256/291/38 249/285/31 +f 249/285/31 256/291/38 257/316/39 250/307/32 +f 250/307/32 257/316/39 258/293/40 251/289/33 +f 252/213/34 258/293/40 265/295/47 259/208/41 +f 252/213/34 259/208/41 260/180/42 253/191/35 +f 253/191/35 260/180/42 261/206/43 254/216/36 +f 254/216/36 261/206/43 262/262/44 255/263/37 +f 255/263/37 262/262/44 263/298/45 256/291/38 +f 256/291/38 263/298/45 264/323/46 257/316/39 +f 257/316/39 264/323/46 265/295/47 258/293/40 +f 259/208/41 265/295/47 244/299/26 238/203/20 +f 267/526/925 271/494/937 270/492/934 266/524/922 +f 269/351/930 273/434/941 272/435/938 268/353/927 +f 274/204/48 280/300/54 287/304/61 281/198/55 +f 274/204/48 281/198/55 282/177/56 275/178/49 +f 275/178/49 282/177/56 283/196/57 276/202/50 +f 275/178/49 296/181/70 295/209/69 274/204/48 +f 276/202/50 283/196/57 284/258/58 277/260/51 +f 276/202/50 297/207/71 296/181/70 275/178/49 +f 277/260/51 284/258/58 285/309/59 278/302/52 +f 277/260/51 298/261/72 297/207/71 276/202/50 +f 278/302/52 285/309/59 286/362/60 279/348/53 +f 278/302/52 299/297/73 298/261/72 277/260/51 +f 279/348/53 286/362/60 287/304/61 280/300/54 +f 279/348/53 300/324/74 299/297/73 278/302/52 +f 280/300/54 301/296/75 300/324/74 279/348/53 +f 281/222/55 287/290/61 294/294/68 288/214/62 +f 281/222/55 288/214/62 289/192/63 282/200/56 +f 282/200/56 289/192/63 290/217/64 283/224/57 +f 283/224/57 290/217/64 291/264/65 284/265/58 +f 284/265/58 291/264/65 292/292/66 285/284/59 +f 285/284/59 292/292/66 293/317/67 286/308/60 +f 286/308/60 293/317/67 294/294/68 287/290/61 +f 288/214/62 294/294/68 301/296/75 295/209/69 +f 288/214/62 295/209/69 296/181/70 289/192/63 +f 289/192/63 296/181/70 297/207/71 290/217/64 +f 290/217/64 297/207/71 298/261/72 291/264/65 +f 291/264/65 298/261/72 299/297/73 292/292/66 +f 292/292/66 299/297/73 300/324/74 293/317/67 +f 293/317/67 300/324/74 301/296/75 294/294/68 +f 295/209/69 301/296/75 280/300/54 274/204/48 +f 305/529/953 353/522/1115 357/530/1129 352/547/1111 +f 310/510/956 314/517/973 315/528/977 311/520/960 +f 312/465/967 335/464/1055 338/476/1065 326/479/1032 +f 313/483/971 328/503/1041 351/500/1109 347/489/1097 +f 316/455/985 337/449/1061 335/464/1054 312/465/966 +f 319/466/997 323/458/1015 322/475/1010 318/480/993 +f 321/519/1004 325/533/1024 324/518/1018 320/512/1000 +f 334/436/1049 339/454/1066 336/463/1057 303/450/949 +f 342/488/1077 345/478/1087 340/496/1070 302/498/945 +f 347/489/1096 349/477/1104 317/467/991 313/483/970 +f 348/509/1098 350/516/1105 346/501/1090 304/497/950 +f 360/419/1138 361/423/1142 358/460/1132 +f 360/419/1141 362/427/1146 359/371/1136 +f 363/456/1149 367/408/1162 366/404/1157 +f 364/369/1151 367/408/1161 365/405/1155 +f 370/380/1170 371/385/1174 368/444/1164 +f 370/380/1173 372/378/1178 369/360/1168 +f 376/507/1192 374/491/1185 377/505/1195 373/523/1182 +f 378/491/1198 381/505/1207 379/523/1201 380/507/1204 +f 383/461/1213 387/420/1225 385/424/1220 +f 384/372/1215 386/416/1223 385/424/1219 +f 391/505/1240 389/523/1233 392/507/1243 388/491/1230 +f 393/457/1245 397/409/1258 396/406/1253 +f 394/374/1247 397/409/1257 395/407/1251 +f 401/505/1272 399/523/1265 402/507/1275 398/491/1262 +f 405/395/1282 406/400/1286 403/367/1276 +f 405/395/1285 407/402/1290 404/452/1280 +f 410/386/1298 412/388/1304 408/442/1292 +f 411/387/1302 412/388/1307 409/361/1296 +f 416/506/1320 414/523/1313 417/507/1323 413/491/1310 +s 2 +f 27/117/171 31/122/186 163/97/678 161/93/671 +f 28/120/175 147/96/619 149/104/627 32/125/191 +f 29/119/179 33/124/195 150/103/631 148/95/623 +f 30/118/183 162/94/675 164/102/683 34/123/199 +f 31/122/187 36/121/207 165/109/687 163/97/679 +f 33/124/194 35/128/203 151/112/635 150/103/630 +f 34/123/198 164/102/682 165/111/686 36/127/206 +f 35/126/202 32/125/190 149/104/626 151/110/634 +f 46/72/247 144/68/608 143/76/605 45/80/243 +f 47/77/252 146/73/613 145/65/611 48/69/259 +f 57/531/283 166/540/691 168/541/699 61/537/299 +f 58/484/286 62/485/302 154/471/646 152/469/638 +f 59/487/290 153/472/642 155/474/650 63/490/306 +f 60/534/295 64/532/311 169/545/703 167/544/695 +f 62/485/303 65/486/315 156/473/655 154/471/647 +f 63/490/307 155/474/651 156/473/654 65/486/314 +f 64/532/310 66/538/319 170/542/707 169/545/702 +f 66/538/318 61/537/298 168/541/698 170/542/706 +f 72/108/344 157/85/657 147/96/618 28/120/174 +f 74/106/354 173/83/715 162/94/674 30/118/182 +f 76/535/364 171/543/709 166/540/690 57/531/282 +f 77/482/369 159/470/663 153/472/643 59/487/291 +f 79/239/380 175/345/723 194/355/790 132/246/571 +f 80/240/383 133/248/574 194/357/789 175/347/721 +f 86/237/409 125/245/548 131/253/568 92/241/435 +f 88/243/418 127/254/555 126/247/553 87/238/414 +f 89/269/422 128/273/558 127/254/556 88/243/419 +f 90/339/426 129/365/561 128/273/559 89/269/423 +f 91/267/430 130/271/564 129/363/562 90/337/427 +f 92/241/434 131/253/567 130/271/565 91/267/431 +f 102/113/461 206/29/823 207/32/827 121/99/538 +f 104/114/469 122/98/539 207/33/825 206/30/821 +f 107/210/486 117/234/526 190/286/773 184/280/749 +f 108/205/491 184/279/751 190/283/775 120/227/535 +f 111/219/506 113/229/514 188/325/765 186/334/757 +f 112/220/511 186/335/759 188/327/767 116/230/523 +f 140/75/595 209/10/832 210/18/836 139/67/592 +f 141/74/600 142/66/602 210/19/838 209/11/834 +f 148/95/622 160/84/667 73/107/350 29/119/178 +f 152/469/639 158/468/661 75/481/359 58/484/287 +f 161/93/670 172/81/713 71/105/340 27/117/170 +f 167/544/694 174/546/719 78/536/374 60/534/294 +f 183/333/747 189/326/771 118/228/529 105/218/476 +f 185/281/755 187/287/763 114/235/517 109/211/496 +f 187/288/761 185/282/753 110/212/500 115/236/518 +f 189/322/769 183/330/745 106/215/480 119/225/530 +f 205/35/819 208/36/830 123/101/544 103/116/466 +f 208/34/828 205/31/817 101/115/454 124/100/545 +f 214/190/848 217/313/857 216/314/854 215/186/851 +f 223/315/877 227/306/889 226/305/886 222/312/874 +f 225/189/882 229/194/893 228/193/890 224/188/879 +f 230/328/896 233/350/905 232/352/902 231/331/899 +f 235/445/912 236/435/916 237/433/919 234/446/909 +f 266/329/920 269/351/929 268/353/926 267/332/923 +f 271/445/936 272/435/940 273/434/943 270/447/933 +f 302/498/944 340/496/1069 343/514/1081 341/504/1073 +f 303/450/947 336/463/1056 338/476/1063 335/464/1052 +f 304/497/951 347/489/1094 351/500/1108 348/509/1099 +f 311/520/963 315/528/980 357/530/1130 353/522/1118 +f 313/483/969 317/467/987 316/455/982 312/465/965 +f 318/480/994 342/488/1079 344/499/1086 327/502/1037 +f 322/475/1011 345/478/1088 342/488/1080 318/480/995 +f 352/547/1112 356/539/1126 354/521/1119 305/529/954 +f 353/522/1117 355/515/1125 329/513/1047 311/520/962 +f 358/460/1133 362/427/1145 360/419/1140 +f 359/371/1135 361/423/1143 360/419/1139 +f 365/405/1154 367/408/1160 363/456/1148 +f 366/404/1158 367/408/1163 364/369/1152 +f 368/444/1165 372/378/1177 370/380/1172 +f 369/360/1167 371/385/1175 370/380/1171 +f 373/368/1181 377/403/1193 375/396/1188 +f 374/453/1183 376/401/1191 375/396/1187 +f 378/441/1197 382/383/1210 381/382/1205 +f 379/359/1199 382/383/1209 380/381/1203 +f 386/505/1224 384/523/1217 387/507/1227 383/491/1214 +f 388/459/1229 392/426/1241 390/418/1236 +f 389/370/1231 391/422/1239 390/418/1235 +f 393/491/1246 396/505/1255 394/523/1249 395/507/1252 +f 398/443/1261 402/377/1273 400/379/1268 +f 399/358/1263 401/384/1271 400/379/1267 +f 406/507/1288 404/491/1281 407/505/1291 403/523/1278 +f 408/442/1293 412/388/1306 411/387/1301 +f 409/361/1295 412/388/1305 410/386/1299 +f 415/425/1314 416/417/1318 413/462/1308 +f 415/425/1317 417/421/1322 414/373/1312 +s 3 +f 2/152/89 95/233/9 112/220/508 38/148/215 +f 3/149/94 97/226/11 86/237/407 68/157/327 +f 4/137/97 99/182/445 108/205/488 40/141/223 +f 5/139/100 94/184/442 109/211/492 41/143/226 +f 6/151/103 96/231/10 79/239/377 70/159/335 +f 7/150/107 98/232/12 105/218/472 43/146/234 +f 9/164/114 81/244/386 80/240/382 67/160/323 +f 10/161/118 92/241/432 91/267/429 14/252/135 +f 11/162/122 88/243/416 87/238/411 69/158/330 +f 12/163/126 85/242/402 84/268/399 16/249/143 +f 13/251/130 82/270/390 81/244/387 9/164/115 +f 14/252/134 91/267/428 90/337/425 18/321/151 +f 15/250/138 89/269/420 88/243/417 11/162/123 +f 16/249/142 84/268/398 83/338/395 17/318/147 +f 17/320/146 83/340/394 82/270/391 13/251/131 +f 18/319/150 90/339/424 89/269/421 15/250/139 +f 37/144/210 110/212/497 93/185/437 1/140/86 +f 38/148/214 112/220/507 110/212/498 37/144/211 +f 39/145/218 106/215/477 97/226/11 3/149/93 +f 40/141/222 108/205/487 106/215/478 39/145/219 +f 41/143/227 109/211/493 111/219/502 42/147/230 +f 42/147/231 111/219/504 96/231/10 6/151/104 +f 43/146/235 105/218/473 107/210/482 44/142/238 +f 44/142/239 107/210/484 100/183/450 8/138/111 +f 50/79/269 200/14/815 209/10/835 140/75/597 +f 52/78/277 141/74/598 209/11/833 200/15/813 +f 67/160/322 80/240/381 95/233/9 2/152/90 +f 68/157/326 86/237/406 92/241/433 10/161/119 +f 69/158/331 87/238/412 98/232/12 7/150/108 +f 70/159/334 79/239/376 85/242/403 12/163/127 +f 93/185/438 110/212/499 185/282/752 177/278/729 +f 96/231/10 178/342/13 175/345/720 79/239/378 +f 97/226/11 106/215/479 183/330/744 179/336/14 +f 105/218/475 98/232/12 179/341/14 183/333/746 +f 109/211/495 94/184/443 177/277/731 185/281/754 +f 114/235/515 187/287/760 188/325/764 113/229/512 +f 115/236/520 116/230/522 188/327/766 187/288/762 +f 118/228/527 189/326/768 190/286/772 117/234/524 +f 119/225/532 120/227/534 190/283/774 189/322/770 +f 121/99/536 207/32/824 213/61/19 192/129/780 +f 122/98/541 191/130/779 213/62/19 207/33/826 +f 123/101/543 208/36/829 213/64/19 191/132/777 +f 124/100/547 192/131/783 213/63/19 208/34/831 +f 126/247/551 127/254/554 128/273/557 129/365/560 193/356/784 +f 130/271/566 131/253/569 125/245/550 193/354/787 129/363/563 +f 139/67/594 210/18/837 199/22/809 49/71/264 +f 144/68/607 211/20/840 212/12/844 143/76/604 +f 145/65/612 146/73/614 212/9/846 211/17/842 +f 147/96/617 157/85/656 158/46/659 152/43/637 +f 148/95/620 150/103/628 155/50/648 153/42/640 +f 150/103/629 151/112/632 156/53/652 155/50/649 +f 151/110/633 149/104/624 154/51/644 156/54/653 +f 152/43/636 154/51/645 149/104/625 147/96/616 +f 153/42/641 159/45/662 160/84/665 148/95/621 +f 161/93/668 163/97/677 168/40/697 166/37/688 +f 162/94/673 173/83/714 174/44/717 167/41/693 +f 163/97/676 165/109/684 170/39/704 168/40/696 +f 166/37/689 171/38/708 172/81/711 161/93/669 +f 167/41/692 169/49/700 164/102/680 162/94/672 +f 169/49/701 170/52/705 165/111/685 164/102/681 +f 175/347/722 178/343/13 95/233/9 80/240/385 +f 176/346/726 179/341/14 98/232/12 87/238/415 +f 178/343/13 186/335/758 112/220/510 95/233/9 +f 179/336/14 176/344/724 86/237/408 97/226/11 +f 180/275/735 184/279/750 108/205/490 99/182/447 +f 184/280/748 180/276/733 100/183/449 107/210/483 +f 186/334/756 178/342/13 96/231/10 111/219/503 +f 199/23/811 210/19/839 142/66/603 51/70/274 +f 214/311/849 218/305/860 221/194/870 217/189/859 +f 216/187/856 220/193/867 219/306/863 215/315/852 +f 219/306/864 220/193/868 221/194/871 218/305/861 +f 222/312/873 226/305/884 229/194/894 225/189/883 +f 224/188/880 228/193/891 227/306/887 223/315/876 +f 227/306/888 228/193/892 229/194/895 226/305/885 +f 231/527/901 235/495/913 234/493/910 230/525/898 +f 233/350/906 237/433/917 236/435/914 232/352/903 +f 266/329/921 270/447/932 273/434/942 269/351/931 +f 268/353/928 272/435/939 271/445/935 267/332/924 +f 302/498/946 341/504/1074 344/499/1084 342/488/1078 +f 305/529/955 354/521/1120 355/515/1123 353/522/1116 +f 319/466/998 326/479/1031 338/476/1064 336/463/1058 +f 320/512/1003 348/509/1101 351/500/1110 328/503/1042 +f 324/518/1021 350/516/1106 348/509/1100 320/512/1002 +f 335/464/1053 337/449/1060 334/436/1048 303/450/948 +f 336/463/1059 339/454/1068 323/458/1017 319/466/999 +f 346/501/1091 349/477/1102 347/489/1095 304/497/952 +f 361/505/1144 359/523/1137 362/507/1147 358/491/1134 +f 363/491/1150 366/505/1159 364/523/1153 365/507/1156 +f 371/505/1176 369/523/1169 372/507/1179 368/491/1166 +f 375/396/1186 376/401/1190 373/368/1180 +f 375/396/1189 377/403/1194 374/453/1184 +f 380/381/1202 382/383/1208 378/441/1196 +f 381/382/1206 382/383/1211 379/359/1200 +f 385/424/1218 386/416/1222 383/461/1212 +f 385/424/1221 387/420/1226 384/372/1216 +f 390/418/1234 391/422/1238 388/459/1228 +f 390/418/1237 392/426/1242 389/370/1232 +f 395/407/1250 397/409/1256 393/457/1244 +f 396/406/1254 397/409/1259 394/374/1248 +f 400/379/1266 401/384/1270 398/443/1260 +f 400/379/1269 402/377/1274 399/358/1264 +f 403/367/1277 407/402/1289 405/395/1284 +f 404/452/1279 406/400/1287 405/395/1283 +f 408/491/1294 411/505/1303 409/523/1297 410/507/1300 +f 413/462/1309 417/421/1321 415/425/1316 +f 414/373/1311 416/417/1319 415/425/1315 +s 4 +f 1/140/85 93/156/436 101/115/452 19/92/153 +f 8/138/110 100/154/448 104/114/468 24/90/166 +f 19/92/154 101/115/453 205/31/816 195/27/793 +f 20/89/158 103/116/462 99/153/444 4/137/96 +f 20/89/159 195/28/795 205/35/818 103/116/465 +f 23/91/162 102/113/458 94/155/441 5/139/99 +f 79/239/379 132/246/570 138/255/590 85/242/405 +f 81/244/388 134/256/577 133/248/575 80/240/384 +f 82/270/392 135/274/580 134/256/578 81/244/389 +f 83/340/396 136/366/583 135/274/581 82/270/393 +f 84/268/400 137/272/586 136/364/584 83/338/397 +f 85/242/404 138/255/589 137/272/587 84/268/401 +f 99/153/446 103/116/463 182/136/740 180/170/732 +f 100/154/451 180/173/734 182/133/742 104/114/470 +f 102/113/457 181/134/736 177/172/728 94/155/440 +f 104/114/467 206/30/820 196/26/797 24/90/165 +f 177/171/730 181/135/738 101/115/455 93/156/439 +f 196/25/799 206/29/822 102/113/460 23/91/163 +f 310/510/958 341/504/1075 343/514/1083 314/517/976 +f 321/519/1006 329/513/1046 355/515/1124 354/521/1121 +f 327/502/1036 344/499/1085 341/504/1076 310/510/959 +f 354/521/1122 356/539/1128 325/533/1027 321/519/1007 +s 5 +f 1/140/84 19/92/152 46/72/245 37/144/208 +f 2/152/88 38/148/213 45/80/241 21/86/1 +f 3/149/91 22/82/2 47/77/250 39/145/216 +f 4/137/95 40/141/221 48/69/257 20/89/157 +f 6/151/101 70/159/332 73/107/346 25/87/3 +f 7/150/106 26/88/4 74/106/351 69/158/328 +f 9/164/112 28/120/172 32/125/189 13/168/129 +f 9/164/113 67/160/321 72/108/343 28/120/173 +f 10/161/117 14/165/132 31/122/184 27/117/169 +f 11/162/120 30/118/180 34/123/196 15/166/136 +f 11/162/121 69/158/329 74/106/353 30/118/181 +f 12/163/124 16/167/140 33/124/192 29/119/176 +f 13/168/128 32/125/188 35/126/200 17/174/144 +f 14/165/133 18/169/148 36/121/204 31/122/185 +f 15/166/137 34/123/197 36/127/205 18/175/149 +f 16/167/141 17/176/145 35/128/201 33/124/193 +f 21/86/1 45/80/242 198/16/804 201/4/15 53/57/5 +f 21/86/1 72/108/342 67/160/320 2/152/87 +f 22/82/2 54/48/6 201/1/15 198/13/806 47/77/253 +f 23/91/161 49/71/261 199/22/808 196/25/796 +f 24/90/164 51/70/271 44/142/237 8/138/109 +f 24/90/167 196/26/798 199/23/810 51/70/273 +f 25/87/3 50/79/266 42/147/229 6/151/102 +f 25/87/3 73/107/347 77/59/366 55/56/7 +f 26/88/4 56/55/8 78/58/371 74/106/352 +f 27/117/168 71/105/336 68/157/324 10/161/116 +f 29/119/177 73/107/348 70/159/333 12/163/125 +f 37/144/209 46/72/246 45/80/240 38/148/212 +f 39/145/217 47/77/251 48/69/256 40/141/220 +f 41/143/224 49/71/260 23/91/160 5/139/98 +f 42/147/228 50/79/265 49/71/262 41/143/225 +f 43/146/232 52/78/275 26/88/4 7/150/105 +f 44/142/236 51/70/270 52/78/276 43/146/233 +f 48/69/255 197/21/800 195/28/792 20/89/156 +f 52/78/279 200/15/814 202/3/16 56/55/8 26/88/4 +f 53/57/5 75/60/356 72/108/341 21/86/1 +f 55/56/7 77/59/367 204/6/18 202/2/16 +f 55/56/7 202/2/16 200/14/812 50/79/267 25/87/3 +f 56/55/8 202/3/16 204/7/18 78/58/375 +f 57/531/280 61/537/297 62/485/301 58/484/284 +f 58/484/285 75/481/357 203/508/17 76/535/362 57/531/281 +f 59/487/288 63/490/304 64/532/308 60/534/292 +f 60/534/293 78/536/372 204/511/18 77/482/368 59/487/289 +f 61/537/296 66/538/316 65/486/312 62/485/300 +f 63/490/305 65/486/313 66/538/317 64/532/309 +f 68/157/325 71/105/337 22/82/2 3/149/92 +f 71/105/338 76/47/363 54/48/6 22/82/2 +f 76/47/361 203/5/17 201/1/15 54/48/6 +f 195/27/794 197/24/802 46/72/248 19/92/155 +f 201/4/15 203/8/17 75/60/360 53/57/5 +f 306/414/76 340/413/1072 345/431/1089 322/428/1012 +f 307/448/77 334/451/1050 337/439/1062 316/438/986 +f 308/411/78 346/412/1093 350/394/1107 324/399/1022 +f 309/376/79 352/375/1114 357/390/1131 315/391/981 +f 311/520/961 329/513/1044 327/502/1035 310/510/957 +f 312/465/964 326/479/1028 328/503/1038 313/483/968 +f 314/397/974 330/415/80 332/398/82 315/391/978 +f 314/397/975 343/393/1082 340/413/1071 306/414/76 +f 315/391/979 332/398/82 325/392/1023 309/376/79 +f 316/438/983 331/429/81 323/437/1014 307/448/77 +f 317/430/988 333/410/83 331/429/81 316/438/984 +f 317/430/990 349/432/1103 346/412/1092 308/411/78 +f 318/480/992 327/502/1033 326/479/1029 319/466/996 +f 320/512/1001 328/503/1040 329/513/1045 321/519/1005 +f 322/428/1008 330/415/80 314/397/972 306/414/76 +f 323/437/1013 331/429/81 330/415/80 322/428/1009 +f 323/437/1016 339/440/1067 334/451/1051 307/448/77 +f 324/399/1020 333/410/83 317/430/989 308/411/78 +f 325/392/1025 332/398/82 333/410/83 324/399/1019 +f 325/392/1026 356/389/1127 352/375/1113 309/376/79 +f 327/502/1034 329/513/1043 328/503/1039 326/479/1030 +f 331/429/81 333/410/83 332/398/82 330/415/80 diff --git a/etc/GLDemonstration.hpp b/etc/GLDemonstration.hpp new file mode 100644 index 0000000..077140c --- /dev/null +++ b/etc/GLDemonstration.hpp @@ -0,0 +1,253 @@ +// Copyright (c) 2014 Robert Kooima +// +// 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 GLDEMONSTRATION_HPP +#define GLDEMONSTRATION_HPP + +#include + +//------------------------------------------------------------------------------ + +namespace gl +{ + class demonstration + { + public: + + /// Initialize an SDL OpenGL window with the given title and size. + + demonstration(const char *title, int w, int h) : + width(w), + height(h), + running(false), + sun_rotation(-90, 0), + drag_sun_rotation(false), + drag_cam_rotation(false) + { + if (SDL_Init(SDL_INIT_VIDEO) == 0) + { + int x = SDL_WINDOWPOS_CENTERED; + int y = SDL_WINDOWPOS_CENTERED; + int f = SDL_WINDOW_OPENGL; + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, + SDL_GL_CONTEXT_PROFILE_CORE); + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + if ((window = SDL_CreateWindow(title, x, y, w, h, f))) + { + context = SDL_GL_CreateContext(window); + running = true; +#ifdef GLEW_VERSION + glewExperimental = GL_TRUE; + glewInit(); +#endif + } + } + } + + /// Dispatch SDL events. + + void run() + { + SDL_Event e; + + while (running) + { + while (SDL_PollEvent(&e)) + switch (e.type) + { + case SDL_MOUSEBUTTONDOWN: button(e.button.button, true); break; + case SDL_MOUSEBUTTONUP: button(e.button.button, false); break; + case SDL_MOUSEMOTION: motion(e.motion.x, e.motion.y); break; + case SDL_KEYDOWN: if (e.key.repeat == 0) key(e.key.keysym.scancode, true); break; + case SDL_KEYUP: if (e.key.repeat == 0) key(e.key.keysym.scancode, false); break; + case SDL_QUIT: running = false; break; + } + + step(); + draw(); + SDL_GL_SwapWindow(window); + } + } + + /// Finalize the SDL OpenGL window. + + virtual ~demonstration() + { + if (context) SDL_GL_DeleteContext(context); + if (window) SDL_DestroyWindow(window); + } + + protected: + + /// Draw the scene. + + virtual void draw() + { + } + + /// Animate. + + virtual void step() + { + mat3 N = normal(inverse(view())); + cam_position = cam_position + N * cam_velocity / 30.0; + } + + /// Handle a mouse button press or release. + + virtual void button(int button, bool down) + { + switch (button) + { + case SDL_BUTTON_LEFT: + drag_cam_rotation = down; + prev_cam_rotation = cam_rotation; + break; + + case SDL_BUTTON_RIGHT: + drag_sun_rotation = down; + prev_sun_rotation = sun_rotation; + break; + } + prev_x = curr_x; + prev_y = curr_y; + } + + /// Handle mouse pointer motion. + + virtual void motion(int x, int y) + { + GLfloat dy = GLfloat(y - prev_y) / height; + GLfloat dx = GLfloat(x - prev_x) / height; + + if (drag_cam_rotation) + { + cam_rotation[0] = prev_cam_rotation[0] + 90.0 * dy; + cam_rotation[1] = prev_cam_rotation[1] + 180.0 * dx; + + if (cam_rotation[0] > 90) cam_rotation[0] = 90; + if (cam_rotation[0] < -90) cam_rotation[0] = -90; + if (cam_rotation[1] > 180) cam_rotation[1] -= 360; + if (cam_rotation[1] < -180) cam_rotation[1] += 360; + } + if (drag_sun_rotation) + { + sun_rotation[0] = prev_sun_rotation[0] + 90.0 * dy; + sun_rotation[1] = prev_sun_rotation[1] + 180.0 * dx; + + if (sun_rotation[0] > 90) sun_rotation[0] = 90; + if (sun_rotation[0] < -90) sun_rotation[0] = -90; + if (sun_rotation[1] > 180) sun_rotation[1] -= 360; + if (sun_rotation[1] < -180) sun_rotation[1] += 360; + } + curr_x = x; + curr_y = y; + } + + /// Handle a key press or release. + + virtual void key(int key, bool down) + { + if (down) + switch (key) + { + case SDL_SCANCODE_A: cam_velocity[0] -= 1.0; break; + case SDL_SCANCODE_D: cam_velocity[0] += 1.0; break; + case SDL_SCANCODE_C: cam_velocity[1] -= 1.0; break; + case SDL_SCANCODE_SPACE: cam_velocity[1] += 1.0; break; + case SDL_SCANCODE_W: cam_velocity[2] -= 1.0; break; + case SDL_SCANCODE_S: cam_velocity[2] += 1.0; break; + } + else + switch (key) + { + case SDL_SCANCODE_A: cam_velocity[0] += 1.0; break; + case SDL_SCANCODE_D: cam_velocity[0] -= 1.0; break; + case SDL_SCANCODE_C: cam_velocity[1] += 1.0; break; + case SDL_SCANCODE_SPACE: cam_velocity[1] -= 1.0; break; + case SDL_SCANCODE_W: cam_velocity[2] += 1.0; break; + case SDL_SCANCODE_S: cam_velocity[2] -= 1.0; break; + } + } + + /// Return the current projection matrix. + + mat4 projection(GLfloat n=0.10f, GLfloat f=100.f) const + { + const GLfloat a = GLfloat(width) / GLfloat(height); + return perspective(to_radians(60.f), a, n, f); + } + + /// Return the current view matrix. + + mat4 view() const + { + return xrotation(to_radians(cam_rotation[0])) + * yrotation(to_radians(cam_rotation[1])) + * translation(-cam_position); + } + + /// Return the current light vector. + + vec4 light() const + { + return xrotation(to_radians(sun_rotation[0])) + * yrotation(to_radians(sun_rotation[1])) * vec4(0, 0, 1, 0); + } + + protected: + + int width; + int height; + bool running; + + vec3 cam_position; + vec3 cam_velocity; + vec2 cam_rotation; + vec2 sun_rotation; + + private: + + bool drag_sun_rotation; + bool drag_cam_rotation; + vec2 prev_sun_rotation; + vec2 prev_cam_rotation; + int prev_x; + int prev_y; + int curr_x; + int curr_y; + + SDL_Window *window; + SDL_GLContext context; + }; +} + +//------------------------------------------------------------------------------ + +#endif diff --git a/etc/GLFundamentals.hpp b/etc/GLFundamentals.hpp new file mode 100644 index 0000000..ffd25b4 --- /dev/null +++ b/etc/GLFundamentals.hpp @@ -0,0 +1,821 @@ +// Copyright (c) 2013 Robert Kooima +// +// 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 GLFUNDAMENTALS_HPP +#define GLFUNDAMENTALS_HPP + +/// This header provides the basic functionality necessary to make effective use +/// of modern OpenGL (e.g. OpenGL 3.2 Core Profile or OpenGL ES 2.0 or later). +/// +/// Given the lack of fixed functionality and matrix handling, all applications +/// will need to load and compile shaders and perform matrix arithmetic. Thus, +/// these capabilities are provided here. +/// +/// Basic TGA read and write procedures for texture handling are also provided. + +//------------------------------------------------------------------------------ + +#ifdef __APPLE__ +# include +#else +# include +#endif + +#include +#include +#include +#include + +//------------------------------------------------------------------------------ + +#ifdef NDEBUG +# define GL_CHECK_ERROR() ((void) 0) +#else +# define GL_CHECK_ERROR() check(__FILE__, __LINE__) +#endif + +namespace gl +{ + inline void check(const char *file, int line, FILE *stream = stderr) + { + switch (glGetError()) + { + case GL_INVALID_ENUM: + fprintf(stream, "%s:%d: Invalid Enum\n", file, line); abort(); + case GL_INVALID_VALUE: + fprintf(stream, "%s:%d: Invalid Value\n", file, line); abort(); + case GL_INVALID_OPERATION: + fprintf(stream, "%s:%d: Invalid Operation\n", file, line); abort(); + case GL_OUT_OF_MEMORY: + fprintf(stream, "%s:%d: Out of Memory\n", file, line); abort(); + } + } + + //-------------------------------------------------------------------------- + + /// 2-component 32-bit floating point vector. + + struct vec2 + { + GLfloat v[2]; + + vec2(GLfloat x=0, GLfloat y=0) + { + v[0] = x; + v[1] = y; + } + + const GLfloat& operator[](int i) const { return v[i]; } + GLfloat& operator[](int i) { return v[i]; } + + operator const GLfloat*() const + { + return const_cast(&v[0]); + } + }; + + //-------------------------------------------------------------------------- + + /// 3-component 32-bit floating point vector. + + struct vec3 + { + GLfloat v[3]; + + vec3(GLfloat x=0, GLfloat y=0, GLfloat z=0) + { + v[0] = x; + v[1] = y; + v[2] = z; + } + vec3(const vec2& a, GLfloat b=0) + { + v[0] = a[0]; + v[1] = a[1]; + v[2] = b; + } + + const GLfloat& operator[](int i) const { return v[i]; } + GLfloat& operator[](int i) { return v[i]; } + + operator const GLfloat*() const + { + return const_cast(&v[0]); + } + }; + + //-------------------------------------------------------------------------- + + /// 4-component 32-bit floating point vector. + + struct vec4 + { + GLfloat v[4]; + + vec4(GLfloat x=0, GLfloat y=0, GLfloat z=0, GLfloat w=0) + { + v[0] = x; + v[1] = y; + v[2] = z; + v[3] = w; + } + vec4(const vec3& a, GLfloat b=0) + { + v[0] = a[0]; + v[1] = a[1]; + v[2] = a[2]; + v[3] = b; + } + + const GLfloat& operator[](int i) const { return v[i]; } + GLfloat& operator[](int i) { return v[i]; } + + operator const GLfloat*() const + { + return const_cast(&v[0]); + } + }; + + //-------------------------------------------------------------------------- + + /// Row-wise 3x3 32-bit floating point matrix. + + struct mat3 + { + vec3 M[3]; + + mat3(GLfloat m00=1, GLfloat m01=0, GLfloat m02=0, + GLfloat m10=0, GLfloat m11=1, GLfloat m12=0, + GLfloat m20=0, GLfloat m21=0, GLfloat m22=1) + { + M[0] = vec3(m00, m01, m02); + M[1] = vec3(m10, m11, m12); + M[2] = vec3(m20, m21, m22); + } + + const vec3& operator[](int i) const { return M[i]; } + vec3& operator[](int i) { return M[i]; } + + operator const GLfloat*() const + { + return const_cast(&M[0][0]); + } + }; + + //-------------------------------------------------------------------------- + + /// Row-wise 4x4 32-bit floating point matrix. + + struct mat4 + { + vec4 M[4]; + + mat4(GLfloat m00=0, GLfloat m01=0, GLfloat m02=0, GLfloat m03=0, + GLfloat m10=0, GLfloat m11=0, GLfloat m12=0, GLfloat m13=0, + GLfloat m20=0, GLfloat m21=0, GLfloat m22=0, GLfloat m23=0, + GLfloat m30=0, GLfloat m31=0, GLfloat m32=0, GLfloat m33=0) + { + M[0] = vec4(m00, m01, m02, m03); + M[1] = vec4(m10, m11, m12, m13); + M[2] = vec4(m20, m21, m22, m23); + M[3] = vec4(m30, m31, m32, m33); + } + + const vec4& operator[](int i) const { return M[i]; } + vec4& operator[](int i) { return M[i]; } + + operator const GLfloat*() const + { + return const_cast(&M[0][0]); + } + }; + + //-------------------------------------------------------------------------- + + /// Convert an angle in degrees to an angle in radians. + + inline GLfloat to_radians(GLfloat degrees) + { + return degrees * 0.01745329; + } + + /// Convent an angle in radians to an angle in degrees. + + inline GLfloat to_degrees(GLfloat radians) + { + return radians * 57.2957795; + } + + //-------------------------------------------------------------------------- + + /// Calculate the 3-component negation of v. + + inline vec3 operator-(const vec3& v) + { + return vec3(-v[0], -v[1], -v[2]); + } + + /// Calculate the 3-component sum of v and w. + + inline vec3 operator+(const vec3& v, const vec3& w) + { + return vec3(v[0] + w[0], v[1] + w[1], v[2] + w[2]); + } + + /// Calculate the 3-component difference of v and w. + + inline vec3 operator-(const vec3& v, const vec3& w) + { + return vec3(v[0] - w[0], v[1] - w[1], v[2] - w[2]); + } + + /// Calculate the 3-component scalar quotient of v and k. + + inline vec3 operator/(const vec3& v, GLfloat k) + { + return vec3(v[0] / k, v[1] / k, v[2] / k); + } + + /// Calculate the 3-component scalar product of v and k. + + inline vec3 operator*(const vec3& v, GLfloat k) + { + return vec3(v[0] * k, v[1] * k, v[2] * k); + } + + //-------------------------------------------------------------------------- + + /// Calculate the 3-component dot product of v and w. + + inline GLfloat operator*(const vec3& v, const vec3& w) + { + return v[0] * w[0] + v[1] * w[1] + v[2] * w[2]; + } + + /// Calculate the 4-component dot product of v and w. + + inline GLfloat operator*(const vec4& v, const vec4& w) + { + return v[0] * w[0] + v[1] * w[1] + v[2] * w[2] + v[3] * w[3]; + } + + /// Calculate the 3-component transform of vector v by matrix A. + + inline vec3 operator*(const mat3& A, const vec3& v) + { + return vec3(A[0] * v, A[1] * v, A[2] * v); + } + + /// Calculate the 4-component transform of vector v by matrix A. + + inline vec4 operator*(const mat4& A, const vec4& v) + { + return vec4(A[0] * v, A[1] * v, A[2] * v, A[3] * v); + } + + /// Calculate the 3x3 matrix product of A and B. + + inline mat3 operator*(const mat3& A, const mat3& B) + { + mat3 M; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + M[i][j] = A[i][0] * B[0][j] + + A[i][1] * B[1][j] + + A[i][2] * B[2][j]; + return M; + } + + /// Calculate the 4x4 matrix product of A and B. + + inline mat4 operator*(const mat4& A, const mat4& B) + { + mat4 M; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + M[i][j] = A[i][0] * B[0][j] + + A[i][1] * B[1][j] + + A[i][2] * B[2][j] + + A[i][3] * B[3][j]; + return M; + } + + //-------------------------------------------------------------------------- + + /// Return the transpose of a 3x3 matrix. + + inline mat3 transpose(const mat3& A) + { + mat3 M; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + M[i][j] = A[j][i]; + return M; + } + + /// Return the transpose of a 4x4 matrix. + + inline mat4 transpose(const mat4& A) + { + mat4 M; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + M[i][j] = A[j][i]; + return M; + } + + /// Return the inverse of 4x4 matrix. + + inline mat4 inverse(const mat4& A) + { + mat4 T; + + T[0][0] = +(A[1][1] * (A[2][2] * A[3][3] - A[3][2] * A[2][3]) - + A[1][2] * (A[2][1] * A[3][3] - A[3][1] * A[2][3]) + + A[1][3] * (A[2][1] * A[3][2] - A[3][1] * A[2][2])); + T[0][1] = -(A[1][0] * (A[2][2] * A[3][3] - A[3][2] * A[2][3]) - + A[1][2] * (A[2][0] * A[3][3] - A[3][0] * A[2][3]) + + A[1][3] * (A[2][0] * A[3][2] - A[3][0] * A[2][2])); + T[0][2] = +(A[1][0] * (A[2][1] * A[3][3] - A[3][1] * A[2][3]) - + A[1][1] * (A[2][0] * A[3][3] - A[3][0] * A[2][3]) + + A[1][3] * (A[2][0] * A[3][1] - A[3][0] * A[2][1])); + T[0][3] = -(A[1][0] * (A[2][1] * A[3][2] - A[3][1] * A[2][2]) - + A[1][1] * (A[2][0] * A[3][2] - A[3][0] * A[2][2]) + + A[1][2] * (A[2][0] * A[3][1] - A[3][0] * A[2][1])); + + T[1][0] = -(A[0][1] * (A[2][2] * A[3][3] - A[3][2] * A[2][3]) - + A[0][2] * (A[2][1] * A[3][3] - A[3][1] * A[2][3]) + + A[0][3] * (A[2][1] * A[3][2] - A[3][1] * A[2][2])); + T[1][1] = +(A[0][0] * (A[2][2] * A[3][3] - A[3][2] * A[2][3]) - + A[0][2] * (A[2][0] * A[3][3] - A[3][0] * A[2][3]) + + A[0][3] * (A[2][0] * A[3][2] - A[3][0] * A[2][2])); + T[1][2] = -(A[0][0] * (A[2][1] * A[3][3] - A[3][1] * A[2][3]) - + A[0][1] * (A[2][0] * A[3][3] - A[3][0] * A[2][3]) + + A[0][3] * (A[2][0] * A[3][1] - A[3][0] * A[2][1])); + T[1][3] = +(A[0][0] * (A[2][1] * A[3][2] - A[3][1] * A[2][2]) - + A[0][1] * (A[2][0] * A[3][2] - A[3][0] * A[2][2]) + + A[0][2] * (A[2][0] * A[3][1] - A[3][0] * A[2][1])); + + T[2][0] = +(A[0][1] * (A[1][2] * A[3][3] - A[3][2] * A[1][3]) - + A[0][2] * (A[1][1] * A[3][3] - A[3][1] * A[1][3]) + + A[0][3] * (A[1][1] * A[3][2] - A[3][1] * A[1][2])); + T[2][1] = -(A[0][0] * (A[1][2] * A[3][3] - A[3][2] * A[1][3]) - + A[0][2] * (A[1][0] * A[3][3] - A[3][0] * A[1][3]) + + A[0][3] * (A[1][0] * A[3][2] - A[3][0] * A[1][2])); + T[2][2] = +(A[0][0] * (A[1][1] * A[3][3] - A[3][1] * A[1][3]) - + A[0][1] * (A[1][0] * A[3][3] - A[3][0] * A[1][3]) + + A[0][3] * (A[1][0] * A[3][1] - A[3][0] * A[1][1])); + T[2][3] = -(A[0][0] * (A[1][1] * A[3][2] - A[3][1] * A[1][2]) - + A[0][1] * (A[1][0] * A[3][2] - A[3][0] * A[1][2]) + + A[0][2] * (A[1][0] * A[3][1] - A[3][0] * A[1][1])); + + T[3][0] = -(A[0][1] * (A[1][2] * A[2][3] - A[2][2] * A[1][3]) - + A[0][2] * (A[1][1] * A[2][3] - A[2][1] * A[1][3]) + + A[0][3] * (A[1][1] * A[2][2] - A[2][1] * A[1][2])); + T[3][1] = +(A[0][0] * (A[1][2] * A[2][3] - A[2][2] * A[1][3]) - + A[0][2] * (A[1][0] * A[2][3] - A[2][0] * A[1][3]) + + A[0][3] * (A[1][0] * A[2][2] - A[2][0] * A[1][2])); + T[3][2] = -(A[0][0] * (A[1][1] * A[2][3] - A[2][1] * A[1][3]) - + A[0][1] * (A[1][0] * A[2][3] - A[2][0] * A[1][3]) + + A[0][3] * (A[1][0] * A[2][1] - A[2][0] * A[1][1])); + T[3][3] = +(A[0][0] * (A[1][1] * A[2][2] - A[2][1] * A[1][2]) - + A[0][1] * (A[1][0] * A[2][2] - A[2][0] * A[1][2]) + + A[0][2] * (A[1][0] * A[2][1] - A[2][0] * A[1][1])); + + const GLfloat d = 1 / (A[0] * T[0]); + + return mat4(T[0][0] * d, T[1][0] * d, T[2][0] * d, T[3][0] * d, + T[0][1] * d, T[1][1] * d, T[2][1] * d, T[3][1] * d, + T[0][2] * d, T[1][2] * d, T[2][2] * d, T[3][2] * d, + T[0][3] * d, T[1][3] * d, T[2][3] * d, T[3][3] * d); + } + + //-------------------------------------------------------------------------- + + /// Compute the length of vector v. + + inline GLfloat length(const vec3 &v) + { + return sqrt(v * v); + } + + /// Compute the cross product of vectors v and w. + + inline vec3 cross(const vec3& v, const vec3& w) + { + return vec3(v[1] * w[2] - v[2] * w[1], + v[2] * w[0] - v[0] * w[2], + v[0] * w[1] - v[1] * w[0]); + } + + /// Compute the normalization of vector v. + + inline vec3 normalize(const vec3& v) + { + return v / length(v); + } + + //-------------------------------------------------------------------------- + + /// Return a matrix giving a rotation about X through a radians. + + inline mat4 xrotation(GLfloat a) + { + return mat4(1, 0, 0, 0, + 0, cos(a), -sin(a), 0, + 0, sin(a), cos(a), 0, + 0, 0, 0, 1); + } + + /// Return a matrix giving a rotation about Y through a radians. + + inline mat4 yrotation(GLfloat a) + { + return mat4( cos(a), 0, sin(a), 0, + 0, 1, 0, 0, + -sin(a), 0, cos(a), 0, + 0, 0, 0, 1); + } + + /// Return a matrix giving a rotation about Z through a radians. + + inline mat4 zrotation(GLfloat a) + { + return mat4(cos(a), -sin(a), 0, 0, + sin(a), cos(a), 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + } + + /// Return a matrix giving a rotation about v through a radians. + + inline mat4 rotation(const vec3& v, double a) + { + const vec3 u = normalize(v); + const GLfloat s = GLfloat(sin(a)); + const GLfloat c = GLfloat(cos(a)); + + return mat4(u[0] * u[0] + (1 - u[0] * u[0]) * c, + u[0] * u[1] + (0 - u[0] * u[1]) * c - u[2] * s, + u[0] * u[2] + (0 - u[0] * u[2]) * c + u[1] * s, + 0, + u[1] * u[0] + (0 - u[1] * u[0]) * c + u[2] * s, + u[1] * u[1] + (1 - u[1] * u[1]) * c, + u[1] * u[2] + (0 - u[1] * u[2]) * c - u[0] * s, + 0, + u[2] * u[0] + (0 - u[2] * u[0]) * c - u[1] * s, + u[2] * u[1] + (0 - u[2] * u[1]) * c + u[0] * s, + u[2] * u[2] + (1 - u[2] * u[2]) * c, + 0, + 0, 0, 0, 1); + } + + /// Return a matrix giving a translation along vector v. + + inline mat4 translation(const vec3& v) + { + return mat4(1, 0, 0, v[0], + 0, 1, 0, v[1], + 0, 0, 1, v[2], + 0, 0, 0, 1); + } + + /// Return a matrix giving a scale along vector v. + + inline mat4 scale(const vec3& v) + { + return mat4(v[0], 0, 0, 0, + 0, v[1], 0, 0, + 0, 0, v[2], 0, + 0, 0, 0, 1); + } + + /// Return a matrix giving a perspective projection with field-of-view v, + /// aspect ratio a, near clipping distance n, and far clipping distance f. + + inline mat4 perspective(GLfloat v, GLfloat a, GLfloat n, GLfloat f) + { + const GLfloat y = n * tan(v / 2); + const GLfloat x = y * a; + + return mat4(n / x, 0, 0, 0, 0, + n / y, 0, 0, 0, 0, (n + f) / (n - f), + 2 * (n * f) / (n - f), 0, 0, -1, 0); + } + + /// Return a matrix giving a perspective projection with the given left, + /// right, bottom, top, near, and far clipping boundaries. + + inline mat4 perspective(GLfloat l, GLfloat r, + GLfloat b, GLfloat t, + GLfloat n, GLfloat f) + { + return mat4((n + n) / (r - l), 0, + (r + l) / (r - l), 0, 0, + (n + n) / (t - b), + (t + b) / (t - b), 0, 0, 0, + (n + f) / (n - f), + 2 * (n * f) / (n - f), 0, 0, -1, 0); + } + + /// Return a matrix giving an orthogonal projection with the given left, + /// right, bottom, top, near, and far clipping boundaries. + + inline mat4 orthogonal(GLfloat l, GLfloat r, + GLfloat b, GLfloat t, + GLfloat n, GLfloat f) + { + return mat4(2 / (r - l), 0, 0, -(r + l) / (r - l), 0, + 2 / (t - b), 0, -(t + b) / (t - b), 0, 0, + -2 / (f - n), -(f + n) / (f - n), 0, 0, 0, 1); + } + + /// Compute a normal matrix for the given model-view matrix by returning + /// the transposed inverse upper 3x3 matrix of the given 4x4 matrix. + + inline mat3 normal(const mat4& M) + { + const GLfloat d = M[0][0] * M[1][1] * M[2][2] + - M[0][0] * M[1][2] * M[2][1] + + M[0][1] * M[1][2] * M[2][0] + - M[0][1] * M[1][0] * M[2][2] + + M[0][2] * M[1][0] * M[2][1] + - M[0][2] * M[1][1] * M[2][0]; + if (fabs(d) > 0.f) + return mat3(-M[1][2] * M[2][1] + M[1][1] * M[2][2], + M[1][2] * M[2][0] - M[1][0] * M[2][2], + -M[1][1] * M[2][0] + M[1][0] * M[2][1], + M[0][2] * M[2][1] - M[0][1] * M[2][2], + -M[0][2] * M[2][0] + M[0][0] * M[2][2], + M[0][1] * M[2][0] - M[0][0] * M[2][1], + -M[0][2] * M[1][1] + M[0][1] * M[1][2], + M[0][2] * M[1][0] - M[0][0] * M[1][2], + -M[0][1] * M[1][0] + M[0][0] * M[1][1]); + else + return mat3(); + } + + //-------------------------------------------------------------------------- + + #pragma pack(push, 1) + struct tga_head + { + unsigned char id_length; + unsigned char color_map_type; + unsigned char image_type; + unsigned short color_map_offset; + unsigned short color_map_length; + unsigned char color_map_size; + unsigned short image_x_origin; + unsigned short image_y_origin; + unsigned short image_width; + unsigned short image_height; + unsigned char image_depth; + unsigned char image_descriptor; + }; + #pragma pack(pop) + + /// Write a 24 or 32-bit uncompressed true-color Targa image file. Receive + /// the raw pixel buffer in p and width, height, and depth in w, h, and d. + /// Return 0 on success and -1 on failure. Errno indicates the error. + + inline int write_tga(const char *filename, int w, int h, int d, void *p) + { + tga_head head; + + memset(&head, 0, sizeof (tga_head)); + + head.image_type = 2; + head.image_width = (unsigned short) w; + head.image_height = (unsigned short) h; + head.image_depth = (unsigned char) d; + head.image_descriptor = (d == 32) ? 8 : 0; + + if (d == 24 || d == 32) + { + if (FILE *stream = fopen(filename, "wb")) + { + if (fwrite(&head, sizeof (tga_head), 1, stream) == 1) + { + if (fwrite(p, d / 8, w * h, stream) == size_t(w * h)) + { + fclose(stream); + return 0; + } + } + fclose(stream); + } + } + return -1; + } + + /// Read a 24 or 32-bit uncompressed true-color Targa image file. Return a + /// pointer to the raw pixels. Give width, height, and depth in w, h, d. + /// Return null on failure. + + inline void *read_tga(const char *filename, int& w, int& h, int& d) + { + tga_head head; + + if (FILE *stream = fopen(filename, "rb")) + { + if (fread(&head, sizeof (tga_head), 1, stream) == 1) + { + if (head.image_type == 2) + { + w = int(head.image_width); + h = int(head.image_height); + d = int(head.image_depth); + + if (fseek(stream, head.id_length, SEEK_CUR) == 0) + { + if (void *p = calloc(w * h, d / 8)) + { + if (fread(p, d / 8, w * h, stream) == size_t(w * h)) + { + fclose(stream); + return p; + } + } + } + } + } + fclose(stream); + } + return 0; + } + + //-------------------------------------------------------------------------- + + /// Load the named file into a newly-allocated buffer. Append nul. + + inline char *read_shader_source(const char *filename) + { + FILE *stream = 0; + void *p = 0; + size_t n = 0; + + if ((stream = fopen(filename, "rb"))) + { + if (fseek(stream, 0, SEEK_END) == 0) + { + if ((n = (size_t) ftell(stream))) + { + if (fseek(stream, 0, SEEK_SET) == 0) + { + if ((p = calloc(n + 1, 1))) + { + fread(p, 1, n, stream); + } + } + } + } + fclose(stream); + } + else fprintf(stderr, "Failed to open '%s'.\n", filename); + + return (char *) p; + } + + /// Check the shader compile status. If failed, print the log. Return status. + + inline bool report_shader_status(GLuint shader, FILE *stream = stderr) + { + GLchar *p = 0; + GLint s = 0; + GLint n = 0; + + glGetShaderiv(shader, GL_COMPILE_STATUS, &s); + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &n); + + if (s == 0) + { + if ((p = (GLchar *) calloc(n + 1, 1))) + { + glGetShaderInfoLog(shader, n, NULL, p); + + fprintf(stream, "Shader Error:\n%s", p); + free(p); + } + return false; + } + return true; + } + + /// Check the program link status. If failed, print the log. Return status. + + inline bool report_program_status(GLuint program, FILE *stream = stderr) + { + GLchar *p = 0; + GLint s = 0; + GLint n = 0; + + glGetProgramiv(program, GL_LINK_STATUS, &s); + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &n); + + if (s == 0) + { + if ((p = (GLchar *) calloc(n + 1, 1))) + { + glGetProgramInfoLog(program, n, NULL, p); + + fprintf(stream, "Program Error:\n%s", p); + free(p); + } + return false; + } + return true; + } + + /// Compile and return a new shader of the given type using the given GLSL + /// source string. Return 0 on failure. + + inline GLuint init_shader(GLenum type, const char *source) + { + GLuint shader = glCreateShader(type); + + if (shader) + { + glShaderSource (shader, 1, (const GLchar **) &source, NULL); + glCompileShader(shader); + + if (report_shader_status(shader)) + return shader; + else + glDeleteShader(shader); + } + return 0; + } + + /// Link and return a new program object with the given vertex and fragment + /// shader objects. Return 0 on failure. + + inline GLuint init_program(GLuint vert_shader, GLuint frag_shader) + { + GLuint program = glCreateProgram(); + + if (program) + { + glAttachShader(program, vert_shader); + glAttachShader(program, frag_shader); + + glLinkProgram(program); + + if (report_program_status(program)) + return program; + else + glDeleteProgram(program); + } + return 0; + } + + /// Initialize and return an OpenGL program object using the named vertex + /// and fragment shader source files. Return 0 on failure. + + inline GLuint init_program(const char *vert_filename, + const char *frag_filename) + { + GLuint program = 0; + + char *vert_source = read_shader_source(vert_filename); + char *frag_source = read_shader_source(frag_filename); + + if (vert_source && frag_source) + { + GLuint vert_shader = init_shader(GL_VERTEX_SHADER, vert_source); + GLuint frag_shader = init_shader(GL_FRAGMENT_SHADER, frag_source); + + if (vert_shader && frag_shader) + program = init_program(vert_shader, frag_shader); + + glDeleteShader(frag_shader); + glDeleteShader(vert_shader); + } + + free(frag_source); + free(vert_source); + + return program; + } + + //-------------------------------------------------------------------------- +} + +#endif diff --git a/etc/Makefile b/etc/Makefile new file mode 100644 index 0000000..011ad57 --- /dev/null +++ b/etc/Makefile @@ -0,0 +1,15 @@ + +OPTS= $(shell /usr/local/bin/sdl2-config --cflags) -I. -I.. -Wall +LIBS= $(shell /usr/local/bin/sdl2-config --libs) -framework OpenGL + +example : example.o ../obj.o + c++ $(OPTS) -o $@ $^ $(LIBS) + +%.o : %.cpp + c++ $(OPTS) -o $@ -c $< + +%.o : %.c + cc $(OPTS) -o $@ -c $< + +clean : + rm example example.o ../obj.o diff --git a/etc/README.md b/etc/README.md new file mode 100644 index 0000000..ea59a91 --- /dev/null +++ b/etc/README.md @@ -0,0 +1,12 @@ +# OBJ Example + +This example demonstrates the display of a model using the [OBJ C](https://github.com/rlk/obj) module. + +- Left mouse button pans and tilts the camera +- Right mouse button moves the light source +- W A S D move the camera + +This code conforms to the OpenGL 3.2 Core Profile and demonstrates diffuse, specular, and normal mapping. Normal map support is a non-standard extension to the MTL specification. + +The example uses [SDL2](http://www.libsdl.org) for window management, with [GLFundamentals.hpp and GLDemonstration.hpp](https://github.com/rlk/GLFundamentals) for OpenGL state handling and interaction. + diff --git a/etc/example.cpp b/etc/example.cpp new file mode 100644 index 0000000..221776a --- /dev/null +++ b/etc/example.cpp @@ -0,0 +1,72 @@ +#include +#include +#include + +class example : public gl::demonstration +{ + obj *object; + GLuint program; + + GLint ProjectionMatrixLocation; + GLint ModelViewMatrixLocation; + GLint NormalMatrixLocation; + GLint LightPositionLocation; + GLint AmbientLightLocation; + +public: + + example(); + void draw(); +}; + +example::example() : gl::demonstration("OBJ Demo", 960, 540), object(0), program(0) +{ + if ((program = gl::init_program("vertex.glsl", "fragment.glsl"))) + { + glUseProgram(program); + + ProjectionMatrixLocation = glGetUniformLocation(program, "ProjectionMatrix"); + ModelViewMatrixLocation = glGetUniformLocation(program, "ModelViewMatrix"); + NormalMatrixLocation = glGetUniformLocation(program, "NormalMatrix"); + LightPositionLocation = glGetUniformLocation(program, "LightPosition"); + AmbientLightLocation = glGetUniformLocation(program, "AmbientLight"); + + glUniform4f(AmbientLightLocation, 0.2, 0.2, 0.2, 1.0); + + if ((object = obj_create("Chest.obj"))) + { + obj_set_vert_loc(object, glGetAttribLocation(program, "vTangent"), + glGetAttribLocation(program, "vNormal"), + glGetAttribLocation(program, "vTexCoord"), + glGetAttribLocation(program, "vPosition")); + + obj_set_prop_loc(object, OBJ_KN, -1, glGetUniformLocation(program, "NormalTexture"), -1); + obj_set_prop_loc(object, OBJ_KD, -1, glGetUniformLocation(program, "DiffuseTexture"), -1); + obj_set_prop_loc(object, OBJ_KS, -1, glGetUniformLocation(program, "SpecularTexture"), -1); + } + } + + glClearColor(0.2, 0.2, 0.2, 0.0); + glEnable(GL_DEPTH_TEST); + + cam_position = gl::vec3(0, 0, 3); +} + +void example::draw() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glUniformMatrix4fv(ProjectionMatrixLocation, 1, GL_TRUE, projection()); + glUniformMatrix4fv(ModelViewMatrixLocation, 1, GL_TRUE, view()); + glUniformMatrix3fv(NormalMatrixLocation, 1, GL_TRUE, normal(view())); + glUniform4fv (LightPositionLocation, 1, light()); + + if (object) obj_render(object); +} + +int main(void) +{ + example demo; + demo.run(); + return 0; +} diff --git a/etc/fragment.glsl b/etc/fragment.glsl new file mode 100644 index 0000000..dfe6217 --- /dev/null +++ b/etc/fragment.glsl @@ -0,0 +1,39 @@ +#version 150 + +uniform vec4 AmbientLight; + +uniform sampler2D NormalTexture; +uniform sampler2D DiffuseTexture; +uniform sampler2D SpecularTexture; + +in vec3 fView; +in vec3 fLight; +in vec2 fTexCoord; + +out vec4 fColor; + +void main() +{ + // Sample the textures. + + vec4 tN = texture(NormalTexture, fTexCoord); + vec4 tD = texture(DiffuseTexture, fTexCoord); + vec4 tS = texture(SpecularTexture, fTexCoord); + + // Determine the per-fragment lighting vectors. + + vec3 N = normalize(2.0 * tN.xyz - 1.0); + vec3 L = normalize(fLight); + vec3 V = normalize(fView); + vec3 R = reflect(L, N); + + // Compute the diffuse shading. + + float kd = max(dot(L, N), 0.0); + float ks = pow(max(dot(V, R), 0.0), 8.0); + + // Calculate the fragment color. + + fColor.rgb = vec3(AmbientLight * tD + kd * tD + tS * ks); + fColor.a = tD.a; +} diff --git a/etc/vertex.glsl b/etc/vertex.glsl new file mode 100644 index 0000000..54bd3b9 --- /dev/null +++ b/etc/vertex.glsl @@ -0,0 +1,32 @@ +#version 150 + +uniform mat4 ProjectionMatrix; +uniform mat4 ModelViewMatrix; +uniform mat3 NormalMatrix; +uniform vec4 LightPosition; + +in vec4 vPosition; +in vec3 vNormal; +in vec3 vTangent; +in vec2 vTexCoord; + +out vec3 fView; +out vec3 fLight; +out vec2 fTexCoord; + +void main() +{ + // Tangent space vectors give the columns of the eye-to-tangent transform. + + vec3 N = NormalMatrix * vNormal; + vec3 T = NormalMatrix * vTangent; + mat3 M = transpose(mat3(T, cross(N, T), N)); + + // Compute the per-fragment attributes. + + fView = M * vec3(ModelViewMatrix * vPosition); + fLight = M * vec3(ModelViewMatrix * LightPosition); + fTexCoord = vTexCoord; + + gl_Position = ProjectionMatrix * ModelViewMatrix * vPosition; +} diff --git a/obj.c b/obj.c new file mode 100644 index 0000000..e54553f --- /dev/null +++ b/obj.c @@ -0,0 +1,2447 @@ +/* Copyright (c) 2005,2013,2014 Robert Kooima */ +/* */ +/* 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. */ + +#include +#include +#include +#include +#include +#include + +#ifndef CONF_NO_GL +#ifdef __APPLE__ +# include +#else +# include +#endif +#endif + +#define MAXSTR 1024 + +/*============================================================================*/ + +#define index_t unsigned int +#define GL_INDEX_T GL_UNSIGNED_INT +/* +#define index_t unsigned short +#define GL_INDEX_T GL_UNSIGNED_SHORT +*/ +/*============================================================================*/ + +#include "obj.h" + +struct obj_prop +{ + char *str; + int opt; + unsigned int map; + + float c[4]; + float o[3]; + float s[3]; +}; + +struct obj_mtrl +{ + char *name; + + struct obj_prop kv[OBJ_PROP_COUNT]; +}; + +struct obj_vert +{ + float u[3]; + float n[3]; + float t[2]; + float v[3]; +}; + +struct obj_poly +{ + index_t vi[3]; +}; + +struct obj_line +{ + index_t vi[2]; +}; + +struct obj_surf +{ + int mi; + + int pc; + int pm; + int lc; + int lm; + + unsigned int pibo; + unsigned int libo; + + struct obj_poly *pv; + struct obj_line *lv; +}; + +struct obj +{ + unsigned int vao; + unsigned int vbo; + + int mc; + int mm; + int vc; + int vm; + int sc; + int sm; + + int uloc; + int nloc; + int tloc; + int vloc; + + int cloc[OBJ_PROP_COUNT]; + int oloc[OBJ_PROP_COUNT]; + int Mloc[OBJ_PROP_COUNT]; + + struct obj_mtrl *mv; + struct obj_vert *vv; + struct obj_surf *sv; +}; + +static void invalidate(obj *); + +/*----------------------------------------------------------------------------*/ + +#define assert_surf(O, i) \ + { assert(O); assert(0 <= i && i < O->sc); } +#define assert_vert(O, i) \ + { assert(O); assert(0 <= i && i < O->vc); } +#define assert_mtrl(O, i) \ + { assert(O); assert(0 <= i && i < O->mc); } + +#define assert_line(O, i, j) \ + { assert_surf(O, i); assert(0 <= j && j < O->sv[i].lc); } +#define assert_poly(O, i, j) \ + { assert_surf(O, i); assert(0 <= j && j < O->sv[i].pc); } +#define assert_prop(O, i, j) \ + { assert_mtrl(O, i); assert(0 <= j && j < OBJ_PROP_COUNT); } + +/*============================================================================*/ +/* Vector cache */ + +struct vec2 +{ + float v[2]; + int _ii; +}; + +struct vec3 +{ + float v[3]; + int _ii; +}; + +struct iset +{ + int vi; + int gi; + + int _vi; + int _ti; + int _ni; + int _ii; +}; + +static int _vc, _vm; +static int _tc, _tm; +static int _nc, _nm; +static int _ic, _im; + +static struct vec3 *_vv; +static struct vec2 *_tv; +static struct vec3 *_nv; +static struct iset *_iv; + +/*----------------------------------------------------------------------------*/ + +static int add__(void **_v, int *_c, int *_m, size_t _s) +{ + int m = (*_m > 0) ? *_m * 2 : 2; + void *v; + + /* If space remains in the current block, return it. */ + + if (*_m > *_c) + return (*_c)++; + + /* Else, try to increase the size of the block. */ + + else if ((v = realloc(*_v, _s * m))) + { + *_v = v; + *_m = m; + return (*_c)++; + } + + /* Else, indicate failure. */ + + else return -1; +} + +static int add_v(void) +{ + return add__((void **) &_vv, &_vc, &_vm, sizeof (struct vec3)); +} + +static int add_t(void) +{ + return add__((void **) &_tv, &_tc, &_tm, sizeof (struct vec2)); +} + +static int add_n(void) +{ + return add__((void **) &_nv, &_nc, &_nm, sizeof (struct vec3)); +} + +static int add_i(void) +{ + return add__((void **) &_iv, &_ic, &_im, sizeof (struct iset)); +} + +/*============================================================================*/ +/* Handy functions */ + +static void cross(float *z, const float *x, const float *y) +{ + float t[3]; + + t[0] = x[1] * y[2] - x[2] * y[1]; + t[1] = x[2] * y[0] - x[0] * y[2]; + t[2] = x[0] * y[1] - x[1] * y[0]; + + z[0] = t[0]; + z[1] = t[1]; + z[2] = t[2]; +} + +static void normalize(float *v) +{ + float k = 1.0f / (float) sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + + v[0] *= k; + v[1] *= k; + v[2] *= k; +} + +static void normal(float *n, const float *a, + const float *b, + const float *c) +{ + float u[3]; + float v[3]; + + u[0] = b[0] - a[0]; + u[1] = b[1] - a[1]; + u[2] = b[2] - a[2]; + + v[0] = c[0] - a[0]; + v[1] = c[1] - a[1]; + v[2] = c[2] - a[2]; + + cross(n, u, v); + normalize(n); +} + +/*============================================================================*/ + +#pragma pack(push, 1) +struct tga_head +{ + unsigned char id_length; + unsigned char color_map_type; + unsigned char image_type; + unsigned short color_map_offset; + unsigned short color_map_length; + unsigned char color_map_size; + unsigned short image_x_origin; + unsigned short image_y_origin; + unsigned short image_width; + unsigned short image_height; + unsigned char image_depth; + unsigned char image_descriptor; +}; +#pragma pack(pop) + +void *read_tga(const char *filename, int *w, int *h, int *d) +{ + struct tga_head head; + FILE *stream; + + if ((stream = fopen(filename, "rb"))) + { + if (fread(&head, sizeof (struct tga_head), 1, stream) == 1) + { + if (head.image_type == 2) + { + *w = (int) head.image_width; + *h = (int) head.image_height; + *d = (int) head.image_depth; + + if (fseek(stream, head.id_length, SEEK_CUR) == 0) + { + size_t s = (*d) / 8; + size_t n = (*w) * (*h); + void *p; + + if ((p = calloc(n, s))) + { + if (fread(p, s, n, stream) == n) + { + fclose(stream); + return p; + } + } + } + } + } + fclose(stream); + } + return 0; +} + +unsigned int obj_load_image(const char *filename) +{ + unsigned int o = 0; + +#ifndef CONF_NO_GL + if (filename) + { + int w; + int h; + int d; + void *p; + + /* Read the image data from the named file to a new pixel buffer. */ + + if ((p = read_tga(filename, &w, &h, &d))) + { + /* Create an OpenGL texture object using these pixels. */ + + glGenTextures(1, &o); + glBindTexture(GL_TEXTURE_2D, o); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + + if (d == 32) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, + GL_BGRA, GL_UNSIGNED_BYTE, p); + if (d == 24) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, + GL_BGR, GL_UNSIGNED_BYTE, p); + + glGenerateMipmap(GL_TEXTURE_2D); + + /* Discard the unnecessary pixel buffer. */ + + free(p); + } + } +#endif + + return o; +} + +static void dirpath(char *pathname) +{ + int i; + + /* Find the path by cutting a file name at the last directory delimiter. */ + + for (i = (int) strlen(pathname) - 1; i >= 0; --i) + if (pathname[i] == '/' || pathname[i] == '\\') + { + pathname[i] = '\0'; + return; + } + + /* If no delimiter was found, return the current directory. */ + + strcpy(pathname, "."); +} + +/*----------------------------------------------------------------------------*/ + +static void read_image(obj *O, int mi, int ki, const char *line, + const char *path) +{ + unsigned int clamp = 0; + + float o[3] = { 0.0f, 0.0f, 0.0f }; + float s[3] = { 1.0f, 1.0f, 1.0f }; + + char pathname[MAXSTR]; + + char map[MAXSTR]; + char val[MAXSTR]; + + const char *end; + + memset(map, 0, MAXSTR); + memset(val, 0, MAXSTR); + + while (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') + { + int n = 0; + + while(isspace(line[0])) line++; + + /* Parse property map options. */ + + if (sscanf(line, "-clamp %s%n", val, &n) >= 1) + { + clamp = (strcmp(val, "on") == 0) ? OBJ_OPT_CLAMP : 0; + line += n; + } + + /* Parse property map scale. */ + + else if (sscanf(line, "-s %f %f %f%n", s + 0, s + 1, s + 2, &n) >= 3) + line += n; + else if (sscanf(line, "-s %f %f%n", s + 0, s + 1, &n) >= 2) + line += n; + else if (sscanf(line, "-s %f%n", s + 0, &n) >= 1) + line += n; + + /* Parse property map offset. */ + + else if (sscanf(line, "-o %f %f %f%n", o + 0, o + 1, o + 2, &n) >= 3) + line += n; + else if (sscanf(line, "-o %f %f%n", o + 0, o + 1, &n) >= 2) + line += n; + else if (sscanf(line, "-o %f%n", o + 0, &n) >= 1) + line += n; + + /* Check for a file name */ + + else if ((end = strstr(line, ".tga"))) { strncpy(map, line, end - line + 4); break; } + else if ((end = strstr(line, ".TGA"))) { strncpy(map, line, end - line + 4); break; } + + /* If we see something we don't recognize, stop looking. */ + + else break; + } + + /* Apply all parsed property attributes to the material. */ + + sprintf(pathname, "%s/%s", path, map); + + obj_set_mtrl_opt(O, mi, ki, clamp); + obj_set_mtrl_map(O, mi, ki, pathname); + obj_set_mtrl_o (O, mi, ki, o); + obj_set_mtrl_s (O, mi, ki, s); +} + +static void read_color(obj *O, int mi, int ki, const char *line) +{ + float c[4]; + + /* Merge incoming color components with existing defaults. */ + + obj_get_mtrl_c(O, mi, ki, c); + sscanf(line, "%f %f %f", c, c + 1, c + 2); + obj_set_mtrl_c(O, mi, ki, c); +} + +static void read_alpha(obj *O, int mi, int ki, const char *line) +{ + float c[4]; + float t; + + /* Merge incoming color components with existing defaults. */ + + obj_get_mtrl_c(O, mi, ki, c); + sscanf(line, "%f", &t); + c[3] = 1.0 - t; + obj_set_mtrl_c(O, mi, ki, c); +} + +static void read_mtl(const char *path, + const char *file, + const char *name, obj *O, int mi) +{ + char pathname[MAXSTR]; + + char buf[MAXSTR]; + char key[MAXSTR]; + char arg[MAXSTR]; + + FILE *fin; + + int scanning = 1; + int n = 0; + + sprintf(pathname, "%s/%s", path, file); + + if ((fin = fopen(pathname, "r"))) + { + /* Process each line of the MTL file. */ + + while (fgets (buf, MAXSTR, fin)) + if (sscanf(buf, "%s%n", key, &n) >= 1) + { + const char *c = buf + n; + + if (scanning) + { + /* Determine if we've found the MTL we're looking for. */ + + if (!strcmp(key, "newmtl")) + { + sscanf(c, "%s", arg); + + if ((scanning = strcmp(arg, name)) == 0) + obj_set_mtrl_name(O, mi, name); + } + } + else + { + /* Stop scanning when the next MTL begins. */ + + if (!strcmp(key, "newmtl")) + break; + + /* Parse this material's properties. */ + + else if (!strcmp(key, "map_Kd")) + read_image(O, mi, OBJ_KD, c, path); + else if (!strcmp(key, "map_Ka")) + read_image(O, mi, OBJ_KA, c, path); + else if (!strcmp(key, "map_Ke")) + read_image(O, mi, OBJ_KE, c, path); + else if (!strcmp(key, "map_Ks")) + read_image(O, mi, OBJ_KS, c, path); + else if (!strcmp(key, "map_Ns")) + read_image(O, mi, OBJ_NS, c, path); + else if (!strcmp(key, "map_Kn")) + read_image(O, mi, OBJ_KN, c, path); + + else if (!strcmp(key, "Kd")) + read_color(O, mi, OBJ_KD, c); + else if (!strcmp(key, "Ka")) + read_color(O, mi, OBJ_KA, c); + else if (!strcmp(key, "Ke")) + read_color(O, mi, OBJ_KE, c); + else if (!strcmp(key, "Ks")) + read_color(O, mi, OBJ_KS, c); + else if (!strcmp(key, "Ns")) + read_color(O, mi, OBJ_NS, c); + + else if (!strcmp(key, "d")) + read_alpha(O, mi, OBJ_KD, c); + else if (!strcmp(key, "Tr")) + read_alpha(O, mi, OBJ_KD, c); + } + } + fclose(fin); + } +} + +static void read_mtllib(char *file, const char *line) +{ + /* Parse the first file name from the given line. */ + + sscanf(line, "%s", file); +} + +static int read_usemtl(const char *path, + const char *file, + const char *line, obj *O) +{ + char name[MAXSTR]; + + int si; + int mi; + + sscanf(line, "%s", name); + + /* Create a new material for the incoming definition. */ + + if ((mi = obj_add_mtrl(O)) >= 0) + { + /* Create a new surface to contain geometry with the new material. */ + + if ((si = obj_add_surf(O)) >= 0) + { + /* Read the material definition and apply it to the new surface. */ + + read_mtl(path, file, name, O, mi); + obj_set_surf(O, si, mi); + + /* Return the surface so that new geometry may be added to it. */ + + return si; + } + } + + /* On failure, return the default surface. */ + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +static int read_poly_indices(const char *line, int *_vi, int *_ti, int *_ni) +{ + int n; + + *_vi = 0; + *_ti = 0; + *_ni = 0; + + /* Parse a face vertex specification from the given line. */ + + if (sscanf(line, "%d/%d/%d%n", _vi, _ti, _ni, &n) >= 3) return n; + if (sscanf(line, "%d/%d%n", _vi, _ti, &n) >= 2) return n; + if (sscanf(line, "%d//%d%n", _vi, _ni, &n) >= 2) return n; + if (sscanf(line, "%d%n", _vi, &n) >= 1) return n; + + return 0; +} + +static int read_poly_vertices(const char *line, obj *O, int gi) +{ + const char *c = line; + + int _vi; + int _ti; + int _ni; + int _ii; + int _ij; + + int dc; + int vi; + int ic = 0; + + /* Scan the face string, converting index sets to vertices. */ + + while ((dc = read_poly_indices(c, &_vi, &_ti, &_ni))) + { + /* Convert face indices to vector cache indices. */ + + _vi += (_vi < 0) ? _vc : -1; + _ti += (_ti < 0) ? _tc : -1; + _ni += (_ni < 0) ? _nc : -1; + + /* Initialize a new index set. */ + + if ((_ii = add_i()) >= 0) + { + _iv[_ii]._vi = _vi; + _iv[_ii]._ni = _ni; + _iv[_ii]._ti = _ti; + + /* Search the vector reference list for a repeated index set. */ + + for (_ij = _vv[_vi]._ii; _ij >= 0; _ij = _iv[_ij]._ii) + if (_iv[_ij]._vi == _vi && + _iv[_ij]._ti == _ti && + _iv[_ij]._ni == _ni && + _iv[_ij]. gi == gi) + { + /* A repeat has been found. Link new to old. */ + + _vv[_vi]._ii = _ii; + _iv[_ii]._ii = _ij; + _iv[_ii]. vi = _iv[_ij].vi; + _iv[_ii]. gi = _iv[_ij].gi; + + break; + } + + /* If no repeat was found, add a new vertex. */ + + if ((_ij < 0) && (vi = obj_add_vert(O)) >= 0) + { + _vv[_vi]._ii = _ii; + _iv[_ii]._ii = -1; + _iv[_ii]. vi = vi; + _iv[_ii]. gi = gi; + + /* Initialize the new vertex using valid cache references. */ + + if (0 <= _vi && _vi < _vc) obj_set_vert_v(O, vi, _vv[_vi].v); + if (0 <= _ni && _ni < _nc) obj_set_vert_n(O, vi, _nv[_ni].v); + if (0 <= _ti && _ti < _tc) obj_set_vert_t(O, vi, _tv[_ti].v); + } + ic++; + } + c += dc; + } + return ic; +} + +static void read_f(const char *line, obj *O, int si, int gi) +{ + float n[3]; + float t[3]; + int i, pi; + + /* Create new vertex references for this face. */ + + int i0 = _ic; + int ic = read_poly_vertices(line, O, gi); + + /* If smoothing, apply this face's normal to vertices that need it. */ + + if (gi) + { + normal(n, _vv[_iv[i0 + 0]._vi].v, + _vv[_iv[i0 + 1]._vi].v, + _vv[_iv[i0 + 2]._vi].v); + + for (i = 0; i < ic; ++i) + if (_iv[i0 + 0]._ni < 0) + { + obj_get_vert_n(O, _iv[i0 + i]._vi, t); + t[0] += n[0]; + t[1] += n[1]; + t[2] += n[2]; + obj_set_vert_n(O, _iv[i0 + i]._vi, t); + } + } + + /* Convert our N new vertex references into N-2 new triangles. */ + + for (i = 0; i < ic - 2; ++i) + + if ((pi = obj_add_poly(O, si)) >= 0) + { + int vi[3]; + + vi[0] = _iv[i0 ].vi; + vi[1] = _iv[i0 + i + 1].vi; + vi[2] = _iv[i0 + i + 2].vi; + + obj_set_poly(O, si, pi, vi); + } +} + +/*----------------------------------------------------------------------------*/ + +static int read_line_indices(const char *line, int *_vi, int *_ti) +{ + int n; + + *_vi = 0; + *_ti = 0; + + /* Parse a line vertex specification from the given line. */ + + if (sscanf(line, "%d/%d%n", _vi, _ti, &n) >= 2) return n; + if (sscanf(line, "%d%n", _vi, &n) >= 1) return n; + + return 0; +} + +static int read_line_vertices(const char *line, obj *O) +{ + const char *c = line; + + int _vi; + int _ti; + int _ii; + int _ij; + + int dc; + int vi; + int ic = 0; + + /* Scan the line string, converting index sets to vertices. */ + + while ((dc = read_line_indices(c, &_vi, &_ti))) + { + /* Convert line indices to vector cache indices. */ + + _vi += (_vi < 0) ? _vc : -1; + _ti += (_ti < 0) ? _tc : -1; + + /* Initialize a new index set. */ + + if ((_ii = add_i()) >= 0) + { + _iv[_ii]._vi = _vi; + _iv[_ii]._ti = _ti; + + /* Search the vector reference list for a repeated index set. */ + + for (_ij = _vv[_vi]._ii; _ij >= 0; _ij = _iv[_ij]._ii) + if (_iv[_ij]._vi == _vi && + _iv[_ij]._ti == _ti) + { + /* A repeat has been found. Link new to old. */ + + _vv[_vi]._ii = _ii; + _iv[_ii]._ii = _ij; + _iv[_ii]. vi = _iv[_ij].vi; + + break; + } + + /* If no repeat was found, add a new vertex. */ + + if ((_ij < 0) && (vi = obj_add_vert(O)) >= 0) + { + _vv[_vi]._ii = _ii; + _iv[_ii]._ii = -1; + _iv[_ii]. vi = vi; + + /* Initialize the new vertex using valid cache references. */ + + if (0 <= _vi && _vi < _vc) obj_set_vert_v(O, vi, _vv[_vi].v); + if (0 <= _ti && _ti < _tc) obj_set_vert_t(O, vi, _tv[_ti].v); + } + ic++; + } + c += dc; + } + return ic; +} + +static void read_l(const char *line, obj *O, int si) +{ + int i, li; + + /* Create new vertices for this line. */ + + int i0 = _ic; + int ic = read_line_vertices(line, O); + + /* Convert our N new vertices into N-1 new lines. */ + + for (i = 0; i < ic - 1; ++i) + + if ((li = obj_add_line(O, si)) >= 0) + { + int vi[2]; + + vi[0] = _iv[i0 + i ].vi; + vi[1] = _iv[i0 + i + 1].vi; + + obj_set_line(O, si, li, vi); + } +} + +/*----------------------------------------------------------------------------*/ + +static void read_v(const char *line) +{ + int _vi; + + /* Parse a vertex position. */ + + if ((_vi = add_v()) >= 0) + { + sscanf(line, "%f %f %f", _vv[_vi].v + 0, + _vv[_vi].v + 1, + _vv[_vi].v + 2); + _vv[_vi]._ii = -1; + } +} + +static void read_vt(const char *line) +{ + int _ti; + + /* Parse a texture coordinate. */ + + if ((_ti = add_t()) >= 0) + { + sscanf(line, "%f %f", _tv[_ti].v + 0, + _tv[_ti].v + 1); + _tv[_ti]._ii = -1; + } +} + +static void read_vn(const char *line) +{ + int _ni; + + /* Parse a normal. */ + + if ((_ni = add_n()) >= 0) + { + sscanf(line, "%f %f %f", _nv[_ni].v + 0, + _nv[_ni].v + 1, + _nv[_ni].v + 2); + _nv[_ni]._ii = -1; + } +} + +/*----------------------------------------------------------------------------*/ + +static void read_obj(obj *O, const char *filename) +{ + char buf[MAXSTR]; + char key[MAXSTR]; + + char L[MAXSTR]; + char D[MAXSTR]; + + FILE *fin; + + /* Flush the vector caches. */ + + _vc = 0; + _tc = 0; + _nc = 0; + _ic = 0; + + /* Add the named file to the given object. */ + + if ((fin = fopen(filename, "r"))) + { + /* Ensure there exists a default surface 0 and default material 0. */ + + int si = obj_add_surf(O); + int mi = obj_add_mtrl(O); + int gi = 0; + int n; + + obj_set_surf(O, si, mi); + + /* Extract the directory from the filename for use in MTL loading. */ + + strncpy(D, filename, MAXSTR); + dirpath(D); + + /* Process each line of the OBJ file, invoking the handler for each. */ + + while (fgets (buf, MAXSTR, fin)) + if (sscanf(buf, "%s%n", key, &n) >= 1) + { + const char *c = buf + n; + + if (!strcmp(key, "f" )) read_f (c, O, si, gi); + else if (!strcmp(key, "l" )) read_l (c, O, si); + else if (!strcmp(key, "vt")) read_vt(c); + else if (!strcmp(key, "vn")) read_vn(c); + else if (!strcmp(key, "v" )) read_v (c); + + else if (!strcmp(key, "mtllib")) read_mtllib( L, c ); + else if (!strcmp(key, "usemtl")) si = read_usemtl(D, L, c, O); + else if (!strcmp(key, "s" )) gi = atoi(c); + } + + fclose(fin); + } +} + +/*----------------------------------------------------------------------------*/ + +static void obj_rel_mtrl(struct obj_mtrl *mp) +{ + /* Release any resources held by this material. */ + + int ki; + + for (ki = 0; ki < OBJ_PROP_COUNT; ki++) + { + if (mp->kv[ki].str) free(mp->kv[ki].str); +#ifndef CONF_NO_GL + if (mp->kv[ki].map) glDeleteTextures(1, &mp->kv[ki].map); +#endif + } +} + +static void obj_rel_surf(struct obj_surf *sp) +{ +#ifndef CONF_NO_GL + if (sp->pibo) glDeleteBuffers(1, &sp->pibo); + if (sp->libo) glDeleteBuffers(1, &sp->libo); +#endif + + sp->pibo = 0; + sp->libo = 0; + + /* Release this surface's polygon and line vectors. */ + + if (sp->pv) free(sp->pv); + if (sp->lv) free(sp->lv); +} + +static void obj_rel(obj *O) +{ + int si; + int mi; + + /* Release resources held by this file and it's materials and surfaces. */ + +#ifndef CONF_NO_GL + if (O->vbo) glDeleteBuffers (1, &O->vbo); + if (O->vao) glDeleteVertexArrays(1, &O->vao); +#endif + + O->vbo = 0; + + for (mi = 0; mi < O->mc; ++mi) obj_rel_mtrl(O->mv + mi); + for (si = 0; si < O->sc; ++si) obj_rel_surf(O->sv + si); +} + +/*============================================================================*/ + +obj *obj_create(const char *filename) +{ + obj *O; + int i; + + /* Allocate and initialize a new file. */ + + if ((O = (obj *) calloc(1, sizeof (obj)))) + { + if (filename) + { + /* Read the named file. */ + + read_obj(O, filename); + + /* Post-process the loaded object. */ + + obj_mini(O); + obj_proc(O); + } + + /* Set default shader locations. */ + + for (i = 0; i < OBJ_PROP_COUNT; i++) + { + O->cloc[i] = -1; + O->oloc[i] = -1; + O->Mloc[i] = -1; + } + O->uloc = -1; + O->nloc = -1; + O->tloc = -1; + O->vloc = -1; + } + return O; +} + +void obj_delete(obj *O) +{ + assert(O); + + obj_rel(O); + + free(O); +} + +/*----------------------------------------------------------------------------*/ + +int obj_add_mtrl(obj *O) +{ + unsigned int opt = 0; + + const float Kd[4] = { 0.8f, 0.8f, 0.8f, 1.0f }; + const float Ka[4] = { 0.2f, 0.2f, 0.2f, 1.0f }; + const float Ke[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + const float Ks[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + const float Ns[4] = { 8.0f, 0.0f, 0.0f, 0.0f }; + const float s[3] = { 1.0f, 1.0f, 1.0f }; + + int mi; + + assert(O); + + /* Allocate and initialize a new material. */ + + if ((mi = add__((void **) &O->mv, + &O->mc, + &O->mm, sizeof (struct obj_mtrl))) >= 0) + { + memset(O->mv + mi, 0, sizeof (struct obj_mtrl)); + + obj_set_mtrl_opt(O, mi, OBJ_KD, opt); + obj_set_mtrl_opt(O, mi, OBJ_KA, opt); + obj_set_mtrl_opt(O, mi, OBJ_KE, opt); + obj_set_mtrl_opt(O, mi, OBJ_KS, opt); + obj_set_mtrl_opt(O, mi, OBJ_NS, opt); + obj_set_mtrl_opt(O, mi, OBJ_KN, opt); + + obj_set_mtrl_c (O, mi, OBJ_KD, Kd); + obj_set_mtrl_c (O, mi, OBJ_KA, Ka); + obj_set_mtrl_c (O, mi, OBJ_KE, Ke); + obj_set_mtrl_c (O, mi, OBJ_KS, Ks); + obj_set_mtrl_c (O, mi, OBJ_NS, Ns); + + obj_set_mtrl_s (O, mi, OBJ_KD, s); + obj_set_mtrl_s (O, mi, OBJ_KA, s); + obj_set_mtrl_s (O, mi, OBJ_KE, s); + obj_set_mtrl_s (O, mi, OBJ_KS, s); + obj_set_mtrl_s (O, mi, OBJ_NS, s); + obj_set_mtrl_s (O, mi, OBJ_KN, s); + } + return mi; +} + +int obj_add_vert(obj *O) +{ + int vi; + + assert(O); + + /* Allocate and initialize a new vertex. */ + + if ((vi = add__((void **) &O->vv, + &O->vc, + &O->vm, sizeof (struct obj_vert))) >= 0) + + memset(O->vv + vi, 0, sizeof (struct obj_vert)); + + return vi; +} + +int obj_add_poly(obj *O, int si) +{ + int pi; + + assert_surf(O, si); + + /* Allocate and initialize a new polygon. */ + + if ((pi = add__((void **) &O->sv[si].pv, + &O->sv[si].pc, + &O->sv[si].pm, sizeof (struct obj_poly)))>=0) + + memset(O->sv[si].pv + pi, 0, sizeof (struct obj_poly)); + + return pi; +} + +int obj_add_line(obj *O, int si) +{ + int li; + + assert_surf(O, si); + + /* Allocate and initialize a new line. */ + + if ((li = add__((void **) &O->sv[si].lv, + &O->sv[si].lc, + &O->sv[si].lm, sizeof (struct obj_line)))>=0) + + memset(O->sv[si].lv + li, 0, sizeof (struct obj_line)); + + return li; +} + +int obj_add_surf(obj *O) +{ + int si; + + assert(O); + + /* Allocate and initialize a new surface. */ + + if ((si = add__((void **) &O->sv, + &O->sc, + &O->sm, sizeof (struct obj_surf))) >= 0) + + memset(O->sv + si, 0, sizeof (struct obj_surf)); + + return si; +} + +/*----------------------------------------------------------------------------*/ + +int obj_num_mtrl(const obj *O) +{ + assert(O); + return O->mc; +} + +int obj_num_vert(const obj *O) +{ + assert(O); + return O->vc; +} + +int obj_num_poly(const obj *O, int si) +{ + assert_surf(O, si); + return O->sv[si].pc; +} + +int obj_num_line(const obj *O, int si) +{ + assert_surf(O, si); + return O->sv[si].lc; +} + +int obj_num_surf(const obj *O) +{ + assert(O); + return O->sc; +} + + +/*----------------------------------------------------------------------------*/ + +void obj_del_mtrl(obj *O, int mi) +{ + int si; + + assert_mtrl(O, mi); + + /* Remove this material from the material vector. */ + + obj_rel_mtrl(O->mv + mi); + + memmove(O->mv + mi, + O->mv + mi + 1, + (O->mc - mi - 1) * sizeof (struct obj_mtrl)); + + O->mc--; + + /* Remove all references to this material. */ + + for (si = O->sc - 1; si >= 0; --si) + { + struct obj_surf *sp = O->sv + si; + + if (sp->mi == mi) + obj_del_surf(O, si); + else + if (sp->mi > mi) + sp->mi--; + } +} + +void obj_del_vert(obj *O, int vi) +{ + int si; + int pi; + int li; + + assert_vert(O, vi); + + /* Remove this vertex from the file's vertex vector. */ + + memmove(O->vv + vi, + O->vv + vi + 1, + (O->vc - vi - 1) * sizeof (struct obj_vert)); + + O->vc--; + + /* Remove all references to this vertex from all surfaces. */ + + for (si = 0; si < O->sc; ++si) + { + /* Delete all referencing polygons. Decrement later references. */ + + for (pi = O->sv[si].pc - 1; pi >= 0; --pi) + { + struct obj_poly *pp = O->sv[si].pv + pi; + + if (pp->vi[0] == vi || pp->vi[1] == vi || pp->vi[2] == vi) + obj_del_poly(O, si, pi); + else + { + if (pp->vi[0] > vi) pp->vi[0]--; + if (pp->vi[1] > vi) pp->vi[1]--; + if (pp->vi[2] > vi) pp->vi[2]--; + } + } + + /* Delete all referencing lines. Decrement later references. */ + + for (li = O->sv[si].lc - 1; li >= 0; --li) + { + struct obj_line *lp = O->sv[si].lv + li; + + if (lp->vi[0] == vi || lp->vi[1] == vi) + obj_del_line(O, si, li); + else + { + if (lp->vi[0] > vi) lp->vi[0]--; + if (lp->vi[1] > vi) lp->vi[1]--; + } + } + } + + /* Schedule the VBO for refresh. */ + + invalidate(O); +} + +void obj_del_poly(obj *O, int si, int pi) +{ + assert_poly(O, si, pi); + + /* Remove this polygon from the surface's polygon vector. */ + + memmove(O->sv[si].pv + pi, + O->sv[si].pv + pi + 1, + (O->sv[si].pc - pi - 1) * sizeof (struct obj_poly)); + + O->sv[si].pc--; +} + +void obj_del_line(obj *O, int si, int li) +{ + assert_line(O, si, li); + + /* Remove this line from the surface's line vector. */ + + memmove(O->sv[si].lv + li, + O->sv[si].lv + li + 1, + (O->sv[si].lc - li - 1) * sizeof (struct obj_line)); + + O->sv[si].lc--; +} + +void obj_del_surf(obj *O, int si) +{ + assert_surf(O, si); + + /* Remove this surface from the file's surface vector. */ + + obj_rel_surf(O->sv + si); + + memmove(O->sv + si, + O->sv + si + 1, + (O->sc - si - 1) * sizeof (struct obj_surf)); + + O->sc--; +} + +/*----------------------------------------------------------------------------*/ + +static char *set_name(char *old, const char *src) +{ + char *dst = NULL; + + if (old) + free(old); + + if (src && (dst = (char *) malloc(strlen(src) + 1))) + strcpy(dst, src); + + return dst; +} + +void obj_set_mtrl_name(obj *O, int mi, const char *name) +{ + assert_mtrl(O, mi); + O->mv[mi].name = set_name(O->mv[mi].name, name); +} + +void obj_set_mtrl_map(obj *O, int mi, int ki, const char *str) +{ + assert_prop(O, mi, ki); + +#ifndef CONF_NO_GL + if (O->mv[mi].kv[ki].map) + glDeleteTextures(1, &O->mv[mi].kv[ki].map); +#endif + + O->mv[mi].kv[ki].map = obj_load_image(str); + O->mv[mi].kv[ki].str = set_name(O->mv[mi].kv[ki].str, str); +} + +void obj_set_mtrl_opt(obj *O, int mi, int ki, unsigned int opt) +{ + assert_prop(O, mi, ki); + + O->mv[mi].kv[ki].opt = opt; +} + +void obj_set_mtrl_c(obj *O, int mi, int ki, const float c[4]) +{ + assert_prop(O, mi, ki); + + O->mv[mi].kv[ki].c[0] = c[0]; + O->mv[mi].kv[ki].c[1] = c[1]; + O->mv[mi].kv[ki].c[2] = c[2]; + O->mv[mi].kv[ki].c[3] = c[3]; +} + +void obj_set_mtrl_s(obj *O, int mi, int ki, const float s[3]) +{ + assert_prop(O, mi, ki); + + O->mv[mi].kv[ki].s[0] = s[0]; + O->mv[mi].kv[ki].s[1] = s[1]; + O->mv[mi].kv[ki].s[2] = s[2]; +} + +void obj_set_mtrl_o(obj *O, int mi, int ki, const float o[3]) +{ + assert_prop(O, mi, ki); + + O->mv[mi].kv[ki].o[0] = o[0]; + O->mv[mi].kv[ki].o[1] = o[1]; + O->mv[mi].kv[ki].o[2] = o[2]; +} + +/*----------------------------------------------------------------------------*/ + +static void invalidate(obj *O) +{ +#ifndef CONF_NO_GL + if (O->vbo) glDeleteBuffers (1, &O->vbo); + if (O->vao) glDeleteVertexArrays(1, &O->vao); +#endif + O->vbo = 0; + O->vao = 0; +} + +void obj_set_vert_v(obj *O, int vi, const float v[3]) +{ + assert_vert(O, vi); + + O->vv[vi].v[0] = v[0]; + O->vv[vi].v[1] = v[1]; + O->vv[vi].v[2] = v[2]; + + invalidate(O); +} + +void obj_set_vert_t(obj *O, int vi, const float t[2]) +{ + assert_vert(O, vi); + + O->vv[vi].t[0] = t[0]; + O->vv[vi].t[1] = t[1]; + + invalidate(O); +} + +void obj_set_vert_n(obj *O, int vi, const float n[3]) +{ + assert_vert(O, vi); + + O->vv[vi].n[0] = n[0]; + O->vv[vi].n[1] = n[1]; + O->vv[vi].n[2] = n[2]; + + invalidate(O); +} + +void obj_set_vert_u(obj *O, int vi, const float u[3]) +{ + assert_vert(O, vi); + + O->vv[vi].u[0] = u[0]; + O->vv[vi].u[1] = u[1]; + O->vv[vi].u[2] = u[2]; + + invalidate(O); +} + +/*----------------------------------------------------------------------------*/ + +void obj_set_poly(obj *O, int si, int pi, const int vi[3]) +{ + assert_poly(O, si, pi); + + O->sv[si].pv[pi].vi[0] = (index_t) vi[0]; + O->sv[si].pv[pi].vi[1] = (index_t) vi[1]; + O->sv[si].pv[pi].vi[2] = (index_t) vi[2]; +} + +void obj_set_line(obj *O, int si, int li, const int vi[2]) +{ + assert_line(O, si, li); + + O->sv[si].lv[li].vi[0] = (index_t) vi[0]; + O->sv[si].lv[li].vi[1] = (index_t) vi[1]; +} + +void obj_set_surf(obj *O, int si, int mi) +{ + assert_surf(O, si); + + O->sv[si].mi = mi; +} + +/*----------------------------------------------------------------------------*/ + +void obj_set_vert_loc(obj *O, int u, int n, int t, int v) +{ + assert(O); + + O->uloc = u; + O->nloc = n; + O->tloc = t; + O->vloc = v; + + invalidate(O); +} + +void obj_set_prop_loc(obj *O, int ki, int c, int o, int M) +{ + assert(O); + assert(0 <= ki && ki < OBJ_PROP_COUNT); + + O->cloc[ki] = c; + O->oloc[ki] = o; + O->Mloc[ki] = M; +} + +/*============================================================================*/ + +const char *obj_get_mtrl_name(const obj *O, int mi) +{ + assert_mtrl(O, mi); + return O->mv[mi].name; +} + +unsigned int obj_get_mtrl_map(const obj *O, int mi, int ki) +{ + assert_prop(O, mi, ki); + return O->mv[mi].kv[ki].map; +} + +unsigned int obj_get_mtrl_opt(const obj *O, int mi, int ki) +{ + assert_prop(O, mi, ki); + return O->mv[mi].kv[ki].opt; +} + +void obj_get_mtrl_c(const obj *O, int mi, int ki, float *c) +{ + assert_prop(O, mi, ki); + + c[0] = O->mv[mi].kv[ki].c[0]; + c[1] = O->mv[mi].kv[ki].c[1]; + c[2] = O->mv[mi].kv[ki].c[2]; + c[3] = O->mv[mi].kv[ki].c[3]; +} + +void obj_get_mtrl_s(const obj *O, int mi, int ki, float *s) +{ + assert_prop(O, mi, ki); + + s[0] = O->mv[mi].kv[ki].s[0]; + s[1] = O->mv[mi].kv[ki].s[1]; + s[2] = O->mv[mi].kv[ki].s[2]; +} + +void obj_get_mtrl_o(const obj *O, int mi, int ki, float *o) +{ + assert_prop(O, mi, ki); + + o[0] = O->mv[mi].kv[ki].o[0]; + o[1] = O->mv[mi].kv[ki].o[1]; + o[2] = O->mv[mi].kv[ki].o[2]; +} + +/*----------------------------------------------------------------------------*/ + +void obj_get_vert_v(const obj *O, int vi, float *v) +{ + assert_vert(O, vi); + + v[0] = O->vv[vi].v[0]; + v[1] = O->vv[vi].v[1]; + v[2] = O->vv[vi].v[2]; +} + +void obj_get_vert_t(const obj *O, int vi, float *t) +{ + assert_vert(O, vi); + + t[0] = O->vv[vi].t[0]; + t[1] = O->vv[vi].t[1]; +} + +void obj_get_vert_n(const obj *O, int vi, float *n) +{ + assert_vert(O, vi); + + n[0] = O->vv[vi].n[0]; + n[1] = O->vv[vi].n[1]; + n[2] = O->vv[vi].n[2]; +} + +/*----------------------------------------------------------------------------*/ + +void obj_get_poly(const obj *O, int si, int pi, int *vi) +{ + assert_poly(O, si, pi); + + vi[0] = (int) O->sv[si].pv[pi].vi[0]; + vi[1] = (int) O->sv[si].pv[pi].vi[1]; + vi[2] = (int) O->sv[si].pv[pi].vi[2]; +} + +void obj_get_line(const obj *O, int si, int li, int *vi) +{ + assert_line(O, si, li); + + vi[0] = (int) O->sv[si].lv[li].vi[0]; + vi[1] = (int) O->sv[si].lv[li].vi[1]; +} + +int obj_get_surf(const obj *O, int si) +{ + assert_surf(O, si); + return O->sv[si].mi; +} + +/*============================================================================*/ + +void obj_mini(obj *O) +{ + int si; + int mi; + + /* Remove empty surfaces. */ + + for (si = O->sc - 1; si >= 0; --si) + if (O->sv[si].pc == 0 && + O->sv[si].lc == 0) + obj_del_surf(O, si); + + /* Remove unreferenced materials. */ + + for (mi = O->mc - 1; mi >= 0; --mi) + { + int cc = 0; + + for (si = 0; si < O->sc; ++si) + if (O->sv[si].mi == mi) + cc++; + + if (cc == 0) + obj_del_mtrl(O, mi); + } +} + +void obj_norm(obj *O) +{ + int vi; + int si; + int pi; + + assert(O); + + /* Zero the normals for all vertices. */ + + for (vi = 0; vi < O->vc; ++vi) + { + O->vv[vi].n[0] = 0; + O->vv[vi].n[1] = 0; + O->vv[vi].n[2] = 0; + } + + /* Compute normals for all faces. */ + + for (si = 0; si < O->sc; ++si) + for (pi = 0; pi < O->sv[si].pc; ++pi) + { + struct obj_vert *v0 = O->vv + O->sv[si].pv[pi].vi[0]; + struct obj_vert *v1 = O->vv + O->sv[si].pv[pi].vi[1]; + struct obj_vert *v2 = O->vv + O->sv[si].pv[pi].vi[2]; + + float n[3]; + + /* Compute the normal formed by these 3 vertices. */ + + normal(n, v0->v, v1->v, v2->v); + + /* Sum this normal to all vertices. */ + + v0->n[0] += n[0]; + v0->n[1] += n[1]; + v0->n[2] += n[2]; + + v1->n[0] += n[0]; + v1->n[1] += n[1]; + v1->n[2] += n[2]; + + v2->n[0] += n[0]; + v2->n[1] += n[1]; + v2->n[2] += n[2]; + } +} + +void obj_proc(obj *O) +{ + int si; + int sj; + int pi; + int vi; + + assert(O); + + /* Normalize all normals. Zero all tangent vectors. */ + + for (vi = 0; vi < O->vc; ++vi) + { + normalize(O->vv[vi].n); + + O->vv[vi].u[0] = 0.0f; + O->vv[vi].u[1] = 0.0f; + O->vv[vi].u[2] = 0.0f; + } + + /* Compute tangent vectors for all vertices. */ + + for (si = 0; si < O->sc; ++si) + for (pi = 0; pi < O->sv[si].pc; ++pi) + { + struct obj_vert *v0 = O->vv + O->sv[si].pv[pi].vi[0]; + struct obj_vert *v1 = O->vv + O->sv[si].pv[pi].vi[1]; + struct obj_vert *v2 = O->vv + O->sv[si].pv[pi].vi[2]; + + float dt1, dv1[3]; + float dt2, dv2[3]; + + float u[3]; + + /* Compute the tangent vector for this polygon. */ + + dv1[0] = v1->v[0] - v0->v[0]; + dv1[1] = v1->v[1] - v0->v[1]; + dv1[2] = v1->v[2] - v0->v[2]; + + dv2[0] = v2->v[0] - v0->v[0]; + dv2[1] = v2->v[1] - v0->v[1]; + dv2[2] = v2->v[2] - v0->v[2]; + + dt1 = v1->t[1] - v0->t[1]; + dt2 = v2->t[1] - v0->t[1]; + + u[0] = dt2 * dv1[0] - dt1 * dv2[0]; + u[1] = dt2 * dv1[1] - dt1 * dv2[1]; + u[2] = dt2 * dv1[2] - dt1 * dv2[2]; + + normalize(u); + + /* Accumulate the tangent vectors for this polygon's vertices. */ + + v0->u[0] += u[0]; v0->u[1] += u[1]; v0->u[2] += u[2]; + v1->u[0] += u[0]; v1->u[1] += u[1]; v1->u[2] += u[2]; + v2->u[0] += u[0]; v2->u[1] += u[1]; v2->u[2] += u[2]; + } + + /* Orthonormalize each tangent basis. */ + + for (vi = 0; vi < O->vc; ++vi) + { + float *n = O->vv[vi].n; + float *u = O->vv[vi].u; + + float v[3]; + + cross(v, n, u); + cross(u, v, n); + normalize(u); + } + + /* Sort surfaces such that transparent ones appear later. */ + + for (si = 0; si < O->sc; ++si) + for (sj = si + 1; sj < O->sc; ++sj) + if (O->mv[O->sv[si].mi].kv[OBJ_KD].c[3] < + O->mv[O->sv[sj].mi].kv[OBJ_KD].c[3]) + { + struct obj_surf temp; + + temp = O->sv[si]; + O->sv[si] = O->sv[sj]; + O->sv[sj] = temp; + } +} + +void obj_init(obj *O) +{ +#ifndef CONF_NO_GL + if (O->vao == 0) + { + const size_t vs = sizeof (struct obj_vert); + const size_t ps = sizeof (struct obj_poly); + const size_t ls = sizeof (struct obj_line); + + int si; + + /* Store the following bindings in a vertex array object. */ + + glGenVertexArrays(1, &O->vao); + glBindVertexArray( O->vao); + + /* Store all vertex data in a vertex buffer object. */ + + glGenBuffers(1, &O->vbo); + glBindBuffer(GL_ARRAY_BUFFER, O->vbo); + glBufferData(GL_ARRAY_BUFFER, O->vc * vs, O->vv, GL_STATIC_DRAW); + + /* Store all index data in index buffer objects. */ + + for (si = 0; si < O->sc; ++si) + { + if (O->sv[si].pc > 0) + { + glGenBuffers(1, &O->sv[si].pibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, O->sv[si].pibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, O->sv[si].pc * ps, + O->sv[si].pv, GL_STATIC_DRAW); + } + + if (O->sv[si].lc > 0) + { + glGenBuffers(1, &O->sv[si].libo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, O->sv[si].libo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, O->sv[si].lc * ls, + O->sv[si].lv, GL_STATIC_DRAW); + } + } + + /* Enable and bind the attributes. */ + + if (O->uloc >= 0) + { + glEnableVertexAttribArray(O->uloc); + glVertexAttribPointer(O->uloc, 3, GL_FLOAT, GL_FALSE, vs, (const GLvoid *) 0); + } + if (O->nloc >= 0) + { + glEnableVertexAttribArray(O->nloc); + glVertexAttribPointer(O->nloc, 3, GL_FLOAT, GL_FALSE, vs, (const GLvoid *) 12); + } + if (O->tloc >= 0) + { + glEnableVertexAttribArray(O->tloc); + glVertexAttribPointer(O->tloc, 2, GL_FLOAT, GL_FALSE, vs, (const GLvoid *) 24); + } + if (O->vloc >= 0) + { + glEnableVertexAttribArray(O->vloc); + glVertexAttribPointer(O->vloc, 3, GL_FLOAT, GL_FALSE, vs, (const GLvoid *) 32); + } + } +#endif +} + +/*----------------------------------------------------------------------------*/ + +int obj_cmp_vert(obj *O, int vi, int vj, float eps, float dot) +{ + if (fabs(O->vv[vi].v[0] - O->vv[vj].v[0]) >= eps) return 0; + if (fabs(O->vv[vi].v[1] - O->vv[vj].v[1]) >= eps) return 0; + if (fabs(O->vv[vi].v[2] - O->vv[vj].v[2]) >= eps) return 0; + + if (fabs(O->vv[vi].t[0] - O->vv[vj].t[0]) >= eps) return 0; + if (fabs(O->vv[vi].t[1] - O->vv[vj].t[1]) >= eps) return 0; + + if (O->vv[vi].n[0] * O->vv[vj].n[0] + + O->vv[vi].n[1] * O->vv[vj].n[1] + + O->vv[vi].n[2] * O->vv[vj].n[2] < dot) return 0; + + return 1; +} + +void obj_swp_vert(obj *O, int vi, int vj) +{ + int si; + int pi; + int li; + + /* Replace all occurrences of vi with vj. */ + + for (si = 0; si < O->sc; ++si) + { + for (pi = 0; pi < O->sv[si].pc; ++pi) + { + if (O->sv[si].pv[pi].vi[0] == vi) + O->sv[si].pv[pi].vi[0] = vj; + if (O->sv[si].pv[pi].vi[1] == vi) + O->sv[si].pv[pi].vi[1] = vj; + if (O->sv[si].pv[pi].vi[2] == vi) + O->sv[si].pv[pi].vi[2] = vj; + } + for (li = 0; li < O->sv[si].lc; ++li) + { + if (O->sv[si].lv[li].vi[0] == vi) + O->sv[si].lv[li].vi[0] = vj; + if (O->sv[si].lv[li].vi[1] == vi) + O->sv[si].lv[li].vi[1] = vj; + } + } +} + +void obj_uniq(obj *O, float eps, float dot, int verbose) +{ + int vc = O->vc; + int vi; + int vj; + int di; + + /* Merge all vertices within epsilon of one another. */ + + for (vi = 0; vi < O->vc; vi += di) + { + di = 1; + + for (vj = 0; vj < vi; ++vj) + { + if (obj_cmp_vert(O, vi, vj, eps, dot)) + { + if (verbose) printf("%d %d\n", vi, vc--); + + obj_swp_vert(O, vi, vj); + obj_del_vert(O, vi); + + di = 0; + break; + } + } + } +} + +/*----------------------------------------------------------------------------*/ + +void obj_sort(obj *O, int qc) +{ + const int vc = O->vc; + + struct vert + { + int qs; /* Cache insertion serial number */ + int *iv; /* Polygon reference list buffer */ + int ic; /* Polygon reference list length */ + }; + + /* Vertex optimization data; vertex FIFO cache */ + + struct vert *vv = (struct vert *) malloc(vc * sizeof (struct vert)); + int *qv = (int *) malloc(qc * sizeof (int )); + + int qs = 1; /* Current cache insertion serial number */ + int qi = 0; /* Current cache insertion point [0, qc) */ + + int si; + int pi; + int vi; + int ii; + int qj; + + /* Initialize the vertex cache to empty. */ + + for (qj = 0; qj < qc; ++qj) + qv[qj] = -1; + + /* Process each surface of this file in turn. */ + + for (si = 0; si < O->sc; ++si) + { + const int pc = O->sv[si].pc; + + /* Allocate the polygon reference list buffers. */ + + int *ip, *iv = (int *) malloc(3 * pc * sizeof (int)); + + /* Count the number of polygon references per vertex. */ + + memset(vv, 0, vc * sizeof (struct vert)); + + for (pi = 0; pi < pc; ++pi) + { + const index_t *i = O->sv[si].pv[pi].vi; + + vv[i[0]].ic++; + vv[i[1]].ic++; + vv[i[2]].ic++; + } + + /* Initialize all vertex optimization data. */ + + for (vi = 0, ip = iv; vi < vc; ++vi) + { + vv[vi].qs = -qc; + vv[vi].iv = ip; + ip += vv[vi].ic; + vv[vi].ic = 0; + } + + /* Fill the polygon reference list buffers. */ + + for (pi = 0; pi < pc; ++pi) + { + const index_t *i = O->sv[si].pv[pi].vi; + + vv[i[0]].iv[vv[i[0]].ic++] = pi; + vv[i[1]].iv[vv[i[1]].ic++] = pi; + vv[i[2]].iv[vv[i[2]].ic++] = pi; + } + + /* Iterate over the polygon array of this surface. */ + + for (pi = 0; pi < pc; ++pi) + { + const index_t *i = O->sv[si].pv[pi].vi; + + int qd = qs - qc; + + int dk = -1; /* The best polygon score */ + int pk = pi; /* The best polygon index */ + + /* Find the best polygon among those referred-to by the cache. */ + + for (qj = 0; qj < qc; ++qj) + if (qv[qj] >= 0) + + for (ii = 0; ii < vv[qv[qj]].ic; ++ii) + { + int pj = vv[qv[qj]].iv[ii]; + int dj = 0; + + const index_t *j = O->sv[si].pv[pj].vi; + + /* Recently-used vertex bonus. */ + + if (vv[j[0]].qs > qd) dj += vv[j[0]].qs - qd; + if (vv[j[1]].qs > qd) dj += vv[j[1]].qs - qd; + if (vv[j[2]].qs > qd) dj += vv[j[2]].qs - qd; + + /* Low-valence vertex bonus. */ + + dj -= vv[j[0]].ic; + dj -= vv[j[1]].ic; + dj -= vv[j[2]].ic; + + if (dk < dj) + { + dk = dj; + pk = pj; + } + } + + if (pk != pi) + { + struct obj_poly temp; + + /* Update the polygon reference list. */ + + for (vi = 0; vi < 3; ++vi) + for (ii = 0; ii < vv[i[vi]].ic; ++ii) + if (vv[i[vi]].iv[ii] == pi) + { + vv[i[vi]].iv[ii] = pk; + break; + } + + /* Swap the best polygon into the current position. */ + + temp = O->sv[si].pv[pi]; + O->sv[si].pv[pi] = O->sv[si].pv[pk]; + O->sv[si].pv[pk] = temp; + } + + /* Iterate over the current polygon's vertices. */ + + for (vi = 0; vi < 3; ++vi) + { + struct vert *vp = vv + i[vi]; + + /* If this vertex was a cache miss then queue it. */ + + if (qs - vp->qs >= qc) + { + vp->qs = qs++; + qv[qi] = i[vi]; + qi = (qi + 1) % qc; + } + + /* Remove the current polygon from the reference list. */ + + vp->ic--; + + for (ii = 0; ii < vp->ic; ++ii) + if (vp->iv[ii] == pk) + { + vp->iv[ii] = vp->iv[vp->ic]; + break; + } + } + } + free(iv); + } + free(qv); + free(vv); +} + +float obj_acmr(obj *O, int qc) +{ + int *vs = (int *) malloc(O->vc * sizeof (int)); + int qs = 1; + + int si; + int vi; + int pi; + + int nn = 0; + int dd = 0; + + for (si = 0; si < O->sc; ++si) + { + for (vi = 0; vi < O->vc; ++vi) + vs[vi] = -qc; + + for (pi = 0; pi < O->sv[si].pc; ++pi) + { + const index_t *i = O->sv[si].pv[pi].vi; + + if (qs - vs[i[0]] >= qc) { vs[i[0]] = qs++; nn++; } + if (qs - vs[i[1]] >= qc) { vs[i[1]] = qs++; nn++; } + if (qs - vs[i[2]] >= qc) { vs[i[2]] = qs++; nn++; } + + dd++; + } + } + + return (float) nn / (float) dd; +} + +/*----------------------------------------------------------------------------*/ + +#ifndef CONF_NO_GL + +static void obj_render_prop(const obj *O, int mi, int ki) +{ + const struct obj_prop *kp = O->mv[mi].kv + ki; + + if (kp->map) + { + GLenum wrap = GL_REPEAT; + + /* Bind the property map. */ + + glBindTexture(GL_TEXTURE_2D, kp->map); + + /* Apply the property options. */ + + if (kp->opt & OBJ_OPT_CLAMP) + wrap = GL_CLAMP_TO_EDGE; + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap); + + /* Apply the texture coordinate offset and scale. */ + + if (O->Mloc[ki] >= 0) + { + GLfloat T[16]; + + memset(T, 0, sizeof (T)); + + T[ 0] = kp->s[0]; + T[ 5] = kp->s[1]; + T[10] = kp->s[2]; + T[12] = kp->o[0]; + T[13] = kp->o[1]; + T[14] = kp->o[2]; + T[15] = 1.0f; + + glUniformMatrix4fv(O->Mloc[ki], 1, GL_FALSE, T); + } + } +} + +void obj_render_mtrl(const obj *O, int mi) +{ + int ki; + + /* Bind all material properties and texture maps. */ + + for (ki = 0; ki < OBJ_PROP_COUNT; ki++) + { + if (O->oloc[ki] >= 0 && obj_get_mtrl_map(O, mi, ki)) + { + glActiveTexture(GL_TEXTURE0 + ki); + obj_render_prop(O, mi, ki); + glUniform1i(O->oloc[ki], ki); + } + if (O->cloc[ki] >= 0) + glUniform4fv(O->cloc[ki], 1, O->mv[mi].kv[ki].c); + } + glActiveTexture(GL_TEXTURE0); +} + +void obj_render_surf(const obj *O, int si) +{ + const struct obj_surf *sp = O->sv + si; + + if (0 < sp->pc || sp->lc > 0) + { + /* Apply this surface's material. */ + + if (0 <= sp->mi && sp->mi < O->mc) + obj_render_mtrl(O, sp->mi); + + /* Render all polygons. */ + + if (sp->pibo) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sp->pibo); + glDrawElements(GL_TRIANGLES, 3 * sp->pc, GL_INDEX_T, (const GLvoid *) 0); + } + + /* Render all lines. */ + + if (sp->libo) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sp->libo); + glDrawElements(GL_LINES, 2 * sp->lc, GL_INDEX_T, (const GLvoid *) 0); + } + } +} + +void obj_render(obj *O) +{ + int si; + + assert(O); + + /* Initialize the vertex arrays. */ + + obj_init(O); + + /* Render each surface. */ + + glBindVertexArray(O->vao); + + for (si = 0; si < O->sc; ++si) + obj_render_surf(O, si); +} + +#else + +void obj_render(obj *O) +{ +} + +#endif + +/*============================================================================*/ + +void obj_bound(const obj *O, float *b) +{ + int vi; + + assert(O); + + /* Compute the bounding box of this object. */ + + if (O->vc > 0) + { + const float *v = O->vv[0].v; + + b[0] = b[3] = v[0]; + b[1] = b[4] = v[1]; + b[2] = b[5] = v[2]; + } + + for (vi = 0; vi < O->vc; ++vi) + { + const float *v = O->vv[vi].v; + + if (b[0] > v[0]) b[0] = v[0]; + if (b[1] > v[1]) b[1] = v[1]; + if (b[2] > v[2]) b[2] = v[2]; + + if (b[3] < v[0]) b[3] = v[0]; + if (b[4] < v[1]) b[4] = v[1]; + if (b[5] < v[2]) b[5] = v[2]; + } +} + +/*============================================================================*/ + +static void obj_write_map(FILE *fout, const obj *O, int mi, int ki, const char *s) +{ + struct obj_prop *kp = O->mv[mi].kv + ki; + + /* If this property has a map... */ + + if (kp->str) + { + fprintf(fout, "map_%s ", s); + + /* Store all map options. */ + + if ((kp->opt & OBJ_OPT_CLAMP) != 0) fprintf(fout, "-clamp on "); + + /* Store the map offset, if any. */ + + if (fabs(kp->o[0]) > 0 || + fabs(kp->o[1]) > 0 || + fabs(kp->o[2]) > 0) fprintf(fout, "-o %f %f %f ", + kp->o[0], kp->o[1], kp->o[2]); + + /* Store the map scale, if any. */ + + if (fabs(kp->s[0] - 1) > 0 || + fabs(kp->s[1] - 1) > 0 || + fabs(kp->s[2] - 1) > 0) fprintf(fout, "-s %f %f %f ", + kp->s[0], kp->s[1], kp->s[2]); + + /* Store the map image file name. */ + + fprintf(fout, "%s\n", kp->str); + } +} + +static void obj_write_mtl(const obj *O, const char *mtl) +{ + FILE *fout; + int mi; + + if ((fout = fopen(mtl, "w"))) + { + for (mi = 0; mi < O->mc; ++mi) + { + struct obj_mtrl *mp = O->mv + mi; + + /* Start a new material. */ + + if (mp->name) + fprintf(fout, "newmtl %s\n", mp->name); + else + fprintf(fout, "newmtl default\n"); + + /* Store all material property colors. */ + + fprintf(fout, "Kd %12.8f %12.8f %12.8f\n", mp->kv[OBJ_KD].c[0], + mp->kv[OBJ_KD].c[1], + mp->kv[OBJ_KD].c[2]); + fprintf(fout, "Ka %12.8f %12.8f %12.8f\n", mp->kv[OBJ_KA].c[0], + mp->kv[OBJ_KA].c[1], + mp->kv[OBJ_KA].c[2]); + fprintf(fout, "Ke %12.8f %12.8f %12.8f\n", mp->kv[OBJ_KE].c[0], + mp->kv[OBJ_KE].c[1], + mp->kv[OBJ_KE].c[2]); + fprintf(fout, "Ks %12.8f %12.8f %12.8f\n", mp->kv[OBJ_KS].c[0], + mp->kv[OBJ_KS].c[1], + mp->kv[OBJ_KS].c[2]); + + fprintf(fout, "Ns %12.8f\n", mp->kv[OBJ_NS].c[0]); + fprintf(fout, "d %12.8f\n", mp->kv[OBJ_KD].c[3]); + + /* Store all material property maps. */ + + obj_write_map(fout, O, mi, OBJ_KD, "Kd"); + obj_write_map(fout, O, mi, OBJ_KA, "Ka"); + obj_write_map(fout, O, mi, OBJ_KA, "Ke"); + obj_write_map(fout, O, mi, OBJ_KS, "Ks"); + obj_write_map(fout, O, mi, OBJ_NS, "Ns"); + obj_write_map(fout, O, mi, OBJ_KN, "Kn"); + } + } + fclose(fout); +} + +static void obj_write_obj(const obj *O, const char *obj, + const char *mtl, int prec) +{ + FILE *fout; + + if ((fout = fopen(obj, "w"))) + { + char formv[256]; + char formt[256]; + char formn[256]; + + int si; + int vi; + int pi; + int li; + + if (mtl) fprintf(fout, "mtllib %s\n", mtl); + + /* Store all vertex data. */ + + sprintf(formv, "v %%.%df %%.%df %%.%df\n", prec, prec, prec); + sprintf(formt, "vt %%.%df %%.%df\n", prec, prec); + sprintf(formn, "vn %%.%df %%.%df %%.%df\n", prec, prec, prec); + + for (vi = 0; vi < O->vc; ++vi) + fprintf(fout, formv, O->vv[vi].v[0], + O->vv[vi].v[1], + O->vv[vi].v[2]); + for (vi = 0; vi < O->vc; ++vi) + fprintf(fout, formt, O->vv[vi].t[0], + O->vv[vi].t[1]); + for (vi = 0; vi < O->vc; ++vi) + fprintf(fout, formn, O->vv[vi].n[0], + O->vv[vi].n[1], + O->vv[vi].n[2]); + + for (si = 0; si < O->sc; ++si) + { + int mi = O->sv[si].mi; + + /* Store the surface's material reference */ + + if (0 <= mi && mi < O->mc && O->mv[mi].name) + fprintf(fout, "usemtl %s\n", O->mv[O->sv[si].mi].name); + else + fprintf(fout, "usemtl default\n"); + + /* Store all polygon definitions. */ + + for (pi = 0; pi < O->sv[si].pc; pi++) + { + int vi0 = O->sv[si].pv[pi].vi[0] + 1; + int vi1 = O->sv[si].pv[pi].vi[1] + 1; + int vi2 = O->sv[si].pv[pi].vi[2] + 1; + + fprintf(fout, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", vi0, vi0, vi0, + vi1, vi1, vi1, + vi2, vi2, vi2); + } + + /* Store all line definitions. */ + + for (li = 0; li < O->sv[si].lc; li++) + { + int vi0 = O->sv[si].lv[li].vi[0] + 1; + int vi1 = O->sv[si].lv[li].vi[1] + 1; + + fprintf(fout, "l %d/%d/%d %d/%d/%d\n", vi0, vi0, vi0, + vi1, vi1, vi1); + } + } + + fclose(fout); + } +} + +void obj_write(const obj *O, const char *obj, const char *mtl, int prec) +{ + assert(O); + + if (obj) obj_write_obj(O, obj, mtl, prec); + if (mtl) obj_write_mtl(O, mtl); +} + +/*============================================================================*/ diff --git a/obj.h b/obj.h new file mode 100644 index 0000000..d2da08c --- /dev/null +++ b/obj.h @@ -0,0 +1,133 @@ +/* Copyright (c) 2005 Robert Kooima */ +/* */ +/* 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 UTIL3D_OBJ_H +#define UTIL3D_OBJ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ + +enum { + OBJ_KD, + OBJ_KA, + OBJ_KE, + OBJ_KS, + OBJ_NS, + OBJ_KN, + OBJ_PROP_COUNT +}; + +#define OBJ_OPT_CLAMP 1 + +/*----------------------------------------------------------------------------*/ + +typedef struct obj obj; + +obj *obj_create(const char *); +void obj_render(obj *); +void obj_delete(obj *); + +/*----------------------------------------------------------------------------*/ + +int obj_add_mtrl(obj *); +int obj_add_vert(obj *); +int obj_add_poly(obj *, int); +int obj_add_line(obj *, int); +int obj_add_surf(obj *); + +int obj_num_mtrl(const obj *); +int obj_num_vert(const obj *); +int obj_num_poly(const obj *, int); +int obj_num_line(const obj *, int); +int obj_num_surf(const obj *); + +void obj_del_mtrl(obj *, int); +void obj_del_vert(obj *, int); +void obj_del_poly(obj *, int, int); +void obj_del_line(obj *, int, int); +void obj_del_surf(obj *, int); + +/*----------------------------------------------------------------------------*/ + +void obj_set_mtrl_name(obj *, int, const char *); +void obj_set_mtrl_map (obj *, int, int, const char *); +void obj_set_mtrl_opt (obj *, int, int, unsigned int); +void obj_set_mtrl_c (obj *, int, int, const float *); +void obj_set_mtrl_o (obj *, int, int, const float *); +void obj_set_mtrl_s (obj *, int, int, const float *); + +void obj_set_vert_v(obj *, int, const float *); +void obj_set_vert_t(obj *, int, const float *); +void obj_set_vert_n(obj *, int, const float *); +void obj_set_vert_u(obj *, int, const float *); + +void obj_set_poly(obj *, int, int, const int *); +void obj_set_line(obj *, int, int, const int *); +void obj_set_surf(obj *, int, int); + +void obj_set_vert_loc(obj *, int, int, int, int); +void obj_set_prop_loc(obj *, int, int, int, int); + +/*----------------------------------------------------------------------------*/ + +const char *obj_get_mtrl_name(const obj *, int); +unsigned int obj_get_mtrl_map (const obj *, int, int); +unsigned int obj_get_mtrl_opt (const obj *, int, int); +void obj_get_mtrl_c (const obj *, int, int, float *); +void obj_get_mtrl_o (const obj *, int, int, float *); +void obj_get_mtrl_s (const obj *, int, int, float *); + +void obj_get_vert_v(const obj *, int, float *); +void obj_get_vert_t(const obj *, int, float *); +void obj_get_vert_n(const obj *, int, float *); + +void obj_get_poly(const obj *, int, int, int *); +void obj_get_line(const obj *, int, int, int *); +int obj_get_surf(const obj *, int); + +/*----------------------------------------------------------------------------*/ + +void obj_render_mtrl(const obj *, int); +void obj_render_surf(const obj *, int); +void obj_render_file(const obj *); + +/*----------------------------------------------------------------------------*/ + +unsigned int obj_load_image(const char *); + +void obj_mini(obj *); +void obj_norm(obj *); +void obj_proc(obj *); +void obj_uniq(obj *, float, float, int); +void obj_sort(obj *, int); +float obj_acmr(obj *, int); + +void obj_bound(const obj *, float *); +void obj_write(const obj *, const char *, const char *, int); + +/*======================================================================+=====*/ + +#ifdef __cplusplus +} +#endif +#endif